Automatically create user home folder

This commit is contained in:
Abhishek Shroff
2024-08-07 16:43:12 +05:30
parent d7b9712f13
commit f6a42f62e0
10 changed files with 163 additions and 26 deletions

View File

@@ -3,15 +3,17 @@ package app
import (
"context"
"github.com/google/uuid"
"github.com/shroff/phylum/server/internal/app/core"
"github.com/shroff/phylum/server/internal/db"
"github.com/shroff/phylum/server/internal/storage"
)
type App struct {
Debug bool
db *db.DbHandler
cs storage.Storage
Debug bool
adminfs core.FileSystem
db *db.DbHandler
cs storage.Storage
}
var Default *App
@@ -23,6 +25,18 @@ func Initialize(db *db.DbHandler, cs storage.Storage, debug bool) error {
cs: cs,
}
if root, err := Default.UserByUsername(context.Background(), "phylum"); err != nil {
return err
} else if fs, err := Default.OpenFileSystem(context.Background(), root.ID()); err != nil {
return err
} else {
Default.adminfs = fs
if _, err := fs.ResourceByPath("/home"); err != nil {
_, err := fs.CreateMemberResource(fs.Root(), uuid.New(), "home", true)
return err
}
}
return nil
}

View File

@@ -17,6 +17,7 @@ import (
type FileSystem interface {
OpenWithRoot(Resource) FileSystem
Root() Resource
ResourceByPath(path string) (Resource, error)
ResourceByID(id uuid.UUID) (Resource, error)
OpenRead(r Resource, start, length int64) (io.ReadCloser, error)
@@ -68,6 +69,10 @@ func OpenFileSystem(db *db.DbHandler, ctx context.Context, cs storage.Storage, r
}, nil
}
func (f filesystem) Root() Resource {
return f.root
}
func (f filesystem) OpenWithRoot(root Resource) FileSystem {
return filesystem{
db: f.db,
@@ -110,7 +115,7 @@ func (f filesystem) ResourceByPath(path string) (Resource, error) {
func (f filesystem) ResourceByID(id uuid.UUID) (Resource, error) {
res, err := f.db.Queries().ResourceByID(f.ctx, db.ResourceByIDParams{Root: f.root.ID(), Permission: f.root.Permission(), ResourceID: id, UserID: f.user})
// TODO: check found
// TODO: verify found
if err == pgx.ErrNoRows || !res.Found || res.Permission == 0 {
err = fs.ErrNotExist
}

View File

@@ -4,6 +4,7 @@ import (
"context"
"errors"
"github.com/google/uuid"
"github.com/jackc/pgx/v5"
"github.com/shroff/phylum/server/internal/cryptutil"
"github.com/shroff/phylum/server/internal/db"
@@ -30,10 +31,18 @@ func (u user) DisplayName() string { return u.displayName }
func (a App) CreateUser(ctx context.Context, username, displayName, password string) error {
if hash, err := cryptutil.GenerateArgon2EncodedHash(password, cryptutil.DefaultArgon2Params()); err != nil {
return err
} else if err = a.db.Queries().CreateUser(ctx, db.CreateUserParams{Username: username, DisplayName: displayName, PasswordHash: hash}); err != nil {
} else if u, err := a.db.Queries().CreateUser(ctx, db.CreateUserParams{Username: username, DisplayName: displayName, PasswordHash: hash}); err != nil {
return err
} else if home, err := a.adminfs.ResourceByPath("/home"); err != nil {
return err
} else if home, err := a.adminfs.CreateMemberResource(home, uuid.New(), username, true); err != nil {
return err
} else if err := a.adminfs.UpdateOwner(home, u.ID); err != nil {
return err
} else {
homeID := home.ID()
return a.db.Queries().UpdateUserHome(ctx, db.UpdateUserHomeParams{ID: u.ID, Home: &homeID})
}
return nil
}
func (a App) ListUsers(ctx context.Context) ([]User, error) {

View File

@@ -275,6 +275,6 @@ func readUserIDFromFlagsreadUsername(cmd *cobra.Command) {
func setupUsernameFlags(cmd *cobra.Command) {
flags := cmd.Flags()
flags.Int32P("user", "u", 0, "Specify User ID for resource operations (cannot be used with -U)")
flags.StringP("username", "U", "root", "Specify Username for resource operations (cannot be used with -u)")
flags.StringP("username", "U", "phylum", "Specify Username for resource operations (cannot be used with -u)")
}

View File

@@ -1,14 +1,18 @@
CREATE TABLE users(
id SERIAL PRIMARY KEY,
username TEXT NOT NULL UNIQUE,
created TIMESTAMP NOT NULL,
modified TIMESTAMP NOT NULL,
display_name TEXT NOT NULL,
password_hash TEXT NOT NULL,
deleted TIMESTAMP
);
INSERT INTO users(username, display_name, password_hash) VALUES(
'root',
'Admin',
INSERT INTO users(username, created, modified, display_name, password_hash) VALUES(
'phylum',
NOW(),
NOW(),
'Phylum',
'CANNOT_LOG_IN'
);

View File

@@ -22,7 +22,7 @@ SELECT '00000000-0000-0000-0000-000000000000',
NULL,
0,
''
FROM users where username = 'root');
FROM users where username = 'phylum');
CREATE UNIQUE INDEX unique_member_resource_name ON resources(parent, name) WHERE deleted IS NULL;

View File

@@ -0,0 +1,5 @@
ALTER TABLE users ADD home uuid REFERENCES resources(id) ON UPDATE CASCADE ON DELETE CASCADE;
---- create above / drop below ----
ALTER TABLE users DROP COLUMN home;

View File

@@ -44,7 +44,10 @@ type StorageBackend struct {
type User struct {
ID int32
Username string
Created pgtype.Timestamp
Modified pgtype.Timestamp
DisplayName string
PasswordHash string
Deleted pgtype.Timestamp
Home *uuid.UUID
}

View File

@@ -7,14 +7,16 @@ package db
import (
"context"
"github.com/google/uuid"
)
const createUser = `-- name: CreateUser :exec
const createUser = `-- name: CreateUser :one
INSERT INTO users(
username, display_name, password_hash
username, created, modified, display_name, password_hash
) VALUES (
$1, $2, $3
)
$1, NOW(), NOW(), $2, $3
) RETURNING id, username, created, modified, display_name, password_hash, deleted, home
`
type CreateUserParams struct {
@@ -23,13 +25,24 @@ type CreateUserParams struct {
PasswordHash string
}
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) error {
_, err := q.db.Exec(ctx, createUser, arg.Username, arg.DisplayName, arg.PasswordHash)
return err
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, error) {
row := q.db.QueryRow(ctx, createUser, arg.Username, arg.DisplayName, arg.PasswordHash)
var i User
err := row.Scan(
&i.ID,
&i.Username,
&i.Created,
&i.Modified,
&i.DisplayName,
&i.PasswordHash,
&i.Deleted,
&i.Home,
)
return i, err
}
const listUsers = `-- name: ListUsers :many
SELECT id, username, display_name, password_hash, deleted from users WHERE deleted IS NULL
SELECT id, username, created, modified, display_name, password_hash, deleted, home from users WHERE deleted IS NULL
`
func (q *Queries) ListUsers(ctx context.Context) ([]User, error) {
@@ -44,9 +57,12 @@ func (q *Queries) ListUsers(ctx context.Context) ([]User, error) {
if err := rows.Scan(
&i.ID,
&i.Username,
&i.Created,
&i.Modified,
&i.DisplayName,
&i.PasswordHash,
&i.Deleted,
&i.Home,
); err != nil {
return nil, err
}
@@ -58,8 +74,62 @@ func (q *Queries) ListUsers(ctx context.Context) ([]User, error) {
return items, nil
}
const updateUserDisplayName = `-- name: UpdateUserDisplayName :exec
UPDATE users
SET
display_name = $1,
modified = NOW()
WHERE id = $2
`
type UpdateUserDisplayNameParams struct {
DisplayName string
ID int32
}
func (q *Queries) UpdateUserDisplayName(ctx context.Context, arg UpdateUserDisplayNameParams) error {
_, err := q.db.Exec(ctx, updateUserDisplayName, arg.DisplayName, arg.ID)
return err
}
const updateUserHome = `-- name: UpdateUserHome :exec
UPDATE users
SET
home = $1,
modified = NOW()
WHERE id = $2
`
type UpdateUserHomeParams struct {
Home *uuid.UUID
ID int32
}
func (q *Queries) UpdateUserHome(ctx context.Context, arg UpdateUserHomeParams) error {
_, err := q.db.Exec(ctx, updateUserHome, arg.Home, arg.ID)
return err
}
const updateUserPasswordHash = `-- name: UpdateUserPasswordHash :exec
UPDATE users
SET
password_hash = $1,
modified = NOW()
WHERE id = $2
`
type UpdateUserPasswordHashParams struct {
PasswordHash string
ID int32
}
func (q *Queries) UpdateUserPasswordHash(ctx context.Context, arg UpdateUserPasswordHashParams) error {
_, err := q.db.Exec(ctx, updateUserPasswordHash, arg.PasswordHash, arg.ID)
return err
}
const userByID = `-- name: UserByID :one
SELECT id, username, display_name, password_hash, deleted from users WHERE id = $1
SELECT id, username, created, modified, display_name, password_hash, deleted, home from users WHERE id = $1
`
func (q *Queries) UserByID(ctx context.Context, id int32) (User, error) {
@@ -68,15 +138,18 @@ func (q *Queries) UserByID(ctx context.Context, id int32) (User, error) {
err := row.Scan(
&i.ID,
&i.Username,
&i.Created,
&i.Modified,
&i.DisplayName,
&i.PasswordHash,
&i.Deleted,
&i.Home,
)
return i, err
}
const userByUsername = `-- name: UserByUsername :one
SELECT id, username, display_name, password_hash, deleted from users WHERE username = $1
SELECT id, username, created, modified, display_name, password_hash, deleted, home from users WHERE username = $1
`
func (q *Queries) UserByUsername(ctx context.Context, username string) (User, error) {
@@ -85,9 +158,12 @@ func (q *Queries) UserByUsername(ctx context.Context, username string) (User, er
err := row.Scan(
&i.ID,
&i.Username,
&i.Created,
&i.Modified,
&i.DisplayName,
&i.PasswordHash,
&i.Deleted,
&i.Home,
)
return i, err
}

View File

@@ -1,9 +1,9 @@
-- name: CreateUser :exec
-- name: CreateUser :one
INSERT INTO users(
username, display_name, password_hash
username, created, modified, display_name, password_hash
) VALUES (
$1, $2, $3
);
$1, NOW(), NOW(), $2, $3
) RETURNING *;
-- name: UserByUsername :one
SELECT * from users WHERE username = $1;
@@ -12,4 +12,25 @@ SELECT * from users WHERE username = $1;
SELECT * from users WHERE id = $1;
-- name: ListUsers :many
SELECT * from users WHERE deleted IS NULL;
SELECT * from users WHERE deleted IS NULL;
-- name: UpdateUserDisplayName :exec
UPDATE users
SET
display_name = $1,
modified = NOW()
WHERE id = $2;
-- name: UpdateUserPasswordHash :exec
UPDATE users
SET
password_hash = $1,
modified = NOW()
WHERE id = $2;
-- name: UpdateUserHome :exec
UPDATE users
SET
home = $1,
modified = NOW()
WHERE id = $2;