postex-auth-sdk-stage 2.3.0 → 2.3.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.
- package/README.md +15 -6
- package/dist/auth.d.ts +4 -2
- package/dist/postex-auth-sdk-stage.es.js +256 -244
- package/dist/postex-auth-sdk-stage.iife.js +1 -1
- package/dist/postex-auth-sdk-stage.umd.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -101,7 +101,7 @@ Accepts either a direct email string or an identifier object.
|
|
|
101
101
|
|
|
102
102
|
```typescript
|
|
103
103
|
async getStatus(
|
|
104
|
-
identifier: string | { email?: string; mobileNumber?: string }
|
|
104
|
+
identifier: string | { email?: string; mobileNumber?: string; username?: string }
|
|
105
105
|
): Promise<AuthStatusResponse>
|
|
106
106
|
```
|
|
107
107
|
|
|
@@ -110,6 +110,7 @@ async getStatus(
|
|
|
110
110
|
- `auth.getStatus('user@example.com')`
|
|
111
111
|
- `auth.getStatus({ email: 'user@example.com' })`
|
|
112
112
|
- `auth.getStatus({ mobileNumber: '03011266254' })`
|
|
113
|
+
- `auth.getStatus({ username: 'user123' })`
|
|
113
114
|
|
|
114
115
|
**Returns:**
|
|
115
116
|
|
|
@@ -126,10 +127,17 @@ Start the authentication process. Returns either a WebAuthn challenge or confirm
|
|
|
126
127
|
|
|
127
128
|
```typescript
|
|
128
129
|
async initiateAuth(
|
|
129
|
-
identifier: string | { email?: string; mobileNumber?: string }
|
|
130
|
+
identifier: string | { email?: string; mobileNumber?: string; username?: string }
|
|
130
131
|
): Promise<InitiateAuthResponse>
|
|
131
132
|
```
|
|
132
133
|
|
|
134
|
+
**Supported input forms:**
|
|
135
|
+
|
|
136
|
+
- `auth.initiateAuth('user@example.com')`
|
|
137
|
+
- `auth.initiateAuth({ email: 'user@example.com' })`
|
|
138
|
+
- `auth.initiateAuth({ mobileNumber: '03011266254' })`
|
|
139
|
+
- `auth.initiateAuth({ username: 'user123' })`
|
|
140
|
+
|
|
133
141
|
**Returns:**
|
|
134
142
|
|
|
135
143
|
- `status`: `'webauthn_challenge'` | `'otp_sent'`
|
|
@@ -140,11 +148,11 @@ async initiateAuth(
|
|
|
140
148
|
#### initiateOTP()
|
|
141
149
|
|
|
142
150
|
Start OTP authentication directly via `/otp/initiate`.
|
|
143
|
-
Requires at least one identifier: `email` or `
|
|
151
|
+
Requires at least one identifier: `email`, `mobileNumber`, or `username`.
|
|
144
152
|
|
|
145
153
|
```typescript
|
|
146
154
|
async initiateOTP(
|
|
147
|
-
identifier: string | { email?: string; mobileNumber?: string }
|
|
155
|
+
identifier: string | { email?: string; mobileNumber?: string; username?: string }
|
|
148
156
|
): Promise<{
|
|
149
157
|
message?: string;
|
|
150
158
|
}>
|
|
@@ -153,11 +161,12 @@ async initiateOTP(
|
|
|
153
161
|
**Supported input forms:**
|
|
154
162
|
- `auth.initiateOTP({ email: 'user@example.com' })`
|
|
155
163
|
- `auth.initiateOTP({ mobileNumber: '03011266254' })`
|
|
156
|
-
- `auth.initiateOTP({
|
|
164
|
+
- `auth.initiateOTP({ username: 'user123' })`
|
|
157
165
|
|
|
158
166
|
**Validation:**
|
|
159
167
|
|
|
160
|
-
- Throws an error when
|
|
168
|
+
- Throws an error when `email`, `mobileNumber`, and `username` are all missing/empty.
|
|
169
|
+
- `username` is trimmed, must be 64 characters or fewer, and must not contain control characters.
|
|
161
170
|
|
|
162
171
|
---
|
|
163
172
|
|
package/dist/auth.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ type AuthEntity = "xstak" | "postex" | "callcourier" | "postexglobal" | "postexs
|
|
|
2
2
|
type AuthIdentifierInput = string | {
|
|
3
3
|
email?: string;
|
|
4
4
|
mobileNumber?: string;
|
|
5
|
+
username?: string;
|
|
5
6
|
realm?: string;
|
|
6
7
|
};
|
|
7
8
|
interface RealmOptions {
|
|
@@ -126,6 +127,7 @@ export declare class AuthSDK {
|
|
|
126
127
|
private assertNoControlChars;
|
|
127
128
|
private validateEmail;
|
|
128
129
|
private validateMobileNumber;
|
|
130
|
+
private validateUsername;
|
|
129
131
|
private validateOTP;
|
|
130
132
|
private validateMagicLinkToken;
|
|
131
133
|
private validateRealm;
|
|
@@ -153,8 +155,8 @@ export declare class AuthSDK {
|
|
|
153
155
|
*/
|
|
154
156
|
initiateAuth(identifier: AuthIdentifierInput, options?: RealmOptions): Promise<InitiateAuthResponse>;
|
|
155
157
|
/**
|
|
156
|
-
* POST /otp/initiate - Direct OTP initiation using email
|
|
157
|
-
* Requires at least one identifier: email or
|
|
158
|
+
* POST /otp/initiate - Direct OTP initiation using email, mobile number, or username.
|
|
159
|
+
* Requires at least one identifier: email, mobileNumber, or username.
|
|
158
160
|
*/
|
|
159
161
|
initiateOTP(identifier: AuthIdentifierInput, options?: RealmOptions): Promise<OTPInitiateResponse>;
|
|
160
162
|
/**
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
function
|
|
1
|
+
function O() {
|
|
2
2
|
return typeof window < "u" && typeof window.PublicKeyCredential < "u" && typeof navigator < "u" && typeof navigator.credentials < "u";
|
|
3
3
|
}
|
|
4
|
-
async function
|
|
5
|
-
if (!
|
|
4
|
+
async function j() {
|
|
5
|
+
if (!O()) return !1;
|
|
6
6
|
try {
|
|
7
7
|
return await PublicKeyCredential.isConditionalMediationAvailable?.() ?? !1;
|
|
8
8
|
} catch {
|
|
9
9
|
return !1;
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
|
-
function
|
|
12
|
+
function N(o) {
|
|
13
13
|
const e = new Uint8Array(o);
|
|
14
14
|
let r = "";
|
|
15
15
|
for (let t = 0; t < e.byteLength; t++)
|
|
@@ -21,115 +21,115 @@ function C(o) {
|
|
|
21
21
|
throw new Error("Invalid base64: expected non-empty string");
|
|
22
22
|
const e = o.replace(/\s/g, "").replace(/-/g, "+").replace(/_/g, "/"), r = e.length % 4, t = r > 0 ? e + "=".repeat(4 - r) : e;
|
|
23
23
|
try {
|
|
24
|
-
const
|
|
25
|
-
for (let a = 0; a <
|
|
26
|
-
|
|
27
|
-
return
|
|
24
|
+
const n = atob(t), s = new Uint8Array(n.length);
|
|
25
|
+
for (let a = 0; a < n.length; a++)
|
|
26
|
+
s[a] = n.charCodeAt(a);
|
|
27
|
+
return s.buffer;
|
|
28
28
|
} catch {
|
|
29
29
|
throw new Error(
|
|
30
30
|
"Invalid base64: string is not correctly encoded. Check challenge/credentialId from server."
|
|
31
31
|
);
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
|
-
function
|
|
35
|
-
return
|
|
34
|
+
function p(o) {
|
|
35
|
+
return N(o).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
|
|
36
36
|
}
|
|
37
|
-
function
|
|
37
|
+
function H(o) {
|
|
38
38
|
return /^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i.test(
|
|
39
39
|
o
|
|
40
40
|
);
|
|
41
41
|
}
|
|
42
|
-
function
|
|
42
|
+
function J(o) {
|
|
43
43
|
const e = o.replace(/-/g, ""), r = new Uint8Array(e.length / 2);
|
|
44
44
|
for (let t = 0; t < r.length; t++)
|
|
45
45
|
r[t] = parseInt(e.substr(t * 2, 2), 16);
|
|
46
46
|
return r.buffer;
|
|
47
47
|
}
|
|
48
|
-
function
|
|
48
|
+
function b(o) {
|
|
49
49
|
if (!o || typeof o != "string")
|
|
50
50
|
throw new Error("Invalid input: expected non-empty string");
|
|
51
|
-
return
|
|
51
|
+
return H(o) ? J(o) : C(o);
|
|
52
52
|
}
|
|
53
53
|
function k(o) {
|
|
54
54
|
return new TextEncoder().encode(o).buffer;
|
|
55
55
|
}
|
|
56
|
-
function
|
|
56
|
+
function F(o) {
|
|
57
57
|
return String.fromCharCode(...o);
|
|
58
58
|
}
|
|
59
|
-
const
|
|
60
|
-
function
|
|
59
|
+
const G = "xpay_webauthn", W = 1, u = "passkey_data", E = "passkey_email", _ = "passkey_mobile_number";
|
|
60
|
+
function y() {
|
|
61
61
|
return new Promise((o, e) => {
|
|
62
|
-
const r = indexedDB.open(
|
|
62
|
+
const r = indexedDB.open(G, W);
|
|
63
63
|
r.onerror = () => e(r.error), r.onsuccess = () => o(r.result), r.onupgradeneeded = () => {
|
|
64
64
|
const t = r.result;
|
|
65
65
|
t.objectStoreNames.contains(u) || t.createObjectStore(u);
|
|
66
66
|
};
|
|
67
67
|
});
|
|
68
68
|
}
|
|
69
|
-
async function
|
|
69
|
+
async function Y() {
|
|
70
70
|
try {
|
|
71
|
-
const o = await
|
|
71
|
+
const o = await y();
|
|
72
72
|
return new Promise((e, r) => {
|
|
73
|
-
const t = o.transaction(u, "readonly"),
|
|
74
|
-
|
|
73
|
+
const t = o.transaction(u, "readonly"), s = t.objectStore(u).get(E);
|
|
74
|
+
s.onerror = () => r(s.error), s.onsuccess = () => e(s.result ?? null), t.oncomplete = () => o.close();
|
|
75
75
|
});
|
|
76
76
|
} catch {
|
|
77
77
|
return null;
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
|
-
async function
|
|
80
|
+
async function V(o) {
|
|
81
81
|
try {
|
|
82
|
-
const e = await
|
|
82
|
+
const e = await y();
|
|
83
83
|
return new Promise((r, t) => {
|
|
84
|
-
const
|
|
85
|
-
a.onerror = () => t(a.error), a.onsuccess = () => r(),
|
|
84
|
+
const n = e.transaction(u, "readwrite"), a = n.objectStore(u).put(o, E);
|
|
85
|
+
a.onerror = () => t(a.error), a.onsuccess = () => r(), n.oncomplete = () => e.close();
|
|
86
86
|
});
|
|
87
87
|
} catch {
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
-
async function
|
|
90
|
+
async function X() {
|
|
91
91
|
try {
|
|
92
|
-
const o = await
|
|
92
|
+
const o = await y();
|
|
93
93
|
return new Promise((e, r) => {
|
|
94
|
-
const t = o.transaction(u, "readwrite"),
|
|
95
|
-
|
|
94
|
+
const t = o.transaction(u, "readwrite"), s = t.objectStore(u).delete(E);
|
|
95
|
+
s.onerror = () => r(s.error), s.onsuccess = () => e(), t.oncomplete = () => o.close();
|
|
96
96
|
});
|
|
97
97
|
} catch {
|
|
98
98
|
}
|
|
99
99
|
}
|
|
100
|
-
async function
|
|
100
|
+
async function Z() {
|
|
101
101
|
try {
|
|
102
|
-
const o = await
|
|
102
|
+
const o = await y();
|
|
103
103
|
return new Promise((e, r) => {
|
|
104
|
-
const t = o.transaction(u, "readonly"),
|
|
105
|
-
|
|
104
|
+
const t = o.transaction(u, "readonly"), s = t.objectStore(u).get(_);
|
|
105
|
+
s.onerror = () => r(s.error), s.onsuccess = () => e(s.result ?? null), t.oncomplete = () => o.close();
|
|
106
106
|
});
|
|
107
107
|
} catch {
|
|
108
108
|
return null;
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
|
-
async function
|
|
111
|
+
async function Q(o) {
|
|
112
112
|
try {
|
|
113
|
-
const e = await
|
|
113
|
+
const e = await y();
|
|
114
114
|
return new Promise((r, t) => {
|
|
115
|
-
const
|
|
116
|
-
a.onerror = () => t(a.error), a.onsuccess = () => r(),
|
|
115
|
+
const n = e.transaction(u, "readwrite"), a = n.objectStore(u).put(o, _);
|
|
116
|
+
a.onerror = () => t(a.error), a.onsuccess = () => r(), n.oncomplete = () => e.close();
|
|
117
117
|
});
|
|
118
118
|
} catch {
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
|
-
async function
|
|
121
|
+
async function ee() {
|
|
122
122
|
try {
|
|
123
|
-
const o = await
|
|
123
|
+
const o = await y();
|
|
124
124
|
return new Promise((e, r) => {
|
|
125
|
-
const t = o.transaction(u, "readwrite"),
|
|
126
|
-
|
|
125
|
+
const t = o.transaction(u, "readwrite"), s = t.objectStore(u).delete(_);
|
|
126
|
+
s.onerror = () => r(s.error), s.onsuccess = () => e(), t.oncomplete = () => o.close();
|
|
127
127
|
});
|
|
128
128
|
} catch {
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
const S = "dpop_private_key", A = "dpop_public_key_jwk";
|
|
132
|
-
function
|
|
132
|
+
function K(o) {
|
|
133
133
|
if (!o || typeof o != "object") return !1;
|
|
134
134
|
const e = o;
|
|
135
135
|
return e.kty === "EC" && e.crv === "P-256" && typeof e.x == "string" && typeof e.y == "string";
|
|
@@ -139,7 +139,7 @@ class g extends Error {
|
|
|
139
139
|
super(e), this.name = "DPoPProofGenerationError";
|
|
140
140
|
}
|
|
141
141
|
}
|
|
142
|
-
function
|
|
142
|
+
function te(o) {
|
|
143
143
|
return {
|
|
144
144
|
kty: "EC",
|
|
145
145
|
crv: "P-256",
|
|
@@ -147,7 +147,7 @@ function ee(o) {
|
|
|
147
147
|
y: o.y
|
|
148
148
|
};
|
|
149
149
|
}
|
|
150
|
-
async function
|
|
150
|
+
async function q(o) {
|
|
151
151
|
const e = JSON.stringify({
|
|
152
152
|
crv: o.crv,
|
|
153
153
|
kty: o.kty,
|
|
@@ -157,47 +157,47 @@ async function K(o) {
|
|
|
157
157
|
"SHA-256",
|
|
158
158
|
new TextEncoder().encode(e)
|
|
159
159
|
);
|
|
160
|
-
return
|
|
160
|
+
return p(r);
|
|
161
161
|
}
|
|
162
|
-
async function
|
|
162
|
+
async function re(o) {
|
|
163
163
|
try {
|
|
164
|
-
const e = await
|
|
164
|
+
const e = await y();
|
|
165
165
|
return new Promise((r, t) => {
|
|
166
|
-
const
|
|
167
|
-
a.onerror = () => t(a.error), a.onsuccess = () => r(),
|
|
166
|
+
const n = e.transaction(u, "readwrite"), a = n.objectStore(u).put(o, S);
|
|
167
|
+
a.onerror = () => t(a.error), a.onsuccess = () => r(), n.oncomplete = () => e.close();
|
|
168
168
|
});
|
|
169
169
|
} catch (e) {
|
|
170
170
|
console.error("Failed to store DPoP private key:", e);
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
|
-
async function
|
|
173
|
+
async function se(o) {
|
|
174
174
|
try {
|
|
175
|
-
const e = await
|
|
175
|
+
const e = await y();
|
|
176
176
|
return new Promise((r, t) => {
|
|
177
|
-
const
|
|
178
|
-
a.onerror = () => t(a.error), a.onsuccess = () => r(),
|
|
177
|
+
const n = e.transaction(u, "readwrite"), a = n.objectStore(u).put(o, A);
|
|
178
|
+
a.onerror = () => t(a.error), a.onsuccess = () => r(), n.oncomplete = () => e.close();
|
|
179
179
|
});
|
|
180
180
|
} catch (e) {
|
|
181
181
|
console.error("Failed to store DPoP public key JWK:", e);
|
|
182
182
|
}
|
|
183
183
|
}
|
|
184
|
-
async function
|
|
184
|
+
async function $() {
|
|
185
185
|
try {
|
|
186
|
-
const o = await
|
|
186
|
+
const o = await y();
|
|
187
187
|
return new Promise((e, r) => {
|
|
188
|
-
const t = o.transaction(u, "readonly"),
|
|
189
|
-
|
|
188
|
+
const t = o.transaction(u, "readonly"), s = t.objectStore(u).get(S);
|
|
189
|
+
s.onerror = () => r(s.error), s.onsuccess = () => e(s.result ?? null), t.oncomplete = () => o.close();
|
|
190
190
|
});
|
|
191
191
|
} catch {
|
|
192
192
|
return null;
|
|
193
193
|
}
|
|
194
194
|
}
|
|
195
|
-
async function
|
|
195
|
+
async function U() {
|
|
196
196
|
try {
|
|
197
|
-
const o = await
|
|
197
|
+
const o = await y();
|
|
198
198
|
return new Promise((e, r) => {
|
|
199
|
-
const t = o.transaction(u, "readonly"),
|
|
200
|
-
|
|
199
|
+
const t = o.transaction(u, "readonly"), s = t.objectStore(u).get(A);
|
|
200
|
+
s.onerror = () => r(s.error), s.onsuccess = () => e(s.result ?? null), t.oncomplete = () => o.close();
|
|
201
201
|
});
|
|
202
202
|
} catch {
|
|
203
203
|
return null;
|
|
@@ -205,10 +205,10 @@ async function $() {
|
|
|
205
205
|
}
|
|
206
206
|
async function T() {
|
|
207
207
|
try {
|
|
208
|
-
const o = await
|
|
208
|
+
const o = await y();
|
|
209
209
|
return new Promise((e, r) => {
|
|
210
|
-
const t = o.transaction(u, "readwrite"),
|
|
211
|
-
|
|
210
|
+
const t = o.transaction(u, "readwrite"), n = t.objectStore(u);
|
|
211
|
+
n.delete(S), n.delete(A), t.onerror = () => r(t.error), t.oncomplete = () => {
|
|
212
212
|
o.close(), e();
|
|
213
213
|
};
|
|
214
214
|
});
|
|
@@ -224,27 +224,27 @@ async function ne() {
|
|
|
224
224
|
!1,
|
|
225
225
|
// Private key is non-extractable
|
|
226
226
|
["sign", "verify"]
|
|
227
|
-
), e = await crypto.subtle.exportKey("jwk", o.publicKey), r =
|
|
228
|
-
return await
|
|
227
|
+
), e = await crypto.subtle.exportKey("jwk", o.publicKey), r = te(e), t = await q(r);
|
|
228
|
+
return await re(o.privateKey), await se(r), { publicKey: r, thumbprint: t };
|
|
229
229
|
}
|
|
230
|
-
async function
|
|
231
|
-
const o = await
|
|
232
|
-
return o &&
|
|
230
|
+
async function oe() {
|
|
231
|
+
const o = await $(), e = await U();
|
|
232
|
+
return o && K(e) ? {
|
|
233
233
|
publicKey: e,
|
|
234
|
-
thumbprint: await
|
|
234
|
+
thumbprint: await q(e)
|
|
235
235
|
} : ((o || e) && await T(), ne());
|
|
236
236
|
}
|
|
237
|
-
async function
|
|
237
|
+
async function ae(o, e, r) {
|
|
238
238
|
try {
|
|
239
|
-
const t = await
|
|
240
|
-
if (!t || !
|
|
239
|
+
const t = await $(), n = await U();
|
|
240
|
+
if (!t || !K(n))
|
|
241
241
|
throw new g(
|
|
242
242
|
"DPoP key material is unavailable or invalid"
|
|
243
243
|
);
|
|
244
|
-
const
|
|
244
|
+
const s = {
|
|
245
245
|
typ: "dpop+jwt",
|
|
246
246
|
alg: "ES256",
|
|
247
|
-
jwk:
|
|
247
|
+
jwk: n
|
|
248
248
|
// Public key in JWK format
|
|
249
249
|
}, a = new URL(
|
|
250
250
|
e,
|
|
@@ -256,73 +256,73 @@ async function oe(o, e, r) {
|
|
|
256
256
|
iat: Math.floor(Date.now() / 1e3)
|
|
257
257
|
};
|
|
258
258
|
if (r) {
|
|
259
|
-
const
|
|
260
|
-
c.ath =
|
|
259
|
+
const L = new TextEncoder().encode(r), M = await crypto.subtle.digest("SHA-256", L);
|
|
260
|
+
c.ath = p(M);
|
|
261
261
|
}
|
|
262
|
-
const d =
|
|
263
|
-
new TextEncoder().encode(JSON.stringify(
|
|
264
|
-
), i =
|
|
262
|
+
const d = p(
|
|
263
|
+
new TextEncoder().encode(JSON.stringify(s)).buffer
|
|
264
|
+
), i = p(
|
|
265
265
|
new TextEncoder().encode(JSON.stringify(c)).buffer
|
|
266
|
-
),
|
|
266
|
+
), m = `${d}.${i}`, f = await crypto.subtle.sign(
|
|
267
267
|
{
|
|
268
268
|
name: "ECDSA",
|
|
269
269
|
hash: { name: "SHA-256" }
|
|
270
270
|
},
|
|
271
271
|
t,
|
|
272
|
-
new TextEncoder().encode(
|
|
273
|
-
), w =
|
|
272
|
+
new TextEncoder().encode(m)
|
|
273
|
+
), w = p(f);
|
|
274
274
|
return `${d}.${i}.${w}`;
|
|
275
275
|
} catch (t) {
|
|
276
276
|
throw console.error("Failed to generate DPoP proof:", t), t instanceof g ? t : new g("Failed to generate DPoP proof");
|
|
277
277
|
}
|
|
278
278
|
}
|
|
279
279
|
const B = {
|
|
280
|
-
isWebAuthnSupported:
|
|
281
|
-
isConditionalUISupported:
|
|
282
|
-
arrayBufferToBase64:
|
|
280
|
+
isWebAuthnSupported: O,
|
|
281
|
+
isConditionalUISupported: j,
|
|
282
|
+
arrayBufferToBase64: N,
|
|
283
283
|
base64ToArrayBuffer: C,
|
|
284
|
-
arrayBufferToBase64url:
|
|
285
|
-
base64urlToArrayBuffer:
|
|
284
|
+
arrayBufferToBase64url: p,
|
|
285
|
+
base64urlToArrayBuffer: b,
|
|
286
286
|
stringToArrayBuffer: k,
|
|
287
|
-
uint8ArrayToString:
|
|
288
|
-
getPasskeyEmail:
|
|
289
|
-
setPasskeyEmail:
|
|
290
|
-
clearPasskeyEmail:
|
|
291
|
-
getPasskeyMobileNumber:
|
|
292
|
-
setPasskeyMobileNumber:
|
|
293
|
-
clearPasskeyMobileNumber:
|
|
287
|
+
uint8ArrayToString: F,
|
|
288
|
+
getPasskeyEmail: Y,
|
|
289
|
+
setPasskeyEmail: V,
|
|
290
|
+
clearPasskeyEmail: X,
|
|
291
|
+
getPasskeyMobileNumber: Z,
|
|
292
|
+
setPasskeyMobileNumber: Q,
|
|
293
|
+
clearPasskeyMobileNumber: ee
|
|
294
294
|
};
|
|
295
295
|
typeof window < "u" && (window.WebAuthn = B);
|
|
296
|
-
const
|
|
297
|
-
|
|
298
|
-
const
|
|
296
|
+
const ie = typeof window < "u" ? window : globalThis;
|
|
297
|
+
ie.WebAuthn = B;
|
|
298
|
+
const P = "postex-auth-token", ce = "postexglobal", le = {
|
|
299
299
|
xstak: "https://auth-stage.xstak.com/public/v1",
|
|
300
300
|
postex: "https://auth-stage.postex.pk/public/v1",
|
|
301
301
|
callcourier: "https://auth-stage.callcourier.com.pk/public/v1",
|
|
302
302
|
postexglobal: "https://auth-stage.postexglobal.com/public/v1",
|
|
303
303
|
postexsa: "https://auth-stage.postex.sa/public/v1"
|
|
304
|
-
},
|
|
305
|
-
class
|
|
304
|
+
}, ue = /^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/, de = /^\+[1-9]\d{6,14}$/, he = /^\d{6}$/, pe = /^[A-Za-z0-9_-]{16,512}$/, me = /[\u0000-\u001F\u007F-\u009F]/, ye = /[A-Za-z]/, fe = /[\u0400-\u04FF]/, v = 254, x = 16, I = 64, D = 64;
|
|
305
|
+
class we extends Error {
|
|
306
306
|
constructor(e, r, t) {
|
|
307
307
|
super(t ?? `Request failed with status ${e}`), this.response = { status: e, data: r }, this.name = "AuthSDKFetchError";
|
|
308
308
|
}
|
|
309
309
|
}
|
|
310
|
-
class
|
|
310
|
+
class h extends Error {
|
|
311
311
|
constructor(e, r, t = "invalid_input") {
|
|
312
312
|
super(r), this.field = e, this.code = t, this.name = "SDKValidationError";
|
|
313
313
|
}
|
|
314
314
|
}
|
|
315
|
-
const
|
|
316
|
-
class
|
|
315
|
+
const R = "auth_sdk_refresh_token";
|
|
316
|
+
class z {
|
|
317
317
|
constructor(e) {
|
|
318
318
|
this.config = e, this.dpopInitializationPromise = this.createDPoPInitializationPromise();
|
|
319
319
|
}
|
|
320
320
|
getBaseUrl() {
|
|
321
|
-
const e = this.config.appId ??
|
|
322
|
-
return
|
|
321
|
+
const e = this.config.appId ?? ce;
|
|
322
|
+
return le[e];
|
|
323
323
|
}
|
|
324
324
|
async initializeDPoPState() {
|
|
325
|
-
await
|
|
325
|
+
await oe();
|
|
326
326
|
}
|
|
327
327
|
async ensureDPoPInitialized() {
|
|
328
328
|
await this.dpopInitializationPromise;
|
|
@@ -337,17 +337,17 @@ class U {
|
|
|
337
337
|
this.dpopInitializationPromise = this.createDPoPInitializationPromise();
|
|
338
338
|
}
|
|
339
339
|
async getRequiredDPoPProof(e, r, t) {
|
|
340
|
-
return await this.ensureDPoPInitialized(),
|
|
340
|
+
return await this.ensureDPoPInitialized(), ae(e.toUpperCase(), r, t);
|
|
341
341
|
}
|
|
342
342
|
containsControlChars(e) {
|
|
343
|
-
return
|
|
343
|
+
return me.test(e);
|
|
344
344
|
}
|
|
345
345
|
hasMixedLatinAndCyrillic(e) {
|
|
346
|
-
return ye.test(e) &&
|
|
346
|
+
return ye.test(e) && fe.test(e);
|
|
347
347
|
}
|
|
348
348
|
assertNoControlChars(e, r) {
|
|
349
349
|
if (this.containsControlChars(r))
|
|
350
|
-
throw new
|
|
350
|
+
throw new h(
|
|
351
351
|
e,
|
|
352
352
|
`${e} must not contain control characters`
|
|
353
353
|
);
|
|
@@ -355,46 +355,57 @@ class U {
|
|
|
355
355
|
validateEmail(e, r = "email") {
|
|
356
356
|
const t = e.trim();
|
|
357
357
|
if (!t)
|
|
358
|
-
throw new
|
|
358
|
+
throw new h(r, `${r} is required`);
|
|
359
359
|
if (t.length > v)
|
|
360
|
-
throw new
|
|
360
|
+
throw new h(
|
|
361
361
|
r,
|
|
362
362
|
`${r} must be ${v} characters or fewer`
|
|
363
363
|
);
|
|
364
364
|
this.assertNoControlChars(r, t);
|
|
365
|
-
const [
|
|
366
|
-
if (this.hasMixedLatinAndCyrillic(
|
|
367
|
-
throw new
|
|
365
|
+
const [n = ""] = t.split("@");
|
|
366
|
+
if (this.hasMixedLatinAndCyrillic(n))
|
|
367
|
+
throw new h(
|
|
368
368
|
r,
|
|
369
369
|
`${r} must not mix Latin and Cyrillic characters in the local part`
|
|
370
370
|
);
|
|
371
|
-
if (!
|
|
372
|
-
throw new
|
|
371
|
+
if (!ue.test(t))
|
|
372
|
+
throw new h(r, `${r} must be a valid email`);
|
|
373
373
|
return t;
|
|
374
374
|
}
|
|
375
375
|
validateMobileNumber(e, r = "mobileNumber") {
|
|
376
376
|
const t = e.trim();
|
|
377
377
|
if (!t)
|
|
378
|
-
throw new
|
|
378
|
+
throw new h(r, `${r} is required`);
|
|
379
379
|
if (t.length > x)
|
|
380
|
-
throw new
|
|
380
|
+
throw new h(
|
|
381
381
|
r,
|
|
382
382
|
`${r} must be ${x} characters or fewer`
|
|
383
383
|
);
|
|
384
|
-
if (this.assertNoControlChars(r, t), !
|
|
385
|
-
throw new
|
|
384
|
+
if (this.assertNoControlChars(r, t), !de.test(t))
|
|
385
|
+
throw new h(r, `${r} must be in E.164 format`);
|
|
386
386
|
return t;
|
|
387
387
|
}
|
|
388
|
+
validateUsername(e, r = "username") {
|
|
389
|
+
const t = e.trim();
|
|
390
|
+
if (!t)
|
|
391
|
+
throw new h(r, `${r} is required`);
|
|
392
|
+
if (t.length > I)
|
|
393
|
+
throw new h(
|
|
394
|
+
r,
|
|
395
|
+
`${r} must be ${I} characters or fewer`
|
|
396
|
+
);
|
|
397
|
+
return this.assertNoControlChars(r, t), t;
|
|
398
|
+
}
|
|
388
399
|
validateOTP(e, r = "otp") {
|
|
389
400
|
const t = e.trim();
|
|
390
|
-
if (this.assertNoControlChars(r, t), !
|
|
391
|
-
throw new
|
|
401
|
+
if (this.assertNoControlChars(r, t), !he.test(t))
|
|
402
|
+
throw new h(r, `${r} must be a 6-digit code`);
|
|
392
403
|
return t;
|
|
393
404
|
}
|
|
394
405
|
validateMagicLinkToken(e, r = "token") {
|
|
395
406
|
const t = e.trim();
|
|
396
|
-
if (this.assertNoControlChars(r, t), !
|
|
397
|
-
throw new
|
|
407
|
+
if (this.assertNoControlChars(r, t), !pe.test(t))
|
|
408
|
+
throw new h(
|
|
398
409
|
r,
|
|
399
410
|
`${r} must be 16-512 URL-safe characters`
|
|
400
411
|
);
|
|
@@ -403,10 +414,10 @@ class U {
|
|
|
403
414
|
validateRealm(e) {
|
|
404
415
|
const r = e?.trim();
|
|
405
416
|
if (r) {
|
|
406
|
-
if (this.assertNoControlChars("realm", r), r.length >
|
|
407
|
-
throw new
|
|
417
|
+
if (this.assertNoControlChars("realm", r), r.length > D)
|
|
418
|
+
throw new h(
|
|
408
419
|
"realm",
|
|
409
|
-
`realm must be ${
|
|
420
|
+
`realm must be ${D} characters or fewer`
|
|
410
421
|
);
|
|
411
422
|
return r;
|
|
412
423
|
}
|
|
@@ -414,7 +425,8 @@ class U {
|
|
|
414
425
|
normalizeAndValidateIdentifier(e) {
|
|
415
426
|
return typeof e == "string" ? { email: this.validateEmail(e) } : {
|
|
416
427
|
email: e.email ? this.validateEmail(e.email) : void 0,
|
|
417
|
-
mobileNumber: e.mobileNumber ? this.validateMobileNumber(e.mobileNumber) : void 0
|
|
428
|
+
mobileNumber: e.mobileNumber ? this.validateMobileNumber(e.mobileNumber) : void 0,
|
|
429
|
+
username: e.username ? this.validateUsername(e.username) : void 0
|
|
418
430
|
};
|
|
419
431
|
}
|
|
420
432
|
normalizeAuthIdentifier(e) {
|
|
@@ -425,20 +437,20 @@ class U {
|
|
|
425
437
|
return this.validateRealm(t);
|
|
426
438
|
}
|
|
427
439
|
buildAuthRequestBody(e, r) {
|
|
428
|
-
const t = this.normalizeAuthIdentifier(e),
|
|
440
|
+
const t = this.normalizeAuthIdentifier(e), n = this.extractRealm(e, r);
|
|
429
441
|
return {
|
|
430
442
|
...t,
|
|
431
|
-
...
|
|
443
|
+
...n ? { realm: n } : {}
|
|
432
444
|
};
|
|
433
445
|
}
|
|
434
446
|
buildUrl(e, r) {
|
|
435
|
-
const t = this.getBaseUrl().replace(/\/$/, ""),
|
|
436
|
-
if (!r || Object.keys(r).length === 0) return
|
|
447
|
+
const t = this.getBaseUrl().replace(/\/$/, ""), n = e.startsWith("/") ? e : `/${e}`, s = `${t}${n}`;
|
|
448
|
+
if (!r || Object.keys(r).length === 0) return s;
|
|
437
449
|
const a = new URLSearchParams(r).toString();
|
|
438
|
-
return `${
|
|
450
|
+
return `${s}?${a}`;
|
|
439
451
|
}
|
|
440
452
|
async request(e, r, t) {
|
|
441
|
-
const
|
|
453
|
+
const n = this.buildUrl(r, t?.params), s = {
|
|
442
454
|
"Content-Type": "application/json",
|
|
443
455
|
Accept: "application/json",
|
|
444
456
|
"X-API-Key": this.config.apiKey ?? "",
|
|
@@ -446,19 +458,19 @@ class U {
|
|
|
446
458
|
}, a = {
|
|
447
459
|
method: e,
|
|
448
460
|
credentials: "include",
|
|
449
|
-
headers:
|
|
461
|
+
headers: s
|
|
450
462
|
};
|
|
451
463
|
t?.body !== void 0 && t?.body !== null && (a.body = JSON.stringify(t.body));
|
|
452
|
-
const l = await fetch(
|
|
464
|
+
const l = await fetch(n, a);
|
|
453
465
|
if (!l.ok) {
|
|
454
466
|
let i;
|
|
455
467
|
try {
|
|
456
|
-
const
|
|
457
|
-
i =
|
|
468
|
+
const m = await l.text();
|
|
469
|
+
i = m ? JSON.parse(m) : void 0;
|
|
458
470
|
} catch {
|
|
459
471
|
i = void 0;
|
|
460
472
|
}
|
|
461
|
-
throw l.status === 401 && (await this.clearTokens(), await T(), this.resetDPoPInitialization()), new
|
|
473
|
+
throw l.status === 401 && (await this.clearTokens(), await T(), this.resetDPoPInitialization()), new we(l.status, i);
|
|
462
474
|
}
|
|
463
475
|
const c = await l.text();
|
|
464
476
|
return { data: c ? JSON.parse(c) : {} };
|
|
@@ -470,12 +482,12 @@ class U {
|
|
|
470
482
|
* @param url - Full request URL
|
|
471
483
|
*/
|
|
472
484
|
async getRequestAuthHeaders(e, r) {
|
|
473
|
-
const t = localStorage.getItem(
|
|
485
|
+
const t = localStorage.getItem(P);
|
|
474
486
|
if (!t) return {};
|
|
475
|
-
const
|
|
487
|
+
const n = r.startsWith("http") ? r : `${this.getBaseUrl()}${r}`, s = await this.getRequiredDPoPProof(e, n, t);
|
|
476
488
|
return {
|
|
477
489
|
Authorization: `Bearer ${t}`,
|
|
478
|
-
DPoP:
|
|
490
|
+
DPoP: s
|
|
479
491
|
};
|
|
480
492
|
}
|
|
481
493
|
/**
|
|
@@ -483,10 +495,10 @@ class U {
|
|
|
483
495
|
* Returns no_session | session_found | webauthn_ready per PostEx Auth BFF spec.
|
|
484
496
|
*/
|
|
485
497
|
async getStatus(e, r) {
|
|
486
|
-
const t = this.normalizeAuthIdentifier(e),
|
|
487
|
-
t.email && (
|
|
498
|
+
const t = this.normalizeAuthIdentifier(e), n = this.extractRealm(e, r), s = {};
|
|
499
|
+
t.email && (s.email = t.email), t.mobileNumber && (s.mobileNumber = t.mobileNumber), t.username && (s.username = t.username), n && (s.realm = n);
|
|
488
500
|
const a = await this.request("GET", "/auth/status", {
|
|
489
|
-
params:
|
|
501
|
+
params: s
|
|
490
502
|
});
|
|
491
503
|
return a.data.data ?? a.data;
|
|
492
504
|
}
|
|
@@ -495,34 +507,34 @@ class U {
|
|
|
495
507
|
* Sets auth_session cookie when otp_sent.
|
|
496
508
|
*/
|
|
497
509
|
async initiateAuth(e, r) {
|
|
498
|
-
const t = this.buildAuthRequestBody(e, r),
|
|
510
|
+
const t = this.buildAuthRequestBody(e, r), n = await this.request("POST", "/auth/initiate", {
|
|
499
511
|
body: t
|
|
500
|
-
}),
|
|
512
|
+
}), s = n.data.data ?? n.data;
|
|
501
513
|
return {
|
|
502
|
-
status:
|
|
503
|
-
challenge:
|
|
504
|
-
credentialIds:
|
|
505
|
-
rp:
|
|
514
|
+
status: s.status,
|
|
515
|
+
challenge: s.challenge,
|
|
516
|
+
credentialIds: s.credentialIds,
|
|
517
|
+
rp: s.rp
|
|
506
518
|
};
|
|
507
519
|
}
|
|
508
520
|
/**
|
|
509
|
-
* POST /otp/initiate - Direct OTP initiation using email
|
|
510
|
-
* Requires at least one identifier: email or
|
|
521
|
+
* POST /otp/initiate - Direct OTP initiation using email, mobile number, or username.
|
|
522
|
+
* Requires at least one identifier: email, mobileNumber, or username.
|
|
511
523
|
*/
|
|
512
524
|
async initiateOTP(e, r) {
|
|
513
|
-
const t = this.normalizeAuthIdentifier(e),
|
|
514
|
-
if (!
|
|
515
|
-
throw new
|
|
525
|
+
const t = this.normalizeAuthIdentifier(e), n = this.extractRealm(e, r), s = t.email, a = t.mobileNumber, l = t.username;
|
|
526
|
+
if (!s && !a && !l)
|
|
527
|
+
throw new h(
|
|
516
528
|
"identifier",
|
|
517
|
-
"Either mobileNumber or
|
|
529
|
+
"Either mobileNumber, email, or username is required"
|
|
518
530
|
);
|
|
519
|
-
const
|
|
520
|
-
|
|
521
|
-
const
|
|
522
|
-
body:
|
|
531
|
+
const c = {};
|
|
532
|
+
s && (c.email = s), a && (c.mobileNumber = a), l && (c.username = l), n && (c.realm = n);
|
|
533
|
+
const i = (await this.request("POST", "/otp/initiate", {
|
|
534
|
+
body: c
|
|
523
535
|
})).data;
|
|
524
536
|
return {
|
|
525
|
-
message:
|
|
537
|
+
message: i.message ?? i.data?.message
|
|
526
538
|
};
|
|
527
539
|
}
|
|
528
540
|
/**
|
|
@@ -533,10 +545,10 @@ class U {
|
|
|
533
545
|
const r = this.validateOTP(e), t = await this.getRequiredDPoPProof(
|
|
534
546
|
"POST",
|
|
535
547
|
`${this.getBaseUrl()}/otp/verify`
|
|
536
|
-
),
|
|
548
|
+
), n = await this.request("POST", "/otp/verify", {
|
|
537
549
|
body: { otp: r },
|
|
538
550
|
headers: { DPoP: t }
|
|
539
|
-
}),
|
|
551
|
+
}), s = n.data.data ?? n.data, a = s.AuthenticationResult ?? s, l = a.access_token ?? a.accessToken ?? a.AccessToken, c = a.refresh_token ?? a.refreshToken ?? a.RefreshToken, d = a.expires_in ?? a.expiresIn, i = a.token_type ?? a.tokenType;
|
|
540
552
|
return l && await this.storeTokens({
|
|
541
553
|
accessToken: l,
|
|
542
554
|
refreshToken: c,
|
|
@@ -572,22 +584,22 @@ class U {
|
|
|
572
584
|
mobileNumber: e,
|
|
573
585
|
otp: r
|
|
574
586
|
}) {
|
|
575
|
-
const t = this.validateMobileNumber(e),
|
|
587
|
+
const t = this.validateMobileNumber(e), n = this.validateOTP(r), s = await this.getRequiredDPoPProof(
|
|
576
588
|
"POST",
|
|
577
589
|
`${this.getBaseUrl()}/otp/signup/verify`
|
|
578
590
|
), a = await this.request("POST", "/otp/signup/verify", {
|
|
579
|
-
body: { mobileNumber: t, otp:
|
|
580
|
-
headers: { DPoP:
|
|
581
|
-
}), l = a.data.data ?? a.data, c = l.AuthenticationResult ?? l, d = c.access_token ?? c.accessToken ?? c.AccessToken, i = c.refresh_token ?? c.refreshToken ?? c.RefreshToken,
|
|
591
|
+
body: { mobileNumber: t, otp: n },
|
|
592
|
+
headers: { DPoP: s }
|
|
593
|
+
}), l = a.data.data ?? a.data, c = l.AuthenticationResult ?? l, d = c.access_token ?? c.accessToken ?? c.AccessToken, i = c.refresh_token ?? c.refreshToken ?? c.RefreshToken, m = c.expires_in ?? c.expiresIn, f = c.token_type ?? c.tokenType;
|
|
582
594
|
return d && await this.storeTokens({
|
|
583
595
|
accessToken: d,
|
|
584
596
|
refreshToken: i,
|
|
585
|
-
expiresIn:
|
|
597
|
+
expiresIn: m,
|
|
586
598
|
tokenType: f
|
|
587
599
|
}), {
|
|
588
600
|
access_token: d,
|
|
589
601
|
refresh_token: i,
|
|
590
|
-
expires_in:
|
|
602
|
+
expires_in: m,
|
|
591
603
|
token_type: f,
|
|
592
604
|
verified: c.verified,
|
|
593
605
|
email: c.email ?? c.Email,
|
|
@@ -601,9 +613,9 @@ class U {
|
|
|
601
613
|
mobileNumber: e,
|
|
602
614
|
email: r = ""
|
|
603
615
|
}) {
|
|
604
|
-
const t = this.validateMobileNumber(e),
|
|
605
|
-
body: { email:
|
|
606
|
-
}), a =
|
|
616
|
+
const t = this.validateMobileNumber(e), n = r ? this.validateEmail(r) : "", s = await this.request("POST", "/otp/signup/resend", {
|
|
617
|
+
body: { email: n, mobileNumber: t }
|
|
618
|
+
}), a = s.data.data ?? s.data;
|
|
607
619
|
return {
|
|
608
620
|
success: a.success,
|
|
609
621
|
message: a.message,
|
|
@@ -635,15 +647,15 @@ class U {
|
|
|
635
647
|
{
|
|
636
648
|
body: {}
|
|
637
649
|
}
|
|
638
|
-
), r = e.data.data ?? e.data, t = r.AuthenticationResult ?? r,
|
|
639
|
-
return
|
|
640
|
-
accessToken:
|
|
641
|
-
refreshToken:
|
|
650
|
+
), r = e.data.data ?? e.data, t = r.AuthenticationResult ?? r, n = t.access_token ?? t.accessToken ?? t.AccessToken, s = t.refresh_token ?? t.refreshToken ?? t.RefreshToken, a = t.expires_in ?? t.expiresIn, l = t.token_type ?? t.tokenType;
|
|
651
|
+
return n && await this.storeTokens({
|
|
652
|
+
accessToken: n,
|
|
653
|
+
refreshToken: s,
|
|
642
654
|
expiresIn: a,
|
|
643
655
|
tokenType: l
|
|
644
656
|
}), {
|
|
645
|
-
access_token:
|
|
646
|
-
refresh_token:
|
|
657
|
+
access_token: n,
|
|
658
|
+
refresh_token: s,
|
|
647
659
|
expires_in: a,
|
|
648
660
|
token_type: l,
|
|
649
661
|
verified: t.verified,
|
|
@@ -663,16 +675,16 @@ class U {
|
|
|
663
675
|
}
|
|
664
676
|
async registerPasskey(e) {
|
|
665
677
|
const r = this.validateEmail(e), t = await this.initiatePasskeyRegistration();
|
|
666
|
-
let
|
|
678
|
+
let n;
|
|
667
679
|
if (t?.user?.id)
|
|
668
680
|
try {
|
|
669
|
-
|
|
681
|
+
n = b(t.user.id);
|
|
670
682
|
} catch {
|
|
671
|
-
|
|
683
|
+
n = k(t.user.id);
|
|
672
684
|
}
|
|
673
685
|
else
|
|
674
|
-
|
|
675
|
-
const
|
|
686
|
+
n = k(r);
|
|
687
|
+
const s = (t.pubKeyCredParams ?? [
|
|
676
688
|
{ type: "public-key", alg: -7 },
|
|
677
689
|
{ type: "public-key", alg: -257 }
|
|
678
690
|
]).map((w) => ({
|
|
@@ -680,19 +692,19 @@ class U {
|
|
|
680
692
|
alg: w.alg
|
|
681
693
|
})), a = t.excludeCredentials?.map((w) => ({
|
|
682
694
|
type: "public-key",
|
|
683
|
-
id:
|
|
695
|
+
id: b(w)
|
|
684
696
|
})), l = {
|
|
685
|
-
challenge:
|
|
697
|
+
challenge: b(t.challenge),
|
|
686
698
|
rp: {
|
|
687
699
|
name: t.rp?.name ?? "XPay",
|
|
688
700
|
id: t.rp?.id ?? window.location.hostname
|
|
689
701
|
},
|
|
690
702
|
user: {
|
|
691
|
-
id:
|
|
703
|
+
id: n,
|
|
692
704
|
name: t.user?.name ?? r,
|
|
693
705
|
displayName: t.user?.displayName ?? r
|
|
694
706
|
},
|
|
695
|
-
pubKeyCredParams:
|
|
707
|
+
pubKeyCredParams: s,
|
|
696
708
|
excludeCredentials: a,
|
|
697
709
|
timeout: t.timeout ?? 6e4,
|
|
698
710
|
attestation: "direct",
|
|
@@ -706,12 +718,12 @@ class U {
|
|
|
706
718
|
});
|
|
707
719
|
if (!c) throw new Error("Credential creation failed");
|
|
708
720
|
const d = c.response, i = {
|
|
709
|
-
clientDataJSON:
|
|
710
|
-
attestationObject:
|
|
711
|
-
rawId:
|
|
721
|
+
clientDataJSON: p(d.clientDataJSON),
|
|
722
|
+
attestationObject: p(d.attestationObject),
|
|
723
|
+
rawId: p(c.rawId)
|
|
712
724
|
};
|
|
713
725
|
if (!i.rawId) throw new Error("Raw ID is required");
|
|
714
|
-
const
|
|
726
|
+
const m = await this.getRequiredDPoPProof(
|
|
715
727
|
"POST",
|
|
716
728
|
`${this.getBaseUrl()}/webauthn/register/challenge`
|
|
717
729
|
), f = await this.request(
|
|
@@ -719,7 +731,7 @@ class U {
|
|
|
719
731
|
"/webauthn/register/challenge",
|
|
720
732
|
{
|
|
721
733
|
body: i,
|
|
722
|
-
headers: { DPoP:
|
|
734
|
+
headers: { DPoP: m }
|
|
723
735
|
}
|
|
724
736
|
);
|
|
725
737
|
return f.data.data ?? f.data;
|
|
@@ -732,28 +744,28 @@ class U {
|
|
|
732
744
|
rp: r,
|
|
733
745
|
credentialIds: t
|
|
734
746
|
}) {
|
|
735
|
-
const
|
|
747
|
+
const n = await navigator.credentials.get({
|
|
736
748
|
publicKey: {
|
|
737
|
-
challenge:
|
|
749
|
+
challenge: b(e),
|
|
738
750
|
rpId: r?.host ?? void 0,
|
|
739
751
|
allowCredentials: t.map((w) => ({
|
|
740
752
|
type: "public-key",
|
|
741
|
-
id:
|
|
753
|
+
id: b(w),
|
|
742
754
|
transports: ["internal"]
|
|
743
755
|
})),
|
|
744
756
|
timeout: 6e4,
|
|
745
757
|
userVerification: "required"
|
|
746
758
|
}
|
|
747
759
|
});
|
|
748
|
-
if (!
|
|
749
|
-
const
|
|
750
|
-
clientDataJSON:
|
|
751
|
-
authenticatorData:
|
|
752
|
-
|
|
760
|
+
if (!n) throw new Error("Authentication failed");
|
|
761
|
+
const s = n.response, a = {
|
|
762
|
+
clientDataJSON: p(s.clientDataJSON),
|
|
763
|
+
authenticatorData: p(
|
|
764
|
+
s.authenticatorData
|
|
753
765
|
),
|
|
754
|
-
signature:
|
|
755
|
-
rawId:
|
|
756
|
-
userHandle:
|
|
766
|
+
signature: p(s.signature),
|
|
767
|
+
rawId: p(n.rawId),
|
|
768
|
+
userHandle: s.userHandle ? p(s.userHandle) : ""
|
|
757
769
|
}, l = await this.getRequiredDPoPProof(
|
|
758
770
|
"POST",
|
|
759
771
|
`${this.getBaseUrl()}/webauthn/authenticate/challenge`
|
|
@@ -764,14 +776,14 @@ class U {
|
|
|
764
776
|
body: a,
|
|
765
777
|
headers: { DPoP: l }
|
|
766
778
|
}
|
|
767
|
-
), d = c.data.data ?? c.data, i = d.AuthenticationResult ?? d,
|
|
768
|
-
return
|
|
769
|
-
accessToken:
|
|
779
|
+
), d = c.data.data ?? c.data, i = d.AuthenticationResult ?? d, m = i.AccessToken ?? i.accessToken ?? i.access_token, f = i.RefreshToken ?? i.refreshToken ?? i.refresh_token;
|
|
780
|
+
return m && await this.storeTokens({
|
|
781
|
+
accessToken: m,
|
|
770
782
|
refreshToken: f,
|
|
771
783
|
expiresIn: i.expiresIn ?? i.ExpiresIn,
|
|
772
784
|
tokenType: i.tokenType ?? i.token_type
|
|
773
785
|
}), {
|
|
774
|
-
access_token:
|
|
786
|
+
access_token: m,
|
|
775
787
|
refresh_token: f,
|
|
776
788
|
email: i.email,
|
|
777
789
|
name: i.name ?? i.userName,
|
|
@@ -784,9 +796,9 @@ class U {
|
|
|
784
796
|
* GET /webauthn/credentials/:username - Get user's passkey status.
|
|
785
797
|
*/
|
|
786
798
|
async getPasskeyStatus(e) {
|
|
787
|
-
const t = `/webauthn/credentials/${encodeURIComponent(e)}`,
|
|
788
|
-
headers:
|
|
789
|
-
}), a =
|
|
799
|
+
const t = `/webauthn/credentials/${encodeURIComponent(e)}`, n = await this.signRequest("GET", t), s = await this.request("GET", t, {
|
|
800
|
+
headers: n.headers
|
|
801
|
+
}), a = s.data.data ?? s.data;
|
|
790
802
|
return {
|
|
791
803
|
...a,
|
|
792
804
|
hasCredentials: !!(a.hasCredentials ?? a.credentialId)
|
|
@@ -796,38 +808,38 @@ class U {
|
|
|
796
808
|
* DELETE /webauthn/credentials/:username - Remove passkey.
|
|
797
809
|
*/
|
|
798
810
|
async removePasskey(e) {
|
|
799
|
-
const t = `/webauthn/credentials/${encodeURIComponent(e)}`,
|
|
811
|
+
const t = `/webauthn/credentials/${encodeURIComponent(e)}`, n = await this.signRequest("DELETE", t);
|
|
800
812
|
await this.request("DELETE", t, {
|
|
801
|
-
headers:
|
|
813
|
+
headers: n.headers
|
|
802
814
|
});
|
|
803
815
|
}
|
|
804
816
|
/**
|
|
805
817
|
* Signs a request with DPoP and Authorization headers (internal use).
|
|
806
818
|
*/
|
|
807
819
|
async signRequest(e, r, t = {}) {
|
|
808
|
-
const
|
|
809
|
-
return { ...t, headers: { ...t.headers, ...
|
|
820
|
+
const n = r.startsWith("http") ? r : `${this.getBaseUrl()}${r}`, s = await this.getRequestAuthHeaders(e, n);
|
|
821
|
+
return { ...t, headers: { ...t.headers, ...s } };
|
|
810
822
|
}
|
|
811
823
|
/**
|
|
812
824
|
* Replaces native fetch or Axios with a DPoP-signed version.
|
|
813
825
|
*/
|
|
814
826
|
async authenticatedFetch(e, r) {
|
|
815
|
-
const t = typeof e == "string" ? e : e instanceof URL ? e.toString() : e.url,
|
|
827
|
+
const t = typeof e == "string" ? e : e instanceof URL ? e.toString() : e.url, n = r?.method || "GET", s = await this.signRequest(n, t, {
|
|
816
828
|
headers: r?.headers
|
|
817
829
|
});
|
|
818
|
-
return fetch(e, { ...r, headers:
|
|
830
|
+
return fetch(e, { ...r, headers: s.headers });
|
|
819
831
|
}
|
|
820
832
|
/**
|
|
821
833
|
* Store tokens from /webauthn/authenticate (per spec: sessionStorage preferred).
|
|
822
834
|
*/
|
|
823
835
|
async storeTokens(e) {
|
|
824
|
-
localStorage.setItem(
|
|
836
|
+
localStorage.setItem(P, e.accessToken), e.refreshToken && localStorage.setItem(R, e.refreshToken);
|
|
825
837
|
}
|
|
826
838
|
/**
|
|
827
839
|
* Clear stored tokens (call on logout).
|
|
828
840
|
*/
|
|
829
841
|
async clearTokens() {
|
|
830
|
-
localStorage.removeItem(
|
|
842
|
+
localStorage.removeItem(P), localStorage.removeItem(R);
|
|
831
843
|
}
|
|
832
844
|
/**
|
|
833
845
|
* POST /auth/refresh - Refresh access token using server-stored refresh token.
|
|
@@ -837,13 +849,13 @@ class U {
|
|
|
837
849
|
async refreshToken(e) {
|
|
838
850
|
const r = this.extractRealm(void 0, e), t = await this.request("POST", "/auth/refresh", {
|
|
839
851
|
body: r ? { realm: r } : {}
|
|
840
|
-
}),
|
|
841
|
-
return
|
|
842
|
-
accessToken:
|
|
852
|
+
}), n = t.data.data ?? t.data, s = n.access_token, a = n.token_type, l = n.expires_in;
|
|
853
|
+
return s && await this.storeTokens({
|
|
854
|
+
accessToken: s,
|
|
843
855
|
expiresIn: l,
|
|
844
856
|
tokenType: a
|
|
845
857
|
}), {
|
|
846
|
-
access_token:
|
|
858
|
+
access_token: s,
|
|
847
859
|
token_type: a,
|
|
848
860
|
expires_in: l
|
|
849
861
|
};
|
|
@@ -861,28 +873,28 @@ class U {
|
|
|
861
873
|
await this.clearTokens();
|
|
862
874
|
}
|
|
863
875
|
async getAccessToken() {
|
|
864
|
-
return localStorage.getItem(
|
|
876
|
+
return localStorage.getItem(P);
|
|
865
877
|
}
|
|
866
878
|
}
|
|
867
|
-
typeof window < "u" && (window.AuthSDK =
|
|
868
|
-
const
|
|
869
|
-
|
|
879
|
+
typeof window < "u" && (window.AuthSDK = z);
|
|
880
|
+
const be = typeof window < "u" ? window : globalThis;
|
|
881
|
+
be.AuthSDK = z;
|
|
870
882
|
export {
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
883
|
+
z as AuthSDK,
|
|
884
|
+
we as AuthSDKFetchError,
|
|
885
|
+
h as SDKValidationError,
|
|
886
|
+
N as arrayBufferToBase64,
|
|
887
|
+
p as arrayBufferToBase64url,
|
|
876
888
|
C as base64ToArrayBuffer,
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
889
|
+
b as base64urlToArrayBuffer,
|
|
890
|
+
X as clearPasskeyEmail,
|
|
891
|
+
ee as clearPasskeyMobileNumber,
|
|
892
|
+
Y as getPasskeyEmail,
|
|
893
|
+
Z as getPasskeyMobileNumber,
|
|
894
|
+
j as isConditionalUISupported,
|
|
895
|
+
O as isWebAuthnSupported,
|
|
896
|
+
V as setPasskeyEmail,
|
|
897
|
+
Q as setPasskeyMobileNumber,
|
|
886
898
|
k as stringToArrayBuffer,
|
|
887
|
-
|
|
899
|
+
F as uint8ArrayToString
|
|
888
900
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var PostexAuthSDKStage=(function(d){"use strict";function T(){return typeof window<"u"&&typeof window.PublicKeyCredential<"u"&&typeof navigator<"u"&&typeof navigator.credentials<"u"}async function N(){if(!T())return!1;try{return await PublicKeyCredential.isConditionalMediationAvailable?.()??!1}catch{return!1}}function E(s){const e=new Uint8Array(s);let r="";for(let t=0;t<e.byteLength;t++)r+=String.fromCharCode(e[t]);return btoa(r)}function _(s){if(typeof s!="string"||!s)throw new Error("Invalid base64: expected non-empty string");const e=s.replace(/\s/g,"").replace(/-/g,"+").replace(/_/g,"/"),r=e.length%4,t=r>0?e+"=".repeat(4-r):e;try{const n=atob(t),a=new Uint8Array(n.length);for(let o=0;o<n.length;o++)a[o]=n.charCodeAt(o);return a.buffer}catch{throw new Error("Invalid base64: string is not correctly encoded. Check challenge/credentialId from server.")}}function y(s){return E(s).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function V(s){return/^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i.test(s)}function X(s){const e=s.replace(/-/g,""),r=new Uint8Array(e.length/2);for(let t=0;t<r.length;t++)r[t]=parseInt(e.substr(t*2,2),16);return r.buffer}function b(s){if(!s||typeof s!="string")throw new Error("Invalid input: expected non-empty string");return V(s)?X(s):_(s)}function g(s){return new TextEncoder().encode(s).buffer}function x(s){return String.fromCharCode(...s)}const Z="xpay_webauthn",Q=1,u="passkey_data",S="passkey_email",A="passkey_mobile_number";function f(){return new Promise((s,e)=>{const r=indexedDB.open(Z,Q);r.onerror=()=>e(r.error),r.onsuccess=()=>s(r.result),r.onupgradeneeded=()=>{const t=r.result;t.objectStoreNames.contains(u)||t.createObjectStore(u)}})}async function C(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readonly"),a=t.objectStore(u).get(S);a.onerror=()=>r(a.error),a.onsuccess=()=>e(a.result??null),t.oncomplete=()=>s.close()})}catch{return null}}async function K(s){try{const e=await f();return new Promise((r,t)=>{const n=e.transaction(u,"readwrite"),o=n.objectStore(u).put(s,S);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),n.oncomplete=()=>e.close()})}catch{}}async function q(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readwrite"),a=t.objectStore(u).delete(S);a.onerror=()=>r(a.error),a.onsuccess=()=>e(),t.oncomplete=()=>s.close()})}catch{}}async function $(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readonly"),a=t.objectStore(u).get(A);a.onerror=()=>r(a.error),a.onsuccess=()=>e(a.result??null),t.oncomplete=()=>s.close()})}catch{return null}}async function B(s){try{const e=await f();return new Promise((r,t)=>{const n=e.transaction(u,"readwrite"),o=n.objectStore(u).put(s,A);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),n.oncomplete=()=>e.close()})}catch{}}async function M(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readwrite"),a=t.objectStore(u).delete(A);a.onerror=()=>r(a.error),a.onsuccess=()=>e(),t.oncomplete=()=>s.close()})}catch{}}const v="dpop_private_key",I="dpop_public_key_jwk";function U(s){if(!s||typeof s!="object")return!1;const e=s;return e.kty==="EC"&&e.crv==="P-256"&&typeof e.x=="string"&&typeof e.y=="string"}class D extends Error{constructor(e){super(e),this.name="DPoPProofGenerationError"}}function ee(s){return{kty:"EC",crv:"P-256",x:s.x,y:s.y}}async function z(s){const e=JSON.stringify({crv:s.crv,kty:s.kty,x:s.x,y:s.y}),r=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(e));return y(r)}async function te(s){try{const e=await f();return new Promise((r,t)=>{const n=e.transaction(u,"readwrite"),o=n.objectStore(u).put(s,v);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),n.oncomplete=()=>e.close()})}catch(e){console.error("Failed to store DPoP private key:",e)}}async function re(s){try{const e=await f();return new Promise((r,t)=>{const n=e.transaction(u,"readwrite"),o=n.objectStore(u).put(s,I);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),n.oncomplete=()=>e.close()})}catch(e){console.error("Failed to store DPoP public key JWK:",e)}}async function L(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readonly"),a=t.objectStore(u).get(v);a.onerror=()=>r(a.error),a.onsuccess=()=>e(a.result??null),t.oncomplete=()=>s.close()})}catch{return null}}async function j(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readonly"),a=t.objectStore(u).get(I);a.onerror=()=>r(a.error),a.onsuccess=()=>e(a.result??null),t.oncomplete=()=>s.close()})}catch{return null}}async function R(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readwrite"),n=t.objectStore(u);n.delete(v),n.delete(I),t.onerror=()=>r(t.error),t.oncomplete=()=>{s.close(),e()}})}catch{}}async function ae(){const s=await crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-256"},!1,["sign","verify"]),e=await crypto.subtle.exportKey("jwk",s.publicKey),r=ee(e),t=await z(r);return await te(s.privateKey),await re(r),{publicKey:r,thumbprint:t}}async function ne(){const s=await L(),e=await j();return s&&U(e)?{publicKey:e,thumbprint:await z(e)}:((s||e)&&await R(),ae())}async function se(s,e,r){try{const t=await L(),n=await j();if(!t||!U(n))throw new D("DPoP key material is unavailable or invalid");const a={typ:"dpop+jwt",alg:"ES256",jwk:n},o=new URL(e,typeof window<"u"?window.location.origin:void 0),l=`${o.origin}${o.pathname}`,c={jti:crypto.randomUUID(),htm:s.toUpperCase(),htu:l,iat:Math.floor(Date.now()/1e3)};if(r){const we=new TextEncoder().encode(r),be=await crypto.subtle.digest("SHA-256",we);c.ath=y(be)}const h=y(new TextEncoder().encode(JSON.stringify(a)).buffer),i=y(new TextEncoder().encode(JSON.stringify(c)).buffer),m=`${h}.${i}`,w=await crypto.subtle.sign({name:"ECDSA",hash:{name:"SHA-256"}},t,new TextEncoder().encode(m)),P=y(w);return`${h}.${i}.${P}`}catch(t){throw console.error("Failed to generate DPoP proof:",t),t instanceof D?t:new D("Failed to generate DPoP proof")}}const H={isWebAuthnSupported:T,isConditionalUISupported:N,arrayBufferToBase64:E,base64ToArrayBuffer:_,arrayBufferToBase64url:y,base64urlToArrayBuffer:b,stringToArrayBuffer:g,uint8ArrayToString:x,getPasskeyEmail:C,setPasskeyEmail:K,clearPasskeyEmail:q,getPasskeyMobileNumber:$,setPasskeyMobileNumber:B,clearPasskeyMobileNumber:M};typeof window<"u"&&(window.WebAuthn=H);const oe=typeof window<"u"?window:globalThis;oe.WebAuthn=H;const k="postex-auth-token",ie="postexglobal",ce={xstak:"https://auth-stage.xstak.com/public/v1",postex:"https://auth-stage.postex.pk/public/v1",callcourier:"https://auth-stage.callcourier.com.pk/public/v1",postexglobal:"https://auth-stage.postexglobal.com/public/v1",postexsa:"https://auth-stage.postex.sa/public/v1"},le=/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/,ue=/^\+[1-9]\d{6,14}$/,de=/^\d{6}$/,he=/^[A-Za-z0-9_-]{16,512}$/,ye=/[\u0000-\u001F\u007F-\u009F]/,pe=/[A-Za-z]/,me=/[\u0400-\u04FF]/,J=254,F=16,W=64;class G extends Error{constructor(e,r,t){super(t??`Request failed with status ${e}`),this.response={status:e,data:r},this.name="AuthSDKFetchError"}}class p extends Error{constructor(e,r,t="invalid_input"){super(r),this.field=e,this.code=t,this.name="SDKValidationError"}}const Y="auth_sdk_refresh_token";class O{constructor(e){this.config=e,this.dpopInitializationPromise=this.createDPoPInitializationPromise()}getBaseUrl(){const e=this.config.appId??ie;return ce[e]}async initializeDPoPState(){await ne()}async ensureDPoPInitialized(){await this.dpopInitializationPromise}createDPoPInitializationPromise(){const e=this.initializeDPoPState();return e.catch(r=>{console.warn("[AuthSDK] DPoP initialization failed:",r)}),e}resetDPoPInitialization(){this.dpopInitializationPromise=this.createDPoPInitializationPromise()}async getRequiredDPoPProof(e,r,t){return await this.ensureDPoPInitialized(),se(e.toUpperCase(),r,t)}containsControlChars(e){return ye.test(e)}hasMixedLatinAndCyrillic(e){return pe.test(e)&&me.test(e)}assertNoControlChars(e,r){if(this.containsControlChars(r))throw new p(e,`${e} must not contain control characters`)}validateEmail(e,r="email"){const t=e.trim();if(!t)throw new p(r,`${r} is required`);if(t.length>J)throw new p(r,`${r} must be ${J} characters or fewer`);this.assertNoControlChars(r,t);const[n=""]=t.split("@");if(this.hasMixedLatinAndCyrillic(n))throw new p(r,`${r} must not mix Latin and Cyrillic characters in the local part`);if(!le.test(t))throw new p(r,`${r} must be a valid email`);return t}validateMobileNumber(e,r="mobileNumber"){const t=e.trim();if(!t)throw new p(r,`${r} is required`);if(t.length>F)throw new p(r,`${r} must be ${F} characters or fewer`);if(this.assertNoControlChars(r,t),!ue.test(t))throw new p(r,`${r} must be in E.164 format`);return t}validateOTP(e,r="otp"){const t=e.trim();if(this.assertNoControlChars(r,t),!de.test(t))throw new p(r,`${r} must be a 6-digit code`);return t}validateMagicLinkToken(e,r="token"){const t=e.trim();if(this.assertNoControlChars(r,t),!he.test(t))throw new p(r,`${r} must be 16-512 URL-safe characters`);return t}validateRealm(e){const r=e?.trim();if(r){if(this.assertNoControlChars("realm",r),r.length>W)throw new p("realm",`realm must be ${W} characters or fewer`);return r}}normalizeAndValidateIdentifier(e){return typeof e=="string"?{email:this.validateEmail(e)}:{email:e.email?this.validateEmail(e.email):void 0,mobileNumber:e.mobileNumber?this.validateMobileNumber(e.mobileNumber):void 0}}normalizeAuthIdentifier(e){return this.normalizeAndValidateIdentifier(e)}extractRealm(e,r){const t=r?.realm??(e&&typeof e!="string"?e.realm:void 0);return this.validateRealm(t)}buildAuthRequestBody(e,r){const t=this.normalizeAuthIdentifier(e),n=this.extractRealm(e,r);return{...t,...n?{realm:n}:{}}}buildUrl(e,r){const t=this.getBaseUrl().replace(/\/$/,""),n=e.startsWith("/")?e:`/${e}`,a=`${t}${n}`;if(!r||Object.keys(r).length===0)return a;const o=new URLSearchParams(r).toString();return`${a}?${o}`}async request(e,r,t){const n=this.buildUrl(r,t?.params),a={"Content-Type":"application/json",Accept:"application/json","X-API-Key":this.config.apiKey??"",...t?.headers},o={method:e,credentials:"include",headers:a};t?.body!==void 0&&t?.body!==null&&(o.body=JSON.stringify(t.body));const l=await fetch(n,o);if(!l.ok){let i;try{const m=await l.text();i=m?JSON.parse(m):void 0}catch{i=void 0}throw l.status===401&&(await this.clearTokens(),await R(),this.resetDPoPInitialization()),new G(l.status,i)}const c=await l.text();return{data:c?JSON.parse(c):{}}}async getRequestAuthHeaders(e,r){const t=localStorage.getItem(k);if(!t)return{};const n=r.startsWith("http")?r:`${this.getBaseUrl()}${r}`,a=await this.getRequiredDPoPProof(e,n,t);return{Authorization:`Bearer ${t}`,DPoP:a}}async getStatus(e,r){const t=this.normalizeAuthIdentifier(e),n=this.extractRealm(e,r),a={};t.email&&(a.email=t.email),t.mobileNumber&&(a.mobileNumber=t.mobileNumber),n&&(a.realm=n);const o=await this.request("GET","/auth/status",{params:a});return o.data.data??o.data}async initiateAuth(e,r){const t=this.buildAuthRequestBody(e,r),n=await this.request("POST","/auth/initiate",{body:t}),a=n.data.data??n.data;return{status:a.status,challenge:a.challenge,credentialIds:a.credentialIds,rp:a.rp}}async initiateOTP(e,r){const t=this.normalizeAuthIdentifier(e),n=this.extractRealm(e,r),a=t.email,o=t.mobileNumber;if(!a&&!o)throw new p("identifier","Either mobileNumber or email is required");const l={};a&&(l.email=a),o&&(l.mobileNumber=o),n&&(l.realm=n);const h=(await this.request("POST","/otp/initiate",{body:l})).data;return{message:h.message??h.data?.message}}async verifyOTP(e){const r=this.validateOTP(e),t=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/otp/verify`),n=await this.request("POST","/otp/verify",{body:{otp:r},headers:{DPoP:t}}),a=n.data.data??n.data,o=a.AuthenticationResult??a,l=o.access_token??o.accessToken??o.AccessToken,c=o.refresh_token??o.refreshToken??o.RefreshToken,h=o.expires_in??o.expiresIn,i=o.token_type??o.tokenType;return l&&await this.storeTokens({accessToken:l,refreshToken:c,expiresIn:h,tokenType:i}),{access_token:l,refresh_token:c,expires_in:h,token_type:i,verified:o.verified,email:o.email??o.Email,...o}}async resendOTP(){const e=await this.request("POST","/otp/resend",{}),r=e.data.data??e.data;return{success:r.success,message:r.message,...r}}async verifySignupOTP({mobileNumber:e,otp:r}){const t=this.validateMobileNumber(e),n=this.validateOTP(r),a=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/otp/signup/verify`),o=await this.request("POST","/otp/signup/verify",{body:{mobileNumber:t,otp:n},headers:{DPoP:a}}),l=o.data.data??o.data,c=l.AuthenticationResult??l,h=c.access_token??c.accessToken??c.AccessToken,i=c.refresh_token??c.refreshToken??c.RefreshToken,m=c.expires_in??c.expiresIn,w=c.token_type??c.tokenType;return h&&await this.storeTokens({accessToken:h,refreshToken:i,expiresIn:m,tokenType:w}),{access_token:h,refresh_token:i,expires_in:m,token_type:w,verified:c.verified,email:c.email??c.Email,...c}}async resendSignupOTP({mobileNumber:e,email:r=""}){const t=this.validateMobileNumber(e),n=r?this.validateEmail(r):"",a=await this.request("POST","/otp/signup/resend",{body:{email:n,mobileNumber:t}}),o=a.data.data??a.data;return{success:o.success,message:o.message,...o}}async verifyMagicLink(e){const r=this.validateMagicLinkToken(e);await this.request("GET","/verify/magic-link",{params:{token:r,redirect_mode:"frontend"}})}async completeMagicLink(){const e=await this.request("POST","/verify/magic-link/complete",{body:{}}),r=e.data.data??e.data,t=r.AuthenticationResult??r,n=t.access_token??t.accessToken??t.AccessToken,a=t.refresh_token??t.refreshToken??t.RefreshToken,o=t.expires_in??t.expiresIn,l=t.token_type??t.tokenType;return n&&await this.storeTokens({accessToken:n,refreshToken:a,expiresIn:o,tokenType:l}),{access_token:n,refresh_token:a,expires_in:o,token_type:l,verified:t.verified,email:t.email??t.Email,...t}}async initiatePasskeyRegistration(){const e=await this.request("POST","/webauthn/initiate/challenge",{body:{}});return e.data.data??e.data}async registerPasskey(e){const r=this.validateEmail(e),t=await this.initiatePasskeyRegistration();let n;if(t?.user?.id)try{n=b(t.user.id)}catch{n=g(t.user.id)}else n=g(r);const a=(t.pubKeyCredParams??[{type:"public-key",alg:-7},{type:"public-key",alg:-257}]).map(P=>({type:"public-key",alg:P.alg})),o=t.excludeCredentials?.map(P=>({type:"public-key",id:b(P)})),l={challenge:b(t.challenge),rp:{name:t.rp?.name??"XPay",id:t.rp?.id??window.location.hostname},user:{id:n,name:t.user?.name??r,displayName:t.user?.displayName??r},pubKeyCredParams:a,excludeCredentials:o,timeout:t.timeout??6e4,attestation:"direct",authenticatorSelection:{residentKey:"required",userVerification:"required",authenticatorAttachment:"platform"}},c=await navigator.credentials.create({publicKey:l});if(!c)throw new Error("Credential creation failed");const h=c.response,i={clientDataJSON:y(h.clientDataJSON),attestationObject:y(h.attestationObject),rawId:y(c.rawId)};if(!i.rawId)throw new Error("Raw ID is required");const m=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/webauthn/register/challenge`),w=await this.request("POST","/webauthn/register/challenge",{body:i,headers:{DPoP:m}});return w.data.data??w.data}async authenticateWithPasskey({challenge:e,rp:r,credentialIds:t}){const n=await navigator.credentials.get({publicKey:{challenge:b(e),rpId:r?.host??void 0,allowCredentials:t.map(P=>({type:"public-key",id:b(P),transports:["internal"]})),timeout:6e4,userVerification:"required"}});if(!n)throw new Error("Authentication failed");const a=n.response,o={clientDataJSON:y(a.clientDataJSON),authenticatorData:y(a.authenticatorData),signature:y(a.signature),rawId:y(n.rawId),userHandle:a.userHandle?y(a.userHandle):""},l=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/webauthn/authenticate/challenge`),c=await this.request("POST","/webauthn/authenticate/challenge",{body:o,headers:{DPoP:l}}),h=c.data.data??c.data,i=h.AuthenticationResult??h,m=i.AccessToken??i.accessToken??i.access_token,w=i.RefreshToken??i.refreshToken??i.refresh_token;return m&&await this.storeTokens({accessToken:m,refreshToken:w,expiresIn:i.expiresIn??i.ExpiresIn,tokenType:i.tokenType??i.token_type}),{access_token:m,refresh_token:w,email:i.email,name:i.name??i.userName,expiresIn:i.expiresIn??i.ExpiresIn,tokenType:i.tokenType??i.token_type,...i}}async getPasskeyStatus(e){const t=`/webauthn/credentials/${encodeURIComponent(e)}`,n=await this.signRequest("GET",t),a=await this.request("GET",t,{headers:n.headers}),o=a.data.data??a.data;return{...o,hasCredentials:!!(o.hasCredentials??o.credentialId)}}async removePasskey(e){const t=`/webauthn/credentials/${encodeURIComponent(e)}`,n=await this.signRequest("DELETE",t);await this.request("DELETE",t,{headers:n.headers})}async signRequest(e,r,t={}){const n=r.startsWith("http")?r:`${this.getBaseUrl()}${r}`,a=await this.getRequestAuthHeaders(e,n);return{...t,headers:{...t.headers,...a}}}async authenticatedFetch(e,r){const t=typeof e=="string"?e:e instanceof URL?e.toString():e.url,n=r?.method||"GET",a=await this.signRequest(n,t,{headers:r?.headers});return fetch(e,{...r,headers:a.headers})}async storeTokens(e){localStorage.setItem(k,e.accessToken),e.refreshToken&&localStorage.setItem(Y,e.refreshToken)}async clearTokens(){localStorage.removeItem(k),localStorage.removeItem(Y)}async refreshToken(e){const r=this.extractRealm(void 0,e),t=await this.request("POST","/auth/refresh",{body:r?{realm:r}:{}}),n=t.data.data??t.data,a=n.access_token,o=n.token_type,l=n.expires_in;return a&&await this.storeTokens({accessToken:a,expiresIn:l,tokenType:o}),{access_token:a,token_type:o,expires_in:l}}async logout(){try{const r=await this.getAccessToken()?await this.signRequest("POST","/auth/logout",{body:{}}):{body:{}};await this.request("POST","/auth/logout",r),await R(),this.resetDPoPInitialization()}catch{}await this.clearTokens()}async getAccessToken(){return localStorage.getItem(k)}}typeof window<"u"&&(window.AuthSDK=O);const fe=typeof window<"u"?window:globalThis;return fe.AuthSDK=O,d.AuthSDK=O,d.AuthSDKFetchError=G,d.SDKValidationError=p,d.arrayBufferToBase64=E,d.arrayBufferToBase64url=y,d.base64ToArrayBuffer=_,d.base64urlToArrayBuffer=b,d.clearPasskeyEmail=q,d.clearPasskeyMobileNumber=M,d.getPasskeyEmail=C,d.getPasskeyMobileNumber=$,d.isConditionalUISupported=N,d.isWebAuthnSupported=T,d.setPasskeyEmail=K,d.setPasskeyMobileNumber=B,d.stringToArrayBuffer=g,d.uint8ArrayToString=x,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"}),d})({});
|
|
1
|
+
var PostexAuthSDKStage=(function(d){"use strict";function T(){return typeof window<"u"&&typeof window.PublicKeyCredential<"u"&&typeof navigator<"u"&&typeof navigator.credentials<"u"}async function O(){if(!T())return!1;try{return await PublicKeyCredential.isConditionalMediationAvailable?.()??!1}catch{return!1}}function E(s){const e=new Uint8Array(s);let r="";for(let t=0;t<e.byteLength;t++)r+=String.fromCharCode(e[t]);return btoa(r)}function _(s){if(typeof s!="string"||!s)throw new Error("Invalid base64: expected non-empty string");const e=s.replace(/\s/g,"").replace(/-/g,"+").replace(/_/g,"/"),r=e.length%4,t=r>0?e+"=".repeat(4-r):e;try{const n=atob(t),a=new Uint8Array(n.length);for(let o=0;o<n.length;o++)a[o]=n.charCodeAt(o);return a.buffer}catch{throw new Error("Invalid base64: string is not correctly encoded. Check challenge/credentialId from server.")}}function y(s){return E(s).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function X(s){return/^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i.test(s)}function Z(s){const e=s.replace(/-/g,""),r=new Uint8Array(e.length/2);for(let t=0;t<r.length;t++)r[t]=parseInt(e.substr(t*2,2),16);return r.buffer}function b(s){if(!s||typeof s!="string")throw new Error("Invalid input: expected non-empty string");return X(s)?Z(s):_(s)}function g(s){return new TextEncoder().encode(s).buffer}function C(s){return String.fromCharCode(...s)}const Q="xpay_webauthn",ee=1,u="passkey_data",S="passkey_email",A="passkey_mobile_number";function f(){return new Promise((s,e)=>{const r=indexedDB.open(Q,ee);r.onerror=()=>e(r.error),r.onsuccess=()=>s(r.result),r.onupgradeneeded=()=>{const t=r.result;t.objectStoreNames.contains(u)||t.createObjectStore(u)}})}async function x(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readonly"),a=t.objectStore(u).get(S);a.onerror=()=>r(a.error),a.onsuccess=()=>e(a.result??null),t.oncomplete=()=>s.close()})}catch{return null}}async function K(s){try{const e=await f();return new Promise((r,t)=>{const n=e.transaction(u,"readwrite"),o=n.objectStore(u).put(s,S);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),n.oncomplete=()=>e.close()})}catch{}}async function q(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readwrite"),a=t.objectStore(u).delete(S);a.onerror=()=>r(a.error),a.onsuccess=()=>e(),t.oncomplete=()=>s.close()})}catch{}}async function $(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readonly"),a=t.objectStore(u).get(A);a.onerror=()=>r(a.error),a.onsuccess=()=>e(a.result??null),t.oncomplete=()=>s.close()})}catch{return null}}async function B(s){try{const e=await f();return new Promise((r,t)=>{const n=e.transaction(u,"readwrite"),o=n.objectStore(u).put(s,A);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),n.oncomplete=()=>e.close()})}catch{}}async function U(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readwrite"),a=t.objectStore(u).delete(A);a.onerror=()=>r(a.error),a.onsuccess=()=>e(),t.oncomplete=()=>s.close()})}catch{}}const v="dpop_private_key",I="dpop_public_key_jwk";function M(s){if(!s||typeof s!="object")return!1;const e=s;return e.kty==="EC"&&e.crv==="P-256"&&typeof e.x=="string"&&typeof e.y=="string"}class D extends Error{constructor(e){super(e),this.name="DPoPProofGenerationError"}}function te(s){return{kty:"EC",crv:"P-256",x:s.x,y:s.y}}async function z(s){const e=JSON.stringify({crv:s.crv,kty:s.kty,x:s.x,y:s.y}),r=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(e));return y(r)}async function re(s){try{const e=await f();return new Promise((r,t)=>{const n=e.transaction(u,"readwrite"),o=n.objectStore(u).put(s,v);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),n.oncomplete=()=>e.close()})}catch(e){console.error("Failed to store DPoP private key:",e)}}async function ae(s){try{const e=await f();return new Promise((r,t)=>{const n=e.transaction(u,"readwrite"),o=n.objectStore(u).put(s,I);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),n.oncomplete=()=>e.close()})}catch(e){console.error("Failed to store DPoP public key JWK:",e)}}async function L(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readonly"),a=t.objectStore(u).get(v);a.onerror=()=>r(a.error),a.onsuccess=()=>e(a.result??null),t.oncomplete=()=>s.close()})}catch{return null}}async function j(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readonly"),a=t.objectStore(u).get(I);a.onerror=()=>r(a.error),a.onsuccess=()=>e(a.result??null),t.oncomplete=()=>s.close()})}catch{return null}}async function R(){try{const s=await f();return new Promise((e,r)=>{const t=s.transaction(u,"readwrite"),n=t.objectStore(u);n.delete(v),n.delete(I),t.onerror=()=>r(t.error),t.oncomplete=()=>{s.close(),e()}})}catch{}}async function ne(){const s=await crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-256"},!1,["sign","verify"]),e=await crypto.subtle.exportKey("jwk",s.publicKey),r=te(e),t=await z(r);return await re(s.privateKey),await ae(r),{publicKey:r,thumbprint:t}}async function se(){const s=await L(),e=await j();return s&&M(e)?{publicKey:e,thumbprint:await z(e)}:((s||e)&&await R(),ne())}async function oe(s,e,r){try{const t=await L(),n=await j();if(!t||!M(n))throw new D("DPoP key material is unavailable or invalid");const a={typ:"dpop+jwt",alg:"ES256",jwk:n},o=new URL(e,typeof window<"u"?window.location.origin:void 0),l=`${o.origin}${o.pathname}`,c={jti:crypto.randomUUID(),htm:s.toUpperCase(),htu:l,iat:Math.floor(Date.now()/1e3)};if(r){const be=new TextEncoder().encode(r),Pe=await crypto.subtle.digest("SHA-256",be);c.ath=y(Pe)}const h=y(new TextEncoder().encode(JSON.stringify(a)).buffer),i=y(new TextEncoder().encode(JSON.stringify(c)).buffer),p=`${h}.${i}`,w=await crypto.subtle.sign({name:"ECDSA",hash:{name:"SHA-256"}},t,new TextEncoder().encode(p)),P=y(w);return`${h}.${i}.${P}`}catch(t){throw console.error("Failed to generate DPoP proof:",t),t instanceof D?t:new D("Failed to generate DPoP proof")}}const H={isWebAuthnSupported:T,isConditionalUISupported:O,arrayBufferToBase64:E,base64ToArrayBuffer:_,arrayBufferToBase64url:y,base64urlToArrayBuffer:b,stringToArrayBuffer:g,uint8ArrayToString:C,getPasskeyEmail:x,setPasskeyEmail:K,clearPasskeyEmail:q,getPasskeyMobileNumber:$,setPasskeyMobileNumber:B,clearPasskeyMobileNumber:U};typeof window<"u"&&(window.WebAuthn=H);const ie=typeof window<"u"?window:globalThis;ie.WebAuthn=H;const k="postex-auth-token",ce="postexglobal",le={xstak:"https://auth-stage.xstak.com/public/v1",postex:"https://auth-stage.postex.pk/public/v1",callcourier:"https://auth-stage.callcourier.com.pk/public/v1",postexglobal:"https://auth-stage.postexglobal.com/public/v1",postexsa:"https://auth-stage.postex.sa/public/v1"},ue=/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/,de=/^\+[1-9]\d{6,14}$/,he=/^\d{6}$/,ye=/^[A-Za-z0-9_-]{16,512}$/,me=/[\u0000-\u001F\u007F-\u009F]/,pe=/[A-Za-z]/,fe=/[\u0400-\u04FF]/,J=254,F=16,W=64,G=64;class Y extends Error{constructor(e,r,t){super(t??`Request failed with status ${e}`),this.response={status:e,data:r},this.name="AuthSDKFetchError"}}class m extends Error{constructor(e,r,t="invalid_input"){super(r),this.field=e,this.code=t,this.name="SDKValidationError"}}const V="auth_sdk_refresh_token";class N{constructor(e){this.config=e,this.dpopInitializationPromise=this.createDPoPInitializationPromise()}getBaseUrl(){const e=this.config.appId??ce;return le[e]}async initializeDPoPState(){await se()}async ensureDPoPInitialized(){await this.dpopInitializationPromise}createDPoPInitializationPromise(){const e=this.initializeDPoPState();return e.catch(r=>{console.warn("[AuthSDK] DPoP initialization failed:",r)}),e}resetDPoPInitialization(){this.dpopInitializationPromise=this.createDPoPInitializationPromise()}async getRequiredDPoPProof(e,r,t){return await this.ensureDPoPInitialized(),oe(e.toUpperCase(),r,t)}containsControlChars(e){return me.test(e)}hasMixedLatinAndCyrillic(e){return pe.test(e)&&fe.test(e)}assertNoControlChars(e,r){if(this.containsControlChars(r))throw new m(e,`${e} must not contain control characters`)}validateEmail(e,r="email"){const t=e.trim();if(!t)throw new m(r,`${r} is required`);if(t.length>J)throw new m(r,`${r} must be ${J} characters or fewer`);this.assertNoControlChars(r,t);const[n=""]=t.split("@");if(this.hasMixedLatinAndCyrillic(n))throw new m(r,`${r} must not mix Latin and Cyrillic characters in the local part`);if(!ue.test(t))throw new m(r,`${r} must be a valid email`);return t}validateMobileNumber(e,r="mobileNumber"){const t=e.trim();if(!t)throw new m(r,`${r} is required`);if(t.length>F)throw new m(r,`${r} must be ${F} characters or fewer`);if(this.assertNoControlChars(r,t),!de.test(t))throw new m(r,`${r} must be in E.164 format`);return t}validateUsername(e,r="username"){const t=e.trim();if(!t)throw new m(r,`${r} is required`);if(t.length>W)throw new m(r,`${r} must be ${W} characters or fewer`);return this.assertNoControlChars(r,t),t}validateOTP(e,r="otp"){const t=e.trim();if(this.assertNoControlChars(r,t),!he.test(t))throw new m(r,`${r} must be a 6-digit code`);return t}validateMagicLinkToken(e,r="token"){const t=e.trim();if(this.assertNoControlChars(r,t),!ye.test(t))throw new m(r,`${r} must be 16-512 URL-safe characters`);return t}validateRealm(e){const r=e?.trim();if(r){if(this.assertNoControlChars("realm",r),r.length>G)throw new m("realm",`realm must be ${G} characters or fewer`);return r}}normalizeAndValidateIdentifier(e){return typeof e=="string"?{email:this.validateEmail(e)}:{email:e.email?this.validateEmail(e.email):void 0,mobileNumber:e.mobileNumber?this.validateMobileNumber(e.mobileNumber):void 0,username:e.username?this.validateUsername(e.username):void 0}}normalizeAuthIdentifier(e){return this.normalizeAndValidateIdentifier(e)}extractRealm(e,r){const t=r?.realm??(e&&typeof e!="string"?e.realm:void 0);return this.validateRealm(t)}buildAuthRequestBody(e,r){const t=this.normalizeAuthIdentifier(e),n=this.extractRealm(e,r);return{...t,...n?{realm:n}:{}}}buildUrl(e,r){const t=this.getBaseUrl().replace(/\/$/,""),n=e.startsWith("/")?e:`/${e}`,a=`${t}${n}`;if(!r||Object.keys(r).length===0)return a;const o=new URLSearchParams(r).toString();return`${a}?${o}`}async request(e,r,t){const n=this.buildUrl(r,t?.params),a={"Content-Type":"application/json",Accept:"application/json","X-API-Key":this.config.apiKey??"",...t?.headers},o={method:e,credentials:"include",headers:a};t?.body!==void 0&&t?.body!==null&&(o.body=JSON.stringify(t.body));const l=await fetch(n,o);if(!l.ok){let i;try{const p=await l.text();i=p?JSON.parse(p):void 0}catch{i=void 0}throw l.status===401&&(await this.clearTokens(),await R(),this.resetDPoPInitialization()),new Y(l.status,i)}const c=await l.text();return{data:c?JSON.parse(c):{}}}async getRequestAuthHeaders(e,r){const t=localStorage.getItem(k);if(!t)return{};const n=r.startsWith("http")?r:`${this.getBaseUrl()}${r}`,a=await this.getRequiredDPoPProof(e,n,t);return{Authorization:`Bearer ${t}`,DPoP:a}}async getStatus(e,r){const t=this.normalizeAuthIdentifier(e),n=this.extractRealm(e,r),a={};t.email&&(a.email=t.email),t.mobileNumber&&(a.mobileNumber=t.mobileNumber),t.username&&(a.username=t.username),n&&(a.realm=n);const o=await this.request("GET","/auth/status",{params:a});return o.data.data??o.data}async initiateAuth(e,r){const t=this.buildAuthRequestBody(e,r),n=await this.request("POST","/auth/initiate",{body:t}),a=n.data.data??n.data;return{status:a.status,challenge:a.challenge,credentialIds:a.credentialIds,rp:a.rp}}async initiateOTP(e,r){const t=this.normalizeAuthIdentifier(e),n=this.extractRealm(e,r),a=t.email,o=t.mobileNumber,l=t.username;if(!a&&!o&&!l)throw new m("identifier","Either mobileNumber, email, or username is required");const c={};a&&(c.email=a),o&&(c.mobileNumber=o),l&&(c.username=l),n&&(c.realm=n);const i=(await this.request("POST","/otp/initiate",{body:c})).data;return{message:i.message??i.data?.message}}async verifyOTP(e){const r=this.validateOTP(e),t=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/otp/verify`),n=await this.request("POST","/otp/verify",{body:{otp:r},headers:{DPoP:t}}),a=n.data.data??n.data,o=a.AuthenticationResult??a,l=o.access_token??o.accessToken??o.AccessToken,c=o.refresh_token??o.refreshToken??o.RefreshToken,h=o.expires_in??o.expiresIn,i=o.token_type??o.tokenType;return l&&await this.storeTokens({accessToken:l,refreshToken:c,expiresIn:h,tokenType:i}),{access_token:l,refresh_token:c,expires_in:h,token_type:i,verified:o.verified,email:o.email??o.Email,...o}}async resendOTP(){const e=await this.request("POST","/otp/resend",{}),r=e.data.data??e.data;return{success:r.success,message:r.message,...r}}async verifySignupOTP({mobileNumber:e,otp:r}){const t=this.validateMobileNumber(e),n=this.validateOTP(r),a=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/otp/signup/verify`),o=await this.request("POST","/otp/signup/verify",{body:{mobileNumber:t,otp:n},headers:{DPoP:a}}),l=o.data.data??o.data,c=l.AuthenticationResult??l,h=c.access_token??c.accessToken??c.AccessToken,i=c.refresh_token??c.refreshToken??c.RefreshToken,p=c.expires_in??c.expiresIn,w=c.token_type??c.tokenType;return h&&await this.storeTokens({accessToken:h,refreshToken:i,expiresIn:p,tokenType:w}),{access_token:h,refresh_token:i,expires_in:p,token_type:w,verified:c.verified,email:c.email??c.Email,...c}}async resendSignupOTP({mobileNumber:e,email:r=""}){const t=this.validateMobileNumber(e),n=r?this.validateEmail(r):"",a=await this.request("POST","/otp/signup/resend",{body:{email:n,mobileNumber:t}}),o=a.data.data??a.data;return{success:o.success,message:o.message,...o}}async verifyMagicLink(e){const r=this.validateMagicLinkToken(e);await this.request("GET","/verify/magic-link",{params:{token:r,redirect_mode:"frontend"}})}async completeMagicLink(){const e=await this.request("POST","/verify/magic-link/complete",{body:{}}),r=e.data.data??e.data,t=r.AuthenticationResult??r,n=t.access_token??t.accessToken??t.AccessToken,a=t.refresh_token??t.refreshToken??t.RefreshToken,o=t.expires_in??t.expiresIn,l=t.token_type??t.tokenType;return n&&await this.storeTokens({accessToken:n,refreshToken:a,expiresIn:o,tokenType:l}),{access_token:n,refresh_token:a,expires_in:o,token_type:l,verified:t.verified,email:t.email??t.Email,...t}}async initiatePasskeyRegistration(){const e=await this.request("POST","/webauthn/initiate/challenge",{body:{}});return e.data.data??e.data}async registerPasskey(e){const r=this.validateEmail(e),t=await this.initiatePasskeyRegistration();let n;if(t?.user?.id)try{n=b(t.user.id)}catch{n=g(t.user.id)}else n=g(r);const a=(t.pubKeyCredParams??[{type:"public-key",alg:-7},{type:"public-key",alg:-257}]).map(P=>({type:"public-key",alg:P.alg})),o=t.excludeCredentials?.map(P=>({type:"public-key",id:b(P)})),l={challenge:b(t.challenge),rp:{name:t.rp?.name??"XPay",id:t.rp?.id??window.location.hostname},user:{id:n,name:t.user?.name??r,displayName:t.user?.displayName??r},pubKeyCredParams:a,excludeCredentials:o,timeout:t.timeout??6e4,attestation:"direct",authenticatorSelection:{residentKey:"required",userVerification:"required",authenticatorAttachment:"platform"}},c=await navigator.credentials.create({publicKey:l});if(!c)throw new Error("Credential creation failed");const h=c.response,i={clientDataJSON:y(h.clientDataJSON),attestationObject:y(h.attestationObject),rawId:y(c.rawId)};if(!i.rawId)throw new Error("Raw ID is required");const p=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/webauthn/register/challenge`),w=await this.request("POST","/webauthn/register/challenge",{body:i,headers:{DPoP:p}});return w.data.data??w.data}async authenticateWithPasskey({challenge:e,rp:r,credentialIds:t}){const n=await navigator.credentials.get({publicKey:{challenge:b(e),rpId:r?.host??void 0,allowCredentials:t.map(P=>({type:"public-key",id:b(P),transports:["internal"]})),timeout:6e4,userVerification:"required"}});if(!n)throw new Error("Authentication failed");const a=n.response,o={clientDataJSON:y(a.clientDataJSON),authenticatorData:y(a.authenticatorData),signature:y(a.signature),rawId:y(n.rawId),userHandle:a.userHandle?y(a.userHandle):""},l=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/webauthn/authenticate/challenge`),c=await this.request("POST","/webauthn/authenticate/challenge",{body:o,headers:{DPoP:l}}),h=c.data.data??c.data,i=h.AuthenticationResult??h,p=i.AccessToken??i.accessToken??i.access_token,w=i.RefreshToken??i.refreshToken??i.refresh_token;return p&&await this.storeTokens({accessToken:p,refreshToken:w,expiresIn:i.expiresIn??i.ExpiresIn,tokenType:i.tokenType??i.token_type}),{access_token:p,refresh_token:w,email:i.email,name:i.name??i.userName,expiresIn:i.expiresIn??i.ExpiresIn,tokenType:i.tokenType??i.token_type,...i}}async getPasskeyStatus(e){const t=`/webauthn/credentials/${encodeURIComponent(e)}`,n=await this.signRequest("GET",t),a=await this.request("GET",t,{headers:n.headers}),o=a.data.data??a.data;return{...o,hasCredentials:!!(o.hasCredentials??o.credentialId)}}async removePasskey(e){const t=`/webauthn/credentials/${encodeURIComponent(e)}`,n=await this.signRequest("DELETE",t);await this.request("DELETE",t,{headers:n.headers})}async signRequest(e,r,t={}){const n=r.startsWith("http")?r:`${this.getBaseUrl()}${r}`,a=await this.getRequestAuthHeaders(e,n);return{...t,headers:{...t.headers,...a}}}async authenticatedFetch(e,r){const t=typeof e=="string"?e:e instanceof URL?e.toString():e.url,n=r?.method||"GET",a=await this.signRequest(n,t,{headers:r?.headers});return fetch(e,{...r,headers:a.headers})}async storeTokens(e){localStorage.setItem(k,e.accessToken),e.refreshToken&&localStorage.setItem(V,e.refreshToken)}async clearTokens(){localStorage.removeItem(k),localStorage.removeItem(V)}async refreshToken(e){const r=this.extractRealm(void 0,e),t=await this.request("POST","/auth/refresh",{body:r?{realm:r}:{}}),n=t.data.data??t.data,a=n.access_token,o=n.token_type,l=n.expires_in;return a&&await this.storeTokens({accessToken:a,expiresIn:l,tokenType:o}),{access_token:a,token_type:o,expires_in:l}}async logout(){try{const r=await this.getAccessToken()?await this.signRequest("POST","/auth/logout",{body:{}}):{body:{}};await this.request("POST","/auth/logout",r),await R(),this.resetDPoPInitialization()}catch{}await this.clearTokens()}async getAccessToken(){return localStorage.getItem(k)}}typeof window<"u"&&(window.AuthSDK=N);const we=typeof window<"u"?window:globalThis;return we.AuthSDK=N,d.AuthSDK=N,d.AuthSDKFetchError=Y,d.SDKValidationError=m,d.arrayBufferToBase64=E,d.arrayBufferToBase64url=y,d.base64ToArrayBuffer=_,d.base64urlToArrayBuffer=b,d.clearPasskeyEmail=q,d.clearPasskeyMobileNumber=U,d.getPasskeyEmail=x,d.getPasskeyMobileNumber=$,d.isConditionalUISupported=O,d.isWebAuthnSupported=T,d.setPasskeyEmail=K,d.setPasskeyMobileNumber=B,d.stringToArrayBuffer=g,d.uint8ArrayToString=C,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"}),d})({});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(d,b){typeof exports=="object"&&typeof module<"u"?b(exports):typeof define=="function"&&define.amd?define(["exports"],b):(d=typeof globalThis<"u"?globalThis:d||self,b(d.PostexAuthSDKStage={}))})(this,(function(d){"use strict";function b(){return typeof window<"u"&&typeof window.PublicKeyCredential<"u"&&typeof navigator<"u"&&typeof navigator.credentials<"u"}async function O(){if(!b())return!1;try{return await PublicKeyCredential.isConditionalMediationAvailable?.()??!1}catch{return!1}}function E(a){const e=new Uint8Array(a);let r="";for(let t=0;t<e.byteLength;t++)r+=String.fromCharCode(e[t]);return btoa(r)}function _(a){if(typeof a!="string"||!a)throw new Error("Invalid base64: expected non-empty string");const e=a.replace(/\s/g,"").replace(/-/g,"+").replace(/_/g,"/"),r=e.length%4,t=r>0?e+"=".repeat(4-r):e;try{const s=atob(t),n=new Uint8Array(s.length);for(let o=0;o<s.length;o++)n[o]=s.charCodeAt(o);return n.buffer}catch{throw new Error("Invalid base64: string is not correctly encoded. Check challenge/credentialId from server.")}}function y(a){return E(a).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function V(a){return/^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i.test(a)}function X(a){const e=a.replace(/-/g,""),r=new Uint8Array(e.length/2);for(let t=0;t<r.length;t++)r[t]=parseInt(e.substr(t*2,2),16);return r.buffer}function P(a){if(!a||typeof a!="string")throw new Error("Invalid input: expected non-empty string");return V(a)?X(a):_(a)}function k(a){return new TextEncoder().encode(a).buffer}function N(a){return String.fromCharCode(...a)}const Z="xpay_webauthn",Q=1,u="passkey_data",S="passkey_email",A="passkey_mobile_number";function f(){return new Promise((a,e)=>{const r=indexedDB.open(Z,Q);r.onerror=()=>e(r.error),r.onsuccess=()=>a(r.result),r.onupgradeneeded=()=>{const t=r.result;t.objectStoreNames.contains(u)||t.createObjectStore(u)}})}async function C(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readonly"),n=t.objectStore(u).get(S);n.onerror=()=>r(n.error),n.onsuccess=()=>e(n.result??null),t.oncomplete=()=>a.close()})}catch{return null}}async function K(a){try{const e=await f();return new Promise((r,t)=>{const s=e.transaction(u,"readwrite"),o=s.objectStore(u).put(a,S);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),s.oncomplete=()=>e.close()})}catch{}}async function q(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readwrite"),n=t.objectStore(u).delete(S);n.onerror=()=>r(n.error),n.onsuccess=()=>e(),t.oncomplete=()=>a.close()})}catch{}}async function $(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readonly"),n=t.objectStore(u).get(A);n.onerror=()=>r(n.error),n.onsuccess=()=>e(n.result??null),t.oncomplete=()=>a.close()})}catch{return null}}async function B(a){try{const e=await f();return new Promise((r,t)=>{const s=e.transaction(u,"readwrite"),o=s.objectStore(u).put(a,A);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),s.oncomplete=()=>e.close()})}catch{}}async function M(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readwrite"),n=t.objectStore(u).delete(A);n.onerror=()=>r(n.error),n.onsuccess=()=>e(),t.oncomplete=()=>a.close()})}catch{}}const v="dpop_private_key",I="dpop_public_key_jwk";function U(a){if(!a||typeof a!="object")return!1;const e=a;return e.kty==="EC"&&e.crv==="P-256"&&typeof e.x=="string"&&typeof e.y=="string"}class D extends Error{constructor(e){super(e),this.name="DPoPProofGenerationError"}}function ee(a){return{kty:"EC",crv:"P-256",x:a.x,y:a.y}}async function z(a){const e=JSON.stringify({crv:a.crv,kty:a.kty,x:a.x,y:a.y}),r=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(e));return y(r)}async function te(a){try{const e=await f();return new Promise((r,t)=>{const s=e.transaction(u,"readwrite"),o=s.objectStore(u).put(a,v);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),s.oncomplete=()=>e.close()})}catch(e){console.error("Failed to store DPoP private key:",e)}}async function re(a){try{const e=await f();return new Promise((r,t)=>{const s=e.transaction(u,"readwrite"),o=s.objectStore(u).put(a,I);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),s.oncomplete=()=>e.close()})}catch(e){console.error("Failed to store DPoP public key JWK:",e)}}async function L(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readonly"),n=t.objectStore(u).get(v);n.onerror=()=>r(n.error),n.onsuccess=()=>e(n.result??null),t.oncomplete=()=>a.close()})}catch{return null}}async function j(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readonly"),n=t.objectStore(u).get(I);n.onerror=()=>r(n.error),n.onsuccess=()=>e(n.result??null),t.oncomplete=()=>a.close()})}catch{return null}}async function R(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readwrite"),s=t.objectStore(u);s.delete(v),s.delete(I),t.onerror=()=>r(t.error),t.oncomplete=()=>{a.close(),e()}})}catch{}}async function ne(){const a=await crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-256"},!1,["sign","verify"]),e=await crypto.subtle.exportKey("jwk",a.publicKey),r=ee(e),t=await z(r);return await te(a.privateKey),await re(r),{publicKey:r,thumbprint:t}}async function se(){const a=await L(),e=await j();return a&&U(e)?{publicKey:e,thumbprint:await z(e)}:((a||e)&&await R(),ne())}async function ae(a,e,r){try{const t=await L(),s=await j();if(!t||!U(s))throw new D("DPoP key material is unavailable or invalid");const n={typ:"dpop+jwt",alg:"ES256",jwk:s},o=new URL(e,typeof window<"u"?window.location.origin:void 0),l=`${o.origin}${o.pathname}`,c={jti:crypto.randomUUID(),htm:a.toUpperCase(),htu:l,iat:Math.floor(Date.now()/1e3)};if(r){const we=new TextEncoder().encode(r),be=await crypto.subtle.digest("SHA-256",we);c.ath=y(be)}const h=y(new TextEncoder().encode(JSON.stringify(n)).buffer),i=y(new TextEncoder().encode(JSON.stringify(c)).buffer),m=`${h}.${i}`,w=await crypto.subtle.sign({name:"ECDSA",hash:{name:"SHA-256"}},t,new TextEncoder().encode(m)),g=y(w);return`${h}.${i}.${g}`}catch(t){throw console.error("Failed to generate DPoP proof:",t),t instanceof D?t:new D("Failed to generate DPoP proof")}}const H={isWebAuthnSupported:b,isConditionalUISupported:O,arrayBufferToBase64:E,base64ToArrayBuffer:_,arrayBufferToBase64url:y,base64urlToArrayBuffer:P,stringToArrayBuffer:k,uint8ArrayToString:N,getPasskeyEmail:C,setPasskeyEmail:K,clearPasskeyEmail:q,getPasskeyMobileNumber:$,setPasskeyMobileNumber:B,clearPasskeyMobileNumber:M};typeof window<"u"&&(window.WebAuthn=H);const oe=typeof window<"u"?window:globalThis;oe.WebAuthn=H;const T="postex-auth-token",ie="postexglobal",ce={xstak:"https://auth-stage.xstak.com/public/v1",postex:"https://auth-stage.postex.pk/public/v1",callcourier:"https://auth-stage.callcourier.com.pk/public/v1",postexglobal:"https://auth-stage.postexglobal.com/public/v1",postexsa:"https://auth-stage.postex.sa/public/v1"},le=/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/,ue=/^\+[1-9]\d{6,14}$/,de=/^\d{6}$/,he=/^[A-Za-z0-9_-]{16,512}$/,ye=/[\u0000-\u001F\u007F-\u009F]/,pe=/[A-Za-z]/,me=/[\u0400-\u04FF]/,J=254,F=16,W=64;class G extends Error{constructor(e,r,t){super(t??`Request failed with status ${e}`),this.response={status:e,data:r},this.name="AuthSDKFetchError"}}class p extends Error{constructor(e,r,t="invalid_input"){super(r),this.field=e,this.code=t,this.name="SDKValidationError"}}const Y="auth_sdk_refresh_token";class x{constructor(e){this.config=e,this.dpopInitializationPromise=this.createDPoPInitializationPromise()}getBaseUrl(){const e=this.config.appId??ie;return ce[e]}async initializeDPoPState(){await se()}async ensureDPoPInitialized(){await this.dpopInitializationPromise}createDPoPInitializationPromise(){const e=this.initializeDPoPState();return e.catch(r=>{console.warn("[AuthSDK] DPoP initialization failed:",r)}),e}resetDPoPInitialization(){this.dpopInitializationPromise=this.createDPoPInitializationPromise()}async getRequiredDPoPProof(e,r,t){return await this.ensureDPoPInitialized(),ae(e.toUpperCase(),r,t)}containsControlChars(e){return ye.test(e)}hasMixedLatinAndCyrillic(e){return pe.test(e)&&me.test(e)}assertNoControlChars(e,r){if(this.containsControlChars(r))throw new p(e,`${e} must not contain control characters`)}validateEmail(e,r="email"){const t=e.trim();if(!t)throw new p(r,`${r} is required`);if(t.length>J)throw new p(r,`${r} must be ${J} characters or fewer`);this.assertNoControlChars(r,t);const[s=""]=t.split("@");if(this.hasMixedLatinAndCyrillic(s))throw new p(r,`${r} must not mix Latin and Cyrillic characters in the local part`);if(!le.test(t))throw new p(r,`${r} must be a valid email`);return t}validateMobileNumber(e,r="mobileNumber"){const t=e.trim();if(!t)throw new p(r,`${r} is required`);if(t.length>F)throw new p(r,`${r} must be ${F} characters or fewer`);if(this.assertNoControlChars(r,t),!ue.test(t))throw new p(r,`${r} must be in E.164 format`);return t}validateOTP(e,r="otp"){const t=e.trim();if(this.assertNoControlChars(r,t),!de.test(t))throw new p(r,`${r} must be a 6-digit code`);return t}validateMagicLinkToken(e,r="token"){const t=e.trim();if(this.assertNoControlChars(r,t),!he.test(t))throw new p(r,`${r} must be 16-512 URL-safe characters`);return t}validateRealm(e){const r=e?.trim();if(r){if(this.assertNoControlChars("realm",r),r.length>W)throw new p("realm",`realm must be ${W} characters or fewer`);return r}}normalizeAndValidateIdentifier(e){return typeof e=="string"?{email:this.validateEmail(e)}:{email:e.email?this.validateEmail(e.email):void 0,mobileNumber:e.mobileNumber?this.validateMobileNumber(e.mobileNumber):void 0}}normalizeAuthIdentifier(e){return this.normalizeAndValidateIdentifier(e)}extractRealm(e,r){const t=r?.realm??(e&&typeof e!="string"?e.realm:void 0);return this.validateRealm(t)}buildAuthRequestBody(e,r){const t=this.normalizeAuthIdentifier(e),s=this.extractRealm(e,r);return{...t,...s?{realm:s}:{}}}buildUrl(e,r){const t=this.getBaseUrl().replace(/\/$/,""),s=e.startsWith("/")?e:`/${e}`,n=`${t}${s}`;if(!r||Object.keys(r).length===0)return n;const o=new URLSearchParams(r).toString();return`${n}?${o}`}async request(e,r,t){const s=this.buildUrl(r,t?.params),n={"Content-Type":"application/json",Accept:"application/json","X-API-Key":this.config.apiKey??"",...t?.headers},o={method:e,credentials:"include",headers:n};t?.body!==void 0&&t?.body!==null&&(o.body=JSON.stringify(t.body));const l=await fetch(s,o);if(!l.ok){let i;try{const m=await l.text();i=m?JSON.parse(m):void 0}catch{i=void 0}throw l.status===401&&(await this.clearTokens(),await R(),this.resetDPoPInitialization()),new G(l.status,i)}const c=await l.text();return{data:c?JSON.parse(c):{}}}async getRequestAuthHeaders(e,r){const t=localStorage.getItem(T);if(!t)return{};const s=r.startsWith("http")?r:`${this.getBaseUrl()}${r}`,n=await this.getRequiredDPoPProof(e,s,t);return{Authorization:`Bearer ${t}`,DPoP:n}}async getStatus(e,r){const t=this.normalizeAuthIdentifier(e),s=this.extractRealm(e,r),n={};t.email&&(n.email=t.email),t.mobileNumber&&(n.mobileNumber=t.mobileNumber),s&&(n.realm=s);const o=await this.request("GET","/auth/status",{params:n});return o.data.data??o.data}async initiateAuth(e,r){const t=this.buildAuthRequestBody(e,r),s=await this.request("POST","/auth/initiate",{body:t}),n=s.data.data??s.data;return{status:n.status,challenge:n.challenge,credentialIds:n.credentialIds,rp:n.rp}}async initiateOTP(e,r){const t=this.normalizeAuthIdentifier(e),s=this.extractRealm(e,r),n=t.email,o=t.mobileNumber;if(!n&&!o)throw new p("identifier","Either mobileNumber or email is required");const l={};n&&(l.email=n),o&&(l.mobileNumber=o),s&&(l.realm=s);const h=(await this.request("POST","/otp/initiate",{body:l})).data;return{message:h.message??h.data?.message}}async verifyOTP(e){const r=this.validateOTP(e),t=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/otp/verify`),s=await this.request("POST","/otp/verify",{body:{otp:r},headers:{DPoP:t}}),n=s.data.data??s.data,o=n.AuthenticationResult??n,l=o.access_token??o.accessToken??o.AccessToken,c=o.refresh_token??o.refreshToken??o.RefreshToken,h=o.expires_in??o.expiresIn,i=o.token_type??o.tokenType;return l&&await this.storeTokens({accessToken:l,refreshToken:c,expiresIn:h,tokenType:i}),{access_token:l,refresh_token:c,expires_in:h,token_type:i,verified:o.verified,email:o.email??o.Email,...o}}async resendOTP(){const e=await this.request("POST","/otp/resend",{}),r=e.data.data??e.data;return{success:r.success,message:r.message,...r}}async verifySignupOTP({mobileNumber:e,otp:r}){const t=this.validateMobileNumber(e),s=this.validateOTP(r),n=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/otp/signup/verify`),o=await this.request("POST","/otp/signup/verify",{body:{mobileNumber:t,otp:s},headers:{DPoP:n}}),l=o.data.data??o.data,c=l.AuthenticationResult??l,h=c.access_token??c.accessToken??c.AccessToken,i=c.refresh_token??c.refreshToken??c.RefreshToken,m=c.expires_in??c.expiresIn,w=c.token_type??c.tokenType;return h&&await this.storeTokens({accessToken:h,refreshToken:i,expiresIn:m,tokenType:w}),{access_token:h,refresh_token:i,expires_in:m,token_type:w,verified:c.verified,email:c.email??c.Email,...c}}async resendSignupOTP({mobileNumber:e,email:r=""}){const t=this.validateMobileNumber(e),s=r?this.validateEmail(r):"",n=await this.request("POST","/otp/signup/resend",{body:{email:s,mobileNumber:t}}),o=n.data.data??n.data;return{success:o.success,message:o.message,...o}}async verifyMagicLink(e){const r=this.validateMagicLinkToken(e);await this.request("GET","/verify/magic-link",{params:{token:r,redirect_mode:"frontend"}})}async completeMagicLink(){const e=await this.request("POST","/verify/magic-link/complete",{body:{}}),r=e.data.data??e.data,t=r.AuthenticationResult??r,s=t.access_token??t.accessToken??t.AccessToken,n=t.refresh_token??t.refreshToken??t.RefreshToken,o=t.expires_in??t.expiresIn,l=t.token_type??t.tokenType;return s&&await this.storeTokens({accessToken:s,refreshToken:n,expiresIn:o,tokenType:l}),{access_token:s,refresh_token:n,expires_in:o,token_type:l,verified:t.verified,email:t.email??t.Email,...t}}async initiatePasskeyRegistration(){const e=await this.request("POST","/webauthn/initiate/challenge",{body:{}});return e.data.data??e.data}async registerPasskey(e){const r=this.validateEmail(e),t=await this.initiatePasskeyRegistration();let s;if(t?.user?.id)try{s=P(t.user.id)}catch{s=k(t.user.id)}else s=k(r);const n=(t.pubKeyCredParams??[{type:"public-key",alg:-7},{type:"public-key",alg:-257}]).map(g=>({type:"public-key",alg:g.alg})),o=t.excludeCredentials?.map(g=>({type:"public-key",id:P(g)})),l={challenge:P(t.challenge),rp:{name:t.rp?.name??"XPay",id:t.rp?.id??window.location.hostname},user:{id:s,name:t.user?.name??r,displayName:t.user?.displayName??r},pubKeyCredParams:n,excludeCredentials:o,timeout:t.timeout??6e4,attestation:"direct",authenticatorSelection:{residentKey:"required",userVerification:"required",authenticatorAttachment:"platform"}},c=await navigator.credentials.create({publicKey:l});if(!c)throw new Error("Credential creation failed");const h=c.response,i={clientDataJSON:y(h.clientDataJSON),attestationObject:y(h.attestationObject),rawId:y(c.rawId)};if(!i.rawId)throw new Error("Raw ID is required");const m=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/webauthn/register/challenge`),w=await this.request("POST","/webauthn/register/challenge",{body:i,headers:{DPoP:m}});return w.data.data??w.data}async authenticateWithPasskey({challenge:e,rp:r,credentialIds:t}){const s=await navigator.credentials.get({publicKey:{challenge:P(e),rpId:r?.host??void 0,allowCredentials:t.map(g=>({type:"public-key",id:P(g),transports:["internal"]})),timeout:6e4,userVerification:"required"}});if(!s)throw new Error("Authentication failed");const n=s.response,o={clientDataJSON:y(n.clientDataJSON),authenticatorData:y(n.authenticatorData),signature:y(n.signature),rawId:y(s.rawId),userHandle:n.userHandle?y(n.userHandle):""},l=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/webauthn/authenticate/challenge`),c=await this.request("POST","/webauthn/authenticate/challenge",{body:o,headers:{DPoP:l}}),h=c.data.data??c.data,i=h.AuthenticationResult??h,m=i.AccessToken??i.accessToken??i.access_token,w=i.RefreshToken??i.refreshToken??i.refresh_token;return m&&await this.storeTokens({accessToken:m,refreshToken:w,expiresIn:i.expiresIn??i.ExpiresIn,tokenType:i.tokenType??i.token_type}),{access_token:m,refresh_token:w,email:i.email,name:i.name??i.userName,expiresIn:i.expiresIn??i.ExpiresIn,tokenType:i.tokenType??i.token_type,...i}}async getPasskeyStatus(e){const t=`/webauthn/credentials/${encodeURIComponent(e)}`,s=await this.signRequest("GET",t),n=await this.request("GET",t,{headers:s.headers}),o=n.data.data??n.data;return{...o,hasCredentials:!!(o.hasCredentials??o.credentialId)}}async removePasskey(e){const t=`/webauthn/credentials/${encodeURIComponent(e)}`,s=await this.signRequest("DELETE",t);await this.request("DELETE",t,{headers:s.headers})}async signRequest(e,r,t={}){const s=r.startsWith("http")?r:`${this.getBaseUrl()}${r}`,n=await this.getRequestAuthHeaders(e,s);return{...t,headers:{...t.headers,...n}}}async authenticatedFetch(e,r){const t=typeof e=="string"?e:e instanceof URL?e.toString():e.url,s=r?.method||"GET",n=await this.signRequest(s,t,{headers:r?.headers});return fetch(e,{...r,headers:n.headers})}async storeTokens(e){localStorage.setItem(T,e.accessToken),e.refreshToken&&localStorage.setItem(Y,e.refreshToken)}async clearTokens(){localStorage.removeItem(T),localStorage.removeItem(Y)}async refreshToken(e){const r=this.extractRealm(void 0,e),t=await this.request("POST","/auth/refresh",{body:r?{realm:r}:{}}),s=t.data.data??t.data,n=s.access_token,o=s.token_type,l=s.expires_in;return n&&await this.storeTokens({accessToken:n,expiresIn:l,tokenType:o}),{access_token:n,token_type:o,expires_in:l}}async logout(){try{const r=await this.getAccessToken()?await this.signRequest("POST","/auth/logout",{body:{}}):{body:{}};await this.request("POST","/auth/logout",r),await R(),this.resetDPoPInitialization()}catch{}await this.clearTokens()}async getAccessToken(){return localStorage.getItem(T)}}typeof window<"u"&&(window.AuthSDK=x);const fe=typeof window<"u"?window:globalThis;fe.AuthSDK=x,d.AuthSDK=x,d.AuthSDKFetchError=G,d.SDKValidationError=p,d.arrayBufferToBase64=E,d.arrayBufferToBase64url=y,d.base64ToArrayBuffer=_,d.base64urlToArrayBuffer=P,d.clearPasskeyEmail=q,d.clearPasskeyMobileNumber=M,d.getPasskeyEmail=C,d.getPasskeyMobileNumber=$,d.isConditionalUISupported=O,d.isWebAuthnSupported=b,d.setPasskeyEmail=K,d.setPasskeyMobileNumber=B,d.stringToArrayBuffer=k,d.uint8ArrayToString=N,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})}));
|
|
1
|
+
(function(d,b){typeof exports=="object"&&typeof module<"u"?b(exports):typeof define=="function"&&define.amd?define(["exports"],b):(d=typeof globalThis<"u"?globalThis:d||self,b(d.PostexAuthSDKStage={}))})(this,(function(d){"use strict";function b(){return typeof window<"u"&&typeof window.PublicKeyCredential<"u"&&typeof navigator<"u"&&typeof navigator.credentials<"u"}async function N(){if(!b())return!1;try{return await PublicKeyCredential.isConditionalMediationAvailable?.()??!1}catch{return!1}}function E(a){const e=new Uint8Array(a);let r="";for(let t=0;t<e.byteLength;t++)r+=String.fromCharCode(e[t]);return btoa(r)}function _(a){if(typeof a!="string"||!a)throw new Error("Invalid base64: expected non-empty string");const e=a.replace(/\s/g,"").replace(/-/g,"+").replace(/_/g,"/"),r=e.length%4,t=r>0?e+"=".repeat(4-r):e;try{const s=atob(t),n=new Uint8Array(s.length);for(let o=0;o<s.length;o++)n[o]=s.charCodeAt(o);return n.buffer}catch{throw new Error("Invalid base64: string is not correctly encoded. Check challenge/credentialId from server.")}}function y(a){return E(a).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/g,"")}function X(a){return/^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/i.test(a)}function Z(a){const e=a.replace(/-/g,""),r=new Uint8Array(e.length/2);for(let t=0;t<r.length;t++)r[t]=parseInt(e.substr(t*2,2),16);return r.buffer}function P(a){if(!a||typeof a!="string")throw new Error("Invalid input: expected non-empty string");return X(a)?Z(a):_(a)}function k(a){return new TextEncoder().encode(a).buffer}function O(a){return String.fromCharCode(...a)}const Q="xpay_webauthn",ee=1,u="passkey_data",S="passkey_email",A="passkey_mobile_number";function f(){return new Promise((a,e)=>{const r=indexedDB.open(Q,ee);r.onerror=()=>e(r.error),r.onsuccess=()=>a(r.result),r.onupgradeneeded=()=>{const t=r.result;t.objectStoreNames.contains(u)||t.createObjectStore(u)}})}async function C(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readonly"),n=t.objectStore(u).get(S);n.onerror=()=>r(n.error),n.onsuccess=()=>e(n.result??null),t.oncomplete=()=>a.close()})}catch{return null}}async function K(a){try{const e=await f();return new Promise((r,t)=>{const s=e.transaction(u,"readwrite"),o=s.objectStore(u).put(a,S);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),s.oncomplete=()=>e.close()})}catch{}}async function q(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readwrite"),n=t.objectStore(u).delete(S);n.onerror=()=>r(n.error),n.onsuccess=()=>e(),t.oncomplete=()=>a.close()})}catch{}}async function $(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readonly"),n=t.objectStore(u).get(A);n.onerror=()=>r(n.error),n.onsuccess=()=>e(n.result??null),t.oncomplete=()=>a.close()})}catch{return null}}async function B(a){try{const e=await f();return new Promise((r,t)=>{const s=e.transaction(u,"readwrite"),o=s.objectStore(u).put(a,A);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),s.oncomplete=()=>e.close()})}catch{}}async function U(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readwrite"),n=t.objectStore(u).delete(A);n.onerror=()=>r(n.error),n.onsuccess=()=>e(),t.oncomplete=()=>a.close()})}catch{}}const v="dpop_private_key",I="dpop_public_key_jwk";function M(a){if(!a||typeof a!="object")return!1;const e=a;return e.kty==="EC"&&e.crv==="P-256"&&typeof e.x=="string"&&typeof e.y=="string"}class D extends Error{constructor(e){super(e),this.name="DPoPProofGenerationError"}}function te(a){return{kty:"EC",crv:"P-256",x:a.x,y:a.y}}async function z(a){const e=JSON.stringify({crv:a.crv,kty:a.kty,x:a.x,y:a.y}),r=await crypto.subtle.digest("SHA-256",new TextEncoder().encode(e));return y(r)}async function re(a){try{const e=await f();return new Promise((r,t)=>{const s=e.transaction(u,"readwrite"),o=s.objectStore(u).put(a,v);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),s.oncomplete=()=>e.close()})}catch(e){console.error("Failed to store DPoP private key:",e)}}async function ne(a){try{const e=await f();return new Promise((r,t)=>{const s=e.transaction(u,"readwrite"),o=s.objectStore(u).put(a,I);o.onerror=()=>t(o.error),o.onsuccess=()=>r(),s.oncomplete=()=>e.close()})}catch(e){console.error("Failed to store DPoP public key JWK:",e)}}async function L(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readonly"),n=t.objectStore(u).get(v);n.onerror=()=>r(n.error),n.onsuccess=()=>e(n.result??null),t.oncomplete=()=>a.close()})}catch{return null}}async function j(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readonly"),n=t.objectStore(u).get(I);n.onerror=()=>r(n.error),n.onsuccess=()=>e(n.result??null),t.oncomplete=()=>a.close()})}catch{return null}}async function R(){try{const a=await f();return new Promise((e,r)=>{const t=a.transaction(u,"readwrite"),s=t.objectStore(u);s.delete(v),s.delete(I),t.onerror=()=>r(t.error),t.oncomplete=()=>{a.close(),e()}})}catch{}}async function se(){const a=await crypto.subtle.generateKey({name:"ECDSA",namedCurve:"P-256"},!1,["sign","verify"]),e=await crypto.subtle.exportKey("jwk",a.publicKey),r=te(e),t=await z(r);return await re(a.privateKey),await ne(r),{publicKey:r,thumbprint:t}}async function ae(){const a=await L(),e=await j();return a&&M(e)?{publicKey:e,thumbprint:await z(e)}:((a||e)&&await R(),se())}async function oe(a,e,r){try{const t=await L(),s=await j();if(!t||!M(s))throw new D("DPoP key material is unavailable or invalid");const n={typ:"dpop+jwt",alg:"ES256",jwk:s},o=new URL(e,typeof window<"u"?window.location.origin:void 0),l=`${o.origin}${o.pathname}`,c={jti:crypto.randomUUID(),htm:a.toUpperCase(),htu:l,iat:Math.floor(Date.now()/1e3)};if(r){const be=new TextEncoder().encode(r),Pe=await crypto.subtle.digest("SHA-256",be);c.ath=y(Pe)}const h=y(new TextEncoder().encode(JSON.stringify(n)).buffer),i=y(new TextEncoder().encode(JSON.stringify(c)).buffer),p=`${h}.${i}`,w=await crypto.subtle.sign({name:"ECDSA",hash:{name:"SHA-256"}},t,new TextEncoder().encode(p)),g=y(w);return`${h}.${i}.${g}`}catch(t){throw console.error("Failed to generate DPoP proof:",t),t instanceof D?t:new D("Failed to generate DPoP proof")}}const H={isWebAuthnSupported:b,isConditionalUISupported:N,arrayBufferToBase64:E,base64ToArrayBuffer:_,arrayBufferToBase64url:y,base64urlToArrayBuffer:P,stringToArrayBuffer:k,uint8ArrayToString:O,getPasskeyEmail:C,setPasskeyEmail:K,clearPasskeyEmail:q,getPasskeyMobileNumber:$,setPasskeyMobileNumber:B,clearPasskeyMobileNumber:U};typeof window<"u"&&(window.WebAuthn=H);const ie=typeof window<"u"?window:globalThis;ie.WebAuthn=H;const T="postex-auth-token",ce="postexglobal",le={xstak:"https://auth-stage.xstak.com/public/v1",postex:"https://auth-stage.postex.pk/public/v1",callcourier:"https://auth-stage.callcourier.com.pk/public/v1",postexglobal:"https://auth-stage.postexglobal.com/public/v1",postexsa:"https://auth-stage.postex.sa/public/v1"},ue=/^[^\s@]+@[^\s@]+\.[^\s@]{2,}$/,de=/^\+[1-9]\d{6,14}$/,he=/^\d{6}$/,ye=/^[A-Za-z0-9_-]{16,512}$/,me=/[\u0000-\u001F\u007F-\u009F]/,pe=/[A-Za-z]/,fe=/[\u0400-\u04FF]/,J=254,F=16,W=64,G=64;class Y extends Error{constructor(e,r,t){super(t??`Request failed with status ${e}`),this.response={status:e,data:r},this.name="AuthSDKFetchError"}}class m extends Error{constructor(e,r,t="invalid_input"){super(r),this.field=e,this.code=t,this.name="SDKValidationError"}}const V="auth_sdk_refresh_token";class x{constructor(e){this.config=e,this.dpopInitializationPromise=this.createDPoPInitializationPromise()}getBaseUrl(){const e=this.config.appId??ce;return le[e]}async initializeDPoPState(){await ae()}async ensureDPoPInitialized(){await this.dpopInitializationPromise}createDPoPInitializationPromise(){const e=this.initializeDPoPState();return e.catch(r=>{console.warn("[AuthSDK] DPoP initialization failed:",r)}),e}resetDPoPInitialization(){this.dpopInitializationPromise=this.createDPoPInitializationPromise()}async getRequiredDPoPProof(e,r,t){return await this.ensureDPoPInitialized(),oe(e.toUpperCase(),r,t)}containsControlChars(e){return me.test(e)}hasMixedLatinAndCyrillic(e){return pe.test(e)&&fe.test(e)}assertNoControlChars(e,r){if(this.containsControlChars(r))throw new m(e,`${e} must not contain control characters`)}validateEmail(e,r="email"){const t=e.trim();if(!t)throw new m(r,`${r} is required`);if(t.length>J)throw new m(r,`${r} must be ${J} characters or fewer`);this.assertNoControlChars(r,t);const[s=""]=t.split("@");if(this.hasMixedLatinAndCyrillic(s))throw new m(r,`${r} must not mix Latin and Cyrillic characters in the local part`);if(!ue.test(t))throw new m(r,`${r} must be a valid email`);return t}validateMobileNumber(e,r="mobileNumber"){const t=e.trim();if(!t)throw new m(r,`${r} is required`);if(t.length>F)throw new m(r,`${r} must be ${F} characters or fewer`);if(this.assertNoControlChars(r,t),!de.test(t))throw new m(r,`${r} must be in E.164 format`);return t}validateUsername(e,r="username"){const t=e.trim();if(!t)throw new m(r,`${r} is required`);if(t.length>W)throw new m(r,`${r} must be ${W} characters or fewer`);return this.assertNoControlChars(r,t),t}validateOTP(e,r="otp"){const t=e.trim();if(this.assertNoControlChars(r,t),!he.test(t))throw new m(r,`${r} must be a 6-digit code`);return t}validateMagicLinkToken(e,r="token"){const t=e.trim();if(this.assertNoControlChars(r,t),!ye.test(t))throw new m(r,`${r} must be 16-512 URL-safe characters`);return t}validateRealm(e){const r=e?.trim();if(r){if(this.assertNoControlChars("realm",r),r.length>G)throw new m("realm",`realm must be ${G} characters or fewer`);return r}}normalizeAndValidateIdentifier(e){return typeof e=="string"?{email:this.validateEmail(e)}:{email:e.email?this.validateEmail(e.email):void 0,mobileNumber:e.mobileNumber?this.validateMobileNumber(e.mobileNumber):void 0,username:e.username?this.validateUsername(e.username):void 0}}normalizeAuthIdentifier(e){return this.normalizeAndValidateIdentifier(e)}extractRealm(e,r){const t=r?.realm??(e&&typeof e!="string"?e.realm:void 0);return this.validateRealm(t)}buildAuthRequestBody(e,r){const t=this.normalizeAuthIdentifier(e),s=this.extractRealm(e,r);return{...t,...s?{realm:s}:{}}}buildUrl(e,r){const t=this.getBaseUrl().replace(/\/$/,""),s=e.startsWith("/")?e:`/${e}`,n=`${t}${s}`;if(!r||Object.keys(r).length===0)return n;const o=new URLSearchParams(r).toString();return`${n}?${o}`}async request(e,r,t){const s=this.buildUrl(r,t?.params),n={"Content-Type":"application/json",Accept:"application/json","X-API-Key":this.config.apiKey??"",...t?.headers},o={method:e,credentials:"include",headers:n};t?.body!==void 0&&t?.body!==null&&(o.body=JSON.stringify(t.body));const l=await fetch(s,o);if(!l.ok){let i;try{const p=await l.text();i=p?JSON.parse(p):void 0}catch{i=void 0}throw l.status===401&&(await this.clearTokens(),await R(),this.resetDPoPInitialization()),new Y(l.status,i)}const c=await l.text();return{data:c?JSON.parse(c):{}}}async getRequestAuthHeaders(e,r){const t=localStorage.getItem(T);if(!t)return{};const s=r.startsWith("http")?r:`${this.getBaseUrl()}${r}`,n=await this.getRequiredDPoPProof(e,s,t);return{Authorization:`Bearer ${t}`,DPoP:n}}async getStatus(e,r){const t=this.normalizeAuthIdentifier(e),s=this.extractRealm(e,r),n={};t.email&&(n.email=t.email),t.mobileNumber&&(n.mobileNumber=t.mobileNumber),t.username&&(n.username=t.username),s&&(n.realm=s);const o=await this.request("GET","/auth/status",{params:n});return o.data.data??o.data}async initiateAuth(e,r){const t=this.buildAuthRequestBody(e,r),s=await this.request("POST","/auth/initiate",{body:t}),n=s.data.data??s.data;return{status:n.status,challenge:n.challenge,credentialIds:n.credentialIds,rp:n.rp}}async initiateOTP(e,r){const t=this.normalizeAuthIdentifier(e),s=this.extractRealm(e,r),n=t.email,o=t.mobileNumber,l=t.username;if(!n&&!o&&!l)throw new m("identifier","Either mobileNumber, email, or username is required");const c={};n&&(c.email=n),o&&(c.mobileNumber=o),l&&(c.username=l),s&&(c.realm=s);const i=(await this.request("POST","/otp/initiate",{body:c})).data;return{message:i.message??i.data?.message}}async verifyOTP(e){const r=this.validateOTP(e),t=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/otp/verify`),s=await this.request("POST","/otp/verify",{body:{otp:r},headers:{DPoP:t}}),n=s.data.data??s.data,o=n.AuthenticationResult??n,l=o.access_token??o.accessToken??o.AccessToken,c=o.refresh_token??o.refreshToken??o.RefreshToken,h=o.expires_in??o.expiresIn,i=o.token_type??o.tokenType;return l&&await this.storeTokens({accessToken:l,refreshToken:c,expiresIn:h,tokenType:i}),{access_token:l,refresh_token:c,expires_in:h,token_type:i,verified:o.verified,email:o.email??o.Email,...o}}async resendOTP(){const e=await this.request("POST","/otp/resend",{}),r=e.data.data??e.data;return{success:r.success,message:r.message,...r}}async verifySignupOTP({mobileNumber:e,otp:r}){const t=this.validateMobileNumber(e),s=this.validateOTP(r),n=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/otp/signup/verify`),o=await this.request("POST","/otp/signup/verify",{body:{mobileNumber:t,otp:s},headers:{DPoP:n}}),l=o.data.data??o.data,c=l.AuthenticationResult??l,h=c.access_token??c.accessToken??c.AccessToken,i=c.refresh_token??c.refreshToken??c.RefreshToken,p=c.expires_in??c.expiresIn,w=c.token_type??c.tokenType;return h&&await this.storeTokens({accessToken:h,refreshToken:i,expiresIn:p,tokenType:w}),{access_token:h,refresh_token:i,expires_in:p,token_type:w,verified:c.verified,email:c.email??c.Email,...c}}async resendSignupOTP({mobileNumber:e,email:r=""}){const t=this.validateMobileNumber(e),s=r?this.validateEmail(r):"",n=await this.request("POST","/otp/signup/resend",{body:{email:s,mobileNumber:t}}),o=n.data.data??n.data;return{success:o.success,message:o.message,...o}}async verifyMagicLink(e){const r=this.validateMagicLinkToken(e);await this.request("GET","/verify/magic-link",{params:{token:r,redirect_mode:"frontend"}})}async completeMagicLink(){const e=await this.request("POST","/verify/magic-link/complete",{body:{}}),r=e.data.data??e.data,t=r.AuthenticationResult??r,s=t.access_token??t.accessToken??t.AccessToken,n=t.refresh_token??t.refreshToken??t.RefreshToken,o=t.expires_in??t.expiresIn,l=t.token_type??t.tokenType;return s&&await this.storeTokens({accessToken:s,refreshToken:n,expiresIn:o,tokenType:l}),{access_token:s,refresh_token:n,expires_in:o,token_type:l,verified:t.verified,email:t.email??t.Email,...t}}async initiatePasskeyRegistration(){const e=await this.request("POST","/webauthn/initiate/challenge",{body:{}});return e.data.data??e.data}async registerPasskey(e){const r=this.validateEmail(e),t=await this.initiatePasskeyRegistration();let s;if(t?.user?.id)try{s=P(t.user.id)}catch{s=k(t.user.id)}else s=k(r);const n=(t.pubKeyCredParams??[{type:"public-key",alg:-7},{type:"public-key",alg:-257}]).map(g=>({type:"public-key",alg:g.alg})),o=t.excludeCredentials?.map(g=>({type:"public-key",id:P(g)})),l={challenge:P(t.challenge),rp:{name:t.rp?.name??"XPay",id:t.rp?.id??window.location.hostname},user:{id:s,name:t.user?.name??r,displayName:t.user?.displayName??r},pubKeyCredParams:n,excludeCredentials:o,timeout:t.timeout??6e4,attestation:"direct",authenticatorSelection:{residentKey:"required",userVerification:"required",authenticatorAttachment:"platform"}},c=await navigator.credentials.create({publicKey:l});if(!c)throw new Error("Credential creation failed");const h=c.response,i={clientDataJSON:y(h.clientDataJSON),attestationObject:y(h.attestationObject),rawId:y(c.rawId)};if(!i.rawId)throw new Error("Raw ID is required");const p=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/webauthn/register/challenge`),w=await this.request("POST","/webauthn/register/challenge",{body:i,headers:{DPoP:p}});return w.data.data??w.data}async authenticateWithPasskey({challenge:e,rp:r,credentialIds:t}){const s=await navigator.credentials.get({publicKey:{challenge:P(e),rpId:r?.host??void 0,allowCredentials:t.map(g=>({type:"public-key",id:P(g),transports:["internal"]})),timeout:6e4,userVerification:"required"}});if(!s)throw new Error("Authentication failed");const n=s.response,o={clientDataJSON:y(n.clientDataJSON),authenticatorData:y(n.authenticatorData),signature:y(n.signature),rawId:y(s.rawId),userHandle:n.userHandle?y(n.userHandle):""},l=await this.getRequiredDPoPProof("POST",`${this.getBaseUrl()}/webauthn/authenticate/challenge`),c=await this.request("POST","/webauthn/authenticate/challenge",{body:o,headers:{DPoP:l}}),h=c.data.data??c.data,i=h.AuthenticationResult??h,p=i.AccessToken??i.accessToken??i.access_token,w=i.RefreshToken??i.refreshToken??i.refresh_token;return p&&await this.storeTokens({accessToken:p,refreshToken:w,expiresIn:i.expiresIn??i.ExpiresIn,tokenType:i.tokenType??i.token_type}),{access_token:p,refresh_token:w,email:i.email,name:i.name??i.userName,expiresIn:i.expiresIn??i.ExpiresIn,tokenType:i.tokenType??i.token_type,...i}}async getPasskeyStatus(e){const t=`/webauthn/credentials/${encodeURIComponent(e)}`,s=await this.signRequest("GET",t),n=await this.request("GET",t,{headers:s.headers}),o=n.data.data??n.data;return{...o,hasCredentials:!!(o.hasCredentials??o.credentialId)}}async removePasskey(e){const t=`/webauthn/credentials/${encodeURIComponent(e)}`,s=await this.signRequest("DELETE",t);await this.request("DELETE",t,{headers:s.headers})}async signRequest(e,r,t={}){const s=r.startsWith("http")?r:`${this.getBaseUrl()}${r}`,n=await this.getRequestAuthHeaders(e,s);return{...t,headers:{...t.headers,...n}}}async authenticatedFetch(e,r){const t=typeof e=="string"?e:e instanceof URL?e.toString():e.url,s=r?.method||"GET",n=await this.signRequest(s,t,{headers:r?.headers});return fetch(e,{...r,headers:n.headers})}async storeTokens(e){localStorage.setItem(T,e.accessToken),e.refreshToken&&localStorage.setItem(V,e.refreshToken)}async clearTokens(){localStorage.removeItem(T),localStorage.removeItem(V)}async refreshToken(e){const r=this.extractRealm(void 0,e),t=await this.request("POST","/auth/refresh",{body:r?{realm:r}:{}}),s=t.data.data??t.data,n=s.access_token,o=s.token_type,l=s.expires_in;return n&&await this.storeTokens({accessToken:n,expiresIn:l,tokenType:o}),{access_token:n,token_type:o,expires_in:l}}async logout(){try{const r=await this.getAccessToken()?await this.signRequest("POST","/auth/logout",{body:{}}):{body:{}};await this.request("POST","/auth/logout",r),await R(),this.resetDPoPInitialization()}catch{}await this.clearTokens()}async getAccessToken(){return localStorage.getItem(T)}}typeof window<"u"&&(window.AuthSDK=x);const we=typeof window<"u"?window:globalThis;we.AuthSDK=x,d.AuthSDK=x,d.AuthSDKFetchError=Y,d.SDKValidationError=m,d.arrayBufferToBase64=E,d.arrayBufferToBase64url=y,d.base64ToArrayBuffer=_,d.base64urlToArrayBuffer=P,d.clearPasskeyEmail=q,d.clearPasskeyMobileNumber=U,d.getPasskeyEmail=C,d.getPasskeyMobileNumber=$,d.isConditionalUISupported=N,d.isWebAuthnSupported=b,d.setPasskeyEmail=K,d.setPasskeyMobileNumber=B,d.stringToArrayBuffer=k,d.uint8ArrayToString=O,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})}));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "postex-auth-sdk-stage",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.1",
|
|
4
4
|
"description": "PostEx Auth SDK for authentication flows: OTP, magic links, passkeys, and token management",
|
|
5
5
|
"main": "./dist/postex-auth-sdk-stage.umd.js",
|
|
6
6
|
"module": "./dist/postex-auth-sdk-stage.es.js",
|