From d3765fd9bb72d7e31eda921be401507661e4cfdc Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Mon, 18 Jun 2018 15:57:21 -0700 Subject: [PATCH] server now has a config file; delete profile.Save (unsued); update cwtch_peer.Save to use indented Marshal --- model/profile.go | 18 ---- model/profile_test.go | 12 --- peer/cwtch_peer.go | 2 +- server/app/main.go | 28 +++--- server/app/serverConfig.json.sample | 7 ++ server/server.go | 19 ++-- server/serverConfig.go | 88 +++++++++++++++++++ .../cwtch_peer_server_intergration_test.go | 3 +- testing/quality.sh | 12 +++ testing/tests.sh | 1 - 10 files changed, 130 insertions(+), 60 deletions(-) create mode 100644 server/app/serverConfig.json.sample create mode 100644 server/serverConfig.go create mode 100755 testing/quality.sh diff --git a/model/profile.go b/model/profile.go index 5a6d9a6..0fd8a41 100644 --- a/model/profile.go +++ b/model/profile.go @@ -5,13 +5,11 @@ import ( "crypto/rsa" "cwtch.im/cwtch/protocol" "encoding/asn1" - "encoding/json" "errors" "github.com/golang/protobuf/proto" "github.com/s-rah/go-ricochet/utils" "golang.org/x/crypto/ed25519" "io" - "io/ioutil" "strconv" "sync" "time" @@ -292,19 +290,3 @@ func (p *Profile) EncryptMessageToGroup(message string, groupID string) ([]byte, } return nil, errors.New("group does not exist") } - -// Save makes a opy of the profile in the given file -func (p *Profile) Save(profilefile string) error { - p.lock.Lock() - defer p.lock.Unlock() - bytes, _ := json.Marshal(p) - return ioutil.WriteFile(profilefile, bytes, 0600) -} - -// LoadProfile loads a saved profile from a file. -func LoadProfile(profilefile string) (*Profile, error) { - bytes, _ := ioutil.ReadFile(profilefile) - profile := new(Profile) - err := json.Unmarshal(bytes, &profile) - return profile, err -} diff --git a/model/profile_test.go b/model/profile_test.go index fdecc1c..8b97058 100644 --- a/model/profile_test.go +++ b/model/profile_test.go @@ -6,18 +6,6 @@ import ( "testing" ) -func TestProfile(t *testing.T) { - profile := GenerateNewProfile("Sarah") - err := profile.Save("./profile_test") - if err != nil { - t.Errorf("Should have saved profile, but got error: %v", err) - } - loadedProfile, err := LoadProfile("./profile_test") - if err != nil || loadedProfile.Name != "Sarah" { - t.Errorf("Issue loading profile from file %v %v", err, loadedProfile) - } -} - func TestProfileIdentity(t *testing.T) { sarah := GenerateNewProfile("Sarah") alice := GenerateNewProfile("Alice") diff --git a/peer/cwtch_peer.go b/peer/cwtch_peer.go index 0d07dbb..6b5f888 100644 --- a/peer/cwtch_peer.go +++ b/peer/cwtch_peer.go @@ -62,7 +62,7 @@ func NewCwtchPeer(name string) *CwtchPeer { // Save saves the CwtchPeer profile state to a file. func (cp *CwtchPeer) Save(profilefile string) error { cp.mutex.Lock() - bytes, _ := json.Marshal(cp) + bytes, _ := json.MarshalIndent(cp, "", "\t") err := ioutil.WriteFile(profilefile, bytes, 0600) cp.profilefile = profilefile cp.mutex.Unlock() diff --git a/server/app/main.go b/server/app/main.go index 846b687..4f5fac8 100644 --- a/server/app/main.go +++ b/server/app/main.go @@ -2,35 +2,33 @@ package main import ( cwtchserver "cwtch.im/cwtch/server" - "github.com/s-rah/go-ricochet/utils" "io/ioutil" "log" "os" ) -const privateKeyFile = "./private_key" +const ( + serverConfigFile = "serverConfig.json" +) -func checkAndGenPrivateKey(privateKeyFile string) { - if _, err := os.Stat(privateKeyFile); os.IsNotExist(err) { - log.Printf("no private key found!") - log.Printf("generating new private key...") - pk, err := utils.GeneratePrivateKey() +func confirmOrCopySampleConfig() { + // if no config file, attempt to copy sample + if _, err := os.Stat(serverConfigFile); os.IsNotExist(err) { + raw, err := ioutil.ReadFile(serverConfigFile + ".sample") if err != nil { - log.Fatalf("error generating new private key: %v\n", err) - } - err = ioutil.WriteFile(privateKeyFile, []byte(utils.PrivateKeyToString(pk)), 0400) - if err != nil { - log.Fatalf("error writing new private key to file %s: %v\n", privateKeyFile, err) + log.Fatal("Could not read sample config to copy: ", err) } + ioutil.WriteFile(serverConfigFile, raw, 0600) } } func main() { - checkAndGenPrivateKey(privateKeyFile) + confirmOrCopySampleConfig() + serverConfig := cwtchserver.LoadConfig(serverConfigFile) server := new(cwtchserver.Server) log.Printf("starting cwtch server...") // TODO load params from .cwtch/server.conf or command line flag - server.Run(privateKeyFile, 100000) -} + server.Run(serverConfig) +} \ No newline at end of file diff --git a/server/app/serverConfig.json.sample b/server/app/serverConfig.json.sample new file mode 100644 index 0000000..985da45 --- /dev/null +++ b/server/app/serverConfig.json.sample @@ -0,0 +1,7 @@ +{ + "maxBufferLines": 100000 + serverReporting: { + reportingGroupId: "" + reportingServerAddr: "" + } +} diff --git a/server/server.go b/server/server.go index 2c98538..d607a91 100644 --- a/server/server.go +++ b/server/server.go @@ -7,27 +7,22 @@ import ( "cwtch.im/cwtch/storage" "github.com/s-rah/go-ricochet/application" "github.com/s-rah/go-ricochet/channels" - "github.com/s-rah/go-ricochet/utils" "log" ) // Server encapsulates a complete, compliant Cwtch server. type Server struct { app *application.RicochetApplication + config *Config } // Run starts a server with the given privateKey // TODO: surface errors -func (s *Server) Run(privateKeyFile string, bufferSize int) { +func (s *Server) Run(serverConfig *Config) { + s.config = serverConfig cwtchserver := new(application.RicochetApplication) - pk, err := utils.LoadPrivateKeyFromFile(privateKeyFile) - - if err != nil { - log.Fatalf("error reading private key file: %v", err) - } - - l, err := application.SetupOnion("127.0.0.1:9051", "tcp4", "", pk, 9878) + l, err := application.SetupOnion("127.0.0.1:9051", "tcp4", "", s.config.PrivateKey(), 9878) if err != nil { log.Fatalf("error setting up onion service: %v", err) @@ -36,7 +31,7 @@ func (s *Server) Run(privateKeyFile string, bufferSize int) { af := application.ApplicationInstanceFactory{} af.Init() ms := new(storage.MessageStore) - ms.Init("cwtch.messages", bufferSize) + ms.Init("cwtch.messages", s.config.MaxBufferLines) af.AddHandler("im.cwtch.server.listen", func(rai *application.ApplicationInstance) func() channels.Handler { si := new(Instance) si.Init(rai, cwtchserver, ms) @@ -66,10 +61,10 @@ func (s *Server) Run(privateKeyFile string, bufferSize int) { } }) - cwtchserver.Init("cwtch server for "+l.Addr().String()[0:16], pk, af, new(application.AcceptAllContactManager)) + cwtchserver.Init("cwtch server for "+l.Addr().String()[0:16], s.config.PrivateKey(), af, new(application.AcceptAllContactManager)) log.Printf("cwtch server running on cwtch:%s", l.Addr().String()[0:16]) s.app = cwtchserver - cwtchserver.Run(l) + s.app.Run(l) } // Shutdown kills the app closing all connections and freeing all goroutines diff --git a/server/serverConfig.go b/server/serverConfig.go new file mode 100644 index 0000000..752caa1 --- /dev/null +++ b/server/serverConfig.go @@ -0,0 +1,88 @@ +package server + +import ( + "sync" + "github.com/s-rah/go-ricochet/utils" + "io/ioutil" + "log" + "encoding/json" + "crypto/rsa" +) + +// Reporting is a struct for storing a the config a server needs to be a peer, and connect to a group to report +type Reporting struct { + PeerPrivateKey string `json:"privateKey"` + ReportingGroupID string `json:"reportingGroupId"` + ReportingServerAddr string `json:"reportingServerAddr"` +} + +// Config is a struct for storing basic server configuration +type Config struct { + MaxBufferLines int `json:"maxBufferLines"` + PrivateKeyBytes string `json:"privateKey"` + ServerReporting Reporting `json:"serverReporting"` + lock sync.Mutex +} + +// PrivateKey returns an rsa.PrivateKey generated from the config's PrivateKeyBytes +func (config *Config) PrivateKey() *rsa.PrivateKey { + pk, err := utils.ParsePrivateKey([]byte(config.PrivateKeyBytes)) + if err != nil { + log.Println("Error parsing private key: ", err) + } + return pk +} + +// Save dumps the latest version of the config to a json file given by filename +func (config *Config) Save(filename string) { + config.lock.Lock() + defer config.lock.Unlock() + bytes, _ := json.MarshalIndent(config, "", "\t") + ioutil.WriteFile(filename, bytes, 0600) +} + +// LoadConfig loads a Config from a json file specified by filename +func LoadConfig(filename string) *Config { + raw, err := ioutil.ReadFile(filename) + if err != nil { + log.Fatal("Could not read config: ", err) + } + + config := Config{} + err = json.Unmarshal(raw, &config) + + if err != nil { + log.Fatal("Error reading config: ", err) + } + + if config.PrivateKeyBytes == "" { + config.generatePrivateKey() + config.Save(filename) + } + if config.ServerReporting.PeerPrivateKey == "" { + config.generatePeerPrivateKey() + config.Save(filename) + } + + return &config +} + +func (config *Config) generatePrivateKey() { + pk, err := utils.GeneratePrivateKey() + if err != nil { + log.Fatalf("error generating new private key: %v\n", err) + } + config.lock.Lock() + config.PrivateKeyBytes = utils.PrivateKeyToString(pk) + config.lock.Unlock() +} + +func (config *Config) generatePeerPrivateKey() { + pk, err := utils.GeneratePrivateKey() + if err != nil { + log.Fatalf("error generating new peer private key: %v\n", err) + } + config.lock.Lock() + config.ServerReporting.PeerPrivateKey = utils.PrivateKeyToString(pk) + config.lock.Unlock() +} diff --git a/testing/cwtch_peer_server_intergration_test.go b/testing/cwtch_peer_server_intergration_test.go index a347ca0..e9719f4 100644 --- a/testing/cwtch_peer_server_intergration_test.go +++ b/testing/cwtch_peer_server_intergration_test.go @@ -129,7 +129,8 @@ func TestCwtchPeerIntegration(t *testing.T) { serverAddr, _ = utils.GetOnionAddress(serverKey) server = new(cwtchserver.Server) fmt.Println("Starting cwtch server...") - go server.Run(localKeyfile, 100) + config := cwtchserver.Config{ PrivateKeyBytes: utils.PrivateKeyToString(serverKey), MaxBufferLines: 100, ServerReporting: cwtchserver.Reporting{ } } + go server.Run(&config) // let tor get established fmt.Printf("Establishing Tor hidden service: %v...\n", serverAddr) diff --git a/testing/quality.sh b/testing/quality.sh new file mode 100755 index 0000000..87db32f --- /dev/null +++ b/testing/quality.sh @@ -0,0 +1,12 @@ +#!/bin/sh + +echo "Checking code quality (you want to see no output here)" +echo "" + +echo "Vetting:" +go list ./... | xargs go vet + +echo "" +echo "Linting:" + +go list ./... | xargs golint diff --git a/testing/tests.sh b/testing/tests.sh index fab52fa..25e238f 100755 --- a/testing/tests.sh +++ b/testing/tests.sh @@ -18,4 +18,3 @@ go test ${1} -coverprofile=server.cover.out -v ./server echo "mode: set" > coverage.out && cat *.cover.out | grep -v mode: | sort -r | \ awk '{if($1 != last) {print $0;last=$1}}' >> coverage.out rm -rf *.cover.out -go list ./... | xargs go vet