Skip to content

Commit

Permalink
GitHub Porter URIs (#555)
Browse files Browse the repository at this point in the history
  • Loading branch information
derekpierre authored Aug 15, 2024
2 parents cf17b4f + 7027418 commit ae5186f
Show file tree
Hide file tree
Showing 9 changed files with 72 additions and 29 deletions.
2 changes: 1 addition & 1 deletion examples/pre/nextjs/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ function App() {
provider,
provider.getSigner(),
domains.TESTNET,
getPorterUri(domains.TESTNET),
await getPorterUri(domains.TESTNET),
policyParams,
);

Expand Down
2 changes: 1 addition & 1 deletion examples/pre/nodejs/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const runExample = async () => {
provider,
signer,
domains.TESTNET,
getPorterUri(domains.TESTNET),
await getPorterUri(domains.TESTNET),
policyParams,
);

Expand Down
2 changes: 1 addition & 1 deletion examples/pre/react/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ function App() {
provider,
provider.getSigner(),
domains.TESTNET,
getPorterUri(domains.TESTNET),
await getPorterUri(domains.TESTNET),
policyParams,
);

Expand Down
2 changes: 1 addition & 1 deletion examples/pre/webpack-5/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ const runExample = async () => {
provider,
provider.getSigner(),
domains.TESTNET,
getPorterUri(domains.TESTNET),
await getPorterUri(domains.TESTNET),
policyParams,
);

Expand Down
1 change: 0 additions & 1 deletion examples/taco/webpack-5/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
EIP4361AuthProvider,
encrypt,
fromBytes,
getPorterUris,
initialize,
toBytes,
} from '@nucypher/taco';
Expand Down
51 changes: 37 additions & 14 deletions packages/shared/src/porter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,36 +17,59 @@ import { Base64EncodedBytes, ChecksumAddress, HexEncodedBytes } from './types';
import { fromBase64, fromHexString, toBase64, toHexString } from './utils';

const defaultPorterUri: Record<string, string> = {
mainnet: 'https://porter.nucypher.community',
tapir: 'https://porter-tapir.nucypher.community',
lynx: 'https://porter-lynx.nucypher.community',
mainnet: 'https://porter.nucypher.io',
tapir: 'https://porter-tapir.nucypher.io',
lynx: 'https://porter-lynx.nucypher.io',
};

const porterUriSource: string =
'https://raw.githubusercontent.com/nucypher/nucypher-porter/main/porter_instances.json';

export type Domain = keyof typeof defaultPorterUri;
export type PorterURISourceResponse = Record<string, string[]>;

export const domains: Record<string, Domain> = {
DEVNET: 'lynx',
TESTNET: 'tapir',
MAINNET: 'mainnet',
};

export const getPorterUri = (domain: Domain): string => {
return getPorterUris(domain)[0];
export const getPorterUri = async (domain: Domain): Promise<string> => {
return (await getPorterUris(domain))[0];
};

export const getPorterUris = (
export const getPorterUris = async (
domain: Domain,
porterUris: string[] = [],
): string[] => {
const fullList = [...porterUris];
): Promise<string[]> => {
const fullList = [];
const uri = defaultPorterUri[domain];
if (!uri) {
throw new Error(`No default Porter URI found for domain: ${domain}`);
}
fullList.push(uri);
const urisFromSource = await getPorterUrisFromSource(domain);
fullList.push(...urisFromSource);
return fullList;
};

export const getPorterUrisFromSource = async (
domain: Domain,
): Promise<string[]> => {
const source = porterUriSource;
if (!source) {
return [];
}
try {
const resp = await axios.get(porterUriSource, {
responseType: 'blob',
});
const uris: PorterURISourceResponse = JSON.parse(resp.data);
return uris[domain];
} catch (e) {
return [];
}
};

// /get_ursulas

export type Ursula = {
Expand Down Expand Up @@ -151,19 +174,19 @@ export class PorterClient {
const localConfig = { ...config, baseURL: porterUrl.toString() };
try {
resp = await axios.request(localConfig);
if (resp.status === HttpStatusCode.Ok) {
return resp;
}
} catch (e) {
lastError = e;
continue;
}
if (resp.status === HttpStatusCode.Ok) {
return resp;
}
}
if (lastError !== undefined) {
if (lastError) {
throw lastError;
}
throw new Error(
'Porter returns bad response: ${resp.status} - ${resp.data}',
`Porter returned bad response: ${resp.status} - ${resp.data}`,
);
}

Expand Down
34 changes: 28 additions & 6 deletions packages/shared/test/porter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ import {
GetUrsulasResult,
PorterClient,
Ursula,
domains,
getPorterUris,
getPorterUrisFromSource,
initialize,
toHexString,
} from '../src';
Expand Down Expand Up @@ -38,14 +41,29 @@ const mockGetUrsulas = (ursulas: Ursula[] = fakeUrsulas()): SpyInstance => {
status: HttpStatusCode.Ok,
data: fakePorterUrsulas(ursulas),
});
case fakePorterUris[1]:
return Promise.resolve({ status: HttpStatusCode.BadRequest, data: '' });
case fakePorterUris[0]:
throw new Error();
default:
throw Promise.resolve({ status: HttpStatusCode.BadRequest });
throw new Error(`Test error`);
}
});
};

describe('getPorterUris', () => {
beforeAll(async () => {
await initialize();
});

it('Get URIs from source', async () => {
for (const domain of Object.values(domains)) {
const uris = await getPorterUrisFromSource(domain);
expect(uris.length).toBeGreaterThan(0);
const fullList = await getPorterUris(domain);
expect(fullList).toEqual(expect.arrayContaining(uris));
}
});
});

describe('PorterClient', () => {
beforeAll(async () => {
await initialize();
Expand Down Expand Up @@ -89,9 +107,13 @@ describe('PorterClient', () => {
it('returns error in case all porters fail', async () => {
const ursulas = fakeUrsulas();
mockGetUrsulas(ursulas);
let porterClient = new PorterClient([fakePorterUris[0], fakePorterUris[1]]);
expect(porterClient.getUrsulas(ursulas.length)).rejects.toThrowError();
let porterClient = new PorterClient([fakePorterUris[1]]);
expect(porterClient.getUrsulas(ursulas.length)).rejects.toThrowError(
Error(`Porter returned bad response: 400 - `),
);
porterClient = new PorterClient([fakePorterUris[1], fakePorterUris[0]]);
expect(porterClient.getUrsulas(ursulas.length)).rejects.toThrowError();
expect(porterClient.getUrsulas(ursulas.length)).rejects.toThrowError(
Error(`Test error`),
);
});
});
1 change: 0 additions & 1 deletion packages/taco/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ const decryptedMessage = await decrypt(
web3Provider,
domains.TESTNET,
messageKit,
getPorterUri(domains.TESTNET),
web3Provider.getSigner(),
);
```
Expand Down
6 changes: 3 additions & 3 deletions packages/taco/src/taco.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ export const encryptWithPublicKey = async (
* Must match the `ritualId`.
* @param {ThresholdMessageKit} messageKit - The kit containing the message to be decrypted
* @param authProvider - The authentication provider that will be used to provide the authorization
* @param {string} [porterUri] - The URI(s) for the Porter service. If not provided, a value will be obtained
* @param {string[]} [porterUris] - The URI(s) for the Porter service. If not provided, a value will be obtained
* from the Domain
* @param {Record<string, CustomContextParam>} [customParameters] - Optional custom parameters that may be required
* depending on the condition used
Expand All @@ -145,10 +145,10 @@ export const decrypt = async (
domain: Domain,
messageKit: ThresholdMessageKit,
authProvider?: EIP4361AuthProvider,
porterUris: string[] = [],
porterUris?: string[],
customParameters?: Record<string, CustomContextParam>,
): Promise<Uint8Array> => {
const porterUrisFull: string[] = getPorterUris(domain, porterUris);
const porterUrisFull: string[] = porterUris ? porterUris : await getPorterUris(domain);

const ritualId = await DkgCoordinatorAgent.getRitualIdFromPublicKey(
provider,
Expand Down

0 comments on commit ae5186f

Please sign in to comment.