Files
phylum/server/internal/core/filesystem_readonly.go
T
2025-07-12 16:34:10 +05:30

90 lines
2.3 KiB
Go

package core
import (
"context"
"errors"
"fmt"
"time"
"codeberg.org/shroff/phylum/server/internal/auth/crypt"
"codeberg.org/shroff/phylum/server/internal/db"
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype"
)
type proxyFileSystemReadOnly struct {
f *FileSystem
}
func (f proxyFileSystemReadOnly) ResourceByPath(path string) (Resource, error) {
return f.f.ResourceByPath(path)
}
func (f proxyFileSystemReadOnly) ReadDir(r Resource, recursive bool) ([]Resource, error) {
return f.f.ReadDir(r, recursive)
}
func (f proxyFileSystemReadOnly) GetVersion(r Resource, versionID uuid.UUID) (Version, error) {
return f.f.GetVersion(r, versionID)
}
func (f proxyFileSystemReadOnly) Walk(r Resource, depth int, fn func(Resource, string) error) error {
return f.f.Walk(r, depth, fn)
}
func OpenFileSystemFromPublink(ctx context.Context, id string, password string) (ReadFileSystem, error) {
d := db.Get(ctx)
fmt.Println(id)
link, err := getPublink(d, id)
if err != nil {
return nil, err
}
// check password
if link.PasswordHash != "" {
if password == "" {
return nil, ErrInsufficientPermissions
}
if ok, err := crypt.VerifyPasswordHash(password, link.PasswordHash); err != nil {
return nil, err
} else if !ok {
return nil, ErrInsufficientPermissions
}
}
// check expiration
if link.Expires != 0 && time.UnixMilli(link.Expires).Before(time.Now()) {
return nil, ErrResourceNotFound
}
// check max accesses
if link.AccessLimit > 0 && link.AccessLimit <= link.Accessed {
return nil, ErrResourceNotFound
}
const q = "UPDATE publinks SET accessed = accessed + 1 WHERE id = $1"
if err := d.RunInTx(func(db db.TxHandler) error {
_, err := db.Exec(q, link.ID)
return err
}); err != nil {
return nil, err
}
f := OpenFileSystem(d, pgtype.UUID{Bytes: link.Root, Valid: true}, -1, -1, []string{link.Root.String() + ":read"})
return proxyFileSystemReadOnly{f: f}, nil
}
func getPublink(d db.Handler, id string) (Publink, error) {
q := "SELECT * FROM publinks WHERE id = $1::TEXT"
if rows, err := d.Query(q, id); err != nil {
return Publink{}, err
} else if link, err := pgx.CollectExactlyOneRow(rows, scanPublink); err != nil {
if errors.Is(err, pgx.ErrNoRows) {
err = ErrParentNotFound
}
return Publink{}, err
} else {
return link, nil
}
}