2023-02-26 22:26:09 +00:00
package proxy
import (
"net/http"
2023-04-18 15:50:12 +00:00
"regexp"
"strconv"
2023-03-10 20:59:56 +00:00
"time"
2023-04-18 15:50:12 +00:00
2023-03-25 20:15:00 +00:00
"github.com/azukaar/cosmos-server/src/user"
2023-04-18 15:50:12 +00:00
"github.com/azukaar/cosmos-server/src/utils"
2023-03-10 20:59:56 +00:00
"github.com/go-chi/httprate"
2023-04-18 15:50:12 +00:00
"github.com/gorilla/mux"
2023-02-26 22:26:09 +00:00
)
2023-05-01 11:59:46 +00:00
func tokenMiddleware ( enabled bool , adminOnly bool ) func ( next http . Handler ) http . Handler {
2023-03-18 19:59:32 +00:00
return func ( next http . Handler ) http . Handler {
return http . HandlerFunc ( func ( w http . ResponseWriter , r * http . Request ) {
2023-04-30 12:03:14 +00:00
r . Header . Del ( "x-cosmos-user" )
r . Header . Del ( "x-cosmos-role" )
r . Header . Del ( "x-cosmos-mfa" )
2023-04-18 15:50:12 +00:00
2023-03-18 19:59:32 +00:00
u , err := user . RefreshUserToken ( w , r )
2023-04-18 15:50:12 +00:00
2023-03-18 19:59:32 +00:00
if err != nil {
return
}
2023-04-18 15:50:12 +00:00
2023-03-18 19:59:32 +00:00
r . Header . Set ( "x-cosmos-user" , u . Nickname )
r . Header . Set ( "x-cosmos-role" , strconv . Itoa ( ( int ) ( u . Role ) ) )
2023-04-30 12:03:14 +00:00
r . Header . Set ( "x-cosmos-mfa" , strconv . Itoa ( ( int ) ( u . MFAState ) ) )
2023-04-18 15:50:12 +00:00
2023-03-18 19:59:32 +00:00
ogcookies := r . Header . Get ( "Cookie" )
cookieRemoveRegex := regexp . MustCompile ( ` jwttoken=[^;]*; ` )
cookies := cookieRemoveRegex . ReplaceAllString ( ogcookies , "" )
r . Header . Set ( "Cookie" , cookies )
// Replace the token with a application speicfic one
r . Header . Set ( "x-cosmos-token" , "1234567890" )
2023-05-01 11:59:46 +00:00
if enabled && adminOnly {
2023-05-01 12:07:01 +00:00
if errT := utils . AdminOnlyWithRedirect ( w , r ) ; errT != nil {
return
}
2023-05-01 11:59:46 +00:00
} else if enabled {
2023-05-01 12:07:01 +00:00
if errT := utils . LoggedInOnlyWithRedirect ( w , r ) ; errT != nil {
return
}
2023-03-18 19:59:32 +00:00
}
next . ServeHTTP ( w , r )
} )
}
}
2023-03-31 19:19:38 +00:00
func RouterGen ( route utils . ProxyRouteConfig , router * mux . Router , destination http . Handler ) * mux . Route {
2023-06-17 17:08:26 +00:00
origin := router . NewRoute ( )
2023-02-26 22:26:09 +00:00
2023-04-18 15:50:12 +00:00
if route . UseHost {
2023-02-26 22:26:09 +00:00
origin = origin . Host ( route . Host )
}
2023-04-18 17:55:59 +00:00
2023-04-18 15:50:12 +00:00
if route . UsePathPrefix {
if route . PathPrefix != "" && route . PathPrefix [ 0 ] != '/' {
2023-03-31 19:19:38 +00:00
utils . Error ( "PathPrefix must start with a /" , nil )
}
2023-02-26 22:26:09 +00:00
origin = origin . PathPrefix ( route . PathPrefix )
2023-03-12 18:17:28 +00:00
}
2023-04-18 17:55:59 +00:00
2023-04-18 15:50:12 +00:00
if route . UsePathPrefix && route . StripPathPrefix {
if route . PathPrefix != "" && route . PathPrefix [ 0 ] != '/' {
2023-03-31 19:19:38 +00:00
utils . Error ( "PathPrefix must start with a /" , nil )
}
destination = http . StripPrefix ( route . PathPrefix , destination )
2023-02-26 22:26:09 +00:00
}
2023-07-19 10:27:48 +00:00
for filter := range route . AddionalFilters {
if route . AddionalFilters [ filter ] . Type == "header" {
origin = origin . Headers ( route . AddionalFilters [ filter ] . Name , route . AddionalFilters [ filter ] . Value )
} else if route . AddionalFilters [ filter ] . Type == "query" {
origin = origin . Queries ( route . AddionalFilters [ filter ] . Name , route . AddionalFilters [ filter ] . Value )
} else if route . AddionalFilters [ filter ] . Type == "method" {
origin = origin . Methods ( route . AddionalFilters [ filter ] . Value )
} else {
utils . Error ( "Unknown filter type: " + route . AddionalFilters [ filter ] . Type , nil )
}
}
2023-04-18 17:55:59 +00:00
2023-04-18 15:50:12 +00:00
destination = SmartShieldMiddleware ( route . SmartShield ) ( destination )
2023-03-10 20:59:56 +00:00
originCORS := route . CORSOrigin
if originCORS == "" {
if route . UseHost {
originCORS = route . Host
} else {
originCORS = utils . GetMainConfig ( ) . HTTPConfig . Hostname
}
}
2023-04-18 15:50:12 +00:00
if route . UsePathPrefix && ! route . StripPathPrefix && ( route . Mode == "STATIC" || route . Mode == "SPA" ) {
2023-03-31 19:19:38 +00:00
utils . Warn ( "PathPrefix is used, but StripPathPrefix is false. The route mode is " + ( string ) ( route . Mode ) + ". This will likely cause issues with the route. Ignore this warning if you know what you are doing." )
}
2023-04-18 15:50:12 +00:00
2023-04-04 20:54:35 +00:00
timeout := route . Timeout
2023-04-18 15:50:12 +00:00
2023-05-10 17:17:11 +00:00
if ( ! utils . GetMainConfig ( ) . HTTPConfig . AcceptAllInsecureHostname ) {
destination = utils . EnsureHostname ( destination )
}
2023-04-18 15:50:12 +00:00
if timeout > 0 {
2023-04-04 20:54:35 +00:00
destination = utils . MiddlewareTimeout ( timeout * time . Millisecond ) ( destination )
}
2023-03-31 19:19:38 +00:00
2023-04-04 20:54:35 +00:00
throttlePerMinute := route . ThrottlePerMinute
2023-04-18 15:50:12 +00:00
if throttlePerMinute > 0 {
2023-04-04 20:54:35 +00:00
throtthleTime := time . Minute
2023-04-18 15:50:12 +00:00
destination = httprate . Limit ( throttlePerMinute , throtthleTime ,
2023-03-10 20:59:56 +00:00
httprate . WithKeyFuncs ( httprate . KeyByIP ) ,
httprate . WithLimitHandler ( func ( w http . ResponseWriter , r * http . Request ) {
utils . Error ( "Too many requests. Throttling" , nil )
2023-04-18 15:50:12 +00:00
utils . HTTPError ( w , "Too many requests" ,
2023-03-10 20:59:56 +00:00
http . StatusTooManyRequests , "HTTP003" )
2023-04-18 15:50:12 +00:00
return
2023-03-10 20:59:56 +00:00
} ) ,
2023-04-04 20:54:35 +00:00
) ( destination )
}
2023-04-18 17:55:59 +00:00
if route . MaxBandwith > 0 {
destination = utils . BandwithLimiterMiddleware ( route . MaxBandwith ) ( destination )
}
2023-04-30 12:03:14 +00:00
if route . BlockCommonBots {
destination = BotDetectionMiddleware ( destination )
}
if route . BlockAPIAbuse {
destination = utils . BlockPostWithoutReferer ( destination )
}
2023-05-01 11:59:46 +00:00
destination = tokenMiddleware ( route . AuthEnabled , route . AdminOnly ) ( utils . CORSHeader ( originCORS ) ( ( destination ) ) )
2023-04-30 12:03:14 +00:00
origin . Handler ( destination )
2023-03-31 19:19:38 +00:00
2023-04-18 15:50:12 +00:00
utils . Log ( "Added route: [" + ( string ) ( route . Mode ) + "] " + route . Host + route . PathPrefix + " to " + route . Target + "" )
2023-02-26 22:26:09 +00:00
return origin
2023-04-18 15:50:12 +00:00
}