diff --git a/socketserver/cmd/socketserver/socketserver.go b/socketserver/cmd/socketserver/socketserver.go index 0b0e052d..5de7a059 100644 --- a/socketserver/cmd/socketserver/socketserver.go +++ b/socketserver/cmd/socketserver/socketserver.go @@ -2,56 +2,52 @@ package main // import "bitbucket.org/stendec/frankerfacez/socketserver/cmd/sock import ( "../../internal/server" + "encoding/json" "flag" + "fmt" + "io/ioutil" "log" "net/http" + "os" ) -var origin *string = flag.String("origin", "localhost:8001", "Client-visible origin of the socket server") -var bindAddress *string = flag.String("listen", "", "Address to bind to, if different from origin") -var usessl *bool = flag.Bool("ssl", false, "Enable the use of SSL for connecting clients and backend connections") -var certificateFile *string = flag.String("crt", "ssl.crt", "CA-signed SSL certificate file") -var privateKeyFile *string = flag.String("key", "ssl.key", "SSL private key file") - -var naclKeysFile *string = flag.String("naclkey", "naclkeys.json", "Keypairs for the NaCl crypto library, for communicating with the backend.") +var configFilename *string = flag.String("config", "config.json", "Configuration file, including the keypairs for the NaCl crypto library, for communicating with the backend.") var generateKeys *bool = flag.Bool("genkeys", false, "Generate NaCl keys instead of serving requests.\nArguments: [int serverId] [base64 backendPublic]\nThe backend public key can either be specified in base64 on the command line, or put in the json file later.") func main() { flag.Parse() if *generateKeys { - GenerateKeys(*naclKeysFile) + GenerateKeys(*configFilename) return } - if *origin == "" { - log.Fatalln("--origin argument required") + confFile, err := os.Open(*configFilename) + if os.IsNotExist(err) { + fmt.Println("Error: No config file. Run with -genkeys and edit config.json") + os.Exit(3) } - if *bindAddress == "" { - bindAddress = origin + if err != nil { + log.Fatal(err) } - if (*certificateFile == "") != (*privateKeyFile == "") { - log.Fatalln("Either both --crt and --key can be provided, or neither.") + conf := &server.ConfigFile{} + confBytes, err := ioutil.ReadAll(confFile) + if err != nil { + log.Fatal(err) } - - conf := &server.Config{ - SSLKeyFile: *privateKeyFile, - SSLCertificateFile: *certificateFile, - UseSSL: *usessl, - NaclKeysFile: *naclKeysFile, - - SocketOrigin: *origin, + err = json.Unmarshal(confBytes, &conf) + if err != nil { + log.Fatal(err) } httpServer := &http.Server{ - Addr: *bindAddress, + Addr: conf.ListenAddr, } server.SetupServerAndHandle(conf, httpServer.TLSConfig, nil) - var err error if conf.UseSSL { - err = httpServer.ListenAndServeTLS(*certificateFile, *privateKeyFile) + err = httpServer.ListenAndServeTLS(conf.SSLCertificateFile, conf.SSLKeyFile) } else { err = httpServer.ListenAndServe() } @@ -63,11 +59,13 @@ func main() { func GenerateKeys(outputFile string) { if flag.NArg() < 1 { - log.Fatal("The server ID must be specified") + fmt.Println("Specify a numeric server ID after -genkeys") + os.Exit(2) } if flag.NArg() >= 2 { server.GenerateKeys(outputFile, flag.Arg(0), flag.Arg(1)) } else { server.GenerateKeys(outputFile, flag.Arg(0), "") } + fmt.Println("Keys generated. Now edit config.json") } diff --git a/socketserver/internal/server/backend.go b/socketserver/internal/server/backend.go index 9f316929..b966b354 100644 --- a/socketserver/internal/server/backend.go +++ b/socketserver/internal/server/backend.go @@ -11,7 +11,6 @@ import ( "log" "net/http" "net/url" - "os" "strconv" "strings" "sync" @@ -29,7 +28,7 @@ var serverId int var messageBufferPool sync.Pool -func SetupBackend(config *Config) { +func SetupBackend(config *ConfigFile) { backendHttpClient.Timeout = 60 * time.Second backendUrl = config.BackendUrl if responseCache != nil { @@ -41,21 +40,10 @@ func SetupBackend(config *Config) { messageBufferPool.New = New4KByteBuffer - var keys CryptoKeysBuf - file, err := os.Open(config.NaclKeysFile) - if err != nil { - log.Fatal(err) - } - dec := json.NewDecoder(file) - err = dec.Decode(&keys) - if err != nil { - log.Fatal(err) - } - var theirPublic, ourPrivate [32]byte - copy(theirPublic[:], keys.TheirPublicKey) - copy(ourPrivate[:], keys.OurPrivateKey) - serverId = keys.ServerId + copy(theirPublic[:], config.BackendPublicKey) + copy(ourPrivate[:], config.OurPrivateKey) + serverId = config.ServerId box.Precompute(&backendSharedKey, &theirPublic, &ourPrivate) } @@ -193,7 +181,7 @@ func FetchBacklogData(chatSubs []string) ([]ClientMessage, error) { func GenerateKeys(outputFile, serverId, theirPublicStr string) { var err error - output := CryptoKeysBuf{} + output := ConfigFile{} output.ServerId, err = strconv.Atoi(serverId) if err != nil { @@ -212,19 +200,16 @@ func GenerateKeys(outputFile, serverId, theirPublicStr string) { if err != nil { log.Fatal(err) } - output.TheirPublicKey = theirPublic + output.BackendPublicKey = theirPublic } - file, err := os.Create(outputFile) + fmt.Println(ourPublic, ourPrivate) + bytes, err := json.MarshalIndent(output, "", "\t") if err != nil { log.Fatal(err) } - enc := json.NewEncoder(file) - err = enc.Encode(output) - if err != nil { - log.Fatal(err) - } - err = file.Close() + fmt.Println(string(bytes)) + err = ioutil.WriteFile(outputFile, bytes, 0600) if err != nil { log.Fatal(err) } diff --git a/socketserver/internal/server/handlecore.go b/socketserver/internal/server/handlecore.go index 1f477f97..7ff9db07 100644 --- a/socketserver/internal/server/handlecore.go +++ b/socketserver/internal/server/handlecore.go @@ -6,31 +6,16 @@ import ( "errors" "fmt" "golang.org/x/net/websocket" + "html/template" "log" "net/http" "strconv" "strings" "sync" - "html/template" ) const MAX_PACKET_SIZE = 1024 -type Config struct { - // SSL/TLS - SSLCertificateFile string - SSLKeyFile string - UseSSL bool - - // NaCl keys for backend messages - NaclKeysFile string - - // Hostname of the socket server - SocketOrigin string - // URL to the backend server - BackendUrl string -} - // A command is how the client refers to a function on the server. It's just a string. type Command string @@ -85,10 +70,10 @@ var ExpectedStringAndInt = errors.New("Error: Expected array of string, int as a var ExpectedStringAndBool = errors.New("Error: Expected array of string, bool as arguments.") var ExpectedStringAndIntGotFloat = errors.New("Error: Second argument was a float, expected an integer.") -var gconfig *Config +var gconfig *ConfigFile // Create a websocket.Server with the options from the provided Config. -func setupServer(config *Config, tlsConfig *tls.Config) *websocket.Server { +func setupServer(config *ConfigFile, tlsConfig *tls.Config) *websocket.Server { gconfig = config sockConf, err := websocket.NewConfig("/", config.SocketOrigin) if err != nil { @@ -120,28 +105,36 @@ func setupServer(config *Config, tlsConfig *tls.Config) *websocket.Server { // Set up a websocket listener and register it on /. // (Uses http.DefaultServeMux .) -func SetupServerAndHandle(config *Config, tlsConfig *tls.Config, serveMux *http.ServeMux) { +func SetupServerAndHandle(config *ConfigFile, tlsConfig *tls.Config, serveMux *http.ServeMux) { sockServer := setupServer(config, tlsConfig) if serveMux == nil { serveMux = http.DefaultServeMux } serveMux.HandleFunc("/", ServeWebsocketOrCatbag(sockServer.ServeHTTP)) + serveMux.Handle("/assets", http.FileServer(nil)) // TODO serveMux.HandleFunc("/pub_msg", HBackendPublishRequest) serveMux.HandleFunc("/dump_backlog", HBackendDumpBacklog) serveMux.HandleFunc("/update_and_pub", HBackendUpdateAndPublish) } -var Catbag = template.Must(template.New(` +var Memes = template.Must(template.New("catbag").Parse(` - - CatBag - - - - -`).Parse("html")) + +
+
+
+
+
+
+ A FrankerFaceZ Service + — CatBag by Wolsk +
+ This socket server hosted by {{.}} +
+
+`)) func ServeWebsocketOrCatbag(sockfunc func(http.ResponseWriter, *http.Request)) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { @@ -149,8 +142,7 @@ func ServeWebsocketOrCatbag(sockfunc func(http.ResponseWriter, *http.Request)) h sockfunc(w, r) return } else { - - Catbag.Execute(w, nil) + Memes.Execute(w, "Todo Add Feature") } } } diff --git a/socketserver/internal/server/publisher_test.go b/socketserver/internal/server/publisher_test.go index e878f709..2dc54ed6 100644 --- a/socketserver/internal/server/publisher_test.go +++ b/socketserver/internal/server/publisher_test.go @@ -126,20 +126,36 @@ func TGetUrls(testserver *httptest.Server) TURLs { } } -const TNaclKeysLocation = "/tmp/test_naclkeys.json" - func TSetup(testserver **httptest.Server, urls *TURLs) { - if backendSharedKey[0] == 0 { - GenerateKeys(TNaclKeysLocation, "2", "+ZMqOmxhaVrCV5c0OMZ09QoSGcJHuqQtJrwzRD+JOjE=") - } DumpCache() + conf := &ConfigFile{ + ServerId: 20, + UseSSL: false, + SocketOrigin: "localhost:2002", + BannerHTML: ` + +CatBag + +
+
+
+
+
+
+ A FrankerFaceZ Service + — CatBag by Wolsk +
+
+`, + OurPublicKey: []byte{176, 149, 72, 209, 35, 42, 110, 220, 22, 236, 212, 129, 213, 199, 1, 227, 185, 167, 150, 159, 117, 202, 164, 100, 9, 107, 45, 141, 122, 221, 155, 73}, + OurPrivateKey: []byte{247, 133, 147, 194, 70, 240, 211, 216, 223, 16, 241, 253, 120, 14, 198, 74, 237, 180, 89, 33, 146, 146, 140, 58, 88, 160, 2, 246, 112, 35, 239, 87}, + BackendPublicKey: []byte{19, 163, 37, 157, 50, 139, 193, 85, 229, 47, 166, 21, 153, 231, 31, 133, 41, 158, 8, 53, 73, 0, 113, 91, 13, 181, 131, 248, 176, 18, 1, 107}, + } + gconfig = conf + SetupBackend(conf) + if testserver != nil { - conf := &Config{ - UseSSL: false, - NaclKeysFile: TNaclKeysLocation, - SocketOrigin: "localhost:2002", - } serveMux := http.NewServeMux() SetupServerAndHandle(conf, nil, serveMux) diff --git a/socketserver/internal/server/types.go b/socketserver/internal/server/types.go index a2bd074d..cc9ba947 100644 --- a/socketserver/internal/server/types.go +++ b/socketserver/internal/server/types.go @@ -9,24 +9,39 @@ import ( const CryptoBoxKeyLength = 32 -type CryptoKeysBuf struct { - OurPrivateKey []byte - OurPublicKey []byte - TheirPublicKey []byte - ServerId int +type ConfigFile struct { + // Numeric server id known to the backend + ServerId int + ListenAddr string + // Hostname of the socket server + SocketOrigin string + // URL to the backend server + BackendUrl string + // Memes go here + BannerHTML string + + // SSL/TLS + UseSSL bool + SSLCertificateFile string + SSLKeyFile string + + // Nacl keys + OurPrivateKey []byte + OurPublicKey []byte + BackendPublicKey []byte } type ClientMessage struct { // Message ID. Increments by 1 for each message sent from the client. // When replying to a command, the message ID must be echoed. // When sending a server-initiated message, this is -1. - MessageID int `json:_` + MessageID int // The command that the client wants from the server. // When sent from the server, the literal string 'True' indicates success. // Before sending, a blank Command will be converted into SuccessCommand. - Command Command `json:cmd` + Command Command // Result of json.Unmarshal on the third field send from the client - Arguments interface{} `json:data` + Arguments interface{} origArguments string }