Skip to content

Commit

Permalink
Merge pull request #9231 from hicommonwealth/rotorsoft/reorg-build-au…
Browse files Browse the repository at this point in the history
…th-waterfall

Restructures auth builder to prioritize comment and thread over community
  • Loading branch information
Rotorsoft authored Sep 17, 2024
2 parents 81f1869 + 5d8f25e commit 4a1bad3
Showing 1 changed file with 59 additions and 63 deletions.
122 changes: 59 additions & 63 deletions libs/model/src/middleware/authorization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,21 @@ export class RejectedMember extends InvalidActor {
/**
* Builds authorization context
*
* @param actor command actor
* @param payload command payload
* @param auth authorization context
* @param roles roles filter
* TODO: Keep developing this pattern for other entities!
* The idea is that authorized requests could include aggregate ids that should be pre-loaded
* and authorized by prefilling the authorization context.
*
* Currenlty, the waterfall is:
* 1. by comment_id
* 3. or by thread_id
* 2. or by community_id (community_id or id)
*
* TODO: Find ways to cache() by args to avoid db trips
*
* @param ctx execution context
* @param roles community roles filter when authorizing specific roles
* @param collaborators flag to include thread collaborators when preloading threads
* @returns authorization context
*/
async function buildAuth(
ctx: Context<ZodSchema, AuthContext>,
Expand All @@ -86,67 +97,52 @@ async function buildAuth(
if (!actor.address)
throw new InvalidActor(ctx.actor, 'Must provide an address');

/*
* Address authorization conventions: => TODO: keep developing this pattern and encapsulate
*
* The idea is that authorized requests must include an entity id that can be mapped to
* a community (community_id), and optionally a topic (topic_id) for gating auth middleware.
*
* TODO: More efficient to just context cache the loaded entities right here
* instead of just adding (caching) the ids in the payload (add to actor?)
*
* TODO: Find ways to cache() by args to avoid db trips
*
* 1. Find by community_id when payload contains community_id or id
* 2. Find by thread_id when payload contains thread_id
* 3. Find by comment_id when payload contains comment_id
*/
const auth: AuthContext = { address: null, is_author: false };
const { id, community_id, topic_id, thread_id, comment_id } = payload;
const auth: AuthContext = {
address: null,
is_author: false,
community_id: community_id || id,
topic_id,
thread_id,
comment_id,
};
(ctx as { auth: AuthContext }).auth = auth;

auth.community_id =
('community_id' in payload && payload.community_id) || payload.id;
auth.topic_id = 'topic_id' in payload && payload.topic_id;
if (!auth.community_id) {
auth.thread_id = 'thread_id' in payload && payload.thread_id;
if (!auth.thread_id) {
auth.comment_id = 'comment_id' in payload && payload.comment_id;
if (!auth.comment_id)
throw new InvalidInput('Must provide community, thread, or comment id');
auth.comment = await models.Comment.findOne({
where: { id: auth.comment_id },
include: [
{
model: models.Thread,
required: true,
},
],
});
if (!auth.comment)
throw new InvalidInput('Must provide a valid comment id');
auth.community_id = auth.comment.Thread!.community_id;
auth.topic_id = auth.comment.Thread!.topic_id;
auth.thread_id = auth.comment.Thread!.id;
auth.author_address_id = auth.comment.address_id;
} else {
const include = collaborators
? {
model: models.Address,
as: 'collaborators',
required: false,
}
: undefined;
auth.thread = await models.Thread.findOne({
where: { id: auth.thread_id },
include,
});
if (!auth.thread)
throw new InvalidInput('Must provide a valid thread id');
auth.community_id = auth.thread.community_id;
auth.topic_id = auth.thread.topic_id;
auth.author_address_id = auth.thread.address_id;
}
}
if (auth.comment_id) {
auth.comment = await models.Comment.findOne({
where: { id: auth.comment_id },
include: [
{
model: models.Thread,
required: true,
},
],
});
if (!auth.comment)
throw new InvalidInput('Must provide a valid comment id');
auth.community_id = auth.comment.Thread!.community_id;
auth.topic_id = auth.comment.Thread!.topic_id;
auth.thread_id = auth.comment.Thread!.id;
auth.author_address_id = auth.comment.address_id;
} else if (auth.thread_id) {
const include = collaborators
? {
model: models.Address,
as: 'collaborators',
required: false,
}
: undefined;
auth.thread = await models.Thread.findOne({
where: { id: auth.thread_id },
include,
});
if (!auth.thread) throw new InvalidInput('Must provide a valid thread id');
auth.community_id = auth.thread.community_id;
auth.topic_id = auth.thread.topic_id;
auth.author_address_id = auth.thread.address_id;
} else if (!auth.community_id)
throw new InvalidInput('Must provide a community id');

auth.address = await models.Address.findOne({
where: {
user_id: actor.user.id,
Expand Down

0 comments on commit 4a1bad3

Please sign in to comment.