Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d83c66d
标签管理
Leslie-Xy Jul 3, 2025
8c0642a
pr检查优化
Leslie-Xy Jul 3, 2025
939676f
feat(role): Implement role management functionality
okatu-loli Jul 10, 2025
80bb29f
refactor(user roles): Support multiple roles for users
okatu-loli Jul 10, 2025
f750a15
feat(user/role): Add path limit check for user and role permissions
okatu-loli Jul 10, 2025
e67bb8a
feat(permission): Add role-based permission handling
okatu-loli Jul 10, 2025
38f3791
refactor(user): Replace integer role values with role IDs
okatu-loli Jul 10, 2025
29f8cab
feat(role_perm): implement support for multiple base paths for roles
okatu-loli Jul 10, 2025
8627993
feat(role): Restrict modifications to default roles (admin and guest)
okatu-loli Jul 10, 2025
cf0f27c
🔄 **refactor(role): Enhance role permission handling**
okatu-loli Jul 10, 2025
6e9bd30
fix(model/user/role): update permission settings for admin and role
okatu-loli Jul 11, 2025
75c2ac2
🔒 feat(role-permissions): Enhance role-based access control
okatu-loli Jul 14, 2025
19c4bae
🔒 fix(permissions): Add permission checks for archive operations
okatu-loli Jul 14, 2025
200b182
🔒 fix(server): Add permission check for offline download
okatu-loli Jul 14, 2025
73a5530
✨ feat(role-permission): Implement path-based role permission checks
okatu-loli Jul 14, 2025
6510e32
✨ feat(role-permission): Implement path-based role permission checks
okatu-loli Jul 14, 2025
b56c253
♻️ refactor(access-control): Update access control logic to use role-…
okatu-loli Jul 14, 2025
50dc659
✨ feat(fs): Improve visibility logic for hidden files
okatu-loli Jul 14, 2025
90783ed
Merge branch 'pr-9197' into feat/enhanced-permission-control
okatu-loli Jul 24, 2025
a5725b5
标签管理
Leslie-Xy Jul 24, 2025
9983121
Merge branch 'pr-9214' into feat/enhanced-permission-control
okatu-loli Jul 24, 2025
8194785
feat(db/auth/user): Enhance role handling and clean permission paths
okatu-loli Jul 24, 2025
a220e2a
feat(storage/db): Implement role permissions path prefix update
okatu-loli Jul 25, 2025
070bc1d
feat(role-migration): Implement role conversion and introduce NEWGENE…
okatu-loli Jul 25, 2025
820b611
feat(role/auth): Add role retrieval by user ID and update path prefixes
okatu-loli Jul 25, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion drivers/alist_v3/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ func (d *AListV3) Init(ctx context.Context) error {
if err != nil {
return err
}
if resp.Data.Role == model.GUEST {
if utils.SliceContains(resp.Data.Role, model.GUEST) {
u := d.Address + "/api/public/settings"
res, err := base.RestyClient.R().Get(u)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion drivers/alist_v3/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ type MeResp struct {
Username string `json:"username"`
Password string `json:"password"`
BasePath string `json:"base_path"`
Role int `json:"role"`
Role []int `json:"role"`
Disabled bool `json:"disabled"`
Permission int `json:"permission"`
SsoId string `json:"sso_id"`
Expand Down
2 changes: 1 addition & 1 deletion drivers/quqi/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ type Group struct {
Type int `json:"type"`
Name string `json:"name"`
IsAdministrator int `json:"is_administrator"`
Role int `json:"role"`
Role []int `json:"role"`
Avatar string `json:"avatar_url"`
IsStick int `json:"is_stick"`
Nickname string `json:"nickname"`
Expand Down
1 change: 1 addition & 0 deletions internal/bootstrap/data/data.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package data
import "github.com/alist-org/alist/v3/cmd/flags"

func InitData() {
initRoles()
initUser()
initSettings()
initTasks()
Expand Down
2 changes: 1 addition & 1 deletion internal/bootstrap/data/dev.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func initDevData() {
Username: "Noah",
Password: "hsu",
BasePath: "/data",
Role: 0,
Role: nil,
Permission: 512,
})
if err != nil {
Expand Down
52 changes: 52 additions & 0 deletions internal/bootstrap/data/role.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package data

// initRoles creates the default admin and guest roles if missing.
// These roles are essential and must not be modified or removed.

import (
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/internal/op"
"github.com/alist-org/alist/v3/pkg/utils"
"github.com/pkg/errors"
"gorm.io/gorm"
)

func initRoles() {
guestRole, err := op.GetRoleByName("guest")
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
guestRole = &model.Role{
ID: uint(model.GUEST),
Name: "guest",
Description: "Guest",
PermissionScopes: []model.PermissionEntry{
{Path: "/", Permission: 0},
},
}
if err := op.CreateRole(guestRole); err != nil {
utils.Log.Fatalf("[init role] Failed to create guest role: %v", err)
}
} else {
utils.Log.Fatalf("[init role] Failed to get guest role: %v", err)
}
}

_, err = op.GetRoleByName("admin")
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
adminRole := &model.Role{
ID: uint(model.ADMIN),
Name: "admin",
Description: "Administrator",
PermissionScopes: []model.PermissionEntry{
{Path: "/", Permission: 0xFFFF},
},
}
if err := op.CreateRole(adminRole); err != nil {
utils.Log.Fatalf("[init role] Failed to create admin role: %v", err)
}
} else {
utils.Log.Fatalf("[init role] Failed to get admin role: %v", err)
}
}
}
50 changes: 26 additions & 24 deletions internal/bootstrap/data/user.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package data

import (
"github.com/alist-org/alist/v3/internal/db"
"os"

"github.com/alist-org/alist/v3/cmd/flags"
"github.com/alist-org/alist/v3/internal/db"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/internal/op"
"github.com/alist-org/alist/v3/pkg/utils"
Expand All @@ -14,6 +14,28 @@ import (
)

func initUser() {
guest, err := op.GetGuest()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
salt := random.String(16)
guestRole, _ := op.GetRoleByName("guest")
guest = &model.User{
Username: "guest",
PwdHash: model.TwoHashPwd("guest", salt),
Salt: salt,
Role: model.Roles{int(guestRole.ID)},
BasePath: "/",
Permission: 0,
Disabled: true,
Authn: "[]",
}
if err := db.CreateUser(guest); err != nil {
utils.Log.Fatalf("[init user] Failed to create guest user: %v", err)
}
} else {
utils.Log.Fatalf("[init user] Failed to get guest user: %v", err)
}
}
admin, err := op.GetAdmin()
adminPassword := random.String(8)
envpass := os.Getenv("ALIST_ADMIN_PASSWORD")
Expand All @@ -25,15 +47,16 @@ func initUser() {
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
salt := random.String(16)
adminRole, _ := op.GetRoleByName("admin")
admin = &model.User{
Username: "admin",
Salt: salt,
PwdHash: model.TwoHashPwd(adminPassword, salt),
Role: model.ADMIN,
Role: model.Roles{int(adminRole.ID)},
BasePath: "/",
Authn: "[]",
// 0(can see hidden) - 7(can remove) & 12(can read archives) - 13(can decompress archives)
Permission: 0x30FF,
Permission: 0xFFFF,
}
if err := op.CreateUser(admin); err != nil {
panic(err)
Expand All @@ -44,25 +67,4 @@ func initUser() {
utils.Log.Fatalf("[init user] Failed to get admin user: %v", err)
}
}
guest, err := op.GetGuest()
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
salt := random.String(16)
guest = &model.User{
Username: "guest",
PwdHash: model.TwoHashPwd("guest", salt),
Salt: salt,
Role: model.GUEST,
BasePath: "/",
Permission: 0,
Disabled: true,
Authn: "[]",
}
if err := db.CreateUser(guest); err != nil {
utils.Log.Fatalf("[init user] Failed to create guest user: %v", err)
}
} else {
utils.Log.Fatalf("[init user] Failed to get guest user: %v", err)
}
}
}
7 changes: 7 additions & 0 deletions internal/bootstrap/patch/all.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"github.com/alist-org/alist/v3/internal/bootstrap/patch/v3_24_0"
"github.com/alist-org/alist/v3/internal/bootstrap/patch/v3_32_0"
"github.com/alist-org/alist/v3/internal/bootstrap/patch/v3_41_0"
"github.com/alist-org/alist/v3/internal/bootstrap/patch/v3_46_0"
)

type VersionPatches struct {
Expand Down Expand Up @@ -32,4 +33,10 @@ var UpgradePatches = []VersionPatches{
v3_41_0.GrantAdminPermissions,
},
},
{
Version: "v3.46.0",
Patches: []func(){
v3_46_0.ConvertLegacyRoles,
},
},
}
129 changes: 129 additions & 0 deletions internal/bootstrap/patch/v3_46_0/convert_role.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package v3_46_0

import (
"errors"
"github.com/alist-org/alist/v3/internal/db"
"github.com/alist-org/alist/v3/internal/model"
"github.com/alist-org/alist/v3/internal/op"
"github.com/alist-org/alist/v3/pkg/utils"
"gorm.io/gorm"
)

// ConvertLegacyRoles migrates old integer role values to a new role model with permission scopes.
func ConvertLegacyRoles() {
guestRole, err := op.GetRoleByName("guest")
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
guestRole = &model.Role{
ID: uint(model.GUEST),
Name: "guest",
Description: "Guest",
PermissionScopes: []model.PermissionEntry{
{
Path: "/",
Permission: 0,
},
},
}
if err = op.CreateRole(guestRole); err != nil {
utils.Log.Errorf("[convert roles] failed to create guest role: %v", err)
return
}
} else {
utils.Log.Errorf("[convert roles] failed to get guest role: %v", err)
return
}
}

adminRole, err := op.GetRoleByName("admin")
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
adminRole = &model.Role{
ID: uint(model.ADMIN),
Name: "admin",
Description: "Administrator",
PermissionScopes: []model.PermissionEntry{
{
Path: "/",
Permission: 0x33FF,
},
},
}
if err = op.CreateRole(adminRole); err != nil {
utils.Log.Errorf("[convert roles] failed to create admin role: %v", err)
return
}
} else {
utils.Log.Errorf("[convert roles] failed to get admin role: %v", err)
return
}
}

generalRole, err := op.GetRoleByName("general")
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
generalRole = &model.Role{
ID: uint(model.NEWGENERAL),
Name: "general",
Description: "General User",
PermissionScopes: []model.PermissionEntry{
{
Path: "/",
Permission: 0,
},
},
}
if err = op.CreateRole(generalRole); err != nil {
utils.Log.Errorf("[convert roles] failed create general role: %v", err)
return
}
} else {
utils.Log.Errorf("[convert roles] failed get general role: %v", err)
return
}
}

users, _, err := op.GetUsers(1, -1)
if err != nil {
utils.Log.Errorf("[convert roles] failed to get users: %v", err)
return
}

for i := range users {
user := users[i]
if user.Role == nil {
continue
}
changed := false
var roles model.Roles
for _, r := range user.Role {
switch r {
case model.ADMIN:
roles = append(roles, int(adminRole.ID))
if int(adminRole.ID) != r {
changed = true
}
case model.GUEST:
roles = append(roles, int(guestRole.ID))
if int(guestRole.ID) != r {
changed = true
}
case model.GENERAL:
roles = append(roles, int(generalRole.ID))
if int(generalRole.ID) != r {
changed = true
}
default:
roles = append(roles, r)
}
}
if changed {
user.Role = roles
if err := db.UpdateUser(&user); err != nil {
utils.Log.Errorf("[convert roles] failed to update user %s: %v", user.Username, err)
}
}
}

utils.Log.Infof("[convert roles] completed role conversion for %d users", len(users))
}
2 changes: 1 addition & 1 deletion internal/db/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ var db *gorm.DB

func Init(d *gorm.DB) {
db = d
err := AutoMigrate(new(model.Storage), new(model.User), new(model.Meta), new(model.SettingItem), new(model.SearchNode), new(model.TaskItem), new(model.SSHPublicKey))
err := AutoMigrate(new(model.Storage), new(model.User), new(model.Meta), new(model.SettingItem), new(model.SearchNode), new(model.TaskItem), new(model.SSHPublicKey), new(model.Role), new(model.Label), new(model.LabelFileBinDing), new(model.ObjFile))
if err != nil {
log.Fatalf("failed migrate database: %s", err.Error())
}
Expand Down
Loading
Loading