diff --git a/src/controllers/ScanController.ts b/src/controllers/ScanController.ts index 7b61b02..6512a9e 100644 --- a/src/controllers/ScanController.ts +++ b/src/controllers/ScanController.ts @@ -1,8 +1,9 @@ -import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers'; +import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam, UseBefore } from 'routing-controllers'; import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi'; import { getConnectionManager, Repository } from 'typeorm'; import { RunnerNotFoundError } from '../errors/RunnerErrors'; import { ScanIdsNotMatchingError, ScanNotFoundError } from '../errors/ScanErrors'; +import StatsAuth from '../middlewares/StatsAuth'; import { CreateScan } from '../models/actions/CreateScan'; import { CreateTrackScan } from '../models/actions/CreateTrackScan'; import { UpdateScan } from '../models/actions/UpdateScan'; @@ -61,7 +62,7 @@ export class ScanController { } @Post("/trackscans") - @Authorized("SCAN:CREATE") + @UseBefore(StatsAuth) @ResponseSchema(ResponseScan) @OpenAPI({ description: 'Create a new track scan.
This is just a alias for posting /scans' }) async postTrackScans(@Body({ validate: true }) createScan: CreateTrackScan) { diff --git a/src/middlewares/ScanAuth.ts b/src/middlewares/ScanAuth.ts new file mode 100644 index 0000000..7b16420 --- /dev/null +++ b/src/middlewares/ScanAuth.ts @@ -0,0 +1,68 @@ +import * as argon2 from "argon2"; +import { Request, Response } from 'express'; +import { getConnectionManager } from 'typeorm'; +import { ScanStation } from '../models/entities/ScanStation'; +import authchecker from './authchecker'; + +/** + * This middleware handels the authentification of scan station api tokens. + * The tokens have to be provided via Bearer auth header. + * @param req Express request object. + * @param res Express response object. + * @param next Next function to call on success. + */ +const ScanAuth = async (req: Request, res: Response, next: () => void) => { + let provided_token: string = req.headers["authorization"]; + if (provided_token == "" || provided_token === undefined || provided_token === null) { + res.status(401).send("No api token provided."); + return; + } + + try { + provided_token = provided_token.replace("Bearer ", ""); + } catch (error) { + res.status(401).send("No valid jwt or api token provided."); + return; + } + + let prefix = ""; + try { + prefix = provided_token.split(".")[0]; + } + finally { + if (prefix == "" || prefix == undefined || prefix == null) { + res.status(401).send("Api token non-existant or invalid syntax."); + return; + } + } + + const station = await getConnectionManager().get().getRepository(ScanStation).findOne({ prefix: prefix }); + if (!station) { + let user_authorized = false; + try { + let action = { request: req, response: res, context: null, next: next } + user_authorized = await authchecker(action, ["SCAN:CREATE"]); + } + finally { + if (user_authorized == false) { + res.status(401).send("Api token non-existant or invalid syntax."); + return; + } + else { + next(); + } + } + } + else { + if (station.enabled == false) { + res.status(401).send("Station disabled."); + } + if (!(await argon2.verify(station.key, provided_token))) { + res.status(401).send("Api token invalid."); + return; + } + + next(); + } +} +export default ScanAuth; \ No newline at end of file