Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ipfs cid v1 base32 #7362

Merged
merged 5 commits into from
Dec 12, 2019
Merged
Show file tree
Hide file tree
Changes from 4 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
13 changes: 11 additions & 2 deletions app/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,15 @@
"invalidSeedPhrase": {
"message": "Invalid seed phrase"
},
"ipfsGateway": {
"message": "IPFS Gateway"
},
"ipfsGatewayDescription": {
"message": "Enter the URL of the ipfs gateway to use for ENS content resolution"
rekmarks marked this conversation as resolved.
Show resolved Hide resolved
},
"invalidIpfsGateway": {
"message": "Invalid IPFS Gateway : the value must be a valid URL"
},
"jsonFile": {
"message": "JSON File",
"description": "format for importing an account"
Expand Down Expand Up @@ -1336,7 +1345,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"
Expand All @@ -1360,7 +1369,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"
Expand Down
9 changes: 9 additions & 0 deletions app/_locales/fr/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,15 @@
"invalidSeedPhrase": {
"message": "Phrase Seed invalide"
},
"ipfsGateway": {
"message": "IPFS Gateway"
},
"ipfsGatewayDescription": {
"message": "Entrez l'URL de la gateway IPFS à utiliser pour résoudre les contenus ENS"
},
"invalidIpfsGateway": {
"message": "IPFS Gateway Invalide : la valeur doit être une URL valide"
},
"jsonFile": {
"message": "Fichier JSON",
"description": "format for importing an account"
Expand Down
6 changes: 4 additions & 2 deletions app/scripts/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down
21 changes: 21 additions & 0 deletions app/scripts/controllers/preferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ class PreferencesController {
completedOnboarding: false,
metaMetricsId: null,
metaMetricsSendCount: 0,

// ENS decentralized website resolution
ipfsGateway: 'ipfs.dweb.link',
rekmarks marked this conversation as resolved.
Show resolved Hide resolved
}, opts.initState)

this.diagnostics = opts.diagnostics
Expand Down Expand Up @@ -647,6 +650,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
//
Expand Down
7 changes: 6 additions & 1 deletion app/scripts/lib/ens-ipfs/resolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -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]) {
Expand Down
5 changes: 3 additions & 2 deletions app/scripts/lib/ens-ipfs/setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -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}/*`)
Expand Down Expand Up @@ -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 || ''}`
rekmarks marked this conversation as resolved.
Show resolved Hide resolved
try {
// check if ipfs gateway has result
const response = await fetch(resolvedUrl, { method: 'HEAD' })
Expand Down
15 changes: 15 additions & 0 deletions app/scripts/metamask-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
73 changes: 73 additions & 0 deletions ui/app/pages/settings/advanced-tab/advanced-tab.component.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: `https://${this.props.ipfsGateway}`,
rekmarks marked this conversation as resolved.
Show resolved Hide resolved
ipfsGatewayError: '',
}

renderMobileSync () {
Expand Down Expand Up @@ -351,6 +355,74 @@ export default class AdvancedTab extends PureComponent {
)
}

handleIpfsGatewayChange (url) {
const { t } = this.context

this.setState(() => {
let ipfsGatewayError = ''

try {
const urlObj = new URL(url) // check if is valid url
if (!urlObj.host) {
throw new Error('invalid url : no host')
rekmarks marked this conversation as resolved.
Show resolved Hide resolved
}
} catch (error) {
ipfsGatewayError = t('invalidIpfsGateway')
}

return {
ipfsGateway: url,
ipfsGatewayError,
}
})
}

handleIpfsGatewaySave () {
const url = new URL(this.state.ipfsGateway)
const host = url.host
this.props.setIpfsGateway(host)
}

renderIpfsGatewayControl () {
const { t } = this.context
const { ipfsGatewayError } = this.state
const { ipfsGateway } = this.props

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}
defaultValue={ipfsGateway}
onChange={e => this.handleIpfsGatewayChange(e.target.value)}
error={ipfsGatewayError}
fullWidth
margin="dense"
/>
<Button
type="primary"
className="settings-tab__rpc-save-button"
disabled={ ipfsGatewayError !== '' }
onClick={() => {
this.handleIpfsGatewaySave()
}}
>
{ t('save') }
</Button>
</div>
</div>
</div>
)
}

renderContent () {
const { warning } = this.props

Expand All @@ -366,6 +438,7 @@ export default class AdvancedTab extends PureComponent {
{ this.renderUseNonceOptIn() }
{ this.renderAutoLogoutTimeLimit() }
{ this.renderThreeBoxControl() }
{ this.renderIpfsGatewayControl() }
</div>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
setThreeBoxSyncingPermission,
turnThreeBoxSyncingOnAndInitialize,
setUseNonceField,
setIpfsGateway,
} from '../../../store/actions'
import { preferencesSelector } from '../../../selectors/selectors'

Expand All @@ -24,6 +25,7 @@ export const mapStateToProps = state => {
threeBoxSyncingAllowed,
threeBoxDisabled,
useNonceField,
ipfsGateway,
} = metamask
const { showFiatInTestnets, autoLogoutTimeLimit } = preferencesSelector(state)

Expand All @@ -36,6 +38,7 @@ export const mapStateToProps = state => {
threeBoxSyncingAllowed,
threeBoxDisabled,
useNonceField,
ipfsGateway,
}
}

Expand All @@ -59,6 +62,9 @@ export const mapDispatchToProps = dispatch => {
dispatch(setThreeBoxSyncingPermission(newThreeBoxSyncingState))
}
},
setIpfsGateway: value => {
return dispatch(setIpfsGateway(value))
},
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down
4 changes: 4 additions & 0 deletions ui/app/selectors/selectors.js
Original file line number Diff line number Diff line change
Expand Up @@ -543,3 +543,7 @@ export function getLastConnectedInfo (state) {
}, {})
return lastConnectedInfoData
}

export function getIpfsGateway (state) {
return state.metamask.ipfsGateway
}
19 changes: 19 additions & 0 deletions ui/app/store/actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -2660,6 +2662,23 @@ 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))
}
})
dispatch({
rekmarks marked this conversation as resolved.
Show resolved Hide resolved
type: actions.SET_IPFS_GATEWAY,
value: val,
})
}
}

function updateCurrentLocale (key) {
return (dispatch) => {
dispatch(actions.showLoadingIndication())
Expand Down
20 changes: 5 additions & 15 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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"

Expand Down