diff --git a/app.go b/app.go new file mode 100644 index 0000000..63bc9cc --- /dev/null +++ b/app.go @@ -0,0 +1,81 @@ +package writefreely + +import ( + "fmt" + _ "github.com/go-sql-driver/mysql" + "net/http" + "os" + "os/signal" + "syscall" + + "github.com/gorilla/mux" + "github.com/gorilla/sessions" + "github.com/writeas/web-core/log" + "github.com/writeas/writefreely/config" +) + +const ( + staticDir = "static/" +) + +type app struct { + router *mux.Router + cfg *config.Config + keys *keychain + sessionStore *sessions.CookieStore +} + +var shttp = http.NewServeMux() + +func Serve() { + log.Info("Initializing...") + + log.Info("Loading configuration...") + cfg, err := config.Load() + if err != nil { + log.Error("Unable to load configuration: %v", err) + os.Exit(1) + } + app := &app{ + cfg: cfg, + } + + // Load keys + log.Info("Loading encryption keys...") + err = initKeys(app) + if err != nil { + log.Error("\n%s\n", err) + } + + // Initialize modules + r := mux.NewRouter() + handler := NewHandler(app.sessionStore) + + // Handle app routes + initRoutes(handler, r, app.cfg) + + // Handle static files + fs := http.FileServer(http.Dir(staticDir)) + shttp.Handle("/", fs) + r.PathPrefix("/").Handler(fs) + + // Handle shutdown + c := make(chan os.Signal, 2) + signal.Notify(c, os.Interrupt, syscall.SIGTERM) + go func() { + <-c + log.Info("Shutting down...") + shutdown(app) + log.Info("Done.") + os.Exit(0) + }() + + // Start web application server + http.Handle("/", r) + log.Info("Serving on http://localhost:%d\n", app.cfg.Server.Port) + log.Info("---") + http.ListenAndServe(fmt.Sprintf(":%d", app.cfg.Server.Port), nil) +} + +func shutdown(app *app) { +} diff --git a/cmd/writefreely/.gitignore b/cmd/writefreely/.gitignore new file mode 100644 index 0000000..0c3aa8d --- /dev/null +++ b/cmd/writefreely/.gitignore @@ -0,0 +1 @@ +writefreely diff --git a/cmd/writefreely/main.go b/cmd/writefreely/main.go new file mode 100644 index 0000000..8f1fefe --- /dev/null +++ b/cmd/writefreely/main.go @@ -0,0 +1,9 @@ +package main + +import ( + "github.com/writeas/writefreely" +) + +func main() { + writefreely.Serve() +} diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..8dff369 --- /dev/null +++ b/config/config.go @@ -0,0 +1,85 @@ +package config + +import ( + "gopkg.in/ini.v1" +) + +const ( + configFile = "config.ini" +) + +type ( + ServerCfg struct { + Host string `ini:"host"` + Port int `ini:"port"` + } + + DatabaseCfg struct { + Type string `ini:"type"` + User string `ini:"username"` + Pass string `ini:"password"` + Host string `ini:"host"` + Port int `ini:"port"` + } + + AppCfg struct { + MultiUser bool `ini:"multiuser"` + OpenSignups bool `ini:"open_signups"` + Federation bool `ini:"federation"` + + Name string `ini:"site_name"` + + JSDisabled bool `ini:"disable_js"` + + // User registration + MinUsernameLen int `ini:"min_username_len"` + } + + Config struct { + Server ServerCfg `ini:"server"` + Database DatabaseCfg `ini:"database"` + App AppCfg `ini:"app"` + } +) + +func New() *Config { + return &Config{ + Server: ServerCfg{ + Host: "http://localhost:8080", + Port: 8080, + }, + Database: DatabaseCfg{ + Type: "mysql", + Host: "localhost", + }, + App: AppCfg{ + Federation: true, + MinUsernameLen: 3, + }, + } +} + +func Load() (*Config, error) { + cfg, err := ini.Load(configFile) + if err != nil { + return nil, err + } + + // Parse INI file + uc := &Config{} + err = cfg.MapTo(uc) + if err != nil { + return nil, err + } + return uc, nil +} + +func Save(uc *Config) error { + cfg := ini.Empty() + err := ini.ReflectFrom(cfg, uc) + if err != nil { + return err + } + + return cfg.SaveTo(configFile) +} diff --git a/keys.go b/keys.go new file mode 100644 index 0000000..505141e --- /dev/null +++ b/keys.go @@ -0,0 +1,26 @@ +package writefreely + +import ( + "io/ioutil" +) + +type keychain struct { + cookieAuthKey, cookieKey []byte +} + +func initKeys(app *app) error { + var err error + app.keys = &keychain{} + + app.keys.cookieAuthKey, err = ioutil.ReadFile("keys/cookies_auth.aes256") + if err != nil { + return err + } + + app.keys.cookieKey, err = ioutil.ReadFile("keys/cookies_enc.aes256") + if err != nil { + return err + } + + return nil +} diff --git a/routes.go b/routes.go new file mode 100644 index 0000000..17ad73b --- /dev/null +++ b/routes.go @@ -0,0 +1,31 @@ +package writefreely + +import ( + "github.com/gorilla/mux" + "github.com/writeas/web-core/log" + "github.com/writeas/writefreely/config" + "strings" +) + +func initRoutes(handler *Handler, r *mux.Router, cfg *config.Config) { + isSingleUser := !cfg.App.MultiUser + + // Write.as router + hostSubroute := cfg.Server.Host[strings.Index(cfg.Server.Host, "://")+3:] + if isSingleUser { + hostSubroute = "{domain}" + } else { + if strings.HasPrefix(hostSubroute, "localhost") { + hostSubroute = "localhost" + } + } + + if isSingleUser { + log.Info("Adding %s routes (single user)...", hostSubroute) + + return + } + + // Primary app routes + log.Info("Adding %s routes (multi-user)...", hostSubroute) +}