From e70a7749084c481ccd4ea02c8870510722c92e30 Mon Sep 17 00:00:00 2001 From: Joel Thorstensson Date: Tue, 13 Feb 2024 19:49:10 +0100 Subject: [PATCH] feat(did-session): session removal support (#187) --- packages/did-session/src/index.ts | 35 +- packages/did-session/src/sessionStore.ts | 9 + .../test/__snapshots__/lib.test.ts.snap | 2 +- packages/did-session/test/lib.test.ts | 428 ++++++++++-------- 4 files changed, 281 insertions(+), 193 deletions(-) diff --git a/packages/did-session/src/index.ts b/packages/did-session/src/index.ts index 756dd45f..1788c00e 100644 --- a/packages/did-session/src/index.ts +++ b/packages/did-session/src/index.ts @@ -202,6 +202,11 @@ export function cacaoContainsResources(cacao: Cacao, resources: Array): return resources.every((res) => cacao.p.resources?.includes(res)) } +function isExpired(expTime?: string): boolean { + if (!expTime) return false + return Date.parse(expTime) < Date.now() +} + /** * DID Session * @@ -261,12 +266,17 @@ export class DIDSession { const store = await SessionStore.create() const result = (await store.get(account)) || {} let { cacao, keypair } = result as { cacao: Cacao; keypair: CryptoKeyPair } - if (cacao && keypair && cacaoContainsResources(cacao, authOpts.resources)) { + if ( + cacao && + keypair && + cacaoContainsResources(cacao, authOpts.resources) && + !isExpired(cacao.p.exp) + ) { const provider = new WebcryptoProvider(keypair) const did = new DID({ provider, resolver: KeyDidResolver.getResolver(), capability: cacao }) await did.authenticate() const session = new DIDSession({ cacao, did }) - if (!session.isExpired) return session + return session } // create a new DID instance using the WebcryptoProvider keypair = await generateP256KeyPair() @@ -275,6 +285,11 @@ export class DIDSession { await didKey.authenticate() const authMethodOpts: AuthMethodOpts = authOpts authMethodOpts.uri = didKey.id + if (authOpts.expiresInSecs) { + const exp = new Date(Date.now() + authOpts.expiresInSecs * 1000) + authMethodOpts.expirationTime = exp.toISOString() + } + cacao = await authMethod(authMethodOpts) const did = await createDIDCacao(didKey, cacao) await store.set(account, { cacao, keypair }) @@ -282,13 +297,23 @@ export class DIDSession { return new DIDSession({ cacao, did }) } + /** + * Removes a session from storage for a given account (if created using `DIDSession.get`) + */ + static async remove(account: AccountId): Promise { + const store = await SessionStore.create() + await store.remove(account) + store.close() + } + /** * Check if there is an active session for a given account. */ static async hasSessionFor(account: AccountId, resources: Array): Promise { const store = await SessionStore.create() const { cacao } = (await store.get(account)) || ({} as { cacao: Cacao }) - return cacao && cacaoContainsResources(cacao, resources) + store.close() + return cacao && cacaoContainsResources(cacao, resources) && !isExpired(cacao.p.exp) } /** @@ -329,9 +354,7 @@ export class DIDSession { * Determine if a session is expired or not */ get isExpired(): boolean { - const expTime = this.#cacao.p.exp - if (!expTime) return false - return Date.parse(expTime) < Date.now() + return isExpired(this.#cacao.p.exp) } /** diff --git a/packages/did-session/src/sessionStore.ts b/packages/did-session/src/sessionStore.ts index 5aff5f6e..9ed65049 100644 --- a/packages/did-session/src/sessionStore.ts +++ b/packages/did-session/src/sessionStore.ts @@ -47,6 +47,15 @@ export class SessionStore { }) } + async remove(accountId: AccountId): Promise { + const store = this.#db.transaction('sessions', 'readwrite').objectStore('sessions') + const request = store.delete(accountId.toString()) + return new Promise((resolve, reject) => { + request.onsuccess = () => resolve() + request.onerror = () => reject(request.error) + }) + } + close() { this.#db.close() } diff --git a/packages/did-session/test/__snapshots__/lib.test.ts.snap b/packages/did-session/test/__snapshots__/lib.test.ts.snap index 4e117844..34f9441e 100644 --- a/packages/did-session/test/__snapshots__/lib.test.ts.snap +++ b/packages/did-session/test/__snapshots__/lib.test.ts.snap @@ -1,3 +1,3 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`did-session Manage session state serializes 1`] = `"eyJzZXNzaW9uS2V5U2VlZCI6IlFLaUhYOHh4TkZwQ3dOdnhJb0M0c0NUNXY5OXM4QVozNGdkUjBoK0F0b3M9IiwiY2FjYW8iOnsiaCI6eyJ0IjoiZWlwNDM2MSJ9LCJwIjp7ImRvbWFpbiI6InNlcnZpY2Uub3JnIiwiaWF0IjoiMjAyMS0wOS0zMFQxNjoyNToyNC4wMDBaIiwiaXNzIjoiZGlkOnBraDplaXAxNTU6MToweEJkOUQ5YzdEQzM4OTcxNWE4OWZDODE0OUU0YTVCZTkxMzM2QjI3OTYiLCJhdWQiOiJkaWQ6a2V5Ono2TWtyQmROZHdVUG5YRFZEMURDeGVkelZWQnBhR2k4YVNtb1hGQWVLTmd0QWVyOCIsInZlcnNpb24iOiIxIiwibm9uY2UiOiIzMjg5MTc1NyIsInN0YXRlbWVudCI6IkkgYWNjZXB0IHRoZSBTZXJ2aWNlT3JnIFRlcm1zIG9mIFNlcnZpY2U6IGh0dHBzOi8vc2VydmljZS5vcmcvdG9zIiwicmVzb3VyY2VzIjpbImBjZXJhbWljOi8vKj9tb2RlbD1rMnQ2d3lmc3U0cGZ6MGZuaWRrNnR6M2dhazd0cjhuNXczNGFoMWMzMXc1dnE5OGI2MmhpcjFwbm4zajJ0eSIsImBjZXJhbWljOi8vKj9tb2RlbD1rMnQ2d3lmc3U0cGd6MGZ0eDY2NHZldWFmMnFpYjk1emo4amUyeDdwZjg5djZnNXA3eGE3bjllbzQ1ZzY0YSJdfSwicyI6eyJ0IjoiZWlwMTkxIiwicyI6IjB4ZTRkYTkyZDlmNDgyYzc3NzVjYmIwM2E1MjdiZGFhOGVhYThhMWEyZDA5ZTFiZDhhYmM2ZjllMjkwODEyNDc1ZTYwNzgyMjZmMDdhYWM3ZTQ0YjQ5MGU3MDI3MzJlMDkwNjUyM2RkMzgzYjZlMDFlMjZjMTBhMGIzZWYxODBhZWUxYiJ9fX0"`; +exports[`did-session DIDSession.authorize Manage session state serializes 1`] = `"eyJzZXNzaW9uS2V5U2VlZCI6IlFLaUhYOHh4TkZwQ3dOdnhJb0M0c0NUNXY5OXM4QVozNGdkUjBoK0F0b3M9IiwiY2FjYW8iOnsiaCI6eyJ0IjoiZWlwNDM2MSJ9LCJwIjp7ImRvbWFpbiI6InNlcnZpY2Uub3JnIiwiaWF0IjoiMjAyMS0wOS0zMFQxNjoyNToyNC4wMDBaIiwiaXNzIjoiZGlkOnBraDplaXAxNTU6MToweEJkOUQ5YzdEQzM4OTcxNWE4OWZDODE0OUU0YTVCZTkxMzM2QjI3OTYiLCJhdWQiOiJkaWQ6a2V5Ono2TWtyQmROZHdVUG5YRFZEMURDeGVkelZWQnBhR2k4YVNtb1hGQWVLTmd0QWVyOCIsInZlcnNpb24iOiIxIiwibm9uY2UiOiIzMjg5MTc1NyIsInN0YXRlbWVudCI6IkkgYWNjZXB0IHRoZSBTZXJ2aWNlT3JnIFRlcm1zIG9mIFNlcnZpY2U6IGh0dHBzOi8vc2VydmljZS5vcmcvdG9zIiwicmVzb3VyY2VzIjpbImBjZXJhbWljOi8vKj9tb2RlbD1rMnQ2d3lmc3U0cGZ6MGZuaWRrNnR6M2dhazd0cjhuNXczNGFoMWMzMXc1dnE5OGI2MmhpcjFwbm4zajJ0eSIsImBjZXJhbWljOi8vKj9tb2RlbD1rMnQ2d3lmc3U0cGd6MGZ0eDY2NHZldWFmMnFpYjk1emo4amUyeDdwZjg5djZnNXA3eGE3bjllbzQ1ZzY0YSJdfSwicyI6eyJ0IjoiZWlwMTkxIiwicyI6IjB4ZTRkYTkyZDlmNDgyYzc3NzVjYmIwM2E1MjdiZGFhOGVhYThhMWEyZDA5ZTFiZDhhYmM2ZjllMjkwODEyNDc1ZTYwNzgyMjZmMDdhYWM3ZTQ0YjQ5MGU3MDI3MzJlMDkwNjUyM2RkMzgzYjZlMDFlMjZjMTBhMGIzZWYxODBhZWUxYiJ9fX0"`; diff --git a/packages/did-session/test/lib.test.ts b/packages/did-session/test/lib.test.ts index eaca6218..c3b1572b 100644 --- a/packages/did-session/test/lib.test.ts +++ b/packages/did-session/test/lib.test.ts @@ -125,223 +125,258 @@ describe('did-session', () => { ) const address = wallet.address - test('authorize, with streamid resources', async () => { - const streamId = `ceramic://z6MkhZCWzHtPFmpNupVPuHA6svtpKKY9RUpgf9uohnhFMNvj` - const session = await DIDSession.authorize(authMethod, { - resources: [streamId], + describe('DIDSession.get', () => { + afterEach(async () => { + // make sure each test starts with a clean slate + await DIDSession.remove(account) }) - const did = session.did - expect(did.capability.p.resources.includes(streamId)).toBe(true) - }) - test('authorize and create/update streams', async () => { - const session = await DIDSession.authorize(authMethod, { - resources: [`ceramic://*`], - }) - ceramic.did = session.did - const doc = await TileDocument.create( - ceramic, - { foo: 'bar' }, - {}, - { - anchor: false, - publish: false, - }, - ) - expect(doc.content).toEqual({ foo: 'bar' }) + test('get and create/update streams from persisted session', async () => { + const authMock = jest.fn(authMethod) + const resources = [`ceramic://*`] + expect(await DIDSession.hasSessionFor(account, resources)).toBeFalsy() - await doc.update({ foo: 'boo' }) - expect(doc.content).toEqual({ foo: 'boo' }) - }) + await DIDSession.get(account, authMock, { + resources, + }) + // auth was used + expect(authMock).toHaveBeenCalledTimes(1) + expect(await DIDSession.hasSessionFor(account, resources)).toBeTruthy() - test('authorize and create/update streams from serialized session', async () => { - const session = await DIDSession.authorize(authMethod, { - resources: [`ceramic://*`], + const session = await DIDSession.get(account, authMethod, { + resources, + }) + // indicates that we loaded auth from session storage + expect(authMock).toHaveBeenCalledTimes(1) + + ceramic.did = session.did + const doc = await TileDocument.create( + ceramic, + { foo: 'bar' }, + {}, + { + anchor: false, + publish: false, + }, + ) + expect(doc.content).toEqual({ foo: 'bar' }) + + await doc.update({ foo: 'boo' }) + expect(doc.content).toEqual({ foo: 'boo' }) }) - const sessionStr = session.serialize() - const session2 = await DIDSession.fromSession(sessionStr) - ceramic.did = session2.did - const doc = await TileDocument.create( - ceramic, - { foo: 'bar' }, - {}, - { - anchor: false, - publish: false, - }, - ) - expect(doc.content).toEqual({ foo: 'bar' }) - await doc.update({ foo: 'boo' }) - expect(doc.content).toEqual({ foo: 'boo' }) - }) + test('Properly removes persisted sessions', async () => { + await DIDSession.get(account, authMethod, { + resources: testResources, + }) + + expect(await DIDSession.hasSessionFor(account, testResources)).toBeTruthy() - test('get and create/update streams from persisted session', async () => { - const authMock = jest.fn(authMethod) - const resources = [`ceramic://*`] - expect(await DIDSession.hasSessionFor(account, resources)).toBeFalsy() + await DIDSession.remove(account) - await DIDSession.get(account, authMock, { - resources, + expect(await DIDSession.hasSessionFor(account, testResources)).toBeFalsy() }) - // auth was used - expect(authMock).toHaveBeenCalledTimes(1) - expect(await DIDSession.hasSessionFor(account, resources)).toBeTruthy() - const session = await DIDSession.get(account, authMethod, { - resources, + test('isAuthorized/isExpired, with valid session and resources', async () => { + const session = await DIDSession.get(account, authMethod, { + resources: testResources, + }) + // Any session authorized and valid, true + expect(session.isAuthorized()).toBe(true) + expect(session.isExpired).toBe(false) + // Authorized for given resources, true + expect(session.isAuthorized(testResources)).toBe(true) + // Authorized for wildcard resource, false + expect(session.isAuthorized([`ceramic://*`])).toBe(false) }) - // indicates that we loaded auth from session storage - expect(authMock).toHaveBeenCalledTimes(1) - ceramic.did = session.did - const doc = await TileDocument.create( - ceramic, - { foo: 'bar' }, - {}, - { - anchor: false, - publish: false, - }, - ) - expect(doc.content).toEqual({ foo: 'bar' }) + test('Creates a new session if persisted one is expired', async () => { + let session = await DIDSession.get(account, authMethod, { + resources: testResources, + expiresInSecs: -1, + }) - await doc.update({ foo: 'boo' }) - expect(doc.content).toEqual({ foo: 'boo' }) - }) + expect(session.isExpired).toBeTruthy() + expect(await DIDSession.hasSessionFor(account, testResources)).toBeFalsy() - test('can create and update model instance stream', async () => { - const session = await DIDSession.authorize(authMethod, { - resources: [`ceramic://*?model=${model.id.toString()}`], - }) - ceramic.did = session.did + session = await DIDSession.get(account, authMethod, { + resources: testResources, + }) - const doc = await ModelInstanceDocument.create(ceramic, CONTENT0, { - model: model.id, + expect(session.isExpired).toBeFalsy() + expect(await DIDSession.hasSessionFor(account, testResources)).toBeTruthy() }) - expect(doc.content).toEqual(CONTENT0) - expect(doc.metadata.model.toString()).toEqual(model.id.toString()) - - await doc.replace(CONTENT1) - expect(doc.content).toEqual(CONTENT1) - }) + test('pass expiresInSecs option for custom time, override default 1 day', async () => { + const oneWeek = 60 * 60 * 24 * 7 + const session = await DIDSession.get(account, authMethod, { + resources: testResources, + expiresInSecs: oneWeek, + }) + expect(session.expireInSecs > oneWeek - 5 && session.expireInSecs <= oneWeek).toBe(true) + }) - test('isAuthorized/isExpired, with valid session and resources', async () => { - const session = await DIDSession.authorize(authMethod, { - resources: testResources, + test('throws if resources not given', async () => { + await expect(DIDSession.get(account, authMethod, {})).rejects.toThrow(/Required:/) + await expect(DIDSession.get(account, authMethod, { resources: [] })).rejects.toThrow( + /Required:/, + ) }) - // Any session authorized and valid, true - expect(session.isAuthorized()).toBe(true) - expect(session.isExpired).toBe(false) - // Authorized for given resources, true - expect(session.isAuthorized(testResources)).toBe(true) - // Authorized for wildcard resource, false - expect(session.isAuthorized([`ceramic://*`])).toBe(false) }) - test('pass expiresInSecs option for custom time, override default 1 day', async () => { - const oneWeek = 60 * 60 * 24 * 7 - const session = await DIDSession.authorize(authMethod, { - resources: testResources, - expiresInSecs: oneWeek, + describe('DIDSession.authorize', () => { + test('authorize, with streamid resources', async () => { + const streamId = `ceramic://z6MkhZCWzHtPFmpNupVPuHA6svtpKKY9RUpgf9uohnhFMNvj` + const session = await DIDSession.authorize(authMethod, { + resources: [streamId], + }) + const did = session.did + expect(did.capability.p.resources.includes(streamId)).toBe(true) }) - expect(session.expireInSecs > oneWeek - 5 && session.expireInSecs <= oneWeek).toBe(true) - }) - test('throws if resources not given', async () => { - await expect(DIDSession.authorize(authMethod, {})).rejects.toThrow(/Required:/) - await expect(DIDSession.authorize(authMethod, { resources: [] })).rejects.toThrow(/Required:/) - }) + test('authorize and create/update streams', async () => { + const session = await DIDSession.authorize(authMethod, { + resources: [`ceramic://*`], + }) + ceramic.did = session.did + const doc = await TileDocument.create( + ceramic, + { foo: 'bar' }, + {}, + { + anchor: false, + publish: false, + }, + ) + expect(doc.content).toEqual({ foo: 'bar' }) + + await doc.update({ foo: 'boo' }) + expect(doc.content).toEqual({ foo: 'boo' }) + }) - test('isAuthorized/isExpired, with expired session', async () => { - // Expired 5 min ago - const msg = new SiweMessage({ - domain: 'service.org', - address: address, - statement: 'I accept the ServiceOrg Terms of Service: https://service.org/tos', - uri: 'did:key:z6MkrBdNdwUPnXDVD1DCxedzVVBpaGi8aSmoXFAeKNgtAer8', - version: '1', - nonce: '32891757', - issuedAt: '2021-09-30T16:25:24.000Z', - expirationTime: new Date(Date.now() - 1000 * 60 * 5).toISOString(), - chainId: '1', - resources: testResources, + test('authorize and create/update streams from serialized session', async () => { + const session = await DIDSession.authorize(authMethod, { + resources: [`ceramic://*`], + }) + const sessionStr = session.serialize() + const session2 = await DIDSession.fromSession(sessionStr) + ceramic.did = session2.did + const doc = await TileDocument.create( + ceramic, + { foo: 'bar' }, + {}, + { + anchor: false, + publish: false, + }, + ) + expect(doc.content).toEqual({ foo: 'bar' }) + + await doc.update({ foo: 'boo' }) + expect(doc.content).toEqual({ foo: 'boo' }) }) - const signature = await wallet.signMessage(msg.toMessage()) - msg.signature = signature - const cacao = Cacao.fromSiweMessage(msg) + test('can create and update model instance stream', async () => { + const session = await DIDSession.authorize(authMethod, { + resources: [`ceramic://*?model=${model.id.toString()}`], + }) + ceramic.did = session.did - const keySeed = new Uint8Array(bytes32) - const didKey = await createDIDKey(keySeed) - const did = await createDIDCacao(didKey, cacao) + const doc = await ModelInstanceDocument.create(ceramic, CONTENT0, { + model: model.id, + }) - const session = new DIDSession({ cacao, keySeed, did }) - expect(session.isExpired).toBe(true) - expect(session.isAuthorized()).toBe(false) - }) + expect(doc.content).toEqual(CONTENT0) + expect(doc.metadata.model.toString()).toEqual(model.id.toString()) - test('expiresInSecs, when session valid', async () => { - // Expires in 5 mins - const msg = new SiweMessage({ - domain: 'service.org', - address: address, - statement: 'I accept the ServiceOrg Terms of Service: https://service.org/tos', - uri: 'did:key:z6MkrBdNdwUPnXDVD1DCxedzVVBpaGi8aSmoXFAeKNgtAer8', - version: '1', - nonce: '32891757', - issuedAt: '2021-09-30T16:25:24.000Z', - expirationTime: new Date(Date.now() + 1000 * 60 * 5).toISOString(), - chainId: '1', - resources: testResources, + await doc.replace(CONTENT1) + expect(doc.content).toEqual(CONTENT1) }) - const signature = await wallet.signMessage(msg.toMessage()) - msg.signature = signature - const cacao = Cacao.fromSiweMessage(msg) - - const keySeed = new Uint8Array(bytes32) - const didKey = await createDIDKey(keySeed) - const did = await createDIDCacao(didKey, cacao) + test('pass expiresInSecs option for custom time, override default 1 day', async () => { + const oneWeek = 60 * 60 * 24 * 7 + const session = await DIDSession.authorize(authMethod, { + resources: testResources, + expiresInSecs: oneWeek, + }) + expect(session.expireInSecs > oneWeek - 5 && session.expireInSecs <= oneWeek).toBe(true) + }) - const session = new DIDSession({ cacao, keySeed, did }) + test('throws if resources not given', async () => { + await expect(DIDSession.authorize(authMethod, {})).rejects.toThrow(/Required:/) + await expect(DIDSession.authorize(authMethod, { resources: [] })).rejects.toThrow(/Required:/) + }) - // 5 sec buffer - expect(session.expireInSecs).toBeGreaterThan(60 * 5 - 5) - expect(session.expireInSecs).toBeLessThan(60 * 5 + 5) - }) + describe('Manage session state', () => { + test('serializes', async () => { + const msg = new SiweMessage({ + domain: 'service.org', + address: address, + statement: 'I accept the ServiceOrg Terms of Service: https://service.org/tos', + uri: 'did:key:z6MkrBdNdwUPnXDVD1DCxedzVVBpaGi8aSmoXFAeKNgtAer8', + version: '1', + nonce: '32891757', + issuedAt: '2021-09-30T16:25:24.000Z', + chainId: '1', + resources: testResources, + }) + + const signature = await wallet.signMessage(msg.toMessage()) + msg.signature = signature + const cacao = Cacao.fromSiweMessage(msg) + + const keySeed = new Uint8Array(bytes32) + const didKey = await createDIDKey(keySeed) + const did = await createDIDCacao(didKey, cacao) + + const session = new DIDSession({ cacao, keySeed, did }) + const sessionStr = session.serialize() + expect(sessionStr).toMatchSnapshot() + }) - test('expiresInSecs, when session expired', async () => { - // Expired 5 min ago - const msg = new SiweMessage({ - domain: 'service.org', - address: address, - statement: 'I accept the ServiceOrg Terms of Service: https://service.org/tos', - uri: 'did:key:z6MkrBdNdwUPnXDVD1DCxedzVVBpaGi8aSmoXFAeKNgtAer8', - version: '1', - nonce: '32891757', - issuedAt: '2021-09-30T16:25:24.000Z', - expirationTime: new Date(Date.now() - 1000 * 60 * 5).toISOString(), - chainId: '1', - resources: testResources, + test('roundtrip serialization, fromSession', async () => { + const session = await DIDSession.authorize(authMethod, { + resources: [`ceramic://*`], + }) + const sessionStr = session.serialize() + const session2 = await DIDSession.fromSession(sessionStr) + const sessionStr2 = session2.serialize() + expect(sessionStr).toEqual(sessionStr2) + }) }) + }) - const signature = await wallet.signMessage(msg.toMessage()) - msg.signature = signature - const cacao = Cacao.fromSiweMessage(msg) + describe('Expiration properties', () => { + test('isAuthorized/isExpired, with expired session', async () => { + // Expired 5 min ago + const msg = new SiweMessage({ + domain: 'service.org', + address: address, + statement: 'I accept the ServiceOrg Terms of Service: https://service.org/tos', + uri: 'did:key:z6MkrBdNdwUPnXDVD1DCxedzVVBpaGi8aSmoXFAeKNgtAer8', + version: '1', + nonce: '32891757', + issuedAt: '2021-09-30T16:25:24.000Z', + expirationTime: new Date(Date.now() - 1000 * 60 * 5).toISOString(), + chainId: '1', + resources: testResources, + }) - const keySeed = new Uint8Array(bytes32) - const didKey = await createDIDKey(keySeed) - const did = await createDIDCacao(didKey, cacao) + const signature = await wallet.signMessage(msg.toMessage()) + msg.signature = signature + const cacao = Cacao.fromSiweMessage(msg) - const session = new DIDSession({ cacao, keySeed, did }) + const keySeed = new Uint8Array(bytes32) + const didKey = await createDIDKey(keySeed) + const did = await createDIDCacao(didKey, cacao) - expect(session.expireInSecs).toEqual(0) - }) + const session = new DIDSession({ cacao, keySeed, did }) + expect(session.isExpired).toBe(true) + expect(session.isAuthorized()).toBe(false) + }) - describe('Manage session state', () => { - test('serializes', async () => { + test('expiresInSecs, when session valid', async () => { + // Expires in 5 mins const msg = new SiweMessage({ domain: 'service.org', address: address, @@ -350,6 +385,7 @@ describe('did-session', () => { version: '1', nonce: '32891757', issuedAt: '2021-09-30T16:25:24.000Z', + expirationTime: new Date(Date.now() + 1000 * 60 * 5).toISOString(), chainId: '1', resources: testResources, }) @@ -363,18 +399,38 @@ describe('did-session', () => { const did = await createDIDCacao(didKey, cacao) const session = new DIDSession({ cacao, keySeed, did }) - const sessionStr = session.serialize() - expect(sessionStr).toMatchSnapshot() + + // 5 sec buffer + expect(session.expireInSecs).toBeGreaterThan(60 * 5 - 5) + expect(session.expireInSecs).toBeLessThan(60 * 5 + 5) }) - test('roundtrip serialization, fromSession', async () => { - const session = await DIDSession.authorize(authMethod, { - resources: [`ceramic://*`], + test('expiresInSecs, when session expired', async () => { + // Expired 5 min ago + const msg = new SiweMessage({ + domain: 'service.org', + address: address, + statement: 'I accept the ServiceOrg Terms of Service: https://service.org/tos', + uri: 'did:key:z6MkrBdNdwUPnXDVD1DCxedzVVBpaGi8aSmoXFAeKNgtAer8', + version: '1', + nonce: '32891757', + issuedAt: '2021-09-30T16:25:24.000Z', + expirationTime: new Date(Date.now() - 1000 * 60 * 5).toISOString(), + chainId: '1', + resources: testResources, }) - const sessionStr = session.serialize() - const session2 = await DIDSession.fromSession(sessionStr) - const sessionStr2 = session2.serialize() - expect(sessionStr).toEqual(sessionStr2) + + const signature = await wallet.signMessage(msg.toMessage()) + msg.signature = signature + const cacao = Cacao.fromSiweMessage(msg) + + const keySeed = new Uint8Array(bytes32) + const didKey = await createDIDKey(keySeed) + const did = await createDIDCacao(didKey, cacao) + + const session = new DIDSession({ cacao, keySeed, did }) + + expect(session.expireInSecs).toEqual(0) }) }) })