@ -12,6 +12,7 @@ const { host, port, domain, useSsl, resourceIdSize, gfyIdSize, resourceIdType, i
//#region Imports
const fs = require ( 'fs-extra' ) ;
const express = require ( 'express' ) ;
const escape = require ( 'escape-html' ) ;
const useragent = require ( 'express-useragent' ) ;
const rateLimit = require ( "express-rate-limit" ) ;
const fetch = require ( 'node-fetch' ) ;
@ -81,15 +82,6 @@ function startup() {
// Don't process favicon requests
app . use ( ( req , res , next ) => req . url . includes ( 'favicon.ico' ) ? res . sendStatus ( 204 ) : next ( ) ) ;
// Middleware for parsing the resource ID and handling 404
app . use ( '/:resourceId' , ( req , res , next ) => {
// Parse the resource ID
req . ass = { resourceId : req . params . resourceId . split ( '.' ) [ 0 ] } ;
// If the ID is invalid, return 404. Otherwise, continue normally
( ! req . ass . resourceId || ! data [ req . ass . resourceId ] ) ? res . sendStatus ( 404 ) : next ( ) ;
} ) ;
// Index
app . get ( '/' , ( _req , res ) => fs . readFile ( path ( 'README.md' ) ) . then ( ( bytes ) => bytes . toString ( ) ) . then ( marked ) . then ( ( data ) => res . render ( 'index' , { data } ) ) ) ;
@ -99,6 +91,12 @@ function startup() {
max : 30 // Limit each IP to 30 requests per windowMs
} ) ) ;
// Block unauthorized requests and attempt token sanitization
app . post ( '/' , ( req , res , next ) => {
req . headers . authorization = req . headers . authorization . replace ( /[^\da-z]/gi , '' ) ;
! verify ( req , users ) ? res . sendStatus ( 401 ) : next ( ) ;
} ) ;
// Upload file (local & S3)
s3enabled
? app . post ( '/' , ( req , res , next ) => uploadS3 ( req , res , ( error ) => ( ( error ) && console . error ( error ) , next ( ) ) ) )
@ -141,9 +139,6 @@ function startup() {
// Process uploaded file
app . post ( '/' , ( req , res ) => {
// Prevent uploads from unauthorized clients
if ( ! verify ( req , users ) ) return res . sendStatus ( 401 ) ;
// Load overrides
let trueDomain = getTrueDomain ( req . headers [ "x-ass-domain" ] ) ;
let generator = req . headers [ "x-ass-access" ] || resourceIdType ;
@ -152,8 +147,7 @@ function startup() {
req . file . timestamp = DateTime . now ( ) . toMillis ( ) ;
// Keep track of the token that uploaded the resource
let uploadToken = req . headers . authorization ;
req . file . token = uploadToken ;
req . file . token = req . headers . authorization ;
// Attach any embed overrides, if necessary
req . file . opengraph = {
@ -173,7 +167,7 @@ function startup() {
// Log the upload
let logInfo = ` ${ req . file . originalname } ( ${ req . file . mimetype } ) ` ;
log ( ` Uploaded: ${ logInfo } (user: ${ users [ uploadToken] ? users [ uploadToke n] . username : '<token-only>' } ) ` ) ;
log ( ` Uploaded: ${ logInfo } (user: ${ users [ req. headers . authorization ] ? users [ req . headers . authorizatio n] . username : '<token-only>' } ) ` ) ;
// Build the URLs
let resourceUrl = ` ${ getTrueHttp ( ) } ${ trueDomain } / ${ resourceId } ` ;
@ -206,18 +200,27 @@ function startup() {
}
// Also update the users upload count
if ( ! users [ uploadToke n] ) {
if ( ! users [ req. headers . authorizatio n] ) {
let generator = ( ) => generateId ( 'random' , 20 , null ) ;
let username = generator ( ) ;
while ( Object . values ( users ) . findIndex ( ( user ) => user . username == username ) != - 1 )
username = generator ( ) ;
users [ uploadToke n] = { username , count : 0 } ;
users [ req. headers . authorizatio n] = { username , count : 0 } ;
}
users [ uploadToke n] . count += 1 ;
users [ req. headers . authorizatio n] . count += 1 ;
fs . writeJsonSync ( path ( 'auth.json' ) , { users } , { spaces : 4 } )
} ) ;
} ) ;
// Middleware for parsing the resource ID and handling 404
app . use ( '/:resourceId' , ( req , res , next ) => {
// Parse the resource ID
req . ass = { resourceId : escape ( req . params . resourceId ) . split ( '.' ) [ 0 ] } ;
// If the ID is invalid, return 404. Otherwise, continue normally
( ! req . ass . resourceId || ! data [ req . ass . resourceId ] ) ? res . sendStatus ( 404 ) : next ( ) ;
} ) ;
// View file
app . get ( '/:resourceId' , ( req , res ) => {
let resourceId = req . ass . resourceId ;
@ -271,8 +274,8 @@ function startup() {
// Delete file
app . get ( '/:resourceId/delete/:deleteId' , ( req , res ) => {
let resourceId = req . param s. resourceId ;
let deleteId = req. params . deleteId ;
let resourceId = req . as s. resourceId ;
let deleteId = escape( req. params . deleteId ) ;
let fileData = data [ resourceId ] ;
// If the delete ID doesn't match, don't delete the file