diff options
Diffstat (limited to 'roseh.moe.go')
| -rw-r--r-- | roseh.moe.go | 147 |
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)) |
