Skip to content

Commit 8d4ccef

Browse files
committed
Add OAuth provider, utils for idp
1 parent b5e778a commit 8d4ccef

File tree

3 files changed

+201
-0
lines changed

3 files changed

+201
-0
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
/**
2+
* @license
3+
* Copyright 2019 Google LLC
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import * as externs from '@firebase/auth-types-exp';
19+
20+
import { AuthErrorCode } from '../errors';
21+
22+
export interface CustomParameters {
23+
[key: string]: string;
24+
}
25+
26+
interface CredentialParameters {
27+
idToken?: string;
28+
accessToken?: string;
29+
rawNonce?: string;
30+
}
31+
32+
export class OAuthProvider implements externs.AuthProvider {
33+
defaultLanguageCode: string | null = null;
34+
private scopes: string[] = [];
35+
private customParameters: CustomParameters = {};
36+
constructor(readonly providerId: externs.ProviderId) {}
37+
static credentialFromResult(
38+
userCredential: externs.UserCredential
39+
): externs.OAuthCredential | null {
40+
throw new Error('not implemented');
41+
}
42+
static credentialFromError(error: AuthErrorCode): externs.OAuthCredential | null {
43+
throw new Error('not implemented');
44+
}
45+
static credentialFromJSON(json: object): externs.OAuthCredential {
46+
throw new Error('not implemented');
47+
}
48+
49+
credential(params: CredentialParameters): externs.OAuthCredential {
50+
throw new Error('no');
51+
}
52+
53+
setDefaultLanguage(languageCode: string | null): void {
54+
this.defaultLanguageCode = languageCode;
55+
}
56+
57+
setCustomParameters(customOAuthParameters: CustomParameters): externs.AuthProvider {
58+
this.customParameters = customOAuthParameters;
59+
return this;
60+
}
61+
62+
getCustomParameters(): CustomParameters {
63+
return this.customParameters;
64+
}
65+
66+
addScope(scope: string) {
67+
// If not already added, add scope to list.
68+
if (!this.scopes.includes(scope)) {
69+
this.scopes.push(scope);
70+
}
71+
return this;
72+
}
73+
74+
getScopes() {
75+
return this.scopes;
76+
}
77+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
2+
/**
3+
* @license
4+
* Copyright 2020 Google LLC
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
export function _generateEventId(prefix?: string): string {
20+
return `${prefix ? prefix : ''}${Math.floor(Math.random() * 1000000000)}`;
21+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/**
2+
* @license
3+
* Copyright 2019 Google Inc.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
import { getUA } from '@firebase/util';
19+
20+
import { AuthErrorCode } from '../errors';
21+
import { assert } from './assert';
22+
23+
const BASE_POPUP_OPTIONS = {
24+
location: 'yes',
25+
resizable: 'yes',
26+
statusbar: 'yes',
27+
toolbar: 'no'
28+
};
29+
30+
const DEFAULT_WIDTH = 500;
31+
const DEFAULT_HEIGHT = 600;
32+
33+
const CHROME_IOS_UA = 'crios/';
34+
const FIREFOX_UA = 'firefox/';
35+
const FIREFOX_EMPTY_URL = 'http://localhost';
36+
37+
export class AuthPopup {
38+
public associatedEvent: string | null = null;
39+
40+
constructor(public readonly window: Window) {}
41+
42+
close() {
43+
try {
44+
this.window.close();
45+
} catch (e) {}
46+
}
47+
}
48+
49+
export function _open(
50+
appName: string,
51+
url?: string,
52+
name?: string,
53+
width = DEFAULT_WIDTH,
54+
height = DEFAULT_HEIGHT
55+
): AuthPopup {
56+
const top = Math.min(
57+
(window.screen.availHeight - height) / 2,
58+
0
59+
).toString();
60+
const left = Math.min((window.screen.availWidth - width) / 2, 0).toString();
61+
let target = '';
62+
63+
const options: { [key: string]: string } = {
64+
...BASE_POPUP_OPTIONS,
65+
width: width.toString(),
66+
height: height.toString(),
67+
top,
68+
left
69+
};
70+
71+
// Chrome iOS 7 and 8 is returning an undefined popup win when target is
72+
// specified, even though the popup is not necessarily blocked.
73+
const ua = getUA().toLowerCase();
74+
75+
if (name) {
76+
target = ua.includes(CHROME_IOS_UA) ? '_blank' : name;
77+
}
78+
79+
if (ua.includes(FIREFOX_UA)) {
80+
// Firefox complains when invalid URLs are popped out. Hacky way to bypass.
81+
url = url || FIREFOX_EMPTY_URL;
82+
// Firefox disables by default scrolling on popup windows, which can create
83+
// issues when the user has many Google accounts, for instance.
84+
options.scrollbars = 'yes';
85+
}
86+
87+
const optionsString = Object.entries(options).reduce((accum, [key, value]) => `${accum}${key}=${value},`, '');
88+
89+
// TODO: Plain-old window.open isn't going to work for iOS, need to fix this
90+
// (see goog.window.open)
91+
92+
// about:blank getting sanitized causing browsers like IE/Edge to display
93+
// brief error message before redirecting to handler.
94+
const newWin = window.open(url || '', target, optionsString);
95+
assert(newWin, appName, AuthErrorCode.POPUP_BLOCKED);
96+
97+
// Flaky on IE edge, encapsulate with a try and catch.
98+
try {
99+
newWin.focus();
100+
} catch (e) {}
101+
102+
return new AuthPopup(newWin);
103+
}

0 commit comments

Comments
 (0)