Skip to content

Commit 87d407b

Browse files
authored
docs: bindings (#60)
* add docs for typescript bindings * fix type errors
1 parent 7c33c71 commit 87d407b

14 files changed

Lines changed: 1493 additions & 266 deletions

File tree

mfkdf2-web/src/api.ts

Lines changed: 1384 additions & 238 deletions
Large diffs are not rendered by default.

mfkdf2-web/src/utils.ts

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
2+
// Helper to convert Buffer/Uint8Array to ArrayBuffer for UniFFI
3+
function toArrayBuffer(input: ArrayBuffer | Buffer | Uint8Array | undefined): ArrayBuffer | undefined {
4+
if (input === undefined) return undefined;
5+
if (input instanceof ArrayBuffer) return input;
6+
// Buffer and Uint8Array have .buffer property, but may be a view with offset
7+
const view = input as Uint8Array;
8+
return view.buffer.slice(view.byteOffset, view.byteOffset + view.byteLength) as ArrayBuffer;
9+
}
10+
11+
// Helper to deep parse JSON strings
12+
function deepParse(value: any): any {
13+
if (typeof value === 'string') {
14+
try {
15+
return deepParse(JSON.parse(value));
16+
} catch {
17+
return value;
18+
}
19+
}
20+
21+
if (Array.isArray(value)) {
22+
return value.map(deepParse);
23+
}
24+
25+
if (value && typeof value === 'object') {
26+
const parsed: any = {};
27+
for (const [key, nested] of Object.entries(value)) {
28+
parsed[key] = deepParse(nested);
29+
}
30+
return parsed;
31+
}
32+
33+
return value;
34+
}
35+
36+
// Helper to stringify policy/factor params/outputs
37+
function stringifyFactorParams(value: any): any {
38+
if (value === undefined || value === null || typeof value === 'string') {
39+
return value;
40+
}
41+
42+
const POLICY_ORDER = ['$id', '$schema', 'factors', 'key', 'memory', 'salt', 'threshold', 'time'];
43+
const FACTOR_ORDER = ['id', 'pad', 'params', 'salt', 'secret', 'type', 'hint'];
44+
45+
const stringifyPolicy = (input: any): string => JSON.stringify(orderValue(input, 'policy'));
46+
47+
function orderValue(input: any, context?: 'policy' | 'factor'): any {
48+
if (Array.isArray(input)) {
49+
if (context === 'policy') {
50+
return input.map((item) => orderValue(item, 'factor'));
51+
}
52+
return input.map((item) => orderValue(item));
53+
}
54+
55+
if (input && typeof input === 'object') {
56+
const baseOrder = context === 'policy' ? POLICY_ORDER : context === 'factor' ? FACTOR_ORDER : [];
57+
const extras = Object.keys(input).filter((key) => !baseOrder.includes(key)).sort();
58+
const keys = [...baseOrder, ...extras];
59+
const ordered: any = {};
60+
61+
for (const key of keys) {
62+
if (!(key in input)) continue;
63+
64+
if (context === 'factor' && key === 'params') {
65+
ordered.params = input[key];
66+
continue;
67+
}
68+
69+
if (key === 'factors' && Array.isArray(input[key])) {
70+
ordered.factors = input[key].map((item: any) => orderValue(item, 'factor'));
71+
continue;
72+
}
73+
74+
ordered[key] = orderValue(input[key]);
75+
}
76+
77+
return ordered;
78+
}
79+
80+
return input;
81+
}
82+
83+
return stringifyPolicy(value);
84+
}
85+
86+
export {
87+
toArrayBuffer,
88+
deepParse,
89+
stringifyFactorParams,
90+
};

mfkdf2-web/test/features/reconstitution.test.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -358,7 +358,5 @@ suite('features/reconstitution', () => {
358358

359359
await setup.reconstitute([], [], 4).should.be.rejectedWith(Mfkdf2Error.InvalidThreshold)
360360
})
361-
362-
// TODO: type error tests are not added
363361
})
364362
});

mfkdf2-web/test/mfkdf2/hints.test.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -104,10 +104,7 @@ suite('mfkdf2/hints', () => {
104104
integrity: false
105105
}
106106
)
107-
setup.getHint().should.be.rejectedWith(TypeError)
108-
setup.getHint(123).should.be.rejectedWith(TypeError)
109107
setup.getHint('unknown').should.be.rejectedWith(RangeError)
110-
setup.getHint('password1', 'string').should.be.rejectedWith(TypeError)
111108
setup.getHint('password1', 0).should.be.rejectedWith(TypeError)
112109
setup.getHint('password1', 300).should.be.rejectedWith(TypeError)
113110
})

mfkdf2-web/test/mfkdf2/security.test.ts

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,6 @@ suite('mfkdf2/security', () => {
118118
await mfkdf.setup.factors.password('password2', { id: 'password2' })
119119
])
120120

121-
// TODO (@lonerapier): current ts api doesn't return closure
122-
// const materialp1 = await mfkdf.derive.factors.password('password1')(
123-
// setup.policy.factors[0].params
124-
// )
125121
const materialp1 = await mfkdf.derive.factors.password('password1')
126122
const padp1 = Buffer.from(setup.policy.factors[0].pad, 'base64')
127123
const stretchedp1 = Buffer.from(
@@ -159,10 +155,6 @@ suite('mfkdf2/security', () => {
159155
})
160156
derive2.key.toString('hex').should.equal(setup.key.toString('hex'))
161157

162-
// TODO (@lonerapier): current ts api doesn't return closure
163-
// const materialp3 = await mfkdf.derive.factors.password('newPassword1')(
164-
// derive.policy.factors[0].params
165-
// )
166158
const materialp3 = await mfkdf.derive.factors.password('newPassword1')
167159
const padp3 = Buffer.from(derive.policy.factors[0].pad, 'base64')
168160
const stretchedp3 = Buffer.from(

mfkdf2-web/test/setup/factors/hmacsha1.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ suite('setup/factors/hmacsha1', () => {
2323
const factor = await mfkdf.setup.factors.hmacsha1()
2424
factor.type.should.equal('hmacsha1')
2525
factor.data.should.have.length(32) // 20 bytes + 12 bytes of padding
26-
factor.id.should.equal('hmacsha1')
26+
factor.id?.should.equal('hmacsha1')
2727
const params = await factor.params()
2828
params.should.have.property('challenge')
2929
params.should.have.property('pad')
@@ -41,7 +41,7 @@ suite('setup/factors/hmacsha1', () => {
4141

4242
test('valid - with id', async () => {
4343
const factor = await mfkdf.setup.factors.hmacsha1({ id: 'myhmac' })
44-
factor.id.should.equal('myhmac')
44+
factor.id?.should.equal('myhmac')
4545
factor.type.should.equal('hmacsha1')
4646
const output = await factor.output()
4747
output.should.have.property('secret')

mfkdf2-web/test/setup/factors/hotp.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ suite('setup/factors/hotp', () => {
5454
issuer: 'TestCorp',
5555
label: 'test@example.com'
5656
})
57-
factor.id.should.equal('myhotp')
57+
factor.id?.should.equal('myhotp')
5858
factor.type.should.equal('hotp')
5959
const output = await factor.output()
6060
output.should.have.property('issuer', 'TestCorp')

mfkdf2-web/test/setup/factors/ooba.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ suite('setup/factors/ooba', () => {
5050
test('valid - with defaults', async () => {
5151
const factor = await mfkdf.setup.factors.ooba({ key: keyPair.publicKey })
5252
factor.type.should.equal('ooba')
53-
factor.id.should.equal('ooba')
53+
factor.id?.should.equal('ooba')
5454
factor.data.should.have.length(32)
5555
const params = await factor.params()
5656
params.should.have.property('length', 6)
@@ -75,7 +75,7 @@ suite('setup/factors/ooba', () => {
7575
length: 8,
7676
params: customParams
7777
})
78-
factor.id.should.equal('myooba')
78+
factor.id?.should.equal('myooba')
7979
factor.type.should.equal('ooba')
8080
})
8181
})

mfkdf2-web/test/setup/factors/passkey.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,15 @@ suite('setup/factors/passkey', () => {
3434
}
3535
const factor = await mfkdf.setup.factors.passkey(secret.buffer)
3636
factor.type.should.equal('passkey')
37-
factor.id.should.equal('passkey')
37+
factor.id?.should.equal('passkey')
3838
factor.data.should.have.length(32)
39-
factor.entropy.should.equal(256)
39+
factor.entropy?.should.equal(256)
4040
})
4141

4242
test('valid - with id', async () => {
4343
const secret = new Uint8Array(32)
4444
const factor = await mfkdf.setup.factors.passkey(secret.buffer, { id: 'mykey' })
45-
factor.id.should.equal('mykey')
45+
factor.id?.should.equal('mykey')
4646
factor.type.should.equal('passkey')
4747
const params = await factor.params()
4848
params.should.deep.equal({})

mfkdf2-web/test/setup/factors/password.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ suite('setup/factors/password - with key parameter', () => {
6969
const params = await factor.params(customKey.buffer);
7070
params.should.deep.equal({});
7171

72-
const output = await factor.output(customKey.buffer);
72+
const output = await factor.output();
7373
output.should.have.property('strength');
7474
});
7575

@@ -83,7 +83,7 @@ suite('setup/factors/password - with key parameter', () => {
8383
paramsNoKey.should.deep.equal(paramsWithKey);
8484

8585
const outputNoKey = await factor.output();
86-
const outputWithKey = await factor.output(new Uint8Array(32).buffer);
86+
const outputWithKey = await factor.output();
8787

8888
// Both should have strength property (value might differ slightly but structure same)
8989
outputNoKey.should.have.property('strength');

0 commit comments

Comments
 (0)