This repository has been archived by the owner on Feb 12, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
Copy pathname.js
168 lines (139 loc) · 5.29 KB
/
name.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
'use strict'
const debug = require('debug')
const promisify = require('promisify-es6')
const waterfall = require('async/waterfall')
const parallel = require('async/parallel')
const human = require('human-to-milliseconds')
const crypto = require('libp2p-crypto')
const errcode = require('err-code')
const log = debug('ipfs:name')
log.error = debug('ipfs:name:error')
const namePubsub = require('./name-pubsub')
const utils = require('../utils')
const path = require('../ipns/path')
const keyLookup = (ipfsNode, kname, callback) => {
if (kname === 'self') {
return callback(null, ipfsNode._peerInfo.id.privKey)
}
const pass = ipfsNode._options.pass
waterfall([
(cb) => ipfsNode._keychain.exportKey(kname, pass, cb),
(pem, cb) => crypto.keys.import(pem, pass, cb)
], (err, privateKey) => {
if (err) {
log.error(err)
return callback(errcode(err, 'ERR_CANNOT_GET_KEY'))
}
return callback(null, privateKey)
})
}
module.exports = function name (self) {
return {
/**
* IPNS is a PKI namespace, where names are the hashes of public keys, and
* the private key enables publishing new (signed) values. In both publish
* and resolve, the default name used is the node's own PeerID,
* which is the hash of its public key.
*
* @param {String} value ipfs path of the object to be published.
* @param {Object} options ipfs publish options.
* @param {boolean} options.resolve resolve given path before publishing.
* @param {String} options.lifetime time duration that the record will be valid for.
This accepts durations such as "300s", "1.5h" or "2h45m". Valid time units are
"ns", "ms", "s", "m", "h". Default is 24h.
* @param {String} options.ttl time duration this record should be cached for (NOT IMPLEMENTED YET).
* This accepts durations such as "300s", "1.5h" or "2h45m". Valid time units are
"ns", "ms", "s", "m", "h" (caution: experimental).
* @param {String} options.key name of the key to be used or a valid PeerID, as listed by 'ipfs key list -l'.
* @param {function(Error)} [callback]
* @returns {Promise|void}
*/
publish: promisify((value, options, callback) => {
if (typeof options === 'function') {
callback = options
options = {}
}
options = options || {}
const resolve = !(options.resolve === false)
const lifetime = options.lifetime || '24h'
const key = options.key || 'self'
if (!self.isOnline()) {
const errMsg = utils.OFFLINE_ERROR
log.error(errMsg)
return callback(errcode(errMsg, 'OFFLINE_ERROR'))
}
// TODO: params related logic should be in the core implementation
// Normalize path value
try {
value = utils.normalizePath(value)
} catch (err) {
log.error(err)
return callback(err)
}
parallel([
(cb) => human(lifetime, cb),
// (cb) => ttl ? human(ttl, cb) : cb(),
(cb) => keyLookup(self, key, cb),
// verify if the path exists, if not, an error will stop the execution
(cb) => resolve.toString() === 'true' ? path.resolvePath(self, value, cb) : cb()
], (err, results) => {
if (err) {
log.error(err)
return callback(err)
}
// Calculate lifetime with nanoseconds precision
const pubLifetime = results[0].toFixed(6)
const privateKey = results[1]
// TODO IMPROVEMENT - Handle ttl for cache
// const ttl = results[1]
// const privateKey = results[2]
// Start publishing process
self._ipns.publish(privateKey, value, pubLifetime, callback)
})
}),
/**
* Given a key, query the DHT for its best value.
*
* @param {String} name ipns name to resolve. Defaults to your node's peerID.
* @param {Object} options ipfs resolve options.
* @param {boolean} options.nocache do not use cached entries.
* @param {boolean} options.recursive resolve until the result is not an IPNS name.
* @param {function(Error)} [callback]
* @returns {Promise|void}
*/
resolve: promisify((name, options, callback) => {
if (typeof options === 'function') {
callback = options
options = {}
}
options = options || {}
const nocache = options.nocache && options.nocache.toString() === 'true'
const recursive = options.recursive && options.recursive.toString() === 'true'
const offline = self._options.offline
if (!self.isOnline() && !offline) {
const errMsg = utils.OFFLINE_ERROR
log.error(errMsg)
return callback(errcode(errMsg, 'OFFLINE_ERROR'))
}
// TODO: params related logic should be in the core implementation
if (offline && nocache) {
const error = 'cannot specify both offline and nocache'
log.error(error)
return callback(errcode(new Error(error), 'ERR_NOCACHE_AND_OFFLINE'))
}
// Set node id as name for being resolved, if it is not received
if (!name) {
name = self._peerInfo.id.toB58String()
}
if (!name.startsWith('/ipns/')) {
name = `/ipns/${name}`
}
const resolveOptions = {
nocache,
recursive
}
self._ipns.resolve(name, resolveOptions, callback)
}),
pubsub: namePubsub(self)
}
}