@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 CHANGED
@@ -282,11 +282,11 @@ function hasKeyPrefix(did) {
282
282
  }
283
283
  function resolveKidOrAuth(doc, kid) {
284
284
  if (kid == null) {
285
- const auth = doc.authentication;
286
- if (auth == null || auth.length === 0) {
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, auth[0]);
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
- if (input.keys.length !== 1) {
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(input.keys[0])) {
176
+ if (!isClassical(firstKey)) {
176
177
  throw new Error('IdentityError.InvalidMethod: did:key requires a classical algorithm');
177
178
  }
178
- if (input.keys[0].purpose !== 'sig') {
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
- if (input.keys.length === 1 && isClassical(input.keys[0]) && input.keys[0].purpose === 'sig') {
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 parts = data.split('.');
129
- if (parts.length !== 2) {
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(parts[0])) === canonicalStringify(token.header) && canonicalStringify(b64uToJSON(parts[1])) === canonicalStringify(token.payload);
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.0",
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
- "@noble/curves": "^2.3.0",
30
- "@noble/hashes": "^2.3.0",
31
- "@scure/base": "^2.3.0",
32
- "@sozai/codec": "^0.4.0",
33
- "@sozai/otel": "^0.3.2",
34
- "@sozai/schema": "^0.1.1",
35
- "@kokuin/otel": "^0.3.0"
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.10.0",
39
- "@opentelemetry/sdk-trace-node": "^2.10.0",
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"