@wazo/sdk 0.40.8 → 0.41.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/wazo-sdk.js +3 -3
- package/esm/__tests__/api-client.test.js +0 -1
- package/esm/domain/__tests__/Session.test.js +1 -5
- package/esm/service/IssueReporter.js +1 -2
- package/esm/service/__tests__/IssueReporter.test.js +4 -7
- package/esm/simple/Auth.js +39 -17
- package/esm/types/service/IssueReporter.d.ts.map +1 -1
- package/esm/types/simple/Auth.d.ts.map +1 -1
- package/esm/types/utils/api-requester.d.ts +0 -1
- package/esm/types/utils/api-requester.d.ts.map +1 -1
- package/esm/utils/__tests__/api-requester.test.js +0 -2
- package/esm/utils/api-requester.js +3 -32
- package/lib/__tests__/api-client.test.js +0 -1
- package/lib/domain/__tests__/Session.test.js +1 -5
- package/lib/service/IssueReporter.js +1 -2
- package/lib/service/__tests__/IssueReporter.test.js +4 -7
- package/lib/simple/Auth.js +32 -8
- package/lib/types/service/IssueReporter.d.ts.map +1 -1
- package/lib/types/simple/Auth.d.ts.map +1 -1
- package/lib/types/utils/api-requester.d.ts +0 -1
- package/lib/types/utils/api-requester.d.ts.map +1 -1
- package/lib/utils/__tests__/api-requester.test.js +0 -2
- package/lib/utils/api-requester.js +3 -34
- package/package.json +2 -7
- package/src/__tests__/api-client.test.ts +0 -1
- package/src/domain/__tests__/Session.test.ts +1 -6
- package/src/service/IssueReporter.ts +1 -2
- package/src/service/__tests__/IssueReporter.test.ts +4 -7
- package/src/simple/Auth.ts +48 -17
- package/src/utils/__tests__/api-requester.test.ts +0 -3
- package/src/utils/api-requester.ts +3 -34
|
@@ -4,13 +4,8 @@ import Line from '../Line';
|
|
|
4
4
|
|
|
5
5
|
describe('Session domain', () => {
|
|
6
6
|
it('can parse a plain session to domain', () => {
|
|
7
|
-
// Can't use `new Headers` because it's not supported on node 16.
|
|
8
|
-
const headers = {
|
|
9
|
-
get: () => 'new-stack',
|
|
10
|
-
};
|
|
11
|
-
|
|
12
7
|
const plain = {
|
|
13
|
-
_headers:
|
|
8
|
+
_headers: new Headers({ 'wazo-stack-host': 'new-stack' }),
|
|
14
9
|
data: {
|
|
15
10
|
token: 'b93ae6bd-08d7-4001-9e61-057e72bbc4b3',
|
|
16
11
|
acl: ['calld.lines.*.presences.read', 'calld.switchboards.#', 'calld.transfers.*.complete.update', 'calld.transfers.*.delete', 'calld.transfers.*.read', 'calld.users.*.presences.read', 'calld.users.me.#', 'confd.infos.read', 'confd.users.me.#.read', 'confd.users.me.forwards.*.*', 'confd.users.me.funckeys.*', 'confd.users.me.funckeys.*.*', 'confd.users.me.read', 'confd.users.me.services.*.*', 'confd.users.me.update', 'dird.#.me.read', 'dird.directories.favorites.#', 'dird.directories.lookup.*.headers.read', 'dird.directories.lookup.*.read', 'dird.directories.personal.*.read', 'dird.personal.#', 'events.calls.me', 'events.chat.message.*.me', 'events.config.users.me.#', 'events.statuses.*', 'events.switchboards.#', 'events.transfers.me', 'events.users.me.#', 'events.directory.me.#', 'websocketd', 'call-logd.users.me.cdr.read'],
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
/* eslint-disable prefer-destructuring, no-param-reassign, no-underscore-dangle */
|
|
4
4
|
import moment from 'moment';
|
|
5
|
-
import { realFetch } from '../utils/api-requester';
|
|
6
5
|
import isMobile from '../utils/isMobile';
|
|
7
6
|
import { obfuscateToken } from '../utils/string';
|
|
8
7
|
|
|
@@ -383,7 +382,7 @@ class IssueReporter {
|
|
|
383
382
|
const url = `http${isSecure ? 's' : ''}://${host}${isSecure ? '' : `:${port}`}/${tag}`;
|
|
384
383
|
const body = Array.isArray(payload) ? `[${payload.map(this._boundParseLoggerBody).join(',')}]` : this._parseLoggerBody(payload as Record<string, any>);
|
|
385
384
|
|
|
386
|
-
|
|
385
|
+
fetch(url, {
|
|
387
386
|
method: 'POST',
|
|
388
387
|
headers: {
|
|
389
388
|
Accept: 'application/json',
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
/* eslint-disable no-console */
|
|
6
6
|
import IssueReporter from '../IssueReporter';
|
|
7
|
-
import { realFetch } from '../../utils/api-requester';
|
|
8
7
|
|
|
9
8
|
jest.mock('../../utils/api-requester');
|
|
10
9
|
let oldLog: any;
|
|
@@ -25,9 +24,7 @@ describe('IssueReporter', () => {
|
|
|
25
24
|
});
|
|
26
25
|
beforeEach(() => {
|
|
27
26
|
jest.resetAllMocks();
|
|
28
|
-
|
|
29
|
-
catch: () => {},
|
|
30
|
-
}));
|
|
27
|
+
jest.spyOn(global, 'fetch');
|
|
31
28
|
});
|
|
32
29
|
afterAll(() => {
|
|
33
30
|
console.log = oldLog;
|
|
@@ -50,7 +47,7 @@ describe('IssueReporter', () => {
|
|
|
50
47
|
|
|
51
48
|
IssueReporter._sendToRemoteLogger('info');
|
|
52
49
|
|
|
53
|
-
expect(
|
|
50
|
+
expect(fetch).toHaveBeenCalled();
|
|
54
51
|
});
|
|
55
52
|
it('should send if verbosity is equal than required', () => {
|
|
56
53
|
// Same level
|
|
@@ -60,7 +57,7 @@ describe('IssueReporter', () => {
|
|
|
60
57
|
|
|
61
58
|
IssueReporter._sendToRemoteLogger('trace');
|
|
62
59
|
|
|
63
|
-
expect(
|
|
60
|
+
expect(fetch).toHaveBeenCalled();
|
|
64
61
|
});
|
|
65
62
|
it('should not send if verbosity is lower than required', () => {
|
|
66
63
|
// Lower level
|
|
@@ -70,7 +67,7 @@ describe('IssueReporter', () => {
|
|
|
70
67
|
|
|
71
68
|
IssueReporter._sendToRemoteLogger('trace');
|
|
72
69
|
|
|
73
|
-
expect(
|
|
70
|
+
expect(fetch).not.toHaveBeenCalled();
|
|
74
71
|
});
|
|
75
72
|
it('should log extra data', () => {
|
|
76
73
|
jest.spyOn(IssueReporter, '_sendToRemoteLogger').mockImplementation(() => {});
|
package/src/simple/Auth.ts
CHANGED
|
@@ -53,8 +53,7 @@ class Auth {
|
|
|
53
53
|
|
|
54
54
|
BACKEND_LDAP: string;
|
|
55
55
|
|
|
56
|
-
|
|
57
|
-
shouldCheckUserUuidHeader: boolean;
|
|
56
|
+
usingEdgeServer: boolean | undefined;
|
|
58
57
|
|
|
59
58
|
constructor() {
|
|
60
59
|
this.expiration = DETAULT_EXPIRATION;
|
|
@@ -62,7 +61,6 @@ class Auth {
|
|
|
62
61
|
this.minSubscriptionType = null;
|
|
63
62
|
this.BACKEND_WAZO = DEFAULT_BACKEND_USER;
|
|
64
63
|
this.BACKEND_LDAP = BACKEND_LDAP_USER;
|
|
65
|
-
this.shouldCheckUserUuidHeader = true;
|
|
66
64
|
}
|
|
67
65
|
|
|
68
66
|
init(clientId: string, expiration: number, minSubscriptionType: number | null | undefined, authorizationName: string | null, mobile: boolean): void {
|
|
@@ -210,6 +208,7 @@ class Auth {
|
|
|
210
208
|
setRefreshToken(null);
|
|
211
209
|
this.session = null;
|
|
212
210
|
this.authenticated = false;
|
|
211
|
+
this.usingEdgeServer = undefined;
|
|
213
212
|
setFetchOptions({});
|
|
214
213
|
}
|
|
215
214
|
|
|
@@ -318,27 +317,54 @@ class Auth {
|
|
|
318
317
|
return `${this.getFirstName()} ${this.getLastName()}`;
|
|
319
318
|
}
|
|
320
319
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
const headers = {
|
|
320
|
+
_getHttpUserUuidHeaders(uuid:string) {
|
|
321
|
+
return {
|
|
326
322
|
...(getFetchOptions()?.headers || {}),
|
|
327
323
|
'X-User-UUID': uuid,
|
|
328
324
|
};
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
setHttpUserUuidHeader(uuid: string) {
|
|
328
|
+
logger.info('Setting http header user uuid', { uuid });
|
|
329
|
+
|
|
330
|
+
if (!uuid) {
|
|
331
|
+
logger.warn('attempting to set a null value to user uuid header');
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const headers = this._getHttpUserUuidHeaders(uuid);
|
|
336
|
+
|
|
337
|
+
setFetchOptions({
|
|
338
|
+
...getFetchOptions(),
|
|
339
|
+
headers,
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
async checkHttpUserUuidHeader(uuid: string | null | undefined) {
|
|
344
|
+
logger.info('Checking user uuid http header', { uuid });
|
|
345
|
+
|
|
346
|
+
if (!uuid) {
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const headers = this._getHttpUserUuidHeaders(uuid);
|
|
329
351
|
|
|
330
352
|
try {
|
|
331
|
-
|
|
332
|
-
|
|
353
|
+
const response: Response = await getApiClient().client.head('auth/0.1/status', null, headers, (r: any) => r);
|
|
354
|
+
|
|
355
|
+
const allowsUserUuidHeader = response.headers.get('access-control-allow-headers')?.includes('X-User-UUID');
|
|
356
|
+
|
|
357
|
+
if (this.mobile && !allowsUserUuidHeader) {
|
|
358
|
+
throw new Error('Server does not allow user UUID header on mobile');
|
|
333
359
|
}
|
|
334
360
|
|
|
335
361
|
// If the previous request went well, it means that the header is accepted
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
362
|
+
this.setHttpUserUuidHeader(uuid);
|
|
363
|
+
this.usingEdgeServer = true;
|
|
364
|
+
logger.info('Setting usingEdgeServer value to TRUE', { requestHeaders: headers, responseHeaders: response.headers, allowsUserUuidHeader });
|
|
365
|
+
} catch (e) {
|
|
366
|
+
this.usingEdgeServer = false;
|
|
367
|
+
logger.info('Setting usingEdgeServer to FALSE', { justification: e });
|
|
342
368
|
}
|
|
343
369
|
}
|
|
344
370
|
|
|
@@ -348,12 +374,17 @@ class Auth {
|
|
|
348
374
|
}
|
|
349
375
|
|
|
350
376
|
const session = rawSession;
|
|
351
|
-
await this.setHttpUserUuidHeader(session.uuid);
|
|
352
377
|
|
|
353
378
|
if (!session) {
|
|
354
379
|
return null;
|
|
355
380
|
}
|
|
356
381
|
|
|
382
|
+
if (this.usingEdgeServer) {
|
|
383
|
+
this.setHttpUserUuidHeader(session.uuid as string);
|
|
384
|
+
} else if (typeof this.usingEdgeServer === 'undefined') {
|
|
385
|
+
await this.checkHttpUserUuidHeader(session.uuid);
|
|
386
|
+
}
|
|
387
|
+
|
|
357
388
|
setApiToken(session.token);
|
|
358
389
|
|
|
359
390
|
if (session.refreshToken) {
|
|
@@ -79,8 +79,6 @@ describe('Retrieving headers', () => {
|
|
|
79
79
|
});
|
|
80
80
|
describe('Calling fetch', () => {
|
|
81
81
|
it('should call fetch without body but query string in get method', async () => {
|
|
82
|
-
jest.mock('node-fetch/src/index', () => {});
|
|
83
|
-
|
|
84
82
|
global.fetch = jest.fn(() => Promise.resolve({
|
|
85
83
|
json: () => Promise.resolve({}),
|
|
86
84
|
headers: {
|
|
@@ -108,7 +106,6 @@ describe('Calling fetch', () => {
|
|
|
108
106
|
|
|
109
107
|
describe('With a refresh token', () => {
|
|
110
108
|
it('should retry the call with a new token', async () => {
|
|
111
|
-
jest.mock('node-fetch/src/index', () => {});
|
|
112
109
|
let calls = 0;
|
|
113
110
|
|
|
114
111
|
global.fetch = jest.fn(() => {
|
|
@@ -1,12 +1,7 @@
|
|
|
1
|
-
/* global window */
|
|
2
|
-
/* eslint-disable global-require */
|
|
3
|
-
/* eslint-disable import/no-dynamic-require */
|
|
4
1
|
import { Base64 } from 'js-base64';
|
|
5
|
-
import { AbortController as NodeAbortController } from 'node-abort-controller';
|
|
6
2
|
|
|
7
3
|
import BadResponse from '../domain/BadResponse';
|
|
8
4
|
import ServerError from '../domain/ServerError';
|
|
9
|
-
import isMobile from './isMobile';
|
|
10
5
|
import type { Token } from '../domain/types';
|
|
11
6
|
import IssueReporter from '../service/IssueReporter';
|
|
12
7
|
|
|
@@ -23,32 +18,6 @@ const methods = ['head', 'get', 'post', 'put', 'delete', 'options'];
|
|
|
23
18
|
const logger = IssueReporter ? IssueReporter.loggerFor('api') : console;
|
|
24
19
|
const REQUEST_TIMEOUT_MS = 300 * 1000; // 300s like the Chrome engine default value.
|
|
25
20
|
|
|
26
|
-
// Use a function here to be able to mock it in tests
|
|
27
|
-
export const realFetch = () => {
|
|
28
|
-
if (typeof fetch !== 'undefined') {
|
|
29
|
-
return fetch;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
if (typeof document !== 'undefined' && window.fetch) {
|
|
33
|
-
// Browser
|
|
34
|
-
return window.fetch;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
if (isMobile()) {
|
|
38
|
-
// React native
|
|
39
|
-
return fetch;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// nodejs
|
|
43
|
-
// this package is disabled for react-native in package.json because it requires nodejs modules
|
|
44
|
-
// Used to trick the optimizer to avoid requiring `node-fetch/lib/index` directly
|
|
45
|
-
// It causes to require it on browsers when delivered by a nodejs engine (cf: vitejs).
|
|
46
|
-
try {
|
|
47
|
-
return require(Math.random() >= 0 ? 'node-fetch/lib/index' : '');
|
|
48
|
-
} catch (e: any) {
|
|
49
|
-
return fetch;
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
21
|
export default class ApiRequester {
|
|
53
22
|
server: string;
|
|
54
23
|
|
|
@@ -167,9 +136,9 @@ export default class ApiRequester {
|
|
|
167
136
|
|
|
168
137
|
const isHead = method === 'head';
|
|
169
138
|
const hasEmptyResponse = method === 'delete' || isHead;
|
|
170
|
-
const newParse = hasEmptyResponse ? ApiRequester.successResponseParser : parse;
|
|
139
|
+
const newParse = hasEmptyResponse && parse === ApiRequester.defaultParser ? ApiRequester.successResponseParser : parse;
|
|
171
140
|
const fetchOptions = { ...(this.fetchOptions || {}) };
|
|
172
|
-
const controller =
|
|
141
|
+
const controller = new AbortController();
|
|
173
142
|
const extraHeaders = fetchOptions.headers || {};
|
|
174
143
|
delete fetchOptions.headers;
|
|
175
144
|
const options = {
|
|
@@ -192,7 +161,7 @@ export default class ApiRequester {
|
|
|
192
161
|
}
|
|
193
162
|
|
|
194
163
|
const start = new Date();
|
|
195
|
-
const requestPromise =
|
|
164
|
+
const requestPromise = fetch(url, options).then((response: any) => {
|
|
196
165
|
const contentType = response.headers.get('content-type') || '';
|
|
197
166
|
const isJson = contentType.indexOf('application/json') !== -1;
|
|
198
167
|
IssueReporter.logRequest(url, options, response, start);
|