@schibsted/account-sdk-browser 6.0.0-alpha.1 → 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 +8 -33
- 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 +38 -22
- 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} +539 -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/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/cache.d.ts +0 -64
- package/src/config.d.ts +0 -34
- 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,40 +656,47 @@ 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);
|
|
683
|
+
} else if (err && err.code >= 500 && err.code < 600 && this._enableSessionCaching) {
|
|
684
|
+
// Temporary fix: 30 seconds cache to limit number of calls when service is unavailable
|
|
685
|
+
this.sessionStorageCache.set(HAS_SESSION_CACHE_KEY, { error: err }, 30 * 1000);
|
|
609
686
|
}
|
|
610
687
|
throw err;
|
|
611
688
|
}
|
|
612
689
|
|
|
613
|
-
if (sessionData){
|
|
690
|
+
if (sessionData) {
|
|
614
691
|
// for expiring session and safari browser do full page redirect to gain new session
|
|
615
|
-
if(_checkRedirectionNeed(sessionData)){
|
|
692
|
+
if (_checkRedirectionNeed(sessionData)) {
|
|
616
693
|
this._blockSessionCall();
|
|
617
694
|
|
|
618
695
|
await this.callbackBeforeRedirect();
|
|
619
696
|
|
|
620
|
-
return this._sessionService.makeUrl(sessionData.redirectURL, {
|
|
697
|
+
return this._sessionService.makeUrl(sessionData.redirectURL, {
|
|
698
|
+
tabId: this._getTabId(),
|
|
699
|
+
});
|
|
621
700
|
}
|
|
622
701
|
|
|
623
702
|
if (this._enableSessionCaching) {
|
|
@@ -628,35 +707,35 @@ export class Identity extends EventEmitter {
|
|
|
628
707
|
|
|
629
708
|
return _postProcess(sessionData);
|
|
630
709
|
};
|
|
631
|
-
this._hasSessionInProgress = _getSession()
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
this._hasSessionInProgress = false;
|
|
635
|
-
|
|
636
|
-
if (isUrl(sessionData)) {
|
|
637
|
-
return this.window.location.href = sessionData;
|
|
638
|
-
}
|
|
710
|
+
this._hasSessionInProgress = _getSession().then(
|
|
711
|
+
(sessionData) => {
|
|
712
|
+
this._hasSessionInProgress = false;
|
|
639
713
|
|
|
714
|
+
if (isUrl(sessionData)) {
|
|
715
|
+
this.window.location.href = sessionData;
|
|
640
716
|
return sessionData;
|
|
641
|
-
},
|
|
642
|
-
err => {
|
|
643
|
-
this.emit('error', err);
|
|
644
|
-
this._hasSessionInProgress = false;
|
|
645
|
-
throw new SDKError('HasSession failed', err);
|
|
646
717
|
}
|
|
647
|
-
);
|
|
648
718
|
|
|
649
|
-
|
|
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
|
+
>;
|
|
650
731
|
}
|
|
651
732
|
|
|
652
733
|
/**
|
|
653
|
-
* @async
|
|
654
734
|
* @summary Allows the client app to check if the user is logged in to Schibsted account
|
|
655
|
-
* @
|
|
735
|
+
* @remarks This function calls {@link Identity#hasSession} internally and thus has the side
|
|
656
736
|
* effect that it might perform an auto-login on the user
|
|
657
|
-
* @return {Promise<boolean>}
|
|
658
737
|
*/
|
|
659
|
-
async isLoggedIn() {
|
|
738
|
+
async isLoggedIn(): Promise<boolean> {
|
|
660
739
|
try {
|
|
661
740
|
const data = await this.hasSession();
|
|
662
741
|
return 'result' in data;
|
|
@@ -667,25 +746,22 @@ export class Identity extends EventEmitter {
|
|
|
667
746
|
|
|
668
747
|
/**
|
|
669
748
|
* Removes the cached user session.
|
|
670
|
-
* @returns {void}
|
|
671
749
|
*/
|
|
672
|
-
clearCachedUserSession() {
|
|
750
|
+
clearCachedUserSession(): void {
|
|
673
751
|
this.sessionStorageCache.delete(HAS_SESSION_CACHE_KEY);
|
|
674
752
|
}
|
|
675
753
|
|
|
676
754
|
/**
|
|
677
|
-
* @async
|
|
678
755
|
* @summary Allows the caller to check if the current user is connected to the client_id in
|
|
679
756
|
* Schibsted account. Being connected means that the user has agreed for their account to be
|
|
680
757
|
* used by your web app and have accepted the required terms
|
|
681
|
-
* @
|
|
758
|
+
* @remarks This function calls {@link Identity#hasSession} internally and thus has the side
|
|
682
759
|
* effect that it might perform an auto-login on the user
|
|
683
760
|
* @summary Check if the user is connected to the client_id
|
|
684
|
-
* @return {Promise<boolean>}
|
|
685
761
|
*/
|
|
686
|
-
async isConnected() {
|
|
762
|
+
async isConnected(): Promise<boolean> {
|
|
687
763
|
try {
|
|
688
|
-
const data = await this.hasSession();
|
|
764
|
+
const data = (await this.hasSession()) as any;
|
|
689
765
|
// if data is not an object, the promise will fail.
|
|
690
766
|
// if the result is present, it's boolean. But if it's not, it should be assumed false.
|
|
691
767
|
return !!data.result;
|
|
@@ -695,16 +771,14 @@ export class Identity extends EventEmitter {
|
|
|
695
771
|
}
|
|
696
772
|
|
|
697
773
|
/**
|
|
698
|
-
* @async
|
|
699
774
|
* @summary Returns information about the user
|
|
700
|
-
* @
|
|
775
|
+
* @remarks This function calls {@link Identity#hasSession} internally and thus has the side
|
|
701
776
|
* effect that it might perform an auto-login on the user
|
|
702
777
|
* @throws {SDKError} If the user isn't connected to the merchant
|
|
703
778
|
* @throws {SDKError} If we couldn't get the user
|
|
704
|
-
* @return {Promise<HasSessionSuccessResponse>}
|
|
705
779
|
*/
|
|
706
|
-
async getUser() {
|
|
707
|
-
const user = await this.hasSession();
|
|
780
|
+
async getUser(): Promise<HasSessionSuccessResponse> {
|
|
781
|
+
const user = (await this.hasSession()) as any;
|
|
708
782
|
if (!user.result) {
|
|
709
783
|
throw new SDKError('The user is not connected to this merchant');
|
|
710
784
|
}
|
|
@@ -712,7 +786,6 @@ export class Identity extends EventEmitter {
|
|
|
712
786
|
}
|
|
713
787
|
|
|
714
788
|
/**
|
|
715
|
-
* @async
|
|
716
789
|
* @summary
|
|
717
790
|
* In Schibsted account, there are multiple ways of identifying a user; the `userId`,
|
|
718
791
|
* `uuid` and `externalId` used for identifying a user-merchant pair (see {@link Identity#getExternalId}).
|
|
@@ -721,13 +794,13 @@ export class Identity extends EventEmitter {
|
|
|
721
794
|
* duplicates. The `userId` was introduced early, so many sites still need to use them for
|
|
722
795
|
* legacy reasons. The `uuid` is universally unique, and so — if we could disregard a lot of
|
|
723
796
|
* Schibsted components depending on the numeric `userId` — it would be a good identifier to use
|
|
724
|
-
* @
|
|
797
|
+
* @remarks This function calls {@link Identity#hasSession} internally and thus has the side
|
|
725
798
|
* effect that it might perform an auto-login on the user
|
|
726
799
|
* @throws {SDKError} If the user isn't connected to the merchant
|
|
727
|
-
* @return
|
|
800
|
+
* @return The `userId` field (not to be confused with the `uuid`)
|
|
728
801
|
*/
|
|
729
|
-
async getUserId() {
|
|
730
|
-
const user = await this.hasSession();
|
|
802
|
+
async getUserId(): Promise<string> {
|
|
803
|
+
const user = (await this.hasSession()) as any;
|
|
731
804
|
if (user.userId && user.result) {
|
|
732
805
|
return user.userId;
|
|
733
806
|
}
|
|
@@ -735,7 +808,6 @@ export class Identity extends EventEmitter {
|
|
|
735
808
|
}
|
|
736
809
|
|
|
737
810
|
/**
|
|
738
|
-
* @async
|
|
739
811
|
* @function
|
|
740
812
|
* @summary
|
|
741
813
|
* Retrieves the external identifier (`externalId`) for the authenticated user.
|
|
@@ -748,58 +820,55 @@ export class Identity extends EventEmitter {
|
|
|
748
820
|
* meaning the same user's ID will differ between merchants.
|
|
749
821
|
* Additionally, this identifier is bound to the external party provided as argument.
|
|
750
822
|
*
|
|
751
|
-
* @param
|
|
752
|
-
* @param
|
|
753
|
-
* @
|
|
823
|
+
* @param externalParty
|
|
824
|
+
* @param optionalSuffix
|
|
825
|
+
* @remarks This function calls {@link Identity#hasSession} internally and thus has the side
|
|
754
826
|
* effect that it might perform an auto-login on the user
|
|
755
827
|
* @throws {SDKError} If the `pairId` is missing in user session.
|
|
756
828
|
* @throws {SDKError} If the `externalParty` is not defined
|
|
757
|
-
* @return
|
|
829
|
+
* @return The merchant- and 3rd-party-specific `externalId`
|
|
758
830
|
*/
|
|
759
|
-
async getExternalId(externalParty, optionalSuffix =
|
|
760
|
-
const { pairId } = await this.hasSession();
|
|
831
|
+
async getExternalId(externalParty: string, optionalSuffix: string = ''): Promise<string> {
|
|
832
|
+
const { pairId } = (await this.hasSession()) as any;
|
|
761
833
|
|
|
762
|
-
if (!pairId)
|
|
763
|
-
throw new SDKError('pairId missing in user session!');
|
|
834
|
+
if (!pairId) throw new SDKError('pairId missing in user session!');
|
|
764
835
|
|
|
765
|
-
if(!externalParty || externalParty.length === 0) {
|
|
836
|
+
if (!externalParty || externalParty.length === 0) {
|
|
766
837
|
throw new SDKError('externalParty cannot be empty');
|
|
767
838
|
}
|
|
768
|
-
const _toHexDigest = (hashBuffer) =>{
|
|
839
|
+
const _toHexDigest = (hashBuffer: any) => {
|
|
769
840
|
// convert buffer to byte array
|
|
770
841
|
const hashArray = Array.from(new Uint8Array(hashBuffer));
|
|
771
842
|
// convert bytes to hex string
|
|
772
|
-
return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
|
|
773
|
-
}
|
|
843
|
+
return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
|
|
844
|
+
};
|
|
774
845
|
|
|
775
|
-
const _getSha256Digest = (data) => {
|
|
846
|
+
const _getSha256Digest = (data: any) => {
|
|
776
847
|
return crypto.subtle.digest('SHA-256', data);
|
|
777
|
-
}
|
|
848
|
+
};
|
|
778
849
|
|
|
779
|
-
const _hashMessage = async (message) => {
|
|
850
|
+
const _hashMessage = async (message: any) => {
|
|
780
851
|
const msgUint8 = new TextEncoder().encode(message);
|
|
781
|
-
return _getSha256Digest(msgUint8).then(
|
|
782
|
-
}
|
|
852
|
+
return _getSha256Digest(msgUint8).then((it: any) => _toHexDigest(it));
|
|
853
|
+
};
|
|
783
854
|
|
|
784
|
-
const _constructMessage = (pairId, externalParty, optionalSuffix) => {
|
|
855
|
+
const _constructMessage = (pairId: any, externalParty: any, optionalSuffix: any) => {
|
|
785
856
|
return optionalSuffix
|
|
786
857
|
? `${pairId}:${externalParty}:${optionalSuffix}`
|
|
787
858
|
: `${pairId}:${externalParty}`;
|
|
788
|
-
}
|
|
859
|
+
};
|
|
789
860
|
|
|
790
|
-
return _hashMessage(_constructMessage(pairId, externalParty, optionalSuffix))
|
|
861
|
+
return _hashMessage(_constructMessage(pairId, externalParty, optionalSuffix));
|
|
791
862
|
}
|
|
792
863
|
|
|
793
864
|
/**
|
|
794
|
-
* @async
|
|
795
865
|
* @summary Enables brands to programmatically get the current the SDRN based on the user's session.
|
|
796
|
-
* @
|
|
866
|
+
* @remarks This function calls {@link Identity#hasSession} internally and thus has the side
|
|
797
867
|
* effect that it might perform an auto-login on the user
|
|
798
868
|
* @throws {SDKError} If the SDRN is missing in user session object.
|
|
799
|
-
* @returns {Promise<string>}
|
|
800
869
|
*/
|
|
801
|
-
async getUserSDRN() {
|
|
802
|
-
const { sdrn } = await this.hasSession();
|
|
870
|
+
async getUserSDRN(): Promise<string> {
|
|
871
|
+
const { sdrn } = (await this.hasSession()) as any;
|
|
803
872
|
if (sdrn) {
|
|
804
873
|
return sdrn;
|
|
805
874
|
}
|
|
@@ -807,20 +876,19 @@ export class Identity extends EventEmitter {
|
|
|
807
876
|
}
|
|
808
877
|
|
|
809
878
|
/**
|
|
810
|
-
* @async
|
|
811
879
|
* @summary In Schibsted account, there are two ways of identifying a user; the `userId` and the
|
|
812
880
|
* `uuid`. There are reasons for them both existing. The `userId` is a numeric identifier, but
|
|
813
881
|
* since Schibsted account is deployed separately in Norway and Sweden, there are a lot of
|
|
814
882
|
* duplicates. The `userId` was introduced early, so many sites still need to use them for
|
|
815
883
|
* legacy reasons. The `uuid` is universally unique, and so — if we could disregard a lot of
|
|
816
884
|
* Schibsted components depending on the numeric `userId` — it would be a good identifier to use
|
|
817
|
-
* @
|
|
885
|
+
* @remarks This function calls {@link Identity#hasSession} internally and thus has the side
|
|
818
886
|
* effect that it might perform an auto-login on the user
|
|
819
887
|
* @throws {SDKError} If the user isn't connected to the merchant
|
|
820
|
-
* @return
|
|
888
|
+
* @return The `uuid` field (not to be confused with the `userId`)
|
|
821
889
|
*/
|
|
822
|
-
async getUserUuid() {
|
|
823
|
-
const user = await this.hasSession();
|
|
890
|
+
async getUserUuid(): Promise<string> {
|
|
891
|
+
const user = (await this.hasSession()) as any;
|
|
824
892
|
if (user.uuid && user.result) {
|
|
825
893
|
return user.uuid;
|
|
826
894
|
}
|
|
@@ -828,16 +896,14 @@ export class Identity extends EventEmitter {
|
|
|
828
896
|
}
|
|
829
897
|
|
|
830
898
|
/**
|
|
831
|
-
* @async
|
|
832
899
|
* @summary Get basic information about any user currently logged-in to their Schibsted account
|
|
833
900
|
* in this browser. Can be used to provide context in a continue-as prompt.
|
|
834
|
-
* @
|
|
901
|
+
* @remarks This function relies on the global Schibsted account user session cookie, which
|
|
835
902
|
* is a third-party cookie and hence might be blocked by the browser (for example due to ITP in
|
|
836
903
|
* Safari). So there's no guarantee any data is returned, even though a user is logged-in in
|
|
837
904
|
* the current browser.
|
|
838
|
-
* @return {Promise<SimplifiedLoginData|null>}
|
|
839
905
|
*/
|
|
840
|
-
async getUserContextData() {
|
|
906
|
+
async getUserContextData(): Promise<SimplifiedLoginData | null> {
|
|
841
907
|
try {
|
|
842
908
|
return await this._globalSessionService.get('user-context');
|
|
843
909
|
} catch (_) {
|
|
@@ -852,23 +918,23 @@ export class Identity extends EventEmitter {
|
|
|
852
918
|
* @summary Perform a login, either using a full-page redirect or a popup
|
|
853
919
|
* @see https://tools.ietf.org/html/rfc6749#section-4.1.1
|
|
854
920
|
*
|
|
855
|
-
* @param
|
|
856
|
-
* @param
|
|
857
|
-
* @param
|
|
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
|
-
* @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)
|
|
872
938
|
*/
|
|
873
939
|
login({
|
|
874
940
|
state,
|
|
@@ -885,8 +951,8 @@ export class Identity extends EventEmitter {
|
|
|
885
951
|
prompt = 'select_account',
|
|
886
952
|
xDomainId = '',
|
|
887
953
|
xEnvironmentId = '',
|
|
888
|
-
originCampaign = ''
|
|
889
|
-
}) {
|
|
954
|
+
originCampaign = '',
|
|
955
|
+
}: LoginOptions): Window | null {
|
|
890
956
|
this._closePopup();
|
|
891
957
|
this.sessionStorageCache.delete(HAS_SESSION_CACHE_KEY);
|
|
892
958
|
const url = this.loginUrl({
|
|
@@ -903,12 +969,14 @@ export class Identity extends EventEmitter {
|
|
|
903
969
|
prompt,
|
|
904
970
|
xDomainId,
|
|
905
971
|
xEnvironmentId,
|
|
906
|
-
originCampaign
|
|
972
|
+
originCampaign,
|
|
907
973
|
});
|
|
908
974
|
|
|
909
975
|
if (preferPopup) {
|
|
910
|
-
this.popup =
|
|
911
|
-
|
|
976
|
+
this.popup = popup.open(this.window, url, 'Schibsted account', {
|
|
977
|
+
width: 360,
|
|
978
|
+
height: 570,
|
|
979
|
+
});
|
|
912
980
|
if (this.popup) {
|
|
913
981
|
return this.popup;
|
|
914
982
|
}
|
|
@@ -918,15 +986,14 @@ export class Identity extends EventEmitter {
|
|
|
918
986
|
}
|
|
919
987
|
|
|
920
988
|
/**
|
|
921
|
-
* @async
|
|
922
989
|
* @summary Retrieve the sp_id (Varnish ID)
|
|
923
|
-
* @
|
|
990
|
+
* @remarks This function calls {@link Identity#hasSession} internally and thus has the side
|
|
924
991
|
* effect that it might perform an auto-login on the user
|
|
925
|
-
* @return
|
|
992
|
+
* @return - The sp_id string or null (if the server didn't return it)
|
|
926
993
|
*/
|
|
927
|
-
async getSpId() {
|
|
994
|
+
async getSpId(): Promise<string | null> {
|
|
928
995
|
try {
|
|
929
|
-
const user = await this.hasSession();
|
|
996
|
+
const user = (await this.hasSession()) as any;
|
|
930
997
|
return user.sp_id || null;
|
|
931
998
|
} catch (_) {
|
|
932
999
|
return null;
|
|
@@ -935,11 +1002,10 @@ export class Identity extends EventEmitter {
|
|
|
935
1002
|
|
|
936
1003
|
/**
|
|
937
1004
|
* @summary Logs the user out from the Identity platform
|
|
938
|
-
* @param
|
|
1005
|
+
* @param redirectUri - Where to redirect the browser after logging out of Schibsted
|
|
939
1006
|
* account
|
|
940
|
-
* @return {void}
|
|
941
1007
|
*/
|
|
942
|
-
logout(redirectUri = this.redirectUri) {
|
|
1008
|
+
logout(redirectUri: string = this.redirectUri): void {
|
|
943
1009
|
this.sessionStorageCache.delete(HAS_SESSION_CACHE_KEY);
|
|
944
1010
|
this._maybeClearVarnishCookie();
|
|
945
1011
|
this.emit('logout');
|
|
@@ -948,39 +1014,42 @@ export class Identity extends EventEmitter {
|
|
|
948
1014
|
|
|
949
1015
|
/**
|
|
950
1016
|
* Generates the link to the new login page that'll be used in the popup or redirect flow
|
|
951
|
-
* @param
|
|
952
|
-
* @param
|
|
953
|
-
* @param
|
|
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
|
-
* @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
|
|
967
1033
|
*/
|
|
968
|
-
loginUrl(
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
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 {
|
|
984
1053
|
if (typeof arguments[0] !== 'object') {
|
|
985
1054
|
// backward compatibility
|
|
986
1055
|
state = arguments[0];
|
|
@@ -992,13 +1061,26 @@ export class Identity extends EventEmitter {
|
|
|
992
1061
|
teaser = arguments[6] || teaser;
|
|
993
1062
|
maxAge = isNaN(arguments[7]) ? maxAge : arguments[7];
|
|
994
1063
|
}
|
|
995
|
-
const isValidAcrValue = (acrValue) =>
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
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
|
+
);
|
|
1002
1084
|
|
|
1003
1085
|
return this._oauthService.makeUrl('oauth/authorize', {
|
|
1004
1086
|
response_type: 'code',
|
|
@@ -1015,16 +1097,16 @@ export class Identity extends EventEmitter {
|
|
|
1015
1097
|
prompt: acrValues ? '' : prompt,
|
|
1016
1098
|
x_domain_id: xDomainId,
|
|
1017
1099
|
x_env_id: xEnvironmentId,
|
|
1018
|
-
utm_campaign: originCampaign
|
|
1100
|
+
utm_campaign: originCampaign,
|
|
1019
1101
|
});
|
|
1020
1102
|
}
|
|
1021
1103
|
|
|
1022
1104
|
/**
|
|
1023
1105
|
* The url for logging the user out
|
|
1024
|
-
* @param
|
|
1025
|
-
* @return
|
|
1106
|
+
* @param redirectUri
|
|
1107
|
+
* @return url
|
|
1026
1108
|
*/
|
|
1027
|
-
logoutUrl(redirectUri = this.redirectUri) {
|
|
1109
|
+
logoutUrl(redirectUri: string = this.redirectUri): string {
|
|
1028
1110
|
assert(isUrl(redirectUri), `logoutUrl(): redirectUri is invalid`);
|
|
1029
1111
|
const params = { redirect_uri: redirectUri };
|
|
1030
1112
|
return this._sessionService.makeUrl('logout', params);
|
|
@@ -1032,25 +1114,23 @@ export class Identity extends EventEmitter {
|
|
|
1032
1114
|
|
|
1033
1115
|
/**
|
|
1034
1116
|
* The account summary page url
|
|
1035
|
-
* @param
|
|
1036
|
-
* @return {string}
|
|
1117
|
+
* @param redirectUri
|
|
1037
1118
|
*/
|
|
1038
|
-
accountUrl(redirectUri = this.redirectUri) {
|
|
1119
|
+
accountUrl(redirectUri: string = this.redirectUri): string {
|
|
1039
1120
|
return this._spid.makeUrl('profile-pages', {
|
|
1040
1121
|
response_type: 'code',
|
|
1041
|
-
redirect_uri: redirectUri
|
|
1122
|
+
redirect_uri: redirectUri,
|
|
1042
1123
|
});
|
|
1043
1124
|
}
|
|
1044
1125
|
|
|
1045
1126
|
/**
|
|
1046
1127
|
* The phone editing page url
|
|
1047
|
-
* @param
|
|
1048
|
-
* @return {string}
|
|
1128
|
+
* @param redirectUri
|
|
1049
1129
|
*/
|
|
1050
|
-
phonesUrl(redirectUri = this.redirectUri) {
|
|
1130
|
+
phonesUrl(redirectUri: string = this.redirectUri): string {
|
|
1051
1131
|
return this._spid.makeUrl('profile-pages/about-you/phone', {
|
|
1052
1132
|
response_type: 'code',
|
|
1053
|
-
redirect_uri: redirectUri
|
|
1133
|
+
redirect_uri: redirectUri,
|
|
1054
1134
|
});
|
|
1055
1135
|
}
|
|
1056
1136
|
|
|
@@ -1059,95 +1139,117 @@ export class Identity extends EventEmitter {
|
|
|
1059
1139
|
* widget will be display is up to you. Preferred way would be to show it once per user,
|
|
1060
1140
|
* and store that info in localStorage. Widget will be display only if user is logged in to SSO.
|
|
1061
1141
|
*
|
|
1062
|
-
* @
|
|
1063
|
-
* @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
|
|
1064
1143
|
* continue action. `state` might be string or async function.
|
|
1065
|
-
* @param
|
|
1144
|
+
* @param options - additional configuration of Simplified Login Widget
|
|
1066
1145
|
* @fires Identity#simplifiedLoginOpened
|
|
1067
1146
|
* @fires Identity#simplifiedLoginCancelled
|
|
1068
|
-
* @return
|
|
1147
|
+
* @return - will resolve to true if widget will be display. Otherwise, will throw SDKError
|
|
1069
1148
|
*/
|
|
1070
|
-
async showSimplifiedLoginWidget(
|
|
1149
|
+
async showSimplifiedLoginWidget(
|
|
1150
|
+
loginParams: SimplifiedLoginWidgetLoginOptions,
|
|
1151
|
+
options?: SimplifiedLoginWidgetOptions,
|
|
1152
|
+
): Promise<boolean | SDKError> {
|
|
1071
1153
|
// getUserContextData doesn't throw exception
|
|
1072
1154
|
const userData = await this.getUserContextData();
|
|
1073
1155
|
|
|
1074
|
-
const queryParams = { client_id: this.clientId };
|
|
1156
|
+
const queryParams: Record<string, string> = { client_id: this.clientId };
|
|
1075
1157
|
if (options && options.encoding) {
|
|
1076
1158
|
queryParams.encoding = options.encoding;
|
|
1077
1159
|
}
|
|
1078
1160
|
const widgetUrl = this._bffService.makeUrl('simplified-login-widget', queryParams, false);
|
|
1079
1161
|
|
|
1080
|
-
const prepareLoginParams = async (loginPrams) => {
|
|
1162
|
+
const prepareLoginParams = async (loginPrams: any) => {
|
|
1081
1163
|
if (typeof loginPrams.state === 'function') {
|
|
1082
1164
|
loginPrams.state = await loginPrams.state();
|
|
1083
1165
|
}
|
|
1084
1166
|
|
|
1085
1167
|
return loginPrams;
|
|
1086
|
-
}
|
|
1087
|
-
|
|
1088
|
-
return new Promise(
|
|
1089
|
-
(resolve, reject) => {
|
|
1090
|
-
if (!userData || !userData.display_text || !userData.identifier) {
|
|
1091
|
-
return reject(new SDKError('Missing user data'));
|
|
1092
|
-
}
|
|
1093
|
-
|
|
1094
|
-
const initialParams = {
|
|
1095
|
-
displayText: userData.display_text,
|
|
1096
|
-
env: this.env,
|
|
1097
|
-
clientName: userData.client_name,
|
|
1098
|
-
clientId: this.clientId,
|
|
1099
|
-
providerId: userData.provider_id,
|
|
1100
|
-
windowWidth: () => window.innerWidth,
|
|
1101
|
-
windowOnResize: (f) => {
|
|
1102
|
-
window.onresize = f;
|
|
1103
|
-
},
|
|
1104
|
-
};
|
|
1105
|
-
|
|
1106
|
-
if (options && options.locale) {
|
|
1107
|
-
initialParams.locale = options.locale;
|
|
1108
|
-
}
|
|
1109
|
-
|
|
1110
|
-
const loginHandler = async () => {
|
|
1111
|
-
this.login(Object.assign(await prepareLoginParams(loginParams), {loginHint: userData.identifier}));
|
|
1112
|
-
};
|
|
1168
|
+
};
|
|
1113
1169
|
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1170
|
+
return new Promise((resolve, reject) => {
|
|
1171
|
+
if (!userData || !userData.display_text || !userData.identifier) {
|
|
1172
|
+
return reject(new SDKError('Missing user data'));
|
|
1173
|
+
}
|
|
1117
1174
|
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
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
|
+
};
|
|
1125
1186
|
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
* @event Identity#simplifiedLoginCancelled
|
|
1130
|
-
*/
|
|
1131
|
-
this.emit('simplifiedLoginCancelled');
|
|
1132
|
-
}
|
|
1187
|
+
if (options && options.locale) {
|
|
1188
|
+
initialParams.locale = options.locale;
|
|
1189
|
+
}
|
|
1133
1190
|
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
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
|
+
}
|
|
1138
1234
|
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
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
|
+
});
|
|
1151
1253
|
}
|
|
1152
1254
|
}
|
|
1153
1255
|
|