@idos-network/kwil-infra 3.0.1 → 5.0.0

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.
@@ -1,7 +1,6 @@
1
1
  // @vitest-environment node
2
2
 
3
3
  import { type KwilSigner, NodeKwil } from "@idos-network/kwil-js";
4
- import { base64UrlEncode, utf8Encode } from "@idos-network/utils/codecs";
5
4
  import { describe, expect, it, vi } from "vitest";
6
5
 
7
6
  import {
@@ -9,19 +8,6 @@ import {
9
8
  createKgwAuthenticatedFetch,
10
9
  } from "./create-kgw-authenticated-fetch";
11
10
  import { KwilActionClient } from "./create-kwil-client";
12
- import { createMmTokenAuth } from "./mm-token/create-mm-token-kwil-signer";
13
-
14
- const mmEnvelopeToken = base64UrlEncode(
15
- utf8Encode(
16
- JSON.stringify({
17
- payload: {
18
- signing_public_key: base64UrlEncode(new Uint8Array(32).fill(7)),
19
- storage_id: "storage-abc",
20
- },
21
- signature: base64UrlEncode(new Uint8Array(64).fill(9)),
22
- }),
23
- ),
24
- );
25
11
 
26
12
  function createTestClient(
27
13
  initialCookie?: string,
@@ -279,6 +265,33 @@ describe("createKgwAuthenticatedFetch", () => {
279
265
  expect(cookieHeader(fetchFn.mock.calls[0])).toBe("kgw_session=valid; Path=/");
280
266
  });
281
267
 
268
+ it.each(["MM_TOKEN_INVALID", "MM_TOKEN_EXPIRED"])(
269
+ "does not reauthenticate when blob-gateway rejects the storage token (%s)",
270
+ async (code) => {
271
+ const { authFetch, fetchFn, refresh } = createTestClient("kgw_session=valid; Path=/");
272
+ fetchFn.mockResolvedValueOnce(Response.json({ error: "token", code }, { status: 401 }));
273
+
274
+ const response = await authFetch("https://blob.example/blob/v1/storage");
275
+
276
+ expect(response.status).toBe(401);
277
+ await expect(response.json()).resolves.toMatchObject({ code });
278
+ expect(refresh).not.toHaveBeenCalled();
279
+ expect(fetchFn).toHaveBeenCalledTimes(1);
280
+ },
281
+ );
282
+
283
+ it("logs in to KGW again when blob-gateway reports a missing session", async () => {
284
+ const { authFetch, fetchFn, refresh } = createTestClient("kgw_session=expired; Path=/");
285
+ fetchFn.mockResolvedValueOnce(
286
+ Response.json({ error: "session", code: "WIPE_UNAUTHORIZED" }, { status: 401 }),
287
+ );
288
+
289
+ await authFetch("https://blob.example/blob/v1/storage", { method: "DELETE" });
290
+
291
+ expect(refresh).toHaveBeenCalledTimes(1);
292
+ expect(fetchFn).toHaveBeenCalledTimes(2);
293
+ });
294
+
282
295
  it("shares one refresh across parallel auth failures", async () => {
283
296
  const { authFetch, fetchFn, refresh } = createTestClient("kgw_session=expired; Path=/");
284
297
  fetchFn
@@ -347,17 +360,7 @@ describe("createKgwAuthenticatedBlobGateway", () => {
347
360
  return new KwilActionClient(nodeKwil);
348
361
  }
349
362
 
350
- it("infers UKYC authorization from an MM signer", () => {
351
- const gateway = createKgwAuthenticatedBlobGateway({
352
- url: "https://blob.example",
353
- kwilClient: kgwSessionClient(),
354
- signer: createMmTokenAuth(mmEnvelopeToken),
355
- });
356
-
357
- expect(gateway.hasAccessToken).toBe(true);
358
- });
359
-
360
- it("accepts an explicit MM authority for a non-MM signer, and none otherwise", () => {
363
+ it("sends a storage token only when one is given", () => {
361
364
  const kwilClient = kgwSessionClient();
362
365
  const signer = {} as KwilSigner;
363
366
 
@@ -366,7 +369,7 @@ describe("createKgwAuthenticatedBlobGateway", () => {
366
369
  url: "https://blob.example",
367
370
  kwilClient,
368
371
  signer,
369
- mmAuth: createMmTokenAuth(mmEnvelopeToken),
372
+ accessToken: "storage-token",
370
373
  }).hasAccessToken,
371
374
  ).toBe(true);
372
375
  expect(
@@ -374,4 +377,21 @@ describe("createKgwAuthenticatedBlobGateway", () => {
374
377
  .hasAccessToken,
375
378
  ).toBe(false);
376
379
  });
380
+
381
+ it("sends the KGW cookie and the storage token on the same request", async () => {
382
+ const fetchFn = vi.fn<typeof fetch>(async () => new Response(null, { status: 204 }));
383
+ const gateway = createKgwAuthenticatedBlobGateway({
384
+ url: "https://blob.example",
385
+ kwilClient: kgwSessionClient(),
386
+ signer: {} as KwilSigner,
387
+ fetchFn,
388
+ }).withAccessToken("storage-token");
389
+
390
+ await gateway.deleteStorage();
391
+
392
+ const [, init] = fetchFn.mock.calls[0];
393
+ const headers = new Headers(init?.headers);
394
+ expect(headers.get("Cookie")).toBe("kgw_session=valid; Path=/");
395
+ expect(headers.get("Authorization")).toBe("AccessToken storage-token");
396
+ });
377
397
  });
@@ -2,9 +2,6 @@ import { type KwilSigner, NodeKwil } from "@idos-network/kwil-js";
2
2
  import { BlobGateway, type BlobGatewayParams } from "@idos-network/utils/blob-gateway";
3
3
 
4
4
  import type { KwilActionClient } from "./create-kwil-client";
5
- import type { MmTokenAuth } from "./mm-token/create-mm-token-kwil-signer";
6
-
7
- import { isMmTokenAuth } from "./mm-token/create-mm-token-kwil-signer";
8
5
 
9
6
  const KGW_AUTH_ERROR_CODE = -901;
10
7
 
@@ -23,10 +20,10 @@ export type CreateKgwAuthenticatedBlobGatewayParams = CreateKgwAuthenticatedFetc
23
20
  url: string;
24
21
  maxFetchBytes?: BlobGatewayParams["maxFetchBytes"];
25
22
  /**
26
- * UKYC storage authority for blob requests. Defaults to `signer` when that signer
27
- * is itself an MM authentication object, so the capability is never passed twice.
23
+ * UKYC storage token, sent as `Authorization: AccessToken <token>` next to the KGW session
24
+ * cookie. Only MM operators use it; `BlobGateway.withAccessToken()` swaps it per request.
28
25
  */
29
- mmAuth?: MmTokenAuth;
26
+ accessToken?: string;
30
27
  };
31
28
 
32
29
  type KgwSessionNodeKwil = NodeKwil & {
@@ -37,16 +34,13 @@ type KgwSessionNodeKwil = NodeKwil & {
37
34
  export function createKgwAuthenticatedBlobGateway({
38
35
  url,
39
36
  maxFetchBytes,
40
- mmAuth,
37
+ accessToken,
41
38
  ...fetchParams
42
39
  }: CreateKgwAuthenticatedBlobGatewayParams): BlobGateway {
43
- const storageAuth =
44
- mmAuth ?? (isMmTokenAuth(fetchParams.signer) ? fetchParams.signer : undefined);
45
-
46
40
  return new BlobGateway({
47
41
  url,
48
42
  maxFetchBytes,
49
- accessToken: storageAuth?.accessToken,
43
+ accessToken,
50
44
  fetchFn: createKgwAuthenticatedFetch(fetchParams),
51
45
  });
52
46
  }
@@ -302,20 +296,22 @@ function withCookie(
302
296
  return [input, { ...init, headers }];
303
297
  }
304
298
 
305
- async function defaultKgwAuthFailurePredicate(response: Response): Promise<boolean> {
306
- if (response.status === 401) {
307
- return true;
308
- }
299
+ // blob-gateway also answers 401 for a bad UKYC storage token. A new KGW session doesn't fix that.
300
+ const STORAGE_TOKEN_AUTH_ERROR_CODES = new Set(["MM_TOKEN_INVALID", "MM_TOKEN_EXPIRED"]);
309
301
 
302
+ async function defaultKgwAuthFailurePredicate(response: Response): Promise<boolean> {
310
303
  const contentType = response.headers.get("content-type");
311
304
  if (!contentType?.includes("application/json")) {
312
- return false;
305
+ return response.status === 401;
313
306
  }
314
307
 
315
308
  try {
316
- const body = (await response.json()) as { error?: { code?: number } };
309
+ const body = (await response.json()) as { code?: unknown; error?: { code?: number } };
310
+ if (response.status === 401) {
311
+ return !(typeof body.code === "string" && STORAGE_TOKEN_AUTH_ERROR_CODES.has(body.code));
312
+ }
317
313
  return body.error?.code === KGW_AUTH_ERROR_CODE;
318
314
  } catch {
319
- return false;
315
+ return response.status === 401;
320
316
  }
321
317
  }
@@ -0,0 +1,40 @@
1
+ import type { NodeKwil } from "@idos-network/kwil-js";
2
+
3
+ import { describe, expect, it, vi } from "vitest";
4
+
5
+ import { KwilActionClient, KwilCallError } from "./create-kwil-client";
6
+
7
+ function clientAnswering(data: { result?: unknown[]; error?: string }) {
8
+ const call = vi.fn(async () => ({ status: 200, data }));
9
+ return new KwilActionClient({ call } as unknown as NodeKwil);
10
+ }
11
+
12
+ const params = { name: "get_user_as_mm_operator", inputs: { storage_token: "t" } } as const;
13
+
14
+ describe("KwilActionClient.call", () => {
15
+ it("resolves to an empty result for a failed view by default", async () => {
16
+ const client = clientAnswering({ result: [], error: "storage token: expired" });
17
+
18
+ await expect(client.call(params)).resolves.toEqual([]);
19
+ });
20
+
21
+ it("throws KwilCallError with the action error when throwOnCallError is set", async () => {
22
+ const client = clientAnswering({ result: [], error: "storage token: expired" });
23
+ client.throwOnCallError = true;
24
+
25
+ const error = await client.call(params).catch((e: unknown) => e);
26
+
27
+ expect(error).toBeInstanceOf(KwilCallError);
28
+ expect(error).toMatchObject({
29
+ actionName: "get_user_as_mm_operator",
30
+ message: "storage token: expired",
31
+ });
32
+ });
33
+
34
+ it("returns the rows of a successful view when throwOnCallError is set", async () => {
35
+ const client = clientAnswering({ result: [{ id: "1" }] });
36
+ client.throwOnCallError = true;
37
+
38
+ await expect(client.call(params)).resolves.toEqual([{ id: "1" }]);
39
+ });
40
+ });
@@ -36,12 +36,33 @@ type AllKwilExecuteAction = {
36
36
 
37
37
  type KwilExecuteActionRequestParams = AllKwilExecuteAction[ActionName];
38
38
 
39
+ /**
40
+ * A view action ran but failed (its `error()` or a runtime error). kwild reports that in the
41
+ * call response's `error` field, not as an HTTP/RPC error, so it is only thrown when
42
+ * `KwilActionClient.throwOnCallError` is set.
43
+ */
44
+ export class KwilCallError extends Error {
45
+ readonly name = "KwilCallError";
46
+
47
+ constructor(
48
+ readonly actionName: string,
49
+ message: string,
50
+ ) {
51
+ super(message);
52
+ }
53
+ }
54
+
39
55
  /**
40
56
  * A client for interacting with kwil with type-safe abstractions for `call` and `execute`.
41
57
  * Has utility methods for creating actions and setting a signer.
42
58
  */
43
59
  export class KwilActionClient {
44
60
  signer?: KwilSigner;
61
+ /**
62
+ * When true, `call` throws `KwilCallError` if the view action reports an error. When false
63
+ * (default) such a call resolves to its (empty) result, as it always has.
64
+ */
65
+ throwOnCallError = false;
45
66
  readonly client: NodeKwil | WebKwil;
46
67
 
47
68
  constructor(client: NodeKwil | WebKwil) {
@@ -81,6 +102,10 @@ export class KwilActionClient {
81
102
  };
82
103
 
83
104
  const response = await this.client.call(action as CallBody, signer);
105
+ const actionError = response?.data?.error;
106
+ if (this.throwOnCallError && actionError) {
107
+ throw new KwilCallError(params.name, actionError);
108
+ }
84
109
  return response?.data?.result as T;
85
110
  }
86
111
 
@@ -1,72 +1,7 @@
1
- import { base64UrlEncode, utf8Encode } from "@idos-network/utils/codecs";
2
- import { MemoryStore } from "@idos-network/utils/store";
3
1
  import nacl from "tweetnacl";
4
- import { describe, expect, it, vi } from "vitest";
2
+ import { describe, expect, it } from "vitest";
5
3
 
6
- import type { KwilActionClient } from "./create-kwil-client";
7
-
8
- import { createClientKwilSigner, createServerKwilSigner } from "./create-kwil-signer";
9
- import { createMmTokenAuth } from "./mm-token/create-mm-token-kwil-signer";
10
-
11
- function mmToken(signingKeyByte: number): string {
12
- return base64UrlEncode(
13
- utf8Encode(
14
- JSON.stringify({
15
- payload: {
16
- signing_public_key: base64UrlEncode(new Uint8Array(32).fill(signingKeyByte)),
17
- storage_id: "storage-abc",
18
- },
19
- signature: base64UrlEncode(new Uint8Array(64).fill(9)),
20
- }),
21
- ),
22
- );
23
- }
24
-
25
- function kwilClientWithLogout(logoutKGW: () => Promise<void>): KwilActionClient {
26
- return { client: { auth: { logoutKGW } } } as unknown as KwilActionClient;
27
- }
28
-
29
- describe("createClientKwilSigner with MM authentication", () => {
30
- it("reports the MM signing identity as address and public key", async () => {
31
- const auth = createMmTokenAuth(mmToken(7));
32
- const logoutKGW = vi.fn(async () => {});
33
-
34
- const [signer, address, publicKey, walletType] = await createClientKwilSigner(
35
- new MemoryStore(),
36
- kwilClientWithLogout(logoutKGW),
37
- auth,
38
- );
39
-
40
- expect(signer).toBe(auth);
41
- expect(walletType).toBe("MM");
42
- expect(address).toBe(base64UrlEncode(auth.identifier));
43
- expect(publicKey).toBe(address);
44
- });
45
-
46
- it("clears the KGW session only when the MM signing identity changes", async () => {
47
- const store = new MemoryStore();
48
- const logoutKGW = vi.fn(async () => {});
49
- const kwilClient = kwilClientWithLogout(logoutKGW);
50
-
51
- await createClientKwilSigner(store, kwilClient, createMmTokenAuth(mmToken(7)));
52
- expect(logoutKGW).toHaveBeenCalledTimes(1);
53
-
54
- // Same identity, freshly issued token: the existing KGW cookie stays valid.
55
- await createClientKwilSigner(store, kwilClient, createMmTokenAuth(mmToken(7)));
56
- expect(logoutKGW).toHaveBeenCalledTimes(1);
57
-
58
- await createClientKwilSigner(store, kwilClient, createMmTokenAuth(mmToken(8)));
59
- expect(logoutKGW).toHaveBeenCalledTimes(2);
60
- });
61
- });
62
-
63
- describe("createServerKwilSigner with MM authentication", () => {
64
- it("uses the MM authentication object as the Kwil signer", async () => {
65
- const auth = createMmTokenAuth(mmToken(7));
66
-
67
- expect(await createServerKwilSigner(auth)).toEqual([auth, base64UrlEncode(auth.identifier)]);
68
- });
69
- });
4
+ import { createServerKwilSigner } from "./create-kwil-signer";
70
5
 
71
6
  describe("createServerKwilSigner with Nacl sign key pair", () => {
72
7
  it("emits lowercase hex SignerAddress matching kwild ed25519 @caller format", async () => {
@@ -6,15 +6,13 @@ import type { KeyPair as NearKeyPair } from "near-api-js";
6
6
  import type { KeyPair as XrpKeyPair } from "ripple-keypairs/src/types";
7
7
 
8
8
  import { KwilSigner } from "@idos-network/kwil-js";
9
- import { base64UrlEncode, bs58Encode, hexDecode, hexEncode } from "@idos-network/utils/codecs";
9
+ import { bs58Encode, hexDecode, hexEncode } from "@idos-network/utils/codecs";
10
10
  import nacl from "tweetnacl";
11
11
 
12
12
  import type { WalletType } from "./actions";
13
13
  import type { KwilActionClient } from "./create-kwil-client";
14
- import type { MmTokenAuth } from "./mm-token/create-mm-token-kwil-signer";
15
14
 
16
15
  import { FaceSignSignerProvider } from "./facesign/facesign-signer";
17
- import { isMmTokenAuth } from "./mm-token/create-mm-token-kwil-signer";
18
16
  import {
19
17
  createNearWalletKwilSigner,
20
18
  implicitAddressFromPublicKey,
@@ -30,7 +28,6 @@ export type Wallet =
30
28
  | JsonRpcSigner
31
29
  | NearWallet
32
30
  | CustomKwilSigner
33
- | MmTokenAuth
34
31
  | FaceSignSignerProvider;
35
32
 
36
33
  /**
@@ -111,8 +108,7 @@ export type KwilSignerType =
111
108
  | nacl.SignKeyPair
112
109
  | JsonRpcSigner
113
110
  | StellarKeypair
114
- | XrpKeyPair
115
- | MmTokenAuth;
111
+ | XrpKeyPair;
116
112
 
117
113
  export type SignerAddress = string;
118
114
  export type SignerPublicKey = string | undefined;
@@ -126,10 +122,6 @@ export type SignerPublicKey = string | undefined;
126
122
  export async function createServerKwilSigner(
127
123
  signer: KwilSignerType,
128
124
  ): Promise<[KwilSigner, SignerAddress]> {
129
- if (isMmTokenAuth(signer)) {
130
- return [signer, base64UrlEncode(signer.identifier)];
131
- }
132
-
133
125
  if (isNaclSignKeyPair(signer)) {
134
126
  return [
135
127
  new KwilSigner(
@@ -247,23 +239,6 @@ export async function createClientKwilSigner(
247
239
  ];
248
240
  }
249
241
 
250
- if (isMmTokenAuth(wallet)) {
251
- const currentAddress = base64UrlEncode(wallet.identifier);
252
- const storedAddress = await store.get<string>("signer-address");
253
-
254
- if (storedAddress !== currentAddress) {
255
- // A different MM signing identity must not re-use the previous KGW cookie.
256
- store.set("signer-address", currentAddress);
257
- try {
258
- await kwilClient.client.auth.logoutKGW();
259
- } catch (error) {
260
- console.log("error logoutKGW", error);
261
- }
262
- }
263
-
264
- return [wallet, currentAddress, currentAddress, "MM"];
265
- }
266
-
267
242
  if (isCustomKwilSigner(wallet) || wallet instanceof FaceSignSignerProvider) {
268
243
  const storedAddress = await store.get<string>("signer-address");
269
244
 
package/src/index.ts CHANGED
@@ -1,7 +1,6 @@
1
1
  export * from "./create-kwil-client";
2
2
  export * from "./create-kgw-authenticated-fetch";
3
3
  export * from "./create-kwil-signer";
4
- export * from "./mm-token/create-mm-token-kwil-signer";
5
4
  export {
6
5
  getNearFullAccessPublicKeys,
7
6
  implicitAddressFromPublicKey,
@@ -1 +0,0 @@
1
- {"version":3,"file":"index-Bk8YCFlx.d.mts","names":[],"sources":["../src/wait-for-kwil-tx.ts","../src/create-kwil-client.ts","../src/mm-token/create-mm-token-kwil-signer.ts","../src/create-kgw-authenticated-fetch.ts","../src/create-kwil-signer.ts","../src/near/create-near-wallet-kwil-signer.ts","../src/actions/actions.ts","../src/actions/index.ts"],"mappings":"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"}
@@ -1,148 +0,0 @@
1
- import { base64UrlEncode, utf8Encode } from "@idos-network/utils/codecs";
2
- import { describe, expect, it } from "vitest";
3
-
4
- import {
5
- createMmTokenAuth,
6
- isMmTokenAuth,
7
- mmTokenCredentialContentUri,
8
- mmTokenStorageId,
9
- type MmTokenEnvelope,
10
- } from "./create-mm-token-kwil-signer.js";
11
-
12
- const signingPublicKeyBytes = new Uint8Array(Array.from({ length: 32 }, (_, index) => index + 1));
13
- const signatureBytes = new Uint8Array(Array.from({ length: 64 }, (_, index) => index + 64));
14
-
15
- function createEnvelope(overrides: Partial<MmTokenEnvelope> = {}): MmTokenEnvelope {
16
- return {
17
- payload: {
18
- version: 1,
19
- aud: ["metamask:user-storage:ukyc", "idos:kwil"],
20
- signing_public_key: base64UrlEncode(signingPublicKeyBytes),
21
- storage_id: "storage-abc",
22
- },
23
- signature: base64UrlEncode(signatureBytes),
24
- ...overrides,
25
- };
26
- }
27
-
28
- function encodeEnvelope(envelope: MmTokenEnvelope): string {
29
- return base64UrlEncode(utf8Encode(JSON.stringify(envelope)));
30
- }
31
-
32
- async function signMessage(signer: ReturnType<typeof createMmTokenAuth>): Promise<Uint8Array> {
33
- return await (signer.signer as (message: Uint8Array) => Promise<Uint8Array>)(
34
- new Uint8Array([1, 2, 3]),
35
- );
36
- }
37
-
38
- describe("createMmTokenAuth", () => {
39
- it("uses mm_token auth type and decoded signing_public_key bytes as identity", () => {
40
- const signer = createMmTokenAuth(encodeEnvelope(createEnvelope()));
41
-
42
- expect(signer.signatureType).toBe("mm_token");
43
- expect(signer.identifier).toEqual(signingPublicKeyBytes);
44
- });
45
-
46
- it("returns the exact encoded envelope bytes from signMessage", async () => {
47
- const encoded = encodeEnvelope(createEnvelope());
48
- const signer = createMmTokenAuth(encoded);
49
-
50
- expect(await signMessage(signer)).toEqual(utf8Encode(encoded));
51
- });
52
-
53
- it("accepts a decoded envelope object and returns its encoded form", async () => {
54
- const envelope = createEnvelope();
55
- const signer = createMmTokenAuth(envelope);
56
-
57
- expect(await signMessage(signer)).toEqual(utf8Encode(encodeEnvelope(envelope)));
58
- });
59
-
60
- it("rejects raw JSON envelope strings (must be base64url-encoded)", () => {
61
- expect(() => createMmTokenAuth(JSON.stringify(createEnvelope()))).toThrow(
62
- "Invalid mm_token envelope encoding",
63
- );
64
- });
65
-
66
- it("rejects invalid signature length", () => {
67
- expect(() =>
68
- createMmTokenAuth(
69
- encodeEnvelope(createEnvelope({ signature: base64UrlEncode(new Uint8Array(63)) })),
70
- ),
71
- ).toThrow("Invalid mm_token signature length: expected 64, got 63");
72
- });
73
-
74
- it("rejects signing_public_key with the wrong byte length", () => {
75
- expect(() =>
76
- createMmTokenAuth(
77
- encodeEnvelope(
78
- createEnvelope({
79
- payload: {
80
- version: 1,
81
- signing_public_key: base64UrlEncode(new Uint8Array(31)),
82
- },
83
- }),
84
- ),
85
- ),
86
- ).toThrow("Invalid mm_token signing_public_key length: expected 32, got 31");
87
- });
88
-
89
- it("carries the exact encoded capability as a non-enumerable access token", () => {
90
- const encoded = encodeEnvelope(createEnvelope());
91
- const auth = createMmTokenAuth(encoded);
92
-
93
- expect(auth.accessToken).toBe(encoded);
94
- expect(isMmTokenAuth(auth)).toBe(true);
95
- // Blob authorization must not leak through logging or serialization.
96
- expect(Object.keys(auth)).not.toContain("accessToken");
97
- expect(JSON.stringify(auth)).not.toContain(encoded);
98
- });
99
-
100
- it("re-encodes a decoded envelope object into the access token", () => {
101
- const envelope = createEnvelope();
102
-
103
- expect(createMmTokenAuth(envelope).accessToken).toBe(encodeEnvelope(envelope));
104
- });
105
-
106
- it("does not recognize a non-MM signer as MM authentication", () => {
107
- expect(isMmTokenAuth({ identifier: "a", signer: () => {}, signatureType: "ed25519" })).toBe(
108
- false,
109
- );
110
- });
111
-
112
- it("keeps the token payload and exposes its storage_id", () => {
113
- const signer = createMmTokenAuth(encodeEnvelope(createEnvelope()));
114
-
115
- expect(signer.mmTokenPayload.storage_id).toBe("storage-abc");
116
- expect(mmTokenStorageId(signer)).toBe("storage-abc");
117
- });
118
-
119
- it("builds the credential ukyc:// URI from a base64url-encoded token", () => {
120
- const credentialId = "0198c21d-79cb-7000-8000-000000000001";
121
- const encodedToken = encodeEnvelope(createEnvelope());
122
- const signer = createMmTokenAuth(encodedToken);
123
- const credential = {
124
- id: credentialId,
125
- content_uri: mmTokenCredentialContentUri(signer, credentialId),
126
- };
127
-
128
- expect(credential).toEqual({
129
- id: credentialId,
130
- content_uri: `ukyc://storage-abc/blobs/${credentialId}`,
131
- });
132
- });
133
-
134
- it("fails when the token payload has no storage_id", () => {
135
- const signer = createMmTokenAuth(
136
- encodeEnvelope(
137
- createEnvelope({
138
- payload: {
139
- version: 1,
140
- signing_public_key: base64UrlEncode(signingPublicKeyBytes),
141
- },
142
- }),
143
- ),
144
- );
145
-
146
- expect(() => mmTokenStorageId(signer)).toThrow("mm_token payload is missing storage_id");
147
- });
148
- });