- Replace manual IP logging with the `withRequestLogAttrs` helper in authentication handlers. - Add user activity logging for API documentation and login page views. - Clean up log calls to use variadic expansion of request attributes.
155 lines
6.0 KiB
Go
155 lines
6.0 KiB
Go
package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"warpbox.dev/backend/libs/helpers"
|
|
"warpbox.dev/backend/libs/web"
|
|
)
|
|
|
|
type apiDocsData struct {
|
|
BaseURL string
|
|
UploadURL string
|
|
HealthURL string
|
|
RequestSchemaURL string
|
|
ResponseSchemaURL string
|
|
ShareXExamplePath string
|
|
ShareXExampleURL string
|
|
ShareXDownloadURL string
|
|
ShareXFileFieldName string
|
|
ShareXGroupWindow string
|
|
}
|
|
|
|
func (a *App) APIDocs(w http.ResponseWriter, r *http.Request) {
|
|
user, loggedIn := a.currentUser(r)
|
|
actor := "anonymous"
|
|
if loggedIn {
|
|
actor = "user"
|
|
}
|
|
a.logger.Info("api docs viewed", withRequestLogAttrs(r,
|
|
"source", "page",
|
|
"severity", "user_activity",
|
|
"code", 2501,
|
|
"actor", actor,
|
|
"user_id", user.ID,
|
|
)...)
|
|
a.renderPage(w, r, http.StatusOK, "api.html", web.PageData{
|
|
Title: "API documentation",
|
|
Description: "Curl and ShareX upload examples for Warpbox.",
|
|
Data: apiDocsData{
|
|
BaseURL: a.cfg.BaseURL,
|
|
UploadURL: a.cfg.BaseURL + "/api/v1/upload",
|
|
HealthURL: a.cfg.BaseURL + "/api/v1/health",
|
|
RequestSchemaURL: a.cfg.BaseURL + "/api/v1/schemas/upload-request.json",
|
|
ResponseSchemaURL: a.cfg.BaseURL + "/api/v1/schemas/upload-response.json",
|
|
ShareXExamplePath: "examples/sharex/warpbox-anonymous.sxcu",
|
|
ShareXExampleURL: a.cfg.BaseURL + "/api/v1/upload",
|
|
ShareXDownloadURL: a.cfg.BaseURL + "/api/v1/sharex/warpbox-anonymous.sxcu",
|
|
ShareXFileFieldName: "sharex",
|
|
ShareXGroupWindow: uploadGroupWindow.String(),
|
|
},
|
|
})
|
|
}
|
|
|
|
func (a *App) ShareXAnonymousConfig(w http.ResponseWriter, r *http.Request) {
|
|
w.Header().Set("Content-Disposition", `attachment; filename="warpbox-anonymous.sxcu"`)
|
|
helpers.WriteJSON(w, http.StatusOK, map[string]any{
|
|
"Version": "18.0.0",
|
|
"Name": "Warpbox Anonymous Upload",
|
|
"DestinationType": "ImageUploader, TextUploader, FileUploader",
|
|
"RequestMethod": "POST",
|
|
"RequestURL": a.cfg.BaseURL + "/api/v1/upload",
|
|
"Headers": map[string]string{
|
|
"Accept": "application/json",
|
|
// Group a multi-file selection (sent as back-to-back requests) into
|
|
// one box. Remove this header for one box per file.
|
|
uploadBatchHeader: "sharex",
|
|
},
|
|
"Body": "MultipartFormData",
|
|
"FileFormName": "sharex",
|
|
"URL": "{json:boxUrl}",
|
|
"ThumbnailURL": "{json:thumbnailUrl}",
|
|
"DeletionURL": "{json:deleteUrl}",
|
|
"ErrorMessage": "{json:error}",
|
|
})
|
|
}
|
|
|
|
func (a *App) UploadRequestSchema(w http.ResponseWriter, r *http.Request) {
|
|
helpers.WriteJSON(w, http.StatusOK, map[string]any{
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"$id": a.cfg.BaseURL + "/api/v1/schemas/upload-request.json",
|
|
"title": "Warpbox anonymous upload request",
|
|
"description": "Multipart/form-data request accepted by POST /api/v1/upload. Send one or more files using either the file or sharex field.",
|
|
"type": "object",
|
|
"properties": map[string]any{
|
|
"file": map[string]any{
|
|
"description": "One or more uploaded files. Use this field for curl and browser-style clients.",
|
|
"type": "array",
|
|
"items": map[string]any{"type": "string", "format": "binary"},
|
|
},
|
|
"sharex": map[string]any{
|
|
"description": "One or more uploaded files. Use this field for ShareX custom uploader configs.",
|
|
"type": "array",
|
|
"items": map[string]any{"type": "string", "format": "binary"},
|
|
},
|
|
"max_days": map[string]any{
|
|
"description": "Optional number of days before the box expires. Defaults to 7.",
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
},
|
|
"max_downloads": map[string]any{
|
|
"description": "Optional maximum number of downloads before the box expires.",
|
|
"type": "integer",
|
|
"minimum": 1,
|
|
},
|
|
"password": map[string]any{
|
|
"description": "Optional box password.",
|
|
"type": "string",
|
|
},
|
|
"obfuscate_metadata": map[string]any{
|
|
"description": "Optional checkbox-style value. When set with a password, hides file names/counts until unlock.",
|
|
"type": "string",
|
|
"enum": []string{"on"},
|
|
},
|
|
},
|
|
"anyOf": []any{
|
|
map[string]any{"required": []string{"file"}},
|
|
map[string]any{"required": []string{"sharex"}},
|
|
},
|
|
})
|
|
}
|
|
|
|
func (a *App) UploadResponseSchema(w http.ResponseWriter, r *http.Request) {
|
|
helpers.WriteJSON(w, http.StatusOK, map[string]any{
|
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
"$id": a.cfg.BaseURL + "/api/v1/schemas/upload-response.json",
|
|
"title": "Warpbox anonymous upload JSON response",
|
|
"description": "JSON response returned by POST /api/v1/upload when Accept: application/json is sent.",
|
|
"type": "object",
|
|
"required": []string{"boxId", "boxUrl", "zipUrl", "manageUrl", "deleteUrl", "expiresAt", "files"},
|
|
"properties": map[string]any{
|
|
"boxId": map[string]any{"type": "string"},
|
|
"boxUrl": map[string]any{"type": "string", "format": "uri"},
|
|
"zipUrl": map[string]any{"type": "string", "format": "uri"},
|
|
"thumbnailUrl": map[string]any{"type": "string", "format": "uri", "description": "Thumbnail of the most recently uploaded file (placeholder until generated)."},
|
|
"manageUrl": map[string]any{"type": "string", "format": "uri", "description": "Private bearer URL for managing/deleting this upload. Returned only at upload time."},
|
|
"deleteUrl": map[string]any{"type": "string", "format": "uri", "description": "Private bearer URL for deleting this upload (GET or POST). Returned only at upload time."},
|
|
"expiresAt": map[string]any{"type": "string", "format": "date-time"},
|
|
"files": map[string]any{
|
|
"type": "array",
|
|
"items": map[string]any{
|
|
"type": "object",
|
|
"required": []string{"id", "name", "size", "url"},
|
|
"properties": map[string]any{
|
|
"id": map[string]any{"type": "string"},
|
|
"name": map[string]any{"type": "string"},
|
|
"size": map[string]any{"type": "string"},
|
|
"url": map[string]any{"type": "string", "format": "uri"},
|
|
"thumbnailUrl": map[string]any{"type": "string", "format": "uri"},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
}
|