From 0faf2dc732c03c4f6ea33e79eb80121e2fc69726 Mon Sep 17 00:00:00 2001 From: Randall Winkhart Date: Thu, 16 May 2024 17:14:42 -0400 Subject: [PATCH] Implement device ID server registration and server-side init --- libmuttonserver.go | 9 +++++++++ src/backend/init.go | 4 +--- src/backend/initUNIX.go | 4 ++-- src/backend/initWIN.go | 4 ++-- src/cli/init.go | 14 ++++++++------ src/sync/client.go | 8 ++++---- src/sync/common.go | 6 ++---- 7 files changed, 28 insertions(+), 21 deletions(-) diff --git a/libmuttonserver.go b/libmuttonserver.go index 88b93c8..344212c 100644 --- a/libmuttonserver.go +++ b/libmuttonserver.go @@ -17,11 +17,20 @@ func main() { switch args[1] { case "fetch": + // print all information needed for syncing to stdout for interpretation by the client sync.GetRemoteDataFromServer() case "shear": + // shear an entry from the server and add it to the deletions directory deviceIDTargetLocation := strings.Split(args[2], "\x1d") targetLocationIncomplete := strings.ReplaceAll(strings.ReplaceAll(deviceIDTargetLocation[1], "\x1f", " "), "\x1e", backend.PathSeparator) sync.Shear(targetLocationIncomplete, deviceIDTargetLocation[0]) + case "register": + // register a new device ID + os.Create(backend.ConfigDir + backend.PathSeparator + "devices" + backend.PathSeparator + args[2]) + case "init": + // create the necessary directories for libmuttonserver to function TODO consider clearing out old directories first + backend.DirInit() + os.MkdirAll(backend.ConfigDir+backend.PathSeparator+"deletions", 0700) default: fmt.Println(backend.AnsiError + "Invalid argument" + backend.AnsiReset) // TODO add server help menu } diff --git a/src/backend/init.go b/src/backend/init.go index bcaf3df..c35b704 100644 --- a/src/backend/init.go +++ b/src/backend/init.go @@ -11,7 +11,7 @@ import ( // TempInit ensures libmutton directories exist and writes the libmutton configuration file func TempInit(configFileMap map[string]string) { // create EntryRoot and ConfigDir - dirInit() + DirInit() // remove existing config file removeFile(ConfigPath) @@ -27,8 +27,6 @@ func TempInit(configFileMap map[string]string) { for key, value := range configFileMap { configFile.WriteString(key + " = " + value + "\n") } - - os.Exit(0) } // GpgUIDListGen generates a list of all GPG key IDs on the system and returns them as a slice of strings diff --git a/src/backend/initUNIX.go b/src/backend/initUNIX.go index 93bbfc2..12be570 100644 --- a/src/backend/initUNIX.go +++ b/src/backend/initUNIX.go @@ -9,8 +9,8 @@ import ( const FallbackEditor = "vi" // vi is pre-installed on most UNIX systems -// dirInit creates the libmutton directories -func dirInit() { +// DirInit creates the libmutton directories +func DirInit() { // create EntryRoot err := os.MkdirAll(EntryRoot, 0700) if err != nil { diff --git a/src/backend/initWIN.go b/src/backend/initWIN.go index b4c1aa8..f402e18 100644 --- a/src/backend/initWIN.go +++ b/src/backend/initWIN.go @@ -9,8 +9,8 @@ import ( const FallbackEditor = "nvim" // since there is no pre-installed CLI editor on Windows, default to the most popular one -// dirInit creates the libmutton directories -func dirInit() { +// DirInit creates the libmutton directories +func DirInit() { // create EntryRoot (includes config directory on Windows) err := os.MkdirAll(EntryRoot, 0700) if err != nil { diff --git a/src/cli/init.go b/src/cli/init.go index e1bdde4..3477689 100644 --- a/src/cli/init.go +++ b/src/cli/init.go @@ -3,6 +3,7 @@ package cli import ( "fmt" "github.com/rwinkhart/MUTN/src/backend" + "github.com/rwinkhart/MUTN/src/sync" "math/rand" "os" ) @@ -30,12 +31,6 @@ func TempInitCli() { // SSH info configSSH := inputBinary("Configure SSH settings (for synchronization)?") if configSSH { - // client device ID - deviceIDPrefix, _ := os.Hostname() - deviceIDSuffix := backend.StringGen(rand.Intn(48)+48, true, 0.2) - deviceID := deviceIDPrefix + "-" + deviceIDSuffix - os.Create(backend.ConfigDir + backend.PathSeparator + "devices" + backend.PathSeparator + deviceID) // TODO remove existing device ID file if it exists, copy device ID to server - // necessary SSH info sshUser := input("Remote SSH username:") sshIP := input("Remote SSH IP address:") @@ -44,6 +39,13 @@ func TempInitCli() { // write config file backend.TempInit(map[string]string{"textEditor": textEditor, "gpgID": gpgID, "sshUser": sshUser, "sshIP": sshIP, "sshPort": sshPort, "sshIdentity": sshIdentity}) + + // client device ID (perform after writing config files, as sync.GetSSHOutput must be able to read it) TODO move to backend + deviceIDPrefix, _ := os.Hostname() + deviceIDSuffix := backend.StringGen(rand.Intn(48)+48, false, 0) // TODO consider using complex string generator and removing unsafe characters manually + deviceID := deviceIDPrefix + "-" + deviceIDSuffix + os.Create(backend.ConfigDir + backend.PathSeparator + "devices" + backend.PathSeparator + deviceID) // TODO remove existing device ID file if it exists (from both client and server) + sync.GetSSHOutput("libmuttonserver register "+deviceID, false) // register device ID with server } else { // write config file backend.TempInit(map[string]string{"textEditor": textEditor, "gpgID": gpgID}) diff --git a/src/sync/client.go b/src/sync/client.go index f2f0851..0c8272f 100644 --- a/src/sync/client.go +++ b/src/sync/client.go @@ -17,9 +17,9 @@ const ( ansiUpload = "\033[38;5;4m" ) -// getSSHOutput runs a command over SSH and returns the output +// GetSSHOutput runs a command over SSH and returns the output // currently only supports password-less key-based authentication TODO add password support, still require key -func getSSHOutput(cmd string, manualSync bool) string { +func GetSSHOutput(cmd string, manualSync bool) string { // get SSH config info, exit if not configured (displaying an error if the sync job was called manually) var sshUserIPPortIdentity []string if manualSync { @@ -102,7 +102,7 @@ func getSSHOutput(cmd string, manualSync bool) string { // getRemoteDataFromClient returns a map of remote entries to their modification times, a list of remote folders, and a list of queued deletions func getRemoteDataFromClient(manualSync bool) (map[string]int64, []string, []string) { // get remote output over SSH - output := getSSHOutput("libmuttonserver fetch", manualSync) + output := GetSSHOutput("libmuttonserver fetch", manualSync) // split output into slice based on occurrences of "\x1d" outputSlice := strings.Split(output, "\x1d") @@ -172,7 +172,7 @@ func syncLists(localEntryModMap, remoteEntryModMap map[string]int64) { // iterate over remaining entries in remoteEntryModMap for entry := range remoteEntryModMap { - fmt.Println(ansiDownload+entry+backend.AnsiReset, "does not exist on server, downloading...") + fmt.Println(ansiDownload+entry+backend.AnsiReset, "does not exist on client, downloading...") // TODO entry does not exist on client, download } } diff --git a/src/sync/common.go b/src/sync/common.go index f83ffcb..6554d3f 100644 --- a/src/sync/common.go +++ b/src/sync/common.go @@ -90,13 +90,11 @@ func Shear(targetLocationIncomplete string, deviceID string) { } } } - } else { - backend.ReadConfig([]string{"sshUser"}, "0") // exits if value does not exist (indicates offline mode) - // if running on the client in online mode... + } else { // if running on the client... (online mode determined dynamically in GetSSHOutput, will simply exit if not in online mode) // determine client device ID (to send to server, avoids creating a deletion file for the client device) deviceID = deviceIDList[0].Name() // below: deviceID and targetLocationIncomplete are separated by \x1d, path separators are replaced with \x1e, and spaces are replaced with \x1f - getSSHOutput("libmuttonserver shear "+deviceID+"\x1d"+strings.ReplaceAll(strings.ReplaceAll(targetLocationIncomplete, backend.PathSeparator, "\x1e"), " ", "\x1f"), true) + GetSSHOutput("libmuttonserver shear "+deviceID+"\x1d"+strings.ReplaceAll(strings.ReplaceAll(targetLocationIncomplete, backend.PathSeparator, "\x1e"), " ", "\x1f"), false) } os.Exit(0)