@schibsted/account-sdk-browser 5.0.1-beta.2 → 5.0.1-beta.4
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/es5/global.js +3186 -3039
- package/es5/global.js.map +1 -1
- package/es5/global.min.js +1 -1
- package/es5/global.min.js.map +1 -1
- package/es5/identity.js +3167 -3020
- package/es5/identity.js.map +1 -1
- package/es5/identity.min.js +1 -1
- package/es5/identity.min.js.map +1 -1
- package/es5/index.js +3190 -3043
- package/es5/index.js.map +1 -1
- package/es5/index.min.js +1 -1
- package/es5/index.min.js.map +1 -1
- package/es5/monetization.js +1 -1
- package/es5/monetization.js.map +1 -1
- package/es5/monetization.min.js +1 -1
- package/es5/monetization.min.js.map +1 -1
- package/package.json +1 -1
- package/src/identity.d.ts +4 -3
- package/src/identity.js +124 -52
- package/src/version.js +1 -1
package/package.json
CHANGED
package/src/identity.d.ts
CHANGED
|
@@ -45,9 +45,10 @@ export class Identity extends TinyEmitter {
|
|
|
45
45
|
*/
|
|
46
46
|
private _getTabId;
|
|
47
47
|
/**
|
|
48
|
-
* Checks if calling
|
|
48
|
+
* Checks if calling GET session is blocked by a cache storage
|
|
49
49
|
* @private
|
|
50
|
-
* @
|
|
50
|
+
* @param {Cache} cache - cache to check
|
|
51
|
+
* @returns {string|null}
|
|
51
52
|
*/
|
|
52
53
|
private _isSessionCallBlocked;
|
|
53
54
|
/**
|
|
@@ -61,7 +62,7 @@ export class Identity extends TinyEmitter {
|
|
|
61
62
|
* @private
|
|
62
63
|
* @returns {void}
|
|
63
64
|
*/
|
|
64
|
-
private
|
|
65
|
+
private _unblockSessionCallByTab;
|
|
65
66
|
/**
|
|
66
67
|
* Set SPiD server URL
|
|
67
68
|
* @private
|
package/src/identity.js
CHANGED
|
@@ -151,6 +151,9 @@ const SESSION_CALL_BLOCKED_TTL = 1000 * 30; //set to 30s, the default period for
|
|
|
151
151
|
const TAB_ID_KEY = 'tab-id-cache';
|
|
152
152
|
const TAB_ID = Math.floor(Math.random() * 100000)
|
|
153
153
|
const TAB_ID_TTL = 1000 * 60 * 60 * 24 * 30;
|
|
154
|
+
const MAX_SESSION_CALL_RETRIES = 10;
|
|
155
|
+
const MIN_SESSION_CALL_WAIT_TIME = 100;
|
|
156
|
+
|
|
154
157
|
|
|
155
158
|
const globalWindow = () => window;
|
|
156
159
|
|
|
@@ -177,7 +180,7 @@ export class Identity extends EventEmitter {
|
|
|
177
180
|
env = 'PRE',
|
|
178
181
|
log,
|
|
179
182
|
window = globalWindow(),
|
|
180
|
-
callbackBeforeRedirect = ()=>{}
|
|
183
|
+
callbackBeforeRedirect = () => {}
|
|
181
184
|
}) {
|
|
182
185
|
super();
|
|
183
186
|
assert(isNonEmptyString(clientId), 'clientId parameter is required');
|
|
@@ -194,7 +197,7 @@ export class Identity extends EventEmitter {
|
|
|
194
197
|
this.window = window;
|
|
195
198
|
this.clientId = clientId;
|
|
196
199
|
this.sessionStorageCache = new Cache(() => this.window && this.window.sessionStorage);
|
|
197
|
-
this.localStorageCache = new Cache(() =>this.window && this.window.localStorage);
|
|
200
|
+
this.localStorageCache = new Cache(() => this.window && this.window.localStorage);
|
|
198
201
|
this.redirectUri = redirectUri;
|
|
199
202
|
this.env = env;
|
|
200
203
|
this.log = log;
|
|
@@ -234,12 +237,13 @@ export class Identity extends EventEmitter {
|
|
|
234
237
|
}
|
|
235
238
|
|
|
236
239
|
/**
|
|
237
|
-
* Checks if calling GET session is blocked
|
|
240
|
+
* Checks if calling GET session is blocked by a cache storage
|
|
238
241
|
* @private
|
|
239
|
-
* @
|
|
242
|
+
* @param {Cache} cache - cache to check
|
|
243
|
+
* @returns {string|null}
|
|
240
244
|
*/
|
|
241
|
-
_isSessionCallBlocked(){
|
|
242
|
-
return
|
|
245
|
+
_isSessionCallBlocked(cache) {
|
|
246
|
+
return cache.get(SESSION_CALL_BLOCKED_CACHE_KEY);
|
|
243
247
|
}
|
|
244
248
|
|
|
245
249
|
/**
|
|
@@ -247,7 +251,15 @@ export class Identity extends EventEmitter {
|
|
|
247
251
|
* @private
|
|
248
252
|
* @returns {void}
|
|
249
253
|
*/
|
|
250
|
-
_blockSessionCall(){
|
|
254
|
+
_blockSessionCall() {
|
|
255
|
+
// session storage block protects against single tab, multiple identity instance concurrency
|
|
256
|
+
this.sessionStorageCache.set(
|
|
257
|
+
SESSION_CALL_BLOCKED_CACHE_KEY,
|
|
258
|
+
this._tabId,
|
|
259
|
+
SESSION_CALL_BLOCKED_TTL
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
// local storage block protects against cross-tab concurrency
|
|
251
263
|
this.localStorageCache.set(
|
|
252
264
|
SESSION_CALL_BLOCKED_CACHE_KEY,
|
|
253
265
|
this._tabId,
|
|
@@ -261,9 +273,11 @@ export class Identity extends EventEmitter {
|
|
|
261
273
|
* @returns {void}
|
|
262
274
|
*/
|
|
263
275
|
_unblockSessionCallByTab() {
|
|
264
|
-
if (this._isSessionCallBlocked() === this._tabId) {
|
|
276
|
+
if (this._isSessionCallBlocked(this.localStorageCache) === this._tabId) {
|
|
265
277
|
this.localStorageCache.delete(SESSION_CALL_BLOCKED_CACHE_KEY);
|
|
266
278
|
}
|
|
279
|
+
|
|
280
|
+
this.sessionStorageCache.delete(SESSION_CALL_BLOCKED_CACHE_KEY);
|
|
267
281
|
}
|
|
268
282
|
|
|
269
283
|
/**
|
|
@@ -339,7 +353,7 @@ export class Identity extends EventEmitter {
|
|
|
339
353
|
this._globalSessionService = new RESTClient({
|
|
340
354
|
serverUrl: urlMapper(url, ENDPOINTS.SESSION_SERVICE),
|
|
341
355
|
log: this.log,
|
|
342
|
-
defaultParams: {
|
|
356
|
+
defaultParams: {client_sdrn, sdk_version: version},
|
|
343
357
|
});
|
|
344
358
|
}
|
|
345
359
|
|
|
@@ -503,7 +517,7 @@ export class Identity extends EventEmitter {
|
|
|
503
517
|
* @returns {void}
|
|
504
518
|
*/
|
|
505
519
|
_clearVarnishCookie() {
|
|
506
|
-
const baseDomain =
|
|
520
|
+
const baseDomain = this._session && typeof this._session.baseDomain === 'string'
|
|
507
521
|
? this._session.baseDomain
|
|
508
522
|
: document.domain;
|
|
509
523
|
|
|
@@ -565,74 +579,128 @@ export class Identity extends EventEmitter {
|
|
|
565
579
|
this._maybeSetVarnishCookie(sessionData);
|
|
566
580
|
this._emitSessionEvent(this._session, sessionData);
|
|
567
581
|
this._session = sessionData;
|
|
582
|
+
|
|
568
583
|
return sessionData;
|
|
569
584
|
};
|
|
570
585
|
|
|
571
|
-
const _checkRedirectionNeed = (sessionData={})=>{
|
|
586
|
+
const _checkRedirectionNeed = (sessionData = {}) => {
|
|
572
587
|
const sessionDataKeys = Object.keys(sessionData);
|
|
573
588
|
|
|
574
589
|
return sessionDataKeys.length === 1 &&
|
|
575
590
|
sessionDataKeys[0] === 'redirectURL';
|
|
576
|
-
}
|
|
591
|
+
};
|
|
577
592
|
|
|
578
593
|
const _getSession = async () => {
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
594
|
+
const callSessionEndpoint = async () => {
|
|
595
|
+
try {
|
|
596
|
+
/* Blocking future calls to session-service. This lock is removed after the response is processed
|
|
597
|
+
to account for redirection that can happen towards session-service too */
|
|
598
|
+
this._blockSessionCall();
|
|
599
|
+
|
|
600
|
+
return await this._sessionService.get('/v2/session', {tabId: this._tabId});
|
|
601
|
+
} catch (err) {
|
|
602
|
+
if (err && err.code === 400 && this._enableSessionCaching) {
|
|
603
|
+
const expiresIn = 1000 * (err.expiresIn || 300);
|
|
604
|
+
this.sessionStorageCache.set(HAS_SESSION_CACHE_KEY, {error: err}, expiresIn);
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
throw err;
|
|
584
608
|
}
|
|
585
|
-
}
|
|
609
|
+
};
|
|
586
610
|
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
611
|
+
const useSessionResponseIfValid = async (sessionData) => {
|
|
612
|
+
if (sessionData) {
|
|
613
|
+
// For expiring session and WebKit browsers do a full page redirect to get a new session
|
|
614
|
+
if (_checkRedirectionNeed(sessionData)) {
|
|
615
|
+
await this.callbackBeforeRedirect();
|
|
592
616
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
617
|
+
// Doing a return here, to avoid caching the redirect response
|
|
618
|
+
return this.window.location.href = this._sessionService.makeUrl(sessionData.redirectURL, {tabId: this._getTabId()});
|
|
619
|
+
}
|
|
596
620
|
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
this.sessionStorageCache.set(HAS_SESSION_CACHE_KEY, { error: err }, expiresIn);
|
|
602
|
-
}
|
|
603
|
-
throw err;
|
|
604
|
-
}
|
|
621
|
+
if (this._enableSessionCaching) {
|
|
622
|
+
const expiresIn = 1000 * (sessionData.expiresIn || 300);
|
|
623
|
+
this.sessionStorageCache.set(HAS_SESSION_CACHE_KEY, sessionData, expiresIn);
|
|
624
|
+
}
|
|
605
625
|
|
|
606
|
-
|
|
607
|
-
// For expiring session and Safari browser do full page redirect to get new session
|
|
608
|
-
if(_checkRedirectionNeed(sessionData)){
|
|
609
|
-
await this.callbackBeforeRedirect();
|
|
610
|
-
this.window.location.href = this._sessionService.makeUrl(sessionData.redirectURL, {tabId: this._getTabId()});
|
|
626
|
+
return _postProcess(sessionData);
|
|
611
627
|
}
|
|
628
|
+
};
|
|
612
629
|
|
|
630
|
+
const checkIfSessionCallIsNeededAndSafe = async (blockedAction) => {
|
|
613
631
|
if (this._enableSessionCaching) {
|
|
614
|
-
|
|
615
|
-
this.sessionStorageCache.
|
|
632
|
+
// Try to resolve from cache (it has a TTL)
|
|
633
|
+
let cachedSession = this.sessionStorageCache.get(HAS_SESSION_CACHE_KEY);
|
|
634
|
+
if (cachedSession) {
|
|
635
|
+
return _postProcess(cachedSession);
|
|
636
|
+
}
|
|
616
637
|
}
|
|
617
|
-
}
|
|
618
638
|
|
|
619
|
-
|
|
639
|
+
if (this._isSessionCallBlocked(this.sessionStorageCache) || this._isSessionCallBlocked(this.localStorageCache)) {
|
|
640
|
+
if (this._session && this._session.userId) {
|
|
641
|
+
return _postProcess(this._session);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
// If blockedAction is defined, do that and return the result, otherwise return null
|
|
645
|
+
if (blockedAction) {
|
|
646
|
+
const blockedResult = await blockedAction();
|
|
647
|
+
|
|
648
|
+
return _postProcess(blockedResult);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
return null;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
// If session service calls are not blocked, call it
|
|
655
|
+
const sessionData = await callSessionEndpoint();
|
|
656
|
+
|
|
657
|
+
return await useSessionResponseIfValid(sessionData);
|
|
658
|
+
};
|
|
659
|
+
|
|
660
|
+
return await checkIfSessionCallIsNeededAndSafe(async () => {
|
|
661
|
+
let retryCount = 0;
|
|
662
|
+
|
|
663
|
+
// Try to call session-service MAX_SESSION_CALL_RETRIES times, waiting up to 1 second each time
|
|
664
|
+
while (retryCount < MAX_SESSION_CALL_RETRIES) {
|
|
665
|
+
retryCount++;
|
|
666
|
+
|
|
667
|
+
const randomWaitingStep = Math.floor(Math.random() * 9); // ignoring waiting times that are too small to matter
|
|
668
|
+
const randomWaitTime = MIN_SESSION_CALL_WAIT_TIME + (randomWaitingStep * 100);
|
|
669
|
+
await new Promise(resolve => setTimeout(resolve, randomWaitTime));
|
|
670
|
+
|
|
671
|
+
// attempt to call session service, but don't take any action if call is blocked and don't use the result
|
|
672
|
+
const result = await checkIfSessionCallIsNeededAndSafe(null);
|
|
673
|
+
if (result) {
|
|
674
|
+
return result;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
// Exceeded number of attempts, returning old session info
|
|
679
|
+
if (this._session && this._session.userId) {
|
|
680
|
+
return this._session;
|
|
681
|
+
}
|
|
682
|
+
|
|
683
|
+
throw new SDKError('HasSession exceeded maximum number of attempts');
|
|
684
|
+
});
|
|
620
685
|
};
|
|
686
|
+
|
|
621
687
|
this._hasSessionInProgress = _getSession()
|
|
622
688
|
.then(
|
|
623
689
|
sessionData => {
|
|
624
690
|
this._hasSessionInProgress = false;
|
|
691
|
+
this._unblockSessionCallByTab();
|
|
625
692
|
|
|
626
693
|
return sessionData;
|
|
627
694
|
},
|
|
628
695
|
err => {
|
|
629
696
|
this.emit('error', err);
|
|
630
697
|
this._hasSessionInProgress = false;
|
|
698
|
+
this._unblockSessionCallByTab();
|
|
699
|
+
|
|
631
700
|
throw new SDKError('HasSession failed', err);
|
|
632
701
|
}
|
|
633
702
|
);
|
|
634
703
|
|
|
635
|
-
this._unblockSessionCallByTab();
|
|
636
704
|
return this._hasSessionInProgress;
|
|
637
705
|
}
|
|
638
706
|
|
|
@@ -673,8 +741,8 @@ export class Identity extends EventEmitter {
|
|
|
673
741
|
async isConnected() {
|
|
674
742
|
try {
|
|
675
743
|
const data = await this.hasSession();
|
|
676
|
-
|
|
677
|
-
|
|
744
|
+
/* If data is not an object, the promise will fail.
|
|
745
|
+
If the result is present, it's boolean. But if it's not, it should be assumed false. */
|
|
678
746
|
return !!data.result;
|
|
679
747
|
} catch (_) {
|
|
680
748
|
return false;
|
|
@@ -749,13 +817,13 @@ export class Identity extends EventEmitter {
|
|
|
749
817
|
if (!pairId)
|
|
750
818
|
throw new SDKError('pairId missing in user session!');
|
|
751
819
|
|
|
752
|
-
if(!externalParty || externalParty.length === 0) {
|
|
820
|
+
if (!externalParty || externalParty.length === 0) {
|
|
753
821
|
throw new SDKError('externalParty cannot be empty');
|
|
754
822
|
}
|
|
755
|
-
const _toHexDigest = (hashBuffer) =>{
|
|
756
|
-
//
|
|
823
|
+
const _toHexDigest = (hashBuffer) => {
|
|
824
|
+
// Convert buffer to byte array
|
|
757
825
|
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
758
|
-
//
|
|
826
|
+
// Convert bytes to hex string
|
|
759
827
|
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
|
760
828
|
}
|
|
761
829
|
|
|
@@ -831,6 +899,7 @@ export class Identity extends EventEmitter {
|
|
|
831
899
|
return null;
|
|
832
900
|
}
|
|
833
901
|
}
|
|
902
|
+
|
|
834
903
|
/**
|
|
835
904
|
* If a popup is desired, this function needs to be called in response to a user event (like
|
|
836
905
|
* click or tap) in order to work correctly. Otherwise the popup will be blocked by the
|
|
@@ -953,7 +1022,7 @@ export class Identity extends EventEmitter {
|
|
|
953
1022
|
prompt = 'select_account',
|
|
954
1023
|
}) {
|
|
955
1024
|
if (typeof arguments[0] !== 'object') {
|
|
956
|
-
//
|
|
1025
|
+
// Backward compatibility
|
|
957
1026
|
state = arguments[0];
|
|
958
1027
|
acrValues = arguments[1];
|
|
959
1028
|
scope = arguments[2] || scope;
|
|
@@ -1081,7 +1150,10 @@ export class Identity extends EventEmitter {
|
|
|
1081
1150
|
};
|
|
1082
1151
|
|
|
1083
1152
|
const loginNotYouHandler = async () => {
|
|
1084
|
-
this.login(Object.assign(await prepareLoginParams(loginParams), {
|
|
1153
|
+
this.login(Object.assign(await prepareLoginParams(loginParams), {
|
|
1154
|
+
loginHint: userData.identifier,
|
|
1155
|
+
prompt: 'login'
|
|
1156
|
+
}));
|
|
1085
1157
|
};
|
|
1086
1158
|
|
|
1087
1159
|
const initHandler = () => {
|
package/src/version.js
CHANGED