@ -16,13 +16,14 @@ const helmet = require('helmet');
const rateLimit = require ( 'express-rate-limit' ) ;
const uploadRouter = require ( './routers/upload' ) ;
const resourceRouter = require ( './routers/resource' ) ;
const { path , log , generateToken } = require ( './utils' ) ;
const { path , log } = require ( './utils' ) ;
const { CODE _NO _CONTENT , CODE _INTERNAL _SERVER _ERROR } = require ( './MagicNumbers.json' ) ;
//#endregion
// Set up premium frontend
const FRONTEND _NAME = 'ass-x' ; // <-- Change this to use a custom frontend
const ASS _PREMIUM = fs . existsSync ( ` ./ ${ FRONTEND _NAME } /package.json ` ) ? ( require ( 'submodule' ) , require ( ` ./ ${ FRONTEND _NAME } ` ) ) : { enabled : false } ;
log ( ` Frontend: ${ ASS _PREMIUM . enabled ? ASS _PREMIUM . brand : '<none>' } ` ) ;
//#region Variables, module setup
const app = express ( ) ;
@ -31,84 +32,50 @@ const ROUTERS = {
resource : resourceRouter
} ;
// Configure filename and location settings
let users = { } ;
let data = { } ;
// Read users and data
const users = require ( './auth' ) ;
const data = require ( './data' ) ;
log ( 'Users & data read from filesystem' ) ;
//#endregion
/ * *
* Operations to run to ensure ass can start properly
* /
function preStartup ( ) {
// Make sure data.json exists
if ( ! fs . existsSync ( path ( 'data.json' ) ) ) {
fs . writeJsonSync ( path ( 'data.json' ) , data , { spaces : 4 } ) ;
log ( 'File [data.json] created' ) ;
} else log ( 'File [data.json] exists' ) ;
// Make sure auth.json exists and generate the first key
if ( ! fs . existsSync ( path ( 'auth.json' ) ) ) {
const token = generateToken ( ) ;
users [ token ] = { username : 'ass' , count : 0 } ;
fs . writeJsonSync ( path ( 'auth.json' ) , { users } , { spaces : 4 } ) ;
log ( ` File [auth.json] created \n !! Important: save this token in a secure spot: ${ Object . keys ( users ) [ 0 ] } \n ` ) ;
} else log ( 'File [auth.json] exists' ) ;
// Read users and data
users = require ( './auth' ) ;
data = require ( './data' ) ;
log ( 'Users & data read from filesystem' ) ;
// Create thumbnails directory
fs . ensureDirSync ( path ( diskFilePath , 'thumbnails' ) ) ;
// Print frontend operating mode
log ( ` Frontend: ${ ASS _PREMIUM . enabled ? ASS _PREMIUM . brand : '<none>' } ` ) ;
}
/ * *
* Builds the router & starts the server
* /
function startup ( ) {
// Enable/disable Express features
app . enable ( 'case sensitive routing' ) ;
app . disable ( 'x-powered-by' ) ;
// Set Express variables
app . set ( 'trust proxy' , isProxied ) ;
app . set ( 'view engine' , 'pug' ) ;
// Helmet security middleware
app . use ( helmet . noSniff ( ) ) ;
app . use ( helmet . ieNoOpen ( ) ) ;
app . use ( helmet . xssFilter ( ) ) ;
app . use ( helmet . referrerPolicy ( ) ) ;
app . use ( helmet . dnsPrefetchControl ( ) ) ;
useSsl && app . use ( helmet . hsts ( { preload : true } ) ) ; // skipcq: JS-0093
// Rate limit middleware
app . use ( rateLimit ( {
windowMs : 1000 * 60 , // 60 seconds // skipcq: JS-0074
max : 90 // Limit each IP to 30 requests per windowMs // skipcq: JS-0074
} ) ) ;
// Don't process favicon requests (custom middleware)
app . use ( ( req , res , next ) => ( req . url . includes ( 'favicon.ico' ) ? res . sendStatus ( CODE _NO _CONTENT ) : next ( ) ) ) ;
// Assign routers ('/:resouceId' always needs to be LAST since it's a catch-all route)
app . use ( '/' , ROUTERS . upload ) ;
ASS _PREMIUM . enabled && app . use ( ASS _PREMIUM . endpoint , ASS _PREMIUM . router ) ; // skipcq: JS-0093
app . use ( '/:resourceId' , ( req , _ , next ) => ( req . resourceId = req . params . resourceId , next ( ) ) , ROUTERS . resource ) ; // skipcq: JS-0086, JS-0090
// Error handler
app . use ( ( [ err , , res , ] ) => {
console . error ( err ) ;
res . sendStatus ( CODE _INTERNAL _SERVER _ERROR ) ;
} ) ;
// Host the server
app . listen ( port , host , ( ) => log ( ` Server started on [ ${ host } : ${ port } ] \n Authorized users: ${ Object . keys ( users ) . length } \n Available files: ${ Object . keys ( data ) . length } ` ) ) ;
}
preStartup ( ) ;
startup ( ) ;
// Create thumbnails directory
fs . ensureDirSync ( path ( diskFilePath , 'thumbnails' ) ) ;
// Enable/disable Express features
app . enable ( 'case sensitive routing' ) ;
app . disable ( 'x-powered-by' ) ;
// Set Express variables
app . set ( 'trust proxy' , isProxied ) ;
app . set ( 'view engine' , 'pug' ) ;
// Helmet security middleware
app . use ( helmet . noSniff ( ) ) ;
app . use ( helmet . ieNoOpen ( ) ) ;
app . use ( helmet . xssFilter ( ) ) ;
app . use ( helmet . referrerPolicy ( ) ) ;
app . use ( helmet . dnsPrefetchControl ( ) ) ;
useSsl && app . use ( helmet . hsts ( { preload : true } ) ) ; // skipcq: JS-0093
// Rate limit middleware
app . use ( rateLimit ( {
windowMs : 1000 * 60 , // 60 seconds // skipcq: JS-0074
max : 90 // Limit each IP to 30 requests per windowMs // skipcq: JS-0074
} ) ) ;
// Don't process favicon requests (custom middleware)
app . use ( ( req , res , next ) => ( req . url . includes ( 'favicon.ico' ) ? res . sendStatus ( CODE _NO _CONTENT ) : next ( ) ) ) ;
// Assign routers ('/:resouceId' always needs to be LAST since it's a catch-all route)
app . use ( '/' , ROUTERS . upload ) ;
ASS _PREMIUM . enabled && app . use ( ASS _PREMIUM . endpoint , ASS _PREMIUM . router ) ; // skipcq: JS-0093
app . use ( '/:resourceId' , ( req , _ , next ) => ( req . resourceId = req . params . resourceId , next ( ) ) , ROUTERS . resource ) ; // skipcq: JS-0086, JS-0090
// Error handler
app . use ( ( [ err , , res , ] ) => {
console . error ( err ) ;
res . sendStatus ( CODE _INTERNAL _SERVER _ERROR ) ;
} ) ;
// Host the server
app . listen ( port , host , ( ) => log ( ` Server started on [ ${ host } : ${ port } ] \n Authorized users: ${ Object . keys ( users ) . length } \n Available files: ${ Object . keys ( data ) . length } ` ) ) ;