@schibsted/account-sdk-browser 5.2.7 → 6.0.0-alpha.2
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/README.md +12 -59
- package/dist/RESTClient.d.ts +91 -0
- package/dist/SDKError.d.ts +27 -0
- package/dist/cache.d.ts +65 -0
- package/dist/config.d.ts +86 -0
- package/dist/global-registry.d.ts +23 -0
- package/dist/globals.d.ts +13 -0
- package/dist/identity-s4nofYmB.js +370 -0
- package/dist/identity-s4nofYmB.js.map +1 -0
- package/dist/identity.d.ts +523 -0
- package/dist/identity.js +2 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +4 -0
- package/dist/monetization.d.ts +94 -0
- package/dist/monetization.js +72 -0
- package/dist/monetization.js.map +1 -0
- package/{src → dist}/object.d.ts +4 -9
- package/dist/popup.d.ts +9 -0
- package/{src → dist}/spidTalk.d.ts +4 -6
- package/dist/url.d.ts +8 -0
- package/dist/validate.d.ts +50 -0
- package/dist/version-spE-k97g.js +289 -0
- package/dist/version-spE-k97g.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/package.json +42 -49
- package/src/RESTClient.ts +226 -0
- package/src/SDKError.ts +59 -0
- package/src/{cache.js → cache.ts} +52 -37
- package/src/{config.js → config.ts} +7 -32
- package/src/global-registry.ts +39 -0
- package/src/globals.ts +10 -0
- package/src/{identity.js → identity.ts} +536 -437
- package/{index.js → src/index.ts} +1 -3
- package/src/{monetization.js → monetization.ts} +77 -48
- package/src/{object.js → object.ts} +8 -15
- package/src/popup.ts +74 -0
- package/src/{spidTalk.js → spidTalk.ts} +10 -12
- package/src/{url.js → url.ts} +6 -10
- package/src/{validate.js → validate.ts} +26 -42
- package/src/{version.js → version.ts} +1 -2
- package/es5/global.js +0 -12968
- package/es5/global.js.map +0 -1
- package/es5/global.min.js +0 -2
- package/es5/global.min.js.map +0 -1
- package/es5/identity.js +0 -12212
- package/es5/identity.js.map +0 -1
- package/es5/identity.min.js +0 -2
- package/es5/identity.min.js.map +0 -1
- package/es5/index.js +0 -12940
- package/es5/index.js.map +0 -1
- package/es5/index.min.js +0 -2
- package/es5/index.min.js.map +0 -1
- package/es5/monetization.js +0 -9176
- package/es5/monetization.js.map +0 -1
- package/es5/monetization.min.js +0 -2
- package/es5/monetization.min.js.map +0 -1
- package/es5/payment.js +0 -8853
- package/es5/payment.js.map +0 -1
- package/es5/payment.min.js +0 -2
- package/es5/payment.min.js.map +0 -1
- package/identity.d.ts +0 -1
- package/identity.js +0 -5
- package/index.d.ts +0 -4
- package/monetization.d.ts +0 -1
- package/monetization.js +0 -5
- package/payment.d.ts +0 -1
- package/payment.js +0 -5
- package/src/RESTClient.d.ts +0 -89
- package/src/RESTClient.js +0 -193
- package/src/SDKError.d.ts +0 -16
- package/src/SDKError.js +0 -55
- package/src/__mocks__/.eslintrc.yml +0 -8
- package/src/__mocks__/RESTClient.js +0 -54
- package/src/cache.d.ts +0 -64
- package/src/config.d.ts +0 -34
- package/src/es5/global.js +0 -13
- package/src/es5/identity.js +0 -10
- package/src/es5/index.js +0 -13
- package/src/es5/monetization.js +0 -10
- package/src/es5/payment.js +0 -10
- package/src/global-registry.js +0 -20
- package/src/identity.d.ts +0 -679
- package/src/monetization.d.ts +0 -80
- package/src/payment.d.ts +0 -115
- package/src/payment.js +0 -211
- package/src/popup.d.ts +0 -10
- package/src/popup.js +0 -59
- package/src/url.d.ts +0 -10
- package/src/validate.d.ts +0 -64
- package/src/version.d.ts +0 -2
|
@@ -2,153 +2,203 @@
|
|
|
2
2
|
* See LICENSE.md in the project root.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
import { assert, isStr, isNonEmptyString, isObject, isUrl, isStrIn } from './validate.js';
|
|
8
|
-
import { cloneDeep } from './object.js';
|
|
9
|
-
import { urlMapper } from './url.js';
|
|
10
|
-
import { ENDPOINTS, NAMESPACE } from './config.js';
|
|
11
|
-
import EventEmitter from 'tiny-emitter';
|
|
5
|
+
import { TinyEmitter } from 'tiny-emitter';
|
|
12
6
|
import Cache from './cache.js';
|
|
7
|
+
import { ENDPOINTS, NAMESPACE } from './config.js';
|
|
8
|
+
import { registerAndDispatchInGlobal } from './global-registry.js';
|
|
9
|
+
import { cloneDeep } from './object.js';
|
|
13
10
|
import * as popup from './popup.js';
|
|
14
11
|
import RESTClient from './RESTClient.js';
|
|
15
12
|
import SDKError from './SDKError.js';
|
|
16
13
|
import * as spidTalk from './spidTalk.js';
|
|
14
|
+
import { urlMapper } from './url.js';
|
|
15
|
+
import { assert, isNonEmptyString, isObject, isStr, isStrIn, isUrl } from './validate.js';
|
|
17
16
|
import version from './version.js';
|
|
18
|
-
import { registerGlobal } from './global-registry.js';
|
|
19
17
|
|
|
20
18
|
/**
|
|
21
|
-
* @
|
|
22
|
-
* @property {string} state - An opaque value used by the client to maintain state between
|
|
23
|
-
* the request and callback. It's also recommended to prevent CSRF {@link https://tools.ietf.org/html/rfc6749#section-10.12}
|
|
24
|
-
* @property {string} [acrValues] - Authentication Context Class Reference Values. If
|
|
25
|
-
* omitted, the user will be asked to authenticate using username+password.
|
|
26
|
-
* For 2FA (Two-Factor Authentication) possible values are `sms`, `otp` (one time password),
|
|
27
|
-
* `password` (will force password confirmation, even if user is already logged in), `eid`. Those values might
|
|
28
|
-
* be mixed as space-separated string. To make sure that user has authenticated with 2FA you need
|
|
29
|
-
* to verify AMR (Authentication Methods References) claim in ID token.
|
|
30
|
-
* Might also be used to ensure additional acr (sms, otp) for already logged-in users.
|
|
31
|
-
* Supported value is also 'otp-email' means one time password using email.
|
|
32
|
-
* @property {string} [scope] - The OAuth scopes for the tokens. This is a list of
|
|
33
|
-
* scopes, separated by space. If the list of scopes contains `openid`, the generated tokens
|
|
34
|
-
* includes the id token which can be useful for getting information about the user. Omitting
|
|
35
|
-
* scope is allowed, while `invalid_scope` is returned when the client asks for a scope you
|
|
36
|
-
* aren’t allowed to request. {@link https://tools.ietf.org/html/rfc6749#section-3.3}
|
|
37
|
-
* @property {string} [redirectUri] - Redirect uri that will receive the
|
|
38
|
-
* code. Must exactly match a redirectUri from your client in self-service
|
|
39
|
-
* @property {boolean} [preferPopup] - Should we try to open a popup window?
|
|
40
|
-
* @property {string} [loginHint] - User email or UUID hint
|
|
41
|
-
* @property {string} [tag] - Pulse tag
|
|
42
|
-
* @property {string} [teaser] - Teaser slug. Teaser with given slug will be displayed
|
|
43
|
-
* in place of default teaser
|
|
44
|
-
* @property {number|string} [maxAge] - Specifies the allowable elapsed time in seconds since
|
|
45
|
-
* the last time the End-User was actively authenticated. If last authentication time is more
|
|
46
|
-
* than maxAge seconds in the past, re-authentication will be required. See the OpenID Connect
|
|
47
|
-
* spec section 3.1.2.1 for more information
|
|
48
|
-
* @property {string} [locale] - Optional parameter to overwrite client locale setting.
|
|
49
|
-
* New flows supports nb_NO, fi_FI, sv_SE, en_US
|
|
50
|
-
* @property {boolean} [oneStepLogin] - Display username and password on one screen
|
|
51
|
-
* @property {string} [prompt] - String that specifies whether the Authorization Server prompts the
|
|
52
|
-
* End-User for re-authentication or confirm account screen. Supported values: `select_account` or `login`
|
|
53
|
-
* @property {string} [xDomainId] - Identifier for cross-domain tracking in Pulse
|
|
54
|
-
* @property {string} [xEnvironmentId] - Environment for cross-domain tracking in Pulse
|
|
55
|
-
* @property {string} [originCampaign] - Campaign identifier for tracking in Pulse
|
|
19
|
+
* Options accepted by {@link Identity#login} and related login URL helpers.
|
|
56
20
|
*/
|
|
21
|
+
export type LoginOptions = {
|
|
22
|
+
/**
|
|
23
|
+
* An opaque value used by the client to maintain state between the request and callback.
|
|
24
|
+
* It's also recommended to prevent CSRF {@link https://tools.ietf.org/html/rfc6749#section-10.12}
|
|
25
|
+
*/
|
|
26
|
+
state: string;
|
|
27
|
+
/**
|
|
28
|
+
* Authentication Context Class Reference Values. If omitted, the user will be asked to
|
|
29
|
+
* authenticate using username+password. For 2FA (Two-Factor Authentication) possible values
|
|
30
|
+
* are `sms`, `otp` (one time password), `password` (will force password confirmation, even if
|
|
31
|
+
* user is already logged in), `eid`. Those values might be mixed as space-separated string.
|
|
32
|
+
* To make sure that user has authenticated with 2FA you need to verify AMR (Authentication
|
|
33
|
+
* Methods References) claim in ID token. Might also be used to ensure additional acr
|
|
34
|
+
* (sms, otp, eid) for already logged in users. Supported value is also 'otp-email' means one
|
|
35
|
+
* time password using email.
|
|
36
|
+
*/
|
|
37
|
+
acrValues?: string;
|
|
38
|
+
/**
|
|
39
|
+
* The OAuth scopes for the tokens. This is a list of scopes, separated by space. If the list
|
|
40
|
+
* of scopes contains `openid`, the generated tokens includes the id token which can be useful
|
|
41
|
+
* for getting information about the user. Omitting scope is allowed, while `invalid_scope` is
|
|
42
|
+
* returned when the client asks for a scope you aren't allowed to request.
|
|
43
|
+
* {@link https://tools.ietf.org/html/rfc6749#section-3.3}
|
|
44
|
+
* Defaults to `openid`.
|
|
45
|
+
*/
|
|
46
|
+
scope?: string;
|
|
47
|
+
/**
|
|
48
|
+
* Redirect uri that will receive the code. Must exactly match a redirectUri from your client
|
|
49
|
+
* in self-service
|
|
50
|
+
*/
|
|
51
|
+
redirectUri?: string;
|
|
52
|
+
/** Should we try to open a popup window? Defaults to `false`. */
|
|
53
|
+
preferPopup?: boolean;
|
|
54
|
+
/** user email or UUID hint */
|
|
55
|
+
loginHint?: string;
|
|
56
|
+
/** Pulse tag */
|
|
57
|
+
tag?: string;
|
|
58
|
+
/** Teaser slug. Teaser with given slug will be displayed in place of default teaser */
|
|
59
|
+
teaser?: string;
|
|
60
|
+
/**
|
|
61
|
+
* Specifies the allowable elapsed time in seconds since the last time the End-User was actively
|
|
62
|
+
* authenticated. If last authentication time is more than maxAge seconds in the past,
|
|
63
|
+
* re-authentication will be required. See the OpenID Connect spec section 3.1.2.1 for more
|
|
64
|
+
* information
|
|
65
|
+
*/
|
|
66
|
+
maxAge?: number | string;
|
|
67
|
+
/**
|
|
68
|
+
* Optional parameter to overwrite client locale setting.
|
|
69
|
+
* New flows supports nb_NO, fi_FI, sv_SE, en_US
|
|
70
|
+
*/
|
|
71
|
+
locale?: string;
|
|
72
|
+
/** display username and password on one screen. Defaults to `false`. */
|
|
73
|
+
oneStepLogin?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* String that specifies whether the Authorization Server prompts the End-User for
|
|
76
|
+
* reauthentication or confirm account screen. Supported values: `select_account` or `login`.
|
|
77
|
+
* Defaults to `select_account`.
|
|
78
|
+
*/
|
|
79
|
+
prompt?: string;
|
|
80
|
+
/** Identifier for cross-domain tracking in Pulse */
|
|
81
|
+
xDomainId?: string;
|
|
82
|
+
/** Environment for cross-domain tracking in Pulse */
|
|
83
|
+
xEnvironmentId?: string;
|
|
84
|
+
/** Campaign identifier for tracking in Pulse */
|
|
85
|
+
originCampaign?: string;
|
|
86
|
+
};
|
|
87
|
+
|
|
57
88
|
/**
|
|
58
|
-
* @
|
|
59
|
-
*
|
|
60
|
-
* the request and callback. It's also recommended to prevent CSRF {@link https://tools.ietf.org/html/rfc6749#section-10.12}
|
|
61
|
-
* @property {string} [acrValues] - Authentication Context Class Reference Values. If
|
|
62
|
-
* omitted, the user will be asked to authenticate using username+password.
|
|
63
|
-
* For 2FA (Two-Factor Authentication) possible values are `sms`, `otp` (one time password) and
|
|
64
|
-
* `password` (will force password confirmation, even if user is already logged in). Those values might
|
|
65
|
-
* be mixed as space-separated string. To make sure that user has authenticated with 2FA you need
|
|
66
|
-
* to verify AMR (Authentication Methods References) claim in ID token.
|
|
67
|
-
* Might also be used to ensure additional acr (sms, otp) for already logged-in users.
|
|
68
|
-
* Supported value is also 'otp-email' means one time password using email.
|
|
69
|
-
* @property {string} [scope] - The OAuth scopes for the tokens. This is a list of
|
|
70
|
-
* scopes, separated by space. If the list of scopes contains `openid`, the generated tokens
|
|
71
|
-
* includes the id token which can be useful for getting information about the user. Omitting
|
|
72
|
-
* scope is allowed, while `invalid_scope` is returned when the client asks for a scope you
|
|
73
|
-
* aren’t allowed to request. {@link https://tools.ietf.org/html/rfc6749#section-3.3}
|
|
74
|
-
* @property {string} [redirectUri] - Redirect uri that will receive the
|
|
75
|
-
* code. Must exactly match a redirectUri from your client in self-service
|
|
76
|
-
* @property {boolean} [preferPopup] - Should we try to open a popup window?
|
|
77
|
-
* @property {string} [loginHint] - User email or UUID hint
|
|
78
|
-
* @property {string} [tag] - Pulse tag
|
|
79
|
-
* @property {string} [teaser] - Teaser slug. Teaser with given slug will be displayed
|
|
80
|
-
* in place of default teaser
|
|
81
|
-
* @property {number|string} [maxAge] - Specifies the allowable elapsed time in seconds since
|
|
82
|
-
* the last time the End-User was actively authenticated. If last authentication time is more
|
|
83
|
-
* than maxAge seconds in the past, re-authentication will be required. See the OpenID Connect
|
|
84
|
-
* spec section 3.1.2.1 for more information
|
|
85
|
-
* @property {string} [locale] - Optional parameter to overwrite client locale setting.
|
|
86
|
-
* New flows supports nb_NO, fi_FI, sv_SE, en_US
|
|
87
|
-
* @property {boolean} [oneStepLogin] - Display username and password on one screen
|
|
88
|
-
* @property {string} [prompt] - String that specifies whether the Authorization Server prompts the
|
|
89
|
-
* End-User for reauthentication or confirm account screen. Supported values: `select_account` or `login`
|
|
90
|
-
* @property {string} [xDomainId] - Identifier for cross-domain tracking in Pulse
|
|
91
|
-
* @property {string} [xEnvironmentId] - Environment for cross-domain tracking in Pulse
|
|
92
|
-
* @property {string} [originCampaign] - Campaign identifier for tracking in Pulse
|
|
89
|
+
* Identical to {@link LoginOptions} except that `state` may also be a (possibly async) function;
|
|
90
|
+
* all other fields reuse the `LoginOptions` documentation.
|
|
93
91
|
*/
|
|
92
|
+
export type SimplifiedLoginWidgetLoginOptions = Omit<LoginOptions, 'state'> & {
|
|
93
|
+
/**
|
|
94
|
+
* An opaque value used by the client to maintain state between the request and callback.
|
|
95
|
+
* It's also recommended to prevent CSRF {@link https://tools.ietf.org/html/rfc6749#section-10.12}
|
|
96
|
+
*/
|
|
97
|
+
state: string | (() => string | Promise<string>);
|
|
98
|
+
};
|
|
94
99
|
|
|
95
100
|
/**
|
|
96
|
-
* @
|
|
97
|
-
* @property {boolean} result - Is the user connected to the merchant? (it means that the merchant
|
|
98
|
-
* id is in the list of merchants listed of this user in the database)? Example: false
|
|
99
|
-
* @property {string} userStatus - Example: 'notConnected' or 'connected'. Deprecated, use
|
|
100
|
-
* `Identity.isConnected()`
|
|
101
|
-
* @property {string} baseDomain - Example: 'localhost'
|
|
102
|
-
* @property {string} id - Example: '58eca10fdbb9f6df72c3368f'. Obsolete
|
|
103
|
-
* @property {number} userId - Example: 37162
|
|
104
|
-
* @property {string} uuid - Example: 'b3b23aa7-34f2-5d02-a10e-5a3455c6ab2c'
|
|
105
|
-
* @property {string} sp_id - Example: 'eyJjbGllbnRfaWQ...'
|
|
106
|
-
* @property {number} expiresIn - Example: 30 * 60 * 1000 (for 30 minutes)
|
|
107
|
-
* @property {number} serverTime - Example: 1506285759
|
|
108
|
-
* @property {string} sig - Example: 'NCdzXaz4ZRb7...' The sig parameter is a concatenation of an
|
|
109
|
-
* HMAC SHA-256 signature string, a dot (.) and a base64url encoded JSON object (session).
|
|
110
|
-
* {@link http://techdocs.spid.no/sdks/js/response-signature-and-validation/}
|
|
111
|
-
* @property {string} displayName - (Only for connected users) Example: 'batman'
|
|
112
|
-
* @property {string} givenName - (Only for connected users) Example: 'Bruce'
|
|
113
|
-
* @property {string} familyName - (Only for connected users) Example: 'Wayne'
|
|
114
|
-
* @property {string} gender - (Only for connected users) Example: 'male', 'female', 'undisclosed'
|
|
115
|
-
* @property {string} photo - (Only for connected users) Example:
|
|
116
|
-
* 'http://www.srv.com/some/picture.jpg'
|
|
117
|
-
* @property {boolean} tracking - (Only for connected users)
|
|
118
|
-
* @property {boolean} clientAgreementAccepted - (Only for connected users)
|
|
119
|
-
* @property {boolean} defaultAgreementAccepted - (Only for connected users)
|
|
120
|
-
* @property {string} pairId
|
|
121
|
-
* @property {string} sdrn
|
|
101
|
+
* Successful response returned from {@link Identity#hasSession}.
|
|
122
102
|
*/
|
|
103
|
+
export type HasSessionSuccessResponse = {
|
|
104
|
+
/**
|
|
105
|
+
* Is the user connected to the merchant? (it means that the merchant id is in the list of
|
|
106
|
+
* merchants listed of this user in the database)? Example: false
|
|
107
|
+
*/
|
|
108
|
+
result: boolean;
|
|
109
|
+
/** Example: 'notConnected' or 'connected'. Deprecated, use `Identity.isConnected()` */
|
|
110
|
+
userStatus: string;
|
|
111
|
+
/** Example: 'localhost' */
|
|
112
|
+
baseDomain: string;
|
|
113
|
+
/** Example: '58eca10fdbb9f6df72c3368f'. Obsolete */
|
|
114
|
+
id: string;
|
|
115
|
+
/** Example: 37162 */
|
|
116
|
+
userId: number;
|
|
117
|
+
/** Example: 'b3b23aa7-34f2-5d02-a10e-5a3455c6ab2c' */
|
|
118
|
+
uuid: string;
|
|
119
|
+
/** Example: 'eyJjbGllbnRfaWQ...' */
|
|
120
|
+
sp_id: string;
|
|
121
|
+
/** Example: 30 * 60 * 1000 (for 30 minutes) */
|
|
122
|
+
expiresIn: number;
|
|
123
|
+
/** Example: 1506285759 */
|
|
124
|
+
serverTime: number;
|
|
125
|
+
/**
|
|
126
|
+
* Example: 'NCdzXaz4ZRb7...' The sig parameter is a concatenation of an HMAC SHA-256 signature
|
|
127
|
+
* string, a dot (.) and a base64url encoded JSON object (session).
|
|
128
|
+
* {@link http://techdocs.spid.no/sdks/js/response-signature-and-validation/}
|
|
129
|
+
*/
|
|
130
|
+
sig: string;
|
|
131
|
+
/** (Only for connected users) Example: 'batman' */
|
|
132
|
+
displayName: string;
|
|
133
|
+
/** (Only for connected users) Example: 'Bruce' */
|
|
134
|
+
givenName: string;
|
|
135
|
+
/** (Only for connected users) Example: 'Wayne' */
|
|
136
|
+
familyName: string;
|
|
137
|
+
/** (Only for connected users) Example: 'male', 'female', 'undisclosed' */
|
|
138
|
+
gender: string;
|
|
139
|
+
/** (Only for connected users) Example: 'http://www.srv.com/some/picture.jpg' */
|
|
140
|
+
photo: string;
|
|
141
|
+
/** (Only for connected users) */
|
|
142
|
+
tracking: boolean;
|
|
143
|
+
/** (Only for connected users) */
|
|
144
|
+
clientAgreementAccepted: boolean;
|
|
145
|
+
/** (Only for connected users) */
|
|
146
|
+
defaultAgreementAccepted: boolean;
|
|
147
|
+
pairId: string;
|
|
148
|
+
sdrn: string;
|
|
149
|
+
};
|
|
123
150
|
|
|
124
151
|
/**
|
|
125
|
-
*
|
|
126
|
-
* @event Identity#error
|
|
152
|
+
* Failure response returned from {@link Identity#hasSession}.
|
|
127
153
|
*/
|
|
154
|
+
export type HasSessionFailureResponse = {
|
|
155
|
+
error: {
|
|
156
|
+
/** Typically an HTTP response code. Example: 401 */
|
|
157
|
+
code: number;
|
|
158
|
+
/** Example: "No session found!" */
|
|
159
|
+
description: string;
|
|
160
|
+
/** Example: "UserException" */
|
|
161
|
+
type: string;
|
|
162
|
+
};
|
|
163
|
+
response: {
|
|
164
|
+
/** Example: "localhost" */
|
|
165
|
+
baseDomain: string;
|
|
166
|
+
/** Time span in milliseconds. Example: 30 * 60 * 1000 (for 30 minutes) */
|
|
167
|
+
expiresIn: number;
|
|
168
|
+
result: boolean;
|
|
169
|
+
/** Server time in seconds since the Unix Epoch. Example: 1506287788 */
|
|
170
|
+
serverTime: number;
|
|
171
|
+
};
|
|
172
|
+
};
|
|
128
173
|
|
|
129
174
|
/**
|
|
130
|
-
*
|
|
131
|
-
* @property {object} error
|
|
132
|
-
* @property {number} error.code - Typically an HTTP response code. Example: 401
|
|
133
|
-
* @property {string} error.description - Example: "No session found!"
|
|
134
|
-
* @property {string} error.type - Example: "UserException"
|
|
135
|
-
* @property {object} response
|
|
136
|
-
* @property {string} response.baseDomain - Example: "localhost"
|
|
137
|
-
* @property {number} response.expiresIn - Time span in milliseconds. Example: 30 * 60 * 1000 (for 30 minutes)
|
|
138
|
-
* @property {boolean} response.result
|
|
139
|
-
* @property {number} response.serverTime - Server time in seconds since the Unix Epoch. Example: 1506287788
|
|
175
|
+
* Minimal user information used by the simplified login widget flow.
|
|
140
176
|
*/
|
|
177
|
+
export type SimplifiedLoginData = {
|
|
178
|
+
/** Deprecated: User UUID, to be be used as `loginHint` for {@link Identity#login} */
|
|
179
|
+
identifier: string;
|
|
180
|
+
/** Human-readable user identifier */
|
|
181
|
+
display_text: string;
|
|
182
|
+
/** Client name */
|
|
183
|
+
client_name: string;
|
|
184
|
+
};
|
|
141
185
|
|
|
142
186
|
/**
|
|
143
|
-
* @
|
|
144
|
-
* @property {string} identifier - Deprecated: User UUID, to be be used as `loginHint` for {@link Identity#login}
|
|
145
|
-
* @property {string} display_text - Human-readable user identifier
|
|
146
|
-
* @property {string} client_name - Client name
|
|
187
|
+
* Configuration options for {@link Identity#showSimplifiedLoginWidget}.
|
|
147
188
|
*/
|
|
189
|
+
export type SimplifiedLoginWidgetOptions = {
|
|
190
|
+
/** expected encoding of simplified login widget. Could be utf-8 (default), iso-8859-1 or iso-8859-15 */
|
|
191
|
+
encoding: string;
|
|
192
|
+
/**
|
|
193
|
+
* expected locale of simplified login widget. Should be provided in a short format like 'nb',
|
|
194
|
+
* 'sv'. If not set, a value from the env variable is used.
|
|
195
|
+
*/
|
|
196
|
+
locale?: 'nb' | 'sv' | 'fi' | 'da' | 'en';
|
|
197
|
+
};
|
|
148
198
|
|
|
149
199
|
/**
|
|
150
|
-
*
|
|
151
|
-
* @
|
|
200
|
+
* Emitted when an error happens (useful for debugging)
|
|
201
|
+
* @event Identity#error
|
|
152
202
|
*/
|
|
153
203
|
|
|
154
204
|
const HAS_SESSION_CACHE_KEY = 'hasSession-cache';
|
|
@@ -156,7 +206,7 @@ const SESSION_CALL_BLOCKED_CACHE_KEY = 'sessionCallBlocked-cache';
|
|
|
156
206
|
const SESSION_CALL_BLOCKED_TTL = 1000 * 60 * 5;
|
|
157
207
|
|
|
158
208
|
const TAB_ID_KEY = 'tab-id-cache';
|
|
159
|
-
const TAB_ID = Math.floor(Math.random() * 100000)
|
|
209
|
+
const TAB_ID = Math.floor(Math.random() * 100000);
|
|
160
210
|
const TAB_ID_TTL = 1000 * 60 * 60 * 24 * 30;
|
|
161
211
|
|
|
162
212
|
const globalWindow = () => window;
|
|
@@ -164,17 +214,41 @@ const globalWindow = () => window;
|
|
|
164
214
|
/**
|
|
165
215
|
* Provides Identity functionalty to a web page
|
|
166
216
|
*/
|
|
167
|
-
export class Identity extends
|
|
217
|
+
export class Identity extends TinyEmitter {
|
|
218
|
+
_sessionInitiatedSent: boolean;
|
|
219
|
+
window: any;
|
|
220
|
+
clientId: string;
|
|
221
|
+
sessionStorageCache: any;
|
|
222
|
+
localStorageCache: any;
|
|
223
|
+
redirectUri: string;
|
|
224
|
+
env: string;
|
|
225
|
+
log?: Function;
|
|
226
|
+
callbackBeforeRedirect: Function;
|
|
227
|
+
_sessionDomain: string;
|
|
228
|
+
_enableSessionCaching: boolean;
|
|
229
|
+
_session: any;
|
|
230
|
+
_spid!: RESTClient;
|
|
231
|
+
_oauthService!: RESTClient;
|
|
232
|
+
_bffService!: RESTClient;
|
|
233
|
+
_sessionService!: RESTClient;
|
|
234
|
+
_globalSessionService!: RESTClient;
|
|
235
|
+
_usedSessionServiceGetSessionEndpoint: any;
|
|
236
|
+
_hasSessionInProgress?: boolean | Promise<any>;
|
|
237
|
+
popup?: Window | null;
|
|
238
|
+
setVarnishCookie?: boolean;
|
|
239
|
+
varnishExpiresIn?: number;
|
|
240
|
+
varnishCookieDomain?: string;
|
|
241
|
+
|
|
168
242
|
/**
|
|
169
|
-
* @param
|
|
170
|
-
* @param
|
|
171
|
-
* @param
|
|
172
|
-
* @param
|
|
173
|
-
* @param
|
|
174
|
-
* @param
|
|
243
|
+
* @param options
|
|
244
|
+
* @param options.clientId - Example: "1234567890abcdef12345678"
|
|
245
|
+
* @param options.sessionDomain - Example: "https://id.site.com"
|
|
246
|
+
* @param options.redirectUri - Example: "https://site.com"
|
|
247
|
+
* @param options.env - Schibsted account environment: `PRE` (default), `PRO`, `PRO_NO`, `PRO_FI` or `PRO_DK`
|
|
248
|
+
* @param options.log - A function that receives debug log information. If not set,
|
|
175
249
|
* no logging will be done
|
|
176
|
-
* @param
|
|
177
|
-
* @param
|
|
250
|
+
* @param options.window - window object
|
|
251
|
+
* @param options.callbackBeforeRedirect - callback triggered before session refresh redirect happen
|
|
178
252
|
* @throws {SDKError} - If any of options are invalid
|
|
179
253
|
*/
|
|
180
254
|
constructor({
|
|
@@ -184,13 +258,24 @@ export class Identity extends EventEmitter {
|
|
|
184
258
|
env = 'PRE',
|
|
185
259
|
log,
|
|
186
260
|
window = globalWindow(),
|
|
187
|
-
callbackBeforeRedirect = ()=>{}
|
|
261
|
+
callbackBeforeRedirect = () => {},
|
|
262
|
+
}: {
|
|
263
|
+
clientId: string;
|
|
264
|
+
sessionDomain: string;
|
|
265
|
+
redirectUri: string;
|
|
266
|
+
env?: string;
|
|
267
|
+
log?: Function;
|
|
268
|
+
window?: Window;
|
|
269
|
+
callbackBeforeRedirect?: Function;
|
|
188
270
|
}) {
|
|
189
271
|
super();
|
|
190
272
|
assert(isNonEmptyString(clientId), 'clientId parameter is required');
|
|
191
273
|
assert(isObject(window), 'The reference to window is missing');
|
|
192
274
|
assert(!redirectUri || isUrl(redirectUri), 'redirectUri parameter is invalid');
|
|
193
|
-
assert(
|
|
275
|
+
assert(
|
|
276
|
+
isNonEmptyString(sessionDomain) && isUrl(sessionDomain),
|
|
277
|
+
'sessionDomain parameter is not a valid URL',
|
|
278
|
+
);
|
|
194
279
|
|
|
195
280
|
spidTalk.emulate(window);
|
|
196
281
|
this._sessionInitiatedSent = false;
|
|
@@ -211,7 +296,10 @@ export class Identity extends EventEmitter {
|
|
|
211
296
|
this._session = {};
|
|
212
297
|
|
|
213
298
|
this._setSessionServiceUrl(sessionDomain);
|
|
214
|
-
this._usedSessionServiceGetSessionEndpoint =
|
|
299
|
+
this._usedSessionServiceGetSessionEndpoint =
|
|
300
|
+
this._sessionService.url.pathname && this._sessionService.url.pathname.length <= 1
|
|
301
|
+
? 'v2/session'
|
|
302
|
+
: 'session';
|
|
215
303
|
|
|
216
304
|
this._setSpidServerUrl(env);
|
|
217
305
|
this._setBffServerUrl(env);
|
|
@@ -220,16 +308,14 @@ export class Identity extends EventEmitter {
|
|
|
220
308
|
|
|
221
309
|
this._unblockSessionCall();
|
|
222
310
|
|
|
223
|
-
|
|
224
|
-
|
|
311
|
+
registerAndDispatchInGlobal(window, 'schIdentity', this);
|
|
225
312
|
}
|
|
226
313
|
|
|
227
314
|
/**
|
|
228
315
|
* Read tabId from session storage
|
|
229
|
-
* @returns {number}
|
|
230
316
|
* @private
|
|
231
317
|
*/
|
|
232
|
-
_getTabId() {
|
|
318
|
+
_getTabId(): number | undefined {
|
|
233
319
|
if (this._enableSessionCaching) {
|
|
234
320
|
const tabId = this.sessionStorageCache.get(TAB_ID_KEY);
|
|
235
321
|
if (!tabId) {
|
|
@@ -245,9 +331,8 @@ export class Identity extends EventEmitter {
|
|
|
245
331
|
* Checks if getting session is blocked
|
|
246
332
|
* @private
|
|
247
333
|
*
|
|
248
|
-
* @returns {boolean|void}
|
|
249
334
|
*/
|
|
250
|
-
_isSessionCallBlocked(){
|
|
335
|
+
_isSessionCallBlocked(): boolean | void {
|
|
251
336
|
return this.localStorageCache.get(SESSION_CALL_BLOCKED_CACHE_KEY);
|
|
252
337
|
}
|
|
253
338
|
|
|
@@ -255,15 +340,14 @@ export class Identity extends EventEmitter {
|
|
|
255
340
|
* Block calls to get session
|
|
256
341
|
* @private
|
|
257
342
|
*
|
|
258
|
-
* @returns {void}
|
|
259
343
|
*/
|
|
260
|
-
_blockSessionCall(){
|
|
344
|
+
_blockSessionCall(): void {
|
|
261
345
|
const SESSION_CALL_BLOCKED = true;
|
|
262
346
|
|
|
263
347
|
this.localStorageCache.set(
|
|
264
348
|
SESSION_CALL_BLOCKED_CACHE_KEY,
|
|
265
349
|
SESSION_CALL_BLOCKED,
|
|
266
|
-
SESSION_CALL_BLOCKED_TTL
|
|
350
|
+
SESSION_CALL_BLOCKED_TTL,
|
|
267
351
|
);
|
|
268
352
|
}
|
|
269
353
|
|
|
@@ -271,19 +355,17 @@ export class Identity extends EventEmitter {
|
|
|
271
355
|
* Unblocks calls to get session
|
|
272
356
|
* @private
|
|
273
357
|
*
|
|
274
|
-
* @returns {void}
|
|
275
358
|
*/
|
|
276
|
-
_unblockSessionCall(){
|
|
359
|
+
_unblockSessionCall(): void {
|
|
277
360
|
this.localStorageCache.delete(SESSION_CALL_BLOCKED_CACHE_KEY);
|
|
278
361
|
}
|
|
279
362
|
|
|
280
363
|
/**
|
|
281
364
|
* Set SPiD server URL
|
|
282
365
|
* @private
|
|
283
|
-
* @param
|
|
284
|
-
* @returns {void}
|
|
366
|
+
* @param url - real URL or 'PRE' style key
|
|
285
367
|
*/
|
|
286
|
-
_setSpidServerUrl(url) {
|
|
368
|
+
_setSpidServerUrl(url: string): void {
|
|
287
369
|
assert(isStr(url), `url parameter is invalid: ${url}`);
|
|
288
370
|
this._spid = new RESTClient({
|
|
289
371
|
serverUrl: urlMapper(url, ENDPOINTS.SPiD),
|
|
@@ -295,10 +377,9 @@ export class Identity extends EventEmitter {
|
|
|
295
377
|
/**
|
|
296
378
|
* Set OAuth server URL
|
|
297
379
|
* @private
|
|
298
|
-
* @param
|
|
299
|
-
* @returns {void}
|
|
380
|
+
* @param url - real URL or 'PRE' style key
|
|
300
381
|
*/
|
|
301
|
-
_setOauthServerUrl(url) {
|
|
382
|
+
_setOauthServerUrl(url: string): void {
|
|
302
383
|
assert(isStr(url), `url parameter is invalid: ${url}`);
|
|
303
384
|
this._oauthService = new RESTClient({
|
|
304
385
|
serverUrl: urlMapper(url, ENDPOINTS.SPiD),
|
|
@@ -310,10 +391,9 @@ export class Identity extends EventEmitter {
|
|
|
310
391
|
/**
|
|
311
392
|
* Set BFF server URL
|
|
312
393
|
* @private
|
|
313
|
-
* @param
|
|
314
|
-
* @returns {void}
|
|
394
|
+
* @param url - real URL or 'PRE' style key
|
|
315
395
|
*/
|
|
316
|
-
_setBffServerUrl(url) {
|
|
396
|
+
_setBffServerUrl(url: string): void {
|
|
317
397
|
assert(isStr(url), `url parameter is invalid: ${url}`);
|
|
318
398
|
this._bffService = new RESTClient({
|
|
319
399
|
serverUrl: urlMapper(url, ENDPOINTS.BFF),
|
|
@@ -325,12 +405,11 @@ export class Identity extends EventEmitter {
|
|
|
325
405
|
/**
|
|
326
406
|
* Set site-specific session-service domain
|
|
327
407
|
* @private
|
|
328
|
-
* @param
|
|
329
|
-
* @returns {void}
|
|
408
|
+
* @param domain - real URL — (**not** 'PRE' style env key)
|
|
330
409
|
*/
|
|
331
|
-
_setSessionServiceUrl(domain) {
|
|
410
|
+
_setSessionServiceUrl(domain: string): void {
|
|
332
411
|
assert(isStr(domain), `domain parameter is invalid: ${domain}`);
|
|
333
|
-
const client_sdrn = `sdrn:${NAMESPACE[this.env]}:client:${this.clientId}`;
|
|
412
|
+
const client_sdrn = `sdrn:${NAMESPACE[this.env as keyof typeof NAMESPACE]}:client:${this.clientId}`;
|
|
334
413
|
this._sessionService = new RESTClient({
|
|
335
414
|
serverUrl: domain,
|
|
336
415
|
log: this.log,
|
|
@@ -341,12 +420,11 @@ export class Identity extends EventEmitter {
|
|
|
341
420
|
/**
|
|
342
421
|
* Set global session-service server URL
|
|
343
422
|
* @private
|
|
344
|
-
* @param
|
|
345
|
-
* @returns {void}
|
|
423
|
+
* @param url - real URL or 'PRE' style key
|
|
346
424
|
*/
|
|
347
|
-
_setGlobalSessionServiceUrl(url) {
|
|
425
|
+
_setGlobalSessionServiceUrl(url: string): void {
|
|
348
426
|
assert(isStr(url), `url parameter is invalid: ${url}`);
|
|
349
|
-
const client_sdrn = `sdrn:${NAMESPACE[this.env]}:client:${this.clientId}`;
|
|
427
|
+
const client_sdrn = `sdrn:${NAMESPACE[this.env as keyof typeof NAMESPACE]}:client:${this.clientId}`;
|
|
350
428
|
this._globalSessionService = new RESTClient({
|
|
351
429
|
serverUrl: urlMapper(url, ENDPOINTS.SESSION_SERVICE),
|
|
352
430
|
log: this.log,
|
|
@@ -357,11 +435,10 @@ export class Identity extends EventEmitter {
|
|
|
357
435
|
/**
|
|
358
436
|
* Emits the relevant events based on the previous and new reply from hassession
|
|
359
437
|
* @private
|
|
360
|
-
* @param
|
|
361
|
-
* @param
|
|
362
|
-
* @returns {void}
|
|
438
|
+
* @param previous
|
|
439
|
+
* @param current
|
|
363
440
|
*/
|
|
364
|
-
_emitSessionEvent(previous, current) {
|
|
441
|
+
_emitSessionEvent(previous: any, current: any): void {
|
|
365
442
|
/**
|
|
366
443
|
* Emitted when the user is logged in (This happens as a result of calling
|
|
367
444
|
* {@link Identity#hasSession}, so it is also emitted if the user was previously logged in)
|
|
@@ -423,9 +500,8 @@ export class Identity extends EventEmitter {
|
|
|
423
500
|
/**
|
|
424
501
|
* Close this.popup if it exists and is open
|
|
425
502
|
* @private
|
|
426
|
-
* @returns {void}
|
|
427
503
|
*/
|
|
428
|
-
_closePopup() {
|
|
504
|
+
_closePopup(): void {
|
|
429
505
|
if (this.popup) {
|
|
430
506
|
if (!this.popup.closed) {
|
|
431
507
|
this.popup.close();
|
|
@@ -437,21 +513,19 @@ export class Identity extends EventEmitter {
|
|
|
437
513
|
/**
|
|
438
514
|
* Set the Varnish cookie (`SP_ID`) when hasSession() is called. Note that most browsers require
|
|
439
515
|
* that you are on a "real domain" for this to work — so, **not** `localhost`
|
|
440
|
-
* @param
|
|
441
|
-
* @param
|
|
516
|
+
* @param options
|
|
517
|
+
* @param options.expiresIn Override this to set number of seconds before the varnish
|
|
442
518
|
* cookie expires. The default is to use the same time that hasSession responses are cached for
|
|
443
|
-
* @param
|
|
444
|
-
* @returns {void}
|
|
519
|
+
* @param options.domain Override cookie domain. E.g. «vg.no» instead of «www.vg.no»
|
|
445
520
|
*/
|
|
446
|
-
enableVarnishCookie(options) {
|
|
521
|
+
enableVarnishCookie(options?: { expiresIn?: number; domain?: string }): void {
|
|
447
522
|
let expiresIn = 0;
|
|
448
|
-
let domain;
|
|
523
|
+
let domain: string | undefined;
|
|
449
524
|
if (Number.isInteger(options)) {
|
|
450
|
-
expiresIn = options;
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
domain = options.domain || domain;
|
|
525
|
+
expiresIn = options as any;
|
|
526
|
+
} else if (typeof options == 'object') {
|
|
527
|
+
expiresIn = (options as any).expiresIn || expiresIn;
|
|
528
|
+
domain = (options as any).domain || domain;
|
|
455
529
|
}
|
|
456
530
|
|
|
457
531
|
assert(Number.isInteger(expiresIn), `'expiresIn' must be an integer`);
|
|
@@ -464,25 +538,26 @@ export class Identity extends EventEmitter {
|
|
|
464
538
|
/**
|
|
465
539
|
* Set the Varnish cookie if configured
|
|
466
540
|
* @private
|
|
467
|
-
* @param
|
|
468
|
-
* @returns {void}
|
|
541
|
+
* @param sessionData
|
|
469
542
|
*/
|
|
470
|
-
_maybeSetVarnishCookie(sessionData) {
|
|
543
|
+
_maybeSetVarnishCookie(sessionData: HasSessionSuccessResponse): void {
|
|
471
544
|
if (!this.setVarnishCookie) {
|
|
472
545
|
return;
|
|
473
546
|
}
|
|
474
547
|
const date = new Date();
|
|
475
|
-
const validExpires =
|
|
476
|
-
|
|
548
|
+
const validExpires =
|
|
549
|
+
this.varnishExpiresIn ||
|
|
550
|
+
(typeof sessionData.expiresIn === 'number' && sessionData.expiresIn > 0);
|
|
477
551
|
if (validExpires) {
|
|
478
552
|
const expires = this.varnishExpiresIn || sessionData.expiresIn;
|
|
479
|
-
date.setTime(date.getTime() +
|
|
553
|
+
date.setTime(date.getTime() + expires * 1000);
|
|
480
554
|
} else {
|
|
481
555
|
date.setTime(0);
|
|
482
556
|
}
|
|
483
557
|
|
|
484
558
|
// If the domain is missing or of the wrong type, we'll use document.domain
|
|
485
|
-
|
|
559
|
+
const domain =
|
|
560
|
+
this.varnishCookieDomain ||
|
|
486
561
|
(typeof sessionData.baseDomain === 'string'
|
|
487
562
|
? sessionData.baseDomain
|
|
488
563
|
: document.domain) ||
|
|
@@ -492,7 +567,7 @@ export class Identity extends EventEmitter {
|
|
|
492
567
|
`SP_ID=${sessionData.sp_id}`,
|
|
493
568
|
`expires=${date.toUTCString()}`,
|
|
494
569
|
`path=/`,
|
|
495
|
-
`domain=.${domain}
|
|
570
|
+
`domain=.${domain}`,
|
|
496
571
|
].join('; ');
|
|
497
572
|
document.cookie = cookie;
|
|
498
573
|
}
|
|
@@ -500,9 +575,8 @@ export class Identity extends EventEmitter {
|
|
|
500
575
|
/**
|
|
501
576
|
* Clear the Varnish cookie if configured
|
|
502
577
|
* @private
|
|
503
|
-
* @returns {void}
|
|
504
578
|
*/
|
|
505
|
-
_maybeClearVarnishCookie() {
|
|
579
|
+
_maybeClearVarnishCookie(): void {
|
|
506
580
|
if (this.setVarnishCookie) {
|
|
507
581
|
this._clearVarnishCookie();
|
|
508
582
|
}
|
|
@@ -511,16 +585,14 @@ export class Identity extends EventEmitter {
|
|
|
511
585
|
/**
|
|
512
586
|
* Clear the Varnish cookie
|
|
513
587
|
* @private
|
|
514
|
-
* @returns {void}
|
|
515
588
|
*/
|
|
516
|
-
_clearVarnishCookie() {
|
|
517
|
-
const baseDomain =
|
|
518
|
-
|
|
519
|
-
|
|
589
|
+
_clearVarnishCookie(): void {
|
|
590
|
+
const baseDomain =
|
|
591
|
+
this._session && typeof this._session.baseDomain === 'string'
|
|
592
|
+
? this._session.baseDomain
|
|
593
|
+
: document.domain;
|
|
520
594
|
|
|
521
|
-
|
|
522
|
-
baseDomain ||
|
|
523
|
-
'';
|
|
595
|
+
const domain = this.varnishCookieDomain || baseDomain || '';
|
|
524
596
|
|
|
525
597
|
document.cookie = `SP_ID=nothing; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.${domain}`;
|
|
526
598
|
}
|
|
@@ -528,9 +600,8 @@ export class Identity extends EventEmitter {
|
|
|
528
600
|
/**
|
|
529
601
|
* Log used settings and version
|
|
530
602
|
* @throws {SDKError} - If log method is not provided
|
|
531
|
-
* @return {void}
|
|
532
603
|
*/
|
|
533
|
-
logSettings() {
|
|
604
|
+
logSettings(): void {
|
|
534
605
|
if (!this.log && !window.console) {
|
|
535
606
|
throw new SDKError('You have to provide log method in constructor');
|
|
536
607
|
}
|
|
@@ -542,15 +613,15 @@ export class Identity extends EventEmitter {
|
|
|
542
613
|
redirectUri: this.redirectUri,
|
|
543
614
|
env: this.env,
|
|
544
615
|
sessionDomain: this._sessionDomain,
|
|
545
|
-
sdkVersion: version
|
|
546
|
-
}
|
|
616
|
+
sdkVersion: version,
|
|
617
|
+
};
|
|
547
618
|
|
|
548
619
|
log(`Schibsted account SDK for browsers settings: \n${JSON.stringify(settings, null, 2)}`);
|
|
549
620
|
}
|
|
550
621
|
|
|
551
622
|
/**
|
|
552
623
|
* @summary Queries the hassession endpoint and returns information about the status of the user
|
|
553
|
-
* @
|
|
624
|
+
* @remarks When we send a request to this endpoint, cookies sent along with the request
|
|
554
625
|
* determines the status of the user.
|
|
555
626
|
* @throws {SDKError} - If the call to the hasSession service fails in any way (this will happen
|
|
556
627
|
* if, say, the user is not logged in)
|
|
@@ -562,19 +633,20 @@ export class Identity extends EventEmitter {
|
|
|
562
633
|
* @fires Identity#sessionInit
|
|
563
634
|
* @fires Identity#statusChange
|
|
564
635
|
* @fires Identity#error
|
|
565
|
-
* @return {Promise<HasSessionSuccessResponse|HasSessionFailureResponse>}
|
|
566
636
|
*/
|
|
567
|
-
hasSession() {
|
|
568
|
-
const isSessionCallBlocked = this._isSessionCallBlocked()
|
|
637
|
+
hasSession(): Promise<HasSessionSuccessResponse | HasSessionFailureResponse> {
|
|
638
|
+
const isSessionCallBlocked = this._isSessionCallBlocked();
|
|
569
639
|
if (isSessionCallBlocked) {
|
|
570
640
|
return this._session;
|
|
571
641
|
}
|
|
572
642
|
|
|
573
643
|
if (this._hasSessionInProgress) {
|
|
574
|
-
return this._hasSessionInProgress
|
|
644
|
+
return this._hasSessionInProgress as Promise<
|
|
645
|
+
HasSessionSuccessResponse | HasSessionFailureResponse
|
|
646
|
+
>;
|
|
575
647
|
}
|
|
576
648
|
|
|
577
|
-
const _postProcess = (sessionData) => {
|
|
649
|
+
const _postProcess = (sessionData: any) => {
|
|
578
650
|
if (sessionData.error) {
|
|
579
651
|
throw new SDKError('HasSession failed', sessionData.error);
|
|
580
652
|
}
|
|
@@ -584,25 +656,27 @@ export class Identity extends EventEmitter {
|
|
|
584
656
|
return sessionData;
|
|
585
657
|
};
|
|
586
658
|
|
|
587
|
-
const _checkRedirectionNeed = (sessionData={})=>{
|
|
659
|
+
const _checkRedirectionNeed = (sessionData: any = {}) => {
|
|
588
660
|
const sessionDataKeys = Object.keys(sessionData);
|
|
589
661
|
|
|
590
|
-
return sessionDataKeys.length === 1 &&
|
|
591
|
-
|
|
592
|
-
}
|
|
662
|
+
return sessionDataKeys.length === 1 && sessionDataKeys[0] === 'redirectURL';
|
|
663
|
+
};
|
|
593
664
|
|
|
594
665
|
const _getSession = async () => {
|
|
595
666
|
if (this._enableSessionCaching) {
|
|
596
667
|
// Try to resolve from cache (it has a TTL)
|
|
597
|
-
|
|
668
|
+
const cachedSession = this.sessionStorageCache.get(HAS_SESSION_CACHE_KEY);
|
|
598
669
|
if (cachedSession) {
|
|
599
670
|
return _postProcess(cachedSession);
|
|
600
671
|
}
|
|
601
672
|
}
|
|
602
673
|
let sessionData = null;
|
|
603
674
|
try {
|
|
604
|
-
sessionData = await this._sessionService.get(
|
|
605
|
-
|
|
675
|
+
sessionData = await this._sessionService.get(
|
|
676
|
+
this._usedSessionServiceGetSessionEndpoint,
|
|
677
|
+
{ tabId: this._getTabId() },
|
|
678
|
+
);
|
|
679
|
+
} catch (err: any) {
|
|
606
680
|
if (err && err.code === 400 && this._enableSessionCaching) {
|
|
607
681
|
const expiresIn = 1000 * (err.expiresIn || 300);
|
|
608
682
|
this.sessionStorageCache.set(HAS_SESSION_CACHE_KEY, { error: err }, expiresIn);
|
|
@@ -613,14 +687,16 @@ export class Identity extends EventEmitter {
|
|
|
613
687
|
throw err;
|
|
614
688
|
}
|
|
615
689
|
|
|
616
|
-
if (sessionData){
|
|
690
|
+
if (sessionData) {
|
|
617
691
|
// for expiring session and safari browser do full page redirect to gain new session
|
|
618
|
-
if(_checkRedirectionNeed(sessionData)){
|
|
692
|
+
if (_checkRedirectionNeed(sessionData)) {
|
|
619
693
|
this._blockSessionCall();
|
|
620
694
|
|
|
621
695
|
await this.callbackBeforeRedirect();
|
|
622
696
|
|
|
623
|
-
return this._sessionService.makeUrl(sessionData.redirectURL, {
|
|
697
|
+
return this._sessionService.makeUrl(sessionData.redirectURL, {
|
|
698
|
+
tabId: this._getTabId(),
|
|
699
|
+
});
|
|
624
700
|
}
|
|
625
701
|
|
|
626
702
|
if (this._enableSessionCaching) {
|
|
@@ -631,35 +707,35 @@ export class Identity extends EventEmitter {
|
|
|
631
707
|
|
|
632
708
|
return _postProcess(sessionData);
|
|
633
709
|
};
|
|
634
|
-
this._hasSessionInProgress = _getSession()
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
this._hasSessionInProgress = false;
|
|
638
|
-
|
|
639
|
-
if (isUrl(sessionData)) {
|
|
640
|
-
return this.window.location.href = sessionData;
|
|
641
|
-
}
|
|
710
|
+
this._hasSessionInProgress = _getSession().then(
|
|
711
|
+
(sessionData) => {
|
|
712
|
+
this._hasSessionInProgress = false;
|
|
642
713
|
|
|
714
|
+
if (isUrl(sessionData)) {
|
|
715
|
+
this.window.location.href = sessionData;
|
|
643
716
|
return sessionData;
|
|
644
|
-
},
|
|
645
|
-
err => {
|
|
646
|
-
this.emit('error', err);
|
|
647
|
-
this._hasSessionInProgress = false;
|
|
648
|
-
throw new SDKError('HasSession failed', err);
|
|
649
717
|
}
|
|
650
|
-
);
|
|
651
718
|
|
|
652
|
-
|
|
719
|
+
return sessionData;
|
|
720
|
+
},
|
|
721
|
+
(err) => {
|
|
722
|
+
this.emit('error', err);
|
|
723
|
+
this._hasSessionInProgress = false;
|
|
724
|
+
throw new SDKError('HasSession failed', err);
|
|
725
|
+
},
|
|
726
|
+
);
|
|
727
|
+
|
|
728
|
+
return this._hasSessionInProgress as Promise<
|
|
729
|
+
HasSessionSuccessResponse | HasSessionFailureResponse
|
|
730
|
+
>;
|
|
653
731
|
}
|
|
654
732
|
|
|
655
733
|
/**
|
|
656
|
-
* @async
|
|
657
734
|
* @summary Allows the client app to check if the user is logged in to Schibsted account
|
|
658
|
-
* @
|
|
735
|
+
* @remarks This function calls {@link Identity#hasSession} internally and thus has the side
|
|
659
736
|
* effect that it might perform an auto-login on the user
|
|
660
|
-
* @return {Promise<boolean>}
|
|
661
737
|
*/
|
|
662
|
-
async isLoggedIn() {
|
|
738
|
+
async isLoggedIn(): Promise<boolean> {
|
|
663
739
|
try {
|
|
664
740
|
const data = await this.hasSession();
|
|
665
741
|
return 'result' in data;
|
|
@@ -670,25 +746,22 @@ export class Identity extends EventEmitter {
|
|
|
670
746
|
|
|
671
747
|
/**
|
|
672
748
|
* Removes the cached user session.
|
|
673
|
-
* @returns {void}
|
|
674
749
|
*/
|
|
675
|
-
clearCachedUserSession() {
|
|
750
|
+
clearCachedUserSession(): void {
|
|
676
751
|
this.sessionStorageCache.delete(HAS_SESSION_CACHE_KEY);
|
|
677
752
|
}
|
|
678
753
|
|
|
679
754
|
/**
|
|
680
|
-
* @async
|
|
681
755
|
* @summary Allows the caller to check if the current user is connected to the client_id in
|
|
682
756
|
* Schibsted account. Being connected means that the user has agreed for their account to be
|
|
683
757
|
* used by your web app and have accepted the required terms
|
|
684
|
-
* @
|
|
758
|
+
* @remarks This function calls {@link Identity#hasSession} internally and thus has the side
|
|
685
759
|
* effect that it might perform an auto-login on the user
|
|
686
760
|
* @summary Check if the user is connected to the client_id
|
|
687
|
-
* @return {Promise<boolean>}
|
|
688
761
|
*/
|
|
689
|
-
async isConnected() {
|
|
762
|
+
async isConnected(): Promise<boolean> {
|
|
690
763
|
try {
|
|
691
|
-
const data = await this.hasSession();
|
|
764
|
+
const data = (await this.hasSession()) as any;
|
|
692
765
|
// if data is not an object, the promise will fail.
|
|
693
766
|
// if the result is present, it's boolean. But if it's not, it should be assumed false.
|
|
694
767
|
return !!data.result;
|
|
@@ -698,16 +771,14 @@ export class Identity extends EventEmitter {
|
|
|
698
771
|
}
|
|
699
772
|
|
|
700
773
|
/**
|
|
701
|
-
* @async
|
|
702
774
|
* @summary Returns information about the user
|
|
703
|
-
* @
|
|
775
|
+
* @remarks This function calls {@link Identity#hasSession} internally and thus has the side
|
|
704
776
|
* effect that it might perform an auto-login on the user
|
|
705
777
|
* @throws {SDKError} If the user isn't connected to the merchant
|
|
706
778
|
* @throws {SDKError} If we couldn't get the user
|
|
707
|
-
* @return {Promise<HasSessionSuccessResponse>}
|
|
708
779
|
*/
|
|
709
|
-
async getUser() {
|
|
710
|
-
const user = await this.hasSession();
|
|
780
|
+
async getUser(): Promise<HasSessionSuccessResponse> {
|
|
781
|
+
const user = (await this.hasSession()) as any;
|
|
711
782
|
if (!user.result) {
|
|
712
783
|
throw new SDKError('The user is not connected to this merchant');
|
|
713
784
|
}
|
|
@@ -715,7 +786,6 @@ export class Identity extends EventEmitter {
|
|
|
715
786
|
}
|
|
716
787
|
|
|
717
788
|
/**
|
|
718
|
-
* @async
|
|
719
789
|
* @summary
|
|
720
790
|
* In Schibsted account, there are multiple ways of identifying a user; the `userId`,
|
|
721
791
|
* `uuid` and `externalId` used for identifying a user-merchant pair (see {@link Identity#getExternalId}).
|
|
@@ -724,13 +794,13 @@ export class Identity extends EventEmitter {
|
|
|
724
794
|
* duplicates. The `userId` was introduced early, so many sites still need to use them for
|
|
725
795
|
* legacy reasons. The `uuid` is universally unique, and so — if we could disregard a lot of
|
|
726
796
|
* Schibsted components depending on the numeric `userId` — it would be a good identifier to use
|
|
727
|
-
* @
|
|
797
|
+
* @remarks This function calls {@link Identity#hasSession} internally and thus has the side
|
|
728
798
|
* effect that it might perform an auto-login on the user
|
|
729
799
|
* @throws {SDKError} If the user isn't connected to the merchant
|
|
730
|
-
* @return
|
|
800
|
+
* @return The `userId` field (not to be confused with the `uuid`)
|
|
731
801
|
*/
|
|
732
|
-
async getUserId() {
|
|
733
|
-
const user = await this.hasSession();
|
|
802
|
+
async getUserId(): Promise<string> {
|
|
803
|
+
const user = (await this.hasSession()) as any;
|
|
734
804
|
if (user.userId && user.result) {
|
|
735
805
|
return user.userId;
|
|
736
806
|
}
|
|
@@ -738,7 +808,6 @@ export class Identity extends EventEmitter {
|
|
|
738
808
|
}
|
|
739
809
|
|
|
740
810
|
/**
|
|
741
|
-
* @async
|
|
742
811
|
* @function
|
|
743
812
|
* @summary
|
|
744
813
|
* Retrieves the external identifier (`externalId`) for the authenticated user.
|
|
@@ -751,58 +820,55 @@ export class Identity extends EventEmitter {
|
|
|
751
820
|
* meaning the same user's ID will differ between merchants.
|
|
752
821
|
* Additionally, this identifier is bound to the external party provided as argument.
|
|
753
822
|
*
|
|
754
|
-
* @param
|
|
755
|
-
* @param
|
|
756
|
-
* @
|
|
823
|
+
* @param externalParty
|
|
824
|
+
* @param optionalSuffix
|
|
825
|
+
* @remarks This function calls {@link Identity#hasSession} internally and thus has the side
|
|
757
826
|
* effect that it might perform an auto-login on the user
|
|
758
827
|
* @throws {SDKError} If the `pairId` is missing in user session.
|
|
759
828
|
* @throws {SDKError} If the `externalParty` is not defined
|
|
760
|
-
* @return
|
|
829
|
+
* @return The merchant- and 3rd-party-specific `externalId`
|
|
761
830
|
*/
|
|
762
|
-
async getExternalId(externalParty, optionalSuffix =
|
|
763
|
-
const { pairId } = await this.hasSession();
|
|
831
|
+
async getExternalId(externalParty: string, optionalSuffix: string = ''): Promise<string> {
|
|
832
|
+
const { pairId } = (await this.hasSession()) as any;
|
|
764
833
|
|
|
765
|
-
if (!pairId)
|
|
766
|
-
throw new SDKError('pairId missing in user session!');
|
|
834
|
+
if (!pairId) throw new SDKError('pairId missing in user session!');
|
|
767
835
|
|
|
768
|
-
if(!externalParty || externalParty.length === 0) {
|
|
836
|
+
if (!externalParty || externalParty.length === 0) {
|
|
769
837
|
throw new SDKError('externalParty cannot be empty');
|
|
770
838
|
}
|
|
771
|
-
const _toHexDigest = (hashBuffer) =>{
|
|
839
|
+
const _toHexDigest = (hashBuffer: any) => {
|
|
772
840
|
// convert buffer to byte array
|
|
773
841
|
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
774
842
|
// convert bytes to hex string
|
|
775
|
-
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
|
776
|
-
}
|
|
843
|
+
return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
|
|
844
|
+
};
|
|
777
845
|
|
|
778
|
-
const _getSha256Digest = (data) => {
|
|
846
|
+
const _getSha256Digest = (data: any) => {
|
|
779
847
|
return crypto.subtle.digest('SHA-256', data);
|
|
780
|
-
}
|
|
848
|
+
};
|
|
781
849
|
|
|
782
|
-
const _hashMessage = async (message) => {
|
|
850
|
+
const _hashMessage = async (message: any) => {
|
|
783
851
|
const msgUint8 = new TextEncoder().encode(message);
|
|
784
|
-
return _getSha256Digest(msgUint8).then(
|
|
785
|
-
}
|
|
852
|
+
return _getSha256Digest(msgUint8).then((it: any) => _toHexDigest(it));
|
|
853
|
+
};
|
|
786
854
|
|
|
787
|
-
const _constructMessage = (pairId, externalParty, optionalSuffix) => {
|
|
855
|
+
const _constructMessage = (pairId: any, externalParty: any, optionalSuffix: any) => {
|
|
788
856
|
return optionalSuffix
|
|
789
857
|
? `${pairId}:${externalParty}:${optionalSuffix}`
|
|
790
858
|
: `${pairId}:${externalParty}`;
|
|
791
|
-
}
|
|
859
|
+
};
|
|
792
860
|
|
|
793
|
-
return _hashMessage(_constructMessage(pairId, externalParty, optionalSuffix))
|
|
861
|
+
return _hashMessage(_constructMessage(pairId, externalParty, optionalSuffix));
|
|
794
862
|
}
|
|
795
863
|
|
|
796
864
|
/**
|
|
797
|
-
* @async
|
|
798
865
|
* @summary Enables brands to programmatically get the current the SDRN based on the user's session.
|
|
799
|
-
* @
|
|
866
|
+
* @remarks This function calls {@link Identity#hasSession} internally and thus has the side
|
|
800
867
|
* effect that it might perform an auto-login on the user
|
|
801
868
|
* @throws {SDKError} If the SDRN is missing in user session object.
|
|
802
|
-
* @returns {Promise<string>}
|
|
803
869
|
*/
|
|
804
|
-
async getUserSDRN() {
|
|
805
|
-
const { sdrn } = await this.hasSession();
|
|
870
|
+
async getUserSDRN(): Promise<string> {
|
|
871
|
+
const { sdrn } = (await this.hasSession()) as any;
|
|
806
872
|
if (sdrn) {
|
|
807
873
|
return sdrn;
|
|
808
874
|
}
|
|
@@ -810,20 +876,19 @@ export class Identity extends EventEmitter {
|
|
|
810
876
|
}
|
|
811
877
|
|
|
812
878
|
/**
|
|
813
|
-
* @async
|
|
814
879
|
* @summary In Schibsted account, there are two ways of identifying a user; the `userId` and the
|
|
815
880
|
* `uuid`. There are reasons for them both existing. The `userId` is a numeric identifier, but
|
|
816
881
|
* since Schibsted account is deployed separately in Norway and Sweden, there are a lot of
|
|
817
882
|
* duplicates. The `userId` was introduced early, so many sites still need to use them for
|
|
818
883
|
* legacy reasons. The `uuid` is universally unique, and so — if we could disregard a lot of
|
|
819
884
|
* Schibsted components depending on the numeric `userId` — it would be a good identifier to use
|
|
820
|
-
* @
|
|
885
|
+
* @remarks This function calls {@link Identity#hasSession} internally and thus has the side
|
|
821
886
|
* effect that it might perform an auto-login on the user
|
|
822
887
|
* @throws {SDKError} If the user isn't connected to the merchant
|
|
823
|
-
* @return
|
|
888
|
+
* @return The `uuid` field (not to be confused with the `userId`)
|
|
824
889
|
*/
|
|
825
|
-
async getUserUuid() {
|
|
826
|
-
const user = await this.hasSession();
|
|
890
|
+
async getUserUuid(): Promise<string> {
|
|
891
|
+
const user = (await this.hasSession()) as any;
|
|
827
892
|
if (user.uuid && user.result) {
|
|
828
893
|
return user.uuid;
|
|
829
894
|
}
|
|
@@ -831,16 +896,14 @@ export class Identity extends EventEmitter {
|
|
|
831
896
|
}
|
|
832
897
|
|
|
833
898
|
/**
|
|
834
|
-
* @async
|
|
835
899
|
* @summary Get basic information about any user currently logged-in to their Schibsted account
|
|
836
900
|
* in this browser. Can be used to provide context in a continue-as prompt.
|
|
837
|
-
* @
|
|
901
|
+
* @remarks This function relies on the global Schibsted account user session cookie, which
|
|
838
902
|
* is a third-party cookie and hence might be blocked by the browser (for example due to ITP in
|
|
839
903
|
* Safari). So there's no guarantee any data is returned, even though a user is logged-in in
|
|
840
904
|
* the current browser.
|
|
841
|
-
* @return {Promise<SimplifiedLoginData|null>}
|
|
842
905
|
*/
|
|
843
|
-
async getUserContextData() {
|
|
906
|
+
async getUserContextData(): Promise<SimplifiedLoginData | null> {
|
|
844
907
|
try {
|
|
845
908
|
return await this._globalSessionService.get('user-context');
|
|
846
909
|
} catch (_) {
|
|
@@ -855,23 +918,23 @@ export class Identity extends EventEmitter {
|
|
|
855
918
|
* @summary Perform a login, either using a full-page redirect or a popup
|
|
856
919
|
* @see https://tools.ietf.org/html/rfc6749#section-4.1.1
|
|
857
920
|
*
|
|
858
|
-
* @param
|
|
859
|
-
* @param
|
|
860
|
-
* @param
|
|
861
|
-
* @param
|
|
862
|
-
* @param
|
|
863
|
-
* @param
|
|
864
|
-
* @param
|
|
865
|
-
* @param
|
|
866
|
-
* @param
|
|
867
|
-
* @param
|
|
868
|
-
* @param
|
|
869
|
-
* @param
|
|
870
|
-
* @param
|
|
871
|
-
* @param
|
|
872
|
-
* @param
|
|
873
|
-
* @param
|
|
874
|
-
* @return
|
|
921
|
+
* @param options
|
|
922
|
+
* @param options.state
|
|
923
|
+
* @param options.acrValues
|
|
924
|
+
* @param options.scope
|
|
925
|
+
* @param options.redirectUri
|
|
926
|
+
* @param options.preferPopup
|
|
927
|
+
* @param options.loginHint
|
|
928
|
+
* @param options.tag
|
|
929
|
+
* @param options.teaser
|
|
930
|
+
* @param options.maxAge
|
|
931
|
+
* @param options.locale
|
|
932
|
+
* @param options.oneStepLogin
|
|
933
|
+
* @param options.prompt
|
|
934
|
+
* @param options.xDomainId
|
|
935
|
+
* @param options.xEnvironmentId
|
|
936
|
+
* @param options.originCampaign
|
|
937
|
+
* @return - Reference to popup window if created (or `null` otherwise)
|
|
875
938
|
*/
|
|
876
939
|
login({
|
|
877
940
|
state,
|
|
@@ -888,8 +951,8 @@ export class Identity extends EventEmitter {
|
|
|
888
951
|
prompt = 'select_account',
|
|
889
952
|
xDomainId = '',
|
|
890
953
|
xEnvironmentId = '',
|
|
891
|
-
originCampaign = ''
|
|
892
|
-
}) {
|
|
954
|
+
originCampaign = '',
|
|
955
|
+
}: LoginOptions): Window | null {
|
|
893
956
|
this._closePopup();
|
|
894
957
|
this.sessionStorageCache.delete(HAS_SESSION_CACHE_KEY);
|
|
895
958
|
const url = this.loginUrl({
|
|
@@ -906,12 +969,14 @@ export class Identity extends EventEmitter {
|
|
|
906
969
|
prompt,
|
|
907
970
|
xDomainId,
|
|
908
971
|
xEnvironmentId,
|
|
909
|
-
originCampaign
|
|
972
|
+
originCampaign,
|
|
910
973
|
});
|
|
911
974
|
|
|
912
975
|
if (preferPopup) {
|
|
913
|
-
this.popup =
|
|
914
|
-
|
|
976
|
+
this.popup = popup.open(this.window, url, 'Schibsted account', {
|
|
977
|
+
width: 360,
|
|
978
|
+
height: 570,
|
|
979
|
+
});
|
|
915
980
|
if (this.popup) {
|
|
916
981
|
return this.popup;
|
|
917
982
|
}
|
|
@@ -921,15 +986,14 @@ export class Identity extends EventEmitter {
|
|
|
921
986
|
}
|
|
922
987
|
|
|
923
988
|
/**
|
|
924
|
-
* @async
|
|
925
989
|
* @summary Retrieve the sp_id (Varnish ID)
|
|
926
|
-
* @
|
|
990
|
+
* @remarks This function calls {@link Identity#hasSession} internally and thus has the side
|
|
927
991
|
* effect that it might perform an auto-login on the user
|
|
928
|
-
* @return
|
|
992
|
+
* @return - The sp_id string or null (if the server didn't return it)
|
|
929
993
|
*/
|
|
930
|
-
async getSpId() {
|
|
994
|
+
async getSpId(): Promise<string | null> {
|
|
931
995
|
try {
|
|
932
|
-
const user = await this.hasSession();
|
|
996
|
+
const user = (await this.hasSession()) as any;
|
|
933
997
|
return user.sp_id || null;
|
|
934
998
|
} catch (_) {
|
|
935
999
|
return null;
|
|
@@ -938,11 +1002,10 @@ export class Identity extends EventEmitter {
|
|
|
938
1002
|
|
|
939
1003
|
/**
|
|
940
1004
|
* @summary Logs the user out from the Identity platform
|
|
941
|
-
* @param
|
|
1005
|
+
* @param redirectUri - Where to redirect the browser after logging out of Schibsted
|
|
942
1006
|
* account
|
|
943
|
-
* @return {void}
|
|
944
1007
|
*/
|
|
945
|
-
logout(redirectUri = this.redirectUri) {
|
|
1008
|
+
logout(redirectUri: string = this.redirectUri): void {
|
|
946
1009
|
this.sessionStorageCache.delete(HAS_SESSION_CACHE_KEY);
|
|
947
1010
|
this._maybeClearVarnishCookie();
|
|
948
1011
|
this.emit('logout');
|
|
@@ -951,39 +1014,42 @@ export class Identity extends EventEmitter {
|
|
|
951
1014
|
|
|
952
1015
|
/**
|
|
953
1016
|
* Generates the link to the new login page that'll be used in the popup or redirect flow
|
|
954
|
-
* @param
|
|
955
|
-
* @param
|
|
956
|
-
* @param
|
|
957
|
-
* @param
|
|
958
|
-
* @param
|
|
959
|
-
* @param
|
|
960
|
-
* @param
|
|
961
|
-
* @param
|
|
962
|
-
* @param
|
|
963
|
-
* @param
|
|
964
|
-
* @param
|
|
965
|
-
* @param
|
|
966
|
-
* @param
|
|
967
|
-
* @param
|
|
968
|
-
* @param
|
|
969
|
-
* @return
|
|
1017
|
+
* @param options
|
|
1018
|
+
* @param options.state
|
|
1019
|
+
* @param options.acrValues
|
|
1020
|
+
* @param options.scope
|
|
1021
|
+
* @param options.redirectUri
|
|
1022
|
+
* @param options.loginHint
|
|
1023
|
+
* @param options.tag
|
|
1024
|
+
* @param options.teaser
|
|
1025
|
+
* @param options.maxAge
|
|
1026
|
+
* @param options.locale
|
|
1027
|
+
* @param options.oneStepLogin
|
|
1028
|
+
* @param options.prompt
|
|
1029
|
+
* @param options.xDomainId
|
|
1030
|
+
* @param options.xEnvironmentId
|
|
1031
|
+
* @param options.originCampaign
|
|
1032
|
+
* @return - The url
|
|
970
1033
|
*/
|
|
971
|
-
loginUrl(
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
1034
|
+
loginUrl(
|
|
1035
|
+
{
|
|
1036
|
+
state,
|
|
1037
|
+
acrValues = '',
|
|
1038
|
+
scope = 'openid',
|
|
1039
|
+
redirectUri = this.redirectUri,
|
|
1040
|
+
loginHint = '',
|
|
1041
|
+
tag = '',
|
|
1042
|
+
teaser = '',
|
|
1043
|
+
maxAge = '',
|
|
1044
|
+
locale = '',
|
|
1045
|
+
oneStepLogin = false,
|
|
1046
|
+
prompt = 'select_account',
|
|
1047
|
+
xDomainId = '',
|
|
1048
|
+
xEnvironmentId = '',
|
|
1049
|
+
originCampaign = '',
|
|
1050
|
+
}: LoginOptions,
|
|
1051
|
+
..._args: any[]
|
|
1052
|
+
): string {
|
|
987
1053
|
if (typeof arguments[0] !== 'object') {
|
|
988
1054
|
// backward compatibility
|
|
989
1055
|
state = arguments[0];
|
|
@@ -995,13 +1061,26 @@ export class Identity extends EventEmitter {
|
|
|
995
1061
|
teaser = arguments[6] || teaser;
|
|
996
1062
|
maxAge = isNaN(arguments[7]) ? maxAge : arguments[7];
|
|
997
1063
|
}
|
|
998
|
-
const isValidAcrValue = (acrValue) =>
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1064
|
+
const isValidAcrValue = (acrValue: any) =>
|
|
1065
|
+
isStrIn(
|
|
1066
|
+
acrValue,
|
|
1067
|
+
['password', 'otp', 'sms', 'eid-dk', 'eid-no', 'eid-se', 'eid-fi', 'eid'],
|
|
1068
|
+
true,
|
|
1069
|
+
);
|
|
1070
|
+
assert(
|
|
1071
|
+
!acrValues ||
|
|
1072
|
+
isStrIn(acrValues, ['', 'otp-email'], true) ||
|
|
1073
|
+
acrValues.split(' ').every(isValidAcrValue),
|
|
1074
|
+
`The acrValues parameter is not acceptable: ${acrValues}`,
|
|
1075
|
+
);
|
|
1076
|
+
assert(
|
|
1077
|
+
isUrl(redirectUri as string),
|
|
1078
|
+
`loginUrl(): redirectUri must be a valid url but is ${redirectUri}`,
|
|
1079
|
+
);
|
|
1080
|
+
assert(
|
|
1081
|
+
isNonEmptyString(state),
|
|
1082
|
+
`the state parameter should be a non empty string but it is ${state}`,
|
|
1083
|
+
);
|
|
1005
1084
|
|
|
1006
1085
|
return this._oauthService.makeUrl('oauth/authorize', {
|
|
1007
1086
|
response_type: 'code',
|
|
@@ -1018,16 +1097,16 @@ export class Identity extends EventEmitter {
|
|
|
1018
1097
|
prompt: acrValues ? '' : prompt,
|
|
1019
1098
|
x_domain_id: xDomainId,
|
|
1020
1099
|
x_env_id: xEnvironmentId,
|
|
1021
|
-
utm_campaign: originCampaign
|
|
1100
|
+
utm_campaign: originCampaign,
|
|
1022
1101
|
});
|
|
1023
1102
|
}
|
|
1024
1103
|
|
|
1025
1104
|
/**
|
|
1026
1105
|
* The url for logging the user out
|
|
1027
|
-
* @param
|
|
1028
|
-
* @return
|
|
1106
|
+
* @param redirectUri
|
|
1107
|
+
* @return url
|
|
1029
1108
|
*/
|
|
1030
|
-
logoutUrl(redirectUri = this.redirectUri) {
|
|
1109
|
+
logoutUrl(redirectUri: string = this.redirectUri): string {
|
|
1031
1110
|
assert(isUrl(redirectUri), `logoutUrl(): redirectUri is invalid`);
|
|
1032
1111
|
const params = { redirect_uri: redirectUri };
|
|
1033
1112
|
return this._sessionService.makeUrl('logout', params);
|
|
@@ -1035,25 +1114,23 @@ export class Identity extends EventEmitter {
|
|
|
1035
1114
|
|
|
1036
1115
|
/**
|
|
1037
1116
|
* The account summary page url
|
|
1038
|
-
* @param
|
|
1039
|
-
* @return {string}
|
|
1117
|
+
* @param redirectUri
|
|
1040
1118
|
*/
|
|
1041
|
-
accountUrl(redirectUri = this.redirectUri) {
|
|
1119
|
+
accountUrl(redirectUri: string = this.redirectUri): string {
|
|
1042
1120
|
return this._spid.makeUrl('profile-pages', {
|
|
1043
1121
|
response_type: 'code',
|
|
1044
|
-
redirect_uri: redirectUri
|
|
1122
|
+
redirect_uri: redirectUri,
|
|
1045
1123
|
});
|
|
1046
1124
|
}
|
|
1047
1125
|
|
|
1048
1126
|
/**
|
|
1049
1127
|
* The phone editing page url
|
|
1050
|
-
* @param
|
|
1051
|
-
* @return {string}
|
|
1128
|
+
* @param redirectUri
|
|
1052
1129
|
*/
|
|
1053
|
-
phonesUrl(redirectUri = this.redirectUri) {
|
|
1130
|
+
phonesUrl(redirectUri: string = this.redirectUri): string {
|
|
1054
1131
|
return this._spid.makeUrl('profile-pages/about-you/phone', {
|
|
1055
1132
|
response_type: 'code',
|
|
1056
|
-
redirect_uri: redirectUri
|
|
1133
|
+
redirect_uri: redirectUri,
|
|
1057
1134
|
});
|
|
1058
1135
|
}
|
|
1059
1136
|
|
|
@@ -1062,95 +1139,117 @@ export class Identity extends EventEmitter {
|
|
|
1062
1139
|
* widget will be display is up to you. Preferred way would be to show it once per user,
|
|
1063
1140
|
* and store that info in localStorage. Widget will be display only if user is logged in to SSO.
|
|
1064
1141
|
*
|
|
1065
|
-
* @
|
|
1066
|
-
* @param {SimplifiedLoginWidgetLoginOptions} loginParams - the same as `options` param for login function. Login will be called on user
|
|
1142
|
+
* @param loginParams - the same as `options` param for login function. Login will be called on user
|
|
1067
1143
|
* continue action. `state` might be string or async function.
|
|
1068
|
-
* @param
|
|
1144
|
+
* @param options - additional configuration of Simplified Login Widget
|
|
1069
1145
|
* @fires Identity#simplifiedLoginOpened
|
|
1070
1146
|
* @fires Identity#simplifiedLoginCancelled
|
|
1071
|
-
* @return
|
|
1147
|
+
* @return - will resolve to true if widget will be display. Otherwise, will throw SDKError
|
|
1072
1148
|
*/
|
|
1073
|
-
async showSimplifiedLoginWidget(
|
|
1149
|
+
async showSimplifiedLoginWidget(
|
|
1150
|
+
loginParams: SimplifiedLoginWidgetLoginOptions,
|
|
1151
|
+
options?: SimplifiedLoginWidgetOptions,
|
|
1152
|
+
): Promise<boolean | SDKError> {
|
|
1074
1153
|
// getUserContextData doesn't throw exception
|
|
1075
1154
|
const userData = await this.getUserContextData();
|
|
1076
1155
|
|
|
1077
|
-
const queryParams = { client_id: this.clientId };
|
|
1156
|
+
const queryParams: Record<string, string> = { client_id: this.clientId };
|
|
1078
1157
|
if (options && options.encoding) {
|
|
1079
1158
|
queryParams.encoding = options.encoding;
|
|
1080
1159
|
}
|
|
1081
1160
|
const widgetUrl = this._bffService.makeUrl('simplified-login-widget', queryParams, false);
|
|
1082
1161
|
|
|
1083
|
-
const prepareLoginParams = async (loginPrams) => {
|
|
1162
|
+
const prepareLoginParams = async (loginPrams: any) => {
|
|
1084
1163
|
if (typeof loginPrams.state === 'function') {
|
|
1085
1164
|
loginPrams.state = await loginPrams.state();
|
|
1086
1165
|
}
|
|
1087
1166
|
|
|
1088
1167
|
return loginPrams;
|
|
1089
|
-
}
|
|
1090
|
-
|
|
1091
|
-
return new Promise(
|
|
1092
|
-
(resolve, reject) => {
|
|
1093
|
-
if (!userData || !userData.display_text || !userData.identifier) {
|
|
1094
|
-
return reject(new SDKError('Missing user data'));
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
const initialParams = {
|
|
1098
|
-
displayText: userData.display_text,
|
|
1099
|
-
env: this.env,
|
|
1100
|
-
clientName: userData.client_name,
|
|
1101
|
-
clientId: this.clientId,
|
|
1102
|
-
providerId: userData.provider_id,
|
|
1103
|
-
windowWidth: () => window.innerWidth,
|
|
1104
|
-
windowOnResize: (f) => {
|
|
1105
|
-
window.onresize = f;
|
|
1106
|
-
},
|
|
1107
|
-
};
|
|
1108
|
-
|
|
1109
|
-
if (options && options.locale) {
|
|
1110
|
-
initialParams.locale = options.locale;
|
|
1111
|
-
}
|
|
1112
|
-
|
|
1113
|
-
const loginHandler = async () => {
|
|
1114
|
-
this.login(Object.assign(await prepareLoginParams(loginParams), {loginHint: userData.identifier}));
|
|
1115
|
-
};
|
|
1168
|
+
};
|
|
1116
1169
|
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1170
|
+
return new Promise((resolve, reject) => {
|
|
1171
|
+
if (!userData || !userData.display_text || !userData.identifier) {
|
|
1172
|
+
return reject(new SDKError('Missing user data'));
|
|
1173
|
+
}
|
|
1120
1174
|
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1175
|
+
const initialParams: Record<string, any> = {
|
|
1176
|
+
displayText: userData.display_text,
|
|
1177
|
+
env: this.env,
|
|
1178
|
+
clientName: userData.client_name,
|
|
1179
|
+
clientId: this.clientId,
|
|
1180
|
+
providerId: (userData as any).provider_id,
|
|
1181
|
+
windowWidth: () => window.innerWidth,
|
|
1182
|
+
windowOnResize: (f: () => void) => {
|
|
1183
|
+
window.onresize = f;
|
|
1184
|
+
},
|
|
1185
|
+
};
|
|
1128
1186
|
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
* @event Identity#simplifiedLoginCancelled
|
|
1133
|
-
*/
|
|
1134
|
-
this.emit('simplifiedLoginCancelled');
|
|
1135
|
-
}
|
|
1187
|
+
if (options && options.locale) {
|
|
1188
|
+
initialParams.locale = options.locale;
|
|
1189
|
+
}
|
|
1136
1190
|
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1191
|
+
const loginHandler = async () => {
|
|
1192
|
+
this.login(
|
|
1193
|
+
Object.assign(await prepareLoginParams(loginParams), {
|
|
1194
|
+
loginHint: userData.identifier,
|
|
1195
|
+
}) as LoginOptions,
|
|
1196
|
+
);
|
|
1197
|
+
};
|
|
1198
|
+
|
|
1199
|
+
const loginNotYouHandler = async () => {
|
|
1200
|
+
this.login(
|
|
1201
|
+
Object.assign(await prepareLoginParams(loginParams), {
|
|
1202
|
+
loginHint: userData.identifier,
|
|
1203
|
+
prompt: 'login',
|
|
1204
|
+
}) as LoginOptions,
|
|
1205
|
+
);
|
|
1206
|
+
};
|
|
1207
|
+
|
|
1208
|
+
const initHandler = () => {
|
|
1209
|
+
/**
|
|
1210
|
+
* Emitted when the simplified login widget is displayed on the screen
|
|
1211
|
+
* @event Identity#simplifiedLoginOpened
|
|
1212
|
+
*/
|
|
1213
|
+
this.emit('simplifiedLoginOpened');
|
|
1214
|
+
};
|
|
1215
|
+
|
|
1216
|
+
const cancelLoginHandler = () => {
|
|
1217
|
+
/**
|
|
1218
|
+
* Emitted when the user closes the simplified login widget
|
|
1219
|
+
* @event Identity#simplifiedLoginCancelled
|
|
1220
|
+
*/
|
|
1221
|
+
this.emit('simplifiedLoginCancelled');
|
|
1222
|
+
};
|
|
1223
|
+
|
|
1224
|
+
if ((window as any).openSimplifiedLoginWidget) {
|
|
1225
|
+
(window as any).openSimplifiedLoginWidget(
|
|
1226
|
+
initialParams,
|
|
1227
|
+
loginHandler,
|
|
1228
|
+
loginNotYouHandler,
|
|
1229
|
+
initHandler,
|
|
1230
|
+
cancelLoginHandler,
|
|
1231
|
+
);
|
|
1232
|
+
return resolve(true);
|
|
1233
|
+
}
|
|
1141
1234
|
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1235
|
+
const simplifiedLoginWidget = document.createElement('script');
|
|
1236
|
+
simplifiedLoginWidget.type = 'text/javascript';
|
|
1237
|
+
simplifiedLoginWidget.src = widgetUrl;
|
|
1238
|
+
simplifiedLoginWidget.onload = () => {
|
|
1239
|
+
(window as any).openSimplifiedLoginWidget(
|
|
1240
|
+
initialParams,
|
|
1241
|
+
loginHandler,
|
|
1242
|
+
loginNotYouHandler,
|
|
1243
|
+
initHandler,
|
|
1244
|
+
cancelLoginHandler,
|
|
1245
|
+
);
|
|
1246
|
+
resolve(true);
|
|
1247
|
+
};
|
|
1248
|
+
simplifiedLoginWidget.onerror = () => {
|
|
1249
|
+
reject(new SDKError('Error when loading simplified login widget content'));
|
|
1250
|
+
};
|
|
1251
|
+
document.getElementsByTagName('body')[0].appendChild(simplifiedLoginWidget);
|
|
1252
|
+
});
|
|
1154
1253
|
}
|
|
1155
1254
|
}
|
|
1156
1255
|
|