Initial commit with user management
This commit is contained in:
commit
a1a928e7cb
98 changed files with 13042 additions and 0 deletions
202
main.go
Normal file
202
main.go
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
// External
|
||||
|
||||
// Internal
|
||||
"notes2/authentication"
|
||||
"notes2/html_template"
|
||||
"os"
|
||||
|
||||
// Standard
|
||||
"bufio"
|
||||
"embed"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"path"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
const VERSION = "v1"
|
||||
|
||||
var (
|
||||
FlagDev bool
|
||||
FlagConfig string
|
||||
FlagCreateUser string
|
||||
FlagChangePassword string
|
||||
Webengine HTMLTemplate.Engine
|
||||
config Config
|
||||
Log *slog.Logger
|
||||
AuthManager authentication.Manager
|
||||
|
||||
//go:embed views
|
||||
ViewFS embed.FS
|
||||
|
||||
//go:embed static
|
||||
StaticFS embed.FS
|
||||
|
||||
//go:embed sql
|
||||
SqlFS embed.FS
|
||||
)
|
||||
|
||||
func init() { // {{{
|
||||
// Configuration filename to use with a somewhat sane default.
|
||||
cfgDir, err := os.UserConfigDir()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cfgFilename := path.Join(cfgDir, "notes2.json")
|
||||
|
||||
flag.StringVar(&FlagConfig, "config", cfgFilename, "Configuration file")
|
||||
flag.BoolVar(&FlagDev, "dev", false, "Use local files instead of embedded files")
|
||||
flag.StringVar(&FlagCreateUser, "create-user", "", "Username for creating a new user")
|
||||
flag.StringVar(&FlagChangePassword, "change-password", "", "Change the password for the given username")
|
||||
flag.Parse()
|
||||
} // }}}
|
||||
func initLog() { // {{{
|
||||
opts := slog.HandlerOptions{}
|
||||
opts.Level = slog.LevelDebug
|
||||
Log = slog.New(slog.NewJSONHandler(os.Stdout, &opts))
|
||||
} // }}}
|
||||
func main() { // {{{
|
||||
initLog()
|
||||
err := readConfig()
|
||||
if err != nil {
|
||||
Log.Error("config", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// dbschema uses the embedded SQL files to keep the database schema up to date.
|
||||
err = initDB()
|
||||
if err != nil {
|
||||
Log.Error("database", "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// The session manager contains authentication, authorization and session settings.
|
||||
AuthManager, err = authentication.NewManager(db, Log, config.JWT.Secret, config.JWT.ExpireDays)
|
||||
|
||||
// A new user?
|
||||
if FlagCreateUser != "" {
|
||||
createNewUser(FlagCreateUser)
|
||||
return
|
||||
}
|
||||
|
||||
// Forgotten the password?
|
||||
if FlagChangePassword != "" {
|
||||
changePassword(FlagChangePassword)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
// The webengine takes layouts, pages and components and renders them into HTML.
|
||||
Webengine, err = HTMLTemplate.NewEngine(ViewFS, StaticFS, FlagDev)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
http.HandleFunc("/", rootHandler)
|
||||
http.HandleFunc("/authenticate", AuthManager.AuthenticationHandler)
|
||||
http.HandleFunc("/service_worker.js", pageServiceWorker)
|
||||
listen := fmt.Sprintf("%s:%d", config.Network.Address, config.Network.Port)
|
||||
http.ListenAndServe(listen, nil)
|
||||
} // }}}
|
||||
|
||||
func rootHandler(w http.ResponseWriter, r *http.Request) { // {{{
|
||||
// All URLs not specifically handled are routed to this function.
|
||||
// Everything going here should be a static resource.
|
||||
if r.URL.Path != "/" {
|
||||
Webengine.StaticResource(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
pageIndex(w, r)
|
||||
} // }}}
|
||||
func pageServiceWorker(w http.ResponseWriter, r *http.Request) { // {{{
|
||||
w.Header().Add("Content-Type", "text/javascript; charset=utf-8")
|
||||
|
||||
var tmpl *template.Template
|
||||
var err error
|
||||
if FlagDev {
|
||||
tmpl, err = template.ParseFiles("static/service_worker.js")
|
||||
} else {
|
||||
tmpl, err = template.ParseFS(StaticFS, "static/service_worker.js")
|
||||
}
|
||||
if err != nil {
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
|
||||
err = tmpl.Execute(w, struct{ VERSION string }{VERSION})
|
||||
if err != nil {
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
} // }}}
|
||||
func pageIndex(w http.ResponseWriter, r *http.Request) { // {{{
|
||||
// Index page is rendered since everything
|
||||
// else are specifically handled.
|
||||
page := HTMLTemplate.SimplePage{
|
||||
Layout: "main",
|
||||
Page: "index",
|
||||
Version: VERSION,
|
||||
}
|
||||
|
||||
err := Webengine.Render(page, w, r)
|
||||
if err != nil {
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
} // }}}
|
||||
func sessionFilter(fn func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) { // {{{
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Printf("Filtered ")
|
||||
fn(w, r)
|
||||
}
|
||||
} // }}}
|
||||
|
||||
func createNewUser(username string) { // {{{
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
|
||||
fmt.Print("\nPassword: ")
|
||||
pwd, _ := reader.ReadString('\n')
|
||||
pwd = strings.Trim(pwd, "\r\n")
|
||||
|
||||
fmt.Print("Name: ")
|
||||
name, _ := reader.ReadString('\n')
|
||||
name = strings.Trim(name, "\r\n")
|
||||
|
||||
alreadyExists, err := AuthManager.CreateUser(username, pwd, name)
|
||||
if alreadyExists {
|
||||
fmt.Printf("\nUser '%s' already exists\n", username)
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
Log.Error("create_user", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("\nUser '%s' with username '%s' is created.\n", name, username)
|
||||
} // }}}
|
||||
func changePassword(username string) { // {{{
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
|
||||
fmt.Print("\nPassword: ")
|
||||
newPwd, _ := reader.ReadString('\n')
|
||||
newPwd = strings.Trim(newPwd, "\r\n")
|
||||
|
||||
hasChanged, err := AuthManager.ChangePassword(username, "", newPwd, true)
|
||||
if !hasChanged {
|
||||
fmt.Printf("Invalid user\n")
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
Log.Error("change_password", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Printf("\nPassword changed\n")
|
||||
} // }}}
|
||||
Loading…
Add table
Add a link
Reference in a new issue