library-ts/node/users/UserManagementServer.ts

282 lines
7.2 KiB
TypeScript

import Fastify, { FastifyHttpsOptions, FastifyInstance, FastifyListenOptions, FastifyRequest } from "fastify";
import fastifyMultipart from "@fastify/multipart";
import cors from '@fastify/cors';
import { EventSlot } from "../../browser/events/EventSlot";
import { JSRandomEngine } from "../../browser/random/JSRandomEngine";
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";
import { FilesSync } from "../files/FilesSync";
import { UserData } from "./UserData";
import { Scheduler } from "./scheduler/Scheduler";
import { DateHelper } from "../../browser/date/DateHelper";
import { DateFormatter } from "../../browser/date/DateFormatter";
import { Duration } from "../../browser/date/Duration";
import { Task } from "./scheduler/Task";
import { UserApp } from "./apps/UserApp";
import { UserAppFactory } from "./apps/UserAppFactory";
import { iTaskScheduler } from "./scheduler/iTaskScheduler";
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<string,Session> = new Map<string,Session>();
_roles = new Map<string,Role>();
_handlers:RequestHandler[] = [];
_settings:UserManagementServerSettings;
_globalRequirements:RequestRequirement[] = [];
get globalRequirements(){ return this._globalRequirements; }
_apps:UserApp<any>[] = [];
get apps(){ return this._apps; }
_scheduler:Scheduler;
get scheduler(){ return this._scheduler; }
readonly onFileChanged = new EventSlot<string>();
async initialize( settings:UserManagementServerSettings, mailService:EmailService, handlers:RequestHandler[], globalRequirements:RequestRequirement[] = null ):Promise<void>
{
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._startApps();
await this._startServer();
this._update();
return Promise.resolve();
}
static DefaultGlobalRequirements():RequestRequirement[]
{
let globalDefaults:RequestRequirement[] =
[
new NotTooManyRequests()
];
return globalDefaults;
}
async _addGlobalRequirements( globalRequirements:RequestRequirement[] ):Promise<void>
{
this._globalRequirements = globalRequirements;
for ( let gr of this._globalRequirements )
{
await gr.initializeGlobal( this );
}
return Promise.resolve();
}
getUser( request:FastifyRequest ):Promise<UserData>
{
let requestBody = request.body;
let tokenData = requestBody as { token:string };
let tokenID = tokenData.token;
let session = this._sessions.get( tokenID );
return this.userDB.byID( session.userID );
}
async sendEmail( to:string, title:string, message:string ):Promise<void>
{
return this.email.send( this._settings.emailFrom, to, title, message );
}
async _initializeApp():Promise<void>
{
if ( this._settings.isDebugMode )
{
this._app = Fastify();
}
else
{
let httpsKey = FilesSync.loadUTF8( this._settings.httpsKeyPath );
let httpsCert = FilesSync.loadUTF8( this._settings.httpsCertPath );
RJLog.log( "Key", httpsKey );
RJLog.log( "Cert", httpsCert );
this._app = Fastify(
{
https:
{
key:httpsKey,
cert:httpsCert
}
}
);
}
this._app.register( fastifyMultipart );
if ( this._settings.isDebugMode )
{
RJLog.log( "Setting any cors:" );
await this._app.register( cors,
{
origin: "*",
});
}
else
{
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();
}
_updateDuration = 60;
protected _update()
{
let self = this;
let waitTimeMS = Duration.toMilliSeconds( this._updateDuration );
setTimeout( () =>{ self._update() }, waitTimeMS );
}
async _addServices( mailService:EmailService ):Promise<void>
{
this._userDB = await UserDB.load( this, this._settings.userDBPath );
this._scheduler = new Scheduler();
// RJLog.log( "Loading roles:", this._settings.rolesPath );
let rolesData = await Files.loadJSON<RolesData>( this._settings.rolesPath );
this._roles = new Map<string,Role>();
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<void>
{
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}` );
}
);
}
async _startApps()
{
for ( let appID of this._settings.userApps )
{
let app = UserAppFactory.create( appID, this );
RJLog.log( "Starting app:", app.id );
this._apps.push( app );
}
for ( let app of this._apps )
{
await app.initialize();
if ( app.schedulesTasks )
{
this.scheduler._taskSchedulers.push( app as any as iTaskScheduler );
}
}
await this._scheduler.update();
}
}