Reorganizing
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
2023-05-03 11:12:59 -04:00
parent 27a78dd471
commit dc72cefece
23 changed files with 163 additions and 87 deletions

31
lib/server/app.ts Normal file
View File

@@ -0,0 +1,31 @@
import Koa from 'koa';
import bodyparser from 'koa-bodyparser';
import cookie from 'koa-cookie';
import session from 'koa-session';
import passport from './passport';
import { performanceLogger, perfromanceTimer } from './middleware/performance';
import { errorHandler } from './middleware/errorHandler';
import { authRouter } from './controllers/auth';
const app: Koa = new Koa();
app.use(errorHandler);
app.use(perfromanceTimer);
app.use(performanceLogger);
app.use(bodyparser());
app.use(cookie());
app.keys = [process.env.SESSION_KEYS as string];
app.use(session({}, app));
app.use(passport.initialize());
app.use(passport.session());
app.use(authRouter.routes());
app.use(authRouter.allowedMethods());
// Application error logging.
app.on('error', console.error);
export default app;

View File

@@ -0,0 +1,50 @@
import Koa from 'koa';
import Router from 'koa-router';
import { StatusCodes } from 'http-status-codes';
import { ROUTE_PREFIX as prefix, RESET_ROUTE } from '../../constants/constants';
import Auth from '../../db/model/auth';
import { sign } from '../../utils/jwt';
import passport from '../passport';
import { ErrorCodes, getErrorBody } from '../../constants/errors';
const routerOpts: Router.IRouterOptions = { prefix };
const router: Router = new Router(routerOpts);
router.post('/', async (ctx) => {
const data = (await Auth.create(ctx.body)).save();
ctx.body = { success: true, data: { ...data, strategies: undefined } };
});
router.post('/login', async (ctx, next) => {
return passport.authenticate('local', (err, user) => {
if (user === false) {
ctx.body = { token: null };
ctx.throw(StatusCodes.UNAUTHORIZED);
}
ctx.body = { token: sign(user) };
return ctx.login(user);
})(ctx, next);
});
router.post(process.env.RESET_ROUTE || RESET_ROUTE, async (ctx, next) => {
const { token = null, password = null } = ctx.request.body as { token?: string, password?: string };
if (token && password) {
const loginToken = await Auth.resetPassword(token, password).catch();
ctx.body({ token: loginToken });
next();
}
ctx.body = { success: false, ...getErrorBody(ErrorCodes.RESET_REQUEST_DATA) };
});
router.patch('/:record', (ctx: Koa.Context) => {
const data = Auth.findOneAndUpdate(
{ record: ctx.params.record },
);
if (!data) {
ctx.throw(StatusCodes.NOT_FOUND);
}
ctx.body = { success: true, data };
});
export { router as authRouter };

View File

@@ -0,0 +1,9 @@
import mongoose from 'mongoose';
const DB_USER = process.env.DB_USER || 'test';
const DB_PASS = process.env.DB_PASSWORD || 'test';
const DB_HOST = process.env.DB_HOST || 'mongodb';
const DB_PORT = process.env.DB_PORT || 27017;
const DB_NAME = process.env.DB_NAME || 'auth';
export const connection = mongoose.connect(`${DB_USER}:${DB_PASS}@${DB_HOST}:${DB_PORT}/${DB_NAME}`);

View File

@@ -0,0 +1,12 @@
import { Middleware } from 'koa';
import { LOGIN_ROUTE } from '../../constants/constants';
export const authenticated = (): Middleware => {
return (ctx, next) => {
if (ctx.isAuthenticated()) {
return next();
} else {
ctx.redirect(process.env.LOGIN_ROUTE || LOGIN_ROUTE);
}
};
};

View File

@@ -0,0 +1,13 @@
import { StatusCodes } from 'http-status-codes';
import { Context, Next } from 'koa';
export const errorHandler = async (ctx: Context, next: Next) => {
try {
await next();
} catch (error: any) {
ctx.status = error.statusCode || error.status || StatusCodes.INTERNAL_SERVER_ERROR;
error.status = ctx.status;
ctx.body = { error };
ctx.app.emit('error', error, ctx);
}
};

View File

View File

@@ -0,0 +1,14 @@
import { Context, Next } from 'koa';
export const performanceLogger = async (ctx: Context, next: Next) => {
await next();
const rt = ctx.response.get('X-Response-Time');
console.log(`${ctx.method} ${ctx.url} - ${rt}`);
};
export const perfromanceTimer = async (ctx: Context, next: Next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
ctx.set('X-Response-Time', `${ms}ms`);
};

View File

@@ -0,0 +1,23 @@
import passport from 'koa-passport';
import Auth from '../../model/auth';
import { Auth as AuthRecord } from '../../db/schema/auth';
import LocalStrategy from './strategies/local';
import JwtStrategy from './strategies/jwt';
passport.serializeUser((user, done) => done(null, (user as AuthRecord).record));
passport.deserializeUser(async (id, done) => {
const user = await Auth.findOne({ record: id });
if (user) {
done(null, user);
}
done('user not found', null);
});
passport.use(LocalStrategy);
passport.use(JwtStrategy);
export default passport;

View File

@@ -0,0 +1,22 @@
// eslint-disable-next-line import/named
import { ExtractJwt, Strategy as JwtStrategy } from 'passport-jwt';
import Auth from '../../../model/auth';
import { getJwtSecret } from '../../../utils/jwt';
const opts = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: getJwtSecret(),
issuer: process.env.JWT_ISSUER,
audience: process.env.JWT_AUDIENCE,
};
export default new JwtStrategy(opts, async (jwt_payload, done) => {
const auth = await Auth.findOne({ record: jwt_payload.sub }).catch();
if (auth) {
return done(null, auth);
}
return done(null, false);
});

View File

@@ -0,0 +1,17 @@
// eslint-disable-next-line import/named
import { Strategy as LocalStrategy } from 'passport-local';
import Auth from '../../../model/auth';
export default new LocalStrategy(async (username: string, password: string, done: any) => {
const user = await Auth.findOne({
where: {
username,
},
}).catch();
if (user && user.authenticate(password)) {
done(null, user);
} else {
done(null, false);
}
});

12
lib/server/server.ts Normal file
View File

@@ -0,0 +1,12 @@
import dotenv from 'dotenv';
import app from './app';
import { connection } from './database/database.connection';
import { PORT } from '../constants/constants';
dotenv.config();
connection.then(
() => app.listen(PORT),
(err) => console.error('ERROR!', err),
);