feat: private directory (not complete)

This commit is contained in:
Project_IO 2025-03-22 12:52:22 +09:00
parent f0a94070d2
commit 36a0a2c78a
8 changed files with 295 additions and 191 deletions

14
app.go
View file

@ -46,11 +46,11 @@ func main() {
// init auth module // init auth module
service.NewAuthService() service.NewAuthService()
gin := gin.Default() app := gin.Default()
routes.New(gin, ver, apiOnly) routes.New(app, ver, apiOnly)
fmt.Fprintf(os.Stdout, "binding server at: http://0.0.0.0:%d\n", cnf.Port) fmt.Fprintf(os.Stdout, "binding server at: http://0.0.0.0:%d\n", cnf.Port)
if err := gin.Run(fmt.Sprintf(":%d", cnf.Port)); err != nil { if err = app.Run(fmt.Sprintf(":%d", cnf.Port)); err != nil {
return err return err
} }
@ -81,7 +81,7 @@ func main() {
} }
fmt.Print("new password: ") fmt.Print("new password: ")
bytePassword, err := term.ReadPassword(int(syscall.Stdin)) bytePassword, err := term.ReadPassword(syscall.Stdin)
if err != nil { if err != nil {
return fmt.Errorf("failed to read password: %v", err) return fmt.Errorf("failed to read password: %v", err)
} }
@ -89,7 +89,7 @@ func main() {
fmt.Println() fmt.Println()
fmt.Print("type new password one more time: ") fmt.Print("type new password one more time: ")
checkByte, err := term.ReadPassword(int(syscall.Stdin)) checkByte, err := term.ReadPassword(syscall.Stdin)
if err != nil { if err != nil {
return fmt.Errorf("failed to read password: %v", err) return fmt.Errorf("failed to read password: %v", err)
} }
@ -101,7 +101,7 @@ func main() {
} }
auth := service.NewAuthService() auth := service.NewAuthService()
if err := auth.Create(&service.Account{Username: username, Password: password}); err != nil { if err = auth.Create(&service.Account{Username: username, Password: password}); err != nil {
return err return err
} }
@ -111,7 +111,7 @@ func main() {
}) })
if err := command.Execute(); err != nil { if err := command.Execute(); err != nil {
fmt.Fprintf(os.Stderr, "%v\n", err) _, _ = fmt.Fprintf(os.Stderr, "%v\n", err)
os.Exit(1) os.Exit(1)
} }
} }

1
go.mod
View file

@ -20,6 +20,7 @@ require (
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.25.0 // indirect github.com/go-playground/validator/v10 v10.25.0 // indirect
github.com/goccy/go-json v0.10.5 // indirect github.com/goccy/go-json v0.10.5 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.2.10 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect
github.com/kr/text v0.2.0 // indirect github.com/kr/text v0.2.0 // indirect

2
go.sum
View file

@ -33,6 +33,8 @@ github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PU
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=

View file

@ -14,11 +14,12 @@ func BasicAuth(ctx *gin.Context) {
var list = []string{"/settings"} var list = []string{"/settings"}
for _, i := range list { for _, i := range list {
if !strings.Contains(ctx.Request.URL.Path, i) { if !strings.HasPrefix(ctx.Request.URL.Path, i) {
continue continue
} }
matches = true matches = true
break
} }
if !matches { if !matches {

View file

@ -9,7 +9,13 @@ import (
) )
func authentication(group *gin.RouterGroup) { func authentication(group *gin.RouterGroup) {
group.POST("/login", func(ctx *gin.Context) { group.POST("/login", login)
group.GET("/read", readAcc)
group.PATCH("/update", updateAcc)
group.DELETE("/delete", deleteAcc)
}
func login(ctx *gin.Context) {
auth := service.NewAuthService() auth := service.NewAuthService()
username := ctx.PostForm("username") username := ctx.PostForm("username")
password := ctx.PostForm("password") password := ctx.PostForm("password")
@ -36,9 +42,9 @@ func authentication(group *gin.RouterGroup) {
"ok": 1, "ok": 1,
"token": auth.Token(acc.Username, acc.Password), "token": auth.Token(acc.Username, acc.Password),
}) })
}) }
group.GET("/read", func(ctx *gin.Context) { func readAcc(ctx *gin.Context) {
auth := service.NewAuthService() auth := service.NewAuthService()
username, password, ok := ctx.Request.BasicAuth() username, password, ok := ctx.Request.BasicAuth()
if !ok { if !ok {
@ -66,9 +72,9 @@ func authentication(group *gin.RouterGroup) {
"ok": 1, "ok": 1,
"username": username, "username": username,
}) })
}) }
group.PATCH("/update", func(ctx *gin.Context) { func updateAcc(ctx *gin.Context) {
auth := service.NewAuthService() auth := service.NewAuthService()
old := ctx.PostForm("password") old := ctx.PostForm("password")
new := ctx.PostForm("new_password") new := ctx.PostForm("new_password")
@ -91,9 +97,9 @@ func authentication(group *gin.RouterGroup) {
} }
ctx.Status(200) ctx.Status(200)
}) }
group.DELETE("/delete", func(ctx *gin.Context) { func deleteAcc(ctx *gin.Context) {
auth := service.NewAuthService() auth := service.NewAuthService()
username, password, ok := ctx.Request.BasicAuth() username, password, ok := ctx.Request.BasicAuth()
if !ok { if !ok {
@ -120,5 +126,4 @@ func authentication(group *gin.RouterGroup) {
} }
ctx.Status(200) ctx.Status(200)
})
} }

View file

@ -16,10 +16,39 @@ func New(app *gin.Engine, version *service.Version, apiOnly bool) {
app.Use(middleware.BasicAuth) app.Use(middleware.BasicAuth)
api := app.Group("/api") api := app.Group("/api")
{ api.GET("/path/*path", readPath)
api.GET("/path/*path", func(ctx *gin.Context) { api.GET("/download/*path", downloadPath)
api.POST("/private")
authentication(api.Group("/auth"))
api.GET("/version", func(ctx *gin.Context) {
ctx.String(200, "%s", version.String())
})
if apiOnly {
return
}
app.Use(static.Serve("/", static.LocalFile("./web", true)))
app.Use(static.Serve("/assets", static.LocalFile("./assets", false)))
app.NoRoute(func(ctx *gin.Context) {
ctx.File("./web/index.html")
})
app.GET("favicon.ico", func(ctx *gin.Context) {
ctx.File("/web/assets/favicon.ico")
})
}
func readPath(ctx *gin.Context) {
worker := service.NewWorkerService() worker := service.NewWorkerService()
path := ctx.Param("path") path := ctx.Param("path")
// TODO: prefix detect
// if strings.HasPrefix(path, "")
data, err := worker.Read(path) data, err := worker.Read(path)
if err != nil { if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "%v\n", err) _, _ = fmt.Fprintf(os.Stderr, "%v\n", err)
@ -69,9 +98,9 @@ func New(app *gin.Engine, version *service.Version, apiOnly bool) {
"is_dir": true, "is_dir": true,
"entries": entries, "entries": entries,
}) })
}) }
api.GET("/download/*path", func(ctx *gin.Context) { func downloadPath(ctx *gin.Context) {
worker := service.NewWorkerService() worker := service.NewWorkerService()
path := ctx.Param("path") path := ctx.Param("path")
data, err := worker.Read(path) data, err := worker.Read(path)
@ -87,28 +116,4 @@ func New(app *gin.Engine, version *service.Version, apiOnly bool) {
} }
ctx.FileAttachment(data.Path, data.Name) ctx.FileAttachment(data.Path, data.Name)
})
auth := api.Group("/auth")
authentication(auth)
api.GET("/version", func(ctx *gin.Context) {
ctx.String(200, "%s", version.String())
})
}
if apiOnly {
return
}
app.Use(static.Serve("/", static.LocalFile("./web", true)))
app.Use(static.Serve("/assets", static.LocalFile("./assets", false)))
app.NoRoute(func(ctx *gin.Context) {
ctx.File("./web/index.html")
})
app.GET("favicon.ico", func(ctx *gin.Context) {
ctx.File("/web/assets/favicon.ico")
})
} }

View file

@ -35,7 +35,7 @@ func init() {
username varchar(25), username varchar(25),
password varchar(255), password varchar(255),
salt varchar(50), salt varchar(50),
primary key (username) constraint PK_Account_ID primary key(username)
); );
`)) `))
if err != nil { if err != nil {

90
internal/service/priv.go Normal file
View file

@ -0,0 +1,90 @@
package service
import (
"fmt"
"github.com/google/uuid"
"os"
"strings"
)
type PrivDirService struct{}
type PrivDir struct {
Id string `json:"id"`
DirName string `json:"dirname"`
Owner string `json:"owner"`
}
func init() {
db, err := Open()
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "%v\n", err)
return
}
defer db.Close()
stmt, err := db.Prepare(strings.TrimSpace(`
create table PrivDir(
id varchar(36),
dirname varchar(250) unique,
owner varchar(25),
constraint PK_PrivDir_ID primary key(id),
constraint FK_Owner_ID foreign key(owner)
references(Account.username) on update cascade on delete cascade
);
`))
if err != nil {
return
}
defer stmt.Close()
if _, err = stmt.Exec(); err != nil {
_, _ = fmt.Fprintf(os.Stderr, "%v\n", err)
return
}
}
func NewPrivDirService() *PrivDirService {
return &PrivDirService{}
}
func (sv *PrivDirService) CreatePriv(dirname string, acc *Account) error {
db, err := Open()
if err != nil {
return err
}
defer db.Close()
id := uuid.NewString()
stmt, err := db.Prepare("insert into PrivDir(id, name, owner) values (?, ?, ?);")
if err != nil {
return err
}
defer stmt.Close()
_, err = stmt.Exec(id, dirname, acc.Username)
return nil
}
func (sv *PrivDirService) ReadPriv(name string) (*PrivDir, error) {
db, err := Open()
if err != nil {
return nil, err
}
defer db.Close()
stmt, err := db.Prepare("select * from PrivDir where name = ?;")
if err != nil {
return nil, err
}
defer stmt.Close()
row := stmt.QueryRow(name)
var data PrivDir
if err = row.Scan(&data.Id, &data.DirName, &data.Owner); err != nil {
return nil, err
}
return &data, nil
}