From 381229cfd764feb28be60cb1eba56df694fd1fab Mon Sep 17 00:00:00 2001 From: sysatom Date: Tue, 23 Mar 2021 18:25:54 +0800 Subject: [PATCH] feat: cloudflare cron --- internal/app/cron/agent/cloudflare.go | 51 +++++++++++ internal/app/cron/rules/rules.go | 7 ++ internal/pkg/vendors/cloudflare/cloudflare.go | 84 +++++++++++++++++++ internal/pkg/vendors/providers.go | 6 ++ 4 files changed, 148 insertions(+) create mode 100644 internal/app/cron/agent/cloudflare.go create mode 100644 internal/pkg/vendors/cloudflare/cloudflare.go diff --git a/internal/app/cron/agent/cloudflare.go b/internal/app/cron/agent/cloudflare.go new file mode 100644 index 00000000..d48be3c2 --- /dev/null +++ b/internal/app/cron/agent/cloudflare.go @@ -0,0 +1,51 @@ +package agent + +import ( + "context" + "encoding/json" + "github.com/tsundata/assistant/api/pb" + "github.com/tsundata/assistant/internal/app/cron/pipeline/result" + "github.com/tsundata/assistant/internal/pkg/rulebot" + "github.com/tsundata/assistant/internal/pkg/utils" + "github.com/tsundata/assistant/internal/pkg/vendors/cloudflare" + "time" +) + +func DomainAnalyticsReport(b *rulebot.RuleBot) []result.Result { + // get key + ctx := context.Background() + reply, err := b.MidClient.GetCredential(ctx, &pb.CredentialRequest{Name: cloudflare.ID}) + if err != nil { + return []result.Result{result.ErrorResult(err)} + } + token := "" + zone := "" + for _, item := range reply.GetContent() { + if item.Key == cloudflare.Token { + token = item.Value + } + if item.Key == cloudflare.ZoneID { + zone = item.Value + } + } + if token == "" || zone == "" { + return []result.Result{result.EmptyResult()} + } + + // get dashboard + end := time.Now().Format("2006-01-02T15:04:05Z") + start := time.Now().Add(time.Duration(-7*24) * time.Hour).Format("2006-01-02T15:04:05Z") + + cf := cloudflare.NewCloudflare(token, zone) + analytics, err := cf.GetAnalytics(start, end) + if err != nil { + return []result.Result{result.ErrorResult(err)} + } + + j, err := json.Marshal(analytics) + if err != nil { + return []result.Result{result.ErrorResult(err)} + } + + return []result.Result{result.MessageResult(utils.ByteToString(j))} +} diff --git a/internal/app/cron/rules/rules.go b/internal/app/cron/rules/rules.go index fc022d8d..d3903d81 100644 --- a/internal/app/cron/rules/rules.go +++ b/internal/app/cron/rules/rules.go @@ -35,6 +35,13 @@ var rules = []Rule{ return agent.WorkflowCron(b) }, }, + { + Name: "cloudflare_report", + When: "0 0 * * 0", + Action: func(b *rulebot.RuleBot) []result.Result { + return agent.DomainAnalyticsReport(b) + }, + }, } var Options = []rulebot.Option{ diff --git a/internal/pkg/vendors/cloudflare/cloudflare.go b/internal/pkg/vendors/cloudflare/cloudflare.go new file mode 100644 index 00000000..1f180d77 --- /dev/null +++ b/internal/pkg/vendors/cloudflare/cloudflare.go @@ -0,0 +1,84 @@ +package cloudflare + +import ( + "fmt" + "github.com/go-resty/resty/v2" + "net/http" + "time" +) + +const ( + ID = "cloudflare" + Token = "token" + ZoneID = "zone_id" + AccountID = "account_id" +) + +type AnalyticResponse struct { + Data struct { + Viewer struct { + Zones []struct { + FirewallEventsAdaptive []struct { + Action string `json:"action"` + ClientRequestHTTPHost string `json:"clientRequestHTTPHost"` + Datetime *time.Time `json:"datetime"` + RayName string `json:"rayName"` + UserAgent string `json:"userAgent"` + } `json:"firewallEventsAdaptive"` + } `json:"zones"` + } `json:"viewer"` + } `json:"data"` + Errors interface{} `json:"errors"` +} + +type Cloudflare struct { + token string + zoneID string +} + +func NewCloudflare(token string, zoneID string) *Cloudflare { + return &Cloudflare{token: token, zoneID: zoneID} +} + +func (v *Cloudflare) GetAnalytics(start, end string) (*AnalyticResponse, error) { + c := resty.New() + resp, err := c.R(). + SetAuthToken(v.token). + SetResult(&AnalyticResponse{}). + SetBody(fmt.Sprintf(` +query +{ + viewer + { + zones(filter: { zoneTag: "%s"}) + { + firewallEventsAdaptive( + filter: { + datetime_gt: "%s", + datetime_lt: "%s" + }, + limit: 2, + orderBy: [datetime_DESC, rayName_DESC]) + { + action + datetime + rayName + clientRequestHTTPHost + userAgent + } + } + } +} +`, v.zoneID, start, end)). + Post("https://api.cloudflare.com/client/v4/graphql") + if err != nil { + return nil, err + } + + if resp.StatusCode() == http.StatusOK { + result := resp.Result().(*AnalyticResponse) + return result, nil + } else { + return nil, fmt.Errorf("cloudflare api error %d", resp.StatusCode()) + } +} diff --git a/internal/pkg/vendors/providers.go b/internal/pkg/vendors/providers.go index e5083d54..c8441416 100644 --- a/internal/pkg/vendors/providers.go +++ b/internal/pkg/vendors/providers.go @@ -5,6 +5,7 @@ import ( "github.com/go-redis/redis/v8" "github.com/gofiber/fiber/v2" "github.com/tsundata/assistant/api/pb" + "github.com/tsundata/assistant/internal/pkg/vendors/cloudflare" "github.com/tsundata/assistant/internal/pkg/vendors/dropbox" "github.com/tsundata/assistant/internal/pkg/vendors/email" "github.com/tsundata/assistant/internal/pkg/vendors/github" @@ -40,6 +41,11 @@ var ProviderCredentialOptions = map[string]interface{}{ email.Username: "Username Mail", email.Password: "Password", }, + cloudflare.ID: map[string]string{ + cloudflare.Token: "Api Token", + cloudflare.ZoneID: "Zone ID", + cloudflare.AccountID: "Account ID", + }, } type OAuthProvider interface {