@libp2p/peer-record 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/LICENSE +4 -0
  2. package/README.md +179 -0
  3. package/dist/src/envelope/envelope.d.ts +77 -0
  4. package/dist/src/envelope/envelope.js +241 -0
  5. package/dist/src/envelope/index.d.ts +47 -0
  6. package/dist/src/envelope/index.d.ts.map +1 -0
  7. package/dist/src/envelope/index.js +126 -0
  8. package/dist/src/envelope/index.js.map +1 -0
  9. package/dist/src/errors.d.ts +4 -0
  10. package/dist/src/errors.d.ts.map +1 -0
  11. package/dist/src/errors.js +4 -0
  12. package/dist/src/errors.js.map +1 -0
  13. package/dist/src/index.d.ts +3 -0
  14. package/dist/src/index.d.ts.map +1 -0
  15. package/dist/src/index.js +3 -0
  16. package/dist/src/index.js.map +1 -0
  17. package/dist/src/peer-record/consts.d.ts +3 -0
  18. package/dist/src/peer-record/consts.d.ts.map +1 -0
  19. package/dist/src/peer-record/consts.js +7 -0
  20. package/dist/src/peer-record/consts.js.map +1 -0
  21. package/dist/src/peer-record/index.d.ts +44 -0
  22. package/dist/src/peer-record/index.d.ts.map +1 -0
  23. package/dist/src/peer-record/index.js +71 -0
  24. package/dist/src/peer-record/index.js.map +1 -0
  25. package/dist/src/peer-record/peer-record.d.ts +133 -0
  26. package/dist/src/peer-record/peer-record.js +365 -0
  27. package/package.json +164 -0
  28. package/src/envelope/envelope.d.ts +77 -0
  29. package/src/envelope/envelope.js +241 -0
  30. package/src/envelope/envelope.proto +19 -0
  31. package/src/envelope/index.ts +159 -0
  32. package/src/errors.ts +4 -0
  33. package/src/index.ts +3 -0
  34. package/src/peer-record/consts.js +9 -0
  35. package/src/peer-record/index.ts +104 -0
  36. package/src/peer-record/peer-record.d.ts +133 -0
  37. package/src/peer-record/peer-record.js +365 -0
  38. package/src/peer-record/peer-record.proto +18 -0
package/LICENSE ADDED
@@ -0,0 +1,4 @@
1
+ This project is dual licensed under MIT and Apache-2.0.
2
+
3
+ MIT: https://www.opensource.org/licenses/mit
4
+ Apache-2.0: https://www.apache.org/licenses/license-2.0
package/README.md ADDED
@@ -0,0 +1,179 @@
1
+ # libp2p-peer-record <!-- omit in toc -->
2
+
3
+ > Peer records are signed records that contain the address information of network peers
4
+
5
+ ## Table of Contents <!-- omit in toc -->
6
+
7
+ - [Description](#description)
8
+ - [Envelope](#envelope)
9
+ - [Usage](#usage)
10
+ - [Peer Record](#peer-record)
11
+ - [Usage](#usage-1)
12
+ - [Libp2p Flows](#libp2p-flows)
13
+ - [Self Record](#self-record)
14
+ - [Self record Updates](#self-record-updates)
15
+ - [Subsystem receiving a record](#subsystem-receiving-a-record)
16
+ - [Subsystem providing a record](#subsystem-providing-a-record)
17
+ - [Future Work](#future-work)
18
+ - [Example](#example)
19
+ - [Installation](#installation)
20
+ - [License](#license)
21
+ - [Contribution](#contribution)
22
+
23
+ ## Description
24
+
25
+ Libp2p nodes need to store data in a public location (e.g. a DHT), or rely on potentially untrustworthy intermediaries to relay information over its lifetime. Accordingly, libp2p nodes need to be able to verify that the data came from a specific peer and that it hasn't been tampered with.
26
+
27
+ ### Envelope
28
+
29
+ Libp2p provides an all-purpose data container called **envelope**. It was created to enable the distribution of verifiable records, which we can prove originated from the addressed peer itself. The envelope includes a signature of the data, so that its authenticity is verified.
30
+
31
+ This envelope stores a marshaled record implementing the [interface-record](https://github.com/libp2p/js-libp2p-interfaces/tree/master/src/record). These Records are designed to be serialized to bytes and placed inside of the envelopes before being shared with other peers.
32
+
33
+ You can read further about the envelope in [libp2p/specs#217](https://github.com/libp2p/specs/pull/217).
34
+
35
+ ## Usage
36
+
37
+ - create an envelope with an instance of an [interface-record](https://github.com/libp2p/js-libp2p-interfaces/tree/master/src/record) implementation and prepare it for being exchanged:
38
+
39
+ ```js
40
+ // interface-record implementation example with the "libp2p-example" namespace
41
+ const Record = require('libp2p-interfaces/src/record')
42
+ const { fromString } = require('uint8arrays/from-string')
43
+
44
+ class ExampleRecord extends Record {
45
+ constructor () {
46
+ super ('libp2p-example', fromString('0302', 'hex'))
47
+ }
48
+
49
+ marshal () {}
50
+
51
+ equals (other) {}
52
+ }
53
+
54
+ ExampleRecord.createFromProtobuf = () => {}
55
+ ```
56
+
57
+ ```js
58
+ const Envelope = require('libp2p/src/record/envelop')
59
+ const ExampleRecord = require('./example-record')
60
+
61
+ const rec = new ExampleRecord()
62
+ const e = await Envelope.seal(rec, peerId)
63
+ const wireData = e.marshal()
64
+ ```
65
+
66
+ - consume a received envelope (`wireData`) and transform it back to a record:
67
+
68
+ ```js
69
+ const Envelope = require('libp2p/src/record/envelop')
70
+ const ExampleRecord = require('./example-record')
71
+
72
+ const domain = 'libp2p-example'
73
+ let e
74
+
75
+ try {
76
+ e = await Envelope.openAndCertify(wireData, domain)
77
+ } catch (err) {}
78
+
79
+ const rec = ExampleRecord.createFromProtobuf(e.payload)
80
+ ```
81
+
82
+ ## Peer Record
83
+
84
+ All libp2p nodes keep a `PeerStore`, that among other information stores a set of known addresses for each peer, which can come from a variety of sources.
85
+
86
+ Libp2p peer records were created to enable the distribution of verifiable address records, which we can prove originated from the addressed peer itself. With such guarantees, libp2p is able to prioritize addresses based on their authenticity, with the most strict strategy being to only dial certified addresses (no strategies have been implemented at the time of writing).
87
+
88
+ A peer record contains the peers' publicly reachable listen addresses, and may be extended in the future to contain additional metadata relevant to routing. It also contains a `seqNumber` field, a timestamp per the spec, so that we can verify the most recent record.
89
+
90
+ You can read further about the Peer Record in [libp2p/specs#217](https://github.com/libp2p/specs/pull/217).
91
+
92
+ ### Usage
93
+
94
+ - create a new Peer Record
95
+
96
+ ```js
97
+ const PeerRecord = require('libp2p/src/record/peer-record')
98
+
99
+ const pr = new PeerRecord({
100
+ peerId: node.peerId,
101
+ multiaddrs: node.multiaddrs
102
+ })
103
+ ```
104
+
105
+ - create a Peer Record from a protobuf
106
+
107
+ ```js
108
+ const PeerRecord = require('libp2p/src/record/peer-record')
109
+
110
+ const pr = PeerRecord.createFromProtobuf(data)
111
+ ```
112
+
113
+ ### Libp2p Flows
114
+
115
+ #### Self Record
116
+
117
+ Once a libp2p node has started and is listening on a set of multiaddrs, its own peer record can be created.
118
+
119
+ The identify service is responsible for creating the self record when the identify protocol kicks in for the first time. This record will be stored for future needs of the identify protocol when connecting with other peers.
120
+
121
+ #### Self record Updates
122
+
123
+ **_NOT_YET_IMPLEMENTED_**
124
+
125
+ While creating peer records is fairly trivial, addresses are not static and might be modified at arbitrary times. This can happen via an Address Manager API, or even through AutoRelay/AutoNAT.
126
+
127
+ When a libp2p node changes its listen addresses, the identify service will be informed. Once that happens, the identify service creates a new self record and stores it. With the new record, the identify push/delta protocol will be used to communicate this change to the connected peers.
128
+
129
+ #### Subsystem receiving a record
130
+
131
+ Considering that a node can discover other peers' addresses from a variety of sources, Libp2p Peerstore can differentiate the addresses that were obtained through a signed peer record.
132
+
133
+ Once a record is received and its signature properly validated, its envelope is stored in the AddressBook in its byte representation. The `seqNumber` remains unmarshalled so that we can quickly compare it against incoming records to determine the most recent record.
134
+
135
+ The AddressBook Addresses will be updated with the content of the envelope with a certified property. This allows other subsystems to identify the known certified addresses of a peer.
136
+
137
+ #### Subsystem providing a record
138
+
139
+ Libp2p subsystems that exchange other peers information will provide the envelope that they received by those peers. As a result, other peers can verify if the envelope was really created by the addressed peer.
140
+
141
+ When a subsystem wants to provide a record, it will get it from the AddressBook, if it exists. Other subsystems are also able to provide the self record, since it is also stored in the AddressBook.
142
+
143
+ ### Future Work
144
+
145
+ - Persistence only considering certified addresses?
146
+ - Peers may not know their own addresses. It's often impossible to automatically infer one's own public address, and peers may need to rely on third party peers to inform them of their observed public addresses.
147
+ - A peer may inadvertently or maliciously sign an address that they do not control. In other words, a signature isn't a guarantee that a given address is valid.
148
+ - Some addresses may be ambiguous. For example, addresses on a private subnet are valid within that subnet but are useless on the public internet.
149
+ - Once all these pieces are in place, we will also need a way to prioritize addresses based on their authenticity, that is, the dialer can prioritize self-certified addresses over addresses from an unknown origin.
150
+ - Modular dialer? (taken from go PR notes)
151
+ - With the modular dialer, users should easily be able to configure precedence. With dialer v1, anything we do to prioritise dials is gonna be spaghetti and adhoc. With the modular dialer, you’d be able to specify the order of dials when instantiating the pipeline.
152
+ - Multiple parallel dials. We already have the issue where new addresses aren't added to existing dials.
153
+
154
+ ## Example
155
+
156
+ ```JavaScript
157
+ import { trackedMap } from '@libp2p/tracked-map'
158
+
159
+ const map = trackedMap<string, string>({ metrics })
160
+
161
+ map.set('key', 'value')
162
+ ```
163
+
164
+ ## Installation
165
+
166
+ ```console
167
+ $ npm i @libp2p/peer-record
168
+ ```
169
+
170
+ ## License
171
+
172
+ Licensed under either of
173
+
174
+ * Apache 2.0, ([LICENSE-APACHE](LICENSE-APACHE) / http://www.apache.org/licenses/LICENSE-2.0)
175
+ * MIT ([LICENSE-MIT](LICENSE-MIT) / http://opensource.org/licenses/MIT)
176
+
177
+ ### Contribution
178
+
179
+ Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
@@ -0,0 +1,77 @@
1
+ import * as $protobuf from "protobufjs";
2
+ /** Properties of an Envelope. */
3
+ export interface IEnvelope {
4
+
5
+ /** Envelope publicKey */
6
+ publicKey?: (Uint8Array|null);
7
+
8
+ /** Envelope payloadType */
9
+ payloadType?: (Uint8Array|null);
10
+
11
+ /** Envelope payload */
12
+ payload?: (Uint8Array|null);
13
+
14
+ /** Envelope signature */
15
+ signature?: (Uint8Array|null);
16
+ }
17
+
18
+ /** Represents an Envelope. */
19
+ export class Envelope implements IEnvelope {
20
+
21
+ /**
22
+ * Constructs a new Envelope.
23
+ * @param [p] Properties to set
24
+ */
25
+ constructor(p?: IEnvelope);
26
+
27
+ /** Envelope publicKey. */
28
+ public publicKey: Uint8Array;
29
+
30
+ /** Envelope payloadType. */
31
+ public payloadType: Uint8Array;
32
+
33
+ /** Envelope payload. */
34
+ public payload: Uint8Array;
35
+
36
+ /** Envelope signature. */
37
+ public signature: Uint8Array;
38
+
39
+ /**
40
+ * Encodes the specified Envelope message. Does not implicitly {@link Envelope.verify|verify} messages.
41
+ * @param m Envelope message or plain object to encode
42
+ * @param [w] Writer to encode to
43
+ * @returns Writer
44
+ */
45
+ public static encode(m: IEnvelope, w?: $protobuf.Writer): $protobuf.Writer;
46
+
47
+ /**
48
+ * Decodes an Envelope message from the specified reader or buffer.
49
+ * @param r Reader or buffer to decode from
50
+ * @param [l] Message length if known beforehand
51
+ * @returns Envelope
52
+ * @throws {Error} If the payload is not a reader or valid buffer
53
+ * @throws {$protobuf.util.ProtocolError} If required fields are missing
54
+ */
55
+ public static decode(r: ($protobuf.Reader|Uint8Array), l?: number): Envelope;
56
+
57
+ /**
58
+ * Creates an Envelope message from a plain object. Also converts values to their respective internal types.
59
+ * @param d Plain object
60
+ * @returns Envelope
61
+ */
62
+ public static fromObject(d: { [k: string]: any }): Envelope;
63
+
64
+ /**
65
+ * Creates a plain object from an Envelope message. Also converts values to other types if specified.
66
+ * @param m Envelope
67
+ * @param [o] Conversion options
68
+ * @returns Plain object
69
+ */
70
+ public static toObject(m: Envelope, o?: $protobuf.IConversionOptions): { [k: string]: any };
71
+
72
+ /**
73
+ * Converts this Envelope to JSON.
74
+ * @returns JSON object
75
+ */
76
+ public toJSON(): { [k: string]: any };
77
+ }
@@ -0,0 +1,241 @@
1
+ /*eslint-disable*/
2
+ import $protobuf from "protobufjs/minimal.js";
3
+
4
+ // Common aliases
5
+ const $Reader = $protobuf.Reader, $Writer = $protobuf.Writer, $util = $protobuf.util;
6
+
7
+ // Exported root namespace
8
+ const $root = $protobuf.roots["libp2p-peer-record-envelope"] || ($protobuf.roots["libp2p-peer-record-envelope"] = {});
9
+
10
+ export const Envelope = $root.Envelope = (() => {
11
+
12
+ /**
13
+ * Properties of an Envelope.
14
+ * @exports IEnvelope
15
+ * @interface IEnvelope
16
+ * @property {Uint8Array|null} [publicKey] Envelope publicKey
17
+ * @property {Uint8Array|null} [payloadType] Envelope payloadType
18
+ * @property {Uint8Array|null} [payload] Envelope payload
19
+ * @property {Uint8Array|null} [signature] Envelope signature
20
+ */
21
+
22
+ /**
23
+ * Constructs a new Envelope.
24
+ * @exports Envelope
25
+ * @classdesc Represents an Envelope.
26
+ * @implements IEnvelope
27
+ * @constructor
28
+ * @param {IEnvelope=} [p] Properties to set
29
+ */
30
+ function Envelope(p) {
31
+ if (p)
32
+ for (var ks = Object.keys(p), i = 0; i < ks.length; ++i)
33
+ if (p[ks[i]] != null)
34
+ this[ks[i]] = p[ks[i]];
35
+ }
36
+
37
+ /**
38
+ * Envelope publicKey.
39
+ * @member {Uint8Array} publicKey
40
+ * @memberof Envelope
41
+ * @instance
42
+ */
43
+ Envelope.prototype.publicKey = $util.newBuffer([]);
44
+
45
+ /**
46
+ * Envelope payloadType.
47
+ * @member {Uint8Array} payloadType
48
+ * @memberof Envelope
49
+ * @instance
50
+ */
51
+ Envelope.prototype.payloadType = $util.newBuffer([]);
52
+
53
+ /**
54
+ * Envelope payload.
55
+ * @member {Uint8Array} payload
56
+ * @memberof Envelope
57
+ * @instance
58
+ */
59
+ Envelope.prototype.payload = $util.newBuffer([]);
60
+
61
+ /**
62
+ * Envelope signature.
63
+ * @member {Uint8Array} signature
64
+ * @memberof Envelope
65
+ * @instance
66
+ */
67
+ Envelope.prototype.signature = $util.newBuffer([]);
68
+
69
+ /**
70
+ * Encodes the specified Envelope message. Does not implicitly {@link Envelope.verify|verify} messages.
71
+ * @function encode
72
+ * @memberof Envelope
73
+ * @static
74
+ * @param {IEnvelope} m Envelope message or plain object to encode
75
+ * @param {$protobuf.Writer} [w] Writer to encode to
76
+ * @returns {$protobuf.Writer} Writer
77
+ */
78
+ Envelope.encode = function encode(m, w) {
79
+ if (!w)
80
+ w = $Writer.create();
81
+ if (m.publicKey != null && Object.hasOwnProperty.call(m, "publicKey"))
82
+ w.uint32(10).bytes(m.publicKey);
83
+ if (m.payloadType != null && Object.hasOwnProperty.call(m, "payloadType"))
84
+ w.uint32(18).bytes(m.payloadType);
85
+ if (m.payload != null && Object.hasOwnProperty.call(m, "payload"))
86
+ w.uint32(26).bytes(m.payload);
87
+ if (m.signature != null && Object.hasOwnProperty.call(m, "signature"))
88
+ w.uint32(42).bytes(m.signature);
89
+ return w;
90
+ };
91
+
92
+ /**
93
+ * Decodes an Envelope message from the specified reader or buffer.
94
+ * @function decode
95
+ * @memberof Envelope
96
+ * @static
97
+ * @param {$protobuf.Reader|Uint8Array} r Reader or buffer to decode from
98
+ * @param {number} [l] Message length if known beforehand
99
+ * @returns {Envelope} Envelope
100
+ * @throws {Error} If the payload is not a reader or valid buffer
101
+ * @throws {$protobuf.util.ProtocolError} If required fields are missing
102
+ */
103
+ Envelope.decode = function decode(r, l) {
104
+ if (!(r instanceof $Reader))
105
+ r = $Reader.create(r);
106
+ var c = l === undefined ? r.len : r.pos + l, m = new $root.Envelope();
107
+ while (r.pos < c) {
108
+ var t = r.uint32();
109
+ switch (t >>> 3) {
110
+ case 1:
111
+ m.publicKey = r.bytes();
112
+ break;
113
+ case 2:
114
+ m.payloadType = r.bytes();
115
+ break;
116
+ case 3:
117
+ m.payload = r.bytes();
118
+ break;
119
+ case 5:
120
+ m.signature = r.bytes();
121
+ break;
122
+ default:
123
+ r.skipType(t & 7);
124
+ break;
125
+ }
126
+ }
127
+ return m;
128
+ };
129
+
130
+ /**
131
+ * Creates an Envelope message from a plain object. Also converts values to their respective internal types.
132
+ * @function fromObject
133
+ * @memberof Envelope
134
+ * @static
135
+ * @param {Object.<string,*>} d Plain object
136
+ * @returns {Envelope} Envelope
137
+ */
138
+ Envelope.fromObject = function fromObject(d) {
139
+ if (d instanceof $root.Envelope)
140
+ return d;
141
+ var m = new $root.Envelope();
142
+ if (d.publicKey != null) {
143
+ if (typeof d.publicKey === "string")
144
+ $util.base64.decode(d.publicKey, m.publicKey = $util.newBuffer($util.base64.length(d.publicKey)), 0);
145
+ else if (d.publicKey.length)
146
+ m.publicKey = d.publicKey;
147
+ }
148
+ if (d.payloadType != null) {
149
+ if (typeof d.payloadType === "string")
150
+ $util.base64.decode(d.payloadType, m.payloadType = $util.newBuffer($util.base64.length(d.payloadType)), 0);
151
+ else if (d.payloadType.length)
152
+ m.payloadType = d.payloadType;
153
+ }
154
+ if (d.payload != null) {
155
+ if (typeof d.payload === "string")
156
+ $util.base64.decode(d.payload, m.payload = $util.newBuffer($util.base64.length(d.payload)), 0);
157
+ else if (d.payload.length)
158
+ m.payload = d.payload;
159
+ }
160
+ if (d.signature != null) {
161
+ if (typeof d.signature === "string")
162
+ $util.base64.decode(d.signature, m.signature = $util.newBuffer($util.base64.length(d.signature)), 0);
163
+ else if (d.signature.length)
164
+ m.signature = d.signature;
165
+ }
166
+ return m;
167
+ };
168
+
169
+ /**
170
+ * Creates a plain object from an Envelope message. Also converts values to other types if specified.
171
+ * @function toObject
172
+ * @memberof Envelope
173
+ * @static
174
+ * @param {Envelope} m Envelope
175
+ * @param {$protobuf.IConversionOptions} [o] Conversion options
176
+ * @returns {Object.<string,*>} Plain object
177
+ */
178
+ Envelope.toObject = function toObject(m, o) {
179
+ if (!o)
180
+ o = {};
181
+ var d = {};
182
+ if (o.defaults) {
183
+ if (o.bytes === String)
184
+ d.publicKey = "";
185
+ else {
186
+ d.publicKey = [];
187
+ if (o.bytes !== Array)
188
+ d.publicKey = $util.newBuffer(d.publicKey);
189
+ }
190
+ if (o.bytes === String)
191
+ d.payloadType = "";
192
+ else {
193
+ d.payloadType = [];
194
+ if (o.bytes !== Array)
195
+ d.payloadType = $util.newBuffer(d.payloadType);
196
+ }
197
+ if (o.bytes === String)
198
+ d.payload = "";
199
+ else {
200
+ d.payload = [];
201
+ if (o.bytes !== Array)
202
+ d.payload = $util.newBuffer(d.payload);
203
+ }
204
+ if (o.bytes === String)
205
+ d.signature = "";
206
+ else {
207
+ d.signature = [];
208
+ if (o.bytes !== Array)
209
+ d.signature = $util.newBuffer(d.signature);
210
+ }
211
+ }
212
+ if (m.publicKey != null && m.hasOwnProperty("publicKey")) {
213
+ d.publicKey = o.bytes === String ? $util.base64.encode(m.publicKey, 0, m.publicKey.length) : o.bytes === Array ? Array.prototype.slice.call(m.publicKey) : m.publicKey;
214
+ }
215
+ if (m.payloadType != null && m.hasOwnProperty("payloadType")) {
216
+ d.payloadType = o.bytes === String ? $util.base64.encode(m.payloadType, 0, m.payloadType.length) : o.bytes === Array ? Array.prototype.slice.call(m.payloadType) : m.payloadType;
217
+ }
218
+ if (m.payload != null && m.hasOwnProperty("payload")) {
219
+ d.payload = o.bytes === String ? $util.base64.encode(m.payload, 0, m.payload.length) : o.bytes === Array ? Array.prototype.slice.call(m.payload) : m.payload;
220
+ }
221
+ if (m.signature != null && m.hasOwnProperty("signature")) {
222
+ d.signature = o.bytes === String ? $util.base64.encode(m.signature, 0, m.signature.length) : o.bytes === Array ? Array.prototype.slice.call(m.signature) : m.signature;
223
+ }
224
+ return d;
225
+ };
226
+
227
+ /**
228
+ * Converts this Envelope to JSON.
229
+ * @function toJSON
230
+ * @memberof Envelope
231
+ * @instance
232
+ * @returns {Object.<string,*>} JSON object
233
+ */
234
+ Envelope.prototype.toJSON = function toJSON() {
235
+ return this.constructor.toObject(this, $protobuf.util.toJSONOptions);
236
+ };
237
+
238
+ return Envelope;
239
+ })();
240
+
241
+ export { $root as default };
@@ -0,0 +1,47 @@
1
+ import { PeerId } from '@libp2p/peer-id';
2
+ import type { Record, Envelope } from '@libp2p/interfaces/record';
3
+ export interface EnvelopeOptions {
4
+ peerId: PeerId;
5
+ payloadType: Uint8Array;
6
+ payload: Uint8Array;
7
+ signature: Uint8Array;
8
+ }
9
+ export declare class RecordEnvelope implements Envelope {
10
+ /**
11
+ * Unmarshal a serialized Envelope protobuf message
12
+ */
13
+ static createFromProtobuf: (data: Uint8Array) => Promise<RecordEnvelope>;
14
+ /**
15
+ * Seal marshals the given Record, places the marshaled bytes inside an Envelope
16
+ * and signs it with the given peerId's private key
17
+ */
18
+ static seal: (record: Record, peerId: PeerId) => Promise<RecordEnvelope>;
19
+ /**
20
+ * Open and certify a given marshalled envelope.
21
+ * Data is unmarshalled and the signature validated for the given domain.
22
+ */
23
+ static openAndCertify: (data: Uint8Array, domain: string) => Promise<RecordEnvelope>;
24
+ peerId: PeerId;
25
+ payloadType: Uint8Array;
26
+ payload: Uint8Array;
27
+ signature: Uint8Array;
28
+ marshaled?: Uint8Array;
29
+ /**
30
+ * The Envelope is responsible for keeping an arbitrary signed record
31
+ * by a libp2p peer.
32
+ */
33
+ constructor(options: EnvelopeOptions);
34
+ /**
35
+ * Marshal the envelope content
36
+ */
37
+ marshal(): Uint8Array;
38
+ /**
39
+ * Verifies if the other Envelope is identical to this one
40
+ */
41
+ equals(other: Envelope): boolean;
42
+ /**
43
+ * Validate envelope data signature for the given domain
44
+ */
45
+ validate(domain: string): Promise<boolean>;
46
+ }
47
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/envelope/index.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAA;AACxC,OAAO,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAA;AAEjE,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,UAAU,CAAA;IACvB,OAAO,EAAE,UAAU,CAAA;IACnB,SAAS,EAAE,UAAU,CAAA;CACtB;AAED,qBAAa,cAAe,YAAW,QAAQ;IAC7C;;OAEG;IACH,MAAM,CAAC,kBAAkB,SAAgB,UAAU,6BAUlD;IAED;;;OAGG;IACH,MAAM,CAAC,IAAI,WAAkB,MAAM,UAAU,MAAM,6BAoBlD;IAED;;;OAGG;IACH,MAAM,CAAC,cAAc,SAAgB,UAAU,UAAU,MAAM,6BAS9D;IAEM,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,UAAU,CAAA;IACvB,OAAO,EAAE,UAAU,CAAA;IACnB,SAAS,EAAE,UAAU,CAAA;IACrB,SAAS,CAAC,EAAE,UAAU,CAAA;IAE7B;;;OAGG;gBACU,OAAO,EAAE,eAAe;IASrC;;OAEG;IACH,OAAO;IAaP;;OAEG;IACH,MAAM,CAAE,KAAK,EAAE,QAAQ;IAIvB;;OAEG;IACH,QAAQ,CAAE,MAAM,EAAE,MAAM;CAWzB"}
@@ -0,0 +1,126 @@
1
+ var _a;
2
+ import errCode from 'err-code';
3
+ import { concat as uint8arraysConcat } from 'uint8arrays/concat';
4
+ import { fromString as uint8arraysFromString } from 'uint8arrays/from-string';
5
+ import { unmarshalPrivateKey, unmarshalPublicKey } from '@libp2p/crypto/keys';
6
+ import varint from 'varint';
7
+ import { equals as uint8arraysEquals } from 'uint8arrays/equals';
8
+ import { codes } from '../errors.js';
9
+ import { Envelope as Protobuf } from './envelope.js';
10
+ import { PeerId } from '@libp2p/peer-id';
11
+ export class RecordEnvelope {
12
+ /**
13
+ * The Envelope is responsible for keeping an arbitrary signed record
14
+ * by a libp2p peer.
15
+ */
16
+ constructor(options) {
17
+ const { peerId, payloadType, payload, signature } = options;
18
+ this.peerId = peerId;
19
+ this.payloadType = payloadType;
20
+ this.payload = payload;
21
+ this.signature = signature;
22
+ }
23
+ /**
24
+ * Marshal the envelope content
25
+ */
26
+ marshal() {
27
+ if (this.marshaled == null) {
28
+ this.marshaled = Protobuf.encode({
29
+ publicKey: this.peerId.publicKey,
30
+ payloadType: this.payloadType,
31
+ payload: this.payload,
32
+ signature: this.signature
33
+ }).finish();
34
+ }
35
+ return this.marshaled;
36
+ }
37
+ /**
38
+ * Verifies if the other Envelope is identical to this one
39
+ */
40
+ equals(other) {
41
+ return uint8arraysEquals(this.marshal(), other.marshal());
42
+ }
43
+ /**
44
+ * Validate envelope data signature for the given domain
45
+ */
46
+ validate(domain) {
47
+ const signData = formatSignaturePayload(domain, this.payloadType, this.payload);
48
+ if (this.peerId.publicKey == null) {
49
+ throw new Error('Missing public key');
50
+ }
51
+ const key = unmarshalPublicKey(this.peerId.publicKey);
52
+ return key.verify(signData, this.signature);
53
+ }
54
+ }
55
+ _a = RecordEnvelope;
56
+ /**
57
+ * Unmarshal a serialized Envelope protobuf message
58
+ */
59
+ RecordEnvelope.createFromProtobuf = async (data) => {
60
+ const envelopeData = Protobuf.decode(data);
61
+ const peerId = await PeerId.fromKeys(envelopeData.publicKey);
62
+ return new RecordEnvelope({
63
+ peerId,
64
+ payloadType: envelopeData.payloadType,
65
+ payload: envelopeData.payload,
66
+ signature: envelopeData.signature
67
+ });
68
+ };
69
+ /**
70
+ * Seal marshals the given Record, places the marshaled bytes inside an Envelope
71
+ * and signs it with the given peerId's private key
72
+ */
73
+ RecordEnvelope.seal = async (record, peerId) => {
74
+ const domain = record.domain;
75
+ const payloadType = record.codec;
76
+ const payload = record.marshal();
77
+ const signData = formatSignaturePayload(domain, payloadType, payload);
78
+ if (peerId.privateKey == null) {
79
+ throw new Error('Missing private key');
80
+ }
81
+ const key = await unmarshalPrivateKey(peerId.privateKey);
82
+ const signature = await key.sign(signData);
83
+ return new RecordEnvelope({
84
+ peerId,
85
+ payloadType,
86
+ payload,
87
+ signature
88
+ });
89
+ };
90
+ /**
91
+ * Open and certify a given marshalled envelope.
92
+ * Data is unmarshalled and the signature validated for the given domain.
93
+ */
94
+ RecordEnvelope.openAndCertify = async (data, domain) => {
95
+ const envelope = await RecordEnvelope.createFromProtobuf(data);
96
+ const valid = await envelope.validate(domain);
97
+ if (!valid) {
98
+ throw errCode(new Error('envelope signature is not valid for the given domain'), codes.ERR_SIGNATURE_NOT_VALID);
99
+ }
100
+ return envelope;
101
+ };
102
+ /**
103
+ * Helper function that prepares a Uint8Array to sign or verify a signature
104
+ */
105
+ const formatSignaturePayload = (domain, payloadType, payload) => {
106
+ // When signing, a peer will prepare a Uint8Array by concatenating the following:
107
+ // - The length of the domain separation string string in bytes
108
+ // - The domain separation string, encoded as UTF-8
109
+ // - The length of the payload_type field in bytes
110
+ // - The value of the payload_type field
111
+ // - The length of the payload field in bytes
112
+ // - The value of the payload field
113
+ const domainUint8Array = uint8arraysFromString(domain);
114
+ const domainLength = varint.encode(domainUint8Array.byteLength);
115
+ const payloadTypeLength = varint.encode(payloadType.length);
116
+ const payloadLength = varint.encode(payload.length);
117
+ return uint8arraysConcat([
118
+ new Uint8Array(domainLength),
119
+ domainUint8Array,
120
+ new Uint8Array(payloadTypeLength),
121
+ payloadType,
122
+ new Uint8Array(payloadLength),
123
+ payload
124
+ ]);
125
+ };
126
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/envelope/index.ts"],"names":[],"mappings":"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"}