From 68949619fecbee12e128eeaf1f77bc12a23ac2d1 Mon Sep 17 00:00:00 2001 From: David Marby Date: Wed, 27 Jan 2021 13:01:53 +0100 Subject: [PATCH] Remove legacy sync (#3028) --- packages/insomnia-app/app/models/settings.js | 6 - .../app/sync-legacy/__tests__/sync.test.js | 557 ----------- .../insomnia-app/app/sync-legacy/index.js | 870 ------------------ .../insomnia-app/app/sync-legacy/logger.js | 37 - .../insomnia-app/app/sync-legacy/network.js | 77 -- .../insomnia-app/app/sync-legacy/storage.js | 240 ----- .../dropdowns/sync-legacy-dropdown.js | 234 ----- .../dropdowns/workspace-dropdown.js | 12 +- .../app/ui/components/modals/login-modal.js | 5 - .../modals/payment-notification-modal.js | 6 +- .../ui/components/modals/setup-sync-modal.js | 181 ---- .../modals/workspace-share-settings-modal.js | 203 ---- .../app/ui/components/page-layout.js | 1 - .../app/ui/components/settings/account.js | 3 +- .../app/ui/components/settings/general.js | 8 - .../app/ui/components/sidebar/sidebar.js | 13 +- .../app/ui/components/wrapper-debug.js | 1 - .../insomnia-app/app/ui/components/wrapper.js | 6 - packages/insomnia-app/app/ui/index.js | 20 +- 19 files changed, 8 insertions(+), 2472 deletions(-) delete mode 100644 packages/insomnia-app/app/sync-legacy/__tests__/sync.test.js delete mode 100644 packages/insomnia-app/app/sync-legacy/index.js delete mode 100644 packages/insomnia-app/app/sync-legacy/logger.js delete mode 100644 packages/insomnia-app/app/sync-legacy/network.js delete mode 100644 packages/insomnia-app/app/sync-legacy/storage.js delete mode 100644 packages/insomnia-app/app/ui/components/dropdowns/sync-legacy-dropdown.js delete mode 100644 packages/insomnia-app/app/ui/components/modals/setup-sync-modal.js delete mode 100644 packages/insomnia-app/app/ui/components/modals/workspace-share-settings-modal.js diff --git a/packages/insomnia-app/app/models/settings.js b/packages/insomnia-app/app/models/settings.js index 971414ce87..c938f92cea 100644 --- a/packages/insomnia-app/app/models/settings.js +++ b/packages/insomnia-app/app/models/settings.js @@ -55,9 +55,6 @@ type BaseSettings = { useBulkHeaderEditor: boolean, useBulkParametersEditor: boolean, validateSSL: boolean, - - // Feature flags - enableSyncBeta: boolean, }; export type Settings = BaseModel & BaseSettings; @@ -111,9 +108,6 @@ export function init(): BaseSettings { useBulkHeaderEditor: false, useBulkParametersEditor: false, validateSSL: true, - - // Feature flags - enableSyncBeta: false, }; } diff --git a/packages/insomnia-app/app/sync-legacy/__tests__/sync.test.js b/packages/insomnia-app/app/sync-legacy/__tests__/sync.test.js deleted file mode 100644 index da5e28e5fc..0000000000 --- a/packages/insomnia-app/app/sync-legacy/__tests__/sync.test.js +++ /dev/null @@ -1,557 +0,0 @@ -import * as sync from '../index'; -import * as models from '../../models'; -import * as db from '../../common/database'; -import * as syncStorage from '../storage'; -import * as network from '../network'; -import { globalBeforeEach } from '../../__jest__/before-each'; -import * as session from '../../account/session'; -import * as crypt from '../../account/crypt'; - -describe('Test push/pull behaviour', () => { - beforeEach(async () => { - await globalBeforeEach(); - - // Reset some things - sync._testReset(); - await _setSessionData(); - await _setupSessionMocks(); - - // Init sync and storage - const config = { inMemoryOnly: true, autoload: false, filename: null }; - await syncStorage.initDB(config, true); - - // Add some data - await models.workspace.create({ _id: 'wrk_1', name: 'Workspace 1' }); - await models.workspace.create({ _id: 'wrk_2', name: 'Workspace 2' }); - await models.request.create({ - _id: 'req_1', - name: 'Request 1', - parentId: 'wrk_1', - }); - await models.request.create({ - _id: 'req_2', - name: 'Request 2', - parentId: 'wrk_2', - }); - - // Create resources, resource groups, and configs - const workspaces = await models.workspace.all(); - const requests = await models.request.all(); - for (const d of [...workspaces, ...requests]) { - await sync.getOrCreateResourceForDoc(d); - } - }); - - it('Pushes sync mode with and without resource group id', async () => { - const request = await models.request.getById('req_1'); - const request2 = await models.request.getById('req_2'); - const resourceRequest = await syncStorage.getResourceByDocId(request._id); - const resourceRequest2 = await syncStorage.getResourceByDocId(request2._id); - - // Set up sync modes - await sync.createOrUpdateConfig(resourceRequest.resourceGroupId, { - syncMode: syncStorage.SYNC_MODE_ON, - }); - await sync.createOrUpdateConfig(resourceRequest2.resourceGroupId, { - syncMode: syncStorage.SYNC_MODE_UNSET, - }); - - await sync.push(); // Push only active configs - await sync.push(resourceRequest.resourceGroupId); // Force push rg_1 - await sync.push(resourceRequest2.resourceGroupId); // Force push rg_2 - - expect(network.syncPush.mock.calls.length).toBe(3); - expect(network.syncPush.mock.calls[0][0].length).toBe(2); - expect(network.syncPush.mock.calls[0][0][0].id).toBe('wrk_1'); - expect(network.syncPush.mock.calls[0][0][1].id).toBe('req_1'); - expect(network.syncPush.mock.calls[1][0].length).toBe(2); - expect(network.syncPush.mock.calls[1][0][0].id).toBe('wrk_1'); - expect(network.syncPush.mock.calls[1][0][1].id).toBe('req_1'); - expect(network.syncPush.mock.calls[2][0].length).toBe(2); - expect(network.syncPush.mock.calls[2][0][0].id).toBe('wrk_2'); - expect(network.syncPush.mock.calls[2][0][1].id).toBe('req_2'); - }); - - it('Updates dirty flag for push response', async () => { - const request = await models.request.getById('req_1'); - const resourceRequest = await syncStorage.getResourceByDocId(request._id); - await sync.createOrUpdateConfig(resourceRequest.resourceGroupId, { - syncMode: syncStorage.SYNC_MODE_ON, - }); - - network.syncPush.mockReturnValueOnce({ - updated: [], - created: [{ id: request._id, version: 'new-version' }], - removed: [], - conflicts: [], - }); - - const resourceBefore = await syncStorage.getResourceByDocId(request._id); - await sync.push(resourceRequest.resourceGroupId); - const resourceAfter = await syncStorage.getResourceByDocId(request._id); - - expect(network.syncPush.mock.calls.length).toBe(1); - expect(network.syncPush.mock.calls[0][0].length).toBe(2); - expect(network.syncPush.mock.calls[0][0][0].id).toBe('wrk_1'); - expect(network.syncPush.mock.calls[0][0][1].id).toBe('req_1'); - expect(resourceBefore.dirty).toBe(true); - expect(resourceAfter.dirty).toBe(false); - }); - - it('Updates resources for pull response', async () => { - const request = await models.request.getById('req_1'); - const request2 = await models.request.getById('req_2'); - const requestNew = Object.assign({}, request, { - _id: 'req_new', - name: 'New Request', - }); - const resourceBefore = await syncStorage.getResourceByDocId(request._id); - const resource2Before = await syncStorage.getResourceByDocId(requestNew._id); - await sync.createOrUpdateConfig(resourceBefore.resourceGroupId, { - syncMode: syncStorage.SYNC_MODE_ON, - }); - const updatedRequest = Object.assign({}, request, { - name: 'Request Updated', - }); - const updatedResource = Object.assign({}, resourceBefore, { - version: 'ver1', - encContent: await sync.encryptDoc(resourceBefore.resourceGroupId, updatedRequest), - }); - const createdResourceNew = Object.assign({}, resourceBefore, { - id: requestNew._id, - resourceGroupId: 'rg_1', - encContent: await sync.encryptDoc(resourceBefore.resourceGroupId, requestNew), - }); - - network.syncPull.mockReturnValueOnce({ - updatedResources: [updatedResource], - createdResources: [createdResourceNew], - idsToPush: [], - idsToRemove: ['req_2'], - }); - - // Pull and get docs/resources - await sync.pull(resourceBefore.resourceGroupId); - const requestAfter = await models.request.getById(request._id); - const request2After = await models.request.getById(request2._id); - const requestNewAfter = await models.request.getById('req_new'); - const resourceAfter = await syncStorage.getResourceByDocId( - request._id, - resourceBefore.resourceGroupId, - ); - const resource2After = await syncStorage.getResourceByDocId(request2._id); - const resourceNewAfter = await syncStorage.getResourceByDocId(requestNewAfter._id); - - // Assert - expect(resourceBefore.version).toBe('__NO_VERSION__'); - expect(resourceAfter.version).toBe(updatedResource.version); - expect(resourceBefore.dirty).toBe(true); - expect(resource2Before).toBe(null); - expect(resourceAfter.dirty).toBe(false); - expect(resource2After.removed).toBe(true); - expect(requestAfter.name).toBe('Request Updated'); - expect(request2After).toBe(null); - expect(resourceNewAfter).not.toBe(null); - }); - - it('Conflict: local version wins on modified before', async () => { - const requestClient = await models.request.getById('req_1'); - const requestServer = Object.assign({}, requestClient, { - name: 'Server Request', - }); - const resourceRequest = await syncStorage.getResourceByDocId(requestClient._id); - const resourceConflict = Object.assign({}, resourceRequest, { - version: 'ver-2', - encContent: await sync.encryptDoc(resourceRequest.resourceGroupId, requestServer), - lastEdited: resourceRequest.lastEdited - 1000, // Same edited time - }); - - network.syncPush.mockReturnValueOnce({ - updated: [], - created: [], - removed: [], - conflicts: [resourceConflict], - }); - - await sync.push(resourceRequest.resourceGroupId); - const resourceAfter = await syncStorage.getResourceByDocId( - requestClient._id, - resourceRequest.resourceGroupId, - ); - const requestAfter = await models.request.getById(requestClient._id); - - // Assert - expect(network.syncPush.mock.calls.length).toBe(1); - expect(network.syncPush.mock.calls[0][0].length).toBe(2); - // Even when local wins, local resource gets the remove resource version - expect(resourceAfter.version).toBe(resourceConflict.version); - // Local resource gets marked as dirty so it's pushed right away - expect(resourceAfter.dirty).toBe(true); - // Local db should not be changed since the local won - expect(requestAfter).toEqual(requestClient); - }); - - it('Conflict: local version wins on modified tie', async () => { - const requestClient = await models.request.getById('req_1'); - const requestServer = Object.assign({}, requestClient, { - name: 'Server Request', - }); - const resourceRequest = await syncStorage.getResourceByDocId(requestClient._id); - const resourceConflict = Object.assign({}, resourceRequest, { - version: 'ver-2', - encContent: await sync.encryptDoc(resourceRequest.resourceGroupId, requestServer), - lastEdited: resourceRequest.lastEdited, // Same edited time - }); - - network.syncPush.mockReturnValueOnce({ - updated: [], - created: [], - removed: [], - conflicts: [resourceConflict], - }); - - await sync.push(resourceRequest.resourceGroupId); - const resourceAfter = await syncStorage.getResourceByDocId( - requestClient._id, - resourceRequest.resourceGroupId, - ); - const requestAfter = await models.request.getById(requestClient._id); - - // Assert - expect(network.syncPush.mock.calls.length).toBe(1); - expect(network.syncPush.mock.calls[0][0].length).toBe(2); - // Even when local wins, local resource gets the remove resource version - expect(resourceAfter.version).toBe(resourceConflict.version); - // Local resource gets marked as dirty so it's pushed right away - expect(resourceAfter.dirty).toBe(true); - // Local db should not be changed since the local won - expect(requestAfter).toEqual(requestClient); - }); - - it('Conflict: server version wins if modified after', async () => { - const requestClient = await models.request.getById('req_1'); - const requestServer = Object.assign({}, requestClient, { - name: 'Server Request', - }); - const resourceRequest = await syncStorage.getResourceByDocId(requestClient._id); - const resourceConflict = Object.assign({}, resourceRequest, { - version: 'ver-2', - encContent: await sync.encryptDoc(resourceRequest.resourceGroupId, requestServer), - lastEdited: resourceRequest.lastEdited + 1000, - }); - - network.syncPush.mockReturnValueOnce({ - updated: [], - created: [], - removed: [], - conflicts: [resourceConflict], - }); - - await sync.push(resourceRequest.resourceGroupId); - const resourceAfter = await syncStorage.getResourceByDocId( - requestClient._id, - resourceRequest.resourceGroupId, - ); - const requestAfter = await models.request.getById(requestClient._id); - - // Assert - expect(network.syncPush.mock.calls.length).toBe(1); - expect(network.syncPush.mock.calls[0][0].length).toBe(2); - expect(resourceAfter.lastEdited).toBeGreaterThan(resourceRequest.lastEdited); - expect(resourceAfter.version).toBe(resourceConflict.version); - // Local resource gets marked as dirty so it's pushed right away - expect(resourceAfter.dirty).toBe(false); - expect(requestAfter.name).toBe('Server Request'); - expect(requestAfter.modified).toBe(requestServer.modified); - }); -}); - -describe('Integration tests for creating Resources and pushing', () => { - beforeEach(async () => { - await globalBeforeEach(); - - // Reset some things - await _setSessionData(); - sync._testReset(); - - // Mock some things - await _setupSessionMocks(); - jest.useFakeTimers(); - - // Init storage - const config = { inMemoryOnly: true, autoload: false, filename: null }; - await syncStorage.initDB(config, true); - - // Add some data - await models.workspace.create({ - _id: 'wrk_empty', - name: 'Workspace Empty', - }); - await models.workspace.create({ _id: 'wrk_1', name: 'Workspace 1' }); - await models.request.create({ - _id: 'req_1', - name: 'Request 1', - parentId: 'wrk_1', - }); - await models.request.create({ - _id: 'req_2', - name: 'Request 2', - parentId: 'wrk_1', - }); - await models.request.create({ - _id: 'req_3', - name: 'Request 3', - parentId: 'wrk_1', - }); - await models.environment.create({ - _id: 'env_2', - name: 'Env Prv', - parentId: 'wrk_1', - isPrivate: true, - }); - - // Flush changes just to be sure they won't affect our tests - await db.flushChanges(); - await sync.writePendingChanges(); - - // Assert that all our new models were created - expect((await models.workspace.all()).length).toBe(2); - expect((await models.request.all()).length).toBe(3); - expect((await models.environment.all()).length).toBe(1); - expect((await models.cookieJar.all()).length).toBe(0); - - // Assert that initializing sync will create the initial resources - expect((await syncStorage.allConfigs()).length).toBe(0); - expect((await syncStorage.allResources()).length).toBe(0); - const promise = sync.init(); - jest.runOnlyPendingTimers(); - await promise; - expect((await syncStorage.allConfigs()).length).toBe(2); - expect((await syncStorage.allResources()).length).toBe(5); - - // Mark all configs as auto sync - const configs = await syncStorage.allConfigs(); - for (const config of configs) { - await syncStorage.updateConfig(config, { - syncMode: syncStorage.SYNC_MODE_ON, - }); - } - - // Do initial push - await sync.push(); - - // Reset mocks once again before tests - await _setupSessionMocks(); - }); - - it('Resources created on DB change', async () => { - // Fetch the workspace and create a new request - await db.bufferChanges(); - await models.request.create({ - _id: 'req_t', - url: 'https://google.com', - parentId: 'wrk_1', - }); - - await db.flushChanges(); - await sync.writePendingChanges(); - await sync.push(); - - // Push changes and get resource - const resource = await syncStorage.getResourceByDocId('req_t'); - - // Assert - expect((await syncStorage.allConfigs()).length).toBe(2); - expect((await syncStorage.allResources()).length).toBe(6); - expect(_decryptResource(resource).url).toBe('https://google.com'); - expect(resource.removed).toBe(false); - - expect(network.syncPush.mock.calls.length).toBe(1); - expect(network.syncPush.mock.calls[0][0].length).toBe(6); - - expect(network.syncPull.mock.calls).toEqual([]); - }); - - it('Resources revived on DB change', async () => { - // Fetch the workspace and create a new request - await db.bufferChanges(); - const request = await models.request.create({ - _id: 'req_t', - name: 'Original Request', - parentId: 'wrk_1', - }); - await db.flushChanges(); - await sync.writePendingChanges(); - await sync.push(); - - // Mark resource as removed - const originalResource = await syncStorage.getResourceByDocId('req_t'); - const updatedResource = await syncStorage.updateResource(originalResource, { - removed: true, - }); - - // Update it and push it again - await db.bufferChanges(); - await models.request.update(request, { name: 'New Name' }); - await db.flushChanges(); - await sync.writePendingChanges(); - await sync.push(); - const finalResource = await syncStorage.getResourceByDocId('req_t'); - - // Assert - expect(originalResource.removed).toBe(false); - expect(updatedResource.removed).toBe(true); - expect(finalResource.removed).toBe(false); - }); - - it('Resources update on DB change', async () => { - // Create, update a request, and fetch it's resource - const request = await models.request.getById('req_1'); - const resource = await syncStorage.getResourceByDocId(request._id); - await db.bufferChanges(); - const updatedRequest = await models.request.update(request, { - name: 'New Name', - }); - - // Drain and fetch new resource - await db.flushChanges(); - await sync.writePendingChanges(); - await sync.push(); - const updatedResource = await syncStorage.getResourceByDocId(request._id); - - // Assert - expect(request.name).toBe('Request 1'); - expect(_decryptResource(resource).name).toBe('Request 1'); - expect(updatedRequest.name).toBe('New Name'); - expect(_decryptResource(updatedResource).name).toBe('New Name'); - expect(resource.removed).toBe(false); - - expect(network.syncPush.mock.calls.length).toBe(1); - expect(network.syncPush.mock.calls[0][0].length).toBe(5); - - expect(network.syncPull.mock.calls).toEqual([]); - }); - - it('Resources removed on DB change', async () => { - // Create, update a request, and fetch it's resource - const request = await models.request.getById('req_1'); - const resource = await syncStorage.getResourceByDocId(request._id); - await db.bufferChanges(); - await models.request.remove(request); - - // Drain and fetch new resource - await db.flushChanges(); - await sync.writePendingChanges(); - await sync.push(); - const updatedResource = await syncStorage.getResourceByDocId(request._id); - - // Assert - expect(resource.removed).toBe(false); - expect(updatedResource.removed).toBe(true); - - expect(network.syncPush.mock.calls.length).toBe(1); - expect(network.syncPush.mock.calls[0][0].length).toBe(5); - - expect(network.syncPull.mock.calls).toEqual([]); - }); -}); - -// ~~~~~~~ // -// Helpers // -// ~~~~~~~ // - -function _decryptResource(resource) { - const message = JSON.parse(resource.encContent); - const fakeKey = 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa'; - const docJSON = crypt.decryptAES(fakeKey, message); - return JSON.parse(docJSON); -} - -async function _setSessionData() { - const symmetricKey = { - alg: 'A256GCM', - ext: true, - k: '3-QU2OcQcpSyFIoL8idgclbImP3M8Y2d0oVAca3Vl4g', - key_ops: ['encrypt', 'decrypt'], - kty: 'oct', - }; - - const publicKey = { - alg: 'RSA-OAEP-256', - e: 'AQAB', - ext: true, - key_ops: ['encrypt'], - kty: 'RSA', - n: 'aaaa', - }; - - const { privateKey } = await crypt.generateKeyPairJWK(); - const encPrivateKey = { - ad: '', - d: Buffer.from(JSON.stringify(privateKey)).toString('hex'), - iv: '968f1d810efdaec58f9e313e', - t: '0e87a2e57a198ca79cb99585fe9c244a', - }; - - // Setup mocks and stuff - session.setSessionData( - 'ses_123', - 'acct_123', - 'Tammy', - 'Tester', - 'greg.schier@konghq.com', - symmetricKey, - publicKey, - encPrivateKey, - ); -} - -async function _setupSessionMocks() { - const resourceGroups = {}; - - network.syncCreateResourceGroup = jest.fn((parentId, name, _) => { - const id = `rg_${Object.keys(resourceGroups).length + 1}`; - - // Generate a public key and use a symmetric equal to it's Id for - // convenience - const publicKey = session.getPublicKey(); - const symmetricKeyStr = JSON.stringify({ k: id }); - const encSymmetricKey = crypt.encryptRSAWithJWK(publicKey, symmetricKeyStr); - - // Store the resource group and return it - resourceGroups[id] = Object.assign( - {}, - { id, encSymmetricKey }, - { - parentResourceId: parentId, - name: name, - encSymmetricKey: encSymmetricKey, - }, - ); - return resourceGroups[id]; - }); - - network.syncGetResourceGroup = jest.fn(id => { - if (resourceGroups[id]) { - return resourceGroups[id]; - } - - const err = new Error(`Not Found for ${id}`); - err.statusCode = 404; - throw err; - }); - - network.syncPull = jest.fn(body => ({ - updatedResources: [], - createdResources: [], - idsToPush: [], - idsToRemove: [], - })); - - network.syncPush = jest.fn(body => ({ - conflicts: [], - updated: [], - created: [], - removed: [], - })); -} diff --git a/packages/insomnia-app/app/sync-legacy/index.js b/packages/insomnia-app/app/sync-legacy/index.js deleted file mode 100644 index 844be3ce29..0000000000 --- a/packages/insomnia-app/app/sync-legacy/index.js +++ /dev/null @@ -1,870 +0,0 @@ -import * as db from '../common/database'; -import * as models from '../models'; -import * as store from './storage'; -import * as misc from '../common/misc'; -import Logger from './logger'; -import * as zlib from 'zlib'; -import { - syncCreateResourceGroup, - syncFixDupes, - syncGetResourceGroup, - syncPull, - syncPush, - syncResetData, -} from './network'; -import * as crypt from '../account/crypt'; -import * as session from '../account/session'; - -export const START_DELAY = 1e3; -export const PULL_PERIOD = 15e3; -export const WRITE_PERIOD = 1e3; - -const WHITE_LIST = { - [models.workspace.type]: true, - [models.request.type]: true, - [models.requestGroup.type]: true, - [models.environment.type]: true, - [models.unitTest.type]: true, - [models.unitTestSuite.type]: true, - - // These can be overridden in sync config - [models.cookieJar.type]: true, - [models.clientCertificate.type]: true, -}; - -export const logger = new Logger(); - -// TODO: Move this stuff somewhere else -const NO_VERSION = '__NO_VERSION__'; -const resourceGroupSymmetricKeysCache = {}; -let _pullChangesInterval = null; -let _writeChangesInterval = null; -let _pendingDBChanges = {}; -let _isInitialized = false; - -// Used to mark whether or not the new sync system is enabled -let _disabledForSession = false; - -export function disableForSession() { - _disabledForSession = true; -} - -export async function init() { - if (_disabledForSession) { - logger.debug('Legacy sync is disabled for current session'); - return; - } - - if (_isInitialized) { - logger.debug('Already enabled'); - return; - } - - // NOTE: This is at the top to prevent race conditions - _isInitialized = true; - db.onChange(async changes => { - // To help prevent bugs, put Workspaces first - const sortedChanges = changes.sort(([event, doc, fromSync]) => - doc.type === models.workspace.type ? 1 : -1, - ); - - for (const [event, doc, fromSync] of sortedChanges) { - const notOnWhitelist = !WHITE_LIST[doc.type]; - const notLoggedIn = !session.isLoggedIn(); - - if (doc.isPrivate) { - logger.debug(`Skip private doc change ${doc._id}`); - continue; - } - - if (notLoggedIn || notOnWhitelist || fromSync) { - continue; - } - - const key = `${event}:${doc._id}`; - _pendingDBChanges[key] = [event, doc, Date.now()]; - } - }); - - await misc.delay(START_DELAY); - - await push(); - await pull(); - - let nextSyncTime = 0; - let isSyncing = false; - _pullChangesInterval = setInterval(async () => { - if (isSyncing) { - return; - } - - if (Date.now() < nextSyncTime) { - return; - } - - // Mark that we are currently executing a sync op - isSyncing = true; - - const syncStartTime = Date.now(); - - let extraDelay = 0; - try { - await push(); - await pull(); - } catch (err) { - logger.error('Sync failed with', err); - extraDelay += PULL_PERIOD; - } - - const totalSyncTime = Date.now() - syncStartTime; - - // Add sync duration to give the server some room if it's being slow. - // Also, multiply it by a random value so everyone doesn't sync up - extraDelay += totalSyncTime * (Math.random() * 2); - - nextSyncTime = Date.now() + PULL_PERIOD + extraDelay; - isSyncing = false; - }, PULL_PERIOD / 5); - - _writeChangesInterval = setInterval(writePendingChanges, WRITE_PERIOD); - - logger.debug('Initialized'); -} - -// Used only during tests! -export function _testReset() { - _isInitialized = false; - clearInterval(_pullChangesInterval); - clearInterval(_writeChangesInterval); -} - -/** - * Non-blocking function to perform initial sync for an account. This will pull - * all remote resources (if they exist) before initializing sync. - */ -export function doInitialSync() { - process.nextTick(async () => { - // First, pull down all remote resources, without first creating new ones. - // This makes sure that the first sync won't create resources locally, when - // they already exist on the server. - await pull(null, false); - - // Make sure sync is on (start the timers) - await init(); - }); -} - -/** - * This is a function to clean up Workspaces that might have had more than one - * ResourceGroup created for them. This function should be called on init (or maybe - * even periodically) and can be removed once the bug stops persisting. - */ -export async function fixDuplicateResourceGroups() { - if (!session.isLoggedIn()) { - return; - } - - let duplicateCount = 0; - const workspaces = await models.workspace.all(); - for (const workspace of workspaces) { - const resources = await store.findResourcesByDocId(workspace._id); - - // No duplicates found - if (resources.length <= 1) { - continue; - } - - // Fix duplicates - const ids = resources.map(r => r.resourceGroupId); - const { deleteResourceGroupIds } = await syncFixDupes(ids); - - for (const idToDelete of deleteResourceGroupIds) { - await store.removeResourceGroup(idToDelete); - } - - duplicateCount++; - } - - if (duplicateCount) { - logger.debug(`Fixed ${duplicateCount}/${workspaces.length} duplicate synced Workspaces`); - } -} - -export async function writePendingChanges() { - // First make a copy and clear pending changes - const changes = Object.assign({}, _pendingDBChanges); - _pendingDBChanges = {}; - - const keys = Object.keys(changes); - - if (keys.length === 0) { - // No changes, just return - return; - } - - for (const key of Object.keys(changes)) { - const [event, doc, timestamp] = changes[key]; - await _handleChangeAndPush(event, doc, timestamp); - } -} - -export async function push(resourceGroupId = null) { - if (_disabledForSession) { - logger.debug('Legacy sync is disabled for current session'); - return; - } - - if (!session.isLoggedIn()) { - return; - } - - let allDirtyResources = []; - if (resourceGroupId) { - allDirtyResources = await store.findActiveDirtyResourcesForResourceGroup(resourceGroupId); - } else { - allDirtyResources = await store.findActiveDirtyResources(); - } - - if (!allDirtyResources.length) { - // No changes to push - return; - } - - const dirtyResources = []; - for (const r of allDirtyResources) { - // Check if resource type is blacklisted by user - const config = await store.getConfig(r.resourceGroupId); - - if (r.type === models.clientCertificate.type && config.syncDisableClientCertificates) { - logger.debug(`Skipping pushing blacklisted client certificate ${r.id}`); - continue; - } - - if (r.type === models.cookieJar.type && config.syncDisableCookieJars) { - logger.debug(`Skipping pushing blacklisted cookie jar ${r.id}`); - continue; - } - - dirtyResources.push(r); - } - - let responseBody; - try { - responseBody = await syncPush(dirtyResources); - } catch (e) { - logger.error('Failed to push changes', e); - return; - } - - const { updated, created, removed, conflicts } = responseBody; - - // Update all resource versions with the ones that were returned - for (const { id, version } of updated) { - const resource = await store.getResourceByDocId(id); - await store.updateResource(resource, { version, dirty: false }); - } - if (updated.length) { - logger.debug(`Push updated ${updated.length} resources`); - } - - // Update all resource versions with the ones that were returned - for (const { id, version } of created) { - const resource = await store.getResourceByDocId(id); - await store.updateResource(resource, { version, dirty: false }); - } - if (created.length) { - logger.debug(`Push created ${created.length} resources`); - } - - // Update all resource versions with the ones that were returned - for (const { id, version } of removed) { - const resource = await store.getResourceByDocId(id); - await store.updateResource(resource, { version, dirty: false }); - } - if (removed.length) { - logger.debug(`Push removed ${removed.length} resources`); - } - - // Resolve conflicts - await db.bufferChanges(); - for (const serverResource of conflicts) { - const localResource = await store.getResourceByDocId( - serverResource.id, - serverResource.resourceGroupId, - ); - - // On conflict, choose last edited one - const serverIsNewer = serverResource.lastEdited > localResource.lastEdited; - const winner = serverIsNewer ? serverResource : localResource; - - // Update local resource - // NOTE: using localResource as the base to make sure we have _id - await store.updateResource(localResource, winner, { - version: serverResource.version, // Act as the server resource no matter what - dirty: !serverIsNewer, // It's dirty if we chose the local doc - }); - - // Decrypt the docs from the resources. Don't fetch the local doc from the - // app database, because it might have been deleted. - const winnerName = serverIsNewer ? 'Server' : 'Local'; - logger.debug(`Resolved conflict for ${serverResource.id} (${winnerName})`); - - // If the server won, update ourselves. If we won, we already have the - // latest version, so do nothing. - if (serverIsNewer) { - const doc = await decryptDoc(winner.resourceGroupId, winner.encContent); - if (winner.removed) { - await db.remove(doc, true); - } else { - await db.update(doc, true); - } - } - } - - db.flushChangesAsync(); -} - -export async function pull(resourceGroupId = null, createMissingResources = true) { - if (_disabledForSession) { - logger.debug('Legacy sync is disabled for current session'); - return; - } - - if (!session.isLoggedIn()) { - return; - } - - // Try to fix duplicates first. Don't worry if this is called a lot since if there - // are no duplicates found it doesn't contact the network. - await fixDuplicateResourceGroups(); - - let allResources; - if (createMissingResources) { - allResources = await getOrCreateAllActiveResources(resourceGroupId); - } else { - allResources = await store.allActiveResources(resourceGroupId); - } - - let blacklistedConfigs; - if (resourceGroupId) { - // When doing specific sync, blacklist all configs except the one we're trying to sync. - const allConfigs = await store.allConfigs(); - blacklistedConfigs = allConfigs.filter(c => c.resourceGroupId !== resourceGroupId); - } else { - // When doing a full sync, blacklist the inactive configs - blacklistedConfigs = await store.findInactiveConfigs(resourceGroupId); - } - - const resources = allResources.map(r => ({ - id: r.id, - resourceGroupId: r.resourceGroupId, - version: r.version, - removed: r.removed, - })); - - const blacklistedResourceGroupIds = blacklistedConfigs.map(c => c.resourceGroupId); - - const body = { - resources, - blacklist: blacklistedResourceGroupIds, - }; - - if (resources.length) { - logger.debug(`Pulling with ${resources.length} resources`); - } - - let responseBody; - try { - responseBody = await syncPull(body); - } catch (e) { - logger.error('Failed to sync changes', e, body); - return; - } - - const { updatedResources, createdResources, idsToPush, idsToRemove } = responseBody; - - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // - // Insert all the created docs to the DB // - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // - - await db.bufferChanges(); - for (const serverResource of createdResources) { - let doc; - - try { - const { resourceGroupId, encContent } = serverResource; - doc = await decryptDoc(resourceGroupId, encContent); - } catch (e) { - logger.warn('Failed to decode created resource', e, serverResource); - return; - } - - // Check if resource type is blacklisted by user - const config = await store.getConfig(serverResource.resourceGroupId); - - if ( - serverResource.type === models.clientCertificate.type && - config.syncDisableClientCertificates - ) { - logger.debug(`[sync] Skipping pulling blacklisted client certificate ${serverResource.id}`); - continue; - } - - if (serverResource.type === models.cookieJar.type && config.syncDisableCookieJars) { - logger.debug(`[sync] Skipping pulling blacklisted cookie jar ${serverResource.id}`); - continue; - } - - // Update local Resource - try { - await store.insertResource(serverResource, { dirty: false }); - } catch (e) { - // This probably means we already have it. This should never happen, but - // might due to a rare race condition. - logger.error('Failed to insert resource', e, serverResource); - return; - } - - // NOTE: If the above Resource insert succeeded, that means we have safely - // insert the document. However, we're using an upsert here instead because - // it's very possible that the client already had that document locally. - // This might happen, for example, if the user logs out and back in again. - const existingDoc = await db.get(doc.type, doc._id); - if (existingDoc) { - await db.update(doc, true); - } else { - // Mark as not seen if we created a new workspace from sync - if (doc.type === models.workspace.type) { - const workspaceMeta = await models.workspaceMeta.getOrCreateByParentId(doc._id); - await models.workspaceMeta.update(workspaceMeta, { hasSeen: false }); - } - await db.insert(doc, true); - } - } - - if (createdResources.length) { - logger.debug(`Pull created ${createdResources.length} resources`); - } - - db.flushChangesAsync(); - - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // - // Save all the updated docs to the DB // - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // - - await db.bufferChanges(); - for (const serverResource of updatedResources) { - try { - const { resourceGroupId, encContent } = serverResource; - const doc = await decryptDoc(resourceGroupId, encContent); - - // Update app database - // Needs to be upsert because we could be "undeleting" something - await db.upsert(doc, true); - - // Update local resource - const resource = await store.getResourceByDocId( - serverResource.id, - serverResource.resourceGroupId, - ); - await store.updateResource(resource, serverResource, { dirty: false }); - } catch (e) { - logger.warn('Failed to decode updated resource', e, serverResource); - } - } - db.flushChangesAsync(); - - if (updatedResources.length) { - logger.debug(`Pull updated ${updatedResources.length} resources`); - } - - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // - // Remove all the docs that need removing // - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // - - await db.bufferChanges(); - for (const id of idsToRemove) { - const resource = await store.getResourceByDocId(id); - if (!resource) { - throw new Error(`Could not find Resource to remove for ${id}`); - } - - const doc = await decryptDoc(resource.resourceGroupId, resource.encContent); - if (!doc) { - throw new Error(`Could not find doc to remove ${id}`); - } - - // Mark resource as deleted - await store.updateResource(resource, { dirty: false, removed: true }); - - // Remove from DB - await db.remove(doc, true); - } - db.flushChangesAsync(); - - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // - // Push all the docs that need pushing // - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // - - for (const id of idsToPush) { - const resource = await store.getResourceByDocId(id); - if (!resource) { - throw new Error(`Could not find Resource to push for id ${id}`); - } - - // Mark all resources to push as dirty for the next push - await store.updateResource(resource, { dirty: true }); - } - - return updatedResources.length + createdResources.length; -} - -export async function getOrCreateConfig(resourceGroupId) { - const config = await store.getConfig(resourceGroupId); - - if (!config) { - return store.insertConfig({ resourceGroupId }); - } else { - return config; - } -} - -export async function ensureConfigExists(resourceGroupId, syncMode) { - const config = await store.getConfig(resourceGroupId); - if (!config) { - await store.insertConfig({ resourceGroupId, syncMode }); - } -} - -export async function createOrUpdateConfig(resourceGroupId, patch) { - const config = await store.getConfig(resourceGroupId); - const finalPatch = { resourceGroupId, ...patch }; - - if (config) { - return store.updateConfig(config, finalPatch); - } else { - return store.insertConfig(finalPatch); - } -} - -export async function logout() { - await session.logout(); - await resetLocalData(); -} - -export async function cancelTrial() { - await session.endTrial(); - await session.logout(); - await resetLocalData(); -} - -export async function resetLocalData() { - for (const c of await store.allConfigs()) { - await store.removeConfig(c); - } - - for (const r of await store.allResources()) { - await store.removeResource(r); - } -} - -export async function resetRemoteData() { - await syncResetData(); -} - -// ~~~~~~~ // -// HELPERS // -// ~~~~~~~ // - -async function _handleChangeAndPush(event, doc, timestamp) { - // Update the resource content and set dirty - // TODO: Remove one of these steps since it does encryption twice - // in the case where the resource does not exist yet - const resource = await getOrCreateResourceForDoc(doc); - - const updatedResource = await store.updateResource(resource, { - name: doc.name || 'n/a', - lastEdited: timestamp, - lastEditedBy: session.getAccountId(), - encContent: await encryptDoc(resource.resourceGroupId, doc), - removed: event === db.CHANGE_REMOVE, - dirty: true, - }); - - // Debounce pushing of dirty resources - logger.debug(`Queue ${event} ${updatedResource.id}`); -} - -/** - * Fetch a ResourceGroup. If it has been fetched before, lookup from memory - * - * @param resourceGroupId - * @returns {*} - */ -const _fetchResourceGroupPromises = {}; -const _resourceGroupCache = {}; - -export async function fetchResourceGroup(resourceGroupId, invalidateCache = false) { - if (invalidateCache) { - delete _resourceGroupCache[resourceGroupId]; - delete _fetchResourceGroupPromises[resourceGroupId]; - } - - // PERF: If we're currently fetching, return stored promise - // TODO: Maybe move parallel fetch caching into the fetch helper - if (_fetchResourceGroupPromises[resourceGroupId]) { - return _fetchResourceGroupPromises[resourceGroupId]; - } - - const promise = new Promise(async (resolve, reject) => { - let resourceGroup = _resourceGroupCache[resourceGroupId]; - - if (!resourceGroup) { - try { - resourceGroup = await syncGetResourceGroup(resourceGroupId); - } catch (e) { - if (e.statusCode === 404) { - await store.removeResourceGroup(resourceGroupId); - logger.debug('ResourceGroup not found. Deleting...'); - reject(new Error('ResourceGroup was not found')); - return; - } else { - logger.error(`Failed to get ResourceGroup ${resourceGroupId}: ${e}`); - reject(e); - return; - } - } - - if (resourceGroup.isDisabled) { - await store.removeResourceGroup(resourceGroup.id); - logger.debug('ResourceGroup was disabled. Deleting...'); - reject(new Error('ResourceGroup was disabled')); - return; - } - - // Also make sure a config exists when we first fetch it. - // (This may not be needed but we'll do it just in case) - await ensureConfigExists(resourceGroupId); - } - - // Bust cached promise because we're done with it. - _fetchResourceGroupPromises[resourceGroupId] = null; - - // Cache the ResourceGroup for next time (they never change) - _resourceGroupCache[resourceGroupId] = resourceGroup; - - // Return the ResourceGroup - resolve(resourceGroup); - }); - - // Cache the Promise in case we get asked for the same thing before done - _fetchResourceGroupPromises[resourceGroupId] = promise; - return promise; -} - -/** - * Get a ResourceGroup's symmetric encryption key - * - * @param resourceGroupId - * @private - */ -async function _getResourceGroupSymmetricKey(resourceGroupId) { - let key = resourceGroupSymmetricKeysCache[resourceGroupId]; - - if (!key) { - const resourceGroup = await fetchResourceGroup(resourceGroupId); - const accountPrivateKey = await session.getPrivateKey(); - - const symmetricKeyStr = crypt.decryptRSAWithJWK( - accountPrivateKey, - resourceGroup.encSymmetricKey, - ); - - key = JSON.parse(symmetricKeyStr); - - // Update cache - resourceGroupSymmetricKeysCache[resourceGroupId] = key; - } - - return key; -} - -export async function encryptDoc(resourceGroupId, doc) { - try { - const symmetricKey = await _getResourceGroupSymmetricKey(resourceGroupId); - - // TODO: Turn on compression once enough users are on version >= 5.7.0 - // const jsonStr = JSON.stringify(doc); - // const docStr = zlib.gzipSync(jsonStr); - - // Don't use compression for now - const docStr = JSON.stringify(doc); - - const message = crypt.encryptAES(symmetricKey, docStr); - return JSON.stringify(message); - } catch (e) { - logger.error(`Failed to encrypt for ${resourceGroupId}: ${e}`); - throw e; - } -} - -export async function decryptDoc(resourceGroupId, messageJSON) { - let decrypted; - try { - const symmetricKey = await _getResourceGroupSymmetricKey(resourceGroupId); - const message = JSON.parse(messageJSON); - decrypted = crypt.decryptAES(symmetricKey, message); - } catch (e) { - logger.error(`Failed to decrypt from ${resourceGroupId}: ${e}`, messageJSON); - throw e; - } - - try { - decrypted = zlib.gunzipSync(decrypted); - } catch (err) { - // It's not compressed (legacy), which is okay for now - } - - try { - return JSON.parse(decrypted); - } catch (e) { - logger.error(`Failed to parse after decrypt from ${resourceGroupId}: ${e}`, decrypted); - throw e; - } -} - -async function _getWorkspaceForDoc(doc) { - const ancestors = await db.withAncestors(doc); - return ancestors.find(d => d.type === models.workspace.type); -} - -export async function createResourceGroup(parentId, name) { - // Generate symmetric key for ResourceGroup - const rgSymmetricJWK = await crypt.generateAES256Key(); - const rgSymmetricJWKStr = JSON.stringify(rgSymmetricJWK); - - // Encrypt the symmetric key with Account public key - const publicJWK = session.getPublicKey(); - const encRGSymmetricJWK = crypt.encryptRSAWithJWK(publicJWK, rgSymmetricJWKStr); - - // Create the new ResourceGroup - let resourceGroup; - try { - resourceGroup = await syncCreateResourceGroup(parentId, name, encRGSymmetricJWK); - } catch (e) { - logger.error(`Failed to create ResourceGroup: ${e}`); - throw e; - } - - // Create a config for it - await ensureConfigExists(resourceGroup.id, store.SYNC_MODE_UNSET); - - logger.debug(`Created ResourceGroup ${resourceGroup.id}`); - return resourceGroup; -} - -export async function createResource(doc, resourceGroupId) { - return store.insertResource({ - id: doc._id, - name: doc.name || 'n/a', // Set name to the doc name if it has one - resourceGroupId: resourceGroupId, - version: NO_VERSION, - createdBy: session.getAccountId(), - lastEdited: doc.modified, - lastEditedBy: session.getAccountId(), - removed: false, - type: doc.type, - encContent: await encryptDoc(resourceGroupId, doc), - dirty: true, - }); -} - -export async function createResourceForDoc(doc) { - // No resource yet, so create one - const workspace = await _getWorkspaceForDoc(doc); - - if (!workspace) { - // Workspace was probably deleted before it's children could be synced. - // TODO: Handle this case better - throw new Error(`Could not find workspace for doc ${doc._id}`); - } - - let workspaceResource = await store.getResourceByDocId(workspace._id); - - if (!workspaceResource) { - const workspaceResourceGroup = await createResourceGroup(workspace._id, workspace.name); - workspaceResource = await createResource(workspace, workspaceResourceGroup.id); - } - - if (workspace === doc) { - // If the current doc IS a Workspace, just return it - return workspaceResource; - } else { - return createResource(doc, workspaceResource.resourceGroupId); - } -} - -export async function getOrCreateResourceForDoc(doc) { - const [resource, ...extras] = await store.findResourcesByDocId(doc._id); - - // Sometimes there may be multiple resources created by accident for - // the same doc. Let's delete the extras here if there are any. - for (const resource of extras) { - await store.removeResource(resource); - } - - if (resource) { - return resource; - } else { - return createResourceForDoc(doc); - } -} - -export async function getOrCreateAllActiveResources(resourceGroupId = null) { - const startTime = Date.now(); - const activeResourceMap = {}; - - let activeResources; - if (resourceGroupId) { - activeResources = await store.activeResourcesForResourceGroup(resourceGroupId); - } else { - activeResources = await store.allActiveResources(); - } - - for (const r of activeResources) { - activeResourceMap[r.id] = r; - } - - // Make sure Workspace is first, because the loop below depends on it - const modelTypes = Object.keys(WHITE_LIST).sort((a, b) => - a.type === models.workspace.type ? 1 : -1, - ); - - let created = 0; - for (const type of modelTypes) { - for (const doc of await db.all(type)) { - if (doc.isPrivate) { - // logger.debug(`Skip private doc ${doc._id}`); - continue; - } - - const resource = await store.getResourceByDocId(doc._id); - if (!resource) { - try { - activeResourceMap[doc._id] = await createResourceForDoc(doc); - created++; - } catch (e) { - // logger.warn(`Failed to create resource for ${doc._id} ${e}`, {doc}); - } - } - } - } - - const resources = Object.keys(activeResourceMap).map(k => activeResourceMap[k]); - - const time = (Date.now() - startTime) / 1000; - if (created > 0) { - logger.debug(`Created ${created}/${resources.length} Resources (${time.toFixed(2)}s)`); - } - return resources; -} diff --git a/packages/insomnia-app/app/sync-legacy/logger.js b/packages/insomnia-app/app/sync-legacy/logger.js deleted file mode 100644 index 5c7bf391eb..0000000000 --- a/packages/insomnia-app/app/sync-legacy/logger.js +++ /dev/null @@ -1,37 +0,0 @@ -export default class Logger { - constructor() { - this._logs = []; - } - - debug(message, ...args) { - this._log('debug', message, ...args); - } - - warn(message, ...args) { - this._log('warn', message, ...args); - } - - error(message, ...args) { - this._log('error', message, ...args); - } - - tail() { - return this._logs; - } - - /** @private */ - _log(type, message, ...args) { - let fn; - if (type === 'debug') { - fn = 'log'; - } else if (type === 'warn') { - fn = 'warn'; - } else { - fn = 'error'; - } - - console[fn](`[sync] ${message}`, ...args); - const date = new Date(); - this._logs.push({ type, date, message }); - } -} diff --git a/packages/insomnia-app/app/sync-legacy/network.js b/packages/insomnia-app/app/sync-legacy/network.js deleted file mode 100644 index 57bf076b13..0000000000 --- a/packages/insomnia-app/app/sync-legacy/network.js +++ /dev/null @@ -1,77 +0,0 @@ -import * as fetch from '../account/fetch'; -import * as session from '../account/session'; -import * as crypt from '../account/crypt'; - -export async function syncCreateResourceGroup(parentResourceId, name, encSymmetricKey) { - return fetch.post( - '/api/resource_groups', - { - parentResourceId, - name, - encSymmetricKey, - }, - session.getCurrentSessionId(), - ); -} - -export async function syncGetResourceGroup(id) { - return fetch.get(`/api/resource_groups/${id}`, session.getCurrentSessionId()); -} - -export async function syncPull(body) { - return fetch.post('/sync/pull', body, session.getCurrentSessionId(), true); -} - -export async function syncPush(body) { - return fetch.post('/sync/push', body, session.getCurrentSessionId(), true); -} - -export async function syncResetData() { - return fetch.post('/auth/reset', null, session.getCurrentSessionId()); -} - -export async function syncFixDupes(resourceGroupIds) { - return fetch.post('/sync/fix-dupes', { ids: resourceGroupIds }, session.getCurrentSessionId()); -} - -export async function unshareWithAllTeams(resourceGroupId) { - return fetch.put( - `/api/resource_groups/${resourceGroupId}/unshare`, - null, - session.getCurrentSessionId(), - ); -} - -export async function shareWithTeam(resourceGroupId, teamId) { - // Ask the server what we need to do to invite the member - const instructions = await fetch.post( - `/api/resource_groups/${resourceGroupId}/share-a`, - { - teamId, - }, - session.getCurrentSessionId(), - ); - - const privateKeyJWK = session.getPrivateKey(); - const resourceGroupSymmetricKey = crypt.decryptRSAWithJWK( - privateKeyJWK, - instructions.encSymmetricKey, - ); - - // Build the invite data request - const newKeys = {}; - for (const accountId of Object.keys(instructions.keys)) { - const accountPublicKeyJWK = JSON.parse(instructions.keys[accountId]); - newKeys[accountId] = crypt.encryptRSAWithJWK(accountPublicKeyJWK, resourceGroupSymmetricKey); - } - - // Actually share it with the team - await fetch.post( - `/api/resource_groups/${resourceGroupId}/share-b`, - { - teamId, - keys: newKeys, - }, - session.getCurrentSessionId(), - ); -} diff --git a/packages/insomnia-app/app/sync-legacy/storage.js b/packages/insomnia-app/app/sync-legacy/storage.js deleted file mode 100644 index 85188e1ff1..0000000000 --- a/packages/insomnia-app/app/sync-legacy/storage.js +++ /dev/null @@ -1,240 +0,0 @@ -import NeDB from 'nedb'; -import fsPath from 'path'; -import crypto from 'crypto'; -import * as util from '../common/misc'; -import { DB_PERSIST_INTERVAL } from '../common/constants'; - -const TYPE_RESOURCE = 'Resource'; -const TYPE_CONFIG = 'Config'; - -export const SYNC_MODE_OFF = 'paused'; -export const SYNC_MODE_ON = 'active'; -export const SYNC_MODE_NEVER = 'never'; -export const SYNC_MODE_UNSET = 'unset'; -let changeListeners = []; - -export function onChange(callback) { - changeListeners.push(callback); -} - -export function offChange(callback) { - changeListeners = changeListeners.filter(l => l !== callback); -} - -let _changeTimeout = null; -function _notifyChange() { - clearTimeout(_changeTimeout); - _changeTimeout = setTimeout(() => { - for (const fn of changeListeners) { - fn(); - } - }, 200); -} - -export function allActiveResources(resourceGroupId = null) { - if (resourceGroupId) { - return findActiveResources({ resourceGroupId }); - } else { - return findActiveResources({}); - } -} - -export function activeResourcesForResourceGroup(resourceGroupId) { - return findActiveResources({ resourceGroupId }); -} - -export function allResources() { - return findResources({}); -} - -export async function findResources(query = {}) { - return _execDB(TYPE_RESOURCE, 'find', query); -} - -export async function findActiveResources(query) { - const configs = await findActiveConfigs(); - const resourceGroupIds = configs.map(c => c.resourceGroupId); - return findResources(Object.assign({ resourceGroupId: { $in: resourceGroupIds } }, query)); -} - -export async function findActiveDirtyResources() { - return findActiveResources({ dirty: true }); -} - -export async function findActiveDirtyResourcesForResourceGroup(resourceGroupId) { - return findActiveResources({ dirty: true, resourceGroupId }); -} - -export async function findDirtyResourcesForResourceGroup(resourceGroupId) { - return findResources({ dirty: true, resourceGroupId }); -} - -export async function findResourcesForResourceGroup(resourceGroupId) { - return findResources({ resourceGroupId }); -} - -export async function getResourceByDocId(id, resourceGroupId = null) { - let query; - if (resourceGroupId) { - query = { id, resourceGroupId }; - } else { - query = { id }; - } - - const rawDocs = await _execDB(TYPE_RESOURCE, 'find', query); - return rawDocs.length >= 1 ? rawDocs[0] : null; -} - -/** - * This function is temporary and should only be called when cleaning - * up duplicate ResourceGroups - * @param id - * @returns {*} - */ -export function findResourcesByDocId(id) { - return _execDB(TYPE_RESOURCE, 'find', { id }); -} - -/** - * This function is temporary and should only be called when cleaning - * up duplicate ResourceGroups - * @param resourceGroupId - * @returns {*} - */ -export async function removeResourceGroup(resourceGroupId) { - await _execDB(TYPE_RESOURCE, 'remove', { resourceGroupId }, { multi: true }); - await _execDB(TYPE_CONFIG, 'remove', { resourceGroupId }, { multi: true }); - _notifyChange(); -} - -export async function insertResource(resource) { - const h = crypto.createHash('md5'); - h.update(resource.resourceGroupId); - h.update(resource.id); - const newResource = Object.assign({}, resource, { - _id: `rs_${h.digest('hex')}`, - }); - await _execDB(TYPE_RESOURCE, 'insert', newResource); - _notifyChange(); - return newResource; -} - -export async function updateResource(resource, ...patches) { - const newDoc = Object.assign({}, resource, ...patches); - await _execDB(TYPE_RESOURCE, 'update', { _id: resource._id }, newDoc, { - multi: true, - }); - _notifyChange(); - return newDoc; -} - -export async function removeResource(resource) { - await _execDB(TYPE_RESOURCE, 'remove', { _id: resource._id }, { multi: true }); - _notifyChange(); -} - -// ~~~~~~ // -// Config // -// ~~~~~~ // - -export function findConfigs(query) { - return _execDB(TYPE_CONFIG, 'find', query); -} - -export function allConfigs() { - return findConfigs({}); -} - -export function findInactiveConfigs(excludedResourceGroupId = null) { - if (excludedResourceGroupId) { - return findConfigs({ - $not: { syncMode: SYNC_MODE_ON, excludedResourceGroupId }, - }); - } else { - return findConfigs({ $not: { syncMode: SYNC_MODE_ON } }); - } -} - -export function findActiveConfigs(resourceGroupId = null) { - if (resourceGroupId) { - return findConfigs({ syncMode: SYNC_MODE_ON, resourceGroupId }); - } else { - return findConfigs({ syncMode: SYNC_MODE_ON }); - } -} - -export async function getConfig(resourceGroupId) { - const rawDocs = await _execDB(TYPE_CONFIG, 'find', { resourceGroupId }); - return rawDocs.length >= 1 ? _initConfig(rawDocs[0]) : null; -} - -export async function updateConfig(config, ...patches) { - const doc = _initConfig(Object.assign(config, ...patches)); - await _execDB(TYPE_CONFIG, 'update', { _id: doc._id }, doc); - return doc; -} - -export function removeConfig(config) { - return _execDB(TYPE_CONFIG, 'remove', { _id: config._id }); -} - -export async function insertConfig(config) { - const doc = _initConfig(config); - await _execDB(TYPE_CONFIG, 'insert', doc); - return doc; -} - -function _initConfig(data) { - return Object.assign( - { - _id: util.generateId('scf'), - syncMode: SYNC_MODE_UNSET, - resourceGroupId: null, - }, - data, - ); -} - -export function initDB(config, forceReset) { - if (!_database || forceReset) { - const basePath = util.getDataDirectory(); - _database = {}; - - // NOTE: Do not EVER change this. EVER! - const resourcePath = fsPath.join(basePath, 'sync/Resource.db'); - const configPath = fsPath.join(basePath, 'sync/Config.db'); - - // Fill in the defaults - _database.Resource = new NeDB( - Object.assign({ filename: resourcePath, autoload: true }, config), - ); - - _database.Config = new NeDB(Object.assign({ filename: configPath, autoload: true }, config)); - - for (const key of Object.keys(_database)) { - _database[key].persistence.setAutocompactionInterval(DB_PERSIST_INTERVAL); - } - - // Done - console.log(`[sync] Initialize Sync DB at ${basePath}`); - } -} - -// ~~~~~~~ // -// Helpers // -// ~~~~~~~ // - -let _database = null; - -function _getDB(type, config = {}) { - initDB(config); - return _database[type]; -} - -function _execDB(type, fnName, ...args) { - return new Promise((resolve, reject) => { - _getDB(type)[fnName](...args, (err, data) => { - err ? reject(err) : resolve(data); - }); - }); -} diff --git a/packages/insomnia-app/app/ui/components/dropdowns/sync-legacy-dropdown.js b/packages/insomnia-app/app/ui/components/dropdowns/sync-legacy-dropdown.js deleted file mode 100644 index 8ad51b31eb..0000000000 --- a/packages/insomnia-app/app/ui/components/dropdowns/sync-legacy-dropdown.js +++ /dev/null @@ -1,234 +0,0 @@ -// @flow -import * as React from 'react'; -import autobind from 'autobind-decorator'; -import { Dropdown, DropdownButton, DropdownDivider, DropdownItem } from '../base/dropdown'; -import { showModal } from '../modals'; -import * as syncStorage from '../../../sync-legacy/storage'; -import * as sync from '../../../sync-legacy'; -import WorkspaceShareSettingsModal from '../modals/workspace-share-settings-modal'; -import SetupSyncModal from '../modals/setup-sync-modal'; -import type { Workspace } from '../../../models/workspace'; -import * as session from '../../../account/session'; -import { clickLink } from '../../../common/misc'; - -type Props = { - workspace: Workspace, - - // Optional - className?: string, -}; - -type State = { - loggedIn: boolean | null, - loading: boolean, - resourceGroupId: string | null, - syncMode: string | null, - syncPercent: number, - workspaceName: string, -}; - -@autobind -class SyncLegacyDropdown extends React.PureComponent { - _hasPrompted: boolean; - _isMounted: boolean; - - constructor(props: Props) { - super(props); - - this._hasPrompted = false; - this._isMounted = false; - - this.state = { - loggedIn: null, - loading: false, - resourceGroupId: null, - syncMode: null, - syncPercent: 0, - workspaceName: '', - }; - } - - _handleShowShareSettings() { - showModal(WorkspaceShareSettingsModal, { workspace: this.props.workspace }); - } - - async _handleSyncResourceGroupId() { - const { resourceGroupId } = this.state; - - // Set loading state - this.setState({ loading: true }); - - await sync.getOrCreateConfig(resourceGroupId); - await sync.pull(resourceGroupId); - await sync.push(resourceGroupId); - - await this._reloadData(); - - // Unset loading state - this.setState({ loading: false }); - } - - async _reloadData() { - const loggedIn = session.isLoggedIn(); - - if (loggedIn !== this.state.loggedIn) { - this.setState({ loggedIn }); - } - - if (!loggedIn) { - return; - } - - // Get or create any related sync data - const { workspace } = this.props; - const { resourceGroupId } = await sync.getOrCreateResourceForDoc(workspace); - const config = await sync.getOrCreateConfig(resourceGroupId); - - // Analyze it - const dirty = await syncStorage.findDirtyResourcesForResourceGroup(resourceGroupId); - const all = await syncStorage.findResourcesForResourceGroup(resourceGroupId); - const numClean = all.length - dirty.length; - const syncPercent = all.length === 0 ? 100 : parseInt((numClean / all.length) * 1000) / 10; - - if (this._isMounted) { - this.setState({ - resourceGroupId, - syncPercent, - syncMode: config.syncMode, - workspaceName: workspace.name, - }); - } - } - - static _handleShowSyncBetaPrompt() { - clickLink('https://support.insomnia.rest/article/67-version-control'); - } - - async _handleShowSyncModePrompt() { - showModal(SetupSyncModal, { - onSelectSyncMode: async syncMode => { - await this._reloadData(); - }, - }); - } - - componentDidMount() { - this._isMounted = true; - syncStorage.onChange(this._reloadData); - this._reloadData(); - } - - componentWillUnmount() { - syncStorage.offChange(this._reloadData); - this._isMounted = false; - } - - componentDidUpdate() { - const { resourceGroupId, syncMode } = this.state; - - if (!resourceGroupId) { - return; - } - - // Sync has not yet been configured for this workspace, so prompt the user to do so - const isModeUnset = !syncMode || syncMode === syncStorage.SYNC_MODE_UNSET; - if (isModeUnset && !this._hasPrompted) { - this._hasPrompted = true; - this._handleShowSyncModePrompt(); - } - } - - _getSyncDescription(syncMode: string | null, syncPercentage: number) { - let el = null; - if (syncMode === syncStorage.SYNC_MODE_NEVER) { - el = Sync Disabled; - } else if (syncPercentage === 100) { - el = Sync Up To Date; - } else if (syncMode === syncStorage.SYNC_MODE_OFF) { - el = ( - - Sync Required - - ); - } else if (syncMode === syncStorage.SYNC_MODE_ON) { - el = Sync Pending; - } else if (!syncMode || syncMode === syncStorage.SYNC_MODE_UNSET) { - el = ( - - Configure Sync - - ); - } - - return el; - } - - render() { - const { className } = this.props; - const { resourceGroupId, loading, loggedIn } = this.state; - - // Don't show the sync menu unless we're logged in - if (!loggedIn) { - return null; - } - - if (!resourceGroupId) { - return ( -
- -
- ); - } else { - const { syncMode, syncPercent } = this.state; - return ( -
- - - {this._getSyncDescription(syncMode, syncPercent)} - - Workspace Synced {syncPercent}% - - - - Change Sync Mode - - - {/* SYNCED */} - - {syncMode !== syncStorage.SYNC_MODE_NEVER ? ( - - {loading ? ( - - ) : ( - - )} - Sync Now - - ) : null} - - {syncMode !== syncStorage.SYNC_MODE_NEVER ? ( - - - Share Settings - - ) : null} - - {syncMode === syncStorage.SYNC_MODE_OFF && [ - // NOTE: We can't use here because the nesting breaks - // the component's child detection - , - - - Try New Sync Beta - , - ]} - -
- ); - } - } -} - -export default SyncLegacyDropdown; diff --git a/packages/insomnia-app/app/ui/components/dropdowns/workspace-dropdown.js b/packages/insomnia-app/app/ui/components/dropdowns/workspace-dropdown.js index c42084c4b2..741d6b5544 100644 --- a/packages/insomnia-app/app/ui/components/dropdowns/workspace-dropdown.js +++ b/packages/insomnia-app/app/ui/components/dropdowns/workspace-dropdown.js @@ -13,7 +13,6 @@ import { getAppName, getAppVersion } from '../../../common/constants'; import { showAlert, showError, showModal, showPrompt } from '../modals'; import Link from '../base/link'; import WorkspaceSettingsModal from '../modals/workspace-settings-modal'; -import WorkspaceShareSettingsModal from '../modals/workspace-share-settings-modal'; import LoginModal from '../modals/login-modal'; import Tooltip from '../tooltip'; import KeydownBinder from '../keydown-binder'; @@ -26,7 +25,6 @@ import * as db from '../../../common/database'; import VCS from '../../../sync/vcs'; import HelpTooltip from '../help-tooltip'; import type { Project } from '../../../sync/types'; -import * as sync from '../../../sync-legacy/index'; import PromptButton from '../base/prompt-button'; import * as session from '../../../account/session'; import type { WorkspaceAction } from '../../../plugins'; @@ -38,7 +36,6 @@ import type { Environment } from '../../../models/environment'; type Props = { activeEnvironment: Environment | null, activeWorkspace: Workspace, - enableSyncBeta: boolean, handleSetActiveWorkspace: (id: string) => void, hotKeyRegistry: HotKeyRegistry, isLoading: boolean, @@ -197,7 +194,7 @@ class WorkspaceDropdown extends React.PureComponent { } static async _handleLogout() { - await sync.logout(); + await session.logout(); } static _handleShowExport() { @@ -213,11 +210,7 @@ class WorkspaceDropdown extends React.PureComponent { } _handleShowShareSettings() { - if (this.props.enableSyncBeta) { - showModal(SyncShareModal); - } else { - showModal(WorkspaceShareSettingsModal); - } + showModal(SyncShareModal); } _handleWorkspaceCreate() { @@ -259,7 +252,6 @@ class WorkspaceDropdown extends React.PureComponent { isLoading, hotKeyRegistry, handleSetActiveWorkspace, - enableSyncBeta, ...other } = this.props; diff --git a/packages/insomnia-app/app/ui/components/modals/login-modal.js b/packages/insomnia-app/app/ui/components/modals/login-modal.js index 042b11391c..e489482450 100644 --- a/packages/insomnia-app/app/ui/components/modals/login-modal.js +++ b/packages/insomnia-app/app/ui/components/modals/login-modal.js @@ -5,7 +5,6 @@ import Modal from '../base/modal'; import ModalBody from '../base/modal-body'; import ModalHeader from '../base/modal-header'; import ModalFooter from '../base/modal-footer'; -import * as sync from '../../../sync-legacy'; import * as session from '../../../account/session'; @autobind @@ -42,10 +41,6 @@ class LoginModal extends PureComponent { try { await session.login(email, password); - - // Clear all existing sync data that might be there and enable sync - await sync.resetLocalData(); - await sync.doInitialSync(); this.hide(); } catch (e) { this.setState({ error: e.message, loading: false }); diff --git a/packages/insomnia-app/app/ui/components/modals/payment-notification-modal.js b/packages/insomnia-app/app/ui/components/modals/payment-notification-modal.js index db40136a95..765bd802ea 100644 --- a/packages/insomnia-app/app/ui/components/modals/payment-notification-modal.js +++ b/packages/insomnia-app/app/ui/components/modals/payment-notification-modal.js @@ -5,8 +5,7 @@ import Link from '../base/link'; import Modal from '../base/modal'; import ModalBody from '../base/modal-body'; import ModalHeader from '../base/modal-header'; -import * as sync from '../../../sync-legacy/index'; -import { getFirstName } from '../../../account/session'; +import { getFirstName, endTrial, logout } from '../../../account/session'; let hidePaymentNotificationUntilNextLaunch = false; @@ -14,7 +13,8 @@ let hidePaymentNotificationUntilNextLaunch = false; class PaymentNotificationModal extends PureComponent { async _handleCancel() { try { - await sync.cancelTrial(); + await endTrial(); + await logout(); } catch (err) { // That's okay } diff --git a/packages/insomnia-app/app/ui/components/modals/setup-sync-modal.js b/packages/insomnia-app/app/ui/components/modals/setup-sync-modal.js deleted file mode 100644 index bc79ef968b..0000000000 --- a/packages/insomnia-app/app/ui/components/modals/setup-sync-modal.js +++ /dev/null @@ -1,181 +0,0 @@ -// @flow -import * as React from 'react'; -import autobind from 'autobind-decorator'; -import Modal from '../base/modal'; -import ModalBody from '../base/modal-body'; -import ModalHeader from '../base/modal-header'; -import ModalFooter from '../base/modal-footer'; -import * as sync from '../../../sync-legacy'; -import { - SYNC_MODE_OFF, - SYNC_MODE_ON, - SYNC_MODE_NEVER, - SYNC_MODE_UNSET, -} from '../../../sync-legacy/storage'; -import type { Workspace } from '../../../models/workspace'; -import HelpTooltip from '../help-tooltip'; - -type Props = { - workspace: Workspace, -}; - -type State = { - syncMode: string, - selectedSyncMode: string, - syncDisableCookieJars: boolean, - syncDisableClientCertificates: boolean, -}; - -@autobind -class SetupSyncModal extends React.PureComponent { - modal: ?Modal; - _onSelectSyncMode: ?(selectedSyncMode: string) => void; - - constructor(props: Props) { - super(props); - this.state = { - syncMode: SYNC_MODE_UNSET, - selectedSyncMode: SYNC_MODE_ON, - syncDisableCookieJars: false, - syncDisableClientCertificates: false, - }; - } - - _setModalRef(n: ?Modal) { - this.modal = n; - } - - _handleToggleSyncCertificates(e: SyntheticEvent) { - this.setState({ syncDisableClientCertificates: !e.currentTarget.checked }); - } - - _handleToggleSyncCookieJars(e: SyntheticEvent) { - this.setState({ syncDisableCookieJars: !e.currentTarget.checked }); - } - - async _handleDone() { - const { workspace } = this.props; - const { selectedSyncMode, syncDisableClientCertificates, syncDisableCookieJars } = this.state; - - const resource = await sync.getOrCreateResourceForDoc(workspace); - await sync.createOrUpdateConfig(resource.resourceGroupId, { - syncMode: selectedSyncMode, - syncDisableClientCertificates: !!syncDisableClientCertificates, - syncDisableCookieJars: !!syncDisableCookieJars, - }); - - this.hide(); - - this._onSelectSyncMode && this._onSelectSyncMode(selectedSyncMode); - } - - _handleSyncModeChange(e: SyntheticEvent) { - const selectedSyncMode = e.currentTarget.value; - - this.setState({ - selectedSyncMode, - }); - } - - async show(options: { onSelectSyncMode: (syncMode: string) => void }) { - const { workspace } = this.props; - - const resource = await sync.getOrCreateResourceForDoc(workspace); - const config = await sync.getOrCreateConfig(resource.resourceGroupId); - const { syncMode, syncDisableCookieJars, syncDisableClientCertificates } = config; - - // Set selected sync mode. If it's unset, default it to ON - const selectedSyncMode = syncMode !== SYNC_MODE_UNSET ? syncMode : SYNC_MODE_ON; - - this.setState({ - syncMode, - selectedSyncMode, - syncDisableCookieJars, - syncDisableClientCertificates, - }); - - this._onSelectSyncMode = options.onSelectSyncMode; - - this.modal && this.modal.show(); - } - - hide() { - this.modal && this.modal.hide(); - } - - render() { - const { workspace } = this.props; - const { - syncMode, - selectedSyncMode, - syncDisableClientCertificates, - syncDisableCookieJars, - } = this.state; - - return ( - - Workspace Sync Setup - - {syncMode === SYNC_MODE_UNSET ? ( -

- You have not yet configured sync for your {workspace.name} workspace. -

- ) : null} -
-
- -
-
- -
- -
-
- -
-
-
- -
- * This can be changed at any time -
- -
-
- ); - } -} - -export default SetupSyncModal; diff --git a/packages/insomnia-app/app/ui/components/modals/workspace-share-settings-modal.js b/packages/insomnia-app/app/ui/components/modals/workspace-share-settings-modal.js deleted file mode 100644 index 0ea9b9a2d3..0000000000 --- a/packages/insomnia-app/app/ui/components/modals/workspace-share-settings-modal.js +++ /dev/null @@ -1,203 +0,0 @@ -import React, { PureComponent } from 'react'; -import PropTypes from 'prop-types'; -import autobind from 'autobind-decorator'; -import { Dropdown, DropdownButton, DropdownDivider, DropdownItem } from '../base/dropdown'; -import Link from '../base/link'; -import Modal from '../base/modal'; -import ModalBody from '../base/modal-body'; -import ModalHeader from '../base/modal-header'; -import ModalFooter from '../base/modal-footer'; -import * as sync from '../../../sync-legacy/index'; -import PromptButton from '../base/prompt-button'; -import { shareWithTeam, unshareWithAllTeams } from '../../../sync-legacy/network'; -import * as session from '../../../account/session'; - -@autobind -class WorkspaceShareSettingsModal extends PureComponent { - constructor(props) { - super(props); - this.state = {}; - } - - static _handleSubmit(e) { - e.preventDefault(); - } - - _handleClose() { - this.hide(); - } - - _setModalRef(n) { - this.modal = n; - } - - async _handleUnshare() { - if (!session.isLoggedIn()) { - return; - } - - const { resourceGroup } = this.state; - - this._resetState({ loading: true }); - - try { - await unshareWithAllTeams(resourceGroup.id); - await this._load(); - } catch (err) { - console.warn('Failed to unshare workspace', err); - this._resetState({ error: err.message, loading: false }); - } - } - - async _handleShareWithTeam(team) { - const { resourceGroup } = this.state; - this._resetState({ loading: true }); - - try { - await shareWithTeam(resourceGroup.id, team.id); - await this._load(); - } catch (err) { - this._resetState({ error: err.message, loading: false }); - } - } - - async _load() { - if (!session.isLoggedIn()) { - this._resetState({}); - return; - } - - const { workspace } = this.props; - const resource = await sync.getOrCreateResourceForDoc(workspace); - - const teams = await session.listTeams(); - - try { - const resourceGroup = await sync.fetchResourceGroup(resource.resourceGroupId, true); - this.setState({ teams, resourceGroup, loading: false, error: '' }); - } catch (err) { - console.warn('Failed to fetch ResourceGroup', err); - this.setState({ - error: 'No sync info found. Please try again.', - loading: false, - }); - } - } - - _resetState(patch = {}) { - this.setState( - Object.assign( - { - teams: [], - resourceGroup: null, - error: '', - loading: false, - }, - patch, - ), - ); - } - - async show() { - this._resetState(); - this.modal.show(); - - // This takes a while, so do it after show() - await this._load(); - } - - hide() { - this.modal.hide(); - } - - // eslint-disable-next-line camelcase - UNSAFE_componentWillMount() { - this._resetState(); - } - - render() { - const { teams, resourceGroup, error, loading } = this.state; - const { workspace } = this.props; - return ( -
- - Share Workspace - -

- Share {workspace.name} to automatically sync your API workspace with - your team members. -

-
- {error ?
Oops: {error}
: null} - - Teams - {!loading ? ( - resourceGroup && resourceGroup.teamId ? ( - - Shared with{' '} - {resourceGroup.teamName} - - ) : ( - - Private - - ) - ) : ( - - Loading...{' '} - - - )} - {teams.map(team => ( - - Share with {team.name} - - ))} - {teams.length === 0 && ( - - You have no teams - - )} - Other - - Private - - -    - {session.isLoggedIn() ? ( - - Manage Teams - - ) : ( - - Manage Teams - - )} -
-
- - - -
- - ); - } -} - -WorkspaceShareSettingsModal.propTypes = { - workspace: PropTypes.object.isRequired, -}; - -export default WorkspaceShareSettingsModal; diff --git a/packages/insomnia-app/app/ui/components/page-layout.js b/packages/insomnia-app/app/ui/components/page-layout.js index f41eb8548e..3dbffa2d32 100644 --- a/packages/insomnia-app/app/ui/components/page-layout.js +++ b/packages/insomnia-app/app/ui/components/page-layout.js @@ -123,7 +123,6 @@ class PageLayout extends React.PureComponent { ref={handleSetSidebarRef} activeEnvironment={activeEnvironment} activeGitRepository={activeGitRepository} - enableSyncBeta={settings.enableSyncBeta} environmentHighlightColorStyle={settings.environmentHighlightColorStyle} handleInitializeEntities={handleInitializeEntities} handleSetActiveEnvironment={handleSetActiveEnvironment} diff --git a/packages/insomnia-app/app/ui/components/settings/account.js b/packages/insomnia-app/app/ui/components/settings/account.js index 5d9ea128bb..a68d37a724 100644 --- a/packages/insomnia-app/app/ui/components/settings/account.js +++ b/packages/insomnia-app/app/ui/components/settings/account.js @@ -1,7 +1,6 @@ // @flow import * as React from 'react'; import autobind from 'autobind-decorator'; -import * as sync from '../../../sync-legacy/index'; import Link from '../base/link'; import LoginModal from '../modals/login-modal'; import { hideAllModals, showModal } from '../modals/index'; @@ -81,7 +80,7 @@ class Account extends React.PureComponent { } async _handleLogout() { - await sync.logout(); + await session.logout(); this.forceUpdate(); } diff --git a/packages/insomnia-app/app/ui/components/settings/general.js b/packages/insomnia-app/app/ui/components/settings/general.js index ec0e886570..de7aaf8a9f 100644 --- a/packages/insomnia-app/app/ui/components/settings/general.js +++ b/packages/insomnia-app/app/ui/components/settings/general.js @@ -19,7 +19,6 @@ import { } from '../../../common/constants'; import type { Settings } from '../../../models/settings'; import { setFont } from '../../../plugins/misc'; -import * as session from '../../../account/session'; import Tooltip from '../tooltip'; import CheckForUpdatesButton from '../check-for-updates-button'; import { initNewOAuthSession } from '../../../network/o-auth-2/misc'; @@ -519,13 +518,6 @@ class General extends React.PureComponent { as request data, names, etc.

- - {session.isLoggedIn() && ( - -
- {this.renderBooleanSetting('Enable version control beta', 'enableSyncBeta', '', true)} -
- )} ); } diff --git a/packages/insomnia-app/app/ui/components/sidebar/sidebar.js b/packages/insomnia-app/app/ui/components/sidebar/sidebar.js index 1495bb2d63..0178e8b3ba 100644 --- a/packages/insomnia-app/app/ui/components/sidebar/sidebar.js +++ b/packages/insomnia-app/app/ui/components/sidebar/sidebar.js @@ -7,14 +7,12 @@ import type { Environment } from '../../../models/environment'; import classnames from 'classnames'; import { COLLAPSE_SIDEBAR_REMS, SIDEBAR_SKINNY_REMS } from '../../../common/constants'; import SyncDropdown from '../dropdowns/sync-dropdown'; -import SyncLegacyDropdown from '../dropdowns/sync-legacy-dropdown'; import type { StatusCandidate } from '../../../sync/types'; import { isLoggedIn } from '../../../account/session'; type Props = {| activeEnvironment: Environment | null, children: React.Node, - enableSyncBeta: boolean, environmentHighlightColorStyle: string, handleSetActiveEnvironment: Function, handleSetActiveWorkspace: Function, @@ -35,7 +33,6 @@ class Sidebar extends React.PureComponent { const { activeEnvironment, children, - enableSyncBeta, environmentHighlightColorStyle, hidden, syncItems, @@ -61,7 +58,7 @@ class Sidebar extends React.PureComponent { }}> {children} - {enableSyncBeta && vcs && isLoggedIn() && ( + {vcs && isLoggedIn() && ( { syncItems={syncItems} /> )} - - {!enableSyncBeta && ( - - )} ); } diff --git a/packages/insomnia-app/app/ui/components/wrapper-debug.js b/packages/insomnia-app/app/ui/components/wrapper-debug.js index 87355bc169..ab500ed214 100644 --- a/packages/insomnia-app/app/ui/components/wrapper-debug.js +++ b/packages/insomnia-app/app/ui/components/wrapper-debug.js @@ -142,7 +142,6 @@ class WrapperDebug extends React.PureComponent { unseenWorkspaces={unseenWorkspaces} hotKeyRegistry={settings.hotKeyRegistry} handleSetActiveWorkspace={handleSetActiveWorkspace} - enableSyncBeta={settings.enableSyncBeta} isLoading={isLoading} vcs={vcs} /> diff --git a/packages/insomnia-app/app/ui/components/wrapper.js b/packages/insomnia-app/app/ui/components/wrapper.js index 13742e6e00..26f428c82b 100644 --- a/packages/insomnia-app/app/ui/components/wrapper.js +++ b/packages/insomnia-app/app/ui/components/wrapper.js @@ -35,7 +35,6 @@ import RequestSwitcherModal from './modals/request-switcher-modal'; import SettingsModal from './modals/settings-modal'; import FilterHelpModal from './modals/filter-help-modal'; import RequestSettingsModal from './modals/request-settings-modal'; -import SetupSyncModal from './modals/setup-sync-modal'; import SyncStagingModal from './modals/sync-staging-modal'; import GitRepositorySettingsModal from './modals/git-repository-settings-modal'; import GitStagingModal from './modals/git-staging-modal'; @@ -49,7 +48,6 @@ import SyncDeleteModal from './modals/sync-delete-modal'; import RequestRenderErrorModal from './modals/request-render-error-modal'; import WorkspaceEnvironmentsEditModal from './modals/workspace-environments-edit-modal'; import WorkspaceSettingsModal from './modals/workspace-settings-modal'; -import WorkspaceShareSettingsModal from './modals/workspace-share-settings-modal'; import CodePromptModal from './modals/code-prompt-modal'; import * as db from '../../common/database'; import * as models from '../../models/index'; @@ -672,8 +670,6 @@ class Wrapper extends React.PureComponent { isVariableUncovered={isVariableUncovered} /> - - { isVariableUncovered={isVariableUncovered} /> - - {gitVCS && ( diff --git a/packages/insomnia-app/app/ui/index.js b/packages/insomnia-app/app/ui/index.js index 9b604824ec..ddcd088d3e 100644 --- a/packages/insomnia-app/app/ui/index.js +++ b/packages/insomnia-app/app/ui/index.js @@ -5,16 +5,14 @@ import App from './containers/app'; import * as models from '../models'; import * as db from '../common/database'; import { init as initStore } from './redux/modules'; -import * as legacySync from '../sync-legacy'; import { init as initPlugins } from '../plugins'; import './css/index.less'; -import { getAppId, getAppLongName, isDevelopment } from '../common/constants'; +import { getAppLongName, isDevelopment } from '../common/constants'; import { setFont, setTheme } from '../plugins/misc'; import { AppContainer } from 'react-hot-loader'; import { DragDropContext } from 'react-dnd'; import DNDBackend from './dnd-backend'; import { trackEvent } from '../common/analytics'; -import { APP_ID_DESIGNER, APP_ID_INSOMNIA } from '../../config'; import * as styledComponents from 'styled-components'; import { initNewOAuthSession } from '../network/o-auth-2/misc'; import { initializeLogging } from '../common/log'; @@ -60,22 +58,6 @@ document.title = getAppLongName(); // render(App); // }); } - - const appId = getAppId(); - - // Legacy sync not part of Designer - if (appId === APP_ID_DESIGNER) { - legacySync.disableForSession(); - } else if (appId === APP_ID_INSOMNIA) { - // Do things that can wait - const { enableSyncBeta } = await models.settings.getOrCreate(); - if (enableSyncBeta) { - console.log('[app] Enabling sync beta'); - legacySync.disableForSession(); - } else { - process.nextTick(legacySync.init); - } - } })(); // Export some useful things for dev