1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-13 21:27:12 +01:00
metamask-extension/app/scripts/lib/util.js
Mark Stacey 7199d9c567 Use externally hosted phishing warning page
An externally hosted phishing warning page is now used rather than the
built-in phishing warning page.The phishing page warning URL is set via
configuration file or environment variable. The default URL is either
the expected production URL or `http://localhost:9999/` for e2e testing
environments.

The new external phishing page includes a design change when it is
loaded within an iframe. In that case it now shows a condensed message,
and prompts the user to open the full warning page in a new tab to see
more details or bypass the warning. This is to prevent a clickjacking
attack from safelisting a site without user consent.

The new external phishing page also includes a simple caching service
worker to ensure it continues to work offline (or if our hosting goes
offline), as long as the user has successfully loaded the page at least
once. We also load the page temporarily during the extension startup
process to trigger the service worker installation.

The old phishing page and all related lines have been removed. The
property `web_accessible_resources` has also been removed from the
manifest. The only entry apart from the phishing page was `inpage.js`,
and we don't need that to be web accessible anymore because we inject
the script inline into each page rather than loading the file directly.

New e2e tests have been added to cover more phishing warning page
functionality, including the "safelist" action and the "iframe" case.
2022-05-16 14:40:50 -02:30

169 lines
4.3 KiB
JavaScript

import browser from 'webextension-polyfill';
import { stripHexPrefix } from 'ethereumjs-util';
import BN from 'bn.js';
import { memoize } from 'lodash';
import {
MAINNET_CHAIN_ID,
TEST_CHAINS,
} from '../../../shared/constants/network';
import {
ENVIRONMENT_TYPE_POPUP,
ENVIRONMENT_TYPE_NOTIFICATION,
ENVIRONMENT_TYPE_FULLSCREEN,
ENVIRONMENT_TYPE_BACKGROUND,
PLATFORM_FIREFOX,
PLATFORM_OPERA,
PLATFORM_CHROME,
PLATFORM_EDGE,
PLATFORM_BRAVE,
} from '../../../shared/constants/app';
/**
* @see {@link getEnvironmentType}
*/
const getEnvironmentTypeMemo = memoize((url) => {
const parsedUrl = new URL(url);
if (parsedUrl.pathname === '/popup.html') {
return ENVIRONMENT_TYPE_POPUP;
} else if (['/home.html'].includes(parsedUrl.pathname)) {
return ENVIRONMENT_TYPE_FULLSCREEN;
} else if (parsedUrl.pathname === '/notification.html') {
return ENVIRONMENT_TYPE_NOTIFICATION;
}
return ENVIRONMENT_TYPE_BACKGROUND;
});
/**
* Returns the window type for the application
*
* - `popup` refers to the extension opened through the browser app icon (in top right corner in chrome and firefox)
* - `fullscreen` refers to the main browser window
* - `notification` refers to the popup that appears in its own window when taking action outside of metamask
* - `background` refers to the background page
*
* NOTE: This should only be called on internal URLs.
*
* @param {string} [url] - the URL of the window
* @returns {string} the environment ENUM
*/
const getEnvironmentType = (url = window.location.href) =>
getEnvironmentTypeMemo(url);
/**
* Returns the platform (browser) where the extension is running.
*
* @returns {string} the platform ENUM
*/
const getPlatform = () => {
const { navigator } = window;
const { userAgent } = navigator;
if (userAgent.includes('Firefox')) {
return PLATFORM_FIREFOX;
} else if ('brave' in navigator) {
return PLATFORM_BRAVE;
} else if (userAgent.includes('Edg/')) {
return PLATFORM_EDGE;
} else if (userAgent.includes('OPR')) {
return PLATFORM_OPERA;
}
return PLATFORM_CHROME;
};
/**
* Converts a hex string to a BN object
*
* @param {string} inputHex - A number represented as a hex string
* @returns {Object} A BN object
*/
function hexToBn(inputHex) {
return new BN(stripHexPrefix(inputHex), 16);
}
/**
* Used to multiply a BN by a fraction
*
* @param {BN} targetBN - The number to multiply by a fraction
* @param {number|string} numerator - The numerator of the fraction multiplier
* @param {number|string} denominator - The denominator of the fraction multiplier
* @returns {BN} The product of the multiplication
*/
function BnMultiplyByFraction(targetBN, numerator, denominator) {
const numBN = new BN(numerator);
const denomBN = new BN(denominator);
return targetBN.mul(numBN).div(denomBN);
}
/**
* Returns an Error if extension.runtime.lastError is present
* this is a workaround for the non-standard error object that's used
*
* @returns {Error|undefined}
*/
function checkForError() {
const { lastError } = browser.runtime;
if (!lastError) {
return undefined;
}
// if it quacks like an Error, its an Error
if (lastError.stack && lastError.message) {
return lastError;
}
// repair incomplete error object (eg chromium v77)
return new Error(lastError.message);
}
/**
* Prefixes a hex string with '0x' or '-0x' and returns it. Idempotent.
*
* @param {string} str - The string to prefix.
* @returns {string} The prefixed string.
*/
const addHexPrefix = (str) => {
if (typeof str !== 'string' || str.match(/^-?0x/u)) {
return str;
}
if (str.match(/^-?0X/u)) {
return str.replace('0X', '0x');
}
if (str.startsWith('-')) {
return str.replace('-', '-0x');
}
return `0x${str}`;
};
/**
* Converts a BN object to a hex string with a '0x' prefix
*
* @param {BN} inputBn - The BN to convert to a hex string
* @returns {string} A '0x' prefixed hex string
*/
function bnToHex(inputBn) {
return addHexPrefix(inputBn.toString(16));
}
function getChainType(chainId) {
if (chainId === MAINNET_CHAIN_ID) {
return 'mainnet';
} else if (TEST_CHAINS.includes(chainId)) {
return 'testnet';
}
return 'custom';
}
export {
getPlatform,
getEnvironmentType,
hexToBn,
BnMultiplyByFraction,
checkForError,
addHexPrefix,
bnToHex,
getChainType,
};