Skip to content

Commit 3166917

Browse files
committed
reduce number of config files
1 parent d6d9bb5 commit 3166917

4 files changed

Lines changed: 45 additions & 61 deletions

File tree

src/config/generateConfigHash.ts

Lines changed: 0 additions & 58 deletions
This file was deleted.

src/config/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
export { loadConfig } from './loadConfig';
22
export { validateConfigCore, validateConfigFile } from './validateConfig';
3-
export { generateConfigHash } from './generateConfigHash';
43
export { makeConfigStore, ConfigStore } from './configStore';
5-
export { appDataLocation, attemptToReadTOMLData } from './utils';
4+
export { appDataLocation, attemptToReadTOMLData, generateConfigHash } from './utils';
65

76
export type { Config } from './Config';

src/config/loadConfig.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import fs from 'node:fs';
1818

1919
import { validateConfigFile } from './validateConfig';
2020
import { loadSaltFile } from './loadSaltFile';
21-
import { generateConfigHash } from './generateConfigHash';
21+
import { generateConfigHash } from './utils';
2222

2323
import { getSaltFilePath, attemptToReadTOMLData } from './utils';
2424
import type { Config } from './Config';

src/config/utils.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,12 @@ import fs from 'node:fs';
1818
import os from 'node:os';
1919
import path from 'node:path';
2020
import toml from 'toml';
21+
import { createHash } from 'node:crypto';
22+
import stableStringify from 'safe-stable-stringify';
23+
2124
import type { Config } from './Config';
2225

26+
2327
// Tries to read the file data, returns null if unsuccessful
2428
export function attemptToReadFileData(filePath: string, encoding: fs.EncodingOption = 'utf-8') {
2529
try {
@@ -87,3 +91,42 @@ export function appDataLocation() {
8791
throw new Error(`Unsupported platform for salt file location: ${process.platform}`);
8892
}
8993
}
94+
95+
const DEFAULT_HASH_TYPE = 'md5';
96+
const HASH_DIGEST_TYPE = 'hex';
97+
98+
type RecursivePartial<T> = { [P in keyof T]?: RecursivePartial<T[P]> };
99+
100+
// Takes a config, removes the "signature" and salt keys from it, generates
101+
// a stable JSON representation and hashes it using the provided algorithm
102+
export function generateConfigHash<T extends Config.CoreConfiguration>(config: T, hashType = DEFAULT_HASH_TYPE) {
103+
// create a nested copy of the object
104+
const configCopy = { ...(JSON.parse(JSON.stringify(config)) as RecursivePartial<T>) };
105+
106+
// remove the "signature" key
107+
if (configCopy.meta && "signature" in configCopy.meta) {
108+
delete configCopy.meta.signature;
109+
}
110+
111+
// remove the "messages" key
112+
// TODO: messages should go in a separate locales file to future proof translations
113+
if ("messages" in configCopy) {
114+
delete configCopy.messages;
115+
}
116+
117+
// remove the "algorithm.salt" part as it may have injected keys
118+
// TODO: this enables messing with the salt file path pre-injection without signature validations, but is required for compatibility w/ the injection workflow
119+
delete configCopy.algorithm!.salt!.value;
120+
// mock the salt source as STRING to ensure that both imported and saved
121+
// (with pre-injected salt) config files work
122+
configCopy.algorithm!.salt!.source = 'STRING';
123+
124+
// generate a stable JSON representation
125+
const stableJson = stableStringify(configCopy);
126+
if (typeof stableJson !== 'string') throw new Error(`Unable to serialise config object to JSON.`);
127+
128+
// generate the hash
129+
const hash = createHash(hashType).update(stableJson).digest(HASH_DIGEST_TYPE);
130+
131+
return hash;
132+
}

0 commit comments

Comments
 (0)