Implement getpubkey
This commit is contained in:
parent
9208e95e20
commit
09f7be7062
|
@ -45,7 +45,7 @@ API documentation is available [here](https://bitchan.github.io/bitmessage/docs/
|
|||
- [x] error
|
||||
- [x] object
|
||||
- [ ] Object types
|
||||
- [ ] getpubkey
|
||||
- [x] getpubkey
|
||||
- [ ] pubkey
|
||||
- [ ] msg
|
||||
- [ ] broadcast
|
||||
|
@ -55,7 +55,6 @@ API documentation is available [here](https://bitchan.github.io/bitmessage/docs/
|
|||
- [ ] Address
|
||||
- [x] encode
|
||||
- [x] decode
|
||||
- [x] getRipe
|
||||
- [x] fromRandom
|
||||
- [ ] fromPassphrase
|
||||
- [x] UserAgent
|
||||
|
|
|
@ -46,6 +46,10 @@ function Address(opts) {
|
|||
* @return {Address} Decoded address object.
|
||||
*/
|
||||
Address.decode = function(str) {
|
||||
if (str instanceof Address) {
|
||||
return str;
|
||||
}
|
||||
|
||||
str = str.trim();
|
||||
if (str.slice(0, 3) === "BM-") {
|
||||
str = str.slice(3);
|
||||
|
@ -121,6 +125,21 @@ Address.prototype.getRipe = function(opts) {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Calculate the address tag.
|
||||
* @return {Buffer} A 32-byte address tag.
|
||||
*/
|
||||
Address.prototype.getTag = function() {
|
||||
var ripe = this.getRipe();
|
||||
var dataToHash = Buffer.concat([
|
||||
var_int.encode(this.version),
|
||||
var_int.encode(this.stream),
|
||||
ripe,
|
||||
]);
|
||||
var hash = bmcrypto.sha512(bmcrypto.sha512(dataToHash));
|
||||
return hash.slice(32);
|
||||
};
|
||||
|
||||
// Get truncated ripe hash length.
|
||||
function getripelen(ripe) {
|
||||
var zeroes = 0;
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* @see {@link https://bitmessage.org/Bitmessage%20Technical%20Paper.pdf}
|
||||
* @module bitmessage/messages
|
||||
*/
|
||||
// TODO(Kagami): Document object-like params.
|
||||
|
||||
"use strict";
|
||||
|
||||
|
@ -266,8 +267,8 @@ var error = exports.error = {
|
|||
* a stream. It is the only message which propagates; all others are
|
||||
* only between two nodes.
|
||||
* NOTE: You shouldn't use `encode` and `decode` methods directly.
|
||||
* Instead, get type of the object and encode/decode it with appropriate
|
||||
* function from `objects` module.
|
||||
* Instead, get type of the object and process it using appropriate
|
||||
* namespace from `objects` module.
|
||||
* @see {@link https://bitmessage.org/wiki/Protocol_specification#object}
|
||||
* @namespace
|
||||
*/
|
||||
|
@ -285,20 +286,21 @@ exports.object = {
|
|||
* @return {?number} Object type.
|
||||
*/
|
||||
getType: function(buf) {
|
||||
// Per v3 spec object starts with nonce (8 bytes), expiresTime (8
|
||||
// bytes) and objectType (4 bytes). So we need only first 20 bytes
|
||||
// to read the type.
|
||||
if (buf.length >= 20) {
|
||||
return buf.readUInt32BE(16, true);
|
||||
}
|
||||
assert(buf.length >= 22, "object message payload is too small");
|
||||
return buf.readUInt32BE(16, true);
|
||||
},
|
||||
|
||||
/**
|
||||
* Decode `object` message payload.
|
||||
* NOTE: `nonce` is copied, `payload` references input buffer.
|
||||
* NOTE: `nonce` and `payload` are copied.
|
||||
* @param {Buffer} buf - Message payload
|
||||
* @return {Object} Decoded `object` structure.
|
||||
*/
|
||||
// FIXME(Kagami): Check for POW.
|
||||
// TODO(Kagami): Option to not fail on bad POW (may be useful for
|
||||
// bitchan).
|
||||
// TODO(Kagami): Option to not fail on expired object (would be useful
|
||||
// for bitchan).
|
||||
decode: function(buf) {
|
||||
// 8 + 8 + 4 + (1+) + (1+)
|
||||
assert(buf.length >= 22, "object message payload is too small");
|
||||
|
@ -311,13 +313,15 @@ exports.object = {
|
|||
var type = buf.readUInt32BE(16, true);
|
||||
var decodedVersion = structs.var_int.decode(buf.slice(20));
|
||||
var decodedStream = structs.var_int.decode(decodedVersion.rest);
|
||||
var payload = new Buffer(decodedStream.rest.length);
|
||||
decodedStream.rest.copy(payload);
|
||||
return {
|
||||
nonce: nonce,
|
||||
ttl: ttl,
|
||||
type: type,
|
||||
version: decodedVersion.value,
|
||||
stream: decodedStream.value,
|
||||
payload: decodedStream.rest,
|
||||
payload: payload,
|
||||
};
|
||||
},
|
||||
|
||||
|
@ -326,6 +330,7 @@ exports.object = {
|
|||
* @param {Object} opts - Object options
|
||||
* @return {Buffer} Encoded payload.
|
||||
*/
|
||||
// TODO(Kagami): Do a POW if nonce is not provided.
|
||||
encode: function(opts) {
|
||||
assert(opts.nonce.length === 8, "Bad nonce");
|
||||
assert(opts.ttl > 0, "Bad TTL");
|
||||
|
|
|
@ -1,5 +1,68 @@
|
|||
/**
|
||||
* Working with objects.
|
||||
* NOTE: All operations with objects in this module are asynchronous and
|
||||
* return promises.
|
||||
* @see {@link https://bitmessage.org/wiki/Protocol_specification#Object_types}
|
||||
* @module bitmessage/objects
|
||||
*/
|
||||
// TODO(Kagami): Document object-like params.
|
||||
|
||||
"use strict";
|
||||
|
||||
var objectAssign = Object.assign || require("object-assign");
|
||||
var assert = require("./util").assert;
|
||||
var promise = require("./platform").promise;
|
||||
var object = require("./messages").object;
|
||||
var Address = require("./address");
|
||||
|
||||
/**
|
||||
* `getpubkey` object. When a node has the hash of a public key (from an
|
||||
* address) but not the public key itself, it must send out a request
|
||||
* for the public key.
|
||||
* @see {@link https://bitmessage.org/wiki/Protocol_specification#getpubkey}
|
||||
* @namespace
|
||||
*/
|
||||
exports.getpubkey = {
|
||||
/**
|
||||
* Decode `getpubkey` object message payload.
|
||||
* @param {Buffer} buf - Message payload
|
||||
* @return {Promise.<Object>} A promise that contained decoded
|
||||
* `object` structure when fulfilled.
|
||||
*/
|
||||
decodeAsync: function(buf) {
|
||||
return new promise(function(resolve) {
|
||||
var decoded = object.decode(buf);
|
||||
assert(decoded.type === object.GETPUBKEY, "Wrong object type");
|
||||
var payload = decoded.payload;
|
||||
delete decoded.payload;
|
||||
if (decoded.version < 4) {
|
||||
assert(payload.length === 20, "getpubkey ripe is too small");
|
||||
// Payload is copied so it's safe to return it right away.
|
||||
decoded.ripe = payload;
|
||||
} else {
|
||||
assert(payload.length === 32, "getpubkey tag is too small");
|
||||
// Payload is copied so it's safe to return it right away.
|
||||
decoded.tag = payload;
|
||||
}
|
||||
resolve(decoded);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Encode `getpubkey` object message payload.
|
||||
* @param {Object} opts - `getpubkey` object options
|
||||
* @return {Promise.<Buffer>} A promise that contained encoded message
|
||||
* payload when fulfilled.
|
||||
*/
|
||||
encodeAsync: function(opts) {
|
||||
return new promise(function(resolve) {
|
||||
opts = objectAssign({}, opts);
|
||||
opts.type = object.GETPUBKEY;
|
||||
var addr = Address.decode(opts.to);
|
||||
opts.version = addr.version;
|
||||
opts.stream = addr.stream;
|
||||
opts.payload = opts.version < 4 ? addr.getRipe() : addr.getTag();
|
||||
resolve(object.encode(opts));
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* @see {@link https://bitmessage.org/wiki/Protocol_specification#Common_structures}
|
||||
* @module bitmessage/structs
|
||||
*/
|
||||
// TODO(Kagami): Find a way how to document object params properly.
|
||||
// TODO(Kagami): Document object-like params.
|
||||
|
||||
"use strict";
|
||||
|
||||
|
|
31
test.js
31
test.js
|
@ -22,6 +22,8 @@ var addr = messages.addr;
|
|||
var inv = messages.inv;
|
||||
var error = messages.error;
|
||||
var object = messages.object;
|
||||
var objects = bitmessage.objects;
|
||||
var getpubkey = objects.getpubkey;
|
||||
var WIF = bitmessage.WIF;
|
||||
var POW = bitmessage.POW;
|
||||
var Address = bitmessage.Address;
|
||||
|
@ -414,6 +416,24 @@ describe("Message types", function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe("Object types", function() {
|
||||
describe("getpubkey", function() {
|
||||
it("should encode and decode", function() {
|
||||
return getpubkey.encodeAsync({
|
||||
nonce: Buffer(8),
|
||||
ttl: 100,
|
||||
to: "2cTux3PGRqHTEH6wyUP2sWeT4LrsGgy63z",
|
||||
}).then(getpubkey.decodeAsync)
|
||||
.then(function(res) {
|
||||
expect(res.ttl).to.equal(100);
|
||||
expect(res.version).to.equal(4);
|
||||
expect(res.stream).to.equal(1);
|
||||
expect(res.tag.toString("hex")).to.equal("facf1e3e6c74916203b7f714ca100d4d60604f0917696d0f09330f82f52bed1a");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("WIF", function() {
|
||||
var wifSign = "5JgQ79vTBusc61xYPtUEHYQ38AXKdDZgQ5rFp7Cbb4ZjXUKFZEV";
|
||||
var wifEnc = "5K2aL8cnsEWHwHfHnUrPo8QdYyRfoYUBmhAnWY5GTpDLbeyusnE";
|
||||
|
@ -521,6 +541,17 @@ describe("High-level classes", function() {
|
|||
expect(addr2.ripe[0]).to.equal(0);
|
||||
});
|
||||
|
||||
it("should calculate tag", function() {
|
||||
var addr = Address.decode("2cTux3PGRqHTEH6wyUP2sWeT4LrsGgy63z");
|
||||
expect(addr.getTag().toString("hex")).to.equal("facf1e3e6c74916203b7f714ca100d4d60604f0917696d0f09330f82f52bed1a");
|
||||
});
|
||||
|
||||
it("should allow to decode Address instance", function() {
|
||||
var addr = Address.decode("2cTux3PGRqHTEH6wyUP2sWeT4LrsGgy63z");
|
||||
expect(addr.ripe.toString("hex")).to.equal("003ab6655de4bd8c603eba9b00dd5970725fdd56");
|
||||
expect(Address.decode(addr)).to.equal(addr);
|
||||
});
|
||||
|
||||
// FIXME(Kagami): Don't run it in browser currently because it's
|
||||
// very slow. This need to be fixed.
|
||||
if (allTests && typeof window === "undefined") {
|
||||
|
|
Loading…
Reference in New Issue
Block a user