├── .gitattributes
├── .gitignore
├── .gitlab-ci.yml
├── .gitlab
└── CODEOWNERS
├── .gitmodules
├── .golangci.yml
├── .grype.yaml
├── BUILDS.md
├── CONTRIBUTING.md
├── COPYING_NOTES.md
├── Changelog.md
├── LICENSE
├── Makefile
├── README.md
├── TODO.md
├── ci
├── build.yml
├── env.yml
├── report.yml
├── rules.yml
├── setup.yml
└── test.yml
├── cmd
├── Desktop-Bridge
│ ├── main.go
│ └── main_test.go
└── launcher
│ ├── main.go
│ └── main_test.go
├── dist
├── Bridge.icns
├── bridge.ico
├── bridge.svg
├── bridgeMacOS.svg
├── info.rc
├── proton-bridge.desktop
└── raw
│ ├── mac_icon_128x128.png
│ ├── mac_icon_128x128@2x.png
│ ├── mac_icon_16x16.png
│ ├── mac_icon_16x16@2x.png
│ ├── mac_icon_256x256.png
│ ├── mac_icon_256x256@2x.png
│ ├── mac_icon_32x32.png
│ ├── mac_icon_32x32@2x.png
│ ├── mac_icon_512x512.png
│ ├── mac_icon_512x512@2x.png
│ ├── win+lin_icon_16x16.svg
│ ├── win+lin_icon_24x24.svg
│ ├── win+lin_icon_256x256.png
│ ├── win+lin_icon_256x256.svg
│ ├── win+lin_icon_32x32.svg
│ └── win+lin_icon_48x48.svg
├── go.mod
├── go.sum
├── internal
├── app
│ ├── app.go
│ ├── bridge.go
│ ├── frontend.go
│ ├── migration.go
│ ├── migration_test.go
│ ├── singleinstance.go
│ ├── testdata
│ │ ├── with_keys
│ │ │ └── protonmail
│ │ │ │ └── bridge
│ │ │ │ ├── cert.pem
│ │ │ │ ├── key.pem
│ │ │ │ └── prefs.json
│ │ └── without_keys
│ │ │ └── protonmail
│ │ │ └── bridge
│ │ │ └── prefs.json
│ └── vault.go
├── bridge
│ ├── api.go
│ ├── api_default.go
│ ├── api_qa.go
│ ├── bridge.go
│ ├── bridge_test.go
│ ├── bug_report.go
│ ├── configure.go
│ ├── debug.go
│ ├── draft_test.go
│ ├── errors.go
│ ├── events.go
│ ├── heartbeat.go
│ ├── identifier.go
│ ├── imap.go
│ ├── imapsmtp_telemetry.go
│ ├── keychain.go
│ ├── locations.go
│ ├── main_test.go
│ ├── mocks.go
│ ├── mocks
│ │ ├── async_mocks.go
│ │ ├── gluon_mocks.go
│ │ ├── matcher.go
│ │ ├── mocks.go
│ │ ├── observability_mocks.go
│ │ └── telemetry_mocks.go
│ ├── observability_test.go
│ ├── refresh_test.go
│ ├── send_test.go
│ ├── sentry_test.go
│ ├── server_manager_test.go
│ ├── settings.go
│ ├── settings_test.go
│ ├── smtp.go
│ ├── sync_test.go
│ ├── sync_unix_test.go
│ ├── testdata
│ │ ├── invite.eml
│ │ └── text-plain.eml
│ ├── tls.go
│ ├── types.go
│ ├── unleash_test.go
│ ├── updates.go
│ ├── updates_test.go
│ ├── user.go
│ ├── user_event_test.go
│ ├── user_events.go
│ └── user_test.go
├── certs
│ ├── cert_store_darwin.go
│ ├── cert_store_darwin_test.go
│ ├── cert_store_linux.go
│ ├── cert_store_windows.go
│ ├── installer.go
│ ├── tls.go
│ └── tls_test.go
├── clientconfig
│ ├── applemail.go
│ └── applemail_test.go
├── constants
│ ├── constants.go
│ ├── host_default.go
│ ├── host_qa.go
│ ├── update_default.go
│ ├── update_qa.go
│ ├── version_default.go
│ ├── version_qa.go
│ └── version_test.go
├── cookies
│ ├── jar.go
│ └── jar_test.go
├── crash
│ ├── actions.go
│ ├── handler.go
│ └── handler_test.go
├── dialer
│ ├── dialer_basic.go
│ ├── dialer_pinning.go
│ ├── dialer_pinning_checker.go
│ ├── dialer_pinning_checker_default.go
│ ├── dialer_pinning_checker_qa.go
│ ├── dialer_pinning_report.go
│ ├── dialer_pinning_reporter.go
│ ├── dialer_pinning_reporter_test.go
│ ├── dialer_pinning_test.go
│ ├── dialer_proxy.go
│ ├── dialer_proxy_provider.go
│ ├── dialer_proxy_provider_test.go
│ ├── dialer_proxy_test.go
│ └── dialer_test.go
├── errors.go
├── events
│ ├── address.go
│ ├── connection.go
│ ├── error.go
│ ├── events.go
│ ├── label.go
│ ├── mocks
│ │ └── mocks.go
│ ├── raise.go
│ ├── serve.go
│ ├── sync.go
│ ├── update.go
│ └── user.go
├── files
│ ├── files.go
│ └── files_test.go
├── focus
│ ├── client.go
│ ├── focus_test.go
│ ├── proto
│ │ ├── focus.go
│ │ ├── focus.pb.go
│ │ ├── focus.proto
│ │ └── focus_grpc.pb.go
│ └── service.go
├── frontend
│ ├── .gitignore
│ ├── Makefile.local
│ ├── bridge-gui
│ │ ├── BridgeSetup.cmake
│ │ ├── CMakeLists.txt
│ │ ├── FindQt.cmake
│ │ ├── README.md
│ │ ├── bridge-gui-tester
│ │ │ ├── .lldbinit
│ │ │ ├── AppController.cpp
│ │ │ ├── AppController.h
│ │ │ ├── CMakeLists.txt
│ │ │ ├── Cert.cpp
│ │ │ ├── Cert.h
│ │ │ ├── Doxyfile
│ │ │ ├── GRPCMetaDataProcessor.cpp
│ │ │ ├── GRPCMetaDataProcessor.h
│ │ │ ├── GRPCQtProxy.cpp
│ │ │ ├── GRPCQtProxy.h
│ │ │ ├── GRPCServerWorker.cpp
│ │ │ ├── GRPCServerWorker.h
│ │ │ ├── GRPCService.cpp
│ │ │ ├── GRPCService.h
│ │ │ ├── MainWindow.cpp
│ │ │ ├── MainWindow.h
│ │ │ ├── MainWindow.ui
│ │ │ ├── Pch.h
│ │ │ ├── Tabs
│ │ │ │ ├── EventsTab.cpp
│ │ │ │ ├── EventsTab.h
│ │ │ │ ├── EventsTab.ui
│ │ │ │ ├── KnowledgeBaseTab.cpp
│ │ │ │ ├── KnowledgeBaseTab.h
│ │ │ │ ├── KnowledgeBaseTab.ui
│ │ │ │ ├── SettingsTab.cpp
│ │ │ │ ├── SettingsTab.h
│ │ │ │ ├── SettingsTab.ui
│ │ │ │ ├── UsersTab.cpp
│ │ │ │ ├── UsersTab.h
│ │ │ │ └── UsersTab.ui
│ │ │ ├── UserDialog.cpp
│ │ │ ├── UserDialog.h
│ │ │ ├── UserDialog.ui
│ │ │ ├── UserTable.cpp
│ │ │ ├── UserTable.h
│ │ │ └── main.cpp
│ │ ├── bridge-gui
│ │ │ ├── .lldbinit
│ │ │ ├── AppController.cpp
│ │ │ ├── AppController.h
│ │ │ ├── BridgeApp.cpp
│ │ │ ├── BridgeApp.h
│ │ │ ├── BuildConfig.h.in
│ │ │ ├── CMakeLists.txt
│ │ │ ├── ClipboardProxy.cpp
│ │ │ ├── ClipboardProxy.h
│ │ │ ├── CommandLine.cpp
│ │ │ ├── CommandLine.h
│ │ │ ├── DeployDarwin.cmake
│ │ │ ├── DeployLinux.cmake
│ │ │ ├── DeployWindows.cmake
│ │ │ ├── Doxyfile
│ │ │ ├── EventStreamWorker.cpp
│ │ │ ├── EventStreamWorker.h
│ │ │ ├── LogUtils.cpp
│ │ │ ├── LogUtils.h
│ │ │ ├── MacOS
│ │ │ │ ├── DockIcon.cpp
│ │ │ │ ├── DockIcon.h
│ │ │ │ ├── DockIcon.mm
│ │ │ │ ├── SecondInstance.h
│ │ │ │ └── SecondInstance.mm
│ │ │ ├── Pch.h
│ │ │ ├── QMLBackend.cpp
│ │ │ ├── QMLBackend.h
│ │ │ ├── README.md
│ │ │ ├── Resources.qrc
│ │ │ ├── Resources.rc.in
│ │ │ ├── SentryUtils.cpp
│ │ │ ├── SentryUtils.h
│ │ │ ├── Settings.cpp
│ │ │ ├── Settings.h
│ │ │ ├── TrayIcon.cpp
│ │ │ ├── TrayIcon.h
│ │ │ ├── UserList.cpp
│ │ │ ├── UserList.h
│ │ │ ├── build.ps1
│ │ │ ├── build.sh
│ │ │ ├── main.cpp
│ │ │ ├── qml
│ │ │ │ ├── AccountDelegate.qml
│ │ │ │ ├── AccountView.qml
│ │ │ │ ├── Banner.qml
│ │ │ │ ├── Bridge.qml
│ │ │ │ ├── BugReport
│ │ │ │ │ ├── BugCategoryView.qml
│ │ │ │ │ ├── BugQuestionView.qml
│ │ │ │ │ ├── BugReportFlow.qml
│ │ │ │ │ ├── BugReportView.qml
│ │ │ │ │ ├── CategoryItem.qml
│ │ │ │ │ └── QuestionItem.qml
│ │ │ │ ├── Configuration.qml
│ │ │ │ ├── ConfigurationItem.qml
│ │ │ │ ├── ConnectionModeSettings.qml
│ │ │ │ ├── ContentWrapper.qml
│ │ │ │ ├── DebugWrapper.qml
│ │ │ │ ├── GeneralSettings.qml
│ │ │ │ ├── HelpView.qml
│ │ │ │ ├── KeychainSettings.qml
│ │ │ │ ├── LocalCacheSettings.qml
│ │ │ │ ├── MainWindow.qml
│ │ │ │ ├── NoAccountView.qml
│ │ │ │ ├── NotificationDialog.qml
│ │ │ │ ├── NotificationPopups.qml
│ │ │ │ ├── Notifications
│ │ │ │ │ ├── Notification.qml
│ │ │ │ │ ├── NotificationFilter.qml
│ │ │ │ │ ├── Notifications.qml
│ │ │ │ │ └── qmldir
│ │ │ │ ├── PortSettings.qml
│ │ │ │ ├── Proton
│ │ │ │ │ ├── Action.qml
│ │ │ │ │ ├── ApplicationWindow.qml
│ │ │ │ │ ├── Button.qml
│ │ │ │ │ ├── CheckBox.qml
│ │ │ │ │ ├── ColorScheme.qml
│ │ │ │ │ ├── ComboBox.qml
│ │ │ │ │ ├── ContextMenu.qml
│ │ │ │ │ ├── Dialog.qml
│ │ │ │ │ ├── InfoTooltip.qml
│ │ │ │ │ ├── Label.qml
│ │ │ │ │ ├── LinkLabel.qml
│ │ │ │ │ ├── Menu.qml
│ │ │ │ │ ├── MenuItem.qml
│ │ │ │ │ ├── Popup.qml
│ │ │ │ │ ├── RadioButton.qml
│ │ │ │ │ ├── Style.qml
│ │ │ │ │ ├── Switch.qml
│ │ │ │ │ ├── TextArea.qml
│ │ │ │ │ ├── TextField.qml
│ │ │ │ │ ├── Toggle.qml
│ │ │ │ │ └── qmldir
│ │ │ │ ├── Resources
│ │ │ │ │ ├── Help
│ │ │ │ │ │ ├── Template.html
│ │ │ │ │ │ ├── WhyBridge.html
│ │ │ │ │ │ ├── WhyCertificate.html
│ │ │ │ │ │ └── WhyProfileWarning.html
│ │ │ │ │ └── bug_report_flow.json
│ │ │ │ ├── SettingsItem.qml
│ │ │ │ ├── SettingsView.qml
│ │ │ │ ├── SetupWizard
│ │ │ │ │ ├── ClientConfigAppleMail.qml
│ │ │ │ │ ├── ClientConfigCertInstall.qml
│ │ │ │ │ ├── ClientConfigEnd.qml
│ │ │ │ │ ├── ClientConfigParameters.qml
│ │ │ │ │ ├── ClientConfigSelector.qml
│ │ │ │ │ ├── ClientListItem.qml
│ │ │ │ │ ├── HelpButton.qml
│ │ │ │ │ ├── LeftPane.qml
│ │ │ │ │ ├── Login.qml
│ │ │ │ │ ├── Onboarding.qml
│ │ │ │ │ ├── SetupWizard.qml
│ │ │ │ │ └── StepDescriptionBox.qml
│ │ │ │ ├── SplashScreen.qml
│ │ │ │ ├── Status.qml
│ │ │ │ ├── UserNotificationDialog.qml
│ │ │ │ └── icons
│ │ │ │ │ ├── Loader_16.svg
│ │ │ │ │ ├── Loader_48.svg
│ │ │ │ │ ├── ic-alert.svg
│ │ │ │ │ ├── ic-apple-mail.svg
│ │ │ │ │ ├── ic-arrow-left.svg
│ │ │ │ │ ├── ic-bridge.svg
│ │ │ │ │ ├── ic-card-identity.svg
│ │ │ │ │ ├── ic-check.svg
│ │ │ │ │ ├── ic-chevron-down.svg
│ │ │ │ │ ├── ic-chevron-left.svg
│ │ │ │ │ ├── ic-chevron-right.svg
│ │ │ │ │ ├── ic-chevron-up.svg
│ │ │ │ │ ├── ic-cog-wheel.svg
│ │ │ │ │ ├── ic-connected.svg
│ │ │ │ │ ├── ic-copy.svg
│ │ │ │ │ ├── ic-cross-close.svg
│ │ │ │ │ ├── ic-dot.svg
│ │ │ │ │ ├── ic-drive.svg
│ │ │ │ │ ├── ic-exclamation-circle-filled.svg
│ │ │ │ │ ├── ic-external-link.svg
│ │ │ │ │ ├── ic-eye-slash.svg
│ │ │ │ │ ├── ic-eye.svg
│ │ │ │ │ ├── ic-illustrative-view-html-code.svg
│ │ │ │ │ ├── ic-info-circle-filled.svg
│ │ │ │ │ ├── ic-info-circle.svg
│ │ │ │ │ ├── ic-info.svg
│ │ │ │ │ ├── ic-microsoft-outlook.svg
│ │ │ │ │ ├── ic-mozilla-thunderbird.svg
│ │ │ │ │ ├── ic-no-connection.svg
│ │ │ │ │ ├── ic-notification-bell.svg
│ │ │ │ │ ├── ic-other-mail-clients.svg
│ │ │ │ │ ├── ic-plus.svg
│ │ │ │ │ ├── ic-question-circle.svg
│ │ │ │ │ ├── ic-splash-check.svg
│ │ │ │ │ ├── ic-success.svg
│ │ │ │ │ ├── ic-three-dots-vertical.svg
│ │ │ │ │ ├── ic-trash.svg
│ │ │ │ │ ├── ic-warning-orange.svg
│ │ │ │ │ ├── img-client-config-selector.svg
│ │ │ │ │ ├── img-client-config-success.svg
│ │ │ │ │ ├── img-macos-cert-screenshot.png
│ │ │ │ │ ├── img-macos-profile-screenshot.png
│ │ │ │ │ ├── img-mail-clients.svg
│ │ │ │ │ ├── img-mail-logo-wordmark-dark.svg
│ │ │ │ │ ├── img-mail-logo-wordmark.svg
│ │ │ │ │ ├── img-proton-logos.png
│ │ │ │ │ ├── img-proton-logos.svg
│ │ │ │ │ ├── img-splash.png
│ │ │ │ │ ├── img-splash.svg
│ │ │ │ │ ├── img-welcome.svg
│ │ │ │ │ ├── product_logos.svg
│ │ │ │ │ ├── product_logos_dark.svg
│ │ │ │ │ ├── systray-color-error.png
│ │ │ │ │ ├── systray-color-norm.png
│ │ │ │ │ ├── systray-color-update.png
│ │ │ │ │ ├── systray-color-warn.png
│ │ │ │ │ ├── systray-mono-error.png
│ │ │ │ │ ├── systray-mono-norm.png
│ │ │ │ │ ├── systray-mono-update.png
│ │ │ │ │ ├── systray-mono-warn.png
│ │ │ │ │ └── systray.svg
│ │ │ └── vcpkg
│ │ │ │ └── triplets
│ │ │ │ ├── arm64-osx-min-11-0.cmake
│ │ │ │ └── x64-osx-min-10-15.cmake
│ │ └── bridgepp
│ │ │ ├── CMakeLists.txt
│ │ │ ├── Doxyfile
│ │ │ ├── Pch.h
│ │ │ ├── Test
│ │ │ ├── TestBridgeUtils.cpp
│ │ │ ├── TestBugReportFlow.cpp
│ │ │ ├── TestBugReportFlow.h
│ │ │ ├── TestCLI.cpp
│ │ │ ├── TestException.cpp
│ │ │ ├── TestSessionID.cpp
│ │ │ ├── TestWorker.cpp
│ │ │ └── TestWorker.h
│ │ │ └── bridgepp
│ │ │ ├── BridgeUtils.cpp
│ │ │ ├── BridgeUtils.h
│ │ │ ├── BugReportFlow
│ │ │ ├── BugReportFlow.cpp
│ │ │ └── BugReportFlow.h
│ │ │ ├── CLI
│ │ │ ├── CLIUtils.cpp
│ │ │ └── CLIUtils.h
│ │ │ ├── Exception
│ │ │ ├── Exception.cpp
│ │ │ └── Exception.h
│ │ │ ├── FocusGRPC
│ │ │ ├── FocusGRPCClient.cpp
│ │ │ └── FocusGRPCClient.h
│ │ │ ├── GRPC
│ │ │ ├── EventFactory.cpp
│ │ │ ├── EventFactory.h
│ │ │ ├── GRPCClient.cpp
│ │ │ ├── GRPCClient.h
│ │ │ ├── GRPCConfig.cpp
│ │ │ ├── GRPCConfig.h
│ │ │ ├── GRPCErrors.cpp
│ │ │ ├── GRPCErrors.h
│ │ │ ├── GRPCUtils.cpp
│ │ │ └── GRPCUtils.h
│ │ │ ├── Log
│ │ │ ├── Log.cpp
│ │ │ ├── Log.h
│ │ │ ├── LogUtils.cpp
│ │ │ └── LogUtils.h
│ │ │ ├── ProcessMonitor.cpp
│ │ │ ├── ProcessMonitor.h
│ │ │ ├── SessionID
│ │ │ ├── SessionID.cpp
│ │ │ └── SessionID.h
│ │ │ ├── User
│ │ │ ├── User.cpp
│ │ │ └── User.h
│ │ │ └── Worker
│ │ │ ├── Overseer.cpp
│ │ │ ├── Overseer.h
│ │ │ └── Worker.h
│ ├── cli
│ │ ├── account_utils.go
│ │ ├── accounts.go
│ │ ├── debug.go
│ │ ├── frontend.go
│ │ ├── system.go
│ │ ├── updates.go
│ │ └── utils.go
│ ├── grpc
│ │ ├── bridge.pb.go
│ │ ├── bridge.proto
│ │ ├── bridge_grpc.pb.go
│ │ ├── event_factory.go
│ │ ├── event_utils.go
│ │ ├── service.go
│ │ ├── service_cert.go
│ │ ├── service_methods.go
│ │ ├── service_stream.go
│ │ ├── service_user.go
│ │ ├── types.go
│ │ ├── utils.go
│ │ └── utils_test.go
│ └── theme
│ │ ├── detect_darwin.go
│ │ ├── detect_default.go
│ │ ├── detect_windows.go
│ │ ├── theme.go
│ │ └── theme_test.go
├── hv
│ ├── hv.go
│ └── hv_test.go
├── identifier
│ └── identifier.go
├── kb
│ ├── kbArticleList.json
│ ├── suggester.go
│ └── suggester_test.go
├── legacy
│ └── credentials
│ │ ├── credentials.go
│ │ ├── credentials_test.go
│ │ ├── store.go
│ │ └── store_test.go
├── locations
│ ├── locations.go
│ ├── locations_test.go
│ └── provider.go
├── logging
│ ├── compression.go
│ ├── compression_test.go
│ ├── crash.go
│ ├── crash_test.go
│ ├── imap_logger.go
│ ├── logging.go
│ ├── logging_test.go
│ ├── pruning.go
│ ├── pruning_test.go
│ ├── rotator.go
│ ├── rotator_test.go
│ ├── sensitive_default.go
│ ├── sensitive_sensitive.go
│ ├── session_id.go
│ ├── session_id_test.go
│ └── smtp_logger.go
├── network
│ └── proton.go
├── plan
│ └── plan.go
├── safe
│ └── mutex.go
├── sentry
│ ├── hostarch_darwin.go
│ ├── hostarch_default.go
│ ├── lang_default.go
│ ├── reporter.go
│ └── reporter_test.go
├── service
│ ├── config.go
│ ├── config_test.go
│ └── types.go
├── services
│ ├── imapservice
│ │ ├── api_client.go
│ │ ├── conflicts.go
│ │ ├── conflicts_test.go
│ │ ├── connector.go
│ │ ├── connector_test.go
│ │ ├── helpers.go
│ │ ├── imap_updates.go
│ │ ├── mocks
│ │ │ └── mocks.go
│ │ ├── observabilitymetrics
│ │ │ ├── evtloopmsgevents
│ │ │ │ └── metrics.go
│ │ │ └── syncmsgevents
│ │ │ │ └── metrics.go
│ │ ├── server_manager.go
│ │ ├── service.go
│ │ ├── service_address_events.go
│ │ ├── service_label_events.go
│ │ ├── service_message_events.go
│ │ ├── service_sync_events.go
│ │ ├── shared_cache.go
│ │ ├── shared_identity.go
│ │ ├── shared_labels.go
│ │ ├── sync_build.go
│ │ ├── sync_build_test.go
│ │ ├── sync_message_builder.go
│ │ ├── sync_reporter.go
│ │ ├── sync_state_provider.go
│ │ ├── sync_state_provider_test.go
│ │ ├── sync_update_applier.go
│ │ ├── utils.go
│ │ └── utils_test.go
│ ├── imapsmtpserver
│ │ ├── imap.go
│ │ ├── listener.go
│ │ ├── service.go
│ │ ├── smtp.go
│ │ └── telemetry.go
│ ├── notifications
│ │ ├── metrics.go
│ │ ├── notification_test.go
│ │ ├── service.go
│ │ └── store.go
│ ├── observability
│ │ ├── adapter.go
│ │ ├── adapter_test.go
│ │ ├── distinction_error_types.go
│ │ ├── distinction_utility.go
│ │ ├── heartbeat.go
│ │ ├── plan_utils.go
│ │ ├── service.go
│ │ ├── test_utils.go
│ │ ├── utils.go
│ │ └── utils_test.go
│ ├── orderedtasks
│ │ └── ordered_cancel.go
│ ├── sendrecorder
│ │ ├── recorder.go
│ │ └── recorder_test.go
│ ├── smtp
│ │ ├── accounts.go
│ │ ├── accounts_test.go
│ │ ├── errors.go
│ │ ├── observabilitymetrics
│ │ │ └── metrics.go
│ │ ├── server_manager.go
│ │ ├── service.go
│ │ ├── smtp.go
│ │ ├── smtp_backend.go
│ │ ├── smtp_debug.go
│ │ ├── smtp_default.go
│ │ ├── smtp_packages.go
│ │ ├── smtp_packages_test.go
│ │ ├── smtp_prefs.go
│ │ └── smtp_prefs_test.go
│ ├── syncservice
│ │ ├── api_client.go
│ │ ├── download_cache.go
│ │ ├── handler.go
│ │ ├── handler_test.go
│ │ ├── interfaces.go
│ │ ├── job.go
│ │ ├── job_test.go
│ │ ├── limits.go
│ │ ├── mocks_test.go
│ │ ├── observabilitymetrics
│ │ │ └── metrics.go
│ │ ├── service.go
│ │ ├── stage_apply.go
│ │ ├── stage_apply_test.go
│ │ ├── stage_build.go
│ │ ├── stage_build_test.go
│ │ ├── stage_download.go
│ │ ├── stage_download_test.go
│ │ ├── stage_metadata.go
│ │ ├── stage_metadata_test.go
│ │ ├── stage_output.go
│ │ └── utils.go
│ ├── telemetry
│ │ ├── service.go
│ │ └── service_test.go
│ ├── userevents
│ │ ├── event_controller.go
│ │ ├── event_poll_waiter.go
│ │ ├── event_source.go
│ │ ├── eventid_store.go
│ │ ├── mocks
│ │ │ └── mocks.go
│ │ ├── mocks_test.go
│ │ ├── service.go
│ │ ├── service_handle_event_error_test.go
│ │ ├── service_handle_event_test.go
│ │ ├── service_test.go
│ │ ├── subscribable.go
│ │ ├── subscriber.go
│ │ ├── subscriber_test.go
│ │ └── subscription.go
│ └── useridentity
│ │ ├── auth.go
│ │ ├── mocks
│ │ └── mocks.go
│ │ ├── service.go
│ │ ├── service_test.go
│ │ └── state.go
├── telemetry
│ ├── heartbeat.go
│ ├── heartbeat_test.go
│ ├── mocks
│ │ └── mocks.go
│ ├── repair.go
│ └── types_heartbeat.go
├── try
│ ├── try.go
│ └── try_test.go
├── unleash
│ └── service.go
├── updater
│ ├── channel.go
│ ├── host_default.go
│ ├── host_qa.go
│ ├── install_darwin.go
│ ├── install_default.go
│ ├── key_default.go
│ ├── keyring.go
│ ├── mocks
│ │ └── mocks.go
│ ├── sync.go
│ ├── sync_test.go
│ ├── types_test.go
│ ├── types_version.go
│ ├── updater.go
│ ├── version.go
│ ├── version_test.go
│ └── versioncompare
│ │ ├── compare_darwin.go
│ │ ├── compare_darwin_test.go
│ │ ├── compare_linux.go
│ │ ├── compare_windows.go
│ │ └── types.go
├── user
│ ├── debug.go
│ ├── errors.go
│ ├── keys_test.go
│ ├── migration.go
│ ├── repair_telemetry.go
│ ├── user.go
│ ├── user_check.go
│ ├── user_check_test.go
│ └── user_test.go
├── useragent
│ ├── platform.go
│ ├── platform_darwin.go
│ ├── platform_default.go
│ ├── platform_test.go
│ ├── useragent.go
│ └── useragent_test.go
├── usertypes
│ ├── addressmode.go
│ ├── keys.go
│ ├── types.go
│ └── types_test.go
├── vault
│ ├── certs.go
│ ├── certs_test.go
│ ├── cookies.go
│ ├── cookies_test.go
│ ├── helper.go
│ ├── helper_test.go
│ ├── keychain_settings.go
│ ├── keychain_settings_test.go
│ ├── migrate.go
│ ├── migrate_test.go
│ ├── migrate_v2.3.x.go
│ ├── migrate_v2.4.x.go
│ ├── password_archive.go
│ ├── settings.go
│ ├── settings_test.go
│ ├── token.go
│ ├── types_certs.go
│ ├── types_data.go
│ ├── types_file.go
│ ├── types_password_archive.go
│ ├── types_settings.go
│ ├── types_user.go
│ ├── user.go
│ ├── user_test.go
│ ├── vault.go
│ ├── vault_bench_test.go
│ ├── vault_debug.go
│ └── vault_test.go
└── versioner
│ ├── install.go
│ ├── name_default.go
│ ├── name_windows.go
│ ├── remove.go
│ ├── remove_darwin.go
│ ├── remove_linux.go
│ ├── remove_windows.go
│ ├── util.go
│ ├── version.go
│ ├── version_test.go
│ ├── versioner.go
│ ├── versioner_remove_test.go
│ └── versioner_test.go
├── pkg
├── algo
│ ├── algo.go
│ ├── encode.go
│ ├── hash.go
│ ├── sets.go
│ └── sets_test.go
├── cpc
│ ├── cpc.go
│ └── cpc_test.go
├── dialer
│ └── dial_client.go
├── files
│ ├── removal.go
│ └── removal_test.go
├── keychain
│ ├── helper_darwin.go
│ ├── helper_dbus_linux.go
│ ├── helper_linux.go
│ ├── helper_windows.go
│ ├── keychain.go
│ ├── keychain_darwin.go
│ ├── keychain_default.go
│ ├── keychain_missing.go
│ ├── keychain_test.go
│ └── test_helper.go
├── message
│ ├── build.go
│ ├── build_custom.go
│ ├── build_framework_test.go
│ ├── build_test.go
│ ├── decrypt.go
│ ├── decrypt_and_build.go
│ ├── header.go
│ ├── header_test.go
│ ├── message.go
│ ├── options.go
│ ├── parser.go
│ ├── parser
│ │ ├── handler.go
│ │ ├── parser.go
│ │ ├── parser_test.go
│ │ ├── part.go
│ │ ├── part_test.go
│ │ ├── testdata
│ │ │ ├── complex_structure.eml
│ │ │ ├── forwarding_html_attachment.eml
│ │ │ ├── multipart_alternative.eml
│ │ │ ├── text_html.eml
│ │ │ └── text_html_octet_attachment.eml
│ │ ├── trimmer.go
│ │ ├── trimmer_test.go
│ │ ├── visitor.go
│ │ ├── walker.go
│ │ ├── walker_test.go
│ │ ├── writer.go
│ │ └── writer_test.go
│ ├── parser_test.go
│ └── testdata
│ │ ├── enc-body-structure.eml
│ │ ├── ics_attachment.eml
│ │ ├── incorrect_boundary_w_invalid_character_tuta.eml
│ │ ├── long_header_line.eml
│ │ ├── long_header_line_multiline.eml
│ │ ├── multipart_alternative.eml
│ │ ├── multipart_alternative_latin1.eml
│ │ ├── multipart_alternative_nested.eml
│ │ ├── multipart_alternative_related_inline_image.eml
│ │ ├── multipart_attachment_encoded_no_quote.eml
│ │ ├── multiple_text_parts.eml
│ │ ├── non-encoded-content-transfer-encoding.eml
│ │ ├── pgp-mime-body-html.eml
│ │ ├── pgp-mime-body-plaintext-latin2.eml
│ │ ├── pgp-mime-body-plaintext.eml
│ │ ├── pgp-mime-body-signed-embedded-message-rfc822-with-pubkey.eml
│ │ ├── pgp-mime-body-signed-html-with-pubkey.eml
│ │ ├── pgp-mime-body-signed-html.eml
│ │ ├── pgp-mime-body-signed-multipart-alternative-with-pubkey.eml
│ │ ├── pgp-mime-body-signed-plaintext-with-pubkey.eml
│ │ ├── pgp-mime-body-signed-plaintext.eml
│ │ ├── plaintext-invalid-header.eml
│ │ ├── plaintext-missing-header.eml
│ │ ├── references-comma.eml
│ │ ├── references.eml
│ │ ├── reply-to_no_references.eml
│ │ ├── rfc2047-content-transfer-encoding-bad.eml
│ │ ├── rfc2047-content-transfer-encoding.eml
│ │ ├── text_html.eml
│ │ ├── text_html_7bit.eml
│ │ ├── text_html_embedded_foreign_encoding.eml
│ │ ├── text_html_image_inline.eml
│ │ ├── text_html_image_inline_no_disposition.eml
│ │ ├── text_html_octet_attachment.eml
│ │ ├── text_html_plain_attachment.eml
│ │ ├── text_html_trailing_end_of_mail.eml
│ │ ├── text_plain.eml
│ │ ├── text_plain_7bit.eml
│ │ ├── text_plain_bad_sender.eml
│ │ ├── text_plain_bad_subject.eml
│ │ ├── text_plain_base64.eml
│ │ ├── text_plain_docx_attachment_cyrillic.eml
│ │ ├── text_plain_duplicate_charset.eml
│ │ ├── text_plain_empty_addresses.eml
│ │ ├── text_plain_image_inline.eml
│ │ ├── text_plain_image_inline2.eml
│ │ ├── text_plain_image_inline_attachment_first.eml
│ │ ├── text_plain_image_inline_between_attachment.eml
│ │ ├── text_plain_latin1.eml
│ │ ├── text_plain_latin2_subject.eml
│ │ ├── text_plain_octet_attachment.eml
│ │ ├── text_plain_octet_attachment_bad_2231_filename.eml
│ │ ├── text_plain_octet_attachment_good_2231_filename.eml
│ │ ├── text_plain_octet_attachment_name_conflict.eml
│ │ ├── text_plain_octet_attachment_name_in_contenttype.eml
│ │ ├── text_plain_pdf_attachment_cyrillic.eml
│ │ ├── text_plain_plain_attachment.eml
│ │ ├── text_plain_plain_attachment_latin1.eml
│ │ ├── text_plain_plain_attachment_latin2.eml
│ │ ├── text_plain_rfc822_attachment.eml
│ │ ├── text_plain_unknown_latin1.eml
│ │ ├── text_plain_unknown_latin2.eml
│ │ ├── text_plain_utf8.eml
│ │ ├── text_plain_utf8_reply_to_and_x_forward.eml
│ │ ├── text_plain_utf8_subject.eml
│ │ ├── text_plain_xml_attachment_cp1250.eml
│ │ └── wrong_base64.eml
├── mime
│ ├── Changelog.md
│ ├── encoding.go
│ ├── encoding_test.go
│ ├── mediaType.go
│ └── utf7Decoder.go
├── mobileconfig
│ ├── config.go
│ └── template.go
├── ports
│ ├── ports.go
│ └── ports_test.go
├── restarter
│ ├── restarter.go
│ ├── restarter_test.go
│ ├── start_default.go
│ └── start_windows.go
├── sum
│ ├── sum.go
│ └── sum_test.go
└── tar
│ └── tar.go
├── release-notes
├── bridge_early.md
└── bridge_stable.md
├── tests
├── README.md
├── _features
│ ├── start.feature
│ └── users
│ │ └── delete.feature
├── api_test.go
├── bdd_test.go
├── bridge_test.go
├── collector_test.go
├── contact_test.go
├── ctx_bridge_test.go
├── ctx_heartbeat_test.go
├── ctx_helper_test.go
├── ctx_imap_test.go
├── ctx_reporter_test.go
├── ctx_smtp_test.go
├── ctx_test.go
├── diff.go
├── diff_test.go
├── e2e
│ └── ui_tests
│ │ └── windows_os
│ │ ├── ProtonMailBridge.UI.Tests.csproj
│ │ ├── Results
│ │ ├── HelpMenuResults.cs
│ │ ├── HomeResult.cs
│ │ └── SettingsMenuResults.cs
│ │ ├── TestSession.cs
│ │ ├── Tests
│ │ ├── HelpMenuTests.cs
│ │ ├── LoginLogoutTests.cs
│ │ ├── SettingsMenuTests.cs
│ │ └── ZeroPercentUpdateTest.cs
│ │ ├── TestsHelper
│ │ ├── TestData.cs
│ │ └── TestUserData.cs
│ │ ├── UIActions.cs
│ │ ├── Windows
│ │ ├── HelpMenuWindow.cs
│ │ ├── HomeWindow.cs
│ │ ├── LoginWindow.cs
│ │ ├── SettingsMenuWindow.cs
│ │ └── ZeroPercentUpdateWindow.cs
│ │ ├── app.config
│ │ └── ui_tests.sln
├── environment_test.go
├── external_test.go
├── fast.go
├── features
│ ├── bridge
│ │ ├── default_ports.feature
│ │ ├── heartbeat.feature
│ │ └── updates_legacy.feature
│ ├── external
│ │ ├── html_external_to_proton.feature
│ │ ├── html_proton_to_external.feature
│ │ ├── plain_external_to_proton.feature
│ │ └── plain_proton_to_external.feature
│ ├── frontend
│ │ └── frontend.feature
│ ├── imap
│ │ ├── addressmode.feature
│ │ ├── auth.feature
│ │ ├── id.feature
│ │ ├── mailbox
│ │ │ ├── create.feature
│ │ │ ├── delete.feature
│ │ │ ├── hide_all_mail.feature
│ │ │ ├── info.feature
│ │ │ ├── list.feature
│ │ │ ├── rename.feature
│ │ │ ├── rename_hiearchy.feature
│ │ │ └── select.feature
│ │ ├── message
│ │ │ ├── copy.feature
│ │ │ ├── create.feature
│ │ │ ├── delete.feature
│ │ │ ├── delete_from_trash.feature
│ │ │ ├── drafts.feature
│ │ │ ├── fetch.feature
│ │ │ ├── import.feature
│ │ │ ├── import_key.feature
│ │ │ ├── move.feature
│ │ │ ├── move_without_support.feature
│ │ │ ├── scheduled.feature
│ │ │ ├── state.feature
│ │ │ └── store.feature
│ │ ├── migration.feature
│ │ └── ports.feature
│ ├── observability
│ │ ├── all_metrics.feature
│ │ ├── gluon_metrics.feature
│ │ └── remote_notification.feature
│ ├── smtp
│ │ ├── addressmode.feature
│ │ ├── auth.feature
│ │ ├── init.feature
│ │ ├── ports.feature
│ │ └── send
│ │ │ ├── attachment.feature
│ │ │ ├── bcc.feature
│ │ │ ├── embedded_message.feature
│ │ │ ├── failures.feature
│ │ │ ├── failures_disabled.feature
│ │ │ ├── html.feature
│ │ │ ├── html_att.feature
│ │ │ ├── html_to_internal.feature
│ │ │ ├── inline.feature
│ │ │ ├── mixed_case.feature
│ │ │ ├── one_account_to_another.feature
│ │ │ ├── plain.feature
│ │ │ ├── plain_att.feature
│ │ │ ├── plain_to_internal.feature
│ │ │ ├── same_message.feature
│ │ │ ├── send_append.feature
│ │ │ ├── send_reply.feature
│ │ │ ├── sender_key.feature
│ │ │ └── two_messages.feature
│ └── user
│ │ ├── account.feature
│ │ ├── addressmode.feature
│ │ ├── contact.feature
│ │ ├── delete.feature
│ │ ├── delete_imap.feature
│ │ ├── kb_article_suggestions.feature
│ │ ├── login.feature
│ │ ├── relogin.feature
│ │ ├── report_problem.feature
│ │ ├── revoke.feature
│ │ ├── sync.feature
│ │ ├── sync_high_number.feature
│ │ └── telemetry.feature
├── frontend_test.go
├── heartbeat_test.go
├── imap_test.go
├── main_test.go
├── observability_test.go
├── smtp_test.go
├── steps_test.go
├── testdata
│ ├── html
│ │ └── foreign_ascii_subject_body.template.eml
│ ├── keys
│ │ └── pubkey.asc
│ ├── multipart
│ │ ├── mixed_with_attachment_encoded.eml
│ │ ├── mixed_with_attachment_encoded_no_quote.eml
│ │ └── mixed_with_attachment_no_quote.eml
│ └── plain
│ │ ├── text_plain_latin1.eml
│ │ ├── text_plain_multiple_attachments.template.eml
│ │ ├── text_plain_unknown_latin1.eml
│ │ └── text_plain_wrong_latin1.eml
├── types_test.go
├── user_test.go
└── utils
│ └── gmail
│ ├── service.go
│ └── tokenservice
│ └── tokenservice.go
└── utils
├── QTBUG-88600
├── README.txt
├── cocoa.patch
└── libqcocoa.dylib
├── bridge-rollout
├── README.md
└── bridge-rollout.go
├── bridge_app_version.ps1
├── bridge_app_version.sh
├── changelog_linter.sh
├── coverage.sh
├── credits.sh
├── debug
└── debug_assemble.go
├── dependency_license.sh
├── dxtn
├── dxtn.cbp
├── dxtn.layout
├── main.cpp
└── main.h
├── export_icons.sh
├── get_revision.sh
├── githooks
└── pre-push
├── govulncheck.sh
├── hasher
└── main.go
├── kb-suggester
└── kb-suggester.go
├── keyring.go
├── license_header.txt
├── missing_license.sh
├── port-blocker
└── port-blocker.go
├── rebranding.sh
├── release_notes.css
├── release_notes.sh
├── remove-bridge
├── README.md
├── Remove-Bridge.ps1
└── remove_bridge
├── remove_non_relative_links_darwin.sh
├── smtp-send
└── main.go
├── sync_bench.py
├── update_test_keys.sh
├── validate_bug_report_file.py
├── vault-editor
├── README.md
└── main.go
└── versioner
└── main.go
/.gitattributes:
--------------------------------------------------------------------------------
1 | unreleased.md merge=union
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # System files
2 | *.app
3 | *.DS_Store
4 |
5 | # Editor files
6 | .*.sw?
7 | *~
8 | .idea
9 | .vscode
10 | .vs
11 |
12 | # Test files
13 | godog.test
14 | debug.test
15 | coverage.html
16 | gobinsec-cache*.yml
17 |
18 | # Run files
19 | mem.pprof
20 |
21 | # Auto generated
22 | internal/**/credits.go
23 | vendor
24 | vendor-cache
25 | /main.go
26 |
27 |
28 | # Build files
29 | /launcher-*
30 | /bridge_*_*.tgz
31 | /ie_*_*.tgz
32 | /versioner
33 | /hasher
34 | cmd/Desktop-Bridge/deploy
35 | cmd/Import-Export/deploy
36 | proton-bridge
37 | cmd/Desktop-Bridge/*.exe
38 | cmd/launcher/*.exe
39 | bin/
40 | obj/
41 |
42 | # Jetbrains (CLion, Golang) cmake build dirs
43 | cmake-build-*/
44 |
45 | # Doxygen doc files
46 | _doc/
47 |
48 | # gRPC auto-generated C++ source files
49 | *.pb.cc
50 | *.pb.h
51 |
--------------------------------------------------------------------------------
/.gitlab/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * inbox-desktop-approvers
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "submodules/vcpkg"]
2 | path = extern/vcpkg
3 | url = https://github.com/Microsoft/vcpkg.git
4 |
--------------------------------------------------------------------------------
/.grype.yaml:
--------------------------------------------------------------------------------
1 | # Check out for configuration details: https://github.com/anchore/grype?tab=readme-ov-file#configuration
2 | fail-on-severity: "medium"
--------------------------------------------------------------------------------
/TODO.md:
--------------------------------------------------------------------------------
1 | - when cache is full, we need to stop the watcher? don't want to keep downloading messages and throwing them away when we try to cache them.
2 |
--------------------------------------------------------------------------------
/ci/report.yml:
--------------------------------------------------------------------------------
1 |
2 | ---
3 |
4 | include:
5 | - project: 'tpe/testmo-reporter'
6 | ref: master
7 | file: '/scenarios/testmo-script.yml'
8 |
9 | testmo-upload:
10 | stage: report
11 | extends:
12 | - .testmo-upload
13 | - .rules-branch-manual-scheduled-and-test-branch-always
14 | needs:
15 | - test-integration-nightly
16 | before_script: []
17 | variables:
18 | TESTMO_TOKEN: "$TESTMO_TOKEN"
19 | TESTMO_URL: "https://proton.testmo.net"
20 | PROJECT_ID: "9"
21 | NAME: "Nightly integration tests"
22 | MILESTONE: "Nightly integration tests"
23 | SOURCE: "test-integration-nightly"
24 | TAGS: "$CI_COMMIT_REF_SLUG"
25 | RESULT_FOLDER: "tests/result/*.xml"
26 |
--------------------------------------------------------------------------------
/ci/setup.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | include:
4 | - project: 'go/bridge-internal'
5 | ref: 'master'
6 | file: 'ci/runners-setup.yml'
7 |
8 |
--------------------------------------------------------------------------------
/dist/Bridge.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/dist/Bridge.icns
--------------------------------------------------------------------------------
/dist/bridge.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/dist/bridge.ico
--------------------------------------------------------------------------------
/dist/info.rc:
--------------------------------------------------------------------------------
1 | #define STRINGIZE_(x) #x
2 | #define STRINGIZE(x) STRINGIZE_(x)
3 |
4 | IDI_ICON1 ICON DISCARDABLE STRINGIZE(ICO_FILE)
5 |
6 | #define FILE_COMMENTS "Proton Mail Bridge is a desktop application that runs in the background, encrypting and decrypting messages as they enter and leave your computer."
7 | #define FILE_DESCRIPTION "Proton Mail Bridge"
8 | #define INTERNAL_NAME STRINGIZE(EXE_NAME)
9 | #define PRODUCT_NAME "Proton Mail Bridge for Windows"
10 |
11 | #define LEGAL_COPYRIGHT "(C) " STRINGIZE(YEAR) " Proton AG"
12 |
13 | 1 VERSIONINFO
14 | FILEVERSION FILE_VERSION_COMMA,0
15 | PRODUCTVERSION FILE_VERSION_COMMA,0
16 | BEGIN
17 | BLOCK "StringFileInfo"
18 | BEGIN
19 | BLOCK "040904b0"
20 | BEGIN
21 | VALUE "Comments", FILE_COMMENTS
22 | VALUE "CompanyName", "Proton AG"
23 | VALUE "FileDescription", FILE_DESCRIPTION
24 | VALUE "FileVersion", STRINGIZE(FILE_VERSION)
25 | VALUE "InternalName", INTERNAL_NAME
26 | VALUE "LegalCopyright", LEGAL_COPYRIGHT
27 | VALUE "OriginalFilename", STRINGIZE(ORIGINAL_FILE_NAME)
28 | VALUE "ProductName", PRODUCT_NAME
29 | VALUE "ProductVersion", STRINGIZE(PRODUCT_VERSION)
30 | END
31 | END
32 | BLOCK "VarFileInfo"
33 | BEGIN
34 | VALUE "Translation", 0x0409, 0x04B0
35 | END
36 | END
37 |
--------------------------------------------------------------------------------
/dist/proton-bridge.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Type=Application
3 | Version=1.1
4 | Name=Proton Mail Bridge
5 | GenericName=Proton Mail Bridge for Linux
6 | Comment=Proton Mail Bridge is a desktop application that runs in the background, encrypting and decrypting messages as they enter and leave your computer.
7 | Icon=protonmail-bridge
8 | Exec=protonmail-bridge
9 | Terminal=false
10 | Categories=Office;Email;Network
11 | StartupWMClass=Proton Mail Bridge
12 |
--------------------------------------------------------------------------------
/dist/raw/mac_icon_128x128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/dist/raw/mac_icon_128x128.png
--------------------------------------------------------------------------------
/dist/raw/mac_icon_128x128@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/dist/raw/mac_icon_128x128@2x.png
--------------------------------------------------------------------------------
/dist/raw/mac_icon_16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/dist/raw/mac_icon_16x16.png
--------------------------------------------------------------------------------
/dist/raw/mac_icon_16x16@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/dist/raw/mac_icon_16x16@2x.png
--------------------------------------------------------------------------------
/dist/raw/mac_icon_256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/dist/raw/mac_icon_256x256.png
--------------------------------------------------------------------------------
/dist/raw/mac_icon_256x256@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/dist/raw/mac_icon_256x256@2x.png
--------------------------------------------------------------------------------
/dist/raw/mac_icon_32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/dist/raw/mac_icon_32x32.png
--------------------------------------------------------------------------------
/dist/raw/mac_icon_32x32@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/dist/raw/mac_icon_32x32@2x.png
--------------------------------------------------------------------------------
/dist/raw/mac_icon_512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/dist/raw/mac_icon_512x512.png
--------------------------------------------------------------------------------
/dist/raw/mac_icon_512x512@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/dist/raw/mac_icon_512x512@2x.png
--------------------------------------------------------------------------------
/dist/raw/win+lin_icon_256x256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/dist/raw/win+lin_icon_256x256.png
--------------------------------------------------------------------------------
/internal/app/testdata/with_keys/protonmail/bridge/cert.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN CERTIFICATE-----
--------------------------------------------------------------------------------
/internal/app/testdata/with_keys/protonmail/bridge/key.pem:
--------------------------------------------------------------------------------
1 | -----BEGIN RSA PRIVATE KEY-----
--------------------------------------------------------------------------------
/internal/bridge/api_default.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build !build_qa && !test_integration
19 |
20 | package bridge
21 |
22 | import (
23 | "net/http"
24 |
25 | "github.com/Masterminds/semver/v3"
26 | "github.com/ProtonMail/gluon/async"
27 | "github.com/ProtonMail/go-proton-api"
28 | )
29 |
30 | // newAPIOptions returns a set of API options for the given parameters.
31 | func newAPIOptions(
32 | apiURL string,
33 | version *semver.Version,
34 | cookieJar http.CookieJar,
35 | transport http.RoundTripper,
36 | panicHandler async.PanicHandler,
37 | ) []proton.Option {
38 | return defaultAPIOptions(apiURL, version, cookieJar, transport, panicHandler)
39 | }
40 |
--------------------------------------------------------------------------------
/internal/bridge/errors.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package bridge
19 |
20 | import "errors"
21 |
22 | var (
23 | ErrVaultInsecure = errors.New("the vault is insecure")
24 | ErrVaultCorrupt = errors.New("the vault is corrupt")
25 | ErrWatchUpdates = errors.New("failed to watch for updates")
26 |
27 | ErrNoSuchUser = errors.New("no such user")
28 | ErrUserAlreadyExists = errors.New("user already exists")
29 | ErrUserAlreadyLoggedIn = errors.New("the user is already logged in")
30 | ErrNotImplemented = errors.New("not implemented")
31 |
32 | ErrSizeTooLarge = errors.New("file is too big")
33 | )
34 |
--------------------------------------------------------------------------------
/internal/bridge/imapsmtp_telemetry.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package bridge
19 |
20 | type bridgeIMAPSMTPTelemetry struct {
21 | b *Bridge
22 | }
23 |
24 | func (b bridgeIMAPSMTPTelemetry) SetCacheLocation(s string) {
25 | b.b.heartbeat.SetCacheLocation(s)
26 | }
27 |
--------------------------------------------------------------------------------
/internal/bridge/keychain.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package bridge
19 |
20 | import "golang.org/x/exp/maps"
21 |
22 | func (bridge *Bridge) GetHelpersNames() []string {
23 | return maps.Keys(bridge.keychains.GetHelpers())
24 | }
25 |
--------------------------------------------------------------------------------
/internal/bridge/locations.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package bridge
19 |
20 | func (bridge *Bridge) GetLogsPath() (string, error) {
21 | return bridge.locator.ProvideLogsPath()
22 | }
23 |
24 | func (bridge *Bridge) GetLicenseFilePath() string {
25 | return bridge.locator.GetLicenseFilePath()
26 | }
27 |
28 | func (bridge *Bridge) GetDependencyLicensesLink() string {
29 | return bridge.locator.GetDependencyLicensesLink()
30 | }
31 |
--------------------------------------------------------------------------------
/internal/bridge/main_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package bridge_test
19 |
20 | import (
21 | "os"
22 | "testing"
23 |
24 | "github.com/sirupsen/logrus"
25 | "go.uber.org/goleak"
26 | )
27 |
28 | func TestMain(m *testing.M) {
29 | if level := os.Getenv("BRIDGE_LOG_LEVEL"); level != "" {
30 | if parsed, err := logrus.ParseLevel(level); err == nil {
31 | logrus.SetLevel(parsed)
32 | }
33 | }
34 |
35 | goleak.VerifyTestMain(m, goleak.IgnoreCurrent())
36 | }
37 |
--------------------------------------------------------------------------------
/internal/bridge/testdata/text-plain.eml:
--------------------------------------------------------------------------------
1 | To: recipient@pm.me
2 | From: sender@pm.me
3 | Subject: Test
4 | Content-Type: text/plain; charset=utf-8
5 |
6 | Test
--------------------------------------------------------------------------------
/internal/bridge/tls.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package bridge
19 |
20 | func (bridge *Bridge) GetBridgeTLSCert() ([]byte, []byte) {
21 | return bridge.vault.GetBridgeTLSCert()
22 | }
23 |
24 | func (bridge *Bridge) SetBridgeTLSCertPath(certPath, keyPath string) error {
25 | return bridge.vault.SetBridgeTLSCertPath(certPath, keyPath)
26 | }
27 |
--------------------------------------------------------------------------------
/internal/certs/cert_store_linux.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package certs
19 |
20 | func osSupportCertInstall() bool {
21 | return false
22 | }
23 |
24 | func installCert([]byte) error {
25 | return nil // Linux doesn't have a root cert store.
26 | }
27 |
28 | func uninstallCert([]byte) error {
29 | return nil // Linux doesn't have a root cert store.
30 | }
31 |
32 | func isCertInstalled([]byte) bool {
33 | return false
34 | }
35 |
--------------------------------------------------------------------------------
/internal/certs/cert_store_windows.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package certs
19 |
20 | func osSupportCertInstall() bool {
21 | return false
22 | }
23 |
24 | func installCert([]byte) error {
25 | return nil // NOTE(GODT-986): Install certs to root cert store?
26 | }
27 |
28 | func uninstallCert([]byte) error {
29 | return nil // NOTE(GODT-986): Uninstall certs from root cert store?
30 | }
31 |
32 | func isCertInstalled([]byte) bool {
33 | return false
34 | }
35 |
--------------------------------------------------------------------------------
/internal/constants/host_default.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build !build_qa
19 |
20 | package constants
21 |
22 | // APIHost is our API address.
23 | const APIHost = "https://mail-api.proton.me"
24 |
--------------------------------------------------------------------------------
/internal/constants/host_qa.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build build_qa
19 |
20 | package constants
21 |
22 | import "os"
23 |
24 | // APIHost is our API address.
25 | var APIHost = "https://mail-api.proton.me"
26 |
27 | func init() {
28 | if apiHost := os.Getenv("BRIDGE_HOST_URL"); apiHost != "" {
29 | APIHost = apiHost
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/internal/constants/update_default.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build !build_qa
19 | // +build !build_qa
20 |
21 | package constants
22 |
23 | import "time"
24 |
25 | // UpdateCheckInterval defines how often we check for new version.
26 | const UpdateCheckInterval = time.Hour
27 |
--------------------------------------------------------------------------------
/internal/constants/update_qa.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build build_qa
19 | // +build build_qa
20 |
21 | package constants
22 |
23 | import "time"
24 |
25 | // UpdateCheckInterval defines how often we check for new version
26 | const UpdateCheckInterval = time.Duration(5 * time.Minute)
27 |
--------------------------------------------------------------------------------
/internal/constants/version_default.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build !build_qa
19 | // +build !build_qa
20 |
21 | package constants
22 |
23 | import "fmt"
24 |
25 | // AppVersion returns the full rendered version of the app (to be used in request headers).
26 | func AppVersion(version string) string {
27 | return fmt.Sprintf("%v-%v@%v", getAPIOS(), AppName, version)
28 | }
29 |
--------------------------------------------------------------------------------
/internal/constants/version_qa.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build build_qa
19 | // +build build_qa
20 |
21 | package constants
22 |
23 | import (
24 | "fmt"
25 |
26 | "github.com/Masterminds/semver/v3"
27 | )
28 |
29 | // AppVersion returns the full rendered version of the app (to be used in request headers).
30 | func AppVersion(version string) string {
31 | ver, _ := semver.MustParse(version).SetPrerelease("dev")
32 |
33 | return fmt.Sprintf("%v-%v@%v", getAPIOS(), AppName, ver.String())
34 | }
35 |
--------------------------------------------------------------------------------
/internal/constants/version_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package constants
19 |
20 | import (
21 | "testing"
22 |
23 | "github.com/Masterminds/semver/v3"
24 | "github.com/stretchr/testify/require"
25 | )
26 |
27 | func TestPrereleaseSemver(t *testing.T) {
28 | ver, err := semver.MustParse("2.3.0+qa").SetPrerelease("dev")
29 | require.NoError(t, err)
30 |
31 | require.Equal(t, "2.3.0-dev+qa", ver.String())
32 |
33 | ver, err = semver.MustParse("2.3.0-dev+qa").SetPrerelease("dev")
34 | require.NoError(t, err)
35 |
36 | require.Equal(t, "2.3.0-dev+qa", ver.String())
37 | }
38 |
--------------------------------------------------------------------------------
/internal/dialer/dialer_pinning_checker_qa.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build build_qa
19 |
20 | package dialer
21 |
22 | import "net"
23 |
24 | // CheckCertificate returns whether the connection presents a known TLS certificate.
25 | // The QA implementation always returns nil.
26 | func (p *TLSPinChecker) CheckCertificate(conn net.Conn) error {
27 | return nil
28 | }
29 |
--------------------------------------------------------------------------------
/internal/dialer/dialer_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package dialer
19 |
20 | import (
21 | "testing"
22 |
23 | "golang.org/x/net/http/httpproxy"
24 | )
25 |
26 | // skipIfProxyIsSet skips the tests if HTTPS proxy is set.
27 | // Should be used for tests depending on proper certificate checks which
28 | // is not possible under our CI setup.
29 | func skipIfProxyIsSet(t *testing.T) {
30 | if httpproxy.FromEnvironment().HTTPSProxy != "" {
31 | t.SkipNow()
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/internal/errors.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package internal
19 |
20 | import (
21 | "errors"
22 | "fmt"
23 | )
24 |
25 | // ErrCause returns the cause of the error, the inner-most error in the wrapped chain.
26 | func ErrCause(err error) error {
27 | cause := err
28 |
29 | for errors.Unwrap(cause) != nil {
30 | cause = errors.Unwrap(cause)
31 | }
32 |
33 | return cause
34 | }
35 |
36 | func ErrCauseType(err error) string {
37 | return fmt.Sprintf("%T", ErrCause(err))
38 | }
39 |
--------------------------------------------------------------------------------
/internal/events/connection.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package events
19 |
20 | type TLSIssue struct {
21 | eventBase
22 | }
23 |
24 | func (event TLSIssue) String() string {
25 | return "TLSIssue"
26 | }
27 |
28 | type ConnStatusUp struct {
29 | eventBase
30 | }
31 |
32 | func (event ConnStatusUp) String() string {
33 | return "ConnStatusUp"
34 | }
35 |
36 | type ConnStatusDown struct {
37 | eventBase
38 | }
39 |
40 | func (event ConnStatusDown) String() string {
41 | return "ConnStatusDown"
42 | }
43 |
--------------------------------------------------------------------------------
/internal/events/error.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package events
19 |
20 | import "fmt"
21 |
22 | type Error struct {
23 | eventBase
24 |
25 | Error error
26 | }
27 |
28 | func (event Error) String() string {
29 | return fmt.Sprintf("Error: %s", event.Error)
30 | }
31 |
--------------------------------------------------------------------------------
/internal/events/raise.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package events
19 |
20 | type Raise struct {
21 | eventBase
22 | }
23 |
24 | func (event Raise) String() string {
25 | return "Raise"
26 | }
27 |
--------------------------------------------------------------------------------
/internal/focus/proto/focus.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | // Package proto provides the gRPC definition of the focus service.
19 | package proto
20 |
21 | //go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative focus.proto
22 |
--------------------------------------------------------------------------------
/internal/frontend/.gitignore:
--------------------------------------------------------------------------------
1 | # Auto generated
2 | moc.cpp
3 | moc.go
4 | moc.h
5 | moc_cgo_*.go
6 | moc_moc.h
7 | rcc.cpp
8 | rcc.qrc
9 | rcc_cgo_*.go
10 | *.qmlc
11 |
12 | # Generated file
13 | bridge-gui/bridge-gui/BuildConfig.h
14 | bridge-gui/bridge-gui/Resources.rc
15 |
--------------------------------------------------------------------------------
/internal/frontend/Makefile.local:
--------------------------------------------------------------------------------
1 | FILES=$(shell find . -iname 'rcc.qrc')
2 | FILES+=$(shell find . -iname 'rcc.cpp')
3 | FILES+=$(shell find . -iname 'rcc_cgo*.go')
4 |
5 | FILES+=$(shell find . -iname 'moc.go')
6 | FILES+=$(shell find . -iname 'moc.cpp')
7 | FILES+=$(shell find . -iname 'moc.h')
8 | FILES+=$(shell find . -iname 'moc_cgo*.go')
9 |
10 | FILES+=$(shell find ./qml -iname '*.qmlc')
11 |
12 | clean:
13 | rm -f ${FILES}
14 |
15 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | # Copyright (c) 2022 Proton AG
2 | #
3 | # This file is part of Proton Mail Bridge.
4 | #
5 | # Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # Proton Mail Bridge is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with Proton Mail Bridge. If not, see .
17 |
18 |
19 | cmake_minimum_required(VERSION 3.22)
20 |
21 |
22 | #*****************************************************************************************************************************************************
23 | # Project
24 | #*****************************************************************************************************************************************************
25 | set(BRIDGE_REPO_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/../../..")
26 | include("BridgeSetup.cmake")
27 |
28 | project(frontend)
29 |
30 | add_subdirectory(bridgepp)
31 | add_subdirectory(bridge-gui)
32 | add_subdirectory(bridge-gui-tester)
33 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/FindQt.cmake:
--------------------------------------------------------------------------------
1 | find_program(QMAKE_EXE NAMES "qmake" "qmake6")
2 | if (NOT QMAKE_EXE)
3 | message(FATAL_ERROR "Could not locate qmake executable, make sure you have Qt 6 installed in that qmake is in your PATH environment variable.")
4 | endif()
5 | message(STATUS "Found qmake at ${QMAKE_EXE}")
6 | execute_process(COMMAND "${QMAKE_EXE}" -query QT_INSTALL_PREFIX OUTPUT_VARIABLE QT_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
7 |
8 | set(CMAKE_PREFIX_PATH ${QT_DIR} ${CMAKE_PREFIX_PATH})
9 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui-tester/.lldbinit:
--------------------------------------------------------------------------------
1 | # The following fix an issue happening using LLDB with OpenSSL 3.1 on ARM64 architecture. (GODT-2680)
2 | # WARNING: this file is ignored if you do not enable reading lldb config from cwd in ~/.lldbinit (`settings set target.load-cwd-lldbinit true`)
3 | settings set platform.plugin.darwin.ignored-exceptions EXC_BAD_INSTRUCTION
4 | process handle SIGILL -n false -p true -s false
5 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui-tester/Cert.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 |
19 | #ifndef BRIDGE_GUI_TESTER_CERT_H
20 | #define BRIDGE_GUI_TESTER_CERT_H
21 |
22 |
23 | extern QString const testTLSCert; ///< The test TLS Cert used by the app, in PEM format.
24 | extern QString const testTLSKey; ///< The test TLS Key used by the app, in PEM format.
25 |
26 |
27 | #endif //BRIDGE_GUI_TESTER_CERT_H
28 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui-tester/Pch.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 |
19 | #ifndef BRIDGE_GUI_PCH_H
20 | #define BRIDGE_GUI_PCH_H
21 |
22 |
23 | #include
24 | #include
25 | #include
26 | #include "AppController.h"
27 |
28 |
29 | #endif // BRIDGE_GUI_PCH_H
30 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/.lldbinit:
--------------------------------------------------------------------------------
1 | # The following fix an issue happening using LLDB with OpenSSL 3.1 on ARM64 architecture. (GODT-2680)
2 | # WARNING: this file is ignored if you do not enable reading lldb config from cwd in ~/.lldbinit (`settings set target.load-cwd-lldbinit true`)
3 | settings set platform.plugin.darwin.ignored-exceptions EXC_BAD_INSTRUCTION
4 | process handle SIGILL -n false -p true -s false
5 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/ClipboardProxy.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | // This file is part of Proton Mail Bridge.
3 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU General Public License as published by
5 | // the Free Software Foundation, either version 3 of the License, or
6 | // (at your option) any later version.
7 | // Proton Mail Bridge is distributed in the hope that it will be useful,
8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | // GNU General Public License for more details.
11 | // You should have received a copy of the GNU General Public License
12 | // along with Proton Mail Bridge. If not, see .
13 | #include "ClipboardProxy.h"
14 |
15 | // The following definitions were taken and adapted from:
16 | // https://stackoverflow.com/questions/40092352/passing-qclipboard-to-qml
17 | // Author: krzaq
18 |
19 | ClipboardProxy::ClipboardProxy(QClipboard* c) : clipboard(c) {
20 | connect(clipboard, &QClipboard::dataChanged, this, &ClipboardProxy::textChanged);
21 | }
22 |
23 | QString ClipboardProxy::text() const {
24 | return clipboard->text();
25 | }
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/ClipboardProxy.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | // This file is part of Proton Mail Bridge.
3 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU General Public License as published by
5 | // the Free Software Foundation, either version 3 of the License, or
6 | // (at your option) any later version.
7 | // Proton Mail Bridge is distributed in the hope that it will be useful,
8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | // GNU General Public License for more details.
11 | // You should have received a copy of the GNU General Public License
12 | // along with Proton Mail Bridge. If not, see .
13 | #ifndef BRIDGE_GUI_CLIPBOARDPROXY_H
14 | #define BRIDGE_GUI_CLIPBOARDPROXY_H
15 |
16 | // The following class declarations were taken and adapted from:
17 | // https://stackoverflow.com/questions/40092352/passing-qclipboard-to-qml
18 | // Author: krzaq
19 |
20 |
21 | class ClipboardProxy : public QObject
22 | {
23 | Q_OBJECT
24 | Q_PROPERTY(QString text READ text NOTIFY textChanged)
25 | public:
26 | explicit ClipboardProxy(QClipboard*);
27 |
28 | QString text() const;
29 |
30 | signals:
31 | void textChanged();
32 |
33 | private:
34 | QClipboard* clipboard;
35 | };
36 |
37 |
38 | #endif //BRIDGE_GUI_CLIPBOARDPROXY_H
39 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/LogUtils.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 |
19 | #ifndef BRIDGE_GUI_LOG_UTILS_H
20 | #define BRIDGE_GUI_LOG_UTILS_H
21 |
22 |
23 | #include
24 |
25 |
26 | bridgepp::Log &initLog(); ///< Initialize the application log.
27 |
28 |
29 | #endif //BRIDGE_GUI_LOG_UTILS_H
30 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/MacOS/DockIcon.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 |
19 |
20 |
21 | #ifndef Q_OS_MACOS
22 |
23 |
24 | void setDockIconVisibleState(bool visible) { Q_UNUSED(visible) }
25 |
26 |
27 | bool getDockIconVisibleState() { return true; }
28 |
29 |
30 | #endif
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/MacOS/DockIcon.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 |
19 | #ifndef BRIDGE_GUI_DOCK_ICON_H
20 | #define BRIDGE_GUI_DOCK_ICON_H
21 |
22 |
23 | void setDockIconVisibleState(bool visible); ///< Set the DOCK icon visibility state
24 | bool getDockIconVisibleState(); ///< Get the Dock icon visibility state
25 |
26 |
27 | #endif // #ifndef BRIDGE_GUI_DOCK_ICON_H
28 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/MacOS/SecondInstance.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 |
19 | #ifndef BRIDGE_GUI_APP_DELEGATE_H
20 | #define BRIDGE_GUI_APP_DELEGATE_H
21 | #ifdef Q_OS_MACOS
22 |
23 |
24 | void registerSecondInstanceHandler();
25 |
26 |
27 | #endif // Q_OS_MACOS
28 | #endif //BRIDGE_GUI_APP_DELEGATE_H
29 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/Pch.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 |
19 | #ifndef BRIDGE_GUI_PCH_H
20 | #define BRIDGE_GUI_PCH_H
21 |
22 |
23 | #include
24 | #include
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include
31 |
32 |
33 | #endif // BRIDGE_GUI_PCH_H
34 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/Resources.rc.in:
--------------------------------------------------------------------------------
1 | IDI_ICON1 ICON DISCARDABLE "${BRIDGE_REPO_ROOT}/dist/bridge.ico"
2 |
3 | 1 VERSIONINFO
4 | FILEVERSION ${BRIDGE_APP_VERSION_COMMA}
5 | PRODUCTVERSION ${BRIDGE_APP_VERSION_COMMA}
6 | BEGIN
7 | BLOCK "StringFileInfo"
8 | BEGIN
9 | BLOCK "040904b0"
10 | BEGIN
11 | VALUE "Comments", "Proton Mail Bridge is a desktop application that runs in the background, encrypting and decrypting messages as they enter and leave your computer."
12 | VALUE "CompanyName", "${BRIDGE_VENDOR}"
13 | VALUE "FileDescription", "${BRIDGE_APP_FULL_NAME}"
14 | VALUE "FileVersion", "${BRIDGE_APP_VERSION_COMMA}"
15 | VALUE "InternalName", "${PROJECT_NAME}.exe"
16 | VALUE "LegalCopyright", "(C) ${BRIDGE_BUILD_YEAR} ${BRIDGE_VENDOR}"
17 | VALUE "OriginalFilename", "${PROJECT_NAME}.exe"
18 | VALUE "ProductName", "${BRIDGE_APP_FULL_NAME} for Windows"
19 | VALUE "ProductVersion", "${BRIDGE_APP_VERSION}"
20 | END
21 | END
22 | BLOCK "VarFileInfo"
23 | BEGIN
24 | VALUE "Translation", 0x0409, 0x04B0
25 | END
26 | END
27 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/SentryUtils.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | #ifndef BRIDGE_GUI_SENTRYUTILS_H
19 | #define BRIDGE_GUI_SENTRYUTILS_H
20 |
21 |
22 | #include
23 |
24 | void initSentry();
25 | QByteArray getProtectedHostname();
26 | void setSentryReportScope();
27 | sentry_options_t* newSentryOptions(const char * sentryDNS, const char * cacheDir);
28 | sentry_uuid_t reportSentryEvent(sentry_level_t level, const char *message);
29 | sentry_uuid_t reportSentryException(QString const& message, bridgepp::Exception const exception);
30 |
31 |
32 | #endif //BRIDGE_GUI_SENTRYUTILS_H
33 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/Notifications/qmldir:
--------------------------------------------------------------------------------
1 | module Notifications
2 | depends QtQml 2.12
3 |
4 | Notifications 1.0 Notifications.qml
5 | NotificationFilter 1.0 NotificationFilter.qml
6 | Notification 1.0 Notification.qml
7 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/Proton/Action.qml:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | // This file is part of Proton Mail Bridge.
3 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
4 | // it under the terms of the GNU General Public License as published by
5 | // the Free Software Foundation, either version 3 of the License, or
6 | // (at your option) any later version.
7 | // Proton Mail Bridge is distributed in the hope that it will be useful,
8 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 | // GNU General Public License for more details.
11 | // You should have received a copy of the GNU General Public License
12 | // along with Proton Mail Bridge. If not, see .
13 | import QtQuick
14 | import QtQuick.Templates as T
15 |
16 | T.Action {
17 | property bool loading
18 | }
19 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/Resources/Help/Template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
12 |
13 |
14 | %1
15 |
16 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/Resources/Help/WhyBridge.html:
--------------------------------------------------------------------------------
1 |
Why do I need bridge?
2 |
3 | Proton does not have access to the content of your messages, so it cannot share your unencrypted messages with your email client from the
4 | Proton servers.
5 |
6 |
7 | Email clients such as Microsoft Outlook, Mozilla Thunderbird and Apple Mail use standard protocols named IMAP and SMTP to receive and send emails.
8 |
9 |
10 | Even though the IMAP and SMTP protocols can use secure channels (using SSL/TLS), they do not offer support for encrypted messages.
11 | Because Proton does not have access to the content of your messages, it is not possible to configure your email client to connect directly to
12 | Proton servers.
13 |
14 |
15 | The key to solving this problem is Bridge. Once installed on your computer and connected to your Proton account, Bridge can access your
16 | encrypted messages stored on the Proton servers. Bridge integrates an IMAP and a SMTP server that run on your computer and are accessible only
17 | to applications executing on your machine. Your email client connects to these local servers and Bridge is responsible for seamlessly encrypting
18 | and decrypting the messages that you send and receive.
19 |
Why do I need to install a certificate when configuring Apple Mail with Bridge?
2 |
3 | Apple Mail requires a secure channel for communications with email servers, and the server needs to be acknowledged as trusted.
4 |
5 |
6 | In order to communicate with Bridge, Apple Mail requires secure connections using SSL/TLS. This cryptographic protocol includes an identity
7 | verification system using certificates. For publicly available servers, certificates are normally issued and digitally signed by a certificate
8 | authority, such as Let's Encrypt. This is not possible for Bridge, as the IMAP and SMTP servers are running on your own computer, and are not
9 | accessible from any network (local or internet).
10 |
11 |
12 | The solution is to use a self-signed certificate. When setting up an email account where the server provides a self-signed certificate, most
13 | email clients will issue a warning asking you whether you trust the server or not, because the certificate was not issued by a certificate
14 | authority.
15 |
16 |
17 | Apple Mail requires an extra step. It will simply refuse to connect if the certificate is not set as trusted. Bridge solves this by storing this
18 | certificate in the macOS keychain. This operation requires that you provide your macOS account password.
19 |
20 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/Loader_16.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/Loader_48.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-alert.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-arrow-left.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-check.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-chevron-down.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-chevron-left.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-chevron-right.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
10 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-chevron-up.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-copy.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-cross-close.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-dot.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-drive.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-exclamation-circle-filled.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-external-link.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-eye.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-illustrative-view-html-code.svg:
--------------------------------------------------------------------------------
1 |
9 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-info-circle-filled.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-info-circle.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-info.svg:
--------------------------------------------------------------------------------
1 |
13 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-plus.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-question-circle.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-splash-check.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-success.svg:
--------------------------------------------------------------------------------
1 |
11 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-three-dots-vertical.svg:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-trash.svg:
--------------------------------------------------------------------------------
1 |
6 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-warning-orange.svg:
--------------------------------------------------------------------------------
1 |
12 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/img-macos-cert-screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/internal/frontend/bridge-gui/bridge-gui/qml/icons/img-macos-cert-screenshot.png
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/img-macos-profile-screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/internal/frontend/bridge-gui/bridge-gui/qml/icons/img-macos-profile-screenshot.png
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/img-proton-logos.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/internal/frontend/bridge-gui/bridge-gui/qml/icons/img-proton-logos.png
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/img-splash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/internal/frontend/bridge-gui/bridge-gui/qml/icons/img-splash.png
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/systray-color-error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/internal/frontend/bridge-gui/bridge-gui/qml/icons/systray-color-error.png
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/systray-color-norm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/internal/frontend/bridge-gui/bridge-gui/qml/icons/systray-color-norm.png
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/systray-color-update.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/internal/frontend/bridge-gui/bridge-gui/qml/icons/systray-color-update.png
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/systray-color-warn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/internal/frontend/bridge-gui/bridge-gui/qml/icons/systray-color-warn.png
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/systray-mono-error.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/internal/frontend/bridge-gui/bridge-gui/qml/icons/systray-mono-error.png
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/systray-mono-norm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/internal/frontend/bridge-gui/bridge-gui/qml/icons/systray-mono-norm.png
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/systray-mono-update.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/internal/frontend/bridge-gui/bridge-gui/qml/icons/systray-mono-update.png
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/qml/icons/systray-mono-warn.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/internal/frontend/bridge-gui/bridge-gui/qml/icons/systray-mono-warn.png
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/vcpkg/triplets/arm64-osx-min-11-0.cmake:
--------------------------------------------------------------------------------
1 | set(VCPKG_TARGET_ARCHITECTURE arm64)
2 | set(VCPKG_CRT_LINKAGE dynamic)
3 | set(VCPKG_LIBRARY_LINKAGE static)
4 |
5 | set(VCPKG_CMAKE_SYSTEM_NAME Darwin)
6 | set(VCPKG_OSX_ARCHITECTURES arm64)
7 | set(VCPKG_OSX_DEPLOYMENT_TARGET "11.0")
8 |
9 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridge-gui/vcpkg/triplets/x64-osx-min-10-15.cmake:
--------------------------------------------------------------------------------
1 | set(VCPKG_TARGET_ARCHITECTURE x64)
2 | set(VCPKG_CRT_LINKAGE dynamic)
3 | set(VCPKG_LIBRARY_LINKAGE static)
4 |
5 | set(VCPKG_CMAKE_SYSTEM_NAME Darwin)
6 | set(VCPKG_OSX_ARCHITECTURES x86_64)
7 | set(VCPKG_OSX_DEPLOYMENT_TARGET "10.15")
8 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridgepp/Pch.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 |
19 | #ifndef BRIDGE_PP_PCH_H
20 | #define BRIDGE_PP_PCH_H
21 |
22 |
23 | #include
24 |
25 |
26 | #endif // BRIDGE_PP_PCH_H
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridgepp/Test/TestSessionID.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 |
19 | #include "QtCore/qdatetime.h"
20 | #include
21 | #include
22 |
23 |
24 | using namespace bridgepp;
25 |
26 |
27 | TEST(SessionID, SessionID) {
28 | QString const sessionID = newSessionID();
29 | EXPECT_TRUE(sessionID.size() > 0);
30 |
31 | EXPECT_FALSE(sessionIDToDateTime("invalidSessionID").isValid());
32 |
33 | QDateTime const dateTime = sessionIDToDateTime(sessionID);
34 | EXPECT_TRUE(dateTime.isValid());
35 | EXPECT_TRUE(qAbs(dateTime.secsTo(QDateTime::currentDateTime())) < 5);
36 | }
37 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridgepp/bridgepp/Log/LogUtils.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 |
19 | #ifndef BRIDGE_PP_LOG_UTILS_H
20 | #define BRIDGE_PP_LOG_UTILS_H
21 |
22 |
23 | namespace bridgepp {
24 |
25 |
26 | QString userLogsDir(); ///< Return the path of the user logs dir.
27 | QByteArray tailOfLatestBridgeLog(QString const &sessionID); ///< Return the last bytes of the last bridge log.
28 |
29 |
30 | } // namespace bridgepp
31 |
32 |
33 | #endif //BRIDGE_PP_LOG_UTILS_H
34 |
--------------------------------------------------------------------------------
/internal/frontend/bridge-gui/bridgepp/bridgepp/SessionID/SessionID.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 |
19 | #ifndef BRIDGE_PP_SESSION_ID_H
20 | #define BRIDGE_PP_SESSION_ID_H
21 |
22 |
23 | namespace bridgepp {
24 |
25 |
26 | extern QString const sessionIDFlag; ///< The sessionID command-line flag (without hyphens)
27 | extern QString const hyphenatedSessionIDFlag; ///< The sessionID command-line flag (with two hyphens)
28 |
29 |
30 | QString newSessionID(); ///< Create a new sessions
31 | QDateTime sessionIDToDateTime(QString const &sessionID); ///< Parse the date/time from a sessionID.
32 |
33 |
34 | } // namespace
35 |
36 | #endif //BRIDGE_PP_SESSION_ID_H
37 |
--------------------------------------------------------------------------------
/internal/frontend/grpc/event_utils.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package grpc
19 |
20 | import "github.com/bradenaw/juniper/xslices"
21 |
22 | // isInternetStatus returns true iff the event is InternetStatus.
23 | func (x *StreamEvent) isInternetStatus() bool {
24 | appEvent := x.GetApp()
25 |
26 | return (appEvent != nil) && (appEvent.GetInternetStatus() != nil)
27 | }
28 |
29 | // filterOutInternetStatusEvents return a copy of the events list where all internet connection events have been removed.
30 | func filterOutInternetStatusEvents(events []*StreamEvent) []*StreamEvent {
31 | return xslices.Filter(events, func(event *StreamEvent) bool { return !event.isInternetStatus() })
32 | }
33 |
--------------------------------------------------------------------------------
/internal/frontend/grpc/types.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package grpc
19 |
20 | type Restarter interface {
21 | Set(restart, crash bool)
22 | AddFlags(flags ...string)
23 | Override(exe string)
24 | }
25 |
--------------------------------------------------------------------------------
/internal/frontend/theme/detect_default.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build !windows && !darwin
19 | // +build !windows,!darwin
20 |
21 | package theme
22 |
23 | func detectSystemTheme() Theme {
24 | return Light
25 | }
26 |
--------------------------------------------------------------------------------
/internal/frontend/theme/theme.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package theme
19 |
20 | import (
21 | "runtime"
22 | )
23 |
24 | type Theme string
25 |
26 | const (
27 | Light = Theme("light")
28 | Dark = Theme("dark")
29 | )
30 |
31 | func IsAvailable(have Theme) bool {
32 | return have == Light || have == Dark
33 | }
34 |
35 | func DefaultTheme() Theme {
36 | switch runtime.GOOS {
37 | case "darwin", "windows":
38 | return detectSystemTheme()
39 | default:
40 | return Light
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/internal/identifier/identifier.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package identifier
19 |
20 | type Identifier interface {
21 | GetUserAgent() string
22 | HasClient() bool
23 | SetClient(name, version string)
24 | SetPlatform(platform string)
25 | SetClientString(client string)
26 | GetClientString() string
27 | }
28 |
29 | type UserAgentUpdater interface {
30 | Identifier
31 | SetUserAgent(name, version string)
32 | }
33 |
--------------------------------------------------------------------------------
/internal/logging/crash_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package logging
19 |
20 | import (
21 | "testing"
22 |
23 | "github.com/ProtonMail/proton-bridge/v3/internal/constants"
24 | "github.com/stretchr/testify/require"
25 | )
26 |
27 | func TestLogging_MatchStackTraceName(t *testing.T) {
28 | filename := getStackTraceName(NewSessionID(), constants.AppName, constants.Version, constants.Tag)
29 | require.True(t, len(filename) > 0)
30 | require.True(t, MatchStackTraceName(filename))
31 | require.False(t, MatchStackTraceName("Invalid.log"))
32 | }
33 |
--------------------------------------------------------------------------------
/internal/logging/imap_logger.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package logging
19 |
20 | import "github.com/sirupsen/logrus"
21 |
22 | // IMAPLogger implements the writer interface for Gluon IMAP logs.
23 | type IMAPLogger struct{}
24 |
25 | func NewIMAPLogger() *IMAPLogger {
26 | return &IMAPLogger{}
27 | }
28 |
29 | func (l *IMAPLogger) Write(p []byte) (n int, err error) {
30 | return logrus.WithField("pkg", "log/IMAP").WriterLevel(logrus.TraceLevel).Write(p)
31 | }
32 |
--------------------------------------------------------------------------------
/internal/logging/sensitive_default.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build !sensitive
19 |
20 | package logging
21 |
22 | import (
23 | "crypto/sha256"
24 | "encoding/hex"
25 | "fmt"
26 | )
27 |
28 | func Sensitive(s string) string {
29 | return fmt.Sprintf("******** (%s)", hash(s))
30 | }
31 |
32 | func hash(s string) string {
33 | h := sha256.New()
34 |
35 | if _, err := h.Write([]byte(s)); err != nil {
36 | panic(err)
37 | }
38 |
39 | return hex.EncodeToString(h.Sum(nil))[0:8]
40 | }
41 |
--------------------------------------------------------------------------------
/internal/logging/sensitive_sensitive.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build sensitive
19 |
20 | package logging
21 |
22 | func Sensitive(s string) string {
23 | return s
24 | }
25 |
--------------------------------------------------------------------------------
/internal/logging/session_id_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 |
17 | package logging
18 |
19 | import (
20 | "testing"
21 | "time"
22 |
23 | "github.com/stretchr/testify/require"
24 | )
25 |
26 | func TestLogging_SessionID(t *testing.T) {
27 | now := time.Now()
28 | sessionID := NewSessionID()
29 | sessionTime := sessionID.toTime()
30 | require.False(t, sessionTime.IsZero())
31 | require.WithinRange(t, sessionTime, now.Add(-1*time.Millisecond), now.Add(1*time.Millisecond))
32 |
33 | fromString := NewSessionIDFromString("")
34 | require.True(t, len(fromString) > 0)
35 | fromString = NewSessionIDFromString(string(sessionID))
36 | require.True(t, len(fromString) > 0)
37 | require.Equal(t, sessionID, fromString)
38 | }
39 |
--------------------------------------------------------------------------------
/internal/sentry/hostarch_default.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build !darwin
19 | // +build !darwin
20 |
21 | package sentry
22 |
23 | import (
24 | "github.com/elastic/go-sysinfo/types"
25 | )
26 |
27 | func getHostArch(host types.Host) string {
28 | return host.Info().Architecture
29 | }
30 |
--------------------------------------------------------------------------------
/internal/sentry/lang_default.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package sentry
19 |
20 | import (
21 | "github.com/jeandeaual/go-locale"
22 | "github.com/sirupsen/logrus"
23 | )
24 |
25 | func GetSystemLang() string {
26 | lang, err := locale.GetLanguage()
27 | if err != nil {
28 | logrus.WithError(err).Error("Failed to get system language")
29 | lang = "Unknown"
30 | }
31 | return lang
32 | }
33 |
--------------------------------------------------------------------------------
/internal/service/types.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package service
19 |
20 | type Locator interface {
21 | ProvideSettingsPath() (string, error)
22 | ProvideUnleashCachePath() (string, error)
23 | }
24 |
--------------------------------------------------------------------------------
/internal/services/imapsmtpserver/telemetry.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package imapsmtpserver
19 |
20 | type Telemetry interface {
21 | SetCacheLocation(string)
22 | }
23 |
--------------------------------------------------------------------------------
/internal/services/smtp/smtp_default.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build !build_qa
19 |
20 | package smtp
21 |
22 | func debugDumpToDisk(_ []byte) error {
23 | return nil
24 | }
25 |
--------------------------------------------------------------------------------
/internal/services/syncservice/utils.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package syncservice
19 |
20 | import (
21 | "context"
22 | "time"
23 | )
24 |
25 | // sleepCtx sleeps for the given duration, or until the context is canceled.
26 | func sleepCtx(ctx context.Context, d time.Duration) {
27 | select {
28 | case <-ctx.Done():
29 | case <-time.After(d):
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/internal/services/userevents/event_controller.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package userevents
19 |
20 | type EventController interface {
21 | Pause()
22 | Resume()
23 | }
24 |
--------------------------------------------------------------------------------
/internal/services/userevents/subscribable.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package userevents
19 |
20 | // Subscribable represents a type that allows the registration of event subscribers.
21 | type Subscribable interface {
22 | Subscribe(subscription EventSubscriber)
23 | Unsubscribe(subscription EventSubscriber)
24 | }
25 |
26 | type NoOpSubscribable struct{}
27 |
28 | func (n NoOpSubscribable) Subscribe(_ EventSubscriber) {
29 | // Does nothing
30 | }
31 |
32 | func (n NoOpSubscribable) Unsubscribe(_ EventSubscriber) {
33 | // Does nothing
34 | }
35 |
--------------------------------------------------------------------------------
/internal/services/useridentity/auth.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package useridentity
19 |
20 | type KeyPassProvider interface {
21 | KeyPass() []byte
22 | }
23 |
24 | type BridgePassProvider interface {
25 | BridgePass() []byte
26 | }
27 |
28 | type FixedBridgePassProvider struct {
29 | pass []byte
30 | }
31 |
32 | func (f FixedBridgePassProvider) BridgePass() []byte {
33 | return f.pass
34 | }
35 |
36 | func NewFixedBridgePassProvider(pass []byte) *FixedBridgePassProvider {
37 | return &FixedBridgePassProvider{pass: pass}
38 | }
39 |
--------------------------------------------------------------------------------
/internal/updater/channel.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package updater
19 |
20 | // Channel represents an update channel users can be subscribed to.
21 | type Channel string
22 |
23 | const (
24 | // StableChannel is the channel all users are subscribed to by default.
25 | StableChannel Channel = "stable"
26 |
27 | // EarlyChannel is the channel users subscribe to when they enable "Early Access".
28 | EarlyChannel Channel = "early"
29 | )
30 |
31 | // DefaultUpdateChannel is the default update channel to subscribe to.
32 | // It is set to the stable channel by default, unless overridden at build time.
33 | var DefaultUpdateChannel = StableChannel //nolint:gochecknoglobals
34 |
--------------------------------------------------------------------------------
/internal/updater/host_default.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build !build_qa
19 | // +build !build_qa
20 |
21 | package updater
22 |
23 | const Host = "https://proton.me/download"
24 |
--------------------------------------------------------------------------------
/internal/updater/host_qa.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build build_qa
19 | // +build build_qa
20 |
21 | package updater
22 |
23 | const Host = "https://bridgeteam.protontech.ch/bridgeteam/autoupdates/download"
24 |
--------------------------------------------------------------------------------
/internal/updater/keyring.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package updater
19 |
20 | import (
21 | "github.com/ProtonMail/gopenpgp/v2/crypto"
22 | "github.com/sirupsen/logrus"
23 | )
24 |
25 | func GetDefaultKeyring() (*crypto.KeyRing, error) {
26 | l := logrus.WithField("pkg", "updater")
27 |
28 | key, err := crypto.NewKeyFromArmored(DefaultPublicKey)
29 | if err != nil {
30 | l.WithError(err).Error("Failed to create new verification key")
31 | return nil, err
32 | }
33 |
34 | kr, err := crypto.NewKeyRing(key)
35 | if err != nil {
36 | l.WithError(err).Fatal("Failed to create new verification keyring")
37 | }
38 |
39 | return kr, nil
40 | }
41 |
--------------------------------------------------------------------------------
/internal/updater/versioncompare/compare_linux.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build linux
19 |
20 | package versioncompare
21 |
22 | import (
23 | "github.com/elastic/go-sysinfo/types"
24 | "github.com/sirupsen/logrus"
25 | )
26 |
27 | // IsHostVersionEligible - Checks whether host OS version is eligible for update. Defaults to true on Linux.
28 | func (sysVer SystemVersion) IsHostVersionEligible(log *logrus.Entry, _ types.Host, _ func(host types.Host) string) (bool, error) {
29 | log.Info("Checking host OS version on Linux. Defaulting to true.")
30 | return true, nil
31 | }
32 |
--------------------------------------------------------------------------------
/internal/updater/versioncompare/compare_windows.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build windows
19 |
20 | package versioncompare
21 |
22 | import (
23 | "github.com/elastic/go-sysinfo/types"
24 | "github.com/sirupsen/logrus"
25 | )
26 |
27 | // IsHostVersionEligible - Checks whether host OS version is eligible for update. Defaults to true on Linux.
28 | func (sysVer SystemVersion) IsHostVersionEligible(log *logrus.Entry, _ types.Host, _ func(host types.Host) string) (bool, error) {
29 | log.Info("Checking host OS version on Windows. Defaulting to true.")
30 | return true, nil
31 | }
32 |
--------------------------------------------------------------------------------
/internal/updater/versioncompare/types.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package versioncompare
19 |
20 | import "fmt"
21 |
22 | type SystemVersion struct {
23 | Minimum string `json:"Minimum,omitempty"`
24 | Maximum string `json:"Maximum,omitempty"`
25 | }
26 |
27 | func (sysVer SystemVersion) String() string {
28 | return fmt.Sprintf("SystemVersion: Maximum %s, Minimum %s", sysVer.Maximum, sysVer.Minimum)
29 | }
30 |
--------------------------------------------------------------------------------
/internal/user/errors.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package user
19 |
20 | import "errors"
21 |
22 | var (
23 | ErrNoSuchAddress = errors.New("no such address")
24 | ErrMissingAddrKey = errors.New("missing address key")
25 | )
26 |
--------------------------------------------------------------------------------
/internal/useragent/platform_darwin.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build darwin
19 | // +build darwin
20 |
21 | package useragent
22 |
23 | import (
24 | "syscall"
25 | )
26 |
27 | func getDarwinVersion() (string, error) {
28 | return syscall.Sysctl("kern.osrelease")
29 | }
30 |
--------------------------------------------------------------------------------
/internal/useragent/platform_default.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build !darwin
19 | // +build !darwin
20 |
21 | package useragent
22 |
23 | import "errors"
24 |
25 | func getDarwinVersion() (string, error) {
26 | return "", errors.New("implemented only for darwin")
27 | }
28 |
--------------------------------------------------------------------------------
/internal/vault/certs_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package vault_test
19 |
20 | import (
21 | "testing"
22 |
23 | "github.com/stretchr/testify/require"
24 | )
25 |
26 | func TestVault_TLSCerts(t *testing.T) {
27 | // create a new test vault.
28 | s := newVault(t)
29 |
30 | // Check the default bridge TLS certs.
31 | cert, key := s.GetBridgeTLSCert()
32 | require.NotEmpty(t, cert)
33 | require.NotEmpty(t, key)
34 | }
35 |
--------------------------------------------------------------------------------
/internal/vault/cookies.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package vault
19 |
20 | func (vault *Vault) GetCookies() ([]byte, error) {
21 | return vault.getSafe().Cookies, nil
22 | }
23 |
24 | func (vault *Vault) SetCookies(cookies []byte) error {
25 | return vault.modSafe(func(data *Data) {
26 | data.Cookies = cookies
27 | })
28 | }
29 |
--------------------------------------------------------------------------------
/internal/vault/migrate.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package vault
19 |
20 | import "fmt"
21 |
22 | type Version int
23 |
24 | const (
25 | v2_3_x Version = iota
26 | v2_4_x
27 | v2_5_x
28 |
29 | Current = v2_5_x
30 | )
31 |
32 | // upgrade migrates the vault from the given version to the next version.
33 | func upgrade(v Version, b []byte) ([]byte, error) {
34 | switch v {
35 | case v2_3_x:
36 | return upgrade_2_3_x(b)
37 |
38 | case v2_4_x:
39 | return upgrade_2_4_x(b)
40 |
41 | case Current:
42 | return nil, fmt.Errorf("already at current version %d", Current)
43 |
44 | default:
45 | return nil, fmt.Errorf("unknown version %d", v)
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/internal/vault/token.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package vault
19 |
20 | import (
21 | "github.com/ProtonMail/gopenpgp/v2/crypto"
22 | )
23 |
24 | // RandomToken is a function that returns a random token.
25 | // By default, we use crypto.RandomToken to generate tokens.
26 | var RandomToken = crypto.RandomToken // nolint:gochecknoglobals
27 |
28 | func newRandomToken(size int) []byte {
29 | token, err := RandomToken(size)
30 | if err != nil {
31 | panic(err)
32 | }
33 |
34 | return token
35 | }
36 |
--------------------------------------------------------------------------------
/internal/vault/types_data.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package vault
19 |
20 | type Data struct {
21 | Settings Settings
22 | Users []UserData
23 | Cookies []byte
24 | Certs Certs
25 | Migrated bool
26 | }
27 |
28 | func newDefaultData(gluonDir string) Data {
29 | return Data{
30 | Settings: newDefaultSettings(gluonDir),
31 | Certs: newDefaultCerts(),
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/internal/vault/types_password_archive.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package vault
19 |
20 | // PasswordArchive maps a list email address hashes to passwords.
21 | // The type is not defined as a map alias to prevent having to handle nil default values when vault was created by an older version of the application.
22 | type PasswordArchive struct {
23 | // we store the SHA-256 sum as string for readability and JSON marshalling of map[[32]byte][]byte will not be allowed, thus breaking vault-editor.
24 | Archive map[string][]byte
25 | }
26 |
--------------------------------------------------------------------------------
/internal/vault/vault_debug.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build debug
19 |
20 | package vault
21 |
22 | import (
23 | "encoding/json"
24 | )
25 |
26 | func (vault *Vault) ImportJSON(dec []byte) {
27 | vault.modSafe(func(data *Data) {
28 | if err := json.Unmarshal(dec, data); err != nil {
29 | panic(err)
30 | }
31 | })
32 | }
33 |
34 | func (vault *Vault) ExportJSON() []byte {
35 | enc, err := json.MarshalIndent(vault.getSafe(), "", " ")
36 | if err != nil {
37 | panic(err)
38 | }
39 |
40 | return enc
41 | }
42 |
--------------------------------------------------------------------------------
/internal/versioner/install.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package versioner
19 |
20 | import (
21 | "compress/gzip"
22 | "io"
23 | "path/filepath"
24 |
25 | "github.com/Masterminds/semver/v3"
26 | "github.com/ProtonMail/proton-bridge/v3/pkg/tar"
27 | )
28 |
29 | // InstallNewVersion installs a tgz update package of the given version.
30 | func (v *Versioner) InstallNewVersion(version *semver.Version, r io.Reader) error {
31 | gr, err := gzip.NewReader(r)
32 | if err != nil {
33 | return err
34 | }
35 | defer func() { _ = gr.Close() }()
36 |
37 | return tar.UntarToDir(gr, filepath.Join(v.root, version.Original()))
38 | }
39 |
--------------------------------------------------------------------------------
/internal/versioner/name_default.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build !windows
19 | // +build !windows
20 |
21 | package versioner
22 |
23 | func getExeName(name string) string {
24 | return name
25 | }
26 |
--------------------------------------------------------------------------------
/internal/versioner/name_windows.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package versioner
19 |
20 | import "strings"
21 |
22 | func getExeName(name string) string {
23 | if strings.HasSuffix(name, ".exe") {
24 | return name
25 | }
26 |
27 | return name + ".exe"
28 | }
29 |
--------------------------------------------------------------------------------
/internal/versioner/util.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package versioner
19 |
20 | import (
21 | "os"
22 | "runtime"
23 | )
24 |
25 | // fileExists returns whether the given file exists.
26 | func fileExists(path string) bool {
27 | _, err := os.Stat(path)
28 | return err == nil
29 | }
30 |
31 | // fileIsExecutable returns the given filepath and true if it exists.
32 | func fileIsExecutable(path string) bool {
33 | if runtime.GOOS == "windows" {
34 | return true
35 | }
36 |
37 | info, err := os.Stat(path)
38 | if err != nil {
39 | return false
40 | }
41 |
42 | return info.Mode()&0o111 != 0
43 | }
44 |
--------------------------------------------------------------------------------
/pkg/algo/algo.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | // Package algo provides some algorithm utils.
19 | package algo
20 |
--------------------------------------------------------------------------------
/pkg/algo/hash.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package algo
19 |
20 | import (
21 | "crypto/sha256"
22 | "encoding/base64"
23 | "encoding/hex"
24 | )
25 |
26 | func Hash256(b []byte) []byte {
27 | h := sha256.Sum256(b)
28 | return h[:]
29 | }
30 |
31 | func HashBase64SHA256(s string) string {
32 | return base64.StdEncoding.EncodeToString(
33 | Hash256([]byte(s)),
34 | )
35 | }
36 |
37 | func HashHexSHA256(s string) string {
38 | return hex.EncodeToString(
39 | Hash256([]byte(s)),
40 | )
41 | }
42 |
--------------------------------------------------------------------------------
/pkg/keychain/keychain_default.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build !darwin
19 | // +build !darwin
20 |
21 | package keychain
22 |
23 | import "fmt"
24 |
25 | // hostURL uniquely identifies the app's keychain items within the system keychain.
26 | func hostURL(keychainName string) string {
27 | return fmt.Sprintf("protonmail/%v/users", keychainName)
28 | }
29 |
--------------------------------------------------------------------------------
/pkg/message/message.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | // Package message contains set of tools to convert message between Proton API
19 | // and IMAP format.
20 | package message
21 |
22 | import (
23 | "github.com/sirupsen/logrus"
24 | )
25 |
26 | var log = logrus.WithField("pkg", "pkg/message") //nolint:gochecknoglobals
27 |
--------------------------------------------------------------------------------
/pkg/message/parser/testdata/multipart_alternative.eml:
--------------------------------------------------------------------------------
1 | To: pmbridgeietest@outlook.com
2 | From: schizofrenic
3 | Subject: aoeuaoeu
4 | Message-ID: <7dc32b61-b9cf-f2d3-8ec5-10e5b4a33ec1@pm.me>
5 | Date: Thu, 30 Jul 2020 13:35:24 +0200
6 | User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:68.0)
7 | Gecko/20100101 Thunderbird/68.11.0
8 | MIME-Version: 1.0
9 | Content-Type: multipart/alternative;
10 | boundary="------------22BC647264E52252E386881A"
11 | Content-Language: en-US
12 |
13 | This is a multi-part message in MIME format.
14 | --------------22BC647264E52252E386881A
15 | Content-Type: text/plain; charset=utf-8; format=flowed
16 | Content-Transfer-Encoding: 7bit
17 |
18 | *aoeuaoeu*
19 |
20 |
21 | --------------22BC647264E52252E386881A
22 | Content-Type: text/html; charset=utf-8
23 | Content-Transfer-Encoding: 7bit
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
aoeuaoeu
32 |
33 |
34 |
35 |
36 | --------------22BC647264E52252E386881A--
37 |
--------------------------------------------------------------------------------
/pkg/message/parser/testdata/text_html.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 | Content-Type: multipart/mixed; boundary=longrandomstring
4 |
5 | --longrandomstring
6 | Content-Type: text/html
7 |
8 | This is body of HTML mail with attachment
9 | --longrandomstring--
10 |
--------------------------------------------------------------------------------
/pkg/message/parser/testdata/text_html_octet_attachment.eml:
--------------------------------------------------------------------------------
1 | Mime-Version: 1.0
2 | From: Sender
3 | To: Receiver
4 | Content-Type: multipart/mixed; boundary=longrandomstring
5 |
6 | --longrandomstring
7 | Content-Type: text/html
8 |
9 | This is body of HTML mail with attachment
10 | --longrandomstring
11 | Content-Type: application/octet-stream
12 | Content-Transfer-Encoding: base64
13 | Content-Disposition: attachment
14 |
15 | aWYgeW91IGFyZSByZWFkaW5nIHRoaXMsIGhpIQ==
16 | --longrandomstring--
17 |
--------------------------------------------------------------------------------
/pkg/message/parser/writer_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package parser
19 |
20 | import (
21 | "bytes"
22 | "strings"
23 | "testing"
24 |
25 | "github.com/stretchr/testify/assert"
26 | )
27 |
28 | func TestParserWrite(t *testing.T) {
29 | p := newTestParser(t, "text_html_octet_attachment.eml")
30 |
31 | w := p.NewWriter()
32 |
33 | buf := new(bytes.Buffer)
34 |
35 | assert.NoError(t, w.Write(buf))
36 | assert.Equal(t, getFileAsString("text_html_octet_attachment.eml"), crlf(buf.String()))
37 | }
38 |
39 | func crlf(s string) string {
40 | return strings.ReplaceAll(s, "\r\n", "\n")
41 | }
42 |
--------------------------------------------------------------------------------
/pkg/message/testdata/ics_attachment.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 | Content-Type: multipart/mixed; boundary=longrandomstring
4 |
5 | --longrandomstring
6 |
7 | body
8 | --longrandomstring
9 | Content-Type: text/calendar; charset=utf-8; method=REQUEST; name=invite.ics'
10 | Content-Transfer-Encoding: Base64
11 | Content-Disposition: attachment; filename=invite.ics
12 |
13 | VGhpcyBpcyBhbiBpY3MgY2FsZW5kYXIgaW52aXRl
14 | --longrandomstring--
15 |
--------------------------------------------------------------------------------
/pkg/message/testdata/incorrect_boundary_w_invalid_character_tuta.eml:
--------------------------------------------------------------------------------
1 | Date: Mon, 01 Jan 2000 00:00:00 +0000 (UTC)
2 | From: Daniel at Test
3 | Mime-Version: 1.0
4 | Subject: Test incorrect original boundary w. invalid character
5 | To: david@test.com
6 | Content-Type: multipart/related; boundary="------------1234567890@tutanota"
7 |
8 | --------------1234567890@tutanota
9 | Content-Type: text/html; charset=UTF-8
10 | Content-transfer-encoding: base64
11 |
12 | PGh0bWw+PGgxPkhlbGxvIFdvcmxkITwvaDE+PC9odG1sPg==
13 | --------------1234567890@tutanota--
14 |
--------------------------------------------------------------------------------
/pkg/message/testdata/multipart_alternative.eml:
--------------------------------------------------------------------------------
1 | To: pmbridgeietest@outlook.com
2 | From: schizofrenic
3 | Subject: aoeuaoeu
4 | Date: Thu, 30 Jul 2020 13:35:24 +0200
5 | MIME-Version: 1.0
6 | Content-Type: multipart/alternative; boundary="------------22BC647264E52252E386881A"
7 | Content-Language: en-US
8 |
9 | This is a multi-part message in MIME format.
10 | --------------22BC647264E52252E386881A
11 | Content-Type: text/plain; charset=utf-8; format=flowed
12 | Content-Transfer-Encoding: 7bit
13 |
14 | *aoeuaoeu*
15 |
16 |
17 | --------------22BC647264E52252E386881A
18 | Content-Type: text/html; charset=utf-8
19 | Content-Transfer-Encoding: 7bit
20 |
21 |
22 |
23 |
24 |
25 |
26 | aoeuaoeu
27 |
28 |
29 |
30 | --------------22BC647264E52252E386881A--
--------------------------------------------------------------------------------
/pkg/message/testdata/multipart_alternative_latin1.eml:
--------------------------------------------------------------------------------
1 | To: pmbridgeietest@outlook.com
2 | From: schizofrenic
3 | Subject: aoeuaoeu
4 | Date: Thu, 30 Jul 2020 13:35:24 +0200
5 | MIME-Version: 1.0
6 | Content-Type: multipart/alternative; boundary="------------22BC647264E52252E386881A"; charset="iso-8859-1"
7 | Content-Language: en-US
8 |
9 | This is a multi-part message in MIME format.
10 | --------------22BC647264E52252E386881A
11 | Content-Type: text/plain
12 | Content-Transfer-Encoding: 7bit
13 |
14 | *aoeuaoeu*
15 |
16 |
17 | --------------22BC647264E52252E386881A
18 | Content-Type: text/html
19 | Content-Transfer-Encoding: 7bit
20 |
21 |
22 |
23 |
24 |
25 |
26 | aoeuaoeu
27 |
28 |
29 |
30 | --------------22BC647264E52252E386881A--
--------------------------------------------------------------------------------
/pkg/message/testdata/multipart_attachment_encoded_no_quote.eml:
--------------------------------------------------------------------------------
1 | From: Bridge Test
2 | Date: 01 Jan 1980 00:00:00 +0000
3 | To: Internal Bridge
4 | Subject: Message with attachment name
5 | Content-type: multipart/mixed; boundary="boundary"
6 | Received: by 2002:0:0:0:0:0:0:0 with SMTP id 0123456789abcdef; Wed, 30 Dec 2020 01:23:45 0000
7 |
8 | This is a multi-part message in MIME format.
9 |
10 | --boundary
11 | Content-Type: text/plain
12 |
13 | Hello
14 |
15 | --boundary
16 | Content-Type: text/html; charset=utf-8
17 | Content-Transfer-Encoding: 7bit
18 |
19 |
HELLO
20 |
21 | --boundary
22 | Content-Type: application/pdf; name==?US-ASCII?Q?filename?=
23 | Content-Disposition: attachment; filename==?US-ASCII?Q?filename?=
24 |
25 | somebytes
26 |
27 | --boundary--
28 |
--------------------------------------------------------------------------------
/pkg/message/testdata/multiple_text_parts.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 | Content-Type: multipart/mixed; boundary=longrandomstring
4 |
5 | this part of the text should be ignored
6 |
7 | --longrandomstring
8 |
9 | body
10 |
11 | --longrandomstring
12 |
13 | some other part of the message
14 | --longrandomstring--
--------------------------------------------------------------------------------
/pkg/message/testdata/non-encoded-content-transfer-encoding.eml:
--------------------------------------------------------------------------------
1 | To: user@somewhere.org
2 | Subject: =?utf-8?Q?aoeuaoeuaoeu?=
3 | Date: Sat, 16 Jun 2020 17:36:02 +0200
4 | MIME-Version: 1.0
5 | Content-Type: text/plain;
6 | charset="utf-8"
7 | Content-Transfer-Encoding: 8bit
8 | From: =?utf-8?Q?Sender?=
9 |
10 | bodybodybody
11 |
--------------------------------------------------------------------------------
/pkg/message/testdata/pgp-mime-body-html.eml:
--------------------------------------------------------------------------------
1 | Content-Type: multipart/mixed; boundary="u5NoTcx3NkhqapFjjYFKJZdxCaEWvrsGw";
2 | protected-headers="v1"
3 | Subject: html no pubkey no sign
4 | From: "pm.bridge.qa"
5 | To: schizofrenic@pm.me
6 | Message-ID:
7 |
8 | --u5NoTcx3NkhqapFjjYFKJZdxCaEWvrsGw
9 | Content-Type: text/html; charset=utf-8
10 | Content-Language: en-US
11 | Content-Transfer-Encoding: quoted-printable
12 |
13 |
14 |
15 |
16 |
18 |
19 |
20 |
21 |
What do you call a poor Santa Claus?St.
22 | Nickel-less.
23 |
Where do boats go when they're sick?To the boat
24 | doc.
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | --u5NoTcx3NkhqapFjjYFKJZdxCaEWvrsGw--
34 |
--------------------------------------------------------------------------------
/pkg/message/testdata/pgp-mime-body-plaintext-latin2.eml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/pkg/message/testdata/pgp-mime-body-plaintext-latin2.eml
--------------------------------------------------------------------------------
/pkg/message/testdata/pgp-mime-body-plaintext.eml:
--------------------------------------------------------------------------------
1 | Content-Type: multipart/mixed; boundary="unlHEst6hn6dMAzATXJvy5dCLgUfF9Vvs";
2 | protected-headers="v1"
3 | Subject: plain no pubkey no sign
4 | From: "pm.bridge.qa"
5 | To: schizofrenic@pm.me
6 | Message-ID: <564b9c7c-91eb-6508-107a-35108f383a44@gmail.com>
7 |
8 | --unlHEst6hn6dMAzATXJvy5dCLgUfF9Vvs
9 | Content-Type: text/plain; charset=utf-8; format=flowed
10 | Content-Transfer-Encoding: quoted-printable
11 | Content-Language: en-US
12 |
13 | Where do fruits go on vacation? Pear-is!
14 |
15 |
16 |
17 | --unlHEst6hn6dMAzATXJvy5dCLgUfF9Vvs--
18 |
--------------------------------------------------------------------------------
/pkg/message/testdata/plaintext-invalid-header.eml:
--------------------------------------------------------------------------------
1 | MalformedKey Value
2 |
3 | How do we know that the ocean is friendly? It waves!
4 |
--------------------------------------------------------------------------------
/pkg/message/testdata/plaintext-missing-header.eml:
--------------------------------------------------------------------------------
1 | How do we know that the ocean is friendly? It waves!
2 |
--------------------------------------------------------------------------------
/pkg/message/testdata/references-comma.eml:
--------------------------------------------------------------------------------
1 | Content-Type: multipart/mixed;
2 | boundary=987c7102dcaf02d01860ce777b465f86d39ec16a3b4e12605eb6b0eb200a
3 | X-Original-To: someone@protonmail.com
4 | Delivered-To: someone@protonmail.com
5 | Date: Sun, 04 Aug 2019 13:03:26 +0000
6 | From: ProtonVPN
7 | Reply-To: ProtonVPN
8 | To: someone
9 | Message-Id:
10 | In-Reply-To:
11 | References: ,
12 | Subject: Some test subject
13 | Mime-Version: 1.0
14 |
15 | --987c7102dcaf02d01860ce777b465f86d39ec16a3b4e12605eb6b0eb200a
16 | Content-Transfer-Encoding: quoted-printable
17 | Content-Type: text/html; charset=utf-8
18 |
19 |
21 |
22 |
23 | test test test
24 |
25 |
26 |
27 | --987c7102dcaf02d01860ce777b465f86d39ec16a3b4e12605eb6b0eb200a--
28 |
--------------------------------------------------------------------------------
/pkg/message/testdata/references.eml:
--------------------------------------------------------------------------------
1 | Content-Type: multipart/mixed;
2 | boundary=987c7102dcaf02d01860ce777b465f86d39ec16a3b4e12605eb6b0eb200a
3 | X-Original-To: someone@protonmail.com
4 | Delivered-To: someone@protonmail.com
5 | Date: Sun, 04 Aug 2019 13:03:26 +0000
6 | From: ProtonVPN
7 | Reply-To: ProtonVPN
8 | To: someone
9 | Message-Id:
10 | In-Reply-To:
11 | References:
12 | Subject: Some test subject
13 | Mime-Version: 1.0
14 |
15 | --987c7102dcaf02d01860ce777b465f86d39ec16a3b4e12605eb6b0eb200a
16 | Content-Transfer-Encoding: quoted-printable
17 | Content-Type: text/html; charset=utf-8
18 |
19 |
21 |
22 |
23 | test test test
24 |
25 |
26 |
27 | --987c7102dcaf02d01860ce777b465f86d39ec16a3b4e12605eb6b0eb200a--
28 |
--------------------------------------------------------------------------------
/pkg/message/testdata/reply-to_no_references.eml:
--------------------------------------------------------------------------------
1 | Content-Type: multipart/mixed;
2 | boundary=987c7102dcaf02d01860ce777b465f86d39ec16a3b4e12605eb6b0eb200a
3 | X-Original-To: someone@protonmail.com
4 | Delivered-To: someone@protonmail.com
5 | Date: Sun, 04 Aug 2019 13:03:26 +0000
6 | From: ProtonVPN
7 | Reply-To: ProtonVPN
8 | To: someone
9 | Message-Id:
10 | In-Reply-To:
11 | Subject: Some test subject
12 | Mime-Version: 1.0
13 |
14 | --987c7102dcaf02d01860ce777b465f86d39ec16a3b4e12605eb6b0eb200a
15 | Content-Transfer-Encoding: quoted-printable
16 | Content-Type: text/html; charset=utf-8
17 |
18 |
20 |
21 |
22 | test test test
23 |
24 |
25 |
26 | --987c7102dcaf02d01860ce777b465f86d39ec16a3b4e12605eb6b0eb200a--
27 |
--------------------------------------------------------------------------------
/pkg/message/testdata/rfc2047-content-transfer-encoding-bad.eml:
--------------------------------------------------------------------------------
1 | To: user@somewhere.org
2 | Subject: =?utf-8?Q?aoeuaoeuaoeu?=
3 | Date: Sat, 16 Jun 2020 17:36:02 +0200
4 | MIME-Version: 1.0
5 | Content-Type: text/plain;
6 | charset="utf-8"
7 | Content-Transfer-Encoding: =?utf-8?Q?8bit
8 | From: =?utf-8?Q?Sender?=
9 |
10 | bodybodybody
11 |
--------------------------------------------------------------------------------
/pkg/message/testdata/rfc2047-content-transfer-encoding.eml:
--------------------------------------------------------------------------------
1 | To: user@somewhere.org
2 | Subject: =?utf-8?Q?aoeuaoeuaoeu?=
3 | Date: Sat, 16 Jun 2020 17:36:02 +0200
4 | MIME-Version: 1.0
5 | Content-Type: text/plain;
6 | charset="utf-8"
7 | Content-Transfer-Encoding: =?utf-8?Q?8bit?=
8 | From: =?utf-8?Q?Sender?=
9 |
10 | bodybodybody
11 |
--------------------------------------------------------------------------------
/pkg/message/testdata/text_html.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 | Content-Type: text/html
4 |
5 | This is body of HTML mail without attachment
--------------------------------------------------------------------------------
/pkg/message/testdata/text_html_7bit.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 | Content-Type: text/html
4 | Content-Transfer-Encoding: 7bit
5 |
6 | This is body of HTML mail without attachment
--------------------------------------------------------------------------------
/pkg/message/testdata/text_html_embedded_foreign_encoding.eml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/pkg/message/testdata/text_html_embedded_foreign_encoding.eml
--------------------------------------------------------------------------------
/pkg/message/testdata/text_html_octet_attachment.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 | Content-Type: multipart/mixed; boundary=longrandomstring
4 |
5 | --longrandomstring
6 | Content-Type: text/html
7 |
8 | This is body of HTML mail with attachment
9 | --longrandomstring
10 | Content-Type: application/octet-stream
11 | Content-Transfer-Encoding: base64
12 |
13 | aWYgeW91IGFyZSByZWFkaW5nIHRoaXMsIGhpIQ==
14 | --longrandomstring--
15 |
--------------------------------------------------------------------------------
/pkg/message/testdata/text_html_plain_attachment.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 | Content-Type: multipart/mixed; boundary=longrandomstring
4 |
5 | --longrandomstring
6 | Content-Type: text/html
7 |
8 | This is body of HTML mail with attachment
9 | --longrandomstring
10 | Content-Disposition: attachment
11 |
12 | attachment
13 | --longrandomstring--
14 |
--------------------------------------------------------------------------------
/pkg/message/testdata/text_html_trailing_end_of_mail.eml:
--------------------------------------------------------------------------------
1 | From: "Sender"
2 | To: "Receiver"
3 | Content-Type: text/html; charset="utf-8"
4 | Content-Transfer-Encoding: base64
5 | MIME-Version: 1.0
6 |
7 | PCFET0NUWVBFIEhUTUw+CjxodG1sPjxib2R5PmJvbyE8L2JvZHk+PC9odG1sPg==
8 | .
9 |
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 |
4 | body
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_7bit.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 | Content-Transfer-Encoding: 7bit
4 |
5 | body
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_bad_sender.eml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/pkg/message/testdata/text_plain_bad_sender.eml
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_bad_subject.eml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/pkg/message/testdata/text_plain_bad_subject.eml
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_base64.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 | Content-Transfer-Encoding: base64
4 |
5 | Ym9keQ==
6 |
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_docx_attachment_cyrillic.eml:
--------------------------------------------------------------------------------
1 | Content-Type: multipart/mixed; boundary="------------nq8WTMHkJcymWO6pWfby0uY3"
2 | To: "Receiver"
3 | From: "Sender"
4 | Subject: Test with cyrillic attachment
5 |
6 | --------------nq8WTMHkJcymWO6pWfby0uY3
7 | Content-Type: text/plain; charset=UTF-8; format=flowed
8 | Content-Transfer-Encoding: 7bit
9 |
10 | Shake that body
11 | --------------nq8WTMHkJcymWO6pWfby0uY3
12 | Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document;
13 | name="=?UTF-8?B?0JDQkdCS0JPQlNCD0JXQltCX0IXQmNCI0JrQm9CJ0JzQndCK0J7Qn9Cg?=
14 | =?UTF-8?B?0KHQotCM0KPQpNCl0KfQj9CX0KguZG9jeA==?="
15 | Content-Disposition: attachment;
16 | filename*0*=UTF-8''%D0%90%D0%91%D0%92%D0%93%D0%94%D0%83%D0%95%D0%96%D0%97;
17 | filename*1*=%D0%85%D0%98%D0%88%D0%9A%D0%9B%D0%89%D0%9C%D0%9D%D0%8A%D0%9E;
18 | filename*2*=%D0%9F%D0%A0%D0%A1%D0%A2%D0%8C%D0%A3%D0%A4%D0%A5%D0%A7%D0%8F;
19 | filename*3*=%D0%97%D0%A8%2E%64%6F%63%78
20 | Content-Transfer-Encoding: base64
21 |
22 | 0JDQkdCS0JPQlNCD0JXQltCX0IXQmNCI0JrQm9CJ0JzQndCK0J7Qn9Cg0KHQotCM0KPQpNCl0KfQj9CX0Kg=
23 |
24 | --------------nq8WTMHkJcymWO6pWfby0uY3--
25 |
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_duplicate_charset.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 | Content-Type: text/plain; charset=utf-8; charset=UTF-8
4 |
5 | body
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_empty_addresses.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 | CC:
4 | Reply-To: <>
5 |
6 | body
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_latin1.eml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/pkg/message/testdata/text_plain_latin1.eml
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_latin2_subject.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 | Subject: =?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=
4 | =?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=
5 |
6 | body
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_octet_attachment.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 | Content-Type: multipart/mixed; boundary=longrandomstring
4 |
5 | --longrandomstring
6 |
7 | body
8 | --longrandomstring
9 | Content-Type: application/octet-stream
10 | Content-Transfer-Encoding: base64
11 |
12 | aWYgeW91IGFyZSByZWFkaW5nIHRoaXMsIGhpIQ==
13 | --longrandomstring--
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_octet_attachment_bad_2231_filename.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 | Content-Type: multipart/mixed; boundary=longrandomstring
4 |
5 | --longrandomstring
6 |
7 | body
8 | --longrandomstring
9 | Content-Type: application/octet-stream
10 | Content-Transfer-Encoding: base64
11 | Content-Disposition: attachment; filename*=utf-8'%F0%9F%98%81%F0%9F%98%82.txt
12 |
13 | aWYgeW91IGFyZSByZWFkaW5nIHRoaXMsIGhpIQ==
14 | --longrandomstring--
15 |
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_octet_attachment_good_2231_filename.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 | Content-Type: multipart/mixed; boundary=longrandomstring
4 |
5 | --longrandomstring
6 |
7 | body
8 | --longrandomstring
9 | Content-Type: application/octet-stream
10 | Content-Transfer-Encoding: base64
11 | Content-Disposition: attachment; filename*=utf-8''%F0%9F%98%81%F0%9F%98%82.txt
12 |
13 | aWYgeW91IGFyZSByZWFkaW5nIHRoaXMsIGhpIQ==
14 | --longrandomstring--
15 |
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_octet_attachment_name_conflict.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 | Content-Type: multipart/mixed; boundary=longrandomstring
4 |
5 | --longrandomstring
6 |
7 | body
8 | --longrandomstring
9 | Content-Type: application/octet-stream; name="attachment-contenttype.txt"
10 | Content-Transfer-Encoding: base64
11 | Content-Disposition: attachment; filename="attachment-disposition.txt"
12 |
13 | aWYgeW91IGFyZSByZWFkaW5nIHRoaXMsIGhpIQ==
14 | --longrandomstring--
15 |
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_octet_attachment_name_in_contenttype.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 | Content-Type: multipart/mixed; boundary=longrandomstring
4 |
5 | --longrandomstring
6 |
7 | body
8 | --longrandomstring
9 | Content-Type: application/octet-stream; name="attachment-contenttype.txt"
10 | Content-Transfer-Encoding: base64
11 | Content-Disposition: attachment
12 |
13 | aWYgeW91IGFyZSByZWFkaW5nIHRoaXMsIGhpIQ==
14 | --longrandomstring--
15 |
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_pdf_attachment_cyrillic.eml:
--------------------------------------------------------------------------------
1 | Content-Type: multipart/mixed; boundary="------------bYzsV6z0EdKTbltmCDZgIM15"
2 | To: "Receiver"
3 | From: "Sender"
4 | Subject: Test with cyrillic attachment
5 |
6 | --------------bYzsV6z0EdKTbltmCDZgIM15
7 | Content-Transfer-Encoding: quoted-printable
8 | Content-Type: text/plain; charset=utf-8
9 |
10 | Shake that body
11 | --------------bYzsV6z0EdKTbltmCDZgIM15
12 | Content-Type: application/pdf;
13 | name="=?UTF-8?B?0JDQkdCS0JPQlNCD0JXQltCX0IXQmNCI0JrQm9CJ0JzQndCK0J7Qn9Cg?=
14 | =?UTF-8?B?0KHQotCM0KPQpNCl0KfQj9CX0KgucGRm?="
15 | Content-Disposition: attachment;
16 | filename*0*=UTF-8''%D0%90%D0%91%D0%92%D0%93%D0%94%D0%83%D0%95%D0%96%D0%97;
17 | filename*1*=%D0%85%D0%98%D0%88%D0%9A%D0%9B%D0%89%D0%9C%D0%9D%D0%8A%D0%9E;
18 | filename*2*=%D0%9F%D0%A0%D0%A1%D0%A2%D0%8C%D0%A3%D0%A4%D0%A5%D0%A7%D0%8F;
19 | filename*3*=%D0%97%D0%A8%2E%70%64%66
20 | Content-Transfer-Encoding: base64
21 |
22 | 0JDQkdCS0JPQlNCD0JXQltCX0IXQmNCI0JrQm9CJ0JzQndCK0J7Qn9Cg0KHQotCM0KPQpNCl0KfQj9CX0Kg=
23 |
24 |
25 | --------------bYzsV6z0EdKTbltmCDZgIM15--
26 |
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_plain_attachment.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 | Content-Type: multipart/mixed; boundary=longrandomstring
4 |
5 | --longrandomstring
6 |
7 | body
8 | --longrandomstring
9 | Content-Disposition: attachment
10 |
11 | attachment
12 | --longrandomstring--
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_plain_attachment_latin1.eml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/pkg/message/testdata/text_plain_plain_attachment_latin1.eml
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_plain_attachment_latin2.eml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/pkg/message/testdata/text_plain_plain_attachment_latin2.eml
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_rfc822_attachment.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 | Content-Type: multipart/mixed; boundary=longrandomstring
4 |
5 | --longrandomstring
6 |
7 | body
8 | --longrandomstring
9 | Content-Type: message/rfc822
10 | Content-Disposition: attachment
11 |
12 | From: Sender
13 | To: Receiver
14 |
15 | inner body
16 | --longrandomstring--
17 |
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_unknown_latin1.eml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/pkg/message/testdata/text_plain_unknown_latin1.eml
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_unknown_latin2.eml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/pkg/message/testdata/text_plain_unknown_latin2.eml
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_utf8.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 | Content-Type: text/plain; charset=utf-8
4 |
5 | body
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_utf8_reply_to_and_x_forward.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 | Content-Type: text/plain; charset=utf-8
4 | X-Forwarded-Message-Id: <00000@protonmail.com>
5 | In-Reply-To: <00000@protonmail.com>
6 |
7 | body
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_utf8_subject.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 | Subject: =?UTF-8?B?5rGJ5a2X5rGJ5a2X5rGJ?=
4 |
5 | body
--------------------------------------------------------------------------------
/pkg/message/testdata/text_plain_xml_attachment_cp1250.eml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/pkg/message/testdata/text_plain_xml_attachment_cp1250.eml
--------------------------------------------------------------------------------
/pkg/message/testdata/wrong_base64.eml:
--------------------------------------------------------------------------------
1 | From: Sender
2 | To: Receiver
3 | Content-Type: multipart/mixed; boundary=longrandomstring
4 |
5 | --longrandomstring
6 | Content-Type: text/html
7 |
8 | This is body of HTML mail with attachment
9 | --longrandomstring
10 | Content-Type: application/octet-stream
11 | Content-Transfer-Encoding: base64
12 |
13 | b'aWYgeW91IGFyZSByZWFkaW5nIHRoaXMsIGhpIQ=='
14 | --longrandomstring--
15 |
--------------------------------------------------------------------------------
/pkg/mime/Changelog.md:
--------------------------------------------------------------------------------
1 | # Do not modify this file!
2 | It is here for historical reasons only. All changes should be documented in the
3 | Changelog at the root of this repository.
4 |
5 |
6 | # Changelog
7 |
8 | ## [2019-12-10] v1.0.2
9 |
10 | ### Added
11 | * support for shift_JIS (cp932) encoding
12 |
13 | ## [2019-09-30] v1.0.1
14 |
15 | ### Changed
16 | * fix divide by zero
17 |
18 | ## [2019-09-26] v1.0.0
19 |
20 | ### Changed
21 | * Import-Export#192: filter header parameters
22 | * ignore twice the same parameter (take the latest)
23 | * convert non utf8 RFC2231 parameters to a single line utf8 RFC2231
24 |
25 |
--------------------------------------------------------------------------------
/pkg/restarter/start_default.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build !windows
19 | // +build !windows
20 |
21 | package restarter
22 |
23 | import (
24 | "os/exec"
25 | "syscall"
26 |
27 | "github.com/sirupsen/logrus"
28 | )
29 |
30 | func run(cmd *exec.Cmd) error {
31 | // Provide a new Group ID to the new process to ensure the child is detached even if parent crash before ending.
32 | cmd.SysProcAttr = &syscall.SysProcAttr{
33 | Setpgid: true,
34 | Pgid: 0,
35 | }
36 |
37 | logrus.WithField("cmd", cmd).Info("Starting new process")
38 |
39 | return cmd.Start()
40 | }
41 |
--------------------------------------------------------------------------------
/pkg/restarter/start_windows.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | //go:build windows
19 | // +build windows
20 |
21 | package restarter
22 |
23 | import (
24 | "os/exec"
25 | "syscall"
26 |
27 | "github.com/sirupsen/logrus"
28 | )
29 |
30 | func run(cmd *exec.Cmd) error {
31 | // Provide a new Group ID to the new process to ensure the child is detached even if parent crash before ending.
32 | cmd.SysProcAttr = &syscall.SysProcAttr{
33 | CreationFlags: syscall.CREATE_NEW_PROCESS_GROUP,
34 | }
35 |
36 | logrus.WithField("cmd", cmd).Info("Starting new process")
37 |
38 | return cmd.Start()
39 | }
40 |
--------------------------------------------------------------------------------
/tests/e2e/ui_tests/windows_os/TestsHelper/TestData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.IO;
4 |
5 | namespace ProtonMailBridge.UI.Tests.TestsHelper
6 | {
7 | public static class TestData
8 | {
9 | public static TimeSpan FiveSecondsTimeout => TimeSpan.FromSeconds(5);
10 | public static TimeSpan TenSecondsTimeout => TimeSpan.FromSeconds(10);
11 | public static TimeSpan ThirtySecondsTimeout => TimeSpan.FromSeconds(30);
12 | public static TimeSpan OneMinuteTimeout => TimeSpan.FromSeconds(60);
13 | public static TimeSpan RetryInterval => TimeSpan.FromMilliseconds(1000);
14 | public static string AppExecutable => "C:\\Program Files\\Proton AG\\Proton Mail Bridge\\proton-bridge.exe";
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/tests/e2e/ui_tests/windows_os/UIActions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using FlaUI.Core.AutomationElements;
3 | using FlaUI.Core.Definitions;
4 | using FlaUI.Core.Input;
5 | using FlaUI.Core.Tools;
6 | using NUnit.Framework;
7 |
8 | namespace ProtonMailBridge.UI.Tests
9 | {
10 | public class UIActions : TestSession
11 | {
12 | public AutomationElement AccountView => Window.FindFirstDescendant(cf => cf.ByControlType(ControlType.Pane));
13 | }
14 | }
--------------------------------------------------------------------------------
/tests/fast.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package tests
19 |
20 | import (
21 | "crypto/x509"
22 |
23 | "github.com/ProtonMail/proton-bridge/v3/internal/certs"
24 | )
25 |
26 | var (
27 | preCompCertPEM []byte
28 | preCompKeyPEM []byte
29 | )
30 |
31 | func FastGenerateCert(_ *x509.Certificate) ([]byte, []byte, error) {
32 | return preCompCertPEM, preCompKeyPEM, nil
33 | }
34 |
35 | func init() {
36 | template, err := certs.NewTLSTemplate()
37 | if err != nil {
38 | panic(err)
39 | }
40 |
41 | certPEM, keyPEM, err := certs.GenerateCert(template)
42 | if err != nil {
43 | panic(err)
44 | }
45 |
46 | preCompCertPEM = certPEM
47 | preCompKeyPEM = keyPEM
48 | }
49 |
--------------------------------------------------------------------------------
/tests/features/bridge/default_ports.feature:
--------------------------------------------------------------------------------
1 | Feature: Bridge picks default ports wisely
2 |
3 | Scenario: bridge picks ports for IMAP and SMTP using default values.
4 | When bridge starts
5 | Then bridge IMAP port is 1143
6 | Then bridge SMTP port is 1025
7 |
8 | Scenario: bridge picks ports for IMAP wisely when default port is busy.
9 | When the network port 1143 is busy
10 | And bridge starts
11 | Then bridge IMAP port is 1144
12 | Then bridge SMTP port is 1025
13 |
14 | Scenario: bridge picks ports for SMTP wisely when default port is busy.
15 | When the network port range 1025-1030 is busy
16 | And bridge starts
17 | Then bridge IMAP port is 1143
18 | Then bridge SMTP port is 1031
19 |
20 | Scenario: bridge picks ports for IMAP SMTP wisely when default ports are busy.
21 | When the network port range 1025-1200 is busy
22 | And bridge starts
23 | Then bridge IMAP port is 1201
24 | Then bridge SMTP port is 1202
25 |
--------------------------------------------------------------------------------
/tests/features/frontend/frontend.feature:
--------------------------------------------------------------------------------
1 | Feature: Frontend events
2 | Scenario: Frontend starts and stops
3 | Given bridge is version "2.3.0" and the latest available version is "2.3.0" reachable from "2.3.0"
4 | When bridge starts
5 | Then frontend sees that bridge is version "2.3.0"
6 |
--------------------------------------------------------------------------------
/tests/features/imap/mailbox/delete.feature:
--------------------------------------------------------------------------------
1 | Feature: IMAP delete mailbox
2 | Background:
3 | Given there exists an account with username "[user:user]" and password "password"
4 | And the account "[user:user]" has the following custom mailboxes:
5 | | name | type |
6 | | one | folder |
7 | | two | folder |
8 | | three | label |
9 | Then it succeeds
10 | When bridge starts
11 | And the user logs in with username "[user:user]" and password "password"
12 | And user "[user:user]" finishes syncing
13 | And user "[user:user]" connects and authenticates IMAP client "1"
14 | Then it succeeds
15 |
16 | Scenario: Delete folder
17 | When IMAP client "1" deletes "Folders/one"
18 | Then IMAP client "1" does not see "Folders/one"
19 | But IMAP client "1" sees "Folders/two"
20 | But IMAP client "1" sees "Labels/three"
21 |
22 | Scenario: Delete label
23 | When IMAP client "1" deletes "Labels/three"
24 | Then IMAP client "1" does not see "Labels/three"
25 | But IMAP client "1" sees "Folders/one"
26 | But IMAP client "1" sees "Folders/two"
27 |
28 | Scenario: Deleting system mailbox is not possible
29 | When IMAP client "1" deletes "INBOX"
30 | Then it fails
31 | And IMAP client "1" sees "INBOX"
32 |
--------------------------------------------------------------------------------
/tests/features/imap/mailbox/info.feature:
--------------------------------------------------------------------------------
1 | Feature: IMAP get mailbox info
2 | Background:
3 | Given there exists an account with username "[user:user]" and password "password"
4 | And the account "[user:user]" has the following custom mailboxes:
5 | | name | type |
6 | | one | folder |
7 | And the address "[user:user]@[domain]" of account "[user:user]" has the following messages in "Folders/one":
8 | | from | to | subject | unread |
9 | | a@example.com | a@example.com | one | true |
10 | | b@example.com | b@example.com | two | false |
11 | Then it succeeds
12 | When bridge starts
13 | And the user logs in with username "[user:user]" and password "password"
14 | And user "[user:user]" finishes syncing
15 | Then it succeeds
16 |
17 | Scenario: Mailbox status reports correct name, total and unread
18 | When user "[user:user]" connects and authenticates IMAP client "1"
19 | Then IMAP client "1" sees the following mailbox info for "Folders/one":
20 | | name | total | unread |
21 | | Folders/one | 2 | 1 |
--------------------------------------------------------------------------------
/tests/features/imap/mailbox/rename.feature:
--------------------------------------------------------------------------------
1 | Feature: IMAP get mailbox info
2 | Background:
3 | Given there exists an account with username "[user:user]" and password "password"
4 | And the account "[user:user]" has the following custom mailboxes:
5 | | name | type |
6 | | f1 | folder |
7 | | l1 | label |
8 | Then it succeeds
9 | When bridge starts
10 | And the user logs in with username "[user:user]" and password "password"
11 | And user "[user:user]" finishes syncing
12 | And user "[user:user]" connects and authenticates IMAP client "1"
13 | Then it succeeds
14 |
15 | Scenario: Rename folder
16 | When IMAP client "1" renames "Folders/f1" to "Folders/f2"
17 | Then IMAP client "1" sees "Folders/f2"
18 | And IMAP client "1" does not see "Folders/f1"
19 |
20 | Scenario: Rename label
21 | When IMAP client "1" renames "Labels/l1" to "Labels/l2"
22 | Then IMAP client "1" sees "Labels/l2"
23 | And IMAP client "1" does not see "Labels/l1"
24 |
25 | Scenario: Renaming folder to label is not possible
26 | When IMAP client "1" renames "Folders/f1" to "Labels/f2"
27 | Then it fails
28 |
29 | Scenario: Renaming system folder is not possible
30 | When IMAP client "1" renames "Labels/l1" to "Folders/l2"
31 | Then it fails
--------------------------------------------------------------------------------
/tests/features/imap/mailbox/rename_hiearchy.feature:
--------------------------------------------------------------------------------
1 | Feature: IMAP get mailbox info
2 | Background:
3 | Given there exists an account with username "[user:user]" and password "password"
4 | And the account "[user:user]" has the following custom mailboxes:
5 | | name | type |
6 | | f1 | folder |
7 | | f1/f2| folder |
8 | Then it succeeds
9 | When bridge starts
10 | And the user logs in with username "[user:user]" and password "password"
11 | And user "[user:user]" finishes syncing
12 | And user "[user:user]" connects and authenticates IMAP client "1"
13 | Then it succeeds
14 |
15 | # with black subfolder is not renamed (maybe missing event?)
16 | @skip-black
17 | Scenario: Rename folder with subfolders
18 | When IMAP client "1" renames "Folders/f1" to "Folders/f3"
19 | And it succeeds
20 | Then IMAP client "1" sees "Folders/f3"
21 | Then IMAP client "1" sees "Folders/f3/f2"
22 | And IMAP client "1" does not see "Folders/f1"
23 | And IMAP client "1" does not see "Folders/f1/f2"
24 |
--------------------------------------------------------------------------------
/tests/features/imap/mailbox/select.feature:
--------------------------------------------------------------------------------
1 | Feature: IMAP select mailbox
2 | Background:
3 | Given there exists an account with username "[user:user]" and password "password"
4 | And the account "[user:user]" has the following custom mailboxes:
5 | | name | type |
6 | | mbox | folder |
7 | | label | label |
8 | Then it succeeds
9 | When bridge starts
10 | And the user logs in with username "[user:user]" and password "password"
11 | And user "[user:user]" finishes syncing
12 | And user "[user:user]" connects and authenticates IMAP client "1"
13 | Then it succeeds
14 |
15 | Scenario: Select inbox
16 | When IMAP client "1" selects "INBOX"
17 | Then it succeeds
18 |
19 | Scenario: Select custom mailbox
20 | When IMAP client "1" selects "Folders/mbox"
21 | Then it succeeds
22 |
23 | Scenario: Select custom label
24 | When IMAP client "1" selects "Labels/label"
25 | Then it succeeds
26 |
27 | Scenario: Select non-existing mailbox
28 | When IMAP client "1" selects "qwerty"
29 | Then it fails
30 |
--------------------------------------------------------------------------------
/tests/features/imap/ports.feature:
--------------------------------------------------------------------------------
1 | Feature: A user can connect an IMAP client to custom ports
2 | Background:
3 | Given there exists an account with username "[user:user]" and password "password"
4 | Then it succeeds
5 | When bridge starts
6 | And the user logs in with username "[user:user]" and password "password"
7 | And the user changes the IMAP port to 1144
8 | Then it succeeds
9 |
10 | Scenario: Authenticates successfully on custom port
11 | When user "[user:user]" connects IMAP client "1" on port 1144
12 | Then IMAP client "1" can authenticate
--------------------------------------------------------------------------------
/tests/features/observability/gluon_metrics.feature:
--------------------------------------------------------------------------------
1 | Feature: Bridge send remote notification observability metrics
2 | Background:
3 | Given there exists an account with username "[user:user1]" and password "password"
4 | Then it succeeds
5 | When bridge starts
6 | Then it succeeds
7 |
8 | Scenario: Test all possible gluon error observability metrics
9 | When the user logs in with username "[user:user1]" and password "password"
10 | And the user with username "[user:user1]" sends all possible gluon error observability metrics
11 | Then it succeeds
12 |
--------------------------------------------------------------------------------
/tests/features/observability/remote_notification.feature:
--------------------------------------------------------------------------------
1 | Feature: Bridge send remote notification observability metrics
2 | Background:
3 | Given there exists an account with username "[user:user1]" and password "password"
4 | And there exists an account with username "[user:user2]" and password "password"
5 | Then it succeeds
6 | When bridge starts
7 | Then it succeeds
8 |
9 |
10 | Scenario: Send notification 'received' and 'processed' observability metric
11 | When the user logs in with username "[user:user1]" and password "password"
12 | And the user with username "[user:user1]" sends the following remote notification observability metric "received"
13 | Then it succeeds
14 | And the user with username "[user:user1]" sends the following remote notification observability metric "processed"
15 | Then it succeeds
16 |
17 |
18 |
--------------------------------------------------------------------------------
/tests/features/smtp/ports.feature:
--------------------------------------------------------------------------------
1 | Feature: A user can connect an SMTP client to custom ports
2 | Background:
3 | Given there exists an account with username "[user:user]" and password "password"
4 | Then it succeeds
5 | When bridge starts
6 | And the user logs in with username "[user:user]" and password "password"
7 | Then it succeeds
8 |
9 | Scenario: Authenticates successfully on custom port
10 | When the user changes the SMTP port to 1144
11 | When user "[user:user]" connects SMTP client "1" on port 1144
12 | Then SMTP client "1" can authenticate
--------------------------------------------------------------------------------
/tests/features/smtp/send/failures_disabled.feature:
--------------------------------------------------------------------------------
1 | Feature: SMTP wrong messages
2 | Background:
3 | Given there exists an account with username "[user:user]" and password "password"
4 | And the account "[user:user]" has additional disabled address "[user:disabled]@[domain]"
5 | And there exists an account with username "[user:to]" and password "password"
6 | Then it succeeds
7 | When bridge starts
8 | And the user logs in with username "[user:user]" and password "password"
9 | And user "[user:user]" connects and authenticates SMTP client "1"
10 | Then it succeeds
11 |
12 | # Need to find way to setup disabled address on black
13 | @skip-black
14 | Scenario: Send from a valid address that cannot send
15 | Given the account "[user:user]" has additional disabled address "[user:disabled]@[domain]"
16 | When SMTP client "1" sends the following message from "[user:disabled]@[domain]" to "[user:to]@[domain]":
17 | """
18 | From: Bridge Test Disabled <[user:disabled]@[domain]>
19 | To: Internal Bridge <[user:to]@[domain]>
20 |
21 | Hello
22 | """
23 | And it fails with error "Error: cannot send from address: [user:disabled]@[domain]"
24 |
25 |
--------------------------------------------------------------------------------
/tests/features/user/account.feature:
--------------------------------------------------------------------------------
1 | Feature: Account settings
2 |
3 | Background:
4 | Given there exists an account with username "[user:user]" and password "password"
5 | Then it succeeds
6 | When bridge starts
7 |
8 | Scenario: Check account default settings
9 | Then the account "[user:user]" matches the following settings:
10 | | DraftMIMEType | AttachPublicKey | Sign | PGPScheme |
11 | | text/html | false | 0 | 0 |
12 | When the account "[user:user]" has public key attachment "enabled"
13 | And the account "[user:user]" has sign external messages "enabled"
14 | And the account "[user:user]" has default draft format "plain"
15 | And the account "[user:user]" has default PGP schema "inline"
16 | Then the account "[user:user]" matches the following settings:
17 | | DraftMIMEType | AttachPublicKey | Sign | PGPScheme |
18 | | text/plain | true | 1 | 8 |
19 |
20 |
--------------------------------------------------------------------------------
/tests/features/user/delete.feature:
--------------------------------------------------------------------------------
1 | Feature: A user can be deleted
2 | Background:
3 | Given there exists an account with username "[user:user]" and password "password"
4 | Then it succeeds
5 | When bridge starts
6 | And the user logs in with username "[user:user]" and password "password"
7 | Then it succeeds
8 |
9 | Scenario: Delete a connected user
10 | When user "[user:user]" is deleted
11 | Then user "[user:user]" is not listed
12 |
13 | Scenario: Delete a disconnected user
14 | Given user "[user:user]" logs out
15 | When user "[user:user]" is deleted
16 | Then user "[user:user]" is not listed
--------------------------------------------------------------------------------
/tests/features/user/delete_imap.feature:
--------------------------------------------------------------------------------
1 | Feature: User deletion with IMAP data removal
2 | Background:
3 | Given there exists an account with username "[user:user]" and password "password"
4 | And the account "[user:user]" has the following custom mailboxes:
5 | | name | type |
6 | | one | folder |
7 | And the address "[user:user]@[domain]" of account "[user:user]" has the following messages in "Folders/one":
8 | | from | to | subject | unread |
9 | | a@example.com | a@example.com | one | true |
10 | | b@example.com | b@example.com | two | false |
11 | | c@example.com | c@example.com | three | true |
12 | | c@example.com | c@example.com | four | false |
13 | Then it succeeds
14 | When bridge starts
15 | And the user logs in with username "[user:user]" and password "password"
16 | And user "[user:user]" finishes syncing
17 | Then it succeeds
18 |
19 | Scenario: User is deleted from Bridge and IMAP data is removed
20 | When user "[user:user]" connects and authenticates IMAP client "1"
21 | Then IMAP client "1" sees the following mailbox info for "Folders/one":
22 | | name | total | unread |
23 | | Folders/one | 4 | 2 |
24 | And user "[user:user]" is deleted alongside IMAP data for client "1"
25 | Then it succeeds
26 |
--------------------------------------------------------------------------------
/tests/features/user/relogin.feature:
--------------------------------------------------------------------------------
1 | Feature: A logged out user can login again
2 | Background:
3 | Given there exists an account with username "[user:user]" and password "password"
4 | Then it succeeds
5 | When bridge starts
6 | And the user logs in with username "[user:user]" and password "password"
7 | Then it succeeds
8 |
9 | Scenario: Login to disconnected account
10 | When user "[user:user]" logs out
11 | And bridge restarts
12 | And the user logs in with username "[user:user]" and password "password"
13 | Then user "[user:user]" is eventually listed and connected
14 |
15 | Scenario: Cannot login to removed account
16 | When user "[user:user]" is deleted
17 | Then user "[user:user]" is not listed
18 |
19 | Scenario: Bridge password persists after logout/login
20 | Given there exists an account with username "[user:test]" and password "password"
21 | And the user logs in with username "[user:test]" and password "password"
22 | And the bridge password of user "[user:test]" is changed to "YnJpZGdlcGFzc3dvcmQK"
23 | And user "[user:test]" is deleted
24 | And the user logs in with username "[user:test]" and password "password"
25 | Then user "[user:test]" is eventually listed and connected
26 | And the bridge password of user "[user:test]" is equal to "YnJpZGdlcGFzc3dvcmQK"
27 |
--------------------------------------------------------------------------------
/tests/features/user/revoke.feature:
--------------------------------------------------------------------------------
1 | Feature: A logged in user is logged out when its auth is revoked.
2 | Background:
3 | Given there exists an account with username "[user:user]" and password "password"
4 | Then it succeeds
5 | When bridge starts
6 | And the user logs in with username "[user:user]" and password "password"
7 | Then it succeeds
8 |
9 | Scenario: The auth is revoked while bridge is running
10 | When the auth of user "[user:user]" is revoked
11 | Then bridge sends a deauth event for user "[user:user]"
12 | And user "[user:user]" is listed but not connected
13 |
14 | Scenario: The auth is revoked while bridge is not running
15 | Given bridge stops
16 | And the auth of user "[user:user]" is revoked
17 | When bridge starts
18 | Then user "[user:user]" is listed but not connected
--------------------------------------------------------------------------------
/tests/features/user/telemetry.feature:
--------------------------------------------------------------------------------
1 | Feature: Bridge send usage metrics
2 | Background:
3 | Given there exists an account with username "[user:user1]" and password "password"
4 | And there exists an account with username "[user:user2]" and password "password"
5 | Then it succeeds
6 | When bridge starts
7 | Then it succeeds
8 |
9 |
10 | Scenario: Telemetry availability - No user
11 | Then bridge telemetry feature is enabled
12 | When the user disables telemetry in bridge settings
13 | Then bridge telemetry feature is disabled
14 | When the user enables telemetry in bridge settings
15 | Then bridge telemetry feature is enabled
16 |
17 |
18 | Scenario: Telemetry availability - Multi user
19 | When the user logs in with username "[user:user1]" and password "password"
20 | And user "[user:user1]" finishes syncing
21 | Then bridge telemetry feature is enabled
22 | When the user logs in with username "[user:user2]" and password "password"
23 | And user "[user:user2]" finishes syncing
24 | When user "[user:user2]" has telemetry set to 0
25 | Then bridge telemetry feature is disabled
26 | When user "[user:user2]" has telemetry set to 1
27 | Then bridge telemetry feature is enabled
28 | When the user disables telemetry in bridge settings
29 | Then bridge telemetry feature is disabled
30 | When the user enables telemetry in bridge settings
31 | Then bridge telemetry feature is enabled
--------------------------------------------------------------------------------
/tests/frontend_test.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package tests
19 |
20 | import (
21 | "context"
22 | "fmt"
23 |
24 | "google.golang.org/protobuf/types/known/emptypb"
25 | )
26 |
27 | func (s *scenario) frontendSeesThatBridgeIsVersion(version string) error {
28 | res, err := s.t.client.Version(context.Background(), &emptypb.Empty{})
29 | if err != nil {
30 | return err
31 | }
32 |
33 | if version != res.GetValue() {
34 | return fmt.Errorf("expected version %s, got %s", version, res.GetValue())
35 | }
36 |
37 | return nil
38 | }
39 |
--------------------------------------------------------------------------------
/tests/testdata/html/foreign_ascii_subject_body.template.eml:
--------------------------------------------------------------------------------
1 | From: Bridge Test <[user:user]@[domain]>
2 | To: External Bridge
3 | Subject: =?UTF-8?B?U3Vias61zq3Pgs+EIMK2IMOEIMOI?=
4 | Content-Type: text/html; charset=UTF-8
5 | Content-Transfer-Encoding: 8bit
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | Subjεέςτ ¶ Ä È
14 |
15 |
16 |
--------------------------------------------------------------------------------
/tests/testdata/multipart/mixed_with_attachment_encoded.eml:
--------------------------------------------------------------------------------
1 | From: Bridge Test
2 | Date: 01 Jan 1980 00:00:00 +0000
3 | To: Internal Bridge
4 | Subject: Message with attachment name
5 | Content-type: multipart/mixed; boundary="boundary"
6 | Received: by 2002:0:0:0:0:0:0:0 with SMTP id 0123456789abcdef; Wed, 30 Dec 2020 01:23:45 0000
7 |
8 | This is a multi-part message in MIME format.
9 |
10 | --boundary
11 | Content-Type: text/plain
12 |
13 | Hello
14 |
15 | --boundary
16 | Content-Type: text/html; charset=utf-8
17 | Content-Transfer-Encoding: 7bit
18 |
19 |
HELLO
20 |
21 | --boundary
22 | Content-Type: application/pdf; name="=?US-ASCII?Q?filename?="
23 | Content-Disposition: attachment; filename="=?US-ASCII?Q?filename?="
24 |
25 | somebytes
26 |
27 | --boundary--
28 |
--------------------------------------------------------------------------------
/tests/testdata/multipart/mixed_with_attachment_encoded_no_quote.eml:
--------------------------------------------------------------------------------
1 | From: Bridge Test
2 | Date: 01 Jan 1980 00:00:00 +0000
3 | To: Internal Bridge
4 | Subject: Message with attachment name
5 | Content-type: multipart/mixed; boundary="boundary"
6 | Received: by 2002:0:0:0:0:0:0:0 with SMTP id 0123456789abcdef; Wed, 30 Dec 2020 01:23:45 0000
7 |
8 | This is a multi-part message in MIME format.
9 |
10 | --boundary
11 | Content-Type: text/plain
12 |
13 | Hello
14 |
15 | --boundary
16 | Content-Type: text/html; charset=utf-8
17 | Content-Transfer-Encoding: 7bit
18 |
19 |
HELLO
20 |
21 | --boundary
22 | Content-Type: application/pdf; name==?US-ASCII?Q?filename?=
23 | Content-Disposition: attachment; filename==?US-ASCII?Q?filename?=
24 |
25 | somebytes
26 |
27 | --boundary--
28 |
--------------------------------------------------------------------------------
/tests/testdata/multipart/mixed_with_attachment_no_quote.eml:
--------------------------------------------------------------------------------
1 | From: Bridge Test
2 | Date: 01 Jan 1980 00:00:00 +0000
3 | To: Internal Bridge
4 | Subject: Message with attachment name
5 | Content-type: multipart/mixed; boundary="boundary"
6 | Received: by 2002:0:0:0:0:0:0:0 with SMTP id 0123456789abcdef; Wed, 30 Dec 2020 01:23:45 0000
7 |
8 | This is a multi-part message in MIME format.
9 |
10 | --boundary
11 | Content-Type: text/plain
12 |
13 | Hello
14 |
15 | --boundary
16 | Content-Type: text/html; charset=utf-8
17 | Content-Transfer-Encoding: 7bit
18 |
19 |
HELLO
20 |
21 | --boundary
22 | Content-Type: application/pdf; name=filename
23 | Content-Disposition: attachment; filename=filename
24 |
25 | somebytes
26 |
27 | --boundary--
28 |
--------------------------------------------------------------------------------
/tests/testdata/plain/text_plain_latin1.eml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/tests/testdata/plain/text_plain_latin1.eml
--------------------------------------------------------------------------------
/tests/testdata/plain/text_plain_unknown_latin1.eml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/tests/testdata/plain/text_plain_unknown_latin1.eml
--------------------------------------------------------------------------------
/tests/testdata/plain/text_plain_wrong_latin1.eml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/tests/testdata/plain/text_plain_wrong_latin1.eml
--------------------------------------------------------------------------------
/utils/QTBUG-88600/README.txt:
--------------------------------------------------------------------------------
1 | This is version of libqcocoa obtained from original Qt 5.13.0 source available at https://github.com/qt/qtbase with patch from cocoa.patch applied.
2 |
3 | Please refer to https://bugreports.qt.io/browse/QTBUG-88600 for patch origin and https://doc.qt.io/qt-5/macos-building.html for instructions how to build Qt from source.
4 |
--------------------------------------------------------------------------------
/utils/QTBUG-88600/cocoa.patch:
--------------------------------------------------------------------------------
1 | diff --git a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
2 | index 4982f5ee05..3ae1e4fca3 100644
3 | --- a/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
4 | +++ b/src/plugins/platforms/cocoa/qcocoasystemtrayicon.mm
5 | @@ -224,6 +224,7 @@ void QCocoaSystemTrayIcon::updateIcon(const QIcon &icon)
6 | r.moveCenter(fullHeightPixmap.rect().center());
7 | p.drawPixmap(r, pixmap);
8 | }
9 | + fullHeightPixmap.setDevicePixelRatio(devicePixelRatio);
10 |
11 | NSImage *nsimage = static_cast(qt_mac_create_nsimage(fullHeightPixmap));
12 | [nsimage setTemplate:icon.isMask()];
13 |
--------------------------------------------------------------------------------
/utils/QTBUG-88600/libqcocoa.dylib:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ProtonMail/proton-bridge/94125056abbcbbb91df6b0f95fb6fe605d583754/utils/QTBUG-88600/libqcocoa.dylib
--------------------------------------------------------------------------------
/utils/bridge-rollout/README.md:
--------------------------------------------------------------------------------
1 | @@ -0,0 +1,10 @@
2 | # Vault Editor
3 |
4 | Bridge uses an encrypted vault to store persistent data. One of the parameters stored in this vault is the roll factor (between 0.0 and 1.0)
5 |
6 | It can be built with `make vault-editor` in the bridge source code root directory.
7 |
8 | Example usage:
9 |
10 | Setting the rollout value:
11 | ```bash
12 | $ ./bridge-rollout set -v=0.81
13 | 0.81
14 | ```
15 | Note that the provided value will be clamped between 0 and 1.
16 |
17 | ```bash
18 | $ ./bridge-rollout get
19 | 0.81
20 | ```
21 |
--------------------------------------------------------------------------------
/utils/bridge_app_version.ps1:
--------------------------------------------------------------------------------
1 | Select-String -Path (Join-Path $PSScriptRoot "../Makefile") -Pattern "^BRIDGE_APP_VERSION\?=(\S*)" |
2 | ForEach-Object {$_.Matches} | ForEach-Object { $_.Groups[1].Value }
--------------------------------------------------------------------------------
/utils/bridge_app_version.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Copyright (c) 2025 Proton AG
4 | #
5 | # This file is part of Proton Mail Bridge.
6 | #
7 | # Proton Mail Bridge is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # Proton Mail Bridge is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with Proton Mail Bridge. If not, see .
19 |
20 | sed -n "s/BRIDGE_APP_VERSION?=\(\S*\)/\1/p" "$(dirname $0)/../Makefile"
21 |
--------------------------------------------------------------------------------
/utils/debug/debug_assemble.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package main
19 |
20 | import (
21 | "fmt"
22 | "os"
23 |
24 | "github.com/ProtonMail/proton-bridge/v3/internal/user"
25 | )
26 |
27 | func main() {
28 | if len(os.Args) < 2 {
29 | fmt.Printf("Usage: %v \n", os.Args[0])
30 | return
31 | }
32 |
33 | if err := user.TryBuildDebugMessage(os.Args[1]); err != nil {
34 | fmt.Printf("%v\n", err.Error())
35 | return
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/utils/dxtn/dxtn.layout:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/utils/dxtn/main.cpp:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | #include "main.h"
19 |
20 | extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
21 | {
22 | return FALSE;
23 | }
24 |
--------------------------------------------------------------------------------
/utils/dxtn/main.h:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | #ifndef __MAIN_H__
19 | #define __MAIN_H__
20 |
21 | #include
22 |
23 | #ifdef BUILD_DLL
24 | #define DLL_EXPORT __declspec(dllexport)
25 | #else
26 | #define DLL_EXPORT __declspec(dllimport)
27 | #endif
28 |
29 | #endif // __MAIN_H__
30 |
--------------------------------------------------------------------------------
/utils/get_revision.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Copyright (c) 2025 Proton AG
4 | #
5 | # This file is part of Proton Mail Bridge.
6 | #
7 | # Proton Mail Bridge is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # Proton Mail Bridge is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with Proton Mail Bridge. If not, see .
19 |
20 |
21 | if ! which git &> /dev/null; then
22 | echo "NOGIT"
23 | exit
24 | fi
25 |
26 | if ! git status &> /dev/null; then
27 | echo "NOREPO"
28 | exit
29 | fi
30 |
31 | if [ "$1" == "tag" ]; then
32 | if ! git describe --tags; then
33 | echo "NOTAG"
34 | fi
35 | exit
36 | fi
37 |
38 | if ! git rev-parse --short=10 HEAD; then
39 | echo "NOREV"
40 | exit
41 | fi
42 |
43 |
--------------------------------------------------------------------------------
/utils/keyring.go:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 | package utils
19 |
20 | import (
21 | "testing"
22 |
23 | "github.com/ProtonMail/gopenpgp/v2/crypto"
24 | "github.com/stretchr/testify/require"
25 | )
26 |
27 | func MakeKeyRing(t *testing.T) *crypto.KeyRing {
28 | key, err := crypto.GenerateKey("name", "email", "rsa", 2048)
29 | require.NoError(t, err)
30 |
31 | kr, err := crypto.NewKeyRing(key)
32 | require.NoError(t, err)
33 |
34 | return kr
35 | }
36 |
--------------------------------------------------------------------------------
/utils/license_header.txt:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2025 Proton AG
2 | //
3 | // This file is part of Proton Mail Bridge.
4 | //
5 | // Proton Mail Bridge is free software: you can redistribute it and/or modify
6 | // it under the terms of the GNU General Public License as published by
7 | // the Free Software Foundation, either version 3 of the License, or
8 | // (at your option) any later version.
9 | //
10 | // Proton Mail Bridge is distributed in the hope that it will be useful,
11 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | // GNU General Public License for more details.
14 | //
15 | // You should have received a copy of the GNU General Public License
16 | // along with Proton Mail Bridge. If not, see .
17 |
18 |
--------------------------------------------------------------------------------