From 05a2248944eeb2f4fcefa6e20a73e7dbabf14a5f Mon Sep 17 00:00:00 2001 From: Piotr Roslaniec Date: Tue, 9 Jul 2024 15:56:28 +0200 Subject: [PATCH] feat!(auth): expose eip4361 auth provider in taco api --- demos/taco-demo/src/App.tsx | 6 ++-- examples/taco/nextjs/package.json | 1 + examples/taco/nextjs/src/hooks/useTaco.ts | 10 +++++-- examples/taco/nodejs/src/index.ts | 14 +++++----- examples/taco/react/package.json | 1 + examples/taco/react/src/hooks/useTaco.ts | 10 +++++-- examples/taco/react/tsconfig.build.json | 3 ++ examples/taco/webpack-5/package.json | 3 +- examples/taco/webpack-5/src/index.ts | 4 ++- examples/taco/webpack-5/tsconfig.json | 3 ++ packages/taco-auth/src/auth-provider.ts | 2 +- packages/taco-auth/src/providers/eip4361.ts | 5 ++-- packages/taco/src/index.ts | 2 +- packages/taco/src/taco.ts | 28 ++++--------------- packages/taco/test/conditions/context.test.ts | 24 ++++++++-------- packages/taco/test/taco.test.ts | 21 ++++---------- pnpm-lock.yaml | 9 ++++++ 17 files changed, 74 insertions(+), 72 deletions(-) diff --git a/demos/taco-demo/src/App.tsx b/demos/taco-demo/src/App.tsx index 7fe6c9c39..2aa5f07a8 100644 --- a/demos/taco-demo/src/App.tsx +++ b/demos/taco-demo/src/App.tsx @@ -13,11 +13,11 @@ import { ethers } from 'ethers'; import React, { useEffect, useState } from 'react'; import { ConditionBuilder } from './ConditionBuilder'; -import { DEFAULT_DOMAIN, DEFAULT_RITUAL_ID } from './config'; import { Decrypt } from './Decrypt'; import { Encrypt } from './Encrypt'; -import { downloadData, getWebIrys, uploadData } from './irys'; import { Spinner } from './Spinner'; +import { DEFAULT_DOMAIN, DEFAULT_RITUAL_ID } from './config'; +import { downloadData, getWebIrys, uploadData } from './irys'; const chainIdForDomain = { [domains.DEVNET]: 80002, @@ -121,7 +121,7 @@ export default function App() {

Notice

In production (mainnet domain), your wallet address (encryptor) will also have - to be allow-listed for this specific ritual. However, we have + to be allow-listed for this specific ritual. However, we have publicly available testnet rituals for use when developing your apps.

diff --git a/examples/taco/nextjs/package.json b/examples/taco/nextjs/package.json index 61ab779a4..70efff2f4 100644 --- a/examples/taco/nextjs/package.json +++ b/examples/taco/nextjs/package.json @@ -13,6 +13,7 @@ "dependencies": { "@nucypher/shared": "workspace:*", "@nucypher/taco": "workspace:*", + "@nucypher/taco-auth": "workspace:*", "@types/node": "20.11.30", "@types/react": "18.2.48", "@types/react-dom": "18.2.18", diff --git a/examples/taco/nextjs/src/hooks/useTaco.ts b/examples/taco/nextjs/src/hooks/useTaco.ts index 376a80a62..795b2b3a6 100644 --- a/examples/taco/nextjs/src/hooks/useTaco.ts +++ b/examples/taco/nextjs/src/hooks/useTaco.ts @@ -7,6 +7,7 @@ import { initialize, ThresholdMessageKit, } from '@nucypher/taco'; +import { EIP4361AuthProvider } from '@nucypher/taco-auth'; import { ethers } from 'ethers'; import { useCallback, useEffect, useState } from 'react'; @@ -26,15 +27,18 @@ export default function useTaco({ }, []); const decryptDataFromBytes = useCallback( - async (encryptedBytes: Uint8Array, signer?: ethers.Signer) => { - if (!isInit || !provider) return; + async (encryptedBytes: Uint8Array, signer: ethers.Signer) => { + if (!isInit || !provider) { + return; + } const messageKit = ThresholdMessageKit.fromBytes(encryptedBytes); + const authProvider = new EIP4361AuthProvider(provider, signer); return decrypt( provider, domain, messageKit, + authProvider, getPorterUri(domain), - signer, ); }, [isInit, provider, domain], diff --git a/examples/taco/nodejs/src/index.ts b/examples/taco/nodejs/src/index.ts index 5b17cd7cc..4db93ea87 100644 --- a/examples/taco/nodejs/src/index.ts +++ b/examples/taco/nodejs/src/index.ts @@ -1,8 +1,7 @@ import { format } from 'node:util'; import { - conditions, - decryptWithAuthProviders, + conditions, decrypt, domains, encrypt, fromBytes, @@ -12,7 +11,7 @@ import { toBytes, toHexString, } from '@nucypher/taco'; -import { makeAuthProviders } from '@nucypher/taco-auth'; +import { EIP4361AuthProvider } from '@nucypher/taco-auth'; import * as dotenv from 'dotenv'; import { ethers } from 'ethers'; @@ -85,15 +84,16 @@ const decryptFromBytes = async (encryptedBytes: Uint8Array) => { const messageKit = ThresholdMessageKit.fromBytes(encryptedBytes); console.log('Decrypting message ...'); - const authProviders = makeAuthProviders(provider, consumerSigner, { + const siweParams = { domain: 'localhost', uri: 'http://localhost:3000', - }); - return decryptWithAuthProviders( + }; + const authProvider = new EIP4361AuthProvider(provider, consumerSigner, siweParams); + return decrypt( provider, domain, messageKit, - authProviders, + authProvider, getPorterUri(domain), ); }; diff --git a/examples/taco/react/package.json b/examples/taco/react/package.json index 42213a78c..8c3aae51e 100644 --- a/examples/taco/react/package.json +++ b/examples/taco/react/package.json @@ -25,6 +25,7 @@ "dependencies": { "@nucypher/shared": "workspace:*", "@nucypher/taco": "workspace:*", + "@nucypher/taco-auth": "workspace:*", "react": "^18.2.0", "react-dom": "^18.2.0" }, diff --git a/examples/taco/react/src/hooks/useTaco.ts b/examples/taco/react/src/hooks/useTaco.ts index 376a80a62..795b2b3a6 100644 --- a/examples/taco/react/src/hooks/useTaco.ts +++ b/examples/taco/react/src/hooks/useTaco.ts @@ -7,6 +7,7 @@ import { initialize, ThresholdMessageKit, } from '@nucypher/taco'; +import { EIP4361AuthProvider } from '@nucypher/taco-auth'; import { ethers } from 'ethers'; import { useCallback, useEffect, useState } from 'react'; @@ -26,15 +27,18 @@ export default function useTaco({ }, []); const decryptDataFromBytes = useCallback( - async (encryptedBytes: Uint8Array, signer?: ethers.Signer) => { - if (!isInit || !provider) return; + async (encryptedBytes: Uint8Array, signer: ethers.Signer) => { + if (!isInit || !provider) { + return; + } const messageKit = ThresholdMessageKit.fromBytes(encryptedBytes); + const authProvider = new EIP4361AuthProvider(provider, signer); return decrypt( provider, domain, messageKit, + authProvider, getPorterUri(domain), - signer, ); }, [isInit, provider, domain], diff --git a/examples/taco/react/tsconfig.build.json b/examples/taco/react/tsconfig.build.json index 22ff2bd0b..beb822b78 100644 --- a/examples/taco/react/tsconfig.build.json +++ b/examples/taco/react/tsconfig.build.json @@ -9,6 +9,9 @@ "references": [ { "path": "../../../packages/taco/tsconfig.es.json" + }, + { + "path": "../../../packages/taco-auth/tsconfig.es.json" } ] } diff --git a/examples/taco/webpack-5/package.json b/examples/taco/webpack-5/package.json index 2a68fce2b..ed205e100 100644 --- a/examples/taco/webpack-5/package.json +++ b/examples/taco/webpack-5/package.json @@ -12,7 +12,8 @@ "type-check": "tsc" }, "dependencies": { - "@nucypher/taco": "workspace:*" + "@nucypher/taco": "workspace:*", + "@nucypher/taco-auth": "workspace:*" }, "devDependencies": { "copy-webpack-plugin": "^12.0.2", diff --git a/examples/taco/webpack-5/src/index.ts b/examples/taco/webpack-5/src/index.ts index 2cfd040d2..771cf5fa4 100644 --- a/examples/taco/webpack-5/src/index.ts +++ b/examples/taco/webpack-5/src/index.ts @@ -8,6 +8,7 @@ import { initialize, toBytes, } from '@nucypher/taco'; +import { EIP4361AuthProvider } from '@nucypher/taco-auth'; import { ethers } from 'ethers'; import { hexlify } from 'ethers/lib/utils'; @@ -60,12 +61,13 @@ const runExample = async () => { ); console.log('Decrypting message...'); + const authProvider = new EIP4361AuthProvider(provider, signer); const decryptedBytes = await decrypt( provider, domain, messageKit, + authProvider, getPorterUri(domain), - signer, ); const decryptedMessage = fromBytes(decryptedBytes); console.log('Decrypted message:', decryptedMessage); diff --git a/examples/taco/webpack-5/tsconfig.json b/examples/taco/webpack-5/tsconfig.json index 8ee7f0a76..56863c42b 100644 --- a/examples/taco/webpack-5/tsconfig.json +++ b/examples/taco/webpack-5/tsconfig.json @@ -10,5 +10,8 @@ { "path": "../../../packages/taco/tsconfig.es.json", }, + { + "path": "../../../packages/taco-auth/tsconfig.es.json", + } ], } diff --git a/packages/taco-auth/src/auth-provider.ts b/packages/taco-auth/src/auth-provider.ts index 8f7d18578..18e83d5e6 100644 --- a/packages/taco-auth/src/auth-provider.ts +++ b/packages/taco-auth/src/auth-provider.ts @@ -24,7 +24,7 @@ export const USER_ADDRESS_PARAM_EIP712 = `:userAddress${EIP712_AUTH_METHOD}`; export const USER_ADDRESS_PARAM_EIP4361 = `:userAddress${EIP4361_AUTH_METHOD}`; export const AUTH_METHOD_FOR_PARAM: Record = { - [USER_ADDRESS_PARAM_DEFAULT]: EIP712_AUTH_METHOD, + [USER_ADDRESS_PARAM_DEFAULT]: EIP4361_AUTH_METHOD, [USER_ADDRESS_PARAM_EIP712]: EIP712_AUTH_METHOD, [USER_ADDRESS_PARAM_EIP4361]: EIP4361_AUTH_METHOD, }; diff --git a/packages/taco-auth/src/providers/eip4361.ts b/packages/taco-auth/src/providers/eip4361.ts index 9e06fcce5..5f95e30ab 100644 --- a/packages/taco-auth/src/providers/eip4361.ts +++ b/packages/taco-auth/src/providers/eip4361.ts @@ -37,10 +37,9 @@ export class EIP4361AuthProvider { private getDefaultParameters() { if (typeof window !== 'undefined') { // If we are in a browser environment, we can get the domain and uri from the window object - const maybeOrigin = window?.location?.origin; return { - domain: maybeOrigin.split('//')[1].split('.')[0], - uri: maybeOrigin, + domain: window.location?.host, + uri: window.location?.origin, }; } // If not, we have no choice but to throw an error diff --git a/packages/taco/src/index.ts b/packages/taco/src/index.ts index 26b93c60e..d737d6ed6 100644 --- a/packages/taco/src/index.ts +++ b/packages/taco/src/index.ts @@ -11,4 +11,4 @@ export { export * as conditions from './conditions'; // Expose registerEncrypters from taco API (#324) -export { decrypt, decryptWithAuthProviders, encrypt, encryptWithPublicKey, isAuthorized } from './taco'; +export { decrypt, encrypt, encryptWithPublicKey, isAuthorized } from './taco'; diff --git a/packages/taco/src/taco.ts b/packages/taco/src/taco.ts index 7ef2e7cba..5e59de4de 100644 --- a/packages/taco/src/taco.ts +++ b/packages/taco/src/taco.ts @@ -13,7 +13,7 @@ import { GlobalAllowListAgent, toBytes, } from '@nucypher/shared'; -import { AuthProviders, makeAuthProviders } from '@nucypher/taco-auth'; +import { AuthProviders, EIP4361_AUTH_METHOD, EIP4361AuthProvider } from '@nucypher/taco-auth'; import { ethers } from 'ethers'; import { keccak256 } from 'ethers/lib/utils'; @@ -125,9 +125,9 @@ export const encryptWithPublicKey = async ( * @param {Domain} domain - Represents the logical network in which the decryption will be performed. * Must match the `ritualId`. * @param {ThresholdMessageKit} messageKit - The kit containing the message to be decrypted + * @param authProvider * @param {string} [porterUri] - The URI for the Porter service. If not provided, a value will be obtained * from the Domain - * @param {ethers.Signer} [signer] - An optional signer for the decryption * @param {Record} [customParameters] - Optional custom parameters that may be required * depending on the condition used * @@ -140,26 +140,7 @@ export const decrypt = async ( provider: ethers.providers.Provider, domain: Domain, messageKit: ThresholdMessageKit, - porterUri?: string, - signer?: ethers.Signer, - customParameters?: Record, -): Promise => { - const authProviders = makeAuthProviders(provider, signer); - return decryptWithAuthProviders( - provider, - domain, - messageKit, - authProviders, - porterUri, - customParameters, - ); -}; - -export const decryptWithAuthProviders = async ( - provider: ethers.providers.Provider, - domain: Domain, - messageKit: ThresholdMessageKit, - authProviders?: AuthProviders, + authProvider: EIP4361AuthProvider, porterUri?: string, customParameters?: Record, ): Promise => { @@ -173,6 +154,9 @@ export const decryptWithAuthProviders = async ( messageKit.acp.publicKey, ); const ritual = await DkgClient.getActiveRitual(provider, domain, ritualId); + const authProviders: AuthProviders = { + [EIP4361_AUTH_METHOD]: authProvider, + }; return retrieveAndDecrypt( provider, domain, diff --git a/packages/taco/test/conditions/context.test.ts b/packages/taco/test/conditions/context.test.ts index 1a42ad330..5120a8685 100644 --- a/packages/taco/test/conditions/context.test.ts +++ b/packages/taco/test/conditions/context.test.ts @@ -405,8 +405,18 @@ describe('No authentication provider', () => { expect(eip712Spy).toHaveBeenCalledOnce(); } - it('supports default auth method (eip712)', async () => { - await testEIP712AuthMethod(USER_ADDRESS_PARAM_DEFAULT); + async function testEIP4361AuthMethod(authMethod: string) { + const eip4361Spy = vi.spyOn( + EIP4361AuthProvider.prototype, + 'getOrCreateAuthSignature', + ); + const authSignature = await makeAuthSignature(authMethod); + await testEIP4361AuthSignature(authSignature); + expect(eip4361Spy).toHaveBeenCalledOnce(); + } + + it('supports default auth method (eip4361)', async () => { + await testEIP4361AuthMethod(USER_ADDRESS_PARAM_DEFAULT); }); it('supports eip712', async () => { @@ -414,15 +424,7 @@ describe('No authentication provider', () => { }); it('supports eip4361', async () => { - const eip4361Spy = vi.spyOn( - EIP4361AuthProvider.prototype, - 'getOrCreateAuthSignature', - ); - - const authSignature = await makeAuthSignature(USER_ADDRESS_PARAM_EIP4361); - await testEIP4361AuthSignature(authSignature); - - expect(eip4361Spy).toHaveBeenCalledOnce(); + await testEIP4361AuthMethod(USER_ADDRESS_PARAM_EIP4361); }); it('supports reusing external eip4361', async () => { diff --git a/packages/taco/test/taco.test.ts b/packages/taco/test/taco.test.ts index c4a738345..af3a06c2c 100644 --- a/packages/taco/test/taco.test.ts +++ b/packages/taco/test/taco.test.ts @@ -16,7 +16,7 @@ import { mockTacoDecrypt, TEST_CHAIN_ID, TEST_SIWE_PARAMS, } from '@nucypher/test-utils'; -import { beforeAll, describe, expect, it, vi } from 'vitest'; +import { beforeAll, describe, expect, it } from 'vitest'; import * as taco from '../src'; import { conditions, domains, toBytes } from '../src'; @@ -83,31 +83,20 @@ describe('taco', () => { ); const getRitualSpy = mockGetActiveRitual(mockedDkgRitual); - const authProviders = tacoAuth.makeAuthProviders(provider, signer,TEST_SIWE_PARAMS); - const decryptedMessage1 = await taco.decryptWithAuthProviders( + const authProvider = new tacoAuth.EIP4361AuthProvider(provider, signer, TEST_SIWE_PARAMS); + const decryptedMessage = await taco.decrypt( provider, domains.DEVNET, messageKit, - authProviders, + authProvider, fakePorterUri, ); - expect(decryptedMessage1).toEqual(toBytes(message)); + expect(decryptedMessage).toEqual(toBytes(message)); expect(getParticipantsSpy).toHaveBeenCalled(); expect(sessionKeySpy).toHaveBeenCalled(); expect(getRitualIdFromPublicKey).toHaveBeenCalled(); expect(getRitualSpy).toHaveBeenCalled(); expect(decryptSpy).toHaveBeenCalled(); - - const makeAuthProvidersSpy = vi.spyOn(tacoAuth, 'makeAuthProviders').mockImplementation(() => authProviders); - const decryptedMessage2 = await taco.decrypt( - provider, - domains.DEVNET, - messageKit, - fakePorterUri, - signer, - ); - expect(makeAuthProvidersSpy).toHaveBeenCalled(); - expect(decryptedMessage2).toEqual(toBytes(message)); }); it('exposes requested parameters', async () => { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ff5e622a9..b0bb7ddbf 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -371,6 +371,9 @@ importers: '@nucypher/taco': specifier: workspace:* version: link:../../../packages/taco + '@nucypher/taco-auth': + specifier: workspace:* + version: link:../../../packages/taco-auth '@types/node': specifier: 20.11.30 version: 20.11.30 @@ -425,6 +428,9 @@ importers: '@nucypher/taco': specifier: workspace:* version: link:../../../packages/taco + '@nucypher/taco-auth': + specifier: workspace:* + version: link:../../../packages/taco-auth ethers: specifier: ^5.7.2 version: 5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10) @@ -453,6 +459,9 @@ importers: '@nucypher/taco': specifier: workspace:* version: link:../../../packages/taco + '@nucypher/taco-auth': + specifier: workspace:* + version: link:../../../packages/taco-auth ethers: specifier: ^5.7.2 version: 5.7.2(bufferutil@4.0.8)(utf-8-validate@5.0.10)