Initial commit

This commit is contained in:
jane 2021-06-09 16:12:47 -04:00
parent 19f203bb04
commit 40ee0c16d7
8 changed files with 1074 additions and 0 deletions

7
config.json Normal file
View File

@ -0,0 +1,7 @@
{
"secret": "TEST_SECRET",
"https": false,
"alter_db": true,
"port": 8080,
"db_url": "postgres://postgres:@127.0.0.1/todo"
}

21
package.json Normal file
View File

@ -0,0 +1,21 @@
{
"name": "todo",
"version": "1.0.0",
"description": "todo list app (because it hasnt been done before)",
"main": "src/index.js",
"scripts": {
"start": "node src/index.js"
},
"repository": {
"type": "git",
"url": "git@ssh.gitdab.com:jane/todo.git"
},
"author": "jane <jane@j4.pm>",
"license": "SEE LICENSE IN LICENSE",
"dependencies": {
"cookie-parser": "^1.4.5",
"express": "^4.17.1",
"pg": "^8.6.0",
"sequelize": "^6.6.2"
}
}

684
pnpm-lock.yaml Normal file
View File

@ -0,0 +1,684 @@
dependencies:
cookie-parser: 1.4.5
express: 4.17.1
pg: 8.6.0
sequelize: 6.6.2_pg@8.6.0
lockfileVersion: 5.2
packages:
/@types/node/15.12.1:
dev: false
resolution:
integrity: sha512-zyxJM8I1c9q5sRMtVF+zdd13Jt6RU4r4qfhTd7lQubyThvLfx6yYekWSQjGCGV2Tkecgxnlpl/DNlb6Hg+dmEw==
/accepts/1.3.7:
dependencies:
mime-types: 2.1.31
negotiator: 0.6.2
dev: false
engines:
node: '>= 0.6'
resolution:
integrity: sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
/any-promise/1.3.0:
dev: false
resolution:
integrity: sha1-q8av7tzqUugJzcA3au0845Y10X8=
/array-flatten/1.1.1:
dev: false
resolution:
integrity: sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
/body-parser/1.19.0:
dependencies:
bytes: 3.1.0
content-type: 1.0.4
debug: 2.6.9
depd: 1.1.2
http-errors: 1.7.2
iconv-lite: 0.4.24
on-finished: 2.3.0
qs: 6.7.0
raw-body: 2.4.0
type-is: 1.6.18
dev: false
engines:
node: '>= 0.8'
resolution:
integrity: sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
/buffer-writer/2.0.0:
dev: false
engines:
node: '>=4'
resolution:
integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==
/bytes/3.1.0:
dev: false
engines:
node: '>= 0.8'
resolution:
integrity: sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
/content-disposition/0.5.3:
dependencies:
safe-buffer: 5.1.2
dev: false
engines:
node: '>= 0.6'
resolution:
integrity: sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
/content-type/1.0.4:
dev: false
engines:
node: '>= 0.6'
resolution:
integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
/cookie-parser/1.4.5:
dependencies:
cookie: 0.4.0
cookie-signature: 1.0.6
dev: false
engines:
node: '>= 0.8.0'
resolution:
integrity: sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==
/cookie-signature/1.0.6:
dev: false
resolution:
integrity: sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
/cookie/0.4.0:
dev: false
engines:
node: '>= 0.6'
resolution:
integrity: sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
/debug/2.6.9:
dependencies:
ms: 2.0.0
dev: false
resolution:
integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
/debug/4.3.1:
dependencies:
ms: 2.1.2
dev: false
engines:
node: '>=6.0'
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
resolution:
integrity: sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
/depd/1.1.2:
dev: false
engines:
node: '>= 0.6'
resolution:
integrity: sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
/destroy/1.0.4:
dev: false
resolution:
integrity: sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
/dottie/2.0.2:
dev: false
resolution:
integrity: sha512-fmrwR04lsniq/uSr8yikThDTrM7epXHBAAjH9TbeH3rEA8tdCO7mRzB9hdmdGyJCxF8KERo9CITcm3kGuoyMhg==
/ee-first/1.1.1:
dev: false
resolution:
integrity: sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
/encodeurl/1.0.2:
dev: false
engines:
node: '>= 0.8'
resolution:
integrity: sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
/escape-html/1.0.3:
dev: false
resolution:
integrity: sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
/etag/1.8.1:
dev: false
engines:
node: '>= 0.6'
resolution:
integrity: sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
/express/4.17.1:
dependencies:
accepts: 1.3.7
array-flatten: 1.1.1
body-parser: 1.19.0
content-disposition: 0.5.3
content-type: 1.0.4
cookie: 0.4.0
cookie-signature: 1.0.6
debug: 2.6.9
depd: 1.1.2
encodeurl: 1.0.2
escape-html: 1.0.3
etag: 1.8.1
finalhandler: 1.1.2
fresh: 0.5.2
merge-descriptors: 1.0.1
methods: 1.1.2
on-finished: 2.3.0
parseurl: 1.3.3
path-to-regexp: 0.1.7
proxy-addr: 2.0.7
qs: 6.7.0
range-parser: 1.2.1
safe-buffer: 5.1.2
send: 0.17.1
serve-static: 1.14.1
setprototypeof: 1.1.1
statuses: 1.5.0
type-is: 1.6.18
utils-merge: 1.0.1
vary: 1.1.2
dev: false
engines:
node: '>= 0.10.0'
resolution:
integrity: sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
/finalhandler/1.1.2:
dependencies:
debug: 2.6.9
encodeurl: 1.0.2
escape-html: 1.0.3
on-finished: 2.3.0
parseurl: 1.3.3
statuses: 1.5.0
unpipe: 1.0.0
dev: false
engines:
node: '>= 0.8'
resolution:
integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
/forwarded/0.2.0:
dev: false
engines:
node: '>= 0.6'
resolution:
integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==
/fresh/0.5.2:
dev: false
engines:
node: '>= 0.6'
resolution:
integrity: sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
/http-errors/1.7.2:
dependencies:
depd: 1.1.2
inherits: 2.0.3
setprototypeof: 1.1.1
statuses: 1.5.0
toidentifier: 1.0.0
dev: false
engines:
node: '>= 0.6'
resolution:
integrity: sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
/http-errors/1.7.3:
dependencies:
depd: 1.1.2
inherits: 2.0.4
setprototypeof: 1.1.1
statuses: 1.5.0
toidentifier: 1.0.0
dev: false
engines:
node: '>= 0.6'
resolution:
integrity: sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==
/iconv-lite/0.4.24:
dependencies:
safer-buffer: 2.1.2
dev: false
engines:
node: '>=0.10.0'
resolution:
integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
/inflection/1.12.0:
dev: false
engines:
'0': node >= 0.4.0
resolution:
integrity: sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=
/inherits/2.0.3:
dev: false
resolution:
integrity: sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
/inherits/2.0.4:
dev: false
resolution:
integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
/ipaddr.js/1.9.1:
dev: false
engines:
node: '>= 0.10'
resolution:
integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
/lodash/4.17.21:
dev: false
resolution:
integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
/lru-cache/6.0.0:
dependencies:
yallist: 4.0.0
dev: false
engines:
node: '>=10'
resolution:
integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
/media-typer/0.3.0:
dev: false
engines:
node: '>= 0.6'
resolution:
integrity: sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
/merge-descriptors/1.0.1:
dev: false
resolution:
integrity: sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
/methods/1.1.2:
dev: false
engines:
node: '>= 0.6'
resolution:
integrity: sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
/mime-db/1.48.0:
dev: false
engines:
node: '>= 0.6'
resolution:
integrity: sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==
/mime-types/2.1.31:
dependencies:
mime-db: 1.48.0
dev: false
engines:
node: '>= 0.6'
resolution:
integrity: sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==
/mime/1.6.0:
dev: false
engines:
node: '>=4'
hasBin: true
resolution:
integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
/moment-timezone/0.5.33:
dependencies:
moment: 2.29.1
dev: false
resolution:
integrity: sha512-PTc2vcT8K9J5/9rDEPe5czSIKgLoGsH8UNpA4qZTVw0Vd/Uz19geE9abbIOQKaAQFcnQ3v5YEXrbSc5BpshH+w==
/moment/2.29.1:
dev: false
resolution:
integrity: sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
/ms/2.0.0:
dev: false
resolution:
integrity: sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
/ms/2.1.1:
dev: false
resolution:
integrity: sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
/ms/2.1.2:
dev: false
resolution:
integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
/negotiator/0.6.2:
dev: false
engines:
node: '>= 0.6'
resolution:
integrity: sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
/on-finished/2.3.0:
dependencies:
ee-first: 1.1.1
dev: false
engines:
node: '>= 0.8'
resolution:
integrity: sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
/packet-reader/1.0.0:
dev: false
resolution:
integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==
/parseurl/1.3.3:
dev: false
engines:
node: '>= 0.8'
resolution:
integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
/path-to-regexp/0.1.7:
dev: false
resolution:
integrity: sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
/pg-connection-string/2.5.0:
dev: false
resolution:
integrity: sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==
/pg-int8/1.0.1:
dev: false
engines:
node: '>=4.0.0'
resolution:
integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==
/pg-pool/3.3.0_pg@8.6.0:
dependencies:
pg: 8.6.0
dev: false
peerDependencies:
pg: '>=8.0'
resolution:
integrity: sha512-0O5huCql8/D6PIRFAlmccjphLYWC+JIzvUhSzXSpGaf+tjTZc4nn+Lr7mLXBbFJfvwbP0ywDv73EiaBsxn7zdg==
/pg-protocol/1.5.0:
dev: false
resolution:
integrity: sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==
/pg-types/2.2.0:
dependencies:
pg-int8: 1.0.1
postgres-array: 2.0.0
postgres-bytea: 1.0.0
postgres-date: 1.0.7
postgres-interval: 1.2.0
dev: false
engines:
node: '>=4'
resolution:
integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==
/pg/8.6.0:
dependencies:
buffer-writer: 2.0.0
packet-reader: 1.0.0
pg-connection-string: 2.5.0
pg-pool: 3.3.0_pg@8.6.0
pg-protocol: 1.5.0
pg-types: 2.2.0
pgpass: 1.0.4
dev: false
engines:
node: '>= 8.0.0'
peerDependencies:
pg-native: '>=2.0.0'
peerDependenciesMeta:
pg-native:
optional: true
resolution:
integrity: sha512-qNS9u61lqljTDFvmk/N66EeGq3n6Ujzj0FFyNMGQr6XuEv4tgNTXvJQTfJdcvGit5p5/DWPu+wj920hAJFI+QQ==
/pgpass/1.0.4:
dependencies:
split2: 3.2.2
dev: false
resolution:
integrity: sha512-YmuA56alyBq7M59vxVBfPJrGSozru8QAdoNlWuW3cz8l+UX3cWge0vTvjKhsSHSJpo3Bom8/Mm6hf0TR5GY0+w==
/postgres-array/2.0.0:
dev: false
engines:
node: '>=4'
resolution:
integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==
/postgres-bytea/1.0.0:
dev: false
engines:
node: '>=0.10.0'
resolution:
integrity: sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=
/postgres-date/1.0.7:
dev: false
engines:
node: '>=0.10.0'
resolution:
integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==
/postgres-interval/1.2.0:
dependencies:
xtend: 4.0.2
dev: false
engines:
node: '>=0.10.0'
resolution:
integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==
/proxy-addr/2.0.7:
dependencies:
forwarded: 0.2.0
ipaddr.js: 1.9.1
dev: false
engines:
node: '>= 0.10'
resolution:
integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==
/qs/6.7.0:
dev: false
engines:
node: '>=0.6'
resolution:
integrity: sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
/range-parser/1.2.1:
dev: false
engines:
node: '>= 0.6'
resolution:
integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
/raw-body/2.4.0:
dependencies:
bytes: 3.1.0
http-errors: 1.7.2
iconv-lite: 0.4.24
unpipe: 1.0.0
dev: false
engines:
node: '>= 0.8'
resolution:
integrity: sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==
/readable-stream/3.6.0:
dependencies:
inherits: 2.0.4
string_decoder: 1.3.0
util-deprecate: 1.0.2
dev: false
engines:
node: '>= 6'
resolution:
integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==
/retry-as-promised/3.2.0:
dependencies:
any-promise: 1.3.0
dev: false
resolution:
integrity: sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg==
/safe-buffer/5.1.2:
dev: false
resolution:
integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
/safe-buffer/5.2.1:
dev: false
resolution:
integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
/safer-buffer/2.1.2:
dev: false
resolution:
integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
/semver/7.3.5:
dependencies:
lru-cache: 6.0.0
dev: false
engines:
node: '>=10'
hasBin: true
resolution:
integrity: sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==
/send/0.17.1:
dependencies:
debug: 2.6.9
depd: 1.1.2
destroy: 1.0.4
encodeurl: 1.0.2
escape-html: 1.0.3
etag: 1.8.1
fresh: 0.5.2
http-errors: 1.7.3
mime: 1.6.0
ms: 2.1.1
on-finished: 2.3.0
range-parser: 1.2.1
statuses: 1.5.0
dev: false
engines:
node: '>= 0.8.0'
resolution:
integrity: sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==
/sequelize-pool/6.1.0:
dev: false
engines:
node: '>= 10.0.0'
resolution:
integrity: sha512-4YwEw3ZgK/tY/so+GfnSgXkdwIJJ1I32uZJztIEgZeAO6HMgj64OzySbWLgxj+tXhZCJnzRfkY9gINw8Ft8ZMg==
/sequelize/6.6.2_pg@8.6.0:
dependencies:
debug: 4.3.1
dottie: 2.0.2
inflection: 1.12.0
lodash: 4.17.21
moment: 2.29.1
moment-timezone: 0.5.33
pg: 8.6.0
retry-as-promised: 3.2.0
semver: 7.3.5
sequelize-pool: 6.1.0
toposort-class: 1.0.1
uuid: 8.3.2
validator: 10.11.0
wkx: 0.5.0
dev: false
engines:
node: '>=10.0.0'
peerDependencies:
mariadb: '*'
mysql2: '*'
pg: '*'
pg-hstore: '*'
sqlite3: '*'
tedious: '*'
peerDependenciesMeta:
mariadb:
optional: true
mysql2:
optional: true
pg:
optional: true
pg-hstore:
optional: true
sqlite3:
optional: true
tedious:
optional: true
resolution:
integrity: sha512-H/zrzmTK+tis9PJaSigkuXI57nKBvNCtPQol0yxCvau1iWLzSOuq8t3tMOVeQ+Ep8QH2HoD9/+FCCIAqzUr/BQ==
/serve-static/1.14.1:
dependencies:
encodeurl: 1.0.2
escape-html: 1.0.3
parseurl: 1.3.3
send: 0.17.1
dev: false
engines:
node: '>= 0.8.0'
resolution:
integrity: sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
/setprototypeof/1.1.1:
dev: false
resolution:
integrity: sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
/split2/3.2.2:
dependencies:
readable-stream: 3.6.0
dev: false
resolution:
integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==
/statuses/1.5.0:
dev: false
engines:
node: '>= 0.6'
resolution:
integrity: sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
/string_decoder/1.3.0:
dependencies:
safe-buffer: 5.2.1
dev: false
resolution:
integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==
/toidentifier/1.0.0:
dev: false
engines:
node: '>=0.6'
resolution:
integrity: sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
/toposort-class/1.0.1:
dev: false
resolution:
integrity: sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=
/type-is/1.6.18:
dependencies:
media-typer: 0.3.0
mime-types: 2.1.31
dev: false
engines:
node: '>= 0.6'
resolution:
integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
/unpipe/1.0.0:
dev: false
engines:
node: '>= 0.8'
resolution:
integrity: sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
/util-deprecate/1.0.2:
dev: false
resolution:
integrity: sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
/utils-merge/1.0.1:
dev: false
engines:
node: '>= 0.4.0'
resolution:
integrity: sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
/uuid/8.3.2:
dev: false
hasBin: true
resolution:
integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
/validator/10.11.0:
dev: false
engines:
node: '>= 0.10'
resolution:
integrity: sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==
/vary/1.1.2:
dev: false
engines:
node: '>= 0.8'
resolution:
integrity: sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
/wkx/0.5.0:
dependencies:
'@types/node': 15.12.1
dev: false
resolution:
integrity: sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==
/xtend/4.0.2:
dev: false
engines:
node: '>=0.4'
resolution:
integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
/yallist/4.0.0:
dev: false
resolution:
integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
specifiers:
cookie-parser: ^1.4.5
express: ^4.17.1
pg: ^8.6.0
sequelize: ^6.6.2

21
src/config.js Normal file
View File

@ -0,0 +1,21 @@
const fs = require('fs');
if (!global.config) {
global.config = {}
const cfg = JSON.parse(fs.readFileSync('./config.json'));
if (cfg) {
global.config = cfg;
}
}
class Config {
get config() {
return global.config;
}
set config(dat) {
global.config = dat;
}
}
module.exports = new Config();

77
src/db_interface.js Normal file
View File

@ -0,0 +1,77 @@
const Sequelize = require('sequelize');
const Config = require('./config.js');
if (!Config.config.db_url) {
console.error("No database url found. please set `db_url` in config.json");
process.exit();
}
const db = new Sequelize(Config.config.db_url);
const User = db.define('User', {
id: {
type: Sequelize.DataTypes.UUID,
defaultValue: Sequelize.UUIDV4,
allowNull: false,
primaryKey: true,
unique: true
},
email: {
type: Sequelize.DataTypes.STRING,
allowNull: false,
unique: true
},
password_hash: {
type: Sequelize.DataTypes.STRING,
allowNull: true
}
});
const Todo = db.define('Todo', {
id: {
type: Sequelize.DataTypes.UUID,
defaultValue: Sequelize.UUIDV4,
allowNull: false,
primaryKey: true,
unique: true
},
content: {
type: Sequelize.DataTypes.TEXT,
allowNull: false
}
});
const Tag = db.define('Tag', {
id: {
type: Sequelize.DataTypes.UUID,
defaultValue: Sequelize.UUIDV4,
allowNull: false,
primaryKey: true,
unique: true
},
content: {
type: Sequelize.DataTypes.STRING,
allowNull: false
}
});
User.hasMany(Todo);
Todo.hasMany(Tag);
let options = {
alter: false
};
if (Config.config.alter_db) {
options.alter = true;
}
User.sync(options);
module.exports = {
db: db,
constructors: {
user: () => { return User.build(); }
},
schemas: {
user: User
}
}

39
src/index.js Normal file
View File

@ -0,0 +1,39 @@
const express = require('express');
const cookieParser = require('cookie-parser');
const Config = require('./config.js');
const UserInterface = require('./user.js');
let app = express();
app.use(cookieParser());
// force https
app.use((req, res, next) => {
if (Config.config.https) {
if (req.headers['x-forwarded-proto'] !== 'https') {
return res.redirect(`https://${req.headers.host}${req.url}`);
}
}
return next();
});
if (!Config.config.secret) {
console.error("No password secret found. please set `secret` in config.json");
process.exit();
}
else if(Config.config.https && Config.config.secret == "TEST_SECRET") {
console.error("please do not use the testing secret in production.");
process.exit();
}
app.use("/user", UserInterface.router);
// serve static files last
// app.use(express.static("./static"));
// DISABLED: no longer needs to serve static files
// due to frontend being employed in elm
app.listen(Config.config.port || 8080, () => {
console.log(`listening on port ${Config.config.port || 8080}`);
});

217
src/user.js Normal file
View File

@ -0,0 +1,217 @@
const express = require('express');
const crypto = require('crypto');
const Config = require('./config.js');
const Database = require('./db_interface.js');
let router = express.Router();
router.use(express.json());
let session_entropy = {};
user_cache = {};
email_cache = {};
async function get_user_details(id) {
console.log(`search for user with id ${id}`);
if (!user_cache[id]) {
let user = await Database.schemas.user.findOne({ where: { id: id } });
if (!user) {
return undefined;
}
user_cache[user.id] = {
id: user.id,
email: user.email,
password_hash: user.password_hash
};
email_cache[user.email] = user.id;
}
console.log(`returning ${JSON.stringify(user_cache[id])}`);
return user_cache[id];
}
async function get_user_details_by_email(email) {
console.log(`search for user with email ${email}}`);
if (!email_cache[email] || !user_cache[email_cache[email]]) {
let user = await Database.schemas.user.findOne({ where: { email: email } });
if (!user) {
return undefined;
}
user_cache[user.id] = {
id: user.id,
email: user.email,
password_hash: user.password_hash
};
email_cache[user.email] = user.id;
}
console.log(`returning ${JSON.stringify(user_cache[email_cache[email]])}`);
return user_cache[email_cache[email]];
}
router.get("/byEmail/:email", async (req, res) => {
if (!req.params?.email) {
res.status(400).json({
error: "email is a required parameter"
});
}
let user = get_user_details_by_email(req.params.email);
console.log(user);
if (user != null) {
res.json({
id: user.id,
email: user.email
});
}
else {
res.sendStatus(404);
}
});
function hash(secret, password) {
let pw_hash = crypto.pbkdf2Sync(password,
secret,
Config.config.key?.iterations || 1000,
Config.config.key?.length || 64,
"sha512");
return pw_hash.toString('base64');
}
function verify(secret, password, hash) {
let pw_hash = crypto.pbkdf2Sync(password,
secret,
Config.config.key?.iterations || 1000,
Config.config.key?.length || 64,
"sha512");
return hash === pw_hash.toString('base64');
}
function hash_password(password) {
return hash(Config.config.secret, password);
}
function verify_password(password, hash) {
return verify(Config.config.secret, password, hash);
}
function get_session_token(id, token) {
session_entropy[id] = crypto.randomBytes(Config.config.session_entropy || 32);
return hash(session_entropy[id], token);
}
function verify_session_token(id, hash, token) {
if (session_entropy[id]) {
return verify(session_entropy[id], hash, token);
}
else {
return false;
}
}
async function enforce_session_login(req, res, next) {
let userid = req.cookies?.userid;
let session_token = req.cookies?._session;
console.log("a", userid, session_token);
if (!userid || !session_token) {
res.sendStatus(401);
}
let user = await get_user_details(userid);
if (!user) {
res.sendStatus(401);
}
let verified_session = verify_session_token(userid, user.password_hash, session_token);
if (!verified_session) {
res.sendStatus(401);
}
return next();
}
router.post("/new", async (req, res) => {
if (!req.body?.email || !req.body?.password) {
res.status(400).json({
error: "must have email and password fields"
});
}
let user = await get_user_details_by_email(req.body.email);
console.log(user);
if (user != null) {
res.status(403).json({
error: `email ${req.body.email} is already in use.`
});
}
else {
let user = await Database.schemas.user.create({
email: String(req.body.email),
password_hash: hash_password(req.body.password)
});
res.json({
id: user.id,
email: user.email
});
}
});
router.post("/login", async (req, res) => {
if (!req.body?.email || !req.body?.password) {
res.status(400).json({
error: "must have email and password fields"
});
}
let user = await get_user_details_by_email(req.body.email);
if (!user) {
res.status(401).json({
error: "incorrect email or password"
});
}
let verified = verify_password(req.body.password, user.password_hash);
if (!verified) {
res.status(401).json({
error: "incorrect email or password"
});
}
res.cookie("userid", user.id);
res.cookie("_session", get_session_token(user.id, user.password_hash));
res.sendStatus(204);
});
router.get("/:id(([a-f0-9\-])+)", async (req, res) => {
if (!req.params?.id) {
res.status(400).json({
error: "must have id parameter"
});
}
let user = await get_user_details(req.body.id);
console.log(user);
if (user != null) {
res.json({
id: user.id,
email: user.email
});
}
else {
res.sendStatus(404);
}
});
router.use("/authorized", enforce_session_login);
router.get("/authorized", async (req, res) => {
let userid = req.cookies?.userid;
let user = get_user_details(userid);
res.json({
authorized: true,
user: {
id: user.id,
email: user.email
}
});
});
module.exports = {
router: router,
enforce_session_login: enforce_session_login
};

8
static/index.html Normal file
View File

@ -0,0 +1,8 @@
<html>
<head>
</head>
<body>
</body>
</html>