User agent

This commit is contained in:
Kagami Hiiragi 2015-01-11 20:24:39 +03:00
parent 887a757f87
commit 001f5b16df
5 changed files with 133 additions and 1 deletions

View File

@ -57,7 +57,7 @@ API documentation is available [here](https://bitchan.github.io/bitmessage/docs/
- [x] getRipe
- [x] fromRandom
- [ ] fromPassphrase
- [ ] UserAgent
- [x] UserAgent
- [ ] Message
- [ ] encrypt
- [ ] decrypt

View File

@ -19,3 +19,5 @@ exports.POW = require("./pow");
/** [Working with addresses.]{@link module:bitmessage/address} */
exports.Address = require("./address");
/** [User Agent.]{@link module:bitmessage/user-agent} */
exports.UserAgent = require("./user-agent");

View File

@ -38,6 +38,7 @@ var message = exports.message = {
/**
* Decode message structure.
* NOTE: `payload` is copied, `rest` references input buffer.
* @param {Buffer} buf - Buffer that starts with encoded message
* structure
* @return {{command: string, payload: Buffer, length: number, rest: Buffer}}
@ -99,6 +100,7 @@ var message = exports.message = {
var var_int = exports.var_int = {
/**
* Decode `var_int`.
* NOTE: `rest` references input buffer.
* @param {Buffer} buf - A buffer that starts with encoded `var_int`
* @return {{value: number, length: number, rest: Buffer}}
* Decoded `var_int` structure.
@ -191,6 +193,7 @@ var var_int = exports.var_int = {
exports.var_str = {
/**
* Decode `var_str`.
* NOTE: `rest` references input buffer.
* @param {Buffer} buf - A buffer that starts with encoded `var_str`
* @return {{str: string, length: number, rest: Buffer}}
* Decoded `var_str` structure.
@ -226,6 +229,7 @@ exports.var_str = {
exports.var_int_list = {
/**
* Decode `var_int_list`.
* NOTE: `rest` references input buffer.
* @param {Buffer} buf - A buffer that starts with encoded
* `var_int_list`
* @return {{list: number[], length: number, rest: Buffer}}
@ -421,6 +425,7 @@ var SECP256K1_TYPE = 714;
exports.encrypted = {
/**
* Decode encrypted payload.
* NOTE: all structure members are copied.
* @param {Buffer} buf - A buffer that contains encrypted payload
* @return {Object} Decoded encrypted structure.
*/

84
lib/user-agent.js Normal file
View File

@ -0,0 +1,84 @@
/**
* Working with Bitmessage user agents.
* @see {@link https://bitmessage.org/wiki/User_Agent}
* @module bitmessage/user-agent
*/
"use strict";
var var_str = require("./structs").var_str;
var BM_NAME = require("../package.json").name;
var BM_VERSION = require("../package.json").version;
/**
* Decode user agent stack.
* NOTE: Decoding is rather loose and non-strict, it won't fail on bad
* user agent format because it's not that important.
* Also note that `rest` references input buffer.
* @param {Buffer} buf - A buffer that starts with encoded user agent
* @return {{software: Object[], length: number, rest: Buffer}}
* Decoded user agent structure.
*/
exports.decode = function(buf) {
var decoded = var_str.decode(buf);
var software = [];
if (decoded.str) {
software = decoded.str.slice(1, -1).split("/");
software = software.map(function(str) {
// That's more readable than /([^:]*)(?::([^(]*)(?:\(([^)]*))?)?/
var soft = {name: str};
var semicolon = soft.name.indexOf(":");
if (semicolon !== -1) {
soft.version = soft.name.slice(semicolon + 1);
soft.name = soft.name.slice(0, semicolon);
var obracket = soft.version.indexOf("(");
if (obracket !== -1) {
soft.comments = soft.version.slice(obracket + 1);
soft.version = soft.version.slice(0, obracket);
var cbracket = soft.comments.indexOf(")");
if (cbracket !== -1) {
soft.comments = soft.comments.slice(0, cbracket);
}
}
}
return soft;
});
}
return {software: software, length: decoded.length, rest: decoded.rest};
};
/**
* Encode user agent. Most underlying software comes first.
* @param {Object[]} software - List of software to encode
* @return {Buffer} Encoded user agent.
*/
var encode = exports.encode = function(software) {
var ua = software.map(function(soft) {
var version = soft.version || "0.0.0";
var str = soft.name + ":" + version;
if (str.comments) {
str += "(" + comments + ")";
}
return str;
}).join("/");
return var_str.encode("/" + ua + "/");
};
/**
* Encode bitmessage's user agent.
* @return {Buffer} Encoded user agent.
*/
exports.encodeSelf = function() {
return encode([{name: BM_NAME, version: BM_VERSION}]);
};
/**
* Encode user agent with bitmessage's user agent underneath. Most
* underlying software comes first.
* @param {Object[]} software - List of software to encode
* @return {Buffer} Encoded user agent.
*/
exports.encodeSelfWith = function(software) {
software = [{name: BM_NAME, version: BM_VERSION}].concat(software);
return encode(software);
};

41
test.js
View File

@ -19,6 +19,7 @@ var pubkeyFeatures = structs.pubkeyFeatures;
var WIF = bitmessage.WIF;
var POW = bitmessage.POW;
var Address = bitmessage.Address;
var UserAgent = bitmessage.UserAgent;
describe("Crypto", function() {
it("should implement SHA-512 hash", function() {
@ -377,4 +378,44 @@ describe("High-level classes", function() {
});
}
});
describe("User Agent", function() {
var pybm = {name: "PyBitmessage", version: "0.4.4"};
var bnode = {name: "bitchan-node", version: "0.0.1"};
var bweb = {name: "bitchan-web"};
it("should decode", function() {
var ua = var_str.encode("/cBitmessage:0.2(iPad; U; CPU OS 3_2_1)/AndroidBuild:0.8/");
var res = UserAgent.decode(ua);
expect(res.software).to.deep.equal([
{name: "cBitmessage", version: "0.2", comments: "iPad; U; CPU OS 3_2_1"},
{name: "AndroidBuild", version: "0.8"},
]);
expect(res.length).to.equal(58);
expect(res.rest.toString("hex")).to.equal("");
});
it("should encode", function() {
var ua = UserAgent.encode([pybm]);
expect(var_str.decode(ua).str).to.equal("/PyBitmessage:0.4.4/");
var res = UserAgent.decode(ua);
expect(res.software).to.deep.equal([pybm]);
expect(res.length).to.equal(21);
expect(res.rest.toString("hex")).to.equal("");
});
it("should encode bitmessage's user agent", function() {
var res = UserAgent.decode(UserAgent.encodeSelf())
var software = res.software;
expect(software[0].name).to.equal("bitmessage");
expect(software[0]).to.have.property("version");
res = UserAgent.decode(UserAgent.encodeSelfWith([bnode, bweb]));
software = res.software;
expect(software[0].name).to.equal("bitmessage");
expect(software[1]).to.deep.equal(bnode);
expect(software[2].name).to.equal(bweb.name);
expect(software[2].version).to.equal("0.0.0");
});
});
});