@prosopo/keyring 2.9.61 → 2.9.62
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/.turbo/turbo-build$colon$cjs.log +2 -2
- package/.turbo/turbo-build$colon$tsc.log +11 -11
- package/.turbo/turbo-build.log +3 -3
- package/CHANGELOG.md +5 -0
- package/dist/accounts/getPair.test.d.ts +2 -0
- package/dist/accounts/getPair.test.d.ts.map +1 -0
- package/dist/accounts/getPair.test.js +86 -0
- package/dist/accounts/getPair.test.js.map +1 -0
- package/dist/accounts/mnemonic.test.d.ts +2 -0
- package/dist/accounts/mnemonic.test.d.ts.map +1 -0
- package/dist/accounts/mnemonic.test.js +64 -0
- package/dist/accounts/mnemonic.test.js.map +1 -0
- package/dist/accounts/testAccounts.test.d.ts +2 -0
- package/dist/accounts/testAccounts.test.d.ts.map +1 -0
- package/dist/accounts/testAccounts.test.js +66 -0
- package/dist/accounts/testAccounts.test.js.map +1 -0
- package/dist/keyring/keyring.test.d.ts +2 -0
- package/dist/keyring/keyring.test.d.ts.map +1 -0
- package/dist/keyring/keyring.test.js +239 -0
- package/dist/keyring/keyring.test.js.map +1 -0
- package/dist/keyring/pairs.test.d.ts +2 -0
- package/dist/keyring/pairs.test.d.ts.map +1 -0
- package/dist/keyring/pairs.test.js +84 -0
- package/dist/keyring/pairs.test.js.map +1 -0
- package/dist/keyring/testing.test.d.ts +2 -0
- package/dist/keyring/testing.test.d.ts.map +1 -0
- package/dist/keyring/testing.test.js +97 -0
- package/dist/keyring/testing.test.js.map +1 -0
- package/dist/keyring.test-d.d.ts +2 -0
- package/dist/keyring.test-d.d.ts.map +1 -0
- package/dist/keyring.test-d.js +66 -0
- package/dist/keyring.test-d.js.map +1 -0
- package/dist/pair/decode.spec.js +1 -1
- package/dist/pair/decode.spec.js.map +1 -1
- package/dist/pair/encode.spec.js +1 -1
- package/dist/pair/encode.spec.js.map +1 -1
- package/dist/pair/nobody.test.d.ts +2 -0
- package/dist/pair/nobody.test.d.ts.map +1 -0
- package/dist/pair/nobody.test.js +77 -0
- package/dist/pair/nobody.test.js.map +1 -0
- package/dist/pair/toJson.spec.js +1 -1
- package/dist/pair/toJson.spec.js.map +1 -1
- package/package.json +1 -1
- package/src/accounts/getPair.test.ts +142 -0
- package/src/accounts/mnemonic.test.ts +103 -0
- package/src/accounts/testAccounts.test.ts +100 -0
- package/src/keyring/keyring.test.ts +373 -0
- package/src/keyring/pairs.test.ts +133 -0
- package/src/keyring/testing.test.ts +146 -0
- package/src/keyring.test-d.ts +134 -0
- package/src/pair/decode.spec.ts +3 -1
- package/src/pair/encode.spec.ts +9 -3
- package/src/pair/nobody.test.ts +127 -0
- package/src/pair/toJson.spec.ts +18 -12
- package/tsconfig.tsbuildinfo +1 -1
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// Copyright 2021-2026 Prosopo (UK) Ltd.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
import type { KeyringPair } from "@prosopo/types";
|
|
16
|
+
import { decodeAddress, encodeAddress } from "@prosopo/util-crypto";
|
|
17
|
+
import { describe, expect, it } from "vitest";
|
|
18
|
+
import { nobody } from "../pair/nobody.js";
|
|
19
|
+
import { Pairs } from "./pairs.js";
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* A pair is stored under `decodeAddress(pair.address).toString()`, which is the
|
|
23
|
+
* comma-joined bytes of the public key. Only `address` and `publicKey` are read
|
|
24
|
+
* by `Pairs`, so the inert `nobody` pair supplies the rest of the surface.
|
|
25
|
+
*/
|
|
26
|
+
const stubPair = (publicKey: Uint8Array): KeyringPair => ({
|
|
27
|
+
...nobody(),
|
|
28
|
+
address: encodeAddress(publicKey, 42),
|
|
29
|
+
addressRaw: publicKey,
|
|
30
|
+
publicKey,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const keyOf = (byte: number): Uint8Array => new Uint8Array(32).fill(byte);
|
|
34
|
+
|
|
35
|
+
describe("Pairs", () => {
|
|
36
|
+
it("returns the pair it was given, so callers can chain off add", () => {
|
|
37
|
+
const pairs = new Pairs();
|
|
38
|
+
const pair = stubPair(keyOf(1));
|
|
39
|
+
expect(pairs.add(pair)).toBe(pair);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("starts empty", () => {
|
|
43
|
+
expect(new Pairs().all()).toEqual([]);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("retrieves a pair by SS58 address, public key or raw bytes", () => {
|
|
47
|
+
const pairs = new Pairs();
|
|
48
|
+
const publicKey = keyOf(2);
|
|
49
|
+
const pair = pairs.add(stubPair(publicKey));
|
|
50
|
+
|
|
51
|
+
expect(pairs.get(pair.address)).toBe(pair);
|
|
52
|
+
expect(pairs.get(publicKey)).toBe(pair);
|
|
53
|
+
// A different SS58 prefix decodes to the same public key, so it must
|
|
54
|
+
// find the same pair — the map is keyed on bytes, not on the string.
|
|
55
|
+
expect(pairs.get(encodeAddress(publicKey, 2))).toBe(pair);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("keeps only the latest pair for a public key", () => {
|
|
59
|
+
const pairs = new Pairs();
|
|
60
|
+
const publicKey = keyOf(3);
|
|
61
|
+
pairs.add(stubPair(publicKey));
|
|
62
|
+
const second = stubPair(publicKey);
|
|
63
|
+
pairs.add(second);
|
|
64
|
+
|
|
65
|
+
expect(pairs.all()).toHaveLength(1);
|
|
66
|
+
expect(pairs.get(publicKey)).toBe(second);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("keeps distinct public keys apart", () => {
|
|
70
|
+
const pairs = new Pairs();
|
|
71
|
+
const first = pairs.add(stubPair(keyOf(4)));
|
|
72
|
+
const second = pairs.add(stubPair(keyOf(5)));
|
|
73
|
+
|
|
74
|
+
expect(pairs.all()).toEqual([first, second]);
|
|
75
|
+
expect(pairs.get(first.address)).toBe(first);
|
|
76
|
+
expect(pairs.get(second.address)).toBe(second);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("names the address it could not find, formatting bytes as hex", () => {
|
|
80
|
+
const pairs = new Pairs();
|
|
81
|
+
// A caller debugging a missing key needs to see which key was asked
|
|
82
|
+
// for; a bare "not found" would be useless.
|
|
83
|
+
expect(() => pairs.get(keyOf(6))).toThrow(
|
|
84
|
+
`Unable to retrieve keypair '0x${"06".repeat(32)}'`,
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("names the address verbatim when it was given as SS58", () => {
|
|
89
|
+
const address = encodeAddress(keyOf(7), 42);
|
|
90
|
+
expect(() => new Pairs().get(address)).toThrow(
|
|
91
|
+
`Unable to retrieve keypair '${address}'`,
|
|
92
|
+
);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it("rejects an address that is not decodable at all", () => {
|
|
96
|
+
expect(() => new Pairs().get("not-an-address")).toThrow();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("removes a pair, after which lookup throws again", () => {
|
|
100
|
+
const pairs = new Pairs();
|
|
101
|
+
const publicKey = keyOf(8);
|
|
102
|
+
pairs.add(stubPair(publicKey));
|
|
103
|
+
pairs.remove(publicKey);
|
|
104
|
+
|
|
105
|
+
expect(pairs.all()).toEqual([]);
|
|
106
|
+
expect(() => pairs.get(publicKey)).toThrow("Unable to retrieve keypair");
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
it("removes by any encoding of the same key", () => {
|
|
110
|
+
const pairs = new Pairs();
|
|
111
|
+
const publicKey = keyOf(9);
|
|
112
|
+
const pair = pairs.add(stubPair(publicKey));
|
|
113
|
+
pairs.remove(encodeAddress(publicKey, 2));
|
|
114
|
+
expect(pairs.all()).toEqual([]);
|
|
115
|
+
expect(pair.address).toBe(encodeAddress(publicKey, 42));
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it("ignores removal of a key that was never added", () => {
|
|
119
|
+
const pairs = new Pairs();
|
|
120
|
+
const kept = pairs.add(stubPair(keyOf(10)));
|
|
121
|
+
expect(() => pairs.remove(keyOf(11))).not.toThrow();
|
|
122
|
+
expect(pairs.all()).toEqual([kept]);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("decodes the address for the map key rather than trusting the string", () => {
|
|
126
|
+
// Guards the assumption the class is built on: two encodings of one
|
|
127
|
+
// key must decode to identical bytes.
|
|
128
|
+
const publicKey = keyOf(12);
|
|
129
|
+
expect(decodeAddress(encodeAddress(publicKey, 42)).toString()).toBe(
|
|
130
|
+
decodeAddress(encodeAddress(publicKey, 2)).toString(),
|
|
131
|
+
);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// Copyright 2021-2026 Prosopo (UK) Ltd.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
import { u8aToHex } from "@polkadot/util";
|
|
16
|
+
import { describe, expect, it } from "vitest";
|
|
17
|
+
import { PAIRSSR25519, createTestKeyring } from "./testing.js";
|
|
18
|
+
import { createTestPairs } from "./testingPairs.js";
|
|
19
|
+
|
|
20
|
+
// Key derivation runs scrypt/pbkdf2 with production parameters and takes
|
|
21
|
+
// seconds per call, so these suites need more than the 10s default.
|
|
22
|
+
const SLOW = { timeout: 60000 };
|
|
23
|
+
|
|
24
|
+
describe("createTestKeyring", SLOW, () => {
|
|
25
|
+
it("adds a pair for every well-known dev account", () => {
|
|
26
|
+
expect(createTestKeyring().getPairs()).toHaveLength(PAIRSSR25519.length);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("names each pair after its seed, lowercased with the path flattened", () => {
|
|
30
|
+
// `Alice//stash` becomes `alice_stash`, which is the name the rest of
|
|
31
|
+
// the stack looks pairs up by.
|
|
32
|
+
const names = createTestKeyring()
|
|
33
|
+
.getPairs()
|
|
34
|
+
.map((pair) => pair.meta.name);
|
|
35
|
+
expect(names).toEqual([
|
|
36
|
+
"alice",
|
|
37
|
+
"alice_stash",
|
|
38
|
+
"bob",
|
|
39
|
+
"bob_stash",
|
|
40
|
+
"charlie",
|
|
41
|
+
"dave",
|
|
42
|
+
"eve",
|
|
43
|
+
"ferdie",
|
|
44
|
+
]);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("marks every pair as a testing pair", () => {
|
|
48
|
+
for (const pair of createTestKeyring().getPairs()) {
|
|
49
|
+
expect(pair.meta.isTesting).toBe(true);
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("uses the hard-coded public keys, not derivation, by default", () => {
|
|
54
|
+
const keyring = createTestKeyring();
|
|
55
|
+
for (const { p } of PAIRSSR25519) {
|
|
56
|
+
expect(u8aToHex(keyring.getPair(p).publicKey)).toBe(p);
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("replaces lock with a no-op so the fixtures stay usable", () => {
|
|
61
|
+
// The pairs carry their secret in the clear; locking them would make
|
|
62
|
+
// every downstream test fail to sign.
|
|
63
|
+
const pair = createTestKeyring().getPairs()[0];
|
|
64
|
+
expect(pair).toBeDefined();
|
|
65
|
+
if (!pair) return;
|
|
66
|
+
expect(() => pair.lock()).not.toThrow();
|
|
67
|
+
expect(pair.isLocked).toBe(false);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("produces signable pairs", () => {
|
|
71
|
+
const pair = createTestKeyring().getPair(PAIRSSR25519[0]?.p ?? "0x");
|
|
72
|
+
const message = new TextEncoder().encode("hello");
|
|
73
|
+
expect(pair.verify(message, pair.sign(message), pair.publicKey)).toBe(true);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it("honours a requested ss58 format", () => {
|
|
77
|
+
const alice = PAIRSSR25519[0]?.p ?? "0x";
|
|
78
|
+
expect(
|
|
79
|
+
createTestKeyring({ ss58Format: 42 }).getPair(alice).address,
|
|
80
|
+
).not.toBe(createTestKeyring({ ss58Format: 2 }).getPair(alice).address);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("derives different keys when asked to, because the seeds are bare names", () => {
|
|
84
|
+
// The `isDerived = false` branch feeds the seed straight to
|
|
85
|
+
// `addFromUri`, and the seeds are names like "Alice" rather than
|
|
86
|
+
// "//Alice". They are therefore padded raw phrases, not dev-phrase
|
|
87
|
+
// derivations, so the pairs are NOT the well-known dev accounts.
|
|
88
|
+
// Anything relying on Alice's address must use the default mode.
|
|
89
|
+
const derived = createTestKeyring({}, false);
|
|
90
|
+
expect(derived.getPairs()).toHaveLength(PAIRSSR25519.length);
|
|
91
|
+
for (const { p } of PAIRSSR25519) {
|
|
92
|
+
expect(() => derived.getPair(p)).toThrow("Unable to retrieve keypair");
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("rejects a keyring type it cannot support", () => {
|
|
97
|
+
expect(() => createTestKeyring({ type: "ed25519" })).toThrow(
|
|
98
|
+
"Expected a keyring type of either 'sr25519'",
|
|
99
|
+
);
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe("createTestPairs", SLOW, () => {
|
|
104
|
+
it("exposes every named pair plus nobody", () => {
|
|
105
|
+
const pairs = createTestPairs();
|
|
106
|
+
for (const name of [
|
|
107
|
+
"nobody",
|
|
108
|
+
"alice",
|
|
109
|
+
"alice_stash",
|
|
110
|
+
"bob",
|
|
111
|
+
"bob_stash",
|
|
112
|
+
"charlie",
|
|
113
|
+
"dave",
|
|
114
|
+
"eve",
|
|
115
|
+
"ferdie",
|
|
116
|
+
]) {
|
|
117
|
+
expect(pairs[name], name).toBeDefined();
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("maps alice to the well-known Alice public key", () => {
|
|
122
|
+
expect(
|
|
123
|
+
u8aToHex(createTestPairs().alice?.publicKey ?? new Uint8Array()),
|
|
124
|
+
).toBe(PAIRSSR25519[0]?.p);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("includes nobody, which cannot verify anything", () => {
|
|
128
|
+
const nobodyPair = createTestPairs().nobody;
|
|
129
|
+
expect(nobodyPair).toBeDefined();
|
|
130
|
+
expect(nobodyPair?.isLocked).toBe(true);
|
|
131
|
+
expect(
|
|
132
|
+
nobodyPair?.verify(
|
|
133
|
+
new Uint8Array(1),
|
|
134
|
+
new Uint8Array(64),
|
|
135
|
+
nobodyPair.publicKey,
|
|
136
|
+
),
|
|
137
|
+
).toBe(false);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("returns independent maps so one test cannot poison another", () => {
|
|
141
|
+
const first = createTestPairs();
|
|
142
|
+
const second = createTestPairs();
|
|
143
|
+
expect(first).not.toBe(second);
|
|
144
|
+
expect(first.alice).not.toBe(second.alice);
|
|
145
|
+
});
|
|
146
|
+
});
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// Copyright 2021-2026 Prosopo (UK) Ltd.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
import type {
|
|
16
|
+
IProviderAccount,
|
|
17
|
+
ISite,
|
|
18
|
+
KeyringInstance,
|
|
19
|
+
KeyringPair,
|
|
20
|
+
KeyringPair$Json,
|
|
21
|
+
} from "@prosopo/types";
|
|
22
|
+
import { assertType, describe, expectTypeOf, it } from "vitest";
|
|
23
|
+
import {
|
|
24
|
+
Keyring,
|
|
25
|
+
generateMiniSecret,
|
|
26
|
+
generateMnemonic,
|
|
27
|
+
getDefaultProviders,
|
|
28
|
+
getDefaultSiteKeys,
|
|
29
|
+
getPair,
|
|
30
|
+
} from "./index.js";
|
|
31
|
+
// The testing helpers and `nobody` are deliberately not re-exported from the
|
|
32
|
+
// package barrel, so they are imported from their modules directly.
|
|
33
|
+
import type {
|
|
34
|
+
DetectMap,
|
|
35
|
+
DetectPairType,
|
|
36
|
+
TestKeyringMapEthereum,
|
|
37
|
+
TestKeyringMapSubstrate,
|
|
38
|
+
} from "./keyring/testingPairs.js";
|
|
39
|
+
import { nobody } from "./pair/nobody.js";
|
|
40
|
+
|
|
41
|
+
describe("Keyring types", () => {
|
|
42
|
+
it("implements the shared KeyringInstance contract", () => {
|
|
43
|
+
expectTypeOf<Keyring>().toExtend<KeyringInstance>();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("returns KeyringPair from every add and create method", () => {
|
|
47
|
+
const keyring = new Keyring();
|
|
48
|
+
expectTypeOf(keyring.addFromUri("//Alice")).toEqualTypeOf<KeyringPair>();
|
|
49
|
+
expectTypeOf(keyring.addFromMnemonic("x")).toEqualTypeOf<KeyringPair>();
|
|
50
|
+
expectTypeOf(
|
|
51
|
+
keyring.addFromSeed(new Uint8Array()),
|
|
52
|
+
).toEqualTypeOf<KeyringPair>();
|
|
53
|
+
expectTypeOf(keyring.addFromAddress("x")).toEqualTypeOf<KeyringPair>();
|
|
54
|
+
expectTypeOf(keyring.getPair("x")).toEqualTypeOf<KeyringPair>();
|
|
55
|
+
expectTypeOf(keyring.getPairs()).toEqualTypeOf<KeyringPair[]>();
|
|
56
|
+
expectTypeOf(keyring.publicKeys).toEqualTypeOf<Uint8Array[]>();
|
|
57
|
+
expectTypeOf(keyring.toJson("x")).toEqualTypeOf<KeyringPair$Json>();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("accepts an address as either a string or raw bytes", () => {
|
|
61
|
+
const keyring = new Keyring();
|
|
62
|
+
assertType(keyring.getPair("5abc"));
|
|
63
|
+
assertType(keyring.getPair(new Uint8Array(32)));
|
|
64
|
+
// @ts-expect-error a number is not an address
|
|
65
|
+
assertType(keyring.getPair(1));
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("rejects a keyring option object with an unknown key", () => {
|
|
69
|
+
// @ts-expect-error `curve` is not an option
|
|
70
|
+
new Keyring({ curve: "sr25519" });
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("has a readonly type", () => {
|
|
74
|
+
expectTypeOf<Keyring["type"]>().toEqualTypeOf<
|
|
75
|
+
import("@prosopo/util-crypto").KeypairType
|
|
76
|
+
>();
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe("account helper types", () => {
|
|
81
|
+
it("returns a pair from getPair with every argument optional", () => {
|
|
82
|
+
expectTypeOf(getPair).returns.toEqualTypeOf<KeyringPair>();
|
|
83
|
+
assertType(getPair());
|
|
84
|
+
assertType(getPair("secret", "account", "sr25519", 42));
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("returns the mnemonic and address as a tuple", () => {
|
|
88
|
+
expectTypeOf(generateMnemonic).returns.resolves.toEqualTypeOf<
|
|
89
|
+
[string, string]
|
|
90
|
+
>();
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
it("returns the mini secret as bytes paired with an address", () => {
|
|
94
|
+
expectTypeOf(generateMiniSecret).returns.resolves.toEqualTypeOf<
|
|
95
|
+
[Uint8Array, string]
|
|
96
|
+
>();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("describes the dev fixtures with the shared account types", () => {
|
|
100
|
+
expectTypeOf(getDefaultSiteKeys()).toEqualTypeOf<ISite[]>();
|
|
101
|
+
expectTypeOf(getDefaultProviders()).toEqualTypeOf<IProviderAccount[]>();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it("returns a real KeyringPair for nobody", () => {
|
|
105
|
+
expectTypeOf(nobody()).toEqualTypeOf<KeyringPair>();
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe("test keyring map inference", () => {
|
|
110
|
+
it("defaults to the substrate map when no options are given", () => {
|
|
111
|
+
expectTypeOf<DetectPairType<undefined>>().toEqualTypeOf<"sr25519">();
|
|
112
|
+
expectTypeOf<
|
|
113
|
+
DetectMap<undefined>
|
|
114
|
+
>().toEqualTypeOf<TestKeyringMapSubstrate>();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("selects the ethereum map only for an ethereum keyring", () => {
|
|
118
|
+
expectTypeOf<
|
|
119
|
+
DetectMap<{ type: "ethereum" }>
|
|
120
|
+
>().toEqualTypeOf<TestKeyringMapEthereum>();
|
|
121
|
+
expectTypeOf<
|
|
122
|
+
DetectMap<{ type: "sr25519" }>
|
|
123
|
+
>().toEqualTypeOf<TestKeyringMapSubstrate>();
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it("indexes the map by arbitrary names, always yielding a pair", () => {
|
|
127
|
+
expectTypeOf<
|
|
128
|
+
TestKeyringMapSubstrate["alice"]
|
|
129
|
+
>().toEqualTypeOf<KeyringPair>();
|
|
130
|
+
expectTypeOf<
|
|
131
|
+
TestKeyringMapSubstrate["anything-else"]
|
|
132
|
+
>().toEqualTypeOf<KeyringPair>();
|
|
133
|
+
});
|
|
134
|
+
});
|
package/src/pair/decode.spec.ts
CHANGED
|
@@ -13,7 +13,9 @@ describe("decode", (): void => {
|
|
|
13
13
|
);
|
|
14
14
|
});
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
// scrypt with the production parameters takes several seconds, which
|
|
17
|
+
// overruns the 10s default on a loaded CI runner.
|
|
18
|
+
it("returns correct publicKey from encoded", { timeout: 60000 }, (): void => {
|
|
17
19
|
const PASS = "testing";
|
|
18
20
|
|
|
19
21
|
expect((): void =>
|
package/src/pair/encode.spec.ts
CHANGED
|
@@ -18,7 +18,13 @@ describe("encode", (): void => {
|
|
|
18
18
|
expect(keyring.alice.encodePkcs8()).toHaveLength(DECODED_LENGTH);
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
// scrypt with the production parameters takes several seconds, which
|
|
22
|
+
// overruns the 10s default on a loaded CI runner.
|
|
23
|
+
it(
|
|
24
|
+
"returns encoded PKCS8 when passphrase supplied",
|
|
25
|
+
{ timeout: 60000 },
|
|
26
|
+
(): void => {
|
|
27
|
+
expect(keyring.alice.encodePkcs8("testing")).toHaveLength(ENCODED_LENGTH);
|
|
28
|
+
},
|
|
29
|
+
);
|
|
24
30
|
});
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// Copyright 2021-2026 Prosopo (UK) Ltd.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
|
|
15
|
+
import { encodeAddress } from "@prosopo/util-crypto";
|
|
16
|
+
import { describe, expect, it } from "vitest";
|
|
17
|
+
import {
|
|
18
|
+
PAIR_DIV,
|
|
19
|
+
PAIR_HDR,
|
|
20
|
+
PUB_LENGTH,
|
|
21
|
+
SALT_LENGTH,
|
|
22
|
+
SEC_LENGTH,
|
|
23
|
+
SEED_LENGTH,
|
|
24
|
+
} from "./defaults.js";
|
|
25
|
+
import { nobody } from "./nobody.js";
|
|
26
|
+
|
|
27
|
+
describe("nobody", () => {
|
|
28
|
+
it("is the all-zero public key, encoded as the well-known address", () => {
|
|
29
|
+
const pair = nobody();
|
|
30
|
+
expect(pair.publicKey).toEqual(new Uint8Array(32));
|
|
31
|
+
expect(pair.address).toBe(
|
|
32
|
+
"5C4hrfjw9DjXZTzV3MwzrrAr9P1MJhSrvWGWqi1eSuyUpnhM",
|
|
33
|
+
);
|
|
34
|
+
// The address is a pre-computed constant in the source; if the encoding
|
|
35
|
+
// ever changed, the constant would silently be wrong.
|
|
36
|
+
expect(pair.address).toBe(encodeAddress(pair.publicKey, 42));
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("is permanently locked", () => {
|
|
40
|
+
const pair = nobody();
|
|
41
|
+
expect(pair.isLocked).toBe(true);
|
|
42
|
+
pair.unlock("anything");
|
|
43
|
+
expect(pair.isLocked).toBe(true);
|
|
44
|
+
pair.lock();
|
|
45
|
+
expect(pair.isLocked).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("never verifies a signature, whatever it is given", () => {
|
|
49
|
+
// This is the whole point of the pair: it stands in for "no account"
|
|
50
|
+
// and must never authenticate anyone.
|
|
51
|
+
const pair = nobody();
|
|
52
|
+
expect(
|
|
53
|
+
pair.verify(new Uint8Array(1), new Uint8Array(64), pair.publicKey),
|
|
54
|
+
).toBe(false);
|
|
55
|
+
expect(
|
|
56
|
+
pair.verify(
|
|
57
|
+
new Uint8Array(0),
|
|
58
|
+
pair.sign(new Uint8Array(1)),
|
|
59
|
+
pair.publicKey,
|
|
60
|
+
),
|
|
61
|
+
).toBe(false);
|
|
62
|
+
expect(
|
|
63
|
+
pair.vrfVerify(new Uint8Array(1), new Uint8Array(96), pair.publicKey),
|
|
64
|
+
).toBe(false);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it("never reports a JWT as valid", () => {
|
|
68
|
+
const result = nobody().jwtVerify(nobody().jwtIssue());
|
|
69
|
+
expect(result.isValid).toBe(false);
|
|
70
|
+
expect(result.error).toBe("JWT verification failed");
|
|
71
|
+
expect(result.publicKey).toEqual(new Uint8Array(32));
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("returns correctly sized but empty signatures", () => {
|
|
75
|
+
const pair = nobody();
|
|
76
|
+
expect(pair.sign(new Uint8Array(1))).toEqual(new Uint8Array(64));
|
|
77
|
+
expect(pair.vrfSign(new Uint8Array(1))).toEqual(new Uint8Array(96));
|
|
78
|
+
expect(pair.encodePkcs8()).toEqual(new Uint8Array(0));
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("derives to itself, so no chain of derivation can escape it", () => {
|
|
82
|
+
const pair = nobody();
|
|
83
|
+
expect(pair.derive("//anything")).toBe(pair);
|
|
84
|
+
expect(pair.derive("//a").derive("//b")).toBe(pair);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("ignores attempts to change its meta", () => {
|
|
88
|
+
const pair = nobody();
|
|
89
|
+
pair.setMeta({ name: "somebody" });
|
|
90
|
+
expect(pair.meta.name).toBe("nobody");
|
|
91
|
+
expect(pair.meta.isTesting).toBe(true);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("serialises to an unencrypted v0 json blob", () => {
|
|
95
|
+
const json = nobody().toJson();
|
|
96
|
+
expect(json.address).toBe(nobody().address);
|
|
97
|
+
expect(json.encoded).toBe("");
|
|
98
|
+
expect(json.encoding.version).toBe("0");
|
|
99
|
+
expect(json.encoding.type).toBe("none");
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("returns the same shared instance each call", () => {
|
|
103
|
+
expect(nobody()).toBe(nobody());
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("accepts pkcs8 decoding without throwing", () => {
|
|
107
|
+
expect(() => nobody().decodePkcs8("pass", new Uint8Array(1))).not.toThrow();
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
describe("pair defaults", () => {
|
|
112
|
+
it("declares the sr25519 key and seed lengths", () => {
|
|
113
|
+
expect(PUB_LENGTH).toBe(32);
|
|
114
|
+
expect(SEED_LENGTH).toBe(32);
|
|
115
|
+
expect(SALT_LENGTH).toBe(32);
|
|
116
|
+
expect(SEC_LENGTH).toBe(64);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it("declares the pkcs8 header and divider used by the encoder", () => {
|
|
120
|
+
// These framing bytes are what makes an exported key readable by
|
|
121
|
+
// polkadot-js; a change here silently breaks every existing backup.
|
|
122
|
+
expect(Array.from(PAIR_DIV)).toEqual([161, 35, 3, 33, 0]);
|
|
123
|
+
expect(Array.from(PAIR_HDR)).toEqual([
|
|
124
|
+
48, 83, 2, 1, 1, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32,
|
|
125
|
+
]);
|
|
126
|
+
});
|
|
127
|
+
});
|
package/src/pair/toJson.spec.ts
CHANGED
|
@@ -24,17 +24,23 @@ describe("toJson", (): void => {
|
|
|
24
24
|
});
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
// scrypt with the production parameters takes several seconds, which
|
|
28
|
+
// overruns the 10s default on a loaded CI runner.
|
|
29
|
+
it(
|
|
30
|
+
"creates an encoded output with passphrase",
|
|
31
|
+
{ timeout: 60000 },
|
|
32
|
+
(): void => {
|
|
33
|
+
const json = keyring.alice.toJson("testing");
|
|
29
34
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
expect(json.encoded).toHaveLength(268);
|
|
36
|
+
expect(json).toMatchObject({
|
|
37
|
+
address: "5Engs9f8Gk6JqvVWz3kFyJ8Kqkgx7pLi8C1UTcr7EZ855qBQ",
|
|
38
|
+
encoding: {
|
|
39
|
+
content: ["pkcs8", "sr25519"],
|
|
40
|
+
type: ["scrypt", "xsalsa20-poly1305"],
|
|
41
|
+
version: "3",
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
);
|
|
40
46
|
});
|