diff --git a/.vscode/settings.json b/.vscode/settings.json index 7bdf821..cf08795 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,10 @@ { - "editor.formatOnSave": true, - "[svelte]": {"editor.defaultFormatter": "svelte.svelte-vscode"} -} \ No newline at end of file + "editor.formatOnSave": true, + "[svelte]": { + "editor.defaultFormatter": "svelte.svelte-vscode" + }, + "[python]": { + "editor.defaultFormatter": "ms-python.autopep8" + }, + "python.formatting.provider": "none" +} diff --git a/application/rules/rules.go b/application/rules/rules.go new file mode 100644 index 0000000..929fd22 --- /dev/null +++ b/application/rules/rules.go @@ -0,0 +1,24 @@ +package gatesentryrules + +import "encoding/json" + +type TimeRestriction struct { + Action string `json:"action"` + To string `json:"to"` + From string `json:"from"` +} + +type Rule struct { + TimeRestriction TimeRestriction `json:"timeRestriction"` + ContentType string `json:"contentType"` + ContentSize int64 `json:"contentSize"` + User string `json:"user"` + Domain string `json:"domain"` +} + +type Rules []Rule + +func ParseRules(jsonStr string) (rules []Rule, err error) { + err = json.Unmarshal([]byte(jsonStr), &rules) + return +} diff --git a/application/runtime.go b/application/runtime.go index 31b1c98..b949bed 100644 --- a/application/runtime.go +++ b/application/runtime.go @@ -10,6 +10,7 @@ import ( "bitbucket.org/abdullah_irfan/gatesentryf/internalfiles" gatesentry2proxy "bitbucket.org/abdullah_irfan/gatesentryf/proxy" + gatesentryrules "bitbucket.org/abdullah_irfan/gatesentryf/rules" GatesentryTypes "bitbucket.org/abdullah_irfan/gatesentryf/types" gatesentryWebserverTypes "bitbucket.org/abdullah_irfan/gatesentryf/webserver/types" @@ -81,6 +82,7 @@ type GSRuntime struct { DNSServerChannel chan int BoundAddress *string DnsServerInfo *GatesentryTypes.DnsServerInfo + Rules []*gatesentryrules.Rule } func SetBaseDir(a string) { @@ -178,6 +180,7 @@ func (R *GSRuntime) Init() { R.GSSettings.SetDefault("idemail", "") R.GSSettings.SetDefault("enable_ai_image_filtering", "false") R.GSSettings.SetDefault("ai_scanner_url", "") + R.GSSettings.SetDefault("ai_scanner_url", "[]") R.GSSettings.SetDefault("version", R.GetApplicationVersion()) R.GSUpdateLog.SetDefault("versions", "") @@ -263,6 +266,17 @@ wR8g0gOPPV1l // R.GSUserRunDataSaver() + // Load rules to memory + rules, err := gatesentryrules.ParseRules(R.GSSettings.Get("rules")) + if err == nil { + R.Rules = make([]*gatesentryrules.Rule, len(rules)) + for i, r := range rules { + R.Rules[i] = &r + } + } else { + log.Println("Error parsing rules:", err) + } + //R.KeepAliveMonitor() /** diff --git a/application/webserver/endpoints/handler_settings.go b/application/webserver/endpoints/handler_settings.go index 30e989e..4acb9b5 100644 --- a/application/webserver/endpoints/handler_settings.go +++ b/application/webserver/endpoints/handler_settings.go @@ -24,7 +24,7 @@ func GSApiSettingsGET(requestedId string, settings *gatesentry2storage.MapStore) value = string(valueJson) } return struct{ Value string }{Value: value} - case "blocktimes", "strictness", "timezone", "idemail", "enable_https_filtering", "capem", "keypem", "enable_dns_server", "dns_custom_entries", "ai_scanner_url", "enable_ai_image_filtering", "EnableUsers": + case "blocktimes", "strictness", "timezone", "idemail", "enable_https_filtering", "capem", "keypem", "enable_dns_server", "dns_custom_entries", "ai_scanner_url", "enable_ai_image_filtering", "EnableUsers", "rules": value := settings.Get(requestedId) return struct { Key string @@ -81,7 +81,7 @@ func GSApiSettingsPOST(requestedId string, settings *gatesentry2storage.MapStore requestedId == "enable_dns_server" || requestedId == "enable_https_filtering" || requestedId == "enable_ai_image_filtering" || - requestedId == "ai_scanner_url" || requestedId == "EnableUsers" || requestedId == "strictness" { + requestedId == "ai_scanner_url" || requestedId == "EnableUsers" || requestedId == "strictness" || requestedId == "rules" { settings.Update(requestedId, temp.Value) } diff --git a/gatesentryproxy/constants.go b/gatesentryproxy/constants.go index 5c0353f..8051623 100644 --- a/gatesentryproxy/constants.go +++ b/gatesentryproxy/constants.go @@ -21,6 +21,7 @@ const ( ProxyActionSSLBump ProxyAction = "ssl-bump" ProxyActionFilterError ProxyAction = "filtererror" ProxyActionFilterNone ProxyAction = "filternone" + ProxyActionBlockedRule ProxyAction = "blocked_rule" ) var EMPTY_BYTES = []byte("") diff --git a/gatesentryproxy/contentscanner.go b/gatesentryproxy/contentscanner.go index 4763c4e..3053f8d 100644 --- a/gatesentryproxy/contentscanner.go +++ b/gatesentryproxy/contentscanner.go @@ -53,6 +53,14 @@ func ScanMedia(dataToScan []byte, contentType string, Content: dataToScan, } IProxy.ContentHandler(&contentFilterData) + + IProxy.RuleHandler(&GSRuleFilterData{ + Url: r.URL.String(), + ContentType: contentType, + ContentSize: int64(len(dataToScan)), + User: passthru.User, + Data: dataToScan, + }) if contentFilterData.FilterResponseAction == ProxyActionBlockedMediaContent { proxyActionPerformed = ProxyActionBlockedMediaContent var reasonForBlockArray []string @@ -90,12 +98,21 @@ func ScanText(dataToScan []byte, var proxyActionPerformed ProxyAction = ProxyActionFilterNone log.Println("ScanText called for url = " + r.URL.String() + " content type = " + contentType) if strings.Contains(contentType, "html") || len(contentType) == 0 { + contentFilterData := GSContentFilterData{ Url: r.URL.String(), ContentType: contentType, Content: (dataToScan), } IProxy.ContentHandler(&contentFilterData) + + IProxy.RuleHandler(&GSRuleFilterData{ + Url: r.URL.String(), + ContentType: contentType, + ContentSize: int64(len(dataToScan)), + User: passthru.User, + Data: dataToScan, + }) // isBlocked, _ := IProxy.RunHandler("content", contentType, (&dataToScan), passthru) if contentFilterData.FilterResponseAction == ProxyActionBlockedTextContent { proxyActionPerformed = ProxyActionBlockedTextContent diff --git a/gatesentryproxy/proxy.go b/gatesentryproxy/proxy.go index 712bb12..fd9f45c 100644 --- a/gatesentryproxy/proxy.go +++ b/gatesentryproxy/proxy.go @@ -447,6 +447,15 @@ func (h ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } + ruleData := GSRuleFilterData{Url: r.URL.String(), ContentType: contentType, ContentSize: int64(len(localCopyData)), User: user, Data: localCopyData} + IProxy.RuleHandler(&ruleData) + if passthru.ProxyActionToLog == ProxyActionBlockedRule { + // IProxy.RunHandler("log", "", &requestUrlBytes, passthru) + IProxy.LogHandler(GSLogData{Url: r.URL.String(), User: user, Action: ProxyActionBlockedRule}) + sendBlockMessageBytes(w, r, nil, ruleData.FilterResponse, nil) + return + } + if gzipOK && len(localCopyData) > 1000 { resp.Header.Set("Content-Encoding", "gzip") copyResponseHeader(w, resp) @@ -454,6 +463,7 @@ func (h ProxyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { var dest io.Writer dest = gzw destwithcounter := &DataPassThru{Writer: dest, Contenttype: contentType, Passthru: passthru} + destwithcounter.Write(localCopyData) gzw.Close() } else { diff --git a/gatesentryproxy/types.go b/gatesentryproxy/types.go index 67fb4ad..e1d8727 100644 --- a/gatesentryproxy/types.go +++ b/gatesentryproxy/types.go @@ -29,6 +29,7 @@ type GSProxy struct { ContentSizeHandler func(GSContentSizeFilterData) UserAccessHandler func(*GSUserAccessFilterData) TimeAccessHandler func(*GSTimeAccessFilterData) + RuleHandler func(*GSRuleFilterData) UrlAccessHandler func(*GSUrlFilterData) ProxyErrorHandler func(*GSProxyErrorData) DoMitm func(host string) bool @@ -62,6 +63,16 @@ type GSContentSizeFilterData struct { User string } +type GSRuleFilterData struct { + Url string + ContentType string + ContentSize int64 + User string + Data []byte + FilterResponseAction ProxyAction + FilterResponse []byte +} + type GSUserAccessFilterData struct { User string FilterResponseAction ProxyAction diff --git a/go.mod b/go.mod index 35cc1b2..062f961 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,9 @@ require ( require ( github.com/CloudyKit/jet/v6 v6.1.0 // indirect + github.com/PuerkitoBio/goquery v1.8.1 // indirect github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect + github.com/andybalholm/cascadia v1.3.2 // indirect github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 // indirect github.com/go-ole/go-ole v1.2.6 // indirect github.com/goccy/go-json v0.9.4 // indirect diff --git a/go.sum b/go.sum index 6fd02ef..4a115eb 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ github.com/CloudyKit/jet/v6 v6.1.0 h1:hvO96X345XagdH1fAoBjpBYG4a1ghhL/QzalkduPuX github.com/CloudyKit/jet/v6 v6.1.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4= github.com/Joker/hpp v1.0.0 h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc= github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY= +github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM= +github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ= github.com/Shopify/goreferrer v0.0.0-20210630161223-536fa16abd6f h1:XeOBnoBP7K19tMBEKeUo1NOxOO+h5FFi2HGzQvvkb44= github.com/Shopify/goreferrer v0.0.0-20210630161223-536fa16abd6f/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= @@ -14,6 +16,9 @@ github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= +github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss= +github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= github.com/antonholmquist/jason v1.0.0 h1:Ytg94Bcf1Bfi965K2q0s22mig/n4eGqEij/atENBhA0= github.com/antonholmquist/jason v1.0.0/go.mod h1:+GxMEKI0Va2U8h3os6oiUAetHAlGMvxjdpAH/9uvUMA= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= @@ -188,29 +193,62 @@ github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCO github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M= github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= golang.org/x/image v0.13.0 h1:3cge/F/QTkNLauhf2QoE9zp+7sr+ZcL4HnoZmdwg9sg= golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns= golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs= golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/go.work.sum b/go.work.sum index 8ec95fe..615ab08 100644 --- a/go.work.sum +++ b/go.work.sum @@ -5,11 +5,13 @@ github.com/CloudyKit/jet/v6 v6.2.0 h1:EpcZ6SR9n28BUGtNJSvlBqf90IpjeFr36Tizxhn/oM github.com/CloudyKit/jet/v6 v6.2.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4= github.com/Joker/jade v1.1.3 h1:Qbeh12Vq6BxURXT1qZBRHsDxeURB8ztcL6f3EXSGeHk= github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM= +github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM= github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP3TjA/dfr4NAY8bghDwnXiU7cTKxQqo0= github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs= github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= +github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= diff --git a/main.go b/main.go index fc9e86a..b96bc35 100644 --- a/main.go +++ b/main.go @@ -218,6 +218,50 @@ func RunGateSentry() { return R.IsUserValid(authheader) } + ngp.RuleHandler = func(gafd *gatesentryproxy.GSRuleFilterData) { + log.Println("Running rule handler") + // log.Println("GPT = ", gpt) + points := 0 + pointsRequired := 0 + for _, rule := range R.Rules { + if rule.Domain != "" { + pointsRequired++ + if rule.Domain == gafd.Url { + points++ + } + break + } + if rule.ContentSize > 0 { + pointsRequired++ + if gafd.ContentSize > rule.ContentSize { + points++ + } + break + } + if rule.ContentType != "" { + pointsRequired++ + if rule.ContentType == gafd.ContentType { + points++ + } + break + } + if rule.User != "" { + pointsRequired++ + if rule.User == gafd.User { + points++ + } + break + } + if rule.TimeRestriction.Action != "" { + } + } + + if points == pointsRequired { + gafd.FilterResponseAction = gatesentryproxy.ProxyActionBlockedRule + gafd.FilterResponse = []byte(gresponder.BuildGeneralResponsePage([]string{"Unable to fulfill your request because it matches the conditions of a filtering rule."}, -1)) + } + } + ngp.ContentHandler = func(gafd *gatesentryproxy.GSContentFilterData) { if strings.Contains(gafd.ContentType, "html") { responder := &gresponder.GSFilterResponder{Blocked: false} diff --git a/performance-test/main.go b/performance-test/main.go new file mode 100644 index 0000000..d5a6383 --- /dev/null +++ b/performance-test/main.go @@ -0,0 +1,74 @@ +package main + +import ( + "crypto/tls" + "fmt" + "net/http" + "net/url" + "time" + + "github.com/PuerkitoBio/goquery" +) + +const numRuns = 3 + +func main() { + // Set up the proxy + proxyURL, err := url.Parse("http://guest:password@10.1.0.141:10413") + if err != nil { + panic(err) + } + httpTransport := &http.Transport{ + // add proxy credentials + + Proxy: http.ProxyURL(proxyURL), + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + httpClient := &http.Client{ + Transport: httpTransport, + } + + // List of websites to visit + websites := []string{"https://edition.cnn.com", "https://nrk.no", "https://www.reddit.com"} + + for _, website := range websites { + var totalDuration time.Duration + + for i := 0; i < numRuns; i++ { + start := time.Now() + + // Fetch the HTML + resp, err := httpClient.Get(website) + if err != nil { + fmt.Println(err) + continue + } + defer resp.Body.Close() + + // Parse the HTML + doc, err := goquery.NewDocumentFromReader(resp.Body) + if err != nil { + fmt.Println(err) + continue + } + + // Find and download assets + doc.Find("img").Each(func(index int, element *goquery.Selection) { + src, exists := element.Attr("src") + if exists { + _, err := httpClient.Get(src) + if err != nil { + fmt.Println(err) + } + } + }) + + elapsed := time.Since(start) + totalDuration += elapsed + } + + // Calculate and print the average time + averageDuration := totalDuration / numRuns + fmt.Printf("Average time taken to download assets from %s: %s\n", website, averageDuration) + } +} diff --git a/performance-test/main.py b/performance-test/main.py new file mode 100644 index 0000000..213129c --- /dev/null +++ b/performance-test/main.py @@ -0,0 +1,52 @@ +import time +import urllib.request +from requests_html import HTMLSession +import time + + +def measure_performance(proxy_server_url, test_url): + """Measures the performance of a proxy server. + + Args: + proxy_server_url: The URL of the proxy server. + test_url: The URL of the website to test the proxy server against. + + Returns: + A tuple of (response_time, status_code). + """ + session = HTMLSession() + proxies = { + "http": proxy_server_url, + "https": proxy_server_url, + } + session.proxies = proxies + + start_time = time.time() + try: + response = session.get(test_url, verify=False) + response.html.render() # This will download the assets and execute JavaScript + status_code = response.status_code + except Exception as e: + print(f"An error occurred: {e}") + status_code = None + finally: + response_time = time.time() - start_time + + return response_time, status_code + + +def main(): + """Measures the performance of a proxy server and prints the results to the console.""" + + proxy_server_url = "http://guest:password@10.1.0.141:10413" + test_url = "https://nrk.no" + + response_time, status_code = measure_performance( + proxy_server_url, test_url) + + print("Response time:", response_time) + print("Status code:", status_code) + + +if __name__ == "__main__": + main() diff --git a/ui/src/components/connectedSettingInput.svelte b/ui/src/components/connectedSettingInput.svelte index 75cfc37..a9a183f 100644 --- a/ui/src/components/connectedSettingInput.svelte +++ b/ui/src/components/connectedSettingInput.svelte @@ -1,8 +1,8 @@ {#if loaded} - {#if type == "radio"} + {#if type == "external"}{:else if type == "radio"} - + +
{timeValidationMessage}
+ + diff --git a/ui/src/menu.ts b/ui/src/menu.ts index 26519c3..b58895a 100644 --- a/ui/src/menu.ts +++ b/ui/src/menu.ts @@ -80,12 +80,12 @@ let menuItems = [ href: "/services", icon: SwitchLayer_2, }, - // { - // type: "link", - // text: "Rules", - // href: "/rules", - // icon: Rule, - // }, + { + type: "link", + text: "Rules", + href: "/rules", + icon: Rule, + }, { type: "link", text: "Stats", diff --git a/ui/src/routes/rules/rform.svelte b/ui/src/routes/rules/rform.svelte index c45db79..aa5d5a4 100644 --- a/ui/src/routes/rules/rform.svelte +++ b/ui/src/routes/rules/rform.svelte @@ -10,6 +10,7 @@ TimePickerSelect, } from "carbon-components-svelte"; import { _ } from "svelte-i18n"; + export let rule = { domain: "", timeRestriction: { from: "", to: "", action: "block" }, @@ -19,155 +20,177 @@ }; export let index; + export let isOpen = false; + + export let toggleRule = (index) => { + isOpen = !isOpen; + }; import { createEventDispatcher } from "svelte"; import Timepicker from "../../components/timepicker.svelte"; import { RowDelete } from "carbon-icons-svelte"; const dispatch = createEventDispatcher(); -
- - -
Rule {index + 1}
-
- -
- Action - { - // @ts-ignore - rule.timeRestriction.action = e.detail.selectedId; - }} - items={[ - { id: "block", text: "Block" }, - { id: "allow", text: "Allow" }, - ]} - /> - - {$_("Will ")} {rule.timeRestriction.action} - {$_("traffic matching the following conditions.... ")} - -
-
- {$_("Domain = ")} - - - - {#if rule.domain != ""} - - {$_("... domain is ")} {rule.domain} - - {/if} -
-
- {$_("Time = ")} - - - - toggleRule(index)} + > + [+] Rule {index + 1} +
+{:else if isOpen} +
+ + +
toggleRule(index)} style="cursor:pointer"> + [-] Rule {index + 1} +
+
+ +
+ Action + { + // @ts-ignore + rule.timeRestriction.action = e.detail.selectedId; + }} + items={[ + { id: "block", text: "Block" }, + { id: "allow", text: "Allow" }, + { id: "sendTo", text: "Send data to service" }, + ]} /> - - - {#if rule.timeRestriction.from != "" && rule.timeRestriction.to != ""} - {$_("...time is between ")} - {rule.timeRestriction.from} - {$_("and")} {rule.timeRestriction.to} + {$_("Will ")} {rule.timeRestriction.action} + {$_("traffic matching the following conditions.... ")} - {/if} -
-
- {$_("User = ")} - - - - {#if rule.user != ""} - - {$_("...user is ")} {rule.user} +
+
+ {$_("Domain = ")} + - {/if} -
-
- {$_("Content Size = ")} - - - - - - {#if rule.contentSize !== 0 && rule.contentSize !== null} - - {$_("...content size is greater than ")} - {rule.contentSize} - {$_("MB")} + + {#if rule.domain != ""} + + {$_("... domain is ")} {rule.domain} + + {/if} +
+
+ {$_("Time = ")} + + + + - {/if} -
- -
- {$_("Content Type = ")} - - - - - - {#if rule.contentType != ""} - - {$_("...content type is ")} - {rule.contentType} + + {#if rule.timeRestriction.from != "" && rule.timeRestriction.to != ""} + + {$_("...time is between ")} + {rule.timeRestriction.from} + {$_("and")} {rule.timeRestriction.to} + + {/if} +
+
+ {$_("User = ")} + + + + {#if rule.user != ""} + + {$_("...user is ")} {rule.user} + + {/if} +
+
+ {$_("Content Size = ")} + + + + + + {#if rule.contentSize !== 0 && rule.contentSize !== null} + + {$_("...content size is greater than ")} + {rule.contentSize} + {$_("MB")} + + {/if} +
+ +
+ {$_("Content Type = ")} + + + - {/if} -
-
-
-
- + + {#if rule.contentType != ""} + + {$_("...content type is ")} + {rule.contentType} + + {/if} +
+ + +
+ +
-
+{/if} diff --git a/ui/src/routes/rules/rulelist.svelte b/ui/src/routes/rules/rulelist.svelte index 5cb1e65..dc7ce96 100644 --- a/ui/src/routes/rules/rulelist.svelte +++ b/ui/src/routes/rules/rulelist.svelte @@ -2,8 +2,11 @@ import { Button, ButtonSet, Column, Row } from "carbon-components-svelte"; import Ruleform from "./rform.svelte"; import { Add, Save } from "carbon-icons-svelte"; + import ConnectedSettingInput from "../../components/connectedSettingInput.svelte"; let rules = []; + let apiRules = null; + let isExpanded = {}; function addRule() { console.log("add rule"); @@ -15,31 +18,66 @@ ]; } + let updateNetwork = null; + function removeRule(e) { const index = e.detail; - console.log("Removing rule", index); rules = rules.filter((_, i) => i !== index); } - function saveRules() { - const json = JSON.stringify({ rules }, null, 2); - console.log(json); // Replace with actual save logic + const saveRules = async () => { + console.log("Rules = ", rules); + const json = JSON.stringify(rules, null, 2); + + await updateNetwork(json); + }; + + function toggleRule(index) { + isExpanded[index] = !isExpanded[index]; + } + + $: { + if (apiRules !== null) { + rules = JSON.parse(apiRules); + } } + + {#if apiRules !== null}{:else}{/if} + {#each rules as rule, index (index)} - + {/each} -
-
- - - - + + + + +
+
+
+
+ +   + + +