201 lines
5.3 KiB
Go
201 lines
5.3 KiB
Go
package main
|
|
|
|
import (
|
|
"net/netip"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestPasswordGeneratorRespectsMinimums(t *testing.T) {
|
|
o := PWOptions{Length: 20, MinLower: 2, MinUpper: 2, MinDigits: 2, MinSymbols: 2, NoAmbig: true, NoSeq: true, NoRepeat: true, SymbolSet: "!@#$%"}
|
|
p, err := generateOne(o)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(p) != 20 {
|
|
t.Fatalf("length=%d", len(p))
|
|
}
|
|
var lo, up, di, sy int
|
|
for _, c := range p {
|
|
switch {
|
|
case strings.ContainsRune(lower, c):
|
|
lo++
|
|
case strings.ContainsRune(upper, c):
|
|
up++
|
|
case strings.ContainsRune(digits, c):
|
|
di++
|
|
default:
|
|
sy++
|
|
}
|
|
}
|
|
if lo < 2 || up < 2 || di < 2 || sy < 2 {
|
|
t.Fatalf("class minimums not met: %q", p)
|
|
}
|
|
}
|
|
|
|
func TestOneTimeClipDisappearsAfterReveal(t *testing.T) {
|
|
r := newRoom("test", 10)
|
|
c := &Clip{ID: "x", Room: "test", Content: "secret", Secret: true, OneTime: true, CreatedAt: time.Now().UTC()}
|
|
r.add(c)
|
|
if _, ok := r.reveal("x"); !ok {
|
|
t.Fatal("first reveal failed")
|
|
}
|
|
if _, ok := r.reveal("x"); ok {
|
|
t.Fatal("one-time clip still exists")
|
|
}
|
|
}
|
|
|
|
func TestExpiredClipIsPruned(t *testing.T) {
|
|
r := newRoom("test", 10)
|
|
exp := time.Now().UTC().Add(-time.Minute)
|
|
r.add(&Clip{ID: "old", Room: "test", Content: "x", ExpiresAt: &exp, CreatedAt: time.Now().UTC().Add(-time.Hour)})
|
|
if got := r.history(10); len(got) != 0 {
|
|
t.Fatalf("expected expired clip to be pruned, got %d", len(got))
|
|
}
|
|
}
|
|
|
|
func TestFilenameIsReducedToBase(t *testing.T) {
|
|
name, err := cleanOriginalName("../../payload.exe")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if name != "payload.exe" {
|
|
t.Fatalf("unexpected name %q", name)
|
|
}
|
|
}
|
|
|
|
func TestIPv4PrefixLastAndMask(t *testing.T) {
|
|
p, err := netip.ParsePrefix("10.20.30.40/24")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := prefixLast(p.Masked()).String(); got != "10.20.30.255" {
|
|
t.Fatalf("last=%s", got)
|
|
}
|
|
if got := prefixMask4(24); got != "255.255.255.0" {
|
|
t.Fatalf("mask=%s", got)
|
|
}
|
|
}
|
|
|
|
func TestParseSRVName(t *testing.T) {
|
|
svc, proto, name := parseSRVName("_ldap._tcp.example.local")
|
|
if svc != "ldap" || proto != "tcp" || name != "example.local" {
|
|
t.Fatalf("got %q %q %q", svc, proto, name)
|
|
}
|
|
}
|
|
|
|
func TestClipboardPersistsRoomsSecretsAndEmptyRooms(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "clipboard.json")
|
|
store := newClipboardStore(20, path, true)
|
|
if err := store.createRoom("alpha"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := store.createRoom("empty-room"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
store.room("alpha").add(&Clip{ID: "normal", Room: "alpha", Type: "text", Content: "hello", CreatedAt: time.Now().UTC()})
|
|
store.room("alpha").add(&Clip{ID: "secret", Room: "alpha", Type: "password", Content: "P@ssw0rd!", Secret: true, CreatedAt: time.Now().UTC()})
|
|
if err := store.save(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
reloaded := newClipboardStore(20, path, true)
|
|
if err := reloaded.load(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, ok := reloaded.getRoom("empty-room"); !ok {
|
|
t.Fatal("empty room was not persisted")
|
|
}
|
|
r, ok := reloaded.getRoom("alpha")
|
|
if !ok {
|
|
t.Fatal("alpha room missing after reload")
|
|
}
|
|
r.mu.RLock()
|
|
defer r.mu.RUnlock()
|
|
if len(r.clips) != 2 {
|
|
t.Fatalf("expected 2 clips after reload, got %d", len(r.clips))
|
|
}
|
|
if !r.clips[1].Secret || r.clips[1].Content != "P@ssw0rd!" {
|
|
t.Fatal("secret was not persisted correctly")
|
|
}
|
|
}
|
|
|
|
func TestClipboardClearKeepsRoomDeleteRemovesRoomPersistently(t *testing.T) {
|
|
dir := t.TempDir()
|
|
path := filepath.Join(dir, "clipboard.json")
|
|
store := newClipboardStore(20, path, true)
|
|
if err := store.createRoom("keep"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
store.room("keep").add(&Clip{ID: "x", Room: "keep", Content: "value", CreatedAt: time.Now().UTC()})
|
|
if err := store.save(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := store.clearRoom("keep"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
reloaded := newClipboardStore(20, path, true)
|
|
if err := reloaded.load(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
r, ok := reloaded.getRoom("keep")
|
|
if !ok {
|
|
t.Fatal("cleared room should still exist")
|
|
}
|
|
if got := len(r.history(10)); got != 0 {
|
|
t.Fatalf("cleared room has %d clips", got)
|
|
}
|
|
if err := reloaded.deleteRoom("keep"); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
reloadedAgain := newClipboardStore(20, path, true)
|
|
if err := reloadedAgain.load(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, ok := reloadedAgain.getRoom("keep"); ok {
|
|
t.Fatal("deleted room reappeared after reload")
|
|
}
|
|
}
|
|
|
|
func TestFileStorePersistsMetadataAndBlob(t *testing.T) {
|
|
dir := t.TempDir()
|
|
store := newFileStore(dir, 1024*1024)
|
|
if err := os.MkdirAll(store.dir, 0o700); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
id := "persisted-file"
|
|
content := []byte("persistent file data")
|
|
if err := os.WriteFile(store.filePath(id), content, 0o600); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
store.files[id] = &FileMeta{ID: id, Name: "test.txt", Size: int64(len(content)), SHA256: "dummy", UploadedAt: time.Now().UTC()}
|
|
store.mu.Lock()
|
|
if err := store.saveLocked(); err != nil {
|
|
store.mu.Unlock()
|
|
t.Fatal(err)
|
|
}
|
|
store.mu.Unlock()
|
|
|
|
reloaded := newFileStore(dir, 1024*1024)
|
|
if err := reloaded.load(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
files := reloaded.list()
|
|
if len(files) != 1 || files[0].ID != id {
|
|
t.Fatalf("file metadata not restored: %#v", files)
|
|
}
|
|
got, err := os.ReadFile(reloaded.filePath(id))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if string(got) != string(content) {
|
|
t.Fatalf("blob changed: %q", got)
|
|
}
|
|
}
|