Skip to content

Commit

Permalink
wip: core-in-whatever
Browse files Browse the repository at this point in the history
  • Loading branch information
mroz22 committed Oct 7, 2024
1 parent 86667cc commit 12ad999
Show file tree
Hide file tree
Showing 6 changed files with 444 additions and 149 deletions.
158 changes: 14 additions & 144 deletions packages/connect-web/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,155 +1,25 @@
import { ConnectFactoryDependencies, factory } from '@trezor/connect/src/factory';
import { factory } from '@trezor/connect/src/factory';
import { CoreInIframe } from './impl/core-in-iframe';
import { CoreInPopup } from './impl/core-in-popup';
import ProxyEventEmitter from './utils/proxy-event-emitter';
import type { ConnectSettings, ConnectSettingsPublic, Manifest } from '@trezor/connect/src/types';
import EventEmitter from 'events';
import { CallMethodPayload } from '@trezor/connect/src/events';
import { getEnv } from './connectSettings';

type TrezorConnectType = 'core-in-popup' | 'iframe';

const IFRAME_ERRORS = ['Init_IframeBlocked', 'Init_IframeTimeout', 'Transport_Missing'];

/**
* Implementation of TrezorConnect that can dynamically switch between iframe and core-in-popup implementations
*/
export class TrezorConnectDynamicImpl implements ConnectFactoryDependencies {
public eventEmitter: EventEmitter;

private currentTarget: TrezorConnectType = 'iframe';
private coreInIframeImpl: CoreInIframe;
private coreInPopupImpl: CoreInPopup;

private lastSettings?: Partial<ConnectSettings>;

public constructor() {
this.coreInIframeImpl = new CoreInIframe();
this.coreInPopupImpl = new CoreInPopup();
this.eventEmitter = new ProxyEventEmitter([
this.coreInIframeImpl.eventEmitter,
this.coreInPopupImpl.eventEmitter,
]);
}

private getTarget() {
return this.currentTarget === 'iframe' ? this.coreInIframeImpl : this.coreInPopupImpl;
}

private async switchTarget(target: TrezorConnectType) {
if (this.currentTarget === target) {
return;
}

await this.getTarget().dispose();
this.currentTarget = target;
await this.getTarget().init(this.lastSettings);
}

public manifest(manifest: Manifest) {
this.lastSettings = {
...this.lastSettings,
manifest,
};

this.getTarget().manifest(manifest);
}

public async init(settings: Partial<ConnectSettingsPublic> = {}) {
const env = getEnv();
if (settings.coreMode === 'iframe' || settings.popup === false || env === 'webextension') {
this.currentTarget = 'iframe';
} else if (settings.coreMode === 'popup') {
this.currentTarget = 'core-in-popup';
} else {
// Default to auto mode with iframe as the first choice
settings.coreMode = 'auto';
this.currentTarget = 'iframe';
}

// Save settings for later use
this.lastSettings = settings;

// Initialize the target
try {
return await this.getTarget().init(settings);
} catch (error) {
// Handle iframe errors by switching to core-in-popup
if (await this.handleErrorFallback(error.code)) {
return await this.getTarget().init(settings);
}

throw error;
}
}

public async call(params: CallMethodPayload) {
const response = await this.getTarget().call(params);
if (!response.success) {
if (await this.handleErrorFallback(response.payload.code)) {
return await this.getTarget().call(params);
}
}

return response;
}

private async handleErrorFallback(errorCode: string) {
// Handle iframe errors by switching to core-in-popup
if (this.lastSettings?.coreMode === 'auto' && IFRAME_ERRORS.includes(errorCode)) {
// Check if WebUSB is available and enabled
const webUsbUnavailableInBrowser = !navigator.usb;
const webUsbDisabledInSettings =
this.lastSettings.transports?.includes('WebUsbTransport') === false ||
this.lastSettings.webusb === false;
if (
errorCode === 'Transport_Missing' &&
(webUsbUnavailableInBrowser || webUsbDisabledInSettings)
) {
// WebUSB not available, no benefit in switching to core-in-popup
return false;
}

await this.switchTarget('core-in-popup');

return true;
}

return false;
}

public requestLogin(params: any) {
return this.getTarget().requestLogin(params);
}

public uiResponse(params: any) {
return this.getTarget().uiResponse(params);
}

public renderWebUSBButton() {
return this.getTarget().renderWebUSBButton();
}

public disableWebUSB() {
return this.getTarget().disableWebUSB();
}

public requestWebUSBDevice() {
return this.getTarget().requestWebUSBDevice();
}

public cancel(error?: string) {
return this.getTarget().cancel(error);
}

public dispose() {
this.eventEmitter.removeAllListeners();

return this.getTarget().dispose();
}
}

const impl = new TrezorConnectDynamicImpl();
const impl = new TrezorConnectDynamicImpl({
impls: [
{
type: 'iframe',
impl: new CoreInIframe(),
},
{
type: 'core-in-popup',
impl: new CoreInPopup(),
},
],
getEnv,
});

const TrezorConnect = factory({
eventEmitter: impl.eventEmitter,
Expand Down
Loading

0 comments on commit 12ad999

Please sign in to comment.