Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions packages/insomnia/src/common/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,10 @@ export const getAllRemoteBackendProjectsByProjectId = async ({
return window.main.sync.remoteBackendProjects({ teamId: organizationId, teamProjectId });
};

export const getAllRemoteBackendProjectsOfOrg = async ({ organizationId }: { organizationId: string }) => {
return window.main.sync.remoteBackendProjectsOfTeam({ teamId: organizationId });
};

export const getUnsyncedRemoteWorkspaces = (remoteFiles: InsomniaFile[], workspaces: Workspace[]) =>
remoteFiles.filter(remoteFile => !workspaces.find(w => w._id === remoteFile.id));

Expand Down
1 change: 1 addition & 0 deletions packages/insomnia/src/entry.preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,7 @@ const sync: SyncBridgeAPI = {
pullRemoteBackendProject: options => invokeWithNormalizedError('sync.pullRemoteBackendProject', options),
push: (...args) => invokeSyncMethod('push', ...args),
remoteBackendProjects: (...args) => invokeSyncMethod('remoteBackendProjects', ...args),
remoteBackendProjectsOfTeam: (...args) => invokeSyncMethod('remoteBackendProjectsOfTeam', ...args),
removeBackendProjectsForRoot: (...args) => invokeSyncMethod('removeBackendProjectsForRoot', ...args),
removeBranch: (...args) => invokeSyncMethod('removeBranch', ...args),
removeRemoteBranch: (...args) => invokeSyncMethod('removeRemoteBranch', ...args),
Expand Down
38 changes: 38 additions & 0 deletions packages/insomnia/src/main/cloud-sync/core/vcs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { generateId } from '../../../common/misc';
import type {
BackendProject,
BackendProjectWithTeams,
BackendProjectWithTeamsAndTeamProjectId,
Branch,
DocumentKey,
Head,
Expand Down Expand Up @@ -205,6 +206,43 @@ export class VCS {
}));
}

async remoteBackendProjectsOfTeam({ teamId }: { teamId: string }) {
console.log(`[remoteBackendProjectsOfTeam] Fetching remote workspaces for teamId=${teamId}`);

const { projects } = await this._runGraphQL<{ projects: BackendProjectWithTeamsAndTeamProjectId[] }>(
`
query ($teamId: ID, $allProjects: Boolean) {
projects(teamId: $teamId, allProjects: $allProjects) {
id
name
rootDocumentId
teamProjectId
teams {
id
name
}
}
}
`,
{
teamId,
allProjects: true,
},
'projects',
);

console.log(`[remoteBackendProjectsOfTeam] Fetched ${projects.length} remote workspaces`);

return projects.map(backend => ({
id: backend.id,
name: backend.name,
rootDocumentId: backend.rootDocumentId,
teamProjectId: backend.teamProjectId,
// A backend project is guaranteed to exist on exactly one team
team: backend.teams[0],
}));
Comment on lines +236 to +243
}

async blobFromLastSnapshot(key: string) {
const branch = await this._getCurrentBranch();
const snapshot = await this._getLatestSnapshot(branch.name);
Expand Down
2 changes: 2 additions & 0 deletions packages/insomnia/src/main/cloud-sync/ipc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { IpcRendererEvent } from 'electron';
import type {
BackendProject,
BackendProjectWithTeam,
BackendProjectWithTeamsAndTeamProjectId,
Compare,
MergeConflict,
Snapshot,
Expand Down Expand Up @@ -43,6 +44,7 @@ export interface SyncBridgeMethods {
}) => Promise<Operation>;
push: (options: { teamId: string; teamProjectId: string }) => Promise<void>;
remoteBackendProjects: (options: { teamId: string; teamProjectId: string }) => Promise<BackendProjectWithTeam[]>;
remoteBackendProjectsOfTeam: (options: { teamId: string }) => Promise<BackendProjectWithTeamsAndTeamProjectId[]>;
removeBackendProjectsForRoot: (rootDocumentId: string) => Promise<void>;
removeBranch: (branchName: string) => Promise<void>;
removeRemoteBranch: (branchName: string) => Promise<void>;
Expand Down
5 changes: 5 additions & 0 deletions packages/insomnia/src/sync/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@ export interface BackendProjectWithTeams extends BackendProject {
teams: Team[];
}

export interface BackendProjectWithTeamsAndTeamProjectId extends BackendProject {
teams: Team[];
teamProjectId: string;
}

export interface BackendProjectWithTeam extends BackendProject {
team: Team;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,7 @@
import { Button as BasicButton } from '~/basic-components/button';
import type { SortOrder } from '~/common/constants';
import { fuzzyMatchAll } from '~/common/misc';
import {
getAllRemoteBackendProjectsByProjectId,
getUnsyncedRemoteWorkspaces,
type InsomniaFile,
} from '~/common/project';
import { getAllRemoteBackendProjectsOfOrg, getUnsyncedRemoteWorkspaces, type InsomniaFile } from '~/common/project';
import { sortMethodMap } from '~/common/sorting';
import type { RequestGroup, Workspace } from '~/insomnia-data';
import { models, services } from '~/insomnia-data';
Expand Down Expand Up @@ -256,32 +252,48 @@
const cloudSyncProjectIds = cloudSyncProjectIdsKey.split(',');
const result = new Map<string, InsomniaFile[]>();
isFetchingUnsyncedFilesRef.current = true;

// set up a map of remoteId to projectId for all cloud sync projects.
const remoteIdToProjectIdMap = new Map<string, string>();
for (const projectId of cloudSyncProjectIds) {
try {
const targetProject = await services.project.get(projectId);
if (targetProject && 'remoteId' in targetProject && targetProject.remoteId) {
const files = await getAllRemoteBackendProjectsByProjectId({
teamProjectId: targetProject.remoteId,
organizationId,
const project = await services.project.get(projectId);
if (project && 'remoteId' in project && project.remoteId) {
remoteIdToProjectIdMap.set(project.remoteId, projectId);
}
}

try {
const files = await getAllRemoteBackendProjectsOfOrg({ organizationId });
const filesByProjectId = new Map<string, InsomniaFile[]>();
// group files by projectId
for (const file of files) {
const projectId = remoteIdToProjectIdMap.get(file.teamProjectId);
if (projectId) {
if (!filesByProjectId.has(projectId)) {
filesByProjectId.set(projectId, []);
}
filesByProjectId.get(projectId)?.push({
id: file.rootDocumentId,
name: file.name,
scope: 'unsynced',
label: 'Unsynced',
remoteId: file.id,
created: 0,
lastModifiedTimestamp: 0,
});
result.set(
projectId,
files.map(f => ({
id: f.rootDocumentId,
name: f.name,
scope: 'unsynced',
label: 'Unsynced',
remoteId: f.id,
created: 0,
lastModifiedTimestamp: 0,
})),
);
}
} catch (error) {
console.error(`Failed to fetch unsynced files for project ${projectId}`, error);
}

for (const [projectId, files] of filesByProjectId.entries()) {
result.set(projectId, files);
}
} catch (error) {
console.error(`Failed to fetch unsynced files for organization ${organizationId}`, error);

Check notice

Code scanning / Semgrep OSS

Semgrep Finding: javascript.lang.security.audit.unsafe-formatstring.unsafe-formatstring Note

Detected string concatenation with a non-literal variable in a util.format / console.log function. If an attacker injects a format specifier in the string, it will forge the log message. Try to use constant values for the format string.
for (const projectId of cloudSyncProjectIds) {
result.set(projectId, []);
}
}

isFetchingUnsyncedFilesRef.current = false;
return setUnsyncedFilesByProjectId(result);
}, [organizationId, cloudSyncProjectIdsKey]);
Expand Down
Loading