diff --git a/src/definitions/custom/modepress.d.ts b/src/definitions/custom/modepress.d.ts index f6a89122..26e904fe 100644 --- a/src/definitions/custom/modepress.d.ts +++ b/src/definitions/custom/modepress.d.ts @@ -219,6 +219,24 @@ * An array of controllers associated with this server */ controllers: Array + + /** + * The URL to redirect to after the user attempts to activate their account. + * User's can activate their account via the '/activate-account' URL, and after its validation the server will redirect to this URL + * adding a query ?message=You%20have%20activated%20your%20account&status=success. + * The status can be either 'success' or 'error' + * + * eg: 'http://localhost/notify-user' + */ + accountRedirectURL: string; + + /** + * The URL sent to users emails for when their password is reset. This URL should + * resolve to a page with a form that allows users to reset their password. (MORE TO COME ON THIS) + * + * eg: 'http://localhost/reset-password' + */ + passwordResetURL: string; } /** @@ -281,6 +299,33 @@ apiKey: string; } + /* + * Users stores data on an external cloud bucket with Google + */ + export interface IWebsocket { + /** + * A key that must be provided in the headers of socket client connections. If the connection headers + * contain 'users-api-key', and it matches this key, then the connection is considered an authorized connection. + */ + socketApiKey: string; + + /** + * The port number to use for web socket communication. You can use this port to send and receive events or messages + * to the server. + * e.g. 8080 + */ + port: number; + + /** + * An array of safe origins for socket communication + * [ + * 'webinate.net', + * 'localhost' + * ] + */ + approvedSocketDomains: Array; + } + /* * Users stores data on an external cloud bucket with Google */ @@ -439,6 +484,11 @@ } */ google: IGoogleProperties; + + /** + * Information regarding the websocket communication. Used for events and IPC + */ + websocket: IWebsocket; } export interface IAuthReq extends Express.Request { @@ -1022,17 +1072,17 @@ * A list of helper functions for creating schema items */ export namespace SchemaFactory { - export var num: typeof SchemaNumber; - export var text: typeof SchemaText; - export var textArray: typeof SchemaTextArray; - export var json: typeof SchemaJSON; - export var numArray: typeof SchemaNumArray; - export var idArray: typeof SchemaIdArray; - export var date: typeof SchemaDate; - export var bool: typeof SchemaBool; - export var id: typeof SchemaId; - export var html: typeof SchemaHtml; - export var foreignKey: typeof SchemaForeignKey; + export const num: typeof SchemaNumber; + export const text: typeof SchemaText; + export const textArray: typeof SchemaTextArray; + export const json: typeof SchemaJSON; + export const numArray: typeof SchemaNumArray; + export const idArray: typeof SchemaIdArray; + export const date: typeof SchemaDate; + export const bool: typeof SchemaBool; + export const id: typeof SchemaId; + export const html: typeof SchemaHtml; + export const foreignKey: typeof SchemaForeignKey; } /** diff --git a/src/definitions/generated/modepress.d.ts b/src/definitions/generated/modepress.d.ts index b639ee19..be794aae 100644 --- a/src/definitions/generated/modepress.d.ts +++ b/src/definitions/generated/modepress.d.ts @@ -219,6 +219,24 @@ declare namespace Modepress { * An array of controllers associated with this server */ controllers: Array + + /** + * The URL to redirect to after the user attempts to activate their account. + * User's can activate their account via the '/activate-account' URL, and after its validation the server will redirect to this URL + * adding a query ?message=You%20have%20activated%20your%20account&status=success. + * The status can be either 'success' or 'error' + * + * eg: 'http://localhost/notify-user' + */ + accountRedirectURL: string; + + /** + * The URL sent to users emails for when their password is reset. This URL should + * resolve to a page with a form that allows users to reset their password. (MORE TO COME ON THIS) + * + * eg: 'http://localhost/reset-password' + */ + passwordResetURL: string; } /** @@ -248,10 +266,116 @@ declare namespace Modepress { variables: { [ name: string ]: string }; } + export interface IMailOptions { } + + /** + * Options for a gmail mailer + */ + export interface IGMail extends IMailOptions { + /* + * The email account to use the gmail API through. This account must be authorized to + * use this application. See: https://admin.google.com/AdminHome?fral=1#SecuritySettings: + */ + apiEmail: string; + + /* + * Path to the key file + */ + keyFile: string; + } + + /** + * Options for a mailgun mailer + */ + export interface IMailgun extends IMailOptions { + /** + * The domain for associated with the mailgun account + */ + domain: string; + + /** + * The api key for your mailgun account + */ + apiKey: string; + } + + /* + * Users stores data on an external cloud bucket with Google + */ + export interface IWebsocket { + /** + * A key that must be provided in the headers of socket client connections. If the connection headers + * contain 'users-api-key', and it matches this key, then the connection is considered an authorized connection. + */ + socketApiKey: string; + + /** + * The port number to use for web socket communication. You can use this port to send and receive events or messages + * to the server. + * e.g. 8080 + */ + port: number; + + /** + * An array of safe origins for socket communication + * [ + * 'webinate.net', + * 'localhost' + * ] + */ + approvedSocketDomains: Array; + } + + /* + * Users stores data on an external cloud bucket with Google + */ + export interface IGoogleProperties { + /* + * Path to the key file + */ + keyFile: string; + + /* + * Describes the bucket details + */ + bucket: { + + /* + * Project ID + */ + projectId: string; + + /** + * The name of the mongodb collection for storing bucket details + * eg: 'buckets' + */ + bucketsCollection: string; + + /** + * The name of the mongodb collection for storing file details + * eg: 'files' + */ + filesCollection: string; + + /** + * The name of the mongodb collection for storing user stats + * eg: 'storageAPI' + */ + statsCollection: string; + + /** + * The length of time the assets should be cached on a user's browser. + * eg: 2592000000 or 30 days + */ + cacheLifetime: number; + } + } + /** * A server configuration */ export interface IConfig { + /** * The length of time the assets should be cached on a user's browser. The default is 30 days. */ @@ -315,6 +439,56 @@ declare namespace Modepress { * eg: 'this-is-my-key' */ usersSocketApiKey: string; + + /** + * If debug is true, certain functions will be emulated and more information logged + */ + debug: boolean; + + /** + * Settings related to sending emails + */ + mail: { + + /** + * The from field sent to recipients + */ + from: string; + + /** + * Specify the type of mailer to use. + * Currently we support either 'gmail' or 'mailgun' + */ + type: 'gmail' | 'mailgun'; + + /** + * Options to be sent to the desired mailer + */ + options: IGMail | IMailgun; + } + + /** + * Information relating to the Google storage platform + * + 'google': { + 'keyFile': '', + 'mail':{ + 'apiEmail': '', + 'from': '' + }, + 'bucket': { + 'projectId': '', + 'bucketsCollection': 'buckets', + 'filesCollection': 'files' + } + } + */ + google: IGoogleProperties; + + /** + * Information regarding the websocket communication. Used for events and IPC + */ + websocket: IWebsocket; } export interface IAuthReq extends Express.Request { @@ -898,17 +1072,17 @@ declare namespace Modepress { * A list of helper functions for creating schema items */ export namespace SchemaFactory { - export var num: typeof SchemaNumber; - export var text: typeof SchemaText; - export var textArray: typeof SchemaTextArray; - export var json: typeof SchemaJSON; - export var numArray: typeof SchemaNumArray; - export var idArray: typeof SchemaIdArray; - export var date: typeof SchemaDate; - export var bool: typeof SchemaBool; - export var id: typeof SchemaId; - export var html: typeof SchemaHtml; - export var foreignKey: typeof SchemaForeignKey; + export const num: typeof SchemaNumber; + export const text: typeof SchemaText; + export const textArray: typeof SchemaTextArray; + export const json: typeof SchemaJSON; + export const numArray: typeof SchemaNumArray; + export const idArray: typeof SchemaIdArray; + export const date: typeof SchemaDate; + export const bool: typeof SchemaBool; + export const id: typeof SchemaId; + export const html: typeof SchemaHtml; + export const foreignKey: typeof SchemaForeignKey; } /** diff --git a/src/server.ts b/src/server.ts index 8f14512c..e7294fd4 100644 --- a/src/server.ts +++ b/src/server.ts @@ -10,11 +10,13 @@ import { Controller } from './controllers/controller' import PageRenderer from './controllers/page-renderer' import CORSController from './controllers/cors-controller'; import { PathHandler } from './path-handler'; +import { SessionController } from './controllers/session-controller'; import { BucketController } from './controllers/bucket-controller'; import { StatsController } from './controllers/stats-controller'; import { FileController } from './controllers/file-controller'; import { AuthController } from './controllers/auth-controller'; import { UserController } from './controllers/user-controller'; +import { AdminController } from './controllers/admin-controller'; import { ErrorController } from './controllers/error-controller'; import { CommsController } from './socket-api/comms-controller'; @@ -60,12 +62,17 @@ export class Server { controllers.push( new PageRenderer( server, config, app ) ); - // Users related - controllers.push( new CommsController( config! ) ); + // Socket manager + let comms = new CommsController( config!, server! ); + await comms.initialize(db); + + // User controllers controllers.push( new BucketController( app, config! ) ); controllers.push( new FileController( app, config! ) ); - controllers.push( new AuthController( app, config! ) ); + controllers.push( new SessionController( app, config! ) ); + controllers.push( new AuthController( app, config!, server! ) ); controllers.push( new UserController( app, config! ) ); + controllers.push( new AdminController( app, config! ) ); controllers.push( new StatsController( app, config! ) ); diff --git a/src/socket-api/comms-controller.ts b/src/socket-api/comms-controller.ts index b2ed305b..78e1eae3 100644 --- a/src/socket-api/comms-controller.ts +++ b/src/socket-api/comms-controller.ts @@ -23,16 +23,18 @@ export class CommsController extends events.EventEmitter { private _connections: ClientConnection[]; private _hashedApiKey: string; private _cfg: Modepress.IConfig; + private _serverConfig: Modepress.IServer; /** * Creates an instance of the Communication server */ - constructor( cfg: Modepress.IConfig ) { + constructor( cfg: Modepress.IConfig, server: Modepress.IServer ) { super(); CommsController.singleton = this; this._connections = []; this._cfg = cfg; + this._serverConfig = server; } /** @@ -160,6 +162,7 @@ export class CommsController extends events.EventEmitter { */ async initialize( db: mongodb.Db ): Promise { let cfg = this._cfg; + let server = this._serverConfig; // Throw error if no socket api key if ( !cfg.websocket.socketApiKey ) @@ -175,15 +178,15 @@ export class CommsController extends events.EventEmitter { }; // Create the web socket server - if ( cfg.ssl ) { + if ( server.ssl ) { winston.info( 'Creating secure socket connection', { process: process.pid } ); let httpsServer: https.Server; - const caChain = [ fs.readFileSync( cfg.sslIntermediate ), fs.readFileSync( cfg.sslRoot ) ]; - const privkey = cfg.sslKey ? fs.readFileSync( cfg.sslKey ) : null; - const theCert = cfg.sslCert ? fs.readFileSync( cfg.sslCert ) : null; + const caChain = [ fs.readFileSync( server.sslIntermediate ), fs.readFileSync( server.sslRoot ) ]; + const privkey = server.sslKey ? fs.readFileSync( server.sslKey ) : null; + const theCert = server.sslCert ? fs.readFileSync( server.sslCert ) : null; winston.info( `Attempting to start Websocket server with SSL...`, { process: process.pid } ); - httpsServer = https.createServer( { key: privkey, cert: theCert, passphrase: cfg.sslPassPhrase, ca: caChain }, processRequest ); + httpsServer = https.createServer( { key: privkey, cert: theCert, passphrase: server.sslPassPhrase, ca: caChain }, processRequest ); httpsServer.listen( cfg.websocket.port ); this._server = new ws.Server( { server: httpsServer } ); }