This commit is contained in:
31
lib/server/app.ts
Normal file
31
lib/server/app.ts
Normal 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;
|
||||
50
lib/server/controllers/auth.ts
Normal file
50
lib/server/controllers/auth.ts
Normal 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 };
|
||||
9
lib/server/database/database.connection.ts
Normal file
9
lib/server/database/database.connection.ts
Normal 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}`);
|
||||
12
lib/server/middleware/authenication.ts
Normal file
12
lib/server/middleware/authenication.ts
Normal 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);
|
||||
}
|
||||
};
|
||||
};
|
||||
13
lib/server/middleware/errorHandler.ts
Normal file
13
lib/server/middleware/errorHandler.ts
Normal 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);
|
||||
}
|
||||
};
|
||||
0
lib/server/middleware/jwt.ts
Normal file
0
lib/server/middleware/jwt.ts
Normal file
14
lib/server/middleware/performance.ts
Normal file
14
lib/server/middleware/performance.ts
Normal 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`);
|
||||
};
|
||||
23
lib/server/passport/index.ts
Normal file
23
lib/server/passport/index.ts
Normal 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;
|
||||
22
lib/server/passport/strategies/jwt.ts
Normal file
22
lib/server/passport/strategies/jwt.ts
Normal 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);
|
||||
});
|
||||
17
lib/server/passport/strategies/local.ts
Normal file
17
lib/server/passport/strategies/local.ts
Normal 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
12
lib/server/server.ts
Normal 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),
|
||||
);
|
||||
Reference in New Issue
Block a user