mirror of
https://codeberg.org/shroff/phylum.git
synced 2026-05-07 04:39:25 -05:00
[server] Move some code to publink_fs.go
This commit is contained in:
@@ -15,7 +15,7 @@ func Setup(r *gin.RouterGroup) {
|
||||
path := c.Param("path")
|
||||
|
||||
_, password, _ := c.Request.BasicAuth()
|
||||
f, err := core.OpenFromPublink(c.Request.Context(), id, password)
|
||||
f, err := core.OpenFileSystemFromPublink(c.Request.Context(), id, password)
|
||||
if err != nil {
|
||||
if errors.Is(err, core.ErrInsufficientPermissions) {
|
||||
c.Header("WWW-Authenticate", "Basic realm=\""+id+"\"")
|
||||
|
||||
@@ -4,15 +4,12 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/doug-martin/goqu/v9"
|
||||
_ "github.com/doug-martin/goqu/v9/dialect/postgres"
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/shroff/phylum/server/internal/crypt"
|
||||
"github.com/shroff/phylum/server/internal/db"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -93,7 +90,7 @@ type FileSystem interface {
|
||||
TrashEmpty() (int, error)
|
||||
}
|
||||
|
||||
func Open(ctx context.Context, userID int32, root pgtype.UUID, fullAccess bool) FileSystem {
|
||||
func OpenFileSystem(ctx context.Context, userID int32, root pgtype.UUID, fullAccess bool) FileSystem {
|
||||
return filesystem{
|
||||
db: db.Get(ctx),
|
||||
userID: userID,
|
||||
@@ -102,6 +99,10 @@ func Open(ctx context.Context, userID int32, root pgtype.UUID, fullAccess bool)
|
||||
}
|
||||
}
|
||||
|
||||
func (u User) OpenFileSystem(ctx context.Context) FileSystem {
|
||||
return OpenFileSystem(ctx, u.ID, u.Home, u.Permissions&PermissionFilesAll != 0)
|
||||
}
|
||||
|
||||
func OpenOmniscient(db db.Handler) FileSystem {
|
||||
return filesystem{
|
||||
db: db,
|
||||
@@ -139,64 +140,3 @@ func _readRootID(ctx context.Context) (uuid.UUID, error) {
|
||||
return id, nil
|
||||
}
|
||||
}
|
||||
|
||||
func OpenFromPublink(ctx context.Context, id string, password string) (ROFileSystem, error) {
|
||||
d := db.Get(ctx)
|
||||
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.Verify(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.Exec(q, link.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return roFilesystem{f: filesystem{
|
||||
db: d,
|
||||
pathRoot: pgtype.UUID{Bytes: link.Root, Valid: true},
|
||||
fullAccess: true, // TODO: #permissions Replace with permissions int
|
||||
}}, nil
|
||||
}
|
||||
|
||||
func getPublink(d db.Handler, id string) (Publink, error) {
|
||||
q := "SELECT * FROM publinks p 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
|
||||
}
|
||||
}
|
||||
|
||||
func CheckNameInvalid(s string) bool {
|
||||
return s == "" || s == "." || s == ".." || strings.ContainsFunc(s, func(r rune) bool {
|
||||
return r == 0 || r == '/'
|
||||
})
|
||||
}
|
||||
@@ -20,32 +20,6 @@ type Publink struct {
|
||||
Expires int64
|
||||
}
|
||||
|
||||
type ROFileSystem interface {
|
||||
ResourceByPath(string) (Resource, error)
|
||||
ReadDir(Resource, bool) ([]Resource, error)
|
||||
FindVersion(Resource, uuid.UUID) (Version, error)
|
||||
Walk(Resource, int, func(Resource, string) error) error
|
||||
}
|
||||
|
||||
type roFilesystem struct {
|
||||
f filesystem
|
||||
}
|
||||
|
||||
func (f roFilesystem) ResourceByPath(path string) (Resource, error) {
|
||||
return f.f.ResourceByPath(path)
|
||||
}
|
||||
func (f roFilesystem) ReadDir(r Resource, recursive bool) ([]Resource, error) {
|
||||
return f.f.ReadDir(r, recursive)
|
||||
}
|
||||
|
||||
func (f roFilesystem) FindVersion(r Resource, versionID uuid.UUID) (Version, error) {
|
||||
return f.f.FindVersion(r, versionID)
|
||||
}
|
||||
|
||||
func (f roFilesystem) Walk(r Resource, depth int, fn func(Resource, string) error) error {
|
||||
return f.f.Walk(r, depth, fn)
|
||||
}
|
||||
|
||||
func scanPublink(row pgx.CollectableRow) (Publink, error) {
|
||||
var p Publink
|
||||
var expires *time.Time
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
package core
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
"github.com/shroff/phylum/server/internal/crypt"
|
||||
"github.com/shroff/phylum/server/internal/db"
|
||||
)
|
||||
|
||||
type ROFileSystem interface {
|
||||
ResourceByPath(string) (Resource, error)
|
||||
ReadDir(Resource, bool) ([]Resource, error)
|
||||
FindVersion(Resource, uuid.UUID) (Version, error)
|
||||
Walk(Resource, int, func(Resource, string) error) error
|
||||
}
|
||||
|
||||
type roFilesystem struct {
|
||||
f filesystem
|
||||
}
|
||||
|
||||
func (f roFilesystem) ResourceByPath(path string) (Resource, error) {
|
||||
return f.f.ResourceByPath(path)
|
||||
}
|
||||
func (f roFilesystem) ReadDir(r Resource, recursive bool) ([]Resource, error) {
|
||||
return f.f.ReadDir(r, recursive)
|
||||
}
|
||||
|
||||
func (f roFilesystem) FindVersion(r Resource, versionID uuid.UUID) (Version, error) {
|
||||
return f.f.FindVersion(r, versionID)
|
||||
}
|
||||
|
||||
func (f roFilesystem) 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) (ROFileSystem, error) {
|
||||
d := db.Get(ctx)
|
||||
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.Verify(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.Exec(q, link.ID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return roFilesystem{f: filesystem{
|
||||
db: d,
|
||||
pathRoot: pgtype.UUID{Bytes: link.Root, Valid: true},
|
||||
fullAccess: true, // TODO: #permissions Replace with permissions int
|
||||
}}, nil
|
||||
}
|
||||
|
||||
func getPublink(d db.Handler, id string) (Publink, error) {
|
||||
q := "SELECT * FROM publinks p 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
|
||||
}
|
||||
}
|
||||
@@ -31,10 +31,6 @@ func scanUser(row pgx.CollectableRow) (User, error) {
|
||||
return u, err
|
||||
}
|
||||
|
||||
func (u User) OpenFileSystem(ctx context.Context) FileSystem {
|
||||
return Open(ctx, u.ID, u.Home, u.Permissions&PermissionFilesAll != 0)
|
||||
}
|
||||
|
||||
type Manager interface {
|
||||
// create.go
|
||||
CreateUser(email, name string, noCreateHome bool) (User, error)
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"crypto/sha256"
|
||||
"hash"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/gabriel-vasile/mimetype"
|
||||
)
|
||||
@@ -52,3 +53,9 @@ func (c *contentPropsComputer) Close() error {
|
||||
}
|
||||
return c.successCallback(c.len, c.sum, mimetype.Detect(c.contents).String())
|
||||
}
|
||||
|
||||
func CheckNameInvalid(s string) bool {
|
||||
return s == "" || s == "." || s == ".." || strings.ContainsFunc(s, func(r rune) bool {
|
||||
return r == 0 || r == '/'
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user