Skip to content

feature(live): webhook / external push for chat channel messages#3445

Open
ArnavBallinCode wants to merge 11 commits intofossasia:devfrom
ArnavBallinCode:feature/chat-webhook-push
Open

feature(live): webhook / external push for chat channel messages#3445
ArnavBallinCode wants to merge 11 commits intofossasia:devfrom
ArnavBallinCode:feature/chat-webhook-push

Conversation

@ArnavBallinCode
Copy link
Copy Markdown
Member

@ArnavBallinCode ArnavBallinCode commented Apr 30, 2026

Closes #3443

Summary

Adds per-room webhook configuration so chat messages and emoji reactions are POSTed to external endpoints with HMAC-SHA256 authentication. This enables external moderation tools (e.g. chatstream-moderate) to receive and process live chat events in real time.

Webhook Payload Schema

{
  "message_id":            "int — Eventyay event_id",
  "channel":               "uuid — Eventyay chat channel identifier",
  "timestamp":             "ISO 8601 — message creation time",
  "screen_name":           "string — chat display name",
  "sender_id":             "string — Eventyay internal user ID (opaque, anonymized)",
  "centralauth_id":        "int | null — Wikimedia CentralAuth gu_id (persistent, globally unique)",
  "centralauth_username":  "string | null — Wikimedia CentralAuth gu_name (global username)",
  "message":               "string — message body text",
  "message_type":          "\"text\" | \"emoji\"",
  "profile_img":           "null (reserved)",
  "user_language":         "string | null — user's locale (BCP 47)",
  "meta":                  "object — type-specific extras (see below)"
}

meta by message type

message_type meta fields
text {}
emoji { "target_message_id", "reaction", "action": "add"|"remove", "reactions": {} }

CentralAuth field mapping

Webhook field Source in Eventyay CentralAuth equivalent
centralauth_id SocialAccount.uid (allauth, provider=mediawiki) → int gu_id — persistent, globally unique numeric ID
centralauth_username User.wikimedia_username (CharField, set at OAuth login) gu_name — global username (can be renamed)
sender_id Eventyay internal user ID (string) No CentralAuth equivalent — opaque, stable, anonymized

Identity resolution for video room users: Video room users are created separately via JWT token auth. Their token_id is sha256(main_user.email)[:7], which allows tracing back to the main Django user's SocialAccount to resolve CentralAuth fields. Both centralauth_id and centralauth_username will be null for users who did not log in via Wikimedia OAuth.

OAuth endpoint: All three OAuth endpoints hit meta.wikimedia.org/w/rest.php/oauth2/ (authorize, access_token, profile). The OIDC sub claim from meta.wikimedia.org is the CentralAuth global user ID (gu_id), not a local wiki ID.

Authentication

  • HMAC-SHA256 signature: X-Eventyay-Signature: sha256=<hex_digest>
  • Computed as HMAC-SHA256(raw_request_body, shared_secret)
  • Secret is per-room, configured in the room settings UI
  • Challenge verification on first registration: GET ?challenge=<token> → respond {"challenge": "<token>"}

Security

  • SSRF protection: Webhook URLs are validated with urlparse, private network blocking via socket.getaddrinfo + ipaddress.ip_address. Private networks are only allowed in DEBUG mode.
  • Secret stripping: webhook_hmac_secret is stripped from get_room_config() so it's never sent to WebSocket clients.
  • Input validation: URL scheme normalization, fragment/credential rejection, specific exception handling.
  • Message type allowlist: Only text and emoji types trigger webhooks; files, deleted, call are skipped.

Screenshots

Screenshot 2026-05-08 at 2 16 45 PM Screenshot 2026-04-30 at 11 03 25 PM Screenshot 2026-04-30 at 11 03 58 PM

- New Celery task (send_chat_webhook) for HMAC-SHA256 signed HTTP POST
- Dispatch webhook after group_send in ChatModule.send() and .react()
- Challenge verification on webhook URL registration in room config patch
- Webhook config stored in module_config JSONField (no migration needed)
- HTTPS-only URL validation, fire-and-forget delivery
- Relax HTTPS requirement when DEBUG=True for local development
- Add tools/test_webhook_receiver.py for manual testing
Copilot AI review requested due to automatic review settings April 30, 2026 09:56
Copy link
Copy Markdown
Contributor

@sourcery-ai sourcery-ai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry @ArnavBallinCode, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@ArnavBallinCode ArnavBallinCode changed the title Feature/chat webhook push Feature: chat webhook push Apr 30, 2026
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Show webhook config inputs under the Chat toggle in the room
sidebar addons panel. Fields are only visible when chat is enabled.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 7 comments.

Comment thread app/eventyay/features/live/modules/room.py Outdated
Comment thread app/eventyay/features/live/modules/room.py
Comment thread app/eventyay/features/live/modules/chat.py Outdated
Comment thread app/eventyay/features/live/modules/chat.py
Comment thread app/eventyay/features/live/modules/chat.py Outdated
Comment thread app/eventyay/features/live/modules/room.py
Comment thread app/eventyay/features/live/modules/room.py Outdated
- Strip webhook_hmac_secret from frontend room configs
- Validate secret whenever webhook_url is set, not just on URL change
- Use urlparse for URL validation, block private networks in prod
- Use sync_to_async instead of database_sync_to_async for HTTP
- Use event_data sender instead of str(sender.id) to avoid 'None'
- Skip webhook for unsupported message types (files, deleted, call)
- Include reaction emoji, action, and reactions snapshot in meta
Copilot AI review requested due to automatic review settings April 30, 2026 12:33
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Look up CentralAuth gu_id (SocialAccount.uid) and gu_name
(User.wikimedia_username) at webhook dispatch time. For video room
users created via JWT token auth, trace back to the main Django user
by matching token_id to sha256(email)[:7] of MediaWiki-linked users.
@ArnavBallinCode ArnavBallinCode changed the title Feature: chat webhook push feature(live): webhook / external push for chat channel messages Apr 30, 2026
@lgelauff
Copy link
Copy Markdown

lgelauff commented May 2, 2026

on the accepting side, we're live: https://chatstream-moderate.toolforge.org/ . Let me know if you like access for testing. Github updated with documentation.

My AI assistant suggested you double check target_message_id and its definition. I didnt verify myself.

Is there a 'channel language' that you could add? Might be helpful. I added some other fields that I thought might be useful, and updated the specs to this PR as much as possible.

Copilot AI review requested due to automatic review settings May 3, 2026 09:24
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@Saksham-Sirohi Saksham-Sirohi requested a review from Copilot May 4, 2026 10:23
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 6 changed files in this pull request and generated 11 comments.

Comment thread app/eventyay/features/live/modules/chat.py
Comment thread app/eventyay/features/live/modules/chat.py
Comment thread app/eventyay/features/live/modules/chat.py Outdated
Comment thread app/eventyay/features/live/modules/chat.py
Comment thread app/eventyay/features/live/modules/chat.py
Comment thread app/eventyay/features/live/modules/room.py
Comment thread app/eventyay/features/live/modules/room.py
Comment thread app/eventyay/base/services/event.py Outdated
Comment thread tools/test_webhook_receiver.py Outdated
Comment thread app/eventyay/features/live/tasks.py Outdated
- Fix sender_id for reactions: always use acting user (self.consumer.user.id)
  instead of event_data['sender'] which is the original message author
- Reuse shared encode_email() from eventyay_common.utils instead of
  duplicating the implementation
- Stricter SSRF: use not ip.is_global instead of is_private to also
  catch loopback, link-local, and reserved ranges via DNS resolution
- Fix misleading error message: 'http or https' instead of 'HTTPS only'
  for the scheme validation that also accepts http
- Guard event.py webhook_hmac_secret pop against missing/non-dict config
- Sanitize webhook URL in log output by stripping query string and fragment
- Remove unused sys import from test_webhook_receiver.py
Copilot AI review requested due to automatic review settings May 8, 2026 08:23
Avoid querying the DB on every webhook dispatch. Results are cached
in Django's cache (Redis) with a 1-hour TTL. CentralAuth renames
are rare so stale data is acceptable, as noted by @lgelauff.
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@ArnavBallinCode ArnavBallinCode requested a review from lgelauff May 8, 2026 08:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

feature(live): webhook / external push for chat channel messages

3 participants