import Fastify, { FastifyInstance, FastifyListenOptions } from "fastify"; import fastifyMultipart from "@fastify/multipart"; import cors from '@fastify/cors'; import { UserDB } from "./UserDB"; import { RequestHandler } from "./RequestHandler"; import { EmailService as EmailService } from "./email/EmailService"; import { TokenDB } from "./TokenDB"; import { UserManagementServerSettings } from "./UserManagementServerSettings"; import { RJLog } from "../log/RJLog"; import { Session } from "./Session"; import { Role } from "./permissions/Role"; import { RolesData } from "./permissions/RolesData"; import { Files } from "../files/Files"; import { LocationService } from "./location/LocationService"; import { RequestRequirement } from "./requirements/RequestRequirement"; import { NotTooManyRequests } from "./requirements/security/NotTooManyRequests"; export class UserManagementServer { _app:FastifyInstance; get app(){ return this._app; } _userDB:UserDB; get userDB(){ return this._userDB; } _tokenDB:TokenDB; get tokenDB(){ return this._tokenDB;} _emailService:EmailService; get email(){ return this._emailService; } _locationService:LocationService; get location(){ return this._locationService; } _sessions:Map = new Map(); _roles = new Map(); _handlers:RequestHandler[] = []; _settings:UserManagementServerSettings; _globalRequirements:RequestRequirement[] = []; get globalRequirements(){ return this._globalRequirements; } async initialize( settings:UserManagementServerSettings, mailService:EmailService, handlers:RequestHandler[], globalRequirements:RequestRequirement[] = null ):Promise { this._settings = settings; UserManagementServerSettings.makeAllPathsAbsolute( settings ); await this._initializeApp(); await this._addGlobalRequirements( globalRequirements || UserManagementServer.DefaultGlobalRequirements() ); await this._addServices( mailService ); await this._addHandlers( handlers ); await this._startServer(); return Promise.resolve(); } static DefaultGlobalRequirements():RequestRequirement[] { let globalDefaults:RequestRequirement[] = [ new NotTooManyRequests() ]; return globalDefaults; } async _addGlobalRequirements( globalRequirements:RequestRequirement[] ):Promise { this._globalRequirements = globalRequirements; for ( let gr of this._globalRequirements ) { await gr.initializeGlobal( this ); } return Promise.resolve(); } async sendEmail( to:string, title:string, message:string ):Promise { return this.email.send( this._settings.emailFrom, to, title, message ); } async _initializeApp():Promise { this._app = Fastify(); this._app.register( fastifyMultipart ); for ( let corsURL of this._settings.corsURLs ) { RJLog.log( "Adding cors:", corsURL ); await this._app.register( cors, { origin: corsURL, credentials: true, methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'] } ); } return Promise.resolve(); } async _addServices( mailService:EmailService ):Promise { this._userDB = await UserDB.load( this, this._settings.userDBPath ); RJLog.log( "Loading roles:", this._settings.rolesPath ); let rolesData = await Files.loadJSON( this._settings.rolesPath ); this._roles = new Map(); rolesData.roles.forEach( r => this._roles.set( r.id, r ) ); this._tokenDB = new TokenDB( this ); this._emailService = mailService; this._locationService = await LocationService.create( this._settings.geoLocationPath, this._settings.geoAccountID, this._settings.geoLicenseKey ); let ipToCheck = "2a02:3100:25e5:2500:65d7:61b7:33f7:9d7f"; let location = await this._locationService.getLocation( ipToCheck ); RJLog.log( "IP", ipToCheck, "Location:", location ); return Promise.resolve(); } async _addHandlers( handlers:RequestHandler[] ):Promise { for ( let handler of handlers ) { await handler.initialize( this ); this._handlers.push( handler ); } return Promise.resolve(); } async _startServer() { let listenOptions:FastifyListenOptions = { port: this._settings.port } if ( ! this._settings.isDebugMode ) { listenOptions.host = "0.0.0.0"; } this.app.listen( listenOptions, ( error, address ) => { if ( error ) { RJLog.error( error ); throw error; } RJLog.log( `Server running on ${address}` ); } ); } }