-
Notifications
You must be signed in to change notification settings - Fork 25
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
fix!: only accept CIDs, PeerIds or strings as values #255
Conversation
This module has accepted `Uint8Array`s as values to store in IPNS records which means it has been mis-used to create records with raw CID bytes. To ensure this doesn't happen in future, accept only CIDs, PeerIds or arbitrary path strings prefixed with `"/"`.
@hacdias @lidel what do you think to tightening up the inputs here, since #234 is a breaking change. I think this module has only ever accepted *= the reason is probably because the protobuf definition has |
@achingbrain I do like the idea. I'm just concerned about the corner case where a CID is actually a libp2p-key encoded Peer ID. Then we'd be generating a |
No, but it sounds like an edge case we can just handle. I'd love to get to the point where we can just treat these values as opaque and the module would just do the right thing rather than the user having to know that some types have to be encoded some ways and other types have to be encoded other ways. |
FWIW Kubo doesn't seem to handle this edge case - trying to publish a peer ID encoded as a CID gives |
src/utils.ts
Outdated
* Normalizes the given record value. It ensures it is a PeerID, a CID or a | ||
* string starting with '/'. PeerIDs become `/ipns/${peerId}`, CIDs become | ||
* `/ipfs/${cidAsV1}`. | ||
*/ | ||
export const normalizeValue = (value: string | Uint8Array): string => { | ||
const str = typeof value === 'string' ? value : uint8ArrayToString(value) | ||
export const normalizeValue = (value?: CID | PeerId | string | Uint8Array): string => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: iirc we try to do opposite and want to remove use of PeerIDs in IPNS context, as it causes bugs where someone tries to parse 12..
one as CID (example) .
In various places we've been normalizing to CIDv1 with libp2p-key and base36 (this way it looks the same on subdomains, and implementers only need to support CIDs, which is more robust for interop).
@achingbrain would it be ok to switch /ipns/
paths to use CIDv1 with libp2p-key? (base does not matter as much as CIDv1)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we try to do opposite and want to remove use of PeerIDs in IPNS context
What I really want to do here is take a PeerID
and do the right thing, rather than relying on users to know what the right thing to do is.
it causes bugs where someone tries to parse 12.. one as CID (example) .
Do you mean people are extracting 12foo
out of /ipns/12foo
and trying to decode it as a CID
? Seems like user error rather than a bug if so.
would it be ok to switch /ipns/ paths to use CIDv1 with libp2p-key?
Do you mean accept a PeerId
and output "/ipns/base32-encoded-libp2p-key-cid"
?
Maybe outputting "/ipfs/base32-encoded-libp2p-key-cid"
would be better? Will Kubo resolve IPNS values like this recursively?
Then {thing}
in /ipns/{thing}
is always a base58btc encoded PeerID
and {thing}
in /ipfs/{thing}
is always a CID
(which could be a libp2p-key
)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@achingbrain I think the goal moving forward into the future is to always refer to /ipns/{libp2p-encoded-cid}
and not as a base56btc: https://specs.ipfs.tech/ipns/ipns-record/#string-representation, including on the gateway.
The current gateway implementation does the redirect even.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, as long as we're fine with it being /ipns/{maybe-CID,maybe-base58btcpeerid}
I guess?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@achingbrain sgtm, pushed jsdoc update to reflect that its cidV1.
See comment inline about also testing against static vectors from ipfs/gateway-conformance#157
it('should fail to normalize path value that is too short', async () => { | ||
const inputValue = '/' | ||
|
||
await expect(ipns.create(peerId, inputValue, 0, 1000000)).to.eventually.be.rejected | ||
.with.property('code', ERRORS.ERR_INVALID_VALUE) | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ℹ️ sgtm, forces people to provide value under a meaningful namespace 👍
// if we have a CID, turn it into an ipfs path | ||
const cid = CID.asCID(value) | ||
if (cid != null) { | ||
// PeerID encoded as a CID | ||
if (cid.code === LIBP2P_CID_CODEC) { | ||
return `/ipns/${cid.toString(base36)}` | ||
} | ||
|
||
return `/ipfs/${cid.toV1().toString()}` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ℹ️ good quality of life improvement, thanks 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💭 slight concern is that (iiuc) we are generating test vectors on the fly using JS functions from src/utils.ts
, and if we change JS code at any point in the future, we may not catch regression until there is a hiccup somewhere in production when interacting with other implementation.
@achingbrain thoughts on including tests against binary fixtures /fixtures/ipns_records/*.ipns-record
in
ipfs/gateway-conformance#157? This will be a solid way to ensure interop with GO and any other languages. We could do it in follow-up PR but
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good!
This module has accepted
Uint8Array
s as values to store in IPNSrecords which means it has been mis-used to create records with
raw CID bytes.
To ensure this doesn't happen in future, accept only CIDs, PeerIds
or arbitrary path strings prefixed with
"/"
.