Files
dbbackup/internal/tui/confirmation.go
Renz a0e7fd71de security: Implement HIGH priority security improvements
HIGH Priority Security Features:
- Path sanitization with filepath.Clean() for all user paths
- Path traversal attack prevention in backup/restore operations
- Secure config file permissions (0600 instead of 0644)
- SHA-256 checksum generation for all backup archives
- Checksum verification during restore operations
- Comprehensive audit logging for compliance

New Security Module (internal/security/):
- paths.go: ValidateBackupPath() and ValidateArchivePath()
- checksum.go: ChecksumFile(), VerifyChecksum(), LoadAndVerifyChecksum()
- audit.go: AuditLogger with structured event tracking

Integration Points:
- Backup engine: Path validation, checksum generation
- Restore engine: Path validation, checksum verification
- All backup/restore operations: Audit logging
- Configuration saves: Audit logging

Security Enhancements:
- .dbbackup.conf now created with 0600 permissions (owner-only)
- All archive files get .sha256 checksum files
- Restore warns if checksum verification fails but continues
- Audit events logged for all administrative operations
- User tracking via $USER/$USERNAME environment variables

Compliance Features:
- Audit trail for backups, restores, config changes
- Structured logging with timestamps, users, actions, results
- Event details include paths, sizes, durations, errors

Testing:
- All code compiles successfully
- Cross-platform build verified
- Ready for integration testing
2025-11-25 12:03:21 +00:00

118 lines
2.6 KiB
Go
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package tui
import (
"context"
"fmt"
"strings"
tea "github.com/charmbracelet/bubbletea"
"dbbackup/internal/config"
"dbbackup/internal/logger"
)
// ConfirmationModel for yes/no confirmations
type ConfirmationModel struct {
config *config.Config
logger logger.Logger
parent tea.Model
ctx context.Context
title string
message string
cursor int
choices []string
confirmed bool
onConfirm func() (tea.Model, tea.Cmd) // Callback when confirmed
}
func NewConfirmationModel(cfg *config.Config, log logger.Logger, parent tea.Model, title, message string) ConfirmationModel {
return ConfirmationModel{
config: cfg,
logger: log,
parent: parent,
title: title,
message: message,
choices: []string{"Yes", "No"},
}
}
func NewConfirmationModelWithAction(cfg *config.Config, log logger.Logger, parent tea.Model, title, message string, onConfirm func() (tea.Model, tea.Cmd)) ConfirmationModel {
return ConfirmationModel{
config: cfg,
logger: log,
parent: parent,
title: title,
message: message,
choices: []string{"Yes", "No"},
onConfirm: onConfirm,
}
}
func (m ConfirmationModel) Init() tea.Cmd {
return nil
}
func (m ConfirmationModel) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyMsg:
switch msg.String() {
case "ctrl+c", "q", "esc", "n":
return m.parent, nil
case "left", "h":
if m.cursor > 0 {
m.cursor--
}
case "right", "l":
if m.cursor < len(m.choices)-1 {
m.cursor++
}
case "enter", "y":
if msg.String() == "y" || m.cursor == 0 {
m.confirmed = true
// Execute the onConfirm callback if provided
if m.onConfirm != nil {
return m.onConfirm()
}
// Default: execute cluster backup for backward compatibility
executor := NewBackupExecution(m.config, m.logger, m.parent, m.ctx, "cluster", "", 0)
return executor, executor.Init()
}
return m.parent, nil
}
}
return m, nil
}
func (m ConfirmationModel) View() string {
var s strings.Builder
header := titleStyle.Render(m.title)
s.WriteString(fmt.Sprintf("\n%s\n\n", header))
s.WriteString(fmt.Sprintf("%s\n\n", m.message))
// Show choices
for i, choice := range m.choices {
cursor := " "
if m.cursor == i {
cursor = ">"
s.WriteString(selectedStyle.Render(fmt.Sprintf("%s [%s]", cursor, choice)))
} else {
s.WriteString(fmt.Sprintf("%s [%s]", cursor, choice))
}
s.WriteString(" ")
}
s.WriteString("\n\n⌨ ←/→: Select • Enter/y: Confirm • n/ESC: Cancel\n")
return s.String()
}
func (m ConfirmationModel) IsConfirmed() bool {
return m.confirmed
}