feat: establish NekoNest Cloud control and relay

This commit is contained in:
2026-08-12 23:25:43 +08:00
commit f27606b709
222 changed files with 71456 additions and 0 deletions
+232
View File
@@ -0,0 +1,232 @@
package attachmentstore
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"os"
"path/filepath"
"strings"
"sync"
"github.com/klarkxy/nekonest/relaycore"
)
type Store struct {
root string
mu sync.RWMutex
usedBytes int64
fileCount int
maxBytes int64
maxFiles int
}
func New(root string) (*Store, error) {
return NewWithLimits(root, 1<<30, 10_000)
}
func NewWithLimits(root string, maxBytes int64, maxFiles int) (*Store, error) {
root = filepath.Clean(strings.TrimSpace(root))
if !filepath.IsAbs(root) {
return nil, fmt.Errorf("attachment root must be absolute")
}
if err := os.MkdirAll(root, 0o700); err != nil {
return nil, fmt.Errorf("create attachment root: %w", err)
}
if err := os.Chmod(root, 0o700); err != nil {
return nil, fmt.Errorf("secure attachment root: %w", err)
}
info, err := os.Lstat(root)
if err != nil {
return nil, err
}
if info.Mode()&os.ModeSymlink != 0 || !info.IsDir() {
return nil, fmt.Errorf("attachment root must be a real directory")
}
if maxBytes <= 0 || maxFiles <= 0 {
return nil, fmt.Errorf("attachment limits must be positive")
}
store := &Store{root: root, maxBytes: maxBytes, maxFiles: maxFiles}
entries, err := os.ReadDir(root)
if err != nil {
return nil, err
}
for _, entry := range entries {
if entry.Type()&os.ModeSymlink != 0 {
return nil, fmt.Errorf("attachment store contains a symbolic link")
}
if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".bin") {
continue
}
info, err := entry.Info()
if err != nil || !info.Mode().IsRegular() {
return nil, fmt.Errorf("inspect attachment payload %q", entry.Name())
}
store.usedBytes += info.Size()
store.fileCount++
}
if store.usedBytes > maxBytes || store.fileCount > maxFiles {
return nil, fmt.Errorf("attachment store already exceeds configured quota")
}
return store, nil
}
func validID(id string) bool {
if len(id) != 32 {
return false
}
for _, char := range id {
if !strings.ContainsRune("0123456789abcdef", char) {
return false
}
}
return true
}
func (s *Store) paths(id string) (string, string, error) {
if !validID(id) {
return "", "", fmt.Errorf("invalid attachment id")
}
payload := filepath.Join(s.root, id+".bin")
metadata := filepath.Join(s.root, id+".json")
if filepath.Dir(payload) != s.root || filepath.Dir(metadata) != s.root {
return "", "", fmt.Errorf("attachment path escaped root")
}
return payload, metadata, nil
}
func (s *Store) Put(ctx context.Context, attachment relaycore.Attachment, body []byte) error {
if err := ctx.Err(); err != nil {
return err
}
s.mu.Lock()
defer s.mu.Unlock()
if int64(len(body)) > s.maxBytes-s.usedBytes || s.fileCount >= s.maxFiles {
return fmt.Errorf("attachment quota exceeded")
}
payloadPath, metadataPath, err := s.paths(attachment.ID)
if err != nil {
return err
}
metadata, err := json.Marshal(attachment)
if err != nil {
return err
}
payload, err := os.OpenFile(payloadPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o600)
if err != nil {
return fmt.Errorf("create attachment payload: %w", err)
}
removePayload := true
defer func() {
_ = payload.Close()
if removePayload {
_ = os.Remove(payloadPath)
}
}()
if _, err := payload.Write(body); err != nil {
return fmt.Errorf("write attachment payload: %w", err)
}
if err := payload.Sync(); err != nil {
return fmt.Errorf("sync attachment payload: %w", err)
}
if err := payload.Close(); err != nil {
return fmt.Errorf("close attachment payload: %w", err)
}
meta, err := os.OpenFile(metadataPath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o600)
if err != nil {
return fmt.Errorf("create attachment metadata: %w", err)
}
if _, err := meta.Write(metadata); err != nil {
_ = meta.Close()
_ = os.Remove(metadataPath)
return fmt.Errorf("write attachment metadata: %w", err)
}
if err := meta.Sync(); err != nil {
_ = meta.Close()
_ = os.Remove(metadataPath)
return fmt.Errorf("sync attachment metadata: %w", err)
}
if err := meta.Close(); err != nil {
_ = os.Remove(metadataPath)
return fmt.Errorf("close attachment metadata: %w", err)
}
removePayload = false
s.usedBytes += int64(len(body))
s.fileCount++
return nil
}
func rejectLink(path string) error {
info, err := os.Lstat(path)
if err != nil {
return err
}
if info.Mode()&os.ModeSymlink != 0 || !info.Mode().IsRegular() {
return fmt.Errorf("attachment artifact is not a regular file")
}
return nil
}
func (s *Store) Get(ctx context.Context, id string) (relaycore.Attachment, io.ReadCloser, error) {
if err := ctx.Err(); err != nil {
return relaycore.Attachment{}, nil, err
}
s.mu.RLock()
defer s.mu.RUnlock()
payloadPath, metadataPath, err := s.paths(id)
if err != nil {
return relaycore.Attachment{}, nil, err
}
if err := rejectLink(metadataPath); err != nil {
return relaycore.Attachment{}, nil, err
}
metadata, err := os.ReadFile(metadataPath)
if err != nil {
return relaycore.Attachment{}, nil, err
}
var attachment relaycore.Attachment
if err := json.Unmarshal(metadata, &attachment); err != nil || attachment.ID != id {
return relaycore.Attachment{}, nil, fmt.Errorf("invalid attachment metadata")
}
if err := rejectLink(payloadPath); err != nil {
return relaycore.Attachment{}, nil, err
}
body, err := os.Open(payloadPath)
if err != nil {
return relaycore.Attachment{}, nil, err
}
return attachment, body, nil
}
func (s *Store) Delete(_ context.Context, id string) error {
s.mu.Lock()
defer s.mu.Unlock()
payloadPath, metadataPath, err := s.paths(id)
if err != nil {
return err
}
var size int64
existed := false
if info, statErr := os.Lstat(payloadPath); statErr == nil && info.Mode().IsRegular() && info.Mode()&os.ModeSymlink == 0 {
size = info.Size()
existed = true
}
var joined error
for _, path := range []string{metadataPath, payloadPath} {
if err := os.Remove(path); err != nil && !errors.Is(err, os.ErrNotExist) {
joined = errors.Join(joined, err)
}
}
if joined == nil && existed {
s.usedBytes -= size
if s.usedBytes < 0 {
s.usedBytes = 0
}
if s.fileCount > 0 {
s.fileCount--
}
}
return joined
}