summaryrefslogtreecommitdiffstats
path: root/roseh.moe.go
diff options
context:
space:
mode:
authorRose Hogenson <rosehogenson@posteo.net>2025-09-23 21:49:08 -0700
committerRose Hogenson <rosehogenson@posteo.net>2025-09-23 21:49:08 -0700
commite3f71dedf3fcbd9e9112880f4b2a442cabd9fba6 (patch)
tree0c6f535f6a6e969e47d22504eb1c5530c33902ef /roseh.moe.go
parentUse pbkdf2 for password hashing instead of sha512 (diff)
downloadroseh.moe-e3f71dedf3fcbd9e9112880f4b2a442cabd9fba6.tar.zst
Encrypt notepad at rest
Diffstat (limited to 'roseh.moe.go')
-rw-r--r--roseh.moe.go43
1 files changed, 40 insertions, 3 deletions
diff --git a/roseh.moe.go b/roseh.moe.go
index a15fd9b..e2500ca 100644
--- a/roseh.moe.go
+++ b/roseh.moe.go
@@ -2,6 +2,8 @@ package main
import (
"bytes"
+ "crypto/aes"
+ "crypto/cipher"
"crypto/ed25519"
"crypto/rand"
"crypto/subtle"
@@ -17,6 +19,7 @@ import (
"os"
"path/filepath"
"strings"
+ "sync"
"time"
"gitlab.com/rhogenson/roseh.moe/internal/pwhash"
@@ -35,6 +38,9 @@ var (
notepadPasswordSalt []byte
privateKey ed25519.PrivateKey
publicKey ed25519.PublicKey
+
+ encryptionKeyMu sync.Mutex
+ encryptionKey cipher.AEAD
)
func loadSecrets() error {
@@ -211,7 +217,7 @@ type loginTemplateArgs struct {
}
func login(w http.ResponseWriter, r *http.Request) {
- pwHash, err := pwhash.Hash(r.FormValue("password"), notepadPasswordSalt)
+ keyBytes, pwHash, err := pwhash.Hash(r.FormValue("password"), notepadPasswordSalt)
if err != nil {
http.Error(w, fmt.Sprintf("Unable to hash password: %s", err), http.StatusInternalServerError)
return
@@ -222,6 +228,17 @@ func login(w http.ResponseWriter, r *http.Request) {
}
return
}
+ block, err := aes.NewCipher(keyBytes)
+ if err != nil {
+ http.Error(w, fmt.Sprintf("Could not create AES key: %s", err), http.StatusInternalServerError)
+ return
+ }
+ key, err := cipher.NewGCMWithRandomNonce(block)
+ encryptionKeyMu.Lock()
+ if encryptionKey == nil {
+ encryptionKey = key
+ }
+ encryptionKeyMu.Unlock()
attachCookie(w)
http.Redirect(w, r, r.FormValue("redirect"), http.StatusSeeOther)
}
@@ -245,11 +262,25 @@ func notepad(w http.ResponseWriter, r *http.Request) {
}
return
}
+ encryptionKeyMu.Lock()
+ key := encryptionKey
+ encryptionKeyMu.Unlock()
+ if key == nil {
+ if err := loginTemplate.Execute(w, loginTemplateArgs{Redirect: "/notepad"}); err != nil {
+ log.Printf("Warning: login: %s", err)
+ }
+ return
+ }
var currentContent string
if currentContentBytes, err := os.ReadFile(*notepadFile); err != nil {
currentContent = fmt.Sprintf("Error reading notepad file: %s", err)
} else {
- currentContent = string(currentContentBytes)
+ decrypted, err := key.Open(nil, nil, currentContentBytes, nil)
+ if err != nil {
+ currentContent = fmt.Sprintf("Could not decrypt notepad contents: %s", err)
+ } else {
+ currentContent = string(decrypted)
+ }
}
if err := notepadTemplate.Execute(w, notepadTemplateArgs{Content: currentContent, CSRFToken: csrfToken}); err != nil {
log.Printf("Warning: notepad: %s", err)
@@ -263,12 +294,18 @@ func saveNote(w http.ResponseWriter, r *http.Request) error {
if _, ok := cookieAuth(w, r); !ok {
return fmt.Errorf("not logged in")
}
+ encryptionKeyMu.Lock()
+ key := encryptionKey
+ encryptionKeyMu.Unlock()
+ if key == nil {
+ 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([]byte(r.FormValue("content"))); err != nil {
+ if _, err = f.Write(key.Seal(nil, nil, []byte(r.FormValue("content")), nil)); err != nil {
return err
}
if err := f.Close(); err != nil {