55 lines
1.4 KiB
Go
55 lines
1.4 KiB
Go
package main
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/subtle"
|
|
"encoding/base64"
|
|
"net/http"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
)
|
|
|
|
// genDeletionToken returns a 32-char url-safe random token
|
|
func genDeletionToken() string {
|
|
b := make([]byte, 24)
|
|
rand.Read(b)
|
|
return base64.RawURLEncoding.EncodeToString(b)
|
|
}
|
|
|
|
// maybeBurn marks a paste soft-deleted if burn_after_read is set.
|
|
// Returns true if this read consumed the paste.
|
|
func (s *Store) maybeBurn(row *PasteRow) bool {
|
|
if !row.BurnAfterRead {
|
|
return false
|
|
}
|
|
s.SoftDelete(row.ID)
|
|
return true
|
|
}
|
|
|
|
func deletionTokenEqual(stored, given string) bool {
|
|
return subtle.ConstantTimeCompare([]byte(stored), []byte(given)) == 1
|
|
}
|
|
|
|
// handleRedeemDeletion lets a holder of the deletion token hard-delete immediately.
|
|
// DELETE /api/pastes/{id}/redeem?token=...
|
|
func (a *apiServer) handleRedeemDeletion(w http.ResponseWriter, r *http.Request) {
|
|
id := chi.URLParam(r, "id")
|
|
token := r.URL.Query().Get("token")
|
|
if token == "" {
|
|
writeErr(w, 400, "token required")
|
|
return
|
|
}
|
|
row, err := a.store.GetPaste(id)
|
|
if err != nil || row == nil {
|
|
writeErr(w, 404, "paste not found")
|
|
return
|
|
}
|
|
if row.DeletionToken.String == "" || !deletionTokenEqual(row.DeletionToken.String, token) {
|
|
writeErr(w, 403, "invalid token")
|
|
return
|
|
}
|
|
// hard delete: pastes table row goes away entirely
|
|
a.store.db.Exec(`DELETE FROM pastes WHERE id = ?`, row.ID)
|
|
writeJSON(w, 200, map[string]string{"status": "deleted"})
|
|
}
|