mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 18:00:18 +01:00
18a21ca57e
* adds build type mmi * run prettier
235 lines
8.3 KiB
JavaScript
235 lines
8.3 KiB
JavaScript
const path = require('path');
|
|
const semver = require('semver');
|
|
const { BuildType } = require('../lib/build-type');
|
|
const { BUILD_TARGETS, ENVIRONMENT } = require('./constants');
|
|
|
|
/**
|
|
* Returns whether the current build is a development build or not.
|
|
*
|
|
* @param {BUILD_TARGETS} buildTarget - The current build target.
|
|
* @returns Whether the current build is a development build.
|
|
*/
|
|
function isDevBuild(buildTarget) {
|
|
return (
|
|
buildTarget === BUILD_TARGETS.DEV || buildTarget === BUILD_TARGETS.TEST_DEV
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Returns whether the current build is an e2e test build or not.
|
|
*
|
|
* @param {BUILD_TARGETS} buildTarget - The current build target.
|
|
* @returns Whether the current build is an e2e test build.
|
|
*/
|
|
function isTestBuild(buildTarget) {
|
|
return (
|
|
buildTarget === BUILD_TARGETS.TEST || buildTarget === BUILD_TARGETS.TEST_DEV
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Map the current version to a format that is compatible with each browser.
|
|
*
|
|
* The given version number is assumed to be a SemVer version number. Additionally, if the version
|
|
* has a prerelease component, it is assumed to have the format "<build type>.<build version",
|
|
* where the build version is a positive integer.
|
|
*
|
|
* @param {string[]} platforms - A list of browsers to generate versions for.
|
|
* @param {string} version - The current version.
|
|
* @returns {object} An object with the browser as the key and the browser-specific version object
|
|
* as the value. For example, the version `9.6.0-beta.1` would return the object
|
|
* `{ firefox: { version: '9.6.0.beta1' }, chrome: { version: '9.6.0.1', version_name: '9.6.0-beta.1' } }`.
|
|
*/
|
|
function getBrowserVersionMap(platforms, version) {
|
|
const major = semver.major(version);
|
|
const minor = semver.minor(version);
|
|
const patch = semver.patch(version);
|
|
const prerelease = semver.prerelease(version);
|
|
let buildType, buildVersionSummary, buildVersion;
|
|
if (prerelease) {
|
|
[buildType, buildVersionSummary] = prerelease;
|
|
// The version could be version: '10.25.0-beta.1-flask.0',
|
|
// That results in buildVersionSummary becomes 1-flask
|
|
// And we only want 1 from this string
|
|
buildVersion =
|
|
typeof buildVersionSummary === 'string'
|
|
? Number(buildVersionSummary.match(/\d+(?:\.\d+)?/u)[0])
|
|
: buildVersionSummary;
|
|
if (!String(buildVersion).match(/^\d+$/u)) {
|
|
throw new Error(`Invalid prerelease build version: '${buildVersion}'`);
|
|
} else if (
|
|
![
|
|
BuildType.beta,
|
|
BuildType.flask,
|
|
BuildType.desktop,
|
|
BuildType.mmi,
|
|
].includes(buildType)
|
|
) {
|
|
throw new Error(`Invalid prerelease build type: ${buildType}`);
|
|
}
|
|
}
|
|
|
|
return platforms.reduce((platformMap, platform) => {
|
|
const versionParts = [major, minor, patch];
|
|
const browserSpecificVersion = {};
|
|
if (prerelease) {
|
|
if (platform === 'firefox') {
|
|
versionParts[2] = `${versionParts[2]}${buildType}${buildVersion}`;
|
|
} else {
|
|
versionParts.push(buildVersion);
|
|
browserSpecificVersion.version_name = version;
|
|
}
|
|
}
|
|
browserSpecificVersion.version = versionParts.join('.');
|
|
platformMap[platform] = browserSpecificVersion;
|
|
return platformMap;
|
|
}, {});
|
|
}
|
|
|
|
/**
|
|
* Get the environment of the current build.
|
|
*
|
|
* @param {object} options - Build options.
|
|
* @param {BUILD_TARGETS} options.buildTarget - The target of the current build.
|
|
* @returns {ENVIRONMENT} The current build environment.
|
|
*/
|
|
function getEnvironment({ buildTarget }) {
|
|
// get environment slug
|
|
if (buildTarget === BUILD_TARGETS.PROD) {
|
|
return ENVIRONMENT.PRODUCTION;
|
|
} else if (isDevBuild(buildTarget)) {
|
|
return ENVIRONMENT.DEVELOPMENT;
|
|
} else if (isTestBuild(buildTarget)) {
|
|
return ENVIRONMENT.TESTING;
|
|
} else if (
|
|
/^Version-v(\d+)[.](\d+)[.](\d+)/u.test(process.env.CIRCLE_BRANCH)
|
|
) {
|
|
return ENVIRONMENT.RELEASE_CANDIDATE;
|
|
} else if (process.env.CIRCLE_BRANCH === 'develop') {
|
|
return ENVIRONMENT.STAGING;
|
|
} else if (process.env.CIRCLE_PULL_REQUEST) {
|
|
return ENVIRONMENT.PULL_REQUEST;
|
|
}
|
|
return ENVIRONMENT.OTHER;
|
|
}
|
|
|
|
/**
|
|
* Log an error to the console.
|
|
*
|
|
* This function includes a workaround for a SES bug that results in errors
|
|
* being printed to the console as `{}`. The workaround is to print the stack
|
|
* instead, which does work correctly.
|
|
*
|
|
* @see {@link https://github.com/endojs/endo/issues/944}
|
|
* @param {Error} error - The error to print
|
|
*/
|
|
function logError(error) {
|
|
console.error(error.stack || error);
|
|
}
|
|
|
|
/**
|
|
* This function wrapAgainstScuttling() tries to generically wrap given code
|
|
* with an environment that allows it to still function under a scuttled environment.
|
|
*
|
|
* It's only (current) use is for sentry code which runs before scuttling happens but
|
|
* later on still leans on properties of the global object which at that point are scuttled.
|
|
*
|
|
* To accomplish that, we wrap the entire provided code with the good old with-proxy trick,
|
|
* which helps us capture access attempts like (1) window.fetch/globalThis.fetch and (2) fetch.
|
|
*
|
|
* wrapAgainstScuttling() function also accepts a bag of the global object's properties the
|
|
* code needs in order to properly function, and within our proxy we make sure to
|
|
* return those whenever the code goes through our proxy asking for them.
|
|
*
|
|
* Specifically when the code tries to set properties to the global object,
|
|
* in addition to the preconfigured properties, we also accept any property
|
|
* starting with on to support global event handlers settings.
|
|
*
|
|
* Also, sentry invokes functions dynamically using Function.prototype's call and apply,
|
|
* and our proxy messes with their this when that happens, so these two required a tailor-made patch.
|
|
*
|
|
* @param content - contents of the js code to wrap
|
|
* @param bag - bag of global object properties to provide to the wrapped js code
|
|
* @returns {string} wrapped js code
|
|
*/
|
|
function wrapAgainstScuttling(content, bag = {}) {
|
|
return `
|
|
{
|
|
function setupProxy(global) {
|
|
// bag of properties to allow vetted shim to access,
|
|
// mapped to their correct this value if needed
|
|
const bag = ${JSON.stringify(bag)};
|
|
// setup vetted shim bag of properties
|
|
for (const prop in bag) {
|
|
const that = bag[prop];
|
|
let api = global[prop];
|
|
if (that) api = api.bind(global[that]);
|
|
bag[prop] = api;
|
|
}
|
|
// setup proxy for the vetted shim to go through
|
|
const proxy = new Proxy(bag, {
|
|
set: function set(target, prop, value) {
|
|
if (bag.hasOwnProperty(prop) || prop.startsWith('on')) {
|
|
return (bag[prop] = global[prop] = value) || true;
|
|
}
|
|
},
|
|
});
|
|
// make sure bind() and apply() are applied with
|
|
// proxy target rather than proxy receiver
|
|
(function(target, receiver) {
|
|
'use strict'; // to work with ses lockdown
|
|
function wrap(obj, prop, target, receiver) {
|
|
const real = obj[prop];
|
|
obj[prop] = function(that) {
|
|
if (that === receiver) that = target;
|
|
const args = [].slice.call(arguments, 1);
|
|
return real.call(this, that, ...args);
|
|
};
|
|
}
|
|
wrap(Function.prototype, 'bind', target, receiver);
|
|
wrap(Function.prototype, 'apply', target, receiver);
|
|
} (global, proxy));
|
|
return proxy;
|
|
}
|
|
const proxy = setupProxy(globalThis);
|
|
with (proxy) {
|
|
with ({window: proxy, self: proxy, globalThis: proxy}) {
|
|
${content}
|
|
}
|
|
}
|
|
};
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* Get the path of a file or folder inside the node_modules folder
|
|
*
|
|
* require.resolve was causing errors on Windows, once the paths were fed into fast-glob
|
|
* (The backslashes had to be converted to forward-slashes)
|
|
* This helper function was written to fix the Windows problem, and also end reliance on writing paths that start with './node_modules/'
|
|
*
|
|
* @see {@link https://github.com/MetaMask/metamask-extension/pull/16550}
|
|
* @param {string} packageName - The name of the package, such as '@lavamoat/lavapack'
|
|
* @param {string} pathToFiles - The path of the file or folder inside the package, optionally starting with /
|
|
*/
|
|
function getPathInsideNodeModules(packageName, pathToFiles) {
|
|
let targetPath = path.dirname(require.resolve(`${packageName}/package.json`));
|
|
|
|
targetPath = path.join(targetPath, pathToFiles);
|
|
|
|
// Force POSIX separators
|
|
targetPath = targetPath.split(path.sep).join(path.posix.sep);
|
|
|
|
return targetPath;
|
|
}
|
|
|
|
module.exports = {
|
|
getBrowserVersionMap,
|
|
getEnvironment,
|
|
isDevBuild,
|
|
isTestBuild,
|
|
logError,
|
|
getPathInsideNodeModules,
|
|
wrapAgainstScuttling,
|
|
};
|