working update

This commit is contained in:
David Dworken
2022-04-06 18:18:46 -07:00
parent 7e51d5fe42
commit 684511f4f7
8 changed files with 73 additions and 61 deletions

View File

@ -4,15 +4,15 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/http"
"io/ioutil" "io/ioutil"
"net/http"
"os" "os"
"strings" "strings"
"gorm.io/gorm" "gorm.io/gorm"
"github.com/ddworken/hishtory/shared"
"github.com/ddworken/hishtory/client/lib" "github.com/ddworken/hishtory/client/lib"
"github.com/ddworken/hishtory/shared"
) )
func main() { func main() {
@ -28,7 +28,7 @@ func main() {
case "export": case "export":
export() export()
case "init": case "init":
lib.CheckFatalError(lib.Setup( os.Args)) lib.CheckFatalError(lib.Setup(os.Args))
case "install": case "install":
lib.CheckFatalError(lib.Install()) lib.CheckFatalError(lib.Install())
case "enable": case "enable":
@ -51,9 +51,9 @@ func main() {
func retrieveAdditionalEntriesFromRemote(db *gorm.DB) error { func retrieveAdditionalEntriesFromRemote(db *gorm.DB) error {
config, err := lib.GetConfig() config, err := lib.GetConfig()
if err != nil { if err != nil {
return err return err
} }
resp, err := http.Get(lib.GetServerHostname()+"/api/v1/equery?device_id=" + config.DeviceId) resp, err := http.Get(lib.GetServerHostname() + "/api/v1/equery?device_id=" + config.DeviceId)
if err != nil { if err != nil {
return fmt.Errorf("failed to pull latest history entries from the backend: %v", err) return fmt.Errorf("failed to pull latest history entries from the backend: %v", err)
} }
@ -75,7 +75,7 @@ func retrieveAdditionalEntriesFromRemote(db *gorm.DB) error {
// TODO: Is this creating duplicate entries? // TODO: Is this creating duplicate entries?
lib.AddToDbIfNew(db, decEntry) lib.AddToDbIfNew(db, decEntry)
} }
return nil return nil
} }
func query(query string) { func query(query string) {

View File

@ -12,7 +12,7 @@ import (
) )
func RunInteractiveBashCommands(t *testing.T, script string) string { func RunInteractiveBashCommands(t *testing.T, script string) string {
shared.Check(t, ioutil.WriteFile("/tmp/hishtory-test-in.sh", []byte("set -euo pipefail\n" + script), 0600)) shared.Check(t, ioutil.WriteFile("/tmp/hishtory-test-in.sh", []byte("set -euo pipefail\n"+script), 0600))
cmd := exec.Command("bash", "-i") cmd := exec.Command("bash", "-i")
cmd.Stdin = strings.NewReader(script) cmd.Stdin = strings.NewReader(script)
var out bytes.Buffer var out bytes.Buffer
@ -28,8 +28,8 @@ func TestIntegration(t *testing.T) {
defer shared.BackupAndRestore(t)() defer shared.BackupAndRestore(t)()
defer shared.RunTestServer(t)() defer shared.RunTestServer(t)()
// Run the test // Run the test
testIntegration(t) testIntegration(t)
} }
func TestIntegrationWithNewDevice(t *testing.T) { func TestIntegrationWithNewDevice(t *testing.T) {
@ -37,8 +37,8 @@ func TestIntegrationWithNewDevice(t *testing.T) {
defer shared.BackupAndRestore(t)() defer shared.BackupAndRestore(t)()
defer shared.RunTestServer(t)() defer shared.RunTestServer(t)()
// Run the test // Run the test
userSecret := testIntegration(t) userSecret := testIntegration(t)
// Clear all local state // Clear all local state
shared.ResetLocalState(t) shared.ResetLocalState(t)
@ -55,13 +55,13 @@ func TestIntegrationWithNewDevice(t *testing.T) {
t.Fatalf("unexpected output from install: %v", out) t.Fatalf("unexpected output from install: %v", out)
} }
// Set the secret key to the previous secret key // Set the secret key to the previous secret key
out = RunInteractiveBashCommands(t, `hishtory init ` + userSecret) out = RunInteractiveBashCommands(t, `hishtory init `+userSecret)
if !strings.Contains(out, "Setting secret hishtory key to " + userSecret) { if !strings.Contains(out, "Setting secret hishtory key to "+userSecret) {
t.Fatalf("Failed to re-init with the user secret: %v", out) t.Fatalf("Failed to re-init with the user secret: %v", out)
} }
// Querying should show the history from the previous run // Querying should show the history from the previous run
out = RunInteractiveBashCommands(t, "hishtory query") out = RunInteractiveBashCommands(t, "hishtory query")
expected := []string{"echo thisisrecorded", "hishtory enable", "echo bar", "echo foo", "ls /foo", "ls /bar", "ls /a"} expected := []string{"echo thisisrecorded", "hishtory enable", "echo bar", "echo foo", "ls /foo", "ls /bar", "ls /a"}
for _, item := range expected { for _, item := range expected {
@ -82,7 +82,7 @@ func TestIntegrationWithNewDevice(t *testing.T) {
t.Fatalf("output has `echo mynewcommand` the wrong number of times") t.Fatalf("output has `echo mynewcommand` the wrong number of times")
} }
// Clear local state again // Clear local state again
shared.ResetLocalState(t) shared.ResetLocalState(t)
// Install it a 3rd time // Install it a 3rd time
@ -97,13 +97,13 @@ func TestIntegrationWithNewDevice(t *testing.T) {
t.Fatalf("unexpected output from install: %v", out) t.Fatalf("unexpected output from install: %v", out)
} }
// Set the secret key to the previous secret key // Set the secret key to the previous secret key
out = RunInteractiveBashCommands(t, `hishtory init ` + userSecret) out = RunInteractiveBashCommands(t, `hishtory init `+userSecret)
if !strings.Contains(out, "Setting secret hishtory key to " + userSecret) { if !strings.Contains(out, "Setting secret hishtory key to "+userSecret) {
t.Fatalf("Failed to re-init with the user secret: %v", out) t.Fatalf("Failed to re-init with the user secret: %v", out)
} }
// Querying should show the history from the previous run // Querying should show the history from the previous run
out = RunInteractiveBashCommands(t, "hishtory query") out = RunInteractiveBashCommands(t, "hishtory query")
expected = []string{"echo thisisrecorded", "echo mynewcommand", "hishtory enable", "echo bar", "echo foo", "ls /foo", "ls /bar", "ls /a"} expected = []string{"echo thisisrecorded", "echo mynewcommand", "hishtory enable", "echo bar", "echo foo", "ls /foo", "ls /bar", "ls /a"}
for _, item := range expected { for _, item := range expected {
@ -140,13 +140,12 @@ func testIntegration(t *testing.T) string {
t.Fatalf("Failed to extract userSecret from output: matches=%#v", matches) t.Fatalf("Failed to extract userSecret from output: matches=%#v", matches)
} }
userSecret := matches[1] userSecret := matches[1]
// TODO(ddworken): Test the status subcommand // TODO(ddworken): Test the status subcommand
out = RunInteractiveBashCommands(t, ` out = RunInteractiveBashCommands(t, `
hishtory status hishtory status
`) `)
if out != "Hishtory: Offline Mode\nEnabled: true\n"{ if out != "Hishtory: Offline Mode\nEnabled: true\n" {
t.Fatalf("status command has unexpected output: %#v", out) t.Fatalf("status command has unexpected output: %#v", out)
} }

View File

@ -9,6 +9,7 @@ import (
"io" "io"
"io/ioutil" "io/ioutil"
"log" "log"
"net/http"
"os" "os"
"os/exec" "os/exec"
"os/user" "os/user"
@ -16,8 +17,8 @@ import (
"path/filepath" "path/filepath"
"strconv" "strconv"
"strings" "strings"
"syscall"
"time" "time"
"net/http"
"gorm.io/gorm" "gorm.io/gorm"
@ -131,12 +132,12 @@ func Setup(args []string) error {
return fmt.Errorf("failed to persist config to disk: %v", err) return fmt.Errorf("failed to persist config to disk: %v", err)
} }
_, err = http.Get(GetServerHostname()+"/api/v1/eregister?user_id=" + shared.UserId(userSecret) + "&device_id=" + config.DeviceId) _, err = http.Get(GetServerHostname() + "/api/v1/eregister?user_id=" + shared.UserId(userSecret) + "&device_id=" + config.DeviceId)
if err != nil { if err != nil {
return fmt.Errorf("failed to register device with backend: %v", err) return fmt.Errorf("failed to register device with backend: %v", err)
} }
resp, err := http.Get(GetServerHostname()+"/api/v1/ebootstrap?user_id=" + shared.UserId(userSecret) + "&device_id=" + config.DeviceId) resp, err := http.Get(GetServerHostname() + "/api/v1/ebootstrap?user_id=" + shared.UserId(userSecret) + "&device_id=" + config.DeviceId)
if err != nil { 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: %v", err)
} }
@ -162,7 +163,7 @@ func Setup(args []string) error {
AddToDbIfNew(db, decEntry) AddToDbIfNew(db, decEntry)
} }
return nil return nil
} }
func AddToDbIfNew(db *gorm.DB, entry shared.HistoryEntry) { func AddToDbIfNew(db *gorm.DB, entry shared.HistoryEntry) {
@ -173,7 +174,7 @@ func AddToDbIfNew(db *gorm.DB, entry shared.HistoryEntry) {
tx = tx.Where("exit_code = ?", entry.ExitCode) tx = tx.Where("exit_code = ?", entry.ExitCode)
tx = tx.Where("start_time = ?", entry.StartTime) tx = tx.Where("start_time = ?", entry.StartTime)
tx = tx.Where("end_time = ?", entry.EndTime) tx = tx.Where("end_time = ?", entry.EndTime)
var results []shared.HistoryEntry var results []shared.HistoryEntry
tx.Limit(1).Find(&results) tx.Limit(1).Find(&results)
if len(results) == 0 { if len(results) == 0 {
db.Create(entry) db.Create(entry)
@ -204,7 +205,7 @@ func DisplayResults(results []*shared.HistoryEntry, displayHostname bool) {
type ClientConfig struct { type ClientConfig struct {
UserSecret string `json:"user_secret"` UserSecret string `json:"user_secret"`
IsEnabled bool `json:"is_enabled"` IsEnabled bool `json:"is_enabled"`
DeviceId string `json:"device_id"` DeviceId string `json:"device_id"`
} }
func GetConfig() (ClientConfig, error) { func GetConfig() (ClientConfig, error) {
@ -375,20 +376,32 @@ func copyFile(src, dst string) error {
func Update(url string) error { func Update(url string) error {
var stdout bytes.Buffer var stdout bytes.Buffer
var stderr bytes.Buffer var stderr bytes.Buffer
cmd := exec.Command("bash", "-c", "curl -o /tmp/hishtory-client "+url+"; chmod +x /tmp/hishtory-client; /tmp/hishtory-client install") cmd := exec.Command("bash", "-c", "curl -o /tmp/hishtory-client "+url+"; chmod +x /tmp/hishtory-client")
cmd.Stdout = &stdout cmd.Stdout = &stdout
cmd.Stderr = &stderr cmd.Stderr = &stderr
err := cmd.Run() err := cmd.Run()
if err != nil { if err != nil {
return fmt.Errorf("Failed to update: %v, stdout=%+v, stderr=%+v", err, stdout.String(), stderr.String()) return fmt.Errorf("Failed to download update: %v, stdout=%#v, stderr=%#v", err, stdout.String(), stderr.String())
}
homedir, err := os.UserHomeDir()
if err != nil {
return fmt.Errorf("failed to get user's home directory: %v", err)
}
err = syscall.Unlink(path.Join(homedir, shared.HISHTORY_PATH, "hishtory"))
if err != nil {
return fmt.Errorf("Failed to unlink: %v", err)
}
cmd = exec.Command("/tmp/hishtory-client", "install")
err = cmd.Run()
if err != nil {
return fmt.Errorf("Failed to update: %v", err)
} }
return nil return nil
} }
func GetServerHostname() string { func GetServerHostname() string {
if server := os.Getenv("HISHTORY_SERVER"); server != "" { if server := os.Getenv("HISHTORY_SERVER"); server != "" {
return server return server
} }
return "https://api.hishtory.dev" return "https://api.hishtory.dev"
} }

View File

@ -3,8 +3,8 @@ package main
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"log"
"io/ioutil" "io/ioutil"
"log"
"net/http" "net/http"
"github.com/ddworken/hishtory/shared" "github.com/ddworken/hishtory/shared"

View File

@ -8,8 +8,8 @@ import (
"net/http/httptest" "net/http/httptest"
"testing" "testing"
"github.com/google/uuid"
"github.com/ddworken/hishtory/shared" "github.com/ddworken/hishtory/shared"
"github.com/google/uuid"
) )
func TestESubmitThenQuery(t *testing.T) { func TestESubmitThenQuery(t *testing.T) {

View File

@ -54,7 +54,7 @@ type Device struct {
// } // }
const ( const (
CONFIG_PATH = ".hishtory.config" CONFIG_PATH = ".hishtory.config"
HISHTORY_PATH = ".hishtory" HISHTORY_PATH = ".hishtory"
DB_PATH = ".hishtory.db" DB_PATH = ".hishtory.db"
KDF_USER_ID = "user_id" KDF_USER_ID = "user_id"

View File

@ -1,13 +1,13 @@
package shared package shared
import ( import (
"testing"
"time"
"os"
"path"
"os/exec"
"bytes" "bytes"
"fmt" "fmt"
"os"
"os/exec"
"path"
"testing"
"time"
) )
func ResetLocalState(t *testing.T) { func ResetLocalState(t *testing.T) {
@ -15,7 +15,7 @@ func ResetLocalState(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to retrieve homedir: %v", err) t.Fatalf("failed to retrieve homedir: %v", err)
} }
os.Remove(path.Join(homedir, HISHTORY_PATH, DB_PATH)) os.Remove(path.Join(homedir, HISHTORY_PATH, DB_PATH))
os.Remove(path.Join(homedir, HISHTORY_PATH, CONFIG_PATH)) os.Remove(path.Join(homedir, HISHTORY_PATH, CONFIG_PATH))
} }
@ -39,7 +39,7 @@ func buildServer(t *testing.T) {
if err != nil { if err != nil {
t.Fatalf("failed to chdir: %v", err) t.Fatalf("failed to chdir: %v", err)
} }
cmd := exec.Command("go", "build", "-o", "/tmp/server","server/server.go") cmd := exec.Command("go", "build", "-o", "/tmp/server", "server/server.go")
var stdout bytes.Buffer var stdout bytes.Buffer
cmd.Stdout = &stdout cmd.Stdout = &stdout
var stderr bytes.Buffer var stderr bytes.Buffer
@ -55,21 +55,21 @@ func buildServer(t *testing.T) {
} }
func RunTestServer(t *testing.T) func() { func RunTestServer(t *testing.T) func() {
os.Setenv("HISHTORY_SERVER" ,"http://localhost:8080") os.Setenv("HISHTORY_SERVER", "http://localhost:8080")
buildServer(t) buildServer(t)
cmd := exec.Command( "/tmp/server" ) cmd := exec.Command("/tmp/server")
var stdout bytes.Buffer var stdout bytes.Buffer
cmd.Stdout = &stdout cmd.Stdout = &stdout
var stderr bytes.Buffer var stderr bytes.Buffer
cmd.Stderr = &stderr cmd.Stderr = &stderr
err := cmd.Start() err := cmd.Start()
if err != nil { if err != nil {
t.Fatalf("failed to start server: %v", err) t.Fatalf("failed to start server: %v", err)
} }
time.Sleep(time.Second*3) time.Sleep(time.Second * 3)
go func() { go func() {
cmd.Wait() cmd.Wait()
}() }()
return func() { return func() {
err := cmd.Process.Kill() err := cmd.Process.Kill()
if err != nil { if err != nil {
@ -93,7 +93,7 @@ func CheckWithInfo(t *testing.T, err error, additionalInfo string) {
} }
func EntryEquals(entry1, entry2 HistoryEntry) bool { func EntryEquals(entry1, entry2 HistoryEntry) bool {
return entry1.LocalUsername == entry2.LocalUsername && return entry1.LocalUsername == entry2.LocalUsername &&
entry1.Hostname == entry2.Hostname && entry1.Hostname == entry2.Hostname &&
entry1.Command == entry2.Command && entry1.Command == entry2.Command &&
entry1.CurrentWorkingDirectory == entry2.CurrentWorkingDirectory && entry1.CurrentWorkingDirectory == entry2.CurrentWorkingDirectory &&
@ -104,12 +104,12 @@ func EntryEquals(entry1, entry2 HistoryEntry) bool {
func MakeFakeHistoryEntry(command string) HistoryEntry { func MakeFakeHistoryEntry(command string) HistoryEntry {
return HistoryEntry{ return HistoryEntry{
LocalUsername: "david", LocalUsername: "david",
Hostname: "localhost", Hostname: "localhost",
Command: command, Command: command,
CurrentWorkingDirectory: "/tmp/", CurrentWorkingDirectory: "/tmp/",
ExitCode: 2, ExitCode: 2,
StartTime: time.Now(), StartTime: time.Now(),
EndTime: time.Now(), EndTime: time.Now(),
} }
} }

Binary file not shown.