Switching to new security rules
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
parent
b3465ea96d
commit
22cb90b6f6
2
.env
2
.env
@ -1,4 +1,4 @@
|
|||||||
PORT = 5000
|
PORT = 5000
|
||||||
ADMIN_KEY = test
|
ADMIN_KEY = test
|
||||||
ACCESS_LOG = true
|
ACCESS_LOG = true
|
||||||
DEV = true
|
DEV = true
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
FROM node:12
|
FROM node:14
|
||||||
|
|
||||||
LABEL maintainer="Fabian Stamm <dev@fabianstamm.de>"
|
LABEL maintainer="Fabian Stamm <dev@fabianstamm.de>"
|
||||||
|
|
||||||
@ -8,6 +8,8 @@ LABEL maintainer="Fabian Stamm <dev@fabianstamm.de>"
|
|||||||
RUN mkdir -p /usr/src/app
|
RUN mkdir -p /usr/src/app
|
||||||
WORKDIR /usr/src/app
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
RUN npm config set registry https://npm.hibas123.de/
|
||||||
|
|
||||||
ENV NODE_ENV=production
|
ENV NODE_ENV=production
|
||||||
|
|
||||||
COPY ["package.json", "package-lock.json", "/usr/src/app/"]
|
COPY ["package.json", "package-lock.json", "/usr/src/app/"]
|
||||||
@ -20,4 +22,4 @@ VOLUME [ "/usr/src/app/databases", "/usr/src/app/logs" ]
|
|||||||
|
|
||||||
EXPOSE 5000/tcp
|
EXPOSE 5000/tcp
|
||||||
|
|
||||||
CMD ["npm", "run", "start"]
|
CMD ["npm", "run", "start"]
|
||||||
|
214
package-lock.json
generated
214
package-lock.json
generated
@ -22,9 +22,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@hibas123/utils": {
|
"@hibas123/utils": {
|
||||||
"version": "2.2.4",
|
"version": "2.2.16",
|
||||||
"resolved": "https://registry.npmjs.org/@hibas123/utils/-/utils-2.2.4.tgz",
|
"resolved": "https://npm.hibas123.de/@hibas123%2futils/-/utils-2.2.16.tgz",
|
||||||
"integrity": "sha512-Mx9H73Q2PNLzqRp3sHN7esskhUJ6pNFHht6u0ykYeHt6jb/kdsISCQPvIHWC32cvAWylBFQ2qHF1dEFEcZyL+Q=="
|
"integrity": "sha512-nwzJL+vaWpbaGmIc+AU6T/7ZZ+ZiB57NOEECIu3GAVB86qo21o12gr0a4AYv/bGzWKupxuT5a3fDyrRQybKLWw=="
|
||||||
},
|
},
|
||||||
"@sindresorhus/is": {
|
"@sindresorhus/is": {
|
||||||
"version": "0.14.0",
|
"version": "0.14.0",
|
||||||
@ -66,12 +66,6 @@
|
|||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/color-name": {
|
|
||||||
"version": "1.1.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
|
|
||||||
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
|
|
||||||
"dev": true
|
|
||||||
},
|
|
||||||
"@types/connect": {
|
"@types/connect": {
|
||||||
"version": "3.4.33",
|
"version": "3.4.33",
|
||||||
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz",
|
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz",
|
||||||
@ -114,9 +108,9 @@
|
|||||||
"integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g=="
|
"integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g=="
|
||||||
},
|
},
|
||||||
"@types/express": {
|
"@types/express": {
|
||||||
"version": "4.17.7",
|
"version": "4.17.8",
|
||||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.7.tgz",
|
"resolved": "https://npm.hibas123.de/@types%2fexpress/-/express-4.17.8.tgz",
|
||||||
"integrity": "sha512-dCOT5lcmV/uC2J9k0rPafATeeyz+99xTt54ReX11/LObZgfzJqZNcW27zGhYyX+9iSEGXGt5qLPwRSvBZcLvtQ==",
|
"integrity": "sha512-wLhcKh3PMlyA2cNAB9sjM1BntnhPMiM0JOBwPBqttjHev2428MLEB4AYVN+d8s2iyCVZac+o41Pflm/ZH5vLXQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/body-parser": "*",
|
"@types/body-parser": "*",
|
||||||
@ -126,9 +120,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/express-serve-static-core": {
|
"@types/express-serve-static-core": {
|
||||||
"version": "4.17.9",
|
"version": "4.17.13",
|
||||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.9.tgz",
|
"resolved": "https://npm.hibas123.de/@types%2fexpress-serve-static-core/-/express-serve-static-core-4.17.13.tgz",
|
||||||
"integrity": "sha512-DG0BYg6yO+ePW+XoDENYz8zhNGC3jDDEpComMYn7WJc4mY1Us8Rw9ax2YhJXxpyk2SF47PQAoQ0YyVT1a0bEkA==",
|
"integrity": "sha512-RgDi5a4nuzam073lRGKTUIaL3eF2+H7LJvJ8eUnCI0wA6SNjXc44DCmWNiTLs/AZ7QlsFWZiw/gTG3nSQGL0fA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/node": "*",
|
"@types/node": "*",
|
||||||
@ -151,6 +145,12 @@
|
|||||||
"integrity": "sha512-PGAK759pxyfXE78NbKxyfRcWYA/KwW17X290cNev/qAsn9eQIxkH4shoNBafH37wewhDG/0p1cHPbK6+SzZjWQ==",
|
"integrity": "sha512-PGAK759pxyfXE78NbKxyfRcWYA/KwW17X290cNev/qAsn9eQIxkH4shoNBafH37wewhDG/0p1cHPbK6+SzZjWQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/http-errors": {
|
||||||
|
"version": "1.8.0",
|
||||||
|
"resolved": "https://npm.hibas123.de/@types%2fhttp-errors/-/http-errors-1.8.0.tgz",
|
||||||
|
"integrity": "sha512-2aoSC4UUbHDj2uCsCxcG/vRMXey/m17bC7UwitVm5hn22nI8O8Y9iDpA76Orc+DWkQ4zZrOKEshCqR/jSuXAHA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"@types/jsonwebtoken": {
|
"@types/jsonwebtoken": {
|
||||||
"version": "8.5.0",
|
"version": "8.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-8.5.0.tgz",
|
||||||
@ -167,15 +167,16 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/koa": {
|
"@types/koa": {
|
||||||
"version": "2.11.3",
|
"version": "2.11.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/koa/-/koa-2.11.3.tgz",
|
"resolved": "https://npm.hibas123.de/@types%2fkoa/-/koa-2.11.6.tgz",
|
||||||
"integrity": "sha512-ABxVkrNWa4O/Jp24EYI/hRNqEVRlhB9g09p48neQp4m3xL1TJtdWk2NyNQSMCU45ejeELMQZBYyfstyVvO2H3Q==",
|
"integrity": "sha512-BhyrMj06eQkk04C97fovEDQMpLpd2IxCB4ecitaXwOKGq78Wi2tooaDOWOFGajPk8IkQOAtMppApgSVkYe1F/A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/accepts": "*",
|
"@types/accepts": "*",
|
||||||
"@types/content-disposition": "*",
|
"@types/content-disposition": "*",
|
||||||
"@types/cookies": "*",
|
"@types/cookies": "*",
|
||||||
"@types/http-assert": "*",
|
"@types/http-assert": "*",
|
||||||
|
"@types/http-errors": "*",
|
||||||
"@types/keygrip": "*",
|
"@types/keygrip": "*",
|
||||||
"@types/koa-compose": "*",
|
"@types/koa-compose": "*",
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
@ -235,14 +236,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "14.0.27",
|
"version": "14.14.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.27.tgz",
|
"resolved": "https://npm.hibas123.de/@types%2fnode/-/node-14.14.5.tgz",
|
||||||
"integrity": "sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g=="
|
"integrity": "sha512-H5Wn24s/ZOukBmDn03nnGTp18A60ny9AmCwnEcgJiTgSGsCO7k+NWP7zjCCbhlcnVCoI+co52dUAt9GMhOSULw=="
|
||||||
},
|
},
|
||||||
"@types/qs": {
|
"@types/qs": {
|
||||||
"version": "6.9.4",
|
"version": "6.9.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.4.tgz",
|
"resolved": "https://npm.hibas123.de/@types%2fqs/-/qs-6.9.5.tgz",
|
||||||
"integrity": "sha512-+wYo+L6ZF6BMoEjtf8zB2esQsqdV6WsjRK/GP9WOgLPrq87PbNWgIxS76dS5uvl/QXtHGakZmwTznIfcPXcKlQ==",
|
"integrity": "sha512-/JHkVHtx/REVG0VVToGRGH2+23hsYLHdyG+GrvoUGlGAd0ErauXDyvHtRI/7H7mzLm+tBCKA7pfcpkQ1lf58iQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/range-parser": {
|
"@types/range-parser": {
|
||||||
@ -252,19 +253,19 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/serve-static": {
|
"@types/serve-static": {
|
||||||
"version": "1.13.5",
|
"version": "1.13.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.5.tgz",
|
"resolved": "https://npm.hibas123.de/@types%2fserve-static/-/serve-static-1.13.6.tgz",
|
||||||
"integrity": "sha512-6M64P58N+OXjU432WoLLBQxbA0LRGBCRm7aAGQJ+SMC1IMl0dgRVi9EFfoDcS2a7Xogygk/eGN94CfwU9UF7UQ==",
|
"integrity": "sha512-nuRJmv7jW7VmCVTn+IgYDkkbbDGyIINOeu/G0d74X3lm6E5KfMeQPJhxIt1ayQeQB3cSxvYs1RA/wipYoFB4EA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/express-serve-static-core": "*",
|
"@types/mime": "*",
|
||||||
"@types/mime": "*"
|
"@types/node": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/ws": {
|
"@types/ws": {
|
||||||
"version": "7.2.6",
|
"version": "7.2.8",
|
||||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.2.6.tgz",
|
"resolved": "https://npm.hibas123.de/@types%2fws/-/ws-7.2.8.tgz",
|
||||||
"integrity": "sha512-Q07IrQUSNpr+cXU4E4LtkSIBPie5GLZyyMC1QtQYRLWz701+XcoVygGUZgvLqElq1nU4ICldMYPnexlBsg3dqQ==",
|
"integrity": "sha512-LGtjDQxcMk4uU7ET85qJWYLwCdsSxLRxqOums/SDDWJw/BCCgFrOvqcvly6rGNkB/OkOiUaRzzhz8pchuxXr7w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/node": "*"
|
"@types/node": "*"
|
||||||
@ -347,6 +348,12 @@
|
|||||||
"picomatch": "^2.0.4"
|
"picomatch": "^2.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"arg": {
|
||||||
|
"version": "4.1.3",
|
||||||
|
"resolved": "https://npm.hibas123.de/arg/-/arg-4.1.3.tgz",
|
||||||
|
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||||
@ -387,12 +394,11 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"ansi-styles": {
|
"ansi-styles": {
|
||||||
"version": "4.2.1",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
|
"resolved": "https://npm.hibas123.de/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||||
"integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
|
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/color-name": "^1.1.1",
|
|
||||||
"color-convert": "^2.0.1"
|
"color-convert": "^2.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -460,9 +466,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"supports-color": {
|
"supports-color": {
|
||||||
"version": "7.1.0",
|
"version": "7.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
|
"resolved": "https://npm.hibas123.de/supports-color/-/supports-color-7.2.0.tgz",
|
||||||
"integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
|
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"has-flag": "^4.0.0"
|
"has-flag": "^4.0.0"
|
||||||
@ -503,6 +509,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||||
"integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
|
"integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
|
||||||
},
|
},
|
||||||
|
"buffer-from": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://npm.hibas123.de/buffer-from/-/buffer-from-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"bytes": {
|
"bytes": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
|
||||||
@ -578,9 +590,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"chokidar": {
|
"chokidar": {
|
||||||
"version": "3.4.2",
|
"version": "3.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz",
|
"resolved": "https://npm.hibas123.de/chokidar/-/chokidar-3.4.3.tgz",
|
||||||
"integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==",
|
"integrity": "sha512-DtM3g7juCXQxFVSNPNByEC2+NImtBuxQQvWlHunpJIS5Ocr0lG306cC7FCi7cEA0fzmybPUIl4txBIobk1gGOQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"anymatch": "~3.1.1",
|
"anymatch": "~3.1.1",
|
||||||
@ -590,7 +602,7 @@
|
|||||||
"is-binary-path": "~2.1.0",
|
"is-binary-path": "~2.1.0",
|
||||||
"is-glob": "~4.0.1",
|
"is-glob": "~4.0.1",
|
||||||
"normalize-path": "~3.0.0",
|
"normalize-path": "~3.0.0",
|
||||||
"readdirp": "~3.4.0"
|
"readdirp": "~3.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ci-info": {
|
"ci-info": {
|
||||||
@ -600,9 +612,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"cli-boxes": {
|
"cli-boxes": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.0.tgz",
|
"resolved": "https://npm.hibas123.de/cli-boxes/-/cli-boxes-2.2.1.tgz",
|
||||||
"integrity": "sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==",
|
"integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"cliui": {
|
"cliui": {
|
||||||
@ -807,10 +819,16 @@
|
|||||||
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
|
||||||
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
|
"integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
|
||||||
},
|
},
|
||||||
|
"diff": {
|
||||||
|
"version": "4.0.2",
|
||||||
|
"resolved": "https://npm.hibas123.de/diff/-/diff-4.0.2.tgz",
|
||||||
|
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"dot-prop": {
|
"dot-prop": {
|
||||||
"version": "5.2.0",
|
"version": "5.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz",
|
"resolved": "https://npm.hibas123.de/dot-prop/-/dot-prop-5.3.0.tgz",
|
||||||
"integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==",
|
"integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"is-obj": "^2.0.0"
|
"is-obj": "^2.0.0"
|
||||||
@ -924,7 +942,7 @@
|
|||||||
},
|
},
|
||||||
"fsevents": {
|
"fsevents": {
|
||||||
"version": "2.1.3",
|
"version": "2.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz",
|
"resolved": "https://npm.hibas123.de/fsevents/-/fsevents-2.1.3.tgz",
|
||||||
"integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
|
"integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"optional": true
|
"optional": true
|
||||||
@ -1460,7 +1478,7 @@
|
|||||||
},
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.20",
|
"version": "4.17.20",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
|
"resolved": "https://npm.hibas123.de/lodash/-/lodash-4.17.20.tgz",
|
||||||
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
|
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
@ -1522,6 +1540,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"make-error": {
|
||||||
|
"version": "1.3.6",
|
||||||
|
"resolved": "https://npm.hibas123.de/make-error/-/make-error-1.3.6.tgz",
|
||||||
|
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"media-typer": {
|
"media-typer": {
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||||
@ -1571,9 +1595,9 @@
|
|||||||
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
|
||||||
},
|
},
|
||||||
"nanoid": {
|
"nanoid": {
|
||||||
"version": "3.1.12",
|
"version": "3.1.16",
|
||||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.12.tgz",
|
"resolved": "https://npm.hibas123.de/nanoid/-/nanoid-3.1.16.tgz",
|
||||||
"integrity": "sha512-1qstj9z5+x491jfiC4Nelk+f8XBad7LN20PmyWINJEMRSf3wcAjAWysw1qaA8z6NSKe2sjq1hRSDpBH5paCb6A=="
|
"integrity": "sha512-+AK8MN0WHji40lj8AEuwLOvLSbWYApQpre/aFJZD71r43wVRLrOYS4FmJOPQYon1TqB462RzrrxlfA74XRES8w=="
|
||||||
},
|
},
|
||||||
"napi-macros": {
|
"napi-macros": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
@ -1596,9 +1620,9 @@
|
|||||||
"integrity": "sha512-dSq1xmcPDKPZ2EED2S6zw/b9NKsqzXRE6dVr8TVQnI3FJOTteUMuqF3Qqs6LZg+mLGYJWqQzMbIjMtJqTv87nQ=="
|
"integrity": "sha512-dSq1xmcPDKPZ2EED2S6zw/b9NKsqzXRE6dVr8TVQnI3FJOTteUMuqF3Qqs6LZg+mLGYJWqQzMbIjMtJqTv87nQ=="
|
||||||
},
|
},
|
||||||
"nodemon": {
|
"nodemon": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.4.tgz",
|
"resolved": "https://npm.hibas123.de/nodemon/-/nodemon-2.0.6.tgz",
|
||||||
"integrity": "sha512-Ltced+hIfTmaS28Zjv1BM552oQ3dbwPqI4+zI0SLgq+wpJhSyqgYude/aZa/3i31VCQWMfXJVxvu86abcam3uQ==",
|
"integrity": "sha512-4I3YDSKXg6ltYpcnZeHompqac4E6JeAMpGm8tJnB9Y3T0ehasLa4139dJOcCrB93HHrUMsCrKtoAlXTqT5n4AQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"chokidar": "^3.2.2",
|
"chokidar": "^3.2.2",
|
||||||
@ -1609,8 +1633,8 @@
|
|||||||
"semver": "^5.7.1",
|
"semver": "^5.7.1",
|
||||||
"supports-color": "^5.5.0",
|
"supports-color": "^5.5.0",
|
||||||
"touch": "^3.1.0",
|
"touch": "^3.1.0",
|
||||||
"undefsafe": "^2.0.2",
|
"undefsafe": "^2.0.3",
|
||||||
"update-notifier": "^4.0.0"
|
"update-notifier": "^4.1.0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"supports-color": {
|
"supports-color": {
|
||||||
@ -1806,9 +1830,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"pupa": {
|
"pupa": {
|
||||||
"version": "2.0.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/pupa/-/pupa-2.0.1.tgz",
|
"resolved": "https://npm.hibas123.de/pupa/-/pupa-2.1.1.tgz",
|
||||||
"integrity": "sha512-hEJH0s8PXLY/cdXh66tNEQGndDrIKNqNC5xmrysZy3i5C3oEoLna7YAOad+7u125+zH1HNXUmGEkrhb3c2VriA==",
|
"integrity": "sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"escape-goat": "^2.0.0"
|
"escape-goat": "^2.0.0"
|
||||||
@ -1878,9 +1902,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"readdirp": {
|
"readdirp": {
|
||||||
"version": "3.4.0",
|
"version": "3.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz",
|
"resolved": "https://npm.hibas123.de/readdirp/-/readdirp-3.5.0.tgz",
|
||||||
"integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==",
|
"integrity": "sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"picomatch": "^2.2.1"
|
"picomatch": "^2.2.1"
|
||||||
@ -1997,6 +2021,16 @@
|
|||||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
|
||||||
},
|
},
|
||||||
|
"source-map-support": {
|
||||||
|
"version": "0.5.19",
|
||||||
|
"resolved": "https://npm.hibas123.de/source-map-support/-/source-map-support-0.5.19.tgz",
|
||||||
|
"integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"buffer-from": "^1.0.0",
|
||||||
|
"source-map": "^0.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"spawn-command": {
|
"spawn-command": {
|
||||||
"version": "0.0.2-1",
|
"version": "0.0.2-1",
|
||||||
"resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz",
|
"resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz",
|
||||||
@ -2091,9 +2125,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"term-size": {
|
"term-size": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz",
|
"resolved": "https://npm.hibas123.de/term-size/-/term-size-2.2.1.tgz",
|
||||||
"integrity": "sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw==",
|
"integrity": "sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"to-readable-stream": {
|
"to-readable-stream": {
|
||||||
@ -2131,6 +2165,19 @@
|
|||||||
"integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
|
"integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"ts-node": {
|
||||||
|
"version": "9.0.0",
|
||||||
|
"resolved": "https://npm.hibas123.de/ts-node/-/ts-node-9.0.0.tgz",
|
||||||
|
"integrity": "sha512-/TqB4SnererCDR/vb4S/QvSZvzQMJN8daAslg7MeaiHvD8rDZsSfXmNeNumyZZzMned72Xoq/isQljYSt8Ynfg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"arg": "^4.1.0",
|
||||||
|
"diff": "^4.0.1",
|
||||||
|
"make-error": "^1.1.1",
|
||||||
|
"source-map-support": "^0.5.17",
|
||||||
|
"yn": "3.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"tslib": {
|
"tslib": {
|
||||||
"version": "1.13.0",
|
"version": "1.13.0",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz",
|
||||||
@ -2167,9 +2214,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"typescript": {
|
"typescript": {
|
||||||
"version": "3.9.7",
|
"version": "4.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.7.tgz",
|
"resolved": "https://npm.hibas123.de/typescript/-/typescript-4.0.5.tgz",
|
||||||
"integrity": "sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw==",
|
"integrity": "sha512-ywmr/VrTVCmNTJ6iV2LwIrfG1P+lv6luD8sUJs+2eI9NLGigaN+nUQc13iHqisq7bra9lnmUSYqbJvegraBOPQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"uglify-js": {
|
"uglify-js": {
|
||||||
@ -2213,9 +2260,9 @@
|
|||||||
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
|
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
|
||||||
},
|
},
|
||||||
"update-notifier": {
|
"update-notifier": {
|
||||||
"version": "4.1.0",
|
"version": "4.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.0.tgz",
|
"resolved": "https://npm.hibas123.de/update-notifier/-/update-notifier-4.1.3.tgz",
|
||||||
"integrity": "sha512-w3doE1qtI0/ZmgeoDoARmI5fjDoT93IfKgEGqm26dGUOh8oNpaSTsGNdYRN/SjOuo10jcJGwkEL3mroKzktkew==",
|
"integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"boxen": "^4.2.0",
|
"boxen": "^4.2.0",
|
||||||
@ -2234,12 +2281,11 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-styles": {
|
"ansi-styles": {
|
||||||
"version": "4.2.1",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz",
|
"resolved": "https://npm.hibas123.de/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||||
"integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==",
|
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/color-name": "^1.1.1",
|
|
||||||
"color-convert": "^2.0.1"
|
"color-convert": "^2.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -2275,9 +2321,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"supports-color": {
|
"supports-color": {
|
||||||
"version": "7.1.0",
|
"version": "7.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
|
"resolved": "https://npm.hibas123.de/supports-color/-/supports-color-7.2.0.tgz",
|
||||||
"integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
|
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"has-flag": "^4.0.0"
|
"has-flag": "^4.0.0"
|
||||||
@ -2466,6 +2512,12 @@
|
|||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/ylru/-/ylru-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/ylru/-/ylru-1.2.1.tgz",
|
||||||
"integrity": "sha512-faQrqNMzcPCHGVC2aaOINk13K+aaBDUPjGWl0teOXywElLjyVAB6Oe2jj62jHYtwsU49jXhScYbvPENK+6zAvQ=="
|
"integrity": "sha512-faQrqNMzcPCHGVC2aaOINk13K+aaBDUPjGWl0teOXywElLjyVAB6Oe2jj62jHYtwsU49jXhScYbvPENK+6zAvQ=="
|
||||||
|
},
|
||||||
|
"yn": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://npm.hibas123.de/yn/-/yn-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==",
|
||||||
|
"dev": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
21
package.json
21
package.json
@ -1,15 +1,13 @@
|
|||||||
{
|
{
|
||||||
"name": "@hibas123/realtimedb",
|
"name": "@hibas123/realtimedb",
|
||||||
"version": "2.0.0-beta.20",
|
"version": "2.0.0-beta.21",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node lib/index.js",
|
"start": "node lib/index.js",
|
||||||
"build": "tsc",
|
"build": "tsc",
|
||||||
"watch-ts": "tsc -w",
|
"watch": "nodemon -e ts --exec ts-node src/index.ts",
|
||||||
"watch-node": "nodemon --ignore *.ts lib/index.js",
|
|
||||||
"watch": "concurrently \"npm:watch-*\"",
|
|
||||||
"build-docker": "npm run build && docker build -t realtimedb .",
|
"build-docker": "npm run build && docker build -t realtimedb .",
|
||||||
"prepublishOnly": "tsc"
|
"prepublishOnly": "tsc"
|
||||||
},
|
},
|
||||||
@ -18,20 +16,21 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/dotenv": "^8.2.0",
|
"@types/dotenv": "^8.2.0",
|
||||||
"@types/jsonwebtoken": "^8.5.0",
|
"@types/jsonwebtoken": "^8.5.0",
|
||||||
"@types/koa": "^2.11.3",
|
"@types/koa": "^2.11.6",
|
||||||
"@types/koa-router": "^7.4.1",
|
"@types/koa-router": "^7.4.1",
|
||||||
"@types/leveldown": "^4.0.2",
|
"@types/leveldown": "^4.0.2",
|
||||||
"@types/levelup": "^4.3.0",
|
"@types/levelup": "^4.3.0",
|
||||||
"@types/nanoid": "^2.1.0",
|
"@types/nanoid": "^2.1.0",
|
||||||
"@types/node": "^14.0.27",
|
"@types/node": "^14.14.5",
|
||||||
"@types/ws": "^7.2.6",
|
"@types/ws": "^7.2.8",
|
||||||
"concurrently": "^5.3.0",
|
"concurrently": "^5.3.0",
|
||||||
"nodemon": "^2.0.4",
|
"nodemon": "^2.0.6",
|
||||||
"typescript": "^3.9.7"
|
"ts-node": "^9.0.0",
|
||||||
|
"typescript": "^4.0.5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hibas123/nodelogging": "^2.4.5",
|
"@hibas123/nodelogging": "^2.4.5",
|
||||||
"@hibas123/utils": "^2.2.4",
|
"@hibas123/utils": "^2.2.16",
|
||||||
"dotenv": "^8.2.0",
|
"dotenv": "^8.2.0",
|
||||||
"handlebars": "^4.7.6",
|
"handlebars": "^4.7.6",
|
||||||
"jsonwebtoken": "^8.5.1",
|
"jsonwebtoken": "^8.5.1",
|
||||||
@ -40,7 +39,7 @@
|
|||||||
"koa-router": "^9.4.0",
|
"koa-router": "^9.4.0",
|
||||||
"leveldown": "^5.6.0",
|
"leveldown": "^5.6.0",
|
||||||
"levelup": "^4.4.0",
|
"levelup": "^4.4.0",
|
||||||
"nanoid": "^3.1.12",
|
"nanoid": "^3.1.16",
|
||||||
"what-the-pack": "^2.0.3",
|
"what-the-pack": "^2.0.3",
|
||||||
"ws": "^7.3.1"
|
"ws": "^7.3.1"
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,24 @@
|
|||||||
import Logging from "@hibas123/nodelogging";
|
import Logging from "@hibas123/nodelogging";
|
||||||
import * as dotenv from "dotenv";
|
import * as dotenv from "dotenv";
|
||||||
import { LoggingTypes } from "@hibas123/logging";
|
import { LoggingTypes } from "@hibas123/logging";
|
||||||
dotenv.config()
|
dotenv.config();
|
||||||
|
|
||||||
|
|
||||||
interface IConfig {
|
interface IConfig {
|
||||||
port: number;
|
port: number;
|
||||||
admin: string;
|
admin: string;
|
||||||
access_log: boolean;
|
access_log: boolean;
|
||||||
dev: boolean
|
dev: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const config: IConfig = {
|
const config: IConfig = {
|
||||||
port: Number(process.env.PORT),
|
port: Number(process.env.PORT),
|
||||||
access_log: (process.env.ACCESS_LOG || "").toLowerCase() === "true",
|
access_log: (process.env.ACCESS_LOG || "").toLowerCase() === "true",
|
||||||
admin: process.env.ADMIN_KEY,
|
admin: process.env.ADMIN_KEY,
|
||||||
dev: (process.env.DEV || "").toLowerCase() === "true"
|
dev: (process.env.DEV || "").toLowerCase() === "true",
|
||||||
}
|
};
|
||||||
|
|
||||||
if (config.dev) {
|
if (config.dev) {
|
||||||
Logging.logLevel = LoggingTypes.Log;
|
Logging.logLevel = LoggingTypes.Log;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default config;
|
export default config;
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { Rules } from "./rules";
|
|
||||||
import Settings from "../settings";
|
import Settings from "../settings";
|
||||||
import getLevelDB, { LevelDB, deleteLevelDB, resNull } from "../storage";
|
import getLevelDB, { deleteLevelDB, resNull } from "../storage";
|
||||||
import DocumentLock from "./lock";
|
import DocumentLock from "./lock";
|
||||||
import {
|
import {
|
||||||
DocumentQuery,
|
DocumentQuery,
|
||||||
@ -14,6 +13,9 @@ import Logging from "@hibas123/nodelogging";
|
|||||||
import Session from "./session";
|
import Session from "./session";
|
||||||
import nanoid = require("nanoid");
|
import nanoid = require("nanoid");
|
||||||
import { Observable } from "@hibas123/utils";
|
import { Observable } from "@hibas123/utils";
|
||||||
|
import { RuleRunner } from "../rules/compile";
|
||||||
|
import compileRule from "../rules";
|
||||||
|
import { RuleError } from "../rules/error";
|
||||||
|
|
||||||
const ALPHABET =
|
const ALPHABET =
|
||||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||||
@ -81,17 +83,27 @@ export class Database {
|
|||||||
return `${collectionid || ""}/${documentid || ""}`;
|
return `${collectionid || ""}/${documentid || ""}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private level = getLevelDB(this.name);
|
#level = getLevelDB(this.name);
|
||||||
|
|
||||||
get data() {
|
get data() {
|
||||||
return this.level.data;
|
return this.#level.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
get collections() {
|
get collections() {
|
||||||
return this.level.collection;
|
return this.#level.collection;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rules: RuleRunner;
|
||||||
|
#rawRules?: string;
|
||||||
|
|
||||||
|
get rawRules() {
|
||||||
|
return this.#rawRules;
|
||||||
|
}
|
||||||
|
|
||||||
|
get rules() {
|
||||||
|
return this.#rules;
|
||||||
}
|
}
|
||||||
|
|
||||||
public rules: Rules;
|
|
||||||
private locks = new DocumentLock();
|
private locks = new DocumentLock();
|
||||||
public collectionLocks = new DocumentLock();
|
public collectionLocks = new DocumentLock();
|
||||||
|
|
||||||
@ -107,7 +119,7 @@ export class Database {
|
|||||||
name: this.name,
|
name: this.name,
|
||||||
accesskey: this.accesskey,
|
accesskey: this.accesskey,
|
||||||
publickey: this.publickey,
|
publickey: this.publickey,
|
||||||
rules: this.rules,
|
rules: this.#rules,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,13 +130,36 @@ export class Database {
|
|||||||
public publickey?: string,
|
public publickey?: string,
|
||||||
public rootkey?: string
|
public rootkey?: string
|
||||||
) {
|
) {
|
||||||
if (rawRules) this.rules = new Rules(rawRules);
|
if (rawRules) this.applyRules(rawRules);
|
||||||
|
}
|
||||||
|
|
||||||
|
private applyRules(rawRules: string): undefined | RuleError {
|
||||||
|
try {
|
||||||
|
JSON.parse(rawRules);
|
||||||
|
Logging.warning(
|
||||||
|
"Found old rule! Replacing with a 100% permissive one!"
|
||||||
|
);
|
||||||
|
rawRules =
|
||||||
|
"service realtimedb {\n match /* {\n allow read, write, list: if false; \n }\n}";
|
||||||
|
// still json, so switching to
|
||||||
|
} catch (err) {}
|
||||||
|
|
||||||
|
let { runner, error } = compileRule(rawRules);
|
||||||
|
if (error) {
|
||||||
|
Logging.warning("Found error in existing config!", error);
|
||||||
|
runner = compileRule("service realtimesb {}").runner;
|
||||||
|
}
|
||||||
|
this.#rules = runner;
|
||||||
|
this.#rawRules = rawRules;
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
async setRules(rawRules: string) {
|
async setRules(rawRules: string) {
|
||||||
let rules = new Rules(rawRules);
|
const { runner, error } = compileRule(rawRules);
|
||||||
|
if (error) return error;
|
||||||
await Settings.setDatabaseRules(this.name, rawRules);
|
await Settings.setDatabaseRules(this.name, rawRules);
|
||||||
this.rules = rules;
|
this.#rules = runner;
|
||||||
|
this.#rawRules = rawRules;
|
||||||
}
|
}
|
||||||
|
|
||||||
async setAccessKey(key: string) {
|
async setAccessKey(key: string) {
|
||||||
|
@ -5,6 +5,7 @@ import Logging from "@hibas123/nodelogging";
|
|||||||
import * as MSGPack from "what-the-pack";
|
import * as MSGPack from "what-the-pack";
|
||||||
import Session from "./session";
|
import Session from "./session";
|
||||||
import { LevelUpChain } from "levelup";
|
import { LevelUpChain } from "levelup";
|
||||||
|
import { Operations } from "../rules/parser";
|
||||||
|
|
||||||
export type IWriteQueries = "set" | "update" | "delete" | "add";
|
export type IWriteQueries = "set" | "update" | "delete" | "add";
|
||||||
export type ICollectionQueries =
|
export type ICollectionQueries =
|
||||||
@ -47,7 +48,7 @@ interface IPreparedQuery {
|
|||||||
needDocument: boolean;
|
needDocument: boolean;
|
||||||
batchCompatible: boolean;
|
batchCompatible: boolean;
|
||||||
runner: Runner;
|
runner: Runner;
|
||||||
permission: "write" | "read";
|
permission: Operations;
|
||||||
additionalLock?: string[];
|
additionalLock?: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +74,7 @@ export abstract class Query {
|
|||||||
public readonly needDocument: boolean;
|
public readonly needDocument: boolean;
|
||||||
public readonly batchCompatible: boolean;
|
public readonly batchCompatible: boolean;
|
||||||
public readonly additionalLock?: string[];
|
public readonly additionalLock?: string[];
|
||||||
public readonly permission: string;
|
public readonly permission: Operations;
|
||||||
private readonly _runner: Runner;
|
private readonly _runner: Runner;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -99,6 +100,7 @@ export abstract class Query {
|
|||||||
this.needDocument = data.needDocument;
|
this.needDocument = data.needDocument;
|
||||||
this.batchCompatible = data.batchCompatible;
|
this.batchCompatible = data.batchCompatible;
|
||||||
this.additionalLock = data.additionalLock;
|
this.additionalLock = data.additionalLock;
|
||||||
|
this.permission = data.permission;
|
||||||
this._runner = data.runner;
|
this._runner = data.runner;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,14 +153,13 @@ export abstract class Query {
|
|||||||
) {
|
) {
|
||||||
let perm = this.database.rules.hasPermission(
|
let perm = this.database.rules.hasPermission(
|
||||||
this.query.path,
|
this.query.path,
|
||||||
|
this.permission,
|
||||||
this.session
|
this.session
|
||||||
);
|
);
|
||||||
if (this.permission === "read" && !perm.read) {
|
|
||||||
throw new QueryError("No permission!");
|
if (!perm) throw new QueryError("No permission!");
|
||||||
} else if (this.permission === "write" && !perm.write) {
|
|
||||||
throw new QueryError("No permission!");
|
// this.query.path = perm.path;
|
||||||
}
|
|
||||||
this.query.path = perm.path;
|
|
||||||
return this._runner.call(
|
return this._runner.call(
|
||||||
this,
|
this,
|
||||||
collection,
|
collection,
|
||||||
@ -173,14 +174,13 @@ export abstract class Query {
|
|||||||
) {
|
) {
|
||||||
let perm = this.database.rules.hasPermission(
|
let perm = this.database.rules.hasPermission(
|
||||||
this.query.path,
|
this.query.path,
|
||||||
|
"read",
|
||||||
this.session
|
this.session
|
||||||
);
|
);
|
||||||
if (!perm.read) {
|
if (!perm) {
|
||||||
throw new QueryError("No permission!");
|
throw new QueryError("No permission!");
|
||||||
}
|
}
|
||||||
|
|
||||||
this.query.path = perm.path;
|
|
||||||
|
|
||||||
const receivedChanges = (changes: Change[]) => {
|
const receivedChanges = (changes: Change[]) => {
|
||||||
let res = changes
|
let res = changes
|
||||||
.filter((change) => this.checkChange(change))
|
.filter((change) => this.checkChange(change))
|
||||||
@ -464,7 +464,7 @@ export class CollectionQuery extends Query {
|
|||||||
batchCompatible: false,
|
batchCompatible: false,
|
||||||
createCollection: false,
|
createCollection: false,
|
||||||
needDocument: false,
|
needDocument: false,
|
||||||
permission: "read",
|
permission: "list",
|
||||||
runner: this.keys,
|
runner: this.keys,
|
||||||
};
|
};
|
||||||
case "list":
|
case "list":
|
||||||
|
@ -1,125 +0,0 @@
|
|||||||
import Session from "./session";
|
|
||||||
import Logging from "@hibas123/nodelogging";
|
|
||||||
|
|
||||||
interface IRule<T> {
|
|
||||||
".write"?: T;
|
|
||||||
".read"?: T;
|
|
||||||
}
|
|
||||||
|
|
||||||
type IRuleConfig<T> =
|
|
||||||
| IRule<T>
|
|
||||||
| {
|
|
||||||
[segment: string]: IRuleConfig<T>;
|
|
||||||
};
|
|
||||||
|
|
||||||
type IRuleRaw = IRuleConfig<string>;
|
|
||||||
type IRuleParsed = IRuleConfig<boolean>;
|
|
||||||
|
|
||||||
const resolve = (value: any) => {
|
|
||||||
if (value === true) {
|
|
||||||
return true;
|
|
||||||
} else if (typeof value === "string") {
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
|
|
||||||
export class Rules {
|
|
||||||
rules: IRuleParsed;
|
|
||||||
constructor(private config: string) {
|
|
||||||
let parsed: IRuleRaw = JSON.parse(config);
|
|
||||||
|
|
||||||
const analyse = (raw: IRuleRaw) => {
|
|
||||||
let r: IRuleParsed = {};
|
|
||||||
|
|
||||||
if (raw[".read"]) {
|
|
||||||
let res = resolve(raw[".read"]);
|
|
||||||
if (res) {
|
|
||||||
r[".read"] = res;
|
|
||||||
}
|
|
||||||
delete raw[".read"];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (raw[".write"]) {
|
|
||||||
let res = resolve(raw[".write"]);
|
|
||||||
if (res) {
|
|
||||||
r[".write"] = res;
|
|
||||||
}
|
|
||||||
delete raw[".write"];
|
|
||||||
}
|
|
||||||
|
|
||||||
for (let segment in raw) {
|
|
||||||
if (segment.startsWith(".")) continue;
|
|
||||||
|
|
||||||
r[segment] = analyse(raw[segment]);
|
|
||||||
}
|
|
||||||
return r;
|
|
||||||
};
|
|
||||||
|
|
||||||
this.rules = analyse(parsed);
|
|
||||||
}
|
|
||||||
|
|
||||||
hasPermission(
|
|
||||||
path: string[],
|
|
||||||
session: Session
|
|
||||||
): { read: boolean; write: boolean; path: string[] } {
|
|
||||||
if (session.root)
|
|
||||||
return {
|
|
||||||
read: true,
|
|
||||||
write: true,
|
|
||||||
path: path
|
|
||||||
};
|
|
||||||
let read = this.rules[".read"] || false;
|
|
||||||
let write = this.rules[".write"] || false;
|
|
||||||
|
|
||||||
let rules = this.rules;
|
|
||||||
|
|
||||||
for (let idx in path) {
|
|
||||||
let segment = path[idx];
|
|
||||||
if (segment.startsWith(".")) {
|
|
||||||
read = false;
|
|
||||||
write = false;
|
|
||||||
Logging.log("Invalid query path (started with '$' or '.'):", path);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
let k = Object.keys(rules)
|
|
||||||
.filter(e => e.startsWith("$"))
|
|
||||||
.find(e => {
|
|
||||||
switch (e) {
|
|
||||||
case "$uid":
|
|
||||||
if (segment === "$uid") {
|
|
||||||
path[idx] = session.uid;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (segment === session.uid) return true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
rules = (k ? rules[k] : undefined) || rules[segment] || rules["*"];
|
|
||||||
|
|
||||||
if (rules) {
|
|
||||||
if (rules[".read"]) {
|
|
||||||
read = rules[".read"];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rules[".write"]) {
|
|
||||||
read = rules[".write"];
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
read: read as boolean,
|
|
||||||
write: write as boolean,
|
|
||||||
path
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
toJSON() {
|
|
||||||
return this.config;
|
|
||||||
}
|
|
||||||
}
|
|
296
src/rules/compile.ts
Normal file
296
src/rules/compile.ts
Normal file
@ -0,0 +1,296 @@
|
|||||||
|
import {
|
||||||
|
Node,
|
||||||
|
MatchStatement,
|
||||||
|
Operations,
|
||||||
|
ServiceStatement,
|
||||||
|
Expression,
|
||||||
|
ValueStatement,
|
||||||
|
Operators,
|
||||||
|
} from "./parser";
|
||||||
|
|
||||||
|
export class CompilerError extends Error {
|
||||||
|
node: Node;
|
||||||
|
constructor(message: string, node: Node) {
|
||||||
|
super(message);
|
||||||
|
this.node = node;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Variables = { [key: string]: string | Variables };
|
||||||
|
|
||||||
|
class Variable {
|
||||||
|
#name: string;
|
||||||
|
constructor(name: string) {
|
||||||
|
this.#name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue(variables: Variables) {
|
||||||
|
const parts = this.#name.split(".");
|
||||||
|
let current = variables as any;
|
||||||
|
while (parts.length > 0) {
|
||||||
|
const name = parts.shift();
|
||||||
|
if (current && typeof current == "object") current = current[name];
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Value {
|
||||||
|
#value: any;
|
||||||
|
constructor(value: any) {
|
||||||
|
this.#value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
get value() {
|
||||||
|
return this.#value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConditionParameters = Value | ConditionMatcher | Variable;
|
||||||
|
class ConditionMatcher {
|
||||||
|
#left: ConditionParameters;
|
||||||
|
#right: ConditionParameters;
|
||||||
|
#operator: Operators;
|
||||||
|
constructor(
|
||||||
|
left: ConditionParameters,
|
||||||
|
right: ConditionParameters,
|
||||||
|
operator: Operators
|
||||||
|
) {
|
||||||
|
this.#left = left;
|
||||||
|
this.#right = right;
|
||||||
|
this.#operator = operator;
|
||||||
|
}
|
||||||
|
|
||||||
|
test(variables: Variables): boolean {
|
||||||
|
let leftValue: any;
|
||||||
|
if (this.#left instanceof Value) {
|
||||||
|
leftValue = this.#left.value;
|
||||||
|
} else if (this.#left instanceof Variable) {
|
||||||
|
leftValue = this.#left.getValue(variables);
|
||||||
|
} else {
|
||||||
|
leftValue = this.#left.test(variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
let rightValue: any;
|
||||||
|
if (this.#right instanceof Value) {
|
||||||
|
rightValue = this.#right.value;
|
||||||
|
} else if (this.#right instanceof Variable) {
|
||||||
|
rightValue = this.#right.getValue(variables);
|
||||||
|
} else {
|
||||||
|
rightValue = this.#right.test(variables);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (this.#operator) {
|
||||||
|
case "==":
|
||||||
|
return leftValue == rightValue;
|
||||||
|
case "!=":
|
||||||
|
return leftValue != rightValue;
|
||||||
|
case ">=":
|
||||||
|
return leftValue >= rightValue;
|
||||||
|
case "<=":
|
||||||
|
return leftValue <= rightValue;
|
||||||
|
case ">":
|
||||||
|
return leftValue > rightValue;
|
||||||
|
case "<":
|
||||||
|
return leftValue < rightValue;
|
||||||
|
case "&&":
|
||||||
|
return leftValue && rightValue;
|
||||||
|
case "||":
|
||||||
|
return leftValue || rightValue;
|
||||||
|
default:
|
||||||
|
throw new Error("Invalid operator " + this.#operator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Rule {
|
||||||
|
#operation: Operations;
|
||||||
|
|
||||||
|
#condition: ConditionParameters;
|
||||||
|
|
||||||
|
get operation() {
|
||||||
|
return this.#operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(operation: Operations, condition: ConditionParameters) {
|
||||||
|
this.#operation = operation;
|
||||||
|
this.#condition = condition;
|
||||||
|
}
|
||||||
|
|
||||||
|
test(variables: Variables): boolean {
|
||||||
|
if (this.#condition instanceof Value) {
|
||||||
|
return Boolean(this.#condition.value);
|
||||||
|
} else if (this.#condition instanceof Variable) {
|
||||||
|
return Boolean(this.#condition.getValue(variables));
|
||||||
|
} else {
|
||||||
|
return this.#condition.test(variables);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Segment {
|
||||||
|
#name: string;
|
||||||
|
#variable: boolean;
|
||||||
|
get name() {
|
||||||
|
return this.#name;
|
||||||
|
}
|
||||||
|
constructor(name: string, variable = false) {
|
||||||
|
this.#name = name;
|
||||||
|
this.#variable = variable;
|
||||||
|
}
|
||||||
|
|
||||||
|
match(segment: string): { match: boolean; variable?: string } {
|
||||||
|
return {
|
||||||
|
match: this.#name === segment || this.#variable,
|
||||||
|
variable: this.#variable && this.#name,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Match {
|
||||||
|
#submatches: Match[];
|
||||||
|
#rules: Rule[];
|
||||||
|
|
||||||
|
#segments: Segment[];
|
||||||
|
#wildcard: boolean;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
segments: Segment[],
|
||||||
|
rules: Rule[],
|
||||||
|
wildcard: boolean,
|
||||||
|
submatches: Match[]
|
||||||
|
) {
|
||||||
|
this.#segments = segments;
|
||||||
|
this.#rules = rules;
|
||||||
|
this.#wildcard = wildcard;
|
||||||
|
this.#submatches = submatches;
|
||||||
|
}
|
||||||
|
|
||||||
|
match(
|
||||||
|
segments: string[],
|
||||||
|
operation: Operations,
|
||||||
|
variables: Variables
|
||||||
|
): boolean {
|
||||||
|
let localVars = { ...variables };
|
||||||
|
if (segments.length >= this.#segments.length) {
|
||||||
|
for (let i = 0; i < this.#segments.length; i++) {
|
||||||
|
const match = this.#segments[i].match(segments[i]);
|
||||||
|
if (match.match) {
|
||||||
|
if (match.variable) {
|
||||||
|
localVars[match.variable] = segments[i];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let remaining = segments.slice(this.#segments.length);
|
||||||
|
if (remaining.length > 0 && !this.#wildcard) {
|
||||||
|
for (const match of this.#submatches) {
|
||||||
|
const res = match.match(remaining, operation, localVars);
|
||||||
|
if (res) return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (const rule of this.#rules) {
|
||||||
|
console.log(rule.operation, operation);
|
||||||
|
if (rule.operation === operation) {
|
||||||
|
if (rule.test(localVars)) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RuleRunner {
|
||||||
|
#root_matches: Match[];
|
||||||
|
constructor(root_matches: Match[]) {
|
||||||
|
this.#root_matches = root_matches;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasPermission(path: string[], operation: Operations, request: any): boolean {
|
||||||
|
if (request.root) return true;
|
||||||
|
for (const match of this.#root_matches) {
|
||||||
|
const res = match.match(path, operation, { request });
|
||||||
|
if (res) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRuleRunner(service: ServiceStatement) {
|
||||||
|
const createMatch = (s_match: MatchStatement) => {
|
||||||
|
let wildcard = false;
|
||||||
|
let segments = s_match.path.segments
|
||||||
|
.map((segment, idx, arr) => {
|
||||||
|
if (typeof segment === "string") {
|
||||||
|
if (segment === "*") {
|
||||||
|
if (idx === arr.length - 1) {
|
||||||
|
wildcard = true;
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
throw new CompilerError("Invalid path wildcard!", s_match);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return new Segment(segment, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return new Segment(segment.name, true);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter((e) => e !== null);
|
||||||
|
|
||||||
|
const resolveParameter = (e: Expression | ValueStatement) => {
|
||||||
|
let val: Value | ConditionMatcher | Variable;
|
||||||
|
if (e.type === "value") {
|
||||||
|
const c = e;
|
||||||
|
if (c.isFalse) {
|
||||||
|
val = new Value(false);
|
||||||
|
} else if (c.isTrue) {
|
||||||
|
val = new Value(true);
|
||||||
|
} else if (c.isNull) {
|
||||||
|
val = new Value(null);
|
||||||
|
} else if (c.isNumber) {
|
||||||
|
val = new Value(Number(c.value));
|
||||||
|
} else if (c.isString) {
|
||||||
|
val = new Value(String(c.value));
|
||||||
|
} else if (c.isVariable) {
|
||||||
|
val = new Variable(String(c.value));
|
||||||
|
} else {
|
||||||
|
throw new CompilerError("Invalid value type!", e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val = createCondition(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
};
|
||||||
|
|
||||||
|
const createCondition = (cond: Expression): ConditionMatcher => {
|
||||||
|
let left: ConditionParameters = resolveParameter(cond.left);
|
||||||
|
let right: ConditionParameters = resolveParameter(cond.right);
|
||||||
|
|
||||||
|
return new ConditionMatcher(left, right, cond.operator);
|
||||||
|
};
|
||||||
|
|
||||||
|
const rules: Rule[] = s_match.rules
|
||||||
|
.map((rule) => {
|
||||||
|
const condition = resolveParameter(rule.condition);
|
||||||
|
return rule.operations.map((op) => new Rule(op, condition));
|
||||||
|
})
|
||||||
|
.flat(1);
|
||||||
|
const submatches = s_match.matches.map((sub) => createMatch(sub));
|
||||||
|
const match = new Match(segments, rules, wildcard, submatches);
|
||||||
|
|
||||||
|
console.log("Adding match", segments, rules, wildcard, submatches);
|
||||||
|
|
||||||
|
return match;
|
||||||
|
};
|
||||||
|
|
||||||
|
const root_matches = service.matches.map((match) => createMatch(match));
|
||||||
|
|
||||||
|
const runner = new RuleRunner(root_matches);
|
||||||
|
|
||||||
|
return runner;
|
||||||
|
}
|
36
src/rules/error.ts
Normal file
36
src/rules/error.ts
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
export interface RuleError {
|
||||||
|
line: number;
|
||||||
|
column: number;
|
||||||
|
message: string;
|
||||||
|
original_err: Error;
|
||||||
|
}
|
||||||
|
|
||||||
|
function indexToLineAndCol(src: string, index: number) {
|
||||||
|
let line = 1;
|
||||||
|
let col = 1;
|
||||||
|
for (let i = 0; i < index; i++) {
|
||||||
|
if (src.charAt(i) === "\n") {
|
||||||
|
line++;
|
||||||
|
col = 1;
|
||||||
|
} else {
|
||||||
|
col++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { line, col };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function transformError(
|
||||||
|
err: Error,
|
||||||
|
data: string,
|
||||||
|
idx: number
|
||||||
|
): RuleError {
|
||||||
|
let loc = indexToLineAndCol(data, idx);
|
||||||
|
|
||||||
|
return {
|
||||||
|
line: loc.line,
|
||||||
|
column: loc.col,
|
||||||
|
message: err.message,
|
||||||
|
original_err: err,
|
||||||
|
};
|
||||||
|
}
|
30
src/rules/index.ts
Normal file
30
src/rules/index.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { RuleError, transformError } from "./error";
|
||||||
|
import parse, { ParserError } from "./parser";
|
||||||
|
import tokenize, { TokenizerError } from "./tokenise";
|
||||||
|
import { getRuleRunner, RuleRunner } from "./compile";
|
||||||
|
import { inspect } from "util";
|
||||||
|
|
||||||
|
export default function compileRule(rule: string) {
|
||||||
|
let runner: RuleRunner | undefined;
|
||||||
|
let error: RuleError | undefined;
|
||||||
|
try {
|
||||||
|
const tokenised = tokenize(rule);
|
||||||
|
// console.log(tokenised);
|
||||||
|
const parsed = parse(tokenised);
|
||||||
|
const dbservice = parsed.find((e) => e.name === "realtimedb");
|
||||||
|
|
||||||
|
if (!dbservice) throw new Error("No realtimedb service available!");
|
||||||
|
|
||||||
|
runner = getRuleRunner(dbservice);
|
||||||
|
} catch (err) {
|
||||||
|
if (err instanceof TokenizerError) {
|
||||||
|
error = transformError(err, rule, err.index);
|
||||||
|
} else if (err instanceof ParserError) {
|
||||||
|
error = transformError(err, rule, err.token.startIdx);
|
||||||
|
} else {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return { runner, error };
|
||||||
|
}
|
349
src/rules/parser.ts
Normal file
349
src/rules/parser.ts
Normal file
@ -0,0 +1,349 @@
|
|||||||
|
import { Token } from "./tokenise";
|
||||||
|
|
||||||
|
export interface Node {
|
||||||
|
type: string;
|
||||||
|
idx: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface PathStatement extends Node {
|
||||||
|
type: "path";
|
||||||
|
segments: (string | { type: "variable"; name: string })[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ValueStatement extends Node {
|
||||||
|
type: "value";
|
||||||
|
isNull: boolean;
|
||||||
|
isTrue: boolean;
|
||||||
|
isFalse: boolean;
|
||||||
|
isNumber: boolean;
|
||||||
|
isString: boolean;
|
||||||
|
isVariable: boolean;
|
||||||
|
|
||||||
|
value?: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Operators = "&&" | "||" | "==" | "<=" | ">=" | "!=" | ">" | "<";
|
||||||
|
|
||||||
|
export interface Expression extends Node {
|
||||||
|
type: "expression";
|
||||||
|
|
||||||
|
left: ValueStatement | Expression;
|
||||||
|
operator: Operators;
|
||||||
|
right: ValueStatement | Expression;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Operations = "read" | "write" | "list"; // | "update" | "create" | "delete" | "list";
|
||||||
|
|
||||||
|
export interface AllowStatement extends Node {
|
||||||
|
type: "permission";
|
||||||
|
operations: Operations[];
|
||||||
|
condition: Expression | ValueStatement;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MatchStatement extends Node {
|
||||||
|
type: "match";
|
||||||
|
path: PathStatement;
|
||||||
|
matches: MatchStatement[];
|
||||||
|
rules: AllowStatement[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServiceStatement extends Node {
|
||||||
|
type: "service";
|
||||||
|
name: string;
|
||||||
|
matches: MatchStatement[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ParserError extends Error {
|
||||||
|
token: Token;
|
||||||
|
constructor(message: string, token: Token) {
|
||||||
|
super(message);
|
||||||
|
this.token = token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function parse(tokens: Token[]) {
|
||||||
|
const tokenIterator = tokens[Symbol.iterator]();
|
||||||
|
let currentToken: Token = tokenIterator.next().value;
|
||||||
|
let nextToken: Token = tokenIterator.next().value;
|
||||||
|
|
||||||
|
const eatToken = (value?: string) => {
|
||||||
|
if (value && value !== currentToken.value) {
|
||||||
|
throw new ParserError(
|
||||||
|
`Unexpected token value, expected '${value}', received '${currentToken.value}'`,
|
||||||
|
currentToken
|
||||||
|
);
|
||||||
|
}
|
||||||
|
let idx = currentToken.startIdx;
|
||||||
|
currentToken = nextToken;
|
||||||
|
nextToken = tokenIterator.next().value;
|
||||||
|
return idx;
|
||||||
|
};
|
||||||
|
|
||||||
|
const eatText = (): [string, number] => {
|
||||||
|
checkTypes("text");
|
||||||
|
let val = currentToken.value;
|
||||||
|
let idx = currentToken.startIdx;
|
||||||
|
eatToken();
|
||||||
|
return [val, idx];
|
||||||
|
};
|
||||||
|
const eatNumber = (): number => {
|
||||||
|
checkTypes("number");
|
||||||
|
let val = Number(currentToken.value);
|
||||||
|
if (Number.isNaN(val)) {
|
||||||
|
throw new ParserError(
|
||||||
|
`Value cannot be parsed as number! ${currentToken.value}`,
|
||||||
|
currentToken
|
||||||
|
);
|
||||||
|
}
|
||||||
|
eatToken();
|
||||||
|
return val;
|
||||||
|
};
|
||||||
|
|
||||||
|
const checkTypes = (...types: string[]) => {
|
||||||
|
if (types.indexOf(currentToken.type) < 0) {
|
||||||
|
throw new ParserError(
|
||||||
|
`Unexpected token value, expected ${types.join(" | ")}, received '${
|
||||||
|
currentToken.value
|
||||||
|
}'`,
|
||||||
|
currentToken
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const parsePathStatement = (): PathStatement => {
|
||||||
|
const segments: (string | { name: string; type: "variable" })[] = [];
|
||||||
|
const idx = currentToken.startIdx;
|
||||||
|
let next = currentToken.type === "slash";
|
||||||
|
while (next) {
|
||||||
|
eatToken("/");
|
||||||
|
if (currentToken.type === "curly_open" && nextToken.type === "text") {
|
||||||
|
eatToken("{");
|
||||||
|
const [name] = eatText();
|
||||||
|
segments.push({
|
||||||
|
type: "variable",
|
||||||
|
name,
|
||||||
|
});
|
||||||
|
eatToken("}");
|
||||||
|
} else if (currentToken.type === "text") {
|
||||||
|
const [name] = eatText();
|
||||||
|
segments.push(name);
|
||||||
|
}
|
||||||
|
next = currentToken.type === "slash";
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: "path",
|
||||||
|
idx,
|
||||||
|
segments,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const parseValue = (): ValueStatement => {
|
||||||
|
const idx = currentToken.startIdx;
|
||||||
|
|
||||||
|
let isTrue = false;
|
||||||
|
let isFalse = false;
|
||||||
|
let isNull = false;
|
||||||
|
let isVariable = false;
|
||||||
|
let isNumber = false;
|
||||||
|
let isString = false;
|
||||||
|
let value: any = undefined;
|
||||||
|
if (currentToken.type === "keyword") {
|
||||||
|
if (currentToken.value === "true") isTrue = true;
|
||||||
|
else if (currentToken.value === "false") isFalse = true;
|
||||||
|
else if (currentToken.value === "null") isNull = true;
|
||||||
|
else {
|
||||||
|
throw new ParserError(
|
||||||
|
`Invalid keyword at this position ${currentToken.value}`,
|
||||||
|
currentToken
|
||||||
|
);
|
||||||
|
}
|
||||||
|
eatToken();
|
||||||
|
} else if (currentToken.type === "string") {
|
||||||
|
isString = true;
|
||||||
|
value = currentToken.value.slice(1, currentToken.value.length - 1);
|
||||||
|
eatToken();
|
||||||
|
} else if (currentToken.type === "number") {
|
||||||
|
isNumber = true;
|
||||||
|
value = eatNumber();
|
||||||
|
} else if (currentToken.type === "text") {
|
||||||
|
isVariable = true;
|
||||||
|
[value] = eatText();
|
||||||
|
} else {
|
||||||
|
throw new ParserError(
|
||||||
|
`Expected value got ${currentToken.type}`,
|
||||||
|
currentToken
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: "value",
|
||||||
|
isFalse,
|
||||||
|
isNull,
|
||||||
|
isNumber,
|
||||||
|
isString,
|
||||||
|
isTrue,
|
||||||
|
isVariable,
|
||||||
|
value,
|
||||||
|
idx,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const parseCondition = (): Expression | ValueStatement => {
|
||||||
|
// let running = true;
|
||||||
|
let res: Expression | ValueStatement;
|
||||||
|
let left: Expression | ValueStatement | undefined;
|
||||||
|
|
||||||
|
// while (running) {
|
||||||
|
const idx = currentToken.startIdx;
|
||||||
|
|
||||||
|
if (!left) {
|
||||||
|
if (currentToken.type === "bracket_open") {
|
||||||
|
eatToken("(");
|
||||||
|
left = parseCondition();
|
||||||
|
eatToken(")");
|
||||||
|
} else {
|
||||||
|
left = parseValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentToken.type === "comparison_operator") {
|
||||||
|
const operator = currentToken.value;
|
||||||
|
|
||||||
|
eatToken();
|
||||||
|
|
||||||
|
let right: Expression | ValueStatement;
|
||||||
|
|
||||||
|
let ct = currentToken; //Quick hack because of TypeScript
|
||||||
|
if (ct.type === "bracket_open") {
|
||||||
|
eatToken("(");
|
||||||
|
right = parseCondition();
|
||||||
|
eatToken(")");
|
||||||
|
} else {
|
||||||
|
right = parseValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
res = {
|
||||||
|
type: "expression",
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
operator: operator as Operators,
|
||||||
|
idx,
|
||||||
|
};
|
||||||
|
} else if (currentToken.type === "logic_operator") {
|
||||||
|
const operator = currentToken.value;
|
||||||
|
|
||||||
|
eatToken();
|
||||||
|
|
||||||
|
const right = parseCondition();
|
||||||
|
|
||||||
|
res = {
|
||||||
|
type: "expression",
|
||||||
|
left,
|
||||||
|
operator: operator as Operators,
|
||||||
|
right,
|
||||||
|
idx,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
res = left;
|
||||||
|
}
|
||||||
|
|
||||||
|
// let ct = currentToken;
|
||||||
|
// if (
|
||||||
|
// ct.type === "comparison_operator" ||
|
||||||
|
// ct.type === "logic_operator"
|
||||||
|
// ) {
|
||||||
|
// left = res;
|
||||||
|
// } else {
|
||||||
|
// running = false;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
const parsePermissionStatement = (): AllowStatement => {
|
||||||
|
const idx = eatToken("allow");
|
||||||
|
|
||||||
|
const operations: Operations[] = [];
|
||||||
|
let next = currentToken.type !== "colon";
|
||||||
|
while (next) {
|
||||||
|
const [operation] = eatText();
|
||||||
|
operations.push(operation as Operations);
|
||||||
|
if (currentToken.type === "comma") {
|
||||||
|
next = true;
|
||||||
|
eatToken(",");
|
||||||
|
} else {
|
||||||
|
next = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
eatToken(":");
|
||||||
|
|
||||||
|
eatToken("if");
|
||||||
|
|
||||||
|
const condition = parseCondition();
|
||||||
|
|
||||||
|
eatToken(";");
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: "permission",
|
||||||
|
idx,
|
||||||
|
operations,
|
||||||
|
condition,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const parseMatchStatement = (): MatchStatement => {
|
||||||
|
const idx = eatToken("match");
|
||||||
|
const path = parsePathStatement();
|
||||||
|
|
||||||
|
eatToken("{");
|
||||||
|
const matches: MatchStatement[] = [];
|
||||||
|
const permissions: AllowStatement[] = [];
|
||||||
|
while (currentToken.type !== "curly_close") {
|
||||||
|
if (currentToken.value === "match") {
|
||||||
|
matches.push(parseMatchStatement());
|
||||||
|
} else if (currentToken.value === "allow") {
|
||||||
|
permissions.push(parsePermissionStatement());
|
||||||
|
} else {
|
||||||
|
throw new ParserError(
|
||||||
|
`Unexpected token value, expected 'match' or 'allow', received '${currentToken.value}'`,
|
||||||
|
currentToken
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eatToken("}");
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: "match",
|
||||||
|
path,
|
||||||
|
idx,
|
||||||
|
matches,
|
||||||
|
rules: permissions,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const parseServiceStatement = (): ServiceStatement => {
|
||||||
|
const idx = eatToken("service");
|
||||||
|
let [name] = eatText();
|
||||||
|
eatToken("{");
|
||||||
|
const matches: MatchStatement[] = [];
|
||||||
|
while (currentToken.value === "match") {
|
||||||
|
matches.push(parseMatchStatement());
|
||||||
|
}
|
||||||
|
eatToken("}");
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: "service",
|
||||||
|
name: name,
|
||||||
|
idx,
|
||||||
|
matches,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const nodes: ServiceStatement[] = [];
|
||||||
|
while (currentToken) {
|
||||||
|
nodes.push(parseServiceStatement());
|
||||||
|
}
|
||||||
|
return nodes;
|
||||||
|
}
|
99
src/rules/tokenise.ts
Normal file
99
src/rules/tokenise.ts
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
export type TokenTypes =
|
||||||
|
| "space"
|
||||||
|
| "comment"
|
||||||
|
| "string"
|
||||||
|
| "keyword"
|
||||||
|
| "colon"
|
||||||
|
| "semicolon"
|
||||||
|
| "comma"
|
||||||
|
| "comparison_operator"
|
||||||
|
| "logic_operator"
|
||||||
|
| "equals"
|
||||||
|
| "slash"
|
||||||
|
| "bracket_open"
|
||||||
|
| "bracket_close"
|
||||||
|
| "curly_open"
|
||||||
|
| "curly_close"
|
||||||
|
| "array"
|
||||||
|
| "questionmark"
|
||||||
|
| "number"
|
||||||
|
| "text";
|
||||||
|
|
||||||
|
export type Token = {
|
||||||
|
type: TokenTypes;
|
||||||
|
value: string;
|
||||||
|
startIdx: number;
|
||||||
|
endIdx: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
type Matcher = (input: string, index: number) => undefined | Token;
|
||||||
|
|
||||||
|
export class TokenizerError extends Error {
|
||||||
|
index: number;
|
||||||
|
constructor(message: string, index: number) {
|
||||||
|
super(message);
|
||||||
|
this.index = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function regexMatcher(regex: string | RegExp, type: TokenTypes): Matcher {
|
||||||
|
if (typeof regex === "string") regex = new RegExp(regex);
|
||||||
|
|
||||||
|
return (input: string, index: number) => {
|
||||||
|
let matches = input.substring(index).match(regex as RegExp);
|
||||||
|
if (!matches || matches.length <= 0) return undefined;
|
||||||
|
|
||||||
|
return {
|
||||||
|
type,
|
||||||
|
value: matches[0],
|
||||||
|
startIdx: index,
|
||||||
|
endIdx: index + matches[0].length,
|
||||||
|
} as Token;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const matcher = [
|
||||||
|
regexMatcher(/^\s+/, "space"),
|
||||||
|
regexMatcher(/^(\/\*)(.|\s)*?(\*\/)/g, "comment"),
|
||||||
|
regexMatcher(/^\/\/.+/, "comment"),
|
||||||
|
regexMatcher(/^#.+/, "comment"),
|
||||||
|
regexMatcher(/^".*?"/, "string"),
|
||||||
|
// regexMatcher(/(?<=^")(.*?)(?=")/, "string"),
|
||||||
|
regexMatcher(/^(service|match|allow|if|true|false|null)/, "keyword"),
|
||||||
|
regexMatcher(/^\:/, "colon"),
|
||||||
|
regexMatcher(/^\;/, "semicolon"),
|
||||||
|
regexMatcher(/^\,/, "comma"),
|
||||||
|
regexMatcher(/^(\=\=|\!\=|\<\=|\>\=|\>|\<)/, "comparison_operator"),
|
||||||
|
regexMatcher(/^(&&|\|\|)/, "logic_operator"),
|
||||||
|
regexMatcher(/^\=/, "equals"),
|
||||||
|
regexMatcher(/^\//, "slash"),
|
||||||
|
regexMatcher(/^\(/, "bracket_open"),
|
||||||
|
regexMatcher(/^\)/, "bracket_close"),
|
||||||
|
regexMatcher(/^{/, "curly_open"),
|
||||||
|
regexMatcher(/^}/, "curly_close"),
|
||||||
|
regexMatcher(/^\[\]/, "array"),
|
||||||
|
regexMatcher(/^\?/, "questionmark"),
|
||||||
|
regexMatcher(/^[0-9]+(\.[0-9]+)?/, "number"),
|
||||||
|
regexMatcher(/^[a-zA-Z_\*]([a-zA-Z0-9_\.\*]?)+/, "text"),
|
||||||
|
];
|
||||||
|
|
||||||
|
export default function tokenize(input: string) {
|
||||||
|
let index = 0;
|
||||||
|
let tokens: Token[] = [];
|
||||||
|
while (index < input.length) {
|
||||||
|
const matches = matcher.map((m) => m(input, index)).filter((e) => !!e);
|
||||||
|
let match = matches[0];
|
||||||
|
if (match) {
|
||||||
|
if (match.type !== "space" && match.type !== "comment") {
|
||||||
|
tokens.push(match);
|
||||||
|
}
|
||||||
|
index += match.value.length;
|
||||||
|
} else {
|
||||||
|
throw new TokenizerError(
|
||||||
|
`Unexpected token '${input.substring(index, index + 1)}'`,
|
||||||
|
index
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return tokens;
|
||||||
|
}
|
@ -2,7 +2,7 @@ import { getTemplate } from "./hb";
|
|||||||
import { Context } from "vm";
|
import { Context } from "vm";
|
||||||
|
|
||||||
interface IFormConfigField {
|
interface IFormConfigField {
|
||||||
type: "text" | "number" | "boolean" | "textarea";
|
type: "text" | "number" | "boolean" | "textarea" | "codemirror";
|
||||||
label: string;
|
label: string;
|
||||||
value?: string;
|
value?: string;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
@ -15,16 +15,16 @@ export default function getForm(
|
|||||||
title: string,
|
title: string,
|
||||||
fieldConfig: IFormConfig
|
fieldConfig: IFormConfig
|
||||||
): (ctx: Context) => void {
|
): (ctx: Context) => void {
|
||||||
let fields = Object.keys(fieldConfig).map(name => ({
|
let fields = Object.keys(fieldConfig).map((name) => ({
|
||||||
name,
|
name,
|
||||||
...fieldConfig[name],
|
...fieldConfig[name],
|
||||||
disabled: fieldConfig.disabled ? "disabled" : ""
|
disabled: fieldConfig.disabled ? "disabled" : "",
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return ctx =>
|
return (ctx) =>
|
||||||
(ctx.body = getTemplate("forms")({
|
(ctx.body = getTemplate("forms")({
|
||||||
url,
|
url,
|
||||||
title,
|
title,
|
||||||
fields
|
fields,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import getTable from "../helper/table";
|
|||||||
import {
|
import {
|
||||||
BadRequestError,
|
BadRequestError,
|
||||||
NoPermissionError,
|
NoPermissionError,
|
||||||
NotFoundError
|
NotFoundError,
|
||||||
} from "../helper/errors";
|
} from "../helper/errors";
|
||||||
import { DatabaseManager } from "../../database/database";
|
import { DatabaseManager } from "../../database/database";
|
||||||
import { MP } from "../../database/query";
|
import { MP } from "../../database/query";
|
||||||
@ -21,17 +21,17 @@ AdminRoute.use(async (ctx, next) => {
|
|||||||
return next();
|
return next();
|
||||||
});
|
});
|
||||||
|
|
||||||
AdminRoute.get("/", async ctx => {
|
AdminRoute.get("/", async (ctx) => {
|
||||||
//TODO: Main Interface
|
//TODO: Main Interface
|
||||||
ctx.body = getView("admin");
|
ctx.body = getView("admin");
|
||||||
});
|
});
|
||||||
|
|
||||||
AdminRoute.get("/settings", async ctx => {
|
AdminRoute.get("/settings", async (ctx) => {
|
||||||
let res = await new Promise<string[][]>((yes, no) => {
|
let res = await new Promise<string[][]>((yes, no) => {
|
||||||
const stream = Settings.db.createReadStream({
|
const stream = Settings.db.createReadStream({
|
||||||
keys: true,
|
keys: true,
|
||||||
values: true,
|
values: true,
|
||||||
valueAsBuffer: true
|
valueAsBuffer: true,
|
||||||
});
|
});
|
||||||
let res = [["key", "value"]];
|
let res = [["key", "value"]];
|
||||||
stream.on("data", ({ key, value }) => {
|
stream.on("data", ({ key, value }) => {
|
||||||
@ -49,7 +49,7 @@ AdminRoute.get("/settings", async ctx => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AdminRoute.get("/data", async ctx => {
|
AdminRoute.get("/data", async (ctx) => {
|
||||||
const { database } = ctx.query;
|
const { database } = ctx.query;
|
||||||
let db = DatabaseManager.getDatabase(database);
|
let db = DatabaseManager.getDatabase(database);
|
||||||
if (!db) throw new BadRequestError("Database not found");
|
if (!db) throw new BadRequestError("Database not found");
|
||||||
@ -59,7 +59,7 @@ AdminRoute.get("/data", async ctx => {
|
|||||||
values: true,
|
values: true,
|
||||||
valueAsBuffer: true,
|
valueAsBuffer: true,
|
||||||
keyAsBuffer: false,
|
keyAsBuffer: false,
|
||||||
limit: 1000
|
limit: 1000,
|
||||||
});
|
});
|
||||||
let res = [["key", "value"]];
|
let res = [["key", "value"]];
|
||||||
stream.on("data", ({ key, value }: { key: string; value: Buffer }) => {
|
stream.on("data", ({ key, value }: { key: string; value: Buffer }) => {
|
||||||
@ -67,7 +67,7 @@ AdminRoute.get("/data", async ctx => {
|
|||||||
key,
|
key,
|
||||||
key.split("/").length > 2
|
key.split("/").length > 2
|
||||||
? value.toString()
|
? value.toString()
|
||||||
: JSON.stringify(MP.decode(value))
|
: JSON.stringify(MP.decode(value)),
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ AdminRoute.get("/data", async ctx => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AdminRoute.get("/database", ctx => {
|
AdminRoute.get("/database", (ctx) => {
|
||||||
const isFull = ctx.query.full === "true" || ctx.query.full === "1";
|
const isFull = ctx.query.full === "true" || ctx.query.full === "1";
|
||||||
let res;
|
let res;
|
||||||
if (isFull) {
|
if (isFull) {
|
||||||
@ -90,7 +90,7 @@ AdminRoute.get("/database", ctx => {
|
|||||||
res = Array.from(DatabaseManager.databases.entries()).map(
|
res = Array.from(DatabaseManager.databases.entries()).map(
|
||||||
([name, config]) => ({
|
([name, config]) => ({
|
||||||
name,
|
name,
|
||||||
...JSON.parse(JSON.stringify(config))
|
...JSON.parse(JSON.stringify(config)),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@ -102,7 +102,7 @@ AdminRoute.get("/database", ctx => {
|
|||||||
} else {
|
} else {
|
||||||
ctx.body = res;
|
ctx.body = res;
|
||||||
}
|
}
|
||||||
}).post("/database", async ctx => {
|
}).post("/database", async (ctx) => {
|
||||||
const { name, rules, publickey, accesskey, rootkey } = ctx.request.body;
|
const { name, rules, publickey, accesskey, rootkey } = ctx.request.body;
|
||||||
|
|
||||||
if (!name) throw new BadRequestError("Name must be set!");
|
if (!name) throw new BadRequestError("Name must be set!");
|
||||||
@ -121,7 +121,7 @@ AdminRoute.get("/database", ctx => {
|
|||||||
ctx.body = "Success";
|
ctx.body = "Success";
|
||||||
});
|
});
|
||||||
|
|
||||||
AdminRoute.get("/collections", async ctx => {
|
AdminRoute.get("/collections", async (ctx) => {
|
||||||
const { database } = ctx.query;
|
const { database } = ctx.query;
|
||||||
let db = DatabaseManager.getDatabase(database);
|
let db = DatabaseManager.getDatabase(database);
|
||||||
if (!db) throw new BadRequestError("Database not found");
|
if (!db) throw new BadRequestError("Database not found");
|
||||||
@ -129,7 +129,7 @@ AdminRoute.get("/collections", async ctx => {
|
|||||||
let res = await new Promise<string[]>((yes, no) => {
|
let res = await new Promise<string[]>((yes, no) => {
|
||||||
const stream = db.collections.createKeyStream({
|
const stream = db.collections.createKeyStream({
|
||||||
keyAsBuffer: false,
|
keyAsBuffer: false,
|
||||||
limit: 1000
|
limit: 1000,
|
||||||
});
|
});
|
||||||
let res = [];
|
let res = [];
|
||||||
stream.on("data", (key: string) => {
|
stream.on("data", (key: string) => {
|
||||||
@ -147,7 +147,7 @@ AdminRoute.get("/collections", async ctx => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
AdminRoute.get("/collections/cleanup", async ctx => {
|
AdminRoute.get("/collections/cleanup", async (ctx) => {
|
||||||
const { database } = ctx.query;
|
const { database } = ctx.query;
|
||||||
let db = DatabaseManager.getDatabase(database);
|
let db = DatabaseManager.getDatabase(database);
|
||||||
if (!db) throw new BadRequestError("Database not found");
|
if (!db) throw new BadRequestError("Database not found");
|
||||||
@ -169,13 +169,13 @@ AdminRoute.get(
|
|||||||
rules: {
|
rules: {
|
||||||
label: "Rules",
|
label: "Rules",
|
||||||
type: "textarea",
|
type: "textarea",
|
||||||
value: `{\n ".write": true, \n ".read": true \n}`
|
value: `{\n ".write": true, \n ".read": true \n}`,
|
||||||
},
|
},
|
||||||
publickey: { label: "Public Key", type: "textarea" }
|
publickey: { label: "Public Key", type: "textarea" },
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
AdminRoute.get("/database/update", async ctx => {
|
AdminRoute.get("/database/update", async (ctx) => {
|
||||||
const { database } = ctx.query;
|
const { database } = ctx.query;
|
||||||
let db = DatabaseManager.getDatabase(database);
|
let db = DatabaseManager.getDatabase(database);
|
||||||
if (!db) throw new NotFoundError("Database not found!");
|
if (!db) throw new NotFoundError("Database not found!");
|
||||||
@ -184,28 +184,28 @@ AdminRoute.get("/database/update", async ctx => {
|
|||||||
label: "Name",
|
label: "Name",
|
||||||
type: "text",
|
type: "text",
|
||||||
value: db.name,
|
value: db.name,
|
||||||
disabled: true
|
disabled: true,
|
||||||
},
|
},
|
||||||
accesskey: {
|
accesskey: {
|
||||||
label: "Access Key",
|
label: "Access Key",
|
||||||
type: "text",
|
type: "text",
|
||||||
value: db.accesskey
|
value: db.accesskey,
|
||||||
},
|
},
|
||||||
rootkey: {
|
rootkey: {
|
||||||
label: "Root access key",
|
label: "Root access key",
|
||||||
type: "text",
|
type: "text",
|
||||||
value: db.rootkey
|
value: db.rootkey,
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
label: "Rules",
|
label: "Rules",
|
||||||
type: "textarea",
|
type: "codemirror",
|
||||||
value: db.rules.toJSON()
|
value: db.rawRules,
|
||||||
},
|
},
|
||||||
publickey: {
|
publickey: {
|
||||||
label: "Public Key",
|
label: "Public Key",
|
||||||
type: "textarea",
|
type: "textarea",
|
||||||
value: db.publickey
|
value: db.publickey,
|
||||||
}
|
},
|
||||||
})(ctx);
|
})(ctx);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1,21 +1,17 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
/* Basic Options */
|
/* Basic Options */
|
||||||
"target": "es2017", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */
|
"target": "es2019" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017','ES2018' or 'ESNEXT'. */,
|
||||||
"module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
|
"module": "commonjs" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */,
|
||||||
"declaration": true, /* Generates corresponding '.d.ts' file. */
|
"declaration": true /* Generates corresponding '.d.ts' file. */,
|
||||||
"sourceMap": true, /* Generates corresponding '.map' file. */
|
"sourceMap": true /* Generates corresponding '.map' file. */,
|
||||||
"outDir": "./lib", /* Redirect output structure to the directory. */
|
"outDir": "./lib" /* Redirect output structure to the directory. */,
|
||||||
"strict": false, /* Enable all strict type-checking options. */
|
"strict": false /* Enable all strict type-checking options. */,
|
||||||
"preserveWatchOutput": true,
|
"preserveWatchOutput": true,
|
||||||
"experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
"experimentalDecorators": true /* Enables experimental support for ES7 decorators. */,
|
||||||
"emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
"emitDecoratorMetadata": true /* Enables experimental support for emitting type metadata for decorators. */,
|
||||||
"resolveJsonModule": true
|
"resolveJsonModule": true
|
||||||
},
|
},
|
||||||
"exclude": [
|
"exclude": ["node_modules/"],
|
||||||
"node_modules/"
|
"include": ["./src"]
|
||||||
],
|
}
|
||||||
"include": [
|
|
||||||
"./src"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
@ -33,12 +33,19 @@
|
|||||||
grid-template-columns: 360px auto;
|
grid-template-columns: 360px auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#navigation {
|
||||||
|
height: 100vh;
|
||||||
|
overflow: auto;
|
||||||
|
border-right: 1px solid darkgrey;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
#content {
|
#content {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100vh;
|
||||||
border: 0;
|
border: 0;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
@ -46,7 +53,7 @@
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<div style="border-right: 1px solid darkgrey; padding: 1rem;">
|
<div id="navigation">
|
||||||
<h2>Navigation:</h2>
|
<h2>Navigation:</h2>
|
||||||
<ul class="list list-clickable">
|
<ul class="list list-clickable">
|
||||||
<li onclick="loadView('settings');">Settings</li>
|
<li onclick="loadView('settings');">Settings</li>
|
||||||
@ -57,10 +64,10 @@
|
|||||||
<div
|
<div
|
||||||
id="dbs"
|
id="dbs"
|
||||||
class="list list-clickable"
|
class="list list-clickable"
|
||||||
style="margin: 1rem;"
|
style="margin: 1rem"
|
||||||
></div>
|
></div>
|
||||||
</div>
|
</div>
|
||||||
<div style="position: relative;">
|
<div style="position: relative">
|
||||||
<iframe id="content"></iframe>
|
<iframe id="content"></iframe>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -101,8 +108,8 @@
|
|||||||
<h3>${database}</h3>
|
<h3>${database}</h3>
|
||||||
<button class=btn onclick="loadView('data', {database:'${database}'})">Data</button>
|
<button class=btn onclick="loadView('data', {database:'${database}'})">Data</button>
|
||||||
<button class=btn onclick="loadView('collections', {database:'${database}'})">Collections</button>
|
<button class=btn onclick="loadView('collections', {database:'${database}'})">Collections</button>
|
||||||
<button class=btn onclick="loadView('collections/cleanup', {database:'${database}'})">Clean</button>
|
|
||||||
<button class=btn onclick="loadView('database/update', {database:'${database}'})">Change</button>
|
<button class=btn onclick="loadView('database/update', {database:'${database}'})">Change</button>
|
||||||
|
<button class=btn onclick="loadView('collections/cleanup', {database:'${database}'})">Clean</button>
|
||||||
</div>`
|
</div>`
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
<title>{{title}}</title>
|
<title>{{title}}</title>
|
||||||
<link rel="stylesheet" href="https://unpkg.com/@hibas123/theme@1/out/base.css">
|
<link rel="stylesheet" href="https://unpkg.com/@hibas123/theme@1/out/base.css">
|
||||||
<link rel="stylesheet" href="https://unpkg.com/@hibas123/theme@1/out/light.css">
|
<link rel="stylesheet" href="https://unpkg.com/@hibas123/theme@1/out/light.css">
|
||||||
|
<link rel="stylesheet" href="https://unpkg.com/codemirror@5.58.2/lib/codemirror.css">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
#message {
|
#message {
|
||||||
@ -46,6 +47,10 @@
|
|||||||
{{#ifCond type "===" "textarea"}}
|
{{#ifCond type "===" "textarea"}}
|
||||||
<textarea class="inp" name="{{name}}" rows="20" {{disabled}}>{{value}}</textarea>
|
<textarea class="inp" name="{{name}}" rows="20" {{disabled}}>{{value}}</textarea>
|
||||||
{{/ifCond}}
|
{{/ifCond}}
|
||||||
|
|
||||||
|
{{#ifCond type "===" "codemirror"}}
|
||||||
|
<textarea codemirror class="inp" name="{{name}}" rows="20" {{disabled}}>{{value}}</textarea>
|
||||||
|
{{/ifCond}}
|
||||||
</div>
|
</div>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
|
||||||
@ -81,6 +86,19 @@
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<script src="https://unpkg.com/codemirror@5.58.2/lib/codemirror.js"></script>
|
||||||
|
<script>
|
||||||
|
document.querySelectorAll("textarea[codemirror]").forEach(elm => {
|
||||||
|
const cm = CodeMirror.fromTextArea(elm, {
|
||||||
|
lineNumbers: true,
|
||||||
|
indentUnit: 3,
|
||||||
|
tabSize: 3,
|
||||||
|
})
|
||||||
|
|
||||||
|
cm.on("change", () => cm.save())
|
||||||
|
})
|
||||||
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
Reference in New Issue
Block a user