Skip to content

Commit 16ded4d

Browse files
authored
Allow extending writeSecureFile with custom options (#113)
1 parent 4aea0fe commit 16ded4d

7 files changed

Lines changed: 52 additions & 13 deletions

File tree

dist/fs.d.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/// <reference types="node" />
22
/// <reference types="node" />
3-
import { PathLike } from 'fs';
3+
import { PathLike, ObjectEncodingOptions, Mode, OpenMode } from 'fs';
44
/**
55
* forceRemove forcibly removes a file or directory (recursively). If the file
66
* or directory does not exist, it does nothing. This is functionally equivalent
@@ -25,10 +25,16 @@ export declare function isEmptyDir(dir: PathLike): Promise<boolean>;
2525
*
2626
* @param outputPath Path in which to create the secure file.
2727
* @param data Data to write to file.
28+
* @param options additional options to pass to writeFile. The default options
29+
* are permissions of 0640, write-exclusive, and flush-on-success.
2830
*
2931
* @returns Path to written file.
3032
*/
31-
export declare function writeSecureFile<T extends PathLike>(outputPath: T, data: string | Buffer): Promise<T>;
33+
export declare function writeSecureFile<T extends PathLike>(outputPath: T, data: string | Buffer, options?: ObjectEncodingOptions & {
34+
mode?: Mode;
35+
flag?: OpenMode;
36+
flush?: boolean;
37+
}): Promise<T>;
3238
/**
3339
* removeFile removes the file at the given path. If the file does not exist, it
3440
* does nothing.

dist/index.js

Lines changed: 8 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/fs.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17-
import { promises as fs, PathLike } from 'fs';
17+
import { promises as fs, PathLike, ObjectEncodingOptions, Mode, OpenMode } from 'fs';
1818

1919
import { errorMessage, isNotFoundError } from './errors';
2020

@@ -60,14 +60,22 @@ export async function isEmptyDir(dir: PathLike): Promise<boolean> {
6060
*
6161
* @param outputPath Path in which to create the secure file.
6262
* @param data Data to write to file.
63+
* @param options additional options to pass to writeFile. The default options
64+
* are permissions of 0640, write-exclusive, and flush-on-success.
6365
*
6466
* @returns Path to written file.
6567
*/
6668
export async function writeSecureFile<T extends PathLike>(
6769
outputPath: T,
6870
data: string | Buffer,
71+
options?: ObjectEncodingOptions & {
72+
mode?: Mode;
73+
flag?: OpenMode;
74+
flush?: boolean;
75+
},
6976
): Promise<T> {
70-
await fs.writeFile(outputPath, data, { mode: 0o640, flag: 'wx' });
77+
const opts = Object.assign({}, { mode: 0o640, flag: 'wx', flush: true }, options);
78+
await fs.writeFile(outputPath, data, opts);
7179
return outputPath;
7280
}
7381

src/ignore.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export async function parseGcloudIgnore(pth: string): Promise<string[]> {
3333

3434
let ignoreContents: string[] = [];
3535
try {
36-
ignoreContents = (await fs.readFile(pth, { encoding: 'utf-8' }))
36+
ignoreContents = (await fs.readFile(pth, { encoding: 'utf8' }))
3737
.toString()
3838
.split(/\r?\n/)
3939
.filter(shouldKeepIgnoreLine)
@@ -51,7 +51,7 @@ export async function parseGcloudIgnore(pth: string): Promise<string[]> {
5151
const includeName = line.substring(10).trim();
5252

5353
const includePth = pathjoin(parentDir, includeName);
54-
const subIgnoreContents = (await fs.readFile(includePth, { encoding: 'utf-8' }))
54+
const subIgnoreContents = (await fs.readFile(includePth, { encoding: 'utf8' }))
5555
.toString()
5656
.split(/\r?\n/)
5757
.filter(shouldKeepIgnoreLine)

src/kv.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ export function parseKVString(input: string): KVPair {
166166
*/
167167
export function parseKVFile(filePath: string): KVPair {
168168
try {
169-
const content = presence(readFileSync(filePath, 'utf-8'));
169+
const content = presence(readFileSync(filePath, 'utf8'));
170170
if (!content || content.length < 1) {
171171
return {};
172172
}

tests/fs.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,28 @@ describe('fs', { concurrency: true }, async () => {
101101

102102
const accessed = await fs.readFile(filepath, 'utf8');
103103
assert.deepStrictEqual(accessed, 'my data');
104+
105+
if (process.platform !== 'win32') {
106+
const stats = await fs.stat(filepath);
107+
assert.deepStrictEqual(stats.mode.toString(8), '100640');
108+
}
109+
});
110+
111+
await suite.test('writes a file with custom options', async () => {
112+
const filepath = randomFilepath();
113+
const result = await writeSecureFile(filepath, 'my data', {
114+
mode: 0o600,
115+
encoding: 'utf8',
116+
});
117+
assert.deepStrictEqual(filepath, result);
118+
119+
const accessed = await fs.readFile(filepath, 'utf8');
120+
assert.deepStrictEqual(accessed, 'my data');
121+
122+
if (process.platform !== 'win32') {
123+
const stats = await fs.stat(filepath);
124+
assert.deepStrictEqual(stats.mode.toString(8), '100600');
125+
}
104126
});
105127
});
106128
});

0 commit comments

Comments
 (0)