wip
This commit is contained in:
parent
515c748e14
commit
bd4a475923
23 changed files with 1217 additions and 192 deletions
97
main.go
97
main.go
|
|
@ -1,8 +1,6 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
// External
|
||||
|
||||
// Internal
|
||||
"notes2/authentication"
|
||||
"notes2/html_template"
|
||||
|
|
@ -10,17 +8,21 @@ import (
|
|||
|
||||
// Standard
|
||||
"bufio"
|
||||
"context"
|
||||
"embed"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"path"
|
||||
"regexp"
|
||||
"strings"
|
||||
"text/template"
|
||||
)
|
||||
|
||||
const VERSION = "v1"
|
||||
const CONTEXT_USER = 1
|
||||
|
||||
var (
|
||||
FlagDev bool
|
||||
|
|
@ -31,6 +33,7 @@ var (
|
|||
config Config
|
||||
Log *slog.Logger
|
||||
AuthManager authentication.Manager
|
||||
RxpBearerToken *regexp.Regexp
|
||||
|
||||
//go:embed views
|
||||
ViewFS embed.FS
|
||||
|
|
@ -55,6 +58,8 @@ func init() { // {{{
|
|||
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()
|
||||
|
||||
RxpBearerToken = regexp.MustCompile("(?i)^\\s*Bearer\\s+(.*?)\\s*$")
|
||||
} // }}}
|
||||
func initLog() { // {{{
|
||||
opts := slog.HandlerOptions{}
|
||||
|
|
@ -91,7 +96,6 @@ func main() { // {{{
|
|||
return
|
||||
}
|
||||
|
||||
|
||||
// The webengine takes layouts, pages and components and renders them into HTML.
|
||||
Webengine, err = HTMLTemplate.NewEngine(ViewFS, StaticFS, FlagDev)
|
||||
if err != nil {
|
||||
|
|
@ -99,23 +103,67 @@ func main() { // {{{
|
|||
}
|
||||
|
||||
http.HandleFunc("/", rootHandler)
|
||||
http.HandleFunc("/notes2", pageNotes2)
|
||||
http.HandleFunc("/login", pageLogin)
|
||||
http.HandleFunc("/authenticate", AuthManager.AuthenticationHandler)
|
||||
|
||||
http.HandleFunc("/user/authenticate", AuthManager.AuthenticationHandler)
|
||||
|
||||
http.HandleFunc("/node/tree", authenticated(actionNodeTree))
|
||||
|
||||
http.HandleFunc("/service_worker.js", pageServiceWorker)
|
||||
|
||||
listen := fmt.Sprintf("%s:%d", config.Network.Address, config.Network.Port)
|
||||
Log.Info("webserver", "listen_address", listen)
|
||||
http.ListenAndServe(listen, nil)
|
||||
} // }}}
|
||||
|
||||
func authenticated(fn func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) { // {{{
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
failed := func(err error) {
|
||||
j, _ := json.Marshal(struct {
|
||||
OK bool
|
||||
Error string
|
||||
AuthFailed bool
|
||||
}{false, err.Error(), true})
|
||||
w.Write(j)
|
||||
}
|
||||
|
||||
// The Bearer token is extracted.
|
||||
authHeader := r.Header.Get("Authorization")
|
||||
authParts := RxpBearerToken.FindStringSubmatch(authHeader)
|
||||
if len(authParts) != 2 {
|
||||
failed(fmt.Errorf("Authorization missing or invalid"))
|
||||
return
|
||||
}
|
||||
token := authParts[1]
|
||||
|
||||
// Token signature is verified with the application secret key.
|
||||
claims, err := AuthManager.VerifyToken(token)
|
||||
if err != nil {
|
||||
failed(err)
|
||||
return
|
||||
}
|
||||
|
||||
// User object is added to the context for the next handler.
|
||||
user := NewUser(claims)
|
||||
r = r.WithContext(context.WithValue(r.Context(), CONTEXT_USER, user))
|
||||
|
||||
Log.Info("webserver", "op", "request", "method", r.Method, "url", r.URL.String(), "username", user.Username)
|
||||
fn(w, r)
|
||||
}
|
||||
} // }}}
|
||||
|
||||
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)
|
||||
if r.URL.Path == "/" {
|
||||
http.Redirect(w, r, "/notes2", http.StatusSeeOther)
|
||||
return
|
||||
}
|
||||
|
||||
pageIndex(w, r)
|
||||
Webengine.StaticResource(w, r)
|
||||
} // }}}
|
||||
|
||||
func pageServiceWorker(w http.ResponseWriter, r *http.Request) { // {{{
|
||||
w.Header().Add("Content-Type", "text/javascript; charset=utf-8")
|
||||
|
||||
|
|
@ -137,20 +185,6 @@ func pageServiceWorker(w http.ResponseWriter, r *http.Request) { // {{{
|
|||
return
|
||||
}
|
||||
} // }}}
|
||||
|
||||
func pageIndex(w http.ResponseWriter, r *http.Request) { // {{{
|
||||
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 pageLogin(w http.ResponseWriter, r *http.Request) { // {{{
|
||||
page := HTMLTemplate.SimplePage{
|
||||
Layout: "main",
|
||||
|
|
@ -164,14 +198,27 @@ func pageLogin(w http.ResponseWriter, r *http.Request) { // {{{
|
|||
return
|
||||
}
|
||||
} // }}}
|
||||
func pageNotes2(w http.ResponseWriter, r *http.Request) { // {{{
|
||||
page := NewPage("notes2")
|
||||
|
||||
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)
|
||||
err := Webengine.Render(page, w, r)
|
||||
if err != nil {
|
||||
w.Write([]byte(err.Error()))
|
||||
return
|
||||
}
|
||||
} // }}}
|
||||
|
||||
func actionNodeTree(w http.ResponseWriter, r *http.Request) { // {{{
|
||||
user, _ := r.Context().Value(CONTEXT_USER).(User)
|
||||
|
||||
j, _ := json.Marshal(struct {
|
||||
OK bool
|
||||
Foo string
|
||||
User User
|
||||
}{true, "FOO", user})
|
||||
w.Write(j)
|
||||
} // }}}
|
||||
|
||||
func createNewUser(username string) { // {{{
|
||||
reader := bufio.NewReader(os.Stdin)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue