Commit Graph

16 Commits

Author SHA1 Message Date
Stanko K.R. 656215b186 Allow bots to delete their own boosts 2026-08-11 14:13:01 +02:00
Ronald Lokers 3ca1dcbf77 Allow bots to update and destroy their own messages
Bots can only create. A lifecycle notification — an alert that fires and then
resolves, a deploy that starts and finishes, a backup that runs — therefore has
to post a second message, and the room becomes an append-only log of states
rather than a view of the current one.

Adds PATCH and DELETE inside the existing bot_key scope, routed to
Messages::ByBotsController. The body is read the way create reads it, so
updating a message is the same request shape as posting one.

No new authorization: both actions already run through ensure_can_administer,
and can_administer? grants access only to a record the user created, so a bot
key reaches that bot's own messages and no others. set_room narrows it again by
looking the room up through the bot's own memberships. A leaked bot key gains
what it could already do by posting: write to rooms that bot belongs to.

update answers head :ok rather than the redirect, which meant extracting the
update and its broadcast into update_message — calling super and then head
would double render, since the parent redirects inside the action. destroy
needs no split, because the parent renders implicitly like create does.
2026-08-11 13:33:01 +02:00
Stanko Krtalić 766bffae56 Merge pull request #190 from jpshackelford/feature/bot-read-messages
feat: Add bot API endpoints for reading messages and adding reactions
2026-08-11 13:24:19 +02:00
Stanko K.R. 80c9e7fbfe Adjust to the in-house style
- Use jbuilder instead of hashes
- Use resource instead of direct HTTP verbs
    Verbs only make sense if you have one or two routes, if there are
    multiple that emulate what resource does then it's better to use resource.
- Paginate using link headers
- Cache responses
2026-08-11 13:15:38 +02:00
Jeremy Daer ee37809220 Authorize the room message stream at subscribe time
Message content is delivered over turbo streams, which ran on the stock
Turbo::StreamsChannel. That channel verifies the signature on the stream name and
nothing else. The name carries no expiry and no binding to a user, so one read off
the page while a member kept working after the membership was revoked.

Revocation made this worse rather than better. Membership#after_destroy_commit
disconnects the user with reconnect: true, and the client replays its subscriptions
on the new socket: RoomChannel re-checks membership and rejects, while the turbo
subscription re-verified only the signature and was accepted.

RoomMessagesChannel re-checks membership on every subscribe, deriving the room from
the verified stream name so there is no parameter to point elsewhere. Since the
subscriber names the channel it wants, the stock channel would otherwise be a way
around that check, so it now turns these stream names away and this is the only door.
2026-08-03 14:55:12 -07:00
Stanko K.R. d79225ecd1 Fix version number for CI built images 2026-07-30 18:34:54 +02:00
Mike Dalessio b065b40a34 Disable libvips unfuzzed operations (#226)
and add test coverage for (un)supported file types.

The avatar and logo variants move into the models and return nil for content
types that are no longer variable, so the controllers fall back to the initials
avatar and stock logo icon instead of raising `ActiveStorage::InvariableError`.
2026-07-28 11:57:57 -04:00
Mike Dalessio 52ccd24efa dep: update action_text-trix 2.1.15 → 2.1.19
Security fix for 3 stored/DOM XSS advisories in Trix:
GHSA-g9jg-w8vm-g96v (attachment attribute), GHSA-qmpg-8xg6-ph5q
(serialized attributes), GHSA-53p3-c7vp-4mcc (JSON deserialization
bypass in drag-and-drop).

EXPOSED: campfire's composer/editor use Trix for message bodies, and the
browser actually ran the hand-vendored vendor/javascript/trix.esm.min.js
pinned at 2.0.10 — which lacks the DOMPurify/isValidAttribute sanitizers.
The gem bump alone is a no-op for the browser; the real fix is
re-vendoring the ESM build:

  - bump gem to 2.1.19 (Gemfile.lock)
  - re-vendor vendor/javascript/trix.esm.min.js from Trix 2.1.19
    (2.0.10 → 2.1.19; bundles DOMPurify 3.4.2, rangy 1.3.2)
  - update importmap pin comment @2.0.10 → @2.1.19

89 commits analyzed. Verified green via full unit + system suites
(system tests drive the Trix composer via fill_in_rich_text_area).

https://github.com/basecamp/37signals-hq/blob/main/upgrade-analysis/campfire-20260609-action_text-trix_v2.1.15..v2.1.19.md

🤖 Assisted by Claude
2026-06-09 12:42:51 -04:00
John-Mason Shackelford 20ab5b1bc6 feat: Add bot API endpoint for adding reactions (boosts) to messages
Adds a new endpoint that allows bots to add emoji reactions (boosts) to messages:
POST /rooms/:room_id/:bot_key/messages/:message_id/boosts

This enables bots to acknowledge messages with reactions like 👀 (eyes) when
mentioned, providing immediate feedback to users before generating a full response.

The endpoint:
- Validates the bot is a member of the room
- Validates the message exists in the room
- Broadcasts the boost to connected clients via Turbo Streams
- Returns 201 Created on success, 404 if room/message not found

Co-authored-by: openhands <openhands@all-hands.dev>
2026-04-08 18:53:03 -04:00
John-Mason Shackelford d4a56784e0 feat: Add bot API endpoint for reading room messages
Adds a new GET endpoint at /rooms/:room_id/:bot_key/messages that allows
bots to read messages from rooms they are members of.

The endpoint returns JSON with:
- Room info (id, name)
- Messages array with body (plain/html), created_at, and creator info
- Pagination info (oldest_id, newest_id, has_more)

Supports pagination via ?before=:id and ?after=:id query parameters,
consistent with the existing pagination in the messages controller.

This enables AI bots and other automated agents to understand conversation
context when responding to messages, rather than only receiving the single
message that triggered the webhook.

Co-authored-by: openhands <openhands@all-hands.dev>
2026-04-08 13:53:17 -04:00
Mike Dalessio 3fada3d997 ci: harden GitHub Actions workflows (#185)
* Add GitHub Actions audit job (actionlint + zizmor) to CI

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Configure dependabot for GitHub Actions, bundler, and Docker

Batches all action updates into a single weekly PR. Adds cooldown
periods to all ecosystems.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Add local GitHub Actions linting (actionlint + zizmor) to bin/setup and bin/ci

Install actionlint, shellcheck, and zizmor in bin/setup. Run both
linters as CI steps in config/ci.rb alongside existing style checks.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Pin all GitHub Actions to SHA hashes

Run pinact to pin action versions to specific commit SHAs,
preventing supply chain attacks from tag mutation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix high severity zizmor findings

- Suppress unpinned-images for redis service containers (digest
  pinning is nontrivial for service containers)
- Move workflow-level permissions to job-level in publish-image.yml
  (build gets full set, manifest gets only what it needs)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix medium severity zizmor findings

- Add persist-credentials: false to all checkout steps
- Add permissions: {} at workflow level in ci.yml
- Add job-level permissions (contents: read) to all CI jobs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Fix informational template-injection findings in publish-image.yml

Move steps.meta.outputs.tags from inline ${{ }} expressions to env
vars in both the manifest creation and cosign signing steps.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* Update brakeman to 8.0.4

bin/brakeman uses --ensure-latest which fails if not on the newest version.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 19:26:25 -04:00
Stanko K.R. 6197f20a31 Upgrade to Rails 8.2.0.alpha 2025-12-01 13:50:53 +01:00
Stanko K.R. 3367ffaf8f Switch to using schema.rb
Previously we had to use structure.sql since schema.rb didn't have support for virtual tables that we needed for search. Since Campfire's release virtuals tables have been added to Rails, so there is no need to use structure.sql anymore
2025-12-01 11:47:51 +01:00
Kevin McConnell 30fe6ab121 Add IP-based user banning
This adds the ability to ban a user by their IP address.

When an admin is viewing a user profile, a new "Ban user" button is
present. Clicking on that will:

- Create a ban on the IP addresses that were tracked for that user's
  sessions
- Remove all the messages authored by that user
- Log the user out immediately

In addition, that user will no longer be shown in most user lists in the
app. They are still shown to admins, in account settings. Viewing their
profile from there will now show a "Remove ban" button which can be used
to restore their access (it doesn't restore their messages though --
those are already gone -- it just removes the blocks so they can log in
again).
2025-11-26 14:30:38 +00:00
Stanko Krtalić eecdb29332 Upgrade to Rails 8 and Ruby 3.4.5 (#1)
* Bump Ruby to 3.4.5
* Update dependencies
* Adjust for Rails 8 and Ruby 3.5 API changes
* Mark params strings as mutable in prepapration for frozen strings in Ruby 3.5
* Update test for HTML5 sanitizer
    With Rails 7.1 the HTML5 sanitizer became the default, this breakts this test because the old sanitizer used to delete unpermitted nodes, while the new one returns their content
    The final string is safe, but different then it used to be in Rails 7.0
* Remove direct Turbo tesh helpers require & parallelize tests
* Fix Zeitwerk issues with rails extensions
* Update Resque setup for Redis 5+
* Remove unused views
* Remove GID v1 handler
2025-09-02 17:02:41 +02:00
Kevin McConnell df76a227dc Hello world
First open source release of Campfire 🎉
2025-08-21 09:31:59 +01:00