Merge remote-tracking branch 'origin/master' into sergio/handlers

This commit is contained in:
Sergio Moura
2023-09-07 09:33:42 -04:00
13 changed files with 186 additions and 173 deletions

View File

@ -198,7 +198,7 @@ func apiSubmitHandler(w http.ResponseWriter, r *http.Request) {
return nil
})
if err != nil {
panic(fmt.Errorf("failed to execute transaction to add entries to DB: %v", err))
panic(fmt.Errorf("failed to execute transaction to add entries to DB: %w", err))
}
if GLOBAL_STATSD != nil {
GLOBAL_STATSD.Count("hishtory.submit", int64(len(devices)), []string{}, 1.0)
@ -323,7 +323,7 @@ func apiGetPendingDumpRequestsHandler(w http.ResponseWriter, r *http.Request) {
checkGormResult(GLOBAL_DB.WithContext(r.Context()).Where("user_id = ? AND requesting_device_id != ?", userId, deviceId).Find(&dumpRequests))
respBody, err := json.Marshal(dumpRequests)
if err != nil {
panic(fmt.Errorf("failed to JSON marshall the dump requests: %v", err))
panic(fmt.Errorf("failed to JSON marshall the dump requests: %w", err))
}
w.Write(respBody)
}
@ -354,7 +354,7 @@ func apiSubmitDumpHandler(w http.ResponseWriter, r *http.Request) {
return nil
})
if err != nil {
panic(fmt.Errorf("failed to execute transaction to add dumped DB: %v", err))
panic(fmt.Errorf("failed to execute transaction to add dumped DB: %w", err))
}
checkGormResult(GLOBAL_DB.WithContext(ctx).Delete(&shared.DumpRequest{}, "user_id = ? AND requesting_device_id = ?", userId, requestingDeviceId))
updateUsageData(ctx, r, userId, srcDeviceId, len(entries), false)
@ -388,7 +388,7 @@ func getDeletionRequestsHandler(w http.ResponseWriter, r *http.Request) {
checkGormResult(GLOBAL_DB.WithContext(ctx).Where("user_id = ? AND destination_device_id = ?", userId, deviceId).Find(&deletionRequests))
respBody, err := json.Marshal(deletionRequests)
if err != nil {
panic(fmt.Errorf("failed to JSON marshall the dump requests: %v", err))
panic(fmt.Errorf("failed to JSON marshall the dump requests: %w", err))
}
w.Write(respBody)
}
@ -514,11 +514,11 @@ func OpenDB() (*gorm.DB, error) {
if isTestEnvironment() {
db, err := gorm.Open(sqlite.Open("file::memory:?_journal_mode=WAL&cache=shared"), &gorm.Config{})
if err != nil {
return nil, fmt.Errorf("failed to connect to the DB: %v", err)
return nil, fmt.Errorf("failed to connect to the DB: %w", err)
}
underlyingDb, err := db.DB()
if err != nil {
return nil, fmt.Errorf("failed to access underlying DB: %v", err)
return nil, fmt.Errorf("failed to access underlying DB: %w", err)
}
underlyingDb.SetMaxOpenConns(1)
db.Exec("PRAGMA journal_mode = WAL")
@ -544,7 +544,7 @@ func OpenDB() (*gorm.DB, error) {
var err error
db, err = gorm.Open(sqlite.Open(sqliteDb), &gorm.Config{Logger: customLogger})
if err != nil {
return nil, fmt.Errorf("failed to connect to the DB: %v", err)
return nil, fmt.Errorf("failed to connect to the DB: %w", err)
}
} else {
postgresDb := fmt.Sprintf(PostgresDb, os.Getenv("POSTGRESQL_PASSWORD"))
@ -558,7 +558,7 @@ func OpenDB() (*gorm.DB, error) {
}
db, err = gormtrace.Open(postgres.New(postgres.Config{Conn: sqlDb}), &gorm.Config{Logger: customLogger})
if err != nil {
return nil, fmt.Errorf("failed to connect to the DB: %v", err)
return nil, fmt.Errorf("failed to connect to the DB: %w", err)
}
}
AddDatabaseTables(db)
@ -628,12 +628,12 @@ type releaseInfo struct {
func updateReleaseVersion() error {
resp, err := http.Get("https://api.github.com/repos/ddworken/hishtory/releases/latest")
if err != nil {
return fmt.Errorf("failed to get latest release version: %v", err)
return fmt.Errorf("failed to get latest release version: %w", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("failed to read github API response body: %v", err)
return fmt.Errorf("failed to read github API response body: %w", err)
}
if resp.StatusCode == 403 && strings.Contains(string(respBody), "API rate limit exceeded for ") {
return nil
@ -644,7 +644,7 @@ func updateReleaseVersion() error {
var info releaseInfo
err = json.Unmarshal(respBody, &info)
if err != nil {
return fmt.Errorf("failed to parse github API response: %v", err)
return fmt.Errorf("failed to parse github API response: %w", err)
}
latestVersionTag := info.Name
ReleaseVersion = decrementVersionIfInvalid(latestVersionTag)
@ -680,7 +680,7 @@ func assertValidUpdate(updateInfo shared.UpdateInfo) error {
for _, url := range urls {
resp, err := http.Get(url)
if err != nil {
return fmt.Errorf("failed to retrieve URL %#v: %v", url, err)
return fmt.Errorf("failed to retrieve URL %#v: %w", url, err)
}
defer resp.Body.Close()
if resp.StatusCode == 404 {
@ -907,7 +907,7 @@ func deepCleanDatabase(ctx context.Context) {
return nil
})
if err != nil {
panic(fmt.Errorf("failed to deep clean DB: %v", err))
panic(fmt.Errorf("failed to deep clean DB: %w", err))
}
}

View File

@ -19,7 +19,7 @@ if platform.system() == 'Linux' and platform.machine() == "x86_64":
elif platform.system() == 'Linux' and platform.machine() == "aarch64":
download_url = download_options['linux_arm_64_url']
elif platform.system() == 'Linux' and platform.machine() == "armv7l":
download_url = download_options['linux_arm_64_url']
download_url = download_options['linux_arm_7_url']
elif platform.system() == 'Darwin' and platform.machine() == 'arm64':
download_url = download_options['darwin_arm_64_url']
elif platform.system() == 'Darwin' and platform.machine() == 'x86_64':

View File

@ -75,7 +75,7 @@ func (b bashTester) RunInteractiveShellRelaxed(t testing.TB, script string) (str
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
return "", fmt.Errorf("unexpected error when running commands, out=%#v, err=%#v: %v", stdout.String(), stderr.String(), err)
return "", fmt.Errorf("unexpected error when running commands, out=%#v, err=%#v: %w", stdout.String(), stderr.String(), err)
}
outStr := stdout.String()
require.NotContains(t, outStr, "hishtory fatal error", "Ran command, but hishtory had a fatal error!")
@ -105,7 +105,7 @@ func (z zshTester) RunInteractiveShellRelaxed(t testing.TB, script string) (stri
cmd.Stderr = &stderr
err := cmd.Run()
if err != nil {
return stdout.String(), fmt.Errorf("unexpected error when running command=%#v, out=%#v, err=%#v: %v", script, stdout.String(), stderr.String(), err)
return stdout.String(), fmt.Errorf("unexpected error when running command=%#v, out=%#v, err=%#v: %w", script, stdout.String(), stderr.String(), err)
}
outStr := stdout.String()
require.NotContains(t, outStr, "hishtory fatal error")
@ -1196,7 +1196,14 @@ echo other`)
func TestInstallViaPythonScriptWithCustomHishtoryPath(t *testing.T) {
defer testutils.BackupAndRestore(t)()
defer testutils.BackupAndRestoreEnv("HISHTORY_PATH")()
os.Setenv("HISHTORY_PATH", ".other-path")
altHishtoryPath := ".other-path"
os.Setenv("HISHTORY_PATH", altHishtoryPath)
// Make sure ~/$HISHTORY_PATH/ is also cleared out and empty
homedir, err := os.UserHomeDir()
require.NoError(t, err)
require.NoError(t, os.RemoveAll(path.Join(homedir, altHishtoryPath)))
testInstallViaPythonScriptChild(t, bashTester{})
}

View File

@ -28,13 +28,13 @@ var disableCmd = &cobra.Command{
},
}
func Enable(ctx *context.Context) error {
func Enable(ctx context.Context) error {
config := hctx.GetConf(ctx)
config.IsEnabled = true
return hctx.SetConfig(config)
}
func Disable(ctx *context.Context) error {
func Disable(ctx context.Context) error {
config := hctx.GetConf(ctx)
config.IsEnabled = false
return hctx.SetConfig(config)

View File

@ -129,7 +129,7 @@ func warnIfUnsupportedBashVersion() error {
cmd := exec.Command("bash", "--version")
bashVersion, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("failed to check bash version: %v", err)
return fmt.Errorf("failed to check bash version: %w", err)
}
if strings.Contains(string(bashVersion), "version 3.") {
fmt.Printf("Warning: Your current bash version does not support overriding control-r. Please upgrade to at least bash 5 to enable the control-r integration.\n")
@ -140,7 +140,7 @@ func warnIfUnsupportedBashVersion() error {
func install(secretKey string, offline bool) error {
homedir, err := os.UserHomeDir()
if err != nil {
return fmt.Errorf("failed to get user's home directory: %v", err)
return fmt.Errorf("failed to get user's home directory: %w", err)
}
err = hctx.MakeHishtoryDir()
if err != nil {
@ -201,16 +201,16 @@ func installBinary(homedir string) (string, error) {
if _, err := os.Stat(clientPath); err == nil {
err = syscall.Unlink(clientPath)
if err != nil {
return "", fmt.Errorf("failed to unlink %s for install: %v", clientPath, err)
return "", fmt.Errorf("failed to unlink %s for install: %w", clientPath, err)
}
}
err = copyFile(os.Args[0], clientPath)
if err != nil {
return "", fmt.Errorf("failed to copy hishtory binary to $PATH: %v", err)
return "", fmt.Errorf("failed to copy hishtory binary to $PATH: %w", err)
}
err = os.Chmod(clientPath, 0o700)
if err != nil {
return "", fmt.Errorf("failed to set permissions on hishtory binary: %v", err)
return "", fmt.Errorf("failed to set permissions on hishtory binary: %w", err)
}
return clientPath, nil
}
@ -236,12 +236,12 @@ func configureFish(homedir, binaryPath string) error {
}
err = os.WriteFile(getFishConfigPath(homedir), []byte(configContents), 0o644)
if err != nil {
return fmt.Errorf("failed to write config.zsh file: %v", err)
return fmt.Errorf("failed to write config.zsh file: %w", err)
}
// Check if we need to configure the fishrc
fishIsConfigured, err := isFishConfigured(homedir)
if err != nil {
return fmt.Errorf("failed to check ~/.config/fish/config.fish: %v", err)
return fmt.Errorf("failed to check ~/.config/fish/config.fish: %w", err)
}
if fishIsConfigured {
return nil
@ -249,7 +249,7 @@ func configureFish(homedir, binaryPath string) error {
// Add to fishrc
err = os.MkdirAll(path.Join(homedir, ".config/fish"), 0o744)
if err != nil {
return fmt.Errorf("failed to create fish config directory: %v", err)
return fmt.Errorf("failed to create fish config directory: %w", err)
}
return addToShellConfig(path.Join(homedir, ".config/fish/config.fish"), getFishConfigFragment(homedir))
}
@ -265,7 +265,7 @@ func isFishConfigured(homedir string) (bool, error) {
}
fishConfig, err := os.ReadFile(path.Join(homedir, ".config/fish/config.fish"))
if err != nil {
return false, fmt.Errorf("failed to read ~/.config/fish/config.fish: %v", err)
return false, fmt.Errorf("failed to read ~/.config/fish/config.fish: %w", err)
}
return strings.Contains(string(fishConfig), getFishConfigFragment(homedir)), nil
}
@ -286,12 +286,12 @@ func configureZshrc(homedir, binaryPath string) error {
}
err := os.WriteFile(getZshConfigPath(homedir), []byte(configContents), 0o644)
if err != nil {
return fmt.Errorf("failed to write config.zsh file: %v", err)
return fmt.Errorf("failed to write config.zsh file: %w", err)
}
// Check if we need to configure the zshrc
zshIsConfigured, err := isZshConfigured(homedir)
if err != nil {
return fmt.Errorf("failed to check .zshrc: %v", err)
return fmt.Errorf("failed to check .zshrc: %w", err)
}
if zshIsConfigured {
return nil
@ -318,7 +318,7 @@ func isZshConfigured(homedir string) (bool, error) {
}
bashrc, err := os.ReadFile(getZshRcPath(homedir))
if err != nil {
return false, fmt.Errorf("failed to read zshrc: %v", err)
return false, fmt.Errorf("failed to read zshrc: %w", err)
}
return strings.Contains(string(bashrc), getZshConfigFragment(homedir)), nil
}
@ -339,12 +339,12 @@ func configureBashrc(homedir, binaryPath string) error {
}
err := os.WriteFile(getBashConfigPath(homedir), []byte(configContents), 0o644)
if err != nil {
return fmt.Errorf("failed to write config.sh file: %v", err)
return fmt.Errorf("failed to write config.sh file: %w", err)
}
// Check if we need to configure the bashrc and configure it if so
bashRcIsConfigured, err := isBashRcConfigured(homedir)
if err != nil {
return fmt.Errorf("failed to check ~/.bashrc: %v", err)
return fmt.Errorf("failed to check ~/.bashrc: %w", err)
}
if !bashRcIsConfigured {
err = addToShellConfig(path.Join(homedir, ".bashrc"), getBashConfigFragment(homedir))
@ -356,7 +356,7 @@ func configureBashrc(homedir, binaryPath string) error {
if doesBashProfileNeedConfig(homedir) {
bashProfileIsConfigured, err := isBashProfileConfigured(homedir)
if err != nil {
return fmt.Errorf("failed to check ~/.bash_profile: %v", err)
return fmt.Errorf("failed to check ~/.bash_profile: %w", err)
}
if !bashProfileIsConfigured {
err = addToShellConfig(path.Join(homedir, ".bash_profile"), getBashConfigFragment(homedir))
@ -371,12 +371,12 @@ func configureBashrc(homedir, binaryPath string) error {
func addToShellConfig(shellConfigPath, configFragment string) error {
f, err := os.OpenFile(shellConfigPath, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0o644)
if err != nil {
return fmt.Errorf("failed to append to %s: %v", shellConfigPath, err)
return fmt.Errorf("failed to append to %s: %w", shellConfigPath, err)
}
defer f.Close()
_, err = f.WriteString(configFragment)
if err != nil {
return fmt.Errorf("failed to append to %s: %v", shellConfigPath, err)
return fmt.Errorf("failed to append to %s: %w", shellConfigPath, err)
}
return nil
}
@ -392,7 +392,7 @@ func isBashRcConfigured(homedir string) (bool, error) {
}
bashrc, err := os.ReadFile(path.Join(homedir, ".bashrc"))
if err != nil {
return false, fmt.Errorf("failed to read bashrc: %v", err)
return false, fmt.Errorf("failed to read bashrc: %w", err)
}
return strings.Contains(string(bashrc), getBashConfigFragment(homedir)), nil
}
@ -418,7 +418,7 @@ func isBashProfileConfigured(homedir string) (bool, error) {
}
bashrc, err := os.ReadFile(path.Join(homedir, ".bash_profile"))
if err != nil {
return false, fmt.Errorf("failed to read bash_profile: %v", err)
return false, fmt.Errorf("failed to read bash_profile: %w", err)
}
return strings.Contains(string(bashrc), getBashConfigFragment(homedir)), nil
}
@ -475,7 +475,7 @@ func copyFile(src, dst string) error {
return destination.Close()
}
func uninstall(ctx *context.Context) error {
func uninstall(ctx context.Context) error {
homedir := hctx.GetHome(ctx)
err := stripLines(path.Join(homedir, ".bashrc"), getBashConfigFragment(homedir))
if err != nil {

View File

@ -60,7 +60,7 @@ var exportCmd = &cobra.Command{
},
}
func export(ctx *context.Context, query string) {
func export(ctx context.Context, query string) {
db := hctx.GetDb(ctx)
err := lib.RetrieveAdditionalEntriesFromRemote(ctx)
if err != nil {
@ -77,7 +77,7 @@ func export(ctx *context.Context, query string) {
}
}
func query(ctx *context.Context, query string) {
func query(ctx context.Context, query string) {
db := hctx.GetDb(ctx)
err := lib.RetrieveAdditionalEntriesFromRemote(ctx)
if err != nil {
@ -94,7 +94,7 @@ func query(ctx *context.Context, query string) {
lib.CheckFatalError(lib.DisplayResults(ctx, data, numResults))
}
func displayBannerIfSet(ctx *context.Context) error {
func displayBannerIfSet(ctx context.Context) error {
respBody, err := lib.GetBanner(ctx)
if lib.IsOfflineError(err) {
return nil

View File

@ -33,7 +33,7 @@ var redactCmd = &cobra.Command{
},
}
func redact(ctx *context.Context, query string, force bool) error {
func redact(ctx context.Context, query string, force bool) error {
tx, err := lib.MakeWhereQueryFromSearch(ctx, hctx.GetDb(ctx), query)
if err != nil {
return err
@ -50,7 +50,7 @@ func redact(ctx *context.Context, query string, force bool) error {
reader := bufio.NewReader(os.Stdin)
resp, err := reader.ReadString('\n')
if err != nil {
return fmt.Errorf("failed to read response: %v", err)
return fmt.Errorf("failed to read response: %w", err)
}
if strings.TrimSpace(resp) != "y" {
fmt.Printf("Aborting delete per user response of %#v\n", strings.TrimSpace(resp))
@ -75,7 +75,7 @@ func redact(ctx *context.Context, query string, force bool) error {
return nil
}
func deleteOnRemoteInstances(ctx *context.Context, historyEntries []*data.HistoryEntry) error {
func deleteOnRemoteInstances(ctx context.Context, historyEntries []*data.HistoryEntry) error {
config := hctx.GetConf(ctx)
if config.IsOffline {
return nil

View File

@ -44,7 +44,7 @@ var presaveHistoryEntryCmd = &cobra.Command{
},
}
func maybeUploadSkippedHistoryEntries(ctx *context.Context) error {
func maybeUploadSkippedHistoryEntries(ctx context.Context) error {
config := hctx.GetConf(ctx)
if !config.HaveMissedUploads {
return nil
@ -58,7 +58,7 @@ func maybeUploadSkippedHistoryEntries(ctx *context.Context) error {
query := fmt.Sprintf("after:%s", time.Unix(config.MissedUploadTimestamp, 0).Format("2006-01-02"))
entries, err := lib.Search(ctx, db, query, 0)
if err != nil {
return fmt.Errorf("failed to retrieve history entries that haven't been uploaded yet: %v", err)
return fmt.Errorf("failed to retrieve history entries that haven't been uploaded yet: %w", err)
}
hctx.GetLogger().Infof("Uploading %d history entries that previously failed to upload (query=%#v)\n", len(entries), query)
jsonValue, err := lib.EncryptAndMarshal(config, entries)
@ -76,12 +76,12 @@ func maybeUploadSkippedHistoryEntries(ctx *context.Context) error {
config.MissedUploadTimestamp = 0
err = hctx.SetConfig(config)
if err != nil {
return fmt.Errorf("failed to mark a history entry as uploaded: %v", err)
return fmt.Errorf("failed to mark a history entry as uploaded: %w", err)
}
return nil
}
func presaveHistoryEntry(ctx *context.Context) {
func presaveHistoryEntry(ctx context.Context) {
config := hctx.GetConf(ctx)
if !config.IsEnabled {
return
@ -122,7 +122,7 @@ func presaveHistoryEntry(ctx *context.Context) {
// TODO: Consider improving this
}
func saveHistoryEntry(ctx *context.Context) {
func saveHistoryEntry(ctx context.Context) {
config := hctx.GetConf(ctx)
if !config.IsEnabled {
hctx.GetLogger().Infof("Skipping saving a history entry because hishtory is disabled\n")
@ -140,11 +140,11 @@ func saveHistoryEntry(ctx *context.Context) {
if config.BetaMode {
tx, err := lib.MakeWhereQueryFromSearch(ctx, db, "cwd:"+entry.CurrentWorkingDirectory+" start_time:"+strconv.FormatInt(entry.StartTime.Unix(), 10))
if err != nil {
lib.CheckFatalError(fmt.Errorf("failed to query for pre-saved history entries: %s", err))
lib.CheckFatalError(fmt.Errorf("failed to query for pre-saved history entries: %w", err))
}
res := tx.Delete(&data.HistoryEntry{})
if res.Error != nil {
lib.CheckFatalError(fmt.Errorf("failed to delete pre-saved history entries: %s", res.Error))
lib.CheckFatalError(fmt.Errorf("failed to delete pre-saved history entries: %w", res.Error))
}
if res.RowsAffected > 1 {
lib.CheckFatalError(fmt.Errorf("attempted to delete pre-saved entry, but something went wrong since we deleted %d rows", res.RowsAffected))
@ -218,20 +218,20 @@ func init() {
rootCmd.AddCommand(presaveHistoryEntryCmd)
}
func buildPreArgsHistoryEntry(ctx *context.Context) (*data.HistoryEntry, error) {
func buildPreArgsHistoryEntry(ctx context.Context) (*data.HistoryEntry, error) {
var entry data.HistoryEntry
// user
user, err := user.Current()
if err != nil {
return nil, fmt.Errorf("failed to build history entry: %v", err)
return nil, fmt.Errorf("failed to build history entry: %w", err)
}
entry.LocalUsername = user.Username
// cwd and homedir
cwd, homedir, err := getCwd(ctx)
if err != nil {
return nil, fmt.Errorf("failed to build history entry: %v", err)
return nil, fmt.Errorf("failed to build history entry: %w", err)
}
entry.CurrentWorkingDirectory = cwd
entry.HomeDirectory = homedir
@ -239,7 +239,7 @@ func buildPreArgsHistoryEntry(ctx *context.Context) (*data.HistoryEntry, error)
// hostname
hostname, err := os.Hostname()
if err != nil {
return nil, fmt.Errorf("failed to build history entry: %v", err)
return nil, fmt.Errorf("failed to build history entry: %w", err)
}
entry.Hostname = hostname
@ -257,7 +257,7 @@ func buildPreArgsHistoryEntry(ctx *context.Context) (*data.HistoryEntry, error)
return &entry, nil
}
func buildHistoryEntry(ctx *context.Context, args []string) (*data.HistoryEntry, error) {
func buildHistoryEntry(ctx context.Context, args []string) (*data.HistoryEntry, error) {
if len(args) < 6 {
hctx.GetLogger().Warnf("buildHistoryEntry called with args=%#v, which has too few entries! This can happen in specific edge cases for newly opened terminals and is likely not a problem.", args)
return nil, nil
@ -272,14 +272,14 @@ func buildHistoryEntry(ctx *context.Context, args []string) (*data.HistoryEntry,
// exitCode
exitCode, err := strconv.Atoi(args[3])
if err != nil {
return nil, fmt.Errorf("failed to build history entry: %v", err)
return nil, fmt.Errorf("failed to build history entry: %w", err)
}
entry.ExitCode = exitCode
// start time
seconds, err := parseCrossPlatformInt(args[5])
if err != nil {
return nil, fmt.Errorf("failed to parse start time %s as int: %v", args[5], err)
return nil, fmt.Errorf("failed to parse start time %s as int: %w", args[5], err)
}
entry.StartTime = time.Unix(seconds, 0)
@ -290,11 +290,11 @@ func buildHistoryEntry(ctx *context.Context, args []string) (*data.HistoryEntry,
if shell == "bash" {
cmd, err := getLastCommand(args[4])
if err != nil {
return nil, fmt.Errorf("failed to build history entry: %v", err)
return nil, fmt.Errorf("failed to build history entry: %w", err)
}
shouldBeSkipped, err := shouldSkipHiddenCommand(ctx, args[4])
if err != nil {
return nil, fmt.Errorf("failed to check if command was hidden: %v", err)
return nil, fmt.Errorf("failed to check if command was hidden: %w", err)
}
if shouldBeSkipped || strings.HasPrefix(cmd, " ") {
// Don't save commands that start with a space
@ -327,7 +327,7 @@ func trimTrailingWhitespace(s string) string {
return strings.TrimSuffix(strings.TrimSuffix(s, "\n"), " ")
}
func buildCustomColumns(ctx *context.Context) (data.CustomColumns, error) {
func buildCustomColumns(ctx context.Context) (data.CustomColumns, error) {
ccs := data.CustomColumns{}
config := hctx.GetConf(ctx)
for _, cc := range config.CustomColumns {
@ -443,7 +443,7 @@ func maybeSkipBashHistTimePrefix(cmdLine string) (string, error) {
}
re, err := regexp.Compile("^" + buildRegexFromTimeFormat(format))
if err != nil {
return "", fmt.Errorf("failed to parse regex for HISTTIMEFORMAT variable: %v", err)
return "", fmt.Errorf("failed to parse regex for HISTTIMEFORMAT variable: %w", err)
}
return re.ReplaceAllLiteralString(cmdLine, ""), nil
}
@ -465,7 +465,7 @@ func getLastCommand(history string) (string, error) {
return split[1], nil
}
func shouldSkipHiddenCommand(ctx *context.Context, historyLine string) (bool, error) {
func shouldSkipHiddenCommand(ctx context.Context, historyLine string) (bool, error) {
config := hctx.GetConf(ctx)
if config.LastSavedHistoryLine == historyLine {
return true, nil
@ -478,10 +478,10 @@ func shouldSkipHiddenCommand(ctx *context.Context, historyLine string) (bool, er
return false, nil
}
func getCwd(ctx *context.Context) (string, string, error) {
func getCwd(ctx context.Context) (string, string, error) {
cwd, err := getCwdWithoutSubstitution()
if err != nil {
return "", "", fmt.Errorf("failed to get cwd for last command: %v", err)
return "", "", fmt.Errorf("failed to get cwd for last command: %w", err)
}
homedir := hctx.GetHome(ctx)
if cwd == homedir {

View File

@ -96,16 +96,16 @@ func makeAead(userSecret string) (cipher.AEAD, error) {
func Encrypt(userSecret string, data, additionalData []byte) ([]byte, []byte, error) {
aead, err := makeAead(userSecret)
if err != nil {
return []byte{}, []byte{}, fmt.Errorf("failed to make AEAD: %v", err)
return []byte{}, []byte{}, fmt.Errorf("failed to make AEAD: %w", err)
}
nonce := make([]byte, 12)
if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
return []byte{}, []byte{}, fmt.Errorf("failed to read a nonce: %v", err)
return []byte{}, []byte{}, fmt.Errorf("failed to read a nonce: %w", err)
}
ciphertext := aead.Seal(nil, nonce, data, additionalData)
_, err = aead.Open(nil, nonce, ciphertext, additionalData)
if err != nil {
return []byte{}, []byte{}, fmt.Errorf("failed to open AEAD: %v", err)
return []byte{}, []byte{}, fmt.Errorf("failed to open AEAD: %w", err)
}
return ciphertext, nonce, nil
}
@ -113,11 +113,11 @@ func Encrypt(userSecret string, data, additionalData []byte) ([]byte, []byte, er
func Decrypt(userSecret string, data, additionalData, nonce []byte) ([]byte, error) {
aead, err := makeAead(userSecret)
if err != nil {
return []byte{}, fmt.Errorf("failed to make AEAD: %v", err)
return []byte{}, fmt.Errorf("failed to make AEAD: %w", err)
}
plaintext, err := aead.Open(nil, nonce, data, additionalData)
if err != nil {
return []byte{}, fmt.Errorf("failed to decrypt: %v", err)
return []byte{}, fmt.Errorf("failed to decrypt: %w", err)
}
return plaintext, nil
}

View File

@ -30,7 +30,7 @@ func GetLogger() *logrus.Logger {
getLoggerOnce.Do(func() {
homedir, err := os.UserHomeDir()
if err != nil {
panic(fmt.Errorf("failed to get user's home directory: %v", err))
panic(fmt.Errorf("failed to get user's home directory: %w", err))
}
err = MakeHishtoryDir()
if err != nil {
@ -59,11 +59,11 @@ func GetLogger() *logrus.Logger {
func MakeHishtoryDir() error {
homedir, err := os.UserHomeDir()
if err != nil {
return fmt.Errorf("failed to get user's home directory: %v", err)
return fmt.Errorf("failed to get user's home directory: %w", err)
}
err = os.MkdirAll(path.Join(homedir, data.GetHishtoryPath()), 0o744)
if err != nil {
return fmt.Errorf("failed to create ~/%s dir: %v", data.GetHishtoryPath(), err)
return fmt.Errorf("failed to create ~/%s dir: %w", data.GetHishtoryPath(), err)
}
return nil
}
@ -71,7 +71,7 @@ func MakeHishtoryDir() error {
func OpenLocalSqliteDb() (*gorm.DB, error) {
homedir, err := os.UserHomeDir()
if err != nil {
return nil, fmt.Errorf("failed to get user's home directory: %v", err)
return nil, fmt.Errorf("failed to get user's home directory: %w", err)
}
err = MakeHishtoryDir()
if err != nil {
@ -90,7 +90,7 @@ func OpenLocalSqliteDb() (*gorm.DB, error) {
dsn := fmt.Sprintf("file:%s?mode=rwc&_journal_mode=WAL", dbFilePath)
db, err := gorm.Open(sqlite.Open(dsn), &gorm.Config{SkipDefaultTransaction: true, Logger: newLogger})
if err != nil {
return nil, fmt.Errorf("failed to connect to the DB: %v", err)
return nil, fmt.Errorf("failed to connect to the DB: %w", err)
}
tx, err := db.DB()
if err != nil {
@ -108,44 +108,50 @@ func OpenLocalSqliteDb() (*gorm.DB, error) {
type hishtoryContextKey string
func MakeContext() *context.Context {
const (
configCtxKey hishtoryContextKey = "config"
dbCtxKey hishtoryContextKey = "db"
homedirCtxKey hishtoryContextKey = "homedir"
)
func MakeContext() context.Context {
ctx := context.Background()
config, err := GetConfig()
if err != nil {
panic(fmt.Errorf("failed to retrieve config: %v", err))
panic(fmt.Errorf("failed to retrieve config: %w", err))
}
ctx = context.WithValue(ctx, hishtoryContextKey("config"), config)
ctx = context.WithValue(ctx, configCtxKey, config)
db, err := OpenLocalSqliteDb()
if err != nil {
panic(fmt.Errorf("failed to open local DB: %v", err))
panic(fmt.Errorf("failed to open local DB: %w", err))
}
ctx = context.WithValue(ctx, hishtoryContextKey("db"), db)
ctx = context.WithValue(ctx, dbCtxKey, db)
homedir, err := os.UserHomeDir()
if err != nil {
panic(fmt.Errorf("failed to get homedir: %v", err))
panic(fmt.Errorf("failed to get homedir: %w", err))
}
ctx = context.WithValue(ctx, hishtoryContextKey("homedir"), homedir)
return &ctx
ctx = context.WithValue(ctx, homedirCtxKey, homedir)
return ctx
}
func GetConf(ctx *context.Context) ClientConfig {
v := (*ctx).Value(hishtoryContextKey("config"))
func GetConf(ctx context.Context) ClientConfig {
v := ctx.Value(configCtxKey)
if v != nil {
return v.(ClientConfig)
}
panic(fmt.Errorf("failed to find config in ctx"))
}
func GetDb(ctx *context.Context) *gorm.DB {
v := (*ctx).Value(hishtoryContextKey("db"))
func GetDb(ctx context.Context) *gorm.DB {
v := ctx.Value(dbCtxKey)
if v != nil {
return v.(*gorm.DB)
}
panic(fmt.Errorf("failed to find db in ctx"))
}
func GetHome(ctx *context.Context) string {
v := (*ctx).Value(hishtoryContextKey("homedir"))
func GetHome(ctx context.Context) string {
v := ctx.Value(homedirCtxKey)
if v != nil {
return v.(string)
}
@ -191,20 +197,20 @@ type CustomColumnDefinition struct {
func GetConfigContents() ([]byte, error) {
homedir, err := os.UserHomeDir()
if err != nil {
return nil, fmt.Errorf("failed to retrieve homedir: %v", err)
return nil, fmt.Errorf("failed to retrieve homedir: %w", err)
}
dat, err := os.ReadFile(path.Join(homedir, data.GetHishtoryPath(), data.CONFIG_PATH))
if err != nil {
files, err := os.ReadDir(path.Join(homedir, data.GetHishtoryPath()))
if err != nil {
return nil, fmt.Errorf("failed to read config file (and failed to list too): %v", err)
return nil, fmt.Errorf("failed to read config file (and failed to list too): %w", err)
}
filenames := ""
for _, file := range files {
filenames += file.Name()
filenames += ", "
}
return nil, fmt.Errorf("failed to read config file (files in HISHTORY_PATH: %s): %v", filenames, err)
return nil, fmt.Errorf("failed to read config file (files in HISHTORY_PATH: %s): %w", filenames, err)
}
return dat, nil
}
@ -217,7 +223,7 @@ func GetConfig() (ClientConfig, error) {
var config ClientConfig
err = json.Unmarshal(data, &config)
if err != nil {
return ClientConfig{}, fmt.Errorf("failed to parse config file: %v", err)
return ClientConfig{}, fmt.Errorf("failed to parse config file: %w", err)
}
if config.DisplayedColumns == nil || len(config.DisplayedColumns) == 0 {
config.DisplayedColumns = []string{"Hostname", "CWD", "Timestamp", "Runtime", "Exit Code", "Command"}
@ -231,11 +237,11 @@ func GetConfig() (ClientConfig, error) {
func SetConfig(config ClientConfig) error {
serializedConfig, err := json.Marshal(config)
if err != nil {
return fmt.Errorf("failed to serialize config: %v", err)
return fmt.Errorf("failed to serialize config: %w", err)
}
homedir, err := os.UserHomeDir()
if err != nil {
return fmt.Errorf("failed to retrieve homedir: %v", err)
return fmt.Errorf("failed to retrieve homedir: %w", err)
}
err = MakeHishtoryDir()
if err != nil {
@ -245,11 +251,11 @@ func SetConfig(config ClientConfig) error {
stagedConfigPath := configPath + ".tmp-" + uuid.Must(uuid.NewRandom()).String()
err = os.WriteFile(stagedConfigPath, serializedConfig, 0o644)
if err != nil {
return fmt.Errorf("failed to write config: %v", err)
return fmt.Errorf("failed to write config: %w", err)
}
err = os.Rename(stagedConfigPath, configPath)
if err != nil {
return fmt.Errorf("failed to replace config file with the updated version: %v", err)
return fmt.Errorf("failed to replace config file with the updated version: %w", err)
}
return nil
}

View File

@ -66,7 +66,7 @@ func Setup(userSecret string, isOffline bool) error {
config.IsOffline = isOffline
err := hctx.SetConfig(config)
if err != nil {
return fmt.Errorf("failed to persist config to disk: %v", err)
return fmt.Errorf("failed to persist config to disk: %w", err)
}
// Drop all existing data
@ -82,22 +82,22 @@ func Setup(userSecret string, isOffline bool) error {
}
_, err = ApiGet("/api/v1/register?user_id=" + data.UserId(userSecret) + "&device_id=" + config.DeviceId)
if err != nil {
return fmt.Errorf("failed to register device with backend: %v", err)
return fmt.Errorf("failed to register device with backend: %w", err)
}
respBody, err := ApiGet("/api/v1/bootstrap?user_id=" + data.UserId(userSecret) + "&device_id=" + config.DeviceId)
if err != nil {
return fmt.Errorf("failed to bootstrap device from the backend: %v", err)
return fmt.Errorf("failed to bootstrap device from the backend: %w", err)
}
var retrievedEntries []*shared.EncHistoryEntry
err = json.Unmarshal(respBody, &retrievedEntries)
if err != nil {
return fmt.Errorf("failed to load JSON response: %v", err)
return fmt.Errorf("failed to load JSON response: %w", err)
}
for _, entry := range retrievedEntries {
decEntry, err := data.DecryptHistoryEntry(userSecret, *entry)
if err != nil {
return fmt.Errorf("failed to decrypt history entry from server: %v", err)
return fmt.Errorf("failed to decrypt history entry from server: %w", err)
}
AddToDbIfNew(db, decEntry)
}
@ -122,7 +122,7 @@ func AddToDbIfNew(db *gorm.DB, entry data.HistoryEntry) {
}
}
func getCustomColumnValue(ctx *context.Context, header string, entry data.HistoryEntry) (string, error) {
func getCustomColumnValue(ctx context.Context, header string, entry data.HistoryEntry) (string, error) {
for _, c := range entry.CustomColumns {
if strings.EqualFold(c.Name, header) {
return c.Val, nil
@ -137,7 +137,7 @@ func getCustomColumnValue(ctx *context.Context, header string, entry data.Histor
return "", fmt.Errorf("failed to find a column matching the column name %#v (is there a typo?)", header)
}
func buildTableRow(ctx *context.Context, columnNames []string, entry data.HistoryEntry) ([]string, error) {
func buildTableRow(ctx context.Context, columnNames []string, entry data.HistoryEntry) ([]string, error) {
row := make([]string, 0)
for _, header := range columnNames {
switch header {
@ -179,7 +179,7 @@ func stringArrayToAnyArray(arr []string) []any {
return ret
}
func DisplayResults(ctx *context.Context, results []*data.HistoryEntry, numResults int) error {
func DisplayResults(ctx context.Context, results []*data.HistoryEntry, numResults int) error {
config := hctx.GetConf(ctx)
headerFmt := color.New(color.FgGreen, color.Underline).SprintfFunc()
@ -212,7 +212,7 @@ func DisplayResults(ctx *context.Context, results []*data.HistoryEntry, numResul
return nil
}
func IsEnabled(ctx *context.Context) (bool, error) {
func IsEnabled(ctx context.Context) (bool, error) {
return hctx.GetConf(ctx).IsEnabled, nil
}
@ -242,7 +242,7 @@ func isBashWeirdness(cmd string) bool {
return firstCommandBugRegex.MatchString(cmd)
}
func ImportHistory(ctx *context.Context, shouldReadStdin, force bool) (int, error) {
func ImportHistory(ctx context.Context, shouldReadStdin, force bool) (int, error) {
config := hctx.GetConf(ctx)
if config.HaveCompletedInitialImport && !force {
// Don't run an import if we already have run one. This avoids importing the same entry multiple times.
@ -252,30 +252,30 @@ func ImportHistory(ctx *context.Context, shouldReadStdin, force bool) (int, erro
bashHistPath := filepath.Join(homedir, ".bash_history")
historyEntries, err := readFileToArray(bashHistPath)
if err != nil {
return 0, fmt.Errorf("failed to parse bash history: %v", err)
return 0, fmt.Errorf("failed to parse bash history: %w", err)
}
zshHistPath := filepath.Join(homedir, ".zsh_history")
extraEntries, err := readFileToArray(zshHistPath)
if err != nil {
return 0, fmt.Errorf("failed to parse zsh history: %v", err)
return 0, fmt.Errorf("failed to parse zsh history: %w", err)
}
historyEntries = append(historyEntries, extraEntries...)
extraEntries, err = parseFishHistory(homedir)
if err != nil {
return 0, fmt.Errorf("failed to parse fish history: %v", err)
return 0, fmt.Errorf("failed to parse fish history: %w", err)
}
historyEntries = append(historyEntries, extraEntries...)
if histfile := os.Getenv("HISTFILE"); histfile != "" && histfile != zshHistPath && histfile != bashHistPath {
extraEntries, err := readFileToArray(histfile)
if err != nil {
return 0, fmt.Errorf("failed to parse histfile: %v", err)
return 0, fmt.Errorf("failed to parse histfile: %w", err)
}
historyEntries = append(historyEntries, extraEntries...)
}
if shouldReadStdin {
extraEntries, err = readStdin()
if err != nil {
return 0, fmt.Errorf("failed to read stdin: %v", err)
return 0, fmt.Errorf("failed to read stdin: %w", err)
}
historyEntries = append(historyEntries, extraEntries...)
}
@ -307,17 +307,17 @@ func ImportHistory(ctx *context.Context, shouldReadStdin, force bool) (int, erro
}
err = ReliableDbCreate(db, entry)
if err != nil {
return 0, fmt.Errorf("failed to insert imported history entry: %v", err)
return 0, fmt.Errorf("failed to insert imported history entry: %w", err)
}
}
err = Reupload(ctx)
if err != nil {
return 0, fmt.Errorf("failed to upload hishtory import: %v", err)
return 0, fmt.Errorf("failed to upload hishtory import: %w", err)
}
config.HaveCompletedInitialImport = true
err = hctx.SetConfig(config)
if err != nil {
return 0, fmt.Errorf("failed to mark initial import as completed, this may lead to duplicate history entries: %v", err)
return 0, fmt.Errorf("failed to mark initial import as completed, this may lead to duplicate history entries: %w", err)
}
// Trigger a checkpoint so that these bulk entries are added from the WAL to the main DB
db.Exec("PRAGMA wal_checkpoint")
@ -386,12 +386,12 @@ func readFileToArray(path string) ([]string, error) {
func GetDownloadData() (shared.UpdateInfo, error) {
respBody, err := ApiGet("/api/v1/download")
if err != nil {
return shared.UpdateInfo{}, fmt.Errorf("failed to download update info: %v", err)
return shared.UpdateInfo{}, fmt.Errorf("failed to download update info: %w", err)
}
var downloadData shared.UpdateInfo
err = json.Unmarshal(respBody, &downloadData)
if err != nil {
return shared.UpdateInfo{}, fmt.Errorf("failed to parse update info: %v", err)
return shared.UpdateInfo{}, fmt.Errorf("failed to parse update info: %w", err)
}
return downloadData, nil
}
@ -404,7 +404,7 @@ func getTmpClientPath() string {
return path.Join(tmpDir, "hishtory-client")
}
func Update(ctx *context.Context) error {
func Update(ctx context.Context) error {
// Download the binary
downloadData, err := GetDownloadData()
if err != nil {
@ -438,7 +438,7 @@ func Update(ctx *context.Context) error {
homedir := hctx.GetHome(ctx)
err = syscall.Unlink(path.Join(homedir, data.GetHishtoryPath(), "hishtory"))
if err != nil {
return fmt.Errorf("failed to unlink %s for update: %v", path.Join(homedir, data.GetHishtoryPath(), "hishtory"), err)
return fmt.Errorf("failed to unlink %s for update: %w", path.Join(homedir, data.GetHishtoryPath(), "hishtory"), err)
}
}
@ -450,7 +450,7 @@ func Update(ctx *context.Context) error {
cmd.Stderr = &stderr
err = cmd.Run()
if err != nil {
return fmt.Errorf("failed to chmod +x the update (stdout=%#v, stderr=%#v): %v", stdout.String(), stderr.String(), err)
return fmt.Errorf("failed to chmod +x the update (stdout=%#v, stderr=%#v): %w", stdout.String(), stderr.String(), err)
}
cmd = exec.Command(getTmpClientPath(), "install")
cmd.Stdout = os.Stdout
@ -458,13 +458,13 @@ func Update(ctx *context.Context) error {
cmd.Stdin = os.Stdin
err = cmd.Run()
if err != nil {
return fmt.Errorf("failed to install update (stderr=%#v), is %s in a noexec directory? (if so, set the TMPDIR environment variable): %v", stderr.String(), getTmpClientPath(), err)
return fmt.Errorf("failed to install update (stderr=%#v), is %s in a noexec directory? (if so, set the TMPDIR environment variable): %w", stderr.String(), getTmpClientPath(), err)
}
fmt.Printf("Successfully updated hishtory from v0.%s to %s\n", Version, downloadData.Version)
return nil
}
func verifyBinaryMac(ctx *context.Context, binaryPath string, downloadData shared.UpdateInfo) error {
func verifyBinaryMac(ctx context.Context, binaryPath string, downloadData shared.UpdateInfo) error {
// On Mac, binary verification is a bit more complicated since mac binaries are code
// signed. To verify a signed binary, we:
// 1. Download the unsigned binary
@ -550,7 +550,7 @@ func stripCodeSignature(inPath, outPath string) error {
cmd.Stderr = &stderr
err = cmd.Run()
if err != nil {
return fmt.Errorf("failed to use codesign_allocate to strip signatures on binary=%v (stdout=%#v, stderr%#v): %v", inPath, stdout.String(), stderr.String(), err)
return fmt.Errorf("failed to use codesign_allocate to strip signatures on binary=%v (stdout=%#v, stderr%#v): %w", inPath, stdout.String(), stderr.String(), err)
}
return nil
}
@ -591,7 +591,7 @@ func downloadFile(filename, url string) error {
// Download the data
resp, err := http.Get(url)
if err != nil {
return fmt.Errorf("failed to download file at %s to %s: %v", url, filename, err)
return fmt.Errorf("failed to download file at %s to %s: %w", url, filename, err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
@ -609,7 +609,7 @@ func downloadFile(filename, url string) error {
// Create the file
out, err := os.Create(filename)
if err != nil {
return fmt.Errorf("failed to save file to %s: %v", filename, err)
return fmt.Errorf("failed to save file to %s: %w", filename, err)
}
defer out.Close()
@ -636,12 +636,12 @@ func ApiGet(path string) ([]byte, error) {
start := time.Now()
req, err := http.NewRequest("GET", getServerHostname()+path, nil)
if err != nil {
return nil, fmt.Errorf("failed to create GET: %v", err)
return nil, fmt.Errorf("failed to create GET: %w", err)
}
req.Header.Set("X-Hishtory-Version", "v0."+Version)
resp, err := httpClient().Do(req)
if err != nil {
return nil, fmt.Errorf("failed to GET %s%s: %v", getServerHostname(), path, err)
return nil, fmt.Errorf("failed to GET %s%s: %w", getServerHostname(), path, err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
@ -649,7 +649,7 @@ func ApiGet(path string) ([]byte, error) {
}
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response body from GET %s%s: %v", getServerHostname(), path, err)
return nil, fmt.Errorf("failed to read response body from GET %s%s: %w", getServerHostname(), path, err)
}
duration := time.Since(start)
hctx.GetLogger().Infof("ApiGet(%#v): %s\n", path, duration.String())
@ -663,13 +663,13 @@ func ApiPost(path, contentType string, data []byte) ([]byte, error) {
start := time.Now()
req, err := http.NewRequest("POST", getServerHostname()+path, bytes.NewBuffer(data))
if err != nil {
return nil, fmt.Errorf("failed to create POST: %v", err)
return nil, fmt.Errorf("failed to create POST: %w", err)
}
req.Header.Set("Content-Type", contentType)
req.Header.Set("X-Hishtory-Version", "v0."+Version)
resp, err := httpClient().Do(req)
if err != nil {
return nil, fmt.Errorf("failed to POST %s: %v", path, err)
return nil, fmt.Errorf("failed to POST %s: %w", path, err)
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
@ -677,7 +677,7 @@ func ApiPost(path, contentType string, data []byte) ([]byte, error) {
}
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response body from POST %s: %v", path, err)
return nil, fmt.Errorf("failed to read response body from POST %s: %w", path, err)
}
duration := time.Since(start)
hctx.GetLogger().Infof("ApiPost(%#v): %s\n", path, duration.String())
@ -721,13 +721,13 @@ func ReliableDbCreate(db *gorm.DB, entry interface{}) error {
return nil
}
}
return fmt.Errorf("unrecoverable sqlite error: %v", err)
return fmt.Errorf("unrecoverable sqlite error: %w", err)
}
if err != nil && err.Error() != "database is locked (5) (SQLITE_BUSY)" {
return fmt.Errorf("unrecoverable sqlite error: %v", err)
return fmt.Errorf("unrecoverable sqlite error: %w", err)
}
}
return fmt.Errorf("failed to create DB entry even with %d retries: %v", i, err)
return fmt.Errorf("failed to create DB entry even with %d retries: %w", i, err)
}
func EncryptAndMarshal(config hctx.ClientConfig, entries []*data.HistoryEntry) ([]byte, error) {
@ -742,34 +742,34 @@ func EncryptAndMarshal(config hctx.ClientConfig, entries []*data.HistoryEntry) (
}
jsonValue, err := json.Marshal(encEntries)
if err != nil {
return jsonValue, fmt.Errorf("failed to marshal encrypted history entry: %v", err)
return jsonValue, fmt.Errorf("failed to marshal encrypted history entry: %w", err)
}
return jsonValue, nil
}
func Reupload(ctx *context.Context) error {
func Reupload(ctx context.Context) error {
config := hctx.GetConf(ctx)
if config.IsOffline {
return nil
}
entries, err := Search(ctx, hctx.GetDb(ctx), "", 0)
if err != nil {
return fmt.Errorf("failed to reupload due to failed search: %v", err)
return fmt.Errorf("failed to reupload due to failed search: %w", err)
}
for _, chunk := range shared.Chunks(entries, 100) {
jsonValue, err := EncryptAndMarshal(config, chunk)
if err != nil {
return fmt.Errorf("failed to reupload due to failed encryption: %v", err)
return fmt.Errorf("failed to reupload due to failed encryption: %w", err)
}
_, err = ApiPost("/api/v1/submit?source_device_id="+config.DeviceId, "application/json", jsonValue)
if err != nil {
return fmt.Errorf("failed to reupload due to failed POST: %v", err)
return fmt.Errorf("failed to reupload due to failed POST: %w", err)
}
}
return nil
}
func RetrieveAdditionalEntriesFromRemote(ctx *context.Context) error {
func RetrieveAdditionalEntriesFromRemote(ctx context.Context) error {
db := hctx.GetDb(ctx)
config := hctx.GetConf(ctx)
if config.IsOffline {
@ -785,19 +785,19 @@ func RetrieveAdditionalEntriesFromRemote(ctx *context.Context) error {
var retrievedEntries []*shared.EncHistoryEntry
err = json.Unmarshal(respBody, &retrievedEntries)
if err != nil {
return fmt.Errorf("failed to load JSON response: %v", err)
return fmt.Errorf("failed to load JSON response: %w", err)
}
for _, entry := range retrievedEntries {
decEntry, err := data.DecryptHistoryEntry(config.UserSecret, *entry)
if err != nil {
return fmt.Errorf("failed to decrypt history entry from server: %v", err)
return fmt.Errorf("failed to decrypt history entry from server: %w", err)
}
AddToDbIfNew(db, decEntry)
}
return ProcessDeletionRequests(ctx)
}
func ProcessDeletionRequests(ctx *context.Context) error {
func ProcessDeletionRequests(ctx context.Context) error {
config := hctx.GetConf(ctx)
if config.IsOffline {
return nil
@ -819,14 +819,14 @@ func ProcessDeletionRequests(ctx *context.Context) error {
for _, entry := range request.Messages.Ids {
res := db.Where("device_id = ? AND end_time = ?", entry.DeviceId, entry.Date).Delete(&data.HistoryEntry{})
if res.Error != nil {
return fmt.Errorf("DB error: %v", res.Error)
return fmt.Errorf("DB error: %w", res.Error)
}
}
}
return nil
}
func GetBanner(ctx *context.Context) ([]byte, error) {
func GetBanner(ctx context.Context) ([]byte, error) {
config := hctx.GetConf(ctx)
if config.IsOffline {
return []byte{}, nil
@ -840,10 +840,10 @@ func parseTimeGenerously(input string) (time.Time, error) {
return dateparse.ParseLocal(input)
}
func MakeWhereQueryFromSearch(ctx *context.Context, db *gorm.DB, query string) (*gorm.DB, error) {
func MakeWhereQueryFromSearch(ctx context.Context, db *gorm.DB, query string) (*gorm.DB, error) {
tokens, err := tokenize(query)
if err != nil {
return nil, fmt.Errorf("failed to tokenize query: %v", err)
return nil, fmt.Errorf("failed to tokenize query: %w", err)
}
tx := db.Model(&data.HistoryEntry{}).Where("true")
for _, token := range tokens {
@ -883,7 +883,7 @@ func MakeWhereQueryFromSearch(ctx *context.Context, db *gorm.DB, query string) (
return tx, nil
}
func Search(ctx *context.Context, db *gorm.DB, query string, limit int) ([]*data.HistoryEntry, error) {
func Search(ctx context.Context, db *gorm.DB, query string, limit int) ([]*data.HistoryEntry, error) {
if ctx == nil && query != "" {
return nil, fmt.Errorf("lib.Search called with a nil context and a non-empty query (this should never happen)")
}
@ -903,7 +903,7 @@ func Search(ctx *context.Context, db *gorm.DB, query string, limit int) ([]*data
var historyEntries []*data.HistoryEntry
result := tx.Find(&historyEntries)
if result.Error != nil {
return nil, fmt.Errorf("DB query error: %v", result.Error)
return nil, fmt.Errorf("DB query error: %w", result.Error)
}
return historyEntries, nil
}
@ -913,7 +913,7 @@ func parseNonAtomizedToken(token string) (string, interface{}, interface{}, inte
return "(command LIKE ? OR hostname LIKE ? OR current_working_directory LIKE ?)", wildcardedToken, wildcardedToken, wildcardedToken, nil
}
func parseAtomizedToken(ctx *context.Context, token string) (string, interface{}, interface{}, error) {
func parseAtomizedToken(ctx context.Context, token string) (string, interface{}, interface{}, error) {
splitToken := splitEscaped(token, ':', 2)
field := unescape(splitToken[0])
val := unescape(splitToken[1])
@ -931,13 +931,13 @@ func parseAtomizedToken(ctx *context.Context, token string) (string, interface{}
case "before":
t, err := parseTimeGenerously(val)
if err != nil {
return "", nil, nil, fmt.Errorf("failed to parse before:%s as a timestamp: %v", val, err)
return "", nil, nil, fmt.Errorf("failed to parse before:%s as a timestamp: %w", val, err)
}
return "(CAST(strftime(\"%s\",start_time) AS INTEGER) < ?)", t.Unix(), nil, nil
case "after":
t, err := parseTimeGenerously(val)
if err != nil {
return "", nil, nil, fmt.Errorf("failed to parse after:%s as a timestamp: %v", val, err)
return "", nil, nil, fmt.Errorf("failed to parse after:%s as a timestamp: %w", val, err)
}
return "(CAST(strftime(\"%s\",start_time) AS INTEGER) > ?)", t.Unix(), nil, nil
case "start_time":
@ -945,7 +945,7 @@ func parseAtomizedToken(ctx *context.Context, token string) (string, interface{}
// internally for pre-saving history entries.
t, err := parseTimeGenerously(val)
if err != nil {
return "", nil, nil, fmt.Errorf("failed to parse after:%s as a timestamp: %v", val, err)
return "", nil, nil, fmt.Errorf("failed to parse after:%s as a timestamp: %w", val, err)
}
return "(CAST(strftime(\"%s\",start_time) AS INTEGER) = ?)", t.Unix(), nil, nil
case "command":
@ -960,7 +960,7 @@ func parseAtomizedToken(ctx *context.Context, token string) (string, interface{}
// Also get all ones that are in the DB
names, err := getAllCustomColumnNames(ctx)
if err != nil {
return "", nil, nil, fmt.Errorf("failed to get custom column names from the DB: %v", err)
return "", nil, nil, fmt.Errorf("failed to get custom column names from the DB: %w", err)
}
knownCustomColumns = append(knownCustomColumns, names...)
// Check if the atom is for a custom column that exists and if it isn't, return an error
@ -978,7 +978,7 @@ func parseAtomizedToken(ctx *context.Context, token string) (string, interface{}
}
}
func getAllCustomColumnNames(ctx *context.Context) ([]string, error) {
func getAllCustomColumnNames(ctx context.Context) ([]string, error) {
db := hctx.GetDb(ctx)
query := `
SELECT DISTINCT json_extract(value, '$.name') as cc_name
@ -1079,7 +1079,7 @@ func SendDeletionRequest(deletionRequest shared.DeletionRequest) error {
}
_, err = ApiPost("/api/v1/add-deletion-request", "application/json", data)
if err != nil {
return fmt.Errorf("failed to send deletion request to backend service, this may cause commands to not get deleted on other instances of hishtory: %v", err)
return fmt.Errorf("failed to send deletion request to backend service, this may cause commands to not get deleted on other instances of hishtory: %w", err)
}
return nil
}

View File

@ -15,7 +15,7 @@ import (
"github.com/slsa-framework/slsa-verifier/verifiers"
)
func verify(ctx *context.Context, provenance []byte, artifactHash, source, branch, versionTag string) error {
func verify(ctx context.Context, provenance []byte, artifactHash, source, branch, versionTag string) error {
provenanceOpts := &options.ProvenanceOpts{
ExpectedSourceURI: source,
ExpectedBranch: &branch,
@ -23,7 +23,7 @@ func verify(ctx *context.Context, provenance []byte, artifactHash, source, branc
ExpectedVersionedTag: &versionTag,
}
builderOpts := &options.BuilderOpts{}
_, _, err := verifiers.Verify(*ctx, provenance, artifactHash, provenanceOpts, builderOpts)
_, _, err := verifiers.Verify(ctx, provenance, artifactHash, provenanceOpts, builderOpts)
return err
}
@ -42,7 +42,7 @@ func checkForDowngrade(currentVersionS, newVersionS string) error {
return nil
}
func verifyBinary(ctx *context.Context, binaryPath, attestationPath, versionTag string) error {
func verifyBinary(ctx context.Context, binaryPath, attestationPath, versionTag string) error {
if os.Getenv("HISHTORY_DISABLE_SLSA_ATTESTATION") == "true" {
return nil
}
@ -61,7 +61,7 @@ func verifyBinary(ctx *context.Context, binaryPath, attestationPath, versionTag
attestation, err := os.ReadFile(attestationPath)
if err != nil {
return fmt.Errorf("failed to read attestation file: %v", err)
return fmt.Errorf("failed to read attestation file: %w", err)
}
hash, err := getFileHash(binaryPath)
@ -75,13 +75,13 @@ func verifyBinary(ctx *context.Context, binaryPath, attestationPath, versionTag
func getFileHash(binaryPath string) (string, error) {
binaryFile, err := os.Open(binaryPath)
if err != nil {
return "", fmt.Errorf("failed to read binary for verification purposes: %v", err)
return "", fmt.Errorf("failed to read binary for verification purposes: %w", err)
}
defer binaryFile.Close()
hasher := sha256.New()
if _, err := io.Copy(hasher, binaryFile); err != nil {
return "", fmt.Errorf("failed to hash binary: %v", err)
return "", fmt.Errorf("failed to hash binary: %w", err)
}
hash := hex.EncodeToString(hasher.Sum(nil))
return hash, nil
@ -95,5 +95,5 @@ func handleSlsaFailure(srcErr error) error {
fmt.Println("Proceeding with update...")
return nil
}
return fmt.Errorf("failed to verify SLSA provenance of the updated binary, aborting update (to bypass, set `export HISHTORY_DISABLE_SLSA_ATTESTATION=true`): %v", srcErr)
return fmt.Errorf("failed to verify SLSA provenance of the updated binary, aborting update (to bypass, set `export HISHTORY_DISABLE_SLSA_ATTESTATION=true`): %w", srcErr)
}

View File

@ -136,7 +136,7 @@ const (
type model struct {
// context
ctx *context.Context
ctx context.Context
// Model for the loading spinner.
spinner spinner.Model
@ -187,7 +187,7 @@ type asyncQueryFinishedMsg struct {
maintainCursor bool
}
func initialModel(ctx *context.Context, t table.Model, tableEntries []*data.HistoryEntry, initialQuery string) model {
func initialModel(ctx context.Context, t table.Model, tableEntries []*data.HistoryEntry, initialQuery string) model {
s := spinner.New()
s.Spinner = spinner.Dot
s.Style = lipgloss.NewStyle().Foreground(lipgloss.Color("205"))
@ -362,7 +362,7 @@ func (m model) View() string {
return fmt.Sprintf("\n%s%s%s\nSearch Query: %s\n\n%s\n", loadingMessage, warning, m.banner, m.queryInput.View(), baseStyle.Render(m.table.View())) + helpView
}
func getRows(ctx *context.Context, columnNames []string, query string, numEntries int) ([]table.Row, []*data.HistoryEntry, error) {
func getRows(ctx context.Context, columnNames []string, query string, numEntries int) ([]table.Row, []*data.HistoryEntry, error) {
db := hctx.GetDb(ctx)
config := hctx.GetConf(ctx)
searchResults, err := Search(ctx, db, query, numEntries)
@ -381,7 +381,7 @@ func getRows(ctx *context.Context, columnNames []string, query string, numEntrie
entry.Command = strings.ReplaceAll(entry.Command, "\n", "\\n")
row, err := buildTableRow(ctx, columnNames, *entry)
if err != nil {
return nil, nil, fmt.Errorf("failed to build row for entry=%#v: %v", entry, err)
return nil, nil, fmt.Errorf("failed to build row for entry=%#v: %w", entry, err)
}
rows = append(rows, row)
filteredData = append(filteredData, entry)
@ -409,7 +409,7 @@ func getTerminalSize() (int, int, error) {
var bigQueryResults []table.Row
func makeTableColumns(ctx *context.Context, columnNames []string, rows []table.Row) ([]table.Column, error) {
func makeTableColumns(ctx context.Context, columnNames []string, rows []table.Row) ([]table.Column, error) {
// Handle an initial query with no results
if len(rows) == 0 || len(rows[0]) == 0 {
allRows, _, err := getRows(ctx, columnNames, "", 25)
@ -449,7 +449,7 @@ func makeTableColumns(ctx *context.Context, columnNames []string, rows []table.R
// Get the actual terminal width. If we're below this, opportunistically add some padding aiming for the maximum column widths
terminalWidth, _, err := getTerminalSize()
if err != nil {
return nil, fmt.Errorf("failed to get terminal size: %v", err)
return nil, fmt.Errorf("failed to get terminal size: %w", err)
}
for totalWidth < (terminalWidth - len(columnNames)) {
prevTotalWidth := totalWidth
@ -499,7 +499,7 @@ func min(a, b int) int {
return b
}
func makeTable(ctx *context.Context, rows []table.Row) (table.Model, error) {
func makeTable(ctx context.Context, rows []table.Row) (table.Model, error) {
config := hctx.GetConf(ctx)
columns, err := makeTableColumns(ctx, config.DisplayedColumns, rows)
if err != nil {
@ -549,7 +549,7 @@ func makeTable(ctx *context.Context, rows []table.Row) (table.Model, error) {
return t, nil
}
func deleteHistoryEntry(ctx *context.Context, entry data.HistoryEntry) error {
func deleteHistoryEntry(ctx context.Context, entry data.HistoryEntry) error {
db := hctx.GetDb(ctx)
// Delete locally
r := db.Model(&data.HistoryEntry{}).Where("device_id = ? AND end_time = ?", entry.DeviceId, entry.EndTime).Delete(&data.HistoryEntry{})
@ -570,7 +570,7 @@ func deleteHistoryEntry(ctx *context.Context, entry data.HistoryEntry) error {
return SendDeletionRequest(dr)
}
func TuiQuery(ctx *context.Context, initialQuery string) error {
func TuiQuery(ctx context.Context, initialQuery string) error {
lipgloss.SetColorProfile(termenv.ANSI)
rows, entries, err := getRows(ctx, hctx.GetConf(ctx).DisplayedColumns, initialQuery, PADDED_NUM_ENTRIES)
if err != nil {