@kokuin/token 0.5.0 → 0.5.1
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/lib/did.js +3 -3
- package/lib/identity.js +9 -4
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/token.js +6 -3
- package/lib/utils.d.ts +5 -1
- package/lib/utils.js +15 -1
- package/package.json +13 -13
package/lib/did.js
CHANGED
|
@@ -282,11 +282,11 @@ function hasKeyPrefix(did) {
|
|
|
282
282
|
}
|
|
283
283
|
function resolveKidOrAuth(doc, kid) {
|
|
284
284
|
if (kid == null) {
|
|
285
|
-
const
|
|
286
|
-
if (
|
|
285
|
+
const firstAuth = doc.authentication?.[0];
|
|
286
|
+
if (firstAuth == null) {
|
|
287
287
|
throw new Error('resolveIssuer: did:peer:4 token missing kid and doc has no authentication entries');
|
|
288
288
|
}
|
|
289
|
-
return resolveKidFromDoc(doc,
|
|
289
|
+
return resolveKidFromDoc(doc, firstAuth);
|
|
290
290
|
}
|
|
291
291
|
// A kid must reference a method the subject authorized for `authentication`. Without this
|
|
292
292
|
// check a key listed only under `assertionMethod` (or any other relationship) could sign
|
package/lib/identity.js
CHANGED
|
@@ -169,19 +169,21 @@ function isClassical(spec) {
|
|
|
169
169
|
function chooseMethod(input) {
|
|
170
170
|
if (input.didMethod != null) {
|
|
171
171
|
if (input.didMethod === 'key') {
|
|
172
|
-
|
|
172
|
+
const [firstKey, ...rest] = input.keys;
|
|
173
|
+
if (firstKey === undefined || rest.length > 0) {
|
|
173
174
|
throw new Error('IdentityError.InvalidMethod: did:key requires exactly one key');
|
|
174
175
|
}
|
|
175
|
-
if (!isClassical(
|
|
176
|
+
if (!isClassical(firstKey)) {
|
|
176
177
|
throw new Error('IdentityError.InvalidMethod: did:key requires a classical algorithm');
|
|
177
178
|
}
|
|
178
|
-
if (
|
|
179
|
+
if (firstKey.purpose !== 'sig') {
|
|
179
180
|
throw new Error('IdentityError.InvalidMethod: did:key requires a signing key');
|
|
180
181
|
}
|
|
181
182
|
}
|
|
182
183
|
return input.didMethod;
|
|
183
184
|
}
|
|
184
|
-
|
|
185
|
+
const [firstKey, ...rest] = input.keys;
|
|
186
|
+
if (firstKey !== undefined && rest.length === 0 && isClassical(firstKey) && firstKey.purpose === 'sig') {
|
|
185
187
|
return 'key';
|
|
186
188
|
}
|
|
187
189
|
return 'peer:4';
|
|
@@ -356,6 +358,9 @@ function buildIdentity(id, longForm, doc, keys) {
|
|
|
356
358
|
const keys = resolveKeys(input);
|
|
357
359
|
if (method === 'key') {
|
|
358
360
|
const [k] = keys;
|
|
361
|
+
if (k === undefined) {
|
|
362
|
+
throw new Error('createIdentity requires at least one key');
|
|
363
|
+
}
|
|
359
364
|
const id = getDID(CODECS.EdDSA, k.publicKey);
|
|
360
365
|
const doc = {
|
|
361
366
|
'@context': [
|
package/lib/index.d.ts
CHANGED
|
@@ -21,5 +21,5 @@ export { decodePrivateKey, encodePrivateKey, randomPrivateKey, } from './signer.
|
|
|
21
21
|
export { assertTimeClaimsValid, now, type TimeClaimsPayload, type TimeValidationOptions, } from './time.js';
|
|
22
22
|
export { createUnsignedToken, isSignedToken, isUnsignedToken, isVerifiedToken, signToken, type VerifyTokenOptions, verifyToken, } from './token.js';
|
|
23
23
|
export type * from './types.js';
|
|
24
|
-
export { concatBytes, stringifyToken } from './utils.js';
|
|
24
|
+
export { concatBytes, decodeSignedToken, stringifyToken } from './utils.js';
|
|
25
25
|
export { getVerifier, type Verifier, type Verifiers, } from './verifier.js';
|
package/lib/index.js
CHANGED
|
@@ -18,5 +18,5 @@ export { capabilitySchema, signedHeaderSchema, signedPayloadSchema, supportedHea
|
|
|
18
18
|
export { decodePrivateKey, encodePrivateKey, randomPrivateKey } from './signer.js';
|
|
19
19
|
export { assertTimeClaimsValid, now } from './time.js';
|
|
20
20
|
export { createUnsignedToken, isSignedToken, isUnsignedToken, isVerifiedToken, signToken, verifyToken } from './token.js';
|
|
21
|
-
export { concatBytes, stringifyToken } from './utils.js';
|
|
21
|
+
export { concatBytes, decodeSignedToken, stringifyToken } from './utils.js';
|
|
22
22
|
export { getVerifier } from './verifier.js';
|
package/lib/token.js
CHANGED
|
@@ -125,12 +125,12 @@ function matchesVerifiableData(token, data) {
|
|
|
125
125
|
if (data === `${b64uFromJSON(token.header)}.${b64uFromJSON(token.payload)}`) {
|
|
126
126
|
return true;
|
|
127
127
|
}
|
|
128
|
-
const
|
|
129
|
-
if (
|
|
128
|
+
const [headerPart, payloadPart, extra] = data.split('.');
|
|
129
|
+
if (headerPart === undefined || payloadPart === undefined || extra !== undefined) {
|
|
130
130
|
return false;
|
|
131
131
|
}
|
|
132
132
|
try {
|
|
133
|
-
return canonicalStringify(b64uToJSON(
|
|
133
|
+
return canonicalStringify(b64uToJSON(headerPart)) === canonicalStringify(token.header) && canonicalStringify(b64uToJSON(payloadPart)) === canonicalStringify(token.payload);
|
|
134
134
|
} catch {
|
|
135
135
|
// invalid base64url or JSON in data
|
|
136
136
|
return false;
|
|
@@ -210,6 +210,9 @@ async function verifyTokenInner(token, options = {}) {
|
|
|
210
210
|
throw new Error('Invalid token format: expected 3 parts separated by dots');
|
|
211
211
|
}
|
|
212
212
|
const [encodedHeader, encodedPayload, signature] = parts;
|
|
213
|
+
if (encodedHeader === undefined || encodedPayload === undefined) {
|
|
214
|
+
throw new Error('Invalid token format: expected 3 parts separated by dots');
|
|
215
|
+
}
|
|
213
216
|
const header = b64uToJSON(encodedHeader);
|
|
214
217
|
if (header.typ !== 'JWT') {
|
|
215
218
|
throw new Error('Invalid token header type');
|
package/lib/utils.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import type { Token } from './types.js';
|
|
1
|
+
import type { SignedToken, Token } from './types.js';
|
|
2
2
|
export declare function concatBytes(a: Uint8Array, b: Uint8Array): Uint8Array;
|
|
3
3
|
/**
|
|
4
4
|
* Convert a Token object to its JWT string representation.
|
|
5
5
|
*/
|
|
6
6
|
export declare function stringifyToken(token: Token): string;
|
|
7
|
+
/**
|
|
8
|
+
* Parse a signed token string without verifying it. `data` keeps the original signed segments.
|
|
9
|
+
*/
|
|
10
|
+
export declare function decodeSignedToken<Payload extends Record<string, unknown> = Record<string, unknown>>(token: string): SignedToken<Payload>;
|
package/lib/utils.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { b64uFromJSON } from '@sozai/codec';
|
|
1
|
+
import { b64uFromJSON, b64uToJSON } from '@sozai/codec';
|
|
2
2
|
export function concatBytes(a, b) {
|
|
3
3
|
const out = new Uint8Array(a.length + b.length);
|
|
4
4
|
out.set(a, 0);
|
|
@@ -17,3 +17,17 @@ export function concatBytes(a, b) {
|
|
|
17
17
|
}
|
|
18
18
|
return parts.join('.');
|
|
19
19
|
}
|
|
20
|
+
/**
|
|
21
|
+
* Parse a signed token string without verifying it. `data` keeps the original signed segments.
|
|
22
|
+
*/ export function decodeSignedToken(token) {
|
|
23
|
+
const [header, payload, signature, ...rest] = token.split('.');
|
|
24
|
+
if (!header || !payload || !signature || rest.length > 0) {
|
|
25
|
+
throw new Error('Invalid token format: expected 3 parts separated by dots');
|
|
26
|
+
}
|
|
27
|
+
return {
|
|
28
|
+
data: `${header}.${payload}`,
|
|
29
|
+
header: b64uToJSON(header),
|
|
30
|
+
payload: b64uToJSON(payload),
|
|
31
|
+
signature
|
|
32
|
+
};
|
|
33
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kokuin/token",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "JWT signing and verification",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"json",
|
|
@@ -26,17 +26,17 @@
|
|
|
26
26
|
"lib/*"
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
|
-
"@
|
|
30
|
-
"@noble/
|
|
31
|
-
"@
|
|
32
|
-
"@
|
|
33
|
-
"@sozai/
|
|
34
|
-
"@sozai/
|
|
35
|
-
"@
|
|
29
|
+
"@kokuin/otel": "^0.3.0",
|
|
30
|
+
"@noble/curves": "^2.4.0",
|
|
31
|
+
"@noble/hashes": "^2.4.0",
|
|
32
|
+
"@scure/base": "^2.4.0",
|
|
33
|
+
"@sozai/codec": "^0.4.2",
|
|
34
|
+
"@sozai/otel": "^0.3.3",
|
|
35
|
+
"@sozai/schema": "^0.1.6"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@opentelemetry/sdk-trace-base": "^2.
|
|
39
|
-
"@opentelemetry/sdk-trace-node": "^2.
|
|
38
|
+
"@opentelemetry/sdk-trace-base": "^2.12.0",
|
|
39
|
+
"@opentelemetry/sdk-trace-node": "^2.12.0",
|
|
40
40
|
"uint8arrays": "^6.1.1"
|
|
41
41
|
},
|
|
42
42
|
"publishConfig": {
|
|
@@ -44,9 +44,9 @@
|
|
|
44
44
|
},
|
|
45
45
|
"scripts": {
|
|
46
46
|
"build": "pnpm run build:clean && pnpm run build:js && pnpm run build:types",
|
|
47
|
-
"build:clean": "del lib",
|
|
48
|
-
"build:js": "swc src -d ./lib --config-file ../../node_modules/@kigu/dev/swc.json --strip-leading-paths",
|
|
49
|
-
"build:types": "tsc --emitDeclarationOnly --skipLibCheck",
|
|
47
|
+
"build:clean": "del-cli lib",
|
|
48
|
+
"build:js": "del-cli 'lib/**/*.js' && swc src -d ./lib --config-file ../../node_modules/@kigu/dev/swc.json --strip-leading-paths",
|
|
49
|
+
"build:types": "del-cli 'lib/**/*.d.ts' 'lib/**/*.d.ts.map' && tsc --emitDeclarationOnly --skipLibCheck",
|
|
50
50
|
"test": "pnpm run test:types && pnpm run test:unit",
|
|
51
51
|
"test:types": "tsc --noEmit --skipLibCheck -p tsconfig.test.json",
|
|
52
52
|
"test:unit": "vitest run"
|