1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-12 20:57:12 +01:00
metamask-extension/app/scripts/platforms/extension.js
Mark Stacey 8866c39623
Update the Firefox prerelease version format (#13158)
The Firefox extension version format does not support the version
format we use (SemVer), so we have to specially format the extension
version to be compatible. The format we chose was
`[major].[minor].[patch].[buildType][buildVersion]`. But when we tried
to submit a build with a version in that format, it was rejected as
invalid for unknown reasons.

The Firefox extension format has been updated to
`[major].[minor].[patch][buildType][buildVersion]`. This seems to pass
validation.
2022-01-03 12:48:10 -03:30

275 lines
7.1 KiB
JavaScript

import extension from 'extensionizer';
import { getBlockExplorerLink } from '@metamask/etherscan-link';
import { getEnvironmentType, checkForError } from '../lib/util';
import { ENVIRONMENT_TYPE_BACKGROUND } from '../../../shared/constants/app';
import { TRANSACTION_STATUSES } from '../../../shared/constants/transaction';
export default class ExtensionPlatform {
//
// Public
//
reload() {
extension.runtime.reload();
}
openTab(options) {
return new Promise((resolve, reject) => {
extension.tabs.create(options, (newTab) => {
const error = checkForError();
if (error) {
return reject(error);
}
return resolve(newTab);
});
});
}
openWindow(options) {
return new Promise((resolve, reject) => {
extension.windows.create(options, (newWindow) => {
const error = checkForError();
if (error) {
return reject(error);
}
return resolve(newWindow);
});
});
}
focusWindow(windowId) {
return new Promise((resolve, reject) => {
extension.windows.update(windowId, { focused: true }, () => {
const error = checkForError();
if (error) {
return reject(error);
}
return resolve();
});
});
}
updateWindowPosition(windowId, left, top) {
return new Promise((resolve, reject) => {
extension.windows.update(windowId, { left, top }, () => {
const error = checkForError();
if (error) {
return reject(error);
}
return resolve();
});
});
}
getLastFocusedWindow() {
return new Promise((resolve, reject) => {
extension.windows.getLastFocused((windowObject) => {
const error = checkForError();
if (error) {
return reject(error);
}
return resolve(windowObject);
});
});
}
closeCurrentWindow() {
return extension.windows.getCurrent((windowDetails) => {
return extension.windows.remove(windowDetails.id);
});
}
getVersion() {
const {
version,
version_name: versionName,
} = extension.runtime.getManifest();
const versionParts = version.split('.');
if (versionName) {
if (versionParts.length < 4) {
throw new Error(`Version missing build number: '${version}'`);
}
// On Chrome, a more descriptive representation of the version is stored
// in the `version_name` field for display purposes.
return versionName;
} else if (versionParts.length !== 3) {
throw new Error(`Invalid version: ${version}`);
} else if (versionParts[2].match(/[^\d]/u)) {
// On Firefox, the build type and build version are in the fourth part of the version.
const [major, minor, patchAndPrerelease] = versionParts;
const matches = patchAndPrerelease.match(/^(\d+)([A-Za-z]+)(\d)+$/u);
if (matches === null) {
throw new Error(`Version contains invalid prerelease: ${version}`);
}
const [, patch, buildType, buildVersion] = matches;
return `${major}.${minor}.${patch}-${buildType}.${buildVersion}`;
}
// If there is no `version_name` and there are only 3 version parts, then this is not a
// prerelease and the version requires no modification.
return version;
}
openExtensionInBrowser(
route = null,
queryString = null,
keepWindowOpen = false,
) {
let extensionURL = extension.runtime.getURL('home.html');
if (route) {
extensionURL += `#${route}`;
}
if (queryString) {
extensionURL += `?${queryString}`;
}
this.openTab({ url: extensionURL });
if (
getEnvironmentType() !== ENVIRONMENT_TYPE_BACKGROUND &&
!keepWindowOpen
) {
window.close();
}
}
getPlatformInfo(cb) {
try {
extension.runtime.getPlatformInfo((platform) => {
cb(null, platform);
});
} catch (e) {
cb(e);
// eslint-disable-next-line no-useless-return
return;
}
}
showTransactionNotification(txMeta, rpcPrefs) {
const { status, txReceipt: { status: receiptStatus } = {} } = txMeta;
if (status === TRANSACTION_STATUSES.CONFIRMED) {
// There was an on-chain failure
receiptStatus === '0x0'
? this._showFailedTransaction(
txMeta,
'Transaction encountered an error.',
)
: this._showConfirmedTransaction(txMeta, rpcPrefs);
} else if (status === TRANSACTION_STATUSES.FAILED) {
this._showFailedTransaction(txMeta);
}
}
addOnRemovedListener(listener) {
extension.windows.onRemoved.addListener(listener);
}
getAllWindows() {
return new Promise((resolve, reject) => {
extension.windows.getAll((windows) => {
const error = checkForError();
if (error) {
return reject(error);
}
return resolve(windows);
});
});
}
getActiveTabs() {
return new Promise((resolve, reject) => {
extension.tabs.query({ active: true }, (tabs) => {
const error = checkForError();
if (error) {
return reject(error);
}
return resolve(tabs);
});
});
}
currentTab() {
return new Promise((resolve, reject) => {
extension.tabs.getCurrent((tab) => {
const err = checkForError();
if (err) {
reject(err);
} else {
resolve(tab);
}
});
});
}
switchToTab(tabId) {
return new Promise((resolve, reject) => {
extension.tabs.update(tabId, { highlighted: true }, (tab) => {
const err = checkForError();
if (err) {
reject(err);
} else {
resolve(tab);
}
});
});
}
closeTab(tabId) {
return new Promise((resolve, reject) => {
extension.tabs.remove(tabId, () => {
const err = checkForError();
if (err) {
reject(err);
} else {
resolve();
}
});
});
}
_showConfirmedTransaction(txMeta, rpcPrefs) {
this._subscribeToNotificationClicked();
const url = getBlockExplorerLink(txMeta, rpcPrefs);
const nonce = parseInt(txMeta.txParams.nonce, 16);
const title = 'Confirmed transaction';
const message = `Transaction ${nonce} confirmed! ${
url.length ? 'View on Etherscan' : ''
}`;
this._showNotification(title, message, url);
}
_showFailedTransaction(txMeta, errorMessage) {
const nonce = parseInt(txMeta.txParams.nonce, 16);
const title = 'Failed transaction';
const message = `Transaction ${nonce} failed! ${
errorMessage || txMeta.err.message
}`;
this._showNotification(title, message);
}
_showNotification(title, message, url) {
extension.notifications.create(url, {
type: 'basic',
title,
iconUrl: extension.extension.getURL('../../images/icon-64.png'),
message,
});
}
_subscribeToNotificationClicked() {
if (!extension.notifications.onClicked.hasListener(this._viewOnEtherscan)) {
extension.notifications.onClicked.addListener(this._viewOnEtherscan);
}
}
_viewOnEtherscan(url) {
if (url.startsWith('https://')) {
extension.tabs.create({ url });
}
}
}