UNPKG

@gandlaf21/bc-ur

Version:

A JS implementation of the Uniform Resources (UR) specification from Blockchain Commons

133 lines (132 loc) 6.49 kB
"use strict"; var __spreadArrays = (this && this.__spreadArrays) || function () { for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length; for (var r = Array(s), k = 0, i = 0; i < il; i++) for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++) r[k] = a[j]; return r; }; Object.defineProperty(exports, "__esModule", { value: true }); var buffer_1 = require("buffer"); var utils_1 = require("./utils"); var bytewords = 'ableacidalsoapexaquaarchatomauntawayaxisbackbaldbarnbeltbetabiasbluebodybragbrewbulbbuzzcalmcashcatschefcityclawcodecolacookcostcruxcurlcuspcyandarkdatadaysdelidicedietdoordowndrawdropdrumdulldutyeacheasyechoedgeepicevenexamexiteyesfactfairfernfigsfilmfishfizzflapflewfluxfoxyfreefrogfuelfundgalagamegeargemsgiftgirlglowgoodgraygrimgurugushgyrohalfhanghardhawkheathelphighhillholyhopehornhutsicedideaidleinchinkyintoirisironitemjadejazzjoinjoltjowljudojugsjumpjunkjurykeepkenokeptkeyskickkilnkingkitekiwiknoblamblavalazyleaflegsliarlimplionlistlogoloudloveluaulucklungmainmanymathmazememomenumeowmildmintmissmonknailnavyneednewsnextnoonnotenumbobeyoboeomitonyxopenovalowlspaidpartpeckplaypluspoempoolposepuffpumapurrquadquizraceramprealredorichroadrockroofrubyruinrunsrustsafesagascarsetssilkskewslotsoapsolosongstubsurfswantacotasktaxitenttiedtimetinytoiltombtoystriptunatwinuglyundouniturgeuservastveryvetovialvibeviewvisavoidvowswallwandwarmwaspwavewaxywebswhatwhenwhizwolfworkyankyawnyellyogayurtzapszerozestzinczonezoom'; var bytewordsLookUpTable = []; var BYTEWORDS_NUM = 256; var BYTEWORD_LENGTH = 4; var MINIMAL_BYTEWORD_LENGTH = 2; var STYLES; (function (STYLES) { STYLES["STANDARD"] = "standard"; STYLES["URI"] = "uri"; STYLES["MINIMAL"] = "minimal"; })(STYLES || (STYLES = {})); var getWord = function (index) { return bytewords.slice(index * BYTEWORD_LENGTH, (index * BYTEWORD_LENGTH) + BYTEWORD_LENGTH); }; var getMinimalWord = function (index) { var byteword = getWord(index); return "" + byteword[0] + byteword[BYTEWORD_LENGTH - 1]; }; var addCRC = function (string) { var crc = utils_1.getCRCHex(buffer_1.Buffer.from(string, 'hex')); return "" + string + crc; }; var encodeWithSeparator = function (word, separator) { var crcAppendedWord = addCRC(word); var crcWordBuff = buffer_1.Buffer.from(crcAppendedWord, 'hex'); var result = crcWordBuff.reduce(function (result, w) { return (__spreadArrays(result, [getWord(w)])); }, []); return result.join(separator); }; var encodeMinimal = function (word) { var crcAppendedWord = addCRC(word); var crcWordBuff = buffer_1.Buffer.from(crcAppendedWord, 'hex'); var result = crcWordBuff.reduce(function (result, w) { return result + getMinimalWord(w); }, ''); return result; }; var decodeWord = function (word, wordLength) { if (word.length !== wordLength) { throw new Error("'Invalid Bytewords: word.length does not match wordLength provided'"); } var dim = 26; // Since the first and last letters of each Byteword are unique, // we can use them as indexes into a two-dimensional lookup table. // This table is generated lazily. if (bytewordsLookUpTable.length === 0) { var array_len = dim * dim; bytewordsLookUpTable = __spreadArrays(new Array(array_len)).map(function () { return -1; }); for (var i = 0; i < BYTEWORDS_NUM; i++) { var byteword = getWord(i); var x_1 = byteword[0].charCodeAt(0) - 'a'.charCodeAt(0); var y_1 = byteword[3].charCodeAt(0) - 'a'.charCodeAt(0); var offset_1 = y_1 * dim + x_1; bytewordsLookUpTable[offset_1] = i; } } // If the coordinates generated by the first and last letters are out of bounds, // or the lookup table contains -1 at the coordinates, then the word is not valid. var x = (word[0]).toLowerCase().charCodeAt(0) - 'a'.charCodeAt(0); var y = (word[wordLength == 4 ? 3 : 1]).toLowerCase().charCodeAt(0) - 'a'.charCodeAt(0); if (!(0 <= x && x < dim && 0 <= y && y < dim)) { throw new Error("Invalid Bytewords: invalid word"); } var offset = y * dim + x; var value = bytewordsLookUpTable[offset]; if (value === -1) { throw new Error("Invalid Bytewords: value not in lookup table"); } // If we're decoding a full four-letter word, verify that the two middle letters are correct. if (wordLength == BYTEWORD_LENGTH) { var byteword = getWord(value); var c1 = word[1].toLowerCase(); var c2 = word[2].toLowerCase(); if (!(c1 === byteword[1] && c2 === byteword[2])) { throw new Error("Invalid Bytewords: invalid middle letters of word"); } } // Successful decode. return buffer_1.Buffer.from([value]).toString('hex'); }; var _decode = function (string, separator, wordLength) { var words = wordLength == BYTEWORD_LENGTH ? string.split(separator) : utils_1.partition(string, 2); var decodedString = words.map(function (word) { return decodeWord(word, wordLength); }).join(''); if (decodedString.length < 5) { throw new Error("Invalid Bytewords: invalid decoded string length"); } var _a = utils_1.split(buffer_1.Buffer.from(decodedString, 'hex'), 4), body = _a[0], bodyChecksum = _a[1]; var checksum = utils_1.getCRCHex(body); // convert to hex if (checksum !== bodyChecksum.toString('hex')) { throw new Error("Invalid Checksum"); } return body.toString('hex'); }; var decode = function (string, style) { if (style === void 0) { style = STYLES.MINIMAL; } switch (style) { case STYLES.STANDARD: return _decode(string, ' ', BYTEWORD_LENGTH); case STYLES.URI: return _decode(string, '-', BYTEWORD_LENGTH); case STYLES.MINIMAL: return _decode(string, '', MINIMAL_BYTEWORD_LENGTH); default: throw new Error("Invalid style " + style); } }; var encode = function (string, style) { if (style === void 0) { style = STYLES.MINIMAL; } switch (style) { case STYLES.STANDARD: return encodeWithSeparator(string, ' '); case STYLES.URI: return encodeWithSeparator(string, '-'); case STYLES.MINIMAL: return encodeMinimal(string); default: throw new Error("Invalid style " + style); } }; exports.default = { decode: decode, encode: encode, STYLES: STYLES };