UNPKG

@trap_stevo/verilink

Version:

Encrypted from the start. Trusted to the end. This client-side protocol redefines secure communication — forging a direct bridge to zero-trust architecture through encrypted sessions, intelligent attestation, and seamless claim validation. Engineered for

442 lines 19.2 kB
import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray"; import _defineProperty from "@babel/runtime/helpers/defineProperty"; import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator"; import _classCallCheck from "@babel/runtime/helpers/classCallCheck"; import _createClass from "@babel/runtime/helpers/createClass"; function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; } function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; } import _regeneratorRuntime from "@babel/runtime/regenerator"; function _classPrivateMethodInitSpec(e, a) { _checkPrivateRedeclaration(e, a), a.add(e); } function _classPrivateFieldInitSpec(e, t, a) { _checkPrivateRedeclaration(e, t), t.set(e, a); } function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); } function _classPrivateFieldGet(s, a) { return s.get(_assertClassBrand(s, a)); } function _classPrivateFieldSet(s, a, r) { return s.set(_assertClassBrand(s, a), r), r; } function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); } import axios from "axios"; var _algorithm = /*#__PURE__*/new WeakMap(); var _ivLength = /*#__PURE__*/new WeakMap(); var _sessionKey = /*#__PURE__*/new WeakMap(); var _sessionID = /*#__PURE__*/new WeakMap(); var _serverURL = /*#__PURE__*/new WeakMap(); var _vaultSGN = /*#__PURE__*/new WeakMap(); var _deviceID = /*#__PURE__*/new WeakMap(); var _linkSGN = /*#__PURE__*/new WeakMap(); var _paired = /*#__PURE__*/new WeakMap(); var _mutator = /*#__PURE__*/new WeakMap(); var _userAgent = /*#__PURE__*/new WeakMap(); var _VeriLink_brand = /*#__PURE__*/new WeakSet(); var VeriLink = /*#__PURE__*/function () { function VeriLink() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; _classCallCheck(this, VeriLink); _classPrivateMethodInitSpec(this, _VeriLink_brand); _classPrivateFieldInitSpec(this, _algorithm, "AES-GCM"); _classPrivateFieldInitSpec(this, _ivLength, 12); _classPrivateFieldInitSpec(this, _sessionKey, void 0); _classPrivateFieldInitSpec(this, _sessionID, void 0); _classPrivateFieldInitSpec(this, _serverURL, void 0); _classPrivateFieldInitSpec(this, _vaultSGN, void 0); _classPrivateFieldInitSpec(this, _deviceID, void 0); _classPrivateFieldInitSpec(this, _linkSGN, void 0); _classPrivateFieldInitSpec(this, _paired, void 0); _classPrivateFieldInitSpec(this, _mutator, void 0); _classPrivateFieldInitSpec(this, _userAgent, void 0); this.persistSessionKey = options.persistSessionKey || false; this.persistSessionID = options.persistSessionID || false; _classPrivateFieldSet(_mutator, this, typeof options.mutator === "string" ? new TextEncoder().encode(options.mutator) : options.mutator || new TextEncoder().encode("vlk")); _classPrivateFieldSet(_userAgent, this, options.userAgent || "verilink-browser"); _classPrivateFieldSet(_deviceID, this, options.deviceID || null); _classPrivateFieldSet(_vaultSGN, this, options.vaultSGN || "vlx"); _classPrivateFieldSet(_linkSGN, this, options.linkSGN || "vli"); _classPrivateFieldSet(_paired, this, false); this.setServer(options.serverURL || ""); if (options.sessionKey) { this.setKey(options.sessionKey); } else { _classPrivateFieldSet(_sessionKey, this, _assertClassBrand(_VeriLink_brand, this, _loadOrGenerateSessionKey).call(this)); } if (options.sessionID) { _classPrivateFieldSet(_sessionID, this, options.sessionID); } else { _classPrivateFieldSet(_sessionID, this, _assertClassBrand(_VeriLink_brand, this, _loadOrGenerateSessionID).call(this, this.persistSessionID)); } } return _createClass(VeriLink, [{ key: "setServer", value: function setServer(url) { _classPrivateFieldSet(_serverURL, this, url); } }, { key: "setKey", value: function setKey(key) { if (typeof key === "string") { _classPrivateFieldSet(_sessionKey, this, _assertClassBrand(_VeriLink_brand, this, _base64ToArrayBuffer).call(this, key)); } else if (key instanceof ArrayBuffer) { _classPrivateFieldSet(_sessionKey, this, key); } else { throw new Error("Invalid session key data (Base64 string or ArrayBuffer)."); } if (this.persistSessionKey) { var mutated = _assertClassBrand(_VeriLink_brand, this, _mutateForStorage).call(this, _classPrivateFieldGet(_sessionKey, this)); localStorage.setItem(_classPrivateFieldGet(_vaultSGN, this), mutated); } } }, { key: "pair", value: function () { var _pair = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() { var _response$data$succes, _response$data; var pairingURL, sessionKey, sessionID, response, _args = arguments; return _regeneratorRuntime.wrap(function _callee$(_context) { while (1) switch (_context.prev = _context.next) { case 0: pairingURL = _args.length > 0 && _args[0] !== undefined ? _args[0] : "/device/pair"; sessionKey = _assertClassBrand(_VeriLink_brand, this, _arrayBufferToBase).call(this, _classPrivateFieldGet(_sessionKey, this)); sessionID = _classPrivateFieldGet(_sessionID, this); _context.next = 5; return axios.post(_classPrivateFieldGet(_serverURL, this) + pairingURL, { sessionKey: sessionKey }, { headers: { "x-vlink-session-id": sessionID } }); case 5: response = _context.sent; _classPrivateFieldSet(_paired, this, (_response$data$succes = (_response$data = response.data) === null || _response$data === void 0 ? void 0 : _response$data.success) !== null && _response$data$succes !== void 0 ? _response$data$succes : false); return _context.abrupt("return", response.data); case 8: case "end": return _context.stop(); } }, _callee, this); })); function pair() { return _pair.apply(this, arguments); } return pair; }() }, { key: "paired", value: function paired() { return _classPrivateFieldGet(_paired, this); } }, { key: "send", value: function () { var _send = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2(method, path) { var _response$data2; var data, headers, options, methodUpper, url, link, vlinkID, encrypted, claim, config, response, decrypted, _args2 = arguments; return _regeneratorRuntime.wrap(function _callee2$(_context2) { while (1) switch (_context2.prev = _context2.next) { case 0: data = _args2.length > 2 && _args2[2] !== undefined ? _args2[2] : {}; headers = _args2.length > 3 && _args2[3] !== undefined ? _args2[3] : {}; options = _args2.length > 4 && _args2[4] !== undefined ? _args2[4] : { fullResponse: false }; methodUpper = method.toUpperCase(); url = _classPrivateFieldGet(_serverURL, this) + path; link = _assertClassBrand(_VeriLink_brand, this, _generateLink).call(this); _context2.next = 8; return _assertClassBrand(_VeriLink_brand, this, _hmac).call(this, _classPrivateFieldGet(_sessionKey, this), link); case 8: vlinkID = _context2.sent; _context2.next = 11; return _assertClassBrand(_VeriLink_brand, this, _encrypt).call(this, data); case 11: encrypted = _context2.sent; _context2.next = 14; return _assertClassBrand(_VeriLink_brand, this, _signClaim).call(this); case 14: claim = _context2.sent; config = { method: methodUpper, url: url, headers: _objectSpread({ "Content-Type": "application/json", "x-vlink-claim-timestamp": claim.timestamp, "x-vlink-session-id": _classPrivateFieldGet(_sessionID, this), "x-vlink-device": claim.deviceID, "x-vlink-claim": claim.signature, "x-vlink-id": vlinkID, "x-vlink": link }, headers) }; if (methodUpper === "GET") { config.params = { encrypted: encrypted }; } else { config.data = { encrypted: encrypted }; } _context2.next = 19; return axios(config); case 19: response = _context2.sent; if (!((_response$data2 = response.data) !== null && _response$data2 !== void 0 && _response$data2.encrypted)) { _context2.next = 25; break; } _context2.next = 23; return _assertClassBrand(_VeriLink_brand, this, _decrypt).call(this, response.data.encrypted); case 23: decrypted = _context2.sent; return _context2.abrupt("return", options.fullResponse ? { headers: response.headers, status: response.status, data: decrypted, response: response } : decrypted); case 25: return _context2.abrupt("return", options.fullResponse ? { headers: response.headers, status: response.status, data: response.data, response: response } : response.data); case 26: case "end": return _context2.stop(); } }, _callee2, this); })); function send(_x, _x2) { return _send.apply(this, arguments); } return send; }() }]); }(); function _encrypt(_x3) { return _encrypt2.apply(this, arguments); } function _encrypt2() { _encrypt2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3(data) { var iv, key, encoded, encrypted, tag, combined; return _regeneratorRuntime.wrap(function _callee3$(_context3) { while (1) switch (_context3.prev = _context3.next) { case 0: iv = crypto.getRandomValues(new Uint8Array(_classPrivateFieldGet(_ivLength, this))); _context3.next = 3; return crypto.subtle.importKey("raw", _classPrivateFieldGet(_sessionKey, this), { name: _classPrivateFieldGet(_algorithm, this) }, false, ["encrypt"]); case 3: key = _context3.sent; encoded = new TextEncoder().encode(JSON.stringify(data)); _context3.next = 7; return crypto.subtle.encrypt({ name: _classPrivateFieldGet(_algorithm, this), iv: iv }, key, encoded); case 7: encrypted = _context3.sent; tag = encrypted.slice(-16); combined = new Uint8Array(iv.length + tag.byteLength + encrypted.byteLength - 16); combined.set(iv, 0); combined.set(new Uint8Array(tag), iv.length); combined.set(new Uint8Array(encrypted).slice(0, -16), iv.length + tag.byteLength); return _context3.abrupt("return", _assertClassBrand(_VeriLink_brand, this, _arrayBufferToBase).call(this, combined.buffer)); case 14: case "end": return _context3.stop(); } }, _callee3, this); })); return _encrypt2.apply(this, arguments); } function _decrypt(_x4) { return _decrypt2.apply(this, arguments); } function _decrypt2() { _decrypt2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4(b64) { var buffer, iv, tag, ciphertext, key, encrypted, decrypted; return _regeneratorRuntime.wrap(function _callee4$(_context4) { while (1) switch (_context4.prev = _context4.next) { case 0: buffer = new Uint8Array(atob(b64).split("").map(function (c) { return c.charCodeAt(0); })); iv = buffer.slice(0, _classPrivateFieldGet(_ivLength, this)); tag = buffer.slice(_classPrivateFieldGet(_ivLength, this), _classPrivateFieldGet(_ivLength, this) + 16); ciphertext = buffer.slice(_classPrivateFieldGet(_ivLength, this) + 16); _context4.next = 6; return crypto.subtle.importKey("raw", _classPrivateFieldGet(_sessionKey, this), { name: _classPrivateFieldGet(_algorithm, this) }, false, ["decrypt"]); case 6: key = _context4.sent; encrypted = new Uint8Array([].concat(_toConsumableArray(ciphertext), _toConsumableArray(tag))); _context4.next = 10; return crypto.subtle.decrypt({ name: _classPrivateFieldGet(_algorithm, this), iv: iv }, key, encrypted); case 10: decrypted = _context4.sent; return _context4.abrupt("return", JSON.parse(new TextDecoder().decode(decrypted))); case 12: case "end": return _context4.stop(); } }, _callee4, this); })); return _decrypt2.apply(this, arguments); } function _signClaim() { return _signClaim2.apply(this, arguments); } function _signClaim2() { _signClaim2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee5() { var timestamp, payload, signature; return _regeneratorRuntime.wrap(function _callee5$(_context5) { while (1) switch (_context5.prev = _context5.next) { case 0: timestamp = Date.now(); payload = { deviceID: _classPrivateFieldGet(_deviceID, this) || null, timestamp: timestamp, userAgent: _classPrivateFieldGet(_userAgent, this) }; _context5.next = 4; return _assertClassBrand(_VeriLink_brand, this, _hmac).call(this, _classPrivateFieldGet(_sessionKey, this), JSON.stringify(payload)); case 4: signature = _context5.sent; return _context5.abrupt("return", { signature: signature, timestamp: timestamp, deviceID: payload.deviceID }); case 6: case "end": return _context5.stop(); } }, _callee5, this); })); return _signClaim2.apply(this, arguments); } function _hmac(_x5, _x6) { return _hmac2.apply(this, arguments); } function _hmac2() { _hmac2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee6(keyBuffer, data) { var key, encoded, signature; return _regeneratorRuntime.wrap(function _callee6$(_context6) { while (1) switch (_context6.prev = _context6.next) { case 0: _context6.next = 2; return crypto.subtle.importKey("raw", keyBuffer, { name: "HMAC", hash: "SHA-256" }, false, ["sign"]); case 2: key = _context6.sent; encoded = new TextEncoder().encode(data); _context6.next = 6; return crypto.subtle.sign("HMAC", key, encoded); case 6: signature = _context6.sent; return _context6.abrupt("return", _assertClassBrand(_VeriLink_brand, this, _arrayBufferToBase).call(this, signature)); case 8: case "end": return _context6.stop(); } }, _callee6, this); })); return _hmac2.apply(this, arguments); } function _generateLink() { var length = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 16; var array = new Uint8Array(length); crypto.getRandomValues(array); return Array.from(array).map(function (b) { return b.toString(16).padStart(2, "0"); }).join(""); } function _loadOrGenerateSessionKey() { if (this.persistSessionKey) { var stored = localStorage.getItem(_classPrivateFieldGet(_vaultSGN, this)); if (stored) { return _assertClassBrand(_VeriLink_brand, this, _unmutateFromStorage).call(this, stored).buffer; } } var key = crypto.getRandomValues(new Uint8Array(32)); if (this.persistSessionKey) { localStorage.setItem(_classPrivateFieldGet(_vaultSGN, this), _assertClassBrand(_VeriLink_brand, this, _mutateForStorage).call(this, key.buffer)); } return key.buffer; } function _loadOrGenerateSessionID(persist) { var _crypto$randomUUID, _crypto; if (persist) { var stored = localStorage.getItem(_classPrivateFieldGet(_linkSGN, this)); if (stored) { return stored; } } var newID = "vl-".concat(((_crypto$randomUUID = (_crypto = crypto).randomUUID) === null || _crypto$randomUUID === void 0 ? void 0 : _crypto$randomUUID.call(_crypto)) || _assertClassBrand(_VeriLink_brand, this, _fallbackUUID).call(this)); if (persist) { localStorage.setItem(_classPrivateFieldGet(_linkSGN, this), newID); } return newID; } function _fallbackUUID() { return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, function (c) { return (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16); }); } function _mutateForStorage(buffer) { var _this = this; var bytes = new Uint8Array(buffer); var mutated = bytes.map(function (b, i) { return b ^ _classPrivateFieldGet(_mutator, _this)[i % _classPrivateFieldGet(_mutator, _this).length]; }); return btoa(String.fromCharCode.apply(String, _toConsumableArray(mutated))); } function _unmutateFromStorage(base64) { var _this2 = this; var bytes = Uint8Array.from(atob(base64), function (c) { return c.charCodeAt(0); }); var restored = bytes.map(function (b, i) { return b ^ _classPrivateFieldGet(_mutator, _this2)[i % _classPrivateFieldGet(_mutator, _this2).length]; }); return restored; } function _arrayBufferToBase(buffer) { var binary = ""; var bytes = new Uint8Array(buffer); for (var i = 0; i < bytes.byteLength; i++) { binary += String.fromCharCode(bytes[i]); } return btoa(binary); } function _base64ToArrayBuffer(base64) { var binary = atob(base64); var bytes = new Uint8Array(binary.length); for (var i = 0; i < binary.length; i++) { bytes[i] = binary.charCodeAt(i); } return bytes.buffer; } ; export { VeriLink };