Inject user middleware

This commit is contained in:
Douglas Barone 2023-06-15 08:04:59 -04:00
parent 7c3bc91f39
commit 26771cecdc
8 changed files with 102 additions and 31 deletions

8
package-lock.json generated
View File

@ -19,7 +19,7 @@
"devDependencies": { "devDependencies": {
"@types/express": "^4.17.17", "@types/express": "^4.17.17",
"@types/jsonwebtoken": "^9.0.2", "@types/jsonwebtoken": "^9.0.2",
"@types/node": "^20.2.5", "@types/node": "^20.3.1",
"nodemon": "^2.0.22", "nodemon": "^2.0.22",
"prisma": "^4.15.0", "prisma": "^4.15.0",
"rimraf": "^5.0.1", "rimraf": "^5.0.1",
@ -214,9 +214,9 @@
"dev": true "dev": true
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "20.2.5", "version": "20.3.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.5.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.1.tgz",
"integrity": "sha512-JJulVEQXmiY9Px5axXHeYGLSjhkZEnD+MDPDGbCbIAbMslkKwmygtZFy1X6s/075Yo94sf8GuSlFfPzysQrWZQ==" "integrity": "sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg=="
}, },
"node_modules/@types/qs": { "node_modules/@types/qs": {
"version": "6.9.7", "version": "6.9.7",

View File

@ -10,13 +10,16 @@
"start": "node dist", "start": "node dist",
"dev": "nodemon --ext js,ts,mts,mjs,json,prisma ./src/index.ts --exec ts-node-esm" "dev": "nodemon --ext js,ts,mts,mjs,json,prisma ./src/index.ts --exec ts-node-esm"
}, },
"prisma": {
"seed": "ts-node --esm prisma/seed.ts"
},
"keywords": [], "keywords": [],
"author": "Douglas Barone", "author": "Douglas Barone",
"license": "ISC", "license": "ISC",
"devDependencies": { "devDependencies": {
"@types/express": "^4.17.17", "@types/express": "^4.17.17",
"@types/jsonwebtoken": "^9.0.2", "@types/jsonwebtoken": "^9.0.2",
"@types/node": "^20.2.5", "@types/node": "^20.3.1",
"nodemon": "^2.0.22", "nodemon": "^2.0.22",
"prisma": "^4.15.0", "prisma": "^4.15.0",
"rimraf": "^5.0.1", "rimraf": "^5.0.1",

View File

@ -1,6 +1,9 @@
-- CreateEnum -- CreateEnum
CREATE TYPE "Role" AS ENUM ('ADMIN', 'INSPECTOR', 'USER'); CREATE TYPE "Role" AS ENUM ('ADMIN', 'INSPECTOR', 'USER');
-- CreateEnum
CREATE TYPE "PrinterModel" AS ENUM ('m3655idn', 'm2040dn', 'p6235cdn');
-- CreateTable -- CreateTable
CREATE TABLE "User" ( CREATE TABLE "User" (
"id" SERIAL NOT NULL, "id" SERIAL NOT NULL,
@ -15,5 +18,18 @@ CREATE TABLE "User" (
CONSTRAINT "User_pkey" PRIMARY KEY ("id") CONSTRAINT "User_pkey" PRIMARY KEY ("id")
); );
-- CreateTable
CREATE TABLE "Printer" (
"id" SERIAL NOT NULL,
"hostname" TEXT,
"friendlyName" TEXT,
"ip" TEXT NOT NULL,
"model" "PrinterModel" NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "Printer_pkey" PRIMARY KEY ("id")
);
-- CreateIndex -- CreateIndex
CREATE UNIQUE INDEX "User_username_key" ON "User"("username"); CREATE UNIQUE INDEX "User_username_key" ON "User"("username");

View File

@ -29,3 +29,21 @@ model User {
roles Role[] @default([USER]) roles Role[] @default([USER])
} }
model Printer {
id Int @id @default(autoincrement())
hostname String?
friendlyName String?
ip String
model PrinterModel
createdAt DateTime @default(now())
updatedAt DateTime @default(now()) @updatedAt
}
enum PrinterModel {
m3655idn
m2040dn
p6235cdn
}

25
prisma/seed.ts Normal file
View File

@ -0,0 +1,25 @@
import { PrismaClient } from '@prisma/client'
export const prisma = new PrismaClient()
async function main() {
await prisma.printer.createMany({
data: [
{ friendlyName: 'p04', ip: '10.7.0.134', model: 'm3655idn' },
{ friendlyName: 'p05', ip: '10.7.0.135', model: 'm2040dn' },
{ friendlyName: 'p06', ip: '10.7.0.136', model: 'm2040dn' },
{ friendlyName: 'p07', ip: '10.7.0.137', model: 'm2040dn' },
{ friendlyName: 'p08', ip: '10.7.0.138', model: 'p6235cdn' }
]
})
}
main()
.then(() => {
prisma.$disconnect()
})
.catch(error => {
console.error(error)
prisma.$disconnect()
process.exit(1)
})

View File

@ -1,12 +1,15 @@
import 'dotenv/config' import 'dotenv/config'
import express, { Request, Response } from 'express' import express, { Request, Response } from 'express'
import bodyParser from 'body-parser' import bodyParser from 'body-parser'
import { login } from './authentication.js'
import { import {
authenticatedMiddleware, authenticatedMiddleware,
hasRolesMiddleware hasRolesMiddleware
} from './middleware/authorization.js' } from './middleware/authorization.js'
import { injectUserMiddleware } from './middleware/injectUser.js'
import { RequestWithUser } from './types.js' import { RequestWithUser } from './types.js'
import { login } from './authentication.js'
import { UserController } from './controllers/UserController.js' import { UserController } from './controllers/UserController.js'
const app = express() const app = express()
@ -15,6 +18,8 @@ const PORT = process.env.PORT || 3000
app.use('/', express.static('public')) app.use('/', express.static('public'))
app.use(injectUserMiddleware)
app.use(bodyParser.json()) app.use(bodyParser.json())
// Test route // Test route

View File

@ -3,35 +3,12 @@ import { authenticate } from '../authentication.js'
import { RequestWithUser } from '../types.js' import { RequestWithUser } from '../types.js'
import { Role } from '@prisma/client' import { Role } from '@prisma/client'
function getToken(req: Request) {
const authHeader = req.headers.authorization as string
if (!authHeader) return null
const [type, token] = authHeader.split(' ')
if (type !== 'Bearer') throw new Error('Expected a Bearer token')
return token
}
async function injectUser(req: RequestWithUser) {
const token = getToken(req)
if (!token) return null
const user = await authenticate(token)
req.user = user
}
export async function authenticatedMiddleware( export async function authenticatedMiddleware(
req: RequestWithUser, req: RequestWithUser,
res: Response, res: Response,
next: NextFunction next: NextFunction
) { ) {
try { try {
await injectUser(req)
if (!req.user) { if (!req.user) {
res.status(401).json({ error: 'Must be logged in' }) res.status(401).json({ error: 'Must be logged in' })
return return
@ -50,8 +27,6 @@ export async function hasRolesMiddleware(roles: Role[]) {
next: NextFunction next: NextFunction
) { ) {
try { try {
await injectUser(req)
const userRoles = req.user?.roles const userRoles = req.user?.roles
if (userRoles === undefined) { if (userRoles === undefined) {

View File

@ -0,0 +1,29 @@
import { NextFunction, Request, Response } from 'express'
import { RequestWithUser } from '../types.js'
import { authenticate } from '../authentication.js'
function getToken(req: Request) {
const authHeader = req.headers.authorization as string
if (!authHeader) return null
const [type, token] = authHeader.split(' ')
if (type !== 'Bearer') throw new Error('Expected a Bearer token')
return token
}
export async function injectUserMiddleware(
req: RequestWithUser,
res: Response,
next: NextFunction
) {
const token = getToken(req)
if (token) {
const user = await authenticate(token)
req.user = user
}
next()
}