178 lines
6.0 KiB
Go
178 lines
6.0 KiB
Go
package app
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func loginTestAdmin(t *testing.T, c *testClient) {
|
|
t.Helper()
|
|
expect(t, c.json(t, "POST", "/admin/login", map[string]string{"username": "admin", "password": "test-password"}), 200)
|
|
}
|
|
func TestAdminRuntimeBudgetsPersistAndProtectExistingFiles(t *testing.T) {
|
|
c := fixture(t, false)
|
|
expect(t, c.request(t, "GET", "/admin/runtime", nil), 401)
|
|
data := []byte("preserved file")
|
|
id, files := c.create(t, []string{"a"}, [][]byte{data}, 3, false)
|
|
c.upload(t, id, files[0], data)
|
|
code := c.publish(t, id)
|
|
loginTestAdmin(t, c)
|
|
settings, e := c.a.runtimeSettings()
|
|
if e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
settings.FileBudget = 1
|
|
expect(t, c.json(t, "PUT", "/admin/runtime", settings), 200)
|
|
expect(t, c.json(t, "POST", "/uploads", Manifest{Files: []ManifestFile{{Name: "new", Size: 1}}}), 507)
|
|
c.resolve(t, code)
|
|
expect(t, c.request(t, "GET", "/pickup/files/"+files[0]+"/download", nil), 200)
|
|
cfg := c.a.cfg
|
|
c.a.Close()
|
|
c.a.db = nil
|
|
c.a.root = nil
|
|
c.a.lock = nil
|
|
a, e := Open(cfg)
|
|
if e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
defer a.Close()
|
|
saved, e := a.runtimeSettings()
|
|
if e != nil || saved.FileBudget != 1 {
|
|
t.Fatal("runtime budget reverted on restart")
|
|
}
|
|
if scalar(t, a, "SELECT count(*) FROM objects") != 1 {
|
|
t.Fatal("reducing quota deleted existing files")
|
|
}
|
|
}
|
|
func TestAuditRetentionRecordsAndUTF8ByteBudget(t *testing.T) {
|
|
c := fixture(t, false)
|
|
settings, e := c.a.runtimeSettings()
|
|
if e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
settings.AuditRetentionDays = 2
|
|
settings.AuditMaxRecords = 3
|
|
settings.AuditMaxBytes = 1024
|
|
b, _ := json.Marshal(settings)
|
|
c.a.db.Exec("UPDATE runtime_settings SET json=? WHERE id=1", string(b))
|
|
_, e = c.a.db.Exec("INSERT INTO audit(created,action,target,source) VALUES(?,?,?,?)", c.a.now().Unix()-3*86400, "old", "", "")
|
|
if e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
for i := 0; i < 8; i++ {
|
|
c.a.audit("new", "target", "203.0.113.1")
|
|
}
|
|
if scalar(t, c.a, "SELECT count(*) FROM audit") != 3 || scalar(t, c.a, "SELECT count(*) FROM audit WHERE action='old'") != 0 {
|
|
t.Fatal("retention/count limits failed")
|
|
}
|
|
settings.AuditMaxRecords = 100
|
|
b, _ = json.Marshal(settings)
|
|
c.a.db.Exec("UPDATE runtime_settings SET json=? WHERE id=1", string(b))
|
|
for i := 0; i < 10; i++ {
|
|
c.a.audit("utf8", strings.Repeat("鸟", 60), "source")
|
|
}
|
|
actual := scalar(t, c.a, "SELECT COALESCE(sum("+auditRecordBytes+"),0) FROM audit")
|
|
ledger := scalar(t, c.a, "SELECT content_bytes FROM audit_usage WHERE id=1")
|
|
if actual != ledger || actual > 1024 {
|
|
t.Fatalf("audit bytes actual=%d ledger=%d", actual, ledger)
|
|
}
|
|
if scalar(t, c.a, "SELECT records FROM audit_usage WHERE id=1") != scalar(t, c.a, "SELECT count(*) FROM audit") {
|
|
t.Fatal("audit count ledger incorrect")
|
|
}
|
|
_, e = c.a.db.Exec("UPDATE audit SET created=?", c.a.now().Unix()-3*86400)
|
|
if e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
if e = c.a.Cleanup(); e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
if scalar(t, c.a, "SELECT count(*) FROM audit") != 0 {
|
|
t.Fatal("background cleanup did not age audit events")
|
|
}
|
|
}
|
|
func TestAnonymousIdentityAndReceiptHaveIndependentLifetimes(t *testing.T) {
|
|
c := fixture(t, false)
|
|
base := time.Now()
|
|
c.a.now = func() time.Time { return base }
|
|
var info struct {
|
|
Expires int64 `json:"visitor_expires"`
|
|
}
|
|
w := c.request(t, "GET", "/policy", nil)
|
|
expect(t, w, 200)
|
|
json.Unmarshal(w.Body.Bytes(), &info)
|
|
if info.Expires != base.Unix()+7*86400 {
|
|
t.Fatal("cookie lifetime not seven days")
|
|
}
|
|
w = c.json(t, "POST", "/uploads", Manifest{Files: []ManifestFile{{Name: "a", Size: 3}}, Days: 7, Downloads: 5, Renew: true})
|
|
expect(t, w, 201)
|
|
var receipt struct {
|
|
ID string `json:"id"`
|
|
Token string `json:"manage_token"`
|
|
Files []struct {
|
|
ID string `json:"id"`
|
|
} `json:"files"`
|
|
}
|
|
json.Unmarshal(w.Body.Bytes(), &receipt)
|
|
c.upload(t, receipt.ID, receipt.Files[0].ID, []byte("abc"))
|
|
code := c.publish(t, receipt.ID)
|
|
c.a.now = func() time.Time { return base.Add(6 * 24 * time.Hour) }
|
|
w = c.request(t, "GET", "/policy", nil)
|
|
json.Unmarshal(w.Body.Bytes(), &info)
|
|
if info.Expires != base.Unix()+7*86400 {
|
|
t.Fatal("fixed visitor lifetime unexpectedly extended")
|
|
}
|
|
c.resolve(t, code)
|
|
expect(t, c.request(t, "GET", "/pickup/files/"+receipt.Files[0].ID+"/download", nil), 200)
|
|
c.a.now = func() time.Time { return base.Add(8 * 24 * time.Hour) }
|
|
expect(t, c.request(t, "GET", "/policy", nil), 200)
|
|
w = c.request(t, "GET", "/mine", nil)
|
|
expect(t, w, 200)
|
|
if strings.TrimSpace(w.Body.String()) != "[]" {
|
|
t.Fatal("expired browser identity still owns old list")
|
|
}
|
|
r := c.makeReceiptRequest("GET", "/uploads/"+receipt.ID, receipt.Token, nil)
|
|
response := serveTest(c, r)
|
|
expect(t, response, 200)
|
|
c.a.now = func() time.Time { return base.Add(31 * 24 * time.Hour) }
|
|
if e := c.a.Cleanup(); e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
expect(t, serveTest(c, c.makeReceiptRequest("GET", "/uploads/"+receipt.ID, receipt.Token, nil)), 404)
|
|
}
|
|
func TestServiceSwitchesDoNotGiveAdminUploadOrPickupBypass(t *testing.T) {
|
|
c := fixture(t, false)
|
|
data := []byte("content")
|
|
id, files := c.create(t, []string{"a"}, [][]byte{data}, 3, false)
|
|
c.upload(t, id, files[0], data)
|
|
c.resolve(t, c.publish(t, id))
|
|
loginTestAdmin(t, c)
|
|
policy, e := c.a.policy()
|
|
if e != nil {
|
|
t.Fatal(e)
|
|
}
|
|
policy.AnonymousUpload = false
|
|
policy.AnonymousDownload = false
|
|
expect(t, c.json(t, "PUT", "/admin/policy", policy), 200)
|
|
expect(t, c.json(t, "POST", "/uploads", Manifest{Files: []ManifestFile{{Name: "a", Size: 1}}}), 403)
|
|
expect(t, c.request(t, "GET", "/pickup/files/"+files[0]+"/download", nil), 403)
|
|
expect(t, c.request(t, "GET", "/admin/stats", nil), 200)
|
|
}
|
|
|
|
func (c *testClient) makeReceiptRequest(method, path, token string, body []byte) *http.Request {
|
|
r := httptest.NewRequest(method, "http://localhost:8080/api/v1"+path, bytes.NewReader(body))
|
|
r.RemoteAddr = c.ip + ":80"
|
|
r.Header.Set("Origin", "http://localhost:8080")
|
|
r.Header.Set("Authorization", "Bearer "+token)
|
|
return r
|
|
}
|
|
func serveTest(c *testClient, r *http.Request) *httptest.ResponseRecorder {
|
|
w := httptest.NewRecorder()
|
|
c.h.ServeHTTP(w, r)
|
|
return w
|
|
}
|