summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--internal/cryptoutil/oae2.go6
-rw-r--r--roseh.moe.go94
2 files changed, 48 insertions, 52 deletions
diff --git a/internal/cryptoutil/oae2.go b/internal/cryptoutil/oae2.go
index 4e667b7..8eb18fb 100644
--- a/internal/cryptoutil/oae2.go
+++ b/internal/cryptoutil/oae2.go
@@ -35,7 +35,7 @@ type oae2 struct {
additionalData []byte
aead cipher.AEAD
- i uint64
+ i int64
noncePrefix [noncePrefixSize]byte
}
@@ -56,10 +56,10 @@ func (o *oae2) initialize(header []byte) error {
func (o *oae2) nonce(nonce []byte, lastBlock bool) error {
copy(nonce, o.noncePrefix[:])
- if o.i == 0 {
+ if o.i < 0 {
return errors.New("counter overflowed (64 bits??)")
}
- binary.BigEndian.PutUint64(nonce[noncePrefixSize:], o.i)
+ binary.BigEndian.PutUint64(nonce[noncePrefixSize:], uint64(o.i))
if lastBlock {
nonce[gcmNonceSize-1] = 1
}
diff --git a/roseh.moe.go b/roseh.moe.go
index 5600a75..33122d2 100644
--- a/roseh.moe.go
+++ b/roseh.moe.go
@@ -18,6 +18,7 @@ import (
"net/http"
"os"
"path/filepath"
+ "strconv"
"strings"
"sync"
"time"
@@ -407,20 +408,20 @@ func listNotes(req *api.ListNotesRequest) (*api.ListNotesResponse, error) {
return &api.ListNotesResponse{Notes: names}, nil
}
-func readLinkedList(w io.Writer, next []byte, key cryptoutil.EncryptionKey, name string) error {
+func dumpFile(w io.Writer, key cryptoutil.EncryptionKey, name string) error {
f, err := os.Open(name)
if err != nil {
return err
}
defer f.Close()
- reader := key.NewReader(f, []byte("chunks/"+filepath.Base(name)))
- if _, err := io.ReadFull(reader, next); err != nil {
- return err
- }
- _, err = io.Copy(w, reader)
+ _, err = io.Copy(w, key.NewReader(f, []byte("chunks/"+filepath.Base(name))))
return err
}
+func chunkName(prefix string, i int64) string {
+ return fmt.Sprintf("%s%013s", prefix, strconv.FormatUint(uint64(i), 36))
+}
+
var (
//go:embed wordlist.txt
wordListString string
@@ -429,8 +430,8 @@ var (
func createNote(req *api.CreateNoteRequest) (*api.CreateNoteResponse, error) {
type continuationToken struct {
- Head string
- Tail []byte
+ Prefix string
+ I int64
}
encryptionKeyMu.Lock()
@@ -439,10 +440,8 @@ func createNote(req *api.CreateNoteRequest) (*api.CreateNoteResponse, error) {
if key == nil {
return nil, fmt.Errorf("%w: need login", api.PermissionDenied)
}
- var (
- contToken continuationToken
- f *os.File
- )
+
+ var contToken continuationToken
if len(req.ContinuationToken) > 0 {
msg, ok := secretKey.Verify(req.ContinuationToken, "continuation-token")
if !ok {
@@ -451,8 +450,19 @@ func createNote(req *api.CreateNoteRequest) (*api.CreateNoteResponse, error) {
if err := gob.NewDecoder(bytes.NewReader(msg)).Decode(&contToken); err != nil {
return nil, fmt.Errorf("bad continuation token")
}
- var err error
- f, err = os.OpenFile(*notepadDir+"/chunks/"+base64.RawURLEncoding.EncodeToString(contToken.Tail), os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0600)
+ } else {
+ token := make([]byte, 64)
+ rand.Read(token)
+ contToken.Prefix = base64.RawURLEncoding.EncodeToString(token)
+ contToken.I = 0
+ }
+
+ if req.More {
+ if err := os.MkdirAll(*notepadDir+"/chunks", 0700); err != nil {
+ return nil, err
+ }
+ name := chunkName(contToken.Prefix, contToken.I)
+ f, err := os.OpenFile(*notepadDir+"/chunks/"+name, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0600)
if err != nil {
if errors.Is(err, os.ErrExist) {
return nil, fmt.Errorf("%w: continuation token expired", api.InvalidArgument)
@@ -460,39 +470,28 @@ func createNote(req *api.CreateNoteRequest) (*api.CreateNoteResponse, error) {
return nil, err
}
defer f.Close()
- } else {
- if err := os.MkdirAll(*notepadDir+"/chunks", 0700); err != nil {
+ if contToken.I > 0 {
+ _, err := os.Stat(*notepadDir + "/chunks/" + chunkName(contToken.Prefix, 0))
+ if err != nil {
+ if errors.Is(err, os.ErrNotExist) {
+ return nil, fmt.Errorf("%w: continuation token expired", api.InvalidArgument)
+ }
+ return nil, err
+ }
+ }
+ encryptingWriter := key.NewWriter(f, []byte("chunks/"+name))
+ if _, err := encryptingWriter.Write(req.Chunk); err != nil {
return nil, err
}
- var err error
- f, err = os.CreateTemp(*notepadDir+"/chunks", "head")
- if err != nil {
+ if err := encryptingWriter.Close(); err != nil {
return nil, err
}
- defer f.Close()
- }
- next := make([]byte, 64)
- rand.Read(next)
- encryptingWriter := key.NewWriter(f, []byte("chunks/"+filepath.Base(f.Name())))
- if _, err := encryptingWriter.Write(next); err != nil {
- return nil, err
- }
- if _, err := encryptingWriter.Write(req.Chunk); err != nil {
- return nil, err
- }
- if err := encryptingWriter.Close(); err != nil {
- return nil, err
- }
- if err := f.Close(); err != nil {
- return nil, err
- }
- head := contToken.Head
- if head == "" {
- head = filepath.Base(f.Name())
- }
- if req.More {
+ if err := f.Close(); err != nil {
+ return nil, err
+ }
+ contToken.I++
buf := new(bytes.Buffer)
- if err := gob.NewEncoder(buf).Encode(continuationToken{Head: head, Tail: next}); err != nil {
+ if err := gob.NewEncoder(buf).Encode(contToken); err != nil {
return nil, err
}
return &api.CreateNoteResponse{ContinuationToken: secretKey.Sign(buf.Bytes(), "continuation-token")}, nil
@@ -520,12 +519,9 @@ func createNote(req *api.CreateNoteRequest) (*api.CreateNoteResponse, error) {
defer finalNote.Close()
break
}
- var chunks []string
writer := key.NewWriter(finalNote, []byte("notes/"+filepath.Base(finalNote.Name())))
- tailBase64 := base64.RawURLEncoding.EncodeToString(next)
- for chunk := head; chunk != tailBase64; chunk = base64.RawURLEncoding.EncodeToString(next) {
- chunks = append(chunks, chunk)
- if err := readLinkedList(writer, next, key, *notepadDir+"/chunks/"+chunk); err != nil {
+ for i := range contToken.I {
+ if err := dumpFile(writer, key, *notepadDir+"/chunks/"+chunkName(contToken.Prefix, i)); err != nil {
return nil, err
}
}
@@ -538,8 +534,8 @@ func createNote(req *api.CreateNoteRequest) (*api.CreateNoteResponse, error) {
if err := finalNote.Close(); err != nil {
return nil, err
}
- for _, chunk := range chunks {
- if err := os.Remove(*notepadDir + "/chunks/" + chunk); err != nil {
+ for i := range contToken.I {
+ if err := os.Remove(*notepadDir + "/chunks/" + chunkName(contToken.Prefix, i)); err != nil {
log.Printf("Warning: createNote: failed to delete chunk: %s", err)
}
}