Added example/dropin replacements for .env.example

Fixed the issue with PlainText (Complete Anon) posting
Need to fix device sign on issues.
Need to make it so that the non-signed in devices can only see their equalivant level of posts. (i.e. plaintext, public-encrypted, private-encrypted)
This commit is contained in:
2025-08-22 22:59:05 -04:00
parent 6a274f4259
commit d87e9322b5
10 changed files with 1239 additions and 1410 deletions

View File

@@ -1,240 +1,151 @@
package storage
package api
import (
"errors"
"crypto/sha256"
"encoding/hex"
"io"
"io/fs"
"os"
"path/filepath"
"strings"
"time"
)
type FSStore struct {
root string
objects string
// SimpleFSStore is a minimal FS-backed implementation of BlobStore.
// Layout under root:
//
// <root>/<hash> - content
// <root>/<hash>.priv - presence means "private"
type SimpleFSStore struct {
root string
}
func NewFS(dir string) (*FSStore, error) {
if dir == "" {
return nil, errors.New("empty storage dir")
}
o := filepath.Join(dir, "objects")
if err := os.MkdirAll(o, 0o755); err != nil {
return nil, err
}
return &FSStore{root: dir, objects: o}, nil
func NewSimpleFSStore(root string) *SimpleFSStore {
return &SimpleFSStore{root: root}
}
func (s *FSStore) pathFlat(hash string) (string, error) {
if hash == "" {
return "", errors.New("empty hash")
}
return filepath.Join(s.objects, hash), nil
func (fs *SimpleFSStore) ensureRoot() error {
return os.MkdirAll(fs.root, 0o755)
}
func isHexHash(name string) bool {
if len(name) != 64 {
return false
}
for i := 0; i < 64; i++ {
c := name[i]
if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) {
return false
}
}
return true
func (fs *SimpleFSStore) pathFor(hash string) string {
return filepath.Join(fs.root, hash)
}
func (fs *SimpleFSStore) privPathFor(hash string) string {
return filepath.Join(fs.root, hash+".priv")
}
func (s *FSStore) findBlobPath(hash string) (string, error) {
if hash == "" {
return "", errors.New("empty hash")
}
// 1) flat
if p, _ := s.pathFlat(hash); fileExists(p) {
return p, nil
}
// 2) objects/<hash>/{blob,data,content}
dir := filepath.Join(s.objects, hash)
for _, cand := range []string{"blob", "data", "content"} {
p := filepath.Join(dir, cand)
if fileExists(p) {
return p, nil
}
}
// 3) objects/<hash>/<single file>
if st, err := os.Stat(dir); err == nil && st.IsDir() {
ents, _ := os.ReadDir(dir)
var picked string
var pickedMod time.Time
for _, de := range ents {
if de.IsDir() {
continue
}
p := filepath.Join(dir, de.Name())
fi, err := os.Stat(p)
if err == nil && fi.Mode().IsRegular() {
if picked == "" || fi.ModTime().After(pickedMod) {
picked, pickedMod = p, fi.ModTime()
}
}
}
if picked != "" {
return picked, nil
}
}
// 4) two-level prefix objects/aa/<hash>
if len(hash) >= 2 {
p := filepath.Join(s.objects, hash[:2], hash)
if fileExists(p) {
return p, nil
}
}
// 5) recursive search
var best string
var bestMod time.Time
_ = filepath.WalkDir(s.objects, func(p string, d fs.DirEntry, err error) error {
if err != nil || d.IsDir() {
return nil
}
base := filepath.Base(p)
if base == hash {
best = p
return fs.SkipDir
}
parent := filepath.Base(filepath.Dir(p))
if parent == hash {
if fi, err := os.Stat(p); err == nil && fi.Mode().IsRegular() {
if best == "" || fi.ModTime().After(bestMod) {
best, bestMod = p, fi.ModTime()
}
}
}
return nil
})
if best != "" {
return best, nil
}
return "", os.ErrNotExist
}
func fileExists(p string) bool {
fi, err := os.Stat(p)
return err == nil && fi.Mode().IsRegular()
}
func (s *FSStore) Put(hash string, r io.Reader) error {
p, err := s.pathFlat(hash)
if err != nil {
return err
}
if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil {
return err
}
tmp := p + ".tmp"
f, err := os.Create(tmp)
if err != nil {
return err
}
_, werr := io.Copy(f, r)
cerr := f.Close()
if werr != nil {
_ = os.Remove(tmp)
return werr
}
if cerr != nil {
_ = os.Remove(tmp)
return cerr
}
return os.Rename(tmp, p)
}
func (s *FSStore) Get(hash string) (io.ReadCloser, int64, error) {
p, err := s.findBlobPath(hash)
if err != nil {
// Get implements BlobStore.Get
func (fs *SimpleFSStore) Get(hash string) (io.ReadCloser, int64, error) {
if err := fs.ensureRoot(); err != nil {
return nil, 0, err
}
f, err := os.Open(p)
f, err := os.Open(fs.pathFor(hash))
if err != nil {
return nil, 0, err
}
st, err := f.Stat()
if err != nil {
return f, 0, nil
_ = f.Close()
return nil, 0, err
}
return f, st.Size(), nil
}
func (s *FSStore) Delete(hash string) error {
if p, _ := s.pathFlat(hash); fileExists(p) {
if err := os.Remove(p); err == nil || errors.Is(err, os.ErrNotExist) {
return nil
// Put implements BlobStore.Put
func (fs *SimpleFSStore) Put(r io.Reader, private bool) (string, int64, time.Time, error) {
if err := fs.ensureRoot(); err != nil {
return "", 0, time.Time{}, err
}
tmp, err := os.CreateTemp(fs.root, "put-*")
if err != nil {
return "", 0, time.Time{}, err
}
defer func() {
_ = tmp.Close()
_ = os.Remove(tmp.Name())
}()
h := sha256.New()
w := io.MultiWriter(tmp, h)
n, err := io.Copy(w, r)
if err != nil {
return "", 0, time.Time{}, err
}
hash := hex.EncodeToString(h.Sum(nil))
final := fs.pathFor(hash)
if err := os.Rename(tmp.Name(), final); err != nil {
return "", 0, time.Time{}, err
}
if private {
if err := os.WriteFile(fs.privPathFor(hash), nil, 0o600); err != nil {
_ = os.Remove(final)
return "", 0, time.Time{}, err
}
}
dir := filepath.Join(s.objects, hash)
for _, cand := range []string{"blob", "data", "content"} {
p := filepath.Join(dir, cand)
if fileExists(p) {
if err := os.Remove(p); err == nil || errors.Is(err, os.ErrNotExist) {
return nil
}
}
st, err := os.Stat(final)
if err != nil {
return "", 0, time.Time{}, err
}
if len(hash) >= 2 {
p := filepath.Join(s.objects, hash[:2], hash)
if fileExists(p) {
if err := os.Remove(p); err == nil || errors.Is(err, os.ErrNotExist) {
return nil
}
}
}
if p, err := s.findBlobPath(hash); err == nil {
if err := os.Remove(p); err == nil || errors.Is(err, os.ErrNotExist) {
return nil
}
}
return nil
return hash, n, st.ModTime().UTC(), nil
}
func (s *FSStore) Walk(fn func(hash string, size int64, mod time.Time) error) error {
type rec struct {
size int64
mod time.Time
// Delete implements BlobStore.Delete
func (fs *SimpleFSStore) Delete(hash string) error {
if err := fs.ensureRoot(); err != nil {
return err
}
agg := make(map[string]rec)
_ = filepath.WalkDir(s.objects, func(p string, d fs.DirEntry, err error) error {
if err != nil || d.IsDir() {
return nil
}
fi, err := os.Stat(p)
if err != nil || !fi.Mode().IsRegular() {
return nil
}
base := filepath.Base(p)
if isHexHash(base) {
if r, ok := agg[base]; !ok || fi.ModTime().After(r.mod) {
agg[base] = rec{fi.Size(), fi.ModTime()}
}
return nil
}
parent := filepath.Base(filepath.Dir(p))
if isHexHash(parent) {
if r, ok := agg[parent]; !ok || fi.ModTime().After(r.mod) {
agg[parent] = rec{fi.Size(), fi.ModTime()}
}
return nil
}
if len(base) == 64 && isHexHash(strings.ToLower(base)) {
if r, ok := agg[base]; !ok || fi.ModTime().After(r.mod) {
agg[base] = rec{fi.Size(), fi.ModTime()}
}
}
return nil
})
for h, r := range agg {
if err := fn(h, r.size, r.mod); err != nil {
return err
}
}
return nil
_ = os.Remove(fs.privPathFor(hash))
return os.Remove(fs.pathFor(hash))
}
// Walk implements BlobStore.Walk
func (fs *SimpleFSStore) Walk(fn func(hash string, bytes int64, private bool, storedAt time.Time) error) (int, error) {
if err := fs.ensureRoot(); err != nil {
return 0, err
}
ents, err := os.ReadDir(fs.root)
if err != nil {
return 0, err
}
count := 0
for _, e := range ents {
if e.IsDir() {
continue
}
name := e.Name()
// skip sidecars and non-64-hex filenames
if strings.HasSuffix(name, ".priv") || len(name) != 64 || !isHex(name) {
continue
}
full := fs.pathFor(name)
st, err := os.Stat(full)
if err != nil {
continue
}
private := false
if _, err := os.Stat(fs.privPathFor(name)); err == nil {
private = true
}
if err := fn(name, st.Size(), private, st.ModTime().UTC()); err != nil {
return count, err
}
count++
}
return count, nil
}
func isHex(s string) bool {
for i := 0; i < len(s); i++ {
c := s[i]
if !((c >= '0' && c <= '9') ||
(c >= 'a' && c <= 'f') ||
(c >= 'A' && c <= 'F')) {
return false
}
}
return true
}