2022-11-15 05:02:16 +01:00
package cmd
import (
2022-11-20 02:14:27 +01:00
"bufio"
"context"
"fmt"
2022-11-15 05:31:20 +01:00
"os"
2022-11-15 05:02:16 +01:00
"strings"
2022-11-20 02:14:27 +01:00
"time"
2022-11-15 05:02:16 +01:00
2022-11-20 02:14:27 +01:00
"github.com/ddworken/hishtory/client/data"
2022-11-15 05:02:16 +01:00
"github.com/ddworken/hishtory/client/hctx"
"github.com/ddworken/hishtory/client/lib"
2022-11-20 02:14:27 +01:00
"github.com/ddworken/hishtory/shared"
2022-11-15 05:02:16 +01:00
"github.com/spf13/cobra"
)
2022-11-15 05:18:22 +01:00
var GROUP_ID_MANAGEMENT string = "group_id_management"
2022-11-15 05:02:16 +01:00
var redactCmd = & cobra . Command {
2022-11-15 05:31:20 +01:00
Use : "redact" ,
Aliases : [ ] string { "delete" } ,
Short : "Query for matching commands and remove them from your shell history" ,
Long : "This removes history entries on the current machine and on all remote machines. Supports the same query format as 'hishtory query'." ,
GroupID : GROUP_ID_MANAGEMENT ,
DisableFlagParsing : true ,
2022-11-15 05:02:16 +01:00
Run : func ( cmd * cobra . Command , args [ ] string ) {
ctx := hctx . MakeContext ( )
2023-10-22 20:43:56 +02:00
skipOnlineRedaction := false
if ! lib . CanReachHishtoryServer ( ctx ) {
fmt . Printf ( "Cannot reach hishtory backend (is this device offline?) so redaction will only apply to this device and not other synced devices. Would you like to continue with a local-only redaction anyways? [y/N] " )
reader := bufio . NewReader ( os . Stdin )
resp , err := reader . ReadString ( '\n' )
lib . CheckFatalError ( err )
if strings . TrimSpace ( resp ) != "y" {
fmt . Printf ( "Aborting redact per user response of %#v\n" , strings . TrimSpace ( resp ) )
return
}
skipOnlineRedaction = true
}
2023-10-15 21:29:50 +02:00
lib . CheckFatalError ( lib . RetrieveAdditionalEntriesFromRemote ( ctx , "redact" ) )
2022-11-15 05:02:16 +01:00
lib . CheckFatalError ( lib . ProcessDeletionRequests ( ctx ) )
query := strings . Join ( args , " " )
2023-10-22 20:43:56 +02:00
lib . CheckFatalError ( redact ( ctx , query , os . Getenv ( "HISHTORY_REDACT_FORCE" ) != "" , skipOnlineRedaction ) )
2022-11-15 05:02:16 +01:00
} ,
}
2023-10-22 20:43:56 +02:00
func redact ( ctx context . Context , query string , skipUserConfirmation , skipOnlineRedaction bool ) error {
2022-11-20 02:14:27 +01:00
tx , err := lib . MakeWhereQueryFromSearch ( ctx , hctx . GetDb ( ctx ) , query )
if err != nil {
return err
}
var historyEntries [ ] * data . HistoryEntry
res := tx . Find ( & historyEntries )
if res . Error != nil {
return res . Error
}
2023-10-22 20:43:56 +02:00
if skipUserConfirmation {
2022-11-20 02:14:27 +01:00
fmt . Printf ( "Permanently deleting %d entries\n" , len ( historyEntries ) )
} else {
2023-10-22 20:43:56 +02:00
fmt . Printf ( "This will permanently delete %d entries, are you sure? [y/N] " , len ( historyEntries ) )
2022-11-20 02:14:27 +01:00
reader := bufio . NewReader ( os . Stdin )
resp , err := reader . ReadString ( '\n' )
if err != nil {
2023-09-05 21:08:55 +02:00
return fmt . Errorf ( "failed to read response: %w" , err )
2022-11-20 02:14:27 +01:00
}
if strings . TrimSpace ( resp ) != "y" {
2023-10-22 20:43:56 +02:00
fmt . Printf ( "Aborting redact per user response of %#v\n" , strings . TrimSpace ( resp ) )
2022-11-20 02:14:27 +01:00
return nil
}
}
tx , err = lib . MakeWhereQueryFromSearch ( ctx , hctx . GetDb ( ctx ) , query )
if err != nil {
return err
}
res = tx . Delete ( & data . HistoryEntry { } )
if res . Error != nil {
return res . Error
}
2023-10-22 20:34:26 +02:00
if res . RowsAffected > int64 ( len ( historyEntries ) ) + 1 || res . RowsAffected < int64 ( len ( historyEntries ) ) - 1 {
2022-11-20 02:14:27 +01:00
return fmt . Errorf ( "DB deleted %d rows, when we only expected to delete %d rows, something may have gone wrong" , res . RowsAffected , len ( historyEntries ) )
}
err = deleteOnRemoteInstances ( ctx , historyEntries )
2023-10-22 20:43:56 +02:00
if err != nil && ! skipOnlineRedaction {
2022-11-20 02:14:27 +01:00
return err
}
return nil
}
2023-09-05 21:45:17 +02:00
func deleteOnRemoteInstances ( ctx context . Context , historyEntries [ ] * data . HistoryEntry ) error {
2022-11-20 02:14:27 +01:00
config := hctx . GetConf ( ctx )
if config . IsOffline {
return nil
}
var deletionRequest shared . DeletionRequest
deletionRequest . SendTime = time . Now ( )
deletionRequest . UserId = data . UserId ( config . UserSecret )
for _ , entry := range historyEntries {
2023-09-22 22:13:46 +02:00
deletionRequest . Messages . Ids = append ( deletionRequest . Messages . Ids ,
2023-09-22 23:03:41 +02:00
shared . MessageIdentifier { DeviceId : entry . DeviceId , EndTime : entry . EndTime , EntryId : entry . EntryId } ,
2023-09-22 22:13:46 +02:00
)
2022-11-20 02:14:27 +01:00
}
2023-10-14 19:52:35 +02:00
return lib . SendDeletionRequest ( ctx , deletionRequest )
2022-11-20 02:14:27 +01:00
}
2022-11-15 05:02:16 +01:00
func init ( ) {
rootCmd . AddCommand ( redactCmd )
}