2022-04-05 07:07:01 +02:00
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2022-04-06 08:31:24 +02:00
|
|
|
"io/ioutil"
|
2022-04-07 03:18:46 +02:00
|
|
|
"net/http"
|
2022-04-05 07:07:01 +02:00
|
|
|
"os"
|
|
|
|
"strings"
|
|
|
|
|
2022-04-06 08:31:24 +02:00
|
|
|
"gorm.io/gorm"
|
|
|
|
|
2022-04-08 05:59:40 +02:00
|
|
|
"github.com/ddworken/hishtory/client/data"
|
2022-04-05 07:07:01 +02:00
|
|
|
"github.com/ddworken/hishtory/client/lib"
|
2022-04-07 03:18:46 +02:00
|
|
|
"github.com/ddworken/hishtory/shared"
|
2022-04-05 07:07:01 +02:00
|
|
|
)
|
|
|
|
|
2022-04-09 23:37:21 +02:00
|
|
|
var (
|
|
|
|
GitCommit string = "Unknown"
|
|
|
|
Version string = "Unknown"
|
|
|
|
)
|
2022-04-07 07:43:07 +02:00
|
|
|
|
2022-04-05 07:07:01 +02:00
|
|
|
func main() {
|
|
|
|
if len(os.Args) == 1 {
|
|
|
|
fmt.Println("Must specify a command! Do you mean `hishtory query`?")
|
|
|
|
return
|
|
|
|
}
|
|
|
|
switch os.Args[1] {
|
|
|
|
case "saveHistoryEntry":
|
|
|
|
saveHistoryEntry()
|
|
|
|
case "query":
|
|
|
|
query(strings.Join(os.Args[2:], " "))
|
|
|
|
case "export":
|
|
|
|
export()
|
|
|
|
case "init":
|
2022-04-07 03:18:46 +02:00
|
|
|
lib.CheckFatalError(lib.Setup(os.Args))
|
2022-04-05 07:07:01 +02:00
|
|
|
case "install":
|
|
|
|
lib.CheckFatalError(lib.Install())
|
|
|
|
case "enable":
|
|
|
|
lib.CheckFatalError(lib.Enable())
|
|
|
|
case "disable":
|
|
|
|
lib.CheckFatalError(lib.Disable())
|
|
|
|
case "status":
|
|
|
|
config, err := lib.GetConfig()
|
|
|
|
lib.CheckFatalError(err)
|
2022-04-09 23:37:21 +02:00
|
|
|
fmt.Print("Hishtory: v0." + Version + "\nEnabled: ")
|
2022-04-05 07:07:01 +02:00
|
|
|
fmt.Print(config.IsEnabled)
|
2022-04-07 07:43:07 +02:00
|
|
|
fmt.Print("\nSecret Key: ")
|
|
|
|
fmt.Print(config.UserSecret)
|
|
|
|
fmt.Print("\nCommit Hash: ")
|
|
|
|
fmt.Print(GitCommit)
|
2022-04-05 07:07:01 +02:00
|
|
|
fmt.Print("\n")
|
|
|
|
case "update":
|
2022-04-09 07:56:44 +02:00
|
|
|
lib.CheckFatalError(lib.Update("https://api.hishtory.dev/download/hishtory-linux-amd64"))
|
2022-04-05 07:07:01 +02:00
|
|
|
default:
|
|
|
|
lib.CheckFatalError(fmt.Errorf("unknown command: %s", os.Args[1]))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-06 08:31:24 +02:00
|
|
|
func retrieveAdditionalEntriesFromRemote(db *gorm.DB) error {
|
|
|
|
config, err := lib.GetConfig()
|
|
|
|
if err != nil {
|
2022-04-07 03:18:46 +02:00
|
|
|
return err
|
2022-04-06 08:31:24 +02:00
|
|
|
}
|
2022-04-07 03:18:46 +02:00
|
|
|
resp, err := http.Get(lib.GetServerHostname() + "/api/v1/equery?device_id=" + config.DeviceId)
|
2022-04-06 08:31:24 +02:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to pull latest history entries from the backend: %v", err)
|
|
|
|
}
|
|
|
|
defer resp.Body.Close()
|
2022-04-07 07:43:07 +02:00
|
|
|
if resp.StatusCode != 200 {
|
|
|
|
return fmt.Errorf("failed to retrieve data from backend, status_code=%d", resp.StatusCode)
|
|
|
|
}
|
2022-04-08 05:59:40 +02:00
|
|
|
respBody, err := ioutil.ReadAll(resp.Body)
|
2022-04-06 08:31:24 +02:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to read latest history entries response body: %v", err)
|
|
|
|
}
|
|
|
|
var retrievedEntries []*shared.EncHistoryEntry
|
2022-04-08 05:59:40 +02:00
|
|
|
err = json.Unmarshal(respBody, &retrievedEntries)
|
2022-04-06 08:31:24 +02:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to load JSON response: %v", err)
|
|
|
|
}
|
|
|
|
for _, entry := range retrievedEntries {
|
2022-04-08 05:59:40 +02:00
|
|
|
decEntry, err := data.DecryptHistoryEntry(config.UserSecret, *entry)
|
2022-04-06 08:31:24 +02:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to decrypt history entry from server: %v", err)
|
|
|
|
}
|
|
|
|
lib.AddToDbIfNew(db, decEntry)
|
|
|
|
}
|
2022-04-07 03:18:46 +02:00
|
|
|
return nil
|
2022-04-06 08:31:24 +02:00
|
|
|
}
|
|
|
|
|
2022-04-05 07:07:01 +02:00
|
|
|
func query(query string) {
|
2022-04-07 07:43:07 +02:00
|
|
|
db, err := lib.OpenLocalSqliteDb()
|
2022-04-05 07:07:01 +02:00
|
|
|
lib.CheckFatalError(err)
|
2022-04-06 08:31:24 +02:00
|
|
|
lib.CheckFatalError(retrieveAdditionalEntriesFromRemote(db))
|
2022-04-07 07:43:07 +02:00
|
|
|
lib.CheckFatalError(displayBannerIfSet())
|
2022-04-08 05:59:40 +02:00
|
|
|
data, err := data.Search(db, query, 25)
|
2022-04-05 07:07:01 +02:00
|
|
|
lib.CheckFatalError(err)
|
2022-04-09 23:52:10 +02:00
|
|
|
lib.DisplayResults(data)
|
2022-04-05 07:07:01 +02:00
|
|
|
}
|
|
|
|
|
2022-04-07 07:43:07 +02:00
|
|
|
func displayBannerIfSet() error {
|
|
|
|
config, err := lib.GetConfig()
|
|
|
|
if err != nil {
|
2022-04-07 07:44:10 +02:00
|
|
|
return fmt.Errorf("failed to get config: %v", err)
|
2022-04-07 07:43:07 +02:00
|
|
|
}
|
|
|
|
url := lib.GetServerHostname() + "/api/v1/banner?commit_hash=" + GitCommit + "&device_id=" + config.DeviceId + "&forced_banner=" + os.Getenv("FORCED_BANNER")
|
|
|
|
resp, err := http.Get(url)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to call /api/v1/banner: %v", err)
|
|
|
|
}
|
|
|
|
if resp.StatusCode != 200 {
|
|
|
|
return fmt.Errorf("failed to call %s, status_code=%d", url, resp.StatusCode)
|
|
|
|
}
|
|
|
|
data, err := ioutil.ReadAll(resp.Body)
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("failed to read /api/v1/banner response body: %v", err)
|
|
|
|
}
|
|
|
|
if len(data) > 0 {
|
2022-04-08 06:40:22 +02:00
|
|
|
fmt.Print(string(data))
|
2022-04-07 07:43:07 +02:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2022-04-05 07:07:01 +02:00
|
|
|
func saveHistoryEntry() {
|
|
|
|
config, err := lib.GetConfig()
|
|
|
|
lib.CheckFatalError(err)
|
|
|
|
if !config.IsEnabled {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
entry, err := lib.BuildHistoryEntry(os.Args)
|
|
|
|
lib.CheckFatalError(err)
|
|
|
|
|
|
|
|
// Persist it locally
|
2022-04-07 07:43:07 +02:00
|
|
|
db, err := lib.OpenLocalSqliteDb()
|
2022-04-05 07:07:01 +02:00
|
|
|
lib.CheckFatalError(err)
|
|
|
|
result := db.Create(entry)
|
|
|
|
lib.CheckFatalError(result.Error)
|
|
|
|
|
|
|
|
// Persist it remotely
|
2022-04-08 05:59:40 +02:00
|
|
|
encEntry, err := data.EncryptHistoryEntry(config.UserSecret, *entry)
|
2022-04-05 07:07:01 +02:00
|
|
|
lib.CheckFatalError(err)
|
2022-04-06 08:31:24 +02:00
|
|
|
jsonValue, err := json.Marshal([]shared.EncHistoryEntry{encEntry})
|
2022-04-05 07:07:01 +02:00
|
|
|
lib.CheckFatalError(err)
|
2022-04-07 07:43:07 +02:00
|
|
|
resp, err := http.Post(lib.GetServerHostname()+"/api/v1/esubmit", "application/json", bytes.NewBuffer(jsonValue))
|
2022-04-05 07:07:01 +02:00
|
|
|
lib.CheckFatalError(err)
|
2022-04-07 07:43:07 +02:00
|
|
|
if resp.StatusCode != 200 {
|
|
|
|
lib.CheckFatalError(fmt.Errorf("failed to submit result to backend, status_code=%d", resp.StatusCode))
|
|
|
|
}
|
2022-04-05 07:07:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func export() {
|
2022-04-07 07:43:07 +02:00
|
|
|
db, err := lib.OpenLocalSqliteDb()
|
2022-04-05 07:07:01 +02:00
|
|
|
lib.CheckFatalError(err)
|
2022-04-06 08:31:24 +02:00
|
|
|
lib.CheckFatalError(retrieveAdditionalEntriesFromRemote(db))
|
2022-04-08 05:59:40 +02:00
|
|
|
data, err := data.Search(db, "", 0)
|
2022-04-05 07:07:01 +02:00
|
|
|
lib.CheckFatalError(err)
|
2022-04-07 08:17:58 +02:00
|
|
|
for i := len(data) - 1; i >= 0; i-- {
|
2022-04-07 08:05:30 +02:00
|
|
|
fmt.Println(data[i].Command)
|
2022-04-05 07:07:01 +02:00
|
|
|
}
|
|
|
|
}
|