Files

93 lines
3.2 KiB
Go

package api
import (
"encoding/json"
"linkport/internal/cryptotool"
"net/http/httptest"
"strings"
"testing"
)
func TestNavicatDecryption(t *testing.T) {
f := newFixture(t)
path := "/api/v1/tools/navicat/decrypt"
body := map[string]any{"version": 12, "ciphertext": "f03a1418eb2928a948cc8c71d92edf1c"}
requireStatus(t, f.request("POST", path, body, false), 401)
f.login()
requireStatus(t, f.request("POST", path, body, false), 403)
w := f.request("POST", path, body, true)
requireStatus(t, w, 200)
if w.Header().Get("Cache-Control") != "no-store" {
t.Fatal("password response must not be cached")
}
var result struct{ Password string }
if err := json.Unmarshal(w.Body.Bytes(), &result); err != nil || result.Password != "密码🔑 test" {
t.Fatalf("unexpected decryption result: %s, %v", w.Body.String(), err)
}
w = f.request("GET", path, nil, false)
requireStatus(t, w, 405)
if w.Header().Get("Allow") != "POST" {
t.Fatal("missing allowed method")
}
for _, invalid := range []map[string]any{
{"version": 12, "ciphertext": "zz"},
{"version": 13, "ciphertext": "45"},
{"version": 12, "ciphertext": strings.Repeat("0", 70000)},
} {
requireStatus(t, f.request("POST", path, invalid, true), 400)
}
events, err := f.store.Events()
if err != nil {
t.Fatal(err)
}
raw, _ := json.Marshal(events)
if strings.Contains(string(raw), result.Password) || strings.Contains(string(raw), body["ciphertext"].(string)) {
t.Fatal("decryption data leaked to audit events")
}
}
func TestNavicatDecryptionRejectsBearer(t *testing.T) {
r := httptest.NewRequest("POST", "/api/v1/tools/navicat/decrypt", strings.NewReader(`{"version":11,"ciphertext":"45"}`))
r.Header.Set("Authorization", "Bearer test-token")
w := httptest.NewRecorder()
(&Server{}).decryptNavicat(w, r)
requireStatus(t, w, 403)
}
func TestCustomDecryption(t *testing.T) {
f := newFixture(t)
path := "/api/v1/tools/decrypt"
body := cryptotool.Options{Algorithm: "AES", Mode: "CBC", Padding: "PKCS7", Key: "libcckeylibcckey", KeyEncoding: "UTF8",
IV: "libcciv libcciv ", IVEncoding: "UTF8", InputEncoding: "Hex", OutputEncoding: "UTF8", Ciphertext: "f03a1418eb2928a948cc8c71d92edf1c"}
requireStatus(t, f.request("POST", path, body, false), 401)
f.login()
requireStatus(t, f.request("POST", path, body, false), 403)
w := f.request("POST", path, body, true)
requireStatus(t, w, 200)
var result map[string]string
if err := json.Unmarshal(w.Body.Bytes(), &result); err != nil || result["plaintext"] != "密码🔑 test" {
t.Fatalf("wrong result: %s, %v", w.Body.String(), err)
}
if w.Header().Get("Cache-Control") != "no-store" {
t.Fatal("decrypted text must not be cached")
}
requireStatus(t, f.request("GET", path, nil, false), 405)
body.IV = "libcciv libcciv"
requireStatus(t, f.request("POST", path, body, true), 400)
events, err := f.store.Events()
if err != nil {
t.Fatal(err)
}
raw, _ := json.Marshal(events)
for _, secret := range []string{body.Key, body.IV, body.Ciphertext, result["plaintext"]} {
if strings.Contains(string(raw), secret) {
t.Fatal("decryption material leaked to audit")
}
}
r := httptest.NewRequest("POST", path, nil)
r.Header.Set("Authorization", "Bearer test-token")
w = httptest.NewRecorder()
f.server.decryptCustom(w, r)
requireStatus(t, w, 403)
}