mirror of
https://github.com/lus/pasty.git
synced 2023-08-10 21:13:09 +03:00
Implement report webhook support
This commit is contained in:
parent
71477f71f6
commit
ebc7b20617
10
README.md
10
README.md
@ -90,6 +90,16 @@ Pasty provides an intuitive system to automatically delete pastes after a specif
|
||||
| `PASTY_AUTODELETE_LIFETIME` | `720h` | `string` | Defines the duration a paste should live until it gets deleted |
|
||||
| `PASTY_AUTODELETE_TASK_INTERVAL` | `5m` | `string` | Defines the interval in which the AutoDelete task should clean up the database |
|
||||
|
||||
## Reports
|
||||
Pasty aims at being lightweight by default. This is why no fully-featured admin interface with an overview over all pastes and reports is included.
|
||||
However, pasty does include a way of abstract reports to allow frontends work with this information.
|
||||
If enabled, pasty makes a standardized request to the configured webhook URL if a paste is reported.
|
||||
| Environment Variable | Default Value | Type | Description |
|
||||
|------------------------------|---------------|----------|-----------------------------------------------------------------------------------------------------|
|
||||
| `PASTY_REPORTS` | `false` | `bool` | Defines whether or not the report system should be enabled |
|
||||
| `PASTY_REPORT_WEBHOOK` | `<empty>` | `string` | Defines the webhook URL that is called whenever a paste is reported |
|
||||
| `PASTY_REPORT_WEBHOOK_TOKEN` | `<empty>` | `string` | Defines the token that is sent in the `Authorization` header on every request to the report webhook |
|
||||
|
||||
## Storage types
|
||||
Pasty supports multiple storage types, defined using the `PASTY_STORAGE_TYPE` environment variable (use the value behind the corresponding title in this README).
|
||||
Every single one of them has its own configuration variables:
|
||||
|
@ -20,6 +20,7 @@ type Config struct {
|
||||
RateLimit string
|
||||
LengthCap int
|
||||
AutoDelete *AutoDeleteConfig
|
||||
Reports *ReportConfig
|
||||
File *FileConfig
|
||||
Postgres *PostgresConfig
|
||||
MongoDB *MongoDBConfig
|
||||
@ -61,6 +62,13 @@ type S3Config struct {
|
||||
Bucket string
|
||||
}
|
||||
|
||||
// ReportConfig represents the configuration specific for the report system
|
||||
type ReportConfig struct {
|
||||
Reports bool
|
||||
ReportWebhook string
|
||||
ReportWebhookToken string
|
||||
}
|
||||
|
||||
// Current holds the currently loaded config
|
||||
var Current *Config
|
||||
|
||||
@ -83,6 +91,11 @@ func Load() {
|
||||
Lifetime: env.MustDuration("AUTODELETE_LIFETIME", 720*time.Hour),
|
||||
TaskInterval: env.MustDuration("AUTODELETE_TASK_INTERVAL", 5*time.Minute),
|
||||
},
|
||||
Reports: &ReportConfig{
|
||||
Reports: env.MustBool("REPORTS", false),
|
||||
ReportWebhook: env.MustString("REPORT_WEBHOOK", ""),
|
||||
ReportWebhookToken: env.MustString("REPORT_WEBHOOK_TOKEN", ""),
|
||||
},
|
||||
File: &FileConfig{
|
||||
Path: env.MustString("STORAGE_FILE_PATH", "./data"),
|
||||
},
|
||||
|
57
internal/report/report.go
Normal file
57
internal/report/report.go
Normal file
@ -0,0 +1,57 @@
|
||||
package report
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/lus/pasty/internal/config"
|
||||
"github.com/valyala/fasthttp"
|
||||
)
|
||||
|
||||
// ReportRequest represents a report request sent to the report webhook
|
||||
type ReportRequest struct {
|
||||
Paste string `json:"paste"`
|
||||
Reason string `json:"reason"`
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
// ReportResponse represents a report response received from the report webhook
|
||||
type ReportResponse struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
// SendReport sends a report request to the report webhook
|
||||
func SendReport(reportRequest *ReportRequest) (*ReportResponse, error) {
|
||||
request := fasthttp.AcquireRequest()
|
||||
defer fasthttp.ReleaseRequest(request)
|
||||
|
||||
response := fasthttp.AcquireResponse()
|
||||
defer fasthttp.ReleaseResponse(response)
|
||||
|
||||
request.Header.SetMethod(fasthttp.MethodPost)
|
||||
request.SetRequestURI(config.Current.Reports.ReportWebhook)
|
||||
if config.Current.Reports.ReportWebhookToken != "" {
|
||||
request.Header.Set("Authorization", "Bearer "+config.Current.Reports.ReportWebhookToken)
|
||||
}
|
||||
|
||||
data, err := json.Marshal(reportRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
request.SetBody(data)
|
||||
|
||||
if err := fasthttp.Do(request, response); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
status := response.StatusCode()
|
||||
if status < 200 || status > 299 {
|
||||
return nil, fmt.Errorf("the report webhook responded with an unexpected error: %d (%s)", status, string(response.Body()))
|
||||
}
|
||||
|
||||
reportResponse := new(ReportResponse)
|
||||
if err := json.Unmarshal(response.Body(), reportResponse); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return reportResponse, nil
|
||||
}
|
@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/fasthttp/router"
|
||||
"github.com/lus/pasty/internal/config"
|
||||
"github.com/lus/pasty/internal/report"
|
||||
"github.com/lus/pasty/internal/shared"
|
||||
"github.com/lus/pasty/internal/storage"
|
||||
"github.com/lus/pasty/internal/utils"
|
||||
@ -21,6 +22,10 @@ func InitializePastesController(group *router.Group, rateLimiterMiddleware *limi
|
||||
group.POST("/", rateLimiterMiddleware.Handle(endpointCreatePaste))
|
||||
group.PATCH("/{id}", rateLimiterMiddleware.Handle(middlewareInjectPaste(middlewareValidateModificationToken(endpointModifyPaste))))
|
||||
group.DELETE("/{id}", rateLimiterMiddleware.Handle(middlewareInjectPaste(middlewareValidateModificationToken(endpointDeletePaste))))
|
||||
|
||||
if config.Current.Reports.Reports {
|
||||
group.POST("/{id}/report", rateLimiterMiddleware.Handle(middlewareInjectPaste(endpointReportPaste)))
|
||||
}
|
||||
}
|
||||
|
||||
// middlewareInjectPaste retrieves and injects the paste with the specified ID
|
||||
@ -230,3 +235,42 @@ func endpointDeletePaste(ctx *fasthttp.RequestCtx) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
type endpointReportPastePayload struct {
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
|
||||
func endpointReportPaste(ctx *fasthttp.RequestCtx) {
|
||||
// Read, parse and validate the request payload
|
||||
payload := new(endpointReportPastePayload)
|
||||
if err := json.Unmarshal(ctx.PostBody(), payload); err != nil {
|
||||
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
||||
ctx.SetBodyString(err.Error())
|
||||
return
|
||||
}
|
||||
if payload.Reason == "" {
|
||||
ctx.SetStatusCode(fasthttp.StatusBadRequest)
|
||||
ctx.SetBodyString("missing report reason")
|
||||
return
|
||||
}
|
||||
|
||||
request := &report.ReportRequest{
|
||||
Paste: ctx.UserValue("_paste").(*shared.Paste).ID,
|
||||
Reason: payload.Reason,
|
||||
Timestamp: time.Now().Unix(),
|
||||
}
|
||||
response, err := report.SendReport(request)
|
||||
if err != nil {
|
||||
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
||||
ctx.SetBodyString(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
jsonData, err := json.Marshal(response)
|
||||
if err != nil {
|
||||
ctx.SetStatusCode(fasthttp.StatusInternalServerError)
|
||||
ctx.SetBodyString(err.Error())
|
||||
return
|
||||
}
|
||||
ctx.SetBody(jsonData)
|
||||
}
|
||||
|
@ -75,6 +75,7 @@ func Serve() error {
|
||||
jsonData, _ := json.Marshal(map[string]interface{}{
|
||||
"version": static.Version,
|
||||
"modificationTokens": config.Current.ModificationTokens,
|
||||
"reports": config.Current.Reports,
|
||||
})
|
||||
ctx.SetBody(jsonData)
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user