Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Insomnia Cloud Sync): Update filesystem driver for VCS sync #7111

Merged
merged 3 commits into from
Feb 27, 2024
Merged
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
123 changes: 49 additions & 74 deletions packages/insomnia/src/sync/store/drivers/file-system-driver.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import fs from 'fs';
import fs from 'fs/promises';
import path from 'path';

import type { BaseDriver } from './base';
Expand All @@ -17,86 +17,62 @@
}

async hasItem(key: string) {
return new Promise<boolean>((resolve, reject) => {
fs.stat(this._getKeyPath(key), err => {
if (err && err.code === 'ENOENT') {
resolve(false);
} else if (err) {
reject(err);
} else {
resolve(true);
}
});
});
}
try {
const stats = await fs.stat(await this._getKeyPath(key));
const result = stats.isFile() || stats.isDirectory() || stats.isSymbolicLink();

setItem(key: string, value: Buffer) {
return new Promise<void>((resolve, reject) => {
const finalPath = this._getKeyPath(key);
return result;
} catch (err) {
if (err && 'code' in err && err.code === 'ENOENT') {
return false;
}

throw err;
}
}

async setItem(key: string, value: Buffer) {
console.log(`[FileSystemDriver] Writing to ${key}`);
const finalPath = await this._getKeyPath(key);
// Temp path contains randomness to avoid race-condition collisions. This
// doesn't actually avoid race conditions but at least it won't fail.
const tmpPath = `${finalPath}.${Math.random()}.tmp`;

const tmpPath = `${finalPath}.${crypto.randomUUID()}.tmp`;
console.log(`[FileSystemDriver] Writing to ${tmpPath} then renaming to ${finalPath}`);
// This method implements atomic writes by first writing to a temporary
// file (non-atomic) then renaming the file to the final value (atomic)
fs.writeFile(tmpPath, value, 'utf8', err => {
if (err) {
return reject(err);
}

fs.rename(tmpPath, finalPath, err => {
if (err) {
return reject(err);
}

resolve();
});
});
});
try {
await fs.writeFile(tmpPath, value, 'utf8');
await fs.rename(tmpPath, finalPath);
} catch (err) {
console.error(`[FileSystemDriver] Failed to write to ${tmpPath} then rename to ${finalPath}`, err);

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.
throw err;
}
}

getItem(key: string) {
return new Promise<Buffer | null>((resolve, reject) => {
fs.readFile(this._getKeyPath(key), (err, data) => {
if (err && err.code === 'ENOENT') {
resolve(null);
} else if (err) {
reject(err);
} else {
resolve(data);
}
});
});
}
async getItem(key: string) {
try {
const file = await fs.readFile(await this._getKeyPath(key));
return file;
} catch (err) {
if (err && 'code' in err && err.code === 'ENOENT') {
return null;
}

removeItem(key: string) {
return new Promise<void>((resolve, reject) => {
fs.unlink(this._getKeyPath(key), err => {
if (err && err.code === 'ENOENT') {
resolve();
} else if (err) {
reject(err);
} else {
resolve();
}
});
});
throw err;
}
}

clear() {
return new Promise<void>((resolve, reject) => {
fs.readdir(this._directory, (err, names) => {
if (err) {
return reject(err);
}
async removeItem(key: string) {
await fs.unlink(await this._getKeyPath(key));
}

for (const name of names) {
fs.unlinkSync(this._getKeyPath(name));
}
async clear() {
const files = await fs.readdir(this._directory);

resolve();
});
});
for (const fileName of files) {
await fs.unlink(await this._getKeyPath(fileName));
}
}

async keys(prefix: string, recursive: boolean) {
Expand All @@ -106,7 +82,7 @@
let names: string[] = [];

try {
names = fs.readdirSync(dir);
names = await fs.readdir(dir);
} catch (err) {
if (err.code !== 'ENOENT') {
reject(err);
Expand All @@ -120,7 +96,7 @@
}

const p = path.join(dir, name);
const isDir = fs.statSync(p).isDirectory();
const isDir = (await fs.stat(p)).isDirectory();

if (isDir && recursive) {
const more = await next(p);
Expand All @@ -136,7 +112,7 @@
});
};

const rawKeys = await next(this._getKeyPath(prefix));
const rawKeys = await next(await this._getKeyPath(prefix));
const keys: string[] = [];

for (const rawKey of rawKeys) {
Expand All @@ -146,11 +122,10 @@
return keys;
}

_getKeyPath(key: string) {
async _getKeyPath(key: string) {
const p = path.join(this._directory, key);
// Create base directory
fs.mkdirSync(path.dirname(p), { recursive: true });

await fs.mkdir(path.dirname(p), { recursive: true });
return p;
}
}
Loading