From 7a04d1f7af9a6326fc44d31d575df8a1bd7cd7d7 Mon Sep 17 00:00:00 2001 From: Timothy Ristau Date: Mon, 9 Mar 2026 14:36:05 -0400 Subject: [PATCH] spelling grammar --- .gitignore | 9 +++ ISSUES.md | 38 +++++---- PERMISSIONS.md | 151 +++++++++++++++++++++++++++++++++++ README.md | 2 +- public/api/auth/index.ts | 19 ++++- public/api/channels/index.ts | 2 +- public/api/users/index.ts | 3 +- 7 files changed, 197 insertions(+), 27 deletions(-) create mode 100644 PERMISSIONS.md diff --git a/.gitignore b/.gitignore index 639a628..319252b 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,12 @@ data/ .fsdb* public/files/* .vscode/* + + +# tim +ABOUT.md +AGENTS.md +API.md +ARCHITECTURE.md +CONTRIBUTING.md +REVIEW.md \ No newline at end of file diff --git a/ISSUES.md b/ISSUES.md index 54a9fad..34a7501 100644 --- a/ISSUES.md +++ b/ISSUES.md @@ -2,29 +2,27 @@ ## Creating Channels -* Creating a channel is weird from a UX perspective. You it the plus arrow and a textfield comes up but there isn't any indication on how to submit it (hitting enter works but not have a button is a weird UX) +* Creating a channel is weird from a UX perspective. You hit the plus arrow and a text field comes up, but there isn't any indication of how to submit it. Hitting Enter works, but not having a button is a weird UX choice. * Hitting the plus icon again hides the text field but doesn't clear the value -* The plus button works as a visibility toggle but doesn't change from + to -. I would add a + button next to the Channels title which opens a mini form that has a text field with a create and cancel button. You can have the ESC key close the dialog but there should be clear buttons on what does what. - +* The plus button works as a visibility toggle but doesn't change from + to -. I would add a + button next to the Channels title that opens a mini form with a text field plus Create and Cancel buttons. You can have the Esc key close the dialog, but there should be clear buttons showing what does what. ## Chatting -* Attaching files doesn't really show whats happening, there should be a preview (whether link or image or whatever). -* The change bar should have a dragable area to drop files into -* The file upload currently accepts anything it seams but creating local links +* Attaching files doesn't really show what's happening; there should be a preview, whether link, image, or whatever. +* The chat bar should have a draggable area to drop files into. * By default it seems 'react' gives a permission error? It also has a weird assortment of emoji's by default. ## Blurbs -* + button acts as hide/show toggle but doesn't change to - or whatever when it is shown -* hiding blurb doesn't clear fields -* character count seems to keep previous character count after blurb -* Need a filter and sort feature so you can see blubs by topic or user. +* The + button acts as a hide/show toggle but doesn't change to - or whatever when it is shown. +* Hiding a blurb doesn't clear the fields. +* The character count seems to keep the previous count after posting a blurb. +* Need a filter and sort feature so you can see blurbs by topic or user. * Need a subscription feature with notifications so you can see what a user is saying -* Need a read/notread feature so users can filter out read blurbs -* Is the goal to be able to repond to blurbs? -* Hastags? +* Need a read/unread feature so users can filter out read blurbs +* Is the goal to be able to respond to blurbs? +* Hashtags? * Sharing and linking to Chats, Essays, and Forums ## Forum @@ -46,25 +44,25 @@ ## Map * Is the point to show where users are? If so users need to be able to set their location. -* Should users be only able to share their location with certain users or everyone +* Should users only be able to share their location with certain users, or everyone? ## General UI * Log out button is very large and in a weird spot. Logging out is not a common activity so it shouldn't have such prominence. -* What is the purpose of the left hand tray? Is it for eventually having access to multiple servers or just a logo? It takes up reastate without providing a use. If the server feature isn't going to exist for awhile it should be removed and the logo placed elsewhere. -* The user's avatar is very large with some properties around it. This should probably follow the more common convenstion of it being an icon in the top right and have the settings in a properties panel or or page. Once set the user isn't going to interact with the profile that much so more room should be given to common operations. -* No theme really or at least the look is very sparse. Setting just a color is find by it would be nice to have the ability to set a swatch or theme of different colors (like an IDE theme) +* What is the purpose of the left-hand tray? Is it for eventually having access to multiple servers, or is it just a logo? It takes up real estate without providing a use. If the server feature isn't going to exist for a while, it should be removed and the logo placed elsewhere. +* The user's avatar is very large with some properties around it. This should probably follow the more common convention of being an icon in the top right, with the settings in a properties panel or page. Once set, the user isn't going to interact with the profile that much, so more room should be given to common operations. +* There isn't really a theme, or at least the look is very sparse. Setting just a color is fine, but it would be nice to have the ability to set a swatch or theme of different colors, like an IDE theme. * Context menu icons are rough * No server admin panel * Need a way to admin users -* History of users actions +* History of user actions * Global search to find chats, blurbs, forums, or essays ## Accessibility * Might need to look at the tabbing order and make sure everything is tabbable. - * hot keys for switching between areas - * Contrast is harsh for different colors in theme. Colors for buttons labels/icons should be calculated to have adequete contrast to primary color + * Hotkeys for switching between areas + * Contrast is harsh for different colors in the theme. Colors for buttons, labels, and icons should be calculated to have adequate contrast with the primary color * Light/dark theme diff --git a/PERMISSIONS.md b/PERMISSIONS.md new file mode 100644 index 0000000..036aea1 --- /dev/null +++ b/PERMISSIONS.md @@ -0,0 +1,151 @@ +# PERMISSIONS.md + +Permission reference for `autonomous.contact`. + +This document was built by crawling the codebase for: + +- default permission assignment in [public/api/users/index.ts](public/api/users/index.ts) +- server-side permission checks in [public/api/](public/api) +- frontend permission gates in [public/tabs/](public/tabs) and related UI files + +## Sources of truth + +Current default permission sets are defined in [public/api/users/index.ts](public/api/users/index.ts#L14-L58). + +- `DEFAULT_USER_PERMISSIONS` are assigned to normal users during signup. +- `DEFAULT_SUPERUSER_PERMISSIONS` are assigned to the first/bootstrap user. + +## How permissions work + +There are two layers of access control in this codebase: + +1. **Global permission strings** stored on the user record. +2. **Object-level ACLs** stored inside resources, especially channel `permissions.read`, `permissions.write`, `permissions.events.read`, and `permissions.events.write`. + +Important consequence: a user may have a global permission and still be blocked by a channel-level ACL. + +## Generic permission families + +These are not stored as standalone permissions, but the server checks for these prefixes: + +- `events.create.*` via [public/api/events/index.ts](public/api/events/index.ts#L188) and [utils/prechecks.ts](utils/prechecks.ts#L47-L48) +- `events.write.*` via [public/api/events/:event_id/index.ts](public/api/events/:event_id/index.ts#L34-L35), [public/api/events/:event_id/index.ts](public/api/events/:event_id/index.ts#L117-L118), and [utils/prechecks.ts](utils/prechecks.ts#L50-L51) + +## Permissions bible + +| Permission | Default user | Bootstrap superuser | Purpose | Where checked | Notes | +| --- | --- | --- | --- | --- | --- | +| `channels.read` | yes | yes | Allows listing channels. | [public/api/channels/index.ts](public/api/channels/index.ts#L12) | Channel detail reads also require channel ACL membership; this permission gates the channel list endpoint only. | +| `channels.create` | no | yes | Allows creating channels. | [public/api/channels/index.ts](public/api/channels/index.ts#L31), [public/tabs/chat/channel_sidebar.html](public/tabs/chat/channel_sidebar.html#L189) | Fully wired. | +| `channels.delete` | no | yes | Intended to allow channel deletion. | Defined in [public/api/users/index.ts](public/api/users/index.ts#L51) | **No direct server-side check found.** Channel deletion currently uses `channel.permissions.write` membership instead of this string. See [public/api/channels/:channel_id/index.ts](public/api/channels/:channel_id/index.ts#L98-L100). | +| `channels.write` | no | yes | Intended to allow channel updates. | Defined in [public/api/users/index.ts](public/api/users/index.ts#L52) | **No direct server-side check found.** Channel updates currently use `channel.permissions.write` membership instead of this string. See [public/api/channels/:channel_id/index.ts](public/api/channels/:channel_id/index.ts#L45-L47). | +| `events.create.blurb` | yes | yes | Allows creating `blurb` events. | [utils/prechecks.ts](utils/prechecks.ts#L47-L48), [public/tabs/blurbs/new_blurb.html](public/tabs/blurbs/new_blurb.html#L28) | Matches server behavior. | +| `events.create.chat` | yes | yes | Allows creating `chat` events. | [utils/prechecks.ts](utils/prechecks.ts#L47-L48) | **UI mismatch:** chat composer is gated by `events.write.chat`, not `events.create.chat`. See [public/tabs/chat/chat.html](public/tabs/chat/chat.html#L151). | +| `events.create.essay` | yes | yes | Allows creating `essay` events. | [utils/prechecks.ts](utils/prechecks.ts#L47-L48), [public/tabs/essays/new_essay.html](public/tabs/essays/new_essay.html#L25) | Matches server behavior. | +| `events.create.post` | yes | yes | Allows creating `post` events. | [utils/prechecks.ts](utils/prechecks.ts#L47-L48), [public/tabs/forum/new_post.html](public/tabs/forum/new_post.html#L9) | Matches server behavior. | +| `events.create.presence` | yes | yes | Intended to allow creating `presence` events. | [utils/prechecks.ts](utils/prechecks.ts#L47-L48) | No dedicated UI or route-specific feature found beyond generic event creation. | +| `events.read.blurb` | yes | yes | Intended to allow viewing blurbs. | [public/tabs/blurbs/blurbs.html](public/tabs/blurbs/blurbs.html#L150) | **Frontend-only gate found.** No matching server-side event-read check by permission string was found. | +| `events.read.chat` | yes | yes | Intended to allow viewing chat. | [public/tabs/chat/chat.html](public/tabs/chat/chat.html#L23) | **Frontend-only gate found.** Server reads rely on authentication and channel ACLs, not this string. | +| `events.read.essay` | yes | yes | Intended to allow viewing essays. | [public/tabs/essays/essays.html](public/tabs/essays/essays.html#L126) | **Frontend-only gate found.** | +| `events.read.post` | yes | yes | Intended to allow viewing posts. | [public/tabs/forum/forum.html](public/tabs/forum/forum.html#L181) | **Frontend-only gate found.** | +| `events.read.presence` | yes | yes | Intended to allow viewing presence events. | Defined in [public/api/users/index.ts](public/api/users/index.ts#L27) | **No active check found** beyond the default assignment. | +| `events.write.blurb` | yes | yes | Allows updating/deleting `blurb` events. | [utils/prechecks.ts](utils/prechecks.ts#L50-L51) | Used by generic event update/delete endpoints. | +| `events.write.chat` | yes | yes | Allows updating/deleting `chat` events. | [utils/prechecks.ts](utils/prechecks.ts#L50-L51), [public/tabs/chat/chat.html](public/tabs/chat/chat.html#L151) | Also used by the chat composer UI, which appears to be stricter/different than server-side create rules. | +| `events.write.essay` | yes | yes | Allows updating/deleting `essay` events. | [utils/prechecks.ts](utils/prechecks.ts#L50-L51) | No dedicated UI gate found. | +| `events.write.post` | yes | yes | Allows updating/deleting `post` events. | [utils/prechecks.ts](utils/prechecks.ts#L50-L51) | No dedicated UI gate found. | +| `events.write.presence` | yes | yes | Intended to allow updating/deleting `presence` events. | [utils/prechecks.ts](utils/prechecks.ts#L50-L51) | No dedicated UI or route-specific usage found beyond generic event mutation logic. | +| `files.write.own` | yes | yes | Allows uploads only inside the current user's home path under `/files/users//...`. | [public/_pre.ts](public/_pre.ts#L12-L20) | Fully wired. | +| `files.write.all` | no | yes | Allows uploads anywhere under `/files/...`. | [public/_pre.ts](public/_pre.ts#L13-L20), [tests/11_file_uploads.test.ts](tests/11_file_uploads.test.ts#L165) | Fully wired. | +| `invites.create` | yes | yes | Allows creating invite codes. | [public/api/users/:user_id/invites/index.ts](public/api/users/:user_id/invites/index.ts#L73) | Fully wired. | +| `invites.read.own` | yes | yes | Allows reading invites for the path user when it is self. | [public/api/users/:user_id/invites/index.ts](public/api/users/:user_id/invites/index.ts#L17-L20) | Route behavior currently has filtering issues; see [REVIEW.md](REVIEW.md). | +| `invites.read.all` | no | yes | Allows reading invites across users. | [public/api/users/:user_id/invites/index.ts](public/api/users/:user_id/invites/index.ts#L18-L20) | Route behavior currently has filtering issues; see [REVIEW.md](REVIEW.md). | +| `self.read` | yes | yes | Allows reading the current authenticated user's own profile. | [public/api/users/me/index.ts](public/api/users/me/index.ts#L8), [public/api/users/:user_id/index.ts](public/api/users/:user_id/index.ts#L13-L17) | Fully wired. | +| `self.write` | yes | yes | Allows updating/deleting the current user's own profile. | [public/api/users/:user_id/index.ts](public/api/users/:user_id/index.ts#L44-L48), [public/api/users/:user_id/index.ts](public/api/users/:user_id/index.ts#L109-L113) | Fully wired. | +| `signups.read.own` | yes | yes | Allows reading signups for the path user when it is self. | [public/api/users/:user_id/signups/index.ts](public/api/users/:user_id/signups/index.ts#L13-L16) | Route behavior currently has filtering issues; see [REVIEW.md](REVIEW.md). | +| `signups.read.all` | no | yes | Allows reading signups across users. | [public/api/users/:user_id/signups/index.ts](public/api/users/:user_id/signups/index.ts#L14-L16) | Route behavior currently has filtering issues; see [REVIEW.md](REVIEW.md). | +| `users.read` | yes | yes | Allows reading/searching other users. | [public/api/users/index.ts](public/api/users/index.ts#L67), [public/api/users/:user_id/index.ts](public/api/users/:user_id/index.ts#L14-L17) | Fully wired. | +| `users.write` | no | yes | Allows updating/deleting other users and editing permissions. | [public/api/users/:user_id/index.ts](public/api/users/:user_id/index.ts#L45), [public/api/users/:user_id/index.ts](public/api/users/:user_id/index.ts#L81), [public/api/users/:user_id/index.ts](public/api/users/:user_id/index.ts#L110) | Fully wired. | +| `watches.create.own` | yes | yes | Allows creating watches for self. | [public/api/users/:user_id/watches/index.ts](public/api/users/:user_id/watches/index.ts#L80-L83) | Fully wired. | +| `watches.create.all` | no | no | Allows creating watches for other users. | [public/api/users/:user_id/watches/index.ts](public/api/users/:user_id/watches/index.ts#L81-L83) | **Referenced but not granted by either default permission set.** Must be assigned manually if needed. | +| `watches.read.own` | yes | yes | Allows reading watches for self. | [public/api/users/:user_id/watches/index.ts](public/api/users/:user_id/watches/index.ts#L15-L18) | Route behavior currently has filtering issues; see [REVIEW.md](REVIEW.md). | +| `watches.read.all` | no | yes | Allows reading watches across users. | [public/api/users/:user_id/watches/index.ts](public/api/users/:user_id/watches/index.ts#L16-L18) | Route behavior currently has filtering issues; see [REVIEW.md](REVIEW.md). | +| `watches.write.own` | yes | yes | Intended to allow updating/deleting own watches. | Defined in [public/api/users/index.ts](public/api/users/index.ts#L44) | **No direct permission check found.** Watch update/delete currently use ownership only. See [public/api/users/:user_id/watches/:watch_id/index.ts](public/api/users/:user_id/watches/:watch_id/index.ts#L20-L22) and [public/api/users/:user_id/watches/:watch_id/index.ts](public/api/users/:user_id/watches/:watch_id/index.ts#L73-L75). | +| `watches.write.all` | no | yes | Intended to allow updating/deleting others' watches. | Defined in [public/api/users/index.ts](public/api/users/index.ts#L58) | **No direct permission check found.** Watch update/delete currently use ownership only. | + +## Summary: default permissions vs actual code + +### Normal-user defaults that are clearly used + +These are present in `DEFAULT_USER_PERMISSIONS` and have matching checks in code: + +- `channels.read` +- `events.create.blurb` +- `events.create.chat` +- `events.create.essay` +- `events.create.post` +- `events.create.presence` +- `events.write.blurb` +- `events.write.chat` +- `events.write.essay` +- `events.write.post` +- `events.write.presence` +- `files.write.own` +- `invites.create` +- `invites.read.own` +- `self.read` +- `self.write` +- `signups.read.own` +- `users.read` +- `watches.create.own` +- `watches.read.own` + +### Defaults that are only partially matched or frontend-only + +- `events.read.blurb` +- `events.read.chat` +- `events.read.essay` +- `events.read.post` +- `events.read.presence` +- `watches.write.own` + +### Bootstrap/superuser defaults that are present but not fully wired as permission strings + +- `channels.delete` +- `channels.write` +- `watches.write.all` + +### Referenced in code but not granted by default + +- `watches.create.all` + +## Biggest mismatches to know about + +1. **Channel update/delete do not use `channels.write` or `channels.delete`.** + They use per-channel ACL membership instead. See [public/api/channels/:channel_id/index.ts](public/api/channels/:channel_id/index.ts). + +2. **Watch update/delete do not use `watches.write.own` or `watches.write.all`.** + They use ownership checks only. See [public/api/users/:user_id/watches/:watch_id/index.ts](public/api/users/:user_id/watches/:watch_id/index.ts). + +3. **`events.read.*` permissions are mostly UI gates, not server-enforced authorization.** + The event read endpoints do not generally check these strings. + +4. **Chat creation UI uses `events.write.chat`, but the server requires `events.create.chat` for POST.** + This is the clearest create-vs-write mismatch in the current code. + +5. **`watches.create.all` exists in code but is missing from both default sets.** + +## Recommendation + +If the goal is to make permissions predictable, the cleanest next step would be to choose one of these approaches: + +1. remove unused permission strings from defaults, or +2. add explicit checks so every documented permission is actually authoritative + +The most important cleanup targets are: + +- `channels.write` +- `channels.delete` +- `watches.write.own` +- `watches.write.all` +- the `events.read.*` family +- the chat UI mismatch between `events.create.chat` and `events.write.chat` diff --git a/README.md b/README.md index b83bfc0..d3f86f6 100644 --- a/README.md +++ b/README.md @@ -134,7 +134,7 @@ feature discussions. 3) Start the server: - `deno run task serve` + `deno run serve` 4) Navigate to http://localhost:8000 diff --git a/public/api/auth/index.ts b/public/api/auth/index.ts index 7d47e32..d1b0d58 100644 --- a/public/api/auth/index.ts +++ b/public/api/auth/index.ts @@ -122,7 +122,8 @@ export async function POST(req: Request, meta: Record): Promise): Promise): Response | undefined => { const can_create_channels = meta.user.permissions.includes('channels.create'); - + console.log('User permissions:', meta.user.permissions); if (!can_create_channels) { return CANNED_RESPONSES.permission_denied(); } diff --git a/public/api/users/index.ts b/public/api/users/index.ts index b3d8c46..6730626 100644 --- a/public/api/users/index.ts +++ b/public/api/users/index.ts @@ -245,7 +245,8 @@ export async function POST(req: Request, meta: Record): Promise