[release] v0.12.0-unstable32
This commit is contained in:
parent
bdfcf0a2bf
commit
6a5f9b74fe
|
@ -1,4 +1,6 @@
|
||||||
|
import { ArrowDownOutlined } from "@ant-design/icons";
|
||||||
import { Button } from "@mui/material";
|
import { Button } from "@mui/material";
|
||||||
|
import ResponsiveButton from "../components/responseiveButton";
|
||||||
|
|
||||||
export const DownloadFile = ({ filename, content, contentGetter, label }) => {
|
export const DownloadFile = ({ filename, content, contentGetter, label }) => {
|
||||||
const downloadFile = async () => {
|
const downloadFile = async () => {
|
||||||
|
@ -34,8 +36,13 @@ export const DownloadFile = ({ filename, content, contentGetter, label }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Button onClick={downloadFile}>
|
<ResponsiveButton
|
||||||
|
color="primary"
|
||||||
|
onClick={downloadFile}
|
||||||
|
variant={"outlined"}
|
||||||
|
startIcon={<ArrowDownOutlined />}
|
||||||
|
>
|
||||||
{label}
|
{label}
|
||||||
</Button>
|
</ResponsiveButton>
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -78,13 +78,6 @@ const ConfigManagement = () => {
|
||||||
}}
|
}}
|
||||||
label={'Purge Metrics Dashboard'}
|
label={'Purge Metrics Dashboard'}
|
||||||
content={'Are you sure you want to purge all the metrics data from the dashboards?'} />
|
content={'Are you sure you want to purge all the metrics data from the dashboards?'} />
|
||||||
|
|
||||||
<DownloadFile
|
|
||||||
filename={'backup.cosmos-compose.json'}
|
|
||||||
label={'Download Docker Backup'}
|
|
||||||
contentGetter={API.config.getBackup}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
{config && <>
|
{config && <>
|
||||||
|
|
|
@ -11,18 +11,35 @@ const ProxyDashboard = ({ xAxis, zoom, setZoom, slot, metrics }) => {
|
||||||
return (<>
|
return (<>
|
||||||
|
|
||||||
<Grid container rowSpacing={4.5} columnSpacing={2.75} >
|
<Grid container rowSpacing={4.5} columnSpacing={2.75} >
|
||||||
<Grid item xs={12} md={7} lg={8}>
|
<Grid item xs={12} md={6} lg={6}>
|
||||||
<PlotComponent xAxis={xAxis} zoom={zoom} setZoom={setZoom} slot={slot} title={'Requests'} data={[
|
<PlotComponent xAxis={xAxis} zoom={zoom} setZoom={setZoom} slot={slot} title={'Requests Resources'} data={[
|
||||||
metrics["cosmos.proxy.all.time"],
|
metrics["cosmos.proxy.all.time"],
|
||||||
|
metrics["cosmos.proxy.all.bytes"],
|
||||||
|
]} />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<Grid item xs={12} md={6} lg={6}>
|
||||||
|
<PlotComponent xAxis={xAxis} zoom={zoom} setZoom={setZoom} slot={slot} title={'Requests Responses'} data={[
|
||||||
metrics["cosmos.proxy.all.success"],
|
metrics["cosmos.proxy.all.success"],
|
||||||
metrics["cosmos.proxy.all.error"],
|
metrics["cosmos.proxy.all.error"],
|
||||||
]} />
|
]} />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<TableComponent xAxis={xAxis} zoom={zoom} setZoom={setZoom} slot={slot} title="Containers - Resources" data={
|
|
||||||
|
<TableComponent xAxis={xAxis} zoom={zoom} setZoom={setZoom} slot={slot} title="Requests Per URLs" data={
|
||||||
Object.keys(metrics).filter((key) => key.startsWith("cosmos.proxy.route.")).map((key) => metrics[key])
|
Object.keys(metrics).filter((key) => key.startsWith("cosmos.proxy.route.")).map((key) => metrics[key])
|
||||||
} />
|
} />
|
||||||
|
|
||||||
|
<Grid item xs={12} md={4} lg={4}>
|
||||||
|
<PlotComponent xAxis={xAxis} zoom={zoom} setZoom={setZoom} slot={slot} title={'Blocked Requests'} data={[
|
||||||
|
metrics["cosmos.proxy.all.blocked"],
|
||||||
|
]} />
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
|
||||||
|
<TableComponent xAxis={xAxis} zoom={zoom} setZoom={setZoom} slot={slot} title="Reasons For Blocked Requests" data={
|
||||||
|
Object.keys(metrics).filter((key) => key.startsWith("cosmos.proxy.blocked.")).map((key) => metrics[key])
|
||||||
|
} />
|
||||||
</Grid>
|
</Grid>
|
||||||
</>)
|
</>)
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ import DockerComposeImport from './containers/docker-compose';
|
||||||
import { ContainerNetworkWarning } from '../../components/containers';
|
import { ContainerNetworkWarning } from '../../components/containers';
|
||||||
import { ServAppIcon } from '../../utils/servapp-icon';
|
import { ServAppIcon } from '../../utils/servapp-icon';
|
||||||
import MiniPlotComponent from '../dashboard/components/mini-plot';
|
import MiniPlotComponent from '../dashboard/components/mini-plot';
|
||||||
|
import { DownloadFile } from '../../api/downloadButton';
|
||||||
|
|
||||||
const Item = styled(Paper)(({ theme }) => ({
|
const Item = styled(Paper)(({ theme }) => ({
|
||||||
backgroundColor: theme.palette.mode === 'dark' ? '#1A2027' : '#fff',
|
backgroundColor: theme.palette.mode === 'dark' ? '#1A2027' : '#fff',
|
||||||
|
@ -152,6 +153,11 @@ const ServApps = () => {
|
||||||
>Start ServApp</ResponsiveButton>
|
>Start ServApp</ResponsiveButton>
|
||||||
</Link>
|
</Link>
|
||||||
<DockerComposeImport refresh={refreshServApps}/>
|
<DockerComposeImport refresh={refreshServApps}/>
|
||||||
|
<DownloadFile
|
||||||
|
filename={'backup.cosmos-compose.json'}
|
||||||
|
label={'Export Docker Backup'}
|
||||||
|
contentGetter={API.config.getBackup}
|
||||||
|
/>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|
||||||
<Grid2 container spacing={{xs: 1, sm: 1, md: 2 }}>
|
<Grid2 container spacing={{xs: 1, sm: 1, md: 2 }}>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "cosmos-server",
|
"name": "cosmos-server",
|
||||||
"version": "0.12.0-unstable31",
|
"version": "0.12.0-unstable32",
|
||||||
"description": "",
|
"description": "",
|
||||||
"main": "test-server.js",
|
"main": "test-server.js",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
|
|
|
@ -153,11 +153,14 @@ func SecureAPI(userRouter *mux.Router, public bool) {
|
||||||
}
|
}
|
||||||
userRouter.Use(proxy.SmartShieldMiddleware(
|
userRouter.Use(proxy.SmartShieldMiddleware(
|
||||||
"__COSMOS",
|
"__COSMOS",
|
||||||
utils.SmartShieldPolicy{
|
utils.ProxyRouteConfig{
|
||||||
|
Name: "_Cosmos",
|
||||||
|
SmartShield: utils.SmartShieldPolicy{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
PolicyStrictness: 1,
|
PolicyStrictness: 1,
|
||||||
PerUserRequestLimit: 5000,
|
PerUserRequestLimit: 5000,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
))
|
))
|
||||||
userRouter.Use(utils.MiddlewareTimeout(45 * time.Second))
|
userRouter.Use(utils.MiddlewareTimeout(45 * time.Second))
|
||||||
userRouter.Use(proxy.BotDetectionMiddleware)
|
userRouter.Use(proxy.BotDetectionMiddleware)
|
||||||
|
|
|
@ -17,6 +17,7 @@ func main() {
|
||||||
utils.Log("Starting...")
|
utils.Log("Starting...")
|
||||||
|
|
||||||
utils.ReBootstrapContainer = docker.BootstrapContainerFromTags
|
utils.ReBootstrapContainer = docker.BootstrapContainerFromTags
|
||||||
|
utils.PushShieldMetrics = metrics.PushShieldMetrics
|
||||||
|
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
|
|
||||||
|
|
|
@ -1,72 +1,47 @@
|
||||||
package metrics
|
package metrics
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
|
||||||
"fmt"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/azukaar/cosmos-server/src/utils"
|
"github.com/azukaar/cosmos-server/src/utils"
|
||||||
)
|
)
|
||||||
|
|
||||||
// responseWriter wraps the original http.ResponseWriter to capture the status code.
|
|
||||||
// type responseWriter struct {
|
|
||||||
// http.ResponseWriter
|
|
||||||
// status int
|
|
||||||
// }
|
|
||||||
|
|
||||||
// func (rw *responseWriter) WriteHeader(status int) {
|
func PushRequestMetrics(route utils.ProxyRouteConfig, statusCode int, TimeStarted time.Time, size int64) error {
|
||||||
// rw.status = status
|
responseTime := time.Since(TimeStarted)
|
||||||
// rw.ResponseWriter.WriteHeader(status)
|
|
||||||
// }
|
|
||||||
|
|
||||||
func MetricsMiddleware(route utils.ProxyRouteConfig) func(next http.Handler) http.Handler {
|
|
||||||
return func(next http.Handler) http.Handler {
|
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
||||||
startTime := time.Now()
|
|
||||||
|
|
||||||
// Call the next handler (which can be another middleware or the final handler).
|
|
||||||
// wrappedWriter := &responseWriter{ResponseWriter: w}
|
|
||||||
|
|
||||||
next.ServeHTTP(w, r)
|
|
||||||
|
|
||||||
// Calculate and log the response time.
|
|
||||||
responseTime := time.Since(startTime)
|
|
||||||
|
|
||||||
utils.Debug(fmt.Sprintf("[%s] %s %s %v", r.Method, r.RequestURI, r.RemoteAddr, responseTime))
|
|
||||||
|
|
||||||
if !utils.GetMainConfig().MonitoringDisabled {
|
if !utils.GetMainConfig().MonitoringDisabled {
|
||||||
go func() {
|
if statusCode >= 400 {
|
||||||
// if wrappedWriter.status >= 400 {
|
PushSetMetric("proxy.all.error", 1, DataDef{
|
||||||
// PushSetMetric("proxy.all.error", 1, DataDef{
|
Max: 0,
|
||||||
// Max: 0,
|
Period: time.Second * 30,
|
||||||
// Period: time.Second * 30,
|
Label: "Global Request Errors",
|
||||||
// Label: "Global Request Errors",
|
AggloType: "sum",
|
||||||
// AggloType: "sum",
|
SetOperation: "sum",
|
||||||
// SetOperation: "sum",
|
})
|
||||||
// })
|
PushSetMetric("proxy.route.error."+route.Name, 1, DataDef{
|
||||||
// PushSetMetric("proxy.route.error."+route.Name, 1, DataDef{
|
Max: 0,
|
||||||
// Max: 0,
|
Period: time.Second * 30,
|
||||||
// Period: time.Second * 30,
|
Label: "Request Errors " + route.Name,
|
||||||
// Label: "Request Errors " + route.Name,
|
AggloType: "sum",
|
||||||
// AggloType: "sum",
|
SetOperation: "sum",
|
||||||
// SetOperation: "sum",
|
})
|
||||||
// })
|
} else {
|
||||||
// } else {
|
PushSetMetric("proxy.all.success", 1, DataDef{
|
||||||
// PushSetMetric("proxy.all.success", 1, DataDef{
|
Max: 0,
|
||||||
// Max: 0,
|
Period: time.Second * 30,
|
||||||
// Period: time.Second * 30,
|
Label: "Global Request Success",
|
||||||
// Label: "Global Request Success",
|
AggloType: "sum",
|
||||||
// AggloType: "sum",
|
SetOperation: "sum",
|
||||||
// SetOperation: "sum",
|
})
|
||||||
// })
|
PushSetMetric("proxy.route.success."+route.Name, 1, DataDef{
|
||||||
// PushSetMetric("proxy.route.success."+route.Name, 1, DataDef{
|
Max: 0,
|
||||||
// Max: 0,
|
Period: time.Second * 30,
|
||||||
// Period: time.Second * 30,
|
Label: "Request Success " + route.Name,
|
||||||
// Label: "Request Success " + route.Name,
|
AggloType: "sum",
|
||||||
// AggloType: "sum",
|
SetOperation: "sum",
|
||||||
// SetOperation: "sum",
|
})
|
||||||
// })
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
PushSetMetric("proxy.all.time", int(responseTime.Milliseconds()), DataDef{
|
PushSetMetric("proxy.all.time", int(responseTime.Milliseconds()), DataDef{
|
||||||
Max: 0,
|
Max: 0,
|
||||||
|
@ -85,9 +60,50 @@ func MetricsMiddleware(route utils.ProxyRouteConfig) func(next http.Handler) htt
|
||||||
SetOperation: "max",
|
SetOperation: "max",
|
||||||
Unit: "ms",
|
Unit: "ms",
|
||||||
})
|
})
|
||||||
}()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
PushSetMetric("proxy.all.bytes", int(size), DataDef{
|
||||||
|
Max: 0,
|
||||||
|
Period: time.Second * 30,
|
||||||
|
Label: "Global Transfered Bytes",
|
||||||
|
AggloType: "sum",
|
||||||
|
Unit: "B",
|
||||||
|
})
|
||||||
|
|
||||||
|
PushSetMetric("proxy.route.bytes."+route.Name, int(size), DataDef{
|
||||||
|
Max: 0,
|
||||||
|
Period: time.Second * 30,
|
||||||
|
Label: "Transfered Bytes " + route.Name,
|
||||||
|
AggloType: "sum",
|
||||||
|
Unit: "B",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func PushShieldMetrics(reason string) {
|
||||||
|
reasonStr := map[string]string{
|
||||||
|
"bots": "Bots",
|
||||||
|
"geo": "By Geolocation",
|
||||||
|
"referer": "By Referer",
|
||||||
|
"hostname": "By Hostname",
|
||||||
|
"ip-whitelists": "By IP Whitelists",
|
||||||
|
"smart-shield": "Smart Shield",
|
||||||
|
}
|
||||||
|
|
||||||
|
PushSetMetric("proxy.blocked."+reason, 1, DataDef{
|
||||||
|
Max: 0,
|
||||||
|
Period: time.Second * 30,
|
||||||
|
Label: "Blocked " + reasonStr[reason],
|
||||||
|
AggloType: "sum",
|
||||||
|
SetOperation: "sum",
|
||||||
|
})
|
||||||
|
|
||||||
|
PushSetMetric("proxy.all.blocked", 1, DataDef{
|
||||||
|
Max: 0,
|
||||||
|
Period: time.Second * 30,
|
||||||
|
Label: "Global Blocked Requests",
|
||||||
|
AggloType: "sum",
|
||||||
|
SetOperation: "sum",
|
||||||
|
})
|
||||||
}
|
}
|
|
@ -2,6 +2,8 @@ package proxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/azukaar/cosmos-server/src/metrics"
|
||||||
)
|
)
|
||||||
|
|
||||||
var botUserAgents = []string{
|
var botUserAgents = []string{
|
||||||
|
@ -28,12 +30,14 @@ func BotDetectionMiddleware(next http.Handler) http.Handler {
|
||||||
userAgent := r.UserAgent()
|
userAgent := r.UserAgent()
|
||||||
|
|
||||||
if userAgent == "" {
|
if userAgent == "" {
|
||||||
|
go metrics.PushShieldMetrics("bots")
|
||||||
http.Error(w, "Access denied: Bots are not allowed.", http.StatusForbidden)
|
http.Error(w, "Access denied: Bots are not allowed.", http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, botUserAgent := range botUserAgents {
|
for _, botUserAgent := range botUserAgents {
|
||||||
if userAgent == botUserAgent {
|
if userAgent == botUserAgent {
|
||||||
|
go metrics.PushShieldMetrics("bots")
|
||||||
http.Error(w, "Access denied: Bots are not allowed.", http.StatusForbidden)
|
http.Error(w, "Access denied: Bots are not allowed.", http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@ import (
|
||||||
|
|
||||||
"github.com/azukaar/cosmos-server/src/user"
|
"github.com/azukaar/cosmos-server/src/user"
|
||||||
"github.com/azukaar/cosmos-server/src/utils"
|
"github.com/azukaar/cosmos-server/src/utils"
|
||||||
"github.com/azukaar/cosmos-server/src/metrics"
|
|
||||||
"github.com/go-chi/httprate"
|
"github.com/go-chi/httprate"
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
|
@ -88,7 +87,7 @@ func RouterGen(route utils.ProxyRouteConfig, router *mux.Router, destination htt
|
||||||
|
|
||||||
destination = utils.Restrictions(route.RestrictToConstellation, route.WhitelistInboundIPs)(destination)
|
destination = utils.Restrictions(route.RestrictToConstellation, route.WhitelistInboundIPs)(destination)
|
||||||
|
|
||||||
destination = SmartShieldMiddleware(route.Name, route.SmartShield)(destination)
|
destination = SmartShieldMiddleware(route.Name, route)(destination)
|
||||||
|
|
||||||
originCORS := route.CORSOrigin
|
originCORS := route.CORSOrigin
|
||||||
|
|
||||||
|
@ -146,8 +145,6 @@ func RouterGen(route utils.ProxyRouteConfig, router *mux.Router, destination htt
|
||||||
destination = utils.SetSecurityHeaders(destination)
|
destination = utils.SetSecurityHeaders(destination)
|
||||||
}
|
}
|
||||||
|
|
||||||
destination = metrics.MetricsMiddleware(route)(destination)
|
|
||||||
|
|
||||||
destination = tokenMiddleware(route.AuthEnabled, route.AdminOnly)(utils.CORSHeader(originCORS)((destination)))
|
destination = tokenMiddleware(route.AuthEnabled, route.AdminOnly)(utils.CORSHeader(originCORS)((destination)))
|
||||||
|
|
||||||
origin.Handler(destination)
|
origin.Handler(destination)
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package proxy
|
package proxy
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/azukaar/cosmos-server/src/utils"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -9,6 +8,9 @@ import (
|
||||||
"net"
|
"net"
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/azukaar/cosmos-server/src/utils"
|
||||||
|
"github.com/azukaar/cosmos-server/src/metrics"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -267,12 +269,10 @@ func isPrivileged(req *http.Request, policy utils.SmartShieldPolicy) bool {
|
||||||
return role >= policy.PrivilegedGroups
|
return role >= policy.PrivilegedGroups
|
||||||
}
|
}
|
||||||
|
|
||||||
func SmartShieldMiddleware(shieldID string, policy utils.SmartShieldPolicy) func(http.Handler) http.Handler {
|
func SmartShieldMiddleware(shieldID string, route utils.ProxyRouteConfig) func(http.Handler) http.Handler {
|
||||||
if policy.Enabled == false {
|
policy := route.SmartShield
|
||||||
return func(next http.Handler) http.Handler {
|
|
||||||
return next
|
if policy.Enabled {
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(policy.PerUserTimeBudget == 0) {
|
if(policy.PerUserTimeBudget == 0) {
|
||||||
policy.PerUserTimeBudget = 2 * 60 * 60 * 1000 // 2 hours
|
policy.PerUserTimeBudget = 2 * 60 * 60 * 1000 // 2 hours
|
||||||
}
|
}
|
||||||
|
@ -298,7 +298,31 @@ func SmartShieldMiddleware(shieldID string, policy utils.SmartShieldPolicy) func
|
||||||
|
|
||||||
return func(next http.Handler) http.Handler {
|
return func(next http.Handler) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
utils.Log("SmartShield: Request received")
|
clientID := GetClientID(r)
|
||||||
|
|
||||||
|
wrapper := &SmartResponseWriterWrapper {
|
||||||
|
ResponseWriter: w,
|
||||||
|
ThrottleNext: 0,
|
||||||
|
TimeStarted: time.Now(),
|
||||||
|
ClientID: clientID,
|
||||||
|
RequestCost: 1,
|
||||||
|
Method: r.Method,
|
||||||
|
shield: shield,
|
||||||
|
shieldID: shieldID,
|
||||||
|
policy: policy,
|
||||||
|
isPrivileged: isPrivileged(r, policy),
|
||||||
|
}
|
||||||
|
|
||||||
|
if !policy.Enabled {
|
||||||
|
next.ServeHTTP(wrapper, r)
|
||||||
|
wrapper.TimeEnded = time.Now()
|
||||||
|
wrapper.isOver = true
|
||||||
|
|
||||||
|
go metrics.PushRequestMetrics(route, wrapper.Status, wrapper.TimeStarted, wrapper.Bytes)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
currentGlobalRequests := shield.GetServerNbReq(shieldID) + 1
|
currentGlobalRequests := shield.GetServerNbReq(shieldID) + 1
|
||||||
utils.Debug(fmt.Sprintf("SmartShield: Current global requests: %d", currentGlobalRequests))
|
utils.Debug(fmt.Sprintf("SmartShield: Current global requests: %d", currentGlobalRequests))
|
||||||
|
|
||||||
|
@ -307,6 +331,7 @@ func SmartShieldMiddleware(shieldID string, policy utils.SmartShieldPolicy) func
|
||||||
wayTooManyReq := currentGlobalRequests > policy.MaxGlobalSimultaneous * 10
|
wayTooManyReq := currentGlobalRequests > policy.MaxGlobalSimultaneous * 10
|
||||||
retries := 50
|
retries := 50
|
||||||
if wayTooManyReq {
|
if wayTooManyReq {
|
||||||
|
go metrics.PushShieldMetrics("smart-shield")
|
||||||
utils.Log("SmartShield: WAYYYY Too many users on the server. Aborting right away.")
|
utils.Log("SmartShield: WAYYYY Too many users on the server. Aborting right away.")
|
||||||
http.Error(w, "Too many requests", http.StatusTooManyRequests)
|
http.Error(w, "Too many requests", http.StatusTooManyRequests)
|
||||||
return
|
return
|
||||||
|
@ -317,6 +342,7 @@ func SmartShieldMiddleware(shieldID string, policy utils.SmartShieldPolicy) func
|
||||||
tooManyReq = currentGlobalRequests > policy.MaxGlobalSimultaneous
|
tooManyReq = currentGlobalRequests > policy.MaxGlobalSimultaneous
|
||||||
retries--
|
retries--
|
||||||
if retries <= 0 {
|
if retries <= 0 {
|
||||||
|
go metrics.PushShieldMetrics("smart-shield")
|
||||||
utils.Log("SmartShield: Too many users on the server")
|
utils.Log("SmartShield: Too many users on the server")
|
||||||
http.Error(w, "Too many requests", http.StatusTooManyRequests)
|
http.Error(w, "Too many requests", http.StatusTooManyRequests)
|
||||||
return
|
return
|
||||||
|
@ -324,11 +350,11 @@ func SmartShieldMiddleware(shieldID string, policy utils.SmartShieldPolicy) func
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clientID := GetClientID(r)
|
|
||||||
userConsumed := shield.GetUserUsedBudgets(shieldID, clientID)
|
userConsumed := shield.GetUserUsedBudgets(shieldID, clientID)
|
||||||
|
|
||||||
if !isPrivileged(r, policy) && !shield.isAllowedToReqest(shieldID, policy, userConsumed) {
|
if !isPrivileged(r, policy) && !shield.isAllowedToReqest(shieldID, policy, userConsumed) {
|
||||||
lastBan := shield.GetLastBan(policy, userConsumed)
|
lastBan := shield.GetLastBan(policy, userConsumed)
|
||||||
|
go metrics.PushShieldMetrics("smart-shield")
|
||||||
utils.Log("SmartShield: User is blocked due to abuse: " + fmt.Sprintf("%+v", lastBan))
|
utils.Log("SmartShield: User is blocked due to abuse: " + fmt.Sprintf("%+v", lastBan))
|
||||||
http.Error(w, "Too many requests", http.StatusTooManyRequests)
|
http.Error(w, "Too many requests", http.StatusTooManyRequests)
|
||||||
return
|
return
|
||||||
|
@ -337,6 +363,7 @@ func SmartShieldMiddleware(shieldID string, policy utils.SmartShieldPolicy) func
|
||||||
if(!isPrivileged(r, policy)) {
|
if(!isPrivileged(r, policy)) {
|
||||||
throttle = shield.computeThrottle(policy, userConsumed)
|
throttle = shield.computeThrottle(policy, userConsumed)
|
||||||
}
|
}
|
||||||
|
|
||||||
wrapper := &SmartResponseWriterWrapper {
|
wrapper := &SmartResponseWriterWrapper {
|
||||||
ResponseWriter: w,
|
ResponseWriter: w,
|
||||||
ThrottleNext: throttle,
|
ThrottleNext: throttle,
|
||||||
|
@ -371,6 +398,7 @@ func SmartShieldMiddleware(shieldID string, policy utils.SmartShieldPolicy) func
|
||||||
shield.Lock()
|
shield.Lock()
|
||||||
wrapper.TimeEnded = time.Now()
|
wrapper.TimeEnded = time.Now()
|
||||||
wrapper.isOver = true
|
wrapper.isOver = true
|
||||||
|
go metrics.PushRequestMetrics(route, wrapper.Status, wrapper.TimeStarted, wrapper.Bytes)
|
||||||
shield.Unlock()
|
shield.Unlock()
|
||||||
})()
|
})()
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,8 @@ import (
|
||||||
|
|
||||||
// https://github.com/go-chi/chi/blob/master/middleware/timeout.go
|
// https://github.com/go-chi/chi/blob/master/middleware/timeout.go
|
||||||
|
|
||||||
|
var PushShieldMetrics func(string)
|
||||||
|
|
||||||
func MiddlewareTimeout(timeout time.Duration) func(next http.Handler) http.Handler {
|
func MiddlewareTimeout(timeout time.Duration) func(next http.Handler) http.Handler {
|
||||||
return func(next http.Handler) http.Handler {
|
return func(next http.Handler) http.Handler {
|
||||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -148,6 +150,7 @@ func BlockByCountryMiddleware(blockedCountries []string, CountryBlacklistIsWhite
|
||||||
}
|
}
|
||||||
|
|
||||||
if blocked {
|
if blocked {
|
||||||
|
PushShieldMetrics("geo")
|
||||||
http.Error(w, "Access denied", http.StatusForbidden)
|
http.Error(w, "Access denied", http.StatusForbidden)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -177,6 +180,7 @@ func BlockPostWithoutReferer(next http.Handler) http.Handler {
|
||||||
if r.Method == "POST" || r.Method == "PUT" || r.Method == "PATCH" || r.Method == "DELETE" {
|
if r.Method == "POST" || r.Method == "PUT" || r.Method == "PATCH" || r.Method == "DELETE" {
|
||||||
referer := r.Header.Get("Referer")
|
referer := r.Header.Get("Referer")
|
||||||
if referer == "" {
|
if referer == "" {
|
||||||
|
PushShieldMetrics("referer")
|
||||||
Error("Blocked POST request without Referer header", nil)
|
Error("Blocked POST request without Referer header", nil)
|
||||||
http.Error(w, "Bad Request: Invalid request.", http.StatusBadRequest)
|
http.Error(w, "Bad Request: Invalid request.", http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
|
@ -213,6 +217,7 @@ func EnsureHostname(next http.Handler) http.Handler {
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isOk {
|
if !isOk {
|
||||||
|
PushShieldMetrics("hostname")
|
||||||
Error("Invalid Hostname " + r.Host + " for request. Expecting one of " + fmt.Sprintf("%v", hostnames), nil)
|
Error("Invalid Hostname " + r.Host + " for request. Expecting one of " + fmt.Sprintf("%v", hostnames), nil)
|
||||||
w.WriteHeader(http.StatusBadRequest)
|
w.WriteHeader(http.StatusBadRequest)
|
||||||
http.Error(w, "Bad Request: Invalid hostname. Use your domain instead of your IP to access your server. Check logs if more details are needed.", http.StatusBadRequest)
|
http.Error(w, "Bad Request: Invalid hostname. Use your domain instead of your IP to access your server. Check logs if more details are needed.", http.StatusBadRequest)
|
||||||
|
@ -306,11 +311,13 @@ func Restrictions(RestrictToConstellation bool, WhitelistInboundIPs []string) fu
|
||||||
if(RestrictToConstellation) {
|
if(RestrictToConstellation) {
|
||||||
if(!isInConstellation) {
|
if(!isInConstellation) {
|
||||||
if(!isUsingWhiteList) {
|
if(!isUsingWhiteList) {
|
||||||
|
PushShieldMetrics("ip-whitelists")
|
||||||
Error("Request from " + ip + " is blocked because of restrictions", nil)
|
Error("Request from " + ip + " is blocked because of restrictions", nil)
|
||||||
Debug("Blocked by RestrictToConstellation isInConstellation isUsingWhiteList")
|
Debug("Blocked by RestrictToConstellation isInConstellation isUsingWhiteList")
|
||||||
http.Error(w, "Access denied", http.StatusForbidden)
|
http.Error(w, "Access denied", http.StatusForbidden)
|
||||||
return
|
return
|
||||||
} else if (!isInWhitelist) {
|
} else if (!isInWhitelist) {
|
||||||
|
PushShieldMetrics("ip-whitelists")
|
||||||
Error("Request from " + ip + " is blocked because of restrictions", nil)
|
Error("Request from " + ip + " is blocked because of restrictions", nil)
|
||||||
Debug("Blocked by RestrictToConstellation isInConstellation isInWhitelist")
|
Debug("Blocked by RestrictToConstellation isInConstellation isInWhitelist")
|
||||||
http.Error(w, "Access denied", http.StatusForbidden)
|
http.Error(w, "Access denied", http.StatusForbidden)
|
||||||
|
@ -318,6 +325,7 @@ func Restrictions(RestrictToConstellation bool, WhitelistInboundIPs []string) fu
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(isUsingWhiteList && !isInWhitelist) {
|
} else if(isUsingWhiteList && !isInWhitelist) {
|
||||||
|
PushShieldMetrics("ip-whitelists")
|
||||||
Error("Request from " + ip + " is blocked because of restrictions", nil)
|
Error("Request from " + ip + " is blocked because of restrictions", nil)
|
||||||
Debug("Blocked by RestrictToConstellation isInConstellation isUsingWhiteList isInWhitelist")
|
Debug("Blocked by RestrictToConstellation isInConstellation isUsingWhiteList isInWhitelist")
|
||||||
http.Error(w, "Access denied", http.StatusForbidden)
|
http.Error(w, "Access denied", http.StatusForbidden)
|
||||||
|
|
Loading…
Reference in a new issue