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

support DNSLink for encoding/decoding IPNS contenthash values #849

Closed
NoahZinsmeister opened this issue Jul 13, 2020 · 17 comments
Closed

support DNSLink for encoding/decoding IPNS contenthash values #849

NoahZinsmeister opened this issue Jul 13, 2020 · 17 comments
Assignees

Comments

@NoahZinsmeister
Copy link

NoahZinsmeister commented Jul 13, 2020

hi, as a follow up to #358, i'm reporting what seems to be an issue in the decoding of IPNS contenthash values.

to give an example, my ENS domain noahzinsmeister.eth has an IPNS contenthash of 0xe501017000136e6f61687a696e736d6569737465722e636f6d, which should decode to /ipns/noahzinsmeister.com (i verified this via ethereal ens contenthash get --domain=noahzinsmeister.eth). however, the ENS app incorrectly reports this value as ipns://1Ghg8vPvQZaVn2UkkRqBiXyKCpJY (see screenshot)

Screen Shot 2020-07-13 at 4 51 26 PM

@NoahZinsmeister
Copy link
Author

i traced this as far as the content-hash package, which incorrectly specifies the decoding function for ipns names: https://github.com/pldespaigne/content-hash/blob/master/src/profiles.js#L111. don't have any more time to dig further atm.

@NoahZinsmeister
Copy link
Author

oh, i realized that the issue is probably specifically with contenthashes that use UTF-8 encoding of DNSLink IPNS names, as opposed to ones that use (base58?) identifiers as in https://docs.ipfs.io/concepts/ipns/#example-ipns-setup

@NoahZinsmeister NoahZinsmeister changed the title IPNS contenthash values are incorrectly decoded support DNSLink for encoding/decoding IPNS contenthash values Jul 13, 2020
@NoahZinsmeister NoahZinsmeister changed the title support DNSLink for encoding/decoding IPNS contenthash values support DNSLink for encoding/decoding IPNS contenthash values Jul 13, 2020
@ligi
Copy link

ligi commented Jul 17, 2020

where can I find that ipns://noahzinsmeister.com is a IPNS URL? When I understand https://docs.ipfs.io/how-to/address-ipfs-on-web/ correctly ipns:// must be followed by a cidv1b32 and as far as I see noahzinsmeister.com is not a valid cidv1b32

@NoahZinsmeister
Copy link
Author

details are here! https://docs.ipfs.io/concepts/dnslink/

@ligi
Copy link

ligi commented Jul 17, 2020

Thanks for the info - but cidv1 is still enforced by EIP-1577 as far as I see - how does this fit together? https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1577.md

@makoto
Copy link
Member

makoto commented Jul 17, 2020

Thank you for reporting @NoahZinsmeister.

Looks like 1Ghg8vPvQZaVn2UkkRqBiXyKCpJY is the base58 version and I have to further decode back to string.

I created PR below and will merge into master.

ensdomains/ui#77

I don't know the exact protocol of IPNS so I am tagging @pldespaigne who is the author of content-hash and @lidel from IPFS to seek advice.

@makoto makoto self-assigned this Jul 17, 2020
@NoahZinsmeister
Copy link
Author

NoahZinsmeister commented Jul 17, 2020

@ligi i don't think that's the case, and if it is then it's a failing of EIP-1577

i believe that specifying 0xe5 for IPNS, 0x01 for the CID version (i'm confused by the second instance of 0x01 which appears after the first in all the 1577 examples, but ignoring that for now), 0x70 for dag-pb (not 100% sure what this does), and 0x00 as the identity transformation, followed by the length of the IPNS identifier and (in the case of DNSLink) the identifier itself in utf-8 is enough to satisfy the requirements

@NoahZinsmeister
Copy link
Author

would love for one of the 1577 authors (@decanus or @Arachnid) to chime in here

@ligi
Copy link

ligi commented Jul 17, 2020

m confused by the second instance of 0x01 which appears after the first in all the 1577 examples, but ignoring that for now

AFAIR the second 0x01 you see there is coming from the VarUInt encoding. Was also wondering about this at first but realized it when implementing the decoding in KEthereum

and (in the case of DNSLink) the identifier itself in utf-8 is enough to satisfy the requirements

How can I determine it is DNSLink from the contenthash to know If I need to treat it as utf-8 or base58 without the need to use heuristics?

@NoahZinsmeister
Copy link
Author

NoahZinsmeister commented Jul 17, 2020

AFAIR the second 0x01 you see there is coming from the VarUInt encoding. Was also wondering about this at first but realized it when implementing the decoding in KEthereum

oh, good to know, thanks!

How can I determine it is DNSLink from the contenthash to know If I need to treat it as utf-8 or base58 without the need to use heuristics?

the 0x00 identity transformation (as compared to e.g. 0x12 for sha2-256) is meant to be the hint!

for example, using multihashes, multihashes.encode(Buffer.from('noahzinsmeister.com'), 'identity') produces the multihash of <Buffer 00 13 6e 6f 61 68 7a 69 6e 73 6d 65 69 73 74 65 72 2e 63 6f 6d> i.e. 00136e6f61687a696e736d6569737465722e636f6d. converting to CIDv1 via cids, new CID(1, 'dag-pb', multihashes.encode(Buffer.from('noahzinsmeister.com'), 'identity')) yields a CID whose prefix is <Buffer 01 70 00 13> i.e. 01700013. so, if you see the 0x00 as the multihash function code, the content is utf-8.

@0xc0de4c0ffee
Copy link

How can I determine it is DNSLink from the contenthash to know If I need to treat it as utf-8 or base58 without the need to use heuristics?

Contenthash.prefix for ipfs/Qm.. hash is Uint8[1, 112, 18, 32] for DNSlink it's [1, 112, 0, length]
*[version, dag-pb, sha-256/0, length]

@makoto
Copy link
Member

makoto commented Jul 18, 2020

Hi, the change was deployed last Friday and looks like it's resolving fine.

Screenshot 2020-07-18 at 19 50 34

Let me know if you still encounter any issues. Otherwise I will close this case.

@makoto makoto closed this as completed Jul 18, 2020
@ligi
Copy link

ligi commented Jul 19, 2020

@app.uniswap.org @0xc0de4c0ffee thanks for the clarification!

@lidel
Copy link

lidel commented Jul 20, 2020

Hi folks, apologies for late reply (OoO/afk for the weekend).

On parsing inlined libp2p-keys

1Ghg8vPvQZaVn2UkkRqBiXyKCpJY suggests it is Base58btc string with a multihash of an inlined libp2p-key. One can tell it is inlined because of identity hash. Usually, it means entire pubkey fits inside a multihash (we use it for small keys such as ED25519, which soon will be the default: ipfs/kubo#6916). Here something strange is occurring, looks like something else was inlined.

We've seen various tools naively expect CID everywhere and fail to properly read identity multihash encoded in Base58btc that starts with 1.. because CID spec says v0 has to start with Qm..

To avoid this problem we plan to switch default text output of libp2p-keys in IPFS to CIDv1 in Base36, but until that happens you may need to special-case multihash identifiers starting with 1.. and manually convert them to CIDv1 with libp2p-key codec.

Please avoid mixing cryptographic identifiers with arbitrary text.


Future proofing by defaulting to CIDv1 with explicit libp2p-key codec

CIDv1 with explicit libp2p-key codec is self-describing and ensures the identifier used in IPNS context is properly interpreted by various tools in the ecosystem.

It will save you headache and you won't need to write any custom code for encoding/decoding. Once you persist identifiers as CID, regular libraries such as cids should be enough.

@makoto FYSA go-ipfs 0.7+ will enable users to use ED25519 keys in DNS-safe encoding (base36), so you may want to ensure your parsing is future-proof. Test you code paths with values:

  • multihash in Base58btc: 1Ghg8vPvQZaVn2UkkRqBiXyKCpJY
  • CIDv1B32: bafzaae3on5qwq6tjnzzw2zljon2gk4romnxw2
  • CIDv1B36: k1opjwj8ctksf985esjcx6yq6f35pz2w7ur1

@makoto
Copy link
Member

makoto commented Feb 10, 2021

FYI, ensdomains/content-hash#3 change now this allows the user of dnslink. While it won't stop resolving .eth.link, our app will no longer decode more encode dnslink based contenthash.

@lidel
Copy link

lidel commented Feb 10, 2021

Refusing plain text DNS names in ENS records is a good decision 👍
DNSLink names are not cryptographic identifiers and should not be allowed in ENS.

@lidel
Copy link

lidel commented Feb 10, 2021

I feel we have too many layers here, so I'll try to provide context why only /ipns/{libp2p-key} identifiers should be allowed in in ENS for ipns-ns content paths.

DNSlink is an interop layer based on DNS protocol that enables us to dns_resolve(fooo.eth.link) and get DNS TXT record for fooo.eth with dnslink= a content path:

  • either an immutable /ipfs/{cid} (cryptographic identifier),
  • or a mutable /ipns/{libp2p-key} (IPNS record hash signed via pubkey crypto) which itself can then be safely resolved to /ipfs/{cid}.

In other words, DNSLink is useful as resolution layer in contexts where ENS can't be used natively, but should not be used beyond the ENS border:

  • 💚 DNSLink → ENS → CID
  • 💔 DNSLink → ENS → DNSLink → CID
    • 👉 There is no point in resolving ENS using blockchain, if the resolved value then points at /ipns/example.com (DNS name), because that needs to be resolved over regular DNS.

If one wants to set ENS record once, and avoid paying for updates every time their website content changes, they should use pubkey IPNS paths like /ipns/{libp2p-key} and then update such mutable path to point at a new CID it via ipfs name publish.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants