[feature] Implement Mastodon-compatible roles (#3136)

* Implement Mastodon-compatible roles

- `Account.role` should only be available through verify_credentials for checking current user's permissions
- `Account.role` now carries a Mastodon-compatible permissions bitmap and a marker for whether it should be shown to the public
- `Account.roles` added for *public* display roles (undocumented but stable since Mastodon 4.1)
- Web template now uses only public display roles (no user-visible change here, we already special-cased the `user` role)

* Handle verify_credentials case for default role

* Update JSON exact-match tests

* Address review comments

* Add blocks bit to admin permissions bitmap
This commit is contained in:
Vyr Cossont
2024-07-31 09:26:09 -07:00
committed by GitHub
parent 2f7d654380
commit fd837776e2
12 changed files with 765 additions and 209 deletions

View File

@@ -18,8 +18,11 @@
package model
import (
"encoding/json"
"errors"
"mime/multipart"
"net"
"strconv"
)
// Account models a fediverse account.
@@ -105,8 +108,13 @@ type Account struct {
// Key/value omitted if false.
HideCollections bool `json:"hide_collections,omitempty"`
// Role of the account on this instance.
// Only available through the `verify_credentials` API method.
// Key/value omitted for remote accounts.
Role *AccountRole `json:"role,omitempty"`
// Roles lists the public roles of the account on this instance.
// Unlike Role, this is always available, but never includes permissions details.
// Key/value omitted for remote accounts.
Roles []AccountDisplayRole `json:"roles,omitempty"`
// If set, indicates that this account is currently inactive, and has migrated to the given account.
// Key/value omitted for accounts that haven't moved, and for suspended accounts.
Moved *Account `json:"moved,omitempty"`
@@ -286,11 +294,35 @@ type AccountAliasRequest struct {
AlsoKnownAsURIs []string `form:"also_known_as_uris" json:"also_known_as_uris" xml:"also_known_as_uris"`
}
// AccountDisplayRole models a public, displayable role of an account.
// This is a subset of AccountRole.
//
// swagger:model accountDisplayRole
type AccountDisplayRole struct {
// ID of the role.
// Not used by GotoSocial, but we set it to the role name, just in case a client expects a unique ID.
ID string `json:"id"`
// Name of the role.
Name AccountRoleName `json:"name"`
// Color is a 6-digit CSS-style hex color code with leading `#`, or an empty string if this role has no color.
// Since GotoSocial doesn't use role colors, we leave this empty.
Color string `json:"color"`
}
// AccountRole models the role of an account.
//
// swagger:model accountRole
type AccountRole struct {
Name AccountRoleName `json:"name"`
AccountDisplayRole
// Permissions is a bitmap serialized as a numeric string, indicating which admin/moderation actions a user can perform.
Permissions AccountRolePermissions `json:"permissions"`
// Highlighted indicates whether the role is publicly visible on the user profile.
// This is always true for GotoSocial's built-in admin and moderator roles, and false otherwise.
Highlighted bool `json:"highlighted"`
}
// AccountRoleName represent the name of the role of an account.
@@ -305,6 +337,103 @@ const (
AccountRoleUnknown AccountRoleName = "" // We don't know / remote account
)
// AccountRolePermissions is a bitmap representing a set of user permissions.
// It's used for Mastodon API compatibility: internally, GotoSocial only tracks admins and moderators.
//
// swagger:type string
type AccountRolePermissions int
// MarshalJSON serializes an AccountRolePermissions as a numeric string.
func (a *AccountRolePermissions) MarshalJSON() ([]byte, error) {
return json.Marshal(strconv.Itoa(int(*a)))
}
// UnmarshalJSON deserializes an AccountRolePermissions from a number or numeric string.
func (a *AccountRolePermissions) UnmarshalJSON(b []byte) error {
if string(b) == "null" {
return nil
}
i := 0
if err := json.Unmarshal(b, &i); err != nil {
s := ""
if err := json.Unmarshal(b, &s); err != nil {
return errors.New("not a number or string")
}
i, err = strconv.Atoi(s)
if err != nil {
return errors.New("not a numeric string")
}
}
*a = AccountRolePermissions(i)
return nil
}
const (
// AccountRolePermissionsNone represents an empty set of permissions.
AccountRolePermissionsNone AccountRolePermissions = 0
// AccountRolePermissionsAdministrator ignores all permission checks.
AccountRolePermissionsAdministrator AccountRolePermissions = 1 << (iota - 1)
// AccountRolePermissionsDevops is not used by GotoSocial.
AccountRolePermissionsDevops
// AccountRolePermissionsViewAuditLog is not used by GotoSocial.
AccountRolePermissionsViewAuditLog
// AccountRolePermissionsViewDashboard is not used by GotoSocial.
AccountRolePermissionsViewDashboard
// AccountRolePermissionsManageReports indicates that the user can view and resolve reports.
AccountRolePermissionsManageReports
// AccountRolePermissionsManageFederation indicates that the user can edit federation allows and blocks.
AccountRolePermissionsManageFederation
// AccountRolePermissionsManageSettings indicates that the user can edit instance metadata.
AccountRolePermissionsManageSettings
// AccountRolePermissionsManageBlocks indicates that the user can manage non-federation blocks, currently including HTTP header blocks.
AccountRolePermissionsManageBlocks
// AccountRolePermissionsManageTaxonomies is not used by GotoSocial.
AccountRolePermissionsManageTaxonomies
// AccountRolePermissionsManageAppeals is not used by GotoSocial.
AccountRolePermissionsManageAppeals
// AccountRolePermissionsManageUsers indicates that the user can view user details and perform user moderation actions.
AccountRolePermissionsManageUsers
// AccountRolePermissionsManageInvites is not used by GotoSocial.
AccountRolePermissionsManageInvites
// AccountRolePermissionsManageRules indicates that the user can edit instance rules.
AccountRolePermissionsManageRules
// AccountRolePermissionsManageAnnouncements is not used by GotoSocial.
AccountRolePermissionsManageAnnouncements
// AccountRolePermissionsManageCustomEmojis indicates that the user can edit custom emoji.
AccountRolePermissionsManageCustomEmojis
// AccountRolePermissionsManageWebhooks is not used by GotoSocial.
AccountRolePermissionsManageWebhooks
// AccountRolePermissionsInviteUsers is not used by GotoSocial.
AccountRolePermissionsInviteUsers
// AccountRolePermissionsManageRoles is not used by GotoSocial.
AccountRolePermissionsManageRoles
// AccountRolePermissionsManageUserAccess is not used by GotoSocial.
AccountRolePermissionsManageUserAccess
// AccountRolePermissionsDeleteUserData indicates that the user can permanently delete user data.
AccountRolePermissionsDeleteUserData
// FUTURE: If we decide to assign our own permissions bits,
// they should start at the other end of the int to avoid conflicts with future Mastodon permissions.
// AccountRolePermissionsForAdminRole includes all of the permissions assigned to GotoSocial's built-in administrator role.
AccountRolePermissionsForAdminRole = AccountRolePermissionsAdministrator |
AccountRolePermissionsManageReports |
AccountRolePermissionsManageFederation |
AccountRolePermissionsManageSettings |
AccountRolePermissionsManageBlocks |
AccountRolePermissionsManageUsers |
AccountRolePermissionsManageRules |
AccountRolePermissionsManageCustomEmojis |
AccountRolePermissionsDeleteUserData
// AccountRolePermissionsForModeratorRole includes all of the permissions assigned to GotoSocial's built-in moderator role.
// (Currently, there aren't any.)
AccountRolePermissionsForModeratorRole = AccountRolePermissionsNone
)
// AccountNoteRequest models a request to update the private note for an account.
//
// swagger:ignore