@wazo/sdk 0.43.4 → 0.43.6
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 +2 -2
- package/esm/__tests__/api-client.test.js +20 -1
- package/esm/api/auth.js +9 -2
- package/esm/simple/Auth.js +4 -10
- package/esm/simple/__tests__/Auth.test.js +7 -63
- package/esm/types/api/auth.d.ts.map +1 -1
- package/esm/types/simple/Auth.d.ts.map +1 -1
- package/esm/types/utils/api-requester.d.ts.map +1 -1
- package/esm/utils/__tests__/api-requester.test.js +17 -0
- package/esm/utils/api-requester.js +9 -1
- package/lib/__tests__/api-client.test.js +20 -1
- package/lib/api/auth.js +9 -2
- package/lib/simple/Auth.js +4 -10
- package/lib/simple/__tests__/Auth.test.js +10 -63
- package/lib/types/api/auth.d.ts.map +1 -1
- package/lib/types/simple/Auth.d.ts.map +1 -1
- package/lib/types/utils/api-requester.d.ts.map +1 -1
- package/lib/utils/__tests__/api-requester.test.js +17 -0
- package/lib/utils/api-requester.js +9 -1
- package/package.json +1 -1
- package/src/__tests__/api-client.test.ts +22 -1
- package/src/api/auth.ts +13 -2
- package/src/simple/Auth.ts +4 -11
- package/src/simple/__tests__/Auth.test.ts +8 -86
- package/src/utils/__tests__/api-requester.test.ts +20 -0
- package/src/utils/api-requester.ts +9 -1
|
@@ -131,7 +131,6 @@ describe('With correct API results', () => {
|
|
|
131
131
|
body: JSON.stringify({ saml_session_id: samlSessionId }),
|
|
132
132
|
signal: expect.any(Object),
|
|
133
133
|
headers: {
|
|
134
|
-
'X-Auth-Token': token,
|
|
135
134
|
'Content-Type': 'application/json',
|
|
136
135
|
Accept: 'application/json',
|
|
137
136
|
},
|
|
@@ -140,6 +139,28 @@ describe('With correct API results', () => {
|
|
|
140
139
|
});
|
|
141
140
|
});
|
|
142
141
|
|
|
142
|
+
describe('samlLogIn mobile test', () => {
|
|
143
|
+
it('should retrieve user token', async () => {
|
|
144
|
+
Wazo.Auth.mobile = true;
|
|
145
|
+
const samlSessionId = 'a1b2C3d4';
|
|
146
|
+
const result = await client.auth.samlLogIn(samlSessionId);
|
|
147
|
+
|
|
148
|
+
expect(result).toBeInstanceOf(Session);
|
|
149
|
+
expect(result?.token).toBe(1);
|
|
150
|
+
expect(global.fetch).toBeCalledWith(`https://${server}/api/auth/${authVersion}/token`, {
|
|
151
|
+
method: 'post',
|
|
152
|
+
body: JSON.stringify({ saml_session_id: samlSessionId }),
|
|
153
|
+
signal: expect.any(Object),
|
|
154
|
+
headers: {
|
|
155
|
+
'Content-Type': 'application/json',
|
|
156
|
+
'Wazo-Session-Type': 'mobile',
|
|
157
|
+
Accept: 'application/json',
|
|
158
|
+
},
|
|
159
|
+
agent: null,
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
|
|
143
164
|
describe('logOut test', () => {
|
|
144
165
|
it('should delete the specified token', async () => {
|
|
145
166
|
const oldToken = 123;
|
package/src/api/auth.ts
CHANGED
|
@@ -116,7 +116,13 @@ export default ((client: ApiRequester, baseUrl: string): AuthD => ({
|
|
|
116
116
|
},
|
|
117
117
|
|
|
118
118
|
logOut: (token: Token): Promise<LogoutResponse> => client.delete(`${baseUrl}/token/${token}`, null, {}, ApiRequester.successResponseParser),
|
|
119
|
+
|
|
119
120
|
samlLogIn: async (samlSessionId: string): Promise<Session | null | undefined> => {
|
|
121
|
+
const headers: Record<string, any> = {
|
|
122
|
+
Accept: 'application/json',
|
|
123
|
+
'Content-Type': 'application/json',
|
|
124
|
+
};
|
|
125
|
+
|
|
120
126
|
const body: SamlLoginBody = {
|
|
121
127
|
saml_session_id: samlSessionId,
|
|
122
128
|
};
|
|
@@ -126,8 +132,13 @@ export default ((client: ApiRequester, baseUrl: string): AuthD => ({
|
|
|
126
132
|
body.client_id = client.clientId;
|
|
127
133
|
}
|
|
128
134
|
|
|
129
|
-
|
|
135
|
+
if (Wazo.Auth.mobile) {
|
|
136
|
+
headers['Wazo-Session-Type'] = 'mobile';
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return client.post(`${baseUrl}/token`, body, headers).then(Session.parse);
|
|
130
140
|
},
|
|
141
|
+
|
|
131
142
|
initiateIdpAuthentication: async (domain: string, redirectUrl: string) => {
|
|
132
143
|
const body = {
|
|
133
144
|
domain,
|
|
@@ -139,7 +150,7 @@ export default ((client: ApiRequester, baseUrl: string): AuthD => ({
|
|
|
139
150
|
'Content-Type': 'application/json',
|
|
140
151
|
};
|
|
141
152
|
|
|
142
|
-
return client.post(`${baseUrl}/saml/sso`, body, headers
|
|
153
|
+
return client.post(`${baseUrl}/saml/sso`, body, headers);
|
|
143
154
|
},
|
|
144
155
|
refreshToken: (refreshToken: string, backend: string, expiration: number, isMobile?: boolean, tenantId?: string, domainName?: string): Promise<Session | null | undefined> => {
|
|
145
156
|
const body: Record<string, any> = {
|
package/src/simple/Auth.ts
CHANGED
|
@@ -168,28 +168,21 @@ export class Auth {
|
|
|
168
168
|
}
|
|
169
169
|
|
|
170
170
|
async initiateIdpAuthentication(domain: string, redirectUrl: string): Promise<{ location: string, saml_session_id: string } | undefined> {
|
|
171
|
-
let response;
|
|
172
171
|
try {
|
|
173
|
-
|
|
172
|
+
return await getApiClient().auth.initiateIdpAuthentication(domain, redirectUrl);
|
|
174
173
|
} catch (e: any) {
|
|
175
174
|
logger.error('Error during IdP authentication initialization:', e.message);
|
|
176
|
-
throw e;
|
|
177
|
-
}
|
|
178
175
|
|
|
179
|
-
|
|
180
|
-
if (response.status === 404) {
|
|
176
|
+
if (e.status === 404) {
|
|
181
177
|
throw new NoSamlRouteError('No route found for SAML SSO');
|
|
182
178
|
}
|
|
183
179
|
|
|
184
|
-
if (
|
|
180
|
+
if (e.status === 500) {
|
|
185
181
|
throw new SamlConfigError('SAML/server configuration error');
|
|
186
182
|
}
|
|
187
183
|
|
|
188
|
-
|
|
189
|
-
throw new Error(error.message || error.reason);
|
|
184
|
+
throw e;
|
|
190
185
|
}
|
|
191
|
-
|
|
192
|
-
return response.json();
|
|
193
186
|
}
|
|
194
187
|
|
|
195
188
|
async logInViaRefreshToken(refreshToken: string): Promise<Session | null> {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import BadResponse from '../../domain/BadResponse';
|
|
2
|
+
import ServerError from '../../domain/ServerError';
|
|
1
3
|
import getApiClient, { setRefreshToken } from '../../service/getApiClient';
|
|
2
4
|
import { Auth as AuthClass } from '../Auth';
|
|
3
5
|
|
|
@@ -124,13 +126,8 @@ describe('simple/Auth', () => {
|
|
|
124
126
|
describe('initiateIdpAuthentication', () => {
|
|
125
127
|
const validResponse = { location: 'idp.com/auth', saml_session_id: 'a1b2C3d4' };
|
|
126
128
|
|
|
127
|
-
it('should return a `location` and `saml_session_id` if the response is
|
|
128
|
-
const initiateIdpAuthentication = jest.fn(() =>
|
|
129
|
-
Promise.resolve({
|
|
130
|
-
ok: true,
|
|
131
|
-
status: 303,
|
|
132
|
-
json: () => Promise.resolve(validResponse),
|
|
133
|
-
}));
|
|
129
|
+
it('should return a `location` and `saml_session_id` if the response is valid', async () => {
|
|
130
|
+
const initiateIdpAuthentication = jest.fn(() => validResponse);
|
|
134
131
|
|
|
135
132
|
(getApiClient as any).mockImplementation(() => ({
|
|
136
133
|
auth: {
|
|
@@ -141,12 +138,9 @@ describe('simple/Auth', () => {
|
|
|
141
138
|
const response = await Auth.initiateIdpAuthentication('example.com', 'https://myapp.xyz');
|
|
142
139
|
expect(response).toBe(validResponse);
|
|
143
140
|
});
|
|
141
|
+
|
|
144
142
|
it('should return a `NoSamlRouteError` if the response is a 404', async () => {
|
|
145
|
-
const initiateIdpAuthentication = jest.fn(() =>
|
|
146
|
-
Promise.resolve({
|
|
147
|
-
ok: false,
|
|
148
|
-
status: 404,
|
|
149
|
-
}));
|
|
143
|
+
const initiateIdpAuthentication = jest.fn(() => { throw BadResponse.fromText('an error message', 404); });
|
|
150
144
|
|
|
151
145
|
(getApiClient as any).mockImplementation(() => ({
|
|
152
146
|
auth: {
|
|
@@ -159,80 +153,8 @@ describe('simple/Auth', () => {
|
|
|
159
153
|
);
|
|
160
154
|
});
|
|
161
155
|
|
|
162
|
-
it('should return
|
|
163
|
-
const initiateIdpAuthentication = jest.fn(() =>
|
|
164
|
-
Promise.resolve({
|
|
165
|
-
ok: false,
|
|
166
|
-
json: () => Promise.resolve({ message: 'an error message', reason: 'an error reason' }),
|
|
167
|
-
}));
|
|
168
|
-
|
|
169
|
-
(getApiClient as any).mockImplementation(() => ({
|
|
170
|
-
auth: {
|
|
171
|
-
initiateIdpAuthentication,
|
|
172
|
-
},
|
|
173
|
-
}));
|
|
174
|
-
|
|
175
|
-
await expect(Auth.initiateIdpAuthentication('example.com', 'https://myapp.xyz')).rejects.toThrow(
|
|
176
|
-
'an error message',
|
|
177
|
-
);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
it('should return an error `reason` if there is no `message` and the response is NOT ok', async () => {
|
|
181
|
-
const initiateIdpAuthentication = jest.fn(() =>
|
|
182
|
-
Promise.resolve({
|
|
183
|
-
ok: false,
|
|
184
|
-
json: () => Promise.resolve({ reason: 'an error reason' }),
|
|
185
|
-
}));
|
|
186
|
-
|
|
187
|
-
(getApiClient as any).mockImplementation(() => ({
|
|
188
|
-
auth: {
|
|
189
|
-
initiateIdpAuthentication,
|
|
190
|
-
},
|
|
191
|
-
}));
|
|
192
|
-
|
|
193
|
-
await expect(Auth.initiateIdpAuthentication('example.com', 'https://myapp.xyz')).rejects.toThrow(
|
|
194
|
-
'an error reason',
|
|
195
|
-
);
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
it('should return an error with a null message if there is no `message` and `reason`', async () => {
|
|
199
|
-
const initiateIdpAuthentication = jest.fn(() =>
|
|
200
|
-
Promise.resolve({
|
|
201
|
-
ok: false,
|
|
202
|
-
json: () => Promise.resolve({}),
|
|
203
|
-
}));
|
|
204
|
-
|
|
205
|
-
(getApiClient as any).mockImplementation(() => ({
|
|
206
|
-
auth: {
|
|
207
|
-
initiateIdpAuthentication,
|
|
208
|
-
},
|
|
209
|
-
}));
|
|
210
|
-
|
|
211
|
-
await expect(Auth.initiateIdpAuthentication('example.com', 'https://myapp.xyz')).rejects.toThrow('');
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
it('should return a NoSAMLRouteError if the response is a 404', async () => {
|
|
215
|
-
const initiateIdpAuthentication = jest.fn(() =>
|
|
216
|
-
Promise.resolve({
|
|
217
|
-
ok: false,
|
|
218
|
-
status: 404,
|
|
219
|
-
}));
|
|
220
|
-
|
|
221
|
-
(getApiClient as any).mockImplementation(() => ({
|
|
222
|
-
auth: {
|
|
223
|
-
initiateIdpAuthentication,
|
|
224
|
-
},
|
|
225
|
-
}));
|
|
226
|
-
|
|
227
|
-
await expect(Auth.initiateIdpAuthentication('example.com', 'https://myapp.xyz')).rejects.toThrow('No route found for SAML SSO');
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
it('should return a SamlConfigError if the response is a 500', async () => {
|
|
231
|
-
const initiateIdpAuthentication = jest.fn(() =>
|
|
232
|
-
Promise.resolve({
|
|
233
|
-
ok: false,
|
|
234
|
-
status: 500,
|
|
235
|
-
}));
|
|
156
|
+
it('should return a `SamlConfigError` if the response is a 500', async () => {
|
|
157
|
+
const initiateIdpAuthentication = jest.fn(() => { throw ServerError.fromText('an error message', 500); });
|
|
236
158
|
|
|
237
159
|
(getApiClient as any).mockImplementation(() => ({
|
|
238
160
|
auth: {
|
|
@@ -158,3 +158,23 @@ describe('With a refresh token', () => {
|
|
|
158
158
|
});
|
|
159
159
|
});
|
|
160
160
|
});
|
|
161
|
+
|
|
162
|
+
describe('base64Encode', () => {
|
|
163
|
+
it('should encode a string using base64', () => {
|
|
164
|
+
const input = 'Hello World!';
|
|
165
|
+
const expectedOutput = 'SGVsbG8gV29ybGQh';
|
|
166
|
+
expect(ApiRequester.base64Encode(input)).toBe(expectedOutput);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it('should handle special characters', () => {
|
|
170
|
+
const input = 'éà$@€';
|
|
171
|
+
const expectedOutput = 'w6nDoCRA4oKs';
|
|
172
|
+
expect(ApiRequester.base64Encode(input)).toBe(expectedOutput);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it('should handle empty string', () => {
|
|
176
|
+
const input = '';
|
|
177
|
+
const expectedOutput = '';
|
|
178
|
+
expect(ApiRequester.base64Encode(input)).toBe(expectedOutput);
|
|
179
|
+
});
|
|
180
|
+
});
|
|
@@ -64,7 +64,15 @@ export default class ApiRequester {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
static base64Encode(str: string): string {
|
|
67
|
-
|
|
67
|
+
if (typeof btoa !== 'undefined') {
|
|
68
|
+
try {
|
|
69
|
+
return btoa(str);
|
|
70
|
+
} catch (error) {
|
|
71
|
+
// fall back to Base64.encode if btoa fails
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return Base64.encode(str);
|
|
68
76
|
}
|
|
69
77
|
|
|
70
78
|
// @see https://github.com/facebook/flow/issues/183#issuecomment-358607052
|