feat: contact form backend for linux and freebsd servers
Test / test (push) Successful in 2m1s
Release / gates (push) Successful in 1m57s
Release / build (amd64, freebsd) (push) Successful in 1m26s
Release / build (amd64, linux) (push) Successful in 1m30s
Release / build (arm64, freebsd) (push) Successful in 1m28s
Release / build (arm64, linux) (push) Successful in 1m49s
Release / build (loong64, linux) (push) Successful in 1m30s
Release / build (riscv64, linux) (push) Successful in 1m29s
Release / release (push) Successful in 41s
Test / test (push) Successful in 2m1s
Release / gates (push) Successful in 1m57s
Release / build (amd64, freebsd) (push) Successful in 1m26s
Release / build (amd64, linux) (push) Successful in 1m30s
Release / build (arm64, freebsd) (push) Successful in 1m28s
Release / build (arm64, linux) (push) Successful in 1m49s
Release / build (loong64, linux) (push) Successful in 1m30s
Release / build (riscv64, linux) (push) Successful in 1m29s
Release / release (push) Successful in 41s
Assisted-by: GLM 5.3 Flash
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
//go:build linux || freebsd
|
||||
|
||||
package storage
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestPendingStoreRoundTrip(t *testing.T) {
|
||||
p := NewPendingStore(filepath.Join(t.TempDir(), "pending.json"), 72*time.Hour)
|
||||
|
||||
if _, ok := p.Consume("unknown-token"); ok {
|
||||
t.Fatal("unknown token must not consume")
|
||||
}
|
||||
|
||||
if err := p.Issue("token-a", PendingSubscription{Email: "Jane@Example.COM", IP: "203.0.113.9"}); err != nil {
|
||||
t.Fatalf("issue: %v", err)
|
||||
}
|
||||
sub, ok := p.Consume("token-a")
|
||||
if !ok {
|
||||
t.Fatal("valid token must consume")
|
||||
}
|
||||
if sub.Email != "Jane@Example.COM" || sub.IP != "203.0.113.9" {
|
||||
t.Errorf("consumed entry = %+v", sub)
|
||||
}
|
||||
if _, ok := p.Consume("token-a"); ok {
|
||||
t.Error("token must be single-use")
|
||||
}
|
||||
}
|
||||
|
||||
// An expired entry is never returned and is purged from the file.
|
||||
func TestPendingStoreExpiry(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "pending.json")
|
||||
stale, _ := json.Marshal(pendingFile{Schema: pendingSchema, Entries: map[string]PendingSubscription{
|
||||
hashToken("old"): {Email: "a@b.c", CreatedAt: time.Now().Add(-96 * time.Hour)},
|
||||
}})
|
||||
if err := os.WriteFile(path, stale, 0o600); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, ok := NewPendingStore(path, 72*time.Hour).Consume("old"); ok {
|
||||
t.Fatal("expired token must not consume")
|
||||
}
|
||||
raw, _ := os.ReadFile(path)
|
||||
if strings.Contains(string(raw), `"a@b.c"`) {
|
||||
t.Error("expired entry was not purged from the file")
|
||||
}
|
||||
}
|
||||
|
||||
// Issue replaces the previous live token for the same address.
|
||||
func TestPendingStoreRotation(t *testing.T) {
|
||||
path := filepath.Join(t.TempDir(), "pending.json")
|
||||
p := NewPendingStore(path, 72*time.Hour)
|
||||
if err := p.Issue("first", PendingSubscription{Email: "jane@example.com"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := p.Issue("second", PendingSubscription{Email: "jane@example.com"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
raw, _ := os.ReadFile(path)
|
||||
if strings.Count(string(raw), "@") != 1 {
|
||||
t.Errorf("expected a single live entry after rotation, got %s", raw)
|
||||
}
|
||||
if _, ok := p.Consume("first"); ok {
|
||||
t.Error("superseded token must no longer work")
|
||||
}
|
||||
if _, ok := p.Consume("second"); !ok {
|
||||
t.Error("current token must still work")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRandomTokenIsHexAndUnique(t *testing.T) {
|
||||
a, err := RandomToken()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
b, err := RandomToken()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(a) != 64 || a == b {
|
||||
t.Errorf("tokens = %q %q, want unique 64-char hex", a, b)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user