@worldcoin/idkit-core 1.1.3 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -20,12 +20,12 @@ declare enum VerificationLevel {
20
20
  type IDKitConfig = {
21
21
  /** Unique identifier for the app verifying the action. This should be the app ID obtained from the Developer Portal. */
22
22
  app_id: `app_${string}`;
23
+ /** Identifier for the action the user is performing. Should be left blank for [Sign in with Worldcoin](https://docs.worldcoin.org/id/sign-in). */
24
+ action: AbiEncodedValue | string;
23
25
  /** The description of the specific action (shown to users in World App). Only recommended for actions created on-the-fly. */
24
26
  action_description?: string;
25
27
  /** Encodes data into a proof that must match when validating. Read more on the [On-chain section](https://docs.worldcoin.org/advanced/on-chain). */
26
28
  signal?: AbiEncodedValue | string;
27
- /** Identifier for the action the user is performing. Should be left blank for [Sign in with Worldcoin](https://docs.worldcoin.org/id/sign-in). */
28
- action?: AbiEncodedValue | string;
29
29
  /** URL to a third-party bridge to use when connecting to the World App. Optional. */
30
30
  bridge_url?: string;
31
31
  /** The minimum required level of verification. Defaults to "orb". */
package/build/index.cjs CHANGED
@@ -69,6 +69,45 @@ var VerificationLevel = /* @__PURE__ */ ((VerificationLevel2) => {
69
69
  // src/bridge.ts
70
70
  var import_zustand = require("zustand");
71
71
 
72
+ // src/lib/validation.ts
73
+ function validate_bridge_url(bridge_url, is_staging) {
74
+ try {
75
+ new URL(bridge_url);
76
+ } catch (e) {
77
+ return { valid: false, errors: ["Failed to parse Bridge URL."] };
78
+ }
79
+ const test_url = new URL(bridge_url);
80
+ const errors = [];
81
+ if (is_staging && ["localhost", "127.0.0.1"].includes(test_url.hostname)) {
82
+ console.log("Using staging app_id with localhost bridge_url. Skipping validation.");
83
+ return { valid: true };
84
+ }
85
+ if (test_url.protocol !== "https:") {
86
+ errors.push("Bridge URL must use HTTPS.");
87
+ }
88
+ if (test_url.port) {
89
+ errors.push("Bridge URL must use the default port (443).");
90
+ }
91
+ if (test_url.pathname !== "/") {
92
+ errors.push("Bridge URL must not have a path.");
93
+ }
94
+ if (test_url.search) {
95
+ errors.push("Bridge URL must not have query parameters.");
96
+ }
97
+ if (test_url.hash) {
98
+ errors.push("Bridge URL must not have a fragment.");
99
+ }
100
+ if (!test_url.hostname.endsWith(".worldcoin.org") && !test_url.hostname.endsWith(".toolsforhumanity.com")) {
101
+ console.warn(
102
+ "Bridge URL should be a subdomain of worldcoin.org or toolsforhumanity.com. The user's identity wallet may refuse to connect. This is a temporary measure and may be removed in the future."
103
+ );
104
+ }
105
+ if (errors.length) {
106
+ return { valid: false, errors };
107
+ }
108
+ return { valid: true };
109
+ }
110
+
72
111
  // src/lib/hashing.ts
73
112
  var import_buffer = require("buffer/index.js");
74
113
  var import_viem = require("viem");
@@ -177,7 +216,15 @@ var useWorldBridgeStore = (0, import_zustand.create)((set, get) => ({
177
216
  verificationState: "loading_widget" /* PreparingClient */,
178
217
  createClient: async ({ bridge_url, app_id, verification_level, action_description, action, signal }) => {
179
218
  const { key, iv } = await generateKey();
180
- const res = await fetch(`${bridge_url ?? DEFAULT_BRIDGE_URL}/request`, {
219
+ if (bridge_url) {
220
+ const validation = validate_bridge_url(bridge_url, app_id.includes("staging"));
221
+ if (!validation.valid) {
222
+ console.error(validation.errors.join("\n"));
223
+ set({ verificationState: "failed" /* Failed */ });
224
+ throw new Error("Invalid bridge_url. Please check the console for more details.");
225
+ }
226
+ }
227
+ const res = await fetch(new URL("/request", bridge_url ?? DEFAULT_BRIDGE_URL), {
181
228
  method: "POST",
182
229
  headers: { "Content-Type": "application/json" },
183
230
  body: JSON.stringify(
@@ -217,7 +264,7 @@ var useWorldBridgeStore = (0, import_zustand.create)((set, get) => ({
217
264
  const key = get().key;
218
265
  if (!key)
219
266
  throw new Error("No keypair found. Please call `createClient` first.");
220
- const res = await fetch(`${get().bridge_url}/response/${get().requestId}`);
267
+ const res = await fetch(new URL(`/response/${get().requestId}`, get().bridge_url));
221
268
  if (!res.ok) {
222
269
  return set({
223
270
  errorCode: "connection_failed" /* ConnectionFailed */,
package/build/index.d.cts CHANGED
@@ -1,39 +1,9 @@
1
- import { V as VerificationLevel, I as IDKitConfig } from './config-325e0567.js';
2
- export { A as AbiEncodedValue, C as CredentialType } from './config-325e0567.js';
1
+ import { I as ISuccessResult, A as AppErrorCodes, V as VerificationState } from './result-01cf95f2.js';
2
+ export { a as IErrorState } from './result-01cf95f2.js';
3
+ import { I as IDKitConfig, V as VerificationLevel } from './config-f327cc3d.js';
4
+ export { A as AbiEncodedValue, C as CredentialType } from './config-f327cc3d.js';
3
5
  import * as zustand from 'zustand';
4
6
 
5
- declare enum AppErrorCodes {
6
- ConnectionFailed = "connection_failed",
7
- VerificationRejected = "verification_rejected",
8
- MaxVerificationsReached = "max_verifications_reached",
9
- CredentialUnavailable = "credential_unavailable",
10
- MalformedRequest = "malformed_request",
11
- InvalidNetwork = "invalid_network",
12
- InclusionProofFailed = "inclusion_proof_failed",
13
- InclusionProofPending = "inclusion_proof_pending",
14
- UnexpectedResponse = "unexpected_response",// NOTE: when the World app returns an unexpected response
15
- FailedByHostApp = "failed_by_host_app",// NOTE: Host app failed/rejected verification (does not come from World App / simulator)
16
- GenericError = "generic_error"
17
- }
18
- declare enum VerificationState {
19
- PreparingClient = "loading_widget",
20
- WaitingForConnection = "awaiting_connection",// Awaiting connection from the wallet
21
- WaitingForApp = "awaiting_app",// Awaiting user confirmation in wallet
22
- Confirmed = "confirmed",
23
- Failed = "failed"
24
- }
25
-
26
- interface ISuccessResult {
27
- proof: string;
28
- merkle_root: string;
29
- nullifier_hash: string;
30
- verification_level: VerificationLevel;
31
- }
32
- interface IErrorState {
33
- code: AppErrorCodes;
34
- message?: string;
35
- }
36
-
37
7
  type WorldBridgeStore = {
38
8
  bridge_url: string;
39
9
  iv: Uint8Array | null;
@@ -57,4 +27,4 @@ declare const DEFAULT_VERIFICATION_LEVEL = VerificationLevel.Orb;
57
27
  */
58
28
  declare const verification_level_to_credential_types: (verification_level: VerificationLevel) => string[];
59
29
 
60
- export { AppErrorCodes, DEFAULT_VERIFICATION_LEVEL, IDKitConfig, IErrorState, ISuccessResult, VerificationLevel, VerificationState, WorldBridgeStore, useWorldBridgeStore, verification_level_to_credential_types };
30
+ export { AppErrorCodes, DEFAULT_VERIFICATION_LEVEL, IDKitConfig, ISuccessResult, VerificationLevel, VerificationState, WorldBridgeStore, useWorldBridgeStore, verification_level_to_credential_types };
package/build/index.d.ts CHANGED
@@ -1,39 +1,9 @@
1
- import { V as VerificationLevel, I as IDKitConfig } from './config-325e0567.js';
2
- export { A as AbiEncodedValue, C as CredentialType } from './config-325e0567.js';
1
+ import { I as ISuccessResult, A as AppErrorCodes, V as VerificationState } from './result-01cf95f2.js';
2
+ export { a as IErrorState } from './result-01cf95f2.js';
3
+ import { I as IDKitConfig, V as VerificationLevel } from './config-f327cc3d.js';
4
+ export { A as AbiEncodedValue, C as CredentialType } from './config-f327cc3d.js';
3
5
  import * as zustand from 'zustand';
4
6
 
5
- declare enum AppErrorCodes {
6
- ConnectionFailed = "connection_failed",
7
- VerificationRejected = "verification_rejected",
8
- MaxVerificationsReached = "max_verifications_reached",
9
- CredentialUnavailable = "credential_unavailable",
10
- MalformedRequest = "malformed_request",
11
- InvalidNetwork = "invalid_network",
12
- InclusionProofFailed = "inclusion_proof_failed",
13
- InclusionProofPending = "inclusion_proof_pending",
14
- UnexpectedResponse = "unexpected_response",// NOTE: when the World app returns an unexpected response
15
- FailedByHostApp = "failed_by_host_app",// NOTE: Host app failed/rejected verification (does not come from World App / simulator)
16
- GenericError = "generic_error"
17
- }
18
- declare enum VerificationState {
19
- PreparingClient = "loading_widget",
20
- WaitingForConnection = "awaiting_connection",// Awaiting connection from the wallet
21
- WaitingForApp = "awaiting_app",// Awaiting user confirmation in wallet
22
- Confirmed = "confirmed",
23
- Failed = "failed"
24
- }
25
-
26
- interface ISuccessResult {
27
- proof: string;
28
- merkle_root: string;
29
- nullifier_hash: string;
30
- verification_level: VerificationLevel;
31
- }
32
- interface IErrorState {
33
- code: AppErrorCodes;
34
- message?: string;
35
- }
36
-
37
7
  type WorldBridgeStore = {
38
8
  bridge_url: string;
39
9
  iv: Uint8Array | null;
@@ -57,4 +27,4 @@ declare const DEFAULT_VERIFICATION_LEVEL = VerificationLevel.Orb;
57
27
  */
58
28
  declare const verification_level_to_credential_types: (verification_level: VerificationLevel) => string[];
59
29
 
60
- export { AppErrorCodes, DEFAULT_VERIFICATION_LEVEL, IDKitConfig, IErrorState, ISuccessResult, VerificationLevel, VerificationState, WorldBridgeStore, useWorldBridgeStore, verification_level_to_credential_types };
30
+ export { AppErrorCodes, DEFAULT_VERIFICATION_LEVEL, IDKitConfig, ISuccessResult, VerificationLevel, VerificationState, WorldBridgeStore, useWorldBridgeStore, verification_level_to_credential_types };
package/build/index.js CHANGED
@@ -42,6 +42,45 @@ var VerificationLevel = /* @__PURE__ */ ((VerificationLevel2) => {
42
42
  // src/bridge.ts
43
43
  import { create } from "zustand";
44
44
 
45
+ // src/lib/validation.ts
46
+ function validate_bridge_url(bridge_url, is_staging) {
47
+ try {
48
+ new URL(bridge_url);
49
+ } catch (e) {
50
+ return { valid: false, errors: ["Failed to parse Bridge URL."] };
51
+ }
52
+ const test_url = new URL(bridge_url);
53
+ const errors = [];
54
+ if (is_staging && ["localhost", "127.0.0.1"].includes(test_url.hostname)) {
55
+ console.log("Using staging app_id with localhost bridge_url. Skipping validation.");
56
+ return { valid: true };
57
+ }
58
+ if (test_url.protocol !== "https:") {
59
+ errors.push("Bridge URL must use HTTPS.");
60
+ }
61
+ if (test_url.port) {
62
+ errors.push("Bridge URL must use the default port (443).");
63
+ }
64
+ if (test_url.pathname !== "/") {
65
+ errors.push("Bridge URL must not have a path.");
66
+ }
67
+ if (test_url.search) {
68
+ errors.push("Bridge URL must not have query parameters.");
69
+ }
70
+ if (test_url.hash) {
71
+ errors.push("Bridge URL must not have a fragment.");
72
+ }
73
+ if (!test_url.hostname.endsWith(".worldcoin.org") && !test_url.hostname.endsWith(".toolsforhumanity.com")) {
74
+ console.warn(
75
+ "Bridge URL should be a subdomain of worldcoin.org or toolsforhumanity.com. The user's identity wallet may refuse to connect. This is a temporary measure and may be removed in the future."
76
+ );
77
+ }
78
+ if (errors.length) {
79
+ return { valid: false, errors };
80
+ }
81
+ return { valid: true };
82
+ }
83
+
45
84
  // src/lib/utils.ts
46
85
  import { Buffer } from "buffer/index.js";
47
86
  var DEFAULT_VERIFICATION_LEVEL = "orb" /* Orb */;
@@ -109,7 +148,15 @@ var useWorldBridgeStore = create((set, get) => ({
109
148
  verificationState: "loading_widget" /* PreparingClient */,
110
149
  createClient: async ({ bridge_url, app_id, verification_level, action_description, action, signal }) => {
111
150
  const { key, iv } = await generateKey();
112
- const res = await fetch(`${bridge_url ?? DEFAULT_BRIDGE_URL}/request`, {
151
+ if (bridge_url) {
152
+ const validation = validate_bridge_url(bridge_url, app_id.includes("staging"));
153
+ if (!validation.valid) {
154
+ console.error(validation.errors.join("\n"));
155
+ set({ verificationState: "failed" /* Failed */ });
156
+ throw new Error("Invalid bridge_url. Please check the console for more details.");
157
+ }
158
+ }
159
+ const res = await fetch(new URL("/request", bridge_url ?? DEFAULT_BRIDGE_URL), {
113
160
  method: "POST",
114
161
  headers: { "Content-Type": "application/json" },
115
162
  body: JSON.stringify(
@@ -149,7 +196,7 @@ var useWorldBridgeStore = create((set, get) => ({
149
196
  const key = get().key;
150
197
  if (!key)
151
198
  throw new Error("No keypair found. Please call `createClient` first.");
152
- const res = await fetch(`${get().bridge_url}/response/${get().requestId}`);
199
+ const res = await fetch(new URL(`/response/${get().requestId}`, get().bridge_url));
153
200
  if (!res.ok) {
154
201
  return set({
155
202
  errorCode: "connection_failed" /* ConnectionFailed */,
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/lib/backend.ts
21
+ var backend_exports = {};
22
+ __export(backend_exports, {
23
+ verifyCloudProof: () => verifyCloudProof
24
+ });
25
+ module.exports = __toCommonJS(backend_exports);
26
+
27
+ // src/lib/hashing.ts
28
+ var import_buffer = require("buffer/index.js");
29
+ var import_viem = require("viem");
30
+ function hashToField(input) {
31
+ if ((0, import_viem.isBytes)(input) || (0, import_viem.isHex)(input))
32
+ return hashEncodedBytes(input);
33
+ return hashString(input);
34
+ }
35
+ function hashString(input) {
36
+ const bytesInput = import_buffer.Buffer.from(input);
37
+ return hashEncodedBytes(bytesInput);
38
+ }
39
+ function hashEncodedBytes(input) {
40
+ const hash = BigInt((0, import_viem.keccak256)(input)) >> 8n;
41
+ const rawDigest = hash.toString(16);
42
+ return { hash, digest: `0x${rawDigest.padStart(64, "0")}` };
43
+ }
44
+
45
+ // src/lib/backend.ts
46
+ var import_browser_or_node = require("browser-or-node");
47
+ async function verifyCloudProof(proof, app_id, action, signal, endpoint) {
48
+ if (import_browser_or_node.isBrowser) {
49
+ throw new Error("verifyCloudProof can only be used in the backend.");
50
+ }
51
+ const response = await fetch(endpoint ?? `https://developer.worldcoin.org/api/v2/verify/${app_id}`, {
52
+ method: "POST",
53
+ headers: {
54
+ "Content-Type": "application/json"
55
+ },
56
+ body: JSON.stringify({
57
+ ...proof,
58
+ action,
59
+ signal_hash: hashToField(signal ?? "").digest
60
+ })
61
+ });
62
+ if (response.ok) {
63
+ return { success: true };
64
+ } else {
65
+ return { success: false, ...await response.json() };
66
+ }
67
+ }
68
+ // Annotate the CommonJS export names for ESM import in node:
69
+ 0 && (module.exports = {
70
+ verifyCloudProof
71
+ });
@@ -0,0 +1,12 @@
1
+ import { I as ISuccessResult } from '../result-01cf95f2.js';
2
+ import '../config-f327cc3d.js';
3
+
4
+ interface IVerifyResponse {
5
+ success: boolean;
6
+ code?: string;
7
+ detail?: string;
8
+ attribute?: string | null;
9
+ }
10
+ declare function verifyCloudProof(proof: ISuccessResult, app_id: `app_${string}`, action: string, signal?: string, endpoint?: URL | string): Promise<IVerifyResponse>;
11
+
12
+ export { IVerifyResponse, verifyCloudProof };
@@ -0,0 +1,12 @@
1
+ import { I as ISuccessResult } from '../result-01cf95f2.js';
2
+ import '../config-f327cc3d.js';
3
+
4
+ interface IVerifyResponse {
5
+ success: boolean;
6
+ code?: string;
7
+ detail?: string;
8
+ attribute?: string | null;
9
+ }
10
+ declare function verifyCloudProof(proof: ISuccessResult, app_id: `app_${string}`, action: string, signal?: string, endpoint?: URL | string): Promise<IVerifyResponse>;
11
+
12
+ export { IVerifyResponse, verifyCloudProof };
@@ -0,0 +1,30 @@
1
+ import {
2
+ hashToField
3
+ } from "../chunk-XHZXOIDF.js";
4
+
5
+ // src/lib/backend.ts
6
+ import { isBrowser } from "browser-or-node";
7
+ async function verifyCloudProof(proof, app_id, action, signal, endpoint) {
8
+ if (isBrowser) {
9
+ throw new Error("verifyCloudProof can only be used in the backend.");
10
+ }
11
+ const response = await fetch(endpoint ?? `https://developer.worldcoin.org/api/v2/verify/${app_id}`, {
12
+ method: "POST",
13
+ headers: {
14
+ "Content-Type": "application/json"
15
+ },
16
+ body: JSON.stringify({
17
+ ...proof,
18
+ action,
19
+ signal_hash: hashToField(signal ?? "").digest
20
+ })
21
+ });
22
+ if (response.ok) {
23
+ return { success: true };
24
+ } else {
25
+ return { success: false, ...await response.json() };
26
+ }
27
+ }
28
+ export {
29
+ verifyCloudProof
30
+ };
@@ -1,4 +1,4 @@
1
- import { A as AbiEncodedValue, I as IDKitConfig } from '../config-325e0567.js';
1
+ import { A as AbiEncodedValue, I as IDKitConfig } from '../config-f327cc3d.js';
2
2
 
3
3
  interface HashFunctionOutput {
4
4
  hash: bigint;
@@ -1,4 +1,4 @@
1
- import { A as AbiEncodedValue, I as IDKitConfig } from '../config-325e0567.js';
1
+ import { A as AbiEncodedValue, I as IDKitConfig } from '../config-f327cc3d.js';
2
2
 
3
3
  interface HashFunctionOutput {
4
4
  hash: bigint;
@@ -0,0 +1,35 @@
1
+ import { V as VerificationLevel } from './config-f327cc3d.js';
2
+
3
+ declare enum AppErrorCodes {
4
+ ConnectionFailed = "connection_failed",
5
+ VerificationRejected = "verification_rejected",
6
+ MaxVerificationsReached = "max_verifications_reached",
7
+ CredentialUnavailable = "credential_unavailable",
8
+ MalformedRequest = "malformed_request",
9
+ InvalidNetwork = "invalid_network",
10
+ InclusionProofFailed = "inclusion_proof_failed",
11
+ InclusionProofPending = "inclusion_proof_pending",
12
+ UnexpectedResponse = "unexpected_response",// NOTE: when the World app returns an unexpected response
13
+ FailedByHostApp = "failed_by_host_app",// NOTE: Host app failed/rejected verification (does not come from World App / simulator)
14
+ GenericError = "generic_error"
15
+ }
16
+ declare enum VerificationState {
17
+ PreparingClient = "loading_widget",
18
+ WaitingForConnection = "awaiting_connection",// Awaiting connection from the wallet
19
+ WaitingForApp = "awaiting_app",// Awaiting user confirmation in wallet
20
+ Confirmed = "confirmed",
21
+ Failed = "failed"
22
+ }
23
+
24
+ interface ISuccessResult {
25
+ proof: string;
26
+ merkle_root: string;
27
+ nullifier_hash: string;
28
+ verification_level: VerificationLevel;
29
+ }
30
+ interface IErrorState {
31
+ code: AppErrorCodes;
32
+ message?: string;
33
+ }
34
+
35
+ export { AppErrorCodes as A, ISuccessResult as I, VerificationState as V, IErrorState as a };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@worldcoin/idkit-core",
3
- "version": "1.1.3",
3
+ "version": "1.2.0",
4
4
  "homepage": "https://docs.worldcoin.org/id/idkit",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -21,10 +21,18 @@
21
21
  "import": "./build/lib/hashing.js",
22
22
  "types": "./build/lib/hashing.d.ts",
23
23
  "require": "./build/lib/hashing.cjs"
24
+ },
25
+ "./backend": {
26
+ "import": "./build/lib/backend.js",
27
+ "types": "./build/lib/backend.d.ts",
28
+ "require": "./build/lib/backend.cjs"
24
29
  }
25
30
  },
26
31
  "typesVersions": {
27
32
  "*": {
33
+ "backend": [
34
+ "./build/lib/backend.d.ts"
35
+ ],
28
36
  "hashing": [
29
37
  "./build/lib/hashing.d.ts"
30
38
  ],
@@ -48,9 +56,10 @@
48
56
  "sybil resistance"
49
57
  ],
50
58
  "dependencies": {
59
+ "browser-or-node": "3.0.0-pre.0",
51
60
  "buffer": "^6.0.3",
52
61
  "viem": "^1.19.11",
53
- "zustand": "^4.3.3"
62
+ "zustand": "^4.5"
54
63
  },
55
64
  "devDependencies": {
56
65
  "@typescript-eslint/eslint-plugin": "^6.13.1",