@webex/internal-plugin-user 2.59.2 → 2.59.3-next.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/.eslintrc.js +6 -6
- package/README.md +42 -42
- package/babel.config.js +3 -3
- package/dist/config.js +2 -2
- package/dist/config.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/user-uuid-batcher.js +36 -36
- package/dist/user-uuid-batcher.js.map +1 -1
- package/dist/user-uuid-store.js +22 -22
- package/dist/user-uuid-store.js.map +1 -1
- package/dist/user.js +112 -112
- package/dist/user.js.map +1 -1
- package/jest.config.js +3 -3
- package/package.json +18 -17
- package/process +1 -1
- package/src/config.js +21 -21
- package/src/index.js +15 -15
- package/src/user-uuid-batcher.js +128 -128
- package/src/user-uuid-store.js +105 -105
- package/src/user.js +466 -466
- package/test/integration/spec/user.js +380 -380
- package/test/unit/spec/user-uuid-batcher.js +98 -98
- package/test/unit/spec/user.js +155 -155
|
@@ -1,380 +1,380 @@
|
|
|
1
|
-
/*!
|
|
2
|
-
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import '@webex/internal-plugin-user';
|
|
6
|
-
|
|
7
|
-
import querystring from 'querystring';
|
|
8
|
-
import url from 'url';
|
|
9
|
-
|
|
10
|
-
import {assert} from '@webex/test-helper-chai';
|
|
11
|
-
import sinon from 'sinon';
|
|
12
|
-
import WebexCore from '@webex/webex-core';
|
|
13
|
-
import testUsers from '@webex/test-helper-test-users';
|
|
14
|
-
import {patterns} from '@webex/common';
|
|
15
|
-
import uuid from 'uuid';
|
|
16
|
-
import {merge} from 'lodash';
|
|
17
|
-
|
|
18
|
-
// Run the tests with and without Federation enabled,
|
|
19
|
-
// for test users in EU (Federation) and US
|
|
20
|
-
// Also try US user with Federation enabled
|
|
21
|
-
const runs = [
|
|
22
|
-
// This line can be ommited until a future pull request is generated to update @ciscospark/test-users-legacy
|
|
23
|
-
// {it: 'with EU user with Federation enabled', EUUser: true, attrs: {config: {credentials: {federation: true}}}},
|
|
24
|
-
{it: 'with US user without Federation enabled', EUUser: false, attrs: {}},
|
|
25
|
-
{
|
|
26
|
-
it: 'with US user with Federation enabled',
|
|
27
|
-
EUUser: false,
|
|
28
|
-
attrs: {config: {credentials: {federation: true}}},
|
|
29
|
-
},
|
|
30
|
-
];
|
|
31
|
-
|
|
32
|
-
runs.forEach((run) => {
|
|
33
|
-
describe(`plugin-user ${run.it}`, function () {
|
|
34
|
-
this.timeout(30000);
|
|
35
|
-
|
|
36
|
-
let webex, user1, user2, user3;
|
|
37
|
-
|
|
38
|
-
const testUserParm = {count: 3};
|
|
39
|
-
|
|
40
|
-
if (run.EUUser) {
|
|
41
|
-
testUserParm.config = {orgId: process.env.EU_PRIMARY_ORG_ID};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
before(() =>
|
|
45
|
-
testUsers.create(testUserParm).then((users) => {
|
|
46
|
-
user1 = users[0];
|
|
47
|
-
user2 = users[1];
|
|
48
|
-
user3 = users[2];
|
|
49
|
-
webex = new WebexCore(
|
|
50
|
-
merge({}, run.attrs, {
|
|
51
|
-
credentials: {
|
|
52
|
-
supertoken: user1.token,
|
|
53
|
-
},
|
|
54
|
-
})
|
|
55
|
-
);
|
|
56
|
-
assert.isDefined(webex.credentials.supertoken);
|
|
57
|
-
assert.isTrue(webex.canAuthorize);
|
|
58
|
-
assert.isFalse(webex.internal.user.hasPassword);
|
|
59
|
-
|
|
60
|
-
return webex.internal.device.register();
|
|
61
|
-
})
|
|
62
|
-
);
|
|
63
|
-
|
|
64
|
-
describe('#verify()', () => {
|
|
65
|
-
const unauthWebex = new WebexCore(run.attrs);
|
|
66
|
-
|
|
67
|
-
it('registers a new user', () =>
|
|
68
|
-
unauthWebex.internal.user
|
|
69
|
-
.verify({email: `Collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`})
|
|
70
|
-
.then((res) => {
|
|
71
|
-
assert.property(res, 'hasPassword');
|
|
72
|
-
assert.property(res, 'verificationEmailTriggered');
|
|
73
|
-
assert.property(res, 'sso');
|
|
74
|
-
assert.isFalse(res.hasPassword);
|
|
75
|
-
assert.isTrue(res.verificationEmailTriggered);
|
|
76
|
-
assert.isFalse(res.sso);
|
|
77
|
-
assert.isFalse(webex.internal.user.hasPassword);
|
|
78
|
-
}));
|
|
79
|
-
|
|
80
|
-
it('verifies an existing user', () =>
|
|
81
|
-
unauthWebex.internal.user.verify({email: user1.email}).then((res) => {
|
|
82
|
-
assert.property(res, 'hasPassword');
|
|
83
|
-
assert.property(res, 'verificationEmailTriggered');
|
|
84
|
-
assert.property(res, 'sso');
|
|
85
|
-
assert.isTrue(res.hasPassword);
|
|
86
|
-
assert.isFalse(res.verificationEmailTriggered);
|
|
87
|
-
assert.isFalse(res.sso);
|
|
88
|
-
assert.isTrue(unauthWebex.internal.user.hasPassword);
|
|
89
|
-
}));
|
|
90
|
-
|
|
91
|
-
it('leaves email address validation up to Atlas', () =>
|
|
92
|
-
assert
|
|
93
|
-
.isRejected(unauthWebex.internal.user.verify({email: 'not an email address'}))
|
|
94
|
-
.then((res) => assert.statusCode(res, 400)));
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
describe('#setPassword()', () => {
|
|
98
|
-
it("sets the user's password", () =>
|
|
99
|
-
webex.internal.user
|
|
100
|
-
.setPassword({password: 'P@ssword123'})
|
|
101
|
-
.then(() => webex.internal.user.verify({email: user1.email}))
|
|
102
|
-
.then((res) => {
|
|
103
|
-
assert.property(res, 'hasPassword');
|
|
104
|
-
assert.property(res, 'verificationEmailTriggered');
|
|
105
|
-
assert.property(res, 'sso');
|
|
106
|
-
assert.isTrue(res.hasPassword);
|
|
107
|
-
assert.isFalse(res.verificationEmailTriggered);
|
|
108
|
-
assert.isFalse(res.sso);
|
|
109
|
-
assert.isTrue(webex.internal.user.hasPassword);
|
|
110
|
-
}));
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
// NOTE: need collabctg+*@gmail.com to get verifyEmailURL
|
|
114
|
-
describe('#activate()', () => {
|
|
115
|
-
const unauthWebex = new WebexCore(run.attrs);
|
|
116
|
-
|
|
117
|
-
it('retrieves a valid user token', () => {
|
|
118
|
-
assert.isUndefined(unauthWebex.credentials.supertoken);
|
|
119
|
-
const email = `collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`;
|
|
120
|
-
|
|
121
|
-
return unauthWebex.internal.user
|
|
122
|
-
.verify({email})
|
|
123
|
-
.then((res) => {
|
|
124
|
-
assert.isTrue(res.verificationEmailTriggered);
|
|
125
|
-
assert.property(res, 'verifyEmailURL');
|
|
126
|
-
const {query} = url.parse(res.verifyEmailURL);
|
|
127
|
-
const token = querystring.parse(query).t;
|
|
128
|
-
|
|
129
|
-
return unauthWebex.internal.user.activate({email, verificationToken: token});
|
|
130
|
-
})
|
|
131
|
-
.then((res) => {
|
|
132
|
-
assert.property(res, 'email');
|
|
133
|
-
assert.property(res, 'tokenData');
|
|
134
|
-
assert.equal(res.email, email);
|
|
135
|
-
assert.isDefined(unauthWebex.credentials.supertoken.access_token);
|
|
136
|
-
|
|
137
|
-
return unauthWebex.internal.user.verify({email});
|
|
138
|
-
})
|
|
139
|
-
.then((res) => {
|
|
140
|
-
// verification email should not trigger if already have valid user token
|
|
141
|
-
assert.property(res, 'hasPassword');
|
|
142
|
-
assert.property(res, 'verificationEmailTriggered');
|
|
143
|
-
assert.property(res, 'sso');
|
|
144
|
-
assert.isFalse(res.hasPassword);
|
|
145
|
-
assert.isFalse(res.verificationEmailTriggered);
|
|
146
|
-
assert.isFalse(res.sso);
|
|
147
|
-
assert.isFalse(unauthWebex.internal.user.hasPassword);
|
|
148
|
-
});
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it('retrieves a valid user token and sets the password', () => {
|
|
152
|
-
const unauthWebex = new WebexCore(run.attrs);
|
|
153
|
-
|
|
154
|
-
assert.isUndefined(unauthWebex.credentials.supertoken);
|
|
155
|
-
const email = `collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`;
|
|
156
|
-
|
|
157
|
-
return unauthWebex.internal.user
|
|
158
|
-
.verify({email})
|
|
159
|
-
.then((res) => {
|
|
160
|
-
assert.isTrue(res.verificationEmailTriggered);
|
|
161
|
-
assert.property(res, 'verifyEmailURL');
|
|
162
|
-
const {query} = url.parse(res.verifyEmailURL);
|
|
163
|
-
const token = querystring.parse(query).t;
|
|
164
|
-
|
|
165
|
-
return unauthWebex.internal.user.activate({email, verificationToken: token});
|
|
166
|
-
})
|
|
167
|
-
.then((res) => {
|
|
168
|
-
assert.property(res, 'email');
|
|
169
|
-
assert.property(res, 'tokenData');
|
|
170
|
-
assert.equal(res.email, email);
|
|
171
|
-
assert.isDefined(unauthWebex.credentials.supertoken.access_token);
|
|
172
|
-
})
|
|
173
|
-
.then(() => unauthWebex.internal.device.register())
|
|
174
|
-
.then(() => unauthWebex.internal.user.get())
|
|
175
|
-
.then((user) =>
|
|
176
|
-
unauthWebex.internal.user.setPassword({email: user.email, password: 'P@ssword123'})
|
|
177
|
-
)
|
|
178
|
-
.then(() => unauthWebex.internal.user.verify({email}))
|
|
179
|
-
.then((res) => {
|
|
180
|
-
assert.property(res, 'hasPassword');
|
|
181
|
-
assert.property(res, 'verificationEmailTriggered');
|
|
182
|
-
assert.property(res, 'sso');
|
|
183
|
-
assert.isTrue(res.hasPassword);
|
|
184
|
-
assert.isFalse(res.verificationEmailTriggered);
|
|
185
|
-
assert.isFalse(res.sso);
|
|
186
|
-
assert.isTrue(unauthWebex.internal.user.hasPassword);
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
describe('#generateOTP() and #validateOTP()', () => {
|
|
192
|
-
it('generates and validates OTP', () => {
|
|
193
|
-
const unauthWebex = new WebexCore(run.attrs);
|
|
194
|
-
|
|
195
|
-
assert.isUndefined(unauthWebex.credentials.supertoken);
|
|
196
|
-
// NOTE: need collabctg+*@gmail.com to get oneTimePassword
|
|
197
|
-
const email = `collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`;
|
|
198
|
-
|
|
199
|
-
return unauthWebex.internal.user
|
|
200
|
-
.verify({email})
|
|
201
|
-
.then((res) => {
|
|
202
|
-
const {query} = url.parse(res.verifyEmailURL);
|
|
203
|
-
const token = querystring.parse(query).t;
|
|
204
|
-
|
|
205
|
-
return unauthWebex.internal.user.activate({email, verificationToken: token});
|
|
206
|
-
})
|
|
207
|
-
.then(() => unauthWebex.internal.device.register())
|
|
208
|
-
.then(() => unauthWebex.internal.user.get())
|
|
209
|
-
.then((user) =>
|
|
210
|
-
unauthWebex.internal.user.setPassword({email: user.email, password: 'P@ssword123'})
|
|
211
|
-
)
|
|
212
|
-
.then(() => unauthWebex.internal.user.verify({email}))
|
|
213
|
-
.then(() => unauthWebex.internal.user.generateOTP({email}))
|
|
214
|
-
.then((res) => {
|
|
215
|
-
assert.property(res, 'oneTimePassword');
|
|
216
|
-
assert.property(res, 'email');
|
|
217
|
-
assert.equal(res.email, email);
|
|
218
|
-
assert.property(res, 'id');
|
|
219
|
-
assert.property(res, 'url');
|
|
220
|
-
assert.property(res, 'status');
|
|
221
|
-
|
|
222
|
-
return unauthWebex.internal.user.validateOTP({
|
|
223
|
-
email,
|
|
224
|
-
oneTimePassword: res.oneTimePassword,
|
|
225
|
-
});
|
|
226
|
-
})
|
|
227
|
-
.then((res) => {
|
|
228
|
-
assert.property(res, 'email');
|
|
229
|
-
assert.property(res, 'id');
|
|
230
|
-
assert.property(res, 'url');
|
|
231
|
-
assert.property(res, 'tokenData');
|
|
232
|
-
assert.equal(res.email, email);
|
|
233
|
-
assert.equal(res.tokenData.token_type, unauthWebex.credentials.supertoken.token_type);
|
|
234
|
-
assert.equal(res.tokenData.expires_in, unauthWebex.credentials.supertoken.expires_in);
|
|
235
|
-
assert.equal(
|
|
236
|
-
res.tokenData.access_token,
|
|
237
|
-
unauthWebex.credentials.supertoken.access_token
|
|
238
|
-
);
|
|
239
|
-
assert.equal(
|
|
240
|
-
res.tokenData.refresh_token_expires_in,
|
|
241
|
-
unauthWebex.credentials.supertoken.refresh_token_expires_in
|
|
242
|
-
);
|
|
243
|
-
});
|
|
244
|
-
});
|
|
245
|
-
});
|
|
246
|
-
|
|
247
|
-
describe('#get()', () => {
|
|
248
|
-
it('gets the current user', () =>
|
|
249
|
-
webex.internal.user.get().then((user) => {
|
|
250
|
-
assert.equal(user.id, webex.internal.device.userId);
|
|
251
|
-
assert.property(user, 'entitlements');
|
|
252
|
-
assert.property(user, 'email');
|
|
253
|
-
assert.property(user, 'name');
|
|
254
|
-
}));
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
describe('#asUUID()', () => {
|
|
258
|
-
function makeEmailAddress() {
|
|
259
|
-
return `webex-js-sdk--test-${uuid.v4()}@example.com`;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
let email;
|
|
263
|
-
|
|
264
|
-
beforeEach(() => {
|
|
265
|
-
email = makeEmailAddress();
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
it('maps an email address to a uuid', () =>
|
|
269
|
-
webex.internal.user
|
|
270
|
-
.asUUID(user2, {force: true})
|
|
271
|
-
.then((result) => assert.equal(result, user2.id)));
|
|
272
|
-
|
|
273
|
-
it('maps an email address for a non-existent user to a fake uuid', () =>
|
|
274
|
-
webex.internal.user
|
|
275
|
-
.asUUID(email)
|
|
276
|
-
.then((result) => assert.match(result, patterns.uuid))
|
|
277
|
-
.then(() => webex.internal.user.store.getByEmail(email))
|
|
278
|
-
.then((u) => assert.isFalse(u.userExists, 'User does not exist')));
|
|
279
|
-
|
|
280
|
-
describe('with {create: true}', () => {
|
|
281
|
-
let spy;
|
|
282
|
-
|
|
283
|
-
beforeEach(() => {
|
|
284
|
-
spy = sinon.spy(webex.internal.user, 'fetchUUID');
|
|
285
|
-
});
|
|
286
|
-
afterEach(() => spy.restore());
|
|
287
|
-
|
|
288
|
-
it('creates a new user', () =>
|
|
289
|
-
webex.internal.user
|
|
290
|
-
.asUUID(email, {create: true})
|
|
291
|
-
.then((result) => assert.match(result, patterns.uuid))
|
|
292
|
-
.then(() => webex.internal.user.store.getByEmail(email))
|
|
293
|
-
.then((u) => assert.isTrue(u.userExists, 'User exists')));
|
|
294
|
-
|
|
295
|
-
it('does not use a cached value if the previous value was marked as non-existent', () =>
|
|
296
|
-
webex.internal.user
|
|
297
|
-
.asUUID(email)
|
|
298
|
-
.then((result) => assert.match(result, patterns.uuid))
|
|
299
|
-
.then(() => webex.internal.user.store.getByEmail(email))
|
|
300
|
-
.then((u) => assert.isFalse(u.userExists, 'User does not exist'))
|
|
301
|
-
.then(() => webex.internal.user.asUUID(email, {create: true}), patterns.uuid)
|
|
302
|
-
.then(() => webex.internal.user.store.getByEmail(email))
|
|
303
|
-
.then((u) => assert.isTrue(u.userExists, 'User exists'))
|
|
304
|
-
.then(() => assert.calledTwice(spy)));
|
|
305
|
-
|
|
306
|
-
it("does not use a cached value if the previous value's existence is unknown", () =>
|
|
307
|
-
webex.internal.user
|
|
308
|
-
.recordUUID({
|
|
309
|
-
id: user3.id,
|
|
310
|
-
emailAddress: user3.email,
|
|
311
|
-
})
|
|
312
|
-
.then(() => webex.internal.user.store.getByEmail(user3.email))
|
|
313
|
-
.then((user) => assert.isUndefined(user.userExists, "User's existence is unknown"))
|
|
314
|
-
.then(() =>
|
|
315
|
-
webex.internal.user
|
|
316
|
-
.asUUID(user3.email, {create: true})
|
|
317
|
-
.then((result) => assert.equal(result, user3.id))
|
|
318
|
-
)
|
|
319
|
-
.then(() => assert.called(spy))
|
|
320
|
-
.then(() => webex.internal.user.store.getByEmail(user3.email))
|
|
321
|
-
.then((user) => assert.isTrue(user.userExists, 'User exists')));
|
|
322
|
-
});
|
|
323
|
-
});
|
|
324
|
-
|
|
325
|
-
describe('#update()', () => {
|
|
326
|
-
it("updates a user's name", () =>
|
|
327
|
-
webex.internal.user.update({displayName: 'New Display Name'}).then((user) => {
|
|
328
|
-
assert.equal(user.id, webex.internal.device.userId);
|
|
329
|
-
assert.property(user, 'entitlements');
|
|
330
|
-
assert.property(user, 'email');
|
|
331
|
-
assert.property(user, 'name');
|
|
332
|
-
assert.equal(user.name, 'New Display Name');
|
|
333
|
-
}));
|
|
334
|
-
});
|
|
335
|
-
describe('#updateName()', () => {
|
|
336
|
-
it("updates a user's displayName", () =>
|
|
337
|
-
webex.internal.user.updateName({displayName: 'New Name'}).then((user) => {
|
|
338
|
-
assert.equal(user.id, webex.internal.device.userId);
|
|
339
|
-
assert.property(user, 'displayName');
|
|
340
|
-
assert.equal(user.displayName, 'New Name');
|
|
341
|
-
}));
|
|
342
|
-
it("updates a user's givenName", () =>
|
|
343
|
-
webex.internal.user.updateName({givenName: 'Jack'}).then((user) => {
|
|
344
|
-
assert.equal(user.id, webex.internal.device.userId);
|
|
345
|
-
assert.property(user, 'name');
|
|
346
|
-
assert.property(user.name, 'givenName');
|
|
347
|
-
assert.equal(user.name.givenName, 'Jack');
|
|
348
|
-
}));
|
|
349
|
-
it("updates a user's familyName", () =>
|
|
350
|
-
webex.internal.user.updateName({familyName: 'Jill'}).then((user) => {
|
|
351
|
-
assert.equal(user.id, webex.internal.device.userId);
|
|
352
|
-
assert.property(user, 'name');
|
|
353
|
-
assert.property(user.name, 'familyName');
|
|
354
|
-
assert.equal(user.name.familyName, 'Jill');
|
|
355
|
-
}));
|
|
356
|
-
it("updates a user's givenName and familyName", () =>
|
|
357
|
-
webex.internal.user.updateName({givenName: 'T', familyName: 'Rex'}).then((user) => {
|
|
358
|
-
assert.equal(user.id, webex.internal.device.userId);
|
|
359
|
-
assert.property(user, 'name');
|
|
360
|
-
assert.property(user.name, 'givenName');
|
|
361
|
-
assert.property(user.name, 'familyName');
|
|
362
|
-
assert.equal(user.name.givenName, 'T');
|
|
363
|
-
assert.equal(user.name.familyName, 'Rex');
|
|
364
|
-
}));
|
|
365
|
-
it("updates a user's givenName familyName and displayName", () =>
|
|
366
|
-
webex.internal.user
|
|
367
|
-
.updateName({givenName: 'Max', familyName: 'Bob', displayName: 'Max Bob'})
|
|
368
|
-
.then((user) => {
|
|
369
|
-
assert.equal(user.id, webex.internal.device.userId);
|
|
370
|
-
assert.property(user, 'displayName');
|
|
371
|
-
assert.equal(user.displayName, 'Max Bob');
|
|
372
|
-
assert.property(user, 'name');
|
|
373
|
-
assert.property(user.name, 'givenName');
|
|
374
|
-
assert.property(user.name, 'familyName');
|
|
375
|
-
assert.equal(user.name.givenName, 'Max');
|
|
376
|
-
assert.equal(user.name.familyName, 'Bob');
|
|
377
|
-
}));
|
|
378
|
-
});
|
|
379
|
-
});
|
|
380
|
-
});
|
|
1
|
+
/*!
|
|
2
|
+
* Copyright (c) 2015-2020 Cisco Systems, Inc. See LICENSE file.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import '@webex/internal-plugin-user';
|
|
6
|
+
|
|
7
|
+
import querystring from 'querystring';
|
|
8
|
+
import url from 'url';
|
|
9
|
+
|
|
10
|
+
import {assert} from '@webex/test-helper-chai';
|
|
11
|
+
import sinon from 'sinon';
|
|
12
|
+
import WebexCore from '@webex/webex-core';
|
|
13
|
+
import testUsers from '@webex/test-helper-test-users';
|
|
14
|
+
import {patterns} from '@webex/common';
|
|
15
|
+
import uuid from 'uuid';
|
|
16
|
+
import {merge} from 'lodash';
|
|
17
|
+
|
|
18
|
+
// Run the tests with and without Federation enabled,
|
|
19
|
+
// for test users in EU (Federation) and US
|
|
20
|
+
// Also try US user with Federation enabled
|
|
21
|
+
const runs = [
|
|
22
|
+
// This line can be ommited until a future pull request is generated to update @ciscospark/test-users-legacy
|
|
23
|
+
// {it: 'with EU user with Federation enabled', EUUser: true, attrs: {config: {credentials: {federation: true}}}},
|
|
24
|
+
{it: 'with US user without Federation enabled', EUUser: false, attrs: {}},
|
|
25
|
+
{
|
|
26
|
+
it: 'with US user with Federation enabled',
|
|
27
|
+
EUUser: false,
|
|
28
|
+
attrs: {config: {credentials: {federation: true}}},
|
|
29
|
+
},
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
runs.forEach((run) => {
|
|
33
|
+
describe(`plugin-user ${run.it}`, function () {
|
|
34
|
+
this.timeout(30000);
|
|
35
|
+
|
|
36
|
+
let webex, user1, user2, user3;
|
|
37
|
+
|
|
38
|
+
const testUserParm = {count: 3};
|
|
39
|
+
|
|
40
|
+
if (run.EUUser) {
|
|
41
|
+
testUserParm.config = {orgId: process.env.EU_PRIMARY_ORG_ID};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
before(() =>
|
|
45
|
+
testUsers.create(testUserParm).then((users) => {
|
|
46
|
+
user1 = users[0];
|
|
47
|
+
user2 = users[1];
|
|
48
|
+
user3 = users[2];
|
|
49
|
+
webex = new WebexCore(
|
|
50
|
+
merge({}, run.attrs, {
|
|
51
|
+
credentials: {
|
|
52
|
+
supertoken: user1.token,
|
|
53
|
+
},
|
|
54
|
+
})
|
|
55
|
+
);
|
|
56
|
+
assert.isDefined(webex.credentials.supertoken);
|
|
57
|
+
assert.isTrue(webex.canAuthorize);
|
|
58
|
+
assert.isFalse(webex.internal.user.hasPassword);
|
|
59
|
+
|
|
60
|
+
return webex.internal.device.register();
|
|
61
|
+
})
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
describe('#verify()', () => {
|
|
65
|
+
const unauthWebex = new WebexCore(run.attrs);
|
|
66
|
+
|
|
67
|
+
it('registers a new user', () =>
|
|
68
|
+
unauthWebex.internal.user
|
|
69
|
+
.verify({email: `Collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`})
|
|
70
|
+
.then((res) => {
|
|
71
|
+
assert.property(res, 'hasPassword');
|
|
72
|
+
assert.property(res, 'verificationEmailTriggered');
|
|
73
|
+
assert.property(res, 'sso');
|
|
74
|
+
assert.isFalse(res.hasPassword);
|
|
75
|
+
assert.isTrue(res.verificationEmailTriggered);
|
|
76
|
+
assert.isFalse(res.sso);
|
|
77
|
+
assert.isFalse(webex.internal.user.hasPassword);
|
|
78
|
+
}));
|
|
79
|
+
|
|
80
|
+
it('verifies an existing user', () =>
|
|
81
|
+
unauthWebex.internal.user.verify({email: user1.email}).then((res) => {
|
|
82
|
+
assert.property(res, 'hasPassword');
|
|
83
|
+
assert.property(res, 'verificationEmailTriggered');
|
|
84
|
+
assert.property(res, 'sso');
|
|
85
|
+
assert.isTrue(res.hasPassword);
|
|
86
|
+
assert.isFalse(res.verificationEmailTriggered);
|
|
87
|
+
assert.isFalse(res.sso);
|
|
88
|
+
assert.isTrue(unauthWebex.internal.user.hasPassword);
|
|
89
|
+
}));
|
|
90
|
+
|
|
91
|
+
it('leaves email address validation up to Atlas', () =>
|
|
92
|
+
assert
|
|
93
|
+
.isRejected(unauthWebex.internal.user.verify({email: 'not an email address'}))
|
|
94
|
+
.then((res) => assert.statusCode(res, 400)));
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
describe('#setPassword()', () => {
|
|
98
|
+
it("sets the user's password", () =>
|
|
99
|
+
webex.internal.user
|
|
100
|
+
.setPassword({password: 'P@ssword123'})
|
|
101
|
+
.then(() => webex.internal.user.verify({email: user1.email}))
|
|
102
|
+
.then((res) => {
|
|
103
|
+
assert.property(res, 'hasPassword');
|
|
104
|
+
assert.property(res, 'verificationEmailTriggered');
|
|
105
|
+
assert.property(res, 'sso');
|
|
106
|
+
assert.isTrue(res.hasPassword);
|
|
107
|
+
assert.isFalse(res.verificationEmailTriggered);
|
|
108
|
+
assert.isFalse(res.sso);
|
|
109
|
+
assert.isTrue(webex.internal.user.hasPassword);
|
|
110
|
+
}));
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
// NOTE: need collabctg+*@gmail.com to get verifyEmailURL
|
|
114
|
+
describe('#activate()', () => {
|
|
115
|
+
const unauthWebex = new WebexCore(run.attrs);
|
|
116
|
+
|
|
117
|
+
it('retrieves a valid user token', () => {
|
|
118
|
+
assert.isUndefined(unauthWebex.credentials.supertoken);
|
|
119
|
+
const email = `collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`;
|
|
120
|
+
|
|
121
|
+
return unauthWebex.internal.user
|
|
122
|
+
.verify({email})
|
|
123
|
+
.then((res) => {
|
|
124
|
+
assert.isTrue(res.verificationEmailTriggered);
|
|
125
|
+
assert.property(res, 'verifyEmailURL');
|
|
126
|
+
const {query} = url.parse(res.verifyEmailURL);
|
|
127
|
+
const token = querystring.parse(query).t;
|
|
128
|
+
|
|
129
|
+
return unauthWebex.internal.user.activate({email, verificationToken: token});
|
|
130
|
+
})
|
|
131
|
+
.then((res) => {
|
|
132
|
+
assert.property(res, 'email');
|
|
133
|
+
assert.property(res, 'tokenData');
|
|
134
|
+
assert.equal(res.email, email);
|
|
135
|
+
assert.isDefined(unauthWebex.credentials.supertoken.access_token);
|
|
136
|
+
|
|
137
|
+
return unauthWebex.internal.user.verify({email});
|
|
138
|
+
})
|
|
139
|
+
.then((res) => {
|
|
140
|
+
// verification email should not trigger if already have valid user token
|
|
141
|
+
assert.property(res, 'hasPassword');
|
|
142
|
+
assert.property(res, 'verificationEmailTriggered');
|
|
143
|
+
assert.property(res, 'sso');
|
|
144
|
+
assert.isFalse(res.hasPassword);
|
|
145
|
+
assert.isFalse(res.verificationEmailTriggered);
|
|
146
|
+
assert.isFalse(res.sso);
|
|
147
|
+
assert.isFalse(unauthWebex.internal.user.hasPassword);
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('retrieves a valid user token and sets the password', () => {
|
|
152
|
+
const unauthWebex = new WebexCore(run.attrs);
|
|
153
|
+
|
|
154
|
+
assert.isUndefined(unauthWebex.credentials.supertoken);
|
|
155
|
+
const email = `collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`;
|
|
156
|
+
|
|
157
|
+
return unauthWebex.internal.user
|
|
158
|
+
.verify({email})
|
|
159
|
+
.then((res) => {
|
|
160
|
+
assert.isTrue(res.verificationEmailTriggered);
|
|
161
|
+
assert.property(res, 'verifyEmailURL');
|
|
162
|
+
const {query} = url.parse(res.verifyEmailURL);
|
|
163
|
+
const token = querystring.parse(query).t;
|
|
164
|
+
|
|
165
|
+
return unauthWebex.internal.user.activate({email, verificationToken: token});
|
|
166
|
+
})
|
|
167
|
+
.then((res) => {
|
|
168
|
+
assert.property(res, 'email');
|
|
169
|
+
assert.property(res, 'tokenData');
|
|
170
|
+
assert.equal(res.email, email);
|
|
171
|
+
assert.isDefined(unauthWebex.credentials.supertoken.access_token);
|
|
172
|
+
})
|
|
173
|
+
.then(() => unauthWebex.internal.device.register())
|
|
174
|
+
.then(() => unauthWebex.internal.user.get())
|
|
175
|
+
.then((user) =>
|
|
176
|
+
unauthWebex.internal.user.setPassword({email: user.email, password: 'P@ssword123'})
|
|
177
|
+
)
|
|
178
|
+
.then(() => unauthWebex.internal.user.verify({email}))
|
|
179
|
+
.then((res) => {
|
|
180
|
+
assert.property(res, 'hasPassword');
|
|
181
|
+
assert.property(res, 'verificationEmailTriggered');
|
|
182
|
+
assert.property(res, 'sso');
|
|
183
|
+
assert.isTrue(res.hasPassword);
|
|
184
|
+
assert.isFalse(res.verificationEmailTriggered);
|
|
185
|
+
assert.isFalse(res.sso);
|
|
186
|
+
assert.isTrue(unauthWebex.internal.user.hasPassword);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
describe('#generateOTP() and #validateOTP()', () => {
|
|
192
|
+
it('generates and validates OTP', () => {
|
|
193
|
+
const unauthWebex = new WebexCore(run.attrs);
|
|
194
|
+
|
|
195
|
+
assert.isUndefined(unauthWebex.credentials.supertoken);
|
|
196
|
+
// NOTE: need collabctg+*@gmail.com to get oneTimePassword
|
|
197
|
+
const email = `collabctg+webex-js-sdk-${uuid.v4()}@gmail.com`;
|
|
198
|
+
|
|
199
|
+
return unauthWebex.internal.user
|
|
200
|
+
.verify({email})
|
|
201
|
+
.then((res) => {
|
|
202
|
+
const {query} = url.parse(res.verifyEmailURL);
|
|
203
|
+
const token = querystring.parse(query).t;
|
|
204
|
+
|
|
205
|
+
return unauthWebex.internal.user.activate({email, verificationToken: token});
|
|
206
|
+
})
|
|
207
|
+
.then(() => unauthWebex.internal.device.register())
|
|
208
|
+
.then(() => unauthWebex.internal.user.get())
|
|
209
|
+
.then((user) =>
|
|
210
|
+
unauthWebex.internal.user.setPassword({email: user.email, password: 'P@ssword123'})
|
|
211
|
+
)
|
|
212
|
+
.then(() => unauthWebex.internal.user.verify({email}))
|
|
213
|
+
.then(() => unauthWebex.internal.user.generateOTP({email}))
|
|
214
|
+
.then((res) => {
|
|
215
|
+
assert.property(res, 'oneTimePassword');
|
|
216
|
+
assert.property(res, 'email');
|
|
217
|
+
assert.equal(res.email, email);
|
|
218
|
+
assert.property(res, 'id');
|
|
219
|
+
assert.property(res, 'url');
|
|
220
|
+
assert.property(res, 'status');
|
|
221
|
+
|
|
222
|
+
return unauthWebex.internal.user.validateOTP({
|
|
223
|
+
email,
|
|
224
|
+
oneTimePassword: res.oneTimePassword,
|
|
225
|
+
});
|
|
226
|
+
})
|
|
227
|
+
.then((res) => {
|
|
228
|
+
assert.property(res, 'email');
|
|
229
|
+
assert.property(res, 'id');
|
|
230
|
+
assert.property(res, 'url');
|
|
231
|
+
assert.property(res, 'tokenData');
|
|
232
|
+
assert.equal(res.email, email);
|
|
233
|
+
assert.equal(res.tokenData.token_type, unauthWebex.credentials.supertoken.token_type);
|
|
234
|
+
assert.equal(res.tokenData.expires_in, unauthWebex.credentials.supertoken.expires_in);
|
|
235
|
+
assert.equal(
|
|
236
|
+
res.tokenData.access_token,
|
|
237
|
+
unauthWebex.credentials.supertoken.access_token
|
|
238
|
+
);
|
|
239
|
+
assert.equal(
|
|
240
|
+
res.tokenData.refresh_token_expires_in,
|
|
241
|
+
unauthWebex.credentials.supertoken.refresh_token_expires_in
|
|
242
|
+
);
|
|
243
|
+
});
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
describe('#get()', () => {
|
|
248
|
+
it('gets the current user', () =>
|
|
249
|
+
webex.internal.user.get().then((user) => {
|
|
250
|
+
assert.equal(user.id, webex.internal.device.userId);
|
|
251
|
+
assert.property(user, 'entitlements');
|
|
252
|
+
assert.property(user, 'email');
|
|
253
|
+
assert.property(user, 'name');
|
|
254
|
+
}));
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
describe('#asUUID()', () => {
|
|
258
|
+
function makeEmailAddress() {
|
|
259
|
+
return `webex-js-sdk--test-${uuid.v4()}@example.com`;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
let email;
|
|
263
|
+
|
|
264
|
+
beforeEach(() => {
|
|
265
|
+
email = makeEmailAddress();
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it('maps an email address to a uuid', () =>
|
|
269
|
+
webex.internal.user
|
|
270
|
+
.asUUID(user2, {force: true})
|
|
271
|
+
.then((result) => assert.equal(result, user2.id)));
|
|
272
|
+
|
|
273
|
+
it('maps an email address for a non-existent user to a fake uuid', () =>
|
|
274
|
+
webex.internal.user
|
|
275
|
+
.asUUID(email)
|
|
276
|
+
.then((result) => assert.match(result, patterns.uuid))
|
|
277
|
+
.then(() => webex.internal.user.store.getByEmail(email))
|
|
278
|
+
.then((u) => assert.isFalse(u.userExists, 'User does not exist')));
|
|
279
|
+
|
|
280
|
+
describe('with {create: true}', () => {
|
|
281
|
+
let spy;
|
|
282
|
+
|
|
283
|
+
beforeEach(() => {
|
|
284
|
+
spy = sinon.spy(webex.internal.user, 'fetchUUID');
|
|
285
|
+
});
|
|
286
|
+
afterEach(() => spy.restore());
|
|
287
|
+
|
|
288
|
+
it('creates a new user', () =>
|
|
289
|
+
webex.internal.user
|
|
290
|
+
.asUUID(email, {create: true})
|
|
291
|
+
.then((result) => assert.match(result, patterns.uuid))
|
|
292
|
+
.then(() => webex.internal.user.store.getByEmail(email))
|
|
293
|
+
.then((u) => assert.isTrue(u.userExists, 'User exists')));
|
|
294
|
+
|
|
295
|
+
it('does not use a cached value if the previous value was marked as non-existent', () =>
|
|
296
|
+
webex.internal.user
|
|
297
|
+
.asUUID(email)
|
|
298
|
+
.then((result) => assert.match(result, patterns.uuid))
|
|
299
|
+
.then(() => webex.internal.user.store.getByEmail(email))
|
|
300
|
+
.then((u) => assert.isFalse(u.userExists, 'User does not exist'))
|
|
301
|
+
.then(() => webex.internal.user.asUUID(email, {create: true}), patterns.uuid)
|
|
302
|
+
.then(() => webex.internal.user.store.getByEmail(email))
|
|
303
|
+
.then((u) => assert.isTrue(u.userExists, 'User exists'))
|
|
304
|
+
.then(() => assert.calledTwice(spy)));
|
|
305
|
+
|
|
306
|
+
it("does not use a cached value if the previous value's existence is unknown", () =>
|
|
307
|
+
webex.internal.user
|
|
308
|
+
.recordUUID({
|
|
309
|
+
id: user3.id,
|
|
310
|
+
emailAddress: user3.email,
|
|
311
|
+
})
|
|
312
|
+
.then(() => webex.internal.user.store.getByEmail(user3.email))
|
|
313
|
+
.then((user) => assert.isUndefined(user.userExists, "User's existence is unknown"))
|
|
314
|
+
.then(() =>
|
|
315
|
+
webex.internal.user
|
|
316
|
+
.asUUID(user3.email, {create: true})
|
|
317
|
+
.then((result) => assert.equal(result, user3.id))
|
|
318
|
+
)
|
|
319
|
+
.then(() => assert.called(spy))
|
|
320
|
+
.then(() => webex.internal.user.store.getByEmail(user3.email))
|
|
321
|
+
.then((user) => assert.isTrue(user.userExists, 'User exists')));
|
|
322
|
+
});
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
describe('#update()', () => {
|
|
326
|
+
it("updates a user's name", () =>
|
|
327
|
+
webex.internal.user.update({displayName: 'New Display Name'}).then((user) => {
|
|
328
|
+
assert.equal(user.id, webex.internal.device.userId);
|
|
329
|
+
assert.property(user, 'entitlements');
|
|
330
|
+
assert.property(user, 'email');
|
|
331
|
+
assert.property(user, 'name');
|
|
332
|
+
assert.equal(user.name, 'New Display Name');
|
|
333
|
+
}));
|
|
334
|
+
});
|
|
335
|
+
describe('#updateName()', () => {
|
|
336
|
+
it("updates a user's displayName", () =>
|
|
337
|
+
webex.internal.user.updateName({displayName: 'New Name'}).then((user) => {
|
|
338
|
+
assert.equal(user.id, webex.internal.device.userId);
|
|
339
|
+
assert.property(user, 'displayName');
|
|
340
|
+
assert.equal(user.displayName, 'New Name');
|
|
341
|
+
}));
|
|
342
|
+
it("updates a user's givenName", () =>
|
|
343
|
+
webex.internal.user.updateName({givenName: 'Jack'}).then((user) => {
|
|
344
|
+
assert.equal(user.id, webex.internal.device.userId);
|
|
345
|
+
assert.property(user, 'name');
|
|
346
|
+
assert.property(user.name, 'givenName');
|
|
347
|
+
assert.equal(user.name.givenName, 'Jack');
|
|
348
|
+
}));
|
|
349
|
+
it("updates a user's familyName", () =>
|
|
350
|
+
webex.internal.user.updateName({familyName: 'Jill'}).then((user) => {
|
|
351
|
+
assert.equal(user.id, webex.internal.device.userId);
|
|
352
|
+
assert.property(user, 'name');
|
|
353
|
+
assert.property(user.name, 'familyName');
|
|
354
|
+
assert.equal(user.name.familyName, 'Jill');
|
|
355
|
+
}));
|
|
356
|
+
it("updates a user's givenName and familyName", () =>
|
|
357
|
+
webex.internal.user.updateName({givenName: 'T', familyName: 'Rex'}).then((user) => {
|
|
358
|
+
assert.equal(user.id, webex.internal.device.userId);
|
|
359
|
+
assert.property(user, 'name');
|
|
360
|
+
assert.property(user.name, 'givenName');
|
|
361
|
+
assert.property(user.name, 'familyName');
|
|
362
|
+
assert.equal(user.name.givenName, 'T');
|
|
363
|
+
assert.equal(user.name.familyName, 'Rex');
|
|
364
|
+
}));
|
|
365
|
+
it("updates a user's givenName familyName and displayName", () =>
|
|
366
|
+
webex.internal.user
|
|
367
|
+
.updateName({givenName: 'Max', familyName: 'Bob', displayName: 'Max Bob'})
|
|
368
|
+
.then((user) => {
|
|
369
|
+
assert.equal(user.id, webex.internal.device.userId);
|
|
370
|
+
assert.property(user, 'displayName');
|
|
371
|
+
assert.equal(user.displayName, 'Max Bob');
|
|
372
|
+
assert.property(user, 'name');
|
|
373
|
+
assert.property(user.name, 'givenName');
|
|
374
|
+
assert.property(user.name, 'familyName');
|
|
375
|
+
assert.equal(user.name.givenName, 'Max');
|
|
376
|
+
assert.equal(user.name.familyName, 'Bob');
|
|
377
|
+
}));
|
|
378
|
+
});
|
|
379
|
+
});
|
|
380
|
+
});
|