Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions js/packages/core/src/__tests__/smoke.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ describe("Enums", () => {
expect(IDKitErrorCodes.CredentialUnavailable).toBe(
"credential_unavailable",
);
expect(IDKitErrorCodes.UserPresenceFailed).toBe("user_presence_failed");
expect(IDKitErrorCodes.Timeout).toBe("timeout");
expect(IDKitErrorCodes.Cancelled).toBe("cancelled");
});
Expand Down
47 changes: 47 additions & 0 deletions js/packages/core/src/transports/native.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,53 @@ describe("native transport request lifecycle", () => {
expect(completion.success).toBe(true);
});

it("defaults missing user_presence_completed to false on success", async () => {
const req = createNativeRequest({ payload: 1 }, baseConfig, {}, "");
activeRequest = req;

const completionPromise = req.pollUntilCompletion({ timeout: 1000 });

miniKitHandlers["miniapp-verify-action"]?.({
status: "success",
protocol_version: "3.0",
verification_level: "orb",
signal_hash: "0xabc",
proof: "0x01",
merkle_root: "0x02",
nullifier_hash: "0x03",
});

const completion = await completionPromise;
expect(completion.success).toBe(true);
if (completion.success) {
expect(completion.result.user_presence_completed).toBe(false);
}
});

it("preserves completed user presence on success", async () => {
const req = createNativeRequest({ payload: 1 }, baseConfig, {}, "");
activeRequest = req;

const completionPromise = req.pollUntilCompletion({ timeout: 1000 });

miniKitHandlers["miniapp-verify-action"]?.({
status: "success",
user_presence_completed: true,
protocol_version: "3.0",
verification_level: "orb",
signal_hash: "0xabc",
proof: "0x01",
merkle_root: "0x02",
nullifier_hash: "0x03",
});

const completion = await completionPromise;
expect(completion.success).toBe(true);
if (completion.success) {
expect(completion.result.user_presence_completed).toBe(true);
}
});

it("uses per-identifier signal hashes when response omits signal_hash", async () => {
const signalHashes = {
proof_of_human: hashSignal("poh-signal"),
Expand Down
17 changes: 17 additions & 0 deletions js/packages/core/src/transports/native.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,13 +167,16 @@ class NativeIDKitRequest implements IDKitRequest {
return;
}

const userPresenceCompleted = getUserPresenceCompleted(responsePayload);

this.complete({
success: true,
result: nativeResultToIDKitResult(
responsePayload,
config,
signalHashes,
legacySignalHash,
userPresenceCompleted,
),
});
};
Expand Down Expand Up @@ -349,6 +352,7 @@ function nativeResultToIDKitResult(
config: BuilderConfig,
signalHashes: Record<string, string>,
legacySignalHash: string,
userPresenceCompleted: boolean,
): IDKitResult {
const p = payload as Record<string, any>;
const rpNonce = config.rp_context?.nonce ?? "";
Expand All @@ -372,6 +376,7 @@ function nativeResultToIDKitResult(
issuer_schema_id: item.issuer_schema_id,
expires_at_min: item.expires_at_min,
})),
user_presence_completed: userPresenceCompleted,
environment: config.environment ?? "production",
} satisfies IDKitResultSession;
}
Expand All @@ -389,6 +394,7 @@ function nativeResultToIDKitResult(
issuer_schema_id: item.issuer_schema_id,
expires_at_min: item.expires_at_min,
})),
user_presence_completed: userPresenceCompleted,
environment: config.environment ?? "production",
} satisfies IDKitResultV4;
}
Expand All @@ -414,6 +420,7 @@ function nativeResultToIDKitResult(
merkle_root: v.merkle_root,
nullifier: v.nullifier_hash,
})),
user_presence_completed: userPresenceCompleted,
environment: config.environment ?? "production",
} satisfies IDKitResultV3;
}
Expand All @@ -435,6 +442,16 @@ function nativeResultToIDKitResult(
nullifier: p.nullifier_hash,
},
],
user_presence_completed: userPresenceCompleted,
environment: config.environment ?? "production",
} satisfies IDKitResultV3;
}

function getUserPresenceCompleted(payload: unknown): boolean {
const p = payload as Record<string, any>;
return (
p?.user_presence_completed === true ||
(p?.proof_response as Record<string, any> | undefined)
?.user_presence_completed === true
);
}
1 change: 0 additions & 1 deletion js/packages/core/src/types/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
export * from "./bridge";
export * from "./config";
export * from "./result";
1 change: 1 addition & 0 deletions js/packages/core/src/types/result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export enum IDKitErrorCodes {
ConnectionFailed = "connection_failed",
MaxVerificationsReached = "max_verifications_reached",
FailedByHostApp = "failed_by_host_app",
UserPresenceFailed = "user_presence_failed",
GenericError = "generic_error",
// Client-side errors
Timeout = "timeout",
Expand Down
12 changes: 6 additions & 6 deletions js/packages/react/src/__tests__/hooks.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ describe("request/session hooks", () => {
useIDKitSession({
app_id: "app_test",
rp_context: baseRpContext,
constraints: { type: "All", children: [] },
constraints: { all: [] },
}),
);

Expand Down Expand Up @@ -194,7 +194,7 @@ describe("request/session hooks", () => {
app_id: "app_test",
rp_context: baseRpContext,
existing_session_id: SESSION_ID_2,
preset: { type: "OrbLegacy" },
constraints: { all: [] },
}),
);

Expand Down Expand Up @@ -276,7 +276,7 @@ describe("request/session hooks", () => {
app_id: "app_test",
rp_context: baseRpContext,
return_to: "idkit://callback?step=create",
constraints: { type: "All", children: [] },
constraints: { all: [] },
}),
);

Expand Down Expand Up @@ -317,7 +317,7 @@ describe("request/session hooks", () => {
rp_context: baseRpContext,
existing_session_id: validSessionId,
return_to: "idkit://callback?step=prove",
constraints: { type: "All", children: [] },
constraints: { all: [] },
}),
);

Expand Down Expand Up @@ -346,7 +346,7 @@ describe("request/session hooks", () => {
app_id: "app_test",
rp_context: baseRpContext,
existing_session_id: " " as unknown as `session_${string}`,
constraints: { type: "All", children: [] },
constraints: { all: [] },
}),
);

Expand All @@ -367,7 +367,7 @@ describe("request/session hooks", () => {
app_id: "app_test",
rp_context: baseRpContext,
existing_session_id: "session_2" as `session_${string}`,
constraints: { type: "All", children: [] },
constraints: { all: [] },
}),
);

Expand Down
4 changes: 2 additions & 2 deletions js/packages/react/src/__tests__/widgets.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ function createRequestProps(
allow_legacy_proofs: false,
preset: { type: "OrbLegacy" },
...overrides,
};
} as IDKitRequestWidgetProps;
}

function createSessionProps(
Expand All @@ -88,7 +88,7 @@ function createSessionProps(
onSuccess: vi.fn(),
app_id: "app_test",
rp_context: baseRpContext,
preset: { type: "OrbLegacy" },
constraints: { all: [] },
...overrides,
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ enum class IDKitErrorCode(val rawValue: String) {
CONNECTION_FAILED("connection_failed"),
MAX_VERIFICATIONS_REACHED("max_verifications_reached"),
FAILED_BY_HOST_APP("failed_by_host_app"),
USER_PRESENCE_FAILED("user_presence_failed"),
GENERIC_ERROR("generic_error"),
TIMEOUT("timeout"),
CANCELLED("cancelled");
Expand All @@ -69,6 +70,7 @@ enum class IDKitErrorCode(val rawValue: String) {
AppError.CONNECTION_FAILED -> CONNECTION_FAILED
AppError.MAX_VERIFICATIONS_REACHED -> MAX_VERIFICATIONS_REACHED
AppError.FAILED_BY_HOST_APP -> FAILED_BY_HOST_APP
AppError.USER_PRESENCE_FAILED -> USER_PRESENCE_FAILED
AppError.GENERIC_ERROR -> GENERIC_ERROR
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,18 @@ import uniffi.idkit_core.RpContext
import uniffi.idkit_core.StatusWrapper

class IDKitTests {
private fun sampleResult(sessionId: String? = null): IDKitResult =
private fun sampleResult(
sessionId: String? = null,
userPresenceCompleted: Boolean = false,
): IDKitResult =
IDKitResult(
protocolVersion = "4.0",
nonce = "0x1234",
action = if (sessionId == null) "login" else null,
actionDescription = "Sample action",
sessionId = sessionId,
responses = emptyList<ResponseItem>(),
userPresenceCompleted = userPresenceCompleted,
environment = "production",
)

Expand Down Expand Up @@ -89,6 +93,10 @@ class IDKitTests {
IDKitStatus.Failed(IDKitErrorCode.INVALID_NETWORK),
IDKitRequest.mapStatus(StatusWrapper.Failed(AppError.INVALID_NETWORK)),
)
assertEquals(
IDKitStatus.Failed(IDKitErrorCode.USER_PRESENCE_FAILED),
IDKitRequest.mapStatus(StatusWrapper.Failed(AppError.USER_PRESENCE_FAILED)),
)
assertEquals(
IDKitStatus.NetworkingError(IDKitErrorCode.CONNECTION_FAILED),
IDKitRequest.mapStatus(StatusWrapper.NetworkingError(AppError.CONNECTION_FAILED)),
Expand Down
Loading
Loading