Skip to content

Commit ab8b0ad

Browse files
committed
feat: ESM migration
1 parent ddbf11e commit ab8b0ad

22 files changed

+4779
-3404
lines changed

.github/workflows/tag.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: "CI / Tag"
1+
npname: "CI / Tag"
22

33
on:
44
push:

package-lock.json

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

package.json

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
"dependencies": {
6262
"@matrixai/async-init": "^2.1.2",
6363
"@matrixai/async-locks": "^5.0.2",
64-
"@matrixai/db": "^5.3.0",
64+
"@matrixai/db": "^6.0.20",
6565
"@matrixai/errors": "^2.1.3",
6666
"@matrixai/logger": "^4.0.3",
6767
"@matrixai/resources": "^2.0.1",
@@ -75,30 +75,30 @@
7575
},
7676
"devDependencies": {
7777
"@fast-check/jest": "^2.1.0",
78-
"@swc/core": "^1.3.62",
79-
"@swc/jest": "^0.2.26",
80-
"@types/jest": "^28.1.3",
81-
"@types/node": "^18.15.0",
78+
"@swc/core": "1.3.82",
79+
"@swc/jest": "^0.2.29",
80+
"@types/jest": "^29.5.2",
81+
"@types/node": "^20.5.7",
8282
"@types/node-forge": "^1.0.2",
8383
"@types/readable-stream": "^2.3.11",
84-
"@typescript-eslint/eslint-plugin": "^5.45.1",
85-
"@typescript-eslint/parser": "^5.45.1",
84+
"@typescript-eslint/eslint-plugin": "^5.61.0",
85+
"@typescript-eslint/parser": "^5.61.0",
8686
"benny": "^3.7.1",
8787
"common-tags": "^1.8.2",
88-
"eslint": "^8.15.0",
89-
"eslint-config-prettier": "^8.5.0",
90-
"eslint-plugin-import": "^2.26.0",
91-
"eslint-plugin-prettier": "^4.0.0",
88+
"eslint": "^8.44.0",
89+
"eslint-config-prettier": "^8.8.0",
90+
"eslint-plugin-import": "^2.27.5",
91+
"eslint-plugin-prettier": "^5.0.0-alpha.2",
9292
"fast-check": "^4.0.0",
93-
"jest": "^28.1.1",
94-
"jest-extended": "^3.0.1",
95-
"jest-junit": "^14.0.0",
96-
"prettier": "^2.6.2",
93+
"jest": "^29.6.2",
94+
"jest-extended": "^4.0.0",
95+
"jest-junit": "^16.0.0",
96+
"prettier": "^3.0.0",
9797
"shx": "^0.3.4",
9898
"systeminformation": "^5.18.5",
9999
"ts-node": "^10.9.1",
100100
"tsx": "^3.12.7",
101-
"typedoc": "^0.23.21",
102-
"typescript": "^4.9.3"
101+
"typedoc": "^0.24.8",
102+
"typescript": "^5.1.6"
103103
}
104104
}

src/EncryptedFS.ts

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
import type { Crypto, DBTransaction } from '@matrixai/db';
1+
import type {
2+
Crypto,
3+
DBTransaction,
4+
DBWorkerManagerInterface,
5+
} from '@matrixai/db';
26
import type {
37
Navigated,
48
ParsedPath,
@@ -7,7 +11,6 @@ import type {
711
Options,
812
Data,
913
File,
10-
EFSWorkerManagerInterface,
1114
} from './types.js';
1215
import type { INodeIndex, INodeType } from './inodes/types.js';
1316
import type { FdIndex, FileDescriptor } from './fd/index.js';
@@ -26,6 +29,7 @@ import * as constants from './constants.js';
2629
import * as permissions from './permissions.js';
2730
import * as utils from './utils.js';
2831
import * as errors from './errors.js';
32+
import efsWorker from './efsWorker.js';
2933

3034
interface EncryptedFS extends createDestroyStartStop.CreateDestroyStartStop {}
3135
@createDestroyStartStop.CreateDestroyStartStop(
@@ -100,10 +104,7 @@ class EncryptedFS {
100104
if (db == null) {
101105
crypto = {
102106
key: dbKey!,
103-
ops: {
104-
encrypt: utils.encrypt,
105-
decrypt: utils.decrypt,
106-
},
107+
ops: efsWorker,
107108
};
108109
try {
109110
db = await DB.createDB({
@@ -309,7 +310,7 @@ class EncryptedFS {
309310
this.logger.info(`Destroyed ${this.constructor.name}`);
310311
}
311312

312-
public setWorkerManager(workerManager: EFSWorkerManagerInterface) {
313+
public setWorkerManager(workerManager: DBWorkerManagerInterface) {
313314
this.db.setWorkerManager(workerManager);
314315
}
315316

@@ -2282,10 +2283,10 @@ class EncryptedFS {
22822283
typeof offsetOrCallback === 'function'
22832284
? offsetOrCallback
22842285
: typeof lengthOrCallback === 'function'
2285-
? lengthOrCallback
2286-
: typeof positionOrCallback === 'function'
2287-
? positionOrCallback
2288-
: callback;
2286+
? lengthOrCallback
2287+
: typeof positionOrCallback === 'function'
2288+
? positionOrCallback
2289+
: callback;
22892290
return utils.maybeCallback(async () => {
22902291
const fd = this.fdMgr.getFd(fdIndex);
22912292
if (!fd) {
@@ -2413,8 +2414,12 @@ class EncryptedFS {
24132414
.filter(([name]) => name !== '.' && name !== '..')
24142415
.map(([name]) => {
24152416
if (options.encoding === 'binary') {
2417+
if (typeof name === 'string') return Buffer.from(name);
24162418
return Buffer.from(name);
24172419
} else {
2420+
if (typeof name === 'string') {
2421+
return Buffer.from(name).toString(options.encoding);
2422+
}
24182423
return Buffer.from(name).toString(options.encoding);
24192424
}
24202425
});
@@ -3304,10 +3309,10 @@ class EncryptedFS {
33043309
typeof offsetOrPosOrCallback === 'function'
33053310
? offsetOrPosOrCallback
33063311
: typeof lengthOrEncodingOrCallback === 'function'
3307-
? lengthOrEncodingOrCallback
3308-
: typeof positionOrCallback === 'function'
3309-
? positionOrCallback
3310-
: callback;
3312+
? lengthOrEncodingOrCallback
3313+
: typeof positionOrCallback === 'function'
3314+
? positionOrCallback
3315+
: callback;
33113316
return utils.maybeCallback(async () => {
33123317
const fd = this.fdMgr.getFd(fdIndex);
33133318
if (!fd) {

src/efsWorker.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import type { WorkerManifest } from '@matrixai/workers';
2+
import type { Crypto } from '@matrixai/db';
3+
import { expose } from '@matrixai/workers';
4+
import * as utils from './utils.js';
5+
6+
const efsWorker: Crypto = {
7+
async encrypt({
8+
key,
9+
plainText,
10+
}: {
11+
key: ArrayBuffer;
12+
plainText: ArrayBuffer;
13+
}): Promise<{ data: ArrayBuffer; transferList: [ArrayBuffer] }> {
14+
const cipherText = await utils.encrypt(key, plainText);
15+
return { data: cipherText, transferList: [cipherText] };
16+
},
17+
async decrypt({
18+
key,
19+
cipherText,
20+
}: {
21+
key: ArrayBuffer;
22+
cipherText: ArrayBuffer;
23+
}): Promise<
24+
| { data: ArrayBuffer; transferList: [ArrayBuffer] }
25+
| { data: undefined; transferList: [] }
26+
> {
27+
const plainText = await utils.decrypt(key, cipherText);
28+
if (plainText != null) {
29+
return { data: plainText, transferList: [plainText] };
30+
} else {
31+
return { data: undefined, transferList: [] };
32+
}
33+
},
34+
} satisfies WorkerManifest;
35+
36+
expose(efsWorker);
37+
38+
type EFSWorker = typeof efsWorker;
39+
40+
export type { EFSWorker };
41+
42+
export default efsWorker;

src/fd/FileDescriptorManager.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ class FileDescriptorManager {
1818
* Make sure not get real fd numbers confused with these fd numbers.
1919
*/
2020
constructor(iNodeMgr: INodeManager) {
21-
this._counter = new Counter(0);
21+
// Using Counter.default since Counter isn't exported properly for ESM
22+
this._counter = new Counter.default(0);
2223
this._fds = new Map();
2324
this._iNodeMgr = iNodeMgr;
2425
}

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
export { default as EncryptedFS } from './EncryptedFS.js';
22
export { default as Stat } from './Stat.js';
33
export * as errors from './errors.js';
4-
export * as workers from './workers/index.js';
4+
export * from './efsWorker.js';
55
export * as inodes from './inodes/index.js';
66
export * as constants from './constants.js';
77
export * as permissions from './permissions.js';

src/inodes/INodeManager.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,8 @@ class INodeManager {
6161

6262
protected logger: Logger;
6363
protected db: DB;
64-
protected iNodeCounter: Counter = new Counter(1);
64+
// Using Counter.default since Counter isn't exported properly for ESM
65+
protected iNodeCounter: Counter = new Counter.default(1);
6566
protected iNodeAllocations: Map<string, Ref<INodeIndex>> = new Map();
6667
protected refs: Map<INodeIndex, number> = new Map();
6768

@@ -96,7 +97,8 @@ class INodeManager {
9697
// Clean up all dangling inodes that could not be removed due to references
9798
await this.gcAll();
9899
// Reset the inode counter, it will be repopulated on start
99-
this.iNodeCounter = new Counter(1);
100+
// Using Counter.default since Counter isn't exported properly for ESM
101+
this.iNodeCounter = new Counter.default(1);
100102
// Reset the references
101103
this.refs.clear();
102104
this.logger.info(`Stopped ${this.constructor.name}`);

src/types.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
import type { WorkerManagerInterface } from '@matrixai/workers';
21
import type { INodeIndex } from './inodes/types.js';
32
import type { FdIndex } from './fd/types.js';
4-
import type { EFSWorkerModule } from './workers/efsWorkerModule';
53

64
/**
75
* Plain data dictionary
@@ -87,8 +85,6 @@ type Data = string | Buffer | Uint8Array;
8785

8886
type File = FdIndex | Path;
8987

90-
type EFSWorkerManagerInterface = WorkerManagerInterface<EFSWorkerModule>;
91-
9288
export type {
9389
POJO,
9490
Opaque,
@@ -104,6 +100,4 @@ export type {
104100
Options,
105101
Data,
106102
File,
107-
EFSWorkerManagerInterface,
108-
EFSWorkerModule,
109103
};

src/utils.ts

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { Callback } from './types.js';
22
import type Stat from './Stat.js';
33
import pathNode from 'path';
4-
import { md, random, pkcs5, cipher, util as forgeUtil } from 'node-forge';
4+
import nodeForge from 'node-forge';
55
import callbackify from 'util-callbackify';
66
import * as constants from './constants.js';
77

@@ -31,7 +31,7 @@ function fromArrayBuffer(
3131

3232
async function getRandomBytes(size: number): Promise<Buffer> {
3333
const p = new Promise<string>((resolve, reject) => {
34-
random.getBytes(size, (e, bytes) => {
34+
nodeForge.random.getBytes(size, (e, bytes) => {
3535
if (e != null) {
3636
reject(e);
3737
} else {
@@ -43,7 +43,7 @@ async function getRandomBytes(size: number): Promise<Buffer> {
4343
}
4444

4545
function getRandomBytesSync(size: number): Buffer {
46-
return Buffer.from(random.getBytesSync(size), 'binary');
46+
return Buffer.from(nodeForge.random.getBytesSync(size), 'binary');
4747
}
4848

4949
async function generateKey(bits: 128 | 192 | 256 = 256): Promise<Buffer> {
@@ -76,12 +76,12 @@ async function generateKeyFromPass(
7676
salt = (await getRandomBytes(16)).toString('binary');
7777
}
7878
const keyLen = Math.floor(bits / 8);
79-
const key = await promisify<string>(pkcs5.pbkdf2)(
79+
const key = await promisify<string>(nodeForge.pkcs5.pbkdf2)(
8080
password,
8181
salt,
8282
2048,
8383
keyLen,
84-
md.sha512.create(),
84+
nodeForge.md.sha512.create(),
8585
);
8686
return [Buffer.from(key, 'binary'), Buffer.from(salt, 'binary')];
8787
}
@@ -98,7 +98,13 @@ function generateKeyFromPassSync(
9898
salt = getRandomBytesSync(16).toString('binary');
9999
}
100100
const keyLen = Math.floor(bits / 8);
101-
const key = pkcs5.pbkdf2(password, salt, 2048, keyLen, md.sha512.create());
101+
const key = nodeForge.pkcs5.pbkdf2(
102+
password,
103+
salt,
104+
2048,
105+
keyLen,
106+
nodeForge.md.sha512.create(),
107+
);
102108
return [Buffer.from(key, 'binary'), Buffer.from(salt, 'binary')];
103109
}
104110

@@ -107,9 +113,12 @@ async function encrypt(
107113
plainText: ArrayBuffer,
108114
): Promise<ArrayBuffer> {
109115
const iv = getRandomBytesSync(ivSize);
110-
const c = cipher.createCipher('AES-GCM', Buffer.from(key).toString('binary'));
116+
const c = nodeForge.cipher.createCipher(
117+
'AES-GCM',
118+
Buffer.from(key).toString('binary'),
119+
);
111120
c.start({ iv: iv.toString('binary'), tagLength: authTagSize * 8 });
112-
c.update(forgeUtil.createBuffer(plainText));
121+
c.update(nodeForge.util.createBuffer(plainText));
113122
c.finish();
114123
const cipherText = Buffer.from(c.output.getBytes(), 'binary');
115124
const authTag = Buffer.from(c.mode.tag.getBytes(), 'binary');
@@ -128,16 +137,16 @@ async function decrypt(
128137
const iv = cipherTextBuf.subarray(0, ivSize);
129138
const authTag = cipherTextBuf.subarray(ivSize, ivSize + authTagSize);
130139
const cipherText_ = cipherTextBuf.subarray(ivSize + authTagSize);
131-
const d = cipher.createDecipher(
140+
const d = nodeForge.cipher.createDecipher(
132141
'AES-GCM',
133142
Buffer.from(key).toString('binary'),
134143
);
135144
d.start({
136145
iv: iv.toString('binary'),
137146
tagLength: authTagSize * 8,
138-
tag: forgeUtil.createBuffer(authTag),
147+
tag: nodeForge.util.createBuffer(authTag),
139148
});
140-
d.update(forgeUtil.createBuffer(cipherText_));
149+
d.update(nodeForge.util.createBuffer(cipherText_));
141150
if (!d.finish()) {
142151
return;
143152
}

0 commit comments

Comments
 (0)