@leancodepl/login-manager 7.1.0
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/index.cjs.d.ts +1 -0
- package/index.cjs.js +395 -0
- package/index.esm.js +384 -0
- package/package.json +10 -0
- package/src/index.d.ts +9 -0
- package/src/lib/asyncLoginManager.d.ts +8 -0
- package/src/lib/baseLoginManager.d.ts +40 -0
- package/src/lib/cannotRefreshToken.d.ts +3 -0
- package/src/lib/facebookClient.d.ts +12 -0
- package/src/lib/localTokenStorage.d.ts +14 -0
- package/src/lib/memoryTokenStorage.d.ts +7 -0
- package/src/lib/sessionTokenStorage.d.ts +14 -0
- package/src/lib/syncLoginManager.d.ts +7 -0
- package/src/lib/tokenStorage.d.ts +17 -0
package/index.cjs.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./src/index";
|
package/index.cjs.js
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var buffer = require('buffer');
|
|
6
|
+
|
|
7
|
+
function _extends() {
|
|
8
|
+
_extends = Object.assign || function assign(target) {
|
|
9
|
+
for(var i = 1; i < arguments.length; i++){
|
|
10
|
+
var source = arguments[i];
|
|
11
|
+
for(var key in source)if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key];
|
|
12
|
+
}
|
|
13
|
+
return target;
|
|
14
|
+
};
|
|
15
|
+
return _extends.apply(this, arguments);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
class BaseLoginManager {
|
|
19
|
+
trySignIn(username, password) {
|
|
20
|
+
return this.acquireToken(this.buildSignInRequest(username, password));
|
|
21
|
+
}
|
|
22
|
+
trySignInWithFacebook(accessToken) {
|
|
23
|
+
return this.acquireToken(this.buildSignInWithFacebookRequest(accessToken));
|
|
24
|
+
}
|
|
25
|
+
async tryRefreshToken() {
|
|
26
|
+
const token = await this.storage.getToken();
|
|
27
|
+
if (token !== null) {
|
|
28
|
+
return await this.tryRefreshTokenInternal(token);
|
|
29
|
+
} else {
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
tryRefreshTokenInternal(token) {
|
|
34
|
+
if (!this.isRefreshingToken) {
|
|
35
|
+
this.isRefreshingToken = true;
|
|
36
|
+
this.acquireToken(this.buildRefreshRequest(token)).then((result)=>{
|
|
37
|
+
this.isRefreshingToken = false;
|
|
38
|
+
this.refreshTokenCallbacks.forEach((c)=>c(result.type === "success"));
|
|
39
|
+
this.refreshTokenCallbacks = [];
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return new Promise((resolve)=>{
|
|
43
|
+
this.refreshTokenCallbacks.push(resolve);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
onChange(callback) {
|
|
47
|
+
this.callbacks.push(callback);
|
|
48
|
+
}
|
|
49
|
+
removeOnChange(callback) {
|
|
50
|
+
const idx = this.callbacks.indexOf(callback);
|
|
51
|
+
if (idx !== -1) {
|
|
52
|
+
this.callbacks.splice(idx, 1);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
async acquireToken(init) {
|
|
56
|
+
try {
|
|
57
|
+
const result = await fetch(this.endpoint + "/connect/token", init);
|
|
58
|
+
if (!result.ok) {
|
|
59
|
+
if (result.status === 400) {
|
|
60
|
+
await this.signOut();
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
type: "failure"
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const tokenResult = await result.json();
|
|
67
|
+
const expDate = new Date();
|
|
68
|
+
expDate.setSeconds(new Date().getSeconds() + tokenResult.expires_in);
|
|
69
|
+
await this.storage.storeToken({
|
|
70
|
+
token: tokenResult.access_token,
|
|
71
|
+
refreshToken: tokenResult.refresh_token,
|
|
72
|
+
expirationDate: expDate
|
|
73
|
+
});
|
|
74
|
+
this.notify(true);
|
|
75
|
+
return {
|
|
76
|
+
type: "success"
|
|
77
|
+
};
|
|
78
|
+
} catch (e) {
|
|
79
|
+
console.warn("Cannot call Auth server, error: ", e);
|
|
80
|
+
return {
|
|
81
|
+
type: "networkError"
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
buildSignInRequest(username, password) {
|
|
86
|
+
const data = _extends({
|
|
87
|
+
grant_type: "password",
|
|
88
|
+
scope: this.scopes,
|
|
89
|
+
username: username,
|
|
90
|
+
password: password
|
|
91
|
+
}, this.additionalParams);
|
|
92
|
+
return {
|
|
93
|
+
method: "POST",
|
|
94
|
+
headers: this.prepareHeaders(),
|
|
95
|
+
body: new URLSearchParams(data)
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
buildSignInWithFacebookRequest(accessToken) {
|
|
99
|
+
const data = _extends({
|
|
100
|
+
grant_type: "facebook",
|
|
101
|
+
scope: this.scopes,
|
|
102
|
+
assertion: accessToken
|
|
103
|
+
}, this.additionalParams);
|
|
104
|
+
return {
|
|
105
|
+
method: "POST",
|
|
106
|
+
headers: this.prepareHeaders(),
|
|
107
|
+
body: new URLSearchParams(data)
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
buildRefreshRequest(token) {
|
|
111
|
+
const data = _extends({
|
|
112
|
+
grant_type: "refresh_token",
|
|
113
|
+
scope: this.scopes,
|
|
114
|
+
refresh_token: token.refreshToken || ""
|
|
115
|
+
}, this.additionalParams);
|
|
116
|
+
return {
|
|
117
|
+
method: "POST",
|
|
118
|
+
headers: this.prepareHeaders(),
|
|
119
|
+
body: new URLSearchParams(data)
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
prepareHeaders() {
|
|
123
|
+
const headers = new Headers();
|
|
124
|
+
if (this.clientSecret) {
|
|
125
|
+
const sec = buffer.Buffer.from(`${this.clientId}:${this.clientSecret}`, "binary").toString("base64");
|
|
126
|
+
headers.append("Authorization", "Basic " + sec);
|
|
127
|
+
}
|
|
128
|
+
headers.append("Content-Type", "application/x-www-form-urlencoded");
|
|
129
|
+
return headers;
|
|
130
|
+
}
|
|
131
|
+
notify(isSignedIn) {
|
|
132
|
+
for (const c of this.callbacks){
|
|
133
|
+
c(isSignedIn);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/* eslint-disable-next-line max-params */ constructor(storage, endpoint, clientSecret, clientId, scopes, additionalParams){
|
|
137
|
+
this.storage = storage;
|
|
138
|
+
this.endpoint = endpoint;
|
|
139
|
+
this.clientSecret = clientSecret;
|
|
140
|
+
this.clientId = clientId;
|
|
141
|
+
this.scopes = scopes;
|
|
142
|
+
this.additionalParams = additionalParams;
|
|
143
|
+
this.callbacks = [];
|
|
144
|
+
this.refreshTokenCallbacks = [];
|
|
145
|
+
this.isRefreshingToken = false;
|
|
146
|
+
if (!clientSecret) {
|
|
147
|
+
this.additionalParams = _extends({}, additionalParams, {
|
|
148
|
+
client_id: clientId
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
class CannotRefreshToken extends Error {
|
|
155
|
+
constructor(m){
|
|
156
|
+
super(m);
|
|
157
|
+
Object.setPrototypeOf(this, CannotRefreshToken.prototype);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
class AsyncLoginManager extends BaseLoginManager {
|
|
162
|
+
async signOut() {
|
|
163
|
+
await this.storage.resetToken();
|
|
164
|
+
this.notify(false);
|
|
165
|
+
}
|
|
166
|
+
async isSigned() {
|
|
167
|
+
return await this.storage.getToken() !== null;
|
|
168
|
+
}
|
|
169
|
+
async getToken() {
|
|
170
|
+
const token = await this.storage.getToken();
|
|
171
|
+
if (token === null) {
|
|
172
|
+
return null;
|
|
173
|
+
} else if (token.expirationDate < new Date()) {
|
|
174
|
+
if (await this.tryRefreshTokenInternal(token)) {
|
|
175
|
+
var _this;
|
|
176
|
+
var _token;
|
|
177
|
+
return (_token = (_this = await this.storage.getToken()) == null ? void 0 : _this.token) != null ? _token : null;
|
|
178
|
+
} else {
|
|
179
|
+
throw new CannotRefreshToken("Cannot refresh access token after it has expired");
|
|
180
|
+
}
|
|
181
|
+
} else {
|
|
182
|
+
return token.token;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
async load() {
|
|
186
|
+
const isSignedIn = await this.isSigned();
|
|
187
|
+
this.notify(isSignedIn);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/// <reference types="facebook-js-sdk" />
|
|
192
|
+
class FacebookClient {
|
|
193
|
+
get accessToken() {
|
|
194
|
+
return this.token;
|
|
195
|
+
}
|
|
196
|
+
setup(loginCallback) {
|
|
197
|
+
const ref = document.getElementsByTagName("script")[0];
|
|
198
|
+
const id = "facebook-jssdk";
|
|
199
|
+
if (document.getElementById(id)) {
|
|
200
|
+
this.initializeSDK();
|
|
201
|
+
this.getLoginStatus(loginCallback);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
const js = document.createElement("script");
|
|
205
|
+
js.id = id;
|
|
206
|
+
js.async = true;
|
|
207
|
+
js.src = "//connect.facebook.net/pl_PL/sdk.js";
|
|
208
|
+
if (ref.parentNode != null) {
|
|
209
|
+
ref.parentNode.insertBefore(js, ref);
|
|
210
|
+
}
|
|
211
|
+
js.onload = ()=>{
|
|
212
|
+
this.initializeSDK();
|
|
213
|
+
this.getLoginStatus(loginCallback);
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
login(callback) {
|
|
217
|
+
FB.login((response)=>{
|
|
218
|
+
if (response.status === "connected") {
|
|
219
|
+
this.isSignedIn = true;
|
|
220
|
+
this.token = response.authResponse.accessToken;
|
|
221
|
+
if (callback) {
|
|
222
|
+
callback(response.authResponse.accessToken);
|
|
223
|
+
}
|
|
224
|
+
} else {
|
|
225
|
+
this.isSignedIn = false;
|
|
226
|
+
}
|
|
227
|
+
}, {
|
|
228
|
+
scope: this.facebookPermissions
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
getLoginStatus(callback) {
|
|
232
|
+
FB.getLoginStatus((response)=>{
|
|
233
|
+
if (response.status === "connected") {
|
|
234
|
+
this.isSignedIn = true;
|
|
235
|
+
this.token = response.authResponse.accessToken;
|
|
236
|
+
if (callback) {
|
|
237
|
+
callback(response.authResponse.accessToken);
|
|
238
|
+
}
|
|
239
|
+
} else {
|
|
240
|
+
this.isSignedIn = false;
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
initializeSDK() {
|
|
245
|
+
FB.init({
|
|
246
|
+
appId: this.facebookAppId,
|
|
247
|
+
xfbml: true,
|
|
248
|
+
version: "v2.9"
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
constructor(facebookAppId, facebookPermissions){
|
|
252
|
+
this.facebookAppId = facebookAppId;
|
|
253
|
+
this.facebookPermissions = facebookPermissions;
|
|
254
|
+
this.isSignedIn = undefined;
|
|
255
|
+
this.token = "";
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
class LocalTokenStorage {
|
|
260
|
+
getToken() {
|
|
261
|
+
if (this.hasValue(this.tokenKey)) {
|
|
262
|
+
return {
|
|
263
|
+
token: this.getValue(this.tokenKey),
|
|
264
|
+
refreshToken: this.getValue(this.refreshKey),
|
|
265
|
+
expirationDate: new Date(Number(this.getValue(this.expiryKey)))
|
|
266
|
+
};
|
|
267
|
+
} else {
|
|
268
|
+
return null;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
storeToken(token) {
|
|
272
|
+
this.setValue(this.tokenKey, token.token);
|
|
273
|
+
this.setValue(this.refreshKey, token.refreshToken);
|
|
274
|
+
this.setValue(this.expiryKey, token.expirationDate.getTime().toString());
|
|
275
|
+
}
|
|
276
|
+
resetToken() {
|
|
277
|
+
this.remove(this.tokenKey);
|
|
278
|
+
this.remove(this.refreshKey);
|
|
279
|
+
this.remove(this.expiryKey);
|
|
280
|
+
}
|
|
281
|
+
hasValue(key) {
|
|
282
|
+
return localStorage.getItem(key) !== null;
|
|
283
|
+
}
|
|
284
|
+
getValue(key) {
|
|
285
|
+
return localStorage.getItem(key);
|
|
286
|
+
}
|
|
287
|
+
setValue(key, val) {
|
|
288
|
+
localStorage.setItem(key, val);
|
|
289
|
+
}
|
|
290
|
+
remove(key) {
|
|
291
|
+
localStorage.removeItem(key);
|
|
292
|
+
}
|
|
293
|
+
constructor(tokenKey = "token", refreshKey = "refresh_token", expiryKey = "expiration_date"){
|
|
294
|
+
this.tokenKey = tokenKey;
|
|
295
|
+
this.refreshKey = refreshKey;
|
|
296
|
+
this.expiryKey = expiryKey;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
class MemoryTokenStorage {
|
|
301
|
+
getToken() {
|
|
302
|
+
return this.token;
|
|
303
|
+
}
|
|
304
|
+
storeToken(token) {
|
|
305
|
+
this.token = {
|
|
306
|
+
token: token.token,
|
|
307
|
+
refreshToken: token.refreshToken,
|
|
308
|
+
expirationDate: token.expirationDate
|
|
309
|
+
};
|
|
310
|
+
return Promise.resolve();
|
|
311
|
+
}
|
|
312
|
+
resetToken() {
|
|
313
|
+
this.token = null;
|
|
314
|
+
return Promise.resolve();
|
|
315
|
+
}
|
|
316
|
+
constructor(){
|
|
317
|
+
this.token = null;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
class SessionTokenStorage {
|
|
322
|
+
getToken() {
|
|
323
|
+
if (this.hasValue(this.tokenKey)) {
|
|
324
|
+
return {
|
|
325
|
+
token: this.getValue(this.tokenKey),
|
|
326
|
+
refreshToken: this.getValue(this.refreshKey),
|
|
327
|
+
expirationDate: new Date(Number(this.getValue(this.expiryKey)))
|
|
328
|
+
};
|
|
329
|
+
} else {
|
|
330
|
+
return null;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
storeToken(token) {
|
|
334
|
+
this.setValue(this.tokenKey, token.token);
|
|
335
|
+
this.setValue(this.refreshKey, token.refreshToken);
|
|
336
|
+
this.setValue(this.expiryKey, token.expirationDate.getTime().toString());
|
|
337
|
+
}
|
|
338
|
+
resetToken() {
|
|
339
|
+
this.remove(this.tokenKey);
|
|
340
|
+
this.remove(this.refreshKey);
|
|
341
|
+
this.remove(this.expiryKey);
|
|
342
|
+
}
|
|
343
|
+
hasValue(key) {
|
|
344
|
+
return sessionStorage.getItem(key) !== null;
|
|
345
|
+
}
|
|
346
|
+
getValue(key) {
|
|
347
|
+
return sessionStorage.getItem(key);
|
|
348
|
+
}
|
|
349
|
+
setValue(key, val) {
|
|
350
|
+
sessionStorage.setItem(key, val);
|
|
351
|
+
}
|
|
352
|
+
remove(key) {
|
|
353
|
+
sessionStorage.removeItem(key);
|
|
354
|
+
}
|
|
355
|
+
constructor(tokenKey = "token", refreshKey = "refresh_token", expiryKey = "expiration_date"){
|
|
356
|
+
this.tokenKey = tokenKey;
|
|
357
|
+
this.refreshKey = refreshKey;
|
|
358
|
+
this.expiryKey = expiryKey;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
class SyncLoginManager extends BaseLoginManager {
|
|
363
|
+
signOut() {
|
|
364
|
+
this.storage.resetToken();
|
|
365
|
+
this.notify(false);
|
|
366
|
+
}
|
|
367
|
+
isSigned() {
|
|
368
|
+
return this.storage.getToken() !== null;
|
|
369
|
+
}
|
|
370
|
+
async getToken() {
|
|
371
|
+
const token = this.storage.getToken();
|
|
372
|
+
if (token === null) {
|
|
373
|
+
return null;
|
|
374
|
+
} else if (token.expirationDate < new Date()) {
|
|
375
|
+
if (await this.tryRefreshTokenInternal(token)) {
|
|
376
|
+
var _this_storage_getToken;
|
|
377
|
+
var _this_storage_getToken_token;
|
|
378
|
+
return (_this_storage_getToken_token = (_this_storage_getToken = this.storage.getToken()) == null ? void 0 : _this_storage_getToken.token) != null ? _this_storage_getToken_token : null;
|
|
379
|
+
} else {
|
|
380
|
+
throw new CannotRefreshToken("Cannot refresh access token after it has expired");
|
|
381
|
+
}
|
|
382
|
+
} else {
|
|
383
|
+
return token.token;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
exports.AsyncLoginManager = AsyncLoginManager;
|
|
389
|
+
exports.BaseLoginManager = BaseLoginManager;
|
|
390
|
+
exports.CannotRefreshToken = CannotRefreshToken;
|
|
391
|
+
exports.FacebookClient = FacebookClient;
|
|
392
|
+
exports.LocalTokenStorage = LocalTokenStorage;
|
|
393
|
+
exports.MemoryTokenStorage = MemoryTokenStorage;
|
|
394
|
+
exports.SessionTokenStorage = SessionTokenStorage;
|
|
395
|
+
exports.SyncLoginManager = SyncLoginManager;
|
package/index.esm.js
ADDED
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
|
|
3
|
+
function _extends() {
|
|
4
|
+
_extends = Object.assign || function assign(target) {
|
|
5
|
+
for(var i = 1; i < arguments.length; i++){
|
|
6
|
+
var source = arguments[i];
|
|
7
|
+
for(var key in source)if (Object.prototype.hasOwnProperty.call(source, key)) target[key] = source[key];
|
|
8
|
+
}
|
|
9
|
+
return target;
|
|
10
|
+
};
|
|
11
|
+
return _extends.apply(this, arguments);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
class BaseLoginManager {
|
|
15
|
+
trySignIn(username, password) {
|
|
16
|
+
return this.acquireToken(this.buildSignInRequest(username, password));
|
|
17
|
+
}
|
|
18
|
+
trySignInWithFacebook(accessToken) {
|
|
19
|
+
return this.acquireToken(this.buildSignInWithFacebookRequest(accessToken));
|
|
20
|
+
}
|
|
21
|
+
async tryRefreshToken() {
|
|
22
|
+
const token = await this.storage.getToken();
|
|
23
|
+
if (token !== null) {
|
|
24
|
+
return await this.tryRefreshTokenInternal(token);
|
|
25
|
+
} else {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
tryRefreshTokenInternal(token) {
|
|
30
|
+
if (!this.isRefreshingToken) {
|
|
31
|
+
this.isRefreshingToken = true;
|
|
32
|
+
this.acquireToken(this.buildRefreshRequest(token)).then((result)=>{
|
|
33
|
+
this.isRefreshingToken = false;
|
|
34
|
+
this.refreshTokenCallbacks.forEach((c)=>c(result.type === "success"));
|
|
35
|
+
this.refreshTokenCallbacks = [];
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return new Promise((resolve)=>{
|
|
39
|
+
this.refreshTokenCallbacks.push(resolve);
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
onChange(callback) {
|
|
43
|
+
this.callbacks.push(callback);
|
|
44
|
+
}
|
|
45
|
+
removeOnChange(callback) {
|
|
46
|
+
const idx = this.callbacks.indexOf(callback);
|
|
47
|
+
if (idx !== -1) {
|
|
48
|
+
this.callbacks.splice(idx, 1);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async acquireToken(init) {
|
|
52
|
+
try {
|
|
53
|
+
const result = await fetch(this.endpoint + "/connect/token", init);
|
|
54
|
+
if (!result.ok) {
|
|
55
|
+
if (result.status === 400) {
|
|
56
|
+
await this.signOut();
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
type: "failure"
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
const tokenResult = await result.json();
|
|
63
|
+
const expDate = new Date();
|
|
64
|
+
expDate.setSeconds(new Date().getSeconds() + tokenResult.expires_in);
|
|
65
|
+
await this.storage.storeToken({
|
|
66
|
+
token: tokenResult.access_token,
|
|
67
|
+
refreshToken: tokenResult.refresh_token,
|
|
68
|
+
expirationDate: expDate
|
|
69
|
+
});
|
|
70
|
+
this.notify(true);
|
|
71
|
+
return {
|
|
72
|
+
type: "success"
|
|
73
|
+
};
|
|
74
|
+
} catch (e) {
|
|
75
|
+
console.warn("Cannot call Auth server, error: ", e);
|
|
76
|
+
return {
|
|
77
|
+
type: "networkError"
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
buildSignInRequest(username, password) {
|
|
82
|
+
const data = _extends({
|
|
83
|
+
grant_type: "password",
|
|
84
|
+
scope: this.scopes,
|
|
85
|
+
username: username,
|
|
86
|
+
password: password
|
|
87
|
+
}, this.additionalParams);
|
|
88
|
+
return {
|
|
89
|
+
method: "POST",
|
|
90
|
+
headers: this.prepareHeaders(),
|
|
91
|
+
body: new URLSearchParams(data)
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
buildSignInWithFacebookRequest(accessToken) {
|
|
95
|
+
const data = _extends({
|
|
96
|
+
grant_type: "facebook",
|
|
97
|
+
scope: this.scopes,
|
|
98
|
+
assertion: accessToken
|
|
99
|
+
}, this.additionalParams);
|
|
100
|
+
return {
|
|
101
|
+
method: "POST",
|
|
102
|
+
headers: this.prepareHeaders(),
|
|
103
|
+
body: new URLSearchParams(data)
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
buildRefreshRequest(token) {
|
|
107
|
+
const data = _extends({
|
|
108
|
+
grant_type: "refresh_token",
|
|
109
|
+
scope: this.scopes,
|
|
110
|
+
refresh_token: token.refreshToken || ""
|
|
111
|
+
}, this.additionalParams);
|
|
112
|
+
return {
|
|
113
|
+
method: "POST",
|
|
114
|
+
headers: this.prepareHeaders(),
|
|
115
|
+
body: new URLSearchParams(data)
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
prepareHeaders() {
|
|
119
|
+
const headers = new Headers();
|
|
120
|
+
if (this.clientSecret) {
|
|
121
|
+
const sec = Buffer.from(`${this.clientId}:${this.clientSecret}`, "binary").toString("base64");
|
|
122
|
+
headers.append("Authorization", "Basic " + sec);
|
|
123
|
+
}
|
|
124
|
+
headers.append("Content-Type", "application/x-www-form-urlencoded");
|
|
125
|
+
return headers;
|
|
126
|
+
}
|
|
127
|
+
notify(isSignedIn) {
|
|
128
|
+
for (const c of this.callbacks){
|
|
129
|
+
c(isSignedIn);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/* eslint-disable-next-line max-params */ constructor(storage, endpoint, clientSecret, clientId, scopes, additionalParams){
|
|
133
|
+
this.storage = storage;
|
|
134
|
+
this.endpoint = endpoint;
|
|
135
|
+
this.clientSecret = clientSecret;
|
|
136
|
+
this.clientId = clientId;
|
|
137
|
+
this.scopes = scopes;
|
|
138
|
+
this.additionalParams = additionalParams;
|
|
139
|
+
this.callbacks = [];
|
|
140
|
+
this.refreshTokenCallbacks = [];
|
|
141
|
+
this.isRefreshingToken = false;
|
|
142
|
+
if (!clientSecret) {
|
|
143
|
+
this.additionalParams = _extends({}, additionalParams, {
|
|
144
|
+
client_id: clientId
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
class CannotRefreshToken extends Error {
|
|
151
|
+
constructor(m){
|
|
152
|
+
super(m);
|
|
153
|
+
Object.setPrototypeOf(this, CannotRefreshToken.prototype);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
class AsyncLoginManager extends BaseLoginManager {
|
|
158
|
+
async signOut() {
|
|
159
|
+
await this.storage.resetToken();
|
|
160
|
+
this.notify(false);
|
|
161
|
+
}
|
|
162
|
+
async isSigned() {
|
|
163
|
+
return await this.storage.getToken() !== null;
|
|
164
|
+
}
|
|
165
|
+
async getToken() {
|
|
166
|
+
const token = await this.storage.getToken();
|
|
167
|
+
if (token === null) {
|
|
168
|
+
return null;
|
|
169
|
+
} else if (token.expirationDate < new Date()) {
|
|
170
|
+
if (await this.tryRefreshTokenInternal(token)) {
|
|
171
|
+
var _this;
|
|
172
|
+
var _token;
|
|
173
|
+
return (_token = (_this = await this.storage.getToken()) == null ? void 0 : _this.token) != null ? _token : null;
|
|
174
|
+
} else {
|
|
175
|
+
throw new CannotRefreshToken("Cannot refresh access token after it has expired");
|
|
176
|
+
}
|
|
177
|
+
} else {
|
|
178
|
+
return token.token;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
async load() {
|
|
182
|
+
const isSignedIn = await this.isSigned();
|
|
183
|
+
this.notify(isSignedIn);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/// <reference types="facebook-js-sdk" />
|
|
188
|
+
class FacebookClient {
|
|
189
|
+
get accessToken() {
|
|
190
|
+
return this.token;
|
|
191
|
+
}
|
|
192
|
+
setup(loginCallback) {
|
|
193
|
+
const ref = document.getElementsByTagName("script")[0];
|
|
194
|
+
const id = "facebook-jssdk";
|
|
195
|
+
if (document.getElementById(id)) {
|
|
196
|
+
this.initializeSDK();
|
|
197
|
+
this.getLoginStatus(loginCallback);
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
const js = document.createElement("script");
|
|
201
|
+
js.id = id;
|
|
202
|
+
js.async = true;
|
|
203
|
+
js.src = "//connect.facebook.net/pl_PL/sdk.js";
|
|
204
|
+
if (ref.parentNode != null) {
|
|
205
|
+
ref.parentNode.insertBefore(js, ref);
|
|
206
|
+
}
|
|
207
|
+
js.onload = ()=>{
|
|
208
|
+
this.initializeSDK();
|
|
209
|
+
this.getLoginStatus(loginCallback);
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
login(callback) {
|
|
213
|
+
FB.login((response)=>{
|
|
214
|
+
if (response.status === "connected") {
|
|
215
|
+
this.isSignedIn = true;
|
|
216
|
+
this.token = response.authResponse.accessToken;
|
|
217
|
+
if (callback) {
|
|
218
|
+
callback(response.authResponse.accessToken);
|
|
219
|
+
}
|
|
220
|
+
} else {
|
|
221
|
+
this.isSignedIn = false;
|
|
222
|
+
}
|
|
223
|
+
}, {
|
|
224
|
+
scope: this.facebookPermissions
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
getLoginStatus(callback) {
|
|
228
|
+
FB.getLoginStatus((response)=>{
|
|
229
|
+
if (response.status === "connected") {
|
|
230
|
+
this.isSignedIn = true;
|
|
231
|
+
this.token = response.authResponse.accessToken;
|
|
232
|
+
if (callback) {
|
|
233
|
+
callback(response.authResponse.accessToken);
|
|
234
|
+
}
|
|
235
|
+
} else {
|
|
236
|
+
this.isSignedIn = false;
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
initializeSDK() {
|
|
241
|
+
FB.init({
|
|
242
|
+
appId: this.facebookAppId,
|
|
243
|
+
xfbml: true,
|
|
244
|
+
version: "v2.9"
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
constructor(facebookAppId, facebookPermissions){
|
|
248
|
+
this.facebookAppId = facebookAppId;
|
|
249
|
+
this.facebookPermissions = facebookPermissions;
|
|
250
|
+
this.isSignedIn = undefined;
|
|
251
|
+
this.token = "";
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
class LocalTokenStorage {
|
|
256
|
+
getToken() {
|
|
257
|
+
if (this.hasValue(this.tokenKey)) {
|
|
258
|
+
return {
|
|
259
|
+
token: this.getValue(this.tokenKey),
|
|
260
|
+
refreshToken: this.getValue(this.refreshKey),
|
|
261
|
+
expirationDate: new Date(Number(this.getValue(this.expiryKey)))
|
|
262
|
+
};
|
|
263
|
+
} else {
|
|
264
|
+
return null;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
storeToken(token) {
|
|
268
|
+
this.setValue(this.tokenKey, token.token);
|
|
269
|
+
this.setValue(this.refreshKey, token.refreshToken);
|
|
270
|
+
this.setValue(this.expiryKey, token.expirationDate.getTime().toString());
|
|
271
|
+
}
|
|
272
|
+
resetToken() {
|
|
273
|
+
this.remove(this.tokenKey);
|
|
274
|
+
this.remove(this.refreshKey);
|
|
275
|
+
this.remove(this.expiryKey);
|
|
276
|
+
}
|
|
277
|
+
hasValue(key) {
|
|
278
|
+
return localStorage.getItem(key) !== null;
|
|
279
|
+
}
|
|
280
|
+
getValue(key) {
|
|
281
|
+
return localStorage.getItem(key);
|
|
282
|
+
}
|
|
283
|
+
setValue(key, val) {
|
|
284
|
+
localStorage.setItem(key, val);
|
|
285
|
+
}
|
|
286
|
+
remove(key) {
|
|
287
|
+
localStorage.removeItem(key);
|
|
288
|
+
}
|
|
289
|
+
constructor(tokenKey = "token", refreshKey = "refresh_token", expiryKey = "expiration_date"){
|
|
290
|
+
this.tokenKey = tokenKey;
|
|
291
|
+
this.refreshKey = refreshKey;
|
|
292
|
+
this.expiryKey = expiryKey;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
class MemoryTokenStorage {
|
|
297
|
+
getToken() {
|
|
298
|
+
return this.token;
|
|
299
|
+
}
|
|
300
|
+
storeToken(token) {
|
|
301
|
+
this.token = {
|
|
302
|
+
token: token.token,
|
|
303
|
+
refreshToken: token.refreshToken,
|
|
304
|
+
expirationDate: token.expirationDate
|
|
305
|
+
};
|
|
306
|
+
return Promise.resolve();
|
|
307
|
+
}
|
|
308
|
+
resetToken() {
|
|
309
|
+
this.token = null;
|
|
310
|
+
return Promise.resolve();
|
|
311
|
+
}
|
|
312
|
+
constructor(){
|
|
313
|
+
this.token = null;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
class SessionTokenStorage {
|
|
318
|
+
getToken() {
|
|
319
|
+
if (this.hasValue(this.tokenKey)) {
|
|
320
|
+
return {
|
|
321
|
+
token: this.getValue(this.tokenKey),
|
|
322
|
+
refreshToken: this.getValue(this.refreshKey),
|
|
323
|
+
expirationDate: new Date(Number(this.getValue(this.expiryKey)))
|
|
324
|
+
};
|
|
325
|
+
} else {
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
storeToken(token) {
|
|
330
|
+
this.setValue(this.tokenKey, token.token);
|
|
331
|
+
this.setValue(this.refreshKey, token.refreshToken);
|
|
332
|
+
this.setValue(this.expiryKey, token.expirationDate.getTime().toString());
|
|
333
|
+
}
|
|
334
|
+
resetToken() {
|
|
335
|
+
this.remove(this.tokenKey);
|
|
336
|
+
this.remove(this.refreshKey);
|
|
337
|
+
this.remove(this.expiryKey);
|
|
338
|
+
}
|
|
339
|
+
hasValue(key) {
|
|
340
|
+
return sessionStorage.getItem(key) !== null;
|
|
341
|
+
}
|
|
342
|
+
getValue(key) {
|
|
343
|
+
return sessionStorage.getItem(key);
|
|
344
|
+
}
|
|
345
|
+
setValue(key, val) {
|
|
346
|
+
sessionStorage.setItem(key, val);
|
|
347
|
+
}
|
|
348
|
+
remove(key) {
|
|
349
|
+
sessionStorage.removeItem(key);
|
|
350
|
+
}
|
|
351
|
+
constructor(tokenKey = "token", refreshKey = "refresh_token", expiryKey = "expiration_date"){
|
|
352
|
+
this.tokenKey = tokenKey;
|
|
353
|
+
this.refreshKey = refreshKey;
|
|
354
|
+
this.expiryKey = expiryKey;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
class SyncLoginManager extends BaseLoginManager {
|
|
359
|
+
signOut() {
|
|
360
|
+
this.storage.resetToken();
|
|
361
|
+
this.notify(false);
|
|
362
|
+
}
|
|
363
|
+
isSigned() {
|
|
364
|
+
return this.storage.getToken() !== null;
|
|
365
|
+
}
|
|
366
|
+
async getToken() {
|
|
367
|
+
const token = this.storage.getToken();
|
|
368
|
+
if (token === null) {
|
|
369
|
+
return null;
|
|
370
|
+
} else if (token.expirationDate < new Date()) {
|
|
371
|
+
if (await this.tryRefreshTokenInternal(token)) {
|
|
372
|
+
var _this_storage_getToken;
|
|
373
|
+
var _this_storage_getToken_token;
|
|
374
|
+
return (_this_storage_getToken_token = (_this_storage_getToken = this.storage.getToken()) == null ? void 0 : _this_storage_getToken.token) != null ? _this_storage_getToken_token : null;
|
|
375
|
+
} else {
|
|
376
|
+
throw new CannotRefreshToken("Cannot refresh access token after it has expired");
|
|
377
|
+
}
|
|
378
|
+
} else {
|
|
379
|
+
return token.token;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
export { AsyncLoginManager, BaseLoginManager, CannotRefreshToken, FacebookClient, LocalTokenStorage, MemoryTokenStorage, SessionTokenStorage, SyncLoginManager };
|
package/package.json
ADDED
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from "./lib/asyncLoginManager";
|
|
2
|
+
export * from "./lib/baseLoginManager";
|
|
3
|
+
export * from "./lib/cannotRefreshToken";
|
|
4
|
+
export * from "./lib/facebookClient";
|
|
5
|
+
export * from "./lib/localTokenStorage";
|
|
6
|
+
export * from "./lib/memoryTokenStorage";
|
|
7
|
+
export * from "./lib/sessionTokenStorage";
|
|
8
|
+
export * from "./lib/syncLoginManager";
|
|
9
|
+
export * from "./lib/tokenStorage";
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { BaseLoginManager, LoginManager } from "./baseLoginManager";
|
|
2
|
+
import { AsyncTokenStorage } from "./tokenStorage";
|
|
3
|
+
export declare class AsyncLoginManager extends BaseLoginManager<AsyncTokenStorage> implements LoginManager {
|
|
4
|
+
signOut(): Promise<void>;
|
|
5
|
+
isSigned(): Promise<boolean>;
|
|
6
|
+
getToken(): Promise<string | null>;
|
|
7
|
+
load(): Promise<void>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { AsyncTokenStorage, Token, TokenStorage } from "./tokenStorage";
|
|
2
|
+
export interface LoginSuccess {
|
|
3
|
+
readonly type: "success";
|
|
4
|
+
}
|
|
5
|
+
export interface LoginFailure {
|
|
6
|
+
readonly type: "failure";
|
|
7
|
+
}
|
|
8
|
+
export interface LoginNetworkError {
|
|
9
|
+
readonly type: "networkError";
|
|
10
|
+
}
|
|
11
|
+
export type LoginResult = LoginSuccess | LoginFailure | LoginNetworkError;
|
|
12
|
+
export interface LoginManager extends BaseLoginManager<TokenStorage> {
|
|
13
|
+
}
|
|
14
|
+
export declare abstract class BaseLoginManager<TStorage extends TokenStorage> {
|
|
15
|
+
protected storage: TStorage;
|
|
16
|
+
private endpoint;
|
|
17
|
+
private clientSecret;
|
|
18
|
+
private clientId;
|
|
19
|
+
private scopes;
|
|
20
|
+
private additionalParams?;
|
|
21
|
+
private callbacks;
|
|
22
|
+
private refreshTokenCallbacks;
|
|
23
|
+
private isRefreshingToken;
|
|
24
|
+
constructor(storage: TStorage, endpoint: string, clientSecret: string | undefined, clientId: string, scopes: string, additionalParams?: Record<string, string> | undefined);
|
|
25
|
+
abstract signOut(): TStorage extends AsyncTokenStorage ? Promise<void> : void;
|
|
26
|
+
abstract isSigned(): TStorage extends AsyncTokenStorage ? Promise<boolean> : boolean;
|
|
27
|
+
abstract getToken(): Promise<string | null>;
|
|
28
|
+
trySignIn(username: string, password: string): Promise<LoginResult>;
|
|
29
|
+
trySignInWithFacebook(accessToken: string): Promise<LoginResult>;
|
|
30
|
+
tryRefreshToken(): Promise<boolean | null>;
|
|
31
|
+
protected tryRefreshTokenInternal(token: Token): Promise<boolean>;
|
|
32
|
+
onChange(callback: (isSignedIn: boolean) => void): void;
|
|
33
|
+
removeOnChange(callback: () => void): void;
|
|
34
|
+
private acquireToken;
|
|
35
|
+
buildSignInRequest(username: string, password: string): RequestInit;
|
|
36
|
+
private buildSignInWithFacebookRequest;
|
|
37
|
+
private buildRefreshRequest;
|
|
38
|
+
private prepareHeaders;
|
|
39
|
+
protected notify(isSignedIn: boolean): void;
|
|
40
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare class FacebookClient {
|
|
2
|
+
private facebookAppId;
|
|
3
|
+
private facebookPermissions;
|
|
4
|
+
isSignedIn?: boolean;
|
|
5
|
+
private token;
|
|
6
|
+
constructor(facebookAppId: string, facebookPermissions: string);
|
|
7
|
+
get accessToken(): string;
|
|
8
|
+
setup(loginCallback?: (accessToken: string) => Promise<void>): void;
|
|
9
|
+
login(callback?: (accessToken: string) => Promise<void>): void;
|
|
10
|
+
private getLoginStatus;
|
|
11
|
+
private initializeSDK;
|
|
12
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SyncTokenStorage, Token } from "./tokenStorage";
|
|
2
|
+
export declare class LocalTokenStorage implements SyncTokenStorage {
|
|
3
|
+
private tokenKey;
|
|
4
|
+
private refreshKey;
|
|
5
|
+
private expiryKey;
|
|
6
|
+
constructor(tokenKey?: string, refreshKey?: string, expiryKey?: string);
|
|
7
|
+
getToken(): Token | null;
|
|
8
|
+
storeToken(token: Token): void;
|
|
9
|
+
resetToken(): void;
|
|
10
|
+
private hasValue;
|
|
11
|
+
private getValue;
|
|
12
|
+
private setValue;
|
|
13
|
+
private remove;
|
|
14
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SyncTokenStorage, Token } from "./tokenStorage";
|
|
2
|
+
export declare class SessionTokenStorage implements SyncTokenStorage {
|
|
3
|
+
private tokenKey;
|
|
4
|
+
private refreshKey;
|
|
5
|
+
private expiryKey;
|
|
6
|
+
constructor(tokenKey?: string, refreshKey?: string, expiryKey?: string);
|
|
7
|
+
getToken(): Token | null;
|
|
8
|
+
storeToken(token: Token): void;
|
|
9
|
+
resetToken(): void;
|
|
10
|
+
private hasValue;
|
|
11
|
+
private getValue;
|
|
12
|
+
private setValue;
|
|
13
|
+
private remove;
|
|
14
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { BaseLoginManager, LoginManager } from "./baseLoginManager";
|
|
2
|
+
import { SyncTokenStorage } from "./tokenStorage";
|
|
3
|
+
export declare class SyncLoginManager extends BaseLoginManager<SyncTokenStorage> implements LoginManager {
|
|
4
|
+
signOut(): void;
|
|
5
|
+
isSigned(): boolean;
|
|
6
|
+
getToken(): Promise<string | null>;
|
|
7
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface Token {
|
|
2
|
+
token: string;
|
|
3
|
+
refreshToken: string;
|
|
4
|
+
expirationDate: Date;
|
|
5
|
+
abc?: string;
|
|
6
|
+
}
|
|
7
|
+
export type TokenStorage = SyncTokenStorage | AsyncTokenStorage;
|
|
8
|
+
export interface SyncTokenStorage {
|
|
9
|
+
getToken(): Token | null;
|
|
10
|
+
storeToken(token: Token): void;
|
|
11
|
+
resetToken(): void;
|
|
12
|
+
}
|
|
13
|
+
export interface AsyncTokenStorage {
|
|
14
|
+
getToken(): Promise<Token | null>;
|
|
15
|
+
storeToken(token: Token): Promise<void>;
|
|
16
|
+
resetToken(): Promise<void>;
|
|
17
|
+
}
|