mirror of
https://github.com/bitwarden/jslib
synced 2025-12-10 13:23:15 +00:00
Revert WebAuthn iFrame handler (#462)
This commit is contained in:
@@ -1,30 +1,87 @@
|
|||||||
import { I18nService } from '../abstractions/i18n.service';
|
import { I18nService } from '../abstractions/i18n.service';
|
||||||
import { PlatformUtilsService } from '../abstractions/platformUtils.service';
|
import { PlatformUtilsService } from '../abstractions/platformUtils.service';
|
||||||
|
|
||||||
import { IFrameComponent } from './iframe_component';
|
export class WebAuthnIFrame {
|
||||||
import { Utils } from './utils';
|
private iframe: HTMLIFrameElement = null;
|
||||||
|
private connectorLink: HTMLAnchorElement;
|
||||||
|
private parseFunction = this.parseMessage.bind(this);
|
||||||
|
|
||||||
export class WebAuthnIFrame extends IFrameComponent {
|
constructor(private win: Window, private webVaultUrl: string, private webAuthnNewTab: boolean,
|
||||||
constructor(win: Window, webVaultUrl: string, private webAuthnNewTab: boolean,
|
|
||||||
private platformUtilsService: PlatformUtilsService, private i18nService: I18nService,
|
private platformUtilsService: PlatformUtilsService, private i18nService: I18nService,
|
||||||
successCallback: (message: string) => any, errorCallback: (message: string) => any,
|
private successCallback: Function, private errorCallback: Function, private infoCallback: Function) {
|
||||||
infoCallback: (message: string) => any) {
|
this.connectorLink = win.document.createElement('a');
|
||||||
super(win, webVaultUrl, 'webauthn-connector.html', 'webauthn_iframe', successCallback, errorCallback, infoCallback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
init(data: any): void {
|
init(data: any): void {
|
||||||
const params = this.createParams({ data: JSON.stringify(data), btnText: this.i18nService.t('webAuthnAuthenticate') }, 2);
|
const params = new URLSearchParams({
|
||||||
|
data: this.base64Encode(JSON.stringify(data)),
|
||||||
|
parent: encodeURIComponent(this.win.document.location.href),
|
||||||
|
btnText: encodeURIComponent(this.i18nService.t('webAuthnAuthenticate')),
|
||||||
|
v: '1',
|
||||||
|
});
|
||||||
|
|
||||||
if (this.webAuthnNewTab) {
|
if (this.webAuthnNewTab) {
|
||||||
// Firefox fallback which opens the webauthn page in a new tab
|
// Firefox fallback which opens the webauthn page in a new tab
|
||||||
params.append('locale', this.i18nService.translationLocale);
|
params.append('locale', this.i18nService.translationLocale);
|
||||||
this.platformUtilsService.launchUri(`${this.webVaultUrl}/webauthn-fallback-connector.html?${params}`);
|
this.platformUtilsService.launchUri(`${this.webVaultUrl}/webauthn-fallback-connector.html?${params}`);
|
||||||
} else {
|
} else {
|
||||||
super.initComponent(params);
|
this.connectorLink.href = `${this.webVaultUrl}/webauthn-connector.html?${params}`;
|
||||||
if (Utils.isNullOrWhitespace(this.iframe.allow)) {
|
this.iframe = this.win.document.getElementById('webauthn_iframe') as HTMLIFrameElement;
|
||||||
this.iframe.allow = 'publickey-credentials-get ' + new URL(this.webVaultUrl).origin;
|
this.iframe.allow = 'publickey-credentials-get ' + new URL(this.webVaultUrl).origin;
|
||||||
|
this.iframe.src = this.connectorLink.href;
|
||||||
|
|
||||||
|
this.win.addEventListener('message', this.parseFunction, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stop() {
|
||||||
|
this.sendMessage('stop');
|
||||||
|
}
|
||||||
|
|
||||||
|
start() {
|
||||||
|
this.sendMessage('start');
|
||||||
|
}
|
||||||
|
|
||||||
|
sendMessage(message: any) {
|
||||||
|
if (!this.iframe || !this.iframe.src || !this.iframe.contentWindow) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.iframe.contentWindow.postMessage(message, this.iframe.src);
|
||||||
|
}
|
||||||
|
|
||||||
|
base64Encode(str: string): string {
|
||||||
|
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (match, p1) => {
|
||||||
|
return String.fromCharCode(('0x' + p1) as any);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
this.win.removeEventListener('message', this.parseFunction, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private parseMessage(event: MessageEvent) {
|
||||||
|
if (!this.validMessage(event)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parts: string[] = event.data.split('|');
|
||||||
|
if (parts[0] === 'success' && this.successCallback) {
|
||||||
|
this.successCallback(parts[1]);
|
||||||
|
} else if (parts[0] === 'error' && this.errorCallback) {
|
||||||
|
this.errorCallback(parts[1]);
|
||||||
|
} else if (parts[0] === 'info' && this.infoCallback) {
|
||||||
|
this.infoCallback(parts[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private validMessage(event: MessageEvent) {
|
||||||
|
if (event.origin == null || event.origin === '' || event.origin !== (this.connectorLink as any).origin ||
|
||||||
|
event.data == null || typeof (event.data) !== 'string') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return event.data.indexOf('success|') === 0 || event.data.indexOf('error|') === 0 ||
|
||||||
|
event.data.indexOf('info|') === 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user