Integrate new account backend

This commit is contained in:
2025-09-28 14:23:31 +02:00
parent 6e93cfdf2c
commit 0315241d76
9 changed files with 4086 additions and 3793 deletions

View File

@@ -9,6 +9,9 @@
"version": "1.0.0",
"license": "GPL-3.0-or-later",
"dependencies": {
"@janishutz/login-sdk-server": "^1.2.0",
"@janishutz/login-sdk-server-stubs": "^1.0.0",
"@janishutz/store-sdk": "^1.0.0",
"@types/body-parser": "^1.19.5",
"@types/cors": "^2.8.17",
"@types/express": "^4.17.21",
@@ -19,9 +22,7 @@
"express-session": "^1.18.0",
"jsonwebtoken": "^9.0.2",
"node-mysql": "^0.4.2",
"oauth-janishutz-client-server": "file:../../oauth/client/server/dist",
"socket.io": "^4.7.5",
"store.janishutz.com-sdk": "file:../../store/sdk/dist"
"socket.io": "^4.7.5"
},
"devDependencies": {
"@eslint/js": "^9.29.0",
@@ -35,6 +36,7 @@
"../../oauth/client/server/dist": {
"name": "oauth-janishutz-client-server",
"version": "1.0.0",
"extraneous": true,
"license": "ISC",
"dependencies": {
"@types/body-parser": "^1.19.5",
@@ -51,6 +53,7 @@
"../../store/sdk/dist": {
"name": "store.janishutz.com-sdk",
"version": "1.0.0",
"extraneous": true,
"license": "ISC",
"dependencies": {
"@types/express": "^4.17.21",
@@ -245,14 +248,14 @@
}
},
"node_modules/@eslint/plugin-kit": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.2.tgz",
"integrity": "sha512-4SaFZCNfJqvk/kenHpI8xvN42DMaoycy4PzKc5otHxRswww1kAt82OlBuwRVLofCACCTZEcla2Ydxv8scMXaTg==",
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.5.tgz",
"integrity": "sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@eslint/core": "^0.15.0",
"@eslint/core": "^0.15.2",
"levn": "^0.4.1"
},
"engines": {
@@ -260,9 +263,9 @@
}
},
"node_modules/@eslint/plugin-kit/node_modules/@eslint/core": {
"version": "0.15.0",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.0.tgz",
"integrity": "sha512-b7ePw78tEWWkpgZCDYkbqDOP8dmM6qe+AOC6iuJqlq1R/0ahMAeH3qynpnqKFGkMltrp44ohV4ubGyvLX28tzw==",
"version": "0.15.2",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.2.tgz",
"integrity": "sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
@@ -344,6 +347,44 @@
"url": "https://github.com/sponsors/nzakas"
}
},
"node_modules/@janishutz/login-sdk-server": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@janishutz/login-sdk-server/-/login-sdk-server-1.2.0.tgz",
"integrity": "sha512-c42ASudljXQ089q3wc0IVzyJhsGezZu2K7C+DVf8N7amy3EZMxgtKY89wyDbSXNMQuEfdtA/xlKMivRk01/0lw==",
"license": "ISC",
"dependencies": {
"@types/body-parser": "^1.19.6",
"@types/cors": "^2.8.19",
"@types/express": "^4.17.21",
"@types/express-rate-limit": "^5.1.3",
"@types/express-session": "^1.18.2",
"axios": "^1.11.0",
"body-parser": "^1.20.3",
"cors": "^2.8.5",
"express": "^4.19.2",
"express-rate-limit": "^8.1.0",
"express-session": "^1.18.2"
}
},
"node_modules/@janishutz/login-sdk-server-stubs": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@janishutz/login-sdk-server-stubs/-/login-sdk-server-stubs-1.0.0.tgz",
"integrity": "sha512-F0zgeVdTbt1fMIVPMCWF6mk0fEg9qutdLRJ8ce6vfwQp+if/IXGwT5McyjR6OFf8FIFu+rM5uwGoUa9i1s20MA==",
"license": "ISC",
"dependencies": {
"express": "^4.19.2"
}
},
"node_modules/@janishutz/store-sdk": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@janishutz/store-sdk/-/store-sdk-1.0.0.tgz",
"integrity": "sha512-7Ffmlf+Bg+Phsve6ff3Ts+R8+6rn/C2xe6TKaUbrf/wQFRIDt/b3BGpOM8Dmkvv6YPFTkAoi5+yN4OPNqZhCJQ==",
"license": "ISC",
"dependencies": {
"axios": "^1.7.2",
"express": "^4.19.2"
}
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -410,9 +451,9 @@
}
},
"node_modules/@types/body-parser": {
"version": "1.19.5",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz",
"integrity": "sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==",
"version": "1.19.6",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz",
"integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==",
"license": "MIT",
"dependencies": {
"@types/connect": "*",
@@ -429,9 +470,9 @@
}
},
"node_modules/@types/cors": {
"version": "2.8.17",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz",
"integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==",
"version": "2.8.19",
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz",
"integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
@@ -457,6 +498,15 @@
"@types/serve-static": "*"
}
},
"node_modules/@types/express-rate-limit": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/@types/express-rate-limit/-/express-rate-limit-5.1.3.tgz",
"integrity": "sha512-H+TYy3K53uPU2TqPGFYaiWc2xJV6+bIFkDd/Ma2/h67Pa6ARk9kWE0p/K9OH1Okm0et9Sfm66fmXoAxsH2PHXg==",
"license": "MIT",
"dependencies": {
"@types/express": "*"
}
},
"node_modules/@types/express-serve-static-core": {
"version": "4.19.3",
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.19.3.tgz",
@@ -470,10 +520,9 @@
}
},
"node_modules/@types/express-session": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/@types/express-session/-/express-session-1.18.0.tgz",
"integrity": "sha512-27JdDRgor6PoYlURY+Y5kCakqp5ulC0kmf7y+QwaY+hv9jEFuQOThgkjyA53RP3jmKuBsH5GR6qEfFmvb8mwOA==",
"dev": true,
"version": "1.18.2",
"resolved": "https://registry.npmjs.org/@types/express-session/-/express-session-1.18.2.tgz",
"integrity": "sha512-k+I0BxwVXsnEU2hV77cCobC08kIsn4y44C3gC0b46uxZVMaXA04lSPgRLR/bSL2w0t0ShJiG8o4jPzRG/nscFg==",
"license": "MIT",
"dependencies": {
"@types/express": "*"
@@ -992,6 +1041,23 @@
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
"license": "MIT"
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"license": "MIT"
},
"node_modules/axios": {
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
"integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.4",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@@ -1112,6 +1178,19 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/call-bind-apply-helpers": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/callsites": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
@@ -1163,6 +1242,18 @@
"license": "MIT",
"peer": true
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"license": "MIT",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@@ -1294,6 +1385,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"license": "MIT",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@@ -1313,6 +1413,20 @@
"npm": "1.2.8000 || >= 1.4.16"
}
},
"node_modules/dunder-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
"es-errors": "^1.3.0",
"gopd": "^1.2.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/ecdsa-sig-formatter": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
@@ -1399,13 +1513,10 @@
"license": "MIT"
},
"node_modules/es-define-property": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
"integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"license": "MIT",
"dependencies": {
"get-intrinsic": "^1.2.4"
},
"engines": {
"node": ">= 0.4"
}
@@ -1419,6 +1530,33 @@
"node": ">= 0.4"
}
},
"node_modules/es-object-atoms": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-set-tostringtag": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.6",
"has-tostringtag": "^1.0.2",
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -1703,17 +1841,35 @@
"url": "https://opencollective.com/express"
}
},
"node_modules/express-rate-limit": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.1.0.tgz",
"integrity": "sha512-4nLnATuKupnmwqiJc27b4dCFmB/T60ExgmtDD7waf4LdrbJ8CPZzZRHYErDYNhoz+ql8fUdYwM/opf90PoPAQA==",
"license": "MIT",
"dependencies": {
"ip-address": "10.0.1"
},
"engines": {
"node": ">= 16"
},
"funding": {
"url": "https://github.com/sponsors/express-rate-limit"
},
"peerDependencies": {
"express": ">= 4.11"
}
},
"node_modules/express-session": {
"version": "1.18.1",
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.1.tgz",
"integrity": "sha512-a5mtTqEaZvBCL9A9aqkrtfz+3SMDhOVUnjafjo+s7A9Txkq+SVX2DLvSp1Zrv4uCXa3lMSK3viWnh9Gg07PBUA==",
"version": "1.18.2",
"resolved": "https://registry.npmjs.org/express-session/-/express-session-1.18.2.tgz",
"integrity": "sha512-SZjssGQC7TzTs9rpPDuUrR23GNZ9+2+IkA/+IJWmvQilTr5OSliEHGF+D9scbIpdC6yGtTI0/VhaHoVes2AN/A==",
"license": "MIT",
"dependencies": {
"cookie": "0.7.2",
"cookie-signature": "1.0.7",
"debug": "2.6.9",
"depd": "~2.0.0",
"on-headers": "~1.0.2",
"on-headers": "~1.1.0",
"parseurl": "~1.3.3",
"safe-buffer": "5.2.1",
"uid-safe": "~2.1.5"
@@ -1887,6 +2043,42 @@
"license": "ISC",
"peer": true
},
"node_modules/follow-redirects": {
"version": "1.15.11",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.2",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@@ -1915,16 +2107,21 @@
}
},
"node_modules/get-intrinsic": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
"integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
"es-define-property": "^1.0.1",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.1.1",
"function-bind": "^1.1.2",
"has-proto": "^1.0.1",
"has-symbols": "^1.0.3",
"hasown": "^2.0.0"
"get-proto": "^1.0.1",
"gopd": "^1.2.0",
"has-symbols": "^1.1.0",
"hasown": "^2.0.2",
"math-intrinsics": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
@@ -1933,6 +2130,19 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/get-proto": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
"es-object-atoms": "^1.0.0"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/glob-parent": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
@@ -1962,12 +2172,12 @@
}
},
"node_modules/gopd": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
"integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"license": "MIT",
"dependencies": {
"get-intrinsic": "^1.1.3"
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -2003,10 +2213,10 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-proto": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
"integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
"node_modules/has-symbols": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
@@ -2015,11 +2225,14 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-symbols": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
"integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
"node_modules/has-tostringtag": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
@@ -2113,6 +2326,15 @@
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
"license": "ISC"
},
"node_modules/ip-address": {
"version": "10.0.1",
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.0.1.tgz",
"integrity": "sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==",
"license": "MIT",
"engines": {
"node": ">= 12"
}
},
"node_modules/ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
@@ -2357,6 +2579,15 @@
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
"license": "MIT"
},
"node_modules/math-intrinsics": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"license": "MIT",
"engines": {
"node": ">= 0.4"
}
},
"node_modules/media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
@@ -2535,10 +2766,6 @@
"url": "https://github.com/fb55/nth-check?sponsor=1"
}
},
"node_modules/oauth-janishutz-client-server": {
"resolved": "../../oauth/client/server/dist",
"link": true
},
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -2573,9 +2800,9 @@
}
},
"node_modules/on-headers": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
"integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz",
"integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==",
"license": "MIT",
"engines": {
"node": ">= 0.8"
@@ -2742,6 +2969,12 @@
"node": ">= 0.10"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"license": "MIT"
},
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -3175,10 +3408,6 @@
"node": ">= 0.8"
}
},
"node_modules/store.janishutz.com-sdk": {
"resolved": "../../store/sdk/dist",
"link": true
},
"node_modules/string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",

View File

@@ -25,6 +25,9 @@
"typescript-eslint": "^8.35.0"
},
"dependencies": {
"@janishutz/login-sdk-server": "^1.2.0",
"@janishutz/login-sdk-server-stubs": "^1.0.0",
"@janishutz/store-sdk": "^1.0.0",
"@types/body-parser": "^1.19.5",
"@types/cors": "^2.8.17",
"@types/express": "^4.17.21",
@@ -35,8 +38,6 @@
"express-session": "^1.18.0",
"jsonwebtoken": "^9.0.2",
"node-mysql": "^0.4.2",
"oauth-janishutz-client-server": "file:../../oauth/client/server/dist",
"socket.io": "^4.7.5",
"store.janishutz.com-sdk": "file:../../store/sdk/dist"
"socket.io": "^4.7.5"
}
}

View File

@@ -3,48 +3,58 @@ import db from './storage/db';
const createUser = ( uid: string, username: string, email: string ): Promise<boolean> => {
return new Promise( ( resolve, reject ) => {
db.writeDataSimple( 'users', 'uid', uid, { 'uid': uid, 'username': username, 'email': email } ).then( () => {
db.writeDataSimple( 'users', 'uid', uid, {
'uid': uid,
'username': username,
'email': email
} ).then( () => {
resolve( true );
} ).catch( err => {
} )
.catch( err => {
reject( err );
} );
} );
}
};
const saveUserData = ( uid: string, data: object ): Promise<boolean> => {
return new Promise( ( resolve, reject ) => {
db.writeDataSimple( 'users', 'uid', uid, { 'data': data } ).then( () => {
db.writeDataSimple( 'users', 'uid', uid, {
'data': data
} ).then( () => {
resolve( true );
} ).catch( err => {
} )
.catch( err => {
reject( err );
} );
} );
}
};
const checkUser = ( uid: string ): Promise<boolean> => {
return new Promise( ( resolve, reject ) => {
db.checkDataAvailability( 'users', 'uid', uid ).then( res => {
resolve( res );
} ).catch( err => {
reject( err );
} )
.catch( err => {
reject( err );
} );
}
} );
};
const getUserData = ( uid: string ): Promise<object> => {
return new Promise( ( resolve, reject ) => {
db.getDataSimple( 'users', 'uid', uid ).then( data => {
resolve( data );
} ).catch( err => {
} )
.catch( err => {
reject( err );
} );
} );
}
};
export default {
createUser,
saveUserData,
checkUser,
getUserData
}
};

View File

@@ -3,8 +3,6 @@ import path from 'path';
import fs from 'fs';
import jwt from 'jsonwebtoken';
import cors from 'cors';
import account from './account';
import sdk from 'oauth-janishutz-client-server';
import {
createServer
} from 'node:http';
@@ -15,26 +13,19 @@ import crypto from 'node:crypto';
import type {
Room, Song
} from './definitions';
import storeSDK from 'store.janishutz.com-sdk';
import bodyParser from 'body-parser';
// ┌ ┐
// │ Handle FOSS vs paid version │
// └ ┘
const isFossVersion = true;
declare let __dirname: string | undefined;
import storeSDK from '@janishutz/store-sdk';
import sdk from '@janishutz/login-sdk-server';
// import storeSDK from './sdk/store-sdk-stub';
// import sdk from '@janishutz/login-sdk-server-stubs';
if ( typeof __dirname === 'undefined' ) {
__dirname = path.resolve( path.dirname( '' ) );
}
// TODO: Change config file, as well as in main.ts, index.html, oauth, if deploying there
// const sdkConfig = JSON.parse( fs.readFileSync( path.join(
// __dirname,
// '/config/sdk.config.testing.json'
// ) ).toString() );
const sdkConfig = JSON.parse( fs.readFileSync( path.join(
__dirname,
'/config/sdk.config.secret.json'
) ).toString() );
const run = () => {
const app = express();
@@ -45,10 +36,6 @@ const run = () => {
} ) );
if ( !isFossVersion ) {
// storeSDK.configure( JSON.parse( fs.readFileSync( path.join(
// __dirname,
// '/config/store-sdk.config.testing.json'
// ) ).toString() ) );
storeSDK.configure( JSON.parse( fs.readFileSync( path.join(
__dirname,
'/config/store-sdk.config.secret.json'
@@ -58,26 +45,49 @@ const run = () => {
const httpServer = createServer( app );
if ( !isFossVersion ) {
const sdkConfig = JSON.parse( fs.readFileSync( path.join(
__dirname,
'/config/sdk.config.secret.json'
) ).toString() );
// Load id.janishutz.com SDK and allow signing in
sdk.routes( app, ( uid: string ) => {
return new Promise( ( resolve, reject ) => {
account.checkUser( uid ).then( stat => {
resolve( stat );
} )
.catch( e => {
reject( e );
sdk.setUp(
{
'prod': false,
'service': {
'serviceID': 'jh-music',
'serviceToken': sdkConfig[ 'token' ]
},
'user-agent': sdkConfig[ 'ua' ],
'sessionType': 'memory',
'frontendURL': 'https://music.janishutz.com',
'corsWhitelist': [ 'https://music.janishutz.com' ],
'recheckTimeout': 300 * 1000,
'advancedVerification': 'sdk'
},
app,
() => {
return new Promise( resolve => {
resolve( true );
} );
},
() => {
return new Promise( resolve => {
resolve( true );
} );
}, ( uid: string, email: string, username: string ) => {
return new Promise( ( resolve, reject ) => {
account.createUser( uid, username, email ).then( stat => {
resolve( stat );
} )
.catch( e => {
reject( e );
},
() => {
return new Promise( resolve => {
resolve( true );
} );
},
() => {
return new Promise( resolve => {
resolve( true );
} );
}, sdkConfig );
},
sdkConfig
);
}
// Websocket for events
@@ -291,7 +301,7 @@ const run = () => {
} ) }\n\n` );
const sid = sdk.getSessionID( request );
if ( sdk.checkAuth( request ) ) {
if ( sdk.getSignedIn( request ) ) {
importantClients[ sid ] = {
'response': response,
'room': String( request.query.room )
@@ -488,8 +498,8 @@ const run = () => {
app.get(
'/createRoomToken',
sdk.loginCheck(),
( request: express.Request, response: express.Response ) => {
if ( sdk.checkAuth( request ) ) {
// eslint-disable-next-line no-constant-binary-expression
const roomName = String( request.query.roomName ) ?? '';
@@ -503,7 +513,7 @@ const run = () => {
'playlistIndex': 0,
'roomName': roomName,
'roomToken': roomToken,
'ownerUID': sdk.getUserData( request ).uid,
'ownerUID': sdk.getUID( request ),
'useAntiTamper': request.query.useAntiTamper === 'true'
? true : false,
};
@@ -511,16 +521,13 @@ const run = () => {
} else {
if (
socketData[ roomName ].ownerUID
=== sdk.getUserData( request ).uid
=== sdk.getUID( request )
) {
response.send( socketData[ roomName ].roomToken );
} else {
response.status( 409 ).send( 'ERR_CONFLICT' );
}
}
} else {
response.status( 403 ).send( 'ERR_FORBIDDEN' );
}
}
);
@@ -569,13 +576,12 @@ const run = () => {
const checkIfOwned = ( request: express.Request ): Promise<boolean> => {
return new Promise( ( resolve, reject ) => {
if ( sdk.checkAuth( request ) ) {
const userData = sdk.getUserData( request );
const uid = sdk.getUID( request );
if ( ownedCache[ userData.uid ] ) {
resolve( ownedCache[ userData.uid ] );
if ( ownedCache[ uid ] ) {
resolve( ownedCache[ uid ] );
} else {
storeSDK.getSubscriptions( userData.uid )
storeSDK.getSubscriptions( uid )
.then( stat => {
const now = new Date().getTime();
@@ -588,12 +594,12 @@ const run = () => {
=== 'com.janishutz.MusicPlayer.subscription-month'
)
) {
ownedCache[ userData.uid ] = true;
ownedCache[ uid ] = true;
resolve( true );
}
}
ownedCache[ userData.uid ] = false;
ownedCache[ uid ] = false;
resolve( false );
} )
.catch( e => {
@@ -601,14 +607,12 @@ const run = () => {
reject( 'ERR_NOT_OWNED' );
} );
}
} else {
reject( 'ERR_AUTH_REQUIRED' );
}
} );
};
app.get(
'/checkUserStatus',
sdk.loginCheck(),
( request: express.Request, response: express.Response ) => {
checkIfOwned( request )
.then( owned => {

View File

@@ -1,41 +0,0 @@
import express from 'express';
import expressSession from 'express-session';
import crypto from 'node:crypto';
// TODO: Use also express-session to make it work with getSessionID and session referencing
const checkAuth = ( request: express.Request ) => {
return true;
}
export interface AuthSDKConfig {
token: string;
name: string;
client: string;
backendURL: string;
failReturnURL: string;
useSecureCookie?: boolean;
}
declare module 'express-session' {
interface SessionData {
isAuth: boolean;
uid: string;
username: string;
email: string;
additionalData: object;
}
}
const getUserData = ( request: express.Request ) => {
if ( !request.session.uid ) {
request.session.uid = crypto.randomUUID();
request.session.username = 'FOSS-Version';
request.session.email = 'example@example.com';
}
return { 'email': request.session.email, 'username': request.session.username, 'uid': request.session.uid, 'id': request.session.id };
}
export default {
checkAuth,
getUserData
}

View File

@@ -1,11 +1,15 @@
const getSubscriptions = ( uid: string ) => {
return [ {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const getSubscriptions = ( _uid: string ) => {
return [
{
'id': 'com.janishutz.MusicPlayer.subscription',
'expires': new Date().getTime() + 200000,
'status': true
} ];
}
}
];
};
export default {
getSubscriptions,
}
};

View File

@@ -11,8 +11,9 @@ import path from 'path';
import fs from 'fs';
import * as sqlDB from './mysqldb.js';
declare let __dirname: string | undefined
if ( typeof( __dirname ) === 'undefined' ) {
declare let __dirname: string | undefined;
if ( typeof __dirname === 'undefined' ) {
__dirname = path.resolve( path.dirname( '' ) );
} else {
__dirname = __dirname + '/../';
@@ -22,9 +23,8 @@ const dbRef = {
'user': 'music_users',
'users': 'music_users',
};
const dbh = new sqlDB.SQLDB();
let dbh = new sqlDB.SQLDB();
dbh.connect();
/**
@@ -32,7 +32,7 @@ dbh.connect();
* @returns {undefined}
*/
const initDB = (): undefined => {
( async() => {
( async () => {
console.log( '[ DB ] Setting up...' );
dbh.setupDB();
console.log( '[ DB ] Setting up complete!' );
@@ -48,9 +48,14 @@ const initDB = (): undefined => {
*/
const getDataSimple = ( db: string, column: string, searchQuery: string ): Promise<object> => {
return new Promise( ( resolve, reject ) => {
dbh.query( { 'command': 'getFilteredData', 'property': column, 'searchQuery': searchQuery }, dbRef[ db ] ).then( data => {
dbh.query( {
'command': 'getFilteredData',
'property': column,
'searchQuery': searchQuery
}, dbRef[ db ] ).then( data => {
resolve( data );
} ).catch( error => {
} )
.catch( error => {
reject( error );
} );
} );
@@ -66,7 +71,7 @@ const getDataSimple = ( db: string, column: string, searchQuery: string ): Promi
* @param {string} nameOfMatchingParam Which properties should be matched to get the data, e.g. order.user_id=users.id
* @returns {Promise<Object | Error>} Returns all records from the db and all matching data specified with the matchingParam from the secondTable.
*/
const getDataWithLeftJoinFunction = ( db: string, column: string, searchQuery: string, secondTable: string, columns: object, nameOfMatchingParam: string ): Promise<Object> => {
const getDataWithLeftJoinFunction = ( db: string, column: string, searchQuery: string, secondTable: string, columns: object, nameOfMatchingParam: string ): Promise<object> => {
/*
LeftJoin (Select values in first table and return all corresponding values of second table):
- operation.property (the column to search for the value),
@@ -76,22 +81,24 @@ const getDataWithLeftJoinFunction = ( db: string, column: string, searchQuery: s
- operation.matchingParam (Which properties should be matched to get the data, e.g. order.user_id=users.id)
*/
return new Promise( ( resolve, reject ) => {
let settings = {
const settings = {
'command': 'LeftJoin',
'property': column,
'searchQuery': searchQuery,
'selection': '',
'secondTable': dbRef[ secondTable ],
'matchingParam': dbRef[ db ] + '.' + nameOfMatchingParam + '=' + dbRef[ secondTable ] + '.' + nameOfMatchingParam,
}
for ( let el in columns ) {
};
for ( const el in columns ) {
settings.selection += dbRef[ columns[ el ].db ] + '.' + columns[ el ].column + ',';
}
settings.selection = settings.selection.slice( 0, settings.selection.length - 1 );
dbh.query( settings, dbRef[ db ] ).then( data => {
resolve( data );
} ).catch( error => {
} )
.catch( error => {
reject( error );
} );
} );
@@ -102,11 +109,14 @@ const getDataWithLeftJoinFunction = ( db: string, column: string, searchQuery: s
* @param {string} db The database of which all data should be retrieved
* @returns {Promise<object>} Returns an object containing all data
*/
const getData = ( db: string ): Promise<Object> => {
const getData = ( db: string ): Promise<object> => {
return new Promise( ( resolve, reject ) => {
dbh.query( { 'command': 'getAllData' }, dbRef[ db ] ).then( data => {
dbh.query( {
'command': 'getAllData'
}, dbRef[ db ] ).then( data => {
resolve( data );
} ).catch( error => {
} )
.catch( error => {
reject( error );
} );
} );
@@ -120,23 +130,38 @@ const getData = ( db: string ): Promise<Object> => {
* @param {string} data The data to write. Also include the column & searchQuery parameters, if they also need to be added
* @returns {Promise<object>} Returns a promise that resolves to the interaction module return.
*/
const writeDataSimple = ( db: string, column: string, searchQuery: string, data: any ): Promise<Object> => {
const writeDataSimple = ( db: string, column: string, searchQuery: string, data: any ): Promise<object> => {
return new Promise( ( resolve, reject ) => {
dbh.query( { 'command': 'checkDataAvailability', 'property': column, 'searchQuery': searchQuery }, dbRef[ db ] ).then( res => {
dbh.query( {
'command': 'checkDataAvailability',
'property': column,
'searchQuery': searchQuery
}, dbRef[ db ] ).then( res => {
if ( res.length > 0 ) {
dbh.query( { 'command': 'updateData', 'property': column, 'searchQuery': searchQuery, 'newValues': data }, dbRef[ db ] ).then( dat => {
dbh.query( {
'command': 'updateData',
'property': column,
'searchQuery': searchQuery,
'newValues': data
}, dbRef[ db ] ).then( dat => {
resolve( dat );
} ).catch( error => {
} )
.catch( error => {
reject( error );
} );
} else {
dbh.query( { 'command': 'addData', 'data': data }, dbRef[ db ] ).then( dat => {
dbh.query( {
'command': 'addData',
'data': data
}, dbRef[ db ] ).then( dat => {
resolve( dat );
} ).catch( error => {
} )
.catch( error => {
reject( error );
} );
}
} ).catch( error => {
} )
.catch( error => {
reject( error );
} );
} );
@@ -151,9 +176,14 @@ const writeDataSimple = ( db: string, column: string, searchQuery: string, data:
*/
const deleteDataSimple = ( db: string, column: string, searchQuery: string ): Promise<object> => {
return new Promise( ( resolve, reject ) => {
dbh.query( { 'command': 'deleteData', 'property': column, 'searchQuery': searchQuery }, dbRef[ db ] ).then( dat => {
dbh.query( {
'command': 'deleteData',
'property': column,
'searchQuery': searchQuery
}, dbRef[ db ] ).then( dat => {
resolve( dat );
} ).catch( error => {
} )
.catch( error => {
reject( error );
} );
} );
@@ -168,13 +198,18 @@ const deleteDataSimple = ( db: string, column: string, searchQuery: string ): Pr
*/
const checkDataAvailability = ( db: string, column: string, searchQuery: string ): Promise<boolean> => {
return new Promise( ( resolve, reject ) => {
dbh.query( { 'command': 'checkDataAvailability', 'property': column, 'searchQuery': searchQuery }, dbRef[ db ] ).then( res => {
dbh.query( {
'command': 'checkDataAvailability',
'property': column,
'searchQuery': searchQuery
}, dbRef[ db ] ).then( res => {
if ( res.length > 0 ) {
resolve( true );
} else {
resolve( false );
}
} ).catch( error => {
} )
.catch( error => {
reject( error );
} );
} );
@@ -186,16 +221,18 @@ const checkDataAvailability = ( db: string, column: string, searchQuery: string
* @returns {Promise<object>} Returns the data from all files
*/
const getJSONDataBatch = async ( files: Array<string> ): Promise<object> => {
let allFiles = {};
for ( let file in files ) {
const allFiles = {};
for ( const file in files ) {
try {
allFiles[ files[ file ] ] = await getJSONData( files[ file ] );
} catch( err ) {
} catch ( err ) {
allFiles[ files[ file ] ] = 'ERROR: ' + err;
}
}
return allFiles;
}
};
/**
* Load all data from a JSON file
@@ -245,7 +282,7 @@ const getJSONDataSimple = ( file: string, identifier: string ): Promise<object>
* @param {string} file The file to be loaded (path relative to root)
* @returns {object} Returns the JSON file
*/
const getJSONDataSync = ( file: string ): Object => {
const getJSONDataSync = ( file: string ): object => {
return JSON.parse( fs.readFileSync( path.join( __dirname + '/' + file ) ).toString() );
};
@@ -263,14 +300,17 @@ const writeJSONDataSimple = ( db: string, identifier: string, values: any ) => {
reject( 'Error occurred: Error trace: ' + error );
} else {
let dat = {};
if ( data.byteLength > 0 ) {
dat = JSON.parse( data.toString() ) ?? {};
}
dat[ identifier ] = values;
fs.writeFile( path.join( __dirname + '/../../data/' + db + '.json' ), JSON.stringify( dat ), ( error ) => {
fs.writeFile( path.join( __dirname + '/../../data/' + db + '.json' ), JSON.stringify( dat ), error => {
if ( error ) {
reject( 'Error occurred: Error trace: ' + error );
}
resolve( true );
} );
}
@@ -286,7 +326,7 @@ const writeJSONDataSimple = ( db: string, identifier: string, values: any ) => {
*/
const writeJSONData = ( db: string, data: object ): Promise<boolean> => {
return new Promise( ( resolve, reject ) => {
fs.writeFile( path.join( __dirname + '/../../data/' + db + '.json' ), JSON.stringify( data ), ( error ) => {
fs.writeFile( path.join( __dirname + '/../../data/' + db + '.json' ), JSON.stringify( data ), error => {
if ( error ) {
reject( 'Error occurred: Error trace: ' + error );
} else {
@@ -309,14 +349,17 @@ const deleteJSONDataSimple = ( db: string, identifier: string ): Promise<boolean
reject( 'Error occurred: Error trace: ' + error );
} else {
let dat = {};
if ( data.byteLength > 0 ) {
dat = JSON.parse( data.toString() ) ?? {};
}
delete dat[ identifier ];
fs.writeFile( path.join( __dirname + '/../../data/' + db + '.json' ), JSON.stringify( dat ), ( error ) => {
fs.writeFile( path.join( __dirname + '/../../data/' + db + '.json' ), JSON.stringify( dat ), error => {
if ( error ) {
reject( 'Error occurred: Error trace: ' + error );
}
resolve( true );
} );
}
@@ -324,7 +367,19 @@ const deleteJSONDataSimple = ( db: string, identifier: string ): Promise<boolean
} );
};
export default { initDB, checkDataAvailability, deleteDataSimple, deleteJSONDataSimple, getData,
getDataSimple, getDataWithLeftJoinFunction, getJSONData, getJSONDataBatch, getJSONDataSimple,
getJSONDataSync, writeDataSimple, writeJSONData, writeJSONDataSimple
export default {
initDB,
checkDataAvailability,
deleteDataSimple,
deleteJSONDataSimple,
getData,
getDataSimple,
getDataWithLeftJoinFunction,
getJSONData,
getJSONDataBatch,
getJSONDataSimple,
getJSONDataSync,
writeDataSimple,
writeJSONData,
writeJSONDataSimple
};

View File

@@ -11,8 +11,9 @@ import mysql from 'mysql';
import fs from 'fs';
import path from 'path';
declare let __dirname: string | undefined
if ( typeof( __dirname ) === 'undefined' ) {
declare let __dirname: string | undefined;
if ( typeof __dirname === 'undefined' ) {
__dirname = path.resolve( path.dirname( '' ) );
} else {
__dirname = __dirname + '/../';
@@ -22,21 +23,35 @@ if ( typeof( __dirname ) === 'undefined' ) {
// to the whitelist of the database
class SQLConfig {
command: string;
property?: string;
searchQuery?: string;
selection?: string;
query?: string;
newValues?: object;
secondTable?: string;
matchingParam?: string;
data?: object;
}
class SQLDB {
sqlConnection: mysql.Connection;
isRecovering: boolean;
config: object;
constructor () {
this.config = JSON.parse( '' + fs.readFileSync( path.join( __dirname + '/config/db.config.secret.json' ) ) );
this.sqlConnection = mysql.createConnection( this.config );
@@ -46,19 +61,23 @@ class SQLDB {
connect () {
return new Promise( ( resolve, reject ) => {
const self = this;
if ( this.isRecovering ) {
console.log( '[ SQL ] Attempting to recover from critical error' );
this.sqlConnection = mysql.createConnection( this.config );
this.isRecovering = false;
}
this.sqlConnection.connect( ( err ) => {
this.sqlConnection.connect( err => {
if ( err ) {
console.error( '[ SQL ]: An error ocurred whilst connecting: ' + err.stack );
reject( err );
return;
}
console.log( '[ SQL ] Connected to database successfully' );
self.sqlConnection.on( 'error', ( err ) => {
self.sqlConnection.on( 'error', err => {
if ( err.code === 'ECONNRESET' ) {
self.isRecovering = true;
setTimeout( () => {
@@ -81,15 +100,17 @@ class SQLDB {
async setupDB () {
this.sqlConnection.query( 'SELECT @@default_storage_engine;', ( error, results ) => {
if ( error ) throw error;
if ( results[ 0 ][ '@@default_storage_engine' ] !== 'InnoDB' ) throw 'DB HAS TO USE InnoDB!';
} );
this.sqlConnection.query( 'CREATE TABLE music_users ( account_id INT ( 10 ) NOT NULL AUTO_INCREMENT, email TINYTEXT NOT NULL, uid TINYTEXT, lang TINYTEXT, username TINYTEXT, settings VARCHAR( 5000 ), PRIMARY KEY ( account_id ) ) ENGINE=INNODB;', ( error ) => {
this.sqlConnection.query( 'CREATE TABLE music_users ( account_id INT ( 10 ) NOT NULL AUTO_INCREMENT, email TINYTEXT NOT NULL, uid TINYTEXT, lang TINYTEXT, username TINYTEXT, settings VARCHAR( 5000 ), PRIMARY KEY ( account_id ) ) ENGINE=INNODB;', error => {
if ( error ) if ( error.code !== 'ER_TABLE_EXISTS_ERROR' ) throw error;
return 'DONE';
} );
}
query ( operation: SQLConfig, table: string ): Promise<Array<Object>> {
query ( operation: SQLConfig, table: string ): Promise<Array<object>> {
return new Promise( ( resolve, reject ) => {
/*
Possible operation.command values (all need the table argument of the method call):
@@ -141,6 +162,7 @@ class SQLDB {
- operation.query (the SQL instruction to be executed) --> NOTE: This command will not be sanitised, so use only with proper sanitisation!
*/
let command = '';
if ( operation.command === 'getAllData' ) {
command = 'SELECT * FROM ' + table;
} else if ( operation.command === 'getFilteredData' || operation.command === 'checkDataAvailability' ) {
@@ -150,19 +172,23 @@ class SQLDB {
} else if ( operation.command === 'addData' ) {
let keys = '';
let values = '';
for ( let key in operation.data ) {
for ( const key in operation.data ) {
keys += String( key ) + ', ';
values += this.sqlConnection.escape( String( operation.data[ key ] ) ) + ', ' ;
values += this.sqlConnection.escape( String( operation.data[ key ] ) ) + ', ';
}
command = 'INSERT INTO ' + table + ' (' + keys.slice( 0, keys.length - 2 ) + ') VALUES (' + values.slice( 0, values.length - 2 ) + ');';
} else if ( operation.command === 'updateData' ) {
if ( !operation.property || !operation.searchQuery ) reject( 'Refusing to run destructive command: Missing Constraints' );
else {
command = 'UPDATE ' + table + ' SET ';
let updatedValues = '';
for ( let value in operation.newValues ) {
for ( const value in operation.newValues ) {
updatedValues += value + ' = ' + this.sqlConnection.escape( String( operation.newValues[ value ] ) ) + ', ';
}
command += updatedValues.slice( 0, updatedValues.length - 2 );
command += ' WHERE ' + operation.property + ' = ' + this.sqlConnection.escape( operation.searchQuery );
}
@@ -178,12 +204,17 @@ class SQLDB {
} else if ( operation.command === 'RightJoin' ) {
command = 'SELECT ' + operation.selection + ' FROM ' + table + ' RIGHT JOIN ' + operation.secondTable + ' ON ' + operation.matchingParam + ' WHERE ' + operation.property + ' = ' + this.sqlConnection.escape( operation.searchQuery );
}
this.sqlConnection.query( command, ( error, results ) => {
if ( error ) reject( error );
resolve( results );
} );
} );
}
}
export { SQLConfig, SQLDB };
export {
SQLConfig, SQLDB
};