Skip to content

Commit

Permalink
rewrite eip712 auth
Browse files Browse the repository at this point in the history
  • Loading branch information
piotr-roslaniec authored and manumonti committed May 27, 2024
1 parent a5d6419 commit d091e6b
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 58 deletions.
86 changes: 36 additions & 50 deletions packages/taco-auth/src/eip712.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import type { TypedDataSigner } from '@ethersproject/abstract-signer';
import { ethers } from 'ethers';
import { utils as ethersUtils } from 'ethers/lib/ethers';

export interface Eip712TypedData {
import { LocalStorage } from './storage';

interface Eip712 {
types: {
Wallet: { name: string; type: string }[];
};
Expand All @@ -20,17 +22,17 @@ export interface Eip712TypedData {
};
}

export interface FormattedTypedData extends Eip712TypedData {
interface FormattedEip712 extends Eip712 {
primaryType: 'Wallet';
types: {
EIP712Domain: { name: string; type: string }[];
Wallet: { name: string; type: string }[];
};
}

export interface TypedSignature {
interface TypedSignature {
signature: string;
typedData: Eip712TypedData;
typedData: Eip712;
address: string;
}

Expand All @@ -40,47 +42,48 @@ interface ChainData {
blockNumber: number;
}

export class WalletAuthenticationProvider {
private walletSignature?: Record<string, string>;
const EIP712Domain = [
{
name: 'name',
type: 'string',
},
{
name: 'version',
type: 'string',
},
{
name: 'chainId',
type: 'uint256',
},
{
name: 'salt',
type: 'bytes32',
},
];

export class EIP712SignatureProvider {
private readonly storage: LocalStorage;

constructor(
private readonly provider: ethers.providers.Provider,
private readonly signer: ethers.Signer,
) {}
) {
this.storage = new LocalStorage();
}

public async getOrCreateWalletSignature(): Promise<TypedSignature> {
const address = await this.signer.getAddress();
const storageKey = `wallet-signature-${address}`;
const storageKey = `eip712-signature-${address}`;

// If we have a signature in localStorage, return it
const isLocalStorage = typeof localStorage !== 'undefined';
if (isLocalStorage) {
const maybeSignature = localStorage.getItem(storageKey);
if (maybeSignature) {
return JSON.parse(maybeSignature);
}
}

// If not, try returning from memory
const maybeSignature = this.walletSignature?.[address];
const maybeSignature = this.storage.getItem(storageKey);
if (maybeSignature) {
if (isLocalStorage) {
localStorage.setItem(storageKey, maybeSignature);
}
return JSON.parse(maybeSignature);
}

// If at this point we didn't return, we need to create a new signature
const typedSignature = await this.createWalletSignature();

// Persist where you can
if (isLocalStorage) {
localStorage.setItem(storageKey, JSON.stringify(typedSignature));
}
if (!this.walletSignature) {
this.walletSignature = {};
}
this.walletSignature[address] = JSON.stringify(typedSignature);
this.storage.setItem(storageKey, JSON.stringify(typedSignature));
return typedSignature;
}

Expand All @@ -91,7 +94,7 @@ export class WalletAuthenticationProvider {
const signatureText = `I'm the owner of address ${address} as of block number ${blockNumber}`;
const salt = ethersUtils.hexlify(ethersUtils.randomBytes(32));

const typedData: Eip712TypedData = {
const typedData: Eip712 = {
types: {
Wallet: [
{ name: 'address', type: 'address' },
Expand All @@ -118,29 +121,12 @@ export class WalletAuthenticationProvider {
this.signer as unknown as TypedDataSigner
)._signTypedData(typedData.domain, typedData.types, typedData.message);

const formattedTypedData: FormattedTypedData = {
const formattedTypedData: FormattedEip712 = {
...typedData,
primaryType: 'Wallet',
types: {
...typedData.types,
EIP712Domain: [
{
name: 'name',
type: 'string',
},
{
name: 'version',
type: 'string',
},
{
name: 'chainId',
type: 'uint256',
},
{
name: 'salt',
type: 'bytes32',
},
],
EIP712Domain,
},
};
return { signature, typedData: formattedTypedData, address };
Expand Down
44 changes: 44 additions & 0 deletions packages/taco-auth/src/storage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
interface IStorage {
getItem(key: string): string | null;

setItem(key: string, value: string): void;
}

class BrowserStorage implements IStorage {
getItem(key: string): string | null {
return localStorage.getItem(key);
}

setItem(key: string, value: string): void {
localStorage.setItem(key, value);
}
}


class NodeStorage implements IStorage {
private storage: Record<string, string> = {};

getItem(key: string): string | null {
return this.storage[key] || null;
}

setItem(key: string, value: string): void {
this.storage[key] = value;
}
}

export class LocalStorage {
private storage: IStorage;

constructor() {
this.storage = typeof localStorage === 'undefined' ? new NodeStorage() : new BrowserStorage();
}

getItem(key: string): string | null {
return this.storage.getItem(key);
}

setItem(key: string, value: string): void {
this.storage.setItem(key, value);
}
}
13 changes: 5 additions & 8 deletions packages/taco/src/conditions/context/context.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import { Context, Conditions as WASMConditions } from '@nucypher/nucypher-core';
import { fromJSON, toJSON } from '@nucypher/shared';
import {
TypedSignature,
WalletAuthenticationProvider,
} from '@nucypher/taco-auth';
import { EIP712SignatureProvider, TypedSignature } from '@nucypher/taco-auth';
import { ethers } from 'ethers';

import { CompoundConditionType } from '../compound-condition';
Expand All @@ -30,7 +27,7 @@ const ERR_UNKNOWN_CONTEXT_PARAMS = (params: string[]) =>
`Unknown custom context parameter(s): ${params.join(', ')}`;

export class ConditionContext {
private readonly walletAuthProvider?: WalletAuthenticationProvider;
private readonly eip712SignatureProvider?: EIP712SignatureProvider;

constructor(
private readonly provider: ethers.providers.Provider,
Expand All @@ -39,7 +36,7 @@ export class ConditionContext {
private readonly signer?: ethers.Signer,
) {
if (this.signer) {
this.walletAuthProvider = new WalletAuthenticationProvider(
this.eip712SignatureProvider = new EIP712SignatureProvider(
this.provider,
this.signer,
);
Expand Down Expand Up @@ -99,11 +96,11 @@ export class ConditionContext {

// Fill in predefined context parameters
if (requestedParameters.has(USER_ADDRESS_PARAM)) {
if (!this.walletAuthProvider) {
if (!this.eip712SignatureProvider) {
throw new Error(ERR_SIGNER_REQUIRED);
}
parameters[USER_ADDRESS_PARAM] =
await this.walletAuthProvider.getOrCreateWalletSignature();
await this.eip712SignatureProvider.getOrCreateWalletSignature();
// Remove from requested parameters
requestedParameters.delete(USER_ADDRESS_PARAM);
}
Expand Down

0 comments on commit d091e6b

Please sign in to comment.