diff options
| -rw-r--r-- | roseh.moe.go | 74 | ||||
| -rw-r--r-- | static/styles.css | 21 | ||||
| -rw-r--r-- | templates/login.html.template | 13 |
3 files changed, 63 insertions, 45 deletions
diff --git a/roseh.moe.go b/roseh.moe.go index e0b3428..3a8f0ef 100644 --- a/roseh.moe.go +++ b/roseh.moe.go @@ -146,7 +146,7 @@ func attachCookie(w http.ResponseWriter) error { return nil } -func checkCookie(w http.ResponseWriter, r *http.Request) bool { +func cookieAuth(w http.ResponseWriter, r *http.Request) bool { cookie, err := r.Cookie("auth") if err != nil { return false @@ -173,32 +173,27 @@ func checkCookie(w http.ResponseWriter, r *http.Request) bool { return true } -func cookieAuth(w http.ResponseWriter, r *http.Request) bool { - if !checkCookie(w, r) { - http.Error(w, "Forbidden", http.StatusForbidden) - return false - } - return true +var ( + //go:embed templates/login.html.template + loginString string + loginTemplate = template.Must(template.Must(outlineTemplate.Clone()).New("body").Parse(loginString)).Lookup("outline") +) + +type loginTemplateArgs struct { + Error string + Redirect string } -func basicAuth(w http.ResponseWriter, r *http.Request) bool { - if checkCookie(w, r) { - return true - } - _, password, ok := r.BasicAuth() - if !ok { - w.Header().Set("WWW-Authenticate", `Basic realm="notepad"`) - http.Error(w, "Unauthorized", http.StatusUnauthorized) - return false - } - pwHash := sha512.Sum512([]byte(password)) +func login(w http.ResponseWriter, r *http.Request) { + pwHash := sha512.Sum512([]byte(r.FormValue("password"))) if subtle.ConstantTimeCompare(pwHash[:], notepadPassword) == 0 { - w.Header().Set("WWW-Authenticate", `Basic realm="notepad"`) - http.Error(w, "Unauthorized", http.StatusUnauthorized) - return false + if err := loginTemplate.Execute(w, loginTemplateArgs{Error: "Incorrect password", Redirect: r.FormValue("redirect")}); err != nil { + log.Printf("Warning: login: %s", err) + } + return } attachCookie(w) - return true + http.Redirect(w, r, r.FormValue("redirect"), http.StatusSeeOther) } var ( @@ -212,7 +207,10 @@ type notepadTemplateArgs struct { } func notepad(w http.ResponseWriter, r *http.Request) { - if !basicAuth(w, r) { + if !cookieAuth(w, r) { + if err := loginTemplate.Execute(w, loginTemplateArgs{Redirect: "/notepad"}); err != nil { + log.Printf("Warning: login: %s", err) + } return } var currentContent string @@ -226,13 +224,16 @@ func notepad(w http.ResponseWriter, r *http.Request) { } } -func saveNote(content []byte) error { +func saveNote(w http.ResponseWriter, r *http.Request) error { + if !cookieAuth(w, r) { + return fmt.Errorf("not logged in") + } f, err := os.CreateTemp(filepath.Dir(*notepadFile), "notepad") if err != nil { return err } defer f.Close() - if _, err = f.Write(content); err != nil { + if _, err = f.Write([]byte(r.FormValue("content"))); err != nil { return err } if err := f.Close(); err != nil { @@ -242,32 +243,15 @@ func saveNote(content []byte) error { } func autosave(w http.ResponseWriter, r *http.Request) { - if !cookieAuth(w, r) { - return - } msg := "Saved ✓" - if err := saveNote([]byte(r.FormValue("content"))); err != nil { - msg = fmt.Sprintf("Error: %s", err) + if err := saveNote(w, r); err != nil { + msg = fmt.Sprintf("Failed to save: %s", err) } if err := notepadTemplate.ExecuteTemplate(w, "saveIndicator", msg); err != nil { log.Printf("Warning: autosave: %s", err) } } -func manualSave(w http.ResponseWriter, r *http.Request) { - if !basicAuth(w, r) { - return - } - content := r.FormValue("content") - if err := saveNote([]byte(content)); err != nil { - http.Error(w, fmt.Sprintf("Error: %s", err), http.StatusInternalServerError) - return - } - if err := notepadTemplate.Execute(w, notepadTemplateArgs{Content: content}); err != nil { - log.Printf("Warning: manualSave: %s", err) - } -} - func main() { flag.Parse() @@ -277,8 +261,8 @@ func main() { } http.HandleFunc("GET /pong", pong) + http.HandleFunc("POST /login", login) http.HandleFunc("GET /notepad", notepad) - http.HandleFunc("POST /notepad", manualSave) http.HandleFunc("POST /notepad/autosave", autosave) http.HandleFunc("GET /static/", static) http.HandleFunc("GET /favicon.ico", favicon) diff --git a/static/styles.css b/static/styles.css index 9e7d347..91e6fde 100644 --- a/static/styles.css +++ b/static/styles.css @@ -73,3 +73,24 @@ div.content-container { padding: 50px; display: flex; } + +p.login-error { + color: red; +} + +form.password-form { + display: flex; + align-items: center; +} + +label.password-label { + padding-right: 20px; +} + +input.password { + background: #f5f5f5; + outline: none; + border: 5px solid #ff69b4; + border-radius: 15px; + box-shadow: 0 0 10px rgba(255, 105, 180, 0.5); +} diff --git a/templates/login.html.template b/templates/login.html.template new file mode 100644 index 0000000..658d477 --- /dev/null +++ b/templates/login.html.template @@ -0,0 +1,13 @@ +{{define "head"}}<title>Login</title>{{end}} + +<p class="login-error">{{.Error}}</p> + +<section> + <div style="display:flex"> + <form class="password-form" action="/login" method="post"> + <label class="password-label" for="password">Enter password</label> + <input id="password" class="password" type="password" name="password"> + <input type="hidden" name="redirect" value="{{.Redirect}}"> + </form> + </div> +</section> |
