@capgo/capacitor-social-login 7.2.3 → 7.4.5
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 +7 -7
- package/android/src/main/java/ee/forgr/capacitor/social/login/GoogleProvider.java +103 -64
- package/dist/docs.json +8 -8
- package/dist/esm/apple-provider.d.ts +17 -0
- package/dist/esm/apple-provider.js +83 -0
- package/dist/esm/apple-provider.js.map +1 -0
- package/dist/esm/base.d.ts +7 -0
- package/dist/esm/base.js +31 -0
- package/dist/esm/base.js.map +1 -0
- package/dist/esm/definitions.d.ts +6 -6
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/facebook-provider.d.ts +15 -0
- package/dist/esm/facebook-provider.js +94 -0
- package/dist/esm/facebook-provider.js.map +1 -0
- package/dist/esm/google-provider.d.ts +28 -0
- package/dist/esm/google-provider.js +350 -0
- package/dist/esm/google-provider.js.map +1 -0
- package/dist/esm/web.d.ts +4 -26
- package/dist/esm/web.js +28 -578
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +433 -432
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +433 -432
- package/dist/plugin.js.map +1 -1
- package/package.json +2 -3
package/dist/esm/web.js
CHANGED
|
@@ -1,18 +1,14 @@
|
|
|
1
1
|
import { WebPlugin } from '@capacitor/core';
|
|
2
|
+
import { AppleSocialLogin } from './apple-provider';
|
|
3
|
+
import { FacebookSocialLogin } from './facebook-provider';
|
|
4
|
+
import { GoogleSocialLogin } from './google-provider';
|
|
2
5
|
export class SocialLoginWeb extends WebPlugin {
|
|
3
6
|
constructor() {
|
|
4
7
|
var _a;
|
|
5
8
|
super();
|
|
6
|
-
this.
|
|
7
|
-
this.
|
|
8
|
-
this.
|
|
9
|
-
this.googleScriptLoaded = false;
|
|
10
|
-
this.googleLoginType = 'online';
|
|
11
|
-
this.appleScriptLoaded = false;
|
|
12
|
-
this.appleScriptUrl = 'https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1/en_US/appleid.auth.js';
|
|
13
|
-
this.GOOGLE_TOKEN_REQUEST_URL = 'https://www.googleapis.com/oauth2/v3/tokeninfo';
|
|
14
|
-
this.facebookAppId = null;
|
|
15
|
-
this.facebookScriptLoaded = false;
|
|
9
|
+
this.googleProvider = new GoogleSocialLogin();
|
|
10
|
+
this.appleProvider = new AppleSocialLogin();
|
|
11
|
+
this.facebookProvider = new FacebookSocialLogin();
|
|
16
12
|
// Set up listener for OAuth redirects if we have a pending OAuth flow
|
|
17
13
|
if (localStorage.getItem(SocialLoginWeb.OAUTH_STATE_KEY)) {
|
|
18
14
|
console.log('OAUTH_STATE_KEY found');
|
|
@@ -24,85 +20,31 @@ export class SocialLoginWeb extends WebPlugin {
|
|
|
24
20
|
}
|
|
25
21
|
}
|
|
26
22
|
handleOAuthRedirect() {
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
if (code && paramsRaw.has('scope')) {
|
|
30
|
-
return {
|
|
31
|
-
provider: 'google',
|
|
32
|
-
result: {
|
|
33
|
-
provider: 'google',
|
|
34
|
-
result: {
|
|
35
|
-
serverAuthCode: code,
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
const hash = window.location.hash.substring(1);
|
|
41
|
-
console.log('handleOAuthRedirect', window.location.hash);
|
|
42
|
-
if (!hash)
|
|
43
|
-
return;
|
|
44
|
-
console.log('handleOAuthRedirect ok');
|
|
45
|
-
const params = new URLSearchParams(hash);
|
|
46
|
-
const accessToken = params.get('access_token');
|
|
47
|
-
const idToken = params.get('id_token');
|
|
48
|
-
if (accessToken && idToken) {
|
|
49
|
-
localStorage.removeItem(SocialLoginWeb.OAUTH_STATE_KEY);
|
|
50
|
-
const profile = this.parseJwt(idToken);
|
|
51
|
-
return {
|
|
52
|
-
provider: 'google',
|
|
53
|
-
result: {
|
|
54
|
-
accessToken: {
|
|
55
|
-
token: accessToken,
|
|
56
|
-
},
|
|
57
|
-
idToken,
|
|
58
|
-
profile: {
|
|
59
|
-
email: profile.email || null,
|
|
60
|
-
familyName: profile.family_name || null,
|
|
61
|
-
givenName: profile.given_name || null,
|
|
62
|
-
id: profile.sub || null,
|
|
63
|
-
name: profile.name || null,
|
|
64
|
-
imageUrl: profile.picture || null,
|
|
65
|
-
},
|
|
66
|
-
},
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
return null;
|
|
23
|
+
const url = new URL(window.location.href);
|
|
24
|
+
return this.googleProvider.handleOAuthRedirect(url);
|
|
70
25
|
}
|
|
71
26
|
async initialize(options) {
|
|
72
27
|
var _a, _b, _c;
|
|
28
|
+
const initPromises = [];
|
|
73
29
|
if ((_a = options.google) === null || _a === void 0 ? void 0 : _a.webClientId) {
|
|
74
|
-
this.
|
|
75
|
-
if (options.google.mode) {
|
|
76
|
-
this.googleLoginType = options.google.mode;
|
|
77
|
-
}
|
|
78
|
-
this.googleHostedDomain = options.google.hostedDomain;
|
|
79
|
-
await this.loadGoogleScript();
|
|
30
|
+
initPromises.push(this.googleProvider.initialize(options.google.webClientId, options.google.mode, options.google.hostedDomain));
|
|
80
31
|
}
|
|
81
32
|
if ((_b = options.apple) === null || _b === void 0 ? void 0 : _b.clientId) {
|
|
82
|
-
this.
|
|
83
|
-
this.appleRedirectUrl = options.apple.redirectUrl || null;
|
|
84
|
-
await this.loadAppleScript();
|
|
33
|
+
initPromises.push(this.appleProvider.initialize(options.apple.clientId, options.apple.redirectUrl));
|
|
85
34
|
}
|
|
86
35
|
if ((_c = options.facebook) === null || _c === void 0 ? void 0 : _c.appId) {
|
|
87
|
-
this.
|
|
88
|
-
await this.loadFacebookScript();
|
|
89
|
-
FB.init({
|
|
90
|
-
appId: this.facebookAppId,
|
|
91
|
-
version: 'v17.0',
|
|
92
|
-
xfbml: true,
|
|
93
|
-
cookie: true,
|
|
94
|
-
});
|
|
36
|
+
initPromises.push(this.facebookProvider.initialize(options.facebook.appId));
|
|
95
37
|
}
|
|
96
|
-
|
|
38
|
+
await Promise.all(initPromises);
|
|
97
39
|
}
|
|
98
40
|
async login(options) {
|
|
99
41
|
switch (options.provider) {
|
|
100
42
|
case 'google':
|
|
101
|
-
return this.
|
|
43
|
+
return this.googleProvider.login(options.options);
|
|
102
44
|
case 'apple':
|
|
103
|
-
return this.
|
|
45
|
+
return this.appleProvider.login(options.options);
|
|
104
46
|
case 'facebook':
|
|
105
|
-
return this.
|
|
47
|
+
return this.facebookProvider.login(options.options);
|
|
106
48
|
default:
|
|
107
49
|
throw new Error(`Login for ${options.provider} is not implemented on web`);
|
|
108
50
|
}
|
|
@@ -110,154 +52,23 @@ export class SocialLoginWeb extends WebPlugin {
|
|
|
110
52
|
async logout(options) {
|
|
111
53
|
switch (options.provider) {
|
|
112
54
|
case 'google':
|
|
113
|
-
|
|
114
|
-
return Promise.reject("Offline login doesn't store tokens. logout is not available");
|
|
115
|
-
}
|
|
116
|
-
// Google doesn't have a specific logout method for web
|
|
117
|
-
// We can revoke the token if we have it stored
|
|
118
|
-
console.log('Google logout: Id token should be revoked on the client side if stored');
|
|
119
|
-
// eslint-disable-next-line
|
|
120
|
-
const state = this.getGoogleState();
|
|
121
|
-
if (!state)
|
|
122
|
-
return;
|
|
123
|
-
await this.rawLogoutGoogle(state.accessToken);
|
|
124
|
-
break;
|
|
55
|
+
return this.googleProvider.logout();
|
|
125
56
|
case 'apple':
|
|
126
|
-
|
|
127
|
-
console.log('Apple logout: Session should be managed on the client side');
|
|
128
|
-
break;
|
|
57
|
+
return this.appleProvider.logout();
|
|
129
58
|
case 'facebook':
|
|
130
|
-
return
|
|
131
|
-
FB.logout(() => resolve());
|
|
132
|
-
});
|
|
59
|
+
return this.facebookProvider.logout();
|
|
133
60
|
default:
|
|
134
61
|
throw new Error(`Logout for ${options.provider} is not implemented`);
|
|
135
62
|
}
|
|
136
63
|
}
|
|
137
|
-
async accessTokenIsValid(accessToken) {
|
|
138
|
-
const url = `${this.GOOGLE_TOKEN_REQUEST_URL}?access_token=${encodeURIComponent(accessToken)}`;
|
|
139
|
-
try {
|
|
140
|
-
// Make the GET request using fetch
|
|
141
|
-
const response = await fetch(url);
|
|
142
|
-
// Check if the response is successful
|
|
143
|
-
if (!response.ok) {
|
|
144
|
-
console.log(`Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. Response not successful. Status code: ${response.status}. Assuming that the token is not valid`);
|
|
145
|
-
return false;
|
|
146
|
-
}
|
|
147
|
-
// Get the response body as text
|
|
148
|
-
const responseBody = await response.text();
|
|
149
|
-
if (!responseBody) {
|
|
150
|
-
console.error(`Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. Response body is null`);
|
|
151
|
-
throw new Error(`Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. Response body is null`);
|
|
152
|
-
}
|
|
153
|
-
// Parse the response body as JSON
|
|
154
|
-
let jsonObject;
|
|
155
|
-
try {
|
|
156
|
-
jsonObject = JSON.parse(responseBody);
|
|
157
|
-
}
|
|
158
|
-
catch (e) {
|
|
159
|
-
console.error(`Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. Response body is not valid JSON. Error: ${e}`);
|
|
160
|
-
throw new Error(`Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. Response body is not valid JSON. Error: ${e}`);
|
|
161
|
-
}
|
|
162
|
-
// Extract the 'expires_in' field
|
|
163
|
-
const expiresInStr = jsonObject['expires_in'];
|
|
164
|
-
if (expiresInStr === undefined || expiresInStr === null) {
|
|
165
|
-
console.error(`Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. Response JSON does not include 'expires_in'.`);
|
|
166
|
-
throw new Error(`Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. Response JSON does not include 'expires_in'.`);
|
|
167
|
-
}
|
|
168
|
-
// Parse 'expires_in' as an integer
|
|
169
|
-
let expiresInInt;
|
|
170
|
-
try {
|
|
171
|
-
expiresInInt = parseInt(expiresInStr, 10);
|
|
172
|
-
if (isNaN(expiresInInt)) {
|
|
173
|
-
throw new Error(`'expires_in' is not a valid integer`);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
catch (e) {
|
|
177
|
-
console.error(`Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. 'expires_in': ${expiresInStr} is not a valid integer. Error: ${e}`);
|
|
178
|
-
throw new Error(`Invalid response from ${this.GOOGLE_TOKEN_REQUEST_URL}. 'expires_in': ${expiresInStr} is not a valid integer. Error: ${e}`);
|
|
179
|
-
}
|
|
180
|
-
// Determine if the access token is valid based on 'expires_in'
|
|
181
|
-
return expiresInInt > 5;
|
|
182
|
-
}
|
|
183
|
-
catch (error) {
|
|
184
|
-
console.error(error);
|
|
185
|
-
throw error;
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
idTokenValid(idToken) {
|
|
189
|
-
try {
|
|
190
|
-
const parsed = this.parseJwt(idToken);
|
|
191
|
-
const currentTime = Math.ceil(Date.now() / 1000) + 5; // Convert current time to seconds since epoch
|
|
192
|
-
return parsed.exp && currentTime < parsed.exp;
|
|
193
|
-
}
|
|
194
|
-
catch (e) {
|
|
195
|
-
return false;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
async rawLogoutGoogle(accessToken, tokenValid = null) {
|
|
199
|
-
if (tokenValid === null) {
|
|
200
|
-
tokenValid = await this.accessTokenIsValid(accessToken);
|
|
201
|
-
}
|
|
202
|
-
if (tokenValid === true) {
|
|
203
|
-
return new Promise((resolve, reject) => {
|
|
204
|
-
try {
|
|
205
|
-
google.accounts.oauth2.revoke(accessToken, async () => {
|
|
206
|
-
this.clearStateGoogle();
|
|
207
|
-
resolve();
|
|
208
|
-
});
|
|
209
|
-
}
|
|
210
|
-
catch (e) {
|
|
211
|
-
reject(e);
|
|
212
|
-
}
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
else {
|
|
216
|
-
this.clearStateGoogle();
|
|
217
|
-
return;
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
64
|
async isLoggedIn(options) {
|
|
221
65
|
switch (options.provider) {
|
|
222
66
|
case 'google':
|
|
223
|
-
|
|
224
|
-
return Promise.reject("Offline login doesn't store tokens. isLoggedIn is not available");
|
|
225
|
-
}
|
|
226
|
-
// For Google, we can check if there's a valid token
|
|
227
|
-
// eslint-disable-next-line
|
|
228
|
-
const state = this.getGoogleState();
|
|
229
|
-
if (!state)
|
|
230
|
-
return { isLoggedIn: false };
|
|
231
|
-
try {
|
|
232
|
-
// todo: cache accessTokenIsValid calls
|
|
233
|
-
const isValidAccessToken = await this.accessTokenIsValid(state.accessToken);
|
|
234
|
-
const isValidIdToken = this.idTokenValid(state.idToken);
|
|
235
|
-
if (isValidAccessToken && isValidIdToken) {
|
|
236
|
-
return { isLoggedIn: true };
|
|
237
|
-
}
|
|
238
|
-
else {
|
|
239
|
-
try {
|
|
240
|
-
await this.rawLogoutGoogle(state.accessToken, false);
|
|
241
|
-
}
|
|
242
|
-
catch (e) {
|
|
243
|
-
console.error('Access token is not valid, but cannot logout', e);
|
|
244
|
-
}
|
|
245
|
-
return { isLoggedIn: false };
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
catch (e) {
|
|
249
|
-
return Promise.reject(e);
|
|
250
|
-
}
|
|
67
|
+
return this.googleProvider.isLoggedIn();
|
|
251
68
|
case 'apple':
|
|
252
|
-
|
|
253
|
-
console.log('Apple login status should be managed on the client side');
|
|
254
|
-
return { isLoggedIn: false };
|
|
69
|
+
return this.appleProvider.isLoggedIn();
|
|
255
70
|
case 'facebook':
|
|
256
|
-
return
|
|
257
|
-
FB.getLoginStatus((response) => {
|
|
258
|
-
resolve({ isLoggedIn: response.status === 'connected' });
|
|
259
|
-
});
|
|
260
|
-
});
|
|
71
|
+
return this.facebookProvider.isLoggedIn();
|
|
261
72
|
default:
|
|
262
73
|
throw new Error(`isLoggedIn for ${options.provider} is not implemented`);
|
|
263
74
|
}
|
|
@@ -265,50 +76,11 @@ export class SocialLoginWeb extends WebPlugin {
|
|
|
265
76
|
async getAuthorizationCode(options) {
|
|
266
77
|
switch (options.provider) {
|
|
267
78
|
case 'google':
|
|
268
|
-
|
|
269
|
-
return Promise.reject("Offline login doesn't store tokens. getAuthorizationCode is not available");
|
|
270
|
-
}
|
|
271
|
-
// For Google, we can use the id_token as the authorization code
|
|
272
|
-
// eslint-disable-next-line
|
|
273
|
-
const state = this.getGoogleState();
|
|
274
|
-
if (!state)
|
|
275
|
-
throw new Error('No Google authorization code available');
|
|
276
|
-
try {
|
|
277
|
-
// todo: cache accessTokenIsValid calls
|
|
278
|
-
const isValidAccessToken = await this.accessTokenIsValid(state.accessToken);
|
|
279
|
-
const isValidIdToken = this.idTokenValid(state.idToken);
|
|
280
|
-
if (isValidAccessToken && isValidIdToken) {
|
|
281
|
-
return { accessToken: state.accessToken, jwt: state.idToken };
|
|
282
|
-
}
|
|
283
|
-
else {
|
|
284
|
-
try {
|
|
285
|
-
await this.rawLogoutGoogle(state.accessToken, false);
|
|
286
|
-
}
|
|
287
|
-
catch (e) {
|
|
288
|
-
console.error('Access token is not valid, but cannot logout', e);
|
|
289
|
-
}
|
|
290
|
-
throw new Error('No Google authorization code available');
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
catch (e) {
|
|
294
|
-
return Promise.reject(e);
|
|
295
|
-
}
|
|
79
|
+
return this.googleProvider.getAuthorizationCode();
|
|
296
80
|
case 'apple':
|
|
297
|
-
|
|
298
|
-
console.log('Apple authorization code should be stored during login');
|
|
299
|
-
throw new Error('Apple authorization code not available');
|
|
81
|
+
return this.appleProvider.getAuthorizationCode();
|
|
300
82
|
case 'facebook':
|
|
301
|
-
return
|
|
302
|
-
FB.getLoginStatus((response) => {
|
|
303
|
-
var _a;
|
|
304
|
-
if (response.status === 'connected') {
|
|
305
|
-
resolve({ jwt: ((_a = response.authResponse) === null || _a === void 0 ? void 0 : _a.accessToken) || '' });
|
|
306
|
-
}
|
|
307
|
-
else {
|
|
308
|
-
reject(new Error('No Facebook authorization code available'));
|
|
309
|
-
}
|
|
310
|
-
});
|
|
311
|
-
});
|
|
83
|
+
return this.facebookProvider.getAuthorizationCode();
|
|
312
84
|
default:
|
|
313
85
|
throw new Error(`getAuthorizationCode for ${options.provider} is not implemented`);
|
|
314
86
|
}
|
|
@@ -316,337 +88,15 @@ export class SocialLoginWeb extends WebPlugin {
|
|
|
316
88
|
async refresh(options) {
|
|
317
89
|
switch (options.provider) {
|
|
318
90
|
case 'google':
|
|
319
|
-
|
|
320
|
-
return Promise.reject('Not implemented');
|
|
91
|
+
return this.googleProvider.refresh();
|
|
321
92
|
case 'apple':
|
|
322
|
-
|
|
323
|
-
console.log('Apple refresh not available on web');
|
|
324
|
-
break;
|
|
93
|
+
return this.appleProvider.refresh();
|
|
325
94
|
case 'facebook':
|
|
326
|
-
|
|
327
|
-
break;
|
|
95
|
+
return this.facebookProvider.refresh(options.options);
|
|
328
96
|
default:
|
|
329
97
|
throw new Error(`Refresh for ${options.provider} is not implemented`);
|
|
330
98
|
}
|
|
331
99
|
}
|
|
332
|
-
loginWithGoogle(options) {
|
|
333
|
-
if (!this.googleClientId) {
|
|
334
|
-
throw new Error('Google Client ID not set. Call initialize() first.');
|
|
335
|
-
}
|
|
336
|
-
let scopes = options.scopes || [];
|
|
337
|
-
if (scopes.length > 0) {
|
|
338
|
-
// If scopes are provided, directly use the traditional OAuth flow
|
|
339
|
-
if (!scopes.includes('https://www.googleapis.com/auth/userinfo.email')) {
|
|
340
|
-
scopes.push('https://www.googleapis.com/auth/userinfo.email');
|
|
341
|
-
}
|
|
342
|
-
if (!scopes.includes('https://www.googleapis.com/auth/userinfo.profile')) {
|
|
343
|
-
scopes.push('https://www.googleapis.com/auth/userinfo.profile');
|
|
344
|
-
}
|
|
345
|
-
if (!scopes.includes('openid')) {
|
|
346
|
-
scopes.push('openid');
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
else {
|
|
350
|
-
scopes = [
|
|
351
|
-
'https://www.googleapis.com/auth/userinfo.email',
|
|
352
|
-
'https://www.googleapis.com/auth/userinfo.profile',
|
|
353
|
-
'openid',
|
|
354
|
-
];
|
|
355
|
-
}
|
|
356
|
-
if (scopes.length > 3 || this.googleLoginType === 'offline' || options.disableOneTap) {
|
|
357
|
-
// If scopes are provided, directly use the traditional OAuth flow
|
|
358
|
-
return this.fallbackToTraditionalOAuth(scopes, this.googleHostedDomain);
|
|
359
|
-
}
|
|
360
|
-
return new Promise((resolve, reject) => {
|
|
361
|
-
google.accounts.id.initialize({
|
|
362
|
-
client_id: this.googleClientId,
|
|
363
|
-
hd: this.googleHostedDomain,
|
|
364
|
-
callback: (response) => {
|
|
365
|
-
console.log('google.accounts.id.initialize callback', response);
|
|
366
|
-
if (response.error) {
|
|
367
|
-
// we use any because type fail but we need to double check if that works
|
|
368
|
-
reject(response.error);
|
|
369
|
-
}
|
|
370
|
-
else {
|
|
371
|
-
const payload = this.parseJwt(response.credential);
|
|
372
|
-
const result = {
|
|
373
|
-
accessToken: null,
|
|
374
|
-
responseType: 'online',
|
|
375
|
-
idToken: response.credential,
|
|
376
|
-
profile: {
|
|
377
|
-
email: payload.email || null,
|
|
378
|
-
familyName: payload.family_name || null,
|
|
379
|
-
givenName: payload.given_name || null,
|
|
380
|
-
id: payload.sub || null,
|
|
381
|
-
name: payload.name || null,
|
|
382
|
-
imageUrl: payload.picture || null,
|
|
383
|
-
},
|
|
384
|
-
};
|
|
385
|
-
resolve({ provider: 'google', result });
|
|
386
|
-
}
|
|
387
|
-
},
|
|
388
|
-
auto_select: true,
|
|
389
|
-
});
|
|
390
|
-
google.accounts.id.prompt((notification) => {
|
|
391
|
-
if (notification.isNotDisplayed() || notification.isSkippedMoment()) {
|
|
392
|
-
console.log('OneTap is not displayed or skipped');
|
|
393
|
-
// Fallback to traditional OAuth if One Tap is not available
|
|
394
|
-
this.fallbackToTraditionalOAuth(scopes, this.googleHostedDomain)
|
|
395
|
-
.then((r) => resolve({ provider: 'google', result: r.result }))
|
|
396
|
-
.catch(reject);
|
|
397
|
-
}
|
|
398
|
-
else {
|
|
399
|
-
console.log('OneTap is displayed');
|
|
400
|
-
}
|
|
401
|
-
});
|
|
402
|
-
});
|
|
403
|
-
}
|
|
404
|
-
parseJwt(token) {
|
|
405
|
-
const base64Url = token.split('.')[1];
|
|
406
|
-
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
|
407
|
-
const jsonPayload = decodeURIComponent(atob(base64)
|
|
408
|
-
.split('')
|
|
409
|
-
.map((c) => {
|
|
410
|
-
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
|
|
411
|
-
})
|
|
412
|
-
.join(''));
|
|
413
|
-
return JSON.parse(jsonPayload);
|
|
414
|
-
}
|
|
415
|
-
async loadGoogleScript() {
|
|
416
|
-
if (this.googleScriptLoaded)
|
|
417
|
-
return;
|
|
418
|
-
return new Promise((resolve, reject) => {
|
|
419
|
-
const script = document.createElement('script');
|
|
420
|
-
script.src = 'https://accounts.google.com/gsi/client';
|
|
421
|
-
script.async = true;
|
|
422
|
-
script.onload = () => {
|
|
423
|
-
this.googleScriptLoaded = true;
|
|
424
|
-
resolve();
|
|
425
|
-
};
|
|
426
|
-
script.onerror = reject;
|
|
427
|
-
document.body.appendChild(script);
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
|
-
async loginWithApple(options) {
|
|
431
|
-
if (!this.appleClientId) {
|
|
432
|
-
throw new Error('Apple Client ID not set. Call initialize() first.');
|
|
433
|
-
}
|
|
434
|
-
if (!this.appleScriptLoaded) {
|
|
435
|
-
throw new Error('Apple Sign-In script not loaded.');
|
|
436
|
-
}
|
|
437
|
-
return new Promise((resolve, reject) => {
|
|
438
|
-
var _a;
|
|
439
|
-
AppleID.auth.init({
|
|
440
|
-
clientId: this.appleClientId,
|
|
441
|
-
scope: ((_a = options.scopes) === null || _a === void 0 ? void 0 : _a.join(' ')) || 'name email',
|
|
442
|
-
redirectURI: this.appleRedirectUrl || window.location.href,
|
|
443
|
-
state: options.state,
|
|
444
|
-
nonce: options.nonce,
|
|
445
|
-
usePopup: true,
|
|
446
|
-
});
|
|
447
|
-
AppleID.auth
|
|
448
|
-
.signIn()
|
|
449
|
-
.then((res) => {
|
|
450
|
-
var _a, _b, _c, _d, _e;
|
|
451
|
-
const result = {
|
|
452
|
-
profile: {
|
|
453
|
-
user: res.user || '',
|
|
454
|
-
email: ((_a = res.user) === null || _a === void 0 ? void 0 : _a.email) || null,
|
|
455
|
-
givenName: ((_c = (_b = res.user) === null || _b === void 0 ? void 0 : _b.name) === null || _c === void 0 ? void 0 : _c.firstName) || null,
|
|
456
|
-
familyName: ((_e = (_d = res.user) === null || _d === void 0 ? void 0 : _d.name) === null || _e === void 0 ? void 0 : _e.lastName) || null,
|
|
457
|
-
},
|
|
458
|
-
accessToken: {
|
|
459
|
-
token: res.authorization.id_token || '',
|
|
460
|
-
},
|
|
461
|
-
idToken: res.authorization.code || null,
|
|
462
|
-
};
|
|
463
|
-
resolve({ provider: 'apple', result });
|
|
464
|
-
})
|
|
465
|
-
.catch((error) => {
|
|
466
|
-
reject(error);
|
|
467
|
-
});
|
|
468
|
-
});
|
|
469
|
-
}
|
|
470
|
-
async loadAppleScript() {
|
|
471
|
-
if (this.appleScriptLoaded)
|
|
472
|
-
return;
|
|
473
|
-
return new Promise((resolve, reject) => {
|
|
474
|
-
const script = document.createElement('script');
|
|
475
|
-
script.src = this.appleScriptUrl;
|
|
476
|
-
script.async = true;
|
|
477
|
-
script.onload = () => {
|
|
478
|
-
this.appleScriptLoaded = true;
|
|
479
|
-
resolve();
|
|
480
|
-
};
|
|
481
|
-
script.onerror = reject;
|
|
482
|
-
document.body.appendChild(script);
|
|
483
|
-
});
|
|
484
|
-
}
|
|
485
|
-
persistStateGoogle(accessToken, idToken) {
|
|
486
|
-
try {
|
|
487
|
-
window.localStorage.setItem('capgo_social_login_google_state', JSON.stringify({ accessToken, idToken }));
|
|
488
|
-
}
|
|
489
|
-
catch (e) {
|
|
490
|
-
console.error('Cannot persist state google', e);
|
|
491
|
-
}
|
|
492
|
-
}
|
|
493
|
-
clearStateGoogle() {
|
|
494
|
-
try {
|
|
495
|
-
window.localStorage.removeItem('capgo_social_login_google_state');
|
|
496
|
-
}
|
|
497
|
-
catch (e) {
|
|
498
|
-
console.error('Cannot clear state google', e);
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
getGoogleState() {
|
|
502
|
-
try {
|
|
503
|
-
const state = window.localStorage.getItem('capgo_social_login_google_state');
|
|
504
|
-
if (!state)
|
|
505
|
-
return null;
|
|
506
|
-
const { accessToken, idToken } = JSON.parse(state);
|
|
507
|
-
return { accessToken, idToken };
|
|
508
|
-
}
|
|
509
|
-
catch (e) {
|
|
510
|
-
console.error('Cannot get state google', e);
|
|
511
|
-
return null;
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
async loadFacebookScript() {
|
|
515
|
-
if (this.facebookScriptLoaded)
|
|
516
|
-
return;
|
|
517
|
-
return new Promise((resolve, reject) => {
|
|
518
|
-
const script = document.createElement('script');
|
|
519
|
-
script.src = 'https://connect.facebook.net/en_US/sdk.js';
|
|
520
|
-
script.async = true;
|
|
521
|
-
script.defer = true;
|
|
522
|
-
script.onload = () => {
|
|
523
|
-
this.facebookScriptLoaded = true;
|
|
524
|
-
resolve();
|
|
525
|
-
};
|
|
526
|
-
script.onerror = reject;
|
|
527
|
-
document.body.appendChild(script);
|
|
528
|
-
});
|
|
529
|
-
}
|
|
530
|
-
async loginWithFacebook(options) {
|
|
531
|
-
if (!this.facebookAppId) {
|
|
532
|
-
throw new Error('Facebook App ID not set. Call initialize() first.');
|
|
533
|
-
}
|
|
534
|
-
return new Promise((resolve, reject) => {
|
|
535
|
-
FB.login((response) => {
|
|
536
|
-
if (response.status === 'connected') {
|
|
537
|
-
FB.api('/me', { fields: 'id,name,email,picture' }, (userInfo) => {
|
|
538
|
-
var _a, _b;
|
|
539
|
-
const result = {
|
|
540
|
-
accessToken: {
|
|
541
|
-
token: response.authResponse.accessToken,
|
|
542
|
-
userId: response.authResponse.userID,
|
|
543
|
-
},
|
|
544
|
-
profile: {
|
|
545
|
-
userID: userInfo.id,
|
|
546
|
-
name: userInfo.name,
|
|
547
|
-
email: userInfo.email || null,
|
|
548
|
-
imageURL: ((_b = (_a = userInfo.picture) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.url) || null,
|
|
549
|
-
friendIDs: [],
|
|
550
|
-
birthday: null,
|
|
551
|
-
ageRange: null,
|
|
552
|
-
gender: null,
|
|
553
|
-
location: null,
|
|
554
|
-
hometown: null,
|
|
555
|
-
profileURL: null,
|
|
556
|
-
},
|
|
557
|
-
idToken: null,
|
|
558
|
-
};
|
|
559
|
-
resolve({ provider: 'facebook', result });
|
|
560
|
-
});
|
|
561
|
-
}
|
|
562
|
-
else {
|
|
563
|
-
reject(new Error('Facebook login failed'));
|
|
564
|
-
}
|
|
565
|
-
}, { scope: options.permissions.join(',') });
|
|
566
|
-
});
|
|
567
|
-
}
|
|
568
|
-
async fallbackToTraditionalOAuth(scopes, hostedDomain) {
|
|
569
|
-
const uniqueScopes = [...new Set([...scopes, 'openid'])];
|
|
570
|
-
const params = new URLSearchParams({
|
|
571
|
-
client_id: this.googleClientId,
|
|
572
|
-
redirect_uri: window.location.href,
|
|
573
|
-
response_type: this.googleLoginType === 'offline' ? 'code' : 'token id_token',
|
|
574
|
-
scope: uniqueScopes.join(' '),
|
|
575
|
-
nonce: Math.random().toString(36).substring(2),
|
|
576
|
-
include_granted_scopes: 'true',
|
|
577
|
-
state: 'popup',
|
|
578
|
-
});
|
|
579
|
-
if (hostedDomain !== undefined) {
|
|
580
|
-
params.append('hd', hostedDomain);
|
|
581
|
-
}
|
|
582
|
-
const url = `https://accounts.google.com/o/oauth2/v2/auth?${params.toString()}`;
|
|
583
|
-
const width = 500;
|
|
584
|
-
const height = 600;
|
|
585
|
-
const left = window.screenX + (window.outerWidth - width) / 2;
|
|
586
|
-
const top = window.screenY + (window.outerHeight - height) / 2;
|
|
587
|
-
localStorage.setItem(SocialLoginWeb.OAUTH_STATE_KEY, 'true');
|
|
588
|
-
const popup = window.open(url, 'Google Sign In', `width=${width},height=${height},left=${left},top=${top},popup=1`);
|
|
589
|
-
// This may never return...
|
|
590
|
-
return new Promise((resolve, reject) => {
|
|
591
|
-
if (!popup) {
|
|
592
|
-
reject(new Error('Failed to open popup'));
|
|
593
|
-
return;
|
|
594
|
-
}
|
|
595
|
-
const handleMessage = (event) => {
|
|
596
|
-
var _a;
|
|
597
|
-
if (event.origin !== window.location.origin)
|
|
598
|
-
return;
|
|
599
|
-
if (((_a = event.data) === null || _a === void 0 ? void 0 : _a.type) === 'oauth-response') {
|
|
600
|
-
window.removeEventListener('message', handleMessage);
|
|
601
|
-
if (this.googleLoginType === 'online') {
|
|
602
|
-
const { accessToken, idToken } = event.data;
|
|
603
|
-
if (accessToken && idToken) {
|
|
604
|
-
const profile = this.parseJwt(idToken);
|
|
605
|
-
this.persistStateGoogle(accessToken.token, idToken);
|
|
606
|
-
resolve({
|
|
607
|
-
provider: 'google',
|
|
608
|
-
result: {
|
|
609
|
-
accessToken: {
|
|
610
|
-
token: accessToken.token,
|
|
611
|
-
},
|
|
612
|
-
idToken,
|
|
613
|
-
profile: {
|
|
614
|
-
email: profile.email || null,
|
|
615
|
-
familyName: profile.family_name || null,
|
|
616
|
-
givenName: profile.given_name || null,
|
|
617
|
-
id: profile.sub || null,
|
|
618
|
-
name: profile.name || null,
|
|
619
|
-
imageUrl: profile.picture || null,
|
|
620
|
-
},
|
|
621
|
-
responseType: 'online',
|
|
622
|
-
},
|
|
623
|
-
});
|
|
624
|
-
}
|
|
625
|
-
}
|
|
626
|
-
else {
|
|
627
|
-
const { serverAuthCode } = event.data.result;
|
|
628
|
-
resolve({
|
|
629
|
-
provider: 'google',
|
|
630
|
-
result: {
|
|
631
|
-
responseType: 'offline',
|
|
632
|
-
serverAuthCode,
|
|
633
|
-
},
|
|
634
|
-
});
|
|
635
|
-
}
|
|
636
|
-
}
|
|
637
|
-
else {
|
|
638
|
-
reject(new Error('Login failed'));
|
|
639
|
-
}
|
|
640
|
-
};
|
|
641
|
-
window.addEventListener('message', handleMessage);
|
|
642
|
-
// Timeout after 5 minutes
|
|
643
|
-
setTimeout(() => {
|
|
644
|
-
window.removeEventListener('message', handleMessage);
|
|
645
|
-
popup.close();
|
|
646
|
-
reject(new Error('OAuth timeout'));
|
|
647
|
-
}, 300000);
|
|
648
|
-
});
|
|
649
|
-
}
|
|
650
100
|
}
|
|
651
101
|
SocialLoginWeb.OAUTH_STATE_KEY = 'social_login_oauth_pending';
|
|
652
102
|
//# sourceMappingURL=web.js.map
|