2023-02-12 07:40:49 +00:00
import "dotenv/config" ;
2022-07-08 19:17:56 +01:00
import express from "express" ;
2022-07-10 15:04:03 +01:00
import cors from "cors" ;
2022-07-08 19:17:56 +01:00
import rateLimit from "express-rate-limit" ;
2023-04-29 12:40:08 +01:00
import { randomBytes } from "crypto" ;
2023-04-29 16:30:59 +01:00
const ipSalt = randomBytes ( 64 ) . toString ( 'hex' ) ;
2022-07-08 19:17:56 +01:00
2023-03-09 18:41:17 +00:00
import path from 'path' ;
import { fileURLToPath } from 'url' ;
const _ _filename = fileURLToPath ( import . meta . url ) ;
const _ _dirname = path . dirname ( _ _filename ) . slice ( 0 , - 4 ) ; // go up another level (get rid of src/)
2023-02-12 07:40:49 +00:00
import { getCurrentBranch , shortCommit } from "./modules/sub/currentCommit.js" ;
2023-02-09 14:45:17 +00:00
import { appName , genericUserAgent , version } from "./modules/config.js" ;
2022-07-08 19:17:56 +01:00
import { getJSON } from "./modules/api.js" ;
2023-04-09 05:58:23 +01:00
import { apiJSON , checkJSONPost , getIP , languageCode } from "./modules/sub/utils.js" ;
2022-12-17 11:09:49 +00:00
import { Bright , Cyan , Green , Red } from "./modules/sub/consoleText.js" ;
2022-07-08 19:17:56 +01:00
import stream from "./modules/stream/stream.js" ;
2022-08-12 14:36:19 +01:00
import loc from "./localization/manager.js" ;
2022-07-30 10:01:54 +01:00
import { buildFront } from "./modules/build.js" ;
2022-09-11 16:04:06 +01:00
import { changelogHistory } from "./modules/pageRender/onDemand.js" ;
2023-01-13 18:34:48 +00:00
import { sha256 } from "./modules/sub/crypto.js" ;
2023-03-09 18:41:17 +00:00
import findRendered from "./modules/pageRender/findRendered.js" ;
2022-07-08 19:17:56 +01:00
2023-04-29 16:30:59 +01:00
if ( process . env . selfURL && process . env . port ) {
2023-04-09 05:42:18 +01:00
const commitHash = shortCommit ( ) ;
const branch = getCurrentBranch ( ) ;
const app = express ( ) ;
2022-07-08 19:17:56 +01:00
2023-04-09 05:42:18 +01:00
app . disable ( 'x-powered-by' ) ;
2023-04-08 11:58:44 +01:00
2023-04-09 05:42:18 +01:00
const corsConfig = process . env . cors === '0' ? { origin : process . env . selfURL , optionsSuccessStatus : 200 } : { } ;
2022-07-10 15:04:03 +01:00
2022-07-08 19:17:56 +01:00
const apiLimiter = rateLimit ( {
2023-02-12 07:40:49 +00:00
windowMs : 60000 ,
2023-03-24 18:14:44 +00:00
max : 25 ,
2023-03-09 18:41:17 +00:00
standardHeaders : false ,
2022-07-08 19:17:56 +01:00
legacyHeaders : false ,
2023-04-29 16:30:59 +01:00
keyGenerator : ( req , res ) => sha256 ( getIP ( req ) , ipSalt ) ,
2022-07-08 19:17:56 +01:00
handler : ( req , res , next , opt ) => {
2022-07-24 11:54:05 +01:00
res . status ( 429 ) . json ( { "status" : "error" , "text" : loc ( languageCode ( req ) , 'ErrorRateLimit' ) } ) ;
2023-03-31 06:20:49 +01:00
return ;
2022-07-08 19:17:56 +01:00
}
2022-12-06 19:21:07 +00:00
} ) ;
2022-07-08 19:17:56 +01:00
const apiLimiterStream = rateLimit ( {
2023-02-12 07:40:49 +00:00
windowMs : 60000 ,
2023-03-24 18:14:44 +00:00
max : 28 ,
2023-03-09 18:41:17 +00:00
standardHeaders : false ,
2022-07-08 19:17:56 +01:00
legacyHeaders : false ,
2023-04-29 16:30:59 +01:00
keyGenerator : ( req , res ) => sha256 ( getIP ( req ) , ipSalt ) ,
2022-07-08 19:17:56 +01:00
handler : ( req , res , next , opt ) => {
2022-07-24 11:54:05 +01:00
res . status ( 429 ) . json ( { "status" : "error" , "text" : loc ( languageCode ( req ) , 'ErrorRateLimit' ) } ) ;
2023-03-31 06:20:49 +01:00
return ;
2022-07-08 19:17:56 +01:00
}
2022-12-06 19:21:07 +00:00
} ) ;
2022-07-08 19:17:56 +01:00
2023-03-09 18:41:17 +00:00
await buildFront ( commitHash , branch ) ;
2023-04-08 11:58:44 +01:00
app . use ( '/api/:type' , cors ( corsConfig ) ) ;
2023-03-24 18:14:44 +00:00
app . use ( '/api/json' , apiLimiter ) ;
2022-07-08 19:17:56 +01:00
app . use ( '/api/stream' , apiLimiterStream ) ;
2023-03-24 18:14:44 +00:00
app . use ( '/api/onDemand' , apiLimiter ) ;
2022-07-30 10:01:54 +01:00
app . use ( '/' , express . static ( './min' ) ) ;
app . use ( '/' , express . static ( './src/front' ) ) ;
2022-07-08 19:17:56 +01:00
app . use ( ( req , res , next ) => {
2023-04-09 05:42:18 +01:00
try { decodeURIComponent ( req . path ) } catch ( e ) { return res . redirect ( '/' ) }
2022-07-08 19:17:56 +01:00
next ( ) ;
} ) ;
2023-02-09 14:45:17 +00:00
app . use ( ( req , res , next ) => {
2023-03-09 18:41:17 +00:00
if ( req . header ( "user-agent" ) && req . header ( "user-agent" ) . includes ( "Trident" ) ) res . destroy ( ) ;
2023-02-09 14:45:17 +00:00
next ( ) ;
} ) ;
2022-11-12 16:40:11 +00:00
app . use ( '/api/json' , express . json ( {
verify : ( req , res , buf ) => {
try {
JSON . parse ( buf ) ;
if ( buf . length > 720 ) throw new Error ( ) ;
2023-03-31 06:20:49 +01:00
if ( String ( req . header ( 'Content-Type' ) ) !== "application/json" ) {
res . status ( 400 ) . json ( { 'status' : 'error' , 'text' : 'invalid content type header' } ) ;
return ;
}
if ( String ( req . header ( 'Accept' ) ) !== "application/json" ) {
res . status ( 400 ) . json ( { 'status' : 'error' , 'text' : 'invalid accept header' } ) ;
return ;
}
2022-11-12 16:40:11 +00:00
} catch ( e ) {
2023-03-31 06:20:49 +01:00
res . status ( 400 ) . json ( { 'status' : 'error' , 'text' : 'invalid json body.' } ) ;
return ;
2022-11-12 16:40:11 +00:00
}
}
} ) ) ;
2023-02-12 07:40:49 +00:00
2023-03-28 23:05:06 +01:00
app . post ( '/api/json' , async ( req , res ) => {
2022-11-12 16:40:11 +00:00
try {
2023-04-29 16:30:59 +01:00
let ip = sha256 ( getIP ( req ) , ipSalt ) ;
2023-02-26 16:49:25 +00:00
let lang = languageCode ( req ) ;
2023-03-09 18:41:17 +00:00
let j = apiJSON ( 0 , { t : "Bad request" } ) ;
try {
let request = req . body ;
if ( request . url ) {
request . dubLang = request . dubLang ? lang : false ;
let chck = checkJSONPost ( request ) ;
if ( chck ) chck [ "ip" ] = ip ;
j = chck ? await getJSON ( chck [ "url" ] , lang , chck ) : apiJSON ( 0 , { t : loc ( lang , 'ErrorCouldntFetch' ) } ) ;
} else {
j = apiJSON ( 0 , { t : loc ( lang , 'ErrorNoLink' ) } ) ;
}
} catch ( e ) {
j = apiJSON ( 0 , { t : loc ( lang , 'ErrorCantProcess' ) } ) ;
2022-11-12 16:40:11 +00:00
}
2023-03-09 18:41:17 +00:00
res . status ( j . status ) . json ( j . body ) ;
2023-03-31 06:20:49 +01:00
return ;
2022-11-12 16:40:11 +00:00
} catch ( e ) {
2023-04-02 16:53:23 +01:00
res . destroy ( ) ;
return
2022-11-12 16:40:11 +00:00
}
} ) ;
2023-02-12 07:40:49 +00:00
2023-03-28 23:05:06 +01:00
app . get ( '/api/:type' , ( req , res ) => {
2022-07-08 19:17:56 +01:00
try {
2023-04-29 16:30:59 +01:00
let ip = sha256 ( getIP ( req ) , ipSalt ) ;
2022-07-08 19:17:56 +01:00
switch ( req . params . type ) {
case 'stream' :
if ( req . query . p ) {
res . status ( 200 ) . json ( { "status" : "continue" } ) ;
2023-03-31 06:20:49 +01:00
return ;
2022-11-12 16:40:11 +00:00
} else if ( req . query . t && req . query . h && req . query . e ) {
2022-08-14 18:09:06 +01:00
stream ( res , ip , req . query . t , req . query . h , req . query . e ) ;
2022-07-08 19:17:56 +01:00
} else {
2022-09-03 16:32:39 +01:00
let j = apiJSON ( 0 , { t : "no stream id" } )
2022-07-08 19:17:56 +01:00
res . status ( j . status ) . json ( j . body ) ;
2023-03-31 06:20:49 +01:00
return ;
2022-07-08 19:17:56 +01:00
}
break ;
2022-09-11 16:04:06 +01:00
case 'onDemand' :
if ( req . query . blockId ) {
let blockId = req . query . blockId . slice ( 0 , 3 )
let r , j ;
switch ( blockId ) {
case "0" :
r = changelogHistory ( ) ;
j = r ? apiJSON ( 3 , { t : r } ) : apiJSON ( 0 , { t : "couldn't render this block" } )
break ;
default :
j = apiJSON ( 0 , { t : "couldn't find a block with this id" } )
break ;
}
res . status ( j . status ) . json ( j . body ) ;
} else {
let j = apiJSON ( 0 , { t : "no block id" } )
res . status ( j . status ) . json ( j . body ) ;
}
break ;
2022-07-08 19:17:56 +01:00
default :
2022-09-11 16:04:06 +01:00
let j = apiJSON ( 0 , { t : "unknown response type" } )
2022-07-08 19:17:56 +01:00
res . status ( j . status ) . json ( j . body ) ;
break ;
}
} catch ( e ) {
2023-03-31 06:20:49 +01:00
res . status ( 500 ) . json ( { 'status' : 'error' , 'text' : loc ( languageCode ( req ) , 'ErrorCantProcess' ) } ) ;
return ;
2022-07-08 19:17:56 +01:00
}
} ) ;
2022-09-01 14:51:18 +01:00
app . get ( "/api" , ( req , res ) => {
2022-07-08 19:17:56 +01:00
res . redirect ( '/api/json' )
} ) ;
2023-04-09 03:40:07 +01:00
app . get ( "/status" , ( req , res ) => {
res . status ( 200 ) . end ( )
} ) ;
2022-09-01 14:51:18 +01:00
app . get ( "/" , ( req , res ) => {
2023-03-09 18:41:17 +00:00
res . sendFile ( ` ${ _ _dirname } / ${ findRendered ( languageCode ( req ) , req . header ( 'user-agent' ) ? req . header ( 'user-agent' ) : genericUserAgent ) } ` ) ;
2022-07-08 19:17:56 +01:00
} ) ;
2022-09-01 14:51:18 +01:00
app . get ( "/favicon.ico" , ( req , res ) => {
2022-07-08 19:17:56 +01:00
res . redirect ( '/icons/favicon.ico' ) ;
} ) ;
2022-09-01 14:51:18 +01:00
app . get ( "/*" , ( req , res ) => {
2022-07-08 19:17:56 +01:00
res . redirect ( '/' )
} ) ;
2023-02-12 07:40:49 +00:00
2022-07-08 19:17:56 +01:00
app . listen ( process . env . port , ( ) => {
2022-12-17 11:40:20 +00:00
let startTime = new Date ( ) ;
2023-02-12 07:40:49 +00:00
console . log ( ` \n ${ Cyan ( appName ) } ${ Bright ( ` v. ${ version } - ${ commitHash } ( ${ branch } ) ` ) } \n Start time: ${ Bright ( ` ${ startTime . toUTCString ( ) } ( ${ Math . floor ( new Date ( ) . getTime ( ) ) } ) ` ) } \n \n URL: ${ Cyan ( ` ${ process . env . selfURL } ` ) } \n Port: ${ process . env . port } \n ` )
2023-04-09 06:11:06 +01:00
} )
2022-07-08 19:17:56 +01:00
} else {
2023-04-09 06:12:11 +01:00
console . log ( Red ( ` cobalt hasn't been configured yet or configuration is invalid. \n ` ) + Bright ( ` please run the setup script to fix this: ` ) + Green ( ` npm run setup ` ) ) ;
2022-08-01 16:48:37 +01:00
}