From cf22a922408aeff2c017b9dc675d5cca230bfbaf Mon Sep 17 00:00:00 2001 From: Mak Muftic Date: Thu, 19 Aug 2021 13:38:41 +0200 Subject: [PATCH 01/16] Catch ipfs and ipns urls --- app/scripts/lib/ens-ipfs/setup.js | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/app/scripts/lib/ens-ipfs/setup.js b/app/scripts/lib/ens-ipfs/setup.js index 8c30de975..b5d4bba0d 100644 --- a/app/scripts/lib/ens-ipfs/setup.js +++ b/app/scripts/lib/ens-ipfs/setup.js @@ -5,6 +5,7 @@ import resolveEnsToIpfsContentId from './resolver'; const fetchWithTimeout = getFetchWithTimeout(30000); const supportedTopLevelDomains = ['eth']; +const supportedProtocols = ['ipfs:', 'ipns:'] export default function setupEnsIpfsResolver({ provider, @@ -12,7 +13,12 @@ export default function setupEnsIpfsResolver({ getIpfsGateway, }) { // install listener - const urlPatterns = supportedTopLevelDomains.map((tld) => `*://*.${tld}/*`); + const urlPatterns = supportedTopLevelDomains.map( + (tld) => `*://*.${tld}/*` + ).concat(supportedProtocols.map( + (p) => `${p}//*`) + ); + extension.webRequest.onErrorOccurred.addListener(webRequestDidFail, { urls: urlPatterns, types: ['main_frame'], @@ -34,15 +40,25 @@ export default function setupEnsIpfsResolver({ return; } // parse ens name - const { hostname: name, pathname, search, hash: fragment } = new URL(url); + const { hostname: name, pathname, search, hash: fragment, protocol } = new URL(url); const domainParts = name.split('.'); const topLevelDomain = domainParts[domainParts.length - 1]; - // if unsupported TLD, abort - if (!supportedTopLevelDomains.includes(topLevelDomain)) { + + if(supportedProtocols.includes(protocol)) { + console.warn(`Resolving ${protocol} not yet supported`); + } else if(supportedTopLevelDomains.includes(topLevelDomain)) { + attemptResolve({ tabId, name, pathname, search, fragment }); + } else { return; } - // otherwise attempt resolve - attemptResolve({ tabId, name, pathname, search, fragment }); + + // // if unsupported TLD, abort + // if (!supportedTopLevelDomains.includes(topLevelDomain)) { + // return; + // } + + // // otherwise attempt resolve + // attemptResolve({ tabId, name, pathname, search, fragment }); } async function attemptResolve({ tabId, name, pathname, search, fragment }) { From f72db8c963938b6c547b8ea933f9fea2f4289589 Mon Sep 17 00:00:00 2001 From: Mak Muftic Date: Mon, 13 Sep 2021 13:44:43 +0200 Subject: [PATCH 02/16] Implement IPFS and IPNS resolving --- app/_locales/en/messages.json | 12 ++ app/manifest/_base.json | 1 + app/scripts/controllers/ipfs.js | 34 ++++++ app/scripts/lib/ens-ipfs/setup.js | 49 +++++--- app/scripts/metamask-controller.js | 30 +++++ ui/app/helpers/constants/routes.js | 4 + ui/app/pages/ipfs-enable/index.js | 1 + ui/app/pages/ipfs-enable/index.scss | 65 ++++++++++ .../ipfs-enable/ipfs-enable.component.js | 115 ++++++++++++++++++ .../ipfs-enable/ipfs-enable.container.js | 31 +++++ ui/app/pages/pages.scss | 1 + ui/app/pages/routes/routes.component.js | 3 + .../advanced-tab/advanced-tab.component.js | 51 +++++++- .../advanced-tab/advanced-tab.container.js | 10 ++ ui/app/store/actions.js | 34 ++++++ 15 files changed, 423 insertions(+), 18 deletions(-) create mode 100644 app/scripts/controllers/ipfs.js create mode 100644 ui/app/pages/ipfs-enable/index.js create mode 100644 ui/app/pages/ipfs-enable/index.scss create mode 100644 ui/app/pages/ipfs-enable/ipfs-enable.component.js create mode 100644 ui/app/pages/ipfs-enable/ipfs-enable.container.js diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index b9501b008..2e32b3370 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -685,6 +685,9 @@ "etherscanView": { "message": "View account on Etherscan" }, + "example": { + "message": "Example" + }, "expandView": { "message": "Expand view" }, @@ -946,6 +949,15 @@ "ipfsGatewayDescription": { "message": "Enter the URL of the IPFS CID gateway to use for ENS content resolution." }, + "ipfsIpnsResolvingTitle": { + "message": "IPFS and IPNS URL resolving" + }, + "ipfsIpnsDescription": { + "message": "Now metamask will resolve # and # urls directly." + }, + "ipfsIpnsExample": { + "message": "If you type # it will be resolved as " + }, "jsonFile": { "message": "JSON File", "description": "format for importing an account" diff --git a/app/manifest/_base.json b/app/manifest/_base.json index 996b7de27..60c02d388 100644 --- a/app/manifest/_base.json +++ b/app/manifest/_base.json @@ -69,6 +69,7 @@ "activeTab", "webRequest", "*://*.eth/", + "chrome-extension://*/*", "notifications" ], "short_name": "__MSG_appName__", diff --git a/app/scripts/controllers/ipfs.js b/app/scripts/controllers/ipfs.js new file mode 100644 index 000000000..f1dcd1f26 --- /dev/null +++ b/app/scripts/controllers/ipfs.js @@ -0,0 +1,34 @@ +import { ObservableStore } from '@metamask/obs-store'; + +const DEFAULT_IPFS_IPNS_ENABLED = false; + +export default class IpfsIpnsController { + + constructor() { + const initState = { + ipfsIpnsEnabled: DEFAULT_IPFS_IPNS_ENABLED, + ipfsIpnsHandlerShouldUpdate: false, + } + this.store = new ObservableStore(initState); + } + + /** + * @param {boolean} status - indicates if ipfs ipns resolving is enabled + * @returns status of ipfs ipns url resolving + */ + setIpfsIpnsUrlResolving(status) { + this.store.updateState({ + ipfsIpnsEnabled: status + }) + return Promise.resolve(status); + } + + /** + * @param {boolean} bool - indicates if protocol handler should be updated + * @returns bool + */ + setIpfsIpnsHandlerShouldUpdate(bool) { + this.store.updateState({ipfsIpnsHandlerShouldUpdate: bool}); + return Promise.resolve(bool); + } +} \ No newline at end of file diff --git a/app/scripts/lib/ens-ipfs/setup.js b/app/scripts/lib/ens-ipfs/setup.js index b5d4bba0d..6025952d0 100644 --- a/app/scripts/lib/ens-ipfs/setup.js +++ b/app/scripts/lib/ens-ipfs/setup.js @@ -5,33 +5,56 @@ import resolveEnsToIpfsContentId from './resolver'; const fetchWithTimeout = getFetchWithTimeout(30000); const supportedTopLevelDomains = ['eth']; -const supportedProtocols = ['ipfs:', 'ipns:'] +const supportedProtocols = ['ipfs', 'ipns'] export default function setupEnsIpfsResolver({ provider, getCurrentChainId, getIpfsGateway, -}) { // install listener +}) { const urlPatterns = supportedTopLevelDomains.map( (tld) => `*://*.${tld}/*` - ).concat(supportedProtocols.map( - (p) => `${p}//*`) ); extension.webRequest.onErrorOccurred.addListener(webRequestDidFail, { - urls: urlPatterns, types: ['main_frame'], + urls: urlPatterns, }); + extension.webRequest.onBeforeRequest.addListener(catchIpfsChromeExt, { + types: ['main_frame'], + urls: ["chrome-extension://*/*"] + }) + // return api object return { // uninstall listener remove() { extension.webRequest.onErrorOccurred.removeListener(webRequestDidFail); + extension.webRequest.onBeforeRequest.removeListener(catchIpfsChromeExt); }, }; + async function catchIpfsChromeExt(details) { + const { tabId, url } = details; + // ignore requests that are not associated with tabs + if (tabId === -1) { + return; + } + + const unUrl = unescape(url); + supportedProtocols.forEach(protocol => { + if(unUrl.includes(`${protocol}:`)) { + const identifier = unUrl.split(`${protocol}:`)[1]; + const ipfsGateway = getIpfsGateway(); + const newUrl = `https://${ipfsGateway}/${protocol}${identifier}`; + extension.tabs.update(tabId, { url: newUrl }); + return; + } + }); + } + async function webRequestDidFail(details) { const { tabId, url } = details; // ignore requests that are not associated with tabs @@ -44,21 +67,13 @@ export default function setupEnsIpfsResolver({ const domainParts = name.split('.'); const topLevelDomain = domainParts[domainParts.length - 1]; - if(supportedProtocols.includes(protocol)) { - console.warn(`Resolving ${protocol} not yet supported`); - } else if(supportedTopLevelDomains.includes(topLevelDomain)) { - attemptResolve({ tabId, name, pathname, search, fragment }); - } else { + // if unsupported TLD, abort + if (!supportedTopLevelDomains.includes(topLevelDomain)) { return; } - // // if unsupported TLD, abort - // if (!supportedTopLevelDomains.includes(topLevelDomain)) { - // return; - // } - - // // otherwise attempt resolve - // attemptResolve({ tabId, name, pathname, search, fragment }); + // otherwise attempt resolve + attemptResolve({ tabId, name, pathname, search, fragment }); } async function attemptResolve({ tabId, name, pathname, search, fragment }) { diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 361050d86..236e81884 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -70,6 +70,7 @@ import { segment, segmentLegacy } from './lib/segment'; import createMetaRPCHandler from './lib/createMetaRPCHandler'; import { WORKER_BLOB_URL } from './lib/worker-blob'; import { FILSNAP_NAME, setupFilsnap } from './lib/filsnap'; +import IpfsIpnsController from './controllers/ipfs'; export const METAMASK_CONTROLLER_EVENTS = { // Fired after state changes that impact the extension badge (unapproved msg count) @@ -459,6 +460,8 @@ export default class MetamaskController extends EventEmitter { ), }); + this.ipfsIpnsController = new IpfsIpnsController(); + // ensure accountTracker updates balances after network change this.networkController.on(NETWORK_EVENTS.NETWORK_DID_CHANGE, () => { this.accountTracker._updateAccounts(); @@ -495,6 +498,7 @@ export default class MetamaskController extends EventEmitter { PluginController: this.pluginController.store, ThreeBoxController: this.threeBoxController.store, AssetsController: this.assetsController.store, + IpfsIpnsController: this.ipfsIpnsController.store, }); this.memStore = new ComposableObservableStore(null, { @@ -525,6 +529,7 @@ export default class MetamaskController extends EventEmitter { EnsController: this.ensController.store, ApprovalController: this.approvalController, AssetsController: this.assetsController.store, + IpfsIpnsController: this.ipfsIpnsController.store, }); this.memStore.subscribe(this.sendUpdate.bind(this)); @@ -717,6 +722,7 @@ export default class MetamaskController extends EventEmitter { swapsController, threeBoxController, txController, + ipfsIpnsController, } = this; return { @@ -727,6 +733,8 @@ export default class MetamaskController extends EventEmitter { setUseNonceField: this.setUseNonceField.bind(this), setUsePhishDetect: this.setUsePhishDetect.bind(this), setIpfsGateway: this.setIpfsGateway.bind(this), + setIpfsIpnsUrlResolving: this.setIpfsIpnsUrlResolving.bind(this), + setIpfsIpnsHandlerShouldUpdate: this.setIpfsIpnsHandlerShouldUpdate.bind(this), setParticipateInMetaMetrics: this.setParticipateInMetaMetrics.bind(this), setMetaMetricsSendCount: this.setMetaMetricsSendCount.bind(this), setFirstTimeFlowType: this.setFirstTimeFlowType.bind(this), @@ -2907,6 +2915,28 @@ export default class MetamaskController extends EventEmitter { } } + setIpfsIpnsUrlResolving(bool, cb) { + try { + this.ipfsIpnsController.setIpfsIpnsUrlResolving(bool); + cb(null); + return; + } catch (err) { + cb(err); + return; + } + } + + setIpfsIpnsHandlerShouldUpdate(bool, cb) { + try { + this.ipfsIpnsController.setIpfsIpnsHandlerShouldUpdate(bool); + cb(null); + return; + } catch (err) { + cb(err); + return; + } + } + /** * Sets whether or not the user will have usage data tracked with MetaMetrics * @param {boolean} bool - True for users that wish to opt-in, false for users that wish to remain out. diff --git a/ui/app/helpers/constants/routes.js b/ui/app/helpers/constants/routes.js index 61b21b50c..0dddd0f53 100644 --- a/ui/app/helpers/constants/routes.js +++ b/ui/app/helpers/constants/routes.js @@ -66,6 +66,8 @@ const DECRYPT_MESSAGE_REQUEST_PATH = '/decrypt-message-request'; const ENCRYPTION_PUBLIC_KEY_REQUEST_PATH = '/encryption-public-key-request'; const CONFIRMATION_V_NEXT_ROUTE = '/confirmation'; +const IPFS_IPNS_URL_RESOLVING = '/ipfs-ipns-resolve'; + // Used to pull a convenient name for analytics tracking events. The key must // be react-router ready path, and can include params such as :id for popup windows const PATH_NAME_MAP = { @@ -135,6 +137,7 @@ const PATH_NAME_MAP = { [LOADING_QUOTES_ROUTE]: 'Swaps Loading Quotes Page', [AWAITING_SWAP_ROUTE]: 'Swaps Awaiting Swaps Page', [SWAPS_ERROR_ROUTE]: 'Swaps Error Page', + [IPFS_IPNS_URL_RESOLVING]: 'Ipfs and Ipns URL Resolving Info Page' }; export { @@ -201,4 +204,5 @@ export { AWAITING_SWAP_ROUTE, SWAPS_ERROR_ROUTE, SWAPS_MAINTENANCE_ROUTE, + IPFS_IPNS_URL_RESOLVING, }; diff --git a/ui/app/pages/ipfs-enable/index.js b/ui/app/pages/ipfs-enable/index.js new file mode 100644 index 000000000..660ac2b12 --- /dev/null +++ b/ui/app/pages/ipfs-enable/index.js @@ -0,0 +1 @@ +export { default } from './ipfs-enable.container'; \ No newline at end of file diff --git a/ui/app/pages/ipfs-enable/index.scss b/ui/app/pages/ipfs-enable/index.scss new file mode 100644 index 000000000..763a4e1bb --- /dev/null +++ b/ui/app/pages/ipfs-enable/index.scss @@ -0,0 +1,65 @@ +.ipfs-enable { + &__container { + display: flex; + min-height: 100%; + } + + &__main-view { + flex: 1 1 66.5%; + background: $white; + min-width: 0; + display: flex; + flex-direction: column; + } + + &__menu { + display: grid; + grid-template-columns: 30% minmax(30%, 1fr) 30%; + column-gap: 5px; + padding: 0 8px; + border-bottom: 1px solid $Grey-100; + height: 64px; + } + + &__title { + grid-column: 2/span 1; + place-self: center stretch; + display: flex; + flex-direction: center; + justify-content: center; + align-items: center; + flex: 1; + } + + &__content { + display: flex; + justify-content: space-between; + align-items: center; + // flex: 1; + min-height: 209px; + padding-top: 40px; + flex-direction: column; + width: 100%; + } + + &__content-item { + flex: 1; + min-width: 0; + display: flex; + flex-direction: column; + margin-bottom: 20px; + } + + &__description { + font-size: 0.875rem; + line-height: 140%; + font-style: normal; + font-weight: normal; + color: #9b9b9b; + padding-top: 5px; + } +} + +.highlight { + font-weight: bold; +} \ No newline at end of file diff --git a/ui/app/pages/ipfs-enable/ipfs-enable.component.js b/ui/app/pages/ipfs-enable/ipfs-enable.component.js new file mode 100644 index 000000000..1c5243501 --- /dev/null +++ b/ui/app/pages/ipfs-enable/ipfs-enable.component.js @@ -0,0 +1,115 @@ +import React, { PureComponent } from 'react'; +import PropTypes from 'prop-types'; +import { IPFS_IPNS_URL_RESOLVING } from '../../helpers/constants/routes'; + +export default class IpfsEnable extends PureComponent { + static contextTypes = { + t: PropTypes.func + } + + static propType = { + ipfsGateway: PropTypes.string.isRequired, + ipfsIpnsEnabled: PropTypes.bool.isRequired, + ipfsIpnsHandlerShouldUpdate: PropTypes.bool.isRequired, + setIpfsIpnsHandlerShouldUpdate: PropTypes.func, + } + + state = { + ipfsGateway: this.props.ipfsGateway, + ipfsIpnsIsEnabled: this.props.ipfsIpnsEnabled, + ipfsIpnsHandlerShouldUpdate: this.props.ipfsIpnsHandlerShouldUpdate, + } + + componentDidMount() { + const { + ipfsIpnsEnabled, + ipfsIpnsHandlerShouldUpdate, + } = this.props; + + if(ipfsIpnsHandlerShouldUpdate) { + const page = IPFS_IPNS_URL_RESOLVING.replace("/", ""); + if(ipfsIpnsEnabled) { + this.registerHandlers(page); + } else { + this.unregisterHandlers(page); + } + this.props.setIpfsIpnsHandlerShouldUpdate(false); + } + } + + registerHandlers(page) { + window.navigator.registerProtocolHandler( + "ipfs", + window.location.href.replace(`/home.html#${page}`, "/%s"), + "Ipfs handler", + ); + window.navigator.registerProtocolHandler( + "ipns", + window.location.href.replace(`/home.html#${page}`, "/%s"), + "Ipns handler", + ); + } + + unregisterHandlers(page) { + window.navigator.unregisterProtocolHandler( + "ipfs", + window.location.href.replace(`/home.html#${page}`, "/%s"), + ); + window.navigator.unregisterProtocolHandler( + "ipns", + window.location.href.replace(`/home.html#${page}`, "/%s"), + ); + } + + render() { + const { t } = this.context; + const ipfsIpnsDescriptionParts = t('ipfsIpnsDescription').split("#"); + const ipfsIpnsExampleParts = t('ipfsIpnsExample').split("#"); + return ( +
+
+
+
+
+ {t('ipfsIpnsResolvingTitle')} +
+
+
+ +
+
+ + {t('ipfsIpnsResolvingTitle')} + +
+ {this.state.ipfsIpnsIsEnabled ? "Enabled" : "Disabled"} +
+
+
+ + {t('ipfsGateway')} + +
+ {this.state.ipfsGateway} +
+
+
+ + {t('example')} + +
+ {ipfsIpnsDescriptionParts[0]} ipfs:// {ipfsIpnsDescriptionParts[1]} ipns:// + {ipfsIpnsDescriptionParts[2]} +
+
+ {ipfsIpnsExampleParts[0]} ipfs://[CID]/ {ipfsIpnsExampleParts[1]} https://ipfs.io/ipfs/[CID]/ . +
+
+
+
+
+
+
+ ) + } +} \ No newline at end of file diff --git a/ui/app/pages/ipfs-enable/ipfs-enable.container.js b/ui/app/pages/ipfs-enable/ipfs-enable.container.js new file mode 100644 index 000000000..d8165d0f5 --- /dev/null +++ b/ui/app/pages/ipfs-enable/ipfs-enable.container.js @@ -0,0 +1,31 @@ +import { connect } from "react-redux" +import IpfsEnable from "./ipfs-enable.component" +import {setIpfsIpnsHandlerShouldUpdate} from "../../store/actions" +import console from "console"; + +const mapStateToProps = (state) => { + const {metamask} = state; + const { + ipfsGateway, + ipfsIpnsEnabled, + ipfsIpnsHandlerShouldUpdate, + } = metamask; + + console.log(state); + + return { + ipfsGateway, + ipfsIpnsEnabled, + ipfsIpnsHandlerShouldUpdate, + } +} + +const mapDispatchToProps = (dispatch) => { + return { + setIpfsIpnsHandlerShouldUpdate: (value) => { + dispatch(setIpfsIpnsHandlerShouldUpdate(value)) + } + } +} + +export default connect(mapStateToProps, mapDispatchToProps)(IpfsEnable) \ No newline at end of file diff --git a/ui/app/pages/pages.scss b/ui/app/pages/pages.scss index 09c1c58bc..cee238ecd 100644 --- a/ui/app/pages/pages.scss +++ b/ui/app/pages/pages.scss @@ -19,3 +19,4 @@ @import 'settings/index'; @import 'swaps/index'; @import 'unlock-page/index'; +@import 'ipfs-enable/index' diff --git a/ui/app/pages/routes/routes.component.js b/ui/app/pages/routes/routes.component.js index 09b5c2fca..3c8135326 100644 --- a/ui/app/pages/routes/routes.component.js +++ b/ui/app/pages/routes/routes.component.js @@ -32,6 +32,7 @@ import AppHeader from '../../components/app/app-header'; import UnlockPage from '../unlock-page'; import Alerts from '../../components/app/alerts'; import Asset from '../asset'; +import IpfsIpnsUrlHandling from '../ipfs-enable'; import { ADD_TOKEN_ROUTE, @@ -54,6 +55,7 @@ import { UNLOCK_ROUTE, BUILD_QUOTE_ROUTE, CONFIRMATION_V_NEXT_ROUTE, + IPFS_IPNS_URL_RESOLVING, } from '../../helpers/constants/routes'; import { @@ -169,6 +171,7 @@ export default class Routes extends Component { path={`${CONNECT_ROUTE}/:id`} component={PermissionsConnect} /> + diff --git a/ui/app/pages/settings/advanced-tab/advanced-tab.component.js b/ui/app/pages/settings/advanced-tab/advanced-tab.component.js index 742d1c233..4e06dbe86 100644 --- a/ui/app/pages/settings/advanced-tab/advanced-tab.component.js +++ b/ui/app/pages/settings/advanced-tab/advanced-tab.component.js @@ -5,7 +5,7 @@ import { exportAsFile } from '../../../helpers/utils/util'; import ToggleButton from '../../../components/ui/toggle-button'; import TextField from '../../../components/ui/text-field'; import Button from '../../../components/ui/button'; -import { MOBILE_SYNC_ROUTE } from '../../../helpers/constants/routes'; +import { MOBILE_SYNC_ROUTE, IPFS_IPNS_URL_RESOLVING } from '../../../helpers/constants/routes'; export default class AdvancedTab extends PureComponent { static contextTypes = { @@ -33,6 +33,11 @@ export default class AdvancedTab extends PureComponent { threeBoxDisabled: PropTypes.bool.isRequired, setIpfsGateway: PropTypes.func.isRequired, ipfsGateway: PropTypes.string.isRequired, + ipfsUrlGateway: PropTypes.string.isRequired, + setIpfsIpnsUrlGateway: PropTypes.func, + ipfsIpnsEnabled: PropTypes.bool, + setIpfsIpnsUrlResolving: PropTypes.func, + setIpfsIpnsHandlerShouldUpdate: PropTypes.func, }; state = { @@ -462,6 +467,49 @@ export default class AdvancedTab extends PureComponent { ); } + renderIpfsUrlResolveControl() { + const { t } = this.context; + const { + ipfsIpnsEnabled, + setIpfsIpnsUrlResolving, + setIpfsIpnsHandlerShouldUpdate, + } = this.props; + + let enabled = ipfsIpnsEnabled; + + return ( +
+
+ Resolve IPFS urls (experimental) +
+ Turn on to have IPFS (ipfs://) and IPNS (ipns://) URLs being resolved by Metamask. This feature is currently experimental; use at your own risk. +
+
+
+
+ { + setIpfsIpnsUrlResolving(!enabled); + setIpfsIpnsHandlerShouldUpdate(true); + global.platform.openExtensionInBrowser(IPFS_IPNS_URL_RESOLVING); + }} + offLabel={t('off')} + onLabel={t('on')} + /> +
+
+
+ ); + } + render() { const { warning } = this.props; @@ -478,6 +526,7 @@ export default class AdvancedTab extends PureComponent { {this.renderAutoLockTimeLimit()} {this.renderThreeBoxControl()} {this.renderIpfsGatewayControl()} + {this.renderIpfsUrlResolveControl()} ); } diff --git a/ui/app/pages/settings/advanced-tab/advanced-tab.container.js b/ui/app/pages/settings/advanced-tab/advanced-tab.container.js index 1bfa82f30..abe1674e2 100644 --- a/ui/app/pages/settings/advanced-tab/advanced-tab.container.js +++ b/ui/app/pages/settings/advanced-tab/advanced-tab.container.js @@ -11,6 +11,8 @@ import { turnThreeBoxSyncingOnAndInitialize, setUseNonceField, setIpfsGateway, + setIpfsIpnsUrlResolving, + setIpfsIpnsHandlerShouldUpdate } from '../../../store/actions'; import { getPreferences } from '../../../selectors'; import AdvancedTab from './advanced-tab.component'; @@ -26,6 +28,7 @@ export const mapStateToProps = (state) => { threeBoxDisabled, useNonceField, ipfsGateway, + ipfsIpnsEnabled, } = metamask; const { showFiatInTestnets, autoLockTimeLimit } = getPreferences(state); @@ -39,6 +42,7 @@ export const mapStateToProps = (state) => { threeBoxDisabled, useNonceField, ipfsGateway, + ipfsIpnsEnabled, }; }; @@ -68,6 +72,12 @@ export const mapDispatchToProps = (dispatch) => { setIpfsGateway: (value) => { return dispatch(setIpfsGateway(value)); }, + setIpfsIpnsUrlResolving: (value) => { + dispatch(setIpfsIpnsUrlResolving(value)) + }, + setIpfsIpnsHandlerShouldUpdate: (value) => { + dispatch(setIpfsIpnsHandlerShouldUpdate(value)) + }, }; }; diff --git a/ui/app/store/actions.js b/ui/app/store/actions.js index 81f4c5ae0..659ee46c5 100644 --- a/ui/app/store/actions.js +++ b/ui/app/store/actions.js @@ -2229,6 +2229,40 @@ export function setIpfsGateway(val) { }; } +export function setIpfsIpnsHandlerShouldUpdate(val) { + return (dispatch) => { + log.debug(`background.setIpfsIpnsHandlerShouldUpdate`); + return new Promise((resolve, reject) => { + background.setIpfsIpnsHandlerShouldUpdate(val, (err) => { + if(err) { + dispatch(displayWarning(err.message)); + reject(err); + return; + } + resolve(val); + }) + }) + } +} + +export function setIpfsIpnsUrlResolving(val) { + return (dispatch) => { + dispatch(showLoadingIndication()); + log.debug(`background.setIpfsIpnsUrlResolving`); + return new Promise((resolve, reject) => { + background.setIpfsIpnsUrlResolving(val, (err) => { + dispatch(hideLoadingIndication()); + if(err) { + dispatch(displayWarning(err.message)); + reject(err); + return; + } + resolve(val); + }); + }) + } +} + export function updateCurrentLocale(key) { return async (dispatch) => { dispatch(showLoadingIndication()); From 65cf27559d2d0852245ae224c219c5ea29aa4da6 Mon Sep 17 00:00:00 2001 From: Mak Muftic Date: Mon, 13 Sep 2021 13:52:58 +0200 Subject: [PATCH 03/16] Fix linter errors --- app/_locales/en/messages.json | 6 +- app/scripts/controllers/ipfs.js | 53 +++-- app/scripts/lib/ens-ipfs/setup.js | 23 +- app/scripts/metamask-controller.js | 6 +- ui/app/helpers/constants/routes.js | 2 +- ui/app/pages/ipfs-enable/index.js | 2 +- .../ipfs-enable/ipfs-enable.component.js | 202 +++++++++--------- .../ipfs-enable/ipfs-enable.container.js | 48 ++--- ui/app/pages/routes/routes.component.js | 5 +- .../advanced-tab/advanced-tab.component.js | 13 +- .../advanced-tab/advanced-tab.container.js | 6 +- ui/app/store/actions.js | 14 +- yarn.lock | 6 +- 13 files changed, 198 insertions(+), 188 deletions(-) diff --git a/app/_locales/en/messages.json b/app/_locales/en/messages.json index 2e32b3370..63ede4dfb 100644 --- a/app/_locales/en/messages.json +++ b/app/_locales/en/messages.json @@ -949,15 +949,15 @@ "ipfsGatewayDescription": { "message": "Enter the URL of the IPFS CID gateway to use for ENS content resolution." }, - "ipfsIpnsResolvingTitle": { - "message": "IPFS and IPNS URL resolving" - }, "ipfsIpnsDescription": { "message": "Now metamask will resolve # and # urls directly." }, "ipfsIpnsExample": { "message": "If you type # it will be resolved as " }, + "ipfsIpnsResolvingTitle": { + "message": "IPFS and IPNS URL resolving" + }, "jsonFile": { "message": "JSON File", "description": "format for importing an account" diff --git a/app/scripts/controllers/ipfs.js b/app/scripts/controllers/ipfs.js index f1dcd1f26..9d667f946 100644 --- a/app/scripts/controllers/ipfs.js +++ b/app/scripts/controllers/ipfs.js @@ -3,32 +3,31 @@ import { ObservableStore } from '@metamask/obs-store'; const DEFAULT_IPFS_IPNS_ENABLED = false; export default class IpfsIpnsController { + constructor() { + const initState = { + ipfsIpnsEnabled: DEFAULT_IPFS_IPNS_ENABLED, + ipfsIpnsHandlerShouldUpdate: false, + }; + this.store = new ObservableStore(initState); + } - constructor() { - const initState = { - ipfsIpnsEnabled: DEFAULT_IPFS_IPNS_ENABLED, - ipfsIpnsHandlerShouldUpdate: false, - } - this.store = new ObservableStore(initState); - } + /** + * @param {boolean} status - indicates if ipfs ipns resolving is enabled + * @returns status of ipfs ipns url resolving + */ + setIpfsIpnsUrlResolving(status) { + this.store.updateState({ + ipfsIpnsEnabled: status, + }); + return Promise.resolve(status); + } - /** - * @param {boolean} status - indicates if ipfs ipns resolving is enabled - * @returns status of ipfs ipns url resolving - */ - setIpfsIpnsUrlResolving(status) { - this.store.updateState({ - ipfsIpnsEnabled: status - }) - return Promise.resolve(status); - } - - /** - * @param {boolean} bool - indicates if protocol handler should be updated - * @returns bool - */ - setIpfsIpnsHandlerShouldUpdate(bool) { - this.store.updateState({ipfsIpnsHandlerShouldUpdate: bool}); - return Promise.resolve(bool); - } -} \ No newline at end of file + /** + * @param {boolean} bool - indicates if protocol handler should be updated + * @returns bool + */ + setIpfsIpnsHandlerShouldUpdate(bool) { + this.store.updateState({ ipfsIpnsHandlerShouldUpdate: bool }); + return Promise.resolve(bool); + } +} diff --git a/app/scripts/lib/ens-ipfs/setup.js b/app/scripts/lib/ens-ipfs/setup.js index 6025952d0..ef2321dfa 100644 --- a/app/scripts/lib/ens-ipfs/setup.js +++ b/app/scripts/lib/ens-ipfs/setup.js @@ -5,7 +5,7 @@ import resolveEnsToIpfsContentId from './resolver'; const fetchWithTimeout = getFetchWithTimeout(30000); const supportedTopLevelDomains = ['eth']; -const supportedProtocols = ['ipfs', 'ipns'] +const supportedProtocols = ['ipfs', 'ipns']; export default function setupEnsIpfsResolver({ provider, @@ -13,9 +13,7 @@ export default function setupEnsIpfsResolver({ getIpfsGateway, // install listener }) { - const urlPatterns = supportedTopLevelDomains.map( - (tld) => `*://*.${tld}/*` - ); + const urlPatterns = supportedTopLevelDomains.map((tld) => `*://*.${tld}/*`); extension.webRequest.onErrorOccurred.addListener(webRequestDidFail, { types: ['main_frame'], @@ -24,8 +22,8 @@ export default function setupEnsIpfsResolver({ extension.webRequest.onBeforeRequest.addListener(catchIpfsChromeExt, { types: ['main_frame'], - urls: ["chrome-extension://*/*"] - }) + urls: ['chrome-extension://*/*'], + }); // return api object return { @@ -44,13 +42,12 @@ export default function setupEnsIpfsResolver({ } const unUrl = unescape(url); - supportedProtocols.forEach(protocol => { - if(unUrl.includes(`${protocol}:`)) { + supportedProtocols.forEach((protocol) => { + if (unUrl.includes(`${protocol}:`)) { const identifier = unUrl.split(`${protocol}:`)[1]; const ipfsGateway = getIpfsGateway(); const newUrl = `https://${ipfsGateway}/${protocol}${identifier}`; extension.tabs.update(tabId, { url: newUrl }); - return; } }); } @@ -63,7 +60,13 @@ export default function setupEnsIpfsResolver({ return; } // parse ens name - const { hostname: name, pathname, search, hash: fragment, protocol } = new URL(url); + const { + hostname: name, + pathname, + search, + hash: fragment, + protocol, + } = new URL(url); const domainParts = name.split('.'); const topLevelDomain = domainParts[domainParts.length - 1]; diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 236e81884..28aea0292 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -734,7 +734,9 @@ export default class MetamaskController extends EventEmitter { setUsePhishDetect: this.setUsePhishDetect.bind(this), setIpfsGateway: this.setIpfsGateway.bind(this), setIpfsIpnsUrlResolving: this.setIpfsIpnsUrlResolving.bind(this), - setIpfsIpnsHandlerShouldUpdate: this.setIpfsIpnsHandlerShouldUpdate.bind(this), + setIpfsIpnsHandlerShouldUpdate: this.setIpfsIpnsHandlerShouldUpdate.bind( + this, + ), setParticipateInMetaMetrics: this.setParticipateInMetaMetrics.bind(this), setMetaMetricsSendCount: this.setMetaMetricsSendCount.bind(this), setFirstTimeFlowType: this.setFirstTimeFlowType.bind(this), @@ -2922,7 +2924,6 @@ export default class MetamaskController extends EventEmitter { return; } catch (err) { cb(err); - return; } } @@ -2933,7 +2934,6 @@ export default class MetamaskController extends EventEmitter { return; } catch (err) { cb(err); - return; } } diff --git a/ui/app/helpers/constants/routes.js b/ui/app/helpers/constants/routes.js index 0dddd0f53..91af96057 100644 --- a/ui/app/helpers/constants/routes.js +++ b/ui/app/helpers/constants/routes.js @@ -137,7 +137,7 @@ const PATH_NAME_MAP = { [LOADING_QUOTES_ROUTE]: 'Swaps Loading Quotes Page', [AWAITING_SWAP_ROUTE]: 'Swaps Awaiting Swaps Page', [SWAPS_ERROR_ROUTE]: 'Swaps Error Page', - [IPFS_IPNS_URL_RESOLVING]: 'Ipfs and Ipns URL Resolving Info Page' + [IPFS_IPNS_URL_RESOLVING]: 'Ipfs and Ipns URL Resolving Info Page', }; export { diff --git a/ui/app/pages/ipfs-enable/index.js b/ui/app/pages/ipfs-enable/index.js index 660ac2b12..ec256a9d9 100644 --- a/ui/app/pages/ipfs-enable/index.js +++ b/ui/app/pages/ipfs-enable/index.js @@ -1 +1 @@ -export { default } from './ipfs-enable.container'; \ No newline at end of file +export { default } from './ipfs-enable.container'; diff --git a/ui/app/pages/ipfs-enable/ipfs-enable.component.js b/ui/app/pages/ipfs-enable/ipfs-enable.component.js index 1c5243501..50c267df6 100644 --- a/ui/app/pages/ipfs-enable/ipfs-enable.component.js +++ b/ui/app/pages/ipfs-enable/ipfs-enable.component.js @@ -3,113 +3,113 @@ import PropTypes from 'prop-types'; import { IPFS_IPNS_URL_RESOLVING } from '../../helpers/constants/routes'; export default class IpfsEnable extends PureComponent { - static contextTypes = { - t: PropTypes.func - } - - static propType = { - ipfsGateway: PropTypes.string.isRequired, - ipfsIpnsEnabled: PropTypes.bool.isRequired, - ipfsIpnsHandlerShouldUpdate: PropTypes.bool.isRequired, - setIpfsIpnsHandlerShouldUpdate: PropTypes.func, - } + static contextTypes = { + t: PropTypes.func, + }; - state = { - ipfsGateway: this.props.ipfsGateway, - ipfsIpnsIsEnabled: this.props.ipfsIpnsEnabled, - ipfsIpnsHandlerShouldUpdate: this.props.ipfsIpnsHandlerShouldUpdate, - } + static propType = { + ipfsGateway: PropTypes.string.isRequired, + ipfsIpnsEnabled: PropTypes.bool.isRequired, + ipfsIpnsHandlerShouldUpdate: PropTypes.bool.isRequired, + setIpfsIpnsHandlerShouldUpdate: PropTypes.func, + }; - componentDidMount() { - const { - ipfsIpnsEnabled, - ipfsIpnsHandlerShouldUpdate, - } = this.props; + state = { + ipfsGateway: this.props.ipfsGateway, + ipfsIpnsIsEnabled: this.props.ipfsIpnsEnabled, + ipfsIpnsHandlerShouldUpdate: this.props.ipfsIpnsHandlerShouldUpdate, + }; - if(ipfsIpnsHandlerShouldUpdate) { - const page = IPFS_IPNS_URL_RESOLVING.replace("/", ""); - if(ipfsIpnsEnabled) { - this.registerHandlers(page); - } else { - this.unregisterHandlers(page); - } - this.props.setIpfsIpnsHandlerShouldUpdate(false); - } - } + componentDidMount() { + const { ipfsIpnsEnabled, ipfsIpnsHandlerShouldUpdate } = this.props; - registerHandlers(page) { - window.navigator.registerProtocolHandler( - "ipfs", - window.location.href.replace(`/home.html#${page}`, "/%s"), - "Ipfs handler", - ); - window.navigator.registerProtocolHandler( - "ipns", - window.location.href.replace(`/home.html#${page}`, "/%s"), - "Ipns handler", - ); + if (ipfsIpnsHandlerShouldUpdate) { + const page = IPFS_IPNS_URL_RESOLVING.replace('/', ''); + if (ipfsIpnsEnabled) { + this.registerHandlers(page); + } else { + this.unregisterHandlers(page); + } + this.props.setIpfsIpnsHandlerShouldUpdate(false); } + } - unregisterHandlers(page) { - window.navigator.unregisterProtocolHandler( - "ipfs", - window.location.href.replace(`/home.html#${page}`, "/%s"), - ); - window.navigator.unregisterProtocolHandler( - "ipns", - window.location.href.replace(`/home.html#${page}`, "/%s"), - ); - } + registerHandlers(page) { + window.navigator.registerProtocolHandler( + 'ipfs', + window.location.href.replace(`/home.html#${page}`, '/%s'), + 'Ipfs handler', + ); + window.navigator.registerProtocolHandler( + 'ipns', + window.location.href.replace(`/home.html#${page}`, '/%s'), + 'Ipns handler', + ); + } - render() { - const { t } = this.context; - const ipfsIpnsDescriptionParts = t('ipfsIpnsDescription').split("#"); - const ipfsIpnsExampleParts = t('ipfsIpnsExample').split("#"); - return ( -
-
-
-
-
- {t('ipfsIpnsResolvingTitle')} -
-
-
- -
-
- - {t('ipfsIpnsResolvingTitle')} - -
- {this.state.ipfsIpnsIsEnabled ? "Enabled" : "Disabled"} -
-
-
- - {t('ipfsGateway')} - -
- {this.state.ipfsGateway} -
-
-
- - {t('example')} - -
- {ipfsIpnsDescriptionParts[0]} ipfs:// {ipfsIpnsDescriptionParts[1]} ipns:// - {ipfsIpnsDescriptionParts[2]} -
-
- {ipfsIpnsExampleParts[0]} ipfs://[CID]/ {ipfsIpnsExampleParts[1]} https://ipfs.io/ipfs/[CID]/ . -
-
-
-
-
+ unregisterHandlers(page) { + window.navigator.unregisterProtocolHandler( + 'ipfs', + window.location.href.replace(`/home.html#${page}`, '/%s'), + ); + window.navigator.unregisterProtocolHandler( + 'ipns', + window.location.href.replace(`/home.html#${page}`, '/%s'), + ); + } + + render() { + const { t } = this.context; + const ipfsIpnsDescriptionParts = t('ipfsIpnsDescription').split('#'); + const ipfsIpnsExampleParts = t('ipfsIpnsExample').split('#'); + return ( +
+
+
+
+
+ {t('ipfsIpnsResolvingTitle')} +
+
+
+ +
+
+ {t('ipfsIpnsResolvingTitle')} +
+ {this.state.ipfsIpnsIsEnabled ? 'Enabled' : 'Disabled'} +
+
+
+ {t('ipfsGateway')} +
+ {this.state.ipfsGateway} +
+
+ {t('example')} +
+ {ipfsIpnsDescriptionParts[0]}{' '} + ipfs://{' '} + {ipfsIpnsDescriptionParts[1]}{' '} + ipns:// + {ipfsIpnsDescriptionParts[2]} +
+
+ {ipfsIpnsExampleParts[0]}{' '} + ipfs://[CID]/{' '} + {ipfsIpnsExampleParts[1]}{' '} + + https://ipfs.io/ipfs/[CID]/ + {' '} + . +
+
+
- ) - } -} \ No newline at end of file +
+
+
+ ); + } +} diff --git a/ui/app/pages/ipfs-enable/ipfs-enable.container.js b/ui/app/pages/ipfs-enable/ipfs-enable.container.js index d8165d0f5..3c5f882a7 100644 --- a/ui/app/pages/ipfs-enable/ipfs-enable.container.js +++ b/ui/app/pages/ipfs-enable/ipfs-enable.container.js @@ -1,31 +1,31 @@ -import { connect } from "react-redux" -import IpfsEnable from "./ipfs-enable.component" -import {setIpfsIpnsHandlerShouldUpdate} from "../../store/actions" -import console from "console"; +import console from 'console'; +import { connect } from 'react-redux'; +import { setIpfsIpnsHandlerShouldUpdate } from '../../store/actions'; +import IpfsEnable from './ipfs-enable.component'; const mapStateToProps = (state) => { - const {metamask} = state; - const { - ipfsGateway, - ipfsIpnsEnabled, - ipfsIpnsHandlerShouldUpdate, - } = metamask; + const { metamask } = state; + const { + ipfsGateway, + ipfsIpnsEnabled, + ipfsIpnsHandlerShouldUpdate, + } = metamask; - console.log(state); + console.log(state); - return { - ipfsGateway, - ipfsIpnsEnabled, - ipfsIpnsHandlerShouldUpdate, - } -} + return { + ipfsGateway, + ipfsIpnsEnabled, + ipfsIpnsHandlerShouldUpdate, + }; +}; const mapDispatchToProps = (dispatch) => { - return { - setIpfsIpnsHandlerShouldUpdate: (value) => { - dispatch(setIpfsIpnsHandlerShouldUpdate(value)) - } - } -} + return { + setIpfsIpnsHandlerShouldUpdate: (value) => { + dispatch(setIpfsIpnsHandlerShouldUpdate(value)); + }, + }; +}; -export default connect(mapStateToProps, mapDispatchToProps)(IpfsEnable) \ No newline at end of file +export default connect(mapStateToProps, mapDispatchToProps)(IpfsEnable); diff --git a/ui/app/pages/routes/routes.component.js b/ui/app/pages/routes/routes.component.js index 3c8135326..26668dd31 100644 --- a/ui/app/pages/routes/routes.component.js +++ b/ui/app/pages/routes/routes.component.js @@ -171,7 +171,10 @@ export default class Routes extends Component { path={`${CONNECT_ROUTE}/:id`} component={PermissionsConnect} /> - + diff --git a/ui/app/pages/settings/advanced-tab/advanced-tab.component.js b/ui/app/pages/settings/advanced-tab/advanced-tab.component.js index 4e06dbe86..c1002604e 100644 --- a/ui/app/pages/settings/advanced-tab/advanced-tab.component.js +++ b/ui/app/pages/settings/advanced-tab/advanced-tab.component.js @@ -5,7 +5,10 @@ import { exportAsFile } from '../../../helpers/utils/util'; import ToggleButton from '../../../components/ui/toggle-button'; import TextField from '../../../components/ui/text-field'; import Button from '../../../components/ui/button'; -import { MOBILE_SYNC_ROUTE, IPFS_IPNS_URL_RESOLVING } from '../../../helpers/constants/routes'; +import { + MOBILE_SYNC_ROUTE, + IPFS_IPNS_URL_RESOLVING, +} from '../../../helpers/constants/routes'; export default class AdvancedTab extends PureComponent { static contextTypes = { @@ -475,8 +478,8 @@ export default class AdvancedTab extends PureComponent { setIpfsIpnsHandlerShouldUpdate, } = this.props; - let enabled = ipfsIpnsEnabled; - + const enabled = ipfsIpnsEnabled; + return (
Resolve IPFS urls (experimental)
- Turn on to have IPFS (ipfs://) and IPNS (ipns://) URLs being resolved by Metamask. This feature is currently experimental; use at your own risk. + Turn on to have IPFS (ipfs://) and IPNS (ipns://) URLs being + resolved by Metamask. This feature is currently experimental; use at + your own risk.
{ return dispatch(setIpfsGateway(value)); }, setIpfsIpnsUrlResolving: (value) => { - dispatch(setIpfsIpnsUrlResolving(value)) + dispatch(setIpfsIpnsUrlResolving(value)); }, setIpfsIpnsHandlerShouldUpdate: (value) => { - dispatch(setIpfsIpnsHandlerShouldUpdate(value)) + dispatch(setIpfsIpnsHandlerShouldUpdate(value)); }, }; }; diff --git a/ui/app/store/actions.js b/ui/app/store/actions.js index 659ee46c5..fadcfa2d5 100644 --- a/ui/app/store/actions.js +++ b/ui/app/store/actions.js @@ -2234,15 +2234,15 @@ export function setIpfsIpnsHandlerShouldUpdate(val) { log.debug(`background.setIpfsIpnsHandlerShouldUpdate`); return new Promise((resolve, reject) => { background.setIpfsIpnsHandlerShouldUpdate(val, (err) => { - if(err) { + if (err) { dispatch(displayWarning(err.message)); reject(err); return; } resolve(val); - }) - }) - } + }); + }); + }; } export function setIpfsIpnsUrlResolving(val) { @@ -2252,15 +2252,15 @@ export function setIpfsIpnsUrlResolving(val) { return new Promise((resolve, reject) => { background.setIpfsIpnsUrlResolving(val, (err) => { dispatch(hideLoadingIndication()); - if(err) { + if (err) { dispatch(displayWarning(err.message)); reject(err); return; } resolve(val); }); - }) - } + }); + }; } export function updateCurrentLocale(key) { diff --git a/yarn.lock b/yarn.lock index eb076e4c0..dc3aa0c5f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6682,9 +6682,9 @@ camelcase@^6.0.0: integrity sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w== caniuse-lite@^1.0.30000810, caniuse-lite@^1.0.30000844, caniuse-lite@^1.0.30001035, caniuse-lite@^1.0.30001097, caniuse-lite@^1.0.30001157: - version "1.0.30001162" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001162.tgz#9f83aad1f42539ce9aab58bb177598f2f8e22ec6" - integrity sha512-E9FktFxaNnp4ky3ucIGzEXLM+Knzlpuq1oN1sFAU0KeayygabGTmOsndpo8QrL4D9pcThlf4D2pUKaDxPCUmVw== + version "1.0.30001257" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001257.tgz" + integrity sha512-JN49KplOgHSXpIsVSF+LUyhD8PUp6xPpAXeRrrcBh4KBeP7W864jHn6RvzJgDlrReyeVjMFJL3PLpPvKIxlIHA== capture-stack-trace@^1.0.0: version "1.0.1" From 195ac5508babf912a4841369581755db0af0ef50 Mon Sep 17 00:00:00 2001 From: Mak Muftic Date: Tue, 14 Sep 2021 10:44:27 +0200 Subject: [PATCH 04/16] Fix imports and failing prop type validation --- app/scripts/lib/ens-ipfs/setup.js | 8 +------- app/scripts/metamask-controller.js | 17 ++++++++++++++++- .../pages/ipfs-enable/ipfs-enable.component.js | 15 ++++++++------- .../pages/ipfs-enable/ipfs-enable.container.js | 3 --- .../advanced-tab/advanced-tab.component.js | 2 -- .../advanced-tab/advanced-tab.container.js | 2 +- 6 files changed, 26 insertions(+), 21 deletions(-) diff --git a/app/scripts/lib/ens-ipfs/setup.js b/app/scripts/lib/ens-ipfs/setup.js index ef2321dfa..d3d76c34d 100644 --- a/app/scripts/lib/ens-ipfs/setup.js +++ b/app/scripts/lib/ens-ipfs/setup.js @@ -60,13 +60,7 @@ export default function setupEnsIpfsResolver({ return; } // parse ens name - const { - hostname: name, - pathname, - search, - hash: fragment, - protocol, - } = new URL(url); + const { hostname: name, pathname, search, hash: fragment } = new URL(url); const domainParts = name.split('.'); const topLevelDomain = domainParts[domainParts.length - 1]; diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index 28aea0292..6d0c1430f 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -722,7 +722,6 @@ export default class MetamaskController extends EventEmitter { swapsController, threeBoxController, txController, - ipfsIpnsController, } = this; return { @@ -2917,6 +2916,12 @@ export default class MetamaskController extends EventEmitter { } } + /** + * Sets IPFS and IPNS URL resolving + * @param {*} bool + * @param {*} cb + * @returns + */ setIpfsIpnsUrlResolving(bool, cb) { try { this.ipfsIpnsController.setIpfsIpnsUrlResolving(bool); @@ -2924,9 +2929,17 @@ export default class MetamaskController extends EventEmitter { return; } catch (err) { cb(err); + // eslint-disable-next-line no-useless-return + return; } } + /** + * Sets if protocol handlers for ipfs and ipns should be updated + * @param {*} bool + * @param {*} cb + * @returns + */ setIpfsIpnsHandlerShouldUpdate(bool, cb) { try { this.ipfsIpnsController.setIpfsIpnsHandlerShouldUpdate(bool); @@ -2934,6 +2947,8 @@ export default class MetamaskController extends EventEmitter { return; } catch (err) { cb(err); + // eslint-disable-next-line no-useless-return + return; } } diff --git a/ui/app/pages/ipfs-enable/ipfs-enable.component.js b/ui/app/pages/ipfs-enable/ipfs-enable.component.js index 50c267df6..00237a6d1 100644 --- a/ui/app/pages/ipfs-enable/ipfs-enable.component.js +++ b/ui/app/pages/ipfs-enable/ipfs-enable.component.js @@ -7,17 +7,18 @@ export default class IpfsEnable extends PureComponent { t: PropTypes.func, }; - static propType = { - ipfsGateway: PropTypes.string.isRequired, - ipfsIpnsEnabled: PropTypes.bool.isRequired, - ipfsIpnsHandlerShouldUpdate: PropTypes.bool.isRequired, - setIpfsIpnsHandlerShouldUpdate: PropTypes.func, - }; + static get propTypes() { + return { + ipfsGateway: PropTypes.string.isRequired, + ipfsIpnsEnabled: PropTypes.bool.isRequired, + ipfsIpnsHandlerShouldUpdate: PropTypes.bool.isRequired, + setIpfsIpnsHandlerShouldUpdate: PropTypes.func, + }; + } state = { ipfsGateway: this.props.ipfsGateway, ipfsIpnsIsEnabled: this.props.ipfsIpnsEnabled, - ipfsIpnsHandlerShouldUpdate: this.props.ipfsIpnsHandlerShouldUpdate, }; componentDidMount() { diff --git a/ui/app/pages/ipfs-enable/ipfs-enable.container.js b/ui/app/pages/ipfs-enable/ipfs-enable.container.js index 3c5f882a7..fe0216783 100644 --- a/ui/app/pages/ipfs-enable/ipfs-enable.container.js +++ b/ui/app/pages/ipfs-enable/ipfs-enable.container.js @@ -1,4 +1,3 @@ -import console from 'console'; import { connect } from 'react-redux'; import { setIpfsIpnsHandlerShouldUpdate } from '../../store/actions'; import IpfsEnable from './ipfs-enable.component'; @@ -11,8 +10,6 @@ const mapStateToProps = (state) => { ipfsIpnsHandlerShouldUpdate, } = metamask; - console.log(state); - return { ipfsGateway, ipfsIpnsEnabled, diff --git a/ui/app/pages/settings/advanced-tab/advanced-tab.component.js b/ui/app/pages/settings/advanced-tab/advanced-tab.component.js index c1002604e..b890822b5 100644 --- a/ui/app/pages/settings/advanced-tab/advanced-tab.component.js +++ b/ui/app/pages/settings/advanced-tab/advanced-tab.component.js @@ -36,8 +36,6 @@ export default class AdvancedTab extends PureComponent { threeBoxDisabled: PropTypes.bool.isRequired, setIpfsGateway: PropTypes.func.isRequired, ipfsGateway: PropTypes.string.isRequired, - ipfsUrlGateway: PropTypes.string.isRequired, - setIpfsIpnsUrlGateway: PropTypes.func, ipfsIpnsEnabled: PropTypes.bool, setIpfsIpnsUrlResolving: PropTypes.func, setIpfsIpnsHandlerShouldUpdate: PropTypes.func, diff --git a/ui/app/pages/settings/advanced-tab/advanced-tab.container.js b/ui/app/pages/settings/advanced-tab/advanced-tab.container.js index b56586b16..0641f4677 100644 --- a/ui/app/pages/settings/advanced-tab/advanced-tab.container.js +++ b/ui/app/pages/settings/advanced-tab/advanced-tab.container.js @@ -11,8 +11,8 @@ import { turnThreeBoxSyncingOnAndInitialize, setUseNonceField, setIpfsGateway, - setIpfsIpnsUrlResolving, setIpfsIpnsHandlerShouldUpdate, + setIpfsIpnsUrlResolving, } from '../../../store/actions'; import { getPreferences } from '../../../selectors'; import AdvancedTab from './advanced-tab.component'; From 4ce6216dfe14597017c144a0a5036a233d17be0a Mon Sep 17 00:00:00 2001 From: Mak Muftic Date: Tue, 28 Sep 2021 15:34:57 +0200 Subject: [PATCH 05/16] Fix setting ipfs ipns handler only on supp. brow. --- app/scripts/lib/ens-ipfs/setup.js | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/app/scripts/lib/ens-ipfs/setup.js b/app/scripts/lib/ens-ipfs/setup.js index d3d76c34d..1883911cb 100644 --- a/app/scripts/lib/ens-ipfs/setup.js +++ b/app/scripts/lib/ens-ipfs/setup.js @@ -6,6 +6,7 @@ const fetchWithTimeout = getFetchWithTimeout(30000); const supportedTopLevelDomains = ['eth']; const supportedProtocols = ['ipfs', 'ipns']; +const supportedBrowsers = ['moz-extension', 'chrome-extension'] export default function setupEnsIpfsResolver({ provider, @@ -15,26 +16,32 @@ export default function setupEnsIpfsResolver({ }) { const urlPatterns = supportedTopLevelDomains.map((tld) => `*://*.${tld}/*`); + for (const browser of supportedBrowsers) { + // only setup ipfs ipns handler on supported browsers + if(window.location.href.startsWith(browser)) { + extension.webRequest.onBeforeRequest.addListener(ipfsIpnsUrlHandler, { + types: ['main_frame'], + urls: [`${browser}://*/*`], + }); + } + } + extension.webRequest.onErrorOccurred.addListener(webRequestDidFail, { types: ['main_frame'], urls: urlPatterns, }); - extension.webRequest.onBeforeRequest.addListener(catchIpfsChromeExt, { - types: ['main_frame'], - urls: ['chrome-extension://*/*'], - }); // return api object return { // uninstall listener remove() { extension.webRequest.onErrorOccurred.removeListener(webRequestDidFail); - extension.webRequest.onBeforeRequest.removeListener(catchIpfsChromeExt); + extension.webRequest.onBeforeRequest.removeListener(ipfsIpnsUrlHandler); }, }; - async function catchIpfsChromeExt(details) { + async function ipfsIpnsUrlHandler(details) { const { tabId, url } = details; // ignore requests that are not associated with tabs if (tabId === -1) { From 71922dcfdcfe351cb7367b9a600d7f36372db385 Mon Sep 17 00:00:00 2001 From: Mak Muftic Date: Tue, 28 Sep 2021 15:35:25 +0200 Subject: [PATCH 06/16] Remove chrome specific perm. from base manifest --- app/manifest/_base.json | 1 - app/manifest/chrome.json | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/manifest/_base.json b/app/manifest/_base.json index 60c02d388..996b7de27 100644 --- a/app/manifest/_base.json +++ b/app/manifest/_base.json @@ -69,7 +69,6 @@ "activeTab", "webRequest", "*://*.eth/", - "chrome-extension://*/*", "notifications" ], "short_name": "__MSG_appName__", diff --git a/app/manifest/chrome.json b/app/manifest/chrome.json index 281c847a4..79496eb63 100644 --- a/app/manifest/chrome.json +++ b/app/manifest/chrome.json @@ -3,5 +3,8 @@ "matches": ["https://metamask.io/*"], "ids": ["*"] }, - "minimum_chrome_version": "63" + "minimum_chrome_version": "63", + "permissions": [ + "chrome-extension://*/*" + ] } From 55da6feb4925e043725e89fc8693cda9b5410082 Mon Sep 17 00:00:00 2001 From: Mak Muftic Date: Tue, 28 Sep 2021 15:36:31 +0200 Subject: [PATCH 07/16] Minor fix in browser loop --- app/scripts/lib/ens-ipfs/setup.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/scripts/lib/ens-ipfs/setup.js b/app/scripts/lib/ens-ipfs/setup.js index 1883911cb..5aee583bf 100644 --- a/app/scripts/lib/ens-ipfs/setup.js +++ b/app/scripts/lib/ens-ipfs/setup.js @@ -23,6 +23,7 @@ export default function setupEnsIpfsResolver({ types: ['main_frame'], urls: [`${browser}://*/*`], }); + break; } } From 37503b4ef9f1afc37b0fe46152a13aae98108942 Mon Sep 17 00:00:00 2001 From: Mak Muftic Date: Wed, 29 Sep 2021 13:58:35 +0200 Subject: [PATCH 08/16] Remove chrome specific manifest --- app/manifest/chrome.json | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/app/manifest/chrome.json b/app/manifest/chrome.json index 79496eb63..281c847a4 100644 --- a/app/manifest/chrome.json +++ b/app/manifest/chrome.json @@ -3,8 +3,5 @@ "matches": ["https://metamask.io/*"], "ids": ["*"] }, - "minimum_chrome_version": "63", - "permissions": [ - "chrome-extension://*/*" - ] + "minimum_chrome_version": "63" } From 25c1998ecc88f69da75ff26a35414d4217103a77 Mon Sep 17 00:00:00 2001 From: Mak Muftic Date: Thu, 30 Sep 2021 15:12:53 +0200 Subject: [PATCH 09/16] Fix browser specific manifest merging bug --- app/manifest/chrome.json | 5 ++++- app/manifest/firefox.json | 19 ++++++++++++++++++- development/build/manifest.js | 12 ++++++++++-- 3 files changed, 32 insertions(+), 4 deletions(-) diff --git a/app/manifest/chrome.json b/app/manifest/chrome.json index 281c847a4..79496eb63 100644 --- a/app/manifest/chrome.json +++ b/app/manifest/chrome.json @@ -3,5 +3,8 @@ "matches": ["https://metamask.io/*"], "ids": ["*"] }, - "minimum_chrome_version": "63" + "minimum_chrome_version": "63", + "permissions": [ + "chrome-extension://*/*" + ] } diff --git a/app/manifest/firefox.json b/app/manifest/firefox.json index 930e1e758..35c064439 100644 --- a/app/manifest/firefox.json +++ b/app/manifest/firefox.json @@ -4,5 +4,22 @@ "id": "webextension@metamask.io", "strict_min_version": "68.0" } - } + }, + "protocol_handlers": [ + { + "protocol": "ipfs", + "name": "IPFS Companion: IPFS Protocol Handler", + "uriTemplate": "https://dweb.link/ipfs/?uri=%s" + }, + { + "protocol": "dweb", + "name": "IPFS Companion: DWEB Protocol Handler", + "uriTemplate": "https://dweb.link/ipfs/?uri=%s" + }, + { + "protocol": "ipns", + "name": "IPFS Companion: IPNS Protocol Handler", + "uriTemplate": "https://dweb.link/ipns/?uri=%s" + } + ] } diff --git a/development/build/manifest.js b/development/build/manifest.js index 340db1272..93b425993 100644 --- a/development/build/manifest.js +++ b/development/build/manifest.js @@ -1,6 +1,6 @@ const { promises: fs } = require('fs'); const path = require('path'); -const { merge, cloneDeep } = require('lodash'); +const { merge, cloneDeep, mergeWith } = require('lodash'); const baseManifest = require('../../app/manifest/_base.json'); @@ -8,6 +8,12 @@ const { createTask, composeSeries } = require('./task'); module.exports = createManifestTasks; +function customArrayMerge(objValue, srcValue) { + if (Array.isArray(objValue)) { + return [...new Set([...objValue ,...srcValue])] + } +} + function createManifestTasks({ browserPlatforms }) { // merge base manifest with per-platform manifests const prepPlatforms = async () => { @@ -23,7 +29,9 @@ function createManifestTasks({ browserPlatforms }) { `${platform}.json`, ), ); - const result = merge(cloneDeep(baseManifest), platformModifications); + const result = mergeWith( + cloneDeep(baseManifest), platformModifications, customArrayMerge + ); const dir = path.join('.', 'dist', platform); await fs.mkdir(dir, { recursive: true }); await writeJson(result, path.join(dir, 'manifest.json')); From 35be0d3eead5b0f97418e8c40352cd7b6fac8183 Mon Sep 17 00:00:00 2001 From: Mak Muftic Date: Fri, 1 Oct 2021 13:33:54 +0200 Subject: [PATCH 10/16] Revert manifest changes --- development/build/manifest.js | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/development/build/manifest.js b/development/build/manifest.js index 93b425993..033b674f7 100644 --- a/development/build/manifest.js +++ b/development/build/manifest.js @@ -1,6 +1,6 @@ const { promises: fs } = require('fs'); const path = require('path'); -const { merge, cloneDeep, mergeWith } = require('lodash'); +const { merge, cloneDeep } = require('lodash'); const baseManifest = require('../../app/manifest/_base.json'); @@ -8,12 +8,6 @@ const { createTask, composeSeries } = require('./task'); module.exports = createManifestTasks; -function customArrayMerge(objValue, srcValue) { - if (Array.isArray(objValue)) { - return [...new Set([...objValue ,...srcValue])] - } -} - function createManifestTasks({ browserPlatforms }) { // merge base manifest with per-platform manifests const prepPlatforms = async () => { @@ -29,9 +23,7 @@ function createManifestTasks({ browserPlatforms }) { `${platform}.json`, ), ); - const result = mergeWith( - cloneDeep(baseManifest), platformModifications, customArrayMerge - ); + const result = mergeWith(cloneDeep(baseManifest), platformModifications); const dir = path.join('.', 'dist', platform); await fs.mkdir(dir, { recursive: true }); await writeJson(result, path.join(dir, 'manifest.json')); From d75563496ed309302393e2b410e4c52f9c41ea88 Mon Sep 17 00:00:00 2001 From: Mak Muftic Date: Fri, 1 Oct 2021 13:34:53 +0200 Subject: [PATCH 11/16] Fix function naming --- development/build/manifest.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/development/build/manifest.js b/development/build/manifest.js index 033b674f7..340db1272 100644 --- a/development/build/manifest.js +++ b/development/build/manifest.js @@ -23,7 +23,7 @@ function createManifestTasks({ browserPlatforms }) { `${platform}.json`, ), ); - const result = mergeWith(cloneDeep(baseManifest), platformModifications); + const result = merge(cloneDeep(baseManifest), platformModifications); const dir = path.join('.', 'dist', platform); await fs.mkdir(dir, { recursive: true }); await writeJson(result, path.join(dir, 'manifest.json')); From 479b2173be544c9a7347a8716893a923be97c20a Mon Sep 17 00:00:00 2001 From: Mak Muftic Date: Fri, 1 Oct 2021 13:54:54 +0200 Subject: [PATCH 12/16] Fix supported browsers array --- app/scripts/lib/ens-ipfs/setup.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/lib/ens-ipfs/setup.js b/app/scripts/lib/ens-ipfs/setup.js index 5aee583bf..26bdcdeaa 100644 --- a/app/scripts/lib/ens-ipfs/setup.js +++ b/app/scripts/lib/ens-ipfs/setup.js @@ -6,7 +6,7 @@ const fetchWithTimeout = getFetchWithTimeout(30000); const supportedTopLevelDomains = ['eth']; const supportedProtocols = ['ipfs', 'ipns']; -const supportedBrowsers = ['moz-extension', 'chrome-extension'] +const supportedBrowsers = ['chrome-extension'] export default function setupEnsIpfsResolver({ provider, From 374473379898232b7c07328a810b2fc46bde1e1d Mon Sep 17 00:00:00 2001 From: Mak Muftic Date: Mon, 4 Oct 2021 14:32:14 +0200 Subject: [PATCH 13/16] Display advnaced settings config only on chrome --- .../advanced-tab/advanced-tab.component.js | 64 ++++++++++--------- 1 file changed, 35 insertions(+), 29 deletions(-) diff --git a/ui/app/pages/settings/advanced-tab/advanced-tab.component.js b/ui/app/pages/settings/advanced-tab/advanced-tab.component.js index b890822b5..be21dbec5 100644 --- a/ui/app/pages/settings/advanced-tab/advanced-tab.component.js +++ b/ui/app/pages/settings/advanced-tab/advanced-tab.component.js @@ -9,6 +9,8 @@ import { MOBILE_SYNC_ROUTE, IPFS_IPNS_URL_RESOLVING, } from '../../../helpers/constants/routes'; +import { getPlatform } from '../../../../../app/scripts/lib/util'; +import { PLATFORM_CHROME } from '../../../../../shared/constants/app'; export default class AdvancedTab extends PureComponent { static contextTypes = { @@ -478,39 +480,43 @@ export default class AdvancedTab extends PureComponent { const enabled = ipfsIpnsEnabled; - return ( -
-
- Resolve IPFS urls (experimental) -
- Turn on to have IPFS (ipfs://) and IPNS (ipns://) URLs being - resolved by Metamask. This feature is currently experimental; use at - your own risk. -
-
+ if(getPlatform() == PLATFORM_CHROME) { + return (
-
- { - setIpfsIpnsUrlResolving(!enabled); - setIpfsIpnsHandlerShouldUpdate(true); - global.platform.openExtensionInBrowser(IPFS_IPNS_URL_RESOLVING); - }} - offLabel={t('off')} - onLabel={t('on')} - /> +
+ Resolve IPFS urls (experimental) +
+ Turn on to have IPFS (ipfs://) and IPNS (ipns://) URLs being + resolved by Metamask. This feature is currently experimental; use at + your own risk. +
+
+
+
+ { + setIpfsIpnsUrlResolving(!enabled); + setIpfsIpnsHandlerShouldUpdate(true); + global.platform.openExtensionInBrowser(IPFS_IPNS_URL_RESOLVING); + }} + offLabel={t('off')} + onLabel={t('on')} + /> +
-
- ); + ); + } else { + return; + } } render() { From 95d0962c1dc358d1245c81e280f4ff02824ca20e Mon Sep 17 00:00:00 2001 From: Mak Muftic Date: Tue, 5 Oct 2021 12:35:31 +0200 Subject: [PATCH 14/16] Change handlers order and add signature --- app/manifest/firefox.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/manifest/firefox.json b/app/manifest/firefox.json index 35c064439..e2b08ea4f 100644 --- a/app/manifest/firefox.json +++ b/app/manifest/firefox.json @@ -7,13 +7,13 @@ }, "protocol_handlers": [ { - "protocol": "ipfs", - "name": "IPFS Companion: IPFS Protocol Handler", + "protocol": "dweb", + "name": "IPFS Companion: DWEB Protocol Handler", "uriTemplate": "https://dweb.link/ipfs/?uri=%s" }, { - "protocol": "dweb", - "name": "IPFS Companion: DWEB Protocol Handler", + "protocol": "ipfs", + "name": "IPFS Companion: IPFS Protocol Handler", "uriTemplate": "https://dweb.link/ipfs/?uri=%s" }, { From 9f7c8a89e6d4507fe054e8ec24cdad6dd2a80b78 Mon Sep 17 00:00:00 2001 From: Mak Muftic Date: Tue, 5 Oct 2021 13:23:35 +0200 Subject: [PATCH 15/16] Empty commit to try fix CLA signing --- app/scripts/lib/ens-ipfs/setup.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/scripts/lib/ens-ipfs/setup.js b/app/scripts/lib/ens-ipfs/setup.js index 26bdcdeaa..a77951fbf 100644 --- a/app/scripts/lib/ens-ipfs/setup.js +++ b/app/scripts/lib/ens-ipfs/setup.js @@ -15,9 +15,8 @@ export default function setupEnsIpfsResolver({ // install listener }) { const urlPatterns = supportedTopLevelDomains.map((tld) => `*://*.${tld}/*`); - + // only setup ipfs ipns handler on supported browsers for (const browser of supportedBrowsers) { - // only setup ipfs ipns handler on supported browsers if(window.location.href.startsWith(browser)) { extension.webRequest.onBeforeRequest.addListener(ipfsIpnsUrlHandler, { types: ['main_frame'], From 6a45893468ae6eced409c7c220f67cf5fe33de01 Mon Sep 17 00:00:00 2001 From: Mak Muftic Date: Tue, 5 Oct 2021 13:30:16 +0200 Subject: [PATCH 16/16] Second try to fix CLA bot failing --- app/scripts/lib/ens-ipfs/setup.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/scripts/lib/ens-ipfs/setup.js b/app/scripts/lib/ens-ipfs/setup.js index a77951fbf..5b5e72455 100644 --- a/app/scripts/lib/ens-ipfs/setup.js +++ b/app/scripts/lib/ens-ipfs/setup.js @@ -15,8 +15,9 @@ export default function setupEnsIpfsResolver({ // install listener }) { const urlPatterns = supportedTopLevelDomains.map((tld) => `*://*.${tld}/*`); - // only setup ipfs ipns handler on supported browsers + for (const browser of supportedBrowsers) { + // only setup ipfs ipns handler on supported browsers if(window.location.href.startsWith(browser)) { extension.webRequest.onBeforeRequest.addListener(ipfsIpnsUrlHandler, { types: ['main_frame'],