Browse Source

password restoration

main
Nikky 4 years ago
parent
commit
810af90c67
  1. 585
      package-lock.json
  2. 1
      package.json
  3. 0
      src/config/database.config.js
  4. 11
      src/config/email.config.js
  5. 4
      src/index.js
  6. 30
      src/logic/email.js
  7. 20
      src/logic/security.js
  8. 13
      src/logic/utils.js
  9. 11
      src/misc/email-templates.js
  10. 6
      src/model/user.model.js
  11. 71
      src/route/auth.controller.js
  12. 2
      src/route/user.controller.js

585
package-lock.json

@ -119,11 +119,26 @@
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
"optional": true
},
"ast-types": {
"version": "0.14.2",
"resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.14.2.tgz",
"integrity": "sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==",
"requires": {
"tslib": "^2.0.1"
}
},
"async": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
"requires": {
"lodash": "^4.17.14"
}
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=",
"optional": true
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"atomic-sleep": {
"version": "1.0.0",
@ -284,6 +299,11 @@
"dicer": "0.3.0"
}
},
"bytes": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
},
"caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
@ -295,6 +315,11 @@
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
},
"co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
},
"code-point-at": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
@ -304,7 +329,6 @@
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"optional": true,
"requires": {
"delayed-stream": "~1.0.0"
}
@ -338,6 +362,11 @@
"assert-plus": "^1.0.0"
}
},
"data-uri-to-buffer": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz",
"integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ=="
},
"debug": {
"version": "4.3.2",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
@ -351,22 +380,41 @@
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
},
"deep-is": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz",
"integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="
},
"deepmerge": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg=="
},
"degenerator": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/degenerator/-/degenerator-1.0.4.tgz",
"integrity": "sha1-/PSQo37OJmRk2cxDGrmMWBnO0JU=",
"requires": {
"ast-types": "0.x.x",
"escodegen": "1.x.x",
"esprima": "3.x.x"
}
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
"optional": true
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
"delegates": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
},
"depd": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
"integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
},
"detect-libc": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
@ -403,11 +451,57 @@
"once": "^1.4.0"
}
},
"es6-promise": {
"version": "4.2.8",
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
},
"es6-promisify": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
"integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
"requires": {
"es6-promise": "^4.0.3"
}
},
"escodegen": {
"version": "1.14.3",
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz",
"integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==",
"requires": {
"esprima": "^4.0.1",
"estraverse": "^4.2.0",
"esutils": "^2.0.2",
"optionator": "^0.8.1",
"source-map": "~0.6.1"
},
"dependencies": {
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
}
}
},
"esprima": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz",
"integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM="
},
"estraverse": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz",
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="
},
"esutils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
},
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
"optional": true
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
},
"extsprintf": {
"version": "1.3.0",
@ -441,6 +535,11 @@
"string-similarity": "^4.0.1"
}
},
"fast-levenshtein": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
},
"fast-redact": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.0.2.tgz",
@ -519,6 +618,11 @@
"reusify": "^1.0.4"
}
},
"file-uri-to-path": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz",
"integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw=="
},
"find-my-way": {
"version": "4.3.3",
"resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-4.3.3.tgz",
@ -542,10 +646,9 @@
"optional": true
},
"form-data": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
"optional": true,
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz",
"integrity": "sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
@ -582,6 +685,38 @@
"rimraf": "2"
}
},
"ftp": {
"version": "0.3.10",
"resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz",
"integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=",
"requires": {
"readable-stream": "1.1.x",
"xregexp": "2.0.0"
},
"dependencies": {
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
},
"readable-stream": {
"version": "1.1.14",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
"integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.1",
"isarray": "0.0.1",
"string_decoder": "~0.10.x"
}
},
"string_decoder": {
"version": "0.10.31",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
}
}
},
"gauge": {
"version": "2.7.4",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
@ -597,6 +732,61 @@
"wide-align": "^1.1.0"
}
},
"get-uri": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.4.tgz",
"integrity": "sha512-v7LT/s8kVjs+Tx0ykk1I+H/rbpzkHvuIq87LmeXptcf5sNWm9uQiwjNAt94SJPA1zOlCntmnOlJvVWKmzsxG8Q==",
"requires": {
"data-uri-to-buffer": "1",
"debug": "2",
"extend": "~3.0.2",
"file-uri-to-path": "1",
"ftp": "~0.3.10",
"readable-stream": "2"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"safe-buffer": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
}
}
},
"getpass": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
@ -651,6 +841,50 @@
"resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz",
"integrity": "sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g=="
},
"http-errors": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz",
"integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==",
"requires": {
"depd": "~1.1.2",
"inherits": "2.0.4",
"setprototypeof": "1.1.1",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.0"
}
},
"http-proxy-agent": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz",
"integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==",
"requires": {
"agent-base": "4",
"debug": "3.1.0"
},
"dependencies": {
"agent-base": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
"integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
"requires": {
"es6-promisify": "^5.0.0"
}
},
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
@ -711,6 +945,11 @@
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
},
"ip": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz",
"integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo="
},
"ipaddr.js": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
@ -724,6 +963,11 @@
"number-is-nan": "^1.0.0"
}
},
"is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
},
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
@ -782,6 +1026,15 @@
"verror": "1.10.0"
}
},
"levn": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
"integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
"requires": {
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2"
}
},
"light-my-request": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/light-my-request/-/light-my-request-4.5.0.tgz",
@ -825,6 +1078,29 @@
"yallist": "^4.0.0"
}
},
"mailgun-js": {
"version": "0.22.0",
"resolved": "https://registry.npmjs.org/mailgun-js/-/mailgun-js-0.22.0.tgz",
"integrity": "sha512-a2alg5nuTZA9Psa1pSEIEsbxr1Zrmqx4VkgGCQ30xVh0kIH7Bu57AYILo+0v8QLSdXtCyLaS+KVmdCrQo0uWFA==",
"requires": {
"async": "^2.6.1",
"debug": "^4.1.0",
"form-data": "^2.3.3",
"inflection": "~1.12.0",
"is-stream": "^1.1.0",
"path-proxy": "~1.0.0",
"promisify-call": "^2.0.2",
"proxy-agent": "^3.0.3",
"tsscmp": "^1.0.6"
},
"dependencies": {
"inflection": {
"version": "1.12.0",
"resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz",
"integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY="
}
}
},
"make-dir": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz",
@ -843,14 +1119,12 @@
"mime-db": {
"version": "1.50.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.50.0.tgz",
"integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A==",
"optional": true
"integrity": "sha512-9tMZCDlYHqeERXEHO9f/hKfNXhre5dK2eE/krIvUjZbS2KPcqGDfNShIWS1uW9XOTKQKqK6qbeOci18rbfW77A=="
},
"mime-types": {
"version": "2.1.33",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.33.tgz",
"integrity": "sha512-plLElXp7pRDd0bNZHw+nMd52vRYjLwQjygaNg7ddJ2uJtTlmnTCjWuPKxVu6//AdaRuME84SvLW91sIkBqGT0g==",
"optional": true,
"requires": {
"mime-db": "1.50.0"
}
@ -938,6 +1212,11 @@
}
}
},
"netmask": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz",
"integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU="
},
"node-addon-api": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz",
@ -1098,6 +1377,19 @@
"wrappy": "1"
}
},
"optionator": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz",
"integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==",
"requires": {
"deep-is": "~0.1.3",
"fast-levenshtein": "~2.0.6",
"levn": "~0.3.0",
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2",
"word-wrap": "~1.2.3"
}
},
"os-homedir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
@ -1117,11 +1409,82 @@
"os-tmpdir": "^1.0.0"
}
},
"pac-proxy-agent": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-3.0.1.tgz",
"integrity": "sha512-44DUg21G/liUZ48dJpUSjZnFfZro/0K5JTyFYLBcmh9+T6Ooi4/i4efwUiEy0+4oQusCBqWdhv16XohIj1GqnQ==",
"requires": {
"agent-base": "^4.2.0",
"debug": "^4.1.1",
"get-uri": "^2.0.0",
"http-proxy-agent": "^2.1.0",
"https-proxy-agent": "^3.0.0",
"pac-resolver": "^3.0.0",
"raw-body": "^2.2.0",
"socks-proxy-agent": "^4.0.1"
},
"dependencies": {
"agent-base": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
"integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
"requires": {
"es6-promisify": "^5.0.0"
}
},
"https-proxy-agent": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz",
"integrity": "sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==",
"requires": {
"agent-base": "^4.3.0",
"debug": "^3.1.0"
},
"dependencies": {
"debug": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"requires": {
"ms": "^2.1.1"
}
}
}
}
}
},
"pac-resolver": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-3.0.0.tgz",
"integrity": "sha512-tcc38bsjuE3XZ5+4vP96OfhOugrX+JcnpUbhfuc4LuXBLQhoTthOstZeoQJBDnQUDYzYmdImKsbz0xSl1/9qeA==",
"requires": {
"co": "^4.6.0",
"degenerator": "^1.0.4",
"ip": "^1.1.5",
"netmask": "^1.0.6",
"thunkify": "^2.1.2"
}
},
"path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
},
"path-proxy": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/path-proxy/-/path-proxy-1.0.0.tgz",
"integrity": "sha1-GOijaFn8nS8aU7SN7hOFQ8Ag3l4=",
"requires": {
"inflection": "~1.3.0"
},
"dependencies": {
"inflection": {
"version": "1.3.8",
"resolved": "https://registry.npmjs.org/inflection/-/inflection-1.3.8.tgz",
"integrity": "sha1-y9Fg2p91sUw8xjV41POWeEvzAU4="
}
}
},
"performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
@ -1147,11 +1510,24 @@
"resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz",
"integrity": "sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg=="
},
"prelude-ls": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
},
"process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
},
"promisify-call": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/promisify-call/-/promisify-call-2.0.4.tgz",
"integrity": "sha1-1IwtRWUszM1SgB3ey9UzptS9X7o=",
"requires": {
"with-callback": "^1.0.2"
}
},
"proxy-addr": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
@ -1161,6 +1537,68 @@
"ipaddr.js": "1.9.1"
}
},
"proxy-agent": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-3.1.1.tgz",
"integrity": "sha512-WudaR0eTsDx33O3EJE16PjBRZWcX8GqCEeERw1W3hZJgH/F2a46g7jty6UGty6NeJ4CKQy8ds2CJPMiyeqaTvw==",
"requires": {
"agent-base": "^4.2.0",
"debug": "4",
"http-proxy-agent": "^2.1.0",
"https-proxy-agent": "^3.0.0",
"lru-cache": "^5.1.1",
"pac-proxy-agent": "^3.0.1",
"proxy-from-env": "^1.0.0",
"socks-proxy-agent": "^4.0.1"
},
"dependencies": {
"agent-base": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
"integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
"requires": {
"es6-promisify": "^5.0.0"
}
},
"https-proxy-agent": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-3.0.1.tgz",
"integrity": "sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==",
"requires": {
"agent-base": "^4.3.0",
"debug": "^3.1.0"
},
"dependencies": {
"debug": {
"version": "3.2.7",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"requires": {
"ms": "^2.1.1"
}
}
}
},
"lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
"integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==",
"requires": {
"yallist": "^3.0.2"
}
},
"yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
}
}
},
"proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
},
"psl": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz",
@ -1188,6 +1626,17 @@
"resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz",
"integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="
},
"raw-body": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.1.tgz",
"integrity": "sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==",
"requires": {
"bytes": "3.1.0",
"http-errors": "1.7.3",
"iconv-lite": "0.4.24",
"unpipe": "1.0.0"
}
},
"rc": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
@ -1237,6 +1686,17 @@
"uuid": "^3.3.2"
},
"dependencies": {
"form-data": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
"optional": true,
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
}
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
@ -1357,11 +1817,49 @@
"resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.4.8.tgz",
"integrity": "sha512-edRH8mBKEWNVIVMKejNnuJxleqYE/ZSdcT8/Nem9/mmosx12pctd80s2Oy00KNZzrogMZS5mauK2/ymL1bvlvg=="
},
"setprototypeof": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
"integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
},
"signal-exit": {
"version": "3.0.5",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.5.tgz",
"integrity": "sha512-KWcOiKeQj6ZyXx7zq4YxSMgHRlod4czeBQZrPb8OKcohcqAXShm7E20kEMle9WBt26hFcAf0qLOcp5zmY7kOqQ=="
},
"smart-buffer": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg=="
},
"socks": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/socks/-/socks-2.3.3.tgz",
"integrity": "sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA==",
"requires": {
"ip": "1.1.5",
"smart-buffer": "^4.1.0"
}
},
"socks-proxy-agent": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz",
"integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==",
"requires": {
"agent-base": "~4.2.1",
"socks": "~2.3.2"
},
"dependencies": {
"agent-base": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz",
"integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==",
"requires": {
"es6-promisify": "^5.0.0"
}
}
}
},
"sonic-boom": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.4.1.tgz",
@ -1371,6 +1869,12 @@
"flatstr": "^1.0.12"
}
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"optional": true
},
"sqlite3": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/sqlite3/-/sqlite3-5.0.2.tgz",
@ -1398,6 +1902,11 @@
"tweetnacl": "~0.14.0"
}
},
"statuses": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
"integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
},
"stream-wormhole": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/stream-wormhole/-/stream-wormhole-1.1.0.tgz",
@ -1455,11 +1964,21 @@
"inherits": "2"
}
},
"thunkify": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/thunkify/-/thunkify-2.1.2.tgz",
"integrity": "sha1-+qDp0jDFGsyVyhOjYawFyn4EVT0="
},
"tiny-lru": {
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-7.0.6.tgz",
"integrity": "sha512-zNYO0Kvgn5rXzWpL0y3RS09sMK67eGaQj9805jlK9G6pSadfriTczzLHFXa/xcW4mIRfmlB9HyQ/+SgL0V1uow=="
},
"toidentifier": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
},
"toposort-class": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz",
@ -1480,6 +1999,16 @@
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
},
"tslib": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz",
"integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
},
"tsscmp": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz",
"integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA=="
},
"tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
@ -1495,6 +2024,19 @@
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
"optional": true
},
"type-check": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
"integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
"requires": {
"prelude-ls": "~1.1.2"
}
},
"unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
},
"uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@ -1568,6 +2110,11 @@
"string-width": "^1.0.2 || 2"
}
},
"with-callback": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/with-callback/-/with-callback-1.0.2.tgz",
"integrity": "sha1-oJYpuakgAo1yFAT7Q1vc/1yRvCE="
},
"wkx": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz",
@ -1576,11 +2123,21 @@
"@types/node": "*"
}
},
"word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"xregexp": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz",
"integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM="
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",

1
package.json

@ -14,6 +14,7 @@
"fastify": "^3.22.0",
"fastify-formbody": "^5.1.0",
"fastify-multipart": "^5.0.2",
"mailgun-js": "^0.22.0",
"sequelize": "^6.7.0",
"sqlite3": "^5.0.2"
}

0
src/config/database.js → src/config/database.config.js

11
src/config/email.config.js

@ -0,0 +1,11 @@
export const MailgunAccount = {
apiKey: '0f5cb2ebb348c88c708f1b9f7e20c385-e5da0167-1b06a230',
publicApiKey: 'pubkey-933b975a7865e74f365bbd6e0bce889d',
host: 'api.eu.mailgun.net',
domain: '7winds.nikky.dev'
};
export const EmailConfig = {
from: "Jun Kuroshio <noreply@7winds.nikky.dev>"
}

4
src/index.js

@ -2,7 +2,7 @@ import Fastify from 'fastify'
import formBodyPlugin from 'fastify-formbody';
import fastifyMultipart from 'fastify-multipart';
import Sequelize from 'sequelize';
import { DatabaseConfig } from './config/database.js';
import { DatabaseConfig } from './config/database.config.js';
import UserEntity from './model/user.model.js';
import AuthController from './route/auth.controller.js';
import UserController from './route/user.controller.js';
@ -36,7 +36,7 @@ async function WebApp(){
(async () => {
//initialize
const step = async (func, name) => {
let start = Date.now();
const start = Date.now();
const msg = await func();
console.log(`[${name}] (${(Date.now() - start)} ms) ${msg || ''}`);
};

30
src/logic/email.js

@ -0,0 +1,30 @@
import { EmailConfig, MailgunAccount } from "../config/email.config.js";
import Mailgun from "mailgun-js";
import { RestorePasswordEmail } from "../misc/email-templates.js";
const mailgun = Mailgun(MailgunAccount);
function sendMail(opts){
return new Promise((resolve, reject) => {
try{
mailgun.messages().send(opts, (error, body) => {
resolve(!error);
});
}catch(error){
reject(error);
}
});
}
export async function sendRestorationLink(user, app){
const template = RestorePasswordEmail({
username: user.username,
url: app.hostname+'/'+user.restoreCode
});
return await sendMail({
from: EmailConfig.from,
to: user.email,
subject: template.subject,
text: template.text
});
}

20
src/logic/security.js

@ -22,24 +22,34 @@ export function doesPasswordMatch(paswd, hash){
return bcrypt.compareSync(paswd, hash);
}
//-- password restore --
const hours = 60*60*1000;
export const restoreValidity = 12 * hours;
export const restoreAttempts = 8;
export function generateRestoreCode(){
return crypto.randomBytes(16).toString('hex');
}
//-- access tokens --
const days = 24*60*60*1000;
export const tokenLifetime = 90 * days;
export const tokenReissue = 60 * days;
export async function reissueToken(user, Users){
export async function reissueToken(user){
const token = generateToken();
const tokenExpiry = newTokenExpiry();
await Users.update({token, tokenExpiry}, {where: {id: user.id}});
await user.update({token, tokenExpiry});
return token;
}
export function generateToken(){
return (
crypto.randomBytes(16).toString('hex')
+ ((++tokenTempCounter).toString(16))+'g'
+ (Date.now().toString(16))
crypto.randomBytes(14).toString('hex')
+ ((++tokenTempCounter).toString(16).slice(-4))+'g'
+ (Date.now().toString(16).slice(-5))
);
}
let tokenTempCounter = 0;

13
src/logic/common.js → src/logic/utils.js

@ -19,3 +19,16 @@ export function reverseString(str){
export function randomElement(arr){
return arr[Math.floor(Math.random()*arr.length)];
}
export function notYet(date){
if(!date) return false;
return (new Date() <= date);
}
// export class CacheTable{
// constructor(){
// this.data = {};
// }
// }

11
src/misc/email-templates.js

@ -0,0 +1,11 @@
export const RestorePasswordEmail = ({username, url}) => ({
subject: `Account recovery`,
text: `
Hello, ${username}.
We received a request to reset your password.
Follow the link below to proceed:
${url}
If you didn't request this change, ignore this email.
`
});

6
src/model/user.model.js

@ -11,10 +11,10 @@ const UserEntity = ({db}) => (
role: Sequelize.TEXT,
firstIp: Sequelize.TEXT,
bannedUntil: Sequelize.DATE,
banReason: Sequelize.TEXT
banReason: Sequelize.TEXT,
// emailed_last: { type: Sequelize.DATE, defaultValue: null },
// visited_times: { type: Sequelize.INTEGER, defaultValue: 0 }
restoreCode: Sequelize.TEXT,
restoreExpiry: Sequelize.DATE
})
);

71
src/route/auth.controller.js

@ -1,6 +1,7 @@
import { checkStringParam, errorOut, randomElement, reverseString } from '../logic/common.js';
import { checkStringParam, errorOut, notYet, randomElement, reverseString } from '../logic/utils.js';
import { Animals } from '../misc/animals.js';
import { reissueToken, generateToken, newTokenExpiry, hashPassword, doesPasswordMatch } from '../logic/security.js';
import { reissueToken, generateToken, newTokenExpiry, hashPassword, doesPasswordMatch, isEndpointAllowedForBannedUsers, isEndpointProtected, generateRestoreCode, restoreValidity, restoreAttempts } from '../logic/security.js';
import { sendRestorationLink } from '../logic/email.js';
/**
* @param {Object} props
@ -14,16 +15,14 @@ function AuthController({app, db}){
{ //validate token header and put .user in every request
app.decorateRequest('user', null);
app.addHook('preHandler', async (request, reply) => {
const unprotectedUrl = (request.url.substring(0, 6) == '/auth/') || (request.url === '/');
if(!unprotectedUrl){
if(isEndpointProtected(request.url)){
const token = request.headers.authorization;
//todo: local cache
const user = await Users.findOne({where: {token}});
const tokenNotExpired = user && (new Date() <= user.tokenExpiry);
const userNotBanned = true;
if(tokenNotExpired && userNotBanned){
const tokenNotExpired = notYet(user?.tokenExpiry);
const userNotBanned = (!notYet(user?.bannedUntil)) || isEndpointAllowedForBannedUsers(request.url);
if(user && tokenNotExpired && userNotBanned){
request.user = user;
}else{
errorOut(reply, 'Unauthorized', 401);
@ -38,8 +37,8 @@ function AuthController({app, db}){
//todo: spam check
{ //form validation
if(!isValidEmail(email)) return errorOut(reply, 'auth.bad_email');
if(!isValidPassword(paswd)) return errorOut(reply, 'auth.bad_paswd');
if(!isValidEmail(email)) return errorOut(reply, 'auth.bad_email');
if(!isValidPassword(paswd)) return errorOut(reply, 'auth.bad_paswd');
}
const fixedEmail = fixEmail(email);
const user = await Users.findOne({where: {email: fixedEmail}});
@ -47,7 +46,7 @@ function AuthController({app, db}){
if(user && doesPasswordMatch(reverseString(paswd), user.paswd)){
let token = user.token;
if(new Date() > user.tokenExpiry){
token = await reissueToken(user, Users);
token = await reissueToken(user);
}
return {token};
}else{
@ -93,6 +92,54 @@ function AuthController({app, db}){
return {token: newUser.token};
});
app.post('/auth/restore/request', async (request, reply) => {
const {email} = request.body || {};
if(!isValidEmail(email)) return errorOut(reply, 'auth.bad_email');
const fixedEmail = fixEmail(email);
const user = await Users.findOne({where: {email: fixedEmail}});
if(!user) return errorOut(reply, 'restore.not_found');
if(user.restoreExpiry && notYet(user.restoreExpiry)){
return errorOut(reply, 'restore.already_sent');
}
const restoreCode = generateRestoreCode();
const restoreExpiry = new Date(Date.now() + restoreValidity);
await user.update({restoreCode, restoreExpiry});
const success = await sendRestorationLink(user, app);
return {success, lifetime: restoreValidity};
});
app.post('/auth/restore/apply', async (request, reply) => {
const {email, code, newpaswd} = request.body || {};
const changeRequested = (newpaswd != null);
if(!isValidEmail(email)) return errorOut(reply, 'auth.bad_email');
if(changeRequested && (!isValidPassword(newpaswd))){
return errorOut(reply, 'auth.bad_paswd');
}
const fixedEmail = fixEmail(email);
const user = await Users.findOne({where: {email: fixedEmail}});
if(!user) return errorOut(reply, 'restore.not_found');
if((!notYet(user.restoreExpiry)) || (!user.restoreCode)){
return errorOut(reply, 'restore.expired');
}
if(user.restoreCode != code){
const restoreExpiry = user.restoreExpiry - (restoreValidity / restoreAttempts);
await user.update({restoreExpiry});
return errorOut(reply, 'restore.wrong_code');
}
if(changeRequested){
const hash = hashPassword(reverseString(newpaswd));
await user.update({paswd: hash, restoreCode: null, restoreExpiry: null});
}
return '👌';
});
}
function fixEmail(email){
@ -107,7 +154,7 @@ function fixUsername(username){
return username.replace(profanities, '💩').replace(badSymbols, '');
}else{
const nick = randomElement(Animals);
const tag = Date.now().toString(10).slice(-4);
const tag = Date.now().toString().slice(-4);
return `Little ${nick} #${tag}`;
}
}

2
src/route/user.controller.js

@ -12,7 +12,7 @@ function UserController({app, db}){
app.get('/users/me', async (request, reply) => {
const {user} = request;
const needsReissue = ((user.tokenExpiry - new Date()) < (tokenLifetime - tokenReissue));
let newToken = needsReissue ? await reissueToken(user, Users) : null;
let newToken = needsReissue ? await reissueToken(user) : null;
return {
username: user.username,

Loading…
Cancel
Save