mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Ipfs cid v1 base32 (#7362)
add ipfs gateway to advanced settings use ipfs gateway from settings use ipfs.dweb.link as default CID gateway disallow gateway.ipfs.io as gateway
This commit is contained in:
parent
f49bc58c09
commit
0ef7f603d6
@ -735,6 +735,18 @@
|
||||
"invalidSeedPhrase": {
|
||||
"message": "Invalid seed phrase"
|
||||
},
|
||||
"ipfsGateway": {
|
||||
"message": "IPFS Gateway"
|
||||
},
|
||||
"ipfsGatewayDescription": {
|
||||
"message": "Enter the URL of the IPFS CID gateway to use for ENS content resolution."
|
||||
},
|
||||
"invalidIpfsGateway": {
|
||||
"message": "Invalid IPFS Gateway: The value must be a valid URL"
|
||||
},
|
||||
"forbiddenIpfsGateway": {
|
||||
"message": "Forbidden IPFS Gateway: Please specify a CID gateway"
|
||||
},
|
||||
"jsonFile": {
|
||||
"message": "JSON File",
|
||||
"description": "format for importing an account"
|
||||
@ -1336,7 +1348,7 @@
|
||||
"message": "Sync data with 3Box (experimental)"
|
||||
},
|
||||
"syncWithThreeBoxDescription": {
|
||||
"message": "Turn on to have your settings backed up with 3Box. This feature is currenty experimental; use at your own risk."
|
||||
"message": "Turn on to have your settings backed up with 3Box. This feature is currently experimental; use at your own risk."
|
||||
},
|
||||
"syncWithThreeBoxDisabled": {
|
||||
"message": "3Box has been disabled due to an error during the initial sync"
|
||||
@ -1360,7 +1372,7 @@
|
||||
"message": "Make sure nobody else is looking at your screen when you scan this code"
|
||||
},
|
||||
"syncWithMobileComplete": {
|
||||
"message": "Your data has been synced succesfully. Enjoy the MetaMask mobile app!"
|
||||
"message": "Your data has been synced successfully. Enjoy the MetaMask mobile app!"
|
||||
},
|
||||
"terms": {
|
||||
"message": "Terms of Use"
|
||||
|
@ -599,6 +599,18 @@
|
||||
"invalidSeedPhrase": {
|
||||
"message": "Phrase Seed invalide"
|
||||
},
|
||||
"ipfsGateway": {
|
||||
"message": "IPFS Gateway"
|
||||
},
|
||||
"ipfsGatewayDescription": {
|
||||
"message": "Entrez l'URL de la gateway CID IPFS à utiliser pour résoudre les contenus ENS."
|
||||
},
|
||||
"invalidIpfsGateway": {
|
||||
"message": "IPFS Gateway Invalide: la valeur doit être une URL valide"
|
||||
},
|
||||
"forbiddenIpfsGateway": {
|
||||
"message": "IPFS Gateway Interdite: veuillez spécifier une gateway CID"
|
||||
},
|
||||
"jsonFile": {
|
||||
"message": "Fichier JSON",
|
||||
"description": "format for importing an account"
|
||||
|
@ -252,8 +252,10 @@ function setupController (initState, initLangCode) {
|
||||
},
|
||||
})
|
||||
|
||||
const provider = controller.provider
|
||||
setupEnsIpfsResolver({ provider })
|
||||
setupEnsIpfsResolver({
|
||||
getIpfsGateway: controller.preferencesController.getIpfsGateway.bind(controller.preferencesController),
|
||||
provider: controller.provider,
|
||||
})
|
||||
|
||||
// submit rpc requests to mesh-metrics
|
||||
controller.networkController.on('rpc-req', (data) => {
|
||||
|
@ -60,6 +60,9 @@ class PreferencesController {
|
||||
completedOnboarding: false,
|
||||
metaMetricsId: null,
|
||||
metaMetricsSendCount: 0,
|
||||
|
||||
// ENS decentralized website resolution
|
||||
ipfsGateway: 'ipfs.dweb.link',
|
||||
}, opts.initState)
|
||||
|
||||
this.diagnostics = opts.diagnostics
|
||||
@ -608,6 +611,24 @@ class PreferencesController {
|
||||
return Promise.resolve(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* A getter for the `ipfsGateway` property
|
||||
* @returns {string} The current IPFS gateway domain
|
||||
*/
|
||||
getIpfsGateway () {
|
||||
return this.store.getState().ipfsGateway
|
||||
}
|
||||
|
||||
/**
|
||||
* A setter for the `ipfsGateway` property
|
||||
* @param {string} domain The new IPFS gateway domain
|
||||
* @returns {Promise<string>} A promise of the update IPFS gateway domain
|
||||
*/
|
||||
setIpfsGateway (domain) {
|
||||
this.store.updateState({ ipfsGateway: domain })
|
||||
return Promise.resolve(domain)
|
||||
}
|
||||
|
||||
//
|
||||
// PRIVATE METHODS
|
||||
//
|
||||
|
@ -32,8 +32,13 @@ async function resolveEnsToIpfsContentId ({ provider, name }) {
|
||||
if (isEIP1577Compliant[0]) {
|
||||
const contentLookupResult = await Resolver.contenthash(hash)
|
||||
const rawContentHash = contentLookupResult[0]
|
||||
const decodedContentHash = contentHash.decode(rawContentHash)
|
||||
let decodedContentHash = contentHash.decode(rawContentHash)
|
||||
const type = contentHash.getCodec(rawContentHash)
|
||||
|
||||
if (type === 'ipfs-ns') {
|
||||
decodedContentHash = contentHash.helpers.cidV0ToV1Base32(decodedContentHash)
|
||||
}
|
||||
|
||||
return { type: type, hash: decodedContentHash }
|
||||
}
|
||||
if (isLegacyResolver[0]) {
|
||||
|
@ -6,7 +6,7 @@ const supportedTopLevelDomains = ['eth']
|
||||
|
||||
module.exports = setupEnsIpfsResolver
|
||||
|
||||
function setupEnsIpfsResolver ({ provider }) {
|
||||
function setupEnsIpfsResolver ({ provider, getIpfsGateway }) {
|
||||
|
||||
// install listener
|
||||
const urlPatterns = supportedTopLevelDomains.map(tld => `*://*.${tld}/*`)
|
||||
@ -40,12 +40,13 @@ function setupEnsIpfsResolver ({ provider }) {
|
||||
}
|
||||
|
||||
async function attemptResolve ({ tabId, name, path, search, fragment }) {
|
||||
const ipfsGateway = getIpfsGateway()
|
||||
extension.tabs.update(tabId, { url: `loading.html` })
|
||||
let url = `https://app.ens.domains/name/${name}`
|
||||
try {
|
||||
const { type, hash } = await resolveEnsToIpfsContentId({ provider, name })
|
||||
if (type === 'ipfs-ns') {
|
||||
const resolvedUrl = `https://gateway.ipfs.io/ipfs/${hash}${path}${search || ''}${fragment || ''}`
|
||||
const resolvedUrl = `https://${hash}.${ipfsGateway}${path}${search || ''}${fragment || ''}`
|
||||
try {
|
||||
// check if ipfs gateway has result
|
||||
const response = await fetch(resolvedUrl, { method: 'HEAD' })
|
||||
|
@ -439,6 +439,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
setCurrentCurrency: this.setCurrentCurrency.bind(this),
|
||||
setUseBlockie: this.setUseBlockie.bind(this),
|
||||
setUseNonceField: this.setUseNonceField.bind(this),
|
||||
setIpfsGateway: this.setIpfsGateway.bind(this),
|
||||
setParticipateInMetaMetrics: this.setParticipateInMetaMetrics.bind(this),
|
||||
setMetaMetricsSendCount: this.setMetaMetricsSendCount.bind(this),
|
||||
setFirstTimeFlowType: this.setFirstTimeFlowType.bind(this),
|
||||
@ -1841,6 +1842,20 @@ module.exports = class MetamaskController extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the IPFS gateway to use for ENS content resolution.
|
||||
* @param {string} val - the host of the gateway to set
|
||||
* @param {Function} cb - A callback function called when complete.
|
||||
*/
|
||||
setIpfsGateway (val, cb) {
|
||||
try {
|
||||
this.preferencesController.setIpfsGateway(val)
|
||||
cb(null)
|
||||
} catch (err) {
|
||||
cb(err)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
|
@ -75,7 +75,7 @@
|
||||
"c3": "^0.6.7",
|
||||
"classnames": "^2.2.5",
|
||||
"clone": "^2.1.2",
|
||||
"content-hash": "^2.4.4",
|
||||
"content-hash": "^2.5.0",
|
||||
"copy-to-clipboard": "^3.0.8",
|
||||
"currency-formatter": "^1.4.2",
|
||||
"d3": "^5.7.0",
|
||||
|
@ -31,11 +31,15 @@ export default class AdvancedTab extends PureComponent {
|
||||
threeBoxSyncingAllowed: PropTypes.bool.isRequired,
|
||||
setThreeBoxSyncingPermission: PropTypes.func.isRequired,
|
||||
threeBoxDisabled: PropTypes.bool.isRequired,
|
||||
setIpfsGateway: PropTypes.func.isRequired,
|
||||
ipfsGateway: PropTypes.string.isRequired,
|
||||
}
|
||||
|
||||
state = {
|
||||
autoLogoutTimeLimit: this.props.autoLogoutTimeLimit,
|
||||
logoutTimeError: '',
|
||||
ipfsGateway: this.props.ipfsGateway,
|
||||
ipfsGatewayError: '',
|
||||
}
|
||||
|
||||
renderMobileSync () {
|
||||
@ -354,6 +358,85 @@ export default class AdvancedTab extends PureComponent {
|
||||
)
|
||||
}
|
||||
|
||||
handleIpfsGatewayChange (url) {
|
||||
const { t } = this.context
|
||||
|
||||
this.setState(() => {
|
||||
let ipfsGatewayError = ''
|
||||
|
||||
try {
|
||||
|
||||
const urlObj = new URL(addUrlProtocolPrefix(url))
|
||||
if (!urlObj.host) {
|
||||
throw new Error()
|
||||
}
|
||||
|
||||
// don't allow the use of this gateway
|
||||
if (urlObj.host === 'gateway.ipfs.io') {
|
||||
throw new Error('Forbidden gateway')
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
ipfsGatewayError = (
|
||||
error.message === 'Forbidden gateway'
|
||||
? t('forbiddenIpfsGateway')
|
||||
: t('invalidIpfsGateway')
|
||||
)
|
||||
}
|
||||
|
||||
return {
|
||||
ipfsGateway: url,
|
||||
ipfsGatewayError,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
handleIpfsGatewaySave () {
|
||||
|
||||
const url = new URL(addUrlProtocolPrefix(this.state.ipfsGateway))
|
||||
const host = url.host
|
||||
|
||||
this.props.setIpfsGateway(host)
|
||||
}
|
||||
|
||||
renderIpfsGatewayControl () {
|
||||
const { t } = this.context
|
||||
const { ipfsGatewayError } = this.state
|
||||
|
||||
return (
|
||||
<div className="settings-page__content-row">
|
||||
<div className="settings-page__content-item">
|
||||
<span>{ t('ipfsGateway') }</span>
|
||||
<div className="settings-page__content-description">
|
||||
{ t('ipfsGatewayDescription') }
|
||||
</div>
|
||||
</div>
|
||||
<div className="settings-page__content-item">
|
||||
<div className="settings-page__content-item-col">
|
||||
<TextField
|
||||
type="text"
|
||||
value={this.state.ipfsGateway}
|
||||
onChange={e => this.handleIpfsGatewayChange(e.target.value)}
|
||||
error={ipfsGatewayError}
|
||||
fullWidth
|
||||
margin="dense"
|
||||
/>
|
||||
<Button
|
||||
type="primary"
|
||||
className="settings-tab__rpc-save-button"
|
||||
disabled={Boolean(ipfsGatewayError)}
|
||||
onClick={() => {
|
||||
this.handleIpfsGatewaySave()
|
||||
}}
|
||||
>
|
||||
{ t('save') }
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
renderContent () {
|
||||
const { warning } = this.props
|
||||
|
||||
@ -369,6 +452,7 @@ export default class AdvancedTab extends PureComponent {
|
||||
{ this.renderUseNonceOptIn() }
|
||||
{ this.renderAutoLogoutTimeLimit() }
|
||||
{ this.renderThreeBoxControl() }
|
||||
{ this.renderIpfsGatewayControl() }
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -377,3 +461,12 @@ export default class AdvancedTab extends PureComponent {
|
||||
return this.renderContent()
|
||||
}
|
||||
}
|
||||
|
||||
function addUrlProtocolPrefix (urlString) {
|
||||
if (!urlString.match(
|
||||
/(^http:\/\/)|(^https:\/\/)/
|
||||
)) {
|
||||
return 'https://' + urlString
|
||||
}
|
||||
return urlString
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import {
|
||||
setThreeBoxSyncingPermission,
|
||||
turnThreeBoxSyncingOnAndInitialize,
|
||||
setUseNonceField,
|
||||
setIpfsGateway,
|
||||
} from '../../../store/actions'
|
||||
import { preferencesSelector } from '../../../selectors/selectors'
|
||||
|
||||
@ -24,6 +25,7 @@ export const mapStateToProps = state => {
|
||||
threeBoxSyncingAllowed,
|
||||
threeBoxDisabled,
|
||||
useNonceField,
|
||||
ipfsGateway,
|
||||
} = metamask
|
||||
const { showFiatInTestnets, autoLogoutTimeLimit } = preferencesSelector(state)
|
||||
|
||||
@ -36,6 +38,7 @@ export const mapStateToProps = state => {
|
||||
threeBoxSyncingAllowed,
|
||||
threeBoxDisabled,
|
||||
useNonceField,
|
||||
ipfsGateway,
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,6 +62,9 @@ export const mapDispatchToProps = dispatch => {
|
||||
dispatch(setThreeBoxSyncingPermission(newThreeBoxSyncingState))
|
||||
}
|
||||
},
|
||||
setIpfsGateway: value => {
|
||||
return dispatch(setIpfsGateway(value))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ describe('AdvancedTab Component', () => {
|
||||
}
|
||||
)
|
||||
|
||||
assert.equal(root.find('.settings-page__content-row').length, 9)
|
||||
assert.equal(root.find('.settings-page__content-row').length, 10)
|
||||
})
|
||||
|
||||
it('should update autoLogoutTimeLimit', () => {
|
||||
|
@ -543,3 +543,7 @@ export function getLastConnectedInfo (state) {
|
||||
}, {})
|
||||
return lastConnectedInfoData
|
||||
}
|
||||
|
||||
export function getIpfsGateway (state) {
|
||||
return state.metamask.ipfsGateway
|
||||
}
|
||||
|
@ -304,6 +304,8 @@ const actions = {
|
||||
setUseNonceField,
|
||||
UPDATE_CUSTOM_NONCE: 'UPDATE_CUSTOM_NONCE',
|
||||
updateCustomNonce,
|
||||
SET_IPFS_GATEWAY: 'SET_IPFS_GATEWAY',
|
||||
setIpfsGateway,
|
||||
|
||||
SET_PARTICIPATE_IN_METAMETRICS: 'SET_PARTICIPATE_IN_METAMETRICS',
|
||||
SET_METAMETRICS_SEND_COUNT: 'SET_METAMETRICS_SEND_COUNT',
|
||||
@ -2660,6 +2662,24 @@ function setUseNonceField (val) {
|
||||
}
|
||||
}
|
||||
|
||||
function setIpfsGateway (val) {
|
||||
return (dispatch) => {
|
||||
dispatch(actions.showLoadingIndication())
|
||||
log.debug(`background.setIpfsGateway`)
|
||||
background.setIpfsGateway(val, (err) => {
|
||||
dispatch(actions.hideLoadingIndication())
|
||||
if (err) {
|
||||
return dispatch(actions.displayWarning(err.message))
|
||||
} else {
|
||||
dispatch({
|
||||
type: actions.SET_IPFS_GATEWAY,
|
||||
value: val,
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function updateCurrentLocale (key) {
|
||||
return (dispatch) => {
|
||||
dispatch(actions.showLoadingIndication())
|
||||
|
20
yarn.lock
20
yarn.lock
@ -6826,16 +6826,6 @@ cids@^0.5.3, cids@~0.5.4, cids@~0.5.6:
|
||||
multicodec "~0.5.0"
|
||||
multihashes "~0.4.14"
|
||||
|
||||
cids@^0.6.0:
|
||||
version "0.6.0"
|
||||
resolved "https://registry.yarnpkg.com/cids/-/cids-0.6.0.tgz#0de7056a5246a7c7ebf3134eb4d83b3b8b841a06"
|
||||
integrity sha512-34wuIeiBZOuvBwUuYR4XooVuXUQI2PYU9VmgM2eB3xkSmQYRlv2kh/dIbmGiLY2GuONlGR3lLtYdVkx1G9yXUg==
|
||||
dependencies:
|
||||
class-is "^1.1.0"
|
||||
multibase "~0.6.0"
|
||||
multicodec "~0.5.0"
|
||||
multihashes "~0.4.14"
|
||||
|
||||
cids@^0.7.1, cids@~0.7.0, cids@~0.7.1:
|
||||
version "0.7.1"
|
||||
resolved "https://registry.yarnpkg.com/cids/-/cids-0.7.1.tgz#d8bba49a35a0e82110879b5001abf1039c62347f"
|
||||
@ -7413,12 +7403,12 @@ content-disposition@0.5.3, content-disposition@^0.5.2, content-disposition@~0.5.
|
||||
dependencies:
|
||||
safe-buffer "5.1.2"
|
||||
|
||||
content-hash@^2.4.4:
|
||||
version "2.4.4"
|
||||
resolved "https://registry.yarnpkg.com/content-hash/-/content-hash-2.4.4.tgz#4bec87caecfcff8cf1a37645301cbef4728a083f"
|
||||
integrity sha512-3FaUsqt7VR725pVxe0vIScGI5efmpryIXdVSeXafQ63fb5gRGparAQlAGxTSOiv0yRg7YeliseXuB20ByD1duQ==
|
||||
content-hash@^2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/content-hash/-/content-hash-2.5.0.tgz#6f8a98feec0360f09213e951c69e57c727093e3a"
|
||||
integrity sha512-Opn9YSjQQc3Wst/VPwGTdKcNONuQr4yc0dtvEbV82UGDIsc7dE2bdTz3FpLRxfnuOkHx8y9/94sZ3aytmUQ1HA==
|
||||
dependencies:
|
||||
cids "^0.6.0"
|
||||
cids "^0.7.1"
|
||||
multicodec "^0.5.5"
|
||||
multihashes "^0.4.15"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user