Skip to content

Commit 1d9f402

Browse files
author
Kian Jamali
committed
Fix trusted types violation
1 parent 60d1b18 commit 1d9f402

File tree

9 files changed

+52
-38
lines changed

9 files changed

+52
-38
lines changed

packages/auth/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@
127127
"@firebase/component": "0.7.0",
128128
"@firebase/logger": "0.5.0",
129129
"@firebase/util": "1.13.0",
130+
"safevalues": "1.2.0",
130131
"tslib": "^2.1.0"
131132
},
132133
"license": "Apache-2.0",

packages/auth/src/platform_browser/iframe/gapi.test.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { testAuth, TestAuth } from '../../../test/helpers/mock_auth';
2626
import { _window } from '../auth_window';
2727
import * as js from '../load_js';
2828
import { _loadGapi, _resetLoader } from './gapi';
29+
import { unwrapResourceUrl } from 'safevalues';
2930

3031
use(sinonChai);
3132
use(chaiAsPromised);
@@ -41,7 +42,7 @@ describe('platform_browser/iframe/gapi', () => {
4142

4243
beforeEach(async () => {
4344
loadJsStub = sinon.stub(js, '_loadJS').callsFake(url => {
44-
onJsLoad(url.split('onload=')[1]);
45+
onJsLoad(unwrapResourceUrl(url).split('onload=')[1]);
4546
return Promise.resolve(new Event('load'));
4647
});
4748

packages/auth/src/platform_browser/iframe/gapi.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
* limitations under the License.
1616
*/
1717

18+
import { appendParams } from 'safevalues';
19+
1820
import { AuthErrorCode } from '../../core/errors';
1921
import { _createError } from '../../core/util/assert';
2022
import { Delay } from '../../core/util/delay';
@@ -104,7 +106,7 @@ function loadGapi(auth: AuthInternal): Promise<gapi.iframes.Context> {
104106
};
105107
// Load GApi loader.
106108
return js
107-
._loadJS(`${js._gapiScriptUrl()}?onload=${cbName}`)
109+
._loadJS(appendParams(js._gapiScriptUrl(), new Map([['onload', cbName]])))
108110
.catch(e => reject(e));
109111
}
110112
}).catch(error => {

packages/auth/src/platform_browser/index.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
*/
1717

1818
import { FirebaseApp, getApp, _getProvider } from '@firebase/app';
19+
import { TrustedResourceUrl, trustedResourceUrl } from 'safevalues';
20+
import { setScriptSrc } from 'safevalues/dom';
1921

2022
import {
2123
initializeAuth,
@@ -120,11 +122,11 @@ function getScriptParentElement(): HTMLDocument | HTMLHeadElement {
120122
}
121123

122124
_setExternalJSProvider({
123-
loadJS(url: string): Promise<Event> {
125+
loadJS(url: TrustedResourceUrl): Promise<Event> {
124126
// TODO: consider adding timeout support & cancellation
125127
return new Promise((resolve, reject) => {
126-
const el = document.createElement('script');
127-
el.setAttribute('src', url);
128+
const el = document.createElement('script') as HTMLScriptElement;
129+
setScriptSrc(el, url);
128130
el.onload = resolve;
129131
el.onerror = e => {
130132
const error = _createError(AuthErrorCode.INTERNAL_ERROR);
@@ -137,10 +139,10 @@ _setExternalJSProvider({
137139
});
138140
},
139141

140-
gapiScript: 'https://apis.google.com/js/api.js',
141-
recaptchaV2Script: 'https://www.google.com/recaptcha/api.js',
142+
gapiScript: trustedResourceUrl`https://apis.google.com/js/api.js`,
143+
recaptchaV2Script: trustedResourceUrl`https://www.google.com/recaptcha/api.js`,
142144
recaptchaEnterpriseScript:
143-
'https://www.google.com/recaptcha/enterprise.js?render='
145+
trustedResourceUrl`https://www.google.com/recaptcha/enterprise.js`
144146
});
145147

146148
registerAuth(ClientPlatform.BROWSER);

packages/auth/src/platform_browser/load_js.test.ts

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import {
2626
} from './load_js';
2727
import { _createError } from '../core/util/assert';
2828
import { AuthErrorCode } from '../core/errors';
29+
import { TrustedResourceUrl, trustedResourceUrl, unwrapResourceUrl } from 'safevalues';
30+
import { setScriptSrc } from 'safevalues/dom';
2931

3032
use(sinonChai);
3133

@@ -41,10 +43,10 @@ describe('platform-browser/load_js', () => {
4143
describe('_loadJS', () => {
4244
it('sets the appropriate properties', () => {
4345
_setExternalJSProvider({
44-
loadJS(url: string): Promise<Event> {
46+
loadJS(url: TrustedResourceUrl): Promise<Event> {
4547
return new Promise((resolve, reject) => {
4648
const el = document.createElement('script');
47-
el.setAttribute('src', url);
49+
setScriptSrc(el, url);
4850
el.onload = resolve;
4951
el.onerror = e => {
5052
const error = _createError(AuthErrorCode.INTERNAL_ERROR);
@@ -55,20 +57,18 @@ describe('platform-browser/load_js', () => {
5557
el.charset = 'UTF-8';
5658
});
5759
},
58-
gapiScript: 'https://gapiScript',
59-
recaptchaV2Script: 'https://recaptchaV2Script',
60-
recaptchaEnterpriseScript: 'https://recaptchaEnterpriseScript'
60+
gapiScript: trustedResourceUrl`https://gapiScript`,
61+
recaptchaV2Script: trustedResourceUrl`https://recaptchaV2Script`,
62+
recaptchaEnterpriseScript: trustedResourceUrl`https://recaptchaEnterpriseScript`
6163
});
6264
const el = document.createElement('script');
6365
sinon.stub(el); // Prevent actually setting the src attribute
6466
sinon.stub(document, 'createElement').returns(el);
6567

68+
const testUrl = trustedResourceUrl`http://localhost/url`;
6669
// eslint-disable-next-line @typescript-eslint/no-floating-promises
67-
_loadJS('http://localhost/url');
68-
expect(el.setAttribute).to.have.been.calledWith(
69-
'src',
70-
'http://localhost/url'
71-
);
70+
_loadJS(testUrl);
71+
expect(el.src).to.eq(unwrapResourceUrl(testUrl));
7272
expect(el.type).to.eq('text/javascript');
7373
expect(el.charset).to.eq('UTF-8');
7474
});

packages/auth/src/platform_browser/load_js.ts

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,40 +15,42 @@
1515
* limitations under the License.
1616
*/
1717

18+
import { TrustedResourceUrl, trustedResourceUrl } from 'safevalues';
19+
1820
interface ExternalJSProvider {
19-
loadJS(url: string): Promise<Event>;
20-
recaptchaV2Script: string;
21-
recaptchaEnterpriseScript: string;
22-
gapiScript: string;
21+
loadJS(url: TrustedResourceUrl): Promise<Event>;
22+
recaptchaV2Script: TrustedResourceUrl;
23+
recaptchaEnterpriseScript: TrustedResourceUrl;
24+
gapiScript: TrustedResourceUrl;
2325
}
2426

2527
let externalJSProvider: ExternalJSProvider = {
26-
async loadJS() {
28+
loadJS(url: TrustedResourceUrl): Promise<Event> {
2729
throw new Error('Unable to load external scripts');
2830
},
2931

30-
recaptchaV2Script: '',
31-
recaptchaEnterpriseScript: '',
32-
gapiScript: ''
32+
recaptchaV2Script: trustedResourceUrl``,
33+
recaptchaEnterpriseScript: trustedResourceUrl``,
34+
gapiScript: trustedResourceUrl``
3335
};
3436

3537
export function _setExternalJSProvider(p: ExternalJSProvider): void {
3638
externalJSProvider = p;
3739
}
3840

39-
export function _loadJS(url: string): Promise<Event> {
41+
export function _loadJS(url: TrustedResourceUrl): Promise<Event> {
4042
return externalJSProvider.loadJS(url);
4143
}
4244

43-
export function _recaptchaV2ScriptUrl(): string {
45+
export function _recaptchaV2ScriptUrl(): TrustedResourceUrl {
4446
return externalJSProvider.recaptchaV2Script;
4547
}
4648

47-
export function _recaptchaEnterpriseScriptUrl(): string {
49+
export function _recaptchaEnterpriseScriptUrl(): TrustedResourceUrl {
4850
return externalJSProvider.recaptchaEnterpriseScript;
4951
}
5052

51-
export function _gapiScriptUrl(): string {
53+
export function _gapiScriptUrl(): TrustedResourceUrl {
5254
return externalJSProvider.gapiScript;
5355
}
5456

packages/auth/src/platform_browser/recaptcha/recaptcha_enterprise_verifier.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
RecaptchaAuthProvider,
2626
EnforcementState
2727
} from '../../api';
28+
import { appendParams, unwrapResourceUrl } from 'safevalues';
2829

2930
import { Auth } from '../../model/public_types';
3031
import { AuthInternal } from '../../model/auth';
@@ -142,8 +143,8 @@ export class RecaptchaEnterpriseVerifier {
142143
return;
143144
}
144145
let url = jsHelpers._recaptchaEnterpriseScriptUrl();
145-
if (url.length !== 0) {
146-
url += siteKey;
146+
if (unwrapResourceUrl(url).toString().length !== 0) {
147+
url = appendParams(url, new Map([['render', siteKey]]));
147148
}
148149
jsHelpers
149150
._loadJS(url)

packages/auth/src/platform_browser/recaptcha/recaptcha_loader.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
* limitations under the License.
1616
*/
1717

18-
import { querystring } from '@firebase/util';
18+
import { appendParams } from 'safevalues';
1919

2020
import { AuthErrorCode } from '../../core/errors';
2121
import { _assert, _createError } from '../../core/util/assert';
@@ -90,11 +90,11 @@ export class ReCaptchaLoaderImpl implements ReCaptchaLoader {
9090
resolve(recaptcha);
9191
};
9292

93-
const url = `${jsHelpers._recaptchaV2ScriptUrl()}?${querystring({
94-
onload: _JSLOAD_CALLBACK,
95-
render: 'explicit',
96-
hl
97-
})}`;
93+
const url = appendParams(jsHelpers._recaptchaV2ScriptUrl(), new Map([
94+
['onload', _JSLOAD_CALLBACK],
95+
['render', 'explicit'],
96+
['hl', hl]
97+
]));
9898

9999
jsHelpers._loadJS(url).catch(() => {
100100
clearTimeout(networkTimeout);

yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14237,6 +14237,11 @@ safe-stable-stringify@^2.3.1:
1423714237
resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
1423814238
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
1423914239

14240+
safevalues@1.2.0:
14241+
version "1.2.0"
14242+
resolved "https://us-npm.pkg.dev/artifact-foundry-prod/ah-3p-staging-npm/safevalues/-/safevalues-1.2.0.tgz#f9e646d6ebf31788004ef192d2a7d646c9896bb2"
14243+
integrity sha512-zIsuhjYvJCjfsfjoim2ab6gLKFYAnTiDSJGh0cC3T44L/4kNLL90hBG2BzrXPrHA3f8Ms8FSJ1mljKH5dVR1cw==
14244+
1424014245
sauce-connect-launcher@^1.2.7:
1424114246
version "1.3.2"
1424214247
resolved "https://registry.npmjs.org/sauce-connect-launcher/-/sauce-connect-launcher-1.3.2.tgz#dfc675a258550809a8eaf457eb9162b943ddbaf0"

0 commit comments

Comments
 (0)