Skip to content
This repository was archived by the owner on May 12, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions app/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,9 @@
"etherscanView": {
"message": "View account on Etherscan"
},
"example": {
"message": "Example"
},
"expandView": {
"message": "Expand view"
},
Expand Down Expand Up @@ -946,6 +949,15 @@
"ipfsGatewayDescription": {
"message": "Enter the URL of the IPFS CID gateway to use for ENS content resolution."
},
"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"
Expand Down
5 changes: 4 additions & 1 deletion app/manifest/chrome.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,8 @@
"matches": ["https://metamask.io/*"],
"ids": ["*"]
},
"minimum_chrome_version": "63"
"minimum_chrome_version": "63",
"permissions": [
"chrome-extension://*/*"
]
}
19 changes: 18 additions & 1 deletion app/manifest/firefox.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,22 @@
"id": "webextension@metamask.io",
"strict_min_version": "68.0"
}
}
},
"protocol_handlers": [
{
"protocol": "dweb",
"name": "IPFS Companion: DWEB Protocol Handler",
"uriTemplate": "https://dweb.link/ipfs/?uri=%s"
},
{
"protocol": "ipfs",
"name": "IPFS Companion: IPFS Protocol Handler",
"uriTemplate": "https://dweb.link/ipfs/?uri=%s"
},
{
"protocol": "ipns",
"name": "IPFS Companion: IPNS Protocol Handler",
"uriTemplate": "https://dweb.link/ipns/?uri=%s"
}
]
}
33 changes: 33 additions & 0 deletions app/scripts/controllers/ipfs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
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);
}
}
40 changes: 38 additions & 2 deletions app/scripts/lib/ens-ipfs/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,61 @@ import resolveEnsToIpfsContentId from './resolver';
const fetchWithTimeout = getFetchWithTimeout(30000);

const supportedTopLevelDomains = ['eth'];
const supportedProtocols = ['ipfs', 'ipns'];
const supportedBrowsers = ['chrome-extension']

export default function setupEnsIpfsResolver({
provider,
getCurrentChainId,
getIpfsGateway,
}) {
// install listener
}) {
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}://*/*`],
});
break;
}
}

extension.webRequest.onErrorOccurred.addListener(webRequestDidFail, {
urls: urlPatterns,
types: ['main_frame'],
urls: urlPatterns,
});


// return api object
return {
// uninstall listener
remove() {
extension.webRequest.onErrorOccurred.removeListener(webRequestDidFail);
extension.webRequest.onBeforeRequest.removeListener(ipfsIpnsUrlHandler);
},
};

async function ipfsIpnsUrlHandler(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 });
}
});
}

async function webRequestDidFail(details) {
const { tabId, url } = details;
// ignore requests that are not associated with tabs
Expand All @@ -37,10 +71,12 @@ export default function setupEnsIpfsResolver({
const { hostname: name, pathname, search, hash: fragment } = new URL(url);
const domainParts = name.split('.');
const topLevelDomain = domainParts[domainParts.length - 1];

// if unsupported TLD, abort
if (!supportedTopLevelDomains.includes(topLevelDomain)) {
return;
}

// otherwise attempt resolve
attemptResolve({ tabId, name, pathname, search, fragment });
}
Expand Down
45 changes: 45 additions & 0 deletions app/scripts/metamask-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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, {
Expand Down Expand Up @@ -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));

Expand Down Expand Up @@ -727,6 +732,10 @@ 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),
Expand Down Expand Up @@ -2907,6 +2916,42 @@ 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);
cb(null);
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);
cb(null);
return;
} catch (err) {
cb(err);
// eslint-disable-next-line no-useless-return
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.
Expand Down
4 changes: 4 additions & 0 deletions ui/app/helpers/constants/routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -201,4 +204,5 @@ export {
AWAITING_SWAP_ROUTE,
SWAPS_ERROR_ROUTE,
SWAPS_MAINTENANCE_ROUTE,
IPFS_IPNS_URL_RESOLVING,
};
1 change: 1 addition & 0 deletions ui/app/pages/ipfs-enable/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './ipfs-enable.container';
65 changes: 65 additions & 0 deletions ui/app/pages/ipfs-enable/index.scss
Original file line number Diff line number Diff line change
@@ -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;
}
Loading