User agent
This commit is contained in:
parent
887a757f87
commit
001f5b16df
|
@ -57,7 +57,7 @@ API documentation is available [here](https://bitchan.github.io/bitmessage/docs/
|
||||||
- [x] getRipe
|
- [x] getRipe
|
||||||
- [x] fromRandom
|
- [x] fromRandom
|
||||||
- [ ] fromPassphrase
|
- [ ] fromPassphrase
|
||||||
- [ ] UserAgent
|
- [x] UserAgent
|
||||||
- [ ] Message
|
- [ ] Message
|
||||||
- [ ] encrypt
|
- [ ] encrypt
|
||||||
- [ ] decrypt
|
- [ ] decrypt
|
||||||
|
|
|
@ -19,3 +19,5 @@ exports.POW = require("./pow");
|
||||||
|
|
||||||
/** [Working with addresses.]{@link module:bitmessage/address} */
|
/** [Working with addresses.]{@link module:bitmessage/address} */
|
||||||
exports.Address = require("./address");
|
exports.Address = require("./address");
|
||||||
|
/** [User Agent.]{@link module:bitmessage/user-agent} */
|
||||||
|
exports.UserAgent = require("./user-agent");
|
||||||
|
|
|
@ -38,6 +38,7 @@ var message = exports.message = {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode message structure.
|
* Decode message structure.
|
||||||
|
* NOTE: `payload` is copied, `rest` references input buffer.
|
||||||
* @param {Buffer} buf - Buffer that starts with encoded message
|
* @param {Buffer} buf - Buffer that starts with encoded message
|
||||||
* structure
|
* structure
|
||||||
* @return {{command: string, payload: Buffer, length: number, rest: Buffer}}
|
* @return {{command: string, payload: Buffer, length: number, rest: Buffer}}
|
||||||
|
@ -99,6 +100,7 @@ var message = exports.message = {
|
||||||
var var_int = exports.var_int = {
|
var var_int = exports.var_int = {
|
||||||
/**
|
/**
|
||||||
* Decode `var_int`.
|
* Decode `var_int`.
|
||||||
|
* NOTE: `rest` references input buffer.
|
||||||
* @param {Buffer} buf - A buffer that starts with encoded `var_int`
|
* @param {Buffer} buf - A buffer that starts with encoded `var_int`
|
||||||
* @return {{value: number, length: number, rest: Buffer}}
|
* @return {{value: number, length: number, rest: Buffer}}
|
||||||
* Decoded `var_int` structure.
|
* Decoded `var_int` structure.
|
||||||
|
@ -191,6 +193,7 @@ var var_int = exports.var_int = {
|
||||||
exports.var_str = {
|
exports.var_str = {
|
||||||
/**
|
/**
|
||||||
* Decode `var_str`.
|
* Decode `var_str`.
|
||||||
|
* NOTE: `rest` references input buffer.
|
||||||
* @param {Buffer} buf - A buffer that starts with encoded `var_str`
|
* @param {Buffer} buf - A buffer that starts with encoded `var_str`
|
||||||
* @return {{str: string, length: number, rest: Buffer}}
|
* @return {{str: string, length: number, rest: Buffer}}
|
||||||
* Decoded `var_str` structure.
|
* Decoded `var_str` structure.
|
||||||
|
@ -226,6 +229,7 @@ exports.var_str = {
|
||||||
exports.var_int_list = {
|
exports.var_int_list = {
|
||||||
/**
|
/**
|
||||||
* Decode `var_int_list`.
|
* Decode `var_int_list`.
|
||||||
|
* NOTE: `rest` references input buffer.
|
||||||
* @param {Buffer} buf - A buffer that starts with encoded
|
* @param {Buffer} buf - A buffer that starts with encoded
|
||||||
* `var_int_list`
|
* `var_int_list`
|
||||||
* @return {{list: number[], length: number, rest: Buffer}}
|
* @return {{list: number[], length: number, rest: Buffer}}
|
||||||
|
@ -421,6 +425,7 @@ var SECP256K1_TYPE = 714;
|
||||||
exports.encrypted = {
|
exports.encrypted = {
|
||||||
/**
|
/**
|
||||||
* Decode encrypted payload.
|
* Decode encrypted payload.
|
||||||
|
* NOTE: all structure members are copied.
|
||||||
* @param {Buffer} buf - A buffer that contains encrypted payload
|
* @param {Buffer} buf - A buffer that contains encrypted payload
|
||||||
* @return {Object} Decoded encrypted structure.
|
* @return {Object} Decoded encrypted structure.
|
||||||
*/
|
*/
|
||||||
|
|
84
lib/user-agent.js
Normal file
84
lib/user-agent.js
Normal 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
41
test.js
|
@ -19,6 +19,7 @@ var pubkeyFeatures = structs.pubkeyFeatures;
|
||||||
var WIF = bitmessage.WIF;
|
var WIF = bitmessage.WIF;
|
||||||
var POW = bitmessage.POW;
|
var POW = bitmessage.POW;
|
||||||
var Address = bitmessage.Address;
|
var Address = bitmessage.Address;
|
||||||
|
var UserAgent = bitmessage.UserAgent;
|
||||||
|
|
||||||
describe("Crypto", function() {
|
describe("Crypto", function() {
|
||||||
it("should implement SHA-512 hash", 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");
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in New Issue
Block a user