Skip to content

Commit

Permalink
feat(did-session): session removal support (#187)
Browse files Browse the repository at this point in the history
  • Loading branch information
oed authored Feb 13, 2024
1 parent 84ca798 commit e70a774
Show file tree
Hide file tree
Showing 4 changed files with 281 additions and 193 deletions.
35 changes: 29 additions & 6 deletions packages/did-session/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,11 @@ export function cacaoContainsResources(cacao: Cacao, resources: Array<string>):
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
*
Expand Down Expand Up @@ -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()
Expand All @@ -275,20 +285,35 @@ 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 })
store.close()
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<void> {
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<string>): Promise<boolean> {
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)
}

/**
Expand Down Expand Up @@ -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)
}

/**
Expand Down
9 changes: 9 additions & 0 deletions packages/did-session/src/sessionStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ export class SessionStore {
})
}

async remove(accountId: AccountId): Promise<void> {
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()
}
Expand Down
2 changes: 1 addition & 1 deletion packages/did-session/test/__snapshots__/lib.test.ts.snap
Original file line number Diff line number Diff line change
@@ -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"`;
Loading

0 comments on commit e70a774

Please sign in to comment.