@iqauth/sdk 2.6.4 → 2.8.1

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.
Files changed (117) hide show
  1. package/README.md +173 -1
  2. package/dist/browser-session.d.mts +4 -4
  3. package/dist/browser-session.d.ts +4 -4
  4. package/dist/browser-session.js +212 -46
  5. package/dist/browser-session.mjs +3 -3
  6. package/dist/browser.d.mts +5 -5
  7. package/dist/browser.d.ts +5 -5
  8. package/dist/browser.js +293 -34
  9. package/dist/browser.mjs +5 -5
  10. package/dist/{chunk-BVV54LPI.mjs → chunk-25SSYDIP.mjs} +10 -4
  11. package/dist/{chunk-XAWYUPMO.mjs → chunk-4V7FKOTG.mjs} +242 -22
  12. package/dist/{chunk-6I6RM4MN.mjs → chunk-6PJRLRB4.mjs} +33 -3
  13. package/dist/{chunk-SL3KRS4W.mjs → chunk-CIJORODR.mjs} +23 -1
  14. package/dist/{chunk-LIZYFXH7.mjs → chunk-DFWHSDYQ.mjs} +1 -1
  15. package/dist/chunk-GLXSIGVS.mjs +66 -0
  16. package/dist/{chunk-DJIBN2N7.mjs → chunk-GN37E64I.mjs} +29 -7
  17. package/dist/{chunk-WQWBJSSS.mjs → chunk-HVHNYPDC.mjs} +6 -6
  18. package/dist/chunk-JRDVUWAL.mjs +46 -0
  19. package/dist/{chunk-UNYDG2L4.mjs → chunk-NUO2I65G.mjs} +56 -23
  20. package/dist/{chunk-5T7GHBX6.mjs → chunk-TLET552H.mjs} +36 -0
  21. package/dist/chunk-VYQ3ETCK.mjs +244 -0
  22. package/dist/{chunk-3JULWS6F.mjs → chunk-WCELYTJ3.mjs} +3 -3
  23. package/dist/chunk-WHT6WKTY.mjs +3180 -0
  24. package/dist/{chunk-MKKZULZR.mjs → chunk-WIFG74IK.mjs} +1 -1
  25. package/dist/chunk-WSH4SW7F.mjs +490 -0
  26. package/dist/{chunk-W3F4JYGP.mjs → chunk-ZLJPABB7.mjs} +139 -23
  27. package/dist/cli/index.js +2 -2
  28. package/dist/cli/index.mjs +2 -2
  29. package/dist/{client-BNQe3AgF.d.ts → client-D8L-PaWr.d.mts} +59 -6
  30. package/dist/{client-kYlJFgPv.d.mts → client-DkPL0EPZ.d.ts} +59 -6
  31. package/dist/{doctor-YYNHNMLD.mjs → doctor-JAFXWU3X.mjs} +2 -2
  32. package/dist/errors-Jl1Jtm-6.d.mts +107 -0
  33. package/dist/errors-Jl1Jtm-6.d.ts +107 -0
  34. package/dist/{express-CHpfa7D_.d.ts → express-Budysq4h.d.ts} +2 -2
  35. package/dist/{express-B6_1vBYZ.d.mts → express-DDTA3qV1.d.mts} +2 -2
  36. package/dist/express.d.mts +7 -6
  37. package/dist/express.d.ts +7 -6
  38. package/dist/express.js +563 -85
  39. package/dist/express.mjs +73 -34
  40. package/dist/fastify.d.mts +10 -0
  41. package/dist/fastify.d.ts +10 -0
  42. package/dist/fastify.js +589 -65
  43. package/dist/fastify.mjs +101 -11
  44. package/dist/hono.d.mts +10 -0
  45. package/dist/hono.d.ts +10 -0
  46. package/dist/hono.js +566 -65
  47. package/dist/hono.mjs +78 -11
  48. package/dist/index-Cko-d5po.d.mts +1848 -0
  49. package/dist/index-RNqwEcmY.d.ts +1848 -0
  50. package/dist/index.d.mts +56 -8
  51. package/dist/index.d.ts +56 -8
  52. package/dist/index.js +694 -75
  53. package/dist/index.mjs +30 -10
  54. package/dist/{keys-NLWFAOEM.mjs → keys-6Y776TG2.mjs} +2 -2
  55. package/dist/locales.d.mts +1 -1
  56. package/dist/locales.d.ts +1 -1
  57. package/dist/locales.js +36 -0
  58. package/dist/locales.mjs +1 -1
  59. package/dist/mobile.d.mts +77 -7
  60. package/dist/mobile.d.ts +77 -7
  61. package/dist/mobile.js +307 -46
  62. package/dist/mobile.mjs +98 -3
  63. package/dist/next.d.mts +10 -1
  64. package/dist/next.d.ts +10 -1
  65. package/dist/next.js +596 -205
  66. package/dist/next.mjs +83 -10
  67. package/dist/{provisioningBridge-88xjOS2n.d.mts → provisioningBridge-BXPMZCLe.d.ts} +30 -2
  68. package/dist/{provisioningBridge-DnTfzdZK.d.ts → provisioningBridge-IEycmsgb.d.mts} +30 -2
  69. package/dist/{publishableKey-BaR0HoAH.d.ts → publishableKey-f2kq-rKw.d.mts} +1 -1
  70. package/dist/{publishableKey-BaR0HoAH.d.mts → publishableKey-f2kq-rKw.d.ts} +1 -1
  71. package/dist/react-permissions.d.mts +52 -0
  72. package/dist/react-permissions.d.ts +52 -0
  73. package/dist/react-permissions.js +239 -0
  74. package/dist/react-permissions.mjs +98 -0
  75. package/dist/react.d.mts +9 -1624
  76. package/dist/react.d.ts +9 -1624
  77. package/dist/react.js +882 -73
  78. package/dist/react.mjs +71 -2631
  79. package/dist/{reverify-4UEJXUS6.mjs → reverify-C64QXKJO.mjs} +2 -2
  80. package/dist/server/handlers.d.mts +200 -4
  81. package/dist/server/handlers.d.ts +200 -4
  82. package/dist/server/handlers.js +530 -16
  83. package/dist/server/handlers.mjs +14 -3
  84. package/dist/server.d.mts +171 -8
  85. package/dist/server.d.ts +171 -8
  86. package/dist/server.js +579 -61
  87. package/dist/server.mjs +99 -12
  88. package/dist/service.d.mts +4 -4
  89. package/dist/service.d.ts +4 -4
  90. package/dist/service.js +212 -46
  91. package/dist/service.mjs +3 -3
  92. package/dist/{signIn-CiIBTJIh.d.mts → signIn-CReqfXsh.d.mts} +95 -3
  93. package/dist/{signIn-OCr88Zf8.d.ts → signIn-Cfa1GTpO.d.ts} +95 -3
  94. package/dist/{signIn-4OKLDEIH.mjs → signIn-SHBW6Z4T.mjs} +1 -1
  95. package/dist/test.mjs +3 -3
  96. package/dist/{tokens-DCyzzn8L.d.mts → tokens-9F6ETrzk.d.ts} +9 -2
  97. package/dist/{tokens-aHiGFr_E.d.ts → tokens-B06VtvUi.d.mts} +9 -2
  98. package/dist/{types-DZAflmmq.d.mts → types-Bn8O-OEd.d.mts} +164 -11
  99. package/dist/{types-DZAflmmq.d.ts → types-Bn8O-OEd.d.ts} +164 -11
  100. package/dist/{types-6bNdxesb.d.ts → types-DnU2LhXR.d.mts} +7 -1
  101. package/dist/{types-6bNdxesb.d.mts → types-DnU2LhXR.d.ts} +7 -1
  102. package/dist/webhooks.d.mts +113 -17
  103. package/dist/webhooks.d.ts +113 -17
  104. package/dist/webhooks.js +179 -15
  105. package/dist/webhooks.mjs +7 -1
  106. package/dist/ws.d.mts +2 -2
  107. package/dist/ws.d.ts +2 -2
  108. package/dist/ws.js +80 -30
  109. package/dist/ws.mjs +4 -4
  110. package/docs/error-handling.md +101 -0
  111. package/docs/guides/effective-permissions.md +171 -0
  112. package/docs/guides/invitations.md +65 -0
  113. package/package.json +19 -4
  114. package/dist/chunk-6TDJJER7.mjs +0 -217
  115. package/dist/chunk-UKZLOHZG.mjs +0 -83
  116. package/dist/errors-CDdl24MP.d.mts +0 -52
  117. package/dist/errors-CDdl24MP.d.ts +0 -52
@@ -0,0 +1,244 @@
1
+ // src/webhooks.ts
2
+ import crypto from "crypto";
3
+ var WebhookSignatureError = class extends Error {
4
+ constructor(code, message) {
5
+ super(message);
6
+ this.name = "WebhookSignatureError";
7
+ this.code = code;
8
+ }
9
+ };
10
+ var IQAUTH_SIGNATURE_HEADER = "x-iqauth-signature";
11
+ var LEGACY_SIGNATURE_HEADERS = [
12
+ "x-webhook-signature",
13
+ "x-iq-auth-signature",
14
+ "x-signature"
15
+ ];
16
+ function toBuffer(p) {
17
+ if (typeof p === "string") return Buffer.from(p, "utf8");
18
+ if (Buffer.isBuffer(p)) return p;
19
+ return Buffer.from(p);
20
+ }
21
+ function parseHeader(header) {
22
+ let t = NaN;
23
+ const v1 = [];
24
+ const trimmed = header.trim();
25
+ if (/^[0-9a-f]+$/i.test(trimmed)) {
26
+ v1.push(trimmed.toLowerCase());
27
+ return { t, v1 };
28
+ }
29
+ for (const part of trimmed.split(",")) {
30
+ const eqIdx = part.indexOf("=");
31
+ if (eqIdx === -1) continue;
32
+ const key = part.slice(0, eqIdx).trim().toLowerCase();
33
+ const value = part.slice(eqIdx + 1).trim();
34
+ if (!value) continue;
35
+ if (key === "t") t = Number(value);
36
+ else if (key === "v1") v1.push(value.toLowerCase());
37
+ }
38
+ return { t, v1 };
39
+ }
40
+ function timingSafeEqualHex(a, b) {
41
+ if (a.length !== b.length) return false;
42
+ try {
43
+ return crypto.timingSafeEqual(Buffer.from(a, "hex"), Buffer.from(b, "hex"));
44
+ } catch {
45
+ return false;
46
+ }
47
+ }
48
+ function computeSignatures(secret, body, t) {
49
+ const modern = crypto.createHmac("sha256", secret).update(body).digest("hex");
50
+ const legacy = Number.isFinite(t) ? crypto.createHmac("sha256", secret).update(`${t}.`).update(body).digest("hex") : null;
51
+ return { modern, legacy };
52
+ }
53
+ function verifyWebhookSignature(opts) {
54
+ const headerRaw = Array.isArray(opts.header) ? opts.header[0] : opts.header;
55
+ if (!headerRaw || typeof headerRaw !== "string") {
56
+ throw new WebhookSignatureError("MISSING_HEADER", "Missing X-IQAuth-Signature header");
57
+ }
58
+ if (!opts.secret) {
59
+ throw new WebhookSignatureError("MISSING_SECRET", "secret is required");
60
+ }
61
+ const { t, v1 } = parseHeader(headerRaw);
62
+ if (v1.length === 0) {
63
+ throw new WebhookSignatureError("MALFORMED_HEADER", `Could not parse signature header: ${headerRaw}`);
64
+ }
65
+ const tolerance = opts.toleranceSeconds ?? 300;
66
+ if (Number.isFinite(t)) {
67
+ const now = opts.nowSeconds ?? Math.floor(Date.now() / 1e3);
68
+ if (Math.abs(now - t) > tolerance) {
69
+ throw new WebhookSignatureError(
70
+ "TIMESTAMP_OUT_OF_TOLERANCE",
71
+ `Signature timestamp ${t} is outside the ${tolerance}s tolerance window (now=${now})`
72
+ );
73
+ }
74
+ }
75
+ const body = toBuffer(opts.payload);
76
+ const { modern, legacy } = computeSignatures(opts.secret, body, t);
77
+ const expected = Number.isFinite(t) ? legacy : modern;
78
+ const matched = expected !== null && v1.some((sig) => timingSafeEqualHex(sig.toLowerCase(), expected));
79
+ if (!matched) {
80
+ throw new WebhookSignatureError("SIGNATURE_MISMATCH", "Webhook signature does not match expected value");
81
+ }
82
+ let parsed;
83
+ try {
84
+ parsed = JSON.parse(body.toString("utf8"));
85
+ } catch {
86
+ throw new WebhookSignatureError("MALFORMED_BODY", "Webhook body is not valid JSON");
87
+ }
88
+ if (!Number.isFinite(t) && !opts.allowMissingTimestamp) {
89
+ const rawTime = parsed.time;
90
+ if (typeof rawTime !== "string" || !rawTime) {
91
+ throw new WebhookSignatureError(
92
+ "MISSING_TIMESTAMP",
93
+ "Modern webhook delivery has no header `t=` and no envelope `time`; cannot enforce replay protection. Use parseWebhookEvent, or set allowMissingTimestamp:true (insecure)."
94
+ );
95
+ }
96
+ const eventMs = Date.parse(rawTime);
97
+ if (!Number.isFinite(eventMs)) {
98
+ throw new WebhookSignatureError(
99
+ "MALFORMED_TIMESTAMP",
100
+ `Envelope \`time\` is not a valid ISO timestamp: ${rawTime}`
101
+ );
102
+ }
103
+ const nowMs = (opts.nowSeconds ?? Math.floor(Date.now() / 1e3)) * 1e3;
104
+ if (Math.abs(nowMs - eventMs) > tolerance * 1e3) {
105
+ throw new WebhookSignatureError(
106
+ "TIMESTAMP_OUT_OF_TOLERANCE",
107
+ `Envelope time ${rawTime} is outside the ${tolerance}s tolerance window`
108
+ );
109
+ }
110
+ }
111
+ return parsed;
112
+ }
113
+ function isValidWebhookSignature(opts) {
114
+ try {
115
+ verifyWebhookSignature(opts);
116
+ return true;
117
+ } catch {
118
+ return false;
119
+ }
120
+ }
121
+ function readHeader(headers, name) {
122
+ if (typeof headers.get === "function") {
123
+ return headers.get(name);
124
+ }
125
+ const lower = name.toLowerCase();
126
+ const obj = headers;
127
+ if (lower in obj) return obj[lower];
128
+ for (const [k, v] of Object.entries(obj)) {
129
+ if (k.toLowerCase() === lower) return v;
130
+ }
131
+ return void 0;
132
+ }
133
+ function pickHeaderValue(value) {
134
+ if (value == null) return null;
135
+ if (Array.isArray(value)) return value[0] ?? null;
136
+ return value;
137
+ }
138
+ function envelopeError(message) {
139
+ throw new WebhookSignatureError("MALFORMED_ENVELOPE", message);
140
+ }
141
+ function parseWebhookEvent(rawBody, headers, secrets, opts = {}) {
142
+ if (!Array.isArray(secrets) || secrets.length === 0 || secrets.every((s) => !s)) {
143
+ throw new WebhookSignatureError("MISSING_SECRET", "At least one signing secret is required");
144
+ }
145
+ let headerValue = pickHeaderValue(readHeader(headers, IQAUTH_SIGNATURE_HEADER));
146
+ let usedHeader = IQAUTH_SIGNATURE_HEADER;
147
+ if (!headerValue) {
148
+ for (const legacy of LEGACY_SIGNATURE_HEADERS) {
149
+ const v = pickHeaderValue(readHeader(headers, legacy));
150
+ if (v) {
151
+ headerValue = v;
152
+ usedHeader = legacy;
153
+ const log = opts.onDeprecation ?? ((m) => console.warn(m));
154
+ log(
155
+ `[iqauth] deprecation: webhook delivery used legacy header "${legacy}"; migrate sender to "X-IQAuth-Signature" (back-compat removed in next minor).`
156
+ );
157
+ break;
158
+ }
159
+ }
160
+ }
161
+ if (!headerValue) {
162
+ throw new WebhookSignatureError(
163
+ "MISSING_HEADER",
164
+ `Missing webhook signature header. Expected "X-IQAuth-Signature" (or one of: ${LEGACY_SIGNATURE_HEADERS.join(", ")}).`
165
+ );
166
+ }
167
+ const { t, v1 } = parseHeader(headerValue);
168
+ if (v1.length === 0) {
169
+ throw new WebhookSignatureError(
170
+ "MALFORMED_HEADER",
171
+ `Could not parse "${usedHeader}" header value: ${headerValue}`
172
+ );
173
+ }
174
+ const body = toBuffer(rawBody);
175
+ let verifiedIdx = -1;
176
+ for (let i = 0; i < secrets.length; i++) {
177
+ const secret = secrets[i];
178
+ if (!secret) continue;
179
+ const { modern, legacy } = computeSignatures(secret, body, t);
180
+ const expected = Number.isFinite(t) ? legacy : modern;
181
+ const ok = expected !== null && v1.some((sig) => timingSafeEqualHex(sig.toLowerCase(), expected));
182
+ if (ok) {
183
+ verifiedIdx = i;
184
+ break;
185
+ }
186
+ }
187
+ if (verifiedIdx === -1) {
188
+ throw new WebhookSignatureError(
189
+ "SIGNATURE_MISMATCH",
190
+ "Webhook signature does not match any provided secret"
191
+ );
192
+ }
193
+ let parsed;
194
+ try {
195
+ parsed = JSON.parse(body.toString("utf8"));
196
+ } catch {
197
+ throw new WebhookSignatureError("MALFORMED_BODY", "Webhook body is not valid JSON");
198
+ }
199
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
200
+ envelopeError("Webhook body must be a JSON object");
201
+ }
202
+ const { id, type, subject, time, data, tenantId, specversion } = parsed;
203
+ if (specversion !== "1.0") {
204
+ envelopeError(`Envelope \`specversion\` must be "1.0" (got: ${JSON.stringify(specversion)})`);
205
+ }
206
+ if (typeof id !== "string" || !id) envelopeError("Envelope missing required string `id`");
207
+ if (typeof type !== "string" || !type) envelopeError("Envelope missing required string `type`");
208
+ if (typeof subject !== "string" || !subject) envelopeError("Envelope missing required string `subject`");
209
+ if (typeof time !== "string" || !time) envelopeError("Envelope missing required string `time`");
210
+ if (typeof tenantId !== "string" || !tenantId) envelopeError("Envelope missing required string `tenantId`");
211
+ if (data === void 0 || data === null || typeof data !== "object" || Array.isArray(data)) {
212
+ envelopeError("Envelope `data` must be an object");
213
+ }
214
+ const tolerance = opts.toleranceSeconds ?? 300;
215
+ const eventMs = Date.parse(time);
216
+ if (!Number.isFinite(eventMs)) envelopeError(`Envelope \`time\` is not a valid ISO timestamp: ${time}`);
217
+ const nowMs = opts.nowMs ?? Date.now();
218
+ if (Math.abs(nowMs - eventMs) > tolerance * 1e3) {
219
+ throw new WebhookSignatureError(
220
+ "TIMESTAMP_OUT_OF_TOLERANCE",
221
+ `Envelope time ${time} is outside the ${tolerance}s tolerance window (now=${new Date(nowMs).toISOString()})`
222
+ );
223
+ }
224
+ return {
225
+ specversion: "1.0",
226
+ id,
227
+ type,
228
+ subject,
229
+ time,
230
+ tenantId,
231
+ data,
232
+ idempotencyKey: id,
233
+ verifiedWithSecretIndex: verifiedIdx
234
+ };
235
+ }
236
+
237
+ export {
238
+ WebhookSignatureError,
239
+ IQAUTH_SIGNATURE_HEADER,
240
+ LEGACY_SIGNATURE_HEADERS,
241
+ verifyWebhookSignature,
242
+ isValidWebhookSignature,
243
+ parseWebhookEvent
244
+ };
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  assertPublishableKey
3
- } from "./chunk-WQWBJSSS.mjs";
3
+ } from "./chunk-HVHNYPDC.mjs";
4
4
  import {
5
5
  TokensModule
6
- } from "./chunk-UNYDG2L4.mjs";
6
+ } from "./chunk-NUO2I65G.mjs";
7
7
  import {
8
8
  IQAuthError
9
- } from "./chunk-6I6RM4MN.mjs";
9
+ } from "./chunk-6PJRLRB4.mjs";
10
10
 
11
11
  // src/ws.ts
12
12
  var DEFAULT_COOKIE = "iqauth_at";