mirror of
https://github.com/lus/pasty.git
synced 2023-08-10 21:13:09 +03:00
implement paste reports
This commit is contained in:
parent
b9a6a81821
commit
bdac813e59
@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"github.com/lus/pasty/internal/config"
|
"github.com/lus/pasty/internal/config"
|
||||||
"github.com/lus/pasty/internal/meta"
|
"github.com/lus/pasty/internal/meta"
|
||||||
|
"github.com/lus/pasty/internal/reports"
|
||||||
"github.com/lus/pasty/internal/storage"
|
"github.com/lus/pasty/internal/storage"
|
||||||
"github.com/lus/pasty/internal/storage/postgres"
|
"github.com/lus/pasty/internal/storage/postgres"
|
||||||
"github.com/lus/pasty/internal/storage/sqlite"
|
"github.com/lus/pasty/internal/storage/sqlite"
|
||||||
@ -74,10 +75,6 @@ func main() {
|
|||||||
|
|
||||||
// Start the web server
|
// Start the web server
|
||||||
log.Info().Str("address", cfg.WebAddress).Msg("Starting the web server...")
|
log.Info().Str("address", cfg.WebAddress).Msg("Starting the web server...")
|
||||||
var adminTokens []string
|
|
||||||
if cfg.ModificationTokenMaster != "" {
|
|
||||||
adminTokens = []string{cfg.ModificationTokenMaster}
|
|
||||||
}
|
|
||||||
webServer := &web.Server{
|
webServer := &web.Server{
|
||||||
Address: cfg.WebAddress,
|
Address: cfg.WebAddress,
|
||||||
Storage: driver,
|
Storage: driver,
|
||||||
@ -88,7 +85,15 @@ func main() {
|
|||||||
ModificationTokensEnabled: cfg.ModificationTokens,
|
ModificationTokensEnabled: cfg.ModificationTokens,
|
||||||
ModificationTokenLength: cfg.ModificationTokenLength,
|
ModificationTokenLength: cfg.ModificationTokenLength,
|
||||||
ModificationTokenCharset: cfg.ModificationTokenCharacters,
|
ModificationTokenCharset: cfg.ModificationTokenCharacters,
|
||||||
AdminTokens: adminTokens,
|
}
|
||||||
|
if cfg.Reports.Enabled {
|
||||||
|
webServer.ReportClient = &reports.Client{
|
||||||
|
WebhookURL: cfg.Reports.WebhookURL,
|
||||||
|
WebhookToken: cfg.Reports.WebhookToken,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if cfg.ModificationTokenMaster != "" {
|
||||||
|
webServer.AdminTokens = []string{cfg.ModificationTokenMaster}
|
||||||
}
|
}
|
||||||
go func() {
|
go func() {
|
||||||
if err := webServer.Start(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
if err := webServer.Start(); err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||||
|
60
internal/reports/client.go
Normal file
60
internal/reports/client.go
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
package reports
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Report struct {
|
||||||
|
Paste string `json:"paste"`
|
||||||
|
Reason string `json:"reason"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
Success bool `json:"success"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
WebhookURL string
|
||||||
|
WebhookToken string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (client *Client) Send(report *Report) (*Response, error) {
|
||||||
|
data, err := json.Marshal(report)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
request, err := http.NewRequest(http.MethodPost, client.WebhookURL, bytes.NewReader(data))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if client.WebhookToken != "" {
|
||||||
|
request.Header.Set("Authorization", "Bearer "+client.WebhookToken)
|
||||||
|
}
|
||||||
|
|
||||||
|
response, err := http.DefaultClient.Do(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err := io.ReadAll(response.Body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if response.StatusCode < 200 || response.StatusCode > 299 {
|
||||||
|
return nil, fmt.Errorf("the report webhook responded with an unexpected error: %d (%s)", response.StatusCode, string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
reportResponse := new(Response)
|
||||||
|
if err := json.Unmarshal(body, &reportResponse); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return reportResponse, nil
|
||||||
|
}
|
@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/go-chi/chi/v5"
|
"github.com/go-chi/chi/v5"
|
||||||
"github.com/lus/pasty/internal/meta"
|
"github.com/lus/pasty/internal/meta"
|
||||||
"github.com/lus/pasty/internal/pastes"
|
"github.com/lus/pasty/internal/pastes"
|
||||||
|
"github.com/lus/pasty/internal/reports"
|
||||||
"github.com/lus/pasty/internal/storage"
|
"github.com/lus/pasty/internal/storage"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
@ -16,6 +17,10 @@ type Server struct {
|
|||||||
// The storage driver to use.
|
// The storage driver to use.
|
||||||
Storage storage.Driver
|
Storage storage.Driver
|
||||||
|
|
||||||
|
// The report client to use to send reports.
|
||||||
|
// If this is set to nil, the report system will be considered deactivated.
|
||||||
|
ReportClient *reports.Client
|
||||||
|
|
||||||
// Whether the Hastebin support should be enabled.
|
// Whether the Hastebin support should be enabled.
|
||||||
// If this is set to 'false', the Hastebin specific endpoints will not be registered.
|
// If this is set to 'false', the Hastebin specific endpoints will not be registered.
|
||||||
HastebinSupport bool
|
HastebinSupport bool
|
||||||
@ -63,11 +68,14 @@ func (server *Server) Start() error {
|
|||||||
router.Post("/api/v2/pastes", server.v2EndpointCreatePaste)
|
router.Post("/api/v2/pastes", server.v2EndpointCreatePaste)
|
||||||
router.With(server.v2MiddlewareInjectPaste, server.v2MiddlewareAuthorize).Patch("/api/v2/pastes/{paste_id}", server.v2EndpointModifyPaste)
|
router.With(server.v2MiddlewareInjectPaste, server.v2MiddlewareAuthorize).Patch("/api/v2/pastes/{paste_id}", server.v2EndpointModifyPaste)
|
||||||
router.With(server.v2MiddlewareInjectPaste, server.v2MiddlewareAuthorize).Delete("/api/v2/pastes/{paste_id}", server.v2EndpointDeletePaste)
|
router.With(server.v2MiddlewareInjectPaste, server.v2MiddlewareAuthorize).Delete("/api/v2/pastes/{paste_id}", server.v2EndpointDeletePaste)
|
||||||
|
if server.ReportClient != nil {
|
||||||
|
router.With(server.v2MiddlewareInjectPaste).Post("/api/v2/pastes/{paste_id}/report", server.v2EndpointReportPaste)
|
||||||
|
}
|
||||||
router.Get("/api/v2/info", func(writer http.ResponseWriter, request *http.Request) {
|
router.Get("/api/v2/info", func(writer http.ResponseWriter, request *http.Request) {
|
||||||
writeJSONOrErr(writer, http.StatusOK, map[string]any{
|
writeJSONOrErr(writer, http.StatusOK, map[string]any{
|
||||||
"version": meta.Version,
|
"version": meta.Version,
|
||||||
"modificationTokens": server.ModificationTokensEnabled,
|
"modificationTokens": server.ModificationTokensEnabled,
|
||||||
"reports": false, // TODO: Return report state
|
"reports": server.ReportClient != nil,
|
||||||
"pasteLifetime": -1, // TODO: Return paste lifetime
|
"pasteLifetime": -1, // TODO: Return paste lifetime
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
48
internal/web/v2_end_report_paste.go
Normal file
48
internal/web/v2_end_report_paste.go
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
package web
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/lus/pasty/internal/pastes"
|
||||||
|
"github.com/lus/pasty/internal/reports"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
type v2EndpointReportPastePayload struct {
|
||||||
|
Reason string `json:"reason"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (server *Server) v2EndpointReportPaste(writer http.ResponseWriter, request *http.Request) {
|
||||||
|
paste, ok := request.Context().Value("paste").(*pastes.Paste)
|
||||||
|
if !ok {
|
||||||
|
writeString(writer, http.StatusInternalServerError, "missing paste object")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read, parse and validate the request payload
|
||||||
|
body, err := io.ReadAll(request.Body)
|
||||||
|
if err != nil {
|
||||||
|
writeErr(writer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
payload := new(v2EndpointReportPastePayload)
|
||||||
|
if err := json.Unmarshal(body, payload); err != nil {
|
||||||
|
writeErr(writer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if payload.Reason == "" {
|
||||||
|
writeString(writer, http.StatusBadRequest, "missing report reason")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
report := &reports.Report{
|
||||||
|
Paste: paste.ID,
|
||||||
|
Reason: payload.Reason,
|
||||||
|
}
|
||||||
|
response, err := server.ReportClient.Send(report)
|
||||||
|
if err != nil {
|
||||||
|
writeErr(writer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
writeJSONOrErr(writer, http.StatusOK, response)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user