feat(cli): add archive command for cross-host data transport

Bundles each browser's decryption-relevant files + Local State into a <browser-key>/<User Data> zip (forward-slash entries) for cross-host restore.
This commit is contained in:
moonD4rk
2026-06-06 20:45:06 +08:00
parent f1219e49ab
commit 96ed041fa0
10 changed files with 420 additions and 15 deletions
+58
View File
@@ -0,0 +1,58 @@
package chromium
import (
"os"
"path/filepath"
"strings"
"testing"
"github.com/moond4rk/hackbrowserdata/types"
)
func TestArchiveSources_ForwardSlashLayout(t *testing.T) {
udd := t.TempDir()
networkDir := filepath.Join(udd, "Default", "Network")
if err := os.MkdirAll(networkDir, 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(udd, "Default", "Preferences"), []byte("{}"), 0o600); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(networkDir, "Cookies"), []byte("x"), 0o600); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(udd, "Local State"), []byte("{}"), 0o600); err != nil {
t.Fatal(err)
}
b, err := NewBrowser(types.BrowserConfig{Key: "chrome", Name: "chrome", Kind: types.Chromium, UserDataDir: udd})
if err != nil || b == nil {
t.Fatalf("NewBrowser: b=%v err=%v", b, err)
}
srcs := b.ArchiveSources([]types.Category{types.Cookie})
var gotCookie, gotMarker, gotLocalState bool
for _, s := range srcs {
if strings.Contains(s.LayoutRel, `\`) {
t.Errorf("LayoutRel must be forward-slash, got %q", s.LayoutRel)
}
switch s.LayoutRel {
case "Default/Network/Cookies":
gotCookie = true
case "Default/Preferences":
gotMarker = true
case "Local State":
gotLocalState = true
}
}
if !gotCookie {
t.Errorf("missing Cookies entry with layout path, got %+v", srcs)
}
if !gotMarker {
t.Errorf("missing Preferences marker entry (needed for restore profile discovery), got %+v", srcs)
}
if !gotLocalState {
t.Errorf("missing Local State entry (User Data root file), got %+v", srcs)
}
}