diff --git a/.gitignore b/.gitignore index 58a8933..2cbc69b 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ keys/ logs/ *.sqlite yarn-error\.log -config.ini \ No newline at end of file +config.ini +.env \ No newline at end of file diff --git a/example.config.ini b/example.config.ini index fe4ef8f..574cd4b 100644 --- a/example.config.ini +++ b/example.config.ini @@ -1,3 +1,7 @@ +[database] +host=localhost +database=openauth + [core] name = OpenAuthService diff --git a/package-lock.json b/package-lock.json index 62dd291..74e128d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -164,20 +164,12 @@ } }, "@types/dotenv": { - "version": "4.0.3", - "resolved": "http://registry.npmjs.org/@types/dotenv/-/dotenv-4.0.3.tgz", - "integrity": "sha512-mmhpINC/HcLGQK5ikFJlLXINVvcxhlrV+ZOUJSN7/ottYl+8X4oSXzS9lBtDkmWAl96EGyGyLrNvk9zqdSH8Fw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@types/dotenv/-/dotenv-6.1.0.tgz", + "integrity": "sha512-gmbNb7V1LbJQA4MmH0hVFgqY1cyKsa6RvKC1Xrq0WBnZ0JuuvXKciXx/s8dN0LVXCJd8xO6wIaSFSyUIoGph9g==", "dev": true, "requires": { "@types/node": "*" - }, - "dependencies": { - "@types/node": { - "version": "10.1.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.1.4.tgz", - "integrity": "sha512-GpQxofkdlHYxjHad98UUdNoMO7JrmzQZoAaghtNg14Gwg7YkohcrCoJEcEMSgllx4VIZ+mYw7ZHjfaeIagP/rg==", - "dev": true - } } }, "@types/events": { @@ -252,9 +244,9 @@ } }, "@types/node": { - "version": "10.12.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.2.tgz", - "integrity": "sha512-53ElVDSnZeFUUFIYzI8WLQ25IhWzb6vbddNp8UHlXQyU0ET2RhV5zg0NfubzU7iNMh5bBXb0htCzfvrSVNgzaQ==", + "version": "10.12.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.5.tgz", + "integrity": "sha512-GzdHjq3t3eGLMv92Al90Iq+EoLL+86mPfQhuglbBFO7HiLdC/rkt+zrzJJumAiBF6nsrBWhou22rPW663AAyFw==", "dev": true }, "@types/node-rsa": { @@ -452,15 +444,6 @@ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", "dev": true }, - "babel-runtime": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", - "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", - "requires": { - "core-js": "^2.4.0", - "regenerator-runtime": "^0.11.0" - } - }, "backo2": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", @@ -539,26 +522,12 @@ "callsite": "1.0.0" } }, - "big-number": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/big-number/-/big-number-0.3.1.tgz", - "integrity": "sha1-rHMCDApZu3nrF8LOLbd/d9l04BM=" - }, "binary-extensions": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.12.0.tgz", "integrity": "sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==", "dev": true }, - "bl": { - "version": "1.2.2", - "resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz", - "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", - "requires": { - "readable-stream": "^2.3.5", - "safe-buffer": "^5.1.1" - } - }, "blob": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", @@ -946,15 +915,11 @@ "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", "dev": true }, - "core-js": { - "version": "2.5.7", - "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", - "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==" - }, "core-util-is": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true }, "cors": { "version": "2.8.5", @@ -2540,7 +2505,8 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true }, "isexe": { "version": "2.0.0", @@ -2971,11 +2937,6 @@ "to-regex": "^3.0.1" } }, - "native-duplexpair": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/native-duplexpair/-/native-duplexpair-1.0.0.tgz", - "integrity": "sha1-eJkHjmS/PIo9cyYBs9QP8F21j6A=" - }, "negotiator": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", @@ -3337,7 +3298,8 @@ "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true }, "proxy-addr": { "version": "2.0.4", @@ -3372,11 +3334,6 @@ "ps-tree": "^1.1.0" } }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" - }, "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", @@ -3425,6 +3382,7 @@ "version": "2.3.6", "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, "requires": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -3451,11 +3409,6 @@ "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.12.tgz", "integrity": "sha512-n+IyV+nGz3+0q3/Yf1ra12KpCyi001bi4XFxSjbiWWjfqb52iTTtpGXmCCAOWWIAn9KEuFZKGqBERHmrtScZ3A==" }, - "regenerator-runtime": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", - "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" - }, "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", @@ -4026,6 +3979,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, "requires": { "safe-buffer": "~5.1.0" } @@ -4069,32 +4023,6 @@ "csextends": "^1.0.3" } }, - "tedious": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/tedious/-/tedious-2.6.4.tgz", - "integrity": "sha512-upFZB4QahZydPIV2VK3H/bz8Fsq5FSjqbxDbhhp1c/66ZJB1qCk5p1cXi2p/VUOgAYbmAzVObTg5kaVvmeyN+Q==", - "requires": { - "babel-runtime": "^6.26.0", - "big-number": "0.3.1", - "bl": "^1.2.2", - "depd": "^1.1.2", - "iconv-lite": "^0.4.23", - "native-duplexpair": "^1.0.0", - "punycode": "^2.1.0", - "readable-stream": "^2.3.6", - "sprintf-js": "^1.1.1" - }, - "dependencies": { - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - } - } - }, "term-size": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", @@ -4399,7 +4327,8 @@ "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true }, "utils-merge": { "version": "1.0.1", diff --git a/package.json b/package.json index b45592c..2601da2 100644 --- a/package.json +++ b/package.json @@ -16,14 +16,14 @@ "@types/body-parser": "^1.17.0", "@types/compression": "^0.0.36", "@types/cookie-parser": "^1.4.1", - "@types/dotenv": "^4.0.3", + "@types/dotenv": "^6.1.0", "@types/express": "^4.16.0", "@types/handlebars": "^4.0.39", "@types/i18n": "^0.8.3", "@types/ini": "^1.3.29", "@types/jsonwebtoken": "^8.3.0", "@types/mongodb": "^3.1.14", - "@types/node": "^10.12.2", + "@types/node": "^10.12.5", "@types/node-rsa": "^0.4.3", "@types/uuid": "^3.4.4", "concurrently": "^4.0.1", @@ -48,7 +48,6 @@ "mongodb": "^3.1.9", "node-rsa": "^1.0.1", "reflect-metadata": "^0.1.12", - "tedious": "^2.6.4", "uuid": "^3.3.2" } } diff --git a/src/api/middlewares/user.ts b/src/api/middlewares/user.ts index 06d6d0b..eec0d9c 100644 --- a/src/api/middlewares/user.ts +++ b/src/api/middlewares/user.ts @@ -21,11 +21,11 @@ export function GetUserMiddleware(json = false, special_token: boolean = false, } try { let { login, special } = req.cookies - if (!login) invalid() let token = await LoginToken.findOne({ token: login, valid: true }) if (!token) invalid() + if (!token.validated) invalid(); let user = await User.findById(token.user); if (!user) { @@ -43,7 +43,7 @@ export function GetUserMiddleware(json = false, special_token: boolean = false, if (special) { Logging.debug("Special found") let st = await LoginToken.findOne({ token: special, special: true, valid: true }) - if (st && st.valid && st.user.toHexString() === token.user.toHexString()) { + if (st && st.validated && st.valid && st.user.toHexString() === token.user.toHexString()) { if (st.validTill.getTime() < new Date().getTime()) { //Token expired Logging.debug("Special expired") st.valid = false; diff --git a/src/api/user/login.ts b/src/api/user/login.ts index b17a082..2435ab8 100644 --- a/src/api/user/login.ts +++ b/src/api/user/login.ts @@ -1,5 +1,5 @@ import { Request, Response } from "express" -import User, { IUser } from "../../models/user"; +import User, { IUser, TokenTypes } from "../../models/user"; import { randomBytes } from "crypto"; import moment = require("moment"); import LoginToken from "../../models/login_token"; @@ -19,14 +19,16 @@ const Login = promiseMiddleware(async (req: Request, res: Response) => { return; } - const sendToken = async (user: IUser) => { + const sendToken = async (user: IUser, tfa?: TokenTypes[]) => { let token_str = randomBytes(16).toString("hex"); + let tfa_exp = moment().add(5, "minutes").toDate() let token_exp = moment().add(6, "months").toDate() let token = LoginToken.new({ token: token_str, valid: true, - validTill: token_exp, - user: user._id + validTill: tfa ? tfa_exp : token_exp, + user: user._id, + validated: tfa ? false : true }); await LoginToken.save(token); @@ -35,15 +37,17 @@ const Login = promiseMiddleware(async (req: Request, res: Response) => { let special = LoginToken.new({ token: special_str, valid: true, - validTill: special_exp, + validTill: tfa ? tfa_exp : special_exp, special: true, - user: user._id + user: user._id, + validated: tfa ? false : true }); await LoginToken.save(special); res.json({ - login: { token: token_str, expires: token_exp.toUTCString() }, - special: { token: special_str, expires: special_exp.toUTCString() } + login: { token: token_str, expires: token.validTill.toUTCString() }, + special: { token: special_str, expires: special.validTill.toUTCString() }, + tfa }); } @@ -61,12 +65,8 @@ const Login = promiseMiddleware(async (req: Request, res: Response) => { } else { if (user.twofactor && user.twofactor.length > 0) { - let types = user.twofactor.map(f => { - return { type: f.type }; - }) - res.json({ - types: types - }); + let types = user.twofactor.filter(f => f.valid).map(f => f.type) + await sendToken(user, types); } else { await sendToken(user); } diff --git a/src/config.ts b/src/config.ts index 3ede2fc..73fc109 100644 --- a/src/config.ts +++ b/src/config.ts @@ -1,11 +1,6 @@ export interface DatabaseConfig { host: string database: string - dialect: "sqlite" | "mysql" | "postgres" | "mssql" - username: string - password: string - storage: string - benchmark: "true" | "false" | undefined } export interface WebConfig { @@ -37,7 +32,7 @@ import { Logging } from "@hibas123/nodelogging"; dotenv.config(); const config: Config = ini.parse(readFileSync("./config.ini").toString()) - +if (config.dev) config.dev = Boolean(config.dev); if (process.env.DEV === "true") { config.dev = true; Logging.warning("DEV mode active. This can cause major performance issues, data loss and vulnerabilities! ") diff --git a/src/database.ts b/src/database.ts index 06d3aac..cca9f4e 100644 --- a/src/database.ts +++ b/src/database.ts @@ -1,3 +1,11 @@ import SafeMongo from "@hibas123/safe_mongo"; -const DB = new SafeMongo("mongodb://localhost", "openauth"); +import Config from "./config" +let dbname = "openauth" +let host = "localhost" +if (Config.database) { + if (Config.database.database) dbname = Config.database.database; + if (Config.database.host) host = Config.database.host; +} +if (Config.dev) dbname += "_dev"; +const DB = new SafeMongo("mongodb://" + host, dbname); export default DB; \ No newline at end of file diff --git a/src/models/login_token.ts b/src/models/login_token.ts index 7914e3e..375710d 100644 --- a/src/models/login_token.ts +++ b/src/models/login_token.ts @@ -8,6 +8,7 @@ export interface ILoginToken extends ModelDataBase { user: ObjectID; validTill: Date; valid: boolean; + validated: boolean; } const LoginToken = DB.addModel({ name: "login_token", @@ -20,6 +21,16 @@ const LoginToken = DB.addModel({ validTill: { type: Date }, valid: { type: Boolean } } + }, { + migration: (doc: ILoginToken) => { doc.validated = true; }, + schema: { + token: { type: String }, + special: { type: Boolean, default: () => false }, + user: { type: ObjectID }, + validTill: { type: Date }, + valid: { type: Boolean }, + validated: { type: Boolean, default: false } + } }] }) diff --git a/src/web.ts b/src/web.ts index fba402f..9bd5d47 100644 --- a/src/web.ts +++ b/src/web.ts @@ -9,7 +9,6 @@ import * as cookieparser from "cookie-parser" import * as i18n from "i18n" import * as compression from "compression"; -import { BADHINTS } from "dns"; import ApiRouter from "./api/api"; import ViewRouter from "./views/views"; import RequestError, { HttpStatusCode } from "./helper/request_error"; diff --git a/views/src/login/login.js b/views/src/login/login.js index c5f6642..2acf823 100644 --- a/views/src/login/login.js +++ b/views/src/login/login.js @@ -75,10 +75,7 @@ loginbutton.onclick = async () => { loading(); let pw = sha(salt + passwordinput.value); try { - let { - login, - special - } = await fetch("/api/user/login?type=password", { + let { login, special, tfa } = await fetch("/api/user/login?type=password", { method: "POST", body: JSON.stringify({ username: usernameinput.value,