mirror of
https://github.com/moonD4rk/HackBrowserData.git
synced 2026-05-19 18:58:03 +02:00
12436217ae
* feat: add filemanager session and crypto version detection * refactor: move copy logic into filemanager, remove fileutil dependency * fix: apply review suggestions for filemanager * feat: add Windows locked file tests, fix readFileContent with ReadFile+FileMapping fallback * fix: remove self-PID skip in findFileHandle to fix Windows CI test * fix: seek to file start before reading duplicated handle * fix: use full path matching in findFileHandle to avoid cross-app handle collision * test: enhance Windows copyLocked tests with write-then-read, large file, and normal copy scenarios * fix: check all errors in Windows tests, use bytes.Equal for large file comparison * fix: use stable path suffix matching to handle Windows short path names in CI
76 lines
2.1 KiB
Go
76 lines
2.1 KiB
Go
package filemanager
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"runtime"
|
|
)
|
|
|
|
// Session manages temporary files for a single browser extraction run.
|
|
// It creates an isolated temp directory and provides methods to copy
|
|
// browser files into it. Call Cleanup() when done to remove all temp files.
|
|
type Session struct {
|
|
tempDir string
|
|
}
|
|
|
|
// NewSession creates a session with a unique temporary directory.
|
|
func NewSession() (*Session, error) {
|
|
dir, err := os.MkdirTemp("", "hbd-*")
|
|
if err != nil {
|
|
return nil, fmt.Errorf("create temp dir: %w", err)
|
|
}
|
|
return &Session{tempDir: dir}, nil
|
|
}
|
|
|
|
// TempDir returns the session's temporary directory path.
|
|
func (s *Session) TempDir() string {
|
|
return s.tempDir
|
|
}
|
|
|
|
// Acquire copies a browser file (or directory) from src to dst.
|
|
// For regular files, it also copies SQLite WAL and SHM companion files
|
|
// if they exist. For directories (e.g. LevelDB), it copies the entire
|
|
// directory while skipping lock files.
|
|
//
|
|
// On Windows, if the normal copy fails (e.g. file locked by Chrome),
|
|
// it falls back to DuplicateHandle + FileMapping to bypass exclusive locks.
|
|
func (s *Session) Acquire(src, dst string, isDir bool) error {
|
|
if isDir {
|
|
return copyDir(src, dst, "lock")
|
|
}
|
|
|
|
// Try normal copy first
|
|
err := copyFile(src, dst)
|
|
if err != nil {
|
|
// Only attempt locked-file fallback on Windows where Chrome holds exclusive locks.
|
|
// On other platforms, return the original error directly.
|
|
if runtime.GOOS != "windows" {
|
|
return fmt.Errorf("copy: %w", err)
|
|
}
|
|
if err2 := copyLocked(src, dst); err2 != nil {
|
|
return errors.Join(
|
|
fmt.Errorf("copy: %w", err),
|
|
fmt.Errorf("locked copy: %w", err2),
|
|
)
|
|
}
|
|
}
|
|
|
|
// Copy SQLite WAL/SHM companion files if present
|
|
var walErrs []error
|
|
for _, suffix := range []string{"-wal", "-shm"} {
|
|
walSrc := src + suffix
|
|
if isFileExists(walSrc) {
|
|
if err := copyFile(walSrc, dst+suffix); err != nil {
|
|
walErrs = append(walErrs, fmt.Errorf("copy %s: %w", suffix, err))
|
|
}
|
|
}
|
|
}
|
|
return errors.Join(walErrs...)
|
|
}
|
|
|
|
// Cleanup removes the session's temporary directory and all its contents.
|
|
func (s *Session) Cleanup() {
|
|
os.RemoveAll(s.tempDir)
|
|
}
|