From acc1814a626d589a412d9dec6a090fa5cc767ad8 Mon Sep 17 00:00:00 2001 From: Florian Walther Date: Mon, 9 Jul 2018 17:48:29 +0200 Subject: [PATCH] WIP: added basis for config restore --- cmd/client/main.go | 23 ++++++++ cmd/server/ConfigHandler.go | 45 ++++++---------- cmd/server/main.go | 2 +- libs/client/client.go | 102 ++++++++++++++++++++++++++++++++++++ 4 files changed, 142 insertions(+), 30 deletions(-) diff --git a/cmd/client/main.go b/cmd/client/main.go index 1c44618..82fda2f 100644 --- a/cmd/client/main.go +++ b/cmd/client/main.go @@ -50,6 +50,7 @@ var saltHex string // submit salt to register process var showUsername bool var toraddr string var outFile string // file to write output, overrides original filename +var restore string // userid to restore func init() { flag.StringVar(&toraddr, "socksproxy", "", "set a socks proxy (e.g. tor) to be used to connect to the server") @@ -78,6 +79,7 @@ func init() { flag.BoolVar(®isterNewMachine, "register-new-host", false, "registers a new machine with a given userID") flag.BoolVar(&unregisterMachine, "unregister-host", false, "invalidates the machine access, deletes local config") flag.StringVar(&outFile, "o", "", "write to this filename") + flag.StringVar(&restore, "restore", "", "userID to restore locally") } func checkFatal(err error) { @@ -109,6 +111,23 @@ func main() { // delete APIToken for that machine OR force a new APIToken onto the account. // delete APIToken for that machine OR force a new APIToken onto the account. } + if restore != "" { + // load config from server + // ask user for minilock credentials + email, password := askpass.Credentials() + keys, err := minilock.GenerateKey(email, password) + checkFatal(err) + //pubID, err := keys.EncodeID() + //checkFatal(err) + c, err := client.New( + client.SetUsername(restore), + client.SetURL(URL), + client.SetKeys(keys)) + err = c.GetConfigOnServer() + checkFatal(err) + log.Printf("Client: %+v\n", c) + return + } // register if register { @@ -170,6 +189,9 @@ func main() { c.Socksproxy = toraddr cy, err := yaml.Marshal(c) checkFatal(err) + // save the config on the server + err = c.SaveConfigOnServer() + checkFatal(err) // make sure that the path exists clientConfigFile = filepath.Join( usr.HomeDir, ".config", @@ -213,6 +235,7 @@ func main() { checkFatal(err) err = yaml.Unmarshal(data, &c) checkFatal(err) + if showUsername { fmt.Printf("Your secureShareUsername is: '%s'\n", c.Username) return diff --git a/cmd/server/ConfigHandler.go b/cmd/server/ConfigHandler.go index 99f670f..1ce7aa9 100644 --- a/cmd/server/ConfigHandler.go +++ b/cmd/server/ConfigHandler.go @@ -1,31 +1,34 @@ package main import ( - "bufio" - "bytes" "github.com/gorilla/mux" - "io" + "io/ioutil" "log" "net/http" "path/filepath" - "strings" + //"strings" ) func ConfigHandler(w http.ResponseWriter, r *http.Request) { + log.Printf("entering ConfigHandler...\n") + /* We can not authenticate because we have no ApiKey on the client yet. username := r.Header.Get("Apiusername") token := r.Header.Get("Apikey") if userDB.APIAuthenticate(username, token) != true { http.Error(w, "Unauthorized", 401) return } + */ vars := mux.Vars(r) userID := vars["UserID"] switch r.Method { case "GET": + log.Printf("ConfigHandler GET\n") // send config to client aka download - filePath := strings.Join([]string{userID, "config"}, "/") - data, err := fileStore.Read(filePath) + //filePath := strings.Join([]string{userID, "config"}, "/") + filePath := filepath.Join(userID, "config") + data, err := clientStore.Read(filePath) if err != nil { log.Printf("ERROR downloading '%s': %s\n", filePath, err.Error()) http.Error(w, "file not found", 404) @@ -41,34 +44,18 @@ func ConfigHandler(w http.ResponseWriter, r *http.Request) { log.Printf("written %d byte to client\n", n) return case "POST": + log.Printf("ConfigHandler POST\n") // retrieve config from client and store aka upload - var inBuf bytes.Buffer - inWrt := bufio.NewWriter(&inBuf) - reader, err := r.MultipartReader() + bodyBytes, err := ioutil.ReadAll(r.Body) if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) + http.Error(w, err.Error(), 500) return } - for { - part, err := reader.NextPart() - if err == io.EOF { - break - } - if part.FileName() == "" { - continue - } - if _, err = io.Copy(inWrt, part); err != nil { - log.Printf("Error copy file part: %s\n", err.Error()) - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - filePath := filepath.Join(userID, "config") - err = clientStore.Write(filePath, inBuf.Bytes()) - if err != nil { - log.Println(err) - } + filePath := filepath.Join(userID, "config") + err = clientStore.Write(filePath, bodyBytes) + if err != nil { + log.Println(err) } - return } return } diff --git a/cmd/server/main.go b/cmd/server/main.go index 76f7276..5782035 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -118,8 +118,8 @@ func main() { }) // initialize http router router := mux.NewRouter().StrictSlash(true) - router.HandleFunc("/{UserID}/{FileID}", Download) router.HandleFunc("/config/{UserID}", ConfigHandler).Name("ConfigHandler") + router.HandleFunc("/{UserID}/{FileID}", Download) router.HandleFunc("/upload/", Upload) router.HandleFunc("/list/", List) router.HandleFunc("/register/", Register) diff --git a/libs/client/client.go b/libs/client/client.go index a662bd7..951f7ec 100644 --- a/libs/client/client.go +++ b/libs/client/client.go @@ -7,6 +7,7 @@ import ( "crypto/rand" "encoding/base64" "encoding/hex" + "encoding/json" "fmt" "github.com/cathalgarvey/go-minilock" "github.com/cathalgarvey/go-minilock/taber" @@ -195,6 +196,107 @@ func (c *Client) UpdateKey(username string) (pubKey string, err error) { return } +func (c *Client) SaveConfigOnServer() (err error) { + // marshal client + clientBytes, err := json.Marshal(c) + if err != nil { + return + } + // encrypt clientBytes + // TODO: minilock.EncryptFileContents() + // create save request + bodyReader := bytes.NewReader(clientBytes) + urlString := c.URL + "config/" + c.Username + req, err := http.NewRequest("POST", urlString, bodyReader) + if err != nil { + return + } + if Debug { + dump, _ := httputil.DumpRequestOut(req, false) + log.Printf("%s", dump) + } + // send request + resp, err := c.Do(req) + if err != nil { + return + } + if Debug { + dump, _ := httputil.DumpResponse(resp, true) + log.Printf("%s", dump) + } + // check response + if resp.StatusCode != 200 { + log.Printf("status code (%d) is NOT OK\n", resp.StatusCode) + body, readErr := ioutil.ReadAll(resp.Body) + if readErr != nil { + return readErr + } + log.Printf("Server error: '%s'\n", body) + err = fmt.Errorf("Server error: '%s'\n", body) + return + } + // return + return +} + +func (c *Client) GetConfigOnServer() (err error) { + urlString := c.URL + "config/" + c.Username + req, err := http.NewRequest("GET", urlString, nil) + if err != nil { + return + } + if Debug { + dump, _ := httputil.DumpRequestOut(req, false) + log.Printf("%s", dump) + } + // send request + resp, err := c.Do(req) + if err != nil { + return + } + if Debug { + dump, _ := httputil.DumpResponse(resp, true) + log.Printf("%s", dump) + } + // check response + if resp.StatusCode != 200 { + log.Printf("status code (%d) is NOT OK\n", resp.StatusCode) + body, readErr := ioutil.ReadAll(resp.Body) + if readErr != nil { + return readErr + } + log.Printf("Server error: '%s'\n", body) + err = fmt.Errorf("Server error: '%s'\n", body) + return + } + // read body + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return + } + /* // decrypt body + senderID, _, rr, err := minilock.DecryptFileContents(body, c.Keys) + if err != nil { + return + } + if senderID != c.Username { + err = fmt.Errorf("config senderID not correct: '%s' vs. '%s'\n", senderID, c.Username) + return + } + // unmarshal + err = json.Unmarshal(rr, c) + if err != nil { + return + } + */ + // unmarshal + err = json.Unmarshal(body, c) + if err != nil { + return + } + return +} + // Register - register a new user at the secureShareServer func (c *Client) Register(pubID string) (user, token, mID, mToken string, err error) { v := url.Values{}