@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.
@@ -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
- return client.post(`${baseUrl}/token`, body).then(Session.parse);
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, (response: any) => response);
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> = {
@@ -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
- response = await getApiClient().auth.initiateIdpAuthentication(domain, redirectUrl);
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
- if (!response.ok) {
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 (response.status === 500) {
180
+ if (e.status === 500) {
185
181
  throw new SamlConfigError('SAML/server configuration error');
186
182
  }
187
183
 
188
- const error = await response.json();
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 ok', async () => {
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 an error `message` if the response is NOT ok', async () => {
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
- return typeof btoa !== 'undefined' ? btoa(str) : Base64.encode(str);
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