Skip to content

Commit

Permalink
Add permission checks for delegates and authors
Browse files Browse the repository at this point in the history
  • Loading branch information
sebastinez committed Nov 20, 2023
1 parent 181fcc1 commit 6828b77
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 16 deletions.
13 changes: 9 additions & 4 deletions src/components/Thread.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
<script lang="ts" strictEvents>
import type { Embed } from "@app/lib/file";
import { tick } from "svelte";
import { partial } from "lodash";
import * as utils from "@app/lib/utils";
import { partial } from "lodash";
import { tick } from "svelte";
import CommentComponent from "@app/components/Comment.svelte";
import CommentToggleInput from "@app/components/CommentToggleInput.svelte";
Expand All @@ -36,6 +36,7 @@
};
export let rawPath: string;
export let enableAttachments: boolean = false;
export let canEditComment: (author: string) => true | undefined;
export let editComment:
| ((commentId: string, body: string, embeds: Embed[]) => Promise<void>)
| undefined;
Expand Down Expand Up @@ -96,7 +97,9 @@
timestamp={root.timestamp}
disableEdit={root.embeds.length > 0}
body={root.body}
editComment={editComment && partial(editComment, root.id)}
editComment={editComment &&
canEditComment(root.author.id) &&
partial(editComment, root.id)}
handleReaction={handleReaction && partial(handleReaction, root.id)}>
<IconSmall name="chat" slot="icon" />
</CommentComponent>
Expand All @@ -116,7 +119,9 @@
timestamp={reply.timestamp}
disableEdit={reply.embeds.length > 0}
body={reply.body}
editComment={editComment && partial(editComment, reply.id)}
editComment={editComment &&
canEditComment(reply.author.id) &&
partial(editComment, reply.id)}
handleReaction={handleReaction &&
partial(handleReaction, reply.id)} />
{/each}
Expand Down
36 changes: 36 additions & 0 deletions src/lib/roles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { parseNodeId } from "@app/lib/utils";

export function isDelegate(
publicKey: string | undefined,
delegates: string[],
): true | undefined {
if (!publicKey) {
return undefined;
}
return (
delegates.some(delegate => parseNodeId(delegate)?.pubkey === publicKey) ||
undefined
);
}

function matchAuthor(
publicKey: string | undefined,
nid: string,
): true | undefined {
// Normalize the passed in NID
const parsedNid = parseNodeId(nid);
return (
(publicKey && parsedNid && parsedNid.pubkey === publicKey) || undefined
);
}

// All restricted actions are a combination of either:
// - the user is a delegate
// - the user is an author of the comment, issue, patch, etc.
export function isDelegateOrAuthor(
publicKey: string | undefined,
delegates: string[],
author: string,
) {
return isDelegate(publicKey, delegates) || matchAuthor(publicKey, author);
}
2 changes: 2 additions & 0 deletions src/views/projects/Cob/Revision.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
export let previousRevId: string | undefined = undefined;
export let previousRevOid: string | undefined = undefined;
export let first: boolean;
export let canEditComment: (author: string) => true | undefined;
export let editComment:
| ((commentId: string, body: string, embeds: Embed[]) => Promise<void>)
| undefined;
Expand Down Expand Up @@ -396,6 +397,7 @@
enableAttachments
rawPath={utils.getRawBasePath(projectId, baseUrl, projectHead)}
thread={element.inner}
{canEditComment}
{editComment}
{createReply}
{handleReaction} />
Expand Down
36 changes: 26 additions & 10 deletions src/views/projects/Issue.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import { isEqual, uniqBy, partial } from "lodash";
import * as modal from "@app/lib/modal";
import * as role from "@app/lib/roles";
import * as router from "@app/lib/router";
import * as utils from "@app/lib/utils";
import { HttpdClient } from "@httpd-client";
Expand Down Expand Up @@ -442,7 +443,13 @@
<CobHeader
id={issue.id}
title={issue.title}
editTitle={session && partial(editTitle, session.id)}
editTitle={session &&
role.isDelegateOrAuthor(
session.publicKey,
project.delegates,
issue.author.id,
) &&
partial(editTitle, session.id)}
on:refresh={refreshIssue}>
<svelte:fragment slot="icon">
<div
Expand All @@ -465,7 +472,7 @@
{/if}
</svelte:fragment>
<div slot="description">
{#if session && descriptionState !== "read"}
{#if descriptionState !== "read"}
<ExtendedTextarea
enableAttachments
body={issue.discussion[0].body}
Expand All @@ -492,7 +499,7 @@
baseUrl,
project.head,
)} />
{#if session}
{#if session && role.isDelegateOrAuthor(session.publicKey, project.delegates, issue.author.id)}
<IconButton
title="edit description"
on:click={() => (descriptionState = "edit")}>
Expand Down Expand Up @@ -537,6 +544,11 @@
enableAttachments
{thread}
{rawPath}
canEditComment={partial(
role.isDelegateOrAuthor,
session?.publicKey,
project.delegates,
)}
editComment={session && partial(editComment, session.id)}
createReply={session && partial(createReply, session.id)}
handleReaction={session && partial(handleReaction, session)} />
Expand All @@ -549,17 +561,20 @@
enableAttachments
submit={session && partial(createComment, session.id)} />
<div style:display="flex">
<CobStateButton
items={items.filter(([, state]) => !isEqual(state, issue.state))}
{selectedItem}
state={issue.state}
save={session && partial(saveStatus, session.id)} />
{#if role.isDelegateOrAuthor(session.publicKey, project.delegates, issue.author.id)}
<CobStateButton
items={items.filter(([, state]) => !isEqual(state, issue.state))}
{selectedItem}
state={issue.state}
save={session && partial(saveStatus, session.id)} />
{/if}
</div>
{/if}
</div>
<div class="metadata">
<AssigneeInput
locallyAuthenticated={Boolean(session)}
locallyAuthenticated={session &&
role.isDelegate(session.publicKey, project.delegates)}
assignees={issue.assignees}
submitInProgress={assigneeState === "submit"}
on:save={async ({ detail: newAssignees }) => {
Expand All @@ -574,7 +589,8 @@
await refreshIssue();
}} />
<LabelInput
locallyAuthenticated={Boolean(session)}
locallyAuthenticated={session &&
role.isDelegate(session.publicKey, project.delegates)}
labels={issue.labels}
submitInProgress={labelState === "submit"}
on:save={async ({ detail: newLabels }) => {
Expand Down
16 changes: 14 additions & 2 deletions src/views/projects/Patch.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import type { ComponentProps } from "svelte";
import * as modal from "@app/lib/modal";
import * as role from "@app/lib/roles";
import * as router from "@app/lib/router";
import * as utils from "@app/lib/utils";
import { HttpdClient } from "@httpd-client";
Expand Down Expand Up @@ -650,7 +651,13 @@
<CobHeader
id={patch.id}
title={patch.title}
editTitle={session && partial(editTitle, session.id)}
editTitle={session &&
role.isDelegateOrAuthor(
session.publicKey,
project.delegates,
patch.author.id,
) &&
partial(editTitle, session.id)}
on:refresh={refreshPatch}>
<svelte:fragment slot="icon">
<div
Expand Down Expand Up @@ -697,7 +704,7 @@
{:else}
<span class="txt-missing">No description available</span>
{/if}
{#if session && descriptionState === "read"}
{#if session && role.isDelegateOrAuthor(session.publicKey, project.delegates, patch.author.id) && descriptionState === "read"}
<div class="edit-buttons">
<IconButton
title="edit description"
Expand Down Expand Up @@ -846,6 +853,11 @@
projectHead={project.head}
{...revision}
first={index === 0}
canEditComment={partial(
role.isDelegateOrAuthor,
session?.publicKey,
project.delegates,
)}
editComment={session &&
partial(editComment, session.id, revision.revisionId)}
handleReaction={session &&
Expand Down

0 comments on commit 6828b77

Please sign in to comment.