bleh
More API stuff. Lots of bleh. Really boring Also need to figure out a somewhat generic way for "requires ownership" permission and then a combinator for permissions
This commit is contained in:
parent
ffe3cf32ae
commit
1bb6cd8a70
8 changed files with 438 additions and 300 deletions
|
@ -40,8 +40,18 @@ func setupLinstromApiV1Router() http.Handler {
|
|||
// 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)
|
||||
// Technically also requires authenticated account to also be owner or correct admin perms,
|
||||
// but that's annoying to handle in a general sense. So leaving that to the function
|
||||
router.HandleFunc(
|
||||
"PATCH /accounts/{accountId}",
|
||||
requireValidSessionMiddleware(linstromUpdateAccount),
|
||||
)
|
||||
// Technically also requires authenticated account to also be owner or correct admin perms,
|
||||
// but that's annoying to handle in a general sense. So leaving that to the function
|
||||
router.HandleFunc(
|
||||
"DELETE /accounts/{accountId}",
|
||||
requireValidSessionMiddleware(linstromDeleteAccount),
|
||||
)
|
||||
// Follow
|
||||
router.HandleFunc("GET /accounts/{accountId}/follow", linstromIsFollowingAccount)
|
||||
router.HandleFunc("POST /accounts/{accountId}/follow", linstromFollowAccount)
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/google/jsonapi"
|
||||
"github.com/rs/zerolog/hlog"
|
||||
"gitlab.com/mstarongitlab/goutils/other"
|
||||
"gitlab.com/mstarongitlab/goutils/sliceutils"
|
||||
"gitlab.com/mstarongitlab/linstrom/storage"
|
||||
)
|
||||
|
||||
|
@ -14,6 +15,7 @@ import (
|
|||
func linstromGetAccount(w http.ResponseWriter, r *http.Request) {
|
||||
store := StorageFromRequest(r)
|
||||
log := hlog.FromRequest(r)
|
||||
|
||||
accId := AccountIdFromRequest(r)
|
||||
acc, err := store.FindAccountById(accId)
|
||||
switch err {
|
||||
|
@ -32,7 +34,30 @@ func linstromGetAccount(w http.ResponseWriter, r *http.Request) {
|
|||
)
|
||||
return
|
||||
}
|
||||
// TODO: Check if caller is actually allowed to view the account requested.
|
||||
actorId, ok := r.Context().Value(ContextKeyActorId).(string)
|
||||
if ok {
|
||||
// Logged in user is accessing account, check if target account has them blocked
|
||||
roles, err := store.FindRolesByNames(acc.Roles)
|
||||
if err != nil {
|
||||
log.Error().
|
||||
Err(err).
|
||||
Strs("role-names", acc.Roles).
|
||||
Msg("Failed to get roles from storage")
|
||||
other.HttpErr(
|
||||
w,
|
||||
HttpErrIdDbFailure,
|
||||
"Failed to get roles of target account",
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
return
|
||||
}
|
||||
collapsedRole := storage.CollapseRolesIntoOne(roles...)
|
||||
if sliceutils.Contains(collapsedRole.BlockedUsers, actorId) {
|
||||
// Actor account is in list of blocked accounts, deny access
|
||||
other.HttpErr(w, HttpErrIdNotAuthenticated, "Access forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
outAccount, err := convertAccountStorageToLinstrom(acc, store)
|
||||
if err != nil {
|
||||
|
@ -53,7 +78,10 @@ func linstromGetAccount(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
func linstromUpdateAccount(w http.ResponseWriter, r *http.Request) {}
|
||||
func linstromUpdateAccount(w http.ResponseWriter, r *http.Request) {
|
||||
store := StorageFromRequest(r)
|
||||
log := hlog.FromRequest(r)
|
||||
}
|
||||
func linstromDeleteAccount(w http.ResponseWriter, r *http.Request) {}
|
||||
|
||||
func linstromIsFollowingAccount(w http.ResponseWriter, r *http.Request) {}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/rs/zerolog/log"
|
||||
"gitlab.com/mstarongitlab/goutils/other"
|
||||
"gitlab.com/mstarongitlab/linstrom/config"
|
||||
"gitlab.com/mstarongitlab/linstrom/storage"
|
||||
)
|
||||
|
||||
type HandlerBuilder func(http.Handler) http.Handler
|
||||
|
@ -152,3 +153,78 @@ func checkSessionMiddleware(handler http.Handler) http.Handler {
|
|||
)
|
||||
})
|
||||
}
|
||||
|
||||
func requireValidSessionMiddleware(
|
||||
h func(http.ResponseWriter, *http.Request),
|
||||
) func(http.ResponseWriter, *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
_, ok := r.Context().Value(ContextKeyActorId).(string)
|
||||
if !ok {
|
||||
other.HttpErr(
|
||||
w,
|
||||
HttpErrIdNotAuthenticated,
|
||||
"Not authenticated",
|
||||
http.StatusUnauthorized,
|
||||
)
|
||||
return
|
||||
}
|
||||
h(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func buildRequirePermissionsMiddleware(permissionRole *storage.Role) HandlerBuilder {
|
||||
return func(h http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
accId, ok := r.Context().Value(ContextKeyActorId).(string)
|
||||
if !ok {
|
||||
other.HttpErr(
|
||||
w,
|
||||
HttpErrIdNotAuthenticated,
|
||||
"Not authenticated",
|
||||
http.StatusUnauthorized,
|
||||
)
|
||||
return
|
||||
}
|
||||
store := StorageFromRequest(r)
|
||||
log := hlog.FromRequest(r)
|
||||
acc, err := store.FindAccountById(accId)
|
||||
// Assumption: If this handler is hit, the middleware for checking if a session exists at all has already passed
|
||||
// and thus a valid account id must exist in the context
|
||||
if err != nil {
|
||||
log.Error().
|
||||
Err(err).
|
||||
Str("account-id", accId).
|
||||
Msg("Error while getting account from session")
|
||||
other.HttpErr(
|
||||
w,
|
||||
HttpErrIdDbFailure,
|
||||
"Error while getting account from session",
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
return
|
||||
}
|
||||
roles, err := store.FindRolesByNames(acc.Roles)
|
||||
// Assumption: There will always be at least two roles per user, default user and user-specific one
|
||||
if err != nil {
|
||||
other.HttpErr(
|
||||
w,
|
||||
HttpErrIdDbFailure,
|
||||
"Failed to get roles for account",
|
||||
http.StatusInternalServerError,
|
||||
)
|
||||
return
|
||||
}
|
||||
collapsedRole := storage.CollapseRolesIntoOne(roles...)
|
||||
if !storage.CompareRoles(&collapsedRole, permissionRole) {
|
||||
other.HttpErr(
|
||||
w,
|
||||
HttpErrIdNotAuthenticated,
|
||||
"Insufficient permisions",
|
||||
http.StatusForbidden,
|
||||
)
|
||||
return
|
||||
}
|
||||
h.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ func buildRootHandler(pkey *passkey.Passkey, reactiveFS, staticFS fs.FS) http.Ha
|
|||
mux.Handle("/", setupFrontendRouter(reactiveFS, staticFS))
|
||||
mux.Handle("/pk/", http.StripPrefix("/pk", http.FileServer(http.Dir("pk-auth"))))
|
||||
mux.HandleFunc("/alive", isAliveHandler)
|
||||
mux.Handle("/api/", http.StripPrefix("/api", setupApiRouter()))
|
||||
mux.Handle("/api/", http.StripPrefix("/api", checkSessionMiddleware(setupApiRouter())))
|
||||
|
||||
mux.Handle(
|
||||
"/profiling/",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue