-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Conversation
53e7b95
to
b9ed2f0
Compare
src/core/ipns/pb/ipnsEntry.js
Outdated
return ipnsEntryProto.decode(marsheled) | ||
}, | ||
validityType: ipnsEntryProto.ValidityType | ||
} |
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.
module.exports = {
create,
marshal : ipnsEntryProto.encode,
unmarshal : ipnsEntryProto.decode,
validityType: ipnsEntryProto.ValidityType
}
src/core/components/name.js
Outdated
const human = require('human-to-milliseconds') | ||
const path = require('../ipns/path') | ||
|
||
const OFFLINE_ERROR = require('../utils').OFFLINE_ERROR |
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.
const { OFFLINE_ERROR } = require('../utils')
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.
Actually, I think it's better to:
const ERRORS = require('../utils')
so when you use it bellow is more meaningful:
return callback(new Error(ERROR.OFFLINE_ERROR))
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.
It is really strange to me that the errors are in a utils.js
file, making those imports really strange. In the future, all errors should be easily accessible from all the project, and we should access them in the same way as @fsdiogo suggested.
src/core/ipns/index.js
Outdated
@@ -0,0 +1,54 @@ | |||
'use strict' | |||
|
|||
const peerId = require('peer-id') |
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.
const { createFromPrivKey } = require('peer-id')
src/core/ipns/validator.js
Outdated
} | ||
|
||
// Validate EOL | ||
const validityDate = Date.parse(validity.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.
consider using https://date-fns.org/
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.
FYI, the only valid time format is RFC3339 with nanosecond precision. That is:
2006-01-02T15:04:05.999999999Z07:00
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.
Note: It's extremely important that you only except strings of this exact form. Not validating this has unfortunate security implications.
This also needs to check the validity type.
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.
I will support milliseconds precision at first here and I added a task to improve the precision to nanosecond later (in the list above).
Basically, JS does not support nanoseconds precision natively and all the libs that I managed to find don't support summing date times with nanosecond precision.
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.
When you say that I must validate if the string has this exact form, you say that it should be compliant with RFC3339, right?
src/core/components/name.js
Outdated
const human = require('human-to-milliseconds') | ||
const path = require('../ipns/path') | ||
|
||
const OFFLINE_ERROR = require('../utils').OFFLINE_ERROR |
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.
Actually, I think it's better to:
const ERRORS = require('../utils')
so when you use it bellow is more meaningful:
return callback(new Error(ERROR.OFFLINE_ERROR))
src/core/components/name.js
Outdated
|
||
// Parse ipfs path value | ||
try { | ||
value = path.parsePath(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.
Note: the value can be any arbitrary path.
src/core/ipns/resolver.js
Outdated
} | ||
|
||
// https://github.com/ipfs/go-ipfs-routing/blob/master/offline/offline.go | ||
resolveLocal (name, publicKey, callback) { |
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.
Eventually, this should be pushed into a non-IPNS specific routing layer.
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.
I had been thinking about the go-ipfs
implementation for the resolver.
For one side, I agree with your approach. That is, you decide which router the IPNS resolver should use, and this router is completely transparent for the IPNS resolver. However, as we are fetching from an offline and local source (datastore), it also seems strange to me to have the OfflineRouter
.
Anyway, I am not sure about where this code should live on. @diasdavid any opinion here?
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.
Basically, it means that we can swap out the router at will. However, given the fact that you're only implementing offline routing, it doesn't really make a difference.
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.
Being a pluggable router is a considerable advantage. But yeah, that's what I thought while putting the resolveLocal
in there.
However, when I integrate the routing I will have to understand if it still makes sense to have the resolveLocal
inside the IPNS layer.
src/core/ipns/validator.js
Outdated
} | ||
|
||
// Validate EOL | ||
const validityDate = Date.parse(validity.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.
Note: It's extremely important that you only except strings of this exact form. Not validating this has unfortunate security implications.
This also needs to check the validity type.
src/core/ipns/validator.js
Outdated
@@ -33,10 +35,12 @@ const verify = (publicKey, entry, callback) => { | |||
} | |||
|
|||
// Validate EOL | |||
const validityDate = Date.parse(validity.toString()) | |||
if (validityType === IpnsEntry.validityType.EOL) { |
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 should fail by default if we can't validate the record.
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.
src/core/ipns/validator.js
Outdated
@@ -33,10 +35,12 @@ const verify = (publicKey, entry, callback) => { | |||
} | |||
|
|||
// Validate EOL | |||
const validityDate = Date.parse(validity.toString()) | |||
if (validityType === IpnsEntry.validityType.EOL) { | |||
const validityDate = Date.parse(validity.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.
So it doesn't get lost in the buried review comments, this needs to explicitly check the date format.
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.
Once js-ipns
initial implementation PR is merged, I will create an issue in there for tackling this with priority. I have been thinking a lot earlier and reading some stuff about bigint
for js and I think that I reached a way to add the nanoseconds precision here. I also need to find a way to explicitly check the date format according to the RFC 3339
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.
I wouldn't feel comfortable merging this until this is fixed. Unfortunately, due to some mistakes in how we make signatures in IPNS, we rely on precisely validating the date for security.
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.
@Stebalien just added it to js-ipns PR!
@Stebalien why go-ipns and not go-libp2p-ipns? Did I miss any important convo? |
As far as I know, IPNS falls under the umbrella of IPFS, not libp2p. |
I see IPNS as a different piece than IPFS and libp2p. But as we don't have an IPNS umbrella, I don't know which would suit best here. By the way @Stebalien and @diasdavid , if one day we decide to completely move IPNS (publish, resolve) to a new repo, this repo should be called |
I know that there is no spec, but IPNS has been libp2p all along -- https://github.com/libp2p/specs/blob/master/4-architecture.md#46-naming Anyway. @vasco-santos, don't forget about the interop tests! You should be able to publish stuff with a go daemon and then read it from the repo with a js-ipfs daemon. |
@diasdavid I will change to the Yeah @diasdavid ! I have been testing everything to guarantee the interoperability between both. There are two fields which I am not sure right now, which are the record |
@vasco-santos mind doing a drawing of the IPNS architecture first as you see it so that we clearly sync what are the pieces and their respective names? |
That's a bit odd. I guess one could, e.g., make an IPNS record point to a multiaddr but I still don't feel like it fits in libp2p. It really does feel like a separate thing. I can move it, I just don't want to shuffle things back and forth. As for lang-ipns versus lang-ipns-record: ipfs/go-ipns#1 However, I held off on that as IPNS is record-store independent. That is, I'd almost expect:
|
@Stebalien I would go with that package naming proposal! |
My claim (and others) is that IPNS is just a specialized version of IPRS and that naming is essential piece to Networking and therefore it should be part of libp2p primitives. But you know what, I'll let you paint the bikeshed the color you want as long as we keep making progress here and we having IPNS working locally, over PubSub and DHT as soon as possible :) |
734b4b9
to
77caec1
Compare
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.
All green apart from commitlint! 💚
A working version of IPNS working locally is here! 🚀 😎 💪
Steps:
Some notes, regarding the previous steps:
ttl
, since it is still experimental, we can add it in a separate PR.Finally, thanks @Stebalien for your help and time answering all my questions regarding the IPNS implementation in GO.
Moreover, since there are no specs, and not that much documentation, I have been writing a document with all the IPNS workflow. It is a WIP by now, but it is currently available here.
Related PRs:
interface-ipfs-core
tests for IPNS injs-ipfs