Skip to content

Commit d86affb

Browse files
committed
feat: user login process audit
1 parent 9191cde commit d86affb

6 files changed

Lines changed: 119 additions & 6 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,3 +105,5 @@ dist
105105

106106
.env.test
107107
**/*.DS_Store
108+
109+
.npmrc

package-lock.json

Lines changed: 20 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@toruslabs/torus.js",
3-
"version": "17.2.2",
3+
"version": "17.2.3",
44
"description": "Handle communication with torus nodes",
55
"main": "dist/lib.cjs/index.js",
66
"module": "dist/lib.esm/index.js",

src/helpers/citadelUtils.ts

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
import { BUILD_ENV_TYPE, CITADEL_SERVER_MAP } from "@toruslabs/constants";
2-
import { get } from "@toruslabs/http-helpers";
1+
import { BUILD_ENV_TYPE, CITADEL_SERVER_MAP, TORUS_NETWORK_TYPE } from "@toruslabs/constants";
2+
import { get, put } from "@toruslabs/http-helpers";
3+
4+
import { RetrieveSharesParams } from "../interfaces";
35

46
export interface CitadelAllowParams {
57
buildEnv: BUILD_ENV_TYPE;
@@ -14,6 +16,24 @@ export interface CitadelAllowParams {
1416
torusLoginFailed?: boolean;
1517
}
1618

19+
export interface CitadelAuthFlowAuditParams {
20+
oauthInitiated?: boolean;
21+
oauthVerified?: boolean;
22+
oauthCompleted?: boolean;
23+
oauthVerificationFailed?: boolean;
24+
oauthFailed?: boolean;
25+
}
26+
27+
export interface CitadelAuditParams extends CitadelAuthFlowAuditParams {
28+
recordId: string;
29+
authConnection: string;
30+
authConnectionId: string;
31+
groupedAuthConnectionId: string;
32+
userId: string;
33+
web3AuthNetwork: string;
34+
web3AuthClientId: string;
35+
}
36+
1737
export function buildAllowUrl(params: CitadelAllowParams): string {
1838
const url = new URL(`${CITADEL_SERVER_MAP[params.buildEnv]}/v1/signer/allow`);
1939
url.searchParams.set("recordid", params.recordId);
@@ -36,10 +56,33 @@ export function buildAllowUrl(params: CitadelAllowParams): string {
3656
return url.toString();
3757
}
3858

59+
export function buildAuditPayload(
60+
network: TORUS_NETWORK_TYPE,
61+
clientId: string,
62+
params: RetrieveSharesParams,
63+
authFlowAuditParams: CitadelAuthFlowAuditParams
64+
): CitadelAuditParams {
65+
return {
66+
...authFlowAuditParams,
67+
recordId: params.recordId,
68+
authConnection: params.authConnection || "",
69+
authConnectionId: params.verifierParams.sub_verifier_ids?.[0] || "",
70+
groupedAuthConnectionId: params.verifier || "",
71+
userId: params.verifierParams.verifier_id || "",
72+
web3AuthNetwork: network,
73+
web3AuthClientId: clientId,
74+
};
75+
}
76+
3977
export async function callAllowApi(params: CitadelAllowParams): Promise<void> {
4078
await get<void>(buildAllowUrl(params));
4179
}
4280

81+
export async function callAuditApi(buildEnv: BUILD_ENV_TYPE, params: CitadelAuditParams): Promise<void> {
82+
const url = new URL(`${CITADEL_SERVER_MAP[buildEnv]}/v1/user/audit`);
83+
await put<void>(url.toString(), params);
84+
}
85+
4386
export function generateRecordId(): string {
4487
const cr = typeof globalThis === "object" ? globalThis.crypto : null;
4588
if (typeof cr?.randomUUID !== "function") throw new Error("crypto.randomUUID must be defined");

src/interfaces.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ export interface VerifierParams {
221221
[key: string]: unknown;
222222
verifier_id: string;
223223
extended_verifier_id?: string;
224+
sub_verifier_ids?: string[];
224225
}
225226

226227
export type StringifiedType = Record<string, unknown>;
@@ -283,6 +284,11 @@ export interface ImportKeyParams {
283284
newPrivateKey: string;
284285
extraParams?: TorusUtilsExtraParams;
285286
checkCommitment?: boolean;
287+
288+
/**
289+
* Optional recordId to used for the analytics tracking.
290+
*/
291+
recordId?: string;
286292
}
287293

288294
export interface RetrieveSharesParams {
@@ -295,4 +301,15 @@ export interface RetrieveSharesParams {
295301
extraParams?: TorusUtilsExtraParams;
296302
useDkg?: boolean;
297303
checkCommitment?: boolean;
304+
305+
/**
306+
* User social login provider name.
307+
* This is used for the analytics tracking.
308+
*/
309+
authConnection?: string;
310+
311+
/**
312+
* Optional recordId to used for the analytics tracking.
313+
*/
314+
recordId?: string;
298315
}

src/torus.ts

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ import { setAPIKey, setEmbedHost } from "@toruslabs/http-helpers";
44
import { config } from "./config";
55
import {
66
bigintToHex,
7+
buildAuditPayload,
78
bytesToHex,
89
callAllowApi,
10+
callAuditApi,
911
CitadelAllowParams,
12+
CitadelAuthFlowAuditParams,
1013
Curve,
1114
encodeEd25519Point,
1215
generateAddressFromPubKey,
@@ -150,17 +153,24 @@ class Torus {
150153
extraParams.session_token_exp_second = Torus.sessionTime;
151154
}
152155

156+
const recordId = params.recordId || generateRecordId();
157+
153158
const allowParams = {
154159
buildEnv: this.buildEnv,
155160
verifier,
156161
verifierId: verifierParams.verifier_id,
157162
network: this.network,
158163
clientId: this.clientId,
159164
source: this.source,
160-
recordId: generateRecordId(),
165+
recordId,
161166
};
162167

163168
let result: TorusKey;
169+
170+
// report oauth completed
171+
// if recordId isn't provided in the params, we will also report oauth initiated
172+
this.reportUserAuthFlowAudit({ ...params, recordId }, { oauthCompleted: true, ...(params.recordId ? {} : { oauthInitiated: true }) });
173+
164174
try {
165175
result = await retrieveOrImportShare({
166176
recordId: allowParams.recordId,
@@ -185,8 +195,13 @@ class Torus {
185195
checkCommitment,
186196
source: this.source,
187197
});
198+
199+
// report oauth verified
200+
this.reportUserAuthFlowAudit({ ...params, recordId }, { oauthVerified: true, ...(params.recordId ? {} : { oauthInitiated: true }) });
188201
} catch (error) {
189202
this.reportSignerAllow({ ...allowParams, torusLoginFailed: true });
203+
// report oauth verification failed
204+
this.reportUserAuthFlowAudit({ ...params, recordId }, { oauthVerificationFailed: true });
190205
throw error;
191206
}
192207

@@ -202,6 +217,21 @@ class Torus {
202217
}
203218
}
204219

220+
/**
221+
* Report user auth flow audit to the citadel server.
222+
* @param recordId - The record id to be used for the analytics tracking.
223+
* @param params - The parameters for the retrieve shares operation.
224+
* @param authStepStatus - The status of the authentication steps.
225+
*/
226+
async reportUserAuthFlowAudit(params: RetrieveSharesParams, authFlowAuditParams: CitadelAuthFlowAuditParams): Promise<void> {
227+
try {
228+
const auditParams = buildAuditPayload(this.network, this.clientId, params, authFlowAuditParams);
229+
await callAuditApi(this.buildEnv, auditParams);
230+
} catch (error) {
231+
log.error("Failed to log user auth flow audit", error);
232+
}
233+
}
234+
205235
async getPublicAddress(
206236
endpoints: string[],
207237
torusNodePubs: INodePub[],
@@ -262,8 +292,10 @@ class Torus {
262292
}
263293
}
264294

295+
const recordId = params.recordId || generateRecordId();
296+
265297
return retrieveOrImportShare({
266-
recordId: generateRecordId(),
298+
recordId,
267299
legacyMetadataHost: this.legacyMetadataHost,
268300
serverTimeOffset: this.serverTimeOffset,
269301
enableOneKey: this.enableOneKey,

0 commit comments

Comments
 (0)