diff options
| author | Gabriel Arakaki Giovanini <mail@gabrielgio.me> | 2023-06-26 22:26:10 +0200 | 
|---|---|---|
| committer | Gabriel Arakaki Giovanini <mail@gabrielgio.me> | 2023-06-26 22:40:16 +0200 | 
| commit | 4d930c0c8cb585979798fac2bb254f991faa62fb (patch) | |
| tree | 0c33e0e0f2a2f47b0f64843f7d9a3eb299abb260 /pkg | |
| parent | d4e1ca3a48e74573df6965ceee217e119ff899ae (diff) | |
| download | lens-4d930c0c8cb585979798fac2bb254f991faa62fb.tar.gz lens-4d930c0c8cb585979798fac2bb254f991faa62fb.tar.bz2 lens-4d930c0c8cb585979798fac2bb254f991faa62fb.zip | |
feat: Add initial user setup
Diffstat (limited to 'pkg')
| -rw-r--r-- | pkg/components/auth/controller.go | 44 | ||||
| -rw-r--r-- | pkg/components/auth/controller_test.go | 19 | ||||
| -rw-r--r-- | pkg/components/errors.go | 8 | ||||
| -rw-r--r-- | pkg/components/media/model.go | 5 | ||||
| -rw-r--r-- | pkg/components/user/model.go | 3 | ||||
| -rw-r--r-- | pkg/database/sql/user.go | 15 | ||||
| -rw-r--r-- | pkg/database/sql/user_test.go | 20 | ||||
| -rw-r--r-- | pkg/ext/middleware.go | 42 | ||||
| -rw-r--r-- | pkg/view/auth.go | 21 | 
9 files changed, 151 insertions, 26 deletions
| diff --git a/pkg/components/auth/controller.go b/pkg/components/auth/controller.go index a81a1c0..2f30fb5 100644 --- a/pkg/components/auth/controller.go +++ b/pkg/components/auth/controller.go @@ -5,18 +5,26 @@ import (  	"golang.org/x/crypto/bcrypt" +	"git.sr.ht/~gabrielgio/img/pkg/components" +	"git.sr.ht/~gabrielgio/img/pkg/components/user"  	"git.sr.ht/~gabrielgio/img/pkg/ext"  )  type Controller struct { -	repository Repository -	key        []byte +	repository     Repository +	userRepository user.Repository +	key            []byte  } -func NewController(repository Repository, key []byte) *Controller { +func NewController( +	repository Repository, +	userRepository user.Repository, +	key []byte, +) *Controller {  	return &Controller{ -		repository: repository, -		key:        key, +		repository:     repository, +		userRepository: userRepository, +		key:            key,  	}  } @@ -41,3 +49,29 @@ func (c *Controller) Login(ctx context.Context, username, password []byte) ([]by  	}  	return ext.WriteToken(token, c.key)  } + +// InitialRegister register a initial user, it will validate if there is another +// user stored already. If so an error `InvlidaInput` will be returned +func (c *Controller) InitialRegister(ctx context.Context, username, password []byte, path []byte) error { +	exist, err := c.userRepository.Any(ctx) +	if err != nil { +		return err +	} + +	if exist { +		return components.InvlidaInput +	} + +	hash, err := bcrypt.GenerateFromPassword(password, bcrypt.MinCost) +	if err != nil { +		return err +	} + +	err = c.userRepository.Create(ctx, &user.CreateUser{ +		Username: string(username), +		Password: hash, +		Path:     string(path), +	}) + +	return err +} diff --git a/pkg/components/auth/controller_test.go b/pkg/components/auth/controller_test.go index 33aa901..6b4e3cd 100644 --- a/pkg/components/auth/controller_test.go +++ b/pkg/components/auth/controller_test.go @@ -9,6 +9,7 @@ import (  	"github.com/samber/lo" +	"git.sr.ht/~gabrielgio/img/pkg/components/user"  	"git.sr.ht/~gabrielgio/img/pkg/ext"  	"git.sr.ht/~gabrielgio/img/pkg/testkit"  ) @@ -43,11 +44,11 @@ func setUp() *scene {  	return &scene{  		ctx:            context.Background(),  		mockRepository: mockUserRepository, -		controller:     *NewController(mockUserRepository, key), +		controller:     *NewController(mockUserRepository, nil, key),  	}  } -func TestRegisterAndLogin(t *testing.T) { +func TestInitialRegisterAndLogin(t *testing.T) {  	testCases := []struct {  		name     string  		username string @@ -64,7 +65,7 @@ func TestRegisterAndLogin(t *testing.T) {  		t.Run(tc.name, func(t *testing.T) {  			scene := setUp() -			err := scene.controller.Register(scene.ctx, []byte(tc.username), tc.password) +			err := scene.controller.InitialRegister(scene.ctx, []byte(tc.username), tc.password, []byte("/"))  			testkit.TestFatalError(t, "Register", err)  			userID := scene.mockRepository.GetLastId() @@ -85,8 +86,8 @@ func TestRegisterAndLogin(t *testing.T) {  	}  } -func toUser(m *mockUser, _ int) *User { -	return &User{ +func toUser(m *mockUser, _ int) *user.User { +	return &user.User{  		ID:       m.id,  		Username: m.username,  	} @@ -96,7 +97,7 @@ func (m *MockUserRepository) GetLastId() uint {  	return m.index  } -func (m *MockUserRepository) List(ctx context.Context) ([]*User, error) { +func (m *MockUserRepository) List(ctx context.Context) ([]*user.User, error) {  	if m.err != nil {  		return nil, m.err  	} @@ -104,7 +105,7 @@ func (m *MockUserRepository) List(ctx context.Context) ([]*User, error) {  	return lo.Map(m.users, toUser), nil  } -func (m *MockUserRepository) Get(ctx context.Context, id uint) (*User, error) { +func (m *MockUserRepository) Get(ctx context.Context, id uint) (*user.User, error) {  	if m.err != nil {  		return nil, m.err  	} @@ -143,7 +144,7 @@ func (m *MockUserRepository) GetPassword(ctx context.Context, id uint) ([]byte,  	return nil, errors.New("Item not found")  } -func (m *MockUserRepository) Create(ctx context.Context, createUser *CreateUser) (uint, error) { +func (m *MockUserRepository) Create(ctx context.Context, createUser *user.CreateUser) (uint, error) {  	if m.err != nil {  		return 0, m.err  	} @@ -159,7 +160,7 @@ func (m *MockUserRepository) Create(ctx context.Context, createUser *CreateUser)  	return m.index, nil  } -func (m *MockUserRepository) Update(ctx context.Context, id uint, update *UpdateUser) error { +func (m *MockUserRepository) Update(ctx context.Context, id uint, update *user.UpdateUser) error {  	if m.err != nil {  		return m.err  	} diff --git a/pkg/components/errors.go b/pkg/components/errors.go new file mode 100644 index 0000000..aedbe88 --- /dev/null +++ b/pkg/components/errors.go @@ -0,0 +1,8 @@ +package components + +import "errors" + +var ( +	NotFound     = errors.New("Not found") +	InvlidaInput = errors.New("Invalid Input") +) diff --git a/pkg/components/media/model.go b/pkg/components/media/model.go index 0e17e92..1962a23 100644 --- a/pkg/components/media/model.go +++ b/pkg/components/media/model.go @@ -2,6 +2,7 @@ package media  import (  	"context" +	"strings"  	"time"  ) @@ -57,3 +58,7 @@ type (  		CreateEXIF(context.Context, uint, *MediaEXIF) error  	}  ) + +func (m *Media) IsVideo() bool { +	return strings.HasPrefix(m.MIMEType, "video") +} diff --git a/pkg/components/user/model.go b/pkg/components/user/model.go index f957c39..ce1b3a5 100644 --- a/pkg/components/user/model.go +++ b/pkg/components/user/model.go @@ -20,7 +20,7 @@ type (  	CreateUser struct {  		Username string  		Name     string -		Password string +		Password []byte  		IsAdmin  bool  		Path     string  	} @@ -29,5 +29,6 @@ type (  		List(ctx context.Context) ([]*User, error)  		Create(ctx context.Context, createUser *CreateUser) error  		Update(ctx context.Context, id uint, updateUser *UpdateUser) error +		Any(ctx context.Context) (bool, error)  	}  ) diff --git a/pkg/database/sql/user.go b/pkg/database/sql/user.go index 2d74162..a02b67b 100644 --- a/pkg/database/sql/user.go +++ b/pkg/database/sql/user.go @@ -187,3 +187,18 @@ func (self *UserRepository) Delete(ctx context.Context, id uint) error {  	}  	return nil  } + +func (u *UserRepository) Any(ctx context.Context) (bool, error) { +	var exists bool +	result := u.db. +		WithContext(ctx). +		Model(&User{}). +		Select("count(id) > 0"). +		Find(&exists) + +	if result.Error != nil { +		return false, result.Error +	} + +	return exists, nil +} diff --git a/pkg/database/sql/user_test.go b/pkg/database/sql/user_test.go index 875b8e6..473ce03 100644 --- a/pkg/database/sql/user_test.go +++ b/pkg/database/sql/user_test.go @@ -12,7 +12,7 @@ import (  	"gorm.io/gorm"  	"gorm.io/gorm/logger" -	"git.sr.ht/~gabrielgio/img/pkg/components/auth" +	"git.sr.ht/~gabrielgio/img/pkg/components/user"  )  func setup(t *testing.T) (*gorm.DB, func()) { @@ -48,7 +48,7 @@ func TestCreate(t *testing.T) {  	repository := NewUserRepository(db) -	id, err := repository.Create(context.Background(), &auth.CreateUser{ +	err := repository.Create(context.Background(), &user.CreateUser{  		Username: "new_username",  		Name:     "new_name",  	}) @@ -56,12 +56,12 @@ func TestCreate(t *testing.T) {  		t.Fatalf("Error creating: %s", err.Error())  	} -	got, err := repository.Get(context.Background(), id) +	got, err := repository.Get(context.Background(), 1)  	if err != nil {  		t.Fatalf("Error getting: %s", err.Error())  	} -	want := &auth.User{ -		ID:       id, +	want := &user.User{ +		ID:       1,  		Username: "new_username",  		Name:     "new_name",  	} @@ -78,7 +78,7 @@ func TestUpdate(t *testing.T) {  	repository := NewUserRepository(db) -	id, err := repository.Create(context.Background(), &auth.CreateUser{ +	err := repository.Create(context.Background(), &user.CreateUser{  		Username: "username",  		Name:     "name",  	}) @@ -86,7 +86,7 @@ func TestUpdate(t *testing.T) {  		t.Fatalf("Error creating user: %s", err.Error())  	} -	err = repository.Update(context.Background(), id, &auth.UpdateUser{ +	err = repository.Update(context.Background(), 1, &user.UpdateUser{  		Username: "new_username",  		Name:     "new_name",  	}) @@ -94,12 +94,12 @@ func TestUpdate(t *testing.T) {  		t.Fatalf("Error update user: %s", err.Error())  	} -	got, err := repository.Get(context.Background(), id) +	got, err := repository.Get(context.Background(), 1)  	if err != nil {  		t.Fatalf("Error getting user: %s", err.Error())  	} -	want := &auth.User{ -		ID:       id, +	want := &user.User{ +		ID:       1,  		Username: "new_username",  		Name:     "new_name",  	} diff --git a/pkg/ext/middleware.go b/pkg/ext/middleware.go index 771c0ac..649272e 100644 --- a/pkg/ext/middleware.go +++ b/pkg/ext/middleware.go @@ -4,6 +4,7 @@ import (  	"encoding/base64"  	"time" +	"git.sr.ht/~gabrielgio/img/pkg/components/user"  	"github.com/sirupsen/logrus"  	"github.com/valyala/fasthttp"  ) @@ -54,7 +55,7 @@ func NewAuthMiddleware(key []byte, log *logrus.Entry) *AuthMiddleware {  func (a *AuthMiddleware) LoggedIn(next fasthttp.RequestHandler) fasthttp.RequestHandler {  	return func(ctx *fasthttp.RequestCtx) {  		path := string(ctx.Path()) -		if path == "/login" { +		if path == "/login" || path == "/initial" {  			next(ctx)  			return  		} @@ -87,3 +88,42 @@ func (a *AuthMiddleware) LoggedIn(next fasthttp.RequestHandler) fasthttp.Request  		next(ctx)  	}  } + +type InitialSetupMiddleware struct { +	userRepository user.Repository +} + +func NewInitialSetupMiddleware(userRepository user.Repository) *InitialSetupMiddleware { +	return &InitialSetupMiddleware{ +		userRepository: userRepository, +	} +} + +func (i *InitialSetupMiddleware) Check(next fasthttp.RequestHandler) fasthttp.RequestHandler { +	return func(ctx *fasthttp.RequestCtx) { +		// if user has been set to context it is logged in already +		_, ok := ctx.UserValue("token").(*Token) +		if ok { +			next(ctx) +			return +		} + +		path := string(ctx.Path()) +		if path == "/initial" { +			next(ctx) +			return +		} + +		exists, err := i.userRepository.Any(ctx) +		if err != nil { +			InternalServerError(ctx, err) +			return +		} + +		if exists { +			next(ctx) +			return +		} +		ctx.Redirect("/initial", 307) +	} +} diff --git a/pkg/view/auth.go b/pkg/view/auth.go index d44424d..3f9e414 100644 --- a/pkg/view/auth.go +++ b/pkg/view/auth.go @@ -68,10 +68,31 @@ func Index(ctx *fasthttp.RequestCtx) {  	ctx.Redirect("/login", 307)  } +func (v *AuthView) InitialRegisterView(ctx *fasthttp.RequestCtx) error { +	return img.Render[interface{}](ctx, "register.html", nil) +} + +func (v *AuthView) InitialRegister(ctx *fasthttp.RequestCtx) error { +	username := ctx.FormValue("username") +	password := ctx.FormValue("password") +	path := ctx.FormValue("path") + +	err := v.userController.InitialRegister(ctx, username, password, path) +	if err != nil { +		return err +	} + +	ctx.Redirect("/login", 307) +	return nil +} +  func (v *AuthView) SetMyselfIn(r *ext.Router) {  	r.GET("/login", v.LoginView)  	r.POST("/login", v.Login)  	r.GET("/logout", v.Logout)  	r.POST("/logout", v.Logout) + +	r.GET("/initial", v.InitialRegisterView) +	r.POST("/initial", v.InitialRegister)  } | 
