GODT-1553: RPC definition and mocks

WIP: updates

WIP: cache on disk and autostart.

WIP: mail, keychain and more.

WIP: updated grpc version in go mod file.

WIP: user list.

WIP: RPC service placeholder

WIP: test C++ RPC client skeleton.

Other: missing license script update.

WIP: use Qt test framework.

WIP: test for app and login calls.

WIP: test for update & cache on disk calls.

WIP: tests for mail settings calls.

WIP: all client tests.

WIP: linter fixes.

WIP: fix missing license link.

WIP: update dependency_license script for gRPC and protobuf.

WIP: removed unused file.

WIP: app & login event streaming tests.

WIP: update event stream tests.

WIP: completed event streaming tests.
This commit is contained in:
Xavier Michelon
2022-05-16 10:59:45 +02:00
committed by Jakub
parent b5321f8993
commit a4e54f063d
24 changed files with 49262 additions and 27 deletions

View File

@ -31,6 +31,7 @@ import (
"github.com/ProtonMail/proton-bridge/v2/internal/frontend"
"github.com/ProtonMail/proton-bridge/v2/internal/frontend/types"
"github.com/ProtonMail/proton-bridge/v2/internal/imap"
"github.com/ProtonMail/proton-bridge/v2/internal/rpc"
"github.com/ProtonMail/proton-bridge/v2/internal/smtp"
"github.com/ProtonMail/proton-bridge/v2/internal/store"
"github.com/ProtonMail/proton-bridge/v2/internal/store/cache"
@ -138,6 +139,11 @@ func mailLoop(b *base.Base, c *cli.Context) error { //nolint:funlen
smtpPort, useSSL, tlsConfig, smtpBackend, b.Listener).ListenAndServe()
}()
go func() {
defer b.CrashHandler.HandlePanic()
rpc.NewServer().ListenAndServe()
}()
// We want to remove old versions if the app exits successfully.
b.AddTeardownAction(b.Versioner.RemoveOldVersions)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,428 @@
// Copyright (c) 2022 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
syntax = "proto3";
import "google/protobuf/empty.proto";
import "google/protobuf/wrappers.proto";
option go_package = "github.com/ProtonMail/proton-bridge/internal/rpc";
package bridgerpc; // ignored by Go, used as namespace name in C++.
//**********************************************************************************************************************
// Service Declaration
//**********************************************************************************************************************
service BridgeRpc {
// App related calls
rpc GetCursorPos (google.protobuf.Empty) returns (PointResponse); // May be unnecessary
rpc GuiReady (google.protobuf.Empty) returns (google.protobuf.Empty);
rpc Quit (google.protobuf.Empty) returns (google.protobuf.Empty);
rpc Restart (google.protobuf.Empty) returns (google.protobuf.Empty);
rpc SetShowOnStartup(google.protobuf.BoolValue) returns (google.protobuf.Empty);
rpc ShowOnStartup(google.protobuf.Empty) returns (google.protobuf.BoolValue);
rpc SetShowSplashScreen(google.protobuf.BoolValue) returns (google.protobuf.Empty);
rpc ShowSplashScreen(google.protobuf.Empty) returns (google.protobuf.BoolValue);
rpc SetDockIconVisible(google.protobuf.BoolValue) returns (google.protobuf.Empty);
rpc DockIconVisible(google.protobuf.Empty) returns (google.protobuf.BoolValue);
rpc SetIsFirstGuiStart(google.protobuf.BoolValue) returns (google.protobuf.Empty);
rpc IsFirstGuiStart(google.protobuf.Empty) returns (google.protobuf.BoolValue);
rpc SetIsAutostartOn(google.protobuf.BoolValue) returns (google.protobuf.Empty);
rpc IsAutostartOn(google.protobuf.Empty) returns (google.protobuf.BoolValue);
rpc SetIsBetaEnabled(google.protobuf.BoolValue) returns (google.protobuf.Empty);
rpc IsBetaEnabled(google.protobuf.Empty) returns (google.protobuf.BoolValue);
rpc GoOs(google.protobuf.Empty) returns (google.protobuf.StringValue);
rpc TriggerReset(google.protobuf.Empty) returns (google.protobuf.Empty);
rpc Version(google.protobuf.Empty) returns (google.protobuf.StringValue);
rpc LogPath(google.protobuf.Empty) returns (google.protobuf.StringValue);
rpc LicensePath(google.protobuf.Empty) returns (google.protobuf.StringValue);
rpc ReleaseNotesLink(google.protobuf.Empty) returns (google.protobuf.StringValue);
rpc LandingPageLink(google.protobuf.Empty) returns (google.protobuf.StringValue);
rpc SetColorSchemeName(google.protobuf.StringValue) returns (google.protobuf.Empty);
rpc ColorSchemeName(google.protobuf.Empty) returns (google.protobuf.StringValue);
rpc SetCurrentEmailClient(google.protobuf.StringValue) returns (google.protobuf.Empty);
rpc CurrentEmailClient(google.protobuf.Empty) returns (google.protobuf.StringValue);
rpc ReportBug(ReportBugRequest) returns (google.protobuf.Empty);
// login
rpc Login(LoginRequest) returns (google.protobuf.Empty);
rpc Login2FA(LoginRequest) returns (google.protobuf.Empty);
rpc Login2Passwords(LoginRequest) returns (google.protobuf.Empty);
rpc LoginAbort(LoginAbortRequest) returns (google.protobuf.Empty);
// update
rpc CheckUpdate(google.protobuf.Empty) returns (google.protobuf.Empty);
rpc InstallUpdate(google.protobuf.Empty) returns (google.protobuf.Empty);
rpc SetIsAutomaticUpdateOn(google.protobuf.BoolValue) returns (google.protobuf.Empty);
rpc IsAutomaticUpdateOn(google.protobuf.Empty) returns (google.protobuf.BoolValue);
// cache
rpc SetIsCacheOnDiskEnabled (google.protobuf.BoolValue) returns (google.protobuf.Empty);
rpc IsCacheOnDiskEnabled (google.protobuf.Empty) returns (google.protobuf.BoolValue);
rpc SetDiskCachePath (google.protobuf.StringValue) returns (google.protobuf.Empty);
rpc DiskCachePath(google.protobuf.Empty) returns (google.protobuf.StringValue);
rpc ChangeLocalCache(ChangeLocalCacheRequest) returns (google.protobuf.Empty);
// mail
rpc SetIsDoHEnabled(google.protobuf.BoolValue) returns (google.protobuf.Empty);
rpc IsDoHEnabled(google.protobuf.Empty) returns (google.protobuf.BoolValue);
rpc SetUseSslForSmtp(google.protobuf.BoolValue) returns (google.protobuf.Empty);
rpc UseSslForSmtp(google.protobuf.Empty) returns (google.protobuf.BoolValue);
rpc Hostname(google.protobuf.Empty) returns (google.protobuf.StringValue);
rpc SetImapPort(google.protobuf.Int32Value) returns (google.protobuf.Empty);
rpc ImapPort(google.protobuf.Empty) returns (google.protobuf.Int32Value);
rpc SetSmtpPort(google.protobuf.Int32Value) returns (google.protobuf.Empty);
rpc SmtpPort(google.protobuf.Empty) returns (google.protobuf.Int32Value);
rpc ChangePorts(ChangePortsRequest) returns (google.protobuf.Empty);
rpc IsPortFree(google.protobuf.Int32Value) returns (google.protobuf.BoolValue);
// keychain
rpc AvailableKeychains(google.protobuf.Empty) returns (AvailableKeychainsResponse);
rpc SetCurrentKeychain(google.protobuf.StringValue) returns (google.protobuf.Empty);
rpc CurrentKeychain(google.protobuf.Empty) returns (google.protobuf.StringValue);
// User & user list
rpc GetUserList(google.protobuf.Empty) returns (UserListResponse);
rpc GetUser(google.protobuf.Empty) returns (User);
rpc SetUserSplitMode(UserSplitModeRequest) returns (google.protobuf.Empty);
rpc LogoutUser(google.protobuf.StringValue) returns (google.protobuf.Empty);
rpc RemoveUser(google.protobuf.StringValue) returns (google.protobuf.Empty);
rpc ConfigureUserAppleMail(ConfigureAppleMailRequest) returns (google.protobuf.Empty);
// Server -> Client event stream
rpc GetEvents(google.protobuf.Empty) returns (stream StreamEvent);
}
//**********************************************************************************************************************
// RPC calls requests and replies messages
//**********************************************************************************************************************
//**********************************************************
// GUI related messages
//**********************************************************
message PointResponse {
int32 x = 1;
int32 y = 2;
};
message ReportBugRequest {
string description = 1;
string address = 2;
string emailClient = 3;
bool includeLogs = 4;
}
// login related messages
message LoginRequest {
string username = 1;
string password = 2;
}
message LoginAbortRequest {
string username = 1;
}
//**********************************************************
// Cache on disk related messages
//**********************************************************
message ChangeLocalCacheRequest {
bool enableDiskCache = 1;
string diskCachePath = 2;
}
//**********************************************************
// Cache on disk related messages
//**********************************************************
message ChangePortsRequest {
int32 imapPort = 1;
int32 smtpPort = 2;
}
//**********************************************************
// Cache on disk related messages
//**********************************************************
message AvailableKeychainsResponse {
repeated string keychains = 1;
}
//**********************************************************
// Cache on disk related messages
//**********************************************************
message User {
string id = 1;
string username = 2;
string avatarText = 3;
bool loggedIn = 4;
bool splitMode = 5;
bool setupGuideSeen = 6;
int64 usedBytes = 7;
int64 totalBytes = 8;
string password = 9;
repeated string addresses = 10;
}
message UserSplitModeRequest {
string userID = 1;
bool active = 2;
}
message UserListResponse {
repeated User users = 1;
}
message ConfigureAppleMailRequest {
string userID = 1;
string address = 2;
}
//**********************************************************************************************************************
// Event stream messages
//**********************************************************************************************************************
message StreamEvent {
oneof event {
AppEvent app = 1;
LoginEvent login = 2;
UpdateEvent update = 3;
CacheEvent cache = 4;
MailSettingsEvent mailSettings = 5;
KeychainEvent keychain = 6;
MailEvent mail = 7;
UserEvent user = 8;
}
}
//**********************************************************
// App related events
//**********************************************************
message AppEvent {
oneof event {
InternetStatusEvent internetStatus = 1;
AutostartFinishedEvent autostartFinished = 2;
ResetFinishedEvent resetFinished = 3;
ReportBugFinishedEvent reportBugFinished = 4;
ReportBugSuccessEvent reportBugSuccess = 5;
ReportBugErrorEvent reportBugError = 6;
ShowMainWindowEvent showMainWindow = 7;
}
}
message InternetStatusEvent {
bool connected = 1;
}
message AutostartFinishedEvent {}
message ResetFinishedEvent {}
message ReportBugFinishedEvent {}
message ReportBugSuccessEvent {}
message ReportBugErrorEvent {}
message ShowMainWindowEvent {}
//**********************************************************
// Login related events
//**********************************************************
message LoginEvent {
oneof event {
LoginErrorEvent error = 1;
LoginTfaRequestedEvent tfaRequested = 2;
LoginTwoPasswordsRequestedEvent twoPasswordRequested = 3;
LoginFinishedEvent finished = 4;
}
}
enum LoginErrorType {
USERNAME_PASSWORD_ERROR = 0;
FREE_USER = 1;
CONNECTION_ERROR = 2;
TFA_ERROR = 3;
TFA_ABORT = 4;
TWO_PASSWORDS_ERROR = 5;
TWO_PASSWORDS_ABORT = 6;
}
message LoginErrorEvent {
LoginErrorType type = 1;
string message = 2;
}
message LoginTfaRequestedEvent {
string username = 1;
}
message LoginTwoPasswordsRequestedEvent {}
message LoginFinishedEvent {
bool wasAlreadyLoggedIn = 1;
}
//**********************************************************
// Update related events
//**********************************************************
message UpdateEvent {
oneof event {
UpdateErrorEvent error = 1;
UpdateManualReadyEvent manualReady = 2;
UpdateManualRestartNeededEvent manualRestartNeeded = 3;
UpdateForceEvent force = 4;
UpdateSilentRestartNeeded silentRestartNeeded = 5;
UpdateIsLatestVersion isLatestVersion = 6;
UpdateCheckFinished checkFinished = 7;
}
}
enum UpdateErrorType {
UPDATE_MANUAL_ERROR = 0;
UPDATE_FORCE_ERROR = 1;
UPDATE_SILENT_ERROR = 2;
}
message UpdateErrorEvent {
UpdateErrorType type = 1;
}
message UpdateManualReadyEvent {
string version = 1;
}
message UpdateManualRestartNeededEvent {};
message UpdateForceEvent {
string version = 1;
}
message UpdateSilentRestartNeeded {}
message UpdateIsLatestVersion {}
message UpdateCheckFinished {}
//**********************************************************
// Cache on disk related events
//**********************************************************
message CacheEvent {
oneof event {
CacheErrorEvent error = 1;
CacheLocationChangeSuccessEvent locationChangedSuccess = 2;
ChangeLocalCacheFinishedEvent changeLocalCacheFinished = 3;
}
}
enum CacheErrorType {
CACHE_UNAVAILABLE_ERROR = 0;
CACHE_CANT_MOVE_ERROR = 1;
DISK_FULL = 2;
};
message CacheErrorEvent {
CacheErrorType type = 1;
}
message CacheLocationChangeSuccessEvent {};
message ChangeLocalCacheFinishedEvent {};
//**********************************************************
// Mail settings related events
//**********************************************************
message MailSettingsEvent {
oneof event {
MailSettingsErrorEvent error = 1;
UseSslForSmtpFinishedEvent useSslForSmtpFinished = 2;
ChangePortsFinishedEvent changePortsFinished = 3;
}
}
enum MailSettingsErrorType {
IMAP_PORT_ISSUE = 0;
SMTP_PORT_ISSUE = 1;
}
message MailSettingsErrorEvent {
MailSettingsErrorType type = 1;
}
message UseSslForSmtpFinishedEvent {}
message ChangePortsFinishedEvent {}
//**********************************************************
// keychain related events
//**********************************************************
message KeychainEvent {
oneof event {
ChangeKeychainFinishedEvent changeKeychainFinished = 1;
HasNoKeychainEvent hasNoKeychain = 2;
RebuildKeychainEvent rebuildKeychain = 3;
}
}
message ChangeKeychainFinishedEvent {}
message HasNoKeychainEvent {}
message RebuildKeychainEvent {}
//**********************************************************
// Mail related events
//**********************************************************
message MailEvent {
oneof event {
NoActiveKeyForRecipientEvent noActiveKeyForRecipientEvent = 1;
AddressChangedEvent addressChanged = 2;
AddressChangedLogoutEvent addressChangedLogout = 3;
ApiCertIssueEvent apiCertIssue = 6;
}
}
message NoActiveKeyForRecipientEvent {
string email = 1;
}
message AddressChangedEvent {
string address = 1; // TODO: user event ?
}
message AddressChangedLogoutEvent {
string address = 1; // TODO: user event ?
}
message ApiCertIssueEvent {}
//**********************************************************
// User list related event
//**********************************************************
message UserEvent {
oneof event {
ToggleSplitModeFinishedEvent toggleSplitModeFinished= 1;
UserDisconnectedEvent userDisconnected = 2;
UserChangedEvent userChanged = 3;
}
}
message ToggleSplitModeFinishedEvent {
string userID = 1;
}
message UserDisconnectedEvent {
string username = 1; // TODO: isn't it userID ?
}
message UserChangedEvent {
User user = 1;
}

File diff suppressed because it is too large Load Diff

121
internal/rpc/server.go Normal file
View File

@ -0,0 +1,121 @@
// Copyright (c) 2022 Proton AG
//
// This file is part of Proton Mail Bridge.Bridge.
//
// Proton Mail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Proton Mail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rpc
import (
"crypto/tls"
"net"
"github.com/sirupsen/logrus"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
)
//go:generate protoc --go_out=. --go_opt=paths=source_relative --go-grpc_out=. --go-grpc_opt=paths=source_relative bridge_rpc.proto
//goland:noinspection SpellCheckingInspection
const (
serverCert = `-----BEGIN CERTIFICATE-----
MIIC5TCCAc2gAwIBAgIJAJL2PajH8kFjMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
BAMMCWxvY2FsaG9zdDAeFw0yMjA1MTAwNjEzMzdaFw0yMjA2MDkwNjEzMzdaMBQx
EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAKyb48XL+08YI8m4X/eeD9TQshV+vybKbU7MOG7BnH3Hv7kUH0aVP7OPnU51
eYRgUu+bkJ8qWhxD7wOLVJBcU5T1lgd+k6St83ix25P02nUc3UeU4MCxMwhjMjYu
R5F9bfSG0UlCCGAEjjmGh+CfnZkS+rgCwE/xGswFnVrynTMvrLQyN02dz/r4zJPp
yyVhTOmjdsUDs0zGDbubLf+ypR8VCXg55qYMw7Abpe+rx3BF+NCEjKlATjMeIZNx
iS0dl0OGjJZ+bfHGhnPiQxP8HxyJ0NjFNtWgblQev2sHmIq65Rry3RP1gbDAW3sk
MiIfjbnp4gGspYrmHWeWXH8g6WMCAwEAAaM6MDgwFAYDVR0RBA0wC4IJbG9jYWxo
b3N0MAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0B
AQsFAAOCAQEAO2WDYnzy9SkaS9VU2jw3nd9MEaILZsXFcVU2+52TKwRBty7b0A1x
zyxT6nT0pN0Im7DcT5/TvwFuVBJUTFs4c2gW09WUvtfuN8HVFOeX/1Pt10lMPJjR
I+wTAUQrXJHt57JE9x13gQEOW/mGUDNuoUH2cE9C1f+TrO0LaRj8dubS/gHMuV1i
aTyxu7hgbLAYq0NGD86CSOwvUvTvs6o628xvfmqqdzlpWIlQq18t2GZYFVWjrISY
LWw3OCormKSASOPrW1FXhrgwoyDXHNmZT1MHL3Rh9U5qyCwV5kDAcY956sc9lD3G
XHtSxOHLE1eDKGCUKRcYop/99inTGjJ6Xg==
-----END CERTIFICATE-----`
serverKey = `-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQCsm+PFy/tPGCPJ
uF/3ng/U0LIVfr8mym1OzDhuwZx9x7+5FB9GlT+zj51OdXmEYFLvm5CfKlocQ+8D
i1SQXFOU9ZYHfpOkrfN4sduT9Np1HN1HlODAsTMIYzI2LkeRfW30htFJQghgBI45
hofgn52ZEvq4AsBP8RrMBZ1a8p0zL6y0MjdNnc/6+MyT6cslYUzpo3bFA7NMxg27
my3/sqUfFQl4OeamDMOwG6Xvq8dwRfjQhIypQE4zHiGTcYktHZdDhoyWfm3xxoZz
4kMT/B8cidDYxTbVoG5UHr9rB5iKuuUa8t0T9YGwwFt7JDIiH4256eIBrKWK5h1n
llx/IOljAgMBAAECggEBAIgsaBKo7XelzL4cpiFc4pJ7nrMUjktVEc1DkhXWytX0
W03xEQeHQX0whOLcDOUhdOyxZvQa3oJEGfFK34kQPaRb52O8OVCHJ3iFoHxmhF42
SmBplLKQWXl5gKh79FxUfwWVwtCvtpnBnk7F0rakVhnofkHjccLfrMtedpjEpL42
xuzcoMnGrDLtCsfyDZTpTA0+xQhYb3qlkX4V1gVS/Sp3zLotUqE9THjCbTVcl0Ux
UKqMaMcqYX+GVBoPE5B2aelmvIKgvUYy1RNVsVdi5mvmO4fdm14/7vgxrWO3gV0Z
RWLnJQ5ISktx/9YCRro3UTu5eR7JO3CKAYTAzQpdDSkCgYEA4SGa/WTBPImMJKnV
aM9pK74Z4yZ3FEv3Le1BE63rduETVOXs8QhWsDt7upu2del6Pb8UI1kkgK2EshXW
l61pzQmsAvUSUO7AW4KPRgwjDy4kRLAozq3kMbmdrSc7cfxXHiktUyZ8Rmt1VjsP
d+/OzB2ZG4DdmGR8Kk8tzCHTjMcCgYEAxEavBi+Mw+EUz3X+8nSDyGO57iJvr63N
poubJfRPrV20lkY1OoGm+c1jXohAI+afGZNJvp84eQwYCyZEczEncmPMYI6nyuJL
i3fyoG9YTFa6edpdLowA9J14x6agh1y1q5ADrbL2L6Gf3to9q+E2RjKlJvlfYd5w
URaQoZ5/CoUCgYBoV/IE9bjWPQ4WRBzkahVdr8tBy6cvYhIbWDZsT5St0Z3rIHIU
OQAsyDUNhXQo7GC606AazgssFMBG5fZC8J3z6UKvUDUAC9hd0YJkPeXV+FXY/Ci9
ujzkixo4kdFsgD9EfGNEgbbh0JZetBr0RNJ9Kk63P5/1LMWbun0IerkZKwKBgQC1
DA4+QnYx6NjtVQZKVzeIDJVhF9q1zjg4O+Zs6CLm49zEERbgVN/U5KOYe03Oz9hK
GxaXAv9wiLtU7YOOTfT5Cx1mo7Aa8QqGJ6piWtKz9/wikk4JtZLcELVsVEMXGWlq
S3lZLA7yeL+jLOReO2t47RZyEOzuteQcqBfZPP4qkQKBgQDHkUXgMbqchcXeM6Nf
LALiNkbf+4BeaWI+h3HteVjFkKRrRCMihDHcBg/nWF0SI/AoVoy+ybxYv7dME7z5
kPas6sPvVg81i96xesKTry7lefM+3H6hSqrKBYZdu7XXItBYvHctuGLSin2gV+WU
vwTpDMetrvhD7qmlwspJPwHaOw==
-----END PRIVATE KEY-----`
)
// Server is the RPC server struct.
type Server struct {
grpcServer *grpc.Server
listener net.Listener
log *logrus.Entry
}
// NewServer returns a new RPC server.
func NewServer() *Server {
log := logrus.WithField("pkg", "rpc")
cert, err := tls.X509KeyPair([]byte(serverCert), []byte(serverKey))
if err != nil {
log.WithError(err).Error("could not create key pair")
panic(err)
}
grpcServer := grpc.NewServer(grpc.Creds(credentials.NewTLS(&tls.Config{
Certificates: []tls.Certificate{cert},
MinVersion: tls.VersionTLS13,
})))
RegisterBridgeRpcServer(grpcServer, NewService(grpcServer, log))
listener, err := net.Listen("tcp", "127.0.0.1:9292") // Port should be configurable from the command-line.
if err != nil {
log.WithError(err).Error("could not create listener")
panic(err)
}
return &Server{grpcServer: grpcServer, listener: listener, log: log}
}
// ListenAndServe provides the RPC service.
func (s *Server) ListenAndServe() {
err := s.grpcServer.Serve(s.listener)
if err != nil {
s.log.WithError(err).Error("error serving RPC")
}
}

690
internal/rpc/service.go Normal file
View File

@ -0,0 +1,690 @@
// Copyright (c) 2022 Proton AG
//
// This file is part of Proton Mail Bridge.Bridge.
//
// Proton Mail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Proton Mail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
package rpc
import (
"context"
"github.com/google/uuid"
"github.com/sirupsen/logrus"
"google.golang.org/grpc"
"google.golang.org/protobuf/types/known/emptypb"
"google.golang.org/protobuf/types/known/wrapperspb"
)
// Service is the RPC service struct.
type Service struct {
UnimplementedBridgeRpcServer
grpcServer *grpc.Server
log *logrus.Entry
showOnStartup bool
showSplashScreen bool
dockIconVisible bool
isFirstGuiStart bool
isAutostartOn bool
isBetaEnabled bool
colorSchemeName string
currentEmailClient string
isAutoUpdateOn bool
isCacheOnDiskEnabled bool
diskCachePath string
isDohEnabled bool
useSSLForSMTP bool
hostname string
imapPort uint16
smtpPort uint16
keychains []string
currentKeychain string
users []*User
currentUser string
}
// NewService returns a new instance of the service.
func NewService(grpcServer *grpc.Server, log *logrus.Entry) *Service {
service := Service{
grpcServer: grpcServer,
log: log,
colorSchemeName: "aName",
currentEmailClient: "aClient",
hostname: "dummy.proton.me",
imapPort: 143,
smtpPort: 25,
keychains: []string{uuid.New().String(), uuid.New().String(), uuid.New().String()},
users: []*User{{
Id: uuid.New().String(),
Username: "user1",
AvatarText: "avatarText1",
LoggedIn: true,
SplitMode: false,
SetupGuideSeen: true,
UsedBytes: 5000000000,
TotalBytes: 1000000000,
Password: "dummyPassword",
Addresses: []string{"dummy@proton.me"},
}, {
Id: uuid.New().String(),
Username: "user2",
AvatarText: "avatarText2",
LoggedIn: false,
SplitMode: true,
SetupGuideSeen: false,
UsedBytes: 4000000000,
TotalBytes: 2000000000,
Password: "dummyPassword2",
Addresses: []string{"dummy2@proton.me"},
}},
}
service.currentKeychain = service.keychains[0]
service.currentUser = service.users[0].Id
return &service
}
func (s *Service) GetCursorPos(context.Context, *emptypb.Empty) (*PointResponse, error) {
s.log.Info("GetCursorPos")
return &PointResponse{X: 100, Y: 200}, nil
}
func (s *Service) GuiReady(context.Context, *emptypb.Empty) (*emptypb.Empty, error) {
s.log.Info("GuiReady")
return &emptypb.Empty{}, nil
}
func (s *Service) Quit(context.Context, *emptypb.Empty) (*emptypb.Empty, error) {
s.log.Info("Quit")
return &emptypb.Empty{}, nil
}
func (s *Service) Restart(context.Context, *emptypb.Empty) (*emptypb.Empty, error) {
s.log.Info("Restart")
return &emptypb.Empty{}, nil
}
func (s *Service) SetShowOnStartup(_ context.Context, show *wrapperspb.BoolValue) (*emptypb.Empty, error) {
s.log.WithField("show", show.Value).Info("SetShowOnStartup")
s.showOnStartup = show.Value
return &emptypb.Empty{}, nil
}
func (s *Service) ShowOnStartup(context.Context, *emptypb.Empty) (*wrapperspb.BoolValue, error) {
s.log.Info("ShowOnStartup")
return wrapperspb.Bool(s.showOnStartup), nil
}
func (s *Service) SetShowSplashScreen(_ context.Context, show *wrapperspb.BoolValue) (*emptypb.Empty, error) {
s.log.WithField("show", show.Value).Info("SetShowSplashScreen")
s.showSplashScreen = show.Value
return &emptypb.Empty{}, nil
}
func (s *Service) ShowSplashScreen(context.Context, *emptypb.Empty) (*wrapperspb.BoolValue, error) {
s.log.Info("ShowSplashScreen")
return wrapperspb.Bool(s.showSplashScreen), nil
}
func (s *Service) SetDockIconVisible(_ context.Context, visible *wrapperspb.BoolValue) (*emptypb.Empty, error) {
s.log.WithField("show", visible.Value).Info("SetDockIconVisible")
s.dockIconVisible = visible.Value
return &emptypb.Empty{}, nil
}
func (s *Service) DockIconVisible(context.Context, *emptypb.Empty) (*wrapperspb.BoolValue, error) {
s.log.Info("DockIconVisible")
return wrapperspb.Bool(s.dockIconVisible), nil
}
func (s *Service) SetIsFirstGuiStart(_ context.Context, isFirst *wrapperspb.BoolValue) (*emptypb.Empty, error) {
s.log.WithField("show", isFirst.Value).Info("SetIsFirstGuiStart")
s.isFirstGuiStart = isFirst.Value
return &emptypb.Empty{}, nil
}
func (s *Service) IsFirstGuiStart(context.Context, *emptypb.Empty) (*wrapperspb.BoolValue, error) {
s.log.Info("IsFirstGuiStart")
return wrapperspb.Bool(s.isFirstGuiStart), nil
}
func (s *Service) SetIsAutostartOn(_ context.Context, isOn *wrapperspb.BoolValue) (*emptypb.Empty, error) {
s.log.WithField("show", isOn.Value).Info("SetIsAutostartOn")
s.isAutostartOn = isOn.Value
return &emptypb.Empty{}, nil
}
func (s *Service) IsAutostartOn(context.Context, *emptypb.Empty) (*wrapperspb.BoolValue, error) {
s.log.Info("IsAutostartOn")
return wrapperspb.Bool(s.isAutostartOn), nil
}
func (s *Service) SetIsBetaEnabled(_ context.Context, isEnabled *wrapperspb.BoolValue) (*emptypb.Empty, error) {
s.log.WithField("show", isEnabled.Value).Info("SetIsBetaEnabled")
s.isBetaEnabled = isEnabled.Value
return &emptypb.Empty{}, nil
}
func (s *Service) IsBetaEnabled(context.Context, *emptypb.Empty) (*wrapperspb.BoolValue, error) {
s.log.Info("IsBetaEnabled")
return wrapperspb.Bool(s.isBetaEnabled), nil
}
func (s *Service) GoOs(context.Context, *emptypb.Empty) (*wrapperspb.StringValue, error) {
s.log.Info("GoOs")
return wrapperspb.String("DummyOsName"), nil
}
func (s *Service) TriggerReset(context.Context, *emptypb.Empty) (*emptypb.Empty, error) {
s.log.Info("TriggerReset")
return &emptypb.Empty{}, nil
}
func (s *Service) Version(context.Context, *emptypb.Empty) (*wrapperspb.StringValue, error) {
s.log.Info("Version")
return wrapperspb.String("1.0"), nil
}
func (s *Service) LogPath(context.Context, *emptypb.Empty) (*wrapperspb.StringValue, error) {
s.log.Info("LogPath")
return wrapperspb.String("/path/to/log"), nil
}
func (s *Service) LicensePath(context.Context, *emptypb.Empty) (*wrapperspb.StringValue, error) {
s.log.Info("LicensePath")
return wrapperspb.String("/path/to/license"), nil
}
func (s *Service) ReleaseNotesLink(context.Context, *emptypb.Empty) (*wrapperspb.StringValue, error) {
s.log.Info("ReleaseNotesLink")
return wrapperspb.String("https//proton.me/release/notes.html"), nil
}
func (s *Service) LandingPageLink(context.Context, *emptypb.Empty) (*wrapperspb.StringValue, error) {
s.log.Info("LandingPageLink")
return wrapperspb.String("https//proton.me"), nil
}
func (s *Service) SetColorSchemeName(_ context.Context, name *wrapperspb.StringValue) (*emptypb.Empty, error) {
s.log.WithField("ColorSchemeName", name.Value).Info("SetColorSchemeName")
s.colorSchemeName = name.Value
return &emptypb.Empty{}, nil
}
func (s *Service) ColorSchemeName(context.Context, *emptypb.Empty) (*wrapperspb.StringValue, error) {
s.log.Info("ColorSchemeName")
return wrapperspb.String(s.colorSchemeName), nil
}
func (s *Service) SetCurrentEmailClient(_ context.Context, client *wrapperspb.StringValue) (*emptypb.Empty, error) {
s.log.WithField("CurrentEmailClient", client.Value).Info("SetCurrentEmailClient")
s.currentEmailClient = client.Value
return &emptypb.Empty{}, nil
}
func (s *Service) CurrentEmailClient(context.Context, *emptypb.Empty) (*wrapperspb.StringValue, error) {
s.log.Info("CurrentEmailClient")
return wrapperspb.String(s.currentEmailClient), nil
}
func (s *Service) ReportBug(_ context.Context, report *ReportBugRequest) (*emptypb.Empty, error) {
s.log.WithField("description", report.Description).
WithField("address", report.Address).
WithField("emailClient", report.EmailClient).
WithField("includeLogs", report.IncludeLogs).
Info("ReportBug")
return &emptypb.Empty{}, nil
}
func (s *Service) Login(_ context.Context, login *LoginRequest) (*emptypb.Empty, error) {
s.log.
WithField("username", login.Username).
Info("Login")
return &emptypb.Empty{}, nil
}
func (s *Service) Login2FA(_ context.Context, login *LoginRequest) (*emptypb.Empty, error) {
s.log.
WithField("username", login.Username).
Info("Login2FA")
return &emptypb.Empty{}, nil
}
func (s *Service) Login2Passwords(_ context.Context, login *LoginRequest) (*emptypb.Empty, error) {
s.log.
WithField("username", login.Username).
Info("Login2Passwords")
return &emptypb.Empty{}, nil
}
func (s *Service) LoginAbort(_ context.Context, loginAbort *LoginAbortRequest) (*emptypb.Empty, error) {
s.log.
WithField("username", loginAbort.Username).
Info("LoginAbort")
return &emptypb.Empty{}, nil
}
func (s *Service) CheckUpdate(context.Context, *emptypb.Empty) (*emptypb.Empty, error) {
s.log.Info("CheckUpdate")
return &emptypb.Empty{}, nil
}
func (s *Service) InstallUpdate(context.Context, *emptypb.Empty) (*emptypb.Empty, error) {
s.log.Info("InstallUpdate")
return &emptypb.Empty{}, nil
}
func (s *Service) SetIsAutomaticUpdateOn(_ context.Context, isOn *wrapperspb.BoolValue) (*emptypb.Empty, error) {
s.log.WithField("isOn", isOn.Value).Info("SetIsAutomaticUpdateOn")
s.isAutoUpdateOn = isOn.Value
return &emptypb.Empty{}, nil
}
func (s *Service) IsAutomaticUpdateOn(context.Context, *emptypb.Empty) (*wrapperspb.BoolValue, error) {
s.log.Info("IsAutomaticUpdateOn")
return wrapperspb.Bool(s.isAutoUpdateOn), nil
}
func (s *Service) SetIsCacheOnDiskEnabled(_ context.Context, isEnabled *wrapperspb.BoolValue) (*emptypb.Empty, error) {
s.log.WithField("isOn", isEnabled.Value).Info("SetIsCacheOnDiskEnabled")
s.isCacheOnDiskEnabled = isEnabled.Value
return &emptypb.Empty{}, nil
}
func (s *Service) IsCacheOnDiskEnabled(context.Context, *emptypb.Empty) (*wrapperspb.BoolValue, error) {
s.log.Info("IsCacheOnDiskEnabled")
return wrapperspb.Bool(s.isCacheOnDiskEnabled), nil
}
func (s *Service) SetDiskCachePath(_ context.Context, path *wrapperspb.StringValue) (*emptypb.Empty, error) {
s.log.WithField("path", path.Value).Info("IsCacheOnDiskEnabled")
s.diskCachePath = path.Value
return &emptypb.Empty{}, nil
}
func (s *Service) DiskCachePath(context.Context, *emptypb.Empty) (*wrapperspb.StringValue, error) {
s.log.Info("DiskCachePath")
return wrapperspb.String(s.diskCachePath), nil
}
func (s *Service) ChangeLocalCache(_ context.Context, change *ChangeLocalCacheRequest) (*emptypb.Empty, error) {
s.log.
WithField("enableDiskCache", change.EnableDiskCache).
WithField("diskCachePath", change.DiskCachePath).
Info("DiskCachePath")
s.isCacheOnDiskEnabled = change.EnableDiskCache
s.diskCachePath = change.DiskCachePath
return &emptypb.Empty{}, nil
}
func (s *Service) SetIsDoHEnabled(_ context.Context, isEnabled *wrapperspb.BoolValue) (*emptypb.Empty, error) {
s.log.WithField("isEnabled", isEnabled.Value).Info("SetIsDohEnabled")
s.isDohEnabled = isEnabled.Value
return &emptypb.Empty{}, nil
}
func (s *Service) IsDoHEnabled(context.Context, *emptypb.Empty) (*wrapperspb.BoolValue, error) {
s.log.Info("IsDohEnabled")
return wrapperspb.Bool(s.isDohEnabled), nil
}
func (s *Service) SetUseSslForSmtp(_ context.Context, useSsl *wrapperspb.BoolValue) (*emptypb.Empty, error) { //nolint:revive,stylecheck
s.log.WithField("useSsl", useSsl.Value).Info("SetUseSslForSmtp")
s.useSSLForSMTP = useSsl.Value
return &emptypb.Empty{}, nil
}
func (s *Service) UseSslForSmtp(context.Context, *emptypb.Empty) (*wrapperspb.BoolValue, error) { //nolint:revive,stylecheck
s.log.Info("UseSslForSmtp")
return wrapperspb.Bool(s.useSSLForSMTP), nil
}
func (s *Service) Hostname(context.Context, *emptypb.Empty) (*wrapperspb.StringValue, error) {
s.log.Info("Hostname")
return wrapperspb.String(s.hostname), nil
}
func (s *Service) SetImapPort(_ context.Context, port *wrapperspb.Int32Value) (*emptypb.Empty, error) {
s.log.WithField("port", port.Value).Info("SetImapPort")
s.imapPort = uint16(port.Value)
return &emptypb.Empty{}, nil
}
func (s *Service) ImapPort(context.Context, *emptypb.Empty) (*wrapperspb.Int32Value, error) {
s.log.Info("ImapPort")
return wrapperspb.Int32(int32(s.imapPort)), nil
}
func (s *Service) SetSmtpPort(_ context.Context, port *wrapperspb.Int32Value) (*emptypb.Empty, error) { //nolint:revive,stylecheck
s.log.WithField("port", port.Value).Info("SetSmtpPort")
s.smtpPort = uint16(port.Value)
return &emptypb.Empty{}, nil
}
func (s *Service) SmtpPort(context.Context, *emptypb.Empty) (*wrapperspb.Int32Value, error) { //nolint:revive,stylecheck
s.log.Info("SmtpPort")
return wrapperspb.Int32(int32(s.smtpPort)), nil
}
func (s *Service) ChangePorts(_ context.Context, ports *ChangePortsRequest) (*emptypb.Empty, error) {
s.log.WithField("imapPort", ports.ImapPort).WithField("smtpPort", ports.SmtpPort).Info("ChangePorts")
s.imapPort = uint16(ports.ImapPort)
s.smtpPort = uint16(ports.SmtpPort)
return &emptypb.Empty{}, nil
}
func (s *Service) IsPortFree(context.Context, *wrapperspb.Int32Value) (*wrapperspb.BoolValue, error) {
s.log.Info("IsPortFree")
return wrapperspb.Bool(true), nil
}
func (s *Service) AvailableKeychains(context.Context, *emptypb.Empty) (*AvailableKeychainsResponse, error) {
s.log.Info("AvailableKeychains")
return &AvailableKeychainsResponse{Keychains: s.keychains}, nil
}
func (s *Service) SetCurrentKeychain(_ context.Context, keychain *wrapperspb.StringValue) (*emptypb.Empty, error) {
s.log.WithField("keychain", keychain.Value).Info("SetCurrentKeyChain") // we do not check validity.
s.currentKeychain = keychain.Value
return &emptypb.Empty{}, nil
}
func (s *Service) CurrentKeychain(context.Context, *emptypb.Empty) (*wrapperspb.StringValue, error) {
s.log.Info("CurrentKeychain")
return wrapperspb.String(s.currentKeychain), nil
}
func (s *Service) GetUserList(context.Context, *emptypb.Empty) (*UserListResponse, error) {
s.log.Info("GetUserList")
return &UserListResponse{Users: s.users}, nil
}
func (s *Service) GetUser(context.Context, *emptypb.Empty) (*User, error) {
s.log.Info("GetUser")
return s.getCurrentUser(), nil
}
func (s *Service) SetUserSplitMode(_ context.Context, splitMode *UserSplitModeRequest) (*emptypb.Empty, error) {
s.log.WithField("UserID", splitMode.UserID).WithField("Active", splitMode.Active).Info("SetUserSplitMode")
user := s.findUser(splitMode.UserID) // we should return an error
if user != nil {
user.SplitMode = splitMode.Active
}
return &emptypb.Empty{}, nil
}
func (s *Service) LogoutUser(_ context.Context, userID *wrapperspb.StringValue) (*emptypb.Empty, error) {
s.log.WithField("UserID", userID.Value).Info("LogoutUser")
user := s.findUser(userID.Value)
if user != nil {
user.LoggedIn = false
}
return &emptypb.Empty{}, nil
}
func (s *Service) RemoveUser(_ context.Context, userID *wrapperspb.StringValue) (*emptypb.Empty, error) {
s.log.WithField("UserID", userID.Value).Info("RemoveUser")
// we actually do nothing
return &emptypb.Empty{}, nil
}
func (s *Service) ConfigureUserAppleMail(_ context.Context, request *ConfigureAppleMailRequest) (*emptypb.Empty, error) {
s.log.WithField("UserID", request.UserID).WithField("Address", request.Address).Info("ConfigureUserAppleMail")
return &emptypb.Empty{}, nil
}
func (s *Service) GetEvents(_ *emptypb.Empty, server BridgeRpc_GetEventsServer) error { // nolint:funlen
s.log.Info("Starting Event stream")
events := []func() *StreamEvent{
// app
internetStatusEvent,
autostartFinishedEvent,
resetFinishedEvent,
reportBugFinishedEvent,
reportBugSuccessEvent,
reportBugErrorEvent,
showMainWindowEvent,
// login
loginError,
loginTfaRequestedEvent,
loginTwoPasswordsRequestedEvent,
loginFinishedEvent,
// update
updateErrorEvent,
updateManualReadyEvent,
updateManualRestartNeededEvent,
updateForceEvent,
updateSilentRestartNeededEvent,
updateIsLatestVersionEvent,
updateCheckFinishedEvent,
// cache
cacheErrorEvent,
cacheLocationChangeSuccessEvent,
cacheChangeLocalCacheFinishedEvent,
// mail settings
mailSettingsErrorEvent,
mailSettingsUseSslForSmtpFinishedEvent,
mailSettingsChangePortFinishedEvent,
// keychain
keychainChangeKeychainFinishedEvent,
keychainHasNoKeychainEvent,
keychainRebuildKeychainEvent,
// mail
mailNoActiveKeyForRecipientEvent,
mailAddressChangeEvent,
mailAddressChangeLogoutEvent,
mailApiCertIssue,
// user
userToggleSplitModeFinishedEvent,
userDisconnectedEvent,
userChangedEvent,
}
for _, eventFunc := range events {
event := eventFunc()
s.log.WithField("event", event).Info("Sending event")
if err := server.Send(eventFunc()); err != nil {
return err
}
}
s.log.Info("Stop Event stream")
return nil
}
func (s *Service) getCurrentUser() *User {
return s.findUser(s.currentUser)
}
func (s *Service) findUser(userID string) *User {
for _, u := range s.users {
if u.Id == userID {
return u
}
}
return nil
}
func appEvent(appEvent *AppEvent) *StreamEvent {
return &StreamEvent{Event: &StreamEvent_App{App: appEvent}}
}
func internetStatusEvent() *StreamEvent {
return appEvent(&AppEvent{Event: &AppEvent_InternetStatus{InternetStatus: &InternetStatusEvent{Connected: true}}})
}
func autostartFinishedEvent() *StreamEvent {
return appEvent(&AppEvent{Event: &AppEvent_AutostartFinished{AutostartFinished: &AutostartFinishedEvent{}}})
}
func resetFinishedEvent() *StreamEvent {
return appEvent(&AppEvent{Event: &AppEvent_ResetFinished{ResetFinished: &ResetFinishedEvent{}}})
}
func reportBugFinishedEvent() *StreamEvent {
return appEvent(&AppEvent{Event: &AppEvent_ReportBugFinished{ReportBugFinished: &ReportBugFinishedEvent{}}})
}
func reportBugSuccessEvent() *StreamEvent {
return appEvent(&AppEvent{Event: &AppEvent_ReportBugSuccess{ReportBugSuccess: &ReportBugSuccessEvent{}}})
}
func reportBugErrorEvent() *StreamEvent {
return appEvent(&AppEvent{Event: &AppEvent_ReportBugError{ReportBugError: &ReportBugErrorEvent{}}})
}
func showMainWindowEvent() *StreamEvent {
return appEvent(&AppEvent{Event: &AppEvent_ShowMainWindow{ShowMainWindow: &ShowMainWindowEvent{}}})
}
func loginEvent(event *LoginEvent) *StreamEvent {
return &StreamEvent{Event: &StreamEvent_Login{Login: event}}
}
func loginError() *StreamEvent {
return loginEvent(&LoginEvent{Event: &LoginEvent_Error{Error: &LoginErrorEvent{Type: LoginErrorType_FREE_USER}}})
}
func loginTfaRequestedEvent() *StreamEvent {
return loginEvent(&LoginEvent{Event: &LoginEvent_TfaRequested{TfaRequested: &LoginTfaRequestedEvent{Username: "dummy@proton.me"}}})
}
func loginTwoPasswordsRequestedEvent() *StreamEvent {
return loginEvent(&LoginEvent{Event: &LoginEvent_TwoPasswordRequested{}})
}
func loginFinishedEvent() *StreamEvent {
return loginEvent(&LoginEvent{Event: &LoginEvent_Finished{Finished: &LoginFinishedEvent{WasAlreadyLoggedIn: true}}})
}
func updateEvent(event *UpdateEvent) *StreamEvent {
return &StreamEvent{Event: &StreamEvent_Update{Update: event}}
}
func updateErrorEvent() *StreamEvent {
return updateEvent(&UpdateEvent{Event: &UpdateEvent_Error{Error: &UpdateErrorEvent{Type: UpdateErrorType_UPDATE_SILENT_ERROR}}})
}
func updateManualReadyEvent() *StreamEvent {
return updateEvent(&UpdateEvent{Event: &UpdateEvent_ManualReady{ManualReady: &UpdateManualReadyEvent{Version: "1.0"}}})
}
func updateManualRestartNeededEvent() *StreamEvent {
return updateEvent(&UpdateEvent{Event: &UpdateEvent_ManualRestartNeeded{ManualRestartNeeded: &UpdateManualRestartNeededEvent{}}})
}
func updateForceEvent() *StreamEvent {
return updateEvent(&UpdateEvent{Event: &UpdateEvent_Force{Force: &UpdateForceEvent{Version: " 2.0"}}})
}
func updateSilentRestartNeededEvent() *StreamEvent {
return updateEvent(&UpdateEvent{Event: &UpdateEvent_SilentRestartNeeded{SilentRestartNeeded: &UpdateSilentRestartNeeded{}}})
}
func updateIsLatestVersionEvent() *StreamEvent {
return updateEvent(&UpdateEvent{Event: &UpdateEvent_IsLatestVersion{IsLatestVersion: &UpdateIsLatestVersion{}}})
}
func updateCheckFinishedEvent() *StreamEvent {
return updateEvent(&UpdateEvent{Event: &UpdateEvent_CheckFinished{CheckFinished: &UpdateCheckFinished{}}})
}
func cacheEvent(event *CacheEvent) *StreamEvent {
return &StreamEvent{Event: &StreamEvent_Cache{Cache: event}}
}
func cacheErrorEvent() *StreamEvent {
return cacheEvent(&CacheEvent{Event: &CacheEvent_Error{Error: &CacheErrorEvent{Type: CacheErrorType_CACHE_UNAVAILABLE_ERROR}}})
}
func cacheLocationChangeSuccessEvent() *StreamEvent {
return cacheEvent(&CacheEvent{Event: &CacheEvent_LocationChangedSuccess{LocationChangedSuccess: &CacheLocationChangeSuccessEvent{}}})
}
func cacheChangeLocalCacheFinishedEvent() *StreamEvent {
return cacheEvent(&CacheEvent{Event: &CacheEvent_ChangeLocalCacheFinished{ChangeLocalCacheFinished: &ChangeLocalCacheFinishedEvent{}}})
}
func mailSettingsEvent(event *MailSettingsEvent) *StreamEvent {
return &StreamEvent{Event: &StreamEvent_MailSettings{MailSettings: event}}
}
func mailSettingsErrorEvent() *StreamEvent {
return mailSettingsEvent(&MailSettingsEvent{Event: &MailSettingsEvent_Error{Error: &MailSettingsErrorEvent{Type: MailSettingsErrorType_IMAP_PORT_ISSUE}}})
}
func mailSettingsUseSslForSmtpFinishedEvent() *StreamEvent { //nolint:revive,stylecheck
return mailSettingsEvent(&MailSettingsEvent{Event: &MailSettingsEvent_UseSslForSmtpFinished{UseSslForSmtpFinished: &UseSslForSmtpFinishedEvent{}}})
}
func mailSettingsChangePortFinishedEvent() *StreamEvent {
return mailSettingsEvent(&MailSettingsEvent{Event: &MailSettingsEvent_ChangePortsFinished{ChangePortsFinished: &ChangePortsFinishedEvent{}}})
}
func keychainEvent(event *KeychainEvent) *StreamEvent {
return &StreamEvent{Event: &StreamEvent_Keychain{Keychain: event}}
}
func keychainChangeKeychainFinishedEvent() *StreamEvent {
return keychainEvent(&KeychainEvent{Event: &KeychainEvent_ChangeKeychainFinished{ChangeKeychainFinished: &ChangeKeychainFinishedEvent{}}})
}
func keychainHasNoKeychainEvent() *StreamEvent {
return keychainEvent(&KeychainEvent{Event: &KeychainEvent_HasNoKeychain{HasNoKeychain: &HasNoKeychainEvent{}}})
}
func keychainRebuildKeychainEvent() *StreamEvent {
return keychainEvent(&KeychainEvent{Event: &KeychainEvent_RebuildKeychain{RebuildKeychain: &RebuildKeychainEvent{}}})
}
func mailEvent(event *MailEvent) *StreamEvent {
return &StreamEvent{Event: &StreamEvent_Mail{Mail: event}}
}
func mailNoActiveKeyForRecipientEvent() *StreamEvent {
return mailEvent(&MailEvent{Event: &MailEvent_NoActiveKeyForRecipientEvent{NoActiveKeyForRecipientEvent: &NoActiveKeyForRecipientEvent{Email: "dummy@proton.me"}}})
}
func mailAddressChangeEvent() *StreamEvent {
return mailEvent(&MailEvent{Event: &MailEvent_AddressChanged{AddressChanged: &AddressChangedEvent{Address: "dummy@proton.me"}}})
}
func mailAddressChangeLogoutEvent() *StreamEvent {
return mailEvent(&MailEvent{Event: &MailEvent_AddressChangedLogout{AddressChangedLogout: &AddressChangedLogoutEvent{Address: "dummy@proton.me"}}})
}
func mailApiCertIssue() *StreamEvent { //nolint:revive,stylecheck
return mailEvent(&MailEvent{Event: &MailEvent_ApiCertIssue{ApiCertIssue: &ApiCertIssueEvent{}}})
}
func userEvent(event *UserEvent) *StreamEvent {
return &StreamEvent{Event: &StreamEvent_User{User: event}}
}
func userToggleSplitModeFinishedEvent() *StreamEvent {
return userEvent(&UserEvent{Event: &UserEvent_ToggleSplitModeFinished{ToggleSplitModeFinished: &ToggleSplitModeFinishedEvent{UserID: "userID"}}})
}
func userDisconnectedEvent() *StreamEvent {
return userEvent(&UserEvent{Event: &UserEvent_UserDisconnected{UserDisconnected: &UserDisconnectedEvent{Username: "dummy@proton.me"}}})
}
func userChangedEvent() *StreamEvent {
return userEvent(&UserEvent{Event: &UserEvent_UserChanged{UserChanged: &UserChangedEvent{User: &User{}}}})
}