@capgo/capacitor-social-login 1.2.6 → 6.0.1

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