diff options
| author | Rose Hogenson <rosehogenson@posteo.net> | 2025-10-01 20:37:26 -0700 |
|---|---|---|
| committer | Rose Hogenson <rosehogenson@posteo.net> | 2025-10-01 20:37:26 -0700 |
| commit | 8f3927cc91b8f9dcc2bd3e05c2ddd225a92c96dc (patch) | |
| tree | b86c45195236428f58ec2883a81c53f317532fe7 /roseh.moe.go | |
| parent | 298f4b4634026f268ad74dadccbca8127ab83076 (diff) | |
| download | roseh.moe-8f3927cc91b8f9dcc2bd3e05c2ddd225a92c96dc.tar.zst | |
Linked list is cool, but have you heard of array
Diffstat (limited to 'roseh.moe.go')
| -rw-r--r-- | roseh.moe.go | 94 |
1 files changed, 45 insertions, 49 deletions
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) } } |
