More work on the api. Also auth middleware stuff

More work on the placeholder functions for the Linstrom API
Additionally, started work on a slightly more sophisticated
authentication control system
And ran `go generate` again
This commit is contained in:
Melody Becker 2024-10-31 16:53:42 +01:00
parent b9c95a0297
commit 873f52d64f
14 changed files with 637 additions and 300 deletions

View file

@ -12,30 +12,70 @@ func setupLinstromApiRouter() http.Handler {
func setupLinstromApiV1Router() http.Handler { func setupLinstromApiV1Router() http.Handler {
router := http.NewServeMux() router := http.NewServeMux()
// Notes // Notes
router.HandleFunc("GET /note/{noteId}", linstromGetNote) router.HandleFunc("GET /notes/{noteId}", linstromGetNote)
router.HandleFunc("POST /note", linstromNewNote) router.HandleFunc("POST /notes", linstromNewNote)
router.HandleFunc("PUT /note/{noteId}", linstromUpdateNote) router.HandleFunc("PATCH /notes/{noteId}", linstromUpdateNote)
router.HandleFunc("DELETE /note/{noteId}", linstromDeleteNote) router.HandleFunc("DELETE /notes/{noteId}", linstromDeleteNote)
// Reactions // Reactions
router.HandleFunc("GET /note/{noteId}/reactions", linstromGetReactions) router.HandleFunc("GET /notes/{noteId}/reactions", linstromGetReactions)
router.HandleFunc("POST /note/{noteId}/reactions", linstromAddReaction) router.HandleFunc("POST /notes/{noteId}/reactions", linstromAddReaction)
router.HandleFunc("PUT /note/{noteId}/reactions", linstromUpdateReaction) router.HandleFunc("PATCH /notes/{noteId}/reactions", linstromUpdateReaction)
router.HandleFunc("DELETE /note/{noteId}/reactions", linstromDeleteReaction) router.HandleFunc("DELETE /notes/{noteId}/reactions", linstromDeleteReaction)
// Boosts // Boosts
router.HandleFunc("GET /note/{noteId}/boosts", linstromGetBoosts) router.HandleFunc("GET /notes/{noteId}/boosts", linstromGetBoosts)
router.HandleFunc("POST /note/{noteId}/boosts", linstromAddBoost) router.HandleFunc("POST /notes/{noteId}/boosts", linstromAddBoost)
router.HandleFunc("DELETE /note/{noteId}/boosts", linstromRemoveBoost) router.HandleFunc("DELETE /notes/{noteId}/boosts", linstromRemoveBoost)
// Quotes // Quotes
router.HandleFunc("GET /note/{noteId}/quotes", linstromGetQuotes) router.HandleFunc("GET /notes/{noteId}/quotes", linstromGetQuotes)
router.HandleFunc("POST /note/{noteId}/quotes", linstromAddQuote) router.HandleFunc("POST /notes/{noteId}/quotes", linstromAddQuote)
// Pinning // Pinning
router.HandleFunc("POST /note/{noteId}/pin", linstromPinNote) router.HandleFunc("POST /notes/{noteId}/pin", linstromPinNote)
router.HandleFunc("DELETE /note/{noteId}/pin", linstromUnpinNote) router.HandleFunc("DELETE /notes/{noteId}/pin", linstromUnpinNote)
// Reports // Reports
router.HandleFunc("POST /note/{noteId}/report", linstromReportNote) router.HandleFunc("POST /notes/{noteId}/report", linstromReportNote)
router.HandleFunc("DELETE /note/{noteId}/report", linstromRetractReportNote) router.HandleFunc("DELETE /notes/{noteId}/report", linstromRetractReportNote)
// Admin // Admin
router.HandleFunc("POST /note/{noteId}/admin/cw", linstromForceCWNote) router.HandleFunc("POST /notes/{noteId}/admin/cw", linstromForceCWNote)
// Accounts
// Creating a new account happens either during fetch of a remote one or during registration with a passkey
router.HandleFunc("GET /accounts/{accountId}", linstromGetAccount)
router.HandleFunc("PATCH /accounts/{accountId}", linstromUpdateAccount)
router.HandleFunc("DELETE /accounts/{accountId}", linstromDeleteAccount)
// Follow
router.HandleFunc("GET /accounts/{accountId}/follow", linstromIsFollowingAccount)
router.HandleFunc("POST /accounts/{accountId}/follow", linstromFollowAccount)
router.HandleFunc("DELETE /accounts/{accountId}/follow", linstromUnfollowAccount)
// Block
router.HandleFunc("GET /accounts/{accountId}/block", linstromIsBlockingAccount)
router.HandleFunc("POST /accounts/{accountId}/block", linstromBlockAccount)
router.HandleFunc("DELETE /accounts/{accountId}/block", linstromUnblockAccount)
// Mute
router.HandleFunc("GET /accounts/{accountId}/mute", linstromIsMutedAccount)
router.HandleFunc("POST /accounts/{accountId}/mute", linstromMuteAccount)
router.HandleFunc("DELETE /accounts/{accountId}/mute", linstromUnmuteAccount)
// Report
router.HandleFunc("POST /accounts/{accountId}/reports", linstromReportAccount)
router.HandleFunc("DELETE /accounts/{accountId}/reports", linstromRetractReportAccount)
// Admin
router.HandleFunc("POST /accounts/{accountId}/admin/roles", linstromAdminAddRoleAccount)
router.HandleFunc(
"DELETE /accounts/{accountId}/admin/roles/{roleName}",
linstromAdminRemoveRoleAccount,
)
router.HandleFunc("POST /accounts/{accountId}/admin/warn", linstromAdminWarnAccount)
// Roles
router.HandleFunc("GET /roles/{roleId}", linstromGetRole)
router.HandleFunc("POST /roles", linstromCreateRole)
router.HandleFunc("PATCH /roles/{roleId}", linstromUpdateRole)
router.HandleFunc("DELETE /roles/{roleId}", linstromDeleteRole)
// Media metadata
router.HandleFunc("GET /media/{mediaId}", linstromGetMediaMetadata)
router.HandleFunc("POST /media", linstromNewMediaMetadata)
router.HandleFunc("PATCH /media/{mediaId}", linstromUpdateMediaMetadata)
router.HandleFunc("DELETE /media/{mediaId}", linstromDeleteMediaMetadata)
// Event streams // Event streams
router.HandleFunc("/streams", linstromEventStream) router.HandleFunc("/streams", linstromEventStream)

View file

@ -0,0 +1,41 @@
package server
import (
"net/http"
"github.com/rs/zerolog/hlog"
)
// No create account. That happens during passkey registration
// and remote accounts are getting created at fetch time
func linstromGetAccount(w http.ResponseWriter, r *http.Request) {
store := StorageFromRequest(r)
log := hlog.FromRequest(r)
}
func linstromUpdateAccount(w http.ResponseWriter, r *http.Request) {}
func linstromDeleteAccount(w http.ResponseWriter, r *http.Request) {}
func linstromIsFollowingAccount(w http.ResponseWriter, r *http.Request) {}
func linstromFollowAccount(w http.ResponseWriter, r *http.Request) {}
func linstromUnfollowAccount(w http.ResponseWriter, r *http.Request) {}
func linstromIsBlockingAccount(w http.ResponseWriter, r *http.Request) {}
func linstromBlockAccount(w http.ResponseWriter, r *http.Request) {}
func linstromUnblockAccount(w http.ResponseWriter, r *http.Request) {}
func linstromIsMutedAccount(w http.ResponseWriter, r *http.Request) {}
func linstromMuteAccount(w http.ResponseWriter, r *http.Request) {}
func linstromUnmuteAccount(w http.ResponseWriter, r *http.Request) {}
func linstromReportAccount(w http.ResponseWriter, r *http.Request) {}
func linstromRetractReportAccount(w http.ResponseWriter, r *http.Request) {}
func linstromAdminAddRoleAccount(w http.ResponseWriter, r *http.Request) {}
func linstromAdminRemoveRoleAccount(w http.ResponseWriter, r *http.Request) {}
func linstromAdminWarnAccount(w http.ResponseWriter, r *http.Request) {}
func linstromGetRole(w http.ResponseWriter, r *http.Request) {}
func linstromCreateRole(w http.ResponseWriter, r *http.Request) {}
func linstromUpdateRole(w http.ResponseWriter, r *http.Request) {}
func linstromDeleteRole(w http.ResponseWriter, r *http.Request) {}

View file

@ -0,0 +1,8 @@
package server
import "net/http"
func linstromGetMediaMetadata(w http.ResponseWriter, r *http.Request) {}
func linstromNewMediaMetadata(w http.ResponseWriter, r *http.Request) {}
func linstromUpdateMediaMetadata(w http.ResponseWriter, r *http.Request) {}
func linstromDeleteMediaMetadata(w http.ResponseWriter, r *http.Request) {}

View file

@ -9,6 +9,8 @@ func linstromGetNote(w http.ResponseWriter, r *http.Request) {
store := StorageFromRequest(r) store := StorageFromRequest(r)
noteId := NoteIdFromRequest(r) noteId := NoteIdFromRequest(r)
note, err := store.FindNoteById(noteId) note, err := store.FindNoteById(noteId)
_ = note
_ = err
} }
func linstromUpdateNote(w http.ResponseWriter, r *http.Request) {} func linstromUpdateNote(w http.ResponseWriter, r *http.Request) {}
func linstromNewNote(w http.ResponseWriter, r *http.Request) {} func linstromNewNote(w http.ResponseWriter, r *http.Request) {}

View file

@ -4,6 +4,15 @@ package server
import "time" import "time"
var (
_ = linstromNote{}
_ = linstromOriginServer{}
_ = linstromMediaMetadata{}
_ = linstromAccount{}
_ = linstromCustomAccountField{}
_ = linstromRole{}
)
type linstromNote struct { type linstromNote struct {
Id string `jsonapi:"primary,notes"` Id string `jsonapi:"primary,notes"`
RawContent string `jsonapi:"attr,content"` RawContent string `jsonapi:"attr,content"`
@ -29,7 +38,7 @@ type linstromOriginServer struct {
Id int `jsonapi:"primary,origins"` Id int `jsonapi:"primary,origins"`
CreatedAt time.Time `jsonapi:"attr,created_at"` CreatedAt time.Time `jsonapi:"attr,created_at"`
UpdatedAt *time.Time `jsonapi:"attr,updated_at,omitempty"` UpdatedAt *time.Time `jsonapi:"attr,updated_at,omitempty"`
ServerType string `jsonapi:"attr,server_type"` // one of "Linstrom", "" ServerType string `jsonapi:"attr,server_type"` // one of "Linstrom", "Mastodon", "Plemora", "Misskey" or "Wafrn"
Domain string `jsonapi:"attr,domain"` Domain string `jsonapi:"attr,domain"`
DisplayName string `jsonapi:"attr,display_name"` DisplayName string `jsonapi:"attr,display_name"`
Icon *linstromMediaMetadata `jsonapi:"relation,icon"` Icon *linstromMediaMetadata `jsonapi:"relation,icon"`
@ -68,10 +77,11 @@ type linstromAccount struct {
RestrictedFollow bool `jsonapi:"attr,restricted_follow"` RestrictedFollow bool `jsonapi:"attr,restricted_follow"`
IdentifiesAs []string `jsonapi:"attr,identifies_as"` IdentifiesAs []string `jsonapi:"attr,identifies_as"`
Pronouns []string `jsonapi:"attr,pronouns"` Pronouns []string `jsonapi:"attr,pronouns"`
Roles []string `jsonapi:"attr,roles"`
} }
type linstromCustomAccountField struct { type linstromCustomAccountField struct {
Id uint Id uint `jsonapi:"primary,custom_account_fields"`
CreatedAt time.Time `jsonapi:"attr,created_at"` CreatedAt time.Time `jsonapi:"attr,created_at"`
UpdatedAt *time.Time `jsonapi:"attr,updated_at,omitempty"` UpdatedAt *time.Time `jsonapi:"attr,updated_at,omitempty"`
Key string `jsonapi:"attr,key"` Key string `jsonapi:"attr,key"`
@ -79,3 +89,86 @@ type linstromCustomAccountField struct {
Verified *bool `jsonapi:"attr,verified,omitempty"` Verified *bool `jsonapi:"attr,verified,omitempty"`
BelongsToId string `jsonapi:"attr,belongs_to_id"` BelongsToId string `jsonapi:"attr,belongs_to_id"`
} }
// Role is essentially just a carbon copy of storage/roles.go
type linstromRole struct {
Id uint `jsonapi:"primary,roles"`
CreatedAt time.Time `jsonapi:"attr,created_at"`
UpdatedAt *time.Time `jsonapi:"attr,updated_at,omitempty"`
// Name of the role
Name string `jsonapi:"attr,name"`
// 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
Priority uint `jsonapi:"attr,priority"`
// 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 `jsonapi:"attr,is_user_role"`
// Whether this role is one built into Linstrom from the start or not
// Note: Built-in roles can't be modified
IsBuiltIn bool `jsonapi:"attr,is_builtin"`
// --- User permissions ---
CanSendMedia *bool `jsonapi:"attr,can_send_media"`
CanSendCustomEmotes *bool `jsonapi:"attr,can_send_custom_emotes"`
CanSendCustomReactions *bool `jsonapi:"attr,can_send_custom_reactions"`
CanSendPublicNotes *bool `jsonapi:"attr,can_send_public_notes"`
CanSendLocalNotes *bool `jsonapi:"attr,can_send_local_notes"`
CanSendFollowerOnlyNotes *bool `jsonapi:"attr,can_send_follower_only_notes"`
CanSendPrivateNotes *bool `jsonapi:"attr,can_send_private_notes"`
CanSendReplies *bool `jsonapi:"attr,can_send_replies"`
CanQuote *bool `jsonapi:"attr,can_quote"`
CanBoost *bool `jsonapi:"attr,can_boost"`
CanIncludeLinks *bool `jsonapi:"attr,can_include_links"`
CanIncludeSurvey *bool `jsonapi:"attr,can_include_survey"`
CanChangeDisplayName *bool `jsonapi:"attr,can_change_display_name"`
BlockedUsers []string `jsonapi:"attr,blocked_users"`
CanSubmitReports *bool `jsonapi:"attr,can_submit_reports"`
CanLogin *bool `jsonapi:"attr,can_login"`
CanMentionOthers *bool `jsonapi:"attr,can_mention_others"`
HasMentionCountLimit *bool `jsonapi:"attr,has_mention_count_limit"`
MentionLimit *uint32 `jsonapi:"attr,mention_count_limit"`
// CanViewBoosts *bool
// CanViewQuotes *bool
// CanViewMedia *bool
// CanViewCustomEmotes *bool
// --- Automod ---
AutoNsfwMedia *bool `jsonapi:"attr,auto_nsfw_media"`
AutoCwPosts *bool `jsonapi:"attr,auto_cw_posts"`
AutoCwPostsText *string `jsonapi:"attr,auto_cw_posts_text"`
ScanCreatedPublicNotes *bool `jsonapi:"attr,scan_created_public_notes"`
ScanCreatedLocalNotes *bool `jsonapi:"attr,scan_created_local_notes"`
ScanCreatedFollowerOnlyNotes *bool `jsonapi:"attr,scan_created_follower_only_notes"`
ScanCreatedPrivateNotes *bool `jsonapi:"attr,scan_created_private_notes"`
DisallowInteractionsWith []string `jsonapi:"attr,disallow_interactions_with"`
WithholdNotesForManualApproval *bool `jsonapi:"attr,withhold_notes_for_manual_approval"`
WithholdNotesBasedOnRegex *bool `jsonapi:"attr,withhold_notes_based_on_regex"`
WithholdNotesRegexes []string `jsonapi:"attr,withhold_notes_regexes"`
// --- Admin perms ---
// If set, counts as all permissions being set as given and all restrictions being disabled
FullAdmin *bool `jsonapi:"attr,full_admin"`
CanAffectOtherAdmins *bool `jsonapi:"attr,can_affect_other_admins"`
CanDeleteNotes *bool `jsonapi:"attr,can_delete_notes"`
CanConfirmWithheldNotes *bool `jsonapi:"attr,can_confirm_withheld_notes"`
CanAssignRoles *bool `jsonapi:"attr,can_assign_roles"`
CanSupressInteractionsBetweenUsers *bool `jsonapi:"attr,can_supress_interactions_between_users"`
CanOverwriteDisplayNames *bool `jsonapi:"attr,can_overwrite_display_names"`
CanManageCustomEmotes *bool `jsonapi:"attr,can_manage_custom_emotes"`
CanViewDeletedNotes *bool `jsonapi:"attr,can_view_deleted_notes"`
CanRecoverDeletedNotes *bool `jsonapi:"attr,can_recover_deleted_notes"`
CanManageAvatarDecorations *bool `jsonapi:"attr,can_manage_avatar_decorations"`
CanManageAds *bool `jsonapi:"attr,can_manage_ads"`
CanSendAnnouncements *bool `jsonapi:"attr,can_send_announcements"`
}

View file

@ -8,11 +8,12 @@ func setupApiRouter() http.Handler {
router.Handle("/linstrom/", setupLinstromApiRouter()) router.Handle("/linstrom/", setupLinstromApiRouter())
// Section MastoApi // Section MastoApi
// First segment are endpoints that will need to be moved to primary router since at top route
router.HandleFunc("GET /oauth/authorize", placeholderEndpoint) router.HandleFunc("GET /oauth/authorize", placeholderEndpoint)
router.HandleFunc("POST /oauth/token", placeholderEndpoint) router.HandleFunc("POST /oauth/token", placeholderEndpoint)
router.HandleFunc("POST /oauth/revoke", placeholderEndpoint) router.HandleFunc("POST /oauth/revoke", placeholderEndpoint)
router.HandleFunc("GET /.well-known/oauth-authorization-server", placeholderEndpoint) router.HandleFunc("GET /.well-known/oauth-authorization-server", placeholderEndpoint)
// These ones are actually mounted under /api/
router.HandleFunc("POST /v1/apps", placeholderEndpoint) router.HandleFunc("POST /v1/apps", placeholderEndpoint)
router.HandleFunc("GET /v1/apps/verify_credentials", placeholderEndpoint) router.HandleFunc("GET /v1/apps/verify_credentials", placeholderEndpoint)
router.HandleFunc("POST /v1/emails/confirmations", placeholderEndpoint) router.HandleFunc("POST /v1/emails/confirmations", placeholderEndpoint)

View file

@ -51,7 +51,7 @@ func fuckWithRegisterRequest(
) { ) {
log := hlog.FromRequest(r) log := hlog.FromRequest(r)
log.Debug().Msg("Messing with register start request") log.Debug().Msg("Messing with register start request")
store := StorageFromRequest(w, r) store := StorageFromRequest(r)
if store == nil { if store == nil {
return return
} }
@ -147,7 +147,7 @@ func fuckWithLoginRequest(
) { ) {
log := hlog.FromRequest(r) log := hlog.FromRequest(r)
log.Debug().Msg("Messing with login start request") log.Debug().Msg("Messing with login start request")
store := StorageFromRequest(w, r) store := StorageFromRequest(r)
if store == nil { if store == nil {
return return
} }

View file

@ -60,7 +60,7 @@ func LoggingMiddleware(handler http.Handler) http.Handler {
func passkeyIdToAccountIdTransformerMiddleware(handler http.Handler) http.Handler { func passkeyIdToAccountIdTransformerMiddleware(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
s := StorageFromRequest(w, r) s := StorageFromRequest(r)
if s == nil { if s == nil {
return return
} }
@ -100,3 +100,55 @@ func profilingAuthenticationMiddleware(handler http.Handler) http.Handler {
handler.ServeHTTP(w, r) handler.ServeHTTP(w, r)
}) })
} }
// Middleware for inserting a logged in account's id into the request context if a session exists
// Does not cancel requests ever. If an error occurs, it's treated as if no session is set
func checkSessionMiddleware(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie("sid")
log := hlog.FromRequest(r)
if err != nil {
// No cookie is ok, this function is only for inserting account id into the context
// if one exists, not for checking permissions
log.Debug().Msg("No session cookie, passing along")
handler.ServeHTTP(w, r)
return
}
store := StorageFromRequest(r)
session, ok := store.GetSession(cookie.Value)
if !ok {
// Failed to get session from cookie id. Log, then move on as if no session is set
log.Warn().
Str("session-id", cookie.Value).
Msg("Cookie with session id found, but session doesn't exist")
handler.ServeHTTP(w, r)
return
}
if session.Expires.Before(time.Now()) {
// Session expired. Move on as if no session was set
store.DeleteSession(cookie.Value)
handler.ServeHTTP(w, r)
return
}
acc, err := store.FindAccountByPasskeyId(session.UserID)
if err != nil {
// Failed to get account for passkey id. Log, then move on as if no session is set
log.Error().
Err(err).
Bytes("passkey-id", session.UserID).
Msg("Failed to get account with passkey id while checking session. Ignoring session")
handler.ServeHTTP(w, r)
return
}
handler.ServeHTTP(
w,
r.WithContext(
context.WithValue(
r.Context(),
ContextKeyActorId,
acc.ID,
),
),
)
})
}

View file

@ -30,3 +30,7 @@ func StorageFromRequest(r *http.Request) *storage.Storage {
func NoteIdFromRequest(r *http.Request) string { func NoteIdFromRequest(r *http.Request) string {
return r.PathValue("noteId") return r.PathValue("noteId")
} }
func AccountIdFromRequest(r *http.Request) string {
return r.PathValue("accountId")
}

View file

@ -7,7 +7,7 @@ import (
// For pretty printing during debug // For pretty printing during debug
// If `go generate` is run, it'll generate the necessary function and data for pretty printing // If `go generate` is run, it'll generate the necessary function and data for pretty printing
//go:generate stringer -type NoteTarget //go:generate stringer -type NoteAccessLevel
// What feed a note is targeting (public, home, followers or dm) // What feed a note is targeting (public, home, followers or dm)
type NoteAccessLevel uint8 type NoteAccessLevel uint8

View file

@ -1,4 +1,4 @@
// Code generated by "stringer -type NoteTarget"; DO NOT EDIT. // Code generated by "stringer -type NoteAccessLevel"; DO NOT EDIT.
package storage package storage
@ -15,23 +15,23 @@ func _() {
} }
const ( const (
_NoteTarget_name_0 = "NOTE_TARGET_PUBLIC" _NoteAccessLevel_name_0 = "NOTE_TARGET_PUBLIC"
_NoteTarget_name_1 = "NOTE_TARGET_HOME" _NoteAccessLevel_name_1 = "NOTE_TARGET_HOME"
_NoteTarget_name_2 = "NOTE_TARGET_FOLLOWERS" _NoteAccessLevel_name_2 = "NOTE_TARGET_FOLLOWERS"
_NoteTarget_name_3 = "NOTE_TARGET_DM" _NoteAccessLevel_name_3 = "NOTE_TARGET_DM"
) )
func (i NoteAccessLevel) String() string { func (i NoteAccessLevel) String() string {
switch { switch {
case i == 0: case i == 0:
return _NoteTarget_name_0 return _NoteAccessLevel_name_0
case i == 2: case i == 2:
return _NoteTarget_name_1 return _NoteAccessLevel_name_1
case i == 4: case i == 4:
return _NoteTarget_name_2 return _NoteAccessLevel_name_2
case i == 8: case i == 8:
return _NoteTarget_name_3 return _NoteAccessLevel_name_3
default: default:
return "NoteTarget(" + strconv.FormatInt(int64(i), 10) + ")" return "NoteAccessLevel(" + strconv.FormatInt(int64(i), 10) + ")"
} }
} }

View file

@ -51,6 +51,8 @@ type Role struct {
CanBoost *bool CanBoost *bool
CanIncludeLinks *bool CanIncludeLinks *bool
CanIncludeSurvey *bool CanIncludeSurvey *bool
CanFederateFedi *bool
CanFederateBsky *bool
CanChangeDisplayName *bool CanChangeDisplayName *bool
@ -75,7 +77,12 @@ type Role struct {
ScanCreatedLocalNotes *bool ScanCreatedLocalNotes *bool
ScanCreatedFollowerOnlyNotes *bool ScanCreatedFollowerOnlyNotes *bool
ScanCreatedPrivateNotes *bool ScanCreatedPrivateNotes *bool
DisallowInteractionsWith []string `gorm:"type:bytes;serializer:gob"` // 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
DisallowInteractionsWith []string `gorm:"type:bytes;serializer:gob"`
WithholdNotesForManualApproval *bool WithholdNotesForManualApproval *bool
WithholdNotesBasedOnRegex *bool WithholdNotesBasedOnRegex *bool

View file

@ -6,6 +6,8 @@ import (
"gitlab.com/mstarongitlab/goutils/other" "gitlab.com/mstarongitlab/goutils/other"
) )
// Default role every user has. Defines sane defaults for a normal user
// Will get overwritten by just about every other role due to every other role having higher priority
var DefaultUserRole = Role{ var DefaultUserRole = Role{
Name: "Default", Name: "Default",
Priority: 0, Priority: 0,
@ -19,10 +21,13 @@ var DefaultUserRole = Role{
CanSendLocalNotes: other.IntoPointer(true), CanSendLocalNotes: other.IntoPointer(true),
CanSendFollowerOnlyNotes: other.IntoPointer(true), CanSendFollowerOnlyNotes: other.IntoPointer(true),
CanSendPrivateNotes: other.IntoPointer(true), CanSendPrivateNotes: other.IntoPointer(true),
CanSendReplies: other.IntoPointer(true),
CanQuote: other.IntoPointer(true), CanQuote: other.IntoPointer(true),
CanBoost: other.IntoPointer(true), CanBoost: other.IntoPointer(true),
CanIncludeLinks: other.IntoPointer(true), CanIncludeLinks: other.IntoPointer(true),
CanIncludeSurvey: other.IntoPointer(true), CanIncludeSurvey: other.IntoPointer(true),
CanFederateFedi: other.IntoPointer(true),
CanFederateBsky: other.IntoPointer(true),
CanChangeDisplayName: other.IntoPointer(true), CanChangeDisplayName: other.IntoPointer(true),
@ -32,7 +37,9 @@ var DefaultUserRole = Role{
CanMentionOthers: other.IntoPointer(true), CanMentionOthers: other.IntoPointer(true),
HasMentionCountLimit: other.IntoPointer(false), HasMentionCountLimit: other.IntoPointer(false),
MentionLimit: other.IntoPointer(uint32(math.MaxUint32)), // Set this to max, even if not used due to *HasMentionCountLimit == false MentionLimit: other.IntoPointer(
uint32(math.MaxUint32),
), // Set this to max, even if not used due to *HasMentionCountLimit == false
AutoNsfwMedia: other.IntoPointer(false), AutoNsfwMedia: other.IntoPointer(false),
AutoCwPosts: other.IntoPointer(false), AutoCwPosts: other.IntoPointer(false),
@ -59,7 +66,8 @@ var DefaultUserRole = Role{
CanSendAnnouncements: other.IntoPointer(false), CanSendAnnouncements: other.IntoPointer(false),
} }
var fullAdminRole = Role{ // Role providing maximum permissions
var FullAdminRole = Role{
Name: "fullAdmin", Name: "fullAdmin",
Priority: math.MaxUint, Priority: math.MaxUint,
IsUserRole: false, IsUserRole: false,
@ -85,7 +93,9 @@ var fullAdminRole = Role{
CanMentionOthers: other.IntoPointer(true), CanMentionOthers: other.IntoPointer(true),
HasMentionCountLimit: other.IntoPointer(false), HasMentionCountLimit: other.IntoPointer(false),
MentionLimit: other.IntoPointer(uint32(math.MaxUint32)), // Set this to max, even if not used due to *HasMentionCountLimit == false MentionLimit: other.IntoPointer(
uint32(math.MaxUint32),
), // Set this to max, even if not used due to *HasMentionCountLimit == false
AutoNsfwMedia: other.IntoPointer(false), AutoNsfwMedia: other.IntoPointer(false),
AutoCwPosts: other.IntoPointer(false), AutoCwPosts: other.IntoPointer(false),
@ -112,7 +122,67 @@ var fullAdminRole = Role{
CanSendAnnouncements: other.IntoPointer(true), CanSendAnnouncements: other.IntoPointer(true),
} }
// Role for totally freezing an account, blocking all activity from it
var AccountFreezeRole = Role{
Name: "accountFreeze",
Priority: math.MaxUint - 1,
IsUserRole: false,
IsBuiltIn: true,
CanSendMedia: other.IntoPointer(false),
CanSendCustomEmotes: other.IntoPointer(false),
CanSendCustomReactions: other.IntoPointer(false),
CanSendPublicNotes: other.IntoPointer(false),
CanSendLocalNotes: other.IntoPointer(false),
CanSendFollowerOnlyNotes: other.IntoPointer(false),
CanSendPrivateNotes: other.IntoPointer(false),
CanSendReplies: other.IntoPointer(false),
CanQuote: other.IntoPointer(false),
CanBoost: other.IntoPointer(false),
CanIncludeLinks: other.IntoPointer(false),
CanIncludeSurvey: other.IntoPointer(false),
CanFederateBsky: other.IntoPointer(false),
CanFederateFedi: other.IntoPointer(false),
CanChangeDisplayName: other.IntoPointer(false),
BlockedUsers: []string{},
CanSubmitReports: other.IntoPointer(false),
CanLogin: other.IntoPointer(false),
CanMentionOthers: other.IntoPointer(false),
HasMentionCountLimit: other.IntoPointer(false),
MentionLimit: other.IntoPointer(
uint32(math.MaxUint32),
), // Set this to max, even if not used due to *HasMentionCountLimit == false
AutoNsfwMedia: other.IntoPointer(true),
AutoCwPosts: other.IntoPointer(false),
AutoCwPostsText: other.IntoPointer("Account frozen"),
WithholdNotesForManualApproval: other.IntoPointer(true),
ScanCreatedPublicNotes: other.IntoPointer(false),
ScanCreatedLocalNotes: other.IntoPointer(false),
ScanCreatedFollowerOnlyNotes: other.IntoPointer(false),
ScanCreatedPrivateNotes: other.IntoPointer(false),
DisallowInteractionsWith: []string{},
FullAdmin: other.IntoPointer(false),
CanAffectOtherAdmins: other.IntoPointer(false),
CanDeleteNotes: other.IntoPointer(false),
CanConfirmWithheldNotes: other.IntoPointer(false),
CanAssignRoles: other.IntoPointer(false),
CanSupressInteractionsBetweenUsers: other.IntoPointer(false),
CanOverwriteDisplayNames: other.IntoPointer(false),
CanManageCustomEmotes: other.IntoPointer(false),
CanViewDeletedNotes: other.IntoPointer(false),
CanRecoverDeletedNotes: other.IntoPointer(false),
CanManageAvatarDecorations: other.IntoPointer(false),
CanManageAds: other.IntoPointer(false),
CanSendAnnouncements: other.IntoPointer(false),
}
var allDefaultRoles = []*Role{ var allDefaultRoles = []*Role{
&DefaultUserRole, &DefaultUserRole,
&fullAdminRole, &FullAdminRole,
&AccountFreezeRole,
} }

File diff suppressed because one or more lines are too long