@owlmeans/basic-keys 0.1.18-rc.46 → 0.1.18-rc.48
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -12
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/basic-keys/SKILL.md +13 -13
- package/build/auth/types.d.ts +10 -0
- package/build/auth/types.d.ts.map +1 -0
- package/build/auth/types.js +2 -0
- package/build/auth/types.js.map +1 -0
- package/build/auth.d.ts +3 -4
- package/build/auth.d.ts.map +1 -1
- package/build/auth.js +43 -39
- package/build/auth.js.map +1 -1
- package/build/helper/types.d.ts +11 -0
- package/build/helper/types.d.ts.map +1 -0
- package/build/helper/types.js +2 -0
- package/build/helper/types.js.map +1 -0
- package/build/helper.d.ts +4 -1
- package/build/helper.d.ts.map +1 -1
- package/build/helper.js +21 -15
- package/build/helper.js.map +1 -1
- package/build/index.d.ts +2 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js.map +1 -1
- package/build/keypair.js +2 -2
- package/build/keypair.js.map +1 -1
- package/build/model.d.ts +2 -2
- package/build/model.d.ts.map +1 -1
- package/build/model.js +16 -16
- package/build/model.js.map +1 -1
- package/build/plugins/ed25519.js +3 -3
- package/build/plugins/ed25519.js.map +1 -1
- package/build/plugins/xchacha.js +2 -2
- package/build/plugins/xchacha.js.map +1 -1
- package/build/utils/types.d.ts +16 -0
- package/build/utils/types.d.ts.map +1 -0
- package/build/utils/types.js +2 -0
- package/build/utils/types.js.map +1 -0
- package/build/utils.d.ts +3 -4
- package/build/utils.d.ts.map +1 -1
- package/build/utils.js +26 -22
- package/build/utils.js.map +1 -1
- package/package.json +9 -9
- package/src/auth/types.ts +17 -0
- package/src/auth.ts +51 -44
- package/src/helper/types.ts +11 -0
- package/src/helper.ts +26 -16
- package/src/index.ts +2 -0
- package/src/keypair.ts +2 -2
- package/src/model.ts +17 -17
- package/src/plugins/ed25519.ts +3 -3
- package/src/plugins/xchacha.ts +2 -2
- package/src/utils/types.ts +15 -0
- package/src/utils.ts +28 -21
- package/tests/auth.spec.ts +5 -5
- package/tests/keys.spec.ts +3 -3
- package/tests/known-answers.spec.ts +68 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/utils/types.ts"],"names":[],"mappings":""}
|
package/build/utils.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
export declare const
|
|
3
|
-
export declare const
|
|
4
|
-
export declare const assertType: (type?: string) => void;
|
|
1
|
+
import type { KeyUtils } from './utils/types.js';
|
|
2
|
+
export declare const createKeyUtils: () => KeyUtils;
|
|
3
|
+
export declare const keyUtils: KeyUtils;
|
|
5
4
|
//# sourceMappingURL=utils.d.ts.map
|
package/build/utils.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAEhD,eAAO,MAAM,cAAc,QAAO,QAiCjC,CAAA;AAED,eAAO,MAAM,QAAQ,UAAmB,CAAA"}
|
package/build/utils.js
CHANGED
|
@@ -1,29 +1,33 @@
|
|
|
1
|
-
import { keccak_256 } from '@noble/hashes/sha3';
|
|
1
|
+
import { keccak_256 } from '@noble/hashes/sha3.js';
|
|
2
2
|
import { base64, utf8 } from '@scure/base';
|
|
3
3
|
import { plugins } from './plugins/index.js';
|
|
4
4
|
import canonicalize from 'canonicalize';
|
|
5
|
-
export const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
export const createKeyUtils = () => {
|
|
6
|
+
const toAddress = (publicKey) => keccak_256(publicKey.slice(4)).slice(-20);
|
|
7
|
+
const prepareKey = (key) => base64.decode(key);
|
|
8
|
+
const prepareData = (data) => {
|
|
9
|
+
if (typeof data === 'object') {
|
|
10
|
+
if (!(data instanceof Uint8Array)) {
|
|
11
|
+
data = canonicalize(data);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
if (typeof data === 'string') {
|
|
15
|
+
data = utf8.decode(data);
|
|
16
|
+
}
|
|
17
|
+
else if (!(data instanceof Uint8Array)) {
|
|
18
|
+
throw new Error('basic.keys:sign-data-type');
|
|
19
|
+
}
|
|
9
20
|
if (!(data instanceof Uint8Array)) {
|
|
10
|
-
|
|
21
|
+
throw new Error('basic.keys:sign-data-type');
|
|
11
22
|
}
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
throw new Error('basic.keys:sign-data-type');
|
|
21
|
-
}
|
|
22
|
-
return data;
|
|
23
|
-
};
|
|
24
|
-
export const assertType = (type) => {
|
|
25
|
-
if (type == null || !(type in plugins)) {
|
|
26
|
-
throw new Error('basic.keys:unknown-type');
|
|
27
|
-
}
|
|
23
|
+
return data;
|
|
24
|
+
};
|
|
25
|
+
const assertType = (type) => {
|
|
26
|
+
if (type == null || !(type in plugins)) {
|
|
27
|
+
throw new Error('basic.keys:unknown-type');
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
return { toAddress, prepareKey, prepareData, assertType };
|
|
28
31
|
};
|
|
32
|
+
export const keyUtils = createKeyUtils();
|
|
29
33
|
//# sourceMappingURL=utils.js.map
|
package/build/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAA;AAClD,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAA;AAC5C,OAAO,YAAY,MAAM,cAAc,CAAA;AAGvC,MAAM,CAAC,MAAM,cAAc,GAAG,GAAa,EAAE;IAC3C,MAAM,SAAS,GAAG,CAAC,SAAqB,EAAc,EAAE,CACtD,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAA;IAE3C,MAAM,UAAU,GAAG,CAAC,GAAW,EAAc,EAAE,CAC7C,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IAEpB,MAAM,WAAW,GAAG,CAAC,IAAa,EAAc,EAAE;QAChD,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,IAAI,CAAC,CAAC,IAAI,YAAY,UAAU,CAAC,EAAE,CAAC;gBAClC,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,CAAA;YAC3B,CAAC;QACH,CAAC;QACD,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA;QAC1B,CAAC;aAAM,IAAI,CAAC,CAAC,IAAI,YAAY,UAAU,CAAC,EAAE,CAAC;YACzC,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAA;QAC9C,CAAC;QAED,IAAI,CAAC,CAAC,IAAI,YAAY,UAAU,CAAC,EAAE,CAAC;YAClC,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAA;QAC9C,CAAC;QAED,OAAO,IAAI,CAAA;IACb,CAAC,CAAA;IAED,MAAM,UAAU,GAAG,CAAC,IAAa,EAAQ,EAAE;QACzC,IAAI,IAAI,IAAI,IAAI,IAAI,CAAC,CAAC,IAAI,IAAI,OAAO,CAAC,EAAE,CAAC;YACvC,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAA;QAC5C,CAAC;IACH,CAAC,CAAA;IAED,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,CAAA;AAC3D,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,cAAc,EAAE,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@owlmeans/basic-keys",
|
|
3
|
-
"version": "0.1.18-rc.
|
|
3
|
+
"version": "0.1.18-rc.48",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"scripts": {
|
|
@@ -40,18 +40,18 @@
|
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@owlmeans/dep-config": "workspace:*",
|
|
43
|
-
"@owlmeans/test-auth": "^0.1.18-rc.
|
|
44
|
-
"@types/bun": "^1.4.
|
|
43
|
+
"@owlmeans/test-auth": "^0.1.18-rc.46",
|
|
44
|
+
"@types/bun": "^1.4.2",
|
|
45
45
|
"nodemon": "^3.1.14",
|
|
46
46
|
"typescript": "^7.0.2"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@noble/ciphers": "^
|
|
50
|
-
"@noble/curves": "^
|
|
51
|
-
"@noble/hashes": "^
|
|
52
|
-
"@owlmeans/auth": "^0.1.18-rc.
|
|
53
|
-
"@scure/base": "^2.
|
|
54
|
-
"canonicalize": "^
|
|
49
|
+
"@noble/ciphers": "^2.4.0",
|
|
50
|
+
"@noble/curves": "^2.4.0",
|
|
51
|
+
"@noble/hashes": "^2.4.0",
|
|
52
|
+
"@owlmeans/auth": "^0.1.18-rc.40",
|
|
53
|
+
"@scure/base": "^2.4.0",
|
|
54
|
+
"canonicalize": "^5.1.0"
|
|
55
55
|
},
|
|
56
56
|
"publishConfig": {
|
|
57
57
|
"access": "public"
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AuthCredentials } from '@owlmeans/auth'
|
|
2
|
+
import type { KeyPairModel, PayloadSigner, PayloadVerifier, UnpackedAuthCredentials, UnsignedAuthCredentials } from '../types.js'
|
|
3
|
+
|
|
4
|
+
/** Signed authentication credentials: the signature packed into `credential` with any extras. */
|
|
5
|
+
export interface AuthCredentialsHelper {
|
|
6
|
+
/** Sign `auth` (plus canonicalized `extra`) and pack the signature into `credential`. */
|
|
7
|
+
packAuthCredentials: <T extends {} | undefined>(
|
|
8
|
+
auth: UnsignedAuthCredentials,
|
|
9
|
+
extra: T,
|
|
10
|
+
signer: KeyPairModel | PayloadSigner
|
|
11
|
+
) => Promise<AuthCredentials>
|
|
12
|
+
/** Take packed credentials apart and, given a verifier, check the signature. */
|
|
13
|
+
unpackAuthCredentials: <T extends {} | undefined>(
|
|
14
|
+
auth: AuthCredentials,
|
|
15
|
+
verifier?: KeyPairModel | PayloadVerifier
|
|
16
|
+
) => Promise<UnpackedAuthCredentials<T>>
|
|
17
|
+
}
|
package/src/auth.ts
CHANGED
|
@@ -1,60 +1,67 @@
|
|
|
1
1
|
import type { AuthCredentials } from '@owlmeans/auth'
|
|
2
2
|
import type { KeyPairModel, PayloadSigner, PayloadVerifier, UnpackedAuthCredentials, UnsignedAuthCredentials } from './types.js'
|
|
3
3
|
import canonicalize from 'canonicalize'
|
|
4
|
+
import type { AuthCredentialsHelper } from './auth/types.js'
|
|
4
5
|
|
|
5
|
-
export const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
6
|
+
export const createAuthCredentialsHelper = (): AuthCredentialsHelper => {
|
|
7
|
+
const packAuthCredentials = async <T extends {} | undefined>(
|
|
8
|
+
auth: UnsignedAuthCredentials,
|
|
9
|
+
extra: T,
|
|
10
|
+
signer: KeyPairModel | PayloadSigner
|
|
11
|
+
): Promise<AuthCredentials> => {
|
|
12
|
+
const unsigned: UnsignedAuthCredentials = {
|
|
13
|
+
...auth,
|
|
14
|
+
...(extra == null ? {} : { credential: canonicalize(extra) as string })
|
|
15
|
+
}
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
if (typeof signer !== 'function') {
|
|
18
|
+
const _signer = signer
|
|
19
|
+
signer = async payload => await _signer.sign(payload)
|
|
20
|
+
}
|
|
19
21
|
|
|
20
|
-
|
|
22
|
+
const signature = await signer(unsigned)
|
|
21
23
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
return {
|
|
25
|
+
...auth,
|
|
26
|
+
credential: extra == null ? signature : canonicalize({ ...extra, signature }) as string,
|
|
27
|
+
}
|
|
25
28
|
}
|
|
26
|
-
}
|
|
27
29
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
): Promise<UnpackedAuthCredentials<T>> => {
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
30
|
+
const unpackAuthCredentials = async <T extends {} | undefined>(
|
|
31
|
+
auth: AuthCredentials,
|
|
32
|
+
verifier?: KeyPairModel | PayloadVerifier
|
|
33
|
+
): Promise<UnpackedAuthCredentials<T>> => {
|
|
34
|
+
let signature: string = ''
|
|
35
|
+
let extras: T
|
|
36
|
+
try {
|
|
37
|
+
extras = JSON.parse(auth.credential)
|
|
38
|
+
if (typeof extras === 'object' && extras != null && "signature" in extras) {
|
|
39
|
+
signature = extras.signature as string
|
|
40
|
+
delete extras.signature
|
|
41
|
+
}
|
|
42
|
+
} catch {
|
|
43
|
+
signature = auth.credential
|
|
44
|
+
extras = undefined as T
|
|
39
45
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
...auth,
|
|
46
|
-
...(extras == null ? {} : { credential: canonicalize(extras) as string })
|
|
47
|
-
}
|
|
48
|
-
let isValid: boolean | undefined = undefined
|
|
46
|
+
const unsigned: UnsignedAuthCredentials = {
|
|
47
|
+
...auth,
|
|
48
|
+
...(extras == null ? {} : { credential: canonicalize(extras) as string })
|
|
49
|
+
}
|
|
50
|
+
let isValid: boolean | undefined = undefined
|
|
49
51
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
if (verifier != null) {
|
|
53
|
+
if (typeof verifier !== 'function') {
|
|
54
|
+
const _verifier = verifier
|
|
55
|
+
verifier = async (payload, signature) => await _verifier.verify(payload, signature)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
isValid = await verifier(unsigned, signature)
|
|
54
59
|
}
|
|
55
60
|
|
|
56
|
-
|
|
61
|
+
return { unsigned, signature, isValid, extras }
|
|
57
62
|
}
|
|
58
63
|
|
|
59
|
-
return {
|
|
64
|
+
return { packAuthCredentials, unpackAuthCredentials }
|
|
60
65
|
}
|
|
66
|
+
|
|
67
|
+
export const authCredentialsHelper = createAuthCredentialsHelper()
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { KeyPairModel } from '../types.js'
|
|
2
|
+
|
|
3
|
+
/** Key models built from what a peer publishes: its public key and its address. */
|
|
4
|
+
export interface KeyHelper {
|
|
5
|
+
/**
|
|
6
|
+
* A verify-only key model of a public key, `<type>:<key>` or a bare key (ed25519 by default).
|
|
7
|
+
*/
|
|
8
|
+
fromPubKey: (pubKey: string, type?: string) => KeyPairModel
|
|
9
|
+
/** Whether an address is the one the public key derives to. */
|
|
10
|
+
matchAddress: (address: string, pubKey: string) => boolean
|
|
11
|
+
}
|
package/src/helper.ts
CHANGED
|
@@ -2,26 +2,36 @@ import { KeyType } from './consts.js'
|
|
|
2
2
|
import { makeKeyPairModel } from './model.js'
|
|
3
3
|
import { plugins } from './plugins/index.js'
|
|
4
4
|
import type { KeyPair, KeyPairModel } from './types.js'
|
|
5
|
-
import {
|
|
5
|
+
import { keyUtils } from './utils.js'
|
|
6
|
+
import type { KeyHelper } from './helper/types.js'
|
|
6
7
|
|
|
7
|
-
export const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
pubKey
|
|
12
|
-
|
|
8
|
+
export const createKeyHelper = (): KeyHelper => {
|
|
9
|
+
const fromPubKey = (pubKey: string, type?: string): KeyPairModel => {
|
|
10
|
+
if (type == null) {
|
|
11
|
+
[type, pubKey] = pubKey.includes(':') ? pubKey.split(':', 2) : [KeyType.ED25519, pubKey]
|
|
12
|
+
if (pubKey == null) {
|
|
13
|
+
pubKey = type
|
|
14
|
+
type = KeyType.ED25519
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const keyPair: KeyPair = {
|
|
19
|
+
privateKey: '',
|
|
20
|
+
publicKey: pubKey,
|
|
21
|
+
type,
|
|
22
|
+
address: plugins[type].toAdress(keyUtils.prepareKey(pubKey))
|
|
13
23
|
}
|
|
14
|
-
}
|
|
15
24
|
|
|
16
|
-
|
|
17
|
-
privateKey: '',
|
|
18
|
-
publicKey: pubKey,
|
|
19
|
-
type,
|
|
20
|
-
address: plugins[type].toAdress(prepareKey(pubKey))
|
|
25
|
+
return makeKeyPairModel(keyPair)
|
|
21
26
|
}
|
|
22
27
|
|
|
23
|
-
|
|
28
|
+
const matchAddress = (address: string, pubKey: string): boolean =>
|
|
29
|
+
address === fromPubKey(pubKey).exportAddress()
|
|
30
|
+
|
|
31
|
+
return { fromPubKey, matchAddress }
|
|
24
32
|
}
|
|
25
33
|
|
|
26
|
-
export const
|
|
27
|
-
|
|
34
|
+
export const keyHelper = createKeyHelper()
|
|
35
|
+
|
|
36
|
+
/** @deprecated compat:factory-refactor — use `keyHelper.fromPubKey(…)` */
|
|
37
|
+
export const fromPubKey = (pubKey: string, type?: string): KeyPairModel => keyHelper.fromPubKey(pubKey, type)
|
package/src/index.ts
CHANGED
package/src/keypair.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { KeyPair } from './types.js'
|
|
|
2
2
|
import { base64 } from '@scure/base'
|
|
3
3
|
import { KeyType } from './consts.js'
|
|
4
4
|
import { plugins } from './plugins/index.js'
|
|
5
|
-
import {
|
|
5
|
+
import { keyUtils } from './utils.js'
|
|
6
6
|
|
|
7
7
|
export const inputToKeyPair = (input?: KeyPair | string): KeyPair => {
|
|
8
8
|
let type: string = KeyType.ED25519
|
|
@@ -27,7 +27,7 @@ export const inputToKeyPair = (input?: KeyPair | string): KeyPair => {
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
if (keyPair == null) {
|
|
30
|
-
assertType(type)
|
|
30
|
+
keyUtils.assertType(type)
|
|
31
31
|
if (primaryKey == null) {
|
|
32
32
|
primaryKey = plugins[type].random()
|
|
33
33
|
}
|
package/src/model.ts
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { KeyPair, KeyPairModel } from './types.js'
|
|
2
2
|
import { plugins } from './plugins/index.js'
|
|
3
3
|
import { base64urlnopad, utf8 } from '@scure/base'
|
|
4
|
-
import {
|
|
4
|
+
import { keyUtils } from './utils.js'
|
|
5
5
|
import { inputToKeyPair } from './keypair.js'
|
|
6
6
|
|
|
7
|
-
export const makeKeyPairModel
|
|
7
|
+
export const makeKeyPairModel = (input?: KeyPair | string): KeyPairModel => {
|
|
8
8
|
const keyPair = inputToKeyPair(input)
|
|
9
9
|
|
|
10
10
|
const _model: KeyPairModel = {
|
|
11
11
|
keyPair,
|
|
12
12
|
|
|
13
13
|
sign: async (data) => {
|
|
14
|
-
data = prepareData(data)
|
|
15
|
-
assertType(_model.keyPair?.type)
|
|
14
|
+
data = keyUtils.prepareData(data)
|
|
15
|
+
keyUtils.assertType(_model.keyPair?.type)
|
|
16
16
|
|
|
17
17
|
if (_model.keyPair == null) {
|
|
18
18
|
throw new Error('basic.keys:missing-keypair')
|
|
@@ -25,14 +25,14 @@ export const makeKeyPairModel: KeyPairModelMaker = input => {
|
|
|
25
25
|
return base64urlnopad.encode(
|
|
26
26
|
plugins[_model.keyPair.type].sign(
|
|
27
27
|
data as Uint8Array,
|
|
28
|
-
prepareKey(_model.keyPair.privateKey)
|
|
28
|
+
keyUtils.prepareKey(_model.keyPair.privateKey)
|
|
29
29
|
)
|
|
30
30
|
)
|
|
31
31
|
},
|
|
32
32
|
|
|
33
33
|
verify: async (data, signature) => {
|
|
34
|
-
data = prepareData(data)
|
|
35
|
-
assertType(_model.keyPair?.type)
|
|
34
|
+
data = keyUtils.prepareData(data)
|
|
35
|
+
keyUtils.assertType(_model.keyPair?.type)
|
|
36
36
|
const sig = base64urlnopad.decode(signature)
|
|
37
37
|
|
|
38
38
|
if (_model.keyPair == null) {
|
|
@@ -42,12 +42,12 @@ export const makeKeyPairModel: KeyPairModelMaker = input => {
|
|
|
42
42
|
return plugins[_model.keyPair.type].verify(
|
|
43
43
|
data as Uint8Array,
|
|
44
44
|
sig,
|
|
45
|
-
prepareKey(_model.keyPair.publicKey)
|
|
45
|
+
keyUtils.prepareKey(_model.keyPair.publicKey)
|
|
46
46
|
)
|
|
47
47
|
},
|
|
48
48
|
|
|
49
49
|
export: () => {
|
|
50
|
-
assertType(_model.keyPair?.type)
|
|
50
|
+
keyUtils.assertType(_model.keyPair?.type)
|
|
51
51
|
|
|
52
52
|
if (_model.keyPair == null) {
|
|
53
53
|
throw new Error('basic.keys:missing-keypair')
|
|
@@ -57,7 +57,7 @@ export const makeKeyPairModel: KeyPairModelMaker = input => {
|
|
|
57
57
|
},
|
|
58
58
|
|
|
59
59
|
exportPublic: () => {
|
|
60
|
-
assertType(_model.keyPair?.type)
|
|
60
|
+
keyUtils.assertType(_model.keyPair?.type)
|
|
61
61
|
|
|
62
62
|
if (_model.keyPair == null) {
|
|
63
63
|
throw new Error('basic.keys:missing-keypair')
|
|
@@ -67,7 +67,7 @@ export const makeKeyPairModel: KeyPairModelMaker = input => {
|
|
|
67
67
|
},
|
|
68
68
|
|
|
69
69
|
exportAddress: () => {
|
|
70
|
-
assertType(_model.keyPair?.type)
|
|
70
|
+
keyUtils.assertType(_model.keyPair?.type)
|
|
71
71
|
|
|
72
72
|
if (_model.keyPair == null) {
|
|
73
73
|
throw new Error('basic.keys:missing-keypair')
|
|
@@ -77,8 +77,8 @@ export const makeKeyPairModel: KeyPairModelMaker = input => {
|
|
|
77
77
|
},
|
|
78
78
|
|
|
79
79
|
encrypt: async data => {
|
|
80
|
-
data = prepareData(data)
|
|
81
|
-
assertType(_model.keyPair?.type)
|
|
80
|
+
data = keyUtils.prepareData(data)
|
|
81
|
+
keyUtils.assertType(_model.keyPair?.type)
|
|
82
82
|
|
|
83
83
|
if (_model.keyPair == null) {
|
|
84
84
|
throw new Error('basic.keys:missing-keypair')
|
|
@@ -87,7 +87,7 @@ export const makeKeyPairModel: KeyPairModelMaker = input => {
|
|
|
87
87
|
return base64urlnopad.encode(
|
|
88
88
|
plugins[_model.keyPair.type].encrypt(
|
|
89
89
|
data as Uint8Array,
|
|
90
|
-
prepareKey(_model.keyPair.publicKey)
|
|
90
|
+
keyUtils.prepareKey(_model.keyPair.publicKey)
|
|
91
91
|
)
|
|
92
92
|
)
|
|
93
93
|
},
|
|
@@ -105,7 +105,7 @@ export const makeKeyPairModel: KeyPairModelMaker = input => {
|
|
|
105
105
|
|
|
106
106
|
dcrpt: async data => {
|
|
107
107
|
data = data instanceof Uint8Array ? data : base64urlnopad.decode(data as string)
|
|
108
|
-
assertType(_model.keyPair?.type)
|
|
108
|
+
keyUtils.assertType(_model.keyPair?.type)
|
|
109
109
|
|
|
110
110
|
if (_model.keyPair == null) {
|
|
111
111
|
throw new Error('basic.keys:missing-keypair')
|
|
@@ -113,7 +113,7 @@ export const makeKeyPairModel: KeyPairModelMaker = input => {
|
|
|
113
113
|
|
|
114
114
|
return plugins[_model.keyPair.type].decrypt(
|
|
115
115
|
data as Uint8Array,
|
|
116
|
-
prepareKey(_model.keyPair.privateKey)
|
|
116
|
+
keyUtils.prepareKey(_model.keyPair.privateKey)
|
|
117
117
|
)
|
|
118
118
|
}
|
|
119
119
|
}
|
package/src/plugins/ed25519.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { KeyType } from '../consts.js'
|
|
2
2
|
import type { KeyPlugin } from './types.js'
|
|
3
|
-
import { ed25519 } from '@noble/curves/ed25519'
|
|
3
|
+
import { ed25519 } from '@noble/curves/ed25519.js'
|
|
4
4
|
import { base58 } from '@scure/base'
|
|
5
|
-
import { keccak_256 } from '@noble/hashes/sha3'
|
|
5
|
+
import { keccak_256 } from '@noble/hashes/sha3.js'
|
|
6
6
|
|
|
7
7
|
export const ed25519Plugin: KeyPlugin = {
|
|
8
8
|
type: KeyType.ED25519,
|
|
9
9
|
|
|
10
|
-
random: () => ed25519.utils.
|
|
10
|
+
random: () => ed25519.utils.randomSecretKey(),
|
|
11
11
|
|
|
12
12
|
sign: (data, pk) => ed25519.sign(data, pk),
|
|
13
13
|
|
package/src/plugins/xchacha.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { KeyType } from '../consts.js'
|
|
2
2
|
import type { KeyPlugin } from './types.js'
|
|
3
|
-
import { xchacha20poly1305 } from '@noble/ciphers/chacha'
|
|
4
|
-
import { randomBytes, managedNonce } from '@noble/ciphers/
|
|
3
|
+
import { xchacha20poly1305 } from '@noble/ciphers/chacha.js'
|
|
4
|
+
import { randomBytes, managedNonce } from '@noble/ciphers/utils.js'
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
export const xChahaPlugin: KeyPlugin = {
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** The low-level key and payload primitives the key models and plugins share. */
|
|
2
|
+
export interface KeyUtils {
|
|
3
|
+
/** The 20-byte address of a public key: the tail of its keccak-256 digest. */
|
|
4
|
+
toAddress: (publicKey: Uint8Array) => Uint8Array
|
|
5
|
+
/** A base64-encoded key as bytes. */
|
|
6
|
+
prepareKey: (key: string) => Uint8Array
|
|
7
|
+
/**
|
|
8
|
+
* Bytes to sign, verify or encrypt: an object is canonicalized, a string UTF-8 encoded.
|
|
9
|
+
*
|
|
10
|
+
* @throws {Error} `basic.keys:sign-data-type` for anything else
|
|
11
|
+
*/
|
|
12
|
+
prepareData: (data: unknown) => Uint8Array
|
|
13
|
+
/** @throws {Error} `basic.keys:unknown-type` for a key type no plugin is registered for */
|
|
14
|
+
assertType: (type?: string) => void
|
|
15
|
+
}
|
package/src/utils.ts
CHANGED
|
@@ -1,35 +1,42 @@
|
|
|
1
|
-
import { keccak_256 } from '@noble/hashes/sha3'
|
|
1
|
+
import { keccak_256 } from '@noble/hashes/sha3.js'
|
|
2
2
|
import { base64, utf8 } from '@scure/base'
|
|
3
3
|
import { plugins } from './plugins/index.js'
|
|
4
4
|
import canonicalize from 'canonicalize'
|
|
5
|
+
import type { KeyUtils } from './utils/types.js'
|
|
5
6
|
|
|
6
|
-
export const
|
|
7
|
-
|
|
7
|
+
export const createKeyUtils = (): KeyUtils => {
|
|
8
|
+
const toAddress = (publicKey: Uint8Array): Uint8Array =>
|
|
9
|
+
keccak_256(publicKey.slice(4)).slice(-20)
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
+
const prepareKey = (key: string): Uint8Array =>
|
|
12
|
+
base64.decode(key)
|
|
13
|
+
|
|
14
|
+
const prepareData = (data: unknown): Uint8Array => {
|
|
15
|
+
if (typeof data === 'object') {
|
|
16
|
+
if (!(data instanceof Uint8Array)) {
|
|
17
|
+
data = canonicalize(data)
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
if (typeof data === 'string') {
|
|
21
|
+
data = utf8.decode(data)
|
|
22
|
+
} else if (!(data instanceof Uint8Array)) {
|
|
23
|
+
throw new Error('basic.keys:sign-data-type')
|
|
24
|
+
}
|
|
11
25
|
|
|
12
|
-
export const prepareData = (data: unknown): Uint8Array => {
|
|
13
|
-
if (typeof data === 'object') {
|
|
14
26
|
if (!(data instanceof Uint8Array)) {
|
|
15
|
-
|
|
27
|
+
throw new Error('basic.keys:sign-data-type')
|
|
16
28
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
data = utf8.decode(data)
|
|
20
|
-
} else if (!(data instanceof Uint8Array)) {
|
|
21
|
-
throw new Error('basic.keys:sign-data-type')
|
|
29
|
+
|
|
30
|
+
return data
|
|
22
31
|
}
|
|
23
32
|
|
|
24
|
-
|
|
25
|
-
|
|
33
|
+
const assertType = (type?: string): void => {
|
|
34
|
+
if (type == null || !(type in plugins)) {
|
|
35
|
+
throw new Error('basic.keys:unknown-type')
|
|
36
|
+
}
|
|
26
37
|
}
|
|
27
38
|
|
|
28
|
-
return
|
|
39
|
+
return { toAddress, prepareKey, prepareData, assertType }
|
|
29
40
|
}
|
|
30
41
|
|
|
31
|
-
export const
|
|
32
|
-
if (type == null || !(type in plugins)) {
|
|
33
|
-
throw new Error('basic.keys:unknown-type')
|
|
34
|
-
}
|
|
35
|
-
}
|
|
42
|
+
export const keyUtils = createKeyUtils()
|
package/tests/auth.spec.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, test } from 'bun:test'
|
|
2
|
-
import {
|
|
2
|
+
import { authCredentialsHelper } from '@owlmeans/basic-keys'
|
|
3
3
|
import { AuthRole, AuthenticationType } from '@owlmeans/auth'
|
|
4
4
|
import type { AuthCredentials } from '@owlmeans/auth'
|
|
5
5
|
import { fixtureKey } from './context.js'
|
|
@@ -15,8 +15,8 @@ const baseCreds = (): Omit<AuthCredentials, 'credential'> => ({
|
|
|
15
15
|
describe('@owlmeans/basic-keys — packAuthCredentials round-trip', () => {
|
|
16
16
|
test('signs and verifies credentials with extras attached', async () => {
|
|
17
17
|
const key = fixtureKey()
|
|
18
|
-
const signed = await packAuthCredentials(baseCreds(), { nonce: 'n-1' }, key)
|
|
19
|
-
const result = await unpackAuthCredentials<{ nonce: string }>(signed, key)
|
|
18
|
+
const signed = await authCredentialsHelper.packAuthCredentials(baseCreds(), { nonce: 'n-1' }, key)
|
|
19
|
+
const result = await authCredentialsHelper.unpackAuthCredentials<{ nonce: string }>(signed, key)
|
|
20
20
|
expect(result.isValid).toBe(true)
|
|
21
21
|
expect(result.extras?.nonce).toBe('n-1')
|
|
22
22
|
})
|
|
@@ -24,8 +24,8 @@ describe('@owlmeans/basic-keys — packAuthCredentials round-trip', () => {
|
|
|
24
24
|
test('verification fails for a different keypair', async () => {
|
|
25
25
|
const signing = fixtureKey('alice')
|
|
26
26
|
const other = fixtureKey('bob')
|
|
27
|
-
const signed = await packAuthCredentials(baseCreds(), { nonce: 'n-1' }, signing)
|
|
28
|
-
const result = await unpackAuthCredentials(signed, other)
|
|
27
|
+
const signed = await authCredentialsHelper.packAuthCredentials(baseCreds(), { nonce: 'n-1' }, signing)
|
|
28
|
+
const result = await authCredentialsHelper.unpackAuthCredentials(signed, other)
|
|
29
29
|
expect(result.isValid).toBe(false)
|
|
30
30
|
})
|
|
31
31
|
})
|
package/tests/keys.spec.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, test } from 'bun:test'
|
|
2
|
-
import {
|
|
2
|
+
import { keyHelper, makeKeyPairModel } from '@owlmeans/basic-keys'
|
|
3
3
|
import { fixtureKey } from './context.js'
|
|
4
4
|
|
|
5
5
|
describe('@owlmeans/basic-keys — KeyPairModel sign/verify', () => {
|
|
@@ -26,13 +26,13 @@ describe('@owlmeans/basic-keys — public-key-only verification (fromPubKey)', (
|
|
|
26
26
|
const signing = fixtureKey('peer-keys-spec')
|
|
27
27
|
const sig = await signing.sign({ event: 'check' })
|
|
28
28
|
|
|
29
|
-
const verifying = fromPubKey(signing.exportPublic())
|
|
29
|
+
const verifying = keyHelper.fromPubKey(signing.exportPublic())
|
|
30
30
|
expect(await verifying.verify({ event: 'check' }, sig)).toBe(true)
|
|
31
31
|
})
|
|
32
32
|
|
|
33
33
|
test('matchAddress agrees with exportAddress() on the same keypair', () => {
|
|
34
34
|
const key = fixtureKey('addr-spec')
|
|
35
|
-
expect(matchAddress(key.exportAddress(), key.exportPublic())).toBe(true)
|
|
35
|
+
expect(keyHelper.matchAddress(key.exportAddress(), key.exportPublic())).toBe(true)
|
|
36
36
|
})
|
|
37
37
|
|
|
38
38
|
test('export() round-trips into a new model that produces the same public key', async () => {
|