Files
pipu-music/services/api/internal/auth/policy.go
T
mrleo1nid a29a8b18ad
ci / api / api (push) Successful in 52s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 1m9s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m35s
release / release (версия и заметки) (push) Successful in 5s
release / android (APK в релиз) (push) Successful in 4m6s
ci / db / db (push) Successful in 1m15s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 1m19s
ci / ts / ts (packages + web) (push) Successful in 2m34s
release / desktop (Linux и Windows в релиз) (push) Successful in 14m27s
release / prune (старые файлы и прогоны) (push) Successful in 6s
feat(admin): manage server updates and local configuration
2026-10-22 23:01:36 +03:00

112 lines
4.7 KiB
Go

package auth
import "github.com/google/uuid"
// Матрица прав из docs/auth-and-roles.md. Проверяется в сервисном слое, а не только в middleware.
// Permission — право, не зависящее от целевого пользователя.
type Permission int
// Глобальные права.
const (
PermAdminPanel Permission = iota // открыть админку
PermListUsers // видеть список пользователей
PermManageLibrary // хранилища, сканирование, переиндексация
PermViewLibraryStatus // статус библиотеки (просмотр)
PermSuggestTracks // предлагать треки, видеть свои предложения
PermReviewUploads // очередь, одобрение, правка метаданных; даёт флаг, не роль
PermSystemStatus // статус рекомендательной системы, аудит
PermManageUpdates // обновление сервера; admin или выданное право
)
var permissions = map[Permission][]Role{
PermAdminPanel: {RoleModerator, RoleAdmin},
PermListUsers: {RoleModerator, RoleAdmin},
PermManageLibrary: {RoleAdmin},
PermViewLibraryStatus: {RoleModerator, RoleAdmin},
PermSuggestTracks: {RoleModerator, RoleAdmin},
PermSystemStatus: {RoleAdmin},
PermManageUpdates: {RoleAdmin},
}
// Can сообщает, есть ли у роли глобальное право.
// Аудит загрузок сюда не входит: его проверяет Principal.Allowed.
func Can(r Role, p Permission) bool {
for _, allowed := range permissions[p] {
if allowed == r {
return true
}
}
return false
}
// Allowed — право конкретного пользователя. Аудит загрузок не вытекает из роли admin.
func (p Principal) Allowed(perm Permission) bool {
if perm == PermManageUpdates {
return p.Role == RoleAdmin || p.ManagesUpdates
}
if perm == PermAdminPanel && p.ManagesUpdates {
return true
}
if perm == PermReviewUploads {
return p.ReviewsUploads
}
return Can(p.Role, perm)
}
// UserAction — действие над учётной записью другого пользователя.
type UserAction int
// Действия над пользователями.
const (
UserCreate UserAction = iota // создать пользователя с ролью target
UserEdit // изменить отображаемое имя
UserResetPassword // сбросить пароль
UserBlock // заблокировать / разблокировать
UserChangeRole // сменить роль (target — текущая роль)
UserDelete // удалить
UserResetRecommendations // сбросить профиль рекомендаций
)
// Actor — кто действует (или над кем). ID нужен, чтобы запретить действия над собой.
type Actor struct {
ID uuid.UUID
Role Role
}
// CanManageUser — может ли actor выполнить action над target.
// Модератор управляет только обычными пользователями; роли и удаление — только админ.
// Блокировать, удалять себя и менять себе роль нельзя никому: так не потерять доступ случайно.
// Правило «последний админ» зависит от данных и проверяется в сервисе.
func CanManageUser(actor, target Actor, action UserAction) bool {
self := actor.ID != uuid.Nil && actor.ID == target.ID
if self && (action == UserBlock || action == UserDelete || action == UserChangeRole) {
return false
}
switch actor.Role {
case RoleAdmin:
return true
case RoleModerator:
switch action {
case UserCreate, UserEdit, UserResetPassword, UserBlock, UserResetRecommendations:
return target.Role == RoleUser
default:
return false
}
default:
return false
}
}
// CanAssignRole — может ли actor выдать роль newRole (при создании или смене роли).
func CanAssignRole(actor Role, newRole Role) bool {
switch actor {
case RoleAdmin:
return newRole.Valid()
case RoleModerator:
return newRole == RoleUser
default:
return false
}
}