bitmessage-js/lib/messages.js

100 lines
3.1 KiB
JavaScript

/**
* Working with messages.
* @see {@link https://bitmessage.org/wiki/Protocol_specification#Message_types}
* @module bitmessage/messages
*/
"use strict";
var assert = require("./util").assert;
var structs = require("./structs");
var UserAgent = require("./user-agent");
var util = require("./util");
/**
* Version message.
* @see {@link https://bitmessage.org/wiki/Protocol_specification#version}
* @namespace
*/
exports.version = {
/** Random nonce used to detect connections to self. */
NONCE: new Buffer("20bde0a3355dad78", "hex"),
/**
* Decode version payload.
* NOTE: `nonce` is copied.
* @param {Buffer} buf - Buffer that starts with encoded version
* payload
* @return {Object} Decoded version structure.
*/
decode: function(payload) {
// 4 + 8 + 8 + 26 + 26 + 8 + (1+) + (1+)
assert(payload.length >= 82, "Message payload is too small");
var protoVersion = payload.readUInt32BE(0, true);
var services = structs.serviceFeatures.decode(payload.slice(4, 12));
var time = util.readTime64BE(payload, 12);
var short = {short: true};
var addrRecv = structs.net_addr.decode(payload.slice(20, 46), short);
var addrFrom = structs.net_addr.decode(payload.slice(46, 72), short);
var nonce = new Buffer(8);
payload.copy(nonce, 0, 72, 80);
var decodedUa = UserAgent.decode(payload.slice(80));
var decodedStreamNumbers = structs.var_int_list.decode(decodedUa.rest);
return {
version: protoVersion,
services: services,
time: time,
remoteHost: addrRecv.host,
remotePort: addrRecv.port,
port: addrFrom.port,
nonce: nonce,
software: decodedUa.software,
streamNumbers: decodedStreamNumbers.list,
// NOTE(Kagami): Real data length. It may be some gap between end
// of stream numbers list and end of payload:
// [payload..............[stream numbers]xxxx]
// We are currently ignoring that.
length: 80 + decodedUa.length + decodedStreamNumbers.length,
};
},
/**
* Encode version payload.
* @param {Object} opts - Version options
* @return {Buffer} Encoded version payload.
*/
encode: function(opts) {
// Deal with default options.
var services = opts.services || [structs.serviceFeatures.NODE_NETWORK];
var time = opts.time || new Date();
var nonce = opts.nonce || exports.version.NONCE;
var software = opts.software || UserAgent.SELF;
var streamNumbers = opts.streamNumbers || [1];
// Start encoding.
var protoVersion = new Buffer(4);
protoVersion.writeUInt32BE(require("./").PROTOCOL_VERSION, 0);
var addrRecv = structs.net_addr.encode({
services: services,
host: opts.remoteHost,
port: opts.remotePort,
short: true,
});
var addrFrom = structs.net_addr.encode({
services: services,
host: "127.0.0.1",
port: opts.port,
short: true,
});
return Buffer.concat([
protoVersion,
structs.serviceFeatures.encode(services),
util.writeTime64BE(null, time),
addrRecv,
addrFrom,
nonce,
UserAgent.encode(software),
structs.var_int_list.encode(streamNumbers),
]);
},
};