diff --git a/packages/connector/package.json b/packages/connector/package.json index 3af88d4d8..9a2409876 100644 --- a/packages/connector/package.json +++ b/packages/connector/package.json @@ -43,8 +43,10 @@ "dependencies": { "@blockchain-lab-um/masca-types": "*", "@blockchain-lab-um/utils": "*", + "@didtools/pkh-ethereum": "0.0.2", "@metamask/detect-provider": "^2.0.0", - "@veramo/core": "5.2.0" + "@veramo/core": "5.2.0", + "did-session": "2.0.1" }, "devDependencies": { "@ianvs/prettier-plugin-sort-imports": "^4.0.1", diff --git a/packages/connector/src/snap.ts b/packages/connector/src/snap.ts index ef488ae9f..d3aee7bf8 100644 --- a/packages/connector/src/snap.ts +++ b/packages/connector/src/snap.ts @@ -18,7 +18,7 @@ import type { SetCurrentAccountRequestParams, VerifyDataRequestParams, } from '@blockchain-lab-um/masca-types'; -import type { Result } from '@blockchain-lab-um/utils'; +import { ResultObject, type Result } from '@blockchain-lab-um/utils'; import type { DIDResolutionResult, IVerifyResult, @@ -27,6 +27,8 @@ import type { W3CVerifiableCredential, } from '@veramo/core'; +import { validateAndSetCeramicSession } from './utils.js'; + async function sendSnapMethod( request: MascaRPCRequest, snapId: string @@ -51,6 +53,8 @@ export async function queryVCs( this: Masca, params?: QueryVCsRequestParams ): Promise> { + await validateAndSetCeramicSession(this); + return sendSnapMethod( { method: 'queryVCs', params: params ?? {} }, this.snapId @@ -68,6 +72,8 @@ export async function createVP( this: Masca, params: CreateVPRequestParams ): Promise> { + await validateAndSetCeramicSession(this); + return sendSnapMethod( { method: 'createVP', @@ -90,6 +96,8 @@ export async function saveVC( vc: W3CVerifiableCredential, options?: SaveVCOptions ): Promise> { + await validateAndSetCeramicSession(this); + return sendSnapMethod( { method: 'saveVC', @@ -115,6 +123,8 @@ export async function deleteVC( id: string, options?: DeleteVCsOptions ): Promise> { + await validateAndSetCeramicSession(this); + return sendSnapMethod( { method: 'deleteVC', @@ -266,6 +276,8 @@ export async function createVC( this: Masca, params: CreateVCRequestParams ): Promise> { + await validateAndSetCeramicSession(this); + return sendSnapMethod( { method: 'createVC', @@ -346,6 +358,40 @@ export async function sendOIDCAuthorizationResponse( ); } +export async function setCeramicSession( + this: Masca, + serializedSession: string +): Promise> { + return sendSnapMethod( + { + method: 'setCeramicSession', + params: { serializedSession }, + }, + this.snapId + ); +} + +export async function validateStoredCeramicSession( + this: Masca +): Promise> { + return sendSnapMethod( + { + method: 'validateStoredCeramicSession', + }, + this.snapId + ); +} + +const wrapper = + (fn: (...args: T) => Promise>) => + async (...args: T): Promise> => { + try { + return await fn(...args); + } catch (e) { + return ResultObject.error((e as Error).toString()); + } + }; + export class Masca { protected readonly snapId: string; @@ -360,26 +406,34 @@ export class Masca { } public getMascaApi = (): MascaApi => ({ - saveVC: saveVC.bind(this), - queryVCs: queryVCs.bind(this), - createVP: createVP.bind(this), - togglePopups: togglePopups.bind(this), - getDID: getDID.bind(this), - getSelectedMethod: getSelectedMethod.bind(this), - getAvailableMethods: getAvailableMethods.bind(this), - switchDIDMethod: switchDIDMethod.bind(this), - getVCStore: getVCStore.bind(this), - setVCStore: setVCStore.bind(this), - getAvailableVCStores: getAvailableVCStores.bind(this), - deleteVC: deleteVC.bind(this), - getSnapSettings: getSnapSettings.bind(this), - getAccountSettings: getAccountSettings.bind(this), - resolveDID: resolveDID.bind(this), - createVC: createVC.bind(this), - setCurrentAccount: setCurrentAccount.bind(this), - verifyData: verifyData.bind(this), - handleOIDCCredentialOffer: handleOIDCCredentialOffer.bind(this), - handleOIDCAuthorizationRequest: handleOIDCAuthorizationRequest.bind(this), - sendOIDCAuthorizationResponse: sendOIDCAuthorizationResponse.bind(this), + saveVC: wrapper(saveVC.bind(this)), + queryVCs: wrapper(queryVCs.bind(this)), + createVP: wrapper(createVP.bind(this)), + togglePopups: wrapper(togglePopups.bind(this)), + getDID: wrapper(getDID.bind(this)), + getSelectedMethod: wrapper(getSelectedMethod.bind(this)), + getAvailableMethods: wrapper(getAvailableMethods.bind(this)), + switchDIDMethod: wrapper(switchDIDMethod.bind(this)), + getVCStore: wrapper(getVCStore.bind(this)), + setVCStore: wrapper(setVCStore.bind(this)), + getAvailableVCStores: wrapper(getAvailableVCStores.bind(this)), + deleteVC: wrapper(deleteVC.bind(this)), + getSnapSettings: wrapper(getSnapSettings.bind(this)), + getAccountSettings: wrapper(getAccountSettings.bind(this)), + resolveDID: wrapper(resolveDID.bind(this)), + createVC: wrapper(createVC.bind(this)), + setCurrentAccount: wrapper(setCurrentAccount.bind(this)), + verifyData: wrapper(verifyData.bind(this)), + handleOIDCCredentialOffer: wrapper(handleOIDCCredentialOffer.bind(this)), + handleOIDCAuthorizationRequest: wrapper( + handleOIDCAuthorizationRequest.bind(this) + ), + sendOIDCAuthorizationResponse: wrapper( + sendOIDCAuthorizationResponse.bind(this) + ), + setCeramicSession: wrapper(setCeramicSession.bind(this)), + validateStoredCeramicSession: wrapper( + validateStoredCeramicSession.bind(this) + ), }); } diff --git a/packages/connector/src/utils.ts b/packages/connector/src/utils.ts new file mode 100644 index 000000000..259656e80 --- /dev/null +++ b/packages/connector/src/utils.ts @@ -0,0 +1,53 @@ +import { isError } from '@blockchain-lab-um/utils'; +import { EthereumWebAuth, getAccountId } from '@didtools/pkh-ethereum'; +import { DIDSession } from 'did-session'; + +import { Masca } from './snap.js'; + +export async function validateAndSetCeramicSession( + masca: Masca +): Promise { + // Check if there is valid session in Masca + const api = masca.getMascaApi(); + + const enabledVCStoresResult = await api.getVCStore(); + if (isError(enabledVCStoresResult)) { + throw new Error('Failed to get enabled VC stores.'); + } + + // Check if ceramic is enabled + if (enabledVCStoresResult.data.ceramic === false) { + return; + } + + const session = await api.validateStoredCeramicSession(); + if (!isError(session)) { + return; + } + + const addresses: string[] = await window.ethereum.request({ + method: 'eth_requestAccounts', + }); + + const accountId = await getAccountId(window.ethereum, addresses[0]); + + const authMethod = await EthereumWebAuth.getAuthMethod( + window.ethereum, + accountId + ); + + let newSession; + try { + newSession = await DIDSession.authorize(authMethod, { + expiresInSecs: 60 * 60 * 24, + resources: [`ceramic://*`], + }); + } catch (e) { + throw new Error('User failed to sign session.'); + } + const serializedSession = newSession.serialize(); + const result = await api.setCeramicSession(serializedSession); + if (isError(result)) { + throw new Error('Failed to set session in Masca.'); + } +} diff --git a/packages/snap/snap.manifest.json b/packages/snap/snap.manifest.json index 5f8199be4..f354b10a5 100644 --- a/packages/snap/snap.manifest.json +++ b/packages/snap/snap.manifest.json @@ -7,7 +7,7 @@ "url": "https://github.com/blockchain-lab-um/masca.git" }, "source": { - "shasum": "kpxsf6Amegq82TeSNWiMdndc9CS6n6FMuKKG6mGPGAg=", + "shasum": "O1UXSOxy+oi/+u0TyrzxY8rHpZ+9hrK+QfSdATkhV60=", "location": { "npm": { "filePath": "dist/snap.js", diff --git a/packages/snap/src/index.ts b/packages/snap/src/index.ts index 61b601987..632bf299f 100644 --- a/packages/snap/src/index.ts +++ b/packages/snap/src/index.ts @@ -14,8 +14,10 @@ import { switchMethod } from './rpc/did/switchMethod'; import { handleOIDCAuthorizationRequest } from './rpc/oidc/handleOIDCAuthorizationRequest'; import { handleOIDCCredentialOffer } from './rpc/oidc/handleOIDCCredentialOffer'; import { sendOIDCAuthorizationResponse } from './rpc/oidc/sendOIDCAuthorizationResponse'; +import { setCeramicSession } from './rpc/setCeramicSession'; import { togglePopups } from './rpc/snap/configure'; import { setCurrentAccount } from './rpc/snap/setCurrentAccount'; +import { validateStoredCeramicSession } from './rpc/validateStoredCeramicSession'; import { createVC } from './rpc/vc/createVC'; import { createVP } from './rpc/vc/createVP'; import { deleteVC } from './rpc/vc/deleteVC'; @@ -186,6 +188,16 @@ export const onRpcRequest: OnRpcRequestHandler = async ({ request.params as unknown as SendOIDCAuthorizationResponseParams ); return ResultObject.success(res); + case 'setCeramicSession': + // TODO (andy) validate request params + res = await setCeramicSession( + apiParams, + (request.params as any).serializedSession as string + ); + return ResultObject.success(res); + case 'validateStoredCeramicSession': + await validateStoredCeramicSession(apiParams); + return ResultObject.success(true); default: throw new Error('Method not found.'); } diff --git a/packages/snap/src/interfaces.ts b/packages/snap/src/interfaces.ts index c3b0a78eb..48497009d 100644 --- a/packages/snap/src/interfaces.ts +++ b/packages/snap/src/interfaces.ts @@ -1,67 +1,7 @@ -import type { - MascaAccountConfig, - MascaConfig, -} from '@blockchain-lab-um/masca-types'; +import { MascaState } from '@blockchain-lab-um/masca-types'; import { BIP44CoinTypeNode } from '@metamask/key-tree'; import { MetaMaskInpageProvider } from '@metamask/providers'; import type { SnapsGlobalObject } from '@metamask/snaps-types'; -import type { IIdentifier, IKey, W3CVerifiableCredential } from '@veramo/core'; -import type { ManagedPrivateKey } from '@veramo/key-manager'; - -export type MascaState = { - /** - * Account specific storage - */ - accountState: Record; - /** - * Current account - */ - currentAccount: string; - /** - * Configuration for Masca - */ - snapConfig: MascaConfig; -}; - -export type ExtendedVerifiableCredential = W3CVerifiableCredential & { - /** - * key for dictionary - */ - key: string; -}; - -/** - * Ceramic Network storedVCs - */ -export type StoredCredentials = { - storedCredentials: ExtendedVerifiableCredential[]; -}; - -/** - * Masca State for a MetaMask address - */ -export type MascaAccountState = { - /** - * Store for {@link SnapPrivateKeyStore} - */ - snapPrivateKeyStore: Record; - /** - * Store for {@link SnapKeyStore} - */ - snapKeyStore: Record; - /** - * Store for {@link SnapDIDStore} - */ - identifiers: Record; - /** - * Store for {@link SnapVCStore} - */ - vcs: Record; - - publicKey: string; - index?: number; - accountConfig: MascaAccountConfig; -}; export type SnapConfirmParams = { prompt: string; diff --git a/packages/snap/src/rpc/setCeramicSession.ts b/packages/snap/src/rpc/setCeramicSession.ts new file mode 100644 index 000000000..c3ecf65bb --- /dev/null +++ b/packages/snap/src/rpc/setCeramicSession.ts @@ -0,0 +1,12 @@ +import { ApiParams } from '../interfaces'; +import { updateSnapState } from '../utils/stateUtils'; + +export async function setCeramicSession( + params: ApiParams, + serializedSession: string +): Promise { + const { state } = params; + state.accountState[state.currentAccount].ceramicSession = serializedSession; + await updateSnapState(snap, state); + return true; +} diff --git a/packages/snap/src/rpc/validateStoredCeramicSession.ts b/packages/snap/src/rpc/validateStoredCeramicSession.ts new file mode 100644 index 000000000..7819a904d --- /dev/null +++ b/packages/snap/src/rpc/validateStoredCeramicSession.ts @@ -0,0 +1,12 @@ +import { ApiParams } from '../interfaces'; +import { validateSession } from '../utils/ceramicUtils'; + +export async function validateStoredCeramicSession( + params: ApiParams +): Promise { + const { state } = params; + const serializedSession = await validateSession( + state.accountState[state.currentAccount].ceramicSession + ); + return serializedSession; +} diff --git a/packages/snap/src/utils/ceramicUtils.ts b/packages/snap/src/utils/ceramicUtils.ts index f1d18be00..92d496936 100644 --- a/packages/snap/src/utils/ceramicUtils.ts +++ b/packages/snap/src/utils/ceramicUtils.ts @@ -1,16 +1,8 @@ +import type { MascaState } from '@blockchain-lab-um/masca-types'; import { CeramicClient } from '@ceramicnetwork/http-client'; -import { EthereumNodeAuth, getAccountId } from '@didtools/pkh-ethereum'; import { MetaMaskInpageProvider } from '@metamask/providers'; import type { SnapsGlobalObject } from '@metamask/snaps-types'; import { DIDSession } from 'did-session'; -import { DID } from 'dids'; -import { Wallet } from 'ethers'; -import type { MascaState } from 'src/interfaces'; - -import { getAddressKeyDeriver, snapGetKeysFromAddress } from './keyPair'; -import { getCurrentAccount } from './snapUtils'; - -const ceramicDID = { did: undefined } as { did: DID | undefined }; export const aliases = { definitions: { @@ -24,78 +16,32 @@ export const aliases = { tiles: {}, }; -class CustomProvider { - constructor( - private readonly wallet: Wallet, - private readonly metamask: MetaMaskInpageProvider - ) { - this.wallet = wallet; - this.metamask = metamask; +// Should return serialized session or throw an error +export async function validateSession( + serializedSession?: string +): Promise { + if (!serializedSession) { + throw new Error('No session found'); } - async request(args: { method: string; params: Array }) { - const { method, params } = args; - - if (method === 'personal_sign') { - // First parameter is the message to sign, second parameter is the address - const [message] = params; - return this.wallet.signMessage(message); - } + const session = await DIDSession.fromSession(serializedSession); - if (method === 'eth_chainId') { - return this.metamask.request(args); - } - - throw new Error('Unsupported method'); + if (session.isExpired) { + throw new Error('Session expired'); } -} -async function authenticateWithEthers(params: { - ethereum: MetaMaskInpageProvider; - snap: SnapsGlobalObject; - state: MascaState; -}) { - if (ceramicDID.did) return ceramicDID.did; - - const { ethereum, snap, state } = params; - - const account = getCurrentAccount(state); - - const bip44CoinTypeNode = await getAddressKeyDeriver({ - state, - snap, - account, - }); - - const res = await snapGetKeysFromAddress( - bip44CoinTypeNode, - state, - account, - snap - ); - - if (res === null) throw new Error('Could not get keys from address'); - - const { privateKey } = res; - - // Ethers is required to sign the DID auth message - const wallet = new Wallet(privateKey); - - const customProvider = new CustomProvider(wallet, ethereum); + if (session.expireInSecs < 3600) { + throw new Error('Session will expire soon'); + } - const accountId = await getAccountId(customProvider, wallet.address); + return serializedSession; +} - const authMethod = await EthereumNodeAuth.getAuthMethod( - customProvider, - accountId, - 'masca' +async function authenticateWithSessionKey(state: MascaState) { + const serializedSession = await validateSession( + state.accountState[state.currentAccount].ceramicSession ); - - const session = await DIDSession.authorize(authMethod, { - resources: [`ceramic://*`], - }); - - ceramicDID.did = session.did; + const session = await DIDSession.fromSession(serializedSession); return session.did; } @@ -105,8 +51,7 @@ export async function getCeramic( state: MascaState ): Promise { const ceramic = new CeramicClient('https://ceramic-clay.3boxlabs.com'); - - const did = await authenticateWithEthers({ ethereum, snap, state }); + const did = await authenticateWithSessionKey(state); await ceramic.setDID(did); return ceramic; diff --git a/packages/snap/src/utils/config.ts b/packages/snap/src/utils/config.ts index 1476e42f9..c52b5d58e 100644 --- a/packages/snap/src/utils/config.ts +++ b/packages/snap/src/utils/config.ts @@ -1,11 +1,11 @@ import type { MascaAccountConfig, + MascaAccountState, MascaConfig, + MascaState, } from '@blockchain-lab-um/masca-types'; import cloneDeep from 'lodash.clonedeep'; -import type { MascaAccountState, MascaState } from '../interfaces'; - const emptyAccountState = { snapKeyStore: {}, snapPrivateKeyStore: {}, @@ -20,7 +20,6 @@ const emptyAccountState = { ceramic: true, }, }, - ceramic: {}, } as MascaAccountConfig, } as MascaAccountState; diff --git a/packages/snap/src/utils/didUtils.ts b/packages/snap/src/utils/didUtils.ts index d79151c58..a1c277f96 100644 --- a/packages/snap/src/utils/didUtils.ts +++ b/packages/snap/src/utils/didUtils.ts @@ -1,6 +1,7 @@ import type { AvailableMethods, AvailableVCStores, + MascaState, } from '@blockchain-lab-um/masca-types'; import { BIP44CoinTypeNode } from '@metamask/key-tree'; import { MetaMaskInpageProvider } from '@metamask/providers'; @@ -9,7 +10,6 @@ import type { IIdentifier } from '@veramo/core'; import type { DIDResolutionResult } from 'did-resolver'; import elliptic from 'elliptic'; -import type { MascaState } from '../interfaces'; import { getAgent } from '../veramo/setup'; import { snapGetKeysFromAddress } from './keyPair'; import { getCurrentNetwork } from './snapUtils'; diff --git a/packages/snap/src/utils/ebsiUtils.ts b/packages/snap/src/utils/ebsiUtils.ts index 35378f84d..779f5dbf2 100644 --- a/packages/snap/src/utils/ebsiUtils.ts +++ b/packages/snap/src/utils/ebsiUtils.ts @@ -1,8 +1,8 @@ +import type { MascaState } from '@blockchain-lab-um/masca-types'; import type { SnapsGlobalObject } from '@metamask/snaps-types'; import type { IDIDManagerCreateArgs } from '@veramo/core'; import { keccak256 } from 'ethers'; -import type { MascaState } from '../interfaces'; import { getAgent } from '../veramo/setup'; import { getAddressKeyDeriver, snapGetKeysFromAddress } from './keyPair'; diff --git a/packages/snap/src/utils/init.ts b/packages/snap/src/utils/init.ts index 1fc2eb870..49414569e 100644 --- a/packages/snap/src/utils/init.ts +++ b/packages/snap/src/utils/init.ts @@ -1,6 +1,6 @@ +import type { MascaState } from '@blockchain-lab-um/masca-types'; import type { SnapsGlobalObject } from '@metamask/snaps-types'; -import type { MascaState } from '../interfaces'; import { initSnapState } from './stateUtils'; export async function init(snap: SnapsGlobalObject): Promise { diff --git a/packages/snap/src/utils/keyPair.ts b/packages/snap/src/utils/keyPair.ts index 4ee84e9b9..12a549db5 100644 --- a/packages/snap/src/utils/keyPair.ts +++ b/packages/snap/src/utils/keyPair.ts @@ -1,4 +1,7 @@ -import { didCoinTypeMappping } from '@blockchain-lab-um/masca-types'; +import { + didCoinTypeMappping, + type MascaState, +} from '@blockchain-lab-um/masca-types'; import { BIP44CoinTypeNode, getBIP44AddressKeyDeriver, @@ -6,7 +9,6 @@ import { import type { SnapsGlobalObject } from '@metamask/snaps-types'; import { Wallet } from 'ethers'; -import type { MascaState } from '../interfaces'; import { updateSnapState } from './stateUtils'; export async function setAccountIndex( diff --git a/packages/snap/src/utils/params.ts b/packages/snap/src/utils/params.ts index 36ef819fd..d5df58412 100644 --- a/packages/snap/src/utils/params.ts +++ b/packages/snap/src/utils/params.ts @@ -6,6 +6,7 @@ import { type CreateVCRequestParams, type CreateVPRequestParams, type DeleteVCsRequestParams, + type MascaState, type QueryVCsRequestParams, type ResolveDIDRequestParams, type SaveVCRequestParams, @@ -15,7 +16,6 @@ import { type VerifyDataRequestParams, } from '@blockchain-lab-um/masca-types'; -import type { MascaState } from '../interfaces'; import { isEnabledVCStore } from './snapUtils'; function isStringArray(input: unknown): input is string[] { diff --git a/packages/snap/src/utils/snapUtils.ts b/packages/snap/src/utils/snapUtils.ts index e5ff26ba3..3b9e50225 100644 --- a/packages/snap/src/utils/snapUtils.ts +++ b/packages/snap/src/utils/snapUtils.ts @@ -1,10 +1,13 @@ -import type { AvailableVCStores } from '@blockchain-lab-um/masca-types'; +import type { + AvailableVCStores, + MascaState, +} from '@blockchain-lab-um/masca-types'; import { BIP44CoinTypeNode } from '@metamask/key-tree'; import { MetaMaskInpageProvider } from '@metamask/providers'; import type { SnapsGlobalObject } from '@metamask/snaps-types'; import type { Component } from '@metamask/snaps-ui'; -import type { ApiParams, MascaState } from '../interfaces'; +import type { ApiParams } from '../interfaces'; import { snapGetKeysFromAddress } from './keyPair'; import { updateSnapState } from './stateUtils'; diff --git a/packages/snap/src/utils/stateUtils.ts b/packages/snap/src/utils/stateUtils.ts index 44970ae90..31e68f91f 100644 --- a/packages/snap/src/utils/stateUtils.ts +++ b/packages/snap/src/utils/stateUtils.ts @@ -1,6 +1,7 @@ +import type { MascaState } from '@blockchain-lab-um/masca-types'; import type { Json, SnapsGlobalObject } from '@metamask/snaps-types'; -import type { ApiParams, MascaState } from '../interfaces'; +import type { ApiParams } from '../interfaces'; import { getEmptyAccountState, getInitialSnapState } from './config'; /** diff --git a/packages/snap/src/utils/veramoUtils.ts b/packages/snap/src/utils/veramoUtils.ts index d650ae69b..51480b4ab 100644 --- a/packages/snap/src/utils/veramoUtils.ts +++ b/packages/snap/src/utils/veramoUtils.ts @@ -2,6 +2,7 @@ import type { AvailableVCStores, CreateVCRequestParams, CreateVPRequestParams, + MascaState, QueryVCsOptions, QueryVCsRequestResult, SaveVCRequestResult, @@ -23,7 +24,7 @@ import type { W3CVerifiableCredential, } from '@veramo/core'; -import type { ApiParams, MascaState } from '../interfaces'; +import type { ApiParams } from '../interfaces'; import { getAgent, type Agent } from '../veramo/setup'; import { getCurrentDid } from './didUtils'; import { snapGetKeysFromAddress } from './keyPair'; diff --git a/packages/snap/tests/rpc/onRpcRequest.spec.ts b/packages/snap/tests/rpc/onRpcRequest.spec.ts index 1936e5464..54e54bfce 100644 --- a/packages/snap/tests/rpc/onRpcRequest.spec.ts +++ b/packages/snap/tests/rpc/onRpcRequest.spec.ts @@ -16,8 +16,8 @@ import type { } from '@veramo/core'; import { onRpcRequest } from '../../src'; -import type { StoredCredentials } from '../../src/interfaces'; import { veramoClearVCs } from '../../src/utils/veramoUtils'; +import type { StoredCredentials } from '../../src/veramo/plugins/ceramicDataStore/ceramicDataStore'; import { getAgent, type Agent } from '../../src/veramo/setup'; import { address, diff --git a/packages/snap/tests/testUtils/constants.ts b/packages/snap/tests/testUtils/constants.ts index 83c46a0b9..0c84a3b59 100644 --- a/packages/snap/tests/testUtils/constants.ts +++ b/packages/snap/tests/testUtils/constants.ts @@ -1,3 +1,4 @@ +import { MascaState } from '@blockchain-lab-um/masca-types'; import type { JsonBIP44CoinTypeNode } from '@metamask/key-tree'; import { heading, panel, text } from '@metamask/snaps-ui'; import type { @@ -8,7 +9,7 @@ import type { W3CVerifiableCredential, } from '@veramo/core'; -import type { MascaState, SnapConfirmParams } from '../../src/interfaces'; +import type { SnapConfirmParams } from '../../src/interfaces'; import { getEmptyAccountState } from '../../src/utils/config'; export const mnemonic = @@ -468,6 +469,9 @@ const defaultSnapState: MascaState = { export const getDefaultSnapState = (): MascaState => { defaultSnapState.accountState[address].publicKey = publicKey; + // Session is valid for two years from 15/06/2023 + defaultSnapState.accountState[address].ceramicSession = + 'eyJzZXNzaW9uS2V5U2VlZCI6IlJCcGVUK3poMmFpQ2xOTVBZYXllYUFSSVBhVkZUZ1pZVHU4M3I0dHBpR1U9IiwiY2FjYW8iOnsiaCI6eyJ0IjoiZWlwNDM2MSJ9LCJwIjp7ImRvbWFpbiI6Ik15Tm9kZUFwcCIsImlhdCI6IjIwMjMtMDYtMTVUMTI6Mjc6NTguNzgyWiIsImlzcyI6ImRpZDpwa2g6ZWlwMTU1OjE6MHhiNjY2NTEyOGVlOTFkODQ1OTBmNzBjMzI2ODc2NTM4NGE5Y2FmYmNkIiwiYXVkIjoiZGlkOmtleTp6Nk1rd1V6aW5FU2lGdWo2dlR1bk1kbVYyTWtvbm1ud3lkdlE4Rjlwc0xzQ0xyUW8iLCJ2ZXJzaW9uIjoiMSIsIm5vbmNlIjoiSnFKTTNZcFc5ayIsImV4cCI6IjIwMjUtMDYtMTRUMTI6Mjc6NTguNzgyWiIsInN0YXRlbWVudCI6IkdpdmUgdGhpcyBhcHBsaWNhdGlvbiBhY2Nlc3MgdG8gc29tZSBvZiB5b3VyIGRhdGEgb24gQ2VyYW1pYyIsInJlc291cmNlcyI6WyJjZXJhbWljOi8vKj9tb2RlbD1ranpsNmh2ZnJidzZjNmlkYWFjdzVkNGdjNDgxZW5wYmV1djRmYXQ2NmdqcTFrazlpdnRhbmFkc2UwNzQ2ZGwiXX0sInMiOnsidCI6ImVpcDE5MSIsInMiOiIweGNmZjk0YjgyZmVlODZmZmM0Zjg0ZjYxODFmMDRkNGY2NGY5ZmVmZTAyODgyNzg4Mzc1M2ZhNWFiYThiM2VkYWQ3NzdhZThjMGY3ZTQ0MTIzMzM2ZmQzNjIwNjA5MWE0NmM0MDYxZTQzZGY4OGVhYzdmZWI2ZTE2M2Y5Yzc2OWI3MWMifX19'; return structuredClone(defaultSnapState); }; diff --git a/packages/snap/tests/testUtils/snap.mock.ts b/packages/snap/tests/testUtils/snap.mock.ts index 0d7743608..b6a345c8a 100644 --- a/packages/snap/tests/testUtils/snap.mock.ts +++ b/packages/snap/tests/testUtils/snap.mock.ts @@ -1,3 +1,4 @@ +import type { MascaState } from '@blockchain-lab-um/masca-types'; import { BIP44CoinTypeNode } from '@metamask/key-tree'; import type { RequestArguments } from '@metamask/providers/dist/BaseProvider'; import type { Maybe } from '@metamask/providers/dist/utils'; @@ -9,7 +10,6 @@ import { type TransactionRequest, } from 'ethers'; -import type { MascaState } from '../../src/interfaces'; import { address, mnemonic, privateKey } from './constants'; interface ISnapMock { diff --git a/packages/snap/tests/utils/veramoUtils.spec.ts b/packages/snap/tests/utils/veramoUtils.spec.ts index 8e7932a87..a1af43375 100644 --- a/packages/snap/tests/utils/veramoUtils.spec.ts +++ b/packages/snap/tests/utils/veramoUtils.spec.ts @@ -5,7 +5,6 @@ import { MetaMaskInpageProvider } from '@metamask/providers'; import type { SnapsGlobalObject } from '@metamask/snaps-types'; import type { IIdentifier } from '@veramo/core'; -import type { StoredCredentials } from '../../src/interfaces'; import * as snapUtils from '../../src/utils/snapUtils'; import { veramoClearVCs, @@ -16,6 +15,7 @@ import { veramoSaveVC, veramoVerifyData, } from '../../src/utils/veramoUtils'; +import type { StoredCredentials } from '../../src/veramo/plugins/ceramicDataStore/ceramicDataStore'; import { getAgent } from '../../src/veramo/setup'; import { address, diff --git a/packages/types/src/api.ts b/packages/types/src/api.ts index a371be74c..6167ea5a1 100644 --- a/packages/types/src/api.ts +++ b/packages/types/src/api.ts @@ -21,7 +21,7 @@ import type { VerifyDataRequestParams, } from './params.js'; import type { QueryVCsRequestResult, SaveVCRequestResult } from './results.js'; -import type { MascaAccountConfig, MascaConfig } from './snapInterfaces.js'; +import type { MascaAccountConfig, MascaConfig } from './state.js'; export interface MascaApi { queryVCs( @@ -67,4 +67,6 @@ export interface MascaApi { sendOIDCAuthorizationResponse( params: SendOIDCAuthorizationResponseParams ): Promise>; + setCeramicSession(serializedSession: string): Promise>; + validateStoredCeramicSession(): Promise>; } diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 1bc744180..a31a6a340 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -4,4 +4,4 @@ export * from './api.js'; export * from './constants.js'; export * from './params.js'; export * from './results.js'; -export * from './snapInterfaces.js'; +export * from './state.js'; diff --git a/packages/types/src/methods.ts b/packages/types/src/methods.ts index d8c665fb2..bf9c4fb17 100644 --- a/packages/types/src/methods.ts +++ b/packages/types/src/methods.ts @@ -8,6 +8,7 @@ import type { ResolveDIDRequestParams, SaveVCRequestParams, SendOIDCAuthorizationResponseParams, + SetCeramicSessionRequestParams, SetCurrentAccountRequestParams, SetVCStoreRequestParams, SwitchMethodRequestParams, @@ -110,3 +111,12 @@ export type SendOIDCAuthorizationResponse = { method: 'sendOIDCAuthorizationResponse'; params: SendOIDCAuthorizationResponseParams; }; + +export type SetCeramicSession = { + method: 'setCeramicSession'; + params: SetCeramicSessionRequestParams; +}; + +export type ValidateStoredCeramicSession = { + method: 'validateStoredCeramicSession'; +}; diff --git a/packages/types/src/params.ts b/packages/types/src/params.ts index af9cf4d1f..a66965369 100644 --- a/packages/types/src/params.ts +++ b/packages/types/src/params.ts @@ -150,3 +150,7 @@ export type SendOIDCAuthorizationResponseParams = { authorizationRequestURI: string; credentials: VerifiableCredential[]; }; + +export type SetCeramicSessionRequestParams = { + serializedSession: string; +}; diff --git a/packages/types/src/requests.ts b/packages/types/src/requests.ts index 7f02d25cf..de161ca77 100644 --- a/packages/types/src/requests.ts +++ b/packages/types/src/requests.ts @@ -15,10 +15,12 @@ import type { ResolveDID, SaveVC, SendOIDCAuthorizationResponse, + SetCeramicSession, SetCurrentAccount, SetVCStore, SwitchMethod, TogglePopups, + ValidateStoredCeramicSession, VerifyData, } from './methods.js'; @@ -43,7 +45,9 @@ export type MascaRPCRequest = | VerifyData | HandleOIDCCredentialOffer | HandleOIDCAuthorizationRequest - | SendOIDCAuthorizationResponse; + | SendOIDCAuthorizationResponse + | SetCeramicSession + | ValidateStoredCeramicSession; export type Method = MascaRPCRequest['method']; diff --git a/packages/types/src/snapInterfaces.ts b/packages/types/src/snapInterfaces.ts index 6b98900aa..452184d01 100644 --- a/packages/types/src/snapInterfaces.ts +++ b/packages/types/src/snapInterfaces.ts @@ -59,4 +59,5 @@ export type MascaAccountState = { publicKey: string; index?: number; accountConfig: MascaAccountConfig; + ceramicSession?: string; }; diff --git a/packages/types/src/state.ts b/packages/types/src/state.ts new file mode 100644 index 000000000..452184d01 --- /dev/null +++ b/packages/types/src/state.ts @@ -0,0 +1,63 @@ +import type { IIdentifier, IKey, W3CVerifiableCredential } from '@veramo/core'; +import type { ManagedPrivateKey } from '@veramo/key-manager'; + +import type { AvailableMethods, AvailableVCStores } from './constants.js'; + +export type MascaConfig = { + snap: { + acceptedTerms: boolean; + }; + dApp: { + disablePopups: boolean; + friendlyDapps: string[]; + }; +}; + +export type MascaAccountConfig = { + ssi: { + didMethod: AvailableMethods; + vcStore: Record; + }; +}; + +export type MascaState = { + /** + * Account specific storage + */ + accountState: Record; + /** + * Current account + */ + currentAccount: string; + /** + * Configuration for Masca + */ + snapConfig: MascaConfig; +}; + +/** + * Masca State for a MetaMask address + */ +export type MascaAccountState = { + /** + * Store for {@link SnapPrivateKeyStore} + */ + snapPrivateKeyStore: Record; + /** + * Store for {@link SnapKeyStore} + */ + snapKeyStore: Record; + /** + * Store for {@link SnapDIDStore} + */ + identifiers: Record; + /** + * Store for {@link SnapVCStore} + */ + vcs: Record; + + publicKey: string; + index?: number; + accountConfig: MascaAccountConfig; + ceramicSession?: string; +}; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 51944f3b6..780e0ee38 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1083,12 +1083,18 @@ importers: '@blockchain-lab-um/utils': specifier: '*' version: link:../../libs/utils + '@didtools/pkh-ethereum': + specifier: 0.0.2 + version: 0.0.2 '@metamask/detect-provider': specifier: ^2.0.0 version: 2.0.0 '@veramo/core': specifier: 5.2.0 version: 5.2.0 + did-session: + specifier: 2.0.1 + version: 2.0.1 devDependencies: '@ianvs/prettier-plugin-sort-imports': specifier: ^4.0.1 @@ -14050,7 +14056,7 @@ packages: resolution: {integrity: sha512-rpwfAcS/CMqo0oCqDf3r9eeLgScRE3l/xHDCXhM3UyrfvIn7PrLq63uHh7yYbv8NzaZn5MVsVhIRpQ+5GZ5HyA==} engines: {node: '>=8'} dependencies: - '@noble/hashes': 1.1.5 + '@noble/hashes': 1.3.1 base-x: 4.0.0 dev: false