From f35c0cf2f1df8c33f65f5900cb8a90c9bd08dece Mon Sep 17 00:00:00 2001 From: polymorpher Date: Sat, 11 Nov 2023 16:12:32 -0800 Subject: [PATCH 01/12] init --- voice/relay/package.json | 3 + voice/relay/src/app.ts | 17 +- voice/relay/src/routes/{index.ts => hard.ts} | 0 voice/relay/src/routes/soft.ts | 28 +++ voice/relay/yarn.lock | 187 ++++++++++++++++++- 5 files changed, 229 insertions(+), 6 deletions(-) rename voice/relay/src/routes/{index.ts => hard.ts} (100%) create mode 100644 voice/relay/src/routes/soft.ts diff --git a/voice/relay/package.json b/voice/relay/package.json index d358af980..87c0e1bb6 100644 --- a/voice/relay/package.json +++ b/voice/relay/package.json @@ -14,11 +14,14 @@ "@types/cookie-parser": "^1.4.4", "axios": "^1.5.1", "cbor": "^9.0.1", + "compression": "^1.7.4", "cookie-parser": "^1.4.6", "cookie-session": "^2.0.0", "cors": "^2.8.5", "dotenv": "^16.3.1", "express": "^4.18.2", + "express-fingerprint": "^1.2.2", + "express-rate-limit": "^7.1.4", "fast-sha256": "^1.3.0", "jsrsasign": "^10.8.6", "morgan": "^1.10.0", diff --git a/voice/relay/src/app.ts b/voice/relay/src/app.ts index 181d320c6..8a3efc075 100644 --- a/voice/relay/src/app.ts +++ b/voice/relay/src/app.ts @@ -1,12 +1,16 @@ import express from 'express' import cookieParser from 'cookie-parser' import morgan from 'morgan' -import apiRouter from './routes/index.js' +import Fingerprint from 'express-fingerprint' + +// import apiRouter from './routes/hard.js' +import apiRouter from './routes/soft.js' import fs from 'fs' import http, { type Server as HttpServer } from 'http' import https from 'https' import config from './config/index.js' import cors from 'cors' +import compression from 'compression' const app = express() let httpServer: HttpServer @@ -30,6 +34,17 @@ if (config.https.only) { httpServer = http.createServer(app) } const httpsServer = https.createServer(httpsOptions, app) +app.use(compression()) +app.use(Fingerprint({ + parameters: [ + // @ts-expect-error missing decl + Fingerprint.useragent, + // @ts-expect-error missing decl + Fingerprint.acceptHeaders, + // @ts-expect-error missing decl + Fingerprint.geoip + ] +})) app.use(morgan('common')) app.use(cookieParser()) diff --git a/voice/relay/src/routes/index.ts b/voice/relay/src/routes/hard.ts similarity index 100% rename from voice/relay/src/routes/index.ts rename to voice/relay/src/routes/hard.ts diff --git a/voice/relay/src/routes/soft.ts b/voice/relay/src/routes/soft.ts new file mode 100644 index 000000000..45710c9ce --- /dev/null +++ b/voice/relay/src/routes/soft.ts @@ -0,0 +1,28 @@ +import { Router, type Request, type Response, type NextFunction } from 'express' +import NodeCache from 'node-cache' +import OpenAIRelay from '../services/openai.js' +import { HttpStatusCode } from 'axios' +import rateLimit from 'express-rate-limit' + +const router: Router = Router() + + +// eslint-disable-next-line @typescript-eslint/explicit-function-return-type +const limiter = (args?: any) => rateLimit({ + windowMs: 1000 * 60, + max: 60, + keyGenerator: req => req.fingerprint?.hash ?? '', + ...args +}) + + + +router.get('/health', (req, res) => { + res.send('OK') +}) + +router.get('/key', limiter(), (req,res) =>{ + +}) + +export default router \ No newline at end of file diff --git a/voice/relay/yarn.lock b/voice/relay/yarn.lock index bf6d38e89..3f0369658 100644 --- a/voice/relay/yarn.lock +++ b/voice/relay/yarn.lock @@ -484,7 +484,7 @@ abort-controller@^3.0.0: dependencies: event-target-shim "^5.0.0" -accepts@~1.3.8: +accepts@~1.3.5, accepts@~1.3.8: version "1.3.8" resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== @@ -633,6 +633,18 @@ asn1js@^3.0.5: pvutils "^1.1.3" tslib "^2.4.0" +"async@2.1 - 2.6.4": + version "2.6.4" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" + integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== + dependencies: + lodash "^4.17.14" + +async@^3.2.0: + version "3.2.5" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66" + integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -702,6 +714,11 @@ braces@^3.0.2: dependencies: fill-range "^7.0.1" +buffer-crc32@~0.2.3: + version "0.2.13" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== + builtins@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.0.1.tgz#87f6db9ab0458be728564fa81d876d8d74552fa9" @@ -709,6 +726,11 @@ builtins@^5.0.1: dependencies: semver "^7.0.0" +bytes@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" + integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== + bytes@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" @@ -756,7 +778,7 @@ cbor@^9.0.1: dependencies: nofilter "^3.1.0" -chalk@^4.0.0, chalk@^4.1.2: +"chalk@4.1 - 4.1.2", chalk@^4.0.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -802,6 +824,26 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" +compressible@~2.0.16: + version "2.0.18" + resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" + integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== + dependencies: + mime-db ">= 1.43.0 < 2" + +compression@^1.7.4: + version "1.7.4" + resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" + integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== + dependencies: + accepts "~1.3.5" + bytes "3.0.0" + compressible "~2.0.16" + debug "2.6.9" + on-headers "~1.0.2" + safe-buffer "5.1.2" + vary "~1.1.2" + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -1329,6 +1371,22 @@ event-target-shim@^5.0.0: resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== +express-fingerprint@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/express-fingerprint/-/express-fingerprint-1.2.2.tgz#bd641a233b6b45096f9c393cf0ad8ae7db7d79a1" + integrity sha512-d+Sw/aEXGslqn4dFoGKliqVghcuiBNY6AAxGGHMz6KcRkMxX+GlrY6TkTmHhCQP/b22KzuXzD9fahDeA1Vq5OQ== + dependencies: + async "^3.2.0" + geoip-lite "^1.4.2" + murmurhash3js "^3.0.1" + traverse "^0.6.6" + useragent "^2.3.0" + +express-rate-limit@^7.1.4: + version "7.1.4" + resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-7.1.4.tgz#c321fe186a8366eacdb2c5edf2ad6a2f6d93e576" + integrity sha512-mv/6z+EwnWpr+MjGVavMGvM4Tl8S/tHmpl9ZsDfrQeHpYy4Hfr0UYdKEf9OOTe280oIr70yPxLRmQ6MfINfJDw== + express@^4.18.2: version "4.18.2" resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" @@ -1404,6 +1462,13 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +fd-slicer@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + integrity sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g== + dependencies: + pend "~1.2.0" + file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -1522,6 +1587,19 @@ functions-have-names@^1.2.3: resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== +geoip-lite@^1.4.2: + version "1.4.8" + resolved "https://registry.yarnpkg.com/geoip-lite/-/geoip-lite-1.4.8.tgz#b9d5353bb43fc67f432fbd5d20eeed01da4c771b" + integrity sha512-72RcD8CsBSDq2Jnbfo1uSy98az8OEg0jP7ikwM/YChG1Okur971Pq7LpEAy6VM1h3EJPNRizuNqoPQwP+RnNbg== + dependencies: + async "2.1 - 2.6.4" + chalk "4.1 - 4.1.2" + iconv-lite "0.4.13 - 0.6.3" + ip-address "5.8.9 - 5.9.4" + lazy "1.0.11" + rimraf "2.5.2 - 2.7.1" + yauzl "2.9.2 - 2.10.0" + get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" @@ -1668,6 +1746,13 @@ humanize-ms@^1.2.1: dependencies: ms "^2.0.0" +"iconv-lite@0.4.13 - 0.6.3": + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -1715,6 +1800,15 @@ internal-slot@^1.0.5: hasown "^2.0.0" side-channel "^1.0.4" +"ip-address@5.8.9 - 5.9.4": + version "5.9.4" + resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-5.9.4.tgz#4660ac261ad61bd397a860a007f7e98e4eaee386" + integrity sha512-dHkI3/YNJq4b/qQaz+c8LuarD3pY24JqZWfjB8aZx1gtpc2MDILu9L9jpZe1sHpzo/yWFweQVn+U//FhazUxmw== + dependencies: + jsbn "1.1.0" + lodash "^4.17.15" + sprintf-js "1.1.2" + ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" @@ -1872,6 +1966,11 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" +jsbn@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" + integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== + json-buffer@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" @@ -1913,6 +2012,11 @@ keyv@^4.5.3: dependencies: json-buffer "3.0.1" +lazy@1.0.11: + version "1.0.11" + resolved "https://registry.yarnpkg.com/lazy/-/lazy-1.0.11.tgz#daa068206282542c088288e975c297c1ae77b690" + integrity sha512-Y+CjUfLmIpoUCCRl0ub4smrYtGGr5AOa2AKOaWelGHOGz33X/Y/KizefGqbkwfz44+cnq/+9habclf8vOmu2LA== + levn@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -1933,11 +2037,19 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash@^4.17.21: +lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +lru-cache@4.1.x: + version "4.1.5" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" + integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== + dependencies: + pseudomap "^1.0.2" + yallist "^2.1.2" + lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -1987,7 +2099,7 @@ micromatch@^4.0.4: braces "^3.0.2" picomatch "^2.3.1" -mime-db@1.52.0: +mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== @@ -2042,6 +2154,11 @@ ms@2.1.3, ms@^2.0.0, ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +murmurhash3js@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/murmurhash3js/-/murmurhash3js-3.0.1.tgz#3e983e5b47c2a06f43a713174e7e435ca044b998" + integrity sha512-KL8QYUaxq7kUbcl0Yto51rMcYt7E/4N4BG3/c96Iqw1PQrTRspu8Cpx4TZ4Nunib1d4bEkIH3gjCYlP2RLBdow== + natural-compare-lite@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" @@ -2192,6 +2309,11 @@ optionator@^0.9.3: prelude-ls "^1.2.1" type-check "^0.4.0" +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== + p-limit@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" @@ -2248,6 +2370,11 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +pend@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== + picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" @@ -2271,6 +2398,11 @@ proxy-from-env@^1.1.0: resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== +pseudomap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + integrity sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ== + punycode@^2.1.0: version "2.3.0" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" @@ -2358,6 +2490,13 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== +"rimraf@2.5.2 - 2.7.1": + version "2.7.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -2408,7 +2547,7 @@ safe-regex-test@^1.0.0: get-intrinsic "^1.1.3" is-regex "^1.1.4" -"safer-buffer@>= 2.1.2 < 3": +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -2514,6 +2653,11 @@ spawn-command@0.0.2: resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2.tgz#9544e1a43ca045f8531aac1a48cb29bdae62338e" integrity sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ== +sprintf-js@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" + integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== + statuses@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" @@ -2596,6 +2740,13 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +tmp@0.0.x: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -2613,6 +2764,11 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== +traverse@^0.6.6: + version "0.6.7" + resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.7.tgz#46961cd2d57dd8706c36664acde06a248f1173fe" + integrity sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg== + tree-kill@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" @@ -2760,6 +2916,14 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +useragent@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.3.0.tgz#217f943ad540cb2128658ab23fc960f6a88c9972" + integrity sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw== + dependencies: + lru-cache "4.1.x" + tmp "0.0.x" + utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" @@ -2846,6 +3010,11 @@ y18n@^5.0.5: resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== +yallist@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + integrity sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A== + yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" @@ -2869,6 +3038,14 @@ yargs@^17.7.2: y18n "^5.0.5" yargs-parser "^21.1.1" +"yauzl@2.9.2 - 2.10.0": + version "2.10.0" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + integrity sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g== + dependencies: + buffer-crc32 "~0.2.3" + fd-slicer "~1.1.0" + yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" From 89bd463e8d022d6c89471bca2d03afd2b10a1ffb Mon Sep 17 00:00:00 2001 From: polymorpher Date: Sat, 11 Nov 2023 18:28:54 -0800 Subject: [PATCH 02/12] relay update --- voice/relay/package.json | 7 +- voice/relay/src/app.ts | 33 +++-- voice/relay/src/config/index.ts | 9 +- voice/relay/src/routes/soft.ts | 62 +++++++--- voice/relay/src/utils.ts | 19 +++ voice/relay/tsconfig.json | 3 +- voice/relay/types/express/index.d.ts | 9 ++ voice/relay/yarn.lock | 174 ++++----------------------- 8 files changed, 134 insertions(+), 182 deletions(-) create mode 100644 voice/relay/types/express/index.d.ts diff --git a/voice/relay/package.json b/voice/relay/package.json index 87c0e1bb6..9fded984a 100644 --- a/voice/relay/package.json +++ b/voice/relay/package.json @@ -12,6 +12,7 @@ "dependencies": { "@simplewebauthn/server": "^8.3.2", "@types/cookie-parser": "^1.4.4", + "@types/request-ip": "^0.0.41", "axios": "^1.5.1", "cbor": "^9.0.1", "compression": "^1.7.4", @@ -20,15 +21,17 @@ "cors": "^2.8.5", "dotenv": "^16.3.1", "express": "^4.18.2", - "express-fingerprint": "^1.2.2", "express-rate-limit": "^7.1.4", "fast-sha256": "^1.3.0", + "http-errors": "^2.0.0", "jsrsasign": "^10.8.6", "morgan": "^1.10.0", "node-cache": "^5.1.2", - "openai": "^4.14.0" + "openai": "^4.14.0", + "request-ip": "^3.3.0" }, "devDependencies": { + "@types/compression": "^1.7.5", "@types/cookie": "^0.5.2", "@types/cookie-session": "^2.0.45", "@types/cors": "^2.8.14", diff --git a/voice/relay/src/app.ts b/voice/relay/src/app.ts index 8a3efc075..5dee494f5 100644 --- a/voice/relay/src/app.ts +++ b/voice/relay/src/app.ts @@ -1,8 +1,7 @@ -import express from 'express' +import express, { type Response, type Request, type NextFunction } from 'express' import cookieParser from 'cookie-parser' import morgan from 'morgan' -import Fingerprint from 'express-fingerprint' - +import createError from 'http-errors' // import apiRouter from './routes/hard.js' import apiRouter from './routes/soft.js' import fs from 'fs' @@ -11,6 +10,7 @@ import https from 'https' import config from './config/index.js' import cors from 'cors' import compression from 'compression' +import requestIp from 'request-ip' const app = express() let httpServer: HttpServer @@ -35,16 +35,7 @@ if (config.https.only) { } const httpsServer = https.createServer(httpsOptions, app) app.use(compression()) -app.use(Fingerprint({ - parameters: [ - // @ts-expect-error missing decl - Fingerprint.useragent, - // @ts-expect-error missing decl - Fingerprint.acceptHeaders, - // @ts-expect-error missing decl - Fingerprint.geoip - ] -})) +app.use(requestIp.mw()) app.use(morgan('common')) app.use(cookieParser()) @@ -75,6 +66,22 @@ app.options('*', async (_req, res) => { app.use('/', apiRouter) +// catch 404 and forward to error handler +app.use(function (req, res, next) { + next(createError(404)) +}) + +// error handler +app.use((err: Error, req: Request, res: Response, next: NextFunction) => { + // set locals, only providing error in development + res.locals.message = err.message + res.locals.error = config.debug ? err : '' + + // render the error page + res.status(500) + res.json({ error: res.locals.error, message: err.message, stack: config.debug ? err.stack : undefined }) +}) + export { httpServer, httpsServer diff --git a/voice/relay/src/config/index.ts b/voice/relay/src/config/index.ts index a98e97c32..b633b941e 100644 --- a/voice/relay/src/config/index.ts +++ b/voice/relay/src/config/index.ts @@ -15,7 +15,14 @@ const config = { packageName: process.env.PACKAGE_NAME ?? '', openai: { key: process.env.OPENAI_KEY ?? '' }, deepgram: { key: process.env.DEEPGRAM_KEY ?? '' }, - playht: { key: process.env.PLAYHT_KEY ?? '' }, + playht: { key: process.env.PLAYHT_KEY ?? '' } } +export const OpenAIDistributedKeys: string[] = JSON.parse(process.env.OPENAI_DISTRIBUTED_KEYS ?? '[]') +export const BlockedDeviceIds: string[] = JSON.parse(process.env.BLOCKED_DEVICE_IDS ?? '[]') +export const BlockedIps: string[] = JSON.parse(process.env.BLOCKED_IPS ?? '[]') + +export const SharedEncryptionSecret: string = process.env.SHARED_ENCRYPTION_SECRET ?? '' +export const SharedEncryptionIV: string = process.env.SHARED_ENCRYPTION_IV ?? '' + export default config diff --git a/voice/relay/src/routes/soft.ts b/voice/relay/src/routes/soft.ts index 45710c9ce..c1cf21918 100644 --- a/voice/relay/src/routes/soft.ts +++ b/voice/relay/src/routes/soft.ts @@ -1,28 +1,62 @@ import { Router, type Request, type Response, type NextFunction } from 'express' -import NodeCache from 'node-cache' -import OpenAIRelay from '../services/openai.js' import { HttpStatusCode } from 'axios' -import rateLimit from 'express-rate-limit' - +import rateLimit, { type Options as RLOptions, type RateLimitRequestHandler } from 'express-rate-limit' +import { BlockedDeviceIds, BlockedIps, OpenAIDistributedKeys } from '../config/index.js' +import { encrypt, hexString, stringToBytes } from '../utils.js' +import { hash as sha256 } from 'fast-sha256' const router: Router = Router() +const deviceLimiter = (args?: RLOptions): RateLimitRequestHandler => rateLimit({ + windowMs: 1000 * 60, + limit: 10, + keyGenerator: req => req.header('x-device-token') ?? '', + ...args +}) // eslint-disable-next-line @typescript-eslint/explicit-function-return-type -const limiter = (args?: any) => rateLimit({ - windowMs: 1000 * 60, - max: 60, - keyGenerator: req => req.fingerprint?.hash ?? '', - ...args +const ipLimiter = (args?: RLOptions): RateLimitRequestHandler => rateLimit({ + windowMs: 1000 * 60, + limit: 10, + keyGenerator: req => req.clientIp ?? 'N/A', + ...args }) - +const parseDeviceToken = (req: Request, res: Response, next: NextFunction): any => { + const deviceToken = req.header('x-device-token') + if (!deviceToken) { + res.status(HttpStatusCode.Forbidden).json({ error: 'device unsupported', code: 100 }) + return + } + if (BlockedDeviceIds.includes(deviceToken)) { + res.status(HttpStatusCode.Forbidden).json({ error: 'device banned', code: 101 }) + return + } + req.deviceToken = deviceToken + next() +} + +const checkIpBan = (req: Request, res: Response, next: NextFunction): any => { + if (!req.clientIp) { + console.error('[checkIpBan] Cannot find ip of request', req) + } + if (BlockedIps.includes(req.clientIp ?? 'N/A')) { + res.status(HttpStatusCode.Forbidden).json({ error: 'ip banned', code: 102 }) + } + next() +} router.get('/health', (req, res) => { - res.send('OK') + res.send('OK') }) -router.get('/key', limiter(), (req,res) =>{ - +router.get('/key', parseDeviceToken, checkIpBan, deviceLimiter(), ipLimiter(), (req, res) => { + const deviceToken = req.deviceToken + const numKeys = BigInt(OpenAIDistributedKeys.length) + const h = hexString(sha256(stringToBytes(deviceToken))) + const keyIndex = Number(BigInt(h) % numKeys) + const key = OpenAIDistributedKeys[keyIndex] + const encryptedKey = encrypt(key) + res.json({ key: encryptedKey.toString('base64') }) }) -export default router \ No newline at end of file +export default router diff --git a/voice/relay/src/utils.ts b/voice/relay/src/utils.ts index 2950c29c1..4f712a4a8 100644 --- a/voice/relay/src/utils.ts +++ b/voice/relay/src/utils.ts @@ -1,3 +1,6 @@ +import crypto from 'crypto' +import { SharedEncryptionIV, SharedEncryptionSecret } from './config/index.js' + export const hexView = (bytes: Buffer | Uint8Array): string => { return bytes && Array.from(bytes).map(x => x.toString(16).padStart(2, '0')).join('') } @@ -20,3 +23,19 @@ export function chunkstr (str: string, size: number): string[] { return chunks } + +const aesKey = crypto + .createHash('sha512') + .update(SharedEncryptionSecret) + .digest('hex') + .substring(0, 32) +const aesIv = crypto + .createHash('sha512') + .update(SharedEncryptionIV) + .digest('hex') + .substring(0, 16) + +export function encrypt (s: string): Buffer { + const cipher = crypto.createCipheriv('aes-256-gcm', aesKey, aesIv) + return Buffer.concat([cipher.update(s, 'utf8'), cipher.final()]) +} diff --git a/voice/relay/tsconfig.json b/voice/relay/tsconfig.json index c5a45e7b0..ffdc6f742 100644 --- a/voice/relay/tsconfig.json +++ b/voice/relay/tsconfig.json @@ -12,6 +12,7 @@ "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ "strict": true, /* Enable all strict type-checking options. */ "skipLibCheck": true, /* Skip type checking all .d.ts files. */ - "declaration": true + "declaration": true, + "typeRoots": ["./types"] } } diff --git a/voice/relay/types/express/index.d.ts b/voice/relay/types/express/index.d.ts new file mode 100644 index 000000000..ea9ed02c8 --- /dev/null +++ b/voice/relay/types/express/index.d.ts @@ -0,0 +1,9 @@ +declare global { + namespace Express { + interface Request { + deviceToken: string + } + } +} + +export {} diff --git a/voice/relay/yarn.lock b/voice/relay/yarn.lock index 3f0369658..2581dd05d 100644 --- a/voice/relay/yarn.lock +++ b/voice/relay/yarn.lock @@ -243,6 +243,13 @@ "@types/connect" "*" "@types/node" "*" +"@types/compression@^1.7.5": + version "1.7.5" + resolved "https://registry.yarnpkg.com/@types/compression/-/compression-1.7.5.tgz#0f80efef6eb031be57b12221c4ba6bc3577808f7" + integrity sha512-AAQvK5pxMpaT+nDvhHrsBhLSYG5yQdtkaJE1WYieSNY2mVFKAgmU4ks65rkZD5oqnGCFLyQpUr1CqI4DmUMyDg== + dependencies: + "@types/express" "*" + "@types/connect@*": version "3.4.37" resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.37.tgz#c66a96689fd3127c8772eb3e9e5c6028ec1a9af5" @@ -371,6 +378,13 @@ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.6.tgz#7cb33992049fd7340d5b10c0098e104184dfcd2a" integrity sha512-+0autS93xyXizIYiyL02FCY8N+KkKPhILhcUSA276HxzreZ16kl+cmwvV2qAM/PuCCwPXzOXOWhiPcw20uSFcA== +"@types/request-ip@^0.0.41": + version "0.0.41" + resolved "https://registry.yarnpkg.com/@types/request-ip/-/request-ip-0.0.41.tgz#c22a3244df2573402989346062851b06b7a5ac4e" + integrity sha512-Qzz0PM2nSZej4lsLzzNfADIORZhhxO7PED0fXpg4FjXiHuJ/lMyUg+YFF5q8x9HPZH3Gl6N+NOM8QZjItNgGKg== + dependencies: + "@types/node" "*" + "@types/semver@^7.3.12": version "7.5.4" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.4.tgz#0a41252ad431c473158b22f9bfb9a63df7541cff" @@ -633,18 +647,6 @@ asn1js@^3.0.5: pvutils "^1.1.3" tslib "^2.4.0" -"async@2.1 - 2.6.4": - version "2.6.4" - resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" - integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== - dependencies: - lodash "^4.17.14" - -async@^3.2.0: - version "3.2.5" - resolved "https://registry.yarnpkg.com/async/-/async-3.2.5.tgz#ebd52a8fdaf7a2289a24df399f8d8485c8a46b66" - integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== - asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -714,11 +716,6 @@ braces@^3.0.2: dependencies: fill-range "^7.0.1" -buffer-crc32@~0.2.3: - version "0.2.13" - resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" - integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== - builtins@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/builtins/-/builtins-5.0.1.tgz#87f6db9ab0458be728564fa81d876d8d74552fa9" @@ -778,7 +775,7 @@ cbor@^9.0.1: dependencies: nofilter "^3.1.0" -"chalk@4.1 - 4.1.2", chalk@^4.0.0, chalk@^4.1.2: +chalk@^4.0.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -1371,17 +1368,6 @@ event-target-shim@^5.0.0: resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== -express-fingerprint@^1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/express-fingerprint/-/express-fingerprint-1.2.2.tgz#bd641a233b6b45096f9c393cf0ad8ae7db7d79a1" - integrity sha512-d+Sw/aEXGslqn4dFoGKliqVghcuiBNY6AAxGGHMz6KcRkMxX+GlrY6TkTmHhCQP/b22KzuXzD9fahDeA1Vq5OQ== - dependencies: - async "^3.2.0" - geoip-lite "^1.4.2" - murmurhash3js "^3.0.1" - traverse "^0.6.6" - useragent "^2.3.0" - express-rate-limit@^7.1.4: version "7.1.4" resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-7.1.4.tgz#c321fe186a8366eacdb2c5edf2ad6a2f6d93e576" @@ -1462,13 +1448,6 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" -fd-slicer@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" - integrity sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g== - dependencies: - pend "~1.2.0" - file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -1587,19 +1566,6 @@ functions-have-names@^1.2.3: resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== -geoip-lite@^1.4.2: - version "1.4.8" - resolved "https://registry.yarnpkg.com/geoip-lite/-/geoip-lite-1.4.8.tgz#b9d5353bb43fc67f432fbd5d20eeed01da4c771b" - integrity sha512-72RcD8CsBSDq2Jnbfo1uSy98az8OEg0jP7ikwM/YChG1Okur971Pq7LpEAy6VM1h3EJPNRizuNqoPQwP+RnNbg== - dependencies: - async "2.1 - 2.6.4" - chalk "4.1 - 4.1.2" - iconv-lite "0.4.13 - 0.6.3" - ip-address "5.8.9 - 5.9.4" - lazy "1.0.11" - rimraf "2.5.2 - 2.7.1" - yauzl "2.9.2 - 2.10.0" - get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" @@ -1728,7 +1694,7 @@ hasown@^2.0.0: dependencies: function-bind "^1.1.2" -http-errors@2.0.0: +http-errors@2.0.0, http-errors@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== @@ -1746,13 +1712,6 @@ humanize-ms@^1.2.1: dependencies: ms "^2.0.0" -"iconv-lite@0.4.13 - 0.6.3": - version "0.6.3" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" - integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== - dependencies: - safer-buffer ">= 2.1.2 < 3.0.0" - iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -1800,15 +1759,6 @@ internal-slot@^1.0.5: hasown "^2.0.0" side-channel "^1.0.4" -"ip-address@5.8.9 - 5.9.4": - version "5.9.4" - resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-5.9.4.tgz#4660ac261ad61bd397a860a007f7e98e4eaee386" - integrity sha512-dHkI3/YNJq4b/qQaz+c8LuarD3pY24JqZWfjB8aZx1gtpc2MDILu9L9jpZe1sHpzo/yWFweQVn+U//FhazUxmw== - dependencies: - jsbn "1.1.0" - lodash "^4.17.15" - sprintf-js "1.1.2" - ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" @@ -1966,11 +1916,6 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" -jsbn@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" - integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== - json-buffer@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" @@ -2012,11 +1957,6 @@ keyv@^4.5.3: dependencies: json-buffer "3.0.1" -lazy@1.0.11: - version "1.0.11" - resolved "https://registry.yarnpkg.com/lazy/-/lazy-1.0.11.tgz#daa068206282542c088288e975c297c1ae77b690" - integrity sha512-Y+CjUfLmIpoUCCRl0ub4smrYtGGr5AOa2AKOaWelGHOGz33X/Y/KizefGqbkwfz44+cnq/+9habclf8vOmu2LA== - levn@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -2037,19 +1977,11 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.21: +lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== -lru-cache@4.1.x: - version "4.1.5" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" - integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - lru-cache@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" @@ -2154,11 +2086,6 @@ ms@2.1.3, ms@^2.0.0, ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -murmurhash3js@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/murmurhash3js/-/murmurhash3js-3.0.1.tgz#3e983e5b47c2a06f43a713174e7e435ca044b998" - integrity sha512-KL8QYUaxq7kUbcl0Yto51rMcYt7E/4N4BG3/c96Iqw1PQrTRspu8Cpx4TZ4Nunib1d4bEkIH3gjCYlP2RLBdow== - natural-compare-lite@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz#17b09581988979fddafe0201e931ba933c96cbb4" @@ -2309,11 +2236,6 @@ optionator@^0.9.3: prelude-ls "^1.2.1" type-check "^0.4.0" -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== - p-limit@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" @@ -2370,11 +2292,6 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== -pend@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" - integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== - picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" @@ -2398,11 +2315,6 @@ proxy-from-env@^1.1.0: resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ== - punycode@^2.1.0: version "2.3.0" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" @@ -2466,6 +2378,11 @@ regexpp@^3.0.0: resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== +request-ip@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/request-ip/-/request-ip-3.3.0.tgz#863451e8fec03847d44f223e30a5d63e369fa611" + integrity sha512-cA6Xh6e0fDBBBwH77SLJaJPBmD3nWVAcF9/XAcsrIHdjhFzFiB5aNQFytdjCGPezU3ROwrR11IddKAM08vohxA== + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -2490,13 +2407,6 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -"rimraf@2.5.2 - 2.7.1": - version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - dependencies: - glob "^7.1.3" - rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -2547,7 +2457,7 @@ safe-regex-test@^1.0.0: get-intrinsic "^1.1.3" is-regex "^1.1.4" -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": +"safer-buffer@>= 2.1.2 < 3": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -2653,11 +2563,6 @@ spawn-command@0.0.2: resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2.tgz#9544e1a43ca045f8531aac1a48cb29bdae62338e" integrity sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ== -sprintf-js@1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" - integrity sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug== - statuses@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" @@ -2740,13 +2645,6 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== -tmp@0.0.x: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -2764,11 +2662,6 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== -traverse@^0.6.6: - version "0.6.7" - resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.6.7.tgz#46961cd2d57dd8706c36664acde06a248f1173fe" - integrity sha512-/y956gpUo9ZNCb99YjxG7OaslxZWHfCHAUUfshwqOXmxUIvqLjVO581BT+gM59+QV9tFe6/CGG53tsA1Y7RSdg== - tree-kill@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" @@ -2916,14 +2809,6 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" -useragent@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.3.0.tgz#217f943ad540cb2128658ab23fc960f6a88c9972" - integrity sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw== - dependencies: - lru-cache "4.1.x" - tmp "0.0.x" - utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" @@ -3010,11 +2895,6 @@ y18n@^5.0.5: resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A== - yallist@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" @@ -3038,14 +2918,6 @@ yargs@^17.7.2: y18n "^5.0.5" yargs-parser "^21.1.1" -"yauzl@2.9.2 - 2.10.0": - version "2.10.0" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" - integrity sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g== - dependencies: - buffer-crc32 "~0.2.3" - fd-slicer "~1.1.0" - yn@3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" From a2244a6d52e1d7e1e3d8830b416d7fb87e988702 Mon Sep 17 00:00:00 2001 From: polymorpher Date: Sat, 11 Nov 2023 20:12:22 -0800 Subject: [PATCH 03/12] relay: add todo for verification; simplify aes --- voice/relay/src/routes/soft.ts | 1 + voice/relay/src/utils.ts | 13 +++---------- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/voice/relay/src/routes/soft.ts b/voice/relay/src/routes/soft.ts index c1cf21918..89e20595e 100644 --- a/voice/relay/src/routes/soft.ts +++ b/voice/relay/src/routes/soft.ts @@ -50,6 +50,7 @@ router.get('/health', (req, res) => { }) router.get('/key', parseDeviceToken, checkIpBan, deviceLimiter(), ipLimiter(), (req, res) => { + // TODO: validate the device token, https://developer.apple.com/documentation/devicecheck/accessing_and_modifying_per-device_data const deviceToken = req.deviceToken const numKeys = BigInt(OpenAIDistributedKeys.length) const h = hexString(sha256(stringToBytes(deviceToken))) diff --git a/voice/relay/src/utils.ts b/voice/relay/src/utils.ts index 4f712a4a8..7ad2e7e82 100644 --- a/voice/relay/src/utils.ts +++ b/voice/relay/src/utils.ts @@ -1,5 +1,6 @@ import crypto from 'crypto' import { SharedEncryptionIV, SharedEncryptionSecret } from './config/index.js' +import { hash as sha256 } from 'fast-sha256' export const hexView = (bytes: Buffer | Uint8Array): string => { return bytes && Array.from(bytes).map(x => x.toString(16).padStart(2, '0')).join('') @@ -24,16 +25,8 @@ export function chunkstr (str: string, size: number): string[] { return chunks } -const aesKey = crypto - .createHash('sha512') - .update(SharedEncryptionSecret) - .digest('hex') - .substring(0, 32) -const aesIv = crypto - .createHash('sha512') - .update(SharedEncryptionIV) - .digest('hex') - .substring(0, 16) +const aesKey = sha256(stringToBytes(SharedEncryptionSecret)).slice(0, 32) +const aesIv = sha256(stringToBytes(SharedEncryptionIV)).slice(0, 16) export function encrypt (s: string): Buffer { const cipher = crypto.createCipheriv('aes-256-gcm', aesKey, aesIv) From b6f6a8a5ee8508b9d1672ceba26aa2eeae56c454 Mon Sep 17 00:00:00 2001 From: polymorpher Date: Sat, 11 Nov 2023 20:17:18 -0800 Subject: [PATCH 04/12] decrypt and process key at client side --- .../Voice AI.xcodeproj/project.pbxproj | 17 ++++ .../xcshareddata/swiftpm/Package.resolved | 9 ++ .../x/AppConfigration/AppConfig.swift | 88 +++++++++++++++++-- .../x/OpenAIService/OpenAIService.swift | 2 +- .../x/OpenAIService/OpenAIStreamService.swift | 2 +- voice/voice-ai/xTests/AppConfigTests.swift | 4 +- 6 files changed, 113 insertions(+), 9 deletions(-) diff --git a/voice/voice-ai/Voice AI.xcodeproj/project.pbxproj b/voice/voice-ai/Voice AI.xcodeproj/project.pbxproj index 7bdea2fb5..f90e4915c 100644 --- a/voice/voice-ai/Voice AI.xcodeproj/project.pbxproj +++ b/voice/voice-ai/Voice AI.xcodeproj/project.pbxproj @@ -148,6 +148,7 @@ CD0D13672ADA74C800031EDD /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD0D13662ADA74C800031EDD /* CoreAudio.framework */; }; CD0D13692ADA74D100031EDD /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CD0D13682ADA74D100031EDD /* AVFoundation.framework */; }; CD0D136B2ADB28CE00031EDD /* logo.png in Resources */ = {isa = PBXBuildFile; fileRef = CD0D136A2ADB28CE00031EDD /* logo.png */; }; + CD8A1A652B0084C400A5B2CC /* CryptoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = CD8A1A642B0084C400A5B2CC /* CryptoSwift */; }; F610490A2AF02D820087F745 /* OpenAIStreamService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F61049092AF02D820087F745 /* OpenAIStreamService.swift */; }; F610490B2AF02D820087F745 /* OpenAIStreamService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F61049092AF02D820087F745 /* OpenAIStreamService.swift */; }; F610490C2AF02D820087F745 /* OpenAIStreamService.swift in Sources */ = {isa = PBXBuildFile; fileRef = F61049092AF02D820087F745 /* OpenAIStreamService.swift */; }; @@ -318,6 +319,7 @@ buildActionMask = 2147483647; files = ( F61049102AF02DEE0087F745 /* SwiftyJSON in Frameworks */, + CD8A1A652B0084C400A5B2CC /* CryptoSwift in Frameworks */, F67E43322AFAC166001B72CD /* SentrySwiftUI in Frameworks */, CD0D13692ADA74D100031EDD /* AVFoundation.framework in Frameworks */, B9B331A32AFB849000F6A9C9 /* StoreKit.framework in Frameworks */, @@ -702,6 +704,7 @@ F610490F2AF02DEE0087F745 /* SwiftyJSON */, F67E43312AFAC166001B72CD /* SentrySwiftUI */, F67E43332AFAC16C001B72CD /* Sentry */, + CD8A1A642B0084C400A5B2CC /* CryptoSwift */, ); productName = x; productReference = CD0D13342ADA73B300031EDD /* Voice AI.app */; @@ -793,6 +796,7 @@ packageReferences = ( F610490E2AF02DE20087F745 /* XCRemoteSwiftPackageReference "SwiftyJSON" */, F67E43302AFAB71F001B72CD /* XCRemoteSwiftPackageReference "sentry-cocoa" */, + CD8A1A632B0084A900A5B2CC /* XCRemoteSwiftPackageReference "CryptoSwift" */, ); productRefGroup = CD0D13352ADA73B300031EDD /* Products */; projectDirPath = ""; @@ -1603,6 +1607,14 @@ /* End XCConfigurationList section */ /* Begin XCRemoteSwiftPackageReference section */ + CD8A1A632B0084A900A5B2CC /* XCRemoteSwiftPackageReference "CryptoSwift" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/krzyzanowskim/CryptoSwift.git"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 1.8.0; + }; + }; F610490E2AF02DE20087F745 /* XCRemoteSwiftPackageReference "SwiftyJSON" */ = { isa = XCRemoteSwiftPackageReference; repositoryURL = "https://github.com/SwiftyJSON/SwiftyJSON"; @@ -1627,6 +1639,11 @@ package = F610490E2AF02DE20087F745 /* XCRemoteSwiftPackageReference "SwiftyJSON" */; productName = SwiftyJSON; }; + CD8A1A642B0084C400A5B2CC /* CryptoSwift */ = { + isa = XCSwiftPackageProductDependency; + package = CD8A1A632B0084A900A5B2CC /* XCRemoteSwiftPackageReference "CryptoSwift" */; + productName = CryptoSwift; + }; F610490F2AF02DEE0087F745 /* SwiftyJSON */ = { isa = XCSwiftPackageProductDependency; package = F610490E2AF02DE20087F745 /* XCRemoteSwiftPackageReference "SwiftyJSON" */; diff --git a/voice/voice-ai/Voice AI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved b/voice/voice-ai/Voice AI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved index 4bef53db1..58a93defd 100644 --- a/voice/voice-ai/Voice AI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/voice/voice-ai/Voice AI.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -1,5 +1,14 @@ { "pins" : [ + { + "identity" : "cryptoswift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/krzyzanowskim/CryptoSwift.git", + "state" : { + "revision" : "db51c407d3be4a051484a141bf0bff36c43d3b1e", + "version" : "1.8.0" + } + }, { "identity" : "sentry-cocoa", "kind" : "remoteSourceControl", diff --git a/voice/voice-ai/x/AppConfigration/AppConfig.swift b/voice/voice-ai/x/AppConfigration/AppConfig.swift index f70718f4d..e67020402 100644 --- a/voice/voice-ai/x/AppConfigration/AppConfig.swift +++ b/voice/voice-ai/x/AppConfigration/AppConfig.swift @@ -1,10 +1,16 @@ +import CryptoSwift +import DeviceCheck import Foundation import Sentry +import SwiftyJSON class AppConfig { // Shared singleton instance static let shared = AppConfig() - private var apiKey: String? + private var openaiKey: String? + private var relayUrl: String? + private var sharedEncryptionSecret: String? + private var sharedEncryptionIV: String? private var deepgramKey: String? private var minimumSignificantEvents: Int? private var daysBetweenPrompts: Int? @@ -16,6 +22,76 @@ class AppConfig { self.loadConfiguration() } + private func decrypt(base64EncodedEncryptedKey: String) throws -> String { + let d = Data(base64Encoded: base64EncodedEncryptedKey) + guard let d = d else { + throw NSError(domain: "Invalid encoded encrypted key", code: -1) + } + let encryptedKey = String(data: d, encoding: .utf8) + guard let encryptedKey = encryptedKey else { + throw NSError(domain: "Malformed key encoding", code: -2) + } + let iv: [UInt8] = Array(self.sharedEncryptionIV!.utf8) + let sharedKey: [UInt8] = Array(self.sharedEncryptionSecret!.utf8) + let aes = try AES(key: sharedKey, blockMode: GCM(iv: iv)) + let dBytes = try aes.decrypt(encryptedKey.bytes) + let dKey = String(data: Data(dBytes), encoding: .utf8) + guard let key = dKey else { + throw NSError(domain: "Key is not a string", code: -3) + } + return key + } + + private func requestOpenAIKey() async { + guard let relayUrl = self.relayUrl else { + print("Relay URL not set") + SentrySDK.capture(message: "Relay URL not set") + return + } + let s = URLSession(configuration: .default) + guard let url = URL(string: "\(relayUrl)/key") else { + let error = NSError(domain: "Invalid Relay URL", code: -1, userInfo: nil) + SentrySDK.capture(message: "Invalid Relay URL") + return + } + var token = "" + do { + let d = try await DCDevice.current.generateToken() + print("token", d) + token = d.base64EncodedString() + } catch { + SentrySDK.capture(message: "Error generating device token") + print(error) + return + } + var r = URLRequest(url: url) + r.setValue(token, forHTTPHeaderField: "X-DEVICE-TOKEN") + s.dataTask(with: r) { data, _, err in + if let err = err { + print("[AppConfig][requestOpenAIKey] cannot get key", err) + SentrySDK.capture(message: "Cannot get key. Error: \(err)") + return + } + do { + let res = try JSON(data: data!) + let eeKey = res["key"].string + guard let eeKey = eeKey else { + print("[AppConfig][requestOpenAIKey] response has no key", res) + SentrySDK.capture(message: "[AppConfig][requestOpenAIKey] response has no key") + return + } + // TODO: decrypt key + let key = try self.decrypt(base64EncodedEncryptedKey: eeKey) + self.openaiKey = key + print("Got key", key) + } catch { + print("[AppConfig][requestOpenAIKey] error processing key response", error) + SentrySDK.capture(message: "[AppConfig][requestOpenAIKey] error processing key response \(error)") + } + } +// s.dataTask(with: "") + } + private func loadConfiguration() { guard let path = Bundle.main.path(forResource: "AppConfig", ofType: "plist") else { fatalError("Unable to locate plist file") @@ -29,10 +105,12 @@ class AppConfig { fatalError("Unable to convert plist into dictionary") } - self.apiKey = dictionary["API_KEY"] - self.sentryDSN = dictionary["SENTRY_DSN"] + self.sharedEncryptionSecret = dictionary["SHARED_ENCRYPTION_SECRET"] + self.sharedEncryptionIV = dictionary["SHARED_ENCRYPTION_IV"] + self.relayUrl = dictionary["RELAY_URL"] + self.themeName = dictionary["THEME_NAME"] self.deepgramKey = dictionary["DEEPGRAM_KEY"] @@ -55,8 +133,8 @@ class AppConfig { } } - func getAPIKey() -> String? { - return self.apiKey + func getOpenAIKey() -> String? { + return self.openaiKey } func getSentryDSN() -> String? { diff --git a/voice/voice-ai/x/OpenAIService/OpenAIService.swift b/voice/voice-ai/x/OpenAIService/OpenAIService.swift index 19d8a803b..161f3e4f9 100644 --- a/voice/voice-ai/x/OpenAIService/OpenAIService.swift +++ b/voice/voice-ai/x/OpenAIService/OpenAIService.swift @@ -6,7 +6,7 @@ struct OpenAIService { // private var conversation: [Message] // Function to send input text to OpenAI for processing mutating func sendToOpenAI(conversation: [Message], completion: @escaping (String?, Error?) -> Void) { - guard let openAI_APIKey = AppConfig.shared.getAPIKey() else { + guard let openAI_APIKey = AppConfig.shared.getOpenAIKey() else { completion(nil, nil) SentrySDK.capture(message: "Open AI Api key is null") return diff --git a/voice/voice-ai/x/OpenAIService/OpenAIStreamService.swift b/voice/voice-ai/x/OpenAIService/OpenAIStreamService.swift index 3b082a686..3f9e630b4 100644 --- a/voice/voice-ai/x/OpenAIService/OpenAIStreamService.swift +++ b/voice/voice-ai/x/OpenAIService/OpenAIStreamService.swift @@ -12,7 +12,7 @@ protocol NetworkService { class OpenAIStreamService: NSObject, URLSessionDataDelegate { private var task: URLSessionDataTask? private var completion: (String?, Error?) -> Void - private let apiKey = AppConfig.shared.getAPIKey() + private let apiKey = AppConfig.shared.getOpenAIKey() private var temperature: Double private let networkService: NetworkService? diff --git a/voice/voice-ai/xTests/AppConfigTests.swift b/voice/voice-ai/xTests/AppConfigTests.swift index 6a4260f84..39014e4e4 100644 --- a/voice/voice-ai/xTests/AppConfigTests.swift +++ b/voice/voice-ai/xTests/AppConfigTests.swift @@ -16,7 +16,7 @@ class AppConfigTests: XCTestCase { } func testAPIKeyIsNotNil() { - XCTAssertNotNil(appConfig.getAPIKey(), "API Key should not be nil") + XCTAssertNotNil(appConfig.getOpenAIKey(), "API Key should not be nil") } func testDeepgramKeyIsNotNil() { @@ -40,7 +40,7 @@ class AppConfigTests: XCTestCase { } func testLoadingValidPlistFile() { - XCTAssertNotNil(appConfig.getAPIKey(), "API Key should not be nil") + XCTAssertNotNil(appConfig.getOpenAIKey(), "API Key should not be nil") XCTAssertNotNil(appConfig.getDeepgramKey(), "Deepgram Key should not be nil") XCTAssertNotNil(appConfig.getThemeName(), "Theme Name should not be nil") // XCTAssertNotNil(appConfig.getSentryDSN(), "Sentry DSN should not be nil") From 021a9764cba9928cbdb1251c9f7d8c8ef7be520c Mon Sep 17 00:00:00 2001 From: polymorpher Date: Sat, 11 Nov 2023 22:32:01 -0800 Subject: [PATCH 05/12] fix bugs --- voice/relay/src/routes/soft.ts | 13 ++++++---- voice/relay/src/utils.ts | 5 +++- voice/relay/types/express/index.d.ts | 1 + voice/voice-ai/x/Actions/ActionsView.swift | 2 +- .../x/AppConfigration/AppConfig.swift | 24 +++++++++---------- 5 files changed, 26 insertions(+), 19 deletions(-) diff --git a/voice/relay/src/routes/soft.ts b/voice/relay/src/routes/soft.ts index 89e20595e..c8d3aa384 100644 --- a/voice/relay/src/routes/soft.ts +++ b/voice/relay/src/routes/soft.ts @@ -2,7 +2,7 @@ import { Router, type Request, type Response, type NextFunction } from 'express' import { HttpStatusCode } from 'axios' import rateLimit, { type Options as RLOptions, type RateLimitRequestHandler } from 'express-rate-limit' import { BlockedDeviceIds, BlockedIps, OpenAIDistributedKeys } from '../config/index.js' -import { encrypt, hexString, stringToBytes } from '../utils.js' +import { encrypt, hexString, hexView, stringToBytes } from '../utils.js' import { hash as sha256 } from 'fast-sha256' const router: Router = Router() @@ -27,11 +27,13 @@ const parseDeviceToken = (req: Request, res: Response, next: NextFunction): any res.status(HttpStatusCode.Forbidden).json({ error: 'device unsupported', code: 100 }) return } - if (BlockedDeviceIds.includes(deviceToken)) { + const deviceTokenHash = hexView(sha256(stringToBytes(deviceToken))) + if (BlockedDeviceIds.includes(deviceTokenHash)) { res.status(HttpStatusCode.Forbidden).json({ error: 'device banned', code: 101 }) return } req.deviceToken = deviceToken + req.deviceTokenHash = deviceTokenHash next() } @@ -51,12 +53,13 @@ router.get('/health', (req, res) => { router.get('/key', parseDeviceToken, checkIpBan, deviceLimiter(), ipLimiter(), (req, res) => { // TODO: validate the device token, https://developer.apple.com/documentation/devicecheck/accessing_and_modifying_per-device_data - const deviceToken = req.deviceToken const numKeys = BigInt(OpenAIDistributedKeys.length) - const h = hexString(sha256(stringToBytes(deviceToken))) - const keyIndex = Number(BigInt(h) % numKeys) + const keyIndex = Number(BigInt('0x' + req.deviceTokenHash) % numKeys) const key = OpenAIDistributedKeys[keyIndex] const encryptedKey = encrypt(key) + const encoded = encryptedKey.toString('base64') + + console.log(`[deviceTokenHash=${req.deviceTokenHash}][ip=${req.clientIp}] Provided encryptedKey ${encoded}`) res.json({ key: encryptedKey.toString('base64') }) }) diff --git a/voice/relay/src/utils.ts b/voice/relay/src/utils.ts index 7ad2e7e82..5e8efd12c 100644 --- a/voice/relay/src/utils.ts +++ b/voice/relay/src/utils.ts @@ -28,7 +28,10 @@ export function chunkstr (str: string, size: number): string[] { const aesKey = sha256(stringToBytes(SharedEncryptionSecret)).slice(0, 32) const aesIv = sha256(stringToBytes(SharedEncryptionIV)).slice(0, 16) +// console.log('aesKey', aesKey) +// console.log('aesIv', aesIv) + export function encrypt (s: string): Buffer { - const cipher = crypto.createCipheriv('aes-256-gcm', aesKey, aesIv) + const cipher = crypto.createCipheriv('aes-256-cbc', aesKey, aesIv) return Buffer.concat([cipher.update(s, 'utf8'), cipher.final()]) } diff --git a/voice/relay/types/express/index.d.ts b/voice/relay/types/express/index.d.ts index ea9ed02c8..1dc48d476 100644 --- a/voice/relay/types/express/index.d.ts +++ b/voice/relay/types/express/index.d.ts @@ -2,6 +2,7 @@ declare global { namespace Express { interface Request { deviceToken: string + deviceTokenHash: string } } } diff --git a/voice/voice-ai/x/Actions/ActionsView.swift b/voice/voice-ai/x/Actions/ActionsView.swift index 82b500b96..d17c8739b 100644 --- a/voice/voice-ai/x/Actions/ActionsView.swift +++ b/voice/voice-ai/x/Actions/ActionsView.swift @@ -4,7 +4,7 @@ import StoreKit import SwiftUI struct ActionsView: View { - let config = AppConfig() + let config = AppConfig.shared @ObservedObject private var timerManager = TimerManager.shared diff --git a/voice/voice-ai/x/AppConfigration/AppConfig.swift b/voice/voice-ai/x/AppConfigration/AppConfig.swift index e67020402..d38157336 100644 --- a/voice/voice-ai/x/AppConfigration/AppConfig.swift +++ b/voice/voice-ai/x/AppConfigration/AppConfig.swift @@ -20,20 +20,20 @@ class AppConfig { init() { self.loadConfiguration() + Task { + await self.requestOpenAIKey() + } } private func decrypt(base64EncodedEncryptedKey: String) throws -> String { - let d = Data(base64Encoded: base64EncodedEncryptedKey) - guard let d = d else { - throw NSError(domain: "Invalid encoded encrypted key", code: -1) - } - let encryptedKey = String(data: d, encoding: .utf8) + let encryptedKey = Data(base64Encoded: base64EncodedEncryptedKey) guard let encryptedKey = encryptedKey else { - throw NSError(domain: "Malformed key encoding", code: -2) + throw NSError(domain: "Invalid encoded encrypted key", code: -1) } - let iv: [UInt8] = Array(self.sharedEncryptionIV!.utf8) - let sharedKey: [UInt8] = Array(self.sharedEncryptionSecret!.utf8) - let aes = try AES(key: sharedKey, blockMode: GCM(iv: iv)) + + let iv = [UInt8](self.sharedEncryptionIV!.data(using: .utf8)!.sha256()[0..<16]) + let sharedKey = [UInt8](self.sharedEncryptionSecret!.data(using: .utf8)!.sha256()[0..<32]) + let aes = try AES(key: sharedKey, blockMode: CBC(iv: iv)) let dBytes = try aes.decrypt(encryptedKey.bytes) let dKey = String(data: Data(dBytes), encoding: .utf8) guard let key = dKey else { @@ -50,7 +50,7 @@ class AppConfig { } let s = URLSession(configuration: .default) guard let url = URL(string: "\(relayUrl)/key") else { - let error = NSError(domain: "Invalid Relay URL", code: -1, userInfo: nil) + print("Invalid Relay URL") SentrySDK.capture(message: "Invalid Relay URL") return } @@ -66,7 +66,7 @@ class AppConfig { } var r = URLRequest(url: url) r.setValue(token, forHTTPHeaderField: "X-DEVICE-TOKEN") - s.dataTask(with: r) { data, _, err in + let t = s.dataTask(with: r) { data, _, err in if let err = err { print("[AppConfig][requestOpenAIKey] cannot get key", err) SentrySDK.capture(message: "Cannot get key. Error: \(err)") @@ -89,7 +89,7 @@ class AppConfig { SentrySDK.capture(message: "[AppConfig][requestOpenAIKey] error processing key response \(error)") } } -// s.dataTask(with: "") + t.resume() } private func loadConfiguration() { From 77835b24687d53f08e98c8521ae5b72433780d57 Mon Sep 17 00:00:00 2001 From: polymorpher Date: Sat, 11 Nov 2023 22:38:20 -0800 Subject: [PATCH 06/12] cleanup --- voice/relay/src/routes/soft.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/voice/relay/src/routes/soft.ts b/voice/relay/src/routes/soft.ts index c8d3aa384..74033e84f 100644 --- a/voice/relay/src/routes/soft.ts +++ b/voice/relay/src/routes/soft.ts @@ -2,7 +2,7 @@ import { Router, type Request, type Response, type NextFunction } from 'express' import { HttpStatusCode } from 'axios' import rateLimit, { type Options as RLOptions, type RateLimitRequestHandler } from 'express-rate-limit' import { BlockedDeviceIds, BlockedIps, OpenAIDistributedKeys } from '../config/index.js' -import { encrypt, hexString, hexView, stringToBytes } from '../utils.js' +import { encrypt, hexView, stringToBytes } from '../utils.js' import { hash as sha256 } from 'fast-sha256' const router: Router = Router() From 55450e0b54032b2cb3e7622563ec0d7e84f5b0a3 Mon Sep 17 00:00:00 2001 From: polymorpher Date: Sat, 11 Nov 2023 23:04:00 -0800 Subject: [PATCH 07/12] deploy scripts --- voice/relay/deploy/enable.sh | 6 ++++++ voice/relay/deploy/log.sh | 2 ++ voice/relay/deploy/port.sh | 8 ++++++++ voice/relay/deploy/voice-ai-relay.service | 15 +++++++++++++++ 4 files changed, 31 insertions(+) create mode 100755 voice/relay/deploy/enable.sh create mode 100755 voice/relay/deploy/log.sh create mode 100644 voice/relay/deploy/port.sh create mode 100644 voice/relay/deploy/voice-ai-relay.service diff --git a/voice/relay/deploy/enable.sh b/voice/relay/deploy/enable.sh new file mode 100755 index 000000000..29f535e89 --- /dev/null +++ b/voice/relay/deploy/enable.sh @@ -0,0 +1,6 @@ +#!/bin/sh +sudo setcap CAP_NET_BIND_SERVICE=+eip /usr/bin/node +sudo cp voice-ai-relay.service /etc/systemd/system/voice-ai-relay.service +sudo systemctl start voice-ai-relay +sudo systemctl enable voice-ai-relay +systemctl status voice-ai-relay diff --git a/voice/relay/deploy/log.sh b/voice/relay/deploy/log.sh new file mode 100755 index 000000000..54b804139 --- /dev/null +++ b/voice/relay/deploy/log.sh @@ -0,0 +1,2 @@ +#!/bin/sh +journalctl -u voice-ai-relay diff --git a/voice/relay/deploy/port.sh b/voice/relay/deploy/port.sh new file mode 100644 index 000000000..59834d6f4 --- /dev/null +++ b/voice/relay/deploy/port.sh @@ -0,0 +1,8 @@ +!#/bin/sh +sudo iptables -A INPUT -i eth0 -p tcp --dport 80 -j ACCEPT +sudo iptables -A INPUT -i eth0 -p tcp --dport 3000 -j ACCEPT +sudo iptables -A INPUT -i eth0 -p tcp --dport 443 -j ACCEPT +sudo iptables -A INPUT -i eth0 -p tcp --dport 8443 -j ACCEPT +sudo iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 3000 +sudo iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 443 -j REDIRECT --to-port 8443 +sudo iptables --flush diff --git a/voice/relay/deploy/voice-ai-relay.service b/voice/relay/deploy/voice-ai-relay.service new file mode 100644 index 000000000..e6e949990 --- /dev/null +++ b/voice/relay/deploy/voice-ai-relay.service @@ -0,0 +1,15 @@ +[Unit] +Description=Voice AI Relay Server +Documentation=https://github.com/harmony-one/x/ +After=network.target + +[Service] +Environment=PORT=80 HTTPS_PORT=443 +Type=simple +User=worker +WorkingDirectory=/opt/git/x/voice/relay +ExecStart=/usr/bin/node /opt/git/x/voice/relay/bin/run.js +Restart=on-failure + +[Install] +WantedBy=multi-user.target From 2f71ffd0a970a82d502fbafccea815e7e7299bb0 Mon Sep 17 00:00:00 2001 From: polymorpher Date: Sat, 11 Nov 2023 23:13:35 -0800 Subject: [PATCH 08/12] fix deploy scripts --- voice/relay/deploy/log.sh | 2 +- voice/relay/deploy/voice-ai-relay.service | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/voice/relay/deploy/log.sh b/voice/relay/deploy/log.sh index 54b804139..9c3d6ea5d 100755 --- a/voice/relay/deploy/log.sh +++ b/voice/relay/deploy/log.sh @@ -1,2 +1,2 @@ #!/bin/sh -journalctl -u voice-ai-relay +journalctl -u voice-ai-relay -n 1000 -f diff --git a/voice/relay/deploy/voice-ai-relay.service b/voice/relay/deploy/voice-ai-relay.service index e6e949990..8e16fdeef 100644 --- a/voice/relay/deploy/voice-ai-relay.service +++ b/voice/relay/deploy/voice-ai-relay.service @@ -8,8 +8,8 @@ Environment=PORT=80 HTTPS_PORT=443 Type=simple User=worker WorkingDirectory=/opt/git/x/voice/relay -ExecStart=/usr/bin/node /opt/git/x/voice/relay/bin/run.js +ExecStart=/usr/bin/node --loader ts-node/esm ./bin/run.ts Restart=on-failure [Install] -WantedBy=multi-user.target +WantedBy=multi-user.target \ No newline at end of file From 5c7e1b9a98533dbf720b92ef2309a1767f5c24c9 Mon Sep 17 00:00:00 2001 From: polymorpher Date: Sat, 11 Nov 2023 23:17:50 -0800 Subject: [PATCH 09/12] route --- voice/relay/src/app.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/voice/relay/src/app.ts b/voice/relay/src/app.ts index 5dee494f5..e4468fa32 100644 --- a/voice/relay/src/app.ts +++ b/voice/relay/src/app.ts @@ -3,7 +3,7 @@ import cookieParser from 'cookie-parser' import morgan from 'morgan' import createError from 'http-errors' // import apiRouter from './routes/hard.js' -import apiRouter from './routes/soft.js' +import softRateLimitedApiRouter from './routes/soft.js' import fs from 'fs' import http, { type Server as HttpServer } from 'http' import https from 'https' @@ -64,7 +64,7 @@ app.options('*', async (_req, res) => { res.end() }) -app.use('/', apiRouter) +app.use('/soft', softRateLimitedApiRouter) // catch 404 and forward to error handler app.use(function (req, res, next) { From baa3b3b525721cd9d39a5770bd6928987f88c24f Mon Sep 17 00:00:00 2001 From: polymorpher Date: Sat, 11 Nov 2023 23:24:56 -0800 Subject: [PATCH 10/12] fix launch script --- voice/relay/deploy/voice-ai-relay.service | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/voice/relay/deploy/voice-ai-relay.service b/voice/relay/deploy/voice-ai-relay.service index 8e16fdeef..9d18ce1a6 100644 --- a/voice/relay/deploy/voice-ai-relay.service +++ b/voice/relay/deploy/voice-ai-relay.service @@ -8,7 +8,7 @@ Environment=PORT=80 HTTPS_PORT=443 Type=simple User=worker WorkingDirectory=/opt/git/x/voice/relay -ExecStart=/usr/bin/node --loader ts-node/esm ./bin/run.ts +ExecStart=/bin/bash -c "source ~/.profile;/usr/bin/node --loader ts-node/esm ./bin/run.ts" Restart=on-failure [Install] From c76aa74f1de8382a7c42680fd337b00e5775e8c3 Mon Sep 17 00:00:00 2001 From: polymorpher Date: Sun, 12 Nov 2023 00:55:47 -0800 Subject: [PATCH 11/12] allow using a local openai key --- voice/relay/deploy/enable.sh | 2 +- voice/voice-ai/x/AppConfigration/AppConfig.swift | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/voice/relay/deploy/enable.sh b/voice/relay/deploy/enable.sh index 29f535e89..109890237 100755 --- a/voice/relay/deploy/enable.sh +++ b/voice/relay/deploy/enable.sh @@ -1,6 +1,6 @@ #!/bin/sh sudo setcap CAP_NET_BIND_SERVICE=+eip /usr/bin/node sudo cp voice-ai-relay.service /etc/systemd/system/voice-ai-relay.service -sudo systemctl start voice-ai-relay +sudo systemctl restart voice-ai-relay sudo systemctl enable voice-ai-relay systemctl status voice-ai-relay diff --git a/voice/voice-ai/x/AppConfigration/AppConfig.swift b/voice/voice-ai/x/AppConfigration/AppConfig.swift index d38157336..6177bfa57 100644 --- a/voice/voice-ai/x/AppConfigration/AppConfig.swift +++ b/voice/voice-ai/x/AppConfigration/AppConfig.swift @@ -20,6 +20,10 @@ class AppConfig { init() { self.loadConfiguration() + if openaiKey != nil && openaiKey != "" { + // if a local key is assigned (for debugging), do not request from server + return + } Task { await self.requestOpenAIKey() } @@ -113,6 +117,7 @@ class AppConfig { self.themeName = dictionary["THEME_NAME"] self.deepgramKey = dictionary["DEEPGRAM_KEY"] + self.openaiKey = dictionary["API_KEY"] // Convert the string values to Int if let eventsString = dictionary["MINIMUM_SIGNIFICANT_EVENTS"], From a6496bc4f5d9818bb20b47bf9b333ba15d7b96d0 Mon Sep 17 00:00:00 2001 From: polymorpher Date: Sun, 12 Nov 2023 00:56:13 -0800 Subject: [PATCH 12/12] fix script --- voice/relay/deploy/enable.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/voice/relay/deploy/enable.sh b/voice/relay/deploy/enable.sh index 109890237..29f535e89 100755 --- a/voice/relay/deploy/enable.sh +++ b/voice/relay/deploy/enable.sh @@ -1,6 +1,6 @@ #!/bin/sh sudo setcap CAP_NET_BIND_SERVICE=+eip /usr/bin/node sudo cp voice-ai-relay.service /etc/systemd/system/voice-ai-relay.service -sudo systemctl restart voice-ai-relay +sudo systemctl start voice-ai-relay sudo systemctl enable voice-ai-relay systemctl status voice-ai-relay