1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-08-03 08:28:31 +00:00

Combine config objects, improve first-run ux

This commit is contained in:
Kane York 2015-10-26 22:16:03 -07:00
parent a6508d32ab
commit 4eee83a561
5 changed files with 104 additions and 98 deletions

View file

@ -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")
}

View file

@ -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)
}

View file

@ -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(`
<!DOCTYPE html>
<html>
<head>
<title>CatBag</title>
</head>
<body>
</body>
</html>
`).Parse("html"))
<link rel="stylesheet" href="//cdn.frankerfacez.com/script/catbag.css">
<div id="container">
<div id="zf0"></div><div id="zf1"></div><div id="zf2"></div>
<div id="zf3"></div><div id="zf4"></div><div id="zf5"></div>
<div id="zf6"></div><div id="zf7"></div><div id="zf8"></div>
<div id="zf9"></div><div id="catbag"></div>
<div id="bottom">
A <a href="http://www.frankerfacez.com/">FrankerFaceZ</a> Service
&mdash; CatBag by <a href="http://www.twitch.tv/wolsk">Wolsk</a>
<br>
This socket server hosted by {{.}}
</div>
</div>
`))
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")
}
}
}

View file

@ -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: `
<!DOCTYPE html>
<title>CatBag</title>
<link rel="stylesheet" href="//cdn.frankerfacez.com/script/catbag.css">
<div id="container">
<div id="zf0"></div><div id="zf1"></div><div id="zf2"></div>
<div id="zf3"></div><div id="zf4"></div><div id="zf5"></div>
<div id="zf6"></div><div id="zf7"></div><div id="zf8"></div>
<div id="zf9"></div><div id="catbag"></div>
<div id="bottom">
A <a href="http://www.frankerfacez.com/">FrankerFaceZ</a> Service
&mdash; CatBag by <a href="http://www.twitch.tv/wolsk">Wolsk</a>
</div>
</div>
`,
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)

View file

@ -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
}