summaryrefslogtreecommitdiffstats
path: root/roseh.moe.go
diff options
context:
space:
mode:
Diffstat (limited to 'roseh.moe.go')
-rw-r--r--roseh.moe.go147
1 files changed, 90 insertions, 57 deletions
diff --git a/roseh.moe.go b/roseh.moe.go
index 988938d..8c7e176 100644
--- a/roseh.moe.go
+++ b/roseh.moe.go
@@ -1,6 +1,7 @@
package main
import (
+ "bufio"
"bytes"
"crypto/rand"
"crypto/subtle"
@@ -16,6 +17,7 @@ import (
"io"
"log"
"net/http"
+ "net/url"
"os"
"path/filepath"
"strconv"
@@ -233,33 +235,6 @@ func setEncryptionKey(rawKey cryptoutil.RawKey) error {
return nil
}
-type redirectTarget int
-
-const (
- redirectDefault redirectTarget = iota
- redirectNotepad
- redirectUpload
-)
-
-func parseRedirectTarget(s string) redirectTarget {
- i, err := strconv.Atoi(s)
- if err != nil {
- return redirectDefault
- }
- return redirectTarget(i)
-}
-
-func (t redirectTarget) path() string {
- switch t {
- case redirectNotepad:
- return "/notepad"
- case redirectUpload:
- return "/notes/upload"
- default:
- return "/"
- }
-}
-
var (
//go:embed templates/login.html.template
loginString string
@@ -268,13 +243,19 @@ var (
type loginTemplateArgs struct {
Error bool
- Redirect redirectTarget
+ Redirect string
+}
+
+func executeLoginTemplate(w io.Writer, redirect string) {
+ if err := loginTemplate.Execute(w, loginTemplateArgs{Redirect: base64.RawURLEncoding.EncodeToString(secretKey.Sign([]byte(redirect), "redirect"))}); err != nil {
+ log.Printf("Warning: login: %s", err)
+ }
}
func login(w http.ResponseWriter, r *http.Request) {
rawKey, err := notepadPassword.CheckPassword(r.FormValue("password"))
if err != nil {
- if err := loginTemplate.Execute(w, loginTemplateArgs{Error: true, Redirect: parseRedirectTarget(r.FormValue("redirect"))}); err != nil {
+ if err := loginTemplate.Execute(w, loginTemplateArgs{Error: true, Redirect: r.FormValue("redirect")}); err != nil {
log.Printf("Warning: login: %s", err)
}
return
@@ -284,7 +265,13 @@ func login(w http.ResponseWriter, r *http.Request) {
return
}
attachCookie(w)
- http.Redirect(w, r, parseRedirectTarget(r.FormValue("redirect")).path(), http.StatusSeeOther)
+ redirect := "/"
+ if b, err := base64.RawURLEncoding.DecodeString(r.FormValue("redirect")); err == nil {
+ if r, ok := secretKey.Verify(b, "redirect"); ok {
+ redirect = string(r)
+ }
+ }
+ http.Redirect(w, r, redirect, http.StatusSeeOther)
}
func readNotepad(key cryptoutil.EncryptionKey) (string, error) {
@@ -314,18 +301,14 @@ type notepadTemplateArgs struct {
func notepad(w http.ResponseWriter, r *http.Request) {
csrfToken, ok := cookieAuth(w, r)
if !ok {
- if err := loginTemplate.Execute(w, loginTemplateArgs{Redirect: redirectNotepad}); err != nil {
- log.Printf("Warning: login: %s", err)
- }
+ executeLoginTemplate(w, "/notepad")
return
}
encryptionKeyMu.Lock()
key := encryptionKey
encryptionKeyMu.Unlock()
if key == nil {
- if err := loginTemplate.Execute(w, loginTemplateArgs{Redirect: redirectNotepad}); err != nil {
- log.Printf("Warning: login: %s", err)
- }
+ executeLoginTemplate(w, "/notepad")
return
}
currentContent, err := readNotepad(key)
@@ -529,6 +512,14 @@ func createNote(req *api.CreateNoteRequest) (*api.CreateNoteResponse, error) {
}
}
encryptingWriter := key.NewWriter(f, cryptoutil.WithAdditionalData([]byte("chunks/"+name)))
+ if contToken.I == 0 {
+ if _, err := encryptingWriter.Write(binary.AppendVarint(nil, int64(len(req.FileName)))); err != nil {
+ return nil, err
+ }
+ if _, err := io.WriteString(encryptingWriter, req.FileName); err != nil {
+ return nil, err
+ }
+ }
if _, err := encryptingWriter.Write(req.Chunk); err != nil {
return nil, err
}
@@ -577,13 +568,15 @@ func createNote(req *api.CreateNoteRequest) (*api.CreateNoteResponse, error) {
}
type readNoteResponseWriter struct {
- stream *encoder
+ fileName string
+ stream *encoder
}
func (w *readNoteResponseWriter) Write(buf []byte) (int, error) {
- if err := w.stream.send(&api.ReadNoteResponseStream{Chunk: buf}); err != nil {
+ if err := w.stream.send(&api.ReadNoteResponseStream{FileName: w.fileName, Chunk: buf}); err != nil {
return 0, err
}
+ w.fileName = ""
return len(buf), nil
}
@@ -602,7 +595,16 @@ func readNote(stream *encoder, req *api.ReadNoteRequest) error {
if key == nil {
return fmt.Errorf("%w: need login", api.PermissionDenied)
}
- _, err = io.Copy(&readNoteResponseWriter{stream: stream}, key.NewReader(f, cryptoutil.WithAdditionalData([]byte("notes/"+req.Note))))
+ reader := bufio.NewReader(key.NewReader(f, cryptoutil.WithAdditionalData([]byte("notes/"+req.Note))))
+ nameLen, err := binary.ReadVarint(reader)
+ if err != nil {
+ return err
+ }
+ fileName := make([]byte, nameLen)
+ if _, err := io.ReadFull(reader, fileName); err != nil {
+ return err
+ }
+ _, err = io.Copy(&readNoteResponseWriter{fileName: string(fileName), stream: stream}, reader)
return err
}
@@ -671,18 +673,14 @@ type uploadTemplateArgs struct {
func uploadPage(w http.ResponseWriter, r *http.Request) {
csrfToken, ok := cookieAuth(w, r)
if !ok {
- if err := loginTemplate.Execute(w, loginTemplateArgs{Redirect: redirectUpload}); err != nil {
- log.Printf("Warning: login: %s", err)
- }
+ executeLoginTemplate(w, "/upload")
return
}
encryptionKeyMu.Lock()
key := encryptionKey
encryptionKeyMu.Unlock()
if key == nil {
- if err := loginTemplate.Execute(w, loginTemplateArgs{Redirect: redirectUpload}); err != nil {
- log.Printf("Warning: login: %s", err)
- }
+ executeLoginTemplate(w, "/upload")
return
}
if err := uploadTemplate.Execute(w, uploadTemplateArgs{CSRFToken: csrfToken}); err != nil {
@@ -696,20 +694,14 @@ func uploadNote(w http.ResponseWriter, r *http.Request) {
return
}
if _, ok := cookieAuth(w, r); !ok {
- log.Printf("asdf: bad auth")
- if err := loginTemplate.Execute(w, loginTemplateArgs{Redirect: redirectUpload}); err != nil {
- log.Printf("Warning: login: %s", err)
- }
+ executeLoginTemplate(w, "/upload")
return
}
encryptionKeyMu.Lock()
key := encryptionKey
encryptionKeyMu.Unlock()
if key == nil {
- log.Printf("asdf: key nil")
- if err := loginTemplate.Execute(w, loginTemplateArgs{Redirect: redirectUpload}); err != nil {
- log.Printf("Warning: login: %s", err)
- }
+ executeLoginTemplate(w, "/upload")
return
}
noteFile, err := newNoteName()
@@ -718,12 +710,20 @@ func uploadNote(w http.ResponseWriter, r *http.Request) {
return
}
defer noteFile.Close()
- contentReader, _, err := r.FormFile("content")
+ contentReader, metadata, err := r.FormFile("content")
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
writer := key.NewWriter(noteFile, cryptoutil.WithAdditionalData([]byte("notes/"+filepath.Base(noteFile.Name()))))
+ if _, err := writer.Write(binary.AppendVarint(nil, int64(len(metadata.Filename)))); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ if _, err := io.WriteString(writer, metadata.Filename); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
if _, err := io.Copy(writer, contentReader); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
@@ -739,6 +739,39 @@ func uploadNote(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "upload! pog\n%s", filepath.Base(noteFile.Name()))
}
+func readNoteContent(w http.ResponseWriter, r *http.Request) {
+ if _, ok := cookieAuth(w, r); !ok {
+ executeLoginTemplate(w, "/note/"+r.PathValue("note"))
+ return
+ }
+ f, err := os.OpenInRoot(*notepadDir+"/notes", r.PathValue("note"))
+ if err != nil {
+ notFound(w, r)
+ return
+ }
+ defer f.Close()
+ encryptionKeyMu.Lock()
+ key := encryptionKey
+ encryptionKeyMu.Unlock()
+ if key == nil {
+ executeLoginTemplate(w, "/note/"+r.PathValue("note"))
+ return
+ }
+ reader := bufio.NewReader(key.NewReader(f, cryptoutil.WithAdditionalData([]byte("notes/"+r.PathValue("note")))))
+ nameLen, err := binary.ReadVarint(reader)
+ if err != nil {
+ http.Error(w, "invalid file", http.StatusInternalServerError)
+ return
+ }
+ fileName := make([]byte, nameLen)
+ if _, err := io.ReadFull(reader, fileName); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ w.Header().Set("Content-Disposition", "attachment; filename*=UTF-8''"+url.QueryEscape(string(fileName)))
+ io.Copy(w, reader)
+}
+
func main() {
flag.Parse()
@@ -751,9 +784,9 @@ func main() {
http.HandleFunc("POST /login", login)
http.HandleFunc("GET /notepad", notepad)
http.HandleFunc("POST /notepad/autosave", autosave)
- http.HandleFunc("GET /notes/upload", uploadPage)
- http.HandleFunc("POST /notes/upload", uploadNote)
- // http.HandleFunc("GET /notes/{note}", readNoteContent)
+ http.HandleFunc("GET /upload", uploadPage)
+ http.HandleFunc("POST /upload", uploadNote)
+ http.HandleFunc("GET /notes/{note}", readNoteContent)
http.HandleFunc("POST /api/login", apiLogin)
http.HandleFunc("GET /api/list-notes", gobReqRespMiddleware(listNotes))
http.HandleFunc("POST /api/create-note", gobReqRespMiddleware(createNote))