Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion server/authToken/strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,13 @@ export const bearerStrategy = () => {
const { expiresAt, user } = authToken;

try {
await ensureUserIsCommunityAdmin({
const community = await ensureUserIsCommunityAdmin({
hostname: req.hostname,
user: user as UserWithPrivateFields,
});
if (community.id !== authToken.communityId) {
throw new ForbiddenError(new Error('Token is not for this community'));
}
} catch (e) {
return done(e, false, 'User is not an admin of this community');
}
Expand Down
10 changes: 10 additions & 0 deletions server/draftCheckpoint/api.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Router } from 'express';

import { Draft, Pub } from 'server/models';
import { getScope } from 'server/utils/queryHelpers';
import { wrap } from 'server/wrap';
import { expect } from 'utils/assert';

Expand Down Expand Up @@ -32,6 +33,15 @@ router.post(
return res.status(404).json({ error: 'Pub or draft not found' });
}

const { activePermissions } = await getScope({
communityId: pub.communityId,
pubId,
loginId: userId,
});
if (!activePermissions.canEdit && !activePermissions.canEditDraft) {
return res.status(403).json({});
}

const checkpoint = await upsertDraftCheckpoint(pub.draft.id, historyKey, doc, Date.now());

return res.status(200).json({ id: checkpoint.id });
Expand Down
33 changes: 17 additions & 16 deletions server/member/permissions.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,26 @@
import type { MemberPermission } from 'types';

import { NotFoundError } from 'server/utils/errors';
import { getMemberDataById, getScope } from 'server/utils/queryHelpers';
import { expect } from 'utils/assert';

/** The member's current level, provided they belong to the scope the request is for */
const getMemberPermission = async (scopeData, memberId?: string) => {
if (memberId) {
const {
elements: { activeIds, activeTargetType },
} = scopeData;
const member = expect(await getMemberDataById(memberId, false));
if (activeTargetType === 'community' && member.communityId === activeIds.communityId) {
return member.permissions;
}
if (activeTargetType === 'collection' && member.collectionId === activeIds.collectionId) {
return member.permissions;
}
if (activeTargetType === 'pub' && member.pubId === activeIds.pubId) {
return member.permissions;
}
if (!memberId) {
return false;
}
return false;
const {
elements: { activeIds, activeTargetType },
} = scopeData;
const member = await getMemberDataById(memberId, false);
const isInScope =
!!member &&
((activeTargetType === 'community' && member.communityId === activeIds.communityId) ||
(activeTargetType === 'collection' && member.collectionId === activeIds.collectionId) ||
(activeTargetType === 'pub' && member.pubId === activeIds.pubId));
if (!isInScope) {
throw new NotFoundError();
}
return member.permissions;
};

export const getPermissions = async ({
Expand Down
24 changes: 21 additions & 3 deletions server/pub/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,22 @@ import { getPubsById, queryPubIds } from './queryMany';

extendZodWithOpenApi(z);

/** The community admin the request is for, provided the pub belongs to that community */
const ensureUserIsAdminOfPubCommunity = async (
req: Parameters<typeof ensureUserIsCommunityAdmin>[0],
pubId: string,
) => {
const community = await ensureUserIsCommunityAdmin(req);
const pub = await Pub.findOne({
where: { id: pubId, communityId: community.id },
attributes: ['id'],
});
if (!pub) {
throw new NotFoundError();
}
return community;
};

type ManyRequestParams = {
query: Omit<types.PubsQuery, 'communityId'>;
alreadyFetchedPubIds: string[];
Expand Down Expand Up @@ -274,13 +290,15 @@ export const pubServer = s.router(contract.pub, {
return { status: 200, body: resource };
},
text: {
get: async ({ params }) => {
get: async ({ req, params }) => {
await ensureUserIsAdminOfPubCommunity(req, params.pubId);

const doc = await getPubDraftDoc(params.pubId);

return { status: 200, body: doc.doc };
},
update: async ({ req, params, body }) => {
await ensureUserIsCommunityAdmin(req);
await ensureUserIsAdminOfPubCommunity(req, params.pubId);

await writeDocumentToPubDraft(params.pubId, body.doc, { method: body.method });

Expand Down Expand Up @@ -350,7 +368,7 @@ export const pubServer = s.router(contract.pub, {
},
],
handler: async ({ req, body, files, params }) => {
await ensureUserIsCommunityAdmin(req);
await ensureUserIsAdminOfPubCommunity(req, params.pubId);

return handleImport({
// @ts-expect-error shh
Expand Down
Loading