import type { NextFunction , Request , Response , Router } from "express" ; import type { Config } from "../Config" ; import type { Main } from "../Main" ; import { BridgeError } from "../bridging" ; import { chatRouter } from "./internal/routes" ; import { playerRouter } from "./internal/routes" ; import { getEvents } from "./internal/getEvents" ; import { LogService } from "matrix-bot-sdk" ; import { v1 as uuid } from "uuid" ; import * as Errors from "./internal/errors" ; export class WebInterface { private readonly main : Main ; private readonly config : Config ; public constructor ( config , main ) { this . main = main ; this . config = config ; } param { Router } app public start ( app ) { app . get ( '/vibecheck' , this . vibeCheck . bind ( this ) ) ; app . use ( '/chat' , this . checkAuth . bind ( this ) ) ; app . use ( '/events' , this . checkAuth . bind ( this ) ) ; app . use ( '/player' , this . checkAuth . bind ( this ) ) ; app . use ( '/chat' , chatRouter ) ; app . get ( '/events' , getEvents ) ; app . use ( '/player' , playerRouter ) ; } param { Request } req param { Response } res private vibeCheck ( req , res ) { const auth = req . header ( 'Authorization' ) ; const id = uuid ( ) ; LogService . info ( "WebInterface" , `[Request ${ id }]` ) ; LogService . info ( "WebInterface" , `[Request ${ id }]: Endpoint ${ req . method } ${ req . path }` ) ; try { res . setHeader ( 'Content-Type' , 'application/json' ) ; if ( ! auth ) { res . status ( 401 ) ; res . send ( Errors . noTokenError ) ; res . end ( ) ; return ; } const token = auth . split ( ' ' ) [ 1 ] ; if ( ! token ) { res . status ( 401 ) ; res . send ( Errors . noTokenError ) ; res . end ( ) ; return ; } const bridge = this . main . bridges . getBridge ( token ) ; LogService . info ( "WebInterface" , `[Request ${ id }]: Authorized` ) ; res . status ( 200 ) ; res . send ( { "status" : "OK" , "bridge" : bridge . room } ) ; res . end ( ) ; } catch ( err ) { if ( err instanceof BridgeError . NotBridgedError ) { LogService . warn ( "WebInterface" , `[Request ${ id }]: Unauthorized` ) ; res . status ( 401 ) ; res . send ( Errors . invalidTokenError ) ; res . end ( ) ; } else { LogService . error ( "marco:WebServer" , err ) ; res . status ( 500 ) ; res . send ( Errors . serverError ) ; } } LogService . info ( "WebInterface" , `[Request ${ id }]: Finished` ) ; } param { Request } req param { Response } res param { NextFunction } next private checkAuth ( req , res , next ) { const id = uuid ( ) ; LogService . info ( "WebInterface" , `[Request ${ id }]` ) ; LogService . info ( "WebInterface" , `[Request ${ id }]: Endpoint ${ req . method } ${ req . path }` ) ; const auth = req . header ( 'Authorization' ) ; if ( auth == undefined ) { res . status ( 401 ) ; res . end ( ) ; return ; } const split = auth . split ( ' ' ) ; if ( split . length < 2 ) { res . status ( 401 ) ; res . end ( ) ; return ; } const token = split [ 1 ] ; try { const bridge = this . main . bridges . getBridge ( token ) ; LogService . info ( "WebInterface" , `[Request ${ id }]: Authorized` ) ; req [ 'main' ] = this . main ; req [ 'bridge' ] = bridge ; req [ 'id' ] = id ; next ( ) ; } catch ( err ) { if ( err instanceof BridgeError . NotBridgedError ) { res . status ( 401 ) ; res . send ( Errors . invalidTokenError ) ; res . end ( ) ; } else { res . status ( 500 ) ; res . send ( Errors . serverError ) ; res . end ( ) ; } } } }