feat: configurable traffic threshold and Feishu bot alerts
This commit is contained in:
1 parent
3e6e481b79
commit
1273f226fd
16 files changed
+660
-20
No files matched your search
@@ -0,0 +1,71 @@
|
||||
package alertnotify
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"vpn-platform/backend/internal/model"
|
||||
"vpn-platform/backend/internal/store"
|
||||
)
|
||||
|
||||
type roundTripFunc func(*http.Request) (*http.Response, error)
|
||||
|
||||
func (f roundTripFunc) RoundTrip(r *http.Request) (*http.Response, error) { return f(r) }
|
||||
|
||||
func TestConfigSecretsAndValidation(t *testing.T) {
|
||||
if err := store.Init(t.TempDir()); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, raw := range []string{"http://open.feishu.cn/open-apis/bot/v2/hook/id", "https://localhost/open-apis/bot/v2/hook/id", "https://open.feishu.cn.evil.test/open-apis/bot/v2/hook/id", "https://open.feishu.cn/open-apis/bot/v2/hook/id?x=1"} {
|
||||
if validWebhook(raw) {
|
||||
t.Errorf("accepted invalid webhook: %s", raw)
|
||||
}
|
||||
}
|
||||
webhook := "https://open.feishu.cn/open-apis/bot/v2/hook/abc-123"
|
||||
status, err := Save(Input{RateThresholdMbps: 75, Enabled: true, Webhook: webhook, SigningSecret: "sign-me"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !status.Configured || !status.Signed || !status.Enabled || status.RateThresholdMbps != 75 {
|
||||
t.Fatalf("unexpected status: %+v", status)
|
||||
}
|
||||
var row model.AlertSetting
|
||||
if err := store.DB.First(&row, 1).Error; err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if strings.Contains(row.WebhookEncrypted, webhook) || strings.Contains(row.SigningEncrypted, "sign-me") {
|
||||
t.Fatal("plaintext credentials stored")
|
||||
}
|
||||
if _, err := Save(Input{RateThresholdMbps: 0}); err == nil {
|
||||
t.Fatal("accepted zero threshold")
|
||||
}
|
||||
if _, err := Save(Input{RateThresholdMbps: 75, Enabled: true}); err != nil {
|
||||
t.Fatal("empty secret fields should retain stored credentials", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendChecksProviderResponse(t *testing.T) {
|
||||
old := client
|
||||
t.Cleanup(func() { client = old })
|
||||
client = &http.Client{Transport: roundTripFunc(func(r *http.Request) (*http.Response, error) {
|
||||
if r.URL.Host != "open.feishu.cn" {
|
||||
t.Fatal("wrong destination")
|
||||
}
|
||||
body, _ := io.ReadAll(r.Body)
|
||||
if !strings.Contains(string(body), `"sign":`) {
|
||||
t.Fatal("missing bot signature")
|
||||
}
|
||||
return &http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(`{"code":0}`)), Header: make(http.Header)}, nil
|
||||
})}
|
||||
if err := send("https://open.feishu.cn/open-apis/bot/v2/hook/id", "secret", "test"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
client.Transport = roundTripFunc(func(*http.Request) (*http.Response, error) {
|
||||
return &http.Response{StatusCode: 200, Body: io.NopCloser(strings.NewReader(`{"code":19021}`)), Header: make(http.Header)}, nil
|
||||
})
|
||||
if err := send("https://open.feishu.cn/open-apis/bot/v2/hook/id", "", "test"); err == nil {
|
||||
t.Fatal("accepted provider rejection")
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user