@qikdev/sdk 0.1.169 → 0.1.170

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.
Files changed (71) hide show
  1. package/.gitlab-ci.yml +24 -0
  2. package/.husky/pre-commit +5 -0
  3. package/eslint.config.js +6 -0
  4. package/jsdoc.conf +10 -0
  5. package/package.json +2 -12
  6. package/public/docs/access.html +3826 -0
  7. package/public/docs/api.html +1356 -0
  8. package/public/docs/auth.html +2180 -0
  9. package/public/docs/cache.html +351 -0
  10. package/public/docs/content.html +2560 -0
  11. package/public/docs/files.html +779 -0
  12. package/public/docs/filter.html +1355 -0
  13. package/public/docs/fonts/Montserrat/Montserrat-Bold.eot +0 -0
  14. package/public/docs/fonts/Montserrat/Montserrat-Bold.ttf +0 -0
  15. package/public/docs/fonts/Montserrat/Montserrat-Bold.woff +0 -0
  16. package/public/docs/fonts/Montserrat/Montserrat-Bold.woff2 +0 -0
  17. package/public/docs/fonts/Montserrat/Montserrat-Regular.eot +0 -0
  18. package/public/docs/fonts/Montserrat/Montserrat-Regular.ttf +0 -0
  19. package/public/docs/fonts/Montserrat/Montserrat-Regular.woff +0 -0
  20. package/public/docs/fonts/Montserrat/Montserrat-Regular.woff2 +0 -0
  21. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.eot +0 -0
  22. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +978 -0
  23. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.ttf +0 -0
  24. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff +0 -0
  25. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.woff2 +0 -0
  26. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.eot +0 -0
  27. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1049 -0
  28. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.ttf +0 -0
  29. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff +0 -0
  30. package/public/docs/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.woff2 +0 -0
  31. package/public/docs/index.html +96 -0
  32. package/public/docs/qik.access.js.html +790 -0
  33. package/public/docs/qik.api.js.html +511 -0
  34. package/public/docs/qik.auth.js.html +1006 -0
  35. package/public/docs/qik.cache.js.html +131 -0
  36. package/public/docs/qik.content.js.html +918 -0
  37. package/public/docs/qik.core.js.html +301 -0
  38. package/public/docs/qik.files.js.html +219 -0
  39. package/public/docs/qik.filter.js.html +611 -0
  40. package/public/docs/qik.socket.js.html +416 -0
  41. package/public/docs/qik.system.js.html +117 -0
  42. package/public/docs/qik.utils.js.html +1467 -0
  43. package/public/docs/scripts/collapse.js +20 -0
  44. package/public/docs/scripts/linenumber.js +25 -0
  45. package/public/docs/scripts/nav.js +12 -0
  46. package/public/docs/scripts/polyfill.js +4 -0
  47. package/public/docs/scripts/prettify/Apache-License-2.0.txt +202 -0
  48. package/public/docs/scripts/prettify/lang-css.js +2 -0
  49. package/public/docs/scripts/prettify/prettify.js +28 -0
  50. package/public/docs/scripts/search.js +83 -0
  51. package/public/docs/socket.html +810 -0
  52. package/public/docs/styles/jsdoc.css +765 -0
  53. package/public/docs/styles/prettify.css +79 -0
  54. package/public/docs/system.html +197 -0
  55. package/src/api/qik.access.js +825 -0
  56. package/src/api/qik.api.js +431 -0
  57. package/src/api/qik.auth.js +881 -0
  58. package/src/api/qik.cache.js +63 -0
  59. package/src/api/qik.content.js +839 -0
  60. package/src/api/qik.core.js +245 -0
  61. package/src/api/qik.files.js +186 -0
  62. package/src/api/qik.filter.js +543 -0
  63. package/src/api/qik.geo.js +895 -0
  64. package/src/api/qik.socket.js +360 -0
  65. package/src/api/qik.system.js +49 -0
  66. package/src/api/qik.utils.js +1412 -0
  67. package/src/index.js +20 -0
  68. package/src/version.js +1 -0
  69. package/test/index.spec.js +41 -0
  70. package/test/mocha.opts +0 -0
  71. package/yarn-error.log +3598 -0
@@ -0,0 +1,1006 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+
5
+ <meta charset="utf-8">
6
+ <title>qik.auth.js - Documentation</title>
7
+
8
+
9
+ <script src="scripts/prettify/prettify.js"></script>
10
+ <script src="scripts/prettify/lang-css.js"></script>
11
+ <!--[if lt IE 9]>
12
+ <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
13
+ <![endif]-->
14
+ <link type="text/css" rel="stylesheet" href="styles/prettify.css">
15
+ <link type="text/css" rel="stylesheet" href="styles/jsdoc.css">
16
+ <script src="scripts/nav.js" defer></script>
17
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
18
+ </head>
19
+ <body>
20
+
21
+ <input type="checkbox" id="nav-trigger" class="nav-trigger" />
22
+ <label for="nav-trigger" class="navicon-button x">
23
+ <div class="navicon"></div>
24
+ </label>
25
+
26
+ <label for="nav-trigger" class="overlay"></label>
27
+
28
+ <nav >
29
+
30
+ <h2><a href="index.html">Home</a></h2><h3>Classes</h3><ul><li><a href="access.html">access</a><ul class='methods'><li data-type='method'><a href="access.html#.actionableScopes">actionableScopes</a></li><li data-type='method'><a href="access.html#.allPermissions">allPermissions</a></li><li data-type='method'><a href="access.html#.allPermissionTypes">allPermissionTypes</a></li><li data-type='method'><a href="access.html#.allUserScopes">allUserScopes</a></li><li data-type='method'><a href="access.html#.canCreate">canCreate</a></li><li data-type='method'><a href="access.html#.canDeleteItem">canDeleteItem</a></li><li data-type='method'><a href="access.html#.canEditItem">canEditItem</a></li><li data-type='method'><a href="access.html#.canEraseItem">canEraseItem</a></li><li data-type='method'><a href="access.html#.canKnowOf">canKnowOf</a></li><li data-type='method'><a href="access.html#.canListItem">canListItem</a></li><li data-type='method'><a href="access.html#.canRestoreItem">canRestoreItem</a></li><li data-type='method'><a href="access.html#.canViewItem">canViewItem</a></li><li data-type='method'><a href="access.html#.checkActionAccess">checkActionAccess</a></li><li data-type='method'><a href="access.html#.getAllDescendants">getAllDescendants</a></li><li data-type='method'><a href="access.html#.has">has</a></li><li data-type='method'><a href="access.html#.hashPermissions">hashPermissions</a></li><li data-type='method'><a href="access.html#.isAdministrator">isAdministrator</a></li><li data-type='method'><a href="access.html#.isOwner">isOwner</a></li></ul></li><li><a href="api.html">api</a><ul class='methods'><li data-type='method'><a href="api.html#.delete">delete</a></li><li data-type='method'><a href="api.html#.generateEndpointURL">generateEndpointURL</a></li><li data-type='method'><a href="api.html#.get">get</a></li><li data-type='method'><a href="api.html#.patch">patch</a></li><li data-type='method'><a href="api.html#.post">post</a></li><li data-type='method'><a href="api.html#.put">put</a></li></ul></li><li><a href="auth.html">auth</a><ul class='methods'><li data-type='method'><a href="auth.html#.changeOrganisation">changeOrganisation</a></li><li data-type='method'><a href="auth.html#.ensureValidToken">ensureValidToken</a></li><li data-type='method'><a href="auth.html#.getCurrentToken">getCurrentToken</a></li><li data-type='method'><a href="auth.html#.getCurrentUser">getCurrentUser</a></li><li data-type='method'><a href="auth.html#.impersonate">impersonate</a></li><li data-type='method'><a href="auth.html#.login">login</a></li><li data-type='method'><a href="auth.html#.logout">logout</a></li><li data-type='method'><a href="auth.html#.retrieveUserFromResetToken">retrieveUserFromResetToken</a></li><li data-type='method'><a href="auth.html#.sendResetPasswordRequest">sendResetPasswordRequest</a></li><li data-type='method'><a href="auth.html#.set">set</a></li><li data-type='method'><a href="auth.html#.sync">sync</a></li><li data-type='method'><a href="auth.html#.updateUserWithToken">updateUserWithToken</a></li></ul></li><li><a href="cache.html">cache</a><ul class='methods'><li data-type='method'><a href="cache.html#.get">get</a></li><li data-type='method'><a href="cache.html#.reset">reset</a></li></ul></li><li><a href="content.html">content</a><ul class='methods'><li data-type='method'><a href="content.html#.create">create</a></li><li data-type='method'><a href="content.html#.delete">delete</a></li><li data-type='method'><a href="content.html#.get">get</a></li><li data-type='method'><a href="content.html#.getFromSlug">getFromSlug</a></li><li data-type='method'><a href="content.html#.glossary">glossary</a></li><li data-type='method'><a href="content.html#.list">list</a></li><li data-type='method'><a href="content.html#.patch">patch</a></li><li data-type='method'><a href="content.html#.restore">restore</a></li><li data-type='method'><a href="content.html#.scopeGlossary">scopeGlossary</a></li><li data-type='method'><a href="content.html#.update">update</a></li><li data-type='method'><a href="content.html#.validateField">validateField</a></li><li data-type='method'><a href="content.html#.variables">variables</a></li></ul></li><li><a href="files.html">files</a><ul class='methods'><li data-type='method'><a href="files.html#.downloadUrl">downloadUrl</a></li><li data-type='method'><a href="files.html#.filesize">filesize</a></li><li data-type='method'><a href="files.html#.getBinaryTypeFromMime">getBinaryTypeFromMime</a></li><li data-type='method'><a href="files.html#.mediaUrl">mediaUrl</a></li></ul></li><li><a href="filter.html">filter</a><ul class='methods'><li data-type='method'><a href="filter.html#.activeFilterKeys">activeFilterKeys</a></li><li data-type='method'><a href="filter.html#.activeFilterKeys">activeFilterKeys</a></li><li data-type='method'><a href="filter.html#.activeFilterOperators">activeFilterOperators</a></li><li data-type='method'><a href="filter.html#.activeFilters">activeFilters</a></li><li data-type='method'><a href="filter.html#.activeFilterValues">activeFilterValues</a></li><li data-type='method'><a href="filter.html#.filterChangeString">filterChangeString</a></li><li data-type='method'><a href="filter.html#.isValidFilter">isValidFilter</a></li></ul></li><li><a href="socket.html">socket</a><ul class='methods'><li data-type='method'><a href="socket.html#.channel">channel</a></li><li data-type='method'><a href="socket.html#.close">close</a></li><li data-type='method'><a href="socket.html#.connect">connect</a></li><li data-type='method'><a href="socket.html#.reconnect">reconnect</a></li><li data-type='method'><a href="socket.html#.subscribe">subscribe</a></li><li data-type='method'><a href="socket.html#.unsubscribe">unsubscribe</a></li></ul></li><li><a href="system.html">system</a><ul class='methods'><li data-type='method'><a href="system.html#.countries">countries</a></li></ul></li></ul>
31
+ </nav>
32
+
33
+ <div id="main">
34
+
35
+ <h1 class="page-title">qik.auth.js</h1>
36
+
37
+
38
+
39
+
40
+
41
+
42
+
43
+ <section>
44
+ <article>
45
+ <pre class="prettyprint source linenums"><code>import axios from 'axios';
46
+ import { EventDispatcher } from './qik.utils.js';
47
+
48
+ ///////////////////////////////////////////////////
49
+
50
+ /**
51
+ * Creates a new instance of QikAuth a module of the SDK
52
+ * that contains all helper functions to do with authentication and user session management
53
+ * @alias auth
54
+ * @constructor
55
+ * @hideconstructor
56
+ * @param {QikAPI} qik A reference to the parent instance of the QikCore module. This module is usually created by a QikCore instance that passes itself in as the first argument.
57
+ */
58
+
59
+ var QikAuth = function(qik) {
60
+
61
+ if (!qik.api) {
62
+ throw new Error(`Please ensure that QikAPI exists before QikAuth`);
63
+ }
64
+
65
+ //Keep track of any refresh requests
66
+ var inflightRefreshRequest;
67
+
68
+ ///////////////////////////////////////////////////
69
+
70
+ var sessionStorage = {};
71
+ var store = sessionStorage;
72
+ const tokenBufferSeconds = 10;
73
+
74
+ ///////////////////////////////////////////////////
75
+
76
+ const service = {
77
+ debug: false,
78
+ }
79
+
80
+ Object.defineProperty(service, 'store', {
81
+ value: store,
82
+ writable: false,
83
+ });
84
+
85
+ //Create a new dispatcher
86
+ const dispatcher = new EventDispatcher();
87
+ dispatcher.bootstrap(service);
88
+
89
+ ///////////////////////////////////////////////////
90
+
91
+ function dispatch(parameters) {
92
+
93
+ //Get the current user
94
+ var user = store.user;
95
+
96
+ //Dispatch the change to the listeners
97
+ if (service.onChange) {
98
+ service.onChange(user);
99
+ }
100
+
101
+ //Dispatch the change event
102
+ dispatcher.dispatch('change', user, parameters);
103
+ }
104
+
105
+
106
+ ///////////////////////////////////////////////////
107
+
108
+ /**
109
+ * @alias auth.set
110
+ * @description Manually set current user session
111
+ * @param {Object} user The user session object to set as the current user session
112
+ * @param {Object} parameters Additional parameters to dispatch
113
+ * @param {Boolean} stopDispatch Whether to supress dispatching a 'change' event.
114
+ * @example
115
+ *
116
+ * const userSession = {_id:'61eca4746971e75c1fc670cf', firstName:'Daffy', lastName:'Duck' ...};
117
+ * sdk.auth.set(userSession);
118
+ */
119
+
120
+ service.set = function(user, parameters, stopDispatch) {
121
+
122
+ if (JSON.stringify(store.user) != JSON.stringify(user)) {
123
+ store.user = user;
124
+ if (!stopDispatch) {
125
+ return dispatch(parameters)
126
+ }
127
+ }
128
+
129
+ }
130
+
131
+
132
+ ///////////////////////////////////////////////////
133
+
134
+ /**
135
+ * @alias auth.logout
136
+ * @description Clear the current user session from memory and erase all caches
137
+ * @example
138
+ * sdk.auth.logout();
139
+ */
140
+
141
+ service.logout = function() {
142
+ delete store.user;
143
+ qik.cache.reset();
144
+ return dispatch()
145
+ }
146
+
147
+ ///////////////////////////////////////////////////
148
+
149
+ /**
150
+ * @alias auth.changeOrganisation
151
+ * @description Manually set current user session
152
+ * @param {(String|Object)} organisation The id of the organisation to switch into
153
+ * @param {Object} options Additional options
154
+ * @param {Boolean} options.disableAutoAuthentication By default when switching organisation, the current user session
155
+ * will be updated to reflect a session in the new organisation, you can use this option to disable that behavior and instead return the
156
+ * user session without dispatching any events
157
+ * @example
158
+ *
159
+ * sdk.auth.changeOrganisation('61eca4746971e75c1fc670cf');
160
+ * // Current user session will be automatically updated
161
+ *
162
+ * const newSession = await sdk.auth.changeOrganisation('61eca4746971e75c1fc670cf', {disableAutoAuthentication:true});
163
+ * // Current user session will not be updated
164
+ * sdk.auth.set(newSession);
165
+ */
166
+ service.changeOrganisation = function(organisationID, options) {
167
+
168
+ //Ensure we just have the ID
169
+ organisationID = qik.utils.id(organisationID);
170
+
171
+ //////////////////////////
172
+
173
+ if (!options) {
174
+ options = {};
175
+ }
176
+
177
+ //////////////////////////
178
+
179
+ //Change the users current tokens straight away
180
+ var autoAuthenticate = true;
181
+
182
+ if (options.disableAutoAuthentication) {
183
+ autoAuthenticate = false;
184
+ }
185
+
186
+ //////////////////////////
187
+
188
+ return new Promise(function(resolve, reject) {
189
+
190
+
191
+ qik.api.post(`/user/switch/${organisationID}`)
192
+ .then(function(response) {
193
+
194
+ if (autoAuthenticate) {
195
+ qik.cache.reset();
196
+ service.set(response.data);
197
+ }
198
+
199
+ resolve(response.data);
200
+ })
201
+ .catch(reject)
202
+
203
+ })
204
+ }
205
+
206
+ ///////////////////////////////////////////////////
207
+
208
+ /**
209
+ * @alias auth.impersonate
210
+ * @description Impersonate another user within your organisation
211
+ * @param {(String|Object)} persona The id of the user persona you want to impersonate
212
+ * @param {Object} options Additional options
213
+ * @param {Boolean} options.disableAutoAuthentication By default when impersonating a user, the current user session
214
+ * will be updated automatically to reflect the new session, you can use this option to disable that behavior and instead return the
215
+ * new impersonation user session without dispatching any events
216
+ * @example
217
+ *
218
+ * sdk.auth.impersonate('61eca4746971e75c1fc670cf');
219
+ * // Current user session will be automatically updated
220
+ *
221
+ * const newSession = await sdk.auth.impersonate('61eca4746971e75c1fc670cf', {disableAutoAuthentication:true});
222
+ * // Current user session will not be updated
223
+ * sdk.auth.set(newSession);
224
+ */
225
+ service.impersonate = function(personaID, options) {
226
+
227
+ //Ensure we just have the ID
228
+ personaID = qik.utils.id(personaID);
229
+
230
+ //////////////////////////
231
+
232
+ if (!options) {
233
+ options = {};
234
+ }
235
+
236
+ //////////////////////////
237
+
238
+ //Change the users current tokens straight away
239
+ var autoAuthenticate = true;
240
+
241
+ if (options.disableAutoAuthentication) {
242
+ autoAuthenticate = false;
243
+ }
244
+
245
+ //////////////////////////
246
+
247
+ var promise = qik.api.post(`/user/impersonate/${personaID}`)
248
+
249
+ promise.then(function(res) {
250
+
251
+ if (autoAuthenticate) {
252
+ qik.cache.reset();
253
+ service.set(res.data);
254
+ }
255
+ }, function(err) {});
256
+
257
+
258
+ return promise;
259
+
260
+ }
261
+
262
+ ///////////////////////////////////////////////////
263
+
264
+ /**
265
+ * @alias auth.login
266
+ * @description Login and authenticate as a user
267
+ * @param {Object} credentials The credentials used to login
268
+ * @param {String} credentials.email The email address to login to
269
+ * @param {String} credentials.password The password to login with
270
+ * @param {String} credentials.mfa The MFA (Multi Factor Authentication) code
271
+ * @param {Object} options Additional options
272
+ * @param {Boolean} options.disableAutoAuthentication By default when logging in the current user session
273
+ * will be updated automatically to reflect the new session, you can use this option to disable that behavior and instead return the
274
+ * session that was logged in to without dispatching any events
275
+ * @example
276
+ *
277
+ * const credentials = {
278
+ * email:'me@email.com',
279
+ * password:'******',
280
+ * mfa:'1234',
281
+ * }
282
+ *
283
+ * sdk.auth.login(credentials);
284
+ * // Current user session will be automatically updated
285
+ *
286
+ * const newSession = await sdk.auth.login(credentials, {disableAutoAuthentication:true});
287
+ * // Current user session will not be updated
288
+ * sdk.auth.set(newSession);
289
+ */
290
+ service.login = async function(credentials, options) {
291
+
292
+ if (!options) {
293
+ options = {};
294
+ }
295
+
296
+ //////////////////////////
297
+
298
+ //Change the users current tokens straight away
299
+ var autoAuthenticate = true;
300
+
301
+ if (options.disableAutoAuthentication) {
302
+ autoAuthenticate = false;
303
+ }
304
+
305
+ //////////////////////////////////////
306
+
307
+ var promise = new Promise(loginCheck)
308
+
309
+ function loginCheck(resolve, reject) {
310
+
311
+ if (!credentials) {
312
+ return reject({
313
+ message: 'Missing credentials!',
314
+ })
315
+ }
316
+
317
+ if (!credentials.email || !credentials.email.length) {
318
+ return reject({
319
+ message: 'Username was not provided',
320
+ })
321
+ }
322
+
323
+ if (!credentials.password || !credentials.password.length) {
324
+ return reject({
325
+ message: 'Password was not provided',
326
+ })
327
+ }
328
+
329
+ /////////////////////////////////////////////
330
+
331
+ var postOptions = {
332
+ bypassInterceptor: true
333
+ }
334
+
335
+ /////////////////////////////////////////////
336
+
337
+ var url = `${qik.apiURL}/user/login`;
338
+
339
+ /////////////////////////////////////////////
340
+
341
+ //If we have a specified url
342
+ if (options.url) {
343
+ url = options.url;
344
+ }
345
+
346
+ /////////////////////////////////////////////
347
+
348
+ qik.api.post(url, credentials, postOptions).then(function(res) {
349
+
350
+ if (autoAuthenticate) {
351
+ service.set(res.data);
352
+
353
+ }
354
+
355
+ resolve(res);
356
+ }, reject);
357
+ }
358
+
359
+ //////////////////////////////////////
360
+
361
+ return promise;
362
+
363
+ }
364
+
365
+ ///////////////////////////////////////////////////
366
+
367
+ service.signup = async function(credentials, options) {
368
+
369
+ if (!options) {
370
+ options = {};
371
+ }
372
+
373
+
374
+ //////////////////////////
375
+
376
+ //Change the users current tokens straight away
377
+ var autoAuthenticate = true;
378
+
379
+ if (options.disableAutoAuthentication) {
380
+ autoAuthenticate = false;
381
+ }
382
+
383
+ //////////////////////////////////////
384
+
385
+ var promise = new Promise(signupCheck)
386
+
387
+ function signupCheck(resolve, reject) {
388
+
389
+ if (!credentials) {
390
+ return reject({
391
+ message: 'No details provided',
392
+ })
393
+ }
394
+
395
+ if (!credentials.firstName || !credentials.firstName.length) {
396
+ return reject({
397
+ message: 'First Name was not provided',
398
+ })
399
+ }
400
+
401
+ if (!credentials.lastName || !credentials.lastName.length) {
402
+ return reject({
403
+ message: 'Last Name was not provided',
404
+ })
405
+ }
406
+
407
+ if (!credentials.email || !credentials.email.length) {
408
+ return reject({
409
+ message: 'Email/Username was not provided',
410
+ })
411
+ }
412
+
413
+
414
+ if (!credentials.password || !credentials.password.length) {
415
+ return reject({
416
+ message: 'Password was not provided',
417
+ })
418
+ }
419
+
420
+ if (!credentials.confirmPassword || !credentials.confirmPassword.length) {
421
+ return reject({
422
+ message: 'Confirm Password was not provided',
423
+ })
424
+ }
425
+
426
+ if (credentials.confirmPassword != credentials.password) {
427
+ return reject({
428
+ message: 'Your passwords do not match',
429
+ })
430
+ }
431
+
432
+ /////////////////////////////////////////////
433
+
434
+ var postOptions = {
435
+ bypassInterceptor: true
436
+ }
437
+
438
+ /////////////////////////////////////////////
439
+
440
+ var url = `${qik.apiURL}/user/signup`;
441
+
442
+ /////////////////////////////////////////////
443
+
444
+ //If we are authenticating as an application
445
+ if (options.application) {
446
+
447
+ //The url is relative to the domain
448
+ url = `${qik.domain || ''}/qik/application/signup`;
449
+ }
450
+
451
+ //If we have a specified url
452
+ if (options.url) {
453
+ url = options.url;
454
+ }
455
+
456
+ /////////////////////////////////////////////
457
+
458
+ qik.api.post(url, credentials, postOptions).then(function(res) {
459
+
460
+ if (autoAuthenticate) {
461
+ service.set(res.data);
462
+ }
463
+
464
+ resolve(res);
465
+ }, reject);
466
+ }
467
+
468
+ //////////////////////////////////////
469
+
470
+ return promise;
471
+
472
+ }
473
+
474
+
475
+ ///////////////////////////////////////////////////
476
+
477
+ /**
478
+ * @alias auth.retrieveUserFromResetToken
479
+ * @description Retrieve user session through use of a valid reset token,
480
+ * Reset tokens are short lived tokens that can be generated when a user has forgotten their password or their
481
+ * password has been reset by an administrator
482
+ * @param {String} resetToken The token to use to authenticate
483
+ * @param {Object} options Additional options for the request
484
+ * @example
485
+ *
486
+ * const resetToken = 'XXX-324623-$$...';
487
+ *
488
+ * // Retrieve the user session by providing a reset token
489
+ * const user = await sdk.auth.retrieveUserFromResetToken(resetToken);
490
+ */
491
+ service.retrieveUserFromResetToken = async function(resetToken, options) {
492
+
493
+ if (!options) {
494
+ options = {};
495
+ }
496
+
497
+ var postOptions = {
498
+ bypassInterceptor: true
499
+ }
500
+
501
+ return new Promise(function(resolve, reject) {
502
+ qik.api.get(options.url || `${qik.apiURL}/user/reset/${resetToken}`, postOptions).then(function(res) {
503
+ return resolve(res.data);
504
+ }, reject);
505
+ });
506
+
507
+ }
508
+
509
+ ///////////////////////////////////////////////////
510
+
511
+ /**
512
+ * @alias auth.updateUserWithToken
513
+ * @description Update a user's credentials through use of a reset token
514
+ * @param {String} resetToken The token to use to authenticate
515
+ * @param {Object} body Updates to be made to the user
516
+ * @param {Object} options Additional options for the request
517
+ * @param {Boolean} options.disableAutoAuthentication By default the current user session
518
+ * will be updated automatically to reflect the new updated session, you can use this option to disable that behavior
519
+ * and instead return the result without dispatching any events
520
+ * @example
521
+ *
522
+ * const resetToken = 'XXX-324623-$$...';
523
+ *
524
+ * // Retrieve the user session by providing a reset token
525
+ * const user = await sdk.auth.retrieveUserFromResetToken(resetToken);
526
+ */
527
+ service.updateUserWithToken = async function(resetToken, body, options) {
528
+
529
+ if (!options) {
530
+ options = {};
531
+ }
532
+
533
+ //////////////////////////
534
+
535
+ //Change the users current tokens straight away
536
+ var autoAuthenticate = true;
537
+
538
+ if (options.disableAutoAuthentication) {
539
+ autoAuthenticate = false;
540
+ }
541
+
542
+ //////////////////////////////////////
543
+
544
+ return new Promise(function(resolve, reject) {
545
+
546
+ var postOptions = {
547
+ bypassInterceptor: true
548
+ }
549
+
550
+ qik.api.post(options.url || `${qik.apiURL}/user/reset/${resetToken}`, body, postOptions)
551
+ .then(function(res) {
552
+
553
+ //If we should automatically authenticate
554
+ //once the request is successful
555
+ //Then clear caches and update the session
556
+ if (autoAuthenticate) {
557
+ qik.cache.reset();
558
+ service.set(res.data);
559
+ }
560
+
561
+ return resolve(res.data);
562
+ }, reject);
563
+ });
564
+
565
+ }
566
+
567
+ /**
568
+ * @alias auth.sendResetPasswordRequest
569
+ * @description This function allows a reset token to be generated and emailed to the requesting user
570
+ * allowing them to modify their user details
571
+ * @param {Object} body Details for the reset request
572
+ * @param {String} body.email The email of the user to generate a token for
573
+ * @example
574
+ *
575
+ * const resetToken = 'XXX-324623-$$...';
576
+ *
577
+ * // Retrieve the user session by providing a reset token
578
+ * const user = await sdk.auth.retrieveUserFromResetToken(resetToken);
579
+ */
580
+ service.sendResetPasswordRequest = function(details, options) {
581
+
582
+ if (!options) {
583
+ options = {};
584
+ }
585
+
586
+ if (!details) {
587
+ return Promise.reject({
588
+ message: 'No details were provided for password reset request',
589
+ })
590
+ }
591
+
592
+ if (!details.email || !details.email.length) {
593
+ return Promise.reject({
594
+ message: 'Email is required but was not provided',
595
+ })
596
+ }
597
+
598
+ return new Promise(function(resolve, reject) {
599
+
600
+ var postOptions = {
601
+ bypassInterceptor: true
602
+ }
603
+
604
+ qik.api.post(options.url || `${qik.apiURL}/user/forgot`, details, postOptions).then(resolve, reject);
605
+ })
606
+ }
607
+
608
+
609
+ ///////////////////////////////////////////////////
610
+
611
+ /**
612
+ * @alias auth.ensureValidToken
613
+ * @description This function forces a check to ensure that the current access token has not expired.
614
+ * If the token has expired, the user session will be refreshed with a new token.
615
+ * @param {Boolean} forceRefresh Whether to force the current token to be refreshed, even if it has not yet expired.
616
+ * @example
617
+ *
618
+ * // Check to ensure that the current access token is valid
619
+ * sdk.auth.ensureValidToken();
620
+ *
621
+ * // Force the token to be refreshed, even if the current token in use has not yet expired.
622
+ * sdk.auth.ensureValidToken(true);
623
+ */
624
+ service.ensureValidToken = async function(forceRefresh) {
625
+
626
+ var currentUser = service.getCurrentUser();
627
+ if (!currentUser) {
628
+
629
+ return Promise.reject('No user');
630
+ }
631
+
632
+ var { token } = currentUser;
633
+ if (!token) {
634
+
635
+ return Promise.reject('No token');
636
+ }
637
+
638
+ /////////////////////////////////////////////////////
639
+
640
+ //Check our date
641
+ var now = new Date();
642
+
643
+ //Give us a bit of buffer so that the backend doesn't beat us to
644
+ //retiring the token
645
+ now.setSeconds(now.getSeconds() + tokenBufferSeconds);
646
+
647
+ /////////////////////////////////////////////////////
648
+
649
+ var expires = new Date(token.expires);
650
+
651
+ if (forceRefresh) {
652
+ console.log('force refresh valid token', token.refreshToken)
653
+ return await service.refreshAccessToken(token.refreshToken);
654
+ }
655
+
656
+ //If the token is still fresh
657
+ if (now &lt; expires) {
658
+
659
+ return token;
660
+ } else {
661
+
662
+ return await service.refreshAccessToken(token.refreshToken);
663
+ }
664
+
665
+
666
+ }
667
+
668
+ ///////////////////////////////////////////////////
669
+
670
+ const refreshContext = {};
671
+
672
+ service.refreshAccessToken = async function(refreshToken) {
673
+
674
+ // /////////////////////////////////////////////
675
+
676
+ // if (appContext) {
677
+
678
+ // } else {
679
+
680
+ // }
681
+
682
+ // /////////////////////////////////////////////
683
+
684
+ //If there is already a request in progress
685
+ if (refreshContext.inflightRefreshRequest) {
686
+
687
+ return refreshContext.inflightRefreshRequest;
688
+ }
689
+
690
+ /////////////////////////////////////////////////////
691
+
692
+ //Create an refresh request
693
+
694
+ refreshContext.inflightRefreshRequest = new Promise(function(resolve, reject) {
695
+
696
+ //Bypass the interceptor on all token refresh calls
697
+ //Because we don't need to add the access token etc onto it
698
+
699
+ qik.api.post(`/user/refresh`, {
700
+ refreshToken: refreshToken
701
+ }, {
702
+ bypassInterceptor: true,
703
+ withoutToken: true,
704
+ })
705
+ .then(function tokenRefreshComplete(res) {
706
+
707
+ //Update the user with any changes
708
+ //returned back from the refresh request
709
+ if (!res) {
710
+
711
+ refreshContext.inflightRefreshRequest = null;
712
+ return reject();
713
+
714
+ } else {
715
+ //Update with our new session
716
+ service.set(res.data);
717
+
718
+
719
+ dispatch();
720
+ }
721
+
722
+ //Resolve with the new token
723
+ resolve(res.data.token);
724
+
725
+ //Remove the inflight request
726
+ setTimeout(function() {
727
+ refreshContext.inflightRefreshRequest = null;
728
+ })
729
+
730
+
731
+ })
732
+ .catch(function(err) {
733
+
734
+
735
+ //TODO Check if invalid_refresh_token
736
+
737
+
738
+
739
+ setTimeout(function() {
740
+ refreshContext.inflightRefreshRequest = null;
741
+ });
742
+ reject(err);
743
+
744
+
745
+
746
+ });
747
+ });
748
+
749
+ //Return the refresh request
750
+ return refreshContext.inflightRefreshRequest;
751
+ }
752
+
753
+ ///////////////////////////////////////////////////
754
+
755
+ var retryCount = 0;
756
+
757
+ /**
758
+ * @alias auth.sync
759
+ * @description A useful function to sync the current user session with the server.
760
+ * @example
761
+ *
762
+ * // Makes request to the API and updates the current user session to match the response
763
+ * sdk.auth.sync();
764
+ */
765
+ service.sync = function() {
766
+
767
+ return qik.api.get('/user')
768
+ .then(function(res) {
769
+
770
+
771
+ if (res.data) {
772
+ if (store.user) {
773
+ Object.assign(store.user.session, res.data);
774
+ }
775
+ } else {
776
+ service.set(null);
777
+ }
778
+
779
+
780
+ retryCount = 0;
781
+
782
+ dispatch();
783
+ })
784
+ .catch(function(err) {
785
+
786
+ // if (retryCount > 2) {
787
+ service.set(null);
788
+ retryCount = 0;
789
+ dispatch();
790
+ // } else {
791
+
792
+ // retryCount++;
793
+ // service.sync();
794
+ // }
795
+
796
+
797
+ });
798
+ }
799
+
800
+ /////////////////////////////////////////////////////
801
+
802
+ /**
803
+ * @alias auth.getCurrentUser
804
+ * @description Retrieves the current user session
805
+ * @example
806
+ *
807
+ * const me = sdk.auth.getCurrentUser();
808
+ */
809
+ service.getCurrentUser = function() {
810
+ return store.user;
811
+ }
812
+
813
+
814
+ /**
815
+ * @alias auth.getCurrentToken
816
+ * @description Retrieves the current access token. If the user is authenticated
817
+ * the response will be the current user's access token, otherwise will fall back to the
818
+ * applications token.
819
+ * @example
820
+ * const currentAccessToken = sdk.auth.getCurrentToken();
821
+ */
822
+ service.getCurrentToken = function() {
823
+
824
+
825
+ var user = service.getCurrentUser();
826
+
827
+ //User is not logged in
828
+ if (!user) {
829
+
830
+ //But there is an application token
831
+ if (qik.applicationToken) {
832
+ //use that instead
833
+ return qik.applicationToken;
834
+ }
835
+
836
+ //No token
837
+ return;
838
+ }
839
+
840
+ var { token } = user;
841
+ if (!token) {
842
+ return;
843
+ }
844
+
845
+ return token.accessToken;
846
+
847
+ }
848
+
849
+ /////////////////////////////////////////////////////
850
+
851
+ qik.api.interceptors.request.use(async function(config) {
852
+
853
+ //If we want to bypass the interceptor
854
+ //then just return the request
855
+ if (config.bypassInterceptor) {
856
+ return config;
857
+ }
858
+
859
+ //////////////////////////////
860
+
861
+ //Get the original request
862
+ var originalRequest = config;
863
+
864
+ //////////////////////////////
865
+
866
+ var userDetails = await service.getCurrentUser();
867
+ var accessToken;
868
+ var refreshToken;
869
+ var expiryDate;
870
+
871
+ if (userDetails) {
872
+ var { token } = userDetails;
873
+ if (token) {
874
+ accessToken = token.accessToken;
875
+ refreshToken = token.refreshToken;
876
+ expiryDate = token.expires;
877
+ }
878
+ }
879
+
880
+ //////////////////////////////
881
+
882
+ //If there is a user token
883
+ if (accessToken) {
884
+ //Set the token of the request as the user's access token
885
+ originalRequest.headers['Authorization'] = `Bearer ${accessToken}`;
886
+
887
+
888
+ } else {
889
+ //Return the original request without a token
890
+
891
+ return originalRequest;
892
+ }
893
+
894
+ /////////////////////////////////////////////////////
895
+
896
+ //If no refresh token
897
+ if (!refreshToken) {
898
+
899
+
900
+ //Continue with the original request
901
+ return originalRequest;
902
+ }
903
+
904
+ /////////////////////////////////////////////////////
905
+
906
+ //We have a refresh token so we need to check
907
+ //whether our access token is stale and needs to be refreshed
908
+ var now = new Date();
909
+
910
+ //Give us a bit of buffer so that the backend doesn't beat us to
911
+ //retiring the token
912
+ now.setSeconds(now.getSeconds() + tokenBufferSeconds);
913
+
914
+ /////////////////////////////////////////////////////
915
+
916
+ var expires = new Date(expiryDate);
917
+
918
+ //If the token is still fresh
919
+ if (now &lt; expires) {
920
+ //Return the original request
921
+ return originalRequest;
922
+ }
923
+
924
+ /////////////////////////////////////////////////////
925
+
926
+ return new Promise(async function(resolve, reject) {
927
+
928
+ //Refresh the token
929
+ await service.refreshAccessToken(refreshToken)
930
+ .then(function(newToken) {
931
+
932
+ //Update the original request with our new token
933
+ originalRequest.headers['Authorization'] = `Bearer ${newToken}`;
934
+ //And continue onward
935
+ return resolve(originalRequest);
936
+ })
937
+ .catch(function(err) {
938
+
939
+ return reject(err);
940
+ });
941
+ });
942
+
943
+
944
+ },
945
+ function(error) {
946
+ return Promise.reject(error);
947
+ })
948
+
949
+
950
+
951
+ /////////////////////////////////////////////////////
952
+
953
+ qik.api.interceptors.response.use(function(response) {
954
+ return response;
955
+ }, function(err) {
956
+
957
+ //////////////////////////////
958
+
959
+ //Get the response status
960
+ var status = (err &amp;&amp; err.response &amp;&amp; err.response.status) || err.status;
961
+
962
+
963
+ switch (status) {
964
+ case 401:
965
+ service.logout();
966
+ break;
967
+ default:
968
+ //Some other error
969
+ break;
970
+ }
971
+
972
+ /////////////////////////////////////////////////////
973
+
974
+ return Promise.reject(err);
975
+ })
976
+
977
+ return service;
978
+
979
+ }
980
+
981
+
982
+ export default QikAuth;</code></pre>
983
+ </article>
984
+ </section>
985
+
986
+
987
+
988
+
989
+
990
+
991
+ </div>
992
+
993
+ <br class="clear">
994
+
995
+ <footer>
996
+ Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.6.11</a> on Thu Sep 28 2023 07:24:39 GMT+1000 (Australian Eastern Standard Time) using the <a href="https://github.com/clenemt/docdash">docdash</a> theme.
997
+ </footer>
998
+
999
+ <script>prettyPrint();</script>
1000
+ <script src="scripts/polyfill.js"></script>
1001
+ <script src="scripts/linenumber.js"></script>
1002
+
1003
+
1004
+
1005
+ </body>
1006
+ </html>