UNPKG

blockchain-link

Version:

Link - The Blockchain File Sharing Protocol

502 lines (434 loc) 15.4 kB
// Generated by CoffeeScript 1.6.3 (function() { var BigInteger, LinkSequenceBuilder, LinkSequenceDecoder, alphabet, base, bytesToHex, crypto, decimalToHex, decodeBase58, encodeAddress, encodeAddresses, encodeBase58, hashBuffer, hexToBytes, nbi, nbv, opCodes; crypto = require("crypto"); BigInteger = require("jsbn"); alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; nbi = function() { return new BigInteger(null); }; nbv = function(i) { var r; r = nbi(); r.fromInt(i); return r; }; BigInteger.valueOf = nbv; base = BigInteger.valueOf(58); BigInteger.fromByteArrayUnsigned = function(ba) { if (!ba.length) { return ba.valueOf(0); } else if (ba[0] & 0x80) { return new BigInteger([0].concat(ba)); } else { return new BigInteger(ba); } }; BigInteger.prototype.toByteArrayUnsigned = function() { var ba; ba = this.abs().toByteArray(); if (ba.length) { if (ba[0] === 0) { ba = ba.slice(1); } return ba.map(function(v) { if (v < 0) { return v + 256; } else { return v; } }); } else { return ba; } }; hexToBytes = function(hex) { var bytes, c; bytes = []; c = 0; while (c < hex.length) { bytes.push(parseInt(hex.substr(c, 2), 16)); c += 2; } return bytes; }; bytesToHex = function(bytes) { var hex, i; hex = []; i = 0; while (i < bytes.length) { hex.push((bytes[i] >>> 4).toString(16)); hex.push((bytes[i] & 0xF).toString(16)); i++; } return hex.join(""); }; encodeBase58 = function(input) { var bi, chars, i, mod; bi = BigInteger.fromByteArrayUnsigned(input); chars = []; while (bi.compareTo(base) >= 0) { mod = bi.mod(base); chars.unshift(alphabet[mod.intValue()]); bi = bi.subtract(mod).divide(base); } chars.unshift(alphabet[bi.intValue()]); i = 0; while (i < input.length) { if (input[i] === 0x00) { chars.unshift(alphabet[0]); } else { break; } i++; } return chars.join(""); }; decodeBase58 = function(input) { var alphaIndex, bi, bytes, i, leadingZerosNum; bi = BigInteger.valueOf(0); leadingZerosNum = 0; i = input.length - 1; while (i >= 0) { alphaIndex = alphabet.indexOf(input[i]); if (alphaIndex < 0) { throw "Invalid character"; } bi = bi.add(BigInteger.valueOf(alphaIndex).multiply(base.pow(input.length - 1 - i))); if (input[i] === "1") { leadingZerosNum++; } else { leadingZerosNum = 0; } i--; } bytes = bi.toByteArrayUnsigned(); while (leadingZerosNum-- > 0) { bytes.unshift(0); } return bytes; }; decimalToHex = function(d, padding) { var hex; hex = Number(d).toString(16); padding = (typeof padding === "undefined" || padding === null ? 2 : padding); while (hex.length < padding) { hex = "0" + hex; } return hex; }; hashBuffer = function(algo, buffer) { var hash; hash = crypto.createHash(algo); hash.update(buffer); return hash.digest(); }; encodeAddress = function(buf, version) { var fin, padding, twice; version = version || 0x00; padding = new Buffer(21); padding.fill(version); buf.copy(padding, 1, 0); twice = hashBuffer("sha256", hashBuffer("sha256", padding)); fin = new Buffer(25); padding.copy(fin); twice.copy(fin, 21); return encodeBase58(hexToBytes(fin.toString("hex"))); }; encodeAddresses = function(buf, version) { var next, result, x; version = version || 0x00; result = []; x = 0; while (x < buf.length) { next = buf.slice(x, x + 20); result.push(encodeAddress(next, version)); x = x + 20; } return result; }; opCodes = { startSequenceOpCode: "4c696e6b", inlinePayloadOpCode: "01", attachmentPayloadOpCode: "02", mimeTypeOpCode: "03", payloadEncodingOpCode: "04", payloadMD5OpCode: "05", payloadSHA1OpCode: "06", payloadSHA256OpCode: "07", nameOpCode: "10", descriptionOpCode: "11", keywordsOpCode: "12", uriOpCode: "13", filenameOpCode: "14", originalCreationDateOpCode: "15", lastModifiedDateOpCode: "16", licenseOpCode: "17", referencesTransactionOpCode: "F1", replacesTransactionOpCode: "F2", nextTransactionOpCode: "FF", endSequence: "00" }; LinkSequenceBuilder = (function() { function LinkSequenceBuilder(version) { this.version = version; } LinkSequenceBuilder.prototype.str = opCodes.startSequenceOpCode; LinkSequenceBuilder.prototype.toString = function() { return this.str + opCodes.endSequence; }; LinkSequenceBuilder.prototype.addName = function(name) { return this.str += this.encodeName(name); }; LinkSequenceBuilder.prototype.addDescription = function(description) { return this.str += this.encodeDescription(description); }; LinkSequenceBuilder.prototype.addURI = function(uri) { return this.str += this.encodeURI(uri); }; LinkSequenceBuilder.prototype.addFilename = function(filename) { return this.str += this.encodeFilename(filename); }; LinkSequenceBuilder.prototype.addMimeType = function(mimeType) { return this.str += this.encodeMimeType(mimeType); }; LinkSequenceBuilder.prototype.addKeywords = function(keywords) { return this.str += this.encodeKeywords(keywords); }; LinkSequenceBuilder.prototype.addOriginalCreationDate = function(date) { return this.str += this.encodeOriginalCreationDate(date); }; LinkSequenceBuilder.prototype.addLastModifiedDate = function(date) { return this.str += this.encodeLastModifiedDate(date); }; LinkSequenceBuilder.prototype.addPayloadInline = function(payload) { return this.str += this.encodePayloadInline(payload); }; LinkSequenceBuilder.prototype.addPayloadAttachment = function(buf) { return this.str += this.encodePayloadAttachment(buf); }; LinkSequenceBuilder.prototype.addPayloadMD5 = function(buf) { return this.str += this.encodePayloadMD5Buffer(buf); }; LinkSequenceBuilder.prototype.addPayloadSHA1 = function(buf) { return this.str += this.encodePayloadSHA1Buffer(buf); }; LinkSequenceBuilder.prototype.addPayloadSHA256 = function(buf) { return this.str += this.encodePayloadSHA256Buffer(buf); }; LinkSequenceBuilder.prototype.addLicense = function(license) { return this.str += this.encodeLicense(license); }; LinkSequenceBuilder.prototype.getAddresses = function() { return encodeAddresses(new Buffer(this.toString(), "hex"), this.version); }; LinkSequenceBuilder.prototype.encodeBuffer = function(buf) { return decimalToHex(buf.length, 4) + buf.toString("hex"); }; LinkSequenceBuilder.prototype.encodeString = function(str) { return this.encodeBuffer(new Buffer(str)); }; LinkSequenceBuilder.prototype.encodePayloadInline = function(str) { return opCodes.inlinePayloadOpCode + this.encodeString(str); }; LinkSequenceBuilder.prototype.encodePayloadAttachment = function(buf) { return opCodes.attachmentPayloadOpCode + this.encodeBuffer(buf); }; LinkSequenceBuilder.prototype.encodePayloadEncoding = function(str) { return opCodes.payloadEncodingOpCode + this.encodeString(str); }; LinkSequenceBuilder.prototype.encodePayloadMD5Buffer = function(buf) { return opCodes.payloadMD5OpCode + hashBuffer("md5", buf).toString("hex"); }; LinkSequenceBuilder.prototype.encodePayloadSHA1Buffer = function(buf) { return opCodes.payloadSHA1OpCode + hashBuffer("sha1", buf).toString("hex"); }; LinkSequenceBuilder.prototype.encodePayloadSHA256Buffer = function(buf) { return opCodes.payloadSHA256OpCode + hashBuffer("sha256", buf).toString("hex"); }; LinkSequenceBuilder.prototype.encodeName = function(str) { return opCodes.nameOpCode + this.encodeString(str); }; LinkSequenceBuilder.prototype.encodeDescription = function(str) { return opCodes.descriptionOpCode + this.encodeString(str); }; LinkSequenceBuilder.prototype.encodeURI = function(str) { return opCodes.uriOpCode + this.encodeString(str); }; LinkSequenceBuilder.prototype.encodeFilename = function(str) { return opCodes.filenameOpCode + this.encodeString(str); }; LinkSequenceBuilder.prototype.encodeKeywords = function(str) { return opCodes.keywordsOpCode + this.encodeString(str); }; LinkSequenceBuilder.prototype.encodeMimeType = function(str) { return opCodes.mimeTypeOpCode + this.encodeString(str); }; LinkSequenceBuilder.prototype.encodeOriginalCreationDate = function(date) { return opCodes.originalCreationDateOpCode + decimalToHex(date.getTime(), 12); }; LinkSequenceBuilder.prototype.encodeLastModifiedDate = function(date) { return opCodes.lastModifiedDateOpCode + decimalToHex(date.getTime(), 12); }; LinkSequenceBuilder.prototype.encodeLicense = function(license) { return opcodes.licenseOpCode + this.encodeString(str); }; return LinkSequenceBuilder; })(); LinkSequenceDecoder = (function() { function LinkSequenceDecoder() {} LinkSequenceDecoder.prototype.decode = function(addresses) { var firstFour, ip, nextOp, op, payload, result, running, sequence, startSequence, x; sequence = new Buffer(addresses.length * 20); sequence.fill(0x00); for (x in addresses) { new Buffer(bytesToHex(decodeBase58(addresses[x]).slice(1)), "hex").copy(sequence, x * 20); } startSequence = new Buffer(4); sequence.copy(startSequence); firstFour = startSequence.toString("utf-8"); if (firstFour !== "Link") { throw "First 4 bytes were: " + firstFour; } ip = 4; running = true; result = {}; while (running) { nextOp = new Buffer(1); sequence.copy(nextOp, 0, ip); op = nextOp.toString("hex"); ip++; switch (op) { case opCodes.inlinePayloadOpCode: payload = this.decodeString(sequence, ip); ip += payload[0]; result.payloadInline = payload[1]; break; case opCodes.nameOpCode: payload = this.decodeString(sequence, ip); ip += payload[0]; result.name = payload[1]; break; case opCodes.keywordsOpCode: payload = this.decodeString(sequence, ip); ip += payload[0]; result.keywords = payload[1]; break; case opCodes.descriptionOpCode: payload = this.decodeString(sequence, ip); ip += payload[0]; result.description = payload[1]; break; case opCodes.uriOpCode: payload = this.decodeString(sequence, ip); ip += payload[0]; result.URI = payload[1]; break; case opCodes.filenameOpCode: payload = this.decodeString(sequence, ip); ip += payload[0]; result.filename = payload[1]; break; case opCodes.attachmentPayloadOpCode: payload = this.decodeBuffer(sequence, ip); ip += payload[0]; result.payloadAttachment = payload[1].toString("hex"); break; case opCodes.payloadMD5OpCode: payload = this.decodeBytes(sequence, ip, 16); ip += payload[0]; result.payloadMD5 = payload[1].toString("hex"); break; case opCodes.payloadSHA1OpCode: payload = this.decodeBytes(sequence, ip, 20); ip += payload[0]; result.payloadSHA1 = payload[1].toString("hex"); break; case opCodes.payloadSHA256OpCode: payload = this.decodeBytes(sequence, ip, 32); ip += payload[0]; result.payloadSHA256 = payload[1].toString("hex"); break; case opCodes.originalCreationDateOpCode: result.originalCreationDate = this.decodeDate(sequence, ip); ip += 6; break; case opCodes.lastModifiedDateOpCode: result.lastModifiedDate = this.decodeDate(sequence, ip); ip += 6; break; case opCodes.licenseOpCode: payload = this.decodeString(sequence, ip); ip += payload[0]; result.license = payload[1]; break; case opCodes.endSequence: running = false; } } return result; }; LinkSequenceDecoder.prototype.verify = function(result) { var errors, h, p; errors = []; p = result.payloadAttachment || result.payloadInline; if (p == null) { return; } if (result.payloadMD5 != null) { h = hashBuffer("md5", p); if (h.toString("hex") !== result.payloadMD5) { errors.push("Expected MD5 was " + result.payloadMD5 + " but the payload MD5 is " + h); } } if (result.payloadSHA1 != null) { h = hashBuffer("sha1", p); if (h.toString("hex") !== result.payloadSHA1) { errors.push("Expected SHA-1 was " + result.payloadSHA1 + " but the payload SHA-1 is " + h); } } if (result.payloadSHA256 != null) { h = hashBuffer("sha256", p); if (h.toString("hex") !== result.payloadSHA256) { errors.push("Expected SHA-256 was " + result.payloadSHA256 + " but the payload SHA-256 is " + h); } } return errors; }; LinkSequenceDecoder.prototype.decodeSize = function(buffer, ip) { return parseInt(this.decodeBytes(buffer, ip, 2)[1].toString("hex"), 16); }; LinkSequenceDecoder.prototype.decodeString = function(buffer, ip) { var size; size = this.decodeSize(buffer, ip); return [size + 2, this.decodeBytes(buffer, ip + 2, size)[1].toString("utf-8")]; }; LinkSequenceDecoder.prototype.decodeBuffer = function(buffer, ip) { var size; size = decodeSize(buffer, ip); return [size + 2, this.decodeBytes(buffer, ip + 2, size)[1]]; }; LinkSequenceDecoder.prototype.decodeBytes = function(buffer, ip, length) { var p; p = new Buffer(length); buffer.copy(p, 0, ip); return [length, p]; }; LinkSequenceDecoder.prototype.decodeDate = function(buffer, ip) { var buf, d; buf = new Buffer(6); buffer.copy(buf, 0, ip); return d = new Date(parseInt(buf.toString("hex"), 16)); }; return LinkSequenceDecoder; })(); if (typeof exports !== "undefined" && exports !== null) { exports.LinkSequenceBuilder = module.exports.LinkSequenceBuilder = LinkSequenceBuilder; exports.LinkSequenceEncoder = module.exports.LinkSequenceDecoder = LinkSequenceDecoder; exports.opCodes = module.exports.opCodes = opCodes; exports.decodeBase58 = decodeBase58; exports.encodeBase58 = encodeBase58; exports.bytesToHex = bytesToHex; exports.hashBuffer = hashBuffer; } }).call(this);