Skip to content

Commit 91e4cb0

Browse files
author
Leon Si
committed
chore: lockfile
1 parent 4febc7c commit 91e4cb0

2 files changed

Lines changed: 333 additions & 4 deletions

File tree

packages/encryption/dist/index.cjs

Lines changed: 327 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,327 @@
1+
'use strict';
2+
3+
Object.defineProperty(exports, '__esModule', { value: true });
4+
5+
var execa = require('@commonjs/execa');
6+
var node_buffer = require('node:buffer');
7+
var crypto = require('node:crypto');
8+
var path = require('node:path');
9+
var node_url = require('node:url');
10+
var process = require('node:process');
11+
var fs = require('node:fs');
12+
13+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
14+
15+
function _interopNamespace(e) {
16+
if (e && e.__esModule) return e;
17+
var n = Object.create(null);
18+
if (e) {
19+
Object.keys(e).forEach(function (k) {
20+
if (k !== 'default') {
21+
var d = Object.getOwnPropertyDescriptor(e, k);
22+
Object.defineProperty(n, k, d.get ? d : {
23+
enumerable: true,
24+
get: function () { return e[k]; }
25+
});
26+
}
27+
});
28+
}
29+
n["default"] = e;
30+
return Object.freeze(n);
31+
}
32+
33+
var execa__default = /*#__PURE__*/_interopDefaultLegacy(execa);
34+
var crypto__namespace = /*#__PURE__*/_interopNamespace(crypto);
35+
var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
36+
var path__namespace = /*#__PURE__*/_interopNamespace(path);
37+
var process__default = /*#__PURE__*/_interopDefaultLegacy(process);
38+
var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
39+
40+
const copyProperty = (to, from, property, ignoreNonConfigurable) => {
41+
// `Function#length` should reflect the parameters of `to` not `from` since we keep its body.
42+
// `Function#prototype` is non-writable and non-configurable so can never be modified.
43+
if (property === 'length' || property === 'prototype') {
44+
return;
45+
}
46+
47+
// `Function#arguments` and `Function#caller` should not be copied. They were reported to be present in `Reflect.ownKeys` for some devices in React Native (#41), so we explicitly ignore them here.
48+
if (property === 'arguments' || property === 'caller') {
49+
return;
50+
}
51+
52+
const toDescriptor = Object.getOwnPropertyDescriptor(to, property);
53+
const fromDescriptor = Object.getOwnPropertyDescriptor(from, property);
54+
55+
if (!canCopyProperty(toDescriptor, fromDescriptor) && ignoreNonConfigurable) {
56+
return;
57+
}
58+
59+
Object.defineProperty(to, property, fromDescriptor);
60+
};
61+
62+
// `Object.defineProperty()` throws if the property exists, is not configurable and either:
63+
// - one its descriptors is changed
64+
// - it is non-writable and its value is changed
65+
const canCopyProperty = function (toDescriptor, fromDescriptor) {
66+
return toDescriptor === undefined || toDescriptor.configurable || (
67+
toDescriptor.writable === fromDescriptor.writable &&
68+
toDescriptor.enumerable === fromDescriptor.enumerable &&
69+
toDescriptor.configurable === fromDescriptor.configurable &&
70+
(toDescriptor.writable || toDescriptor.value === fromDescriptor.value)
71+
);
72+
};
73+
74+
const changePrototype = (to, from) => {
75+
const fromPrototype = Object.getPrototypeOf(from);
76+
if (fromPrototype === Object.getPrototypeOf(to)) {
77+
return;
78+
}
79+
80+
Object.setPrototypeOf(to, fromPrototype);
81+
};
82+
83+
const wrappedToString = (withName, fromBody) => `/* Wrapped ${withName}*/\n${fromBody}`;
84+
85+
const toStringDescriptor = Object.getOwnPropertyDescriptor(Function.prototype, 'toString');
86+
const toStringName = Object.getOwnPropertyDescriptor(Function.prototype.toString, 'name');
87+
88+
// We call `from.toString()` early (not lazily) to ensure `from` can be garbage collected.
89+
// We use `bind()` instead of a closure for the same reason.
90+
// Calling `from.toString()` early also allows caching it in case `to.toString()` is called several times.
91+
const changeToString = (to, from, name) => {
92+
const withName = name === '' ? '' : `with ${name.trim()}() `;
93+
const newToString = wrappedToString.bind(null, withName, from.toString());
94+
// Ensure `to.toString.toString` is non-enumerable and has the same `same`
95+
Object.defineProperty(newToString, 'name', toStringName);
96+
Object.defineProperty(to, 'toString', {...toStringDescriptor, value: newToString});
97+
};
98+
99+
function mimicFunction(to, from, {ignoreNonConfigurable = false} = {}) {
100+
const {name} = to;
101+
102+
for (const property of Reflect.ownKeys(from)) {
103+
copyProperty(to, from, property, ignoreNonConfigurable);
104+
}
105+
106+
changePrototype(to, from);
107+
changeToString(to, from, name);
108+
109+
return to;
110+
}
111+
112+
const calledFunctions = new WeakMap();
113+
114+
const onetime = (function_, options = {}) => {
115+
if (typeof function_ !== 'function') {
116+
throw new TypeError('Expected a function');
117+
}
118+
119+
let returnValue;
120+
let callCount = 0;
121+
const functionName = function_.displayName || function_.name || '<anonymous>';
122+
123+
const onetime = function (...arguments_) {
124+
calledFunctions.set(onetime, ++callCount);
125+
126+
if (callCount === 1) {
127+
returnValue = function_.apply(this, arguments_);
128+
function_ = null;
129+
} else if (options.throw === true) {
130+
throw new Error(`Function \`${functionName}\` can only be called once`);
131+
}
132+
133+
return returnValue;
134+
};
135+
136+
mimicFunction(onetime, function_);
137+
calledFunctions.set(onetime, callCount);
138+
139+
return onetime;
140+
};
141+
142+
onetime.callCount = function_ => {
143+
if (!calledFunctions.has(function_)) {
144+
throw new Error(`The given function \`${function_.name}\` is not wrapped by the \`onetime\` package`);
145+
}
146+
147+
return calledFunctions.get(function_);
148+
};
149+
150+
const typeMappings = {
151+
directory: 'isDirectory',
152+
file: 'isFile',
153+
};
154+
155+
function checkType(type) {
156+
if (type in typeMappings) {
157+
return;
158+
}
159+
160+
throw new Error(`Invalid type specified: ${type}`);
161+
}
162+
163+
const matchType = (type, stat) => type === undefined || stat[typeMappings[type]]();
164+
165+
const toPath$1 = urlOrPath => urlOrPath instanceof URL ? node_url.fileURLToPath(urlOrPath) : urlOrPath;
166+
167+
function locatePathSync(
168+
paths,
169+
{
170+
cwd = process__default["default"].cwd(),
171+
type = 'file',
172+
allowSymlinks = true,
173+
} = {},
174+
) {
175+
checkType(type);
176+
cwd = toPath$1(cwd);
177+
178+
const statFunction = allowSymlinks ? fs__default["default"].statSync : fs__default["default"].lstatSync;
179+
180+
for (const path_ of paths) {
181+
try {
182+
const stat = statFunction(path__default["default"].resolve(cwd, path_));
183+
184+
if (matchType(type, stat)) {
185+
return path_;
186+
}
187+
} catch {}
188+
}
189+
}
190+
191+
const toPath = urlOrPath => urlOrPath instanceof URL ? node_url.fileURLToPath(urlOrPath) : urlOrPath;
192+
193+
const findUpStop = Symbol('findUpStop');
194+
195+
function findUpMultipleSync(name, options = {}) {
196+
let directory = path__default["default"].resolve(toPath(options.cwd) || '');
197+
const {root} = path__default["default"].parse(directory);
198+
const stopAt = options.stopAt || root;
199+
const limit = options.limit || Number.POSITIVE_INFINITY;
200+
const paths = [name].flat();
201+
202+
const runMatcher = locateOptions => {
203+
if (typeof name !== 'function') {
204+
return locatePathSync(paths, locateOptions);
205+
}
206+
207+
const foundPath = name(locateOptions.cwd);
208+
if (typeof foundPath === 'string') {
209+
return locatePathSync([foundPath], locateOptions);
210+
}
211+
212+
return foundPath;
213+
};
214+
215+
const matches = [];
216+
// eslint-disable-next-line no-constant-condition
217+
while (true) {
218+
const foundPath = runMatcher({...options, cwd: directory});
219+
220+
if (foundPath === findUpStop) {
221+
break;
222+
}
223+
224+
if (foundPath) {
225+
matches.push(path__default["default"].resolve(directory, foundPath));
226+
}
227+
228+
if (directory === stopAt || matches.length >= limit) {
229+
break;
230+
}
231+
232+
directory = path__default["default"].dirname(directory);
233+
}
234+
235+
return matches;
236+
}
237+
238+
function findUpSync(name, options = {}) {
239+
const matches = findUpMultipleSync(name, {...options, limit: 1});
240+
return matches[0];
241+
}
242+
243+
function packageDirectorySync({cwd} = {}) {
244+
const filePath = findUpSync('package.json', {cwd});
245+
return filePath && path__default["default"].dirname(filePath);
246+
}
247+
248+
const getBruteForcerExecutablePath = onetime(() => {
249+
// eslint-disable-next-line unicorn/prefer-module
250+
const rootDir = packageDirectorySync({ cwd: __dirname });
251+
return path__namespace.join(rootDir, 'encryption-brute-forcer/target/release/encryption-brute-forcer');
252+
});
253+
254+
/**
255+
Implementation of using `aes-256-gcm` with node.js's `crypto` lib.
256+
*/
257+
function aes256gcm(key) {
258+
const ALGO = 'aes-256-gcm';
259+
// encrypt returns base64-encoded ciphertext
260+
function encrypt(str) {
261+
// The `iv` for a given key must be globally unique to prevent
262+
// against forgery attacks. `randomBytes` is convenient for
263+
// demonstration but a poor way to achieve this in practice.
264+
//
265+
// See: e.g. https://csrc.nist.gov/publications/detail/sp/800-38d/final
266+
const iv = node_buffer.Buffer.from('unique nonce', 'utf8');
267+
const cipher = crypto__namespace.createCipheriv(ALGO, key, iv);
268+
// Hint: Larger inputs (it's GCM, after all!) should use the stream API
269+
let enc = cipher.update(str, 'utf8', 'base64');
270+
enc += cipher.final('base64');
271+
return {
272+
enc: node_buffer.Buffer.from(enc, 'base64'),
273+
iv,
274+
authTag: cipher.getAuthTag(),
275+
};
276+
}
277+
// decrypt decodes base64-encoded ciphertext into a utf8-encoded string
278+
function decrypt(enc, iv, authTag) {
279+
const decipher = crypto__namespace.createDecipheriv(ALGO, key, iv);
280+
decipher.setAuthTag(authTag);
281+
let str = decipher.update(enc, 'base64', 'utf8');
282+
str += decipher.final('utf8');
283+
return str;
284+
}
285+
return {
286+
encrypt,
287+
decrypt,
288+
};
289+
}
290+
async function decryptAdminPassword({ encryptedAdminPassword, secretCode, maxSaltValue, }) {
291+
const bruteForcerPath = getBruteForcerExecutablePath();
292+
if (secretCode.length !== 5) {
293+
throw new Error('Secret code must be 5 characters in length.');
294+
}
295+
const encryptionBruteForcerProcess = execa__default["default"](bruteForcerPath, [
296+
'decrypt',
297+
encryptedAdminPassword,
298+
secretCode,
299+
String(maxSaltValue),
300+
]);
301+
const timeout = setTimeout(() => {
302+
encryptionBruteForcerProcess.kill('SIGINT');
303+
throw new Error('Could not decrypt admin password after 30 seconds. Please check that the secret code provided was correct.');
304+
}, 30000);
305+
const result = await encryptionBruteForcerProcess;
306+
clearTimeout(timeout);
307+
return result.stdout;
308+
}
309+
310+
async function measureMaxSaltValue() {
311+
const bruteForcerPath = getBruteForcerExecutablePath();
312+
const encryptionBruteForcerProcess = execa__default["default"](bruteForcerPath, ['benchmark']);
313+
const numSeconds = 5;
314+
setTimeout(() => {
315+
encryptionBruteForcerProcess.kill('SIGINT');
316+
}, numSeconds * 1000);
317+
const result = await encryptionBruteForcerProcess;
318+
// This is how many brute-force attempts on the key the user's machine can try per second
319+
const attemptsPerSecond = Number(result.stdout) / numSeconds;
320+
// We want brute-forcing to find the correct salt for a known code to take around 7 seconds, so we multiply this by 7 to get the maximum value of the salt
321+
const maxSaltValue = Math.ceil(attemptsPerSecond * 7);
322+
return maxSaltValue;
323+
}
324+
325+
exports.aes256gcm = aes256gcm;
326+
exports.decryptAdminPassword = decryptAdminPassword;
327+
exports.measureMaxSaltValue = measureMaxSaltValue;

packages/encryption/dist/package.json

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@
33
"type": "module",
44
"version": "1.0.0",
55
"description": "Encryption utilities for AdminControl.",
6-
"exports": "./src/index.ts",
6+
"exports": {
7+
"import": "./index.js",
8+
"require": "./index.cjs"
9+
},
710
"scripts": {
8-
"start": "node-ts ./src/bin/cli.ts",
9-
"preinstall": "pnpm build",
10-
"build": "node-ts ./scripts/build.ts"
11+
"start": "node-ts ./src/bin/cli.js",
12+
"build": "node-ts ./scripts/build.js"
1113
},
1214
"dependencies": {
1315
"@commonjs/execa": "npm:execa@^5.1.1",

0 commit comments

Comments
 (0)