diff --git a/config.json b/config.json new file mode 100644 index 0000000..87abf0b --- /dev/null +++ b/config.json @@ -0,0 +1,7 @@ +{ + "secret": "TEST_SECRET", + "https": false, + "alter_db": true, + "port": 8080, + "db_url": "postgres://postgres:@127.0.0.1/todo" +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..2bcaeaf --- /dev/null +++ b/package.json @@ -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 ", + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "cookie-parser": "^1.4.5", + "express": "^4.17.1", + "pg": "^8.6.0", + "sequelize": "^6.6.2" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..7711e79 --- /dev/null +++ b/pnpm-lock.yaml @@ -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 diff --git a/src/config.js b/src/config.js new file mode 100644 index 0000000..9343cec --- /dev/null +++ b/src/config.js @@ -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(); \ No newline at end of file diff --git a/src/db_interface.js b/src/db_interface.js new file mode 100644 index 0000000..d841c92 --- /dev/null +++ b/src/db_interface.js @@ -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 + } +} \ No newline at end of file diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..af37430 --- /dev/null +++ b/src/index.js @@ -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}`); +}); \ No newline at end of file diff --git a/src/user.js b/src/user.js new file mode 100644 index 0000000..2563baf --- /dev/null +++ b/src/user.js @@ -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 +}; \ No newline at end of file diff --git a/static/index.html b/static/index.html new file mode 100644 index 0000000..ec57bad --- /dev/null +++ b/static/index.html @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file