Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -105,3 +105,5 @@ dist

.env.test
**/*.DS_Store

.npmrc
21 changes: 20 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

47 changes: 45 additions & 2 deletions src/helpers/citadelUtils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { BUILD_ENV_TYPE, CITADEL_SERVER_MAP } from "@toruslabs/constants";
import { get } from "@toruslabs/http-helpers";
import { BUILD_ENV_TYPE, CITADEL_SERVER_MAP, TORUS_NETWORK_TYPE } from "@toruslabs/constants";
import { get, put } from "@toruslabs/http-helpers";
Comment thread
arch1995 marked this conversation as resolved.

import { RetrieveSharesParams } from "../interfaces";

export interface CitadelAllowParams {
buildEnv: BUILD_ENV_TYPE;
Expand All @@ -14,6 +16,24 @@ export interface CitadelAllowParams {
torusLoginFailed?: boolean;
}

export interface CitadelAuthFlowAuditParams {
oauthInitiated?: boolean;
oauthVerified?: boolean;
oauthCompleted?: boolean;
oauthVerificationFailed?: boolean;
oauthFailed?: boolean;
}

export interface CitadelAuditParams extends CitadelAuthFlowAuditParams {
recordId: string;
authConnection: string;
authConnectionId: string;
groupedAuthConnectionId: string;
oauthUserId: string;
web3AuthNetwork: string;
web3AuthClientId: string;
}

export function buildAllowUrl(params: CitadelAllowParams): string {
const url = new URL(`${CITADEL_SERVER_MAP[params.buildEnv]}/v1/signer/allow`);
url.searchParams.set("recordid", params.recordId);
Expand All @@ -36,10 +56,33 @@ export function buildAllowUrl(params: CitadelAllowParams): string {
return url.toString();
}

export function buildAuditPayload(
network: TORUS_NETWORK_TYPE,
clientId: string,
params: RetrieveSharesParams,
authFlowAuditParams: CitadelAuthFlowAuditParams
): CitadelAuditParams {
return {
...authFlowAuditParams,
recordId: params.recordId,
Comment thread
cursor[bot] marked this conversation as resolved.
authConnection: params.authConnection || "",
authConnectionId: params.verifierParams.sub_verifier_ids?.[0] || "",
groupedAuthConnectionId: params.verifier || "",
oauthUserId: params.verifierParams.verifier_id || "",
web3AuthNetwork: network,
web3AuthClientId: clientId,
};
}

export async function callAllowApi(params: CitadelAllowParams): Promise<void> {
await get<void>(buildAllowUrl(params));
}

export async function callAuditApi(buildEnv: BUILD_ENV_TYPE, params: CitadelAuditParams): Promise<void> {
const url = new URL(`${CITADEL_SERVER_MAP[buildEnv]}/v1/user/audit`);
await put<void>(url.toString(), params);
}

export function generateRecordId(): string {
const cr = typeof globalThis === "object" ? globalThis.crypto : null;
if (typeof cr?.randomUUID !== "function") throw new Error("crypto.randomUUID must be defined");
Expand Down
17 changes: 17 additions & 0 deletions src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ export interface VerifierParams {
[key: string]: unknown;
verifier_id: string;
extended_verifier_id?: string;
sub_verifier_ids?: string[];
}

export type StringifiedType = Record<string, unknown>;
Expand Down Expand Up @@ -283,6 +284,11 @@ export interface ImportKeyParams {
newPrivateKey: string;
extraParams?: TorusUtilsExtraParams;
checkCommitment?: boolean;

/**
* Optional recordId to used for the analytics tracking.
*/
recordId?: string;
}

export interface RetrieveSharesParams {
Expand All @@ -295,4 +301,15 @@ export interface RetrieveSharesParams {
extraParams?: TorusUtilsExtraParams;
useDkg?: boolean;
checkCommitment?: boolean;

/**
* User social login provider name.
* This is used for the analytics tracking.
*/
authConnection?: string;

/**
* Optional recordId to used for the analytics tracking.
*/
recordId?: string;
}
36 changes: 34 additions & 2 deletions src/torus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ import { setAPIKey, setEmbedHost } from "@toruslabs/http-helpers";
import { config } from "./config";
import {
bigintToHex,
buildAuditPayload,
bytesToHex,
callAllowApi,
callAuditApi,
CitadelAllowParams,
CitadelAuthFlowAuditParams,
Curve,
encodeEd25519Point,
generateAddressFromPubKey,
Expand Down Expand Up @@ -150,17 +153,24 @@ class Torus {
extraParams.session_token_exp_second = Torus.sessionTime;
}

const recordId = params.recordId || generateRecordId();

const allowParams = {
buildEnv: this.buildEnv,
verifier,
verifierId: verifierParams.verifier_id,
network: this.network,
clientId: this.clientId,
source: this.source,
recordId: generateRecordId(),
recordId,
};

let result: TorusKey;

// report oauth completed, we won't await this call as it's only for analytics tracking
// if recordId isn't provided in the params, we will also report oauth initiated
this.reportUserAuthFlowAudit({ ...params, recordId }, { oauthCompleted: true, ...(params.recordId ? {} : { oauthInitiated: true }) });

try {
result = await retrieveOrImportShare({
recordId: allowParams.recordId,
Expand All @@ -185,8 +195,13 @@ class Torus {
checkCommitment,
source: this.source,
});

// report oauth verified, we won't await this call as it's only for analytics tracking
this.reportUserAuthFlowAudit({ ...params, recordId }, { oauthVerified: true });
} catch (error) {
this.reportSignerAllow({ ...allowParams, torusLoginFailed: true });
// report oauth verification failed, we won't await this call as it's only for analytics tracking
this.reportUserAuthFlowAudit({ ...params, recordId }, { oauthVerificationFailed: true });
throw error;
}

Expand All @@ -202,6 +217,21 @@ class Torus {
}
}

/**
* Report user auth flow audit to the citadel server.
* @param recordId - The record id to be used for the analytics tracking.
* @param params - The parameters for the retrieve shares operation.
* @param authStepStatus - The status of the authentication steps.
*/
async reportUserAuthFlowAudit(params: RetrieveSharesParams, authFlowAuditParams: CitadelAuthFlowAuditParams): Promise<void> {
try {
const auditParams = buildAuditPayload(this.network, this.clientId, params, authFlowAuditParams);
await callAuditApi(this.buildEnv, auditParams);
} catch (error) {
log.error("Failed to log user auth flow audit", error);
}
}

async getPublicAddress(
endpoints: string[],
torusNodePubs: INodePub[],
Expand Down Expand Up @@ -262,8 +292,10 @@ class Torus {
}
}

const recordId = params.recordId || generateRecordId();

return retrieveOrImportShare({
recordId: generateRecordId(),
recordId,
legacyMetadataHost: this.legacyMetadataHost,
serverTimeOffset: this.serverTimeOffset,
enableOneKey: this.enableOneKey,
Expand Down
Loading