@polyguard/sdk 1.1.3 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/sdk.js +200 -199
- package/package.json +2 -2
- package/src/PolyguardWebsocketClientImpl.js +75 -36
- package/src/generated/src/ApiClient.js +0 -16
- package/src/index.js +1 -9
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@polyguard/sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"main": "dist/sdk.js",
|
|
5
5
|
"module": "dist/sdk.js",
|
|
6
6
|
"browser": "dist/sdk.js",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"superagent": "^8.1.2"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"esbuild": "^0.
|
|
23
|
+
"esbuild": "^0.25.0"
|
|
24
24
|
},
|
|
25
25
|
"repository": {
|
|
26
26
|
"type": "git",
|
|
@@ -24,7 +24,7 @@ const LOADING_SPINNER = `<svg xmlns="http://www.w3.org/2000/svg" width="200" hei
|
|
|
24
24
|
export class PolyguardWebsocketClientImpl {
|
|
25
25
|
constructor(params = {}) {
|
|
26
26
|
this.apiClient = new PolyguardApi.ApiClient();
|
|
27
|
-
const { apiKey, baseUrl, appId, apiServer, requiredProofs = ['Full Name'], scanType = 'single', redirectUrl, callbackUrl, cookieName } = params;
|
|
27
|
+
const { apiKey, baseUrl, appId, apiServer, requiredProofs = ['Full Name'], scanType = 'single', redirectUrl, callbackUrl, cookieName, link_uuid } = params;
|
|
28
28
|
if (baseUrl) {
|
|
29
29
|
this.apiClient.basePath = baseUrl;
|
|
30
30
|
}
|
|
@@ -49,6 +49,7 @@ export class PolyguardWebsocketClientImpl {
|
|
|
49
49
|
this.redirectUrl = redirectUrl;
|
|
50
50
|
this.callbackUrl = callbackUrl;
|
|
51
51
|
this.cookieName = cookieName;
|
|
52
|
+
this.link_uuid = link_uuid;
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
buildModal() {
|
|
@@ -83,23 +84,46 @@ export class PolyguardWebsocketClientImpl {
|
|
|
83
84
|
return modal;
|
|
84
85
|
}
|
|
85
86
|
|
|
86
|
-
async verify() {
|
|
87
|
+
async verify(target = null, rawJwt = false) {
|
|
87
88
|
// Only websocket integration is supported for modal
|
|
88
|
-
|
|
89
|
-
|
|
89
|
+
let modal = null;
|
|
90
|
+
let qrDiv = null;
|
|
91
|
+
let isTargetMode = false;
|
|
90
92
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
+
if (target) {
|
|
94
|
+
// Target mode: render QR code in specified element
|
|
95
|
+
isTargetMode = true;
|
|
96
|
+
qrDiv = document.getElementById(target);
|
|
97
|
+
if (!qrDiv) {
|
|
98
|
+
throw new Error(`Target element with ID '${target}' not found`);
|
|
99
|
+
}
|
|
100
|
+
} else {
|
|
101
|
+
// Modal mode: create modal DOM
|
|
102
|
+
modal = this.buildModal();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
if (!isTargetMode) {
|
|
106
|
+
// Show modal immediately with spinner
|
|
107
|
+
document.body.appendChild(modal);
|
|
108
|
+
|
|
109
|
+
// Initialize QR div with spinner
|
|
110
|
+
qrDiv = modal.querySelector('#polyguard-qr');
|
|
111
|
+
}
|
|
93
112
|
|
|
94
|
-
// Initialize QR div with spinner
|
|
95
|
-
const qrDiv = modal.querySelector('#polyguard-qr');
|
|
96
113
|
if (qrDiv) {
|
|
97
114
|
qrDiv.innerHTML = LOADING_SPINNER;
|
|
98
115
|
}
|
|
99
116
|
|
|
100
|
-
// Helper to cleanup modal
|
|
117
|
+
// Helper to cleanup modal or target
|
|
101
118
|
function cleanup() {
|
|
102
|
-
if (
|
|
119
|
+
if (isTargetMode) {
|
|
120
|
+
// Clear target element content
|
|
121
|
+
if (qrDiv) {
|
|
122
|
+
qrDiv.innerHTML = '';
|
|
123
|
+
}
|
|
124
|
+
} else if (modal && modal.parentNode) {
|
|
125
|
+
modal.parentNode.removeChild(modal);
|
|
126
|
+
}
|
|
103
127
|
}
|
|
104
128
|
// Promise for JWT
|
|
105
129
|
return new Promise(async (resolve, reject) => {
|
|
@@ -107,19 +131,28 @@ export class PolyguardWebsocketClientImpl {
|
|
|
107
131
|
let closed = false;
|
|
108
132
|
|
|
109
133
|
function returnError(msg, score = "OFFLINE") {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
errDiv.style.display = 'block';
|
|
114
|
-
}
|
|
115
|
-
setTimeout(() => {
|
|
134
|
+
if (isTargetMode) {
|
|
135
|
+
// In target mode, just log the error and resolve with error data
|
|
136
|
+
console.error('Polyguard Error:', msg);
|
|
116
137
|
cleanup();
|
|
117
138
|
resolve({presence: { score: score, msg: msg }});
|
|
118
|
-
}
|
|
139
|
+
} else {
|
|
140
|
+
const errDiv = modal.querySelector('#polyguard-error');
|
|
141
|
+
if (errDiv) {
|
|
142
|
+
errDiv.textContent = msg;
|
|
143
|
+
errDiv.style.display = 'block';
|
|
144
|
+
}
|
|
145
|
+
setTimeout(() => {
|
|
146
|
+
cleanup();
|
|
147
|
+
resolve({presence: { score: score, msg: msg }});
|
|
148
|
+
}, 1250);
|
|
149
|
+
}
|
|
119
150
|
}
|
|
120
151
|
function clearError() {
|
|
121
|
-
|
|
122
|
-
|
|
152
|
+
if (!isTargetMode) {
|
|
153
|
+
const errDiv = modal.querySelector('#polyguard-error');
|
|
154
|
+
if (errDiv) errDiv.style.display = 'none';
|
|
155
|
+
}
|
|
123
156
|
}
|
|
124
157
|
// Close/cancel handler
|
|
125
158
|
function handleClose() {
|
|
@@ -129,15 +162,20 @@ export class PolyguardWebsocketClientImpl {
|
|
|
129
162
|
reject(new Error('User cancelled'));
|
|
130
163
|
}
|
|
131
164
|
|
|
132
|
-
// Set up close/cancel handlers
|
|
133
|
-
|
|
134
|
-
|
|
165
|
+
// Set up close/cancel handlers (only in modal mode)
|
|
166
|
+
if (!isTargetMode) {
|
|
167
|
+
modal.querySelector('#polyguard-modal-close').onclick = handleClose;
|
|
168
|
+
modal.querySelector('#polyguard-modal-cancel').onclick = handleClose;
|
|
169
|
+
}
|
|
135
170
|
|
|
136
171
|
// Start ticket/ws flow
|
|
137
172
|
try {
|
|
138
173
|
clearError();
|
|
139
174
|
const wsProtocol = window.location.protocol === 'https:' ? 'wss' : 'ws';
|
|
140
|
-
const
|
|
175
|
+
const ticketUrl = this.link_uuid
|
|
176
|
+
? `https://${this.apiServer}/v2/ticket/${this.appId}/${this.link_uuid}`
|
|
177
|
+
: `https://${this.apiServer}/v2/ticket/${this.appId}`;
|
|
178
|
+
const ticketRes = await fetch(ticketUrl, {
|
|
141
179
|
method: 'POST',
|
|
142
180
|
headers: { 'Content-Type': 'application/json' },
|
|
143
181
|
body: JSON.stringify({ requiredProofs: this.requiredProofs, scanType: this.scanType }),
|
|
@@ -182,7 +220,6 @@ export class PolyguardWebsocketClientImpl {
|
|
|
182
220
|
ws.send(JSON.stringify({ type: 'pong', seq: pcre[1] }));
|
|
183
221
|
}
|
|
184
222
|
|
|
185
|
-
const qrDiv = modal.querySelector('#polyguard-qr');
|
|
186
223
|
if (!qrDiv) return;
|
|
187
224
|
|
|
188
225
|
const isMobile = /Mobi|Android/i.test(navigator.userAgent);
|
|
@@ -193,14 +230,16 @@ export class PolyguardWebsocketClientImpl {
|
|
|
193
230
|
qrDiv.style.background = 'transparent';
|
|
194
231
|
qrDiv.querySelector('#polyguard-open-app-button').onclick = () => window.location.assign(data.qr_url);
|
|
195
232
|
|
|
196
|
-
// Update surrounding text
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
instructionText
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
instructionList.children[1]
|
|
233
|
+
// Update surrounding text only in modal mode
|
|
234
|
+
if (!isTargetMode) {
|
|
235
|
+
const instructionText = qrDiv.nextElementSibling;
|
|
236
|
+
if (instructionText) {
|
|
237
|
+
instructionText.textContent = 'Tap the button to verify with the Polyguard app.';
|
|
238
|
+
}
|
|
239
|
+
const instructionList = instructionText.nextElementSibling;
|
|
240
|
+
if (instructionList && instructionList.children[1]) {
|
|
241
|
+
instructionList.children[1].textContent = 'If you do not have the Polyguard app, you will be redirected to download it.';
|
|
242
|
+
}
|
|
204
243
|
}
|
|
205
244
|
} else {
|
|
206
245
|
const startTime = Date.now();
|
|
@@ -215,12 +254,11 @@ export class PolyguardWebsocketClientImpl {
|
|
|
215
254
|
} else if (data && data.jwt) {
|
|
216
255
|
cleanup();
|
|
217
256
|
ws.close();
|
|
218
|
-
resolve(data.jwt);
|
|
257
|
+
resolve(rawJwt ? data : data.jwt);
|
|
219
258
|
return;
|
|
220
259
|
} else if (data && data.status) {
|
|
221
260
|
// ignore
|
|
222
261
|
// generate a spinner in svg and set the qr code to it
|
|
223
|
-
const qrDiv = modal.querySelector('#polyguard-qr');
|
|
224
262
|
if (!qrDiv) return;
|
|
225
263
|
qrDiv.innerHTML = LOADING_SPINNER;
|
|
226
264
|
return;
|
|
@@ -257,11 +295,12 @@ export class PolyguardWebsocketClientImpl {
|
|
|
257
295
|
/**
|
|
258
296
|
* Wrapper around verify that checks received proof values against expected values.
|
|
259
297
|
* @param {Object} expectedProofs - An object mapping proof names to expected values.
|
|
298
|
+
* @param {string} target - Optional ID of target element to render QR code in.
|
|
260
299
|
* @returns {Promise<boolean>} - Resolves to true if all expected proofs match, false otherwise or if cancelled.
|
|
261
300
|
*/
|
|
262
|
-
async require(expectedProofs = {}) {
|
|
301
|
+
async require(expectedProofs = {}, target = null) {
|
|
263
302
|
try {
|
|
264
|
-
const jwt = await this.verify();
|
|
303
|
+
const jwt = await this.verify(target);
|
|
265
304
|
if (!jwt) return false;
|
|
266
305
|
// Decode JWT (without verifying signature)
|
|
267
306
|
const payload = JSON.parse(atob(jwt.split('.')[1]));
|
|
@@ -203,22 +203,6 @@ class ApiClient {
|
|
|
203
203
|
* @returns {Boolean} <code>true</code> if <code>param</code> represents a file.
|
|
204
204
|
*/
|
|
205
205
|
isFileParam(param) {
|
|
206
|
-
// fs.ReadStream in Node.js and Electron (but not in runtime like browserify)
|
|
207
|
-
if (typeof require === 'function') {
|
|
208
|
-
let fs;
|
|
209
|
-
try {
|
|
210
|
-
fs = require('fs');
|
|
211
|
-
} catch (err) {}
|
|
212
|
-
if (fs && fs.ReadStream && param instanceof fs.ReadStream) {
|
|
213
|
-
return true;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// Buffer in Node.js
|
|
218
|
-
if (typeof Buffer === 'function' && param instanceof Buffer) {
|
|
219
|
-
return true;
|
|
220
|
-
}
|
|
221
|
-
|
|
222
206
|
// Blob in browser
|
|
223
207
|
if (typeof Blob === 'function' && param instanceof Blob) {
|
|
224
208
|
return true;
|
package/src/index.js
CHANGED
|
@@ -9,12 +9,4 @@ if (typeof window !== 'undefined') {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
export { PolyguardClient };
|
|
12
|
-
export * from './generated/src/index.js';
|
|
13
|
-
|
|
14
|
-
// Add this for CommonJS compatibility
|
|
15
|
-
if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
|
16
|
-
module.exports = {
|
|
17
|
-
PolyguardClient,
|
|
18
|
-
...PolyguardApi
|
|
19
|
-
};
|
|
20
|
-
}
|
|
12
|
+
export * from './generated/src/index.js';
|