-
Notifications
You must be signed in to change notification settings - Fork 15
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'origin/main' into feat/auth-code-flow
- Loading branch information
Showing
13 changed files
with
303 additions
and
65 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
EXPO_PUBLIC_WALLET_SERVICE_PROVIDER_URL= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,32 @@ | ||
import { setFallbackSecureEnvironment } from '@animo-id/expo-secure-environment' | ||
import { trustedX509Certificates } from '@easypid/constants' | ||
import { WalletServiceProviderClient } from '@easypid/crypto/WalletServiceProviderClient' | ||
import { initializeEasyPIDAgent } from '@package/agent' | ||
|
||
export function initializeAppAgent({ walletKey, walletKeyVersion }: { walletKey: string; walletKeyVersion: number }) { | ||
return initializeEasyPIDAgent({ | ||
export async function initializeAppAgent({ | ||
walletKey, | ||
walletKeyVersion, | ||
registerWallet, | ||
}: { walletKey: string; walletKeyVersion: number; registerWallet?: boolean }) { | ||
const agent = await initializeEasyPIDAgent({ | ||
keyDerivation: 'raw', | ||
walletId: `easypid-wallet-${walletKeyVersion}`, | ||
walletKey, | ||
walletLabel: 'EasyPID Wallet', | ||
trustedX509Certificates, | ||
}) | ||
|
||
/** | ||
* | ||
* Setup specific for the Wallet Service provider | ||
* | ||
*/ | ||
const wsp = new WalletServiceProviderClient(process.env.EXPO_PUBLIC_WALLET_SERVICE_PROVIDER_URL as string, agent) | ||
if (registerWallet) { | ||
await wsp.createSalt() | ||
await wsp.register() | ||
} | ||
setFallbackSecureEnvironment(wsp) | ||
|
||
return agent | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
import type { SecureEnvironment } from '@animo-id/expo-secure-environment' | ||
import { | ||
CredoWebCrypto, | ||
type JwsProtectedHeaderOptions, | ||
JwsService, | ||
JwtPayload, | ||
TypedArrayEncoder, | ||
getJwkFromKey, | ||
} from '@credo-ts/core' | ||
import type { EasyPIDAppAgent } from 'packages/agent/src' | ||
import { deriveKeypairFromPin } from './pin' | ||
|
||
let __pin: Array<number> | undefined | ||
export const setWalletServiceProviderPin = (pin?: Array<number>) => { | ||
__pin = pin | ||
} | ||
export const getWalletServiceProviderPin = () => __pin | ||
|
||
const GENERIC_RECORD_WALLET_SERVICE_PROVIDER_SALT_ID = 'GENERIC_RECORD_WALLET_SERVICE_PROVIDER_SALT_ID' | ||
|
||
export class WalletServiceProviderClient implements SecureEnvironment { | ||
private headers: Headers = new Headers({ | ||
'Content-Type': 'application/json', | ||
}) | ||
|
||
public constructor( | ||
private hsmUrl: string, | ||
private agent: EasyPIDAppAgent | ||
) {} | ||
|
||
public async register() { | ||
await this.post('register-wallet', {}) | ||
} | ||
|
||
private async post<T>(path: string, claims: Record<string, unknown>): Promise<T> { | ||
const pin = getWalletServiceProviderPin() | ||
if (!pin) | ||
throw new Error( | ||
'Pin not set! call `setWalletServiceProviderPin(pin)` before calling a method on the WalletServiceProvider' | ||
) | ||
const jwsService = this.agent.context.dependencyManager.resolve(JwsService) | ||
const salt = await this.getOrCreateSalt() | ||
const key = await deriveKeypairFromPin(this.agent.context, pin, salt) | ||
|
||
const payload = new JwtPayload({ | ||
additionalClaims: claims, | ||
}) | ||
|
||
const protectedHeaderOptions: JwsProtectedHeaderOptions = { | ||
alg: 'ES256', | ||
jwk: getJwkFromKey(key), | ||
} | ||
|
||
const compactJws = await jwsService.createJwsCompact(this.agent.context, { | ||
key, | ||
payload, | ||
protectedHeaderOptions, | ||
}) | ||
|
||
const body = { | ||
jwt: compactJws, | ||
} | ||
|
||
const response = await fetch(`${this.hsmUrl}/${path}`, { | ||
method: 'POST', | ||
headers: this.headers, | ||
body: JSON.stringify(body), | ||
}) | ||
|
||
const parsedData = await response.json() | ||
return parsedData | ||
} | ||
|
||
public async sign(keyId: string, message: Uint8Array): Promise<Uint8Array> { | ||
const { signature } = await this.post<{ signature: Array<number> }>('sign', { | ||
data: new Array(...message), | ||
keyId, | ||
}) | ||
|
||
if (!signature) { | ||
throw new Error('No signature property found on the response of the wallet service provider') | ||
} | ||
|
||
return new Uint8Array(signature) | ||
} | ||
|
||
public async generateKeypair(id: string): Promise<void> { | ||
await this.post('create-key', { keyType: 'P256', keyId: id }) | ||
} | ||
|
||
public async getPublicBytesForKeyId(keyId: string): Promise<Uint8Array> { | ||
const { publicKey } = await this.post<{ publicKey: Array<number> }>('get-publickey', { keyId }) | ||
if (!publicKey) { | ||
throw new Error('No publicKey property found on the response of the wallet service provider') | ||
} | ||
|
||
return new Uint8Array(publicKey) | ||
} | ||
|
||
public async createSalt() { | ||
const maybeSalt = await this.getSalt() | ||
if (maybeSalt) return maybeSalt | ||
|
||
const crypto = new CredoWebCrypto(this.agent.context) | ||
|
||
const saltBytes = crypto.getRandomValues(new Uint8Array(12)) | ||
const saltString = TypedArrayEncoder.toBase64URL(saltBytes) | ||
await this.agent.genericRecords.save({ | ||
content: { salt: saltString }, | ||
id: GENERIC_RECORD_WALLET_SERVICE_PROVIDER_SALT_ID, | ||
}) | ||
return saltString | ||
} | ||
|
||
private async getSalt(): Promise<string | null> { | ||
return (await this.agent.genericRecords.findById(GENERIC_RECORD_WALLET_SERVICE_PROVIDER_SALT_ID))?.content | ||
.salt as string | ||
} | ||
|
||
private async getOrCreateSalt() { | ||
const maybeSalt = await this.getSalt() | ||
return maybeSalt ?? (await this.createSalt()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,15 +38,17 @@ | |
"@credo-ts/react-native": "0.6.0-alpha-20241119125554", | ||
"@credo-ts/react-hooks": "0.6.1", | ||
"@animo-id/expo-ausweis-sdk": "0.0.1-alpha.14", | ||
"@animo-id/expo-secure-environment": "0.1.0-alpha.5", | ||
"@animo-id/expo-secure-environment": "0.1.0-alpha.9", | ||
"@animo-id/expo-mdoc-data-transfer": "0.0.3-alpha.7", | ||
"@types/react": "~18.2.79", | ||
"react-docgen-typescript": "2.2.2", | ||
"react": "18.3.1", | ||
"react-native": "~0.74.5" | ||
}, | ||
"patchedDependencies": { | ||
"@hyperledger/[email protected]": "patches/@[email protected]" | ||
"@hyperledger/[email protected]": "patches/@[email protected]", | ||
"@credo-ts/[email protected]": "patches/@[email protected]", | ||
"@animo-id/[email protected]": "patches/@[email protected]" | ||
} | ||
} | ||
} |
Oops, something went wrong.