Skip to content

encrypt private messages end to end - #276

Open
matheusfillipe wants to merge 4 commits into
mainfrom
feat/c2c-e2ee
Open

encrypt private messages end to end#276
matheusfillipe wants to merge 4 commits into
mainfrom
feat/c2c-e2ee

Conversation

@matheusfillipe

@matheusfillipe matheusfillipe commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Encrypts private messages and file attachments between two Obby clients. It also speaks OTR, so it works with irssi, Pidgin and WeeChat. Everything happens in the client. The server only ever relays bytes it cannot read.

  • Key agreement with X3DH, then a Double Ratchet per message. XChaCha20-Poly1305.
  • The handshake goes in a TAGMSG tag and messages go in the PRIVMSG body, so replies, reactions and history keep working.
  • Files are encrypted in the browser and uploaded as .obb. Needs obby-api 0.1.1.
  • A contact's fingerprint is pinned the first time you talk. If it changes later the chat stops and asks you before carrying on.
  • Reloading the page brings the encrypted session back. You approve a contact once, not every time.
  • Once a chat is encrypted, nothing in it is ever sent unencrypted. If encryption breaks the message is held back and you are told why.
  • OTR can only send text messages. A file sent in an OTR chat is uploaded unencrypted, so the client asks first.

Why the diff is big

Only about 9.5k lines are hand written. The rest is a vendored library and translations, both marked in .gitattributes so GitHub collapses them.

  • 7.3k lines are the OTR engine, src/lib/otr/vendor/otr.bundle.js.
  • 6.7k lines are the message catalogs for 18 languages.

Why OTR is vendored instead of installed

It is four UMD files from 2015 that predate modules: CryptoJS, EventEmitter, Leemon Baird BigInt and otr.js. To run at all they have to be concatenated, handed a root object carrying Web Crypto, and re-exported as ESM, with module and define shadowed so each file attaches itself to the global instead. You cannot write that as a dependency in package.json.

Two more reasons to leave it vendored. OTRv3 is frozen, so the file lands once and never changes again. And it is crypto, so the bytes we reviewed are the bytes that ship, instead of whatever a 2015 npm account serves at install time.

@coderabbitai

coderabbitai Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Too many files!

This PR contains 127 files, which is 27 over the limit of 100.

To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch.

Upgrade to a paid plan to raise the limit.

This review couldn't start because sufficient usage credits or metered capacity aren't available. Add credits or update usage-based reviews in the billing tab, then retry.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f8e48114-4f07-45a6-b821-99c4ae261fab

📥 Commits

Reviewing files that changed from the base of the PR and between 73388ae and 2c8b57d.

⛔ Files ignored due to path filters (4)
  • package-lock.json is excluded by !**/package-lock.json
  • src-tauri/gen/android/app/build.gradle.kts is excluded by !**/gen/**
  • src-tauri/gen/android/build.gradle.kts is excluded by !**/gen/**
  • src-tauri/gen/android/gradle/wrapper/gradle-wrapper.properties is excluded by !**/gen/**
📒 Files selected for processing (127)
  • .gitattributes
  • .markdownlintignore
  • AGENTS.md
  • claudedocs/e2ee-over-irc-research.md
  • claudedocs/e2ee-pm-implementation-plan.md
  • lingui.config.ts
  • package.json
  • src/components/layout/ChannelMessageList.tsx
  • src/components/layout/ChatArea.tsx
  • src/components/layout/ChatHeader.tsx
  • src/components/layout/VoiceChannelView.tsx
  • src/components/message/E2EEUnprotectedBadge.tsx
  • src/components/message/EncryptedMediaPreview.tsx
  • src/components/message/MessageHeader.tsx
  • src/components/message/MessageItem.tsx
  • src/components/message/MessageReactions.tsx
  • src/components/message/SystemMessage.tsx
  • src/components/ui/BotToolsCard.tsx
  • src/components/ui/BotToolsHistoryButton.tsx
  • src/components/ui/BotToolsTray.tsx
  • src/components/ui/E2EELockControl.tsx
  • src/components/ui/E2EERequestBanner.tsx
  • src/components/ui/E2EEVerifyModal.tsx
  • src/components/ui/HeaderOverflowMenu.tsx
  • src/components/ui/HoverTooltip.tsx
  • src/components/ui/LoadingSpinner.tsx
  • src/components/ui/Popover.tsx
  • src/components/ui/UnencryptedUploadConfirmModal.tsx
  • src/components/ui/UploadProgressOverlay.tsx
  • src/hooks/useMessageSending.ts
  • src/lib/base64.ts
  • src/lib/e2ee/backend.ts
  • src/lib/e2ee/classify.ts
  • src/lib/e2ee/fingerprint.ts
  • src/lib/e2ee/media.ts
  • src/lib/e2ee/messageFlags.ts
  • src/lib/e2ee/obbyIdentity.ts
  • src/lib/e2ee/otr/backend.ts
  • src/lib/e2ee/otr/identity.ts
  • src/lib/e2ee/otr/keygen.worker.ts
  • src/lib/e2ee/peerTrust.ts
  • src/lib/e2ee/protocol.ts
  • src/lib/e2ee/ratchet.ts
  • src/lib/e2ee/session.ts
  • src/lib/e2ee/transport.ts
  • src/lib/irc/IRCClient.ts
  • src/lib/irc/handlers/connection.ts
  • src/lib/ircClient.ts
  • src/lib/mediaUpload.ts
  • src/lib/messageGrouping.ts
  • src/lib/otr/vendor/loader.ts
  • src/lib/otr/vendor/otr.bundle.d.ts
  • src/lib/otr/vendor/otr.bundle.js
  • src/lib/voice.ts
  • src/locales/cs/messages.mjs
  • src/locales/cs/messages.po
  • src/locales/de/messages.mjs
  • src/locales/de/messages.po
  • src/locales/en/messages.mjs
  • src/locales/en/messages.po
  • src/locales/es/messages.mjs
  • src/locales/es/messages.po
  • src/locales/fi/messages.mjs
  • src/locales/fi/messages.po
  • src/locales/fr/messages.mjs
  • src/locales/fr/messages.po
  • src/locales/it/messages.mjs
  • src/locales/it/messages.po
  • src/locales/ja/messages.mjs
  • src/locales/ja/messages.po
  • src/locales/ko/messages.mjs
  • src/locales/ko/messages.po
  • src/locales/nl/messages.mjs
  • src/locales/nl/messages.po
  • src/locales/pl/messages.mjs
  • src/locales/pl/messages.po
  • src/locales/pt/messages.mjs
  • src/locales/pt/messages.po
  • src/locales/ro/messages.mjs
  • src/locales/ro/messages.po
  • src/locales/ru/messages.mjs
  • src/locales/ru/messages.po
  • src/locales/sv/messages.mjs
  • src/locales/sv/messages.po
  • src/locales/tr/messages.mjs
  • src/locales/tr/messages.po
  • src/locales/uk/messages.mjs
  • src/locales/uk/messages.po
  • src/locales/zh-TW/messages.mjs
  • src/locales/zh-TW/messages.po
  • src/locales/zh/messages.mjs
  • src/locales/zh/messages.po
  • src/store/handlers/auth.ts
  • src/store/handlers/connection.ts
  • src/store/handlers/e2ee.ts
  • src/store/handlers/e2eeConversation.ts
  • src/store/handlers/e2eeOutbound.ts
  • src/store/handlers/index.ts
  • src/store/handlers/messages.ts
  • src/store/handlers/otr.ts
  • src/store/handlers/privateChatArrival.ts
  • src/store/index.ts
  • tailwind.config.js
  • tests/fixtures/otrKeys.ts
  • tests/lib/e2ee/backend.test.ts
  • tests/lib/e2ee/classify.test.ts
  • tests/lib/e2ee/fingerprint.test.ts
  • tests/lib/e2ee/media.test.ts
  • tests/lib/e2ee/obbyIdentity.test.ts
  • tests/lib/e2ee/otr/backend.test.ts
  • tests/lib/e2ee/otr/identity.test.ts
  • tests/lib/e2ee/peerTrust.test.ts
  • tests/lib/e2ee/protocol.test.ts
  • tests/lib/e2ee/ratchet.test.ts
  • tests/lib/e2ee/session.test.ts
  • tests/lib/e2ee/transport.test.ts
  • tests/lib/messageGrouping.test.ts
  • tests/store/capSaslBatching.test.ts
  • tests/store/e2eeOpensPrivateChat.test.ts
  • tests/store/e2eeOutbound.test.ts
  • tests/store/e2eeReconnect.test.ts
  • tests/store/e2eeResilience.test.ts
  • tests/store/e2eeSendRouting.test.ts
  • tests/store/e2eeUploadPosture.test.ts
  • tests/store/initialization.test.ts
  • tests/store/otrInbound.test.ts
  • vite.config.ts

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown

Pages Preview
Preview URL: https://feat-c2c-e2ee.obsidianirc.pages.dev

Automated deployment preview for the PR in the Cloudflare Pages.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant