Comparing version 0.0.48 to 0.1.0
@@ -9,11 +9,3 @@ import AxiomObject from "./AxiomObject"; | ||
import SignedMessage from "./SignedMessage"; | ||
export { AxiomObject, Channel, Database, KeyPair, Node, Peer, Sequence, SignedMessage }; | ||
export default class AxiomAPI { | ||
network: string; | ||
verbose: boolean; | ||
constructor(options?: { | ||
network?: string; | ||
verbose?: boolean; | ||
}); | ||
createNode(): Node; | ||
} | ||
export { AxiomObject, Channel, Database, KeyPair, Peer, Sequence, SignedMessage }; | ||
export default Node; |
@@ -16,5 +16,3 @@ "use strict"; | ||
exports.KeyPair = KeyPair_1.default; | ||
var NetworkConfig_1 = __importDefault(require("./NetworkConfig")); | ||
var Node_1 = __importDefault(require("./Node")); | ||
exports.Node = Node_1.default; | ||
var Peer_1 = __importDefault(require("./Peer")); | ||
@@ -26,15 +24,3 @@ exports.Peer = Peer_1.default; | ||
exports.SignedMessage = SignedMessage_1.default; | ||
var AxiomAPI = /** @class */ (function () { | ||
function AxiomAPI(options) { | ||
options = options || {}; | ||
this.network = options.network || "alpha"; | ||
this.verbose = !!options.verbose; | ||
} | ||
AxiomAPI.prototype.createNode = function () { | ||
var config = new NetworkConfig_1.default(this.network); | ||
return new Node_1.default(null, config.bootstrap, this.verbose); | ||
}; | ||
return AxiomAPI; | ||
}()); | ||
exports.default = AxiomAPI; | ||
exports.default = Node_1.default; | ||
//# sourceMappingURL=AxiomAPI.js.map |
export default interface BasicPeer { | ||
onClose(callback: () => void): void; | ||
onConnect(callback: () => void): void; | ||
onData(callback: (any: any) => void): void; | ||
onError(callback: (Error: any) => void): void; | ||
onSignal(callback: (any: any) => void): void; | ||
onData(callback: (data: any) => void): void; | ||
onError(callback: (error: Error) => void): void; | ||
onSignal(callback: (sig: any) => void): void; | ||
signal(sig: any): void; | ||
@@ -8,0 +8,0 @@ send(data: any): void; |
@@ -9,3 +9,3 @@ "use strict"; | ||
var OPTIONAL = { | ||
wrtc: null | ||
wrtc: undefined | ||
}; | ||
@@ -12,0 +12,0 @@ if (typeof global === "object") { |
export default class Cipher { | ||
static keyFromPassword(password: any, salt: any): any; | ||
static makeIV(): any; | ||
static makeSalt(): any; | ||
static encrypt(password: any, iv: any, salt: any, plaintext: any): any; | ||
static decrypt(password: any, iv: any, salt: any, ciphertext: any): any; | ||
static keyFromPassword(password: string, salt: string): string; | ||
static makeIV(): string; | ||
static makeSalt(): string; | ||
static encrypt(password: string, iv: string, salt: string, plaintext: string): string; | ||
static decrypt(password: string, iv: string, salt: string, ciphertext: string): string; | ||
} |
"use strict"; | ||
// A wrapper for AES encryption and decryption | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; | ||
result["default"] = mod; | ||
return result; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var forge = __importStar(require("node-forge")); | ||
var node_forge_1 = __importDefault(require("node-forge")); | ||
var Cipher = /** @class */ (function () { | ||
@@ -17,11 +13,11 @@ function Cipher() { | ||
var keySize = 32; | ||
return forge.pkcs5.pbkdf2(password, salt, 1000, keySize); | ||
return node_forge_1.default.pkcs5.pbkdf2(password, salt, 1000, keySize); | ||
}; | ||
// Returns a new hex-encoded initialization vector | ||
Cipher.makeIV = function () { | ||
return forge.util.bytesToHex(forge.random.getBytes(16)); | ||
return node_forge_1.default.util.bytesToHex(node_forge_1.default.random.getBytes(16)); | ||
}; | ||
// Returns a new hex-encoded salt | ||
Cipher.makeSalt = function () { | ||
return forge.util.bytesToHex(forge.random.getBytes(8)); | ||
return node_forge_1.default.util.bytesToHex(node_forge_1.default.random.getBytes(8)); | ||
}; | ||
@@ -31,7 +27,7 @@ // Encrypts some utf8 plaintext with AES. | ||
Cipher.encrypt = function (password, iv, salt, plaintext) { | ||
iv = forge.util.hexToBytes(iv); | ||
salt = forge.util.hexToBytes(salt); | ||
var input = forge.util.createBuffer(plaintext, "utf8"); | ||
iv = node_forge_1.default.util.hexToBytes(iv); | ||
salt = node_forge_1.default.util.hexToBytes(salt); | ||
var input = node_forge_1.default.util.createBuffer(plaintext, "utf8"); | ||
var key = Cipher.keyFromPassword(password, salt); | ||
var cipher = forge.cipher.createCipher("AES-CBC", key); | ||
var cipher = node_forge_1.default.cipher.createCipher("AES-CBC", key); | ||
cipher.start({ iv: iv }); | ||
@@ -47,8 +43,8 @@ cipher.update(input); | ||
Cipher.decrypt = function (password, iv, salt, ciphertext) { | ||
iv = forge.util.hexToBytes(iv); | ||
salt = forge.util.hexToBytes(salt); | ||
var bytes = forge.util.hexToBytes(ciphertext); | ||
var buffer = forge.util.createBuffer(bytes); | ||
iv = node_forge_1.default.util.hexToBytes(iv); | ||
salt = node_forge_1.default.util.hexToBytes(salt); | ||
var bytes = node_forge_1.default.util.hexToBytes(ciphertext); | ||
var buffer = node_forge_1.default.util.createBuffer(bytes); | ||
var key = Cipher.keyFromPassword(password, salt); | ||
var decipher = forge.cipher.createDecipher("AES-CBC", key); | ||
var decipher = node_forge_1.default.cipher.createDecipher("AES-CBC", key); | ||
decipher.start({ iv: iv }); | ||
@@ -58,3 +54,4 @@ decipher.update(buffer); | ||
try { | ||
var answer = decipher.output.toString("utf8"); | ||
// Decipher output string conversion always assumes utf-8 | ||
var answer = decipher.output.toString(); | ||
if (answer == "") { | ||
@@ -61,0 +58,0 @@ return null; |
@@ -19,8 +19,8 @@ import AxiomObject from "./AxiomObject"; | ||
db: any; | ||
filterer: (AxiomObject: any) => boolean; | ||
filterer: (obj: AxiomObject) => boolean; | ||
callbacks: DatabaseCallback[]; | ||
constructor(name: string, channel: Channel, node?: Node, prefix?: string); | ||
setFilter(filterer: (AxiomObject: any) => boolean): void; | ||
applyFilter(filterer: (AxiomObject: any) => boolean): Promise<void>; | ||
useFilter(filterer: (AxiomObject: any) => boolean): Promise<void>; | ||
setFilter(filterer: (obj: AxiomObject) => boolean): void; | ||
applyFilter(filterer: (obj: AxiomObject) => boolean): Promise<void>; | ||
useFilter(filterer: (obj: AxiomObject) => boolean): Promise<void>; | ||
allSignedMessages(): Promise<SignedMessage[]>; | ||
@@ -27,0 +27,0 @@ onMessage(callback: DatabaseCallback): Promise<void>; |
@@ -249,3 +249,7 @@ "use strict"; | ||
}; | ||
// Convert a SignedMessage to a form storable in PouchDB | ||
// Convert a SignedMessage to a form storable in PouchDB. | ||
// Of the top-level fields, most of them are the user-generated data. | ||
// There is also _id, which is the object id, aka | ||
// "owner:objectName". | ||
// There is also metadata, which we reserve the right to add junk to in the future. | ||
// TODO: Throw an error if the message is invalid | ||
@@ -262,4 +266,2 @@ Database.prototype.signedMessageToDocument = function (sm) { | ||
type: sm.message.type, | ||
channel: sm.message.channel, | ||
database: sm.message.database, | ||
signature: sm.signature | ||
@@ -304,4 +306,4 @@ } }); | ||
var messageContent = { | ||
channel: doc.metadata.channel, | ||
database: doc.metadata.database, | ||
channel: this.channel.name, | ||
database: this.name, | ||
timestamp: doc.metadata.timestamp, | ||
@@ -308,0 +310,0 @@ name: name |
@@ -1,31 +0,33 @@ | ||
import Message from "./Message"; | ||
declare module "node-forge" { | ||
namespace md { | ||
namespace sha512 { | ||
namespace sha256 { | ||
function create(): md.MessageDigest; | ||
} | ||
} | ||
} | ||
} | ||
export default class KeyPair { | ||
publicKey: Uint8Array; | ||
privateKey: Uint8Array; | ||
constructor(publicKey: any, privateKey: any); | ||
constructor(publicKey: Uint8Array, privateKey: Uint8Array); | ||
inspect(): string; | ||
static fromPrivateKey(priv: any): KeyPair; | ||
static fromPrivateKey(priv: string): KeyPair; | ||
static fromPlain(j: any): KeyPair; | ||
static fromSerialized(s: any): KeyPair; | ||
static fromSerialized(s: string): KeyPair; | ||
static fromRandom(): KeyPair; | ||
static fromSecretPhrase(phrase: any): KeyPair; | ||
static fromSecretPhrase(phrase: string): KeyPair; | ||
plain(): { | ||
public: string; | ||
private: any; | ||
private: string; | ||
}; | ||
serialize(): String; | ||
sign(string: any): String; | ||
signOperation(type: any, operation: any): { | ||
operation: any; | ||
type: any; | ||
signature: String; | ||
}; | ||
signOperationMessage(opm: any): Message; | ||
static verifySignature(publicKey: any, message: any, signature: any): boolean; | ||
serialize(): string; | ||
sign(s: string): string; | ||
static verifySignature(publicKey: string, message: string, signature: string): boolean; | ||
static isValidPublicKey(key: string): boolean; | ||
static isValidHexString(key: string): boolean; | ||
static decodePublicKey(input: any): Uint8Array; | ||
static encodePublicKey(key: any): string; | ||
static decodePublicKey(input: string): Uint8Array; | ||
static encodePublicKey(key: Uint8Array): string; | ||
getPublicKey(): string; | ||
getPrivateKey(): any; | ||
getPrivateKey(): string; | ||
} |
@@ -5,20 +5,2 @@ "use strict"; | ||
// a "private key". We try to name things "private key" when possible here. | ||
var __assign = (this && this.__assign) || function () { | ||
__assign = Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; | ||
result["default"] = mod; | ||
return result; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
@@ -29,7 +11,5 @@ return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
var base64_js_1 = require("base64-js"); | ||
var nacl = __importStar(require("tweetnacl")); | ||
var forge = __importStar(require("node-forge")); | ||
var tweetnacl_1 = __importDefault(require("tweetnacl")); | ||
var node_forge_1 = require("node-forge"); | ||
var text_encoding_shim_1 = require("text-encoding-shim"); | ||
var stringify = require("json-stable-stringify"); | ||
var Message_1 = __importDefault(require("./Message")); | ||
// Decodes a Uint8Array from a base64 string. | ||
@@ -76,3 +56,3 @@ // Adds = padding at the end, which our library requires but some do not. | ||
} | ||
// Creates a forge sha512/256 hash object from bytes | ||
// Creates a forge sha512/256 message digest from bytes | ||
function forgeHash(bytes) { | ||
@@ -84,3 +64,3 @@ // Convert bytes to the format for bytes that forge wants | ||
} | ||
var hash = forge.md.sha512.sha256.create(); | ||
var hash = node_forge_1.md.sha512.sha256.create(); | ||
hash.update(s); | ||
@@ -126,6 +106,6 @@ return hash; | ||
var bytes = base64Decode(priv); | ||
var keys = nacl.sign.keyPair.fromSecretKey(bytes); | ||
var keys = tweetnacl_1.default.sign.keyPair.fromSecretKey(bytes); | ||
return new KeyPair(keys.publicKey, keys.secretKey); | ||
}; | ||
// The "plain" format is a plain object with 'public' and 'private' keys | ||
// The "plain" format should be a plain object with 'public' and 'private' keys | ||
KeyPair.fromPlain = function (j) { | ||
@@ -151,3 +131,3 @@ var publicString = j.public || j.Public; | ||
KeyPair.fromRandom = function () { | ||
var keys = nacl.sign.keyPair(); | ||
var keys = tweetnacl_1.default.sign.keyPair(); | ||
return new KeyPair(keys.publicKey, keys.secretKey); | ||
@@ -160,3 +140,3 @@ }; | ||
var seed = sha512_256(bytes); | ||
var keys = nacl.sign.keyPair.fromSeed(seed); | ||
var keys = tweetnacl_1.default.sign.keyPair.fromSeed(seed); | ||
return new KeyPair(keys.publicKey, keys.secretKey); | ||
@@ -179,40 +159,7 @@ }; | ||
// Signatures are returned in base64 encoding. | ||
KeyPair.prototype.sign = function (string) { | ||
var bytes = new text_encoding_shim_1.TextEncoder("utf-8").encode(string); | ||
var sig = nacl.sign.detached(bytes, this.privateKey); | ||
KeyPair.prototype.sign = function (s) { | ||
var bytes = new text_encoding_shim_1.TextEncoder("utf-8").encode(s); | ||
var sig = tweetnacl_1.default.sign.detached(bytes, this.privateKey); | ||
return base64Encode(sig); | ||
}; | ||
// Signs an operation, represented as a plain old object. | ||
// A "signer" field is automatically added. | ||
// TODO: this isn't used, should we remove it? | ||
KeyPair.prototype.signOperation = function (type, operation) { | ||
var op = __assign(__assign({}, operation), { signer: this.getPublicKey() }); | ||
var json = stringify(op); | ||
var signed = { | ||
operation: op, | ||
type: type, | ||
signature: this.sign(type + json) | ||
}; | ||
return signed; | ||
}; | ||
// Signs the individual operations in an operation message | ||
// The "signer" field is added to each op | ||
// Any other fields besides operations are dropped | ||
KeyPair.prototype.signOperationMessage = function (opm) { | ||
if (opm.type != "Operation") { | ||
throw new Error("expected operation message in signOperationMessage"); | ||
} | ||
var operations = []; | ||
for (var _i = 0, _a = opm.operations; _i < _a.length; _i++) { | ||
var sop = _a[_i]; | ||
var op = __assign({ signer: this.getPublicKey() }, sop.operation); | ||
var signature = this.sign(sop.type + stringify(op)); | ||
operations.push({ | ||
operation: op, | ||
type: sop.type, | ||
signature: signature | ||
}); | ||
} | ||
return new Message_1.default("Operation", { operations: operations }); | ||
}; | ||
// publicKey and signature are both base64-encoded strings | ||
@@ -225,3 +172,3 @@ // Returns whether the signature is legitimate. | ||
try { | ||
return nacl.sign.detached.verify(msg, sig, key); | ||
return tweetnacl_1.default.sign.detached.verify(msg, sig, key); | ||
} | ||
@@ -228,0 +175,0 @@ catch (e) { |
"use strict"; | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; | ||
result["default"] = mod; | ||
return result; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
@@ -13,7 +6,7 @@ return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var forge = __importStar(require("node-forge")); | ||
var node_forge_1 = require("node-forge"); | ||
var KeyPair_1 = __importDefault(require("./KeyPair")); | ||
// Testing that our JavaScript libraries work like our Go libraries | ||
test("KeyPair crypto basics", function () { | ||
var hash = forge.md.sha512.sha256.create(); | ||
var hash = node_forge_1.md.sha512.sha256.create(); | ||
var sum = hash.digest().getBytes(); | ||
@@ -23,4 +16,4 @@ if (sum.charCodeAt(0) != 198) { | ||
} | ||
hash = forge.md.sha512.sha256.create(); | ||
hash.update("qq", "utf-8"); | ||
hash = node_forge_1.md.sha512.sha256.create(); | ||
hash.update("qq", "utf8"); | ||
sum = hash.digest().getBytes(); | ||
@@ -32,3 +25,3 @@ expect(sum.charCodeAt(0)).toBe(59); | ||
String.fromCharCode(4); | ||
hash = forge.md.sha512.sha256.create(); | ||
hash = node_forge_1.md.sha512.sha256.create(); | ||
hash.update(bytes); | ||
@@ -35,0 +28,0 @@ sum = hash.digest().getBytes(); |
export default class Message { | ||
type: string; | ||
_serialized: string; | ||
constructor(type: string, properties?: {}); | ||
[key: string]: any; | ||
constructor(type: string, properties?: any); | ||
serialize(): string; | ||
static fromSerialized(serialized: any): any; | ||
static fromSerialized(serialized: string): Message; | ||
} |
@@ -6,3 +6,2 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var KeyPair_1 = __importDefault(require("./KeyPair")); | ||
var Node_1 = __importDefault(require("./Node")); | ||
@@ -33,3 +32,3 @@ var Peer_1 = __importDefault(require("./Peer")); | ||
for (var i = 0; i < bootstrap.length; i++) { | ||
var node = new Node_1.default(KeyPair_1.default.fromRandom(), bootstrap, false); | ||
var node = new Node_1.default({ bootstrap: bootstrap }); | ||
answer.push(new MockPeerServer(node)); | ||
@@ -36,0 +35,0 @@ } |
export default class NetworkConfig { | ||
name: string; | ||
chain: string[]; | ||
trackers: string[]; | ||
proxies: string[]; | ||
bootstrap: string[]; | ||
retries: number; | ||
constructor(name: any); | ||
getChain(): any; | ||
getProxy(): any; | ||
constructor(name: string); | ||
} |
@@ -7,3 +7,4 @@ "use strict"; | ||
// local: the local network on your machine for testing | ||
// alpha: the alpha test network running under alphatest.network | ||
// prod: the production network | ||
// "alpha" is an old name for prod. | ||
var NetworkConfig = /** @class */ (function () { | ||
@@ -13,32 +14,5 @@ function NetworkConfig(name) { | ||
if (name == "local") { | ||
this.chain = [ | ||
"http://localhost:8000", | ||
"http://localhost:8001", | ||
"http://localhost:8002", | ||
"http://localhost:8003" | ||
]; | ||
this.trackers = ["ws://localhost:4000"]; | ||
this.proxies = ["localhost:3000"]; | ||
this.bootstrap = ["ws://localhost:3500"]; | ||
this.retries = 3; | ||
} | ||
else if (name == "alpha") { | ||
this.chain = [ | ||
"http://0.alphatest.network:8000", | ||
"http://1.alphatest.network:8000", | ||
"http://2.alphatest.network:8000", | ||
"http://3.alphatest.network:8000" | ||
]; | ||
this.trackers = [ | ||
"ws://0.alphatest.network:4000", | ||
"ws://1.alphatest.network:4000", | ||
"ws://2.alphatest.network:4000", | ||
"ws://3.alphatest.network:4000" | ||
]; | ||
this.proxies = [ | ||
"0.alphatest.network:3000", | ||
"1.alphatest.network:3000", | ||
"2.alphatest.network:3000", | ||
"3.alphatest.network:3000" | ||
]; | ||
else if (name == "alpha" || name == "prod") { | ||
this.bootstrap = [ | ||
@@ -50,3 +24,2 @@ "wss://0.axiombootstrap.com", | ||
]; | ||
this.retries = -1; | ||
} | ||
@@ -57,15 +30,5 @@ else { | ||
} | ||
NetworkConfig.prototype.getChain = function () { | ||
return randomChoice(this.chain); | ||
}; | ||
NetworkConfig.prototype.getProxy = function () { | ||
return randomChoice(this.proxies); | ||
}; | ||
return NetworkConfig; | ||
}()); | ||
exports.default = NetworkConfig; | ||
function randomChoice(list) { | ||
var i = Math.floor(list.length * Math.random()); | ||
return list[i]; | ||
} | ||
//# sourceMappingURL=NetworkConfig.js.map |
@@ -20,4 +20,4 @@ import Channel from "./Channel"; | ||
}; | ||
nextMessageCallbacks: ((SignedMessage: any) => void)[]; | ||
everyMessageCallbacks: ((SignedMessage: any) => void)[]; | ||
nextMessageCallbacks: ((sm: SignedMessage) => void)[]; | ||
everyMessageCallbacks: ((sm: SignedMessage) => void)[]; | ||
destroyed: boolean; | ||
@@ -38,3 +38,8 @@ channelMembers: { | ||
timer: IntervalTimer; | ||
constructor(keyPair: KeyPair, urls: string[], verbose: boolean); | ||
constructor(options?: { | ||
network?: string; | ||
keyPair?: KeyPair; | ||
bootstrap?: string[]; | ||
verbose?: boolean; | ||
}); | ||
log(...args: any[]): void; | ||
@@ -48,4 +53,4 @@ statusLine(): string; | ||
bootstrap(): void; | ||
onNextMessage(callback: (SignedMessage: any) => void): void; | ||
onEveryMessage(callback: (SignedMessage: any) => void): void; | ||
onNextMessage(callback: (sm: SignedMessage) => void): void; | ||
onEveryMessage(callback: (sm: SignedMessage) => void): void; | ||
waitForMessage(): Promise<SignedMessage>; | ||
@@ -52,0 +57,0 @@ waitUntil(f: () => boolean): Promise<void>; |
@@ -54,2 +54,3 @@ "use strict"; | ||
var Message_1 = __importDefault(require("./Message")); | ||
var NetworkConfig_1 = __importDefault(require("./NetworkConfig")); | ||
var Peer_1 = __importDefault(require("./Peer")); | ||
@@ -59,13 +60,20 @@ var SignedMessage_1 = __importDefault(require("./SignedMessage")); | ||
// A Node represents a member of the Axiom peer-to-peer network. | ||
// Externally, this object is the entry point to the public-facing API, and | ||
// is typically just named "Axiom". | ||
// See the README in this directory for a description of message formats. | ||
var Node = /** @class */ (function () { | ||
function Node(keyPair, urls, verbose) { | ||
// If bootstrap is provided, it overrides network. | ||
function Node(options) { | ||
var _this = this; | ||
this.keyPair = keyPair; | ||
if (!this.keyPair) { | ||
this.keyPair = KeyPair_1.default.fromRandom(); | ||
options = options || {}; | ||
this.keyPair = options.keyPair || KeyPair_1.default.fromRandom(); | ||
var bootstrap = options.bootstrap; | ||
if (!bootstrap) { | ||
var network = options.network || "prod"; | ||
var config = new NetworkConfig_1.default(network); | ||
bootstrap = config.bootstrap; | ||
} | ||
this.pendingByURL = {}; | ||
for (var _i = 0, urls_1 = urls; _i < urls_1.length; _i++) { | ||
var url = urls_1[_i]; | ||
for (var _i = 0, bootstrap_1 = bootstrap; _i < bootstrap_1.length; _i++) { | ||
var url = bootstrap_1[_i]; | ||
this.pendingByURL[url] = null; | ||
@@ -76,3 +84,3 @@ } | ||
this.destroyed = false; | ||
this.verbose = verbose; | ||
this.verbose = !!options.verbose; | ||
this.peers = {}; | ||
@@ -79,0 +87,0 @@ this.nextMessageCallbacks = []; |
@@ -21,3 +21,3 @@ import BasicPeer from "./BasicPeer"; | ||
static intercept: { | ||
[url: string]: (Peer: any) => void; | ||
[url: string]: (p: Peer) => void; | ||
}; | ||
@@ -40,3 +40,3 @@ static connectToServer(keyPair: KeyPair, url: string, verbose: boolean): Peer; | ||
onData(callback: (data: any) => void): void; | ||
onError(callback: (Error: any) => void): void; | ||
onError(callback: (e: Error) => void): void; | ||
onClose(callback: () => void): void; | ||
@@ -43,0 +43,0 @@ sendData(data: any): void; |
@@ -102,3 +102,5 @@ "use strict"; | ||
try { | ||
var signal = JSON.parse(event.data); | ||
// According to TypeScript, at least, there are a bunch of stringlike data | ||
// types we could receive here. In practice I have only seen strings. | ||
var signal = JSON.parse(event.data.toString()); | ||
incomingSignals.push(signal); | ||
@@ -105,0 +107,0 @@ } |
export default class Sequence<T> { | ||
items: T[]; | ||
callbacks: ((T: any) => void)[]; | ||
callbacks: ((t: T) => void)[]; | ||
constructor(); | ||
push(item: T): void; | ||
forEach(callback: (T: any) => void): void; | ||
forEach(callback: (t: T) => void): void; | ||
finish(): void; | ||
} |
@@ -0,1 +1,3 @@ | ||
import KeyPair from "./KeyPair"; | ||
import Message from "./Message"; | ||
export default class SignedMessage { | ||
@@ -7,10 +9,10 @@ message: any; | ||
verified: boolean; | ||
constructor({ message, messageString, signer, signature, verified }: { | ||
message: any; | ||
messageString: any; | ||
signer: any; | ||
signature: any; | ||
verified: any; | ||
constructor(args: { | ||
message: Message; | ||
messageString: string; | ||
signer: string; | ||
signature: string; | ||
verified: boolean; | ||
}); | ||
static fromSigning(message: any, keyPair: any, signature?: string): SignedMessage; | ||
static fromSigning(message: Message, keyPair: KeyPair, signature?: string): SignedMessage; | ||
serialize(): string; | ||
@@ -17,0 +19,0 @@ verify(): void; |
@@ -13,9 +13,8 @@ "use strict"; | ||
// signer and signature are base64-encoded. | ||
function SignedMessage(_a) { | ||
var message = _a.message, messageString = _a.messageString, signer = _a.signer, signature = _a.signature, verified = _a.verified; | ||
this.message = message; | ||
this.messageString = messageString; | ||
this.signer = signer; | ||
this.signature = signature; | ||
this.verified = verified; | ||
function SignedMessage(args) { | ||
this.message = args.message; | ||
this.messageString = args.messageString; | ||
this.signer = args.signer; | ||
this.signature = args.signature; | ||
this.verified = args.verified; | ||
} | ||
@@ -22,0 +21,0 @@ // Construct a SignedMessage by signing a Message. |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var tracking = process.hrtime && process.hrtime.bigint ? true : false; | ||
function sign(a) { | ||
if (a > 0) { | ||
return 1; | ||
} | ||
if (a < 0) { | ||
return -1; | ||
} | ||
return 0; | ||
} | ||
var TimeTracker = /** @class */ (function () { | ||
@@ -43,3 +52,3 @@ function TimeTracker() { | ||
var n2 = _b[0], t2 = _b[1], c2 = _b[2]; | ||
return t2 - t1; | ||
return sign(t2 - t1); | ||
}); | ||
@@ -46,0 +55,0 @@ for (var _i = 0, items_1 = items; _i < items_1.length; _i++) { |
@@ -1,3 +0,2 @@ | ||
export declare function sleep(ms: any): Promise<unknown>; | ||
export declare function sleep(ms: number): Promise<unknown>; | ||
export declare function isEmpty(obj: object): boolean; | ||
export declare function makeBucketName(input: any): string; |
@@ -15,28 +15,2 @@ "use strict"; | ||
exports.isEmpty = isEmpty; | ||
// Makes a validated bucket name from a user-provided one. | ||
// Throws an error if the input is invalid. | ||
function makeBucketName(input) { | ||
var parts = input.split(":"); | ||
if (parts.length > 2) { | ||
throw new Error("bucket name has too many parts: " + input); | ||
} | ||
if (parts.length == 0) { | ||
throw new Error('bucket name ("' + input + '") is empty'); | ||
} | ||
if (parts.length == 1) { | ||
parts.unshift("www"); | ||
} | ||
// Validate the parts. Make sure this regex matches the one in bucket.go | ||
var regex = RegExp("^[-a-zA-Z0-9]+$"); | ||
for (var i = 0; i < 2; i++) { | ||
if (i == 0 && parts[0] == "www") { | ||
continue; | ||
} | ||
if (!regex.test(parts[i])) { | ||
throw new Error("bucket name has an invalid part: " + parts[i]); | ||
} | ||
} | ||
return parts.join(":"); | ||
} | ||
exports.makeBucketName = makeBucketName; | ||
//# sourceMappingURL=Util.js.map |
{ | ||
"name": "axiom-api", | ||
"version": "0.0.48", | ||
"version": "0.1.0", | ||
"description": "API for interacting with the Axiom.org platform", | ||
@@ -34,3 +34,10 @@ "repository": { | ||
"devDependencies": { | ||
"@types/base64-js": "^1.2.5", | ||
"@types/jest": "^24.0.18", | ||
"@types/json-stable-stringify": "^1.0.32", | ||
"@types/node-forge": "^0.8.6", | ||
"@types/pouchdb": "^6.4.0", | ||
"@types/pouchdb-adapter-memory": "^6.1.3", | ||
"@types/simple-peer": "^6.1.6", | ||
"@types/ws": "^6.0.3", | ||
"jest": "^24.9.0", | ||
@@ -37,0 +44,0 @@ "pouchdb-adapter-memory": "^7.1.1", |
@@ -19,3 +19,2 @@ // AxiomAPI is the public-facing API that developers will use. | ||
KeyPair, | ||
Node, | ||
Peer, | ||
@@ -26,17 +25,2 @@ Sequence, | ||
export default class AxiomAPI { | ||
network: string; | ||
verbose: boolean; | ||
constructor(options?: { network?: string; verbose?: boolean }) { | ||
options = options || {}; | ||
this.network = options.network || "alpha"; | ||
this.verbose = !!options.verbose; | ||
} | ||
createNode(): Node { | ||
let config = new NetworkConfig(this.network); | ||
return new Node(null, config.bootstrap, this.verbose); | ||
} | ||
} | ||
export default Node; |
@@ -8,4 +8,4 @@ // BasicPeer is a small wrapper around the SimplePeer provided by the | ||
// TODO: solve this at compile-time rather than at runtime | ||
let OPTIONAL = { | ||
wrtc: null | ||
let OPTIONAL: { wrtc: any } = { | ||
wrtc: undefined | ||
}; | ||
@@ -24,5 +24,5 @@ declare var global: any; | ||
onConnect(callback: () => void): void; | ||
onData(callback: (any) => void): void; | ||
onError(callback: (Error) => void): void; | ||
onSignal(callback: (any) => void): void; | ||
onData(callback: (data: any) => void): void; | ||
onError(callback: (error: Error) => void): void; | ||
onSignal(callback: (sig: any) => void): void; | ||
signal(sig: any): void; | ||
@@ -35,3 +35,3 @@ send(data: any): void; | ||
class WebRTCBasicPeer implements BasicPeer { | ||
_peer: SimplePeer; | ||
_peer: any; | ||
@@ -53,11 +53,11 @@ constructor(initiator: boolean) { | ||
onData(callback: (any) => void) { | ||
onData(callback: (data: any) => void) { | ||
this._peer.on("data", callback); | ||
} | ||
onError(callback: (Error) => void) { | ||
onError(callback: (error: Error) => void) { | ||
this._peer.on("error", callback); | ||
} | ||
onSignal(callback: (any) => void) { | ||
onSignal(callback: (sig: any) => void) { | ||
this._peer.on("signal", callback); | ||
@@ -96,3 +96,3 @@ } | ||
class MockBasicPeer implements BasicPeer { | ||
partner: MockBasicPeer; | ||
partner?: MockBasicPeer; | ||
id: number; | ||
@@ -103,5 +103,5 @@ static allPeers: MockBasicPeer[] = []; | ||
initiator: boolean; | ||
closeCallback: () => void; | ||
connectCallback: () => void; | ||
dataCallback: (any) => void; | ||
closeCallback?: () => void; | ||
connectCallback?: () => void; | ||
dataCallback?: (data: any) => void; | ||
@@ -137,3 +137,3 @@ static clear() { | ||
onData(callback: (any) => void) { | ||
onData(callback: (data: any) => void) { | ||
if (this.dataCallback) { | ||
@@ -145,5 +145,5 @@ throw new Error("multiple dataCallback"); | ||
onError(callback: (Error) => void) {} | ||
onError(callback: (error: Error) => void) {} | ||
onSignal(callback: (any) => void) { | ||
onSignal(callback: (sig: any) => void) { | ||
callback(this.id); | ||
@@ -150,0 +150,0 @@ } |
// A wrapper for AES encryption and decryption | ||
import * as forge from "node-forge"; | ||
import forge from "node-forge"; | ||
export default class Cipher { | ||
static keyFromPassword(password, salt) { | ||
static keyFromPassword(password: string, salt: string) { | ||
let keySize = 32; | ||
@@ -12,3 +12,3 @@ return forge.pkcs5.pbkdf2(password, salt, 1000, keySize); | ||
// Returns a new hex-encoded initialization vector | ||
static makeIV() { | ||
static makeIV(): string { | ||
return forge.util.bytesToHex(forge.random.getBytes(16)); | ||
@@ -18,3 +18,3 @@ } | ||
// Returns a new hex-encoded salt | ||
static makeSalt() { | ||
static makeSalt(): string { | ||
return forge.util.bytesToHex(forge.random.getBytes(8)); | ||
@@ -25,3 +25,8 @@ } | ||
// Returns a hex-encoded string so that we don't need to muck around with bytes. | ||
static encrypt(password, iv, salt, plaintext) { | ||
static encrypt( | ||
password: string, | ||
iv: string, | ||
salt: string, | ||
plaintext: string | ||
): string { | ||
iv = forge.util.hexToBytes(iv); | ||
@@ -43,3 +48,8 @@ salt = forge.util.hexToBytes(salt); | ||
// It might just return garbage if the password is wrong, though. | ||
static decrypt(password, iv, salt, ciphertext) { | ||
static decrypt( | ||
password: string, | ||
iv: string, | ||
salt: string, | ||
ciphertext: string | ||
) { | ||
iv = forge.util.hexToBytes(iv); | ||
@@ -57,3 +67,4 @@ salt = forge.util.hexToBytes(salt); | ||
try { | ||
let answer = decipher.output.toString("utf8"); | ||
// Decipher output string conversion always assumes utf-8 | ||
let answer = decipher.output.toString(); | ||
if (answer == "") { | ||
@@ -60,0 +71,0 @@ return null; |
@@ -40,3 +40,3 @@ import PouchDB from "pouchdb"; | ||
db: any; | ||
filterer: (AxiomObject) => boolean; | ||
filterer: (obj: AxiomObject) => boolean; | ||
@@ -67,3 +67,3 @@ callbacks: DatabaseCallback[]; | ||
// A filter returns true for objects that are to be kept. | ||
setFilter(filterer: (AxiomObject) => boolean): void { | ||
setFilter(filterer: (obj: AxiomObject) => boolean): void { | ||
this.filterer = filterer; | ||
@@ -74,3 +74,3 @@ } | ||
// Returns when we are done filtering. | ||
async applyFilter(filterer: (AxiomObject) => boolean): Promise<void> { | ||
async applyFilter(filterer: (obj: AxiomObject) => boolean): Promise<void> { | ||
let objects = await this.find({ selector: {} }); | ||
@@ -82,3 +82,3 @@ let forgettable = objects.filter(x => !filterer(x)); | ||
// Applies a filter to both objects already in the database, and new objects. | ||
async useFilter(filterer: (AxiomObject) => boolean): Promise<void> { | ||
async useFilter(filterer: (obj: AxiomObject) => boolean): Promise<void> { | ||
this.setFilter(filterer); | ||
@@ -170,3 +170,7 @@ await this.applyFilter(filterer); | ||
// Convert a SignedMessage to a form storable in PouchDB | ||
// Convert a SignedMessage to a form storable in PouchDB. | ||
// Of the top-level fields, most of them are the user-generated data. | ||
// There is also _id, which is the object id, aka | ||
// "owner:objectName". | ||
// There is also metadata, which we reserve the right to add junk to in the future. | ||
// TODO: Throw an error if the message is invalid | ||
@@ -188,4 +192,2 @@ signedMessageToDocument(sm: SignedMessage): any { | ||
type: sm.message.type, | ||
channel: sm.message.channel, | ||
database: sm.message.database, | ||
signature: sm.signature | ||
@@ -236,4 +238,4 @@ } | ||
let messageContent: any = { | ||
channel: doc.metadata.channel, | ||
database: doc.metadata.database, | ||
channel: this.channel.name, | ||
database: this.name, | ||
timestamp: doc.metadata.timestamp, | ||
@@ -280,3 +282,3 @@ name | ||
} | ||
let data = {}; | ||
let data: any = {}; | ||
for (let key in doc) { | ||
@@ -283,0 +285,0 @@ if (!key.startsWith("_") && key !== "metadata") { |
@@ -1,2 +0,2 @@ | ||
import * as forge from "node-forge"; | ||
import { md } from "node-forge"; | ||
@@ -7,3 +7,3 @@ import KeyPair from "./KeyPair"; | ||
test("KeyPair crypto basics", () => { | ||
let hash = forge.md.sha512.sha256.create(); | ||
let hash = md.sha512.sha256.create(); | ||
let sum = hash.digest().getBytes(); | ||
@@ -14,4 +14,4 @@ if (sum.charCodeAt(0) != 198) { | ||
hash = forge.md.sha512.sha256.create(); | ||
hash.update("qq", "utf-8"); | ||
hash = md.sha512.sha256.create(); | ||
hash.update("qq", "utf8"); | ||
sum = hash.digest().getBytes(); | ||
@@ -25,3 +25,3 @@ expect(sum.charCodeAt(0)).toBe(59); | ||
String.fromCharCode(4); | ||
hash = forge.md.sha512.sha256.create(); | ||
hash = md.sha512.sha256.create(); | ||
hash.update(bytes); | ||
@@ -28,0 +28,0 @@ sum = hash.digest().getBytes(); |
@@ -7,4 +7,4 @@ // An ed25519 keypair. Designed to be parallel to the Go implementation. | ||
import * as nacl from "tweetnacl"; | ||
import * as forge from "node-forge"; | ||
import nacl from "tweetnacl"; | ||
import { md } from "node-forge"; | ||
import { TextEncoder } from "text-encoding-shim"; | ||
@@ -15,5 +15,14 @@ import stringify = require("json-stable-stringify"); | ||
// node-forge is missing a typescript definition for sha512/256 | ||
declare module "node-forge" { | ||
namespace md { | ||
namespace sha512 { | ||
namespace sha256 { function create(): md.MessageDigest; } | ||
} | ||
} | ||
} | ||
// Decodes a Uint8Array from a base64 string. | ||
// Adds = padding at the end, which our library requires but some do not. | ||
function base64Decode(s) { | ||
function base64Decode(s: string) { | ||
while (s.length % 4 != 0) { | ||
@@ -27,3 +36,3 @@ s += "="; | ||
// Removes any = padding at the end. | ||
function base64Encode(bytes) { | ||
function base64Encode(bytes: Uint8Array): string { | ||
let padded = fromByteArray(bytes); | ||
@@ -34,3 +43,3 @@ return padded.replace(/=*$/, ""); | ||
// Decodes a Uint8Array from a hex string. | ||
function hexDecode(s) { | ||
function hexDecode(s: string): Uint8Array { | ||
if (s.length % 2 != 0) { | ||
@@ -55,3 +64,3 @@ throw new Error("hex-encoded byte arrays should be even length"); | ||
// Shorten a string where the inside doesn't matter, typically some key for display | ||
function shorten(s) { | ||
function shorten(s: string): string { | ||
return s.slice(0, 6) + "..." + s.slice(-4); | ||
@@ -61,3 +70,3 @@ } | ||
// Encodes a Uint8Array into a hex string. | ||
function hexEncode(bytes: Uint8Array) { | ||
function hexEncode(bytes: Uint8Array): string { | ||
return Array.from(bytes) | ||
@@ -68,4 +77,4 @@ .map(byte => byte.toString(16).padStart(2, "0")) | ||
// Creates a forge sha512/256 hash object from bytes | ||
function forgeHash(bytes) { | ||
// Creates a forge sha512/256 message digest from bytes | ||
function forgeHash(bytes: Uint8Array) { | ||
// Convert bytes to the format for bytes that forge wants | ||
@@ -76,3 +85,3 @@ let s = ""; | ||
} | ||
let hash = forge.md.sha512.sha256.create(); | ||
let hash = md.sha512.sha256.create(); | ||
hash.update(s); | ||
@@ -83,3 +92,3 @@ return hash; | ||
// Returns a hex checksum from a Uint8array public key. | ||
function hexChecksum(bytes) { | ||
function hexChecksum(bytes: Uint8Array) { | ||
let hash = forgeHash(bytes); | ||
@@ -91,3 +100,3 @@ let digest = hash.digest(); | ||
// Returns a Uint8Array sha512_256 hash from a Uint8Array input. | ||
function sha512_256(inputBytes) { | ||
function sha512_256(inputBytes: Uint8Array) { | ||
let hash = forgeHash(inputBytes); | ||
@@ -106,3 +115,3 @@ let byteString = hash.digest().bytes(); | ||
constructor(publicKey, privateKey) { | ||
constructor(publicKey: Uint8Array, privateKey: Uint8Array) { | ||
this.publicKey = publicKey; | ||
@@ -134,3 +143,3 @@ this.privateKey = privateKey; | ||
// Throws an error if priv is not a valid private key. | ||
static fromPrivateKey(priv) { | ||
static fromPrivateKey(priv: string) { | ||
let bytes = base64Decode(priv); | ||
@@ -141,4 +150,4 @@ let keys = nacl.sign.keyPair.fromSecretKey(bytes); | ||
// The "plain" format is a plain object with 'public' and 'private' keys | ||
static fromPlain(j) { | ||
// The "plain" format should be a plain object with 'public' and 'private' keys | ||
static fromPlain(j: any) { | ||
let publicString = j.public || j.Public; | ||
@@ -158,3 +167,3 @@ let privateString = j.private || j.Private; | ||
// The input format is a serialized JSON string with 'public' and 'private' keys | ||
static fromSerialized(s) { | ||
static fromSerialized(s: string) { | ||
let j = JSON.parse(s); | ||
@@ -165,3 +174,3 @@ return KeyPair.fromPlain(j); | ||
// Generates a keypair randomly | ||
static fromRandom() { | ||
static fromRandom(): KeyPair { | ||
let keys = nacl.sign.keyPair(); | ||
@@ -172,3 +181,3 @@ return new KeyPair(keys.publicKey, keys.secretKey); | ||
// Generates a keypair from a secret phrase | ||
static fromSecretPhrase(phrase) { | ||
static fromSecretPhrase(phrase: string): KeyPair { | ||
// Hash the phrase for the ed25519 entropy seed bytes | ||
@@ -190,3 +199,3 @@ let bytes = new TextEncoder("utf-8").encode(phrase); | ||
// serialize() returns a serialized JSON string | ||
serialize(): String { | ||
serialize(): string { | ||
let j = this.plain(); | ||
@@ -200,4 +209,4 @@ | ||
// Signatures are returned in base64 encoding. | ||
sign(string): String { | ||
let bytes = new TextEncoder("utf-8").encode(string); | ||
sign(s: string): string { | ||
let bytes = new TextEncoder("utf-8").encode(s); | ||
let sig = nacl.sign.detached(bytes, this.privateKey); | ||
@@ -207,47 +216,9 @@ return base64Encode(sig); | ||
// Signs an operation, represented as a plain old object. | ||
// A "signer" field is automatically added. | ||
// TODO: this isn't used, should we remove it? | ||
signOperation(type, operation) { | ||
let op = { | ||
...operation, | ||
signer: this.getPublicKey() | ||
}; | ||
let json = stringify(op); | ||
let signed = { | ||
operation: op, | ||
type: type, | ||
signature: this.sign(type + json) | ||
}; | ||
return signed; | ||
} | ||
// Signs the individual operations in an operation message | ||
// The "signer" field is added to each op | ||
// Any other fields besides operations are dropped | ||
signOperationMessage(opm) { | ||
if (opm.type != "Operation") { | ||
throw new Error("expected operation message in signOperationMessage"); | ||
} | ||
let operations = []; | ||
for (let sop of opm.operations) { | ||
let op = { | ||
signer: this.getPublicKey(), | ||
...sop.operation | ||
}; | ||
let signature = this.sign(sop.type + stringify(op)); | ||
operations.push({ | ||
operation: op, | ||
type: sop.type, | ||
signature | ||
}); | ||
} | ||
return new Message("Operation", { operations }); | ||
} | ||
// publicKey and signature are both base64-encoded strings | ||
// Returns whether the signature is legitimate. | ||
static verifySignature(publicKey, message, signature) { | ||
static verifySignature( | ||
publicKey: string, | ||
message: string, | ||
signature: string | ||
): boolean { | ||
let key = KeyPair.decodePublicKey(publicKey); | ||
@@ -282,3 +253,3 @@ let msg = new TextEncoder("utf-8").encode(message); | ||
// Throws an error if the input format is not valid. | ||
static decodePublicKey(input) { | ||
static decodePublicKey(input: string) { | ||
if (input.length != 70) { | ||
@@ -307,3 +278,3 @@ throw new Error("public key " + input + " should be 70 characters long"); | ||
// The checksum is added at the end | ||
static encodePublicKey(key) { | ||
static encodePublicKey(key: Uint8Array): string { | ||
if (key.length != 32) { | ||
@@ -316,3 +287,3 @@ throw new Error("public keys should be 32 bytes long"); | ||
// Returns the public key in hex format | ||
getPublicKey() { | ||
getPublicKey(): string { | ||
return KeyPair.encodePublicKey(this.publicKey); | ||
@@ -322,5 +293,5 @@ } | ||
// Returns the private key in base64 format | ||
getPrivateKey() { | ||
getPrivateKey(): string { | ||
return base64Encode(this.privateKey); | ||
} | ||
} |
@@ -7,4 +7,5 @@ import stringify = require("json-stable-stringify"); | ||
_serialized: string; | ||
[key: string]: any; | ||
constructor(type: string, properties = {}) { | ||
constructor(type: string, properties: any = {}) { | ||
this.type = type; | ||
@@ -24,3 +25,3 @@ this._serialized = stringify({ | ||
static fromSerialized(serialized): any { | ||
static fromSerialized(serialized: string): Message { | ||
let { type, message } = JSON.parse(serialized); | ||
@@ -27,0 +28,0 @@ return new Message(type, message); |
@@ -25,3 +25,3 @@ import KeyPair from "./KeyPair"; | ||
for (let i = 0; i < bootstrap.length; i++) { | ||
let node = new Node(KeyPair.fromRandom(), bootstrap, false); | ||
let node = new Node({ bootstrap }); | ||
answer.push(new MockPeerServer(node)); | ||
@@ -28,0 +28,0 @@ } |
@@ -5,45 +5,13 @@ // A NetworkConfig object specifies how to connect to a particular network. | ||
// local: the local network on your machine for testing | ||
// alpha: the alpha test network running under alphatest.network | ||
// prod: the production network | ||
// "alpha" is an old name for prod. | ||
export default class NetworkConfig { | ||
name: string; | ||
chain: string[]; | ||
trackers: string[]; | ||
proxies: string[]; | ||
bootstrap: string[]; | ||
// A negative number means no limit | ||
retries: number; | ||
constructor(name) { | ||
constructor(name: string) { | ||
this.name = name; | ||
if (name == "local") { | ||
this.chain = [ | ||
"http://localhost:8000", | ||
"http://localhost:8001", | ||
"http://localhost:8002", | ||
"http://localhost:8003" | ||
]; | ||
this.trackers = ["ws://localhost:4000"]; | ||
this.proxies = ["localhost:3000"]; | ||
this.bootstrap = ["ws://localhost:3500"]; | ||
this.retries = 3; | ||
} else if (name == "alpha") { | ||
this.chain = [ | ||
"http://0.alphatest.network:8000", | ||
"http://1.alphatest.network:8000", | ||
"http://2.alphatest.network:8000", | ||
"http://3.alphatest.network:8000" | ||
]; | ||
this.trackers = [ | ||
"ws://0.alphatest.network:4000", | ||
"ws://1.alphatest.network:4000", | ||
"ws://2.alphatest.network:4000", | ||
"ws://3.alphatest.network:4000" | ||
]; | ||
this.proxies = [ | ||
"0.alphatest.network:3000", | ||
"1.alphatest.network:3000", | ||
"2.alphatest.network:3000", | ||
"3.alphatest.network:3000" | ||
]; | ||
} else if (name == "alpha" || name == "prod") { | ||
this.bootstrap = [ | ||
@@ -55,3 +23,2 @@ "wss://0.axiombootstrap.com", | ||
]; | ||
this.retries = -1; | ||
} else { | ||
@@ -61,15 +28,2 @@ throw new Error("unrecognized network config name: " + name); | ||
} | ||
getChain() { | ||
return randomChoice(this.chain); | ||
} | ||
getProxy() { | ||
return randomChoice(this.proxies); | ||
} | ||
} | ||
function randomChoice(list) { | ||
let i = Math.floor(list.length * Math.random()); | ||
return list[i]; | ||
} |
@@ -6,2 +6,3 @@ import Channel from "./Channel"; | ||
import Message from "./Message"; | ||
import NetworkConfig from "./NetworkConfig"; | ||
import Peer from "./Peer"; | ||
@@ -13,2 +14,4 @@ import SignedMessage from "./SignedMessage"; | ||
// A Node represents a member of the Axiom peer-to-peer network. | ||
// Externally, this object is the entry point to the public-facing API, and | ||
// is typically just named "Axiom". | ||
// See the README in this directory for a description of message formats. | ||
@@ -36,6 +39,6 @@ export default class Node { | ||
// Callbacks that will run on the next message received | ||
nextMessageCallbacks: ((SignedMessage) => void)[]; | ||
nextMessageCallbacks: ((sm: SignedMessage) => void)[]; | ||
// Callbacks that will run on every message received | ||
everyMessageCallbacks: ((SignedMessage) => void)[]; | ||
everyMessageCallbacks: ((sm: SignedMessage) => void)[]; | ||
@@ -64,10 +67,22 @@ // Whether this Node has been destroyed | ||
constructor(keyPair: KeyPair, urls: string[], verbose: boolean) { | ||
this.keyPair = keyPair; | ||
if (!this.keyPair) { | ||
this.keyPair = KeyPair.fromRandom(); | ||
// If bootstrap is provided, it overrides network. | ||
constructor(options?: { | ||
network?: string; | ||
keyPair?: KeyPair; | ||
bootstrap?: string[]; | ||
verbose?: boolean; | ||
}) { | ||
options = options || {}; | ||
this.keyPair = options.keyPair || KeyPair.fromRandom(); | ||
let bootstrap = options.bootstrap; | ||
if (!bootstrap) { | ||
let network = options.network || "prod"; | ||
let config = new NetworkConfig(network); | ||
bootstrap = config.bootstrap; | ||
} | ||
this.pendingByURL = {}; | ||
for (let url of urls) { | ||
for (let url of bootstrap) { | ||
this.pendingByURL[url] = null; | ||
@@ -81,3 +96,3 @@ } | ||
this.destroyed = false; | ||
this.verbose = verbose; | ||
this.verbose = !!options.verbose; | ||
this.peers = {}; | ||
@@ -100,3 +115,3 @@ this.nextMessageCallbacks = []; | ||
log(...args) { | ||
log(...args: any[]) { | ||
if (this.verbose) { | ||
@@ -193,7 +208,7 @@ console.log(`${this.keyPair.getPublicKey().slice(0, 6)}:`, ...args); | ||
onNextMessage(callback: (SignedMessage) => void) { | ||
onNextMessage(callback: (sm: SignedMessage) => void) { | ||
this.nextMessageCallbacks.push(callback); | ||
} | ||
onEveryMessage(callback: (SignedMessage) => void) { | ||
onEveryMessage(callback: (sm: SignedMessage) => void) { | ||
this.everyMessageCallbacks.push(callback); | ||
@@ -200,0 +215,0 @@ } |
@@ -54,3 +54,3 @@ import WebSocket = require("isomorphic-ws"); | ||
// Server URLs to intercept with a handler function | ||
static intercept: { [url: string]: (Peer) => void } = {}; | ||
static intercept: { [url: string]: (p: Peer) => void } = {}; | ||
@@ -87,3 +87,5 @@ // Creates a Peer by connecting to a PeerServer. | ||
try { | ||
let signal = JSON.parse(event.data); | ||
// According to TypeScript, at least, there are a bunch of stringlike data | ||
// types we could receive here. In practice I have only seen strings. | ||
let signal = JSON.parse(event.data.toString()); | ||
incomingSignals.push(signal); | ||
@@ -182,3 +184,3 @@ } catch (e) { | ||
log(...args) { | ||
log(...args: any[]) { | ||
if (this.verbose) { | ||
@@ -197,3 +199,3 @@ console.log(...args); | ||
onError(callback: (Error) => void) { | ||
onError(callback: (e: Error) => void) { | ||
this._peer.onError(callback); | ||
@@ -200,0 +202,0 @@ } |
@@ -6,3 +6,3 @@ // A Sequence is like a list that can be asynchronously populated. | ||
items: T[]; | ||
callbacks: ((T) => void)[]; | ||
callbacks: ((t: T) => void)[]; | ||
@@ -24,3 +24,3 @@ constructor() { | ||
forEach(callback: (T) => void) { | ||
forEach(callback: (t: T) => void) { | ||
for (let item of this.items) { | ||
@@ -27,0 +27,0 @@ callback(item); |
@@ -15,12 +15,22 @@ import KeyPair from "./KeyPair"; | ||
// signer and signature are base64-encoded. | ||
constructor({ message, messageString, signer, signature, verified }) { | ||
this.message = message; | ||
this.messageString = messageString; | ||
this.signer = signer; | ||
this.signature = signature; | ||
this.verified = verified; | ||
constructor(args: { | ||
message: Message; | ||
messageString: string; | ||
signer: string; | ||
signature: string; | ||
verified: boolean; | ||
}) { | ||
this.message = args.message; | ||
this.messageString = args.messageString; | ||
this.signer = args.signer; | ||
this.signature = args.signature; | ||
this.verified = args.verified; | ||
} | ||
// Construct a SignedMessage by signing a Message. | ||
static fromSigning(message, keyPair, signature?: string) { | ||
static fromSigning( | ||
message: Message, | ||
keyPair: KeyPair, | ||
signature?: string | ||
): SignedMessage { | ||
if (!message) { | ||
@@ -48,7 +58,7 @@ throw new Error("cannot sign a falsy message"); | ||
serialize() { | ||
serialize(): string { | ||
return "e:" + this.signer + ":" + this.signature + ":" + this.messageString; | ||
} | ||
verify() { | ||
verify(): void { | ||
if (this.verified) { | ||
@@ -77,3 +87,3 @@ return; | ||
// Returns null if the serialization is just an "ok" | ||
static fromSerialized(serialized, skipVerify: boolean) { | ||
static fromSerialized(serialized: any, skipVerify: boolean): SignedMessage { | ||
let s = typeof serialized === "string" ? serialized : serialized.toString(); | ||
@@ -80,0 +90,0 @@ |
@@ -6,2 +6,12 @@ declare var process: any; | ||
function sign(a: bigint): number { | ||
if (a > 0) { | ||
return 1; | ||
} | ||
if (a < 0) { | ||
return -1; | ||
} | ||
return 0; | ||
} | ||
export default class TimeTracker { | ||
@@ -40,3 +50,3 @@ static nanoseconds: { [name: string]: bigint } = {}; | ||
static show() { | ||
let items = []; | ||
let items: [string, bigint, number][] = []; | ||
for (let name in TimeTracker.nanoseconds) { | ||
@@ -49,3 +59,3 @@ items.push([ | ||
} | ||
items.sort(([n1, t1, c1], [n2, t2, c2]) => t2 - t1); | ||
items.sort(([n1, t1, c1], [n2, t2, c2]) => sign(t2 - t1)); | ||
for (let [name, total, calls] of items) { | ||
@@ -52,0 +62,0 @@ console.log( |
// Utility functions | ||
export function sleep(ms) { | ||
export function sleep(ms: number) { | ||
return new Promise(resolve => setTimeout(resolve, ms)); | ||
@@ -13,29 +13,1 @@ } | ||
} | ||
// Makes a validated bucket name from a user-provided one. | ||
// Throws an error if the input is invalid. | ||
export function makeBucketName(input): string { | ||
let parts = input.split(":"); | ||
if (parts.length > 2) { | ||
throw new Error("bucket name has too many parts: " + input); | ||
} | ||
if (parts.length == 0) { | ||
throw new Error('bucket name ("' + input + '") is empty'); | ||
} | ||
if (parts.length == 1) { | ||
parts.unshift("www"); | ||
} | ||
// Validate the parts. Make sure this regex matches the one in bucket.go | ||
let regex = RegExp("^[-a-zA-Z0-9]+$"); | ||
for (let i = 0; i < 2; i++) { | ||
if (i == 0 && parts[0] == "www") { | ||
continue; | ||
} | ||
if (!regex.test(parts[i])) { | ||
throw new Error("bucket name has an invalid part: " + parts[i]); | ||
} | ||
} | ||
return parts.join(":"); | ||
} |
@@ -8,2 +8,3 @@ { | ||
"lib": [ "es2017", "dom" ], | ||
"noImplicitAny": true, | ||
"types": [ | ||
@@ -10,0 +11,0 @@ "jest", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
0
342731
12
6687