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

add auth for fetching nonce #145

Merged
merged 1 commit into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 23 additions & 8 deletions src/helpers/metadataUtils.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import { decrypt } from "@toruslabs/eccrypto";
import { Data, post } from "@toruslabs/http-helpers";
import BN from "bn.js";
import { ec } from "elliptic";
import { ec as EC } from "elliptic";
import stringify from "json-stable-stringify";
import log from "loglevel";

import { SAPPHIRE_METADATA_URL } from "../constants";
import { EciesHex, GetOrSetNonceResult, MetadataParams } from "../interfaces";
import { EciesHex, GetOrSetNonceResult, MetadataParams, SapphireMetadataParams } from "../interfaces";
import { encParamsHexToBuf } from "./common";
import { keccak256 } from "./keyUtils";

const secp256k1Curve = new EC("secp256k1");
export function convertMetadataToNonce(params: { message?: string }) {
if (!params || !params.message) {
return new BN(0);
Expand All @@ -26,7 +27,7 @@ export async function decryptNodeData(eciesData: EciesHex, ciphertextHex: string
return decryptedSigBuffer;
}

export function generateMetadataParams(ecCurve: ec, serverTimeOffset: number, message: string, privateKey: BN): MetadataParams {
export function generateMetadataParams(ecCurve: EC, serverTimeOffset: number, message: string, privateKey: BN): MetadataParams {
const key = ecCurve.keyFromPrivate(privateKey.toString("hex", 64));
const setData = {
data: message,
Expand Down Expand Up @@ -60,7 +61,7 @@ export async function getMetadata(

export async function getOrSetNonce(
legacyMetadataHost: string,
ecCurve: ec,
ecCurve: EC,
serverTimeOffset: number,
X: string,
Y: string,
Expand All @@ -83,21 +84,35 @@ export async function getOrSetNonce(

export async function getNonce(
legacyMetadataHost: string,
ecCurve: ec,
ecCurve: EC,
serverTimeOffset: number,
X: string,
Y: string,
privKey?: BN
): Promise<GetOrSetNonceResult> {
return getOrSetNonce(legacyMetadataHost, ecCurve, serverTimeOffset, X, Y, privKey, true);
}

export async function getOrSetSapphireMetadataNonce(X: string, Y: string): Promise<GetOrSetNonceResult> {
const data = {
export async function getOrSetSapphireMetadataNonce(X: string, Y: string, serverTimeOffset?: number, privKey?: BN): Promise<GetOrSetNonceResult> {
let data: SapphireMetadataParams = {
pub_key_X: X,
pub_key_Y: Y,
key_type: "secp256k1",
set_data: { operation: "getOrSetNonce" },
};
if (privKey) {
const key = secp256k1Curve.keyFromPrivate(privKey.toString("hex", 64));

const setData = {
operation: "getOrSetNonce",
timestamp: new BN(~~(serverTimeOffset + Date.now() / 1000)).toString(16),
};
const sig = key.sign(keccak256(Buffer.from(stringify(setData), "utf8")).slice(2));
data = {
...data,
set_data: setData,
signature: Buffer.from(sig.r.toString(16, 64) + sig.s.toString(16, 64) + new BN("").toString(16, 2), "hex").toString("base64"),
};
}

return post<GetOrSetNonceResult>(`${SAPPHIRE_METADATA_URL}/get_or_set_nonce`, data, undefined, { useAPIKey: true });
}
40 changes: 20 additions & 20 deletions src/helpers/nodeUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ export const GetPubKeyOrKeyAssign = async (params: {
// rechecking nonceResult to avoid promise race condition.
if (!nonceResult && metadataNonceResult) {
nonceResult = metadataNonceResult;
if (nonceResult.nonce) {
delete nonceResult.nonce;
}
}
}
}
Expand Down Expand Up @@ -375,29 +378,11 @@ export async function retrieveOrImportShare(params: {
}
});

// if both thresholdNonceData and extended_verifier_id are not available
// then we need to throw other wise address would be incorrect.
if (!thresholdNonceData && !verifierParams.extended_verifier_id && !LEGACY_NETWORKS_ROUTE_MAP[network as TORUS_LEGACY_NETWORK_TYPE]) {
const metadataNonceResult = await getOrSetSapphireMetadataNonce(thresholdPublicKey.X, thresholdPublicKey.Y);
// rechecking nonceResult to avoid promise race condition.
if (metadataNonceResult && !thresholdNonceData) {
thresholdNonceData = metadataNonceResult;
} else {
throw new Error(
`invalid metadata result from nodes, nonce metadata is empty for verifier: ${verifier} and verifierId: ${verifierParams.verifier_id}`
);
}
}

const thresholdReqCount = importedShares.length > 0 ? endpoints.length : minThreshold;
// optimistically run lagrange interpolation once threshold number of shares have been received
// this is matched against the user public key to ensure that shares are consistent
// Note: no need of thresholdMetadataNonce for extended_verifier_id key
if (
completedRequests.length >= thresholdReqCount &&
thresholdPublicKey &&
(thresholdNonceData || verifierParams.extended_verifier_id || LEGACY_NETWORKS_ROUTE_MAP[network as TORUS_LEGACY_NETWORK_TYPE])
) {
if (completedRequests.length >= thresholdReqCount && thresholdPublicKey) {
const sharePromises: Promise<void | Buffer>[] = [];
const sessionTokenSigPromises: Promise<void | Buffer>[] = [];
const sessionTokenPromises: Promise<void | Buffer>[] = [];
Expand Down Expand Up @@ -564,13 +549,28 @@ export async function retrieveOrImportShare(params: {
});
})
.then(async (res) => {
const { privateKey, sessionTokenData, thresholdNonceData, nodeIndexes, isNewKey, serverTimeOffsetResponse } = res;
const { privateKey, sessionTokenData, nodeIndexes, thresholdNonceData, isNewKey, serverTimeOffsetResponse } = res;
let nonceResult = thresholdNonceData;
if (!privateKey) throw new Error("Invalid private key returned");

const oAuthKey = privateKey;
const oAuthPubKey = getPublic(Buffer.from(oAuthKey.toString(16, 64), "hex")).toString("hex");
const oAuthPubkeyX = oAuthPubKey.slice(2, 66);
const oAuthPubkeyY = oAuthPubKey.slice(66);

// if both thresholdNonceData and extended_verifier_id are not available
// then we need to throw other wise address would be incorrect.
if (!nonceResult && !verifierParams.extended_verifier_id && !LEGACY_NETWORKS_ROUTE_MAP[network as TORUS_LEGACY_NETWORK_TYPE]) {
const metadataNonceResult = await getOrSetSapphireMetadataNonce(oAuthPubkeyX, oAuthPubkeyY, serverTimeOffset, oAuthKey);
// rechecking nonceResult to avoid promise race condition.
if (metadataNonceResult && !thresholdNonceData) {
nonceResult = metadataNonceResult;
} else {
throw new Error(
`invalid metadata result from nodes, nonce metadata is empty for verifier: ${verifier} and verifierId: ${verifierParams.verifier_id}`
);
}
}
let metadataNonce = new BN(nonceResult?.nonce ? nonceResult.nonce.padStart(64, "0") : "0", "hex");
let finalPubKey: curve.base.BasePoint;
let pubNonce: { X: string; Y: string } | undefined;
Expand Down
12 changes: 12 additions & 0 deletions src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,3 +194,15 @@ export interface MetadataParams {
};
signature: string;
}

export interface SapphireMetadataParams {
namespace?: string;
pub_key_X: string;
pub_key_Y: string;
key_type: "secp256k1" | "ed25519";
set_data: {
operation: "getNonce" | "getOrSetNonce" | string;
timestamp?: string;
};
signature?: string;
}
Loading