import { appendFileSync } from "fs" ; import { IncomingMessage , ServerResponse } from "http" ; import { Writable } from "stream" ; import { format } from "util" ; import * as WebSocket from "ws" ; import { ServerConfig , ServerConfig_AccessOptions , Config , OptionsConfig } from "./server-config" ; import { parseHostList , testAddress , resolvePath , PathResolverResult , as , DirectoryIndexOptions } from "./server-types" ; import { checkCookieAuth } from "./cookies" ; import { parse } from "url" ; import { createLogWritable } from './logger' ; import { generateDirectoryListing } from './generate-directory-listing' ; export class RequestEvent { handled : boolean = false ; username : string = "" ; authAccountKey : string = "" ; localAddressPermissionsKey : string = "" ; treeHostIndex : number = 0 ; debugOutput : Writable ; network : { iface : string ; host : string | undefined ; addr : string ; } ; client : WebSocket = undefined as any ; response : ServerResponse = undefined as any ; url : string ; constructor ( settings , request , iface , type , response ) ; constructor ( settings , request , iface , type , response ) ; constructor ( public settings , public request , iface , public type , response ) { let host = request . headers . host ; let addr = request . socket . localAddress ; this . network = { host , addr , iface } ; this . debugOutput = RequestEvent . MakeDebugOutput ( settings ) ; this . url = this . request . url || "/" ; switch ( type ) { case "client" : this . client = response as WebSocket ; break ; case "response" : this . response = response as ServerResponse ; break ; default : throw new Error ( "Invalid response type" ) ; } } async requestHandlerHostLevelChecks < T extends RequestEvent > ( preflighter ? ) { { let localAddress = this . request . socket . localAddress ; let keys = Object . keys ( this . settings . bindInfo . localAddressPermissions ) ; let isLocalhost = testAddress ( localAddress , "127.0.0.1" , 8 ) ; let matches = parseHostList ( keys ) ( localAddress ) ; if ( isLocalhost && keys . indexOf ( "localhost" ) !== - 1 ) { this . localAddressPermissionsKey = "localhost" ; } else if ( matches . lastMatch !== - 1 ) { this . localAddressPermissionsKey = keys [ matches . lastMatch ] ; } else { this . localAddressPermissionsKey = "*" ; } } this . treeHostIndex = 0 ; let { registerNotice } = this . settings . bindInfo . localAddressPermissions [ this . localAddressPermissionsKey ] ; let auth = checkCookieAuth ( this . request , this . settings ) ; if ( auth ) { this . authAccountKey = auth [ 0 ] ; this . username = auth [ 1 ] ; } let ev2 = await ( preflighter ? preflighter ( this ) : Promise . resolve ( this ) ) ; if ( ev2 . handled ) return ev2 as any ; if ( ! this . response !== ! ev2 . response || ! this . client !== ! ev2 . client ) throw new Error ( "DEV: Request Event types got mixed up" ) ; if ( ev2 . treeHostIndex > ev2 . settings . tree . length - 1 ) throw format ( "treeHostIndex of %s is not within array length of %s" , ev2 . treeHostIndex , ev2 . settings . tree . length ) ; if ( ! ev2 . settings . bindInfo . localAddressPermissions [ ev2 . localAddressPermissionsKey ] ) throw format ( "localAddressPermissions key of %s does not exist" , ev2 . localAddressPermissionsKey ) ; if ( ev2 . authAccountKey && ! ev2 . settings . authAccounts [ ev2 . authAccountKey ] ) throw format ( "authAccounts key of %s does not exist" , ev2 . authAccountKey ) ; return ev2 as any ; } resolvePath ( ) { let root = this . settings . tree [ this . treeHostIndex ] ; let pathname = ( parse ( this . request . url as string ) . pathname || "/" ) . split ( "/" ) ; return resolvePath ( pathname , root ) ; } get allow ( ) : ServerConfig_AccessOptions { if ( this . authAccountKey ) { return this . settings . authAccounts [ this . authAccountKey ] . permissions ; } else { return this . settings . bindInfo . localAddressPermissions [ this . localAddressPermissionsKey ] ; } } get hostRoot ( ) { return this . settings . tree [ this . treeHostIndex ] ; } close ( code , message ? ) { if ( this . type === "response" ) { this . response . writeHead ( code ) ; if ( message ) this . response . write ( message ) ; this . response . end ( ) ; } else if ( this . type === "client" ) { this . client . close ( code , message ) ; } } getTreeOptions ( result ) { let ancestry = [ ... result . ancestry , result . item ] ; let options = { auth : { $element : "auth" , authError : 403 , authList : null } , putsaver : { $element : "putsaver" , ... this . settings . putsaver } , index : { $element : "index" , defaultType : this . settings . directoryIndex . defaultType , indexFile : [ ] , indexExts : [ ] , } , upload : { $element : "upload" , maxFileSize : 200 * 1024 * 1024 } } ; ancestry . forEach ( e => { e . $options && e . $options . forEach ( f => { if ( f . $element === "auth" || f . $element === "putsaver" || f . $element === "index" || f . $element === "upload" ) { Object . keys ( f ) . forEach ( k => { if ( f [ k ] === undefined ) return ; options [ f . $element ] [ k ] = f [ k ] ; } ) ; } } ) ; } ) ; return options ; } static MakeDebugOutput ( settings ) { return process . stderr ; } }