@polyguard/sdk 1.5.0 → 1.5.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/LICENSE +200 -0
- package/README.md +328 -0
- package/package.json +7 -3
- package/coverage/base.css +0 -224
- package/coverage/block-navigation.js +0 -87
- package/coverage/clover.xml +0 -268
- package/coverage/coverage-final.json +0 -8
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +0 -131
- package/coverage/prettify.css +0 -1
- package/coverage/prettify.js +0 -2
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +0 -210
- package/coverage/src/PolyguardClient.js.html +0 -160
- package/coverage/src/PolyguardWebsocketClientImpl.js.html +0 -634
- package/coverage/src/__tests__/helpers/fixtures.js.html +0 -166
- package/coverage/src/__tests__/helpers/index.html +0 -131
- package/coverage/src/__tests__/helpers/mockWebSocket.js.html +0 -283
- package/coverage/src/index.html +0 -176
- package/coverage/src/messageHandler.js.html +0 -448
- package/coverage/src/ticketService.js.html +0 -157
- package/coverage/src/ui.js.html +0 -349
- package/dist/sdk.global.js +0 -11256
- package/scripts/regenerate-client.sh +0 -59
- package/src/PolyguardClient.js +0 -25
- package/src/PolyguardWebsocketClientImpl.js +0 -198
- package/src/__tests__/PolyguardClient.test.js +0 -65
- package/src/__tests__/PolyguardWebsocketClientImpl.test.js +0 -617
- package/src/__tests__/helpers/fixtures.js +0 -27
- package/src/__tests__/helpers/mockWebSocket.js +0 -66
- package/src/__tests__/server.test.js +0 -148
- package/src/__tests__/sidebar.test.js +0 -289
- package/src/browser.js +0 -9
- package/src/generated/.babelrc +0 -33
- package/src/generated/.openapi-generator/FILES +0 -63
- package/src/generated/.openapi-generator/VERSION +0 -1
- package/src/generated/.openapi-generator-ignore +0 -23
- package/src/generated/.travis.yml +0 -5
- package/src/generated/README.md +0 -211
- package/src/generated/docs/ApiControllersPslStirCallRequest.md +0 -18
- package/src/generated/docs/ApiModelsApiCallModelsCallRequest.md +0 -12
- package/src/generated/docs/AppId.md +0 -8
- package/src/generated/docs/AppleApi.md +0 -88
- package/src/generated/docs/AuthApi.md +0 -1464
- package/src/generated/docs/BlockingApi.md +0 -208
- package/src/generated/docs/CallsApi.md +0 -140
- package/src/generated/docs/Certainty.md +0 -8
- package/src/generated/docs/CreateLinkRequest.md +0 -12
- package/src/generated/docs/DefaultApi.md +0 -128
- package/src/generated/docs/HTTPValidationError.md +0 -9
- package/src/generated/docs/InviteRequestModel.md +0 -10
- package/src/generated/docs/JWTRequest.md +0 -11
- package/src/generated/docs/LinksApi.md +0 -162
- package/src/generated/docs/NumberVerification.md +0 -10
- package/src/generated/docs/SdkApi.md +0 -54
- package/src/generated/docs/SecureLinksApi.md +0 -614
- package/src/generated/docs/StartAttestationRequest.md +0 -9
- package/src/generated/docs/StartMeetingRequest.md +0 -9
- package/src/generated/docs/StirApi.md +0 -52
- package/src/generated/docs/TwilioApi.md +0 -138
- package/src/generated/docs/UsersApi.md +0 -362
- package/src/generated/docs/ValidationError.md +0 -11
- package/src/generated/docs/ValidationErrorLocInner.md +0 -8
- package/src/generated/docs/VeriffApi.md +0 -188
- package/src/generated/docs/VeriffSessionRequest.md +0 -10
- package/src/generated/docs/VerifyRequest.md +0 -10
- package/src/generated/docs/WellKnownApi.md +0 -128
- package/src/generated/docs/ZoomApi.md +0 -848
- package/src/generated/git_push.sh +0 -57
- package/src/generated/mocha.opts +0 -1
- package/src/generated/package.json +0 -46
- package/src/generated/src/ApiClient.js +0 -677
- package/src/generated/src/api/AppleApi.js +0 -109
- package/src/generated/src/api/AuthApi.js +0 -1512
- package/src/generated/src/api/BlockingApi.js +0 -217
- package/src/generated/src/api/CallsApi.js +0 -164
- package/src/generated/src/api/DefaultApi.js +0 -145
- package/src/generated/src/api/LinksApi.js +0 -195
- package/src/generated/src/api/SdkApi.js +0 -81
- package/src/generated/src/api/SecureLinksApi.js +0 -670
- package/src/generated/src/api/StirApi.js +0 -80
- package/src/generated/src/api/TwilioApi.js +0 -158
- package/src/generated/src/api/UsersApi.js +0 -375
- package/src/generated/src/api/VeriffApi.js +0 -209
- package/src/generated/src/api/WellKnownApi.js +0 -145
- package/src/generated/src/api/ZoomApi.js +0 -823
- package/src/generated/src/index.js +0 -244
- package/src/generated/src/model/ApiControllersPslStirCallRequest.js +0 -211
- package/src/generated/src/model/ApiModelsApiCallModelsCallRequest.js +0 -119
- package/src/generated/src/model/CreateLinkRequest.js +0 -131
- package/src/generated/src/model/HTTPValidationError.js +0 -94
- package/src/generated/src/model/InviteRequestModel.js +0 -109
- package/src/generated/src/model/JWTRequest.js +0 -113
- package/src/generated/src/model/NumberVerification.js +0 -107
- package/src/generated/src/model/StartAttestationRequest.js +0 -95
- package/src/generated/src/model/StartMeetingRequest.js +0 -95
- package/src/generated/src/model/ValidationError.js +0 -130
- package/src/generated/src/model/VeriffSessionRequest.js +0 -107
- package/src/generated/src/model/VerifyRequest.js +0 -109
- package/src/generated/test/api/AppleApi.spec.js +0 -73
- package/src/generated/test/api/AuthApi.spec.js +0 -353
- package/src/generated/test/api/BlockingApi.spec.js +0 -103
- package/src/generated/test/api/CallsApi.spec.js +0 -83
- package/src/generated/test/api/DefaultApi.spec.js +0 -73
- package/src/generated/test/api/LinksApi.spec.js +0 -83
- package/src/generated/test/api/SdkApi.spec.js +0 -63
- package/src/generated/test/api/SecureLinksApi.spec.js +0 -143
- package/src/generated/test/api/StirApi.spec.js +0 -63
- package/src/generated/test/api/TwilioApi.spec.js +0 -83
- package/src/generated/test/api/UsersApi.spec.js +0 -133
- package/src/generated/test/api/VeriffApi.spec.js +0 -93
- package/src/generated/test/api/WellKnownApi.spec.js +0 -83
- package/src/generated/test/api/ZoomApi.spec.js +0 -213
- package/src/generated/test/model/ApiControllersPslStirCallRequest.spec.js +0 -119
- package/src/generated/test/model/ApiModelsApiCallModelsCallRequest.spec.js +0 -83
- package/src/generated/test/model/AppId.spec.js +0 -59
- package/src/generated/test/model/Certainty.spec.js +0 -59
- package/src/generated/test/model/CreateLinkRequest.spec.js +0 -83
- package/src/generated/test/model/HTTPValidationError.spec.js +0 -65
- package/src/generated/test/model/InviteRequestModel.spec.js +0 -71
- package/src/generated/test/model/JWTRequest.spec.js +0 -77
- package/src/generated/test/model/NumberVerification.spec.js +0 -71
- package/src/generated/test/model/StartAttestationRequest.spec.js +0 -65
- package/src/generated/test/model/StartMeetingRequest.spec.js +0 -65
- package/src/generated/test/model/ValidationError.spec.js +0 -77
- package/src/generated/test/model/ValidationErrorLocInner.spec.js +0 -59
- package/src/generated/test/model/VeriffSessionRequest.spec.js +0 -71
- package/src/generated/test/model/VerifyRequest.spec.js +0 -71
- package/src/index.js +0 -16
- package/src/messageHandler.js +0 -121
- package/src/server.js +0 -91
- package/src/ticketService.js +0 -28
- package/src/ui.js +0 -88
- package/vitest.config.js +0 -10
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mock for reconnecting-websocket.
|
|
3
|
-
* Captures the URL/protocols/options passed to the constructor and
|
|
4
|
-
* exposes helpers to drive the message handler under test.
|
|
5
|
-
*/
|
|
6
|
-
export class MockReconnectingWebSocket {
|
|
7
|
-
static instances = [];
|
|
8
|
-
|
|
9
|
-
constructor(url, protocols, options) {
|
|
10
|
-
this.url = url;
|
|
11
|
-
this.protocols = protocols;
|
|
12
|
-
this.options = options;
|
|
13
|
-
this._listeners = {};
|
|
14
|
-
this.readyState = 1; // OPEN
|
|
15
|
-
this.sent = [];
|
|
16
|
-
MockReconnectingWebSocket.instances.push(this);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
addEventListener(type, handler) {
|
|
20
|
-
if (!this._listeners[type]) this._listeners[type] = [];
|
|
21
|
-
this._listeners[type].push(handler);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
removeEventListener(type, handler) {
|
|
25
|
-
if (!this._listeners[type]) return;
|
|
26
|
-
this._listeners[type] = this._listeners[type].filter(h => h !== handler);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
send(data) {
|
|
30
|
-
this.sent.push(data);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
close() {
|
|
34
|
-
this.readyState = 3; // CLOSED
|
|
35
|
-
this._emit('close', {});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// --- Test helpers ---
|
|
39
|
-
|
|
40
|
-
simulateMessage(data) {
|
|
41
|
-
this._emit('message', { data: JSON.stringify(data) });
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
simulateError() {
|
|
45
|
-
this._emit('error', {});
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
simulateClose() {
|
|
49
|
-
this._emit('close', {});
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
_emit(type, event) {
|
|
53
|
-
const handlers = this._listeners[type] || [];
|
|
54
|
-
for (const h of handlers) {
|
|
55
|
-
h(event);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
static reset() {
|
|
60
|
-
MockReconnectingWebSocket.instances = [];
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
static latest() {
|
|
64
|
-
return MockReconnectingWebSocket.instances[MockReconnectingWebSocket.instances.length - 1];
|
|
65
|
-
}
|
|
66
|
-
}
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
-
import { createProxyHandler } from '../server.js';
|
|
3
|
-
|
|
4
|
-
function makeRequest(method, url, { headers = {}, body = null } = {}) {
|
|
5
|
-
const init = { method, headers };
|
|
6
|
-
if (body !== null) init.body = typeof body === 'string' ? body : JSON.stringify(body);
|
|
7
|
-
return new Request(url, init);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
function stubFetch(responseOpts = {}) {
|
|
11
|
-
const { status = 200, body = '{"ok":true}', headers = { 'content-type': 'application/json' } } = responseOpts;
|
|
12
|
-
const mock = vi.fn().mockImplementation(async () => new Response(body, { status, headers }));
|
|
13
|
-
vi.stubGlobal('fetch', mock);
|
|
14
|
-
return mock;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
describe('createProxyHandler', () => {
|
|
18
|
-
beforeEach(() => {
|
|
19
|
-
vi.restoreAllMocks();
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
it('throws when apiKey is missing', () => {
|
|
23
|
-
expect(() => createProxyHandler({ apiServer: 'api.polyguard.ai' })).toThrow(/apiKey is required/);
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
it('throws when apiServer is falsy', () => {
|
|
27
|
-
expect(() => createProxyHandler({ apiKey: 'pgk_live_x.y', apiServer: '' })).toThrow(/apiServer is required/);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
it('returns 404 for paths not in the allowlist', async () => {
|
|
31
|
-
stubFetch();
|
|
32
|
-
const handler = createProxyHandler({ apiKey: 'pgk_live_x.y', apiServer: 'api.polyguard.ai' });
|
|
33
|
-
const req = makeRequest('GET', 'http://localhost/api/polyguard/account/1/apps/3/api-keys');
|
|
34
|
-
const res = await handler(req);
|
|
35
|
-
expect(res.status).toBe(404);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it('returns 404 for an allowlisted prefix used with the wrong HTTP method', async () => {
|
|
39
|
-
stubFetch();
|
|
40
|
-
const handler = createProxyHandler({ apiKey: 'pgk_live_x.y', apiServer: 'api.polyguard.ai' });
|
|
41
|
-
const req = makeRequest('GET', 'http://localhost/api/polyguard/v2/ticket/3');
|
|
42
|
-
const res = await handler(req);
|
|
43
|
-
expect(res.status).toBe(404);
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
it('forwards POST /v2/ticket/* with x-pg-api-key injected', async () => {
|
|
47
|
-
const fetchMock = stubFetch();
|
|
48
|
-
const handler = createProxyHandler({ apiKey: 'pgk_live_x.y', apiServer: 'api.polyguard.ai' });
|
|
49
|
-
const req = makeRequest('POST', 'http://localhost/api/polyguard/v2/ticket/3', {
|
|
50
|
-
headers: { 'content-type': 'application/json' },
|
|
51
|
-
body: { requiredProofs: ['name'], scanType: 'single' },
|
|
52
|
-
});
|
|
53
|
-
const res = await handler(req);
|
|
54
|
-
expect(res.status).toBe(200);
|
|
55
|
-
expect(fetchMock).toHaveBeenCalledOnce();
|
|
56
|
-
const [forwardedUrl, init] = fetchMock.mock.calls[0];
|
|
57
|
-
expect(forwardedUrl).toBe('https://api.polyguard.ai/v2/ticket/3');
|
|
58
|
-
expect(init.method).toBe('POST');
|
|
59
|
-
const headers = new Headers(init.headers);
|
|
60
|
-
expect(headers.get('x-pg-api-key')).toBe('pgk_live_x.y');
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
it('strips client-supplied x-pg-api-key before injecting', async () => {
|
|
64
|
-
const fetchMock = stubFetch();
|
|
65
|
-
const handler = createProxyHandler({ apiKey: 'pgk_live_real.secret', apiServer: 'api.polyguard.ai' });
|
|
66
|
-
const req = makeRequest('POST', 'http://localhost/api/polyguard/v2/ticket/3', {
|
|
67
|
-
headers: { 'x-pg-api-key': 'pgk_live_attacker.smuggled', 'content-type': 'application/json' },
|
|
68
|
-
body: {},
|
|
69
|
-
});
|
|
70
|
-
await handler(req);
|
|
71
|
-
const init = fetchMock.mock.calls[0][1];
|
|
72
|
-
const headers = new Headers(init.headers);
|
|
73
|
-
expect(headers.get('x-pg-api-key')).toBe('pgk_live_real.secret');
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
it('strips client-supplied authorization header', async () => {
|
|
77
|
-
const fetchMock = stubFetch();
|
|
78
|
-
const handler = createProxyHandler({ apiKey: 'pgk_live_x.y', apiServer: 'api.polyguard.ai' });
|
|
79
|
-
const req = makeRequest('POST', 'http://localhost/api/polyguard/v2/ticket/3', {
|
|
80
|
-
headers: { authorization: 'Bearer pgk_live_attacker.smuggled', 'content-type': 'application/json' },
|
|
81
|
-
body: {},
|
|
82
|
-
});
|
|
83
|
-
await handler(req);
|
|
84
|
-
const init = fetchMock.mock.calls[0][1];
|
|
85
|
-
const headers = new Headers(init.headers);
|
|
86
|
-
expect(headers.get('authorization')).toBeNull();
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
it('preserves query string when forwarding', async () => {
|
|
90
|
-
const fetchMock = stubFetch();
|
|
91
|
-
const handler = createProxyHandler({ apiKey: 'pgk_live_x.y', apiServer: 'api.polyguard.ai' });
|
|
92
|
-
const req = makeRequest('GET', 'http://localhost/api/polyguard/v2/preview/3/link-abc?format=svg');
|
|
93
|
-
await handler(req);
|
|
94
|
-
expect(fetchMock.mock.calls[0][0]).toBe('https://api.polyguard.ai/v2/preview/3/link-abc?format=svg');
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it('forwards PUT /link/* (link creation)', async () => {
|
|
98
|
-
const fetchMock = stubFetch();
|
|
99
|
-
const handler = createProxyHandler({ apiKey: 'pgk_live_x.y', apiServer: 'api.polyguard.ai' });
|
|
100
|
-
const req = makeRequest('PUT', 'http://localhost/api/polyguard/link/3', {
|
|
101
|
-
headers: { 'content-type': 'application/json' },
|
|
102
|
-
body: { type: 'login' },
|
|
103
|
-
});
|
|
104
|
-
const res = await handler(req);
|
|
105
|
-
expect(res.status).toBe(200);
|
|
106
|
-
expect(fetchMock.mock.calls[0][0]).toBe('https://api.polyguard.ai/link/3');
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it('honors a custom allowedPaths list', async () => {
|
|
110
|
-
stubFetch();
|
|
111
|
-
const handler = createProxyHandler({
|
|
112
|
-
apiKey: 'pgk_live_x.y',
|
|
113
|
-
apiServer: 'api.polyguard.ai',
|
|
114
|
-
allowedPaths: ['POST /v2/ticket/'],
|
|
115
|
-
});
|
|
116
|
-
const denied = await handler(makeRequest('PUT', 'http://localhost/api/polyguard/link/3'));
|
|
117
|
-
expect(denied.status).toBe(404);
|
|
118
|
-
const allowed = await handler(makeRequest('POST', 'http://localhost/api/polyguard/v2/ticket/3', { body: {} }));
|
|
119
|
-
expect(allowed.status).toBe(200);
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
it('honors a custom pathPrefix', async () => {
|
|
123
|
-
const fetchMock = stubFetch();
|
|
124
|
-
const handler = createProxyHandler({
|
|
125
|
-
apiKey: 'pgk_live_x.y',
|
|
126
|
-
apiServer: 'api.polyguard.ai',
|
|
127
|
-
pathPrefix: '/custom/proxy',
|
|
128
|
-
});
|
|
129
|
-
await handler(makeRequest('POST', 'http://localhost/custom/proxy/v2/ticket/3', { body: {} }));
|
|
130
|
-
expect(fetchMock.mock.calls[0][0]).toBe('https://api.polyguard.ai/v2/ticket/3');
|
|
131
|
-
});
|
|
132
|
-
|
|
133
|
-
it('strips hop-by-hop response headers and set-cookie', async () => {
|
|
134
|
-
stubFetch({
|
|
135
|
-
headers: {
|
|
136
|
-
'content-type': 'application/json',
|
|
137
|
-
'set-cookie': 'session=abc; path=/',
|
|
138
|
-
'transfer-encoding': 'chunked',
|
|
139
|
-
'x-custom': 'visible',
|
|
140
|
-
},
|
|
141
|
-
});
|
|
142
|
-
const handler = createProxyHandler({ apiKey: 'pgk_live_x.y', apiServer: 'api.polyguard.ai' });
|
|
143
|
-
const res = await handler(makeRequest('POST', 'http://localhost/api/polyguard/v2/ticket/3', { body: {} }));
|
|
144
|
-
expect(res.headers.get('set-cookie')).toBeNull();
|
|
145
|
-
expect(res.headers.get('transfer-encoding')).toBeNull();
|
|
146
|
-
expect(res.headers.get('x-custom')).toBe('visible');
|
|
147
|
-
});
|
|
148
|
-
});
|
|
@@ -1,289 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
-
import { buildFakeJwt, DEFAULT_PARAMS, mockTicketResponse } from './helpers/fixtures.js';
|
|
3
|
-
import { MockReconnectingWebSocket } from './helpers/mockWebSocket.js';
|
|
4
|
-
|
|
5
|
-
// ---- Module mocks ----
|
|
6
|
-
|
|
7
|
-
const { MockApiClient, generatedMock, mockQRCode } = vi.hoisted(() => {
|
|
8
|
-
class MockApiClient {
|
|
9
|
-
constructor() {
|
|
10
|
-
this.basePath = '';
|
|
11
|
-
this.authentications = { bearerAuth: { apiKey: null } };
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const generatedMock = { ApiClient: MockApiClient };
|
|
16
|
-
const apiClassNames = [
|
|
17
|
-
'BlockingApi', 'CallsApi', 'DefaultApi', 'LinksApi', 'SdkApi',
|
|
18
|
-
'SecureLinksApi', 'StirApi', 'TwilioApi', 'UsersApi', 'VeriffApi',
|
|
19
|
-
'WellKnownApi', 'ZoomApi',
|
|
20
|
-
];
|
|
21
|
-
for (const name of apiClassNames) {
|
|
22
|
-
generatedMock[name] = class {
|
|
23
|
-
constructor(apiClient) { this._apiClient = apiClient; }
|
|
24
|
-
};
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const mockQRCode = {
|
|
28
|
-
toString: null,
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
return { MockApiClient, generatedMock, mockQRCode };
|
|
32
|
-
});
|
|
33
|
-
|
|
34
|
-
vi.mock('../generated/src', () => generatedMock);
|
|
35
|
-
|
|
36
|
-
vi.mock('reconnecting-websocket', async () => {
|
|
37
|
-
const { MockReconnectingWebSocket } = await import('./helpers/mockWebSocket.js');
|
|
38
|
-
return { default: MockReconnectingWebSocket };
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
vi.mock('qrcode', () => ({
|
|
42
|
-
default: mockQRCode,
|
|
43
|
-
}));
|
|
44
|
-
|
|
45
|
-
const { PolyguardWebsocketClientImpl } = await import('../PolyguardWebsocketClientImpl.js');
|
|
46
|
-
|
|
47
|
-
// ---- Helpers ----
|
|
48
|
-
|
|
49
|
-
async function flushMicrotasks() {
|
|
50
|
-
await new Promise(resolve => setTimeout(resolve, 0));
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function stubFetch(ticket = 'test-ticket-123', ok = true) {
|
|
54
|
-
const mock = vi.fn().mockResolvedValue(mockTicketResponse(ticket, ok));
|
|
55
|
-
vi.stubGlobal('fetch', mock);
|
|
56
|
-
return mock;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
function setProtocol(protocol) {
|
|
60
|
-
Object.defineProperty(window, 'location', {
|
|
61
|
-
value: { protocol, assign: vi.fn(), href: '' },
|
|
62
|
-
writable: true,
|
|
63
|
-
configurable: true,
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function setUserAgent(ua) {
|
|
68
|
-
Object.defineProperty(navigator, 'userAgent', {
|
|
69
|
-
value: ua,
|
|
70
|
-
writable: true,
|
|
71
|
-
configurable: true,
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async function startVerifyAndGetWs(client, target = null, rawJwt = false) {
|
|
76
|
-
const promise = client.verify(target, rawJwt);
|
|
77
|
-
await flushMicrotasks();
|
|
78
|
-
const ws = MockReconnectingWebSocket.latest();
|
|
79
|
-
return { promise, ws };
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function setCookie(name, value) {
|
|
83
|
-
Object.defineProperty(document, 'cookie', {
|
|
84
|
-
value: `${name}=${value}; other=stuff`,
|
|
85
|
-
writable: true,
|
|
86
|
-
configurable: true,
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
function clearCookies() {
|
|
91
|
-
Object.defineProperty(document, 'cookie', {
|
|
92
|
-
value: '',
|
|
93
|
-
writable: true,
|
|
94
|
-
configurable: true,
|
|
95
|
-
});
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
// ---- Tests ----
|
|
99
|
-
|
|
100
|
-
describe('sidebarUrl feature', () => {
|
|
101
|
-
beforeEach(() => {
|
|
102
|
-
vi.clearAllMocks();
|
|
103
|
-
MockReconnectingWebSocket.reset();
|
|
104
|
-
setProtocol('https:');
|
|
105
|
-
setUserAgent('Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)');
|
|
106
|
-
stubFetch();
|
|
107
|
-
mockQRCode.toString = vi.fn((data, opts, cb) => cb(null, '<svg>mock-qr</svg>'));
|
|
108
|
-
clearCookies();
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
afterEach(() => {
|
|
112
|
-
vi.restoreAllMocks();
|
|
113
|
-
document.body.innerHTML = '';
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
describe('constructor', () => {
|
|
117
|
-
it('stores sidebarUrl when provided', () => {
|
|
118
|
-
const client = new PolyguardWebsocketClientImpl({
|
|
119
|
-
...DEFAULT_PARAMS,
|
|
120
|
-
sidebarUrl: 'https://teams.polyguard.ai/ms-teams/sidebar-standalone',
|
|
121
|
-
});
|
|
122
|
-
expect(client.sidebarUrl).toBe('https://teams.polyguard.ai/ms-teams/sidebar-standalone');
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
it('sidebarUrl is undefined when not provided', () => {
|
|
126
|
-
const client = new PolyguardWebsocketClientImpl(DEFAULT_PARAMS);
|
|
127
|
-
expect(client.sidebarUrl).toBeUndefined();
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
describe('without sidebarUrl - existing behavior unchanged', () => {
|
|
132
|
-
it('jwt with redirect_url resolves normally', async () => {
|
|
133
|
-
const client = new PolyguardWebsocketClientImpl(DEFAULT_PARAMS);
|
|
134
|
-
const fakeJwt = buildFakeJwt({ redirect_url: 'https://teams.microsoft.com/meet/123' });
|
|
135
|
-
const { promise, ws } = await startVerifyAndGetWs(client);
|
|
136
|
-
ws.simulateMessage({ jwt: fakeJwt });
|
|
137
|
-
const result = await promise;
|
|
138
|
-
expect(result).toBe(fakeJwt);
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
it('does not call window.open', async () => {
|
|
142
|
-
const openSpy = vi.fn();
|
|
143
|
-
vi.stubGlobal('open', openSpy);
|
|
144
|
-
const client = new PolyguardWebsocketClientImpl(DEFAULT_PARAMS);
|
|
145
|
-
const fakeJwt = buildFakeJwt({ redirect_url: 'https://teams.microsoft.com/meet/123' });
|
|
146
|
-
const { promise, ws } = await startVerifyAndGetWs(client);
|
|
147
|
-
ws.simulateMessage({ jwt: fakeJwt });
|
|
148
|
-
await promise;
|
|
149
|
-
expect(openSpy).not.toHaveBeenCalled();
|
|
150
|
-
});
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
describe('with sidebarUrl and pg_msft_session cookie (authenticated user)', () => {
|
|
154
|
-
it('auto-redirects without showing a button', async () => {
|
|
155
|
-
setCookie('pg_msft_session', '1');
|
|
156
|
-
const client = new PolyguardWebsocketClientImpl({
|
|
157
|
-
...DEFAULT_PARAMS,
|
|
158
|
-
sidebarUrl: 'https://teams.polyguard.ai/ms-teams/sidebar-standalone',
|
|
159
|
-
link_uuid: 'link-abc',
|
|
160
|
-
});
|
|
161
|
-
document.body.innerHTML = '<div id="test-target"></div>';
|
|
162
|
-
const jwtClaims = { redirect_url: 'https://teams.microsoft.com/meet/123' };
|
|
163
|
-
const { promise, ws } = await startVerifyAndGetWs(client, 'test-target');
|
|
164
|
-
ws.simulateMessage({ jwt: jwtClaims });
|
|
165
|
-
await promise;
|
|
166
|
-
expect(window.location.assign).toHaveBeenCalledWith('https://teams.microsoft.com/meet/123');
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
it('does not render a join button', async () => {
|
|
170
|
-
setCookie('pg_msft_session', '1');
|
|
171
|
-
const client = new PolyguardWebsocketClientImpl({
|
|
172
|
-
...DEFAULT_PARAMS,
|
|
173
|
-
sidebarUrl: 'https://teams.polyguard.ai/ms-teams/sidebar-standalone',
|
|
174
|
-
link_uuid: 'link-abc',
|
|
175
|
-
});
|
|
176
|
-
document.body.innerHTML = '<div id="test-target"></div>';
|
|
177
|
-
const jwtClaims = { redirect_url: 'https://teams.microsoft.com/meet/123' };
|
|
178
|
-
const { promise, ws } = await startVerifyAndGetWs(client, 'test-target');
|
|
179
|
-
ws.simulateMessage({ jwt: jwtClaims });
|
|
180
|
-
await promise;
|
|
181
|
-
expect(document.querySelector('#polyguard-join-meeting')).toBeNull();
|
|
182
|
-
});
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
describe('with sidebarUrl and NO cookie (anonymous user)', () => {
|
|
186
|
-
it('renders a join button instead of auto-redirecting', async () => {
|
|
187
|
-
clearCookies();
|
|
188
|
-
const client = new PolyguardWebsocketClientImpl({
|
|
189
|
-
...DEFAULT_PARAMS,
|
|
190
|
-
sidebarUrl: 'https://teams.polyguard.ai/ms-teams/sidebar-standalone',
|
|
191
|
-
link_uuid: 'link-abc',
|
|
192
|
-
});
|
|
193
|
-
document.body.innerHTML = '<div id="test-target"></div>';
|
|
194
|
-
const jwtClaims = { redirect_url: 'https://teams.microsoft.com/meet/123' };
|
|
195
|
-
const { promise, ws } = await startVerifyAndGetWs(client, 'test-target');
|
|
196
|
-
ws.simulateMessage({ jwt: jwtClaims });
|
|
197
|
-
// Should not have redirected yet
|
|
198
|
-
expect(window.location.assign).not.toHaveBeenCalled();
|
|
199
|
-
// Should show join button
|
|
200
|
-
const btn = document.querySelector('#polyguard-join-meeting');
|
|
201
|
-
expect(btn).not.toBeNull();
|
|
202
|
-
// Resolve by clicking the button
|
|
203
|
-
btn.click();
|
|
204
|
-
await promise;
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
it('clicking join button opens sidebar popup', async () => {
|
|
208
|
-
clearCookies();
|
|
209
|
-
const openSpy = vi.fn().mockReturnValue({});
|
|
210
|
-
vi.stubGlobal('open', openSpy);
|
|
211
|
-
const client = new PolyguardWebsocketClientImpl({
|
|
212
|
-
...DEFAULT_PARAMS,
|
|
213
|
-
sidebarUrl: 'https://teams.polyguard.ai/ms-teams/sidebar-standalone',
|
|
214
|
-
link_uuid: 'link-abc',
|
|
215
|
-
});
|
|
216
|
-
document.body.innerHTML = '<div id="test-target"></div>';
|
|
217
|
-
const jwtClaims = { redirect_url: 'https://teams.microsoft.com/meet/123' };
|
|
218
|
-
const { promise, ws } = await startVerifyAndGetWs(client, 'test-target');
|
|
219
|
-
ws.simulateMessage({ jwt: jwtClaims });
|
|
220
|
-
const btn = document.querySelector('#polyguard-join-meeting');
|
|
221
|
-
btn.click();
|
|
222
|
-
await promise;
|
|
223
|
-
expect(openSpy).toHaveBeenCalledWith(
|
|
224
|
-
'https://teams.polyguard.ai/ms-teams/sidebar-standalone?linkUuid=link-abc',
|
|
225
|
-
'polyguard-sidebar',
|
|
226
|
-
expect.stringContaining('width=320')
|
|
227
|
-
);
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
it('clicking join button redirects to meeting', async () => {
|
|
231
|
-
clearCookies();
|
|
232
|
-
vi.stubGlobal('open', vi.fn().mockReturnValue({}));
|
|
233
|
-
const client = new PolyguardWebsocketClientImpl({
|
|
234
|
-
...DEFAULT_PARAMS,
|
|
235
|
-
sidebarUrl: 'https://teams.polyguard.ai/ms-teams/sidebar-standalone',
|
|
236
|
-
link_uuid: 'link-abc',
|
|
237
|
-
});
|
|
238
|
-
document.body.innerHTML = '<div id="test-target"></div>';
|
|
239
|
-
const jwtClaims = { redirect_url: 'https://teams.microsoft.com/meet/123' };
|
|
240
|
-
const { promise, ws } = await startVerifyAndGetWs(client, 'test-target');
|
|
241
|
-
ws.simulateMessage({ jwt: jwtClaims });
|
|
242
|
-
document.querySelector('#polyguard-join-meeting').click();
|
|
243
|
-
await promise;
|
|
244
|
-
expect(window.location.assign).toHaveBeenCalledWith('https://teams.microsoft.com/meet/123');
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
it('button survives a late WebSocket close event (race regression)', async () => {
|
|
248
|
-
// Real browsers dispatch the 'close' event asynchronously after ws.close(),
|
|
249
|
-
// so it lands after the synchronous button append. If the close listener's
|
|
250
|
-
// cleanup() runs in that window, it wipes the qrDiv — and the button with it.
|
|
251
|
-
// markClosed() in the message handler must defuse the close listener.
|
|
252
|
-
clearCookies();
|
|
253
|
-
vi.stubGlobal('open', vi.fn().mockReturnValue({}));
|
|
254
|
-
const client = new PolyguardWebsocketClientImpl({
|
|
255
|
-
...DEFAULT_PARAMS,
|
|
256
|
-
sidebarUrl: 'https://teams.polyguard.ai/ms-teams/sidebar-standalone',
|
|
257
|
-
link_uuid: 'link-abc',
|
|
258
|
-
});
|
|
259
|
-
document.body.innerHTML = '<div id="test-target"></div>';
|
|
260
|
-
const jwtClaims = { redirect_url: 'https://teams.microsoft.com/meet/123' };
|
|
261
|
-
const { promise, ws } = await startVerifyAndGetWs(client, 'test-target');
|
|
262
|
-
ws.simulateMessage({ jwt: jwtClaims });
|
|
263
|
-
expect(document.querySelector('#polyguard-join-meeting')).not.toBeNull();
|
|
264
|
-
// Mimic a real browser dispatching close on the next tick (after the message handler returned).
|
|
265
|
-
ws.simulateClose();
|
|
266
|
-
expect(document.querySelector('#polyguard-join-meeting')).not.toBeNull();
|
|
267
|
-
document.querySelector('#polyguard-join-meeting').click();
|
|
268
|
-
await promise;
|
|
269
|
-
});
|
|
270
|
-
});
|
|
271
|
-
|
|
272
|
-
describe('with sidebarUrl but no redirect_url in JWT (non-meeting links)', () => {
|
|
273
|
-
it('resolves normally without button or redirect', async () => {
|
|
274
|
-
clearCookies();
|
|
275
|
-
const client = new PolyguardWebsocketClientImpl({
|
|
276
|
-
...DEFAULT_PARAMS,
|
|
277
|
-
sidebarUrl: 'https://teams.polyguard.ai/ms-teams/sidebar-standalone',
|
|
278
|
-
link_uuid: 'link-abc',
|
|
279
|
-
});
|
|
280
|
-
const jwtClaims = { confirmation_code: 'ABC123' };
|
|
281
|
-
const { promise, ws } = await startVerifyAndGetWs(client);
|
|
282
|
-
// No redirect_url in the JWT claims
|
|
283
|
-
ws.simulateMessage({ jwt: jwtClaims });
|
|
284
|
-
const result = await promise;
|
|
285
|
-
expect(result).toEqual(jwtClaims);
|
|
286
|
-
expect(window.location.assign).not.toHaveBeenCalled();
|
|
287
|
-
});
|
|
288
|
-
});
|
|
289
|
-
});
|
package/src/browser.js
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Browser/script-tag entry point. Exposes a single global (Polyguard) when built as IIFE.
|
|
3
|
-
* Use this build via: <script src="https://cdn.polyguard.ai/sdk/latest/sdk.js"></script>
|
|
4
|
-
* Named exports become window.Polyguard.Client, window.Polyguard.AuthApi, etc.
|
|
5
|
-
*/
|
|
6
|
-
import { PolyguardClient } from './PolyguardClient.js';
|
|
7
|
-
|
|
8
|
-
export { PolyguardClient as Client };
|
|
9
|
-
export * from './generated/src/index.js';
|
package/src/generated/.babelrc
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"presets": [
|
|
3
|
-
"@babel/preset-env"
|
|
4
|
-
],
|
|
5
|
-
"plugins": [
|
|
6
|
-
"@babel/plugin-syntax-dynamic-import",
|
|
7
|
-
"@babel/plugin-syntax-import-meta",
|
|
8
|
-
"@babel/plugin-proposal-class-properties",
|
|
9
|
-
"@babel/plugin-proposal-json-strings",
|
|
10
|
-
[
|
|
11
|
-
"@babel/plugin-proposal-decorators",
|
|
12
|
-
{
|
|
13
|
-
"legacy": true
|
|
14
|
-
}
|
|
15
|
-
],
|
|
16
|
-
"@babel/plugin-proposal-function-sent",
|
|
17
|
-
"@babel/plugin-proposal-export-namespace-from",
|
|
18
|
-
"@babel/plugin-proposal-numeric-separator",
|
|
19
|
-
"@babel/plugin-proposal-throw-expressions",
|
|
20
|
-
"@babel/plugin-proposal-export-default-from",
|
|
21
|
-
"@babel/plugin-proposal-logical-assignment-operators",
|
|
22
|
-
"@babel/plugin-proposal-optional-chaining",
|
|
23
|
-
[
|
|
24
|
-
"@babel/plugin-proposal-pipeline-operator",
|
|
25
|
-
{
|
|
26
|
-
"proposal": "minimal"
|
|
27
|
-
}
|
|
28
|
-
],
|
|
29
|
-
"@babel/plugin-proposal-nullish-coalescing-operator",
|
|
30
|
-
"@babel/plugin-proposal-do-expressions",
|
|
31
|
-
"@babel/plugin-proposal-function-bind"
|
|
32
|
-
]
|
|
33
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
.babelrc
|
|
2
|
-
.gitignore
|
|
3
|
-
.travis.yml
|
|
4
|
-
README.md
|
|
5
|
-
docs/ApiControllersPslStirCallRequest.md
|
|
6
|
-
docs/ApiModelsApiCallModelsCallRequest.md
|
|
7
|
-
docs/AppId.md
|
|
8
|
-
docs/BlockingApi.md
|
|
9
|
-
docs/CallsApi.md
|
|
10
|
-
docs/Certainty.md
|
|
11
|
-
docs/CreateLinkRequest.md
|
|
12
|
-
docs/DefaultApi.md
|
|
13
|
-
docs/HTTPValidationError.md
|
|
14
|
-
docs/InviteRequestModel.md
|
|
15
|
-
docs/JWTRequest.md
|
|
16
|
-
docs/LinksApi.md
|
|
17
|
-
docs/NumberVerification.md
|
|
18
|
-
docs/SdkApi.md
|
|
19
|
-
docs/SecureLinksApi.md
|
|
20
|
-
docs/StartAttestationRequest.md
|
|
21
|
-
docs/StartMeetingRequest.md
|
|
22
|
-
docs/StirApi.md
|
|
23
|
-
docs/TwilioApi.md
|
|
24
|
-
docs/UsersApi.md
|
|
25
|
-
docs/ValidationError.md
|
|
26
|
-
docs/ValidationErrorLocInner.md
|
|
27
|
-
docs/VeriffApi.md
|
|
28
|
-
docs/VeriffSessionRequest.md
|
|
29
|
-
docs/VerifyRequest.md
|
|
30
|
-
docs/WellKnownApi.md
|
|
31
|
-
docs/ZoomApi.md
|
|
32
|
-
git_push.sh
|
|
33
|
-
mocha.opts
|
|
34
|
-
package.json
|
|
35
|
-
src/ApiClient.js
|
|
36
|
-
src/api/BlockingApi.js
|
|
37
|
-
src/api/CallsApi.js
|
|
38
|
-
src/api/DefaultApi.js
|
|
39
|
-
src/api/LinksApi.js
|
|
40
|
-
src/api/SdkApi.js
|
|
41
|
-
src/api/SecureLinksApi.js
|
|
42
|
-
src/api/StirApi.js
|
|
43
|
-
src/api/TwilioApi.js
|
|
44
|
-
src/api/UsersApi.js
|
|
45
|
-
src/api/VeriffApi.js
|
|
46
|
-
src/api/WellKnownApi.js
|
|
47
|
-
src/api/ZoomApi.js
|
|
48
|
-
src/index.js
|
|
49
|
-
src/model/ApiControllersPslStirCallRequest.js
|
|
50
|
-
src/model/ApiModelsApiCallModelsCallRequest.js
|
|
51
|
-
src/model/AppId.js
|
|
52
|
-
src/model/Certainty.js
|
|
53
|
-
src/model/CreateLinkRequest.js
|
|
54
|
-
src/model/HTTPValidationError.js
|
|
55
|
-
src/model/InviteRequestModel.js
|
|
56
|
-
src/model/JWTRequest.js
|
|
57
|
-
src/model/NumberVerification.js
|
|
58
|
-
src/model/StartAttestationRequest.js
|
|
59
|
-
src/model/StartMeetingRequest.js
|
|
60
|
-
src/model/ValidationError.js
|
|
61
|
-
src/model/ValidationErrorLocInner.js
|
|
62
|
-
src/model/VeriffSessionRequest.js
|
|
63
|
-
src/model/VerifyRequest.js
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
7.14.0-SNAPSHOT
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
# OpenAPI Generator Ignore
|
|
2
|
-
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
|
|
3
|
-
|
|
4
|
-
# Use this file to prevent files from being overwritten by the generator.
|
|
5
|
-
# The patterns follow closely to .gitignore or .dockerignore.
|
|
6
|
-
|
|
7
|
-
# As an example, the C# client generator defines ApiClient.cs.
|
|
8
|
-
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
|
|
9
|
-
#ApiClient.cs
|
|
10
|
-
|
|
11
|
-
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
|
|
12
|
-
#foo/*/qux
|
|
13
|
-
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
|
|
14
|
-
|
|
15
|
-
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
|
|
16
|
-
#foo/**/qux
|
|
17
|
-
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
|
|
18
|
-
|
|
19
|
-
# You can also negate patterns with an exclamation (!).
|
|
20
|
-
# For example, you can ignore all files in a docs folder with the file extension .md:
|
|
21
|
-
#docs/*.md
|
|
22
|
-
# Then explicitly reverse the ignore rule for a single file:
|
|
23
|
-
#!docs/README.md
|