Skip to content

Commit

Permalink
Update dApp connection for OpenBit
Browse files Browse the repository at this point in the history
  • Loading branch information
saltict committed May 29, 2024
1 parent 8dba7e1 commit 42cd93b
Show file tree
Hide file tree
Showing 3 changed files with 181 additions and 37 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
145 changes: 108 additions & 37 deletions packages/extension-koni/src/content.ts
Original file line number Diff line number Diff line change
@@ -1,58 +1,129 @@
// Copyright 2019-2022 @polkadot/extension authors & contributors
// SPDX-License-Identifier: Apache-2.0

import type { Message } from '@subwallet/extension-base/types';

import { TransportRequestMessage } from '@subwallet/extension-base/background/types';
import { MESSAGE_ORIGIN_CONTENT, MESSAGE_ORIGIN_PAGE, PORT_CONTENT } from '@subwallet/extension-base/defaults';
import { Message } from '@subwallet/extension-base/types';
import { getId } from '@subwallet/extension-base/utils/getId';
import { addNotificationPopUp } from '@subwallet/extension-koni/helper/PageNotification';

// connect to the extension
const port = chrome.runtime.connect({ name: PORT_CONTENT });

// redirect users if this page is considered as phishing, otherwise return false
const handleRedirectPhishing: { id: string, resolve?: (value: (boolean | PromiseLike<boolean>)) => void, reject?: (e: Error) => void } = {
id: 'redirect-phishing-' + getId()
};

const redirectIfPhishingProm = new Promise<boolean>((resolve, reject) => {
handleRedirectPhishing.resolve = resolve;
handleRedirectPhishing.reject = reject;
function checkForLastError () {
const { lastError } = chrome.runtime;

if (!lastError) {
return undefined;
}

// repair incomplete error object (eg chromium v77)
return new Error(lastError.message);
}

export class ContentHandler {
port?: chrome.runtime.Port;
isShowNotification = false;
isConnected = false;

const transportRequestMessage: TransportRequestMessage<'pub(phishing.redirectIfDenied)'> = {
id: handleRedirectPhishing.id,
message: 'pub(phishing.redirectIfDenied)',
origin: MESSAGE_ORIGIN_PAGE,
request: null
};
// Get the port to communicate with the background and init handlers
getPort (): chrome.runtime.Port {
if (!this.port) {
const port = chrome.runtime.connect({ name: PORT_CONTENT });
const onMessageHandler = this.onPortMessageHandler.bind(this);

port.postMessage(transportRequestMessage);
});
const disconnectHandler = () => {
this.onDisconnectPort(port, onMessageHandler, disconnectHandler);
};

// send any messages from the extension back to the page
port.onMessage.addListener((data: {id: string, response: any}): void => {
const { id, resolve } = handleRedirectPhishing;
this.port = port;
this.port.onMessage.addListener(onMessageHandler);
this.port.onDisconnect.addListener(disconnectHandler);
}

if (data?.id === id) {
resolve && resolve(Boolean(data.response));
} else {
window.postMessage({ ...data, origin: MESSAGE_ORIGIN_CONTENT }, '*');
return this.port;
}
});

// // all messages from the page, pass them to the extension
window.addEventListener('message', ({ data, source }: Message): void => {
// only allow messages from our window, by the inject
if (source !== window || data.origin !== MESSAGE_ORIGIN_PAGE) {
return;
// Handle messages from the background
onPortMessageHandler (data: {id: string, response: any}): void {
const { id, resolve } = handleRedirectPhishing;

if (data?.id === id) {
resolve && resolve(Boolean(data.response));
} else {
window.postMessage({ ...data, origin: MESSAGE_ORIGIN_CONTENT }, '*');
}
}

port.postMessage(data);
});
// Handle disconnecting the port from the background
onDisconnectPort (port: chrome.runtime.Port, onMessage: (data: {id: string, response: any}) => void, onDisconnect: () => void): void {
const err = checkForLastError();

if (err) {
console.warn(`${err.message}, port is disconnected.`);
}

port.onMessage.removeListener(onMessage);
port.onDisconnect.removeListener(onDisconnect);

redirectIfPhishingProm.then((gotRedirected) => {
if (!gotRedirected) {
console.log('Check phishing by URL: Passed.');
this.port = undefined;
}
}).catch((e) => {
console.warn(`Unable to determine if the site is in the phishing list: ${(e as Error).message}`);
});

// Handle messages from the webpage
onPageMessage ({ data, source }: Message): void {
// only allow messages from our window, by the inject
if (source !== window || data.origin !== MESSAGE_ORIGIN_PAGE) {
return;
}

try {
this.isConnected = true;
this.getPort().postMessage(data);
} catch (e) {
console.error(e);

if (!this.isShowNotification) {
console.log('The OpenBit extension is not installed. Please install the extension to use the wallet.');
addNotificationPopUp();
this.isShowNotification = true;

setTimeout(() => {
this.isShowNotification = false;
}, 5000);
}
}
}

// Detect phishing by URL
redirectIfPhishingProm (): void {
new Promise<boolean>((resolve, reject) => {
handleRedirectPhishing.resolve = resolve;
handleRedirectPhishing.reject = reject;

const transportRequestMessage: TransportRequestMessage<'pub(phishing.redirectIfDenied)'> = {
id: handleRedirectPhishing.id,
message: 'pub(phishing.redirectIfDenied)',
origin: MESSAGE_ORIGIN_PAGE,
request: null
};

this.getPort().postMessage(transportRequestMessage);
}).then((gotRedirected) => {
if (!gotRedirected) {
console.log('Check phishing by URL: Passed.');
}
}).catch((e) => {
console.warn(`Unable to determine if the site is in the phishing list: ${(e as Error).message}`);
});
}

constructor () {
this.redirectIfPhishingProm();
window.addEventListener('message', this.onPageMessage.bind(this));
}
}

// @ts-ignore
const contentHandler = new ContentHandler();
73 changes: 73 additions & 0 deletions packages/extension-koni/src/helper/PageNotification.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Copyright 2019-2022 @polkadot/extension authors & contributors
// SPDX-License-Identifier: Apache-2.0

const unableConnectImageSrc = chrome.runtime.getURL('/images/icons/__error__.png');

export function removeNotificationPopup () {
const divContainerExisted = document.getElementById('__notification-container');

divContainerExisted && divContainerExisted.remove();
}

export function addNotificationPopUp () {
removeNotificationPopup();

const divContainer = document.createElement('div');
const divBox = document.createElement('div');
const imgElement = document.createElement('img');
const divContent = document.createElement('div');
const styleElement = document.createElement('style');

const notificationContainerStyles: Partial<CSSStyleDeclaration> = {
position: 'fixed',
top: '5%',
zIndex: '10001',
width: '100%',
animation: 'slideDown 5s ease-in-out'
};

const notificationBoxStyles: Partial<CSSStyleDeclaration> = {
borderRadius: '8px',
margin: 'auto',
width: 'fit-content',
backgroundColor: 'black',
alignItems: 'center',
border: '2px solid #BF1616',
display: 'flex',
gap: '8px',
padding: '8px 16px 8px 16px'
};

const notificationContentStyles: Partial<CSSStyleDeclaration> = {
fontFamily: 'inherit',
fontSize: '14px',
fontStyle: 'normal',
color: 'rgba(255, 255, 255, 0.85)',
fontWeight: '500',
lineHeight: '22px'
};

const keyframes = `@keyframes slideDown {
0% { transform: translateY(-100%); opacity: 0; }
20% { transform: translateY(0); opacity: 1; }
95% { transform: translateY(0); opacity: 1; }
100% { transform: translateY(-100%); opacity: 0; }
}`;

Object.assign(divContent.style, notificationContentStyles);
Object.assign(divContainer.style, notificationContainerStyles);
Object.assign(divBox.style, notificationBoxStyles);

divContainer.id = '__notification-container';
imgElement.src = unableConnectImageSrc;
divContent.innerText = 'Unable to connect. Reload dApp site and try again.';
styleElement.innerHTML = keyframes;

document.head.appendChild(styleElement);
unableConnectImageSrc !== 'chrome-extension://invalid/' && divBox.appendChild(imgElement);
divBox.appendChild(divContent);
divContainer.appendChild(divBox);
document.body.appendChild(divContainer);

setTimeout(removeNotificationPopup, 5000);
}

0 comments on commit 42cd93b

Please sign in to comment.