2024-08-28 15:20:38 +00:00
|
|
|
package storage
|
|
|
|
|
2024-09-17 13:46:05 +00:00
|
|
|
import (
|
2024-11-06 15:57:44 +00:00
|
|
|
"github.com/rs/zerolog/log"
|
2024-12-18 14:24:56 +00:00
|
|
|
"git.mstar.dev/mstar/goutils/sliceutils"
|
|
|
|
"git.mstar.dev/mstar/linstrom/util"
|
2024-09-17 13:46:05 +00:00
|
|
|
"gorm.io/gorm"
|
|
|
|
)
|
|
|
|
|
2024-11-20 15:11:11 +00:00
|
|
|
// Could I collapse all these go:generate command into more condensed ones?
|
|
|
|
// Yes
|
|
|
|
// Will I do that?
|
|
|
|
// No
|
|
|
|
// This is explicit in what is being done. And easier to understand
|
|
|
|
|
2024-09-18 09:15:44 +00:00
|
|
|
//go:generate go build -o RolesGenerator ../cmd/RolesGenerator/main.go
|
2024-09-18 11:49:10 +00:00
|
|
|
//go:generate ./RolesGenerator -input=roles.go -output=rolesUtil_generated.go
|
2024-09-18 08:54:04 +00:00
|
|
|
//go:generate rm RolesGenerator
|
|
|
|
|
2024-11-20 12:37:31 +00:00
|
|
|
//go:generate go build -o ApiGenerator ../cmd/RolesApiTypeGenerator/main.go
|
|
|
|
//go:generate ./ApiGenerator -input=roles.go -output=../server/apiLinstromTypes_generated.go
|
|
|
|
//go:generate rm ApiGenerator
|
|
|
|
|
|
|
|
//go:generate go build -o HelperGenerator ../cmd/RolesApiConverter/main.go
|
|
|
|
//go:generate ./HelperGenerator -input=roles.go -output=../server/apiLinstromTypeHelpers_generated.go
|
|
|
|
//go:generate rm HelperGenerator
|
|
|
|
|
|
|
|
//go:generate go build -o FrontendGenerator ../cmd/RolesFrontendGenerator/main.go
|
|
|
|
//go:generate ./FrontendGenerator -input=roles.go -output=../frontend-reactive/app/models/role.ts
|
2024-11-20 15:11:11 +00:00
|
|
|
//go:generate rm FrontendGenerator
|
2024-11-20 12:37:31 +00:00
|
|
|
|
2024-09-17 13:46:05 +00:00
|
|
|
// A role is, in concept, similar to how Discord handles roles
|
|
|
|
// Some permission can be either disallowed (&false), don't care (nil) or allowed (&true)
|
|
|
|
// Don't care just says to use the value from the next lower role where it is set
|
2024-08-28 15:20:38 +00:00
|
|
|
type Role struct {
|
2024-09-13 13:02:32 +00:00
|
|
|
// TODO: More control options
|
|
|
|
// Extend upon whatever Masto, Akkoma and Misskey have
|
|
|
|
// Lots of details please
|
2024-09-17 13:46:05 +00:00
|
|
|
|
|
|
|
// --- Role metadata ---
|
|
|
|
|
|
|
|
// Include full db model stuff
|
|
|
|
gorm.Model
|
|
|
|
|
|
|
|
// Name of the role
|
2024-11-05 15:29:01 +00:00
|
|
|
Name string `gorm:"primaryKey;unique"`
|
2024-09-17 13:46:05 +00:00
|
|
|
|
|
|
|
// Priority of the role
|
|
|
|
// Lower priority gets applied first and thus overwritten by higher priority ones
|
|
|
|
// If two roles have the same priority, the order is undetermined and may be random
|
|
|
|
// Default priority for new roles is 1 to always overwrite default user
|
|
|
|
// And full admin has max priority possible
|
2024-11-05 15:29:01 +00:00
|
|
|
Priority uint32
|
2024-09-17 13:46:05 +00:00
|
|
|
// Whether this role is for a for a single user only (like custom, per user permissions in Discord)
|
|
|
|
// If yes, Name will be the id of the user in question
|
|
|
|
IsUserRole bool
|
|
|
|
|
|
|
|
// Whether this role is one built into Linstrom from the start or not
|
|
|
|
// Note: Built-in roles can't be modified
|
|
|
|
IsBuiltIn bool
|
|
|
|
|
|
|
|
// --- User permissions ---
|
2024-11-04 15:25:39 +00:00
|
|
|
CanSendMedia *bool // Local & remote
|
|
|
|
CanSendCustomEmotes *bool // Local & remote
|
|
|
|
CanSendCustomReactions *bool // Local & remote
|
|
|
|
CanSendPublicNotes *bool // Local & remote
|
|
|
|
CanSendLocalNotes *bool // Local & remote
|
|
|
|
CanSendFollowerOnlyNotes *bool // Local & remote
|
|
|
|
CanSendPrivateNotes *bool // Local & remote
|
|
|
|
CanSendReplies *bool // Local & remote
|
|
|
|
CanQuote *bool // Local only
|
|
|
|
CanBoost *bool // Local only
|
|
|
|
CanIncludeLinks *bool // Local & remote
|
|
|
|
CanIncludeSurvey *bool // Local
|
|
|
|
CanFederateFedi *bool // Local & remote
|
|
|
|
CanFederateBsky *bool // Local
|
|
|
|
|
|
|
|
CanChangeDisplayName *bool // Local
|
|
|
|
|
|
|
|
// Internal ids of accounts blocked by this role
|
|
|
|
BlockedUsers []string `gorm:"type:bytes;serializer:gob"` // Local
|
|
|
|
CanSubmitReports *bool // Local & remote
|
|
|
|
CanLogin *bool // Local
|
|
|
|
|
|
|
|
CanMentionOthers *bool // Local & remote
|
|
|
|
HasMentionCountLimit *bool // Local & remote
|
|
|
|
MentionLimit *uint32 // Local & remote
|
2024-09-17 13:46:05 +00:00
|
|
|
|
|
|
|
// CanViewBoosts *bool
|
|
|
|
// CanViewQuotes *bool
|
|
|
|
// CanViewMedia *bool
|
|
|
|
// CanViewCustomEmotes *bool
|
|
|
|
|
|
|
|
// --- Automod ---
|
2024-11-04 15:25:39 +00:00
|
|
|
AutoNsfwMedia *bool // Local & remote
|
|
|
|
AutoCwPosts *bool // Local & remote
|
|
|
|
AutoCwPostsText *string // Local & remote
|
|
|
|
ScanCreatedPublicNotes *bool // Local & remote
|
|
|
|
ScanCreatedLocalNotes *bool // Local & remote
|
|
|
|
ScanCreatedFollowerOnlyNotes *bool // Local & remote
|
|
|
|
ScanCreatedPrivateNotes *bool // Local & remote
|
2024-10-31 15:53:42 +00:00
|
|
|
// Blocks all interactions and federation between users with the role and all included ids/handles
|
|
|
|
// TODO: Decide whether this is a list of handles or of account ids
|
|
|
|
// Handles would increase the load due to having to search for them first
|
|
|
|
// while ids would require to store every single account mentioned
|
|
|
|
// which could cause escalating storage costs
|
2024-11-04 15:25:39 +00:00
|
|
|
DisallowInteractionsWith []string `gorm:"type:bytes;serializer:gob"` // Local & remote
|
2024-09-17 13:46:05 +00:00
|
|
|
|
2024-11-04 15:25:39 +00:00
|
|
|
WithholdNotesForManualApproval *bool // Local & remote
|
|
|
|
WithholdNotesBasedOnRegex *bool // Local & remote
|
|
|
|
WithholdNotesRegexes []string `gorm:"type:bytes;serializer:gob"` // Local & remote
|
2024-09-17 13:46:05 +00:00
|
|
|
|
|
|
|
// --- Admin perms ---
|
|
|
|
// If set, counts as all permissions being set as given and all restrictions being disabled
|
2024-11-04 15:25:39 +00:00
|
|
|
FullAdmin *bool // Local
|
|
|
|
CanAffectOtherAdmins *bool // Local
|
|
|
|
CanDeleteNotes *bool // Local
|
|
|
|
CanConfirmWithheldNotes *bool // Local
|
|
|
|
CanAssignRoles *bool // Local
|
|
|
|
CanSupressInteractionsBetweenUsers *bool // Local
|
|
|
|
CanOverwriteDisplayNames *bool // Local
|
|
|
|
CanManageCustomEmotes *bool // Local
|
|
|
|
CanViewDeletedNotes *bool // Local
|
|
|
|
CanRecoverDeletedNotes *bool // Local
|
|
|
|
CanManageAvatarDecorations *bool // Local
|
|
|
|
CanManageAds *bool // Local
|
|
|
|
CanSendAnnouncements *bool // Local
|
2024-08-28 15:20:38 +00:00
|
|
|
}
|
2024-09-17 14:21:00 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
Mastodon permissions (highest permission to lowest):
|
|
|
|
- Admin
|
|
|
|
- Devops
|
|
|
|
- View Audit log
|
|
|
|
- View Dashboard
|
|
|
|
- Manage Reports
|
|
|
|
- Manage Federation
|
|
|
|
- Manage Settings
|
|
|
|
- Manage Blocks
|
|
|
|
- Manage Taxonomies
|
|
|
|
- Manage Appeals
|
|
|
|
- Manage Users
|
|
|
|
- Manage Invites
|
|
|
|
- Manage Rules
|
|
|
|
- Manage Announcements
|
|
|
|
- Manage Custom Emojis
|
|
|
|
- Manage Webhooks
|
|
|
|
- Invite Users
|
|
|
|
- Manage Roles
|
|
|
|
- Manage User Access
|
|
|
|
- Delete User Data
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
Misskey "permissions" (no order):
|
|
|
|
- Global timeline available (interact with global timeline I think)
|
|
|
|
- Local timeline available (same as global, but for local)
|
|
|
|
- b-something timeline available
|
|
|
|
- Can send public notes
|
|
|
|
- How many mentions a note can have
|
|
|
|
- Can invite others
|
|
|
|
- How many invites can be sent
|
|
|
|
- InviteLimitCycle (whatever that means)
|
|
|
|
- Invite Expiration time (duration of how long invites stay valid I think)
|
|
|
|
- Manage custom emojis
|
|
|
|
- Manage custom avatar decorations
|
|
|
|
- Seach for notes
|
|
|
|
- Use translator
|
|
|
|
- Hide ads from self
|
|
|
|
- How much storage space the user has
|
|
|
|
- Whether to mark all posts from account as nsfw
|
|
|
|
- max number of pinned messages
|
|
|
|
- max number of antennas
|
|
|
|
- max number of muted words
|
|
|
|
- max number of webhooks
|
|
|
|
- max number of clips
|
|
|
|
- max number of notes contained in a clip (? I think. Don't know enough about clips)
|
|
|
|
- Max number of lists of users
|
|
|
|
- max number of users in a user list
|
|
|
|
- rate limit multiplier
|
|
|
|
- max number of applied avatar decorations
|
|
|
|
*/
|
2024-09-17 15:11:55 +00:00
|
|
|
|
|
|
|
func (s *Storage) NewEmptyRole(name string) (*Role, error) {
|
2024-11-06 15:57:44 +00:00
|
|
|
defer util.Untrace(util.Trace(&log.Logger))
|
|
|
|
// Check if a role with the given name already exists
|
2024-09-17 15:11:55 +00:00
|
|
|
_, err := s.FindRoleByName(name)
|
|
|
|
switch err {
|
|
|
|
case nil:
|
|
|
|
return nil, ErrEntryAlreadyExists
|
|
|
|
case ErrEntryNotFound: // Empty case, since this is what we want
|
|
|
|
default:
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2024-11-04 15:25:39 +00:00
|
|
|
// New roles have a priority of 1 by default
|
|
|
|
newRole := Role{Name: name, Priority: 1}
|
2024-09-17 15:11:55 +00:00
|
|
|
err = s.db.Create(&newRole).Error
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return &newRole, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *Storage) FindRoleByName(name string) (*Role, error) {
|
2024-11-06 15:57:44 +00:00
|
|
|
defer util.Untrace(util.Trace(&log.Logger))
|
2024-09-17 15:11:55 +00:00
|
|
|
role := Role{}
|
|
|
|
err := s.db.Where("name = ?", name).First(&role).Error
|
|
|
|
switch err {
|
|
|
|
case nil:
|
|
|
|
return &role, nil
|
|
|
|
case gorm.ErrRecordNotFound:
|
|
|
|
return nil, ErrEntryNotFound
|
|
|
|
default:
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
2024-11-04 15:25:39 +00:00
|
|
|
|
|
|
|
func (s *Storage) FindRolesByNames(names []string) ([]Role, error) {
|
2024-11-06 15:57:44 +00:00
|
|
|
defer util.Untrace(util.Trace(&log.Logger))
|
2024-11-04 15:25:39 +00:00
|
|
|
roles := []Role{}
|
|
|
|
err := s.db.Where("name IN ?", names).Find(&roles).Error
|
|
|
|
switch err {
|
|
|
|
case nil:
|
|
|
|
return roles, nil
|
|
|
|
case gorm.ErrRecordNotFound:
|
|
|
|
return nil, ErrEntryNotFound
|
|
|
|
default:
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
2024-11-06 15:57:44 +00:00
|
|
|
|
|
|
|
func (s *Storage) UpdateRole(role *Role) error {
|
|
|
|
defer util.Untrace(util.Trace(&log.Logger))
|
|
|
|
return s.db.Save(role).Error
|
|
|
|
}
|
2024-11-07 09:45:02 +00:00
|
|
|
|
|
|
|
func (s *Storage) DeleteRoleByName(name string) error {
|
|
|
|
// Prevent deletion of built-in roles
|
|
|
|
if sliceutils.Contains(
|
|
|
|
sliceutils.Map(allDefaultRoles, func(t *Role) string { return t.Name }),
|
|
|
|
name,
|
|
|
|
) {
|
|
|
|
return ErrNotAllowed
|
|
|
|
}
|
|
|
|
defer util.Untrace(util.Trace(&log.Logger))
|
|
|
|
return s.db.Where(&Role{Name: name, IsBuiltIn: false}).Delete(&Role{}).Error
|
|
|
|
}
|