Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GitHub Porter URIs #555

Merged
merged 10 commits into from
Aug 15, 2024
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 (
piotr-roslaniec marked this conversation as resolved.
Show resolved Hide resolved
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