default values for env and critic check for values
This commit is contained in:
parent
b3d1c2d729
commit
d889f92643
8 changed files with 92 additions and 27 deletions
|
@ -1,5 +1,6 @@
|
||||||
import { dataSource } from "../data-source";
|
import { dataSource } from "../data-source";
|
||||||
import { refresh } from "../entity/refresh";
|
import { refresh } from "../entity/refresh";
|
||||||
|
import { REFRESH_EXPIRATION } from "../env.defaults";
|
||||||
import InternalException from "../exceptions/internalException";
|
import InternalException from "../exceptions/internalException";
|
||||||
import { JWTHelper } from "../helpers/jwtHelper";
|
import { JWTHelper } from "../helpers/jwtHelper";
|
||||||
import { StringHelper } from "../helpers/stringHelper";
|
import { StringHelper } from "../helpers/stringHelper";
|
||||||
|
@ -28,7 +29,7 @@ export default abstract class RefreshCommandHandler {
|
||||||
.values({
|
.values({
|
||||||
token: refreshToken,
|
token: refreshToken,
|
||||||
user: await UserService.getById(createRefresh.userId),
|
user: await UserService.getById(createRefresh.userId),
|
||||||
expiry: new Date(Date.now() + ms(process.env.REFRESH_EXPIRATION)),
|
expiry: new Date(Date.now() + ms(REFRESH_EXPIRATION)),
|
||||||
})
|
})
|
||||||
.execute()
|
.execute()
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
|
|
|
@ -15,6 +15,7 @@ import MailHelper from "../helpers/mailHelper";
|
||||||
import InviteService from "../service/inviteService";
|
import InviteService from "../service/inviteService";
|
||||||
import UserService from "../service/userService";
|
import UserService from "../service/userService";
|
||||||
import CustomRequestException from "../exceptions/customRequestException";
|
import CustomRequestException from "../exceptions/customRequestException";
|
||||||
|
import { CLUB_NAME } from "../env.defaults";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description start first user
|
* @description start first user
|
||||||
|
@ -43,7 +44,7 @@ export async function inviteUser(req: Request, res: Response): Promise<any> {
|
||||||
throw new CustomRequestException(409, "Username and Mail are already in use");
|
throw new CustomRequestException(409, "Username and Mail are already in use");
|
||||||
}
|
}
|
||||||
|
|
||||||
var secret = speakeasy.generateSecret({ length: 20, name: `Mitgliederverwaltung ${process.env.CLUB_NAME}` });
|
var secret = speakeasy.generateSecret({ length: 20, name: `Mitgliederverwaltung ${CLUB_NAME}` });
|
||||||
|
|
||||||
let createInvite: CreateInviteCommand = {
|
let createInvite: CreateInviteCommand = {
|
||||||
username: username,
|
username: username,
|
||||||
|
@ -58,7 +59,7 @@ export async function inviteUser(req: Request, res: Response): Promise<any> {
|
||||||
let mailhelper = new MailHelper();
|
let mailhelper = new MailHelper();
|
||||||
await mailhelper.sendMail(
|
await mailhelper.sendMail(
|
||||||
mail,
|
mail,
|
||||||
`Email Bestätigung für Mitglieder Admin-Portal von ${process.env.CLUB_NAME}`,
|
`Email Bestätigung für Mitglieder Admin-Portal von ${CLUB_NAME}`,
|
||||||
`Öffne folgenden Link: ${origin}/setup/verify?mail=${mail}&token=${token}`
|
`Öffne folgenden Link: ${origin}/setup/verify?mail=${mail}&token=${token}`
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -77,11 +78,14 @@ export async function verifyInvite(req: Request, res: Response): Promise<any> {
|
||||||
|
|
||||||
let { secret } = await InviteService.getByMailAndToken(mail, token);
|
let { secret } = await InviteService.getByMailAndToken(mail, token);
|
||||||
|
|
||||||
const url = `otpauth://totp/Mitgliederverwaltung ${process.env.CLUB_NAME}?secret=${secret}`;
|
const url = `otpauth://totp/Mitgliederverwaltung ${CLUB_NAME}?secret=${secret}`;
|
||||||
|
|
||||||
QRCode.toDataURL(url)
|
QRCode.toDataURL(url)
|
||||||
.then((result) => {
|
.then((result) => {
|
||||||
res.send(result);
|
res.json({
|
||||||
|
dataUrl: result,
|
||||||
|
otp: secret,
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
throw new InternalException("QRCode not created");
|
throw new InternalException("QRCode not created");
|
||||||
|
|
|
@ -9,14 +9,15 @@ import { invite } from "./entity/invite";
|
||||||
import { Initial1724317398939 } from "./migrations/1724317398939-initial";
|
import { Initial1724317398939 } from "./migrations/1724317398939-initial";
|
||||||
import { RefreshPrimaryChange1724573307851 } from "./migrations/1724573307851-refreshPrimaryChange";
|
import { RefreshPrimaryChange1724573307851 } from "./migrations/1724573307851-refreshPrimaryChange";
|
||||||
import { Invite1724579024939 } from "./migrations/1724579024939-invite";
|
import { Invite1724579024939 } from "./migrations/1724579024939-invite";
|
||||||
|
import { DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME } from "./env.defaults";
|
||||||
|
|
||||||
const dataSource = new DataSource({
|
const dataSource = new DataSource({
|
||||||
type: "mysql",
|
type: "mysql",
|
||||||
host: process.env.NODE_ENV || process.env.DBMODE ? "localhost" : process.env.DB_HOST,
|
host: process.env.NODE_ENV || process.env.DBMODE ? "localhost" : DB_HOST,
|
||||||
port: 3306,
|
port: 3306,
|
||||||
username: process.env.DB_USERNAME,
|
username: DB_USERNAME,
|
||||||
password: process.env.DB_PASSWORD,
|
password: DB_PASSWORD,
|
||||||
database: process.env.DB_NAME,
|
database: DB_NAME,
|
||||||
synchronize: false,
|
synchronize: false,
|
||||||
logging: process.env.NODE_ENV ? true : ["schema", "error", "warn", "log", "migration"],
|
logging: process.env.NODE_ENV ? true : ["schema", "error", "warn", "log", "migration"],
|
||||||
bigNumberStrings: false,
|
bigNumberStrings: false,
|
||||||
|
|
51
src/env.defaults.ts
Normal file
51
src/env.defaults.ts
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import "dotenv/config";
|
||||||
|
import ms from "ms";
|
||||||
|
|
||||||
|
export const DB_HOST = process.env.DB_HOST ?? "";
|
||||||
|
export const DB_NAME = process.env.DB_NAME ?? "";
|
||||||
|
export const DB_USERNAME = process.env.DB_USERNAME ?? "";
|
||||||
|
export const DB_PASSWORD = process.env.DB_PASSWORD ?? "";
|
||||||
|
|
||||||
|
export const SERVER_PORT = Number(process.env.SERVER_PORT ?? 5000);
|
||||||
|
|
||||||
|
export const JWT_SECRET = process.env.JWT_SECRET ?? "my_jwt_secret_string_ilughfnadiuhgq§$IUZGFVRweiouarbt1oub3h5q4a";
|
||||||
|
export const JWT_EXPIRATION = process.env.JWT_EXPIRATION ?? "15m";
|
||||||
|
export const REFRESH_EXPIRATION = process.env.REFRESH_EXPIRATION ?? "1d";
|
||||||
|
|
||||||
|
export const MAIL_USERNAME = process.env.MAIL_USERNAME ?? "";
|
||||||
|
export const MAIL_PASSWORD = process.env.MAIL_PASSWORD ?? "";
|
||||||
|
export const MAIL_HOST = process.env.MAIL_HOST ?? "";
|
||||||
|
export const MAIL_PORT = Number(process.env.MAIL_PORT ?? "587");
|
||||||
|
export const MAIL_SECURE = process.env.MAIL_SECURE ?? "false";
|
||||||
|
|
||||||
|
export const CLUB_NAME = process.env.CLUB_NAME ?? "";
|
||||||
|
|
||||||
|
export function configCheck() {
|
||||||
|
if (DB_HOST == "" ?? typeof DB_HOST != "string") throw new Error("set valid value to DB_HOST");
|
||||||
|
if (DB_NAME == "" ?? typeof DB_NAME != "string") throw new Error("set valid value to DB_NAME");
|
||||||
|
if (DB_USERNAME == "" ?? typeof DB_USERNAME != "string") throw new Error("set valid value to DB_USERNAME");
|
||||||
|
if (DB_PASSWORD == "" ?? typeof DB_PASSWORD != "string") throw new Error("set valid value to DB_PASSWORD");
|
||||||
|
|
||||||
|
if (typeof SERVER_PORT != "number") throw new Error("set valid numeric value to SERVER_PORT");
|
||||||
|
|
||||||
|
if (JWT_SECRET == "" ?? typeof JWT_SECRET != "string") throw new Error("set valid value to JWT_SECRET");
|
||||||
|
checkMS(JWT_EXPIRATION, "JWT_EXPIRATION");
|
||||||
|
checkMS(REFRESH_EXPIRATION, "REFRESH_EXPIRATION");
|
||||||
|
|
||||||
|
if (MAIL_USERNAME == "" ?? typeof MAIL_USERNAME != "string") throw new Error("set valid value to MAIL_USERNAME");
|
||||||
|
if (MAIL_PASSWORD == "" ?? typeof MAIL_PASSWORD != "string") throw new Error("set valid value to MAIL_PASSWORD");
|
||||||
|
if (MAIL_HOST == "" ?? typeof MAIL_HOST != "string") throw new Error("set valid value to MAIL_HOST");
|
||||||
|
if (typeof MAIL_PORT != "number") throw new Error("set valid numeric value to MAIL_PORT");
|
||||||
|
if (MAIL_SECURE != "true" && MAIL_SECURE != "false") throw new Error("set 'true' or 'false' to MAIL_SECURE");
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkMS(input: string, origin: string) {
|
||||||
|
try {
|
||||||
|
const result = ms(input);
|
||||||
|
if (result === undefined) {
|
||||||
|
throw new Error(`set valid ms value to ${origin}`);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(`set valid ms value to ${origin}`);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,11 @@
|
||||||
import jwt from "jsonwebtoken";
|
import jwt from "jsonwebtoken";
|
||||||
import { JWTData } from "../type/jwtTypes";
|
import { JWTData } from "../type/jwtTypes";
|
||||||
|
import { JWT_SECRET, JWT_EXPIRATION } from "../env.defaults";
|
||||||
|
|
||||||
export abstract class JWTHelper {
|
export abstract class JWTHelper {
|
||||||
static validate(token: string): Promise<string | jwt.JwtPayload> {
|
static validate(token: string): Promise<string | jwt.JwtPayload> {
|
||||||
return new Promise<string | jwt.JwtPayload>((resolve, reject) => {
|
return new Promise<string | jwt.JwtPayload>((resolve, reject) => {
|
||||||
jwt.verify(token, process.env.JWT_SECRET, (err, decoded) => {
|
jwt.verify(token, JWT_SECRET, (err, decoded) => {
|
||||||
if (err) reject(err.message);
|
if (err) reject(err.message);
|
||||||
else resolve(decoded);
|
else resolve(decoded);
|
||||||
});
|
});
|
||||||
|
@ -15,9 +16,9 @@ export abstract class JWTHelper {
|
||||||
return new Promise<string>((resolve, reject) => {
|
return new Promise<string>((resolve, reject) => {
|
||||||
jwt.sign(
|
jwt.sign(
|
||||||
data,
|
data,
|
||||||
process.env.JWT_SECRET,
|
JWT_SECRET,
|
||||||
{
|
{
|
||||||
expiresIn: process.env.JWT_EXPIRATION,
|
expiresIn: JWT_EXPIRATION,
|
||||||
},
|
},
|
||||||
(err, token) => {
|
(err, token) => {
|
||||||
if (err) reject(err.message);
|
if (err) reject(err.message);
|
||||||
|
|
|
@ -1,16 +1,17 @@
|
||||||
import { Transporter, createTransport, TransportOptions } from "nodemailer";
|
import { Transporter, createTransport, TransportOptions } from "nodemailer";
|
||||||
|
import { CLUB_NAME, MAIL_HOST, MAIL_PASSWORD, MAIL_PORT, MAIL_SECURE, MAIL_USERNAME } from "../env.defaults";
|
||||||
|
|
||||||
export default class MailHelper {
|
export default class MailHelper {
|
||||||
private readonly transporter: Transporter;
|
private readonly transporter: Transporter;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.transporter = createTransport({
|
this.transporter = createTransport({
|
||||||
host: process.env.MAIL_HOST,
|
host: MAIL_HOST,
|
||||||
port: Number(process.env.MAIL_PORT),
|
port: MAIL_PORT,
|
||||||
secure: (process.env.MAIL_SECURE as "true" | "false") == "true",
|
secure: (MAIL_SECURE as "true" | "false") == "true",
|
||||||
auth: {
|
auth: {
|
||||||
user: process.env.MAIL_USERNAME,
|
user: MAIL_USERNAME,
|
||||||
pass: process.env.MAIL_PASSWORD,
|
pass: MAIL_PASSWORD,
|
||||||
},
|
},
|
||||||
} as TransportOptions);
|
} as TransportOptions);
|
||||||
}
|
}
|
||||||
|
@ -26,7 +27,7 @@ export default class MailHelper {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.transporter
|
this.transporter
|
||||||
.sendMail({
|
.sendMail({
|
||||||
from: `"${process.env.CLUB_NAME}" <${process.env.MAIL_USERNAME}>`,
|
from: `"${CLUB_NAME}" <${MAIL_USERNAME}>`,
|
||||||
to: target,
|
to: target,
|
||||||
subject,
|
subject,
|
||||||
text: content,
|
text: content,
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
|
import crypto from "crypto";
|
||||||
|
|
||||||
export abstract class StringHelper {
|
export abstract class StringHelper {
|
||||||
static random(len: number, charSet?: string): string {
|
static random(len: number, charSet?: string): string {
|
||||||
charSet = charSet || "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
// charSet = charSet || "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||||
var randomString = "";
|
// var randomString = "";
|
||||||
for (var i = 0; i < len; i++) {
|
// for (var i = 0; i < len; i++) {
|
||||||
var randomPoz = Math.floor(Math.random() * charSet.length);
|
// var randomPoz = Math.floor(Math.random() * charSet.length);
|
||||||
randomString += charSet.substring(randomPoz, randomPoz + 1);
|
// randomString += charSet.substring(randomPoz, randomPoz + 1);
|
||||||
}
|
// }
|
||||||
return randomString;
|
// return randomString;
|
||||||
|
return crypto.randomBytes(len).toString("base64");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import "dotenv/config";
|
import "dotenv/config";
|
||||||
import express from "express";
|
import express from "express";
|
||||||
|
|
||||||
|
import { configCheck, SERVER_PORT } from "./env.defaults";
|
||||||
|
configCheck();
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
namespace Express {
|
namespace Express {
|
||||||
export interface Request {
|
export interface Request {
|
||||||
|
@ -18,6 +21,6 @@ dataSource.initialize();
|
||||||
const app = express();
|
const app = express();
|
||||||
import router from "./routes/index";
|
import router from "./routes/index";
|
||||||
router(app);
|
router(app);
|
||||||
app.listen(process.env.SERVER_PORT, () => {
|
app.listen(SERVER_PORT, () => {
|
||||||
console.log(`listening on *:${process.env.SERVER_PORT}`);
|
console.log(`listening on *:${SERVER_PORT}`);
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue