From 732201ddf33352cfbdb2a526ec8d2b4f40520d7e Mon Sep 17 00:00:00 2001 From: SuperSonic Date: Wed, 15 Mar 2023 11:44:23 +0000 Subject: [PATCH] fix: bugs --- .devcontainer/devcontainer.json | 6 +++--- .env.sample | 17 +++++++++++++++-- src/controllers/login.js | 8 +++++--- src/controllers/profile.js | 4 +++- src/controllers/register.js | 18 ++++++++++-------- src/init/const.js | 16 ++++++++++++++++ src/utils/mail_sender.js | 16 ++++++++-------- src/utils/sara_token.js | 22 ++++++++++++---------- src/utils/testing.js | 4 +++- 9 files changed, 75 insertions(+), 36 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 3daf187..c46398a 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -18,13 +18,13 @@ "mongodb.mongodb-vscode" ] } - } + }, // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [3000, 27017], + "forwardPorts": [3000, 3500], // Use 'postCreateCommand' to run commands after the container is created. - // "postCreateCommand": "yarn install", + "postCreateCommand": "npm install" // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. // "remoteUser": "root" diff --git a/.env.sample b/.env.sample index e76945c..40f9a25 100644 --- a/.env.sample +++ b/.env.sample @@ -25,6 +25,19 @@ ENABLED_CORS="no" # cors ('yes' or 'no'), CORS_ORIGIN is required ENABLED_CORS_ORIGIN_CHECK="no" # is the API public to every client ('yes' or 'no') CORS_ORIGIN="https://example.org" +## mail sender +MAIL_SMTP_HOST="smtp.example.org" +MAIL_SMTP_PORT="25" +MAIL_SMTP_SECURE="no" +MAIL_SMTP_USERNAME="empty_to_disable_auth" +MAIL_SMTP_PASSWORD="your_smtp_password" +MAIL_SMTP_FROM='"sara.recv" ' + # sara configs -SARA_ISSUER="9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" -SARA_AUDIENCE="https://example.org" +SARA_AUDIENCE_URL="https://example.org" +SARA_CLIENT_LOGIN_URL="https://example.org/login" +SARA_CLIENT_REGISTER_URL="https://example.org/register" +SARA_API_TOKEN_VERIFY_URL="https://example.org/api/token/verify" +SARA_API_TOKEN_DECODE_URL="https://example.org/api/token/decode" +SARA_SYSTEM_ADMIN_SECRET="your_system_admin_secret" +SARA_SYSTEM_ADMIN_IP_ADDRESS="127.0.0.1" diff --git a/src/controllers/login.js b/src/controllers/login.js index 8458297..1620580 100644 --- a/src/controllers/login.js +++ b/src/controllers/login.js @@ -1,6 +1,6 @@ "use strict"; -const {isProduction} = require("../config"); +const {isProduction, getMust} = require("../config"); const {StatusCodes} = require("http-status-codes"); const {useApp, express} = require("../init/express"); @@ -24,10 +24,12 @@ const middlewareValidator = require("express-validator"); const {Router: newRouter} = express; const router = newRouter(); +router.use(express.urlencoded({extended: true})); + const database = useDatabase(); router.post("/", - middlewareValidator.body("email").isEmail().notEmpty(), + middlewareValidator.body("email").isEmail(), middlewareInspector, (req, res, next) => { if (!utilBFAP.inspect( @@ -48,7 +50,7 @@ router.post("/", const {token, code} = utilSaraToken.issueCodeToken(6, metadata); const data = { to: req.body.email, - website: process.env.WEBSITE_URL, + website: getMust("SARA_AUDIENCE_URL"), ip_address: utilVisitor.getIPAddress(req), code, }; diff --git a/src/controllers/profile.js b/src/controllers/profile.js index 0fe85a9..9b16285 100644 --- a/src/controllers/profile.js +++ b/src/controllers/profile.js @@ -1,5 +1,7 @@ "use strict"; +const {getMust} = require("../config"); + const {StatusCodes} = require("http-status-codes"); const {useApp, express} = require("../init/express"); @@ -67,7 +69,7 @@ router.put("/email", ); const data = { to: req.body.email, - website: process.env.WEBSITE_URL, + website: getMust("SARA_AUDIENCE_URL"), ip_address: utilVisitor.getIPAddress(req), code, }; diff --git a/src/controllers/register.js b/src/controllers/register.js index 69fa156..3bc1ea6 100644 --- a/src/controllers/register.js +++ b/src/controllers/register.js @@ -5,7 +5,7 @@ const {useApp, express} = require("../init/express"); const {useDatabase} = require("../init/database"); -const {isProduction} = require("../config"); +const {getMust, isProduction} = require("../config"); // Import modules const constant = require("../init/const"); @@ -26,17 +26,19 @@ const {getPosixTimestamp} = require("../utils/native"); const {Router: newRouter} = express; const router = newRouter(); +router.use(express.urlencoded({extended: true})); + const database = useDatabase(); router.post("/", - middlewareValidator.body("nickname").isString().notEmpty(), - middlewareValidator.body("email").isEmail().notEmpty(), + middlewareValidator.body("nickname").notEmpty(), + middlewareValidator.body("email").isEmail(), middlewareInspector, (req, res, next) => { if (!utilBFAP.inspect( constant.BFAP_CONFIG_IP_REGISTER, utilVisitor.getIPAddress(req), - )) next(); + )) return next(); res.sendStatus(StatusCodes.FORBIDDEN); console.error("brute_force"); return; @@ -53,7 +55,7 @@ router.post("/", ); const data = { to: req.body.email, - website: process.env.WEBSITE_URL, + website: getMust("SARA_AUDIENCE_URL"), ip_address: utilVisitor.getIPAddress(req), code, }; @@ -72,9 +74,9 @@ router.post("/", ); router.post("/verify", - middlewareValidator.body("code").isNumeric().notEmpty(), - middlewareValidator.body("code").isLength({min: 7, max: 7}).notEmpty(), - middlewareValidator.body("register_token").isString().notEmpty(), + middlewareValidator.body("code").isNumeric(), + middlewareValidator.body("code").isLength({min: 7, max: 7}), + middlewareValidator.body("register_token").notEmpty(), middlewareInspector, async (req, res) => { const tokenData = utilSaraToken.validateCodeToken( diff --git a/src/init/const.js b/src/init/const.js index 13f7db6..232827b 100644 --- a/src/init/const.js +++ b/src/init/const.js @@ -3,3 +3,19 @@ exports.APP_NAME = "sara.recv"; exports.SECRET_FILENAME = "secret.key"; + +exports.BFAP_CONFIG_CODE_TOKEN = { + type: "code_token", + maxRetry: 10, + ttl: 86_400, +}; +exports.BFAP_CONFIG_IP_LOGIN = { + type: "ip_login", + maxRetry: 10, + ttl: 3_600, +}; +exports.BFAP_CONFIG_IP_REGISTER = { + type: "ip_register", + maxRetry: 20, + ttl: 3_600, +}; diff --git a/src/utils/mail_sender.js b/src/utils/mail_sender.js index 6dfd441..e6d25eb 100644 --- a/src/utils/mail_sender.js +++ b/src/utils/mail_sender.js @@ -2,16 +2,16 @@ // Mail Sender of Sara const nodemailer = require("nodemailer"); -const {isProduction} = require("../config"); +const {isProduction, getMust, getEnabled} = require("../config"); const testing = require("./testing"); const transporter = nodemailer.createTransport({ - host: process.env.MAIL_SMTP_HOST, - port: process.env.MAIL_SMTP_PORT, - secure: process.env.MAIL_SMTP_SECURE === "yes", - auth: process.env.MAIL_SMTP_USERNAME ? { - user: process.env.MAIL_SMTP_USERNAME, - pass: process.env.MAIL_SMTP_PASSWORD, + host: getMust("MAIL_SMTP_HOST"), + port: getMust("MAIL_SMTP_PORT"), + secure: getEnabled("MAIL_SMTP_SECURE"), + auth: getMust("MAIL_SMTP_USERNAME") ? { + user: getMust("MAIL_SMTP_USERNAME"), + pass: getMust("MAIL_SMTP_PASSWORD"), } : null, }); @@ -25,7 +25,7 @@ module.exports = function(template, data) { const {subject, text, html} = require(`../templates/mail/${template}.js`); return transporter.sendMail({ - from: process.env.MAIL_SMTP_FROM, + from: getMust("MAIL_SMTP_FROM"), to: data.to, subject: subject(data), text: text(data), diff --git a/src/utils/sara_token.js b/src/utils/sara_token.js index 35b5ca9..7739623 100644 --- a/src/utils/sara_token.js +++ b/src/utils/sara_token.js @@ -19,6 +19,8 @@ const {inspect: bfapInspact} = require("../utils/bfap"); // Import constant const constant = require("../init/const"); +const {getMust} = require("../config"); + const {useJwtSecret} = require("../init/jwt_secret"); const {useCache} = require("../init/cache"); @@ -34,7 +36,7 @@ const generalIssueOptions = ({type}) => ({ algorithm: "HS256", expiresIn: "1d", notBefore: "500ms", - audience: process.env.WEBSITE_URL, + audience: getMust("SARA_AUDIENCE_URL"), issuer: sha256(jwtSecret), noTimestamp: false, mutatePayload: false, @@ -44,13 +46,13 @@ const generalIssueOptions = ({type}) => ({ type: type, point: { client: { - login: process.env.SARA_CLIENT_LOGIN_URL, - register: process.env.SARA_CLIENT_REGISTER_URL, + login: getMust("SARA_CLIENT_LOGIN_URL"), + register: getMust("SARA_CLIENT_REGISTER_URL"), }, api: { token: { - verify: process.env.SARA_API_TOKEN_VERIFY_URL, - decode: process.env.SARA_API_TOKEN_DECODE_URL, + verify: getMust("SARA_API_TOKEN_VERIFY_URL"), + decode: getMust("SARA_API_TOKEN_DECODE_URL"), }, }, }, @@ -61,7 +63,7 @@ const generalIssueOptions = ({type}) => ({ // Define generalValidateOptions generator const generalValidateOptions = () => ({ algorithms: ["HS256"], - audience: process.env.WEBSITE_URL, + audience: getMust("SARA_AUDIENCE_URL"), issuer: sha256(jwtSecret), complete: true, }); @@ -101,7 +103,7 @@ function issueCodeToken(codeLength, data) { 10 ** (codeLength - 1), (10 ** codeLength) - 1, ).toString(); - const jwtSecret = `${jwtSecret}_${code}`; + const codeSecret = `${jwtSecret}_${code}`; const issueOptions = generalIssueOptions({type: "code"}); const payload = { data, @@ -110,7 +112,7 @@ function issueCodeToken(codeLength, data) { }; const token = jwt.sign( payload, - jwtSecret, + codeSecret, issueOptions, null, ); @@ -155,9 +157,9 @@ function validateCodeToken(code, token) { return false; } try { - const jwtSecret = `${jwtSecret}_${code}`; + const codeSecret = `${jwtSecret}_${code}`; const validateOptions = generalValidateOptions(); - const data = jwt.verify(token, jwtSecret, validateOptions, null); + const data = jwt.verify(token, codeSecret, validateOptions, null); if ( data?.header?.sara?.version !== 1 || data?.header?.sara?.type !== "code" diff --git a/src/utils/testing.js b/src/utils/testing.js index 3cdff59..3b1d48c 100644 --- a/src/utils/testing.js +++ b/src/utils/testing.js @@ -1,11 +1,13 @@ "use strict"; +const {isProduction} = require("../config"); + /** * Print message with testing notification. * @param {any} messages */ function log(...messages) { - if (process.env.NODE_ENV !== "development") return; + if (isProduction()) return; console.info("[!] Test mode:", ...messages); }