2025-02-21 14:52:21 +00:00
|
|
|
package auth
|
|
|
|
|
2025-02-28 14:01:12 +00:00
|
|
|
import (
|
|
|
|
"git.mstar.dev/mstar/goutils/sliceutils"
|
|
|
|
"git.mstar.dev/mstar/linstrom/storage"
|
|
|
|
"github.com/rs/zerolog/log"
|
|
|
|
)
|
2025-02-21 14:52:21 +00:00
|
|
|
|
2025-02-28 14:01:12 +00:00
|
|
|
// Can actorId read the account with targetId?
|
|
|
|
func (a *Authentication) CanReadAccount(actorId *string, targetId string) bool {
|
|
|
|
targetAccount, err := a.store.FindAccountById(targetId)
|
|
|
|
if err != nil {
|
|
|
|
if err == storage.ErrEntryNotFound {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
log.Error().
|
|
|
|
Err(err).
|
|
|
|
Str("account-id", targetId).
|
|
|
|
Msg("Failed to receive account for permission check")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if actorId == nil {
|
|
|
|
// TODO: Decide if roles should have a field to declare an account as follow only/hidden
|
|
|
|
// and then check for that flag here
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
roles, err := a.store.FindRolesByNames(targetAccount.Roles)
|
|
|
|
if err != nil {
|
|
|
|
log.Error().
|
|
|
|
Err(err).
|
|
|
|
Strs("role-names", targetAccount.Roles).
|
|
|
|
Msg("Failed to get roles for target account")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
combined := storage.CollapseRolesIntoOne(roles...)
|
|
|
|
if sliceutils.Contains(combined.BlockedUsers, *actorId) {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
}
|
2025-02-21 14:52:21 +00:00
|
|
|
|
|
|
|
// Can actorId edit the account with targetId?
|
2025-02-28 14:01:12 +00:00
|
|
|
// If actorId is nil, it is assumed to be an anonymous user trying to edit the target account
|
|
|
|
// if targetId is nil, it is assumed that the actor is editing themselves
|
|
|
|
func (a *Authentication) CanEditAccount(actorId *string, targetId *string) bool {
|
|
|
|
// FIXME: This entire function feels wrong, idk
|
|
|
|
// Only the owner of an account should be able to edit said account's data
|
|
|
|
// But how do moderation actions play with this? Do they count as edit or as something separate?
|
|
|
|
if actorId == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if targetId == nil {
|
|
|
|
targetId = actorId
|
|
|
|
}
|
|
|
|
targetAccount, err := a.store.FindAccountById(*targetId)
|
|
|
|
if err != nil {
|
|
|
|
if err != storage.ErrEntryNotFound {
|
|
|
|
log.Error().
|
|
|
|
Err(err).
|
|
|
|
Str("target-id", *targetId).
|
|
|
|
Msg("Failed to receive account for permission checks")
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
if targetId == actorId {
|
|
|
|
targetRoles, err := a.store.FindRolesByNames(targetAccount.Roles)
|
|
|
|
if err != nil {
|
|
|
|
log.Error().
|
|
|
|
Err(err).
|
|
|
|
Strs("role-names", targetAccount.Roles).
|
|
|
|
Msg("Failed to get roles from storage")
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
combined := storage.CollapseRolesIntoOne(targetRoles...)
|
|
|
|
return *combined.CanLogin
|
|
|
|
} else {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
}
|
2025-02-21 14:52:21 +00:00
|
|
|
|
|
|
|
// Can actorId delete the account with targetId?
|
2025-02-28 14:01:12 +00:00
|
|
|
// If actorId is nil, it is assumed to be an anonymous user trying to delete the target account
|
|
|
|
// if targetId is nil, it is assumed that the actor is deleting themselves
|
|
|
|
func (a *Authentication) CanDeleteAccount(actorId *string, targetId *string) bool {
|
|
|
|
if actorId == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
acc, err := a.store.FindAccountById(*actorId)
|
|
|
|
if err != nil {
|
|
|
|
// TODO: Logging
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
roles, err := a.store.FindRolesByNames(acc.Roles)
|
|
|
|
if err != nil {
|
|
|
|
// TODO: Logging
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
collapsed := storage.CollapseRolesIntoOne(roles...)
|
|
|
|
if targetId == nil {
|
|
|
|
return *collapsed.CanLogin
|
|
|
|
} else {
|
|
|
|
return *collapsed.CanDeleteAccounts
|
|
|
|
}
|
|
|
|
}
|
2025-02-21 14:52:21 +00:00
|
|
|
|
|
|
|
// Can actorId create a new post at all?
|
|
|
|
// Specific restrictions regarding the content are not checked
|
|
|
|
func (a *Authentication) CanCreatePost(actorId string) bool { return true }
|
|
|
|
|
|
|
|
// Ensures that a given post conforms with all roles attached to the author account.
|
|
|
|
// Returns the conforming note (or nil of it can't be changed to conform)
|
|
|
|
// and whether the note was changed
|
|
|
|
func (a *Authentication) EnsureNoteConformsWithRoles(note *storage.Note) (*storage.Note, bool) {
|
|
|
|
return note, false
|
|
|
|
}
|
|
|
|
|
|
|
|
// Does the given note conform with the roles attached to the author account?
|
|
|
|
func (a *Authentication) DoesNoteConform(note *storage.Note) bool { return true }
|