From e1dff67c1019630560a10dce6d2ee08fe509d587 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Thu, 16 Mar 2023 11:11:29 +0100 Subject: [PATCH 01/54] fix(GODT-2481): Fix DBUS Secert Service Fix the path we are checking for was not updated for V3. Ensure that we only inspect items that start with the correct prefix. Some implementation (e.g.: KeepassXC) return some values which are not valid. Finally, remove unnecessary attributes. --- pkg/keychain/helper_dbus_linux.go | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/pkg/keychain/helper_dbus_linux.go b/pkg/keychain/helper_dbus_linux.go index b759c7f4..bdd1f53e 100644 --- a/pkg/keychain/helper_dbus_linux.go +++ b/pkg/keychain/helper_dbus_linux.go @@ -20,6 +20,8 @@ package keychain import ( "strings" + "github.com/ProtonMail/proton-bridge/v3/internal/constants" + "github.com/bradenaw/juniper/xslices" "github.com/docker/docker-credential-helpers/credentials" "github.com/godbus/dbus" "github.com/keybase/go-keychain/secretservice" @@ -30,10 +32,13 @@ const ( labelAtt = "label" usernameAtt = "username" - defaulDomain = "protonmail/bridge/users/" - defaultLabel = "Docker Credentials" + defaultLabel = "Proton Mail Bridge Credentials" ) +func getDomain() string { + return hostURL(constants.KeyChainName) +} + func getSession() (*secretservice.SecretService, *secretservice.Session, error) { service, err := secretservice.NewService() if err != nil { @@ -73,8 +78,9 @@ func getItems(service *secretservice.SecretService, attributes map[string]string if err != nil { return nil, err } - - return items, err + return xslices.Filter(items, func(t dbus.ObjectPath) bool { + return strings.HasPrefix(string(t), "/org/freedesktop/secrets") + }), err } func unlock(service *secretservice.SecretService) error { @@ -105,11 +111,9 @@ func (s *SecretServiceDBusHelper) Add(creds *credentials.Credentials) error { } attributes := map[string]string{ - usernameAtt: creds.Username, - serverAtt: creds.ServerURL, - labelAtt: defaultLabel, - "xdg:schema": "io.docker.Credentials", - "docker_cli": "1", + usernameAtt: creds.Username, + serverAtt: creds.ServerURL, + labelAtt: defaultLabel, } return handleTimeout(func() error { @@ -203,13 +207,15 @@ func (s *SecretServiceDBusHelper) List() (map[string]string, error) { return nil, err } + defaultDomain := getDomain() + for _, it := range items { attributes, err := service.GetAttributes(it) if err != nil { return nil, err } - if !strings.HasPrefix(attributes[serverAtt], defaulDomain) { + if !strings.HasPrefix(attributes[serverAtt], defaultDomain) { continue } From 622b76b57b7103576a387c642d3b402298dceea2 Mon Sep 17 00:00:00 2001 From: Xavier Michelon Date: Wed, 15 Mar 2023 12:02:25 +0100 Subject: [PATCH 02/54] feat(GODT-2483): install cert without external tool on macOS. --- internal/certs/cert_store_darwin.go | 166 ++++++++++++++++------- internal/certs/cert_store_darwin_test.go | 44 ++++++ 2 files changed, 163 insertions(+), 47 deletions(-) create mode 100644 internal/certs/cert_store_darwin_test.go diff --git a/internal/certs/cert_store_darwin.go b/internal/certs/cert_store_darwin.go index c034adec..8e1f9570 100644 --- a/internal/certs/cert_store_darwin.go +++ b/internal/certs/cert_store_darwin.go @@ -17,69 +17,141 @@ package certs -import ( - "os" +/* +#cgo CFLAGS: -x objective-c +#cgo LDFLAGS: -framework Foundation -framework Security +#import +#import - "golang.org/x/sys/execabs" + +int installTrustedCert(char const *bytes, unsigned long long length) { + if (length == 0) { + return errSecInvalidData; + } + + NSData *der = [NSData dataWithBytes:bytes length:length]; + + // Step 1. Import the certificate in the keychain. + SecCertificateRef cert = SecCertificateCreateWithData(NULL, (CFDataRef) der); + NSDictionary* addQuery = @{ + (id)kSecValueRef: (__bridge id) cert, + (id)kSecClass: (id)kSecClassCertificate, + }; + + OSStatus status = SecItemAdd((__bridge CFDictionaryRef) addQuery, NULL); + if ((errSecSuccess != status) && (errSecDuplicateItem != status)) { + CFRelease(cert); + return status; + } + + // Step 2. Set the trust for the certificate. + SecPolicyRef policy = SecPolicyCreateSSL(true, NULL); // we limit our trust to SSL + NSDictionary *trustSettings = @{ + (id)kSecTrustSettingsResult: [NSNumber numberWithInt:kSecTrustSettingsResultTrustRoot], + (id)kSecTrustSettingsPolicy: (__bridge id) policy, + }; + status = SecTrustSettingsSetTrustSettings(cert, kSecTrustSettingsDomainAdmin, (__bridge CFTypeRef)(trustSettings)); + CFRelease(policy); + CFRelease(cert); + + return status; +} + + +int removeTrustedCert(char const *bytes, unsigned long long length) { + if (0 == length) { + return errSecInvalidData; + } + + NSData *der = [NSData dataWithBytes: bytes length: length]; + SecCertificateRef cert = SecCertificateCreateWithData(NULL, (CFDataRef) der); + + // Step 1. Unset the trust for the certificate. + SecPolicyRef policy = SecPolicyCreateSSL(true, NULL); + NSDictionary * trustSettings = @{ + (id)kSecTrustSettingsResult: [NSNumber numberWithInt:kSecTrustSettingsResultUnspecified], + (id)kSecTrustSettingsPolicy: (__bridge id) policy, + }; + OSStatus status = SecTrustSettingsSetTrustSettings(cert, kSecTrustSettingsDomainAdmin, (__bridge CFTypeRef)(trustSettings)); + CFRelease(policy); + if (errSecSuccess != status) { + CFRelease(cert); + return status; + } + + // Step 2. Remove the certificate from the keychain. + NSDictionary *query = @{ (id)kSecClass: (id)kSecClassCertificate, + (id)kSecMatchItemList: @[(__bridge id)cert], + (id)kSecMatchLimit: (id)kSecMatchLimitOne, + }; + status = SecItemDelete((__bridge CFDictionaryRef) query); + + CFRelease(cert); + return status; +} +*/ +import "C" + +import ( + "encoding/pem" + "errors" + "fmt" + "unsafe" ) +// some of the error codes returned by Apple's Security framework. +const ( + errSecSuccess = 0 + errAuthorizationCanceled = -60006 +) + +// certPEMToDER converts a certificate in PEM format to DER format, which is the format required by Apple's Security framework. +func certPEMToDER(certPEM []byte) ([]byte, error) { + + block, left := pem.Decode(certPEM) + if block == nil { + return []byte{}, errors.New("invalid PEM certificate") + } + + if len(left) > 0 { + return []byte{}, errors.New("trailing data found at the end of a PEM certificate") + } + + return block.Bytes, nil +} + func installCert(certPEM []byte) error { - name, err := writeToTempFile(certPEM) + certDER, err := certPEMToDER(certPEM) if err != nil { return err } - return addTrustedCert(name) + p := C.CBytes(certDER) + defer C.free(unsafe.Pointer(p)) + + errCode := C.installTrustedCert((*C.char)(p), (C.ulonglong)(len(certDER))) + switch errCode { + case errSecSuccess: + return nil + case errAuthorizationCanceled: + return fmt.Errorf("the user cancelled the authorization dialog") + default: + return fmt.Errorf("could not install certification into keychain (error %v)", errCode) + } } func uninstallCert(certPEM []byte) error { - name, err := writeToTempFile(certPEM) + certDER, err := certPEMToDER(certPEM) if err != nil { return err } - return removeTrustedCert(name) -} + p := C.CBytes(certDER) + defer C.free(unsafe.Pointer(p)) -func addTrustedCert(certPath string) error { - return execabs.Command( //nolint:gosec - "/usr/bin/security", - "execute-with-privileges", - "/usr/bin/security", - "add-trusted-cert", - "-d", - "-r", "trustRoot", - "-p", "ssl", - "-k", "/Library/Keychains/System.keychain", - certPath, - ).Run() -} - -func removeTrustedCert(certPath string) error { - return execabs.Command( //nolint:gosec - "/usr/bin/security", - "execute-with-privileges", - "/usr/bin/security", - "remove-trusted-cert", - "-d", - certPath, - ).Run() -} - -// writeToTempFile writes the given data to a temporary file and returns the path. -func writeToTempFile(data []byte) (string, error) { - f, err := os.CreateTemp("", "tls") - if err != nil { - return "", err + if errCode := C.removeTrustedCert((*C.char)(p), (C.ulonglong)(len(certDER))); errCode != 0 { + return fmt.Errorf("could not install certificate from keychain (error %v)", errCode) } - if _, err := f.Write(data); err != nil { - return "", err - } - - if err := f.Close(); err != nil { - return "", err - } - - return f.Name(), nil + return nil } diff --git a/internal/certs/cert_store_darwin_test.go b/internal/certs/cert_store_darwin_test.go new file mode 100644 index 00000000..9ac9c698 --- /dev/null +++ b/internal/certs/cert_store_darwin_test.go @@ -0,0 +1,44 @@ +// Copyright (c) 2023 Proton AG +// +// This file is part of Proton Mail 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 . + +//go:build darwin + +package certs + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +// This test implies human interactions to enter password and is disabled by default. +func _TestTrustedCertsDarwin(t *testing.T) { + template, err := NewTLSTemplate() + require.NoError(t, err) + + certPEM, _, err := GenerateCert(template) + require.NoError(t, err) + + require.Error(t, installCert([]byte{0})) // Cannot install an invalid cert. + require.Error(t, uninstallCert(certPEM)) // Cannot uninstall a cert that is not installed. + require.NoError(t, installCert(certPEM)) // Can install a valid cert. + require.NoError(t, installCert(certPEM)) // Can install an already installed cert. + require.NoError(t, uninstallCert(certPEM)) // Can uninstall an installed cert. + require.Error(t, uninstallCert(certPEM)) // Cannot uninstall an already uninstalled cert. + require.NoError(t, installCert(certPEM)) // Can reinstall an uninstalled cert. + require.NoError(t, uninstallCert(certPEM)) // Can uninstall a reinstalled cert. +} From b3d0dfc60b3c4e10bd302f34eb4cb329efcfafb1 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Thu, 16 Mar 2023 14:37:50 +0100 Subject: [PATCH 03/54] fix(GODT-2497): Do not report EOF and network errors --- internal/user/user.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/internal/user/user.go b/internal/user/user.go index 168967ef..2d0769cb 100644 --- a/internal/user/user.go +++ b/internal/user/user.go @@ -678,11 +678,6 @@ func (user *User) doEventPoll(ctx context.Context) error { // Catch all for uncategorized net errors that may slip through. if netErr := new(net.OpError); errors.As(err, &netErr) { - user.eventCh.Enqueue(events.UncategorizedEventError{ - UserID: user.ID(), - Error: err, - }) - return fmt.Errorf("failed to handle event due to network issues (uncategorized): %w", err) } @@ -698,11 +693,6 @@ func (user *User) doEventPoll(ctx context.Context) error { // If the error is an unexpected EOF, return error to retry later. if errors.Is(err, io.ErrUnexpectedEOF) { - user.eventCh.Enqueue(events.UncategorizedEventError{ - UserID: user.ID(), - Error: err, - }) - return fmt.Errorf("failed to handle event due to EOF: %w", err) } From 02ca6428b5920c2662436f397a7269f3d93ecc84 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Fri, 17 Mar 2023 13:11:07 +0100 Subject: [PATCH 04/54] fix(GODT-2407): Replace invalid email addresses with emtpy for new Drafts --- internal/user/imap.go | 2 +- internal/user/smtp.go | 2 +- pkg/message/parser.go | 51 ++++++++++++++++++++++++++++++-------- pkg/message/parser_test.go | 29 +++++++++++++++++++++- 4 files changed, 70 insertions(+), 14 deletions(-) diff --git a/internal/user/imap.go b/internal/user/imap.go index fb5cdaa3..8a62ba3a 100644 --- a/internal/user/imap.go +++ b/internal/user/imap.go @@ -626,7 +626,7 @@ func (conn *imapConnector) createDraft(ctx context.Context, literal []byte, addr return proton.Message{}, fmt.Errorf("failed to create parser: %w", err) } - message, err := message.ParseWithParser(parser) + message, err := message.ParseWithParser(parser, true) if err != nil { return proton.Message{}, fmt.Errorf("failed to parse message: %w", err) } diff --git a/internal/user/smtp.go b/internal/user/smtp.go index 1a0dd706..27eee7e9 100644 --- a/internal/user/smtp.go +++ b/internal/user/smtp.go @@ -137,7 +137,7 @@ func (user *User) sendMail(authID string, from string, to []string, r io.Reader) } // Parse the message we want to send (after we have attached the public key). - message, err := message.ParseWithParser(parser) + message, err := message.ParseWithParser(parser, false) if err != nil { return fmt.Errorf("failed to parse message: %w", err) } diff --git a/pkg/message/parser.go b/pkg/message/parser.go index cba83aee..ff6472c2 100644 --- a/pkg/message/parser.go +++ b/pkg/message/parser.go @@ -73,6 +73,15 @@ type Attachment struct { // Parse parses an RFC822 message. func Parse(r io.Reader) (m Message, err error) { + return parseIOReaderImpl(r, false) +} + +// ParseAndAllowInvalidAddressLists parses an RFC822 message and allows email address lists to be invalid. +func ParseAndAllowInvalidAddressLists(r io.Reader) (m Message, err error) { + return parseIOReaderImpl(r, true) +} + +func parseIOReaderImpl(r io.Reader, allowInvalidAddressLists bool) (m Message, err error) { defer func() { if r := recover(); r != nil { err = fmt.Errorf("panic while parsing message: %v", r) @@ -84,21 +93,21 @@ func Parse(r io.Reader) (m Message, err error) { return Message{}, errors.Wrap(err, "failed to create new parser") } - return parse(p) + return parse(p, allowInvalidAddressLists) } // ParseWithParser parses an RFC822 message using an existing parser. -func ParseWithParser(p *parser.Parser) (m Message, err error) { +func ParseWithParser(p *parser.Parser, allowInvalidAddressLists bool) (m Message, err error) { defer func() { if r := recover(); r != nil { err = fmt.Errorf("panic while parsing message: %v", r) } }() - return parse(p) + return parse(p, allowInvalidAddressLists) } -func parse(p *parser.Parser) (Message, error) { +func parse(p *parser.Parser, allowInvalidAddressLists bool) (Message, error) { if err := convertEncodedTransferEncoding(p); err != nil { return Message{}, errors.Wrap(err, "failed to convert encoded transfer encoding") } @@ -107,7 +116,7 @@ func parse(p *parser.Parser) (Message, error) { return Message{}, errors.Wrap(err, "failed to convert foreign encodings") } - m, err := parseMessageHeader(p.Root().Header) + m, err := parseMessageHeader(p.Root().Header, allowInvalidAddressLists) if err != nil { return Message{}, errors.Wrap(err, "failed to parse message header") } @@ -433,7 +442,7 @@ func getPlainBody(part *parser.Part) []byte { } } -func parseMessageHeader(h message.Header) (Message, error) { +func parseMessageHeader(h message.Header, allowInvalidAddressLists bool) (Message, error) { var m Message for fields := h.Fields(); fields.Next(); { @@ -451,7 +460,11 @@ func parseMessageHeader(h message.Header) (Message, error) { case "from": sender, err := rfc5322.ParseAddressList(fields.Value()) if err != nil { - return Message{}, errors.Wrap(err, "failed to parse from") + if !allowInvalidAddressLists { + return Message{}, errors.Wrap(err, "failed to parse from") + } + + logrus.WithError(err).Warn("failed to parse from") } if len(sender) > 0 { @@ -461,7 +474,11 @@ func parseMessageHeader(h message.Header) (Message, error) { case "to": toList, err := rfc5322.ParseAddressList(fields.Value()) if err != nil { - return Message{}, errors.Wrap(err, "failed to parse to") + if !allowInvalidAddressLists { + return Message{}, errors.Wrap(err, "failed to parse to") + } + + logrus.WithError(err).Warn("failed to parse to") } m.ToList = toList @@ -469,7 +486,11 @@ func parseMessageHeader(h message.Header) (Message, error) { case "reply-to": replyTos, err := rfc5322.ParseAddressList(fields.Value()) if err != nil { - return Message{}, errors.Wrap(err, "failed to parse reply-to") + if !allowInvalidAddressLists { + return Message{}, errors.Wrap(err, "failed to parse reply-to") + } + + logrus.WithError(err).Warn("failed to parse reply-to") } m.ReplyTos = replyTos @@ -477,7 +498,11 @@ func parseMessageHeader(h message.Header) (Message, error) { case "cc": ccList, err := rfc5322.ParseAddressList(fields.Value()) if err != nil { - return Message{}, errors.Wrap(err, "failed to parse cc") + if !allowInvalidAddressLists { + return Message{}, errors.Wrap(err, "failed to parse cc") + } + + logrus.WithError(err).Warn("failed to parse cc") } m.CCList = ccList @@ -485,7 +510,11 @@ func parseMessageHeader(h message.Header) (Message, error) { case "bcc": bccList, err := rfc5322.ParseAddressList(fields.Value()) if err != nil { - return Message{}, errors.Wrap(err, "failed to parse bcc") + if !allowInvalidAddressLists { + return Message{}, errors.Wrap(err, "failed to parse bcc") + } + + logrus.WithError(err).Warn("failed to parse bcc") } m.BCCList = bccList diff --git a/pkg/message/parser_test.go b/pkg/message/parser_test.go index 6942deee..d536333b 100644 --- a/pkg/message/parser_test.go +++ b/pkg/message/parser_test.go @@ -23,6 +23,7 @@ import ( "io" "os" "path/filepath" + "strings" "testing" "github.com/ProtonMail/go-proton-api" @@ -444,7 +445,7 @@ func TestParseWithAttachedPublicKey(t *testing.T) { p, err := parser.New(f) require.NoError(t, err) - m, err := ParseWithParser(p) + m, err := ParseWithParser(p, false) require.NoError(t, err) p.AttachPublicKey("publickey", "publickeyname") @@ -636,6 +637,32 @@ func TestParseIcsAttachment(t *testing.T) { assert.Equal(t, string(m.Attachments[0].Data), "This is an ics calendar invite") } +func TestParseAllowInvalidAddress(t *testing.T) { + const literal = `To: foo + From: bar + BCC: fff + CC: FFF + Reply-To: AAA + Subject: Test +` + + // This will fail as the addresses are not valid. + { + _, err := Parse(strings.NewReader(literal)) + require.Error(t, err) + } + + // This will work as invalid addresses will be ignored. + m, err := ParseAndAllowInvalidAddressLists(strings.NewReader(literal)) + require.NoError(t, err) + + assert.Empty(t, m.ToList) + assert.Empty(t, m.Sender) + assert.Empty(t, m.CCList) + assert.Empty(t, m.BCCList) + assert.Empty(t, m.ReplyTos) +} + func TestParsePanic(t *testing.T) { var err error From 4f49c87bc6913de5a58476ea120deaee7211c405 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Fri, 17 Mar 2023 15:23:22 +0100 Subject: [PATCH 05/54] chore: Replace go-rfc5322 with gluon's rfc5322 parser Bumps Gluon version in order to get the fixes from https://github.com/ProtonMail/gluon/pull/327. --- COPYING_NOTES.md | 2 -- go.mod | 4 +--- go.sum | 9 ++------- internal/user/smtp.go | 2 +- pkg/message/build.go | 2 +- pkg/message/parser.go | 2 +- pkg/message/parser_test.go | 10 +++++----- tests/ctx_test.go | 22 ++++++++++++++++++++++ tests/environment_test.go | 3 ++- 9 files changed, 35 insertions(+), 21 deletions(-) diff --git a/COPYING_NOTES.md b/COPYING_NOTES.md index 171fa8fd..94fac254 100644 --- a/COPYING_NOTES.md +++ b/COPYING_NOTES.md @@ -26,7 +26,6 @@ Proton Mail Bridge includes the following 3rd party software: * [gluon](https://github.com/ProtonMail/gluon) available under [license](https://github.com/ProtonMail/gluon/blob/master/LICENSE) * [go-autostart](https://github.com/ProtonMail/go-autostart) available under [license](https://github.com/ProtonMail/go-autostart/blob/master/LICENSE) * [go-proton-api](https://github.com/ProtonMail/go-proton-api) available under [license](https://github.com/ProtonMail/go-proton-api/blob/master/LICENSE) -* [go-rfc5322](https://github.com/ProtonMail/go-rfc5322) available under [license](https://github.com/ProtonMail/go-rfc5322/blob/master/LICENSE) * [gopenpgp](https://github.com/ProtonMail/gopenpgp/v2) available under [license](https://github.com/ProtonMail/gopenpgp/v2/blob/master/LICENSE) * [goquery](https://github.com/PuerkitoBio/goquery) available under [license](https://github.com/PuerkitoBio/goquery/blob/master/LICENSE) * [ishell](https://github.com/abiosoft/ishell) available under [license](https://github.com/abiosoft/ishell/blob/master/LICENSE) @@ -77,7 +76,6 @@ Proton Mail Bridge includes the following 3rd party software: * [readline](https://github.com/abiosoft/readline) available under [license](https://github.com/abiosoft/readline/blob/master/LICENSE) * [levenshtein](https://github.com/agext/levenshtein) available under [license](https://github.com/agext/levenshtein/blob/master/LICENSE) * [cascadia](https://github.com/andybalholm/cascadia) available under [license](https://github.com/andybalholm/cascadia/blob/master/LICENSE) -* [antlr](https://github.com/antlr/antlr4/runtime/Go/antlr) available under [license](https://github.com/antlr/antlr4/runtime/Go/antlr/blob/master/LICENSE) * [go-textseg](https://github.com/apparentlymart/go-textseg/v13) available under [license](https://github.com/apparentlymart/go-textseg/v13/blob/master/LICENSE) * [sonic](https://github.com/bytedance/sonic) available under [license](https://github.com/bytedance/sonic/blob/master/LICENSE) * [base64x](https://github.com/chenzhuoyu/base64x) available under [license](https://github.com/chenzhuoyu/base64x/blob/master/LICENSE) diff --git a/go.mod b/go.mod index 06511858..372279e7 100644 --- a/go.mod +++ b/go.mod @@ -5,10 +5,9 @@ go 1.18 require ( github.com/0xAX/notificator v0.0.0-20220220101646-ee9b8921e557 github.com/Masterminds/semver/v3 v3.2.0 - github.com/ProtonMail/gluon v0.15.1-0.20230310125443-f755e8ce082a + github.com/ProtonMail/gluon v0.15.1-0.20230317141727-9f7c827f39d2 github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a github.com/ProtonMail/go-proton-api v0.4.1-0.20230314144605-dd633a1d4739 - github.com/ProtonMail/go-rfc5322 v0.11.0 github.com/ProtonMail/gopenpgp/v2 v2.5.2 github.com/PuerkitoBio/goquery v1.8.1 github.com/abiosoft/ishell v2.0.0+incompatible @@ -62,7 +61,6 @@ require ( github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db // indirect github.com/agext/levenshtein v1.2.3 // indirect github.com/andybalholm/cascadia v1.3.1 // indirect - github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 // indirect github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect github.com/bytedance/sonic v1.8.1 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect diff --git a/go.sum b/go.sum index 9dee4d92..c024b799 100644 --- a/go.sum +++ b/go.sum @@ -28,8 +28,8 @@ github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf h1:yc9daCCYUefEs github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf/go.mod h1:o0ESU9p83twszAU8LBeJKFAAMX14tISa0yk4Oo5TOqo= github.com/ProtonMail/docker-credential-helpers v1.1.0 h1:+kvUIpwWcbtP3WFv5sSvkFn/XLzSqPOB5AAthuk9xPk= github.com/ProtonMail/docker-credential-helpers v1.1.0/go.mod h1:mK0aBveCxhnQ756AmaTfXMZDeULvheYVhF/MWMErN5g= -github.com/ProtonMail/gluon v0.15.1-0.20230310125443-f755e8ce082a h1:o7gQKDCJMYju8svD4ufB/YfcUcWUPfQjau3MDNF2dQQ= -github.com/ProtonMail/gluon v0.15.1-0.20230310125443-f755e8ce082a/go.mod h1:yA4hk6CJw0BMo+YL8Y3ckCYs5L20sysu9xseshwY3QI= +github.com/ProtonMail/gluon v0.15.1-0.20230317141727-9f7c827f39d2 h1:WT74oKGqW6gCvzXUvgTK4LarotUvyBz9YsNJqftAO74= +github.com/ProtonMail/gluon v0.15.1-0.20230317141727-9f7c827f39d2/go.mod h1:yA4hk6CJw0BMo+YL8Y3ckCYs5L20sysu9xseshwY3QI= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:D+aZah+k14Gn6kmL7eKxoo/4Dr/lK3ChBcwce2+SQP4= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4= github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= @@ -42,8 +42,6 @@ github.com/ProtonMail/go-mime v0.0.0-20221031134845-8fd9bc37cf08 h1:dS7r5z4iGS0q github.com/ProtonMail/go-mime v0.0.0-20221031134845-8fd9bc37cf08/go.mod h1:qRZgbeASl2a9OwmsV85aWwRqic0NHPh+9ewGAzb4cgM= github.com/ProtonMail/go-proton-api v0.4.1-0.20230314144605-dd633a1d4739 h1:sJhJQKQcG06mDcqikvLLnMuTz2rngcGTiTvOnc7lQbU= github.com/ProtonMail/go-proton-api v0.4.1-0.20230314144605-dd633a1d4739/go.mod h1:4AXhqhB+AGVasVIlift9Lr1Btxg5S83xXPiyiT7mKUc= -github.com/ProtonMail/go-rfc5322 v0.11.0 h1:o5Obrm4DpmQEffvgsVqG6S4BKwC1Wat+hYwjIp2YcCY= -github.com/ProtonMail/go-rfc5322 v0.11.0/go.mod h1:6oOKr0jXvpoE6pwTx/HukigQpX2J9WUf6h0auplrFTw= github.com/ProtonMail/go-srp v0.0.5 h1:xhUioxZgDbCnpo9JehyFhwwsn9JLWkUGfB0oiKXgiGg= github.com/ProtonMail/go-srp v0.0.5/go.mod h1:06iYHtLXW8vjLtccWj++x3MKy65sIT8yZd7nrJF49rs= github.com/ProtonMail/gopenpgp/v2 v2.5.2 h1:97SjlWNAxXl9P22lgwgrZRshQdiEfAht0g3ZoiA1GCw= @@ -62,9 +60,6 @@ github.com/allan-simon/go-singleinstance v0.0.0-20210120080615-d0997106ab37 h1:2 github.com/allan-simon/go-singleinstance v0.0.0-20210120080615-d0997106ab37/go.mod h1:6AXRstqK+32jeFmw89QGL2748+dj34Av4xc/I9oo9BY= github.com/andybalholm/cascadia v1.3.1 h1:nhxRkql1kdYCc8Snf7D5/D3spOX+dBgjA6u8x004T2c= github.com/andybalholm/cascadia v1.3.1/go.mod h1:R4bJ1UQfqADjvDa4P6HZHLh/3OxWWEqc0Sk8XGwHqvA= -github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20220816024939-bc8df83d7b9d/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= -github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 h1:yL7+Jz0jTC6yykIK/Wh74gnTJnrGr5AyrNMXuA0gves= -github.com/antlr/antlr4/runtime/Go/antlr v1.4.10/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY= github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= diff --git a/internal/user/smtp.go b/internal/user/smtp.go index 27eee7e9..6ca03c47 100644 --- a/internal/user/smtp.go +++ b/internal/user/smtp.go @@ -30,9 +30,9 @@ import ( "time" "github.com/ProtonMail/gluon/reporter" + "github.com/ProtonMail/gluon/rfc5322" "github.com/ProtonMail/gluon/rfc822" "github.com/ProtonMail/go-proton-api" - "github.com/ProtonMail/go-rfc5322" "github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/ProtonMail/proton-bridge/v3/internal/logging" "github.com/ProtonMail/proton-bridge/v3/internal/safe" diff --git a/pkg/message/build.go b/pkg/message/build.go index 57d7eb42..b67503e2 100644 --- a/pkg/message/build.go +++ b/pkg/message/build.go @@ -27,9 +27,9 @@ import ( "time" "unicode/utf8" + "github.com/ProtonMail/gluon/rfc5322" "github.com/ProtonMail/gluon/rfc822" "github.com/ProtonMail/go-proton-api" - "github.com/ProtonMail/go-rfc5322" "github.com/ProtonMail/gopenpgp/v2/crypto" "github.com/ProtonMail/proton-bridge/v3/pkg/algo" "github.com/bradenaw/juniper/xslices" diff --git a/pkg/message/parser.go b/pkg/message/parser.go index ff6472c2..ead63a8d 100644 --- a/pkg/message/parser.go +++ b/pkg/message/parser.go @@ -26,9 +26,9 @@ import ( "regexp" "strings" + "github.com/ProtonMail/gluon/rfc5322" "github.com/ProtonMail/gluon/rfc822" "github.com/ProtonMail/go-proton-api" - "github.com/ProtonMail/go-rfc5322" "github.com/ProtonMail/proton-bridge/v3/pkg/message/parser" pmmime "github.com/ProtonMail/proton-bridge/v3/pkg/mime" "github.com/emersion/go-message" diff --git a/pkg/message/parser_test.go b/pkg/message/parser_test.go index d536333b..5bbce163 100644 --- a/pkg/message/parser_test.go +++ b/pkg/message/parser_test.go @@ -639,11 +639,11 @@ func TestParseIcsAttachment(t *testing.T) { func TestParseAllowInvalidAddress(t *testing.T) { const literal = `To: foo - From: bar - BCC: fff - CC: FFF - Reply-To: AAA - Subject: Test +From: bar +BCC: fff +CC: FFF +Reply-To: AAA +Subject: Test ` // This will fail as the addresses are not valid. diff --git a/tests/ctx_test.go b/tests/ctx_test.go index 2089ea89..fd6be67c 100644 --- a/tests/ctx_test.go +++ b/tests/ctx_test.go @@ -366,6 +366,28 @@ func (t *testCtx) getLastCall(method, pathExp string) (server.Call, error) { return server.Call{}, fmt.Errorf("no call with method %q and path %q was made", method, pathExp) } +func (t *testCtx) getLastCallExcludingHTTPOverride(method, pathExp string) (server.Call, error) { + t.callsLock.RLock() + defer t.callsLock.RUnlock() + + root, err := url.Parse(t.api.GetHostURL()) + if err != nil { + return server.Call{}, err + } + + if matches := xslices.Filter(xslices.Join(t.calls...), func(call server.Call) bool { + if len(call.RequestHeader.Get("X-HTTP-Method-Override")) != 0 || len(call.RequestHeader.Get("X-Http-Method")) != 0 { + return false + } + + return call.Method == method && regexp.MustCompile("^"+pathExp+"$").MatchString(strings.TrimPrefix(call.URL.Path, root.Path)) + }); len(matches) > 0 { + return matches[len(matches)-1], nil + } + + return server.Call{}, fmt.Errorf("no call with method %q and path %q was made", method, pathExp) +} + func (t *testCtx) pushError(err error) { t.errorsLock.Lock() defer t.errorsLock.Unlock() diff --git a/tests/environment_test.go b/tests/environment_test.go index d3c1243d..da78767d 100644 --- a/tests/environment_test.go +++ b/tests/environment_test.go @@ -88,7 +88,8 @@ func (s *scenario) theHeaderInTheRequestToHasSetTo(method, path, key, value stri } func (s *scenario) theBodyInTheRequestToIs(method, path string, value *godog.DocString) error { - call, err := s.t.getLastCall(method, path) + // We have to exclude HTTP-Overrides to avoid race condition with the creating and sending of the draft message. + call, err := s.t.getLastCallExcludingHTTPOverride(method, path) if err != nil { return err } From d8bf2cc25e16d4957a843715578b6f11f38e021d Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Mon, 20 Mar 2023 13:19:05 +0100 Subject: [PATCH 06/54] fix(GODT-2418): Do not issue connector renames for inferiors Bump Gluon (https://github.com/ProtonMail/gluon/pull/328) and add test. --- go.mod | 2 +- go.sum | 4 ++-- .../imap/mailbox/rename_hiearchy.feature | 19 +++++++++++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) create mode 100644 tests/features/imap/mailbox/rename_hiearchy.feature diff --git a/go.mod b/go.mod index 372279e7..1cc1c247 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/0xAX/notificator v0.0.0-20220220101646-ee9b8921e557 github.com/Masterminds/semver/v3 v3.2.0 - github.com/ProtonMail/gluon v0.15.1-0.20230317141727-9f7c827f39d2 + github.com/ProtonMail/gluon v0.15.1-0.20230320120726-45de5f1292d7 github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a github.com/ProtonMail/go-proton-api v0.4.1-0.20230314144605-dd633a1d4739 github.com/ProtonMail/gopenpgp/v2 v2.5.2 diff --git a/go.sum b/go.sum index c024b799..b9071ed5 100644 --- a/go.sum +++ b/go.sum @@ -28,8 +28,8 @@ github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf h1:yc9daCCYUefEs github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf/go.mod h1:o0ESU9p83twszAU8LBeJKFAAMX14tISa0yk4Oo5TOqo= github.com/ProtonMail/docker-credential-helpers v1.1.0 h1:+kvUIpwWcbtP3WFv5sSvkFn/XLzSqPOB5AAthuk9xPk= github.com/ProtonMail/docker-credential-helpers v1.1.0/go.mod h1:mK0aBveCxhnQ756AmaTfXMZDeULvheYVhF/MWMErN5g= -github.com/ProtonMail/gluon v0.15.1-0.20230317141727-9f7c827f39d2 h1:WT74oKGqW6gCvzXUvgTK4LarotUvyBz9YsNJqftAO74= -github.com/ProtonMail/gluon v0.15.1-0.20230317141727-9f7c827f39d2/go.mod h1:yA4hk6CJw0BMo+YL8Y3ckCYs5L20sysu9xseshwY3QI= +github.com/ProtonMail/gluon v0.15.1-0.20230320120726-45de5f1292d7 h1:IV5UN40uycUfexsuMOY1TAuGLVjKof6V2ybHsNPq1CM= +github.com/ProtonMail/gluon v0.15.1-0.20230320120726-45de5f1292d7/go.mod h1:yA4hk6CJw0BMo+YL8Y3ckCYs5L20sysu9xseshwY3QI= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:D+aZah+k14Gn6kmL7eKxoo/4Dr/lK3ChBcwce2+SQP4= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4= github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= diff --git a/tests/features/imap/mailbox/rename_hiearchy.feature b/tests/features/imap/mailbox/rename_hiearchy.feature new file mode 100644 index 00000000..7bb0de8d --- /dev/null +++ b/tests/features/imap/mailbox/rename_hiearchy.feature @@ -0,0 +1,19 @@ +Feature: IMAP get mailbox info + Background: + Given there exists an account with username "[user:user]" and password "password" + And the account "[user:user]" has the following custom mailboxes: + | name | type | + | f1 | folder | + | f1/f2| folder | + And bridge starts + And the user logs in with username "[user:user]" and password "password" + And user "[user:user]" finishes syncing + And user "[user:user]" connects and authenticates IMAP client "1" + + Scenario: Rename folder with subfolders + When IMAP client "1" renames "Folders/f1" to "Folders/f3" + And it succeeds + Then IMAP client "1" sees "Folders/f3" + Then IMAP client "1" sees "Folders/f3/f2" + And IMAP client "1" does not see "Folders/f1" + And IMAP client "1" does not see "Folders/f1/f2" From a8250ff65ed1bcb146c8ffcee9a89fd9dc01aec9 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Tue, 21 Mar 2023 08:45:01 +0100 Subject: [PATCH 07/54] fix(GODT-2507): Memory consumption bug Fix was made in Gluon: https://github.com/ProtonMail/gluon/pull/329 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 1cc1c247..678b6325 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/0xAX/notificator v0.0.0-20220220101646-ee9b8921e557 github.com/Masterminds/semver/v3 v3.2.0 - github.com/ProtonMail/gluon v0.15.1-0.20230320120726-45de5f1292d7 + github.com/ProtonMail/gluon v0.15.1-0.20230321074233-2d09826346c1 github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a github.com/ProtonMail/go-proton-api v0.4.1-0.20230314144605-dd633a1d4739 github.com/ProtonMail/gopenpgp/v2 v2.5.2 diff --git a/go.sum b/go.sum index b9071ed5..c33dfd96 100644 --- a/go.sum +++ b/go.sum @@ -28,8 +28,8 @@ github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf h1:yc9daCCYUefEs github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf/go.mod h1:o0ESU9p83twszAU8LBeJKFAAMX14tISa0yk4Oo5TOqo= github.com/ProtonMail/docker-credential-helpers v1.1.0 h1:+kvUIpwWcbtP3WFv5sSvkFn/XLzSqPOB5AAthuk9xPk= github.com/ProtonMail/docker-credential-helpers v1.1.0/go.mod h1:mK0aBveCxhnQ756AmaTfXMZDeULvheYVhF/MWMErN5g= -github.com/ProtonMail/gluon v0.15.1-0.20230320120726-45de5f1292d7 h1:IV5UN40uycUfexsuMOY1TAuGLVjKof6V2ybHsNPq1CM= -github.com/ProtonMail/gluon v0.15.1-0.20230320120726-45de5f1292d7/go.mod h1:yA4hk6CJw0BMo+YL8Y3ckCYs5L20sysu9xseshwY3QI= +github.com/ProtonMail/gluon v0.15.1-0.20230321074233-2d09826346c1 h1:zVKqnKO/vTMrVw1dleGsj1JlY9jbhK890X0htvGCbjY= +github.com/ProtonMail/gluon v0.15.1-0.20230321074233-2d09826346c1/go.mod h1:yA4hk6CJw0BMo+YL8Y3ckCYs5L20sysu9xseshwY3QI= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:D+aZah+k14Gn6kmL7eKxoo/4Dr/lK3ChBcwce2+SQP4= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4= github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= From 03c3e95b344166f970a4843ddbb279b957416cc5 Mon Sep 17 00:00:00 2001 From: Xavier Michelon Date: Tue, 21 Mar 2023 12:30:23 +0100 Subject: [PATCH 08/54] feat(GODT-2511): add bridge-gui switches to permanently select the QML rendering backend. --- .../frontend/bridge-gui/bridge-gui/CommandLine.cpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/internal/frontend/bridge-gui/bridge-gui/CommandLine.cpp b/internal/frontend/bridge-gui/bridge-gui/CommandLine.cpp index 5a892da0..420e7901 100644 --- a/internal/frontend/bridge-gui/bridge-gui/CommandLine.cpp +++ b/internal/frontend/bridge-gui/bridge-gui/CommandLine.cpp @@ -18,6 +18,7 @@ #include "Pch.h" #include "CommandLine.h" +#include "Settings.h" using namespace bridgepp; @@ -28,7 +29,10 @@ namespace { QString const launcherFlag = "--launcher"; ///< launcher flag parameter used for bridge. QString const noWindowFlag = "--no-window"; ///< The no-window command-line flag. -QString const softwareRendererFlag = "--software-renderer"; ///< The 'software-renderer' command-line flag. +QString const softwareRendererFlag = "--software-renderer"; ///< The 'software-renderer' command-line flag. enable software rendering for a single execution +QString const setSoftwareRendererFlag = "--set-software-renderer"; ///< The 'set-software-renderer' command-line flag. Software rendering will be used for all subsequent executions of the application. +QString const setHardwareRendererFlag = "--set-hardware-renderer"; ///< The 'set-hardware-renderer' command-line flag. Hardware rendering will be used for all subsequent executions of the application. + //**************************************************************************************************************************************************** /// \brief parse a command-line string argument as expected by go's CLI package. @@ -101,6 +105,14 @@ CommandLineOptions parseCommandLine(int argc, char *argv[]) { options.bridgeGuiArgs.append(arg); options.useSoftwareRenderer = true; } + if (arg == setSoftwareRendererFlag) { + app().settings().setUseSoftwareRenderer(true); + continue; // setting is permanent. no need to keep/pass it to bridge for restart. + } + if (arg == setHardwareRendererFlag) { + app().settings().setUseSoftwareRenderer(false); + continue; // setting is permanent. no need to keep/pass it to bridge for restart. + } if (arg == noWindowFlag) { options.noWindow = true; } From dbd156a272d6fcdc9d08734c92bf8864543bd2b3 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Tue, 21 Mar 2023 11:52:32 +0100 Subject: [PATCH 09/54] fix(GODT-2512): Catch unhandled API errors Bump GPA https://github.com/ProtonMail/go-proton-api/pull/63 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 678b6325..389b343d 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/Masterminds/semver/v3 v3.2.0 github.com/ProtonMail/gluon v0.15.1-0.20230321074233-2d09826346c1 github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a - github.com/ProtonMail/go-proton-api v0.4.1-0.20230314144605-dd633a1d4739 + github.com/ProtonMail/go-proton-api v0.4.1-0.20230321105122-1945ba8a46f9 github.com/ProtonMail/gopenpgp/v2 v2.5.2 github.com/PuerkitoBio/goquery v1.8.1 github.com/abiosoft/ishell v2.0.0+incompatible diff --git a/go.sum b/go.sum index c33dfd96..99e41542 100644 --- a/go.sum +++ b/go.sum @@ -40,8 +40,8 @@ github.com/ProtonMail/go-message v0.0.0-20210611055058-fabeff2ec753 h1:I8IsYA297 github.com/ProtonMail/go-message v0.0.0-20210611055058-fabeff2ec753/go.mod h1:NBAn21zgCJ/52WLDyed18YvYFm5tEoeDauubFqLokM4= github.com/ProtonMail/go-mime v0.0.0-20221031134845-8fd9bc37cf08 h1:dS7r5z4iGS0qCjM7UwWdsEMzQesUQbGcXdSm2/tWboA= github.com/ProtonMail/go-mime v0.0.0-20221031134845-8fd9bc37cf08/go.mod h1:qRZgbeASl2a9OwmsV85aWwRqic0NHPh+9ewGAzb4cgM= -github.com/ProtonMail/go-proton-api v0.4.1-0.20230314144605-dd633a1d4739 h1:sJhJQKQcG06mDcqikvLLnMuTz2rngcGTiTvOnc7lQbU= -github.com/ProtonMail/go-proton-api v0.4.1-0.20230314144605-dd633a1d4739/go.mod h1:4AXhqhB+AGVasVIlift9Lr1Btxg5S83xXPiyiT7mKUc= +github.com/ProtonMail/go-proton-api v0.4.1-0.20230321105122-1945ba8a46f9 h1:RyOYt/rc3hQtIKFUDJObah2g8wouIFVTorou5mmIHQI= +github.com/ProtonMail/go-proton-api v0.4.1-0.20230321105122-1945ba8a46f9/go.mod h1:4AXhqhB+AGVasVIlift9Lr1Btxg5S83xXPiyiT7mKUc= github.com/ProtonMail/go-srp v0.0.5 h1:xhUioxZgDbCnpo9JehyFhwwsn9JLWkUGfB0oiKXgiGg= github.com/ProtonMail/go-srp v0.0.5/go.mod h1:06iYHtLXW8vjLtccWj++x3MKy65sIT8yZd7nrJF49rs= github.com/ProtonMail/gopenpgp/v2 v2.5.2 h1:97SjlWNAxXl9P22lgwgrZRshQdiEfAht0g3ZoiA1GCw= From ee5e87fe854e09fdbf2bcdb5b2634991da3b31da Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Tue, 21 Mar 2023 14:37:20 +0100 Subject: [PATCH 10/54] test: Add 503 request test for message create event Simulate 503 status during a message create event when the message data is being downloaded. --- internal/bridge/user_event_test.go | 41 ++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/internal/bridge/user_event_test.go b/internal/bridge/user_event_test.go index c4404f0b..3f08afe8 100644 --- a/internal/bridge/user_event_test.go +++ b/internal/bridge/user_event_test.go @@ -765,6 +765,47 @@ func TestBridge_User_HandleParentLabelRename(t *testing.T) { }) } +func TestBridge503DuringEventDoesNotCauseBadEvent(t *testing.T) { + withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, storeKey []byte) { + // Create a user. + userID, addrID, err := s.CreateUser("user", password) + require.NoError(t, err) + + labelID, err := s.CreateLabel(userID, "folder", "", proton.LabelTypeFolder) + require.NoError(t, err) + + // Create 10 messages for the user. + withClient(ctx, t, s, "user", password, func(ctx context.Context, c *proton.Client) { + createNumMessages(ctx, t, c, addrID, labelID, 10) + }) + + withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) { + userLoginAndSync(ctx, t, bridge, "user", password) + + var messageIDs []string + + // Create 10 more messages for the user, generating events. + withClient(ctx, t, s, "user", password, func(ctx context.Context, c *proton.Client) { + messageIDs = createNumMessages(ctx, t, c, addrID, labelID, 10) + }) + + mocks.Reporter.EXPECT().ReportMessageWithContext(gomock.Any(), gomock.Any()).MinTimes(1) + + s.AddStatusHook(func(req *http.Request) (int, bool) { + if xslices.Index(xslices.Map(messageIDs[0:5], func(messageID string) string { + return "/mail/v4/messages/" + messageID + }), req.URL.Path) < 0 { + return 0, false + } + + return http.StatusServiceUnavailable, true + }) + + userContinueEventProcess(ctx, t, s, bridge) + }) + }) +} + // userLoginAndSync logs in user and waits until user is fully synced. func userLoginAndSync( ctx context.Context, From 4c94606e20c4ac9115e4da2fb4f164d710286a08 Mon Sep 17 00:00:00 2001 From: Xavier Michelon Date: Wed, 22 Mar 2023 09:10:26 +0100 Subject: [PATCH 11/54] fix(GODT-2516): log error when the vault key cannot be created/loaded from the keychain. Backported from release/perth-narrows. --- internal/app/vault.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/app/vault.go b/internal/app/vault.go index 55b583b1..af5e1238 100644 --- a/internal/app/vault.go +++ b/internal/app/vault.go @@ -80,6 +80,7 @@ func newVault(locations *locations.Locations) (*vault.Vault, bool, bool, error) ) if key, err := loadVaultKey(vaultDir); err != nil { + logrus.WithError(err).Error("Could not load/create vault key") insecure = true // We store the insecure vault in a separate directory From 58df3312c1ba3ea07d5a0d8bdda66875d9f96be0 Mon Sep 17 00:00:00 2001 From: James Houlahan Date: Mon, 20 Mar 2023 14:55:49 +0100 Subject: [PATCH 12/54] feat(GODT-2509): Migrate TLS cert from v1/v2 location during upgrade to v3 --- internal/app/migration.go | 27 +++++- internal/app/migration_test.go | 95 +++++++++++++------ .../with_keys/protonmail/bridge/cert.pem | 1 + .../with_keys/protonmail/bridge/key.pem | 1 + .../protonmail/bridge}/prefs.json | 0 .../without_keys/protonmail/bridge/prefs.json | 31 ++++++ internal/vault/certs.go | 8 ++ 7 files changed, 131 insertions(+), 32 deletions(-) create mode 100644 internal/app/testdata/with_keys/protonmail/bridge/cert.pem create mode 100644 internal/app/testdata/with_keys/protonmail/bridge/key.pem rename internal/app/testdata/{ => with_keys/protonmail/bridge}/prefs.json (100%) create mode 100644 internal/app/testdata/without_keys/protonmail/bridge/prefs.json diff --git a/internal/app/migration.go b/internal/app/migration.go index 4c440e6b..c5197ad9 100644 --- a/internal/app/migration.go +++ b/internal/app/migration.go @@ -87,6 +87,11 @@ func migrateOldSettings(v *vault.Vault) error { return fmt.Errorf("failed to get user config dir: %w", err) } + return migrateOldSettingsWithDir(configDir, v) +} + +// nolint:gosec +func migrateOldSettingsWithDir(configDir string, v *vault.Vault) error { b, err := os.ReadFile(filepath.Join(configDir, "protonmail", "bridge", "prefs.json")) if errors.Is(err, fs.ErrNotExist) { return nil @@ -94,7 +99,27 @@ func migrateOldSettings(v *vault.Vault) error { return fmt.Errorf("failed to read old prefs file: %w", err) } - return migratePrefsToVault(v, b) + if err := migratePrefsToVault(v, b); err != nil { + return fmt.Errorf("failed to migrate prefs to vault: %w", err) + } + + logrus.Info("Migrating TLS certificate") + + certPEM, err := os.ReadFile(filepath.Join(configDir, "protonmail", "bridge", "cert.pem")) + if errors.Is(err, fs.ErrNotExist) { + return nil + } else if err != nil { + return fmt.Errorf("failed to read old cert file: %w", err) + } + + keyPEM, err := os.ReadFile(filepath.Join(configDir, "protonmail", "bridge", "key.pem")) + if errors.Is(err, fs.ErrNotExist) { + return nil + } else if err != nil { + return fmt.Errorf("failed to read old key file: %w", err) + } + + return v.SetBridgeTLSCertKey(certPEM, keyPEM) } func migrateOldAccounts(locations *locations.Locations, v *vault.Vault) error { diff --git a/internal/app/migration_test.go b/internal/app/migration_test.go index fd0b41e1..02dff7e1 100644 --- a/internal/app/migration_test.go +++ b/internal/app/migration_test.go @@ -38,51 +38,49 @@ import ( "github.com/stretchr/testify/require" ) -func TestMigratePrefsToVault(t *testing.T) { +func TestMigratePrefsToVaultWithKeys(t *testing.T) { // Create a new vault. vault, corrupt, err := vault.New(t.TempDir(), t.TempDir(), []byte("my secret key")) require.NoError(t, err) require.False(t, corrupt) // load the old prefs file. - b, err := os.ReadFile(filepath.Join("testdata", "prefs.json")) - require.NoError(t, err) + configDir := filepath.Join("testdata", "with_keys") // Migrate the old prefs file to the new vault. - require.NoError(t, migratePrefsToVault(vault, b)) + require.NoError(t, migrateOldSettingsWithDir(configDir, vault)) - // Check that the IMAP and SMTP prefs are migrated. - require.Equal(t, 2143, vault.GetIMAPPort()) - require.Equal(t, 2025, vault.GetSMTPPort()) - require.True(t, vault.GetSMTPSSL()) + // Check Json Settings + validateJSONPrefs(t, vault) - // Check that the update channel is migrated. - require.True(t, vault.GetAutoUpdate()) - require.Equal(t, updater.EarlyChannel, vault.GetUpdateChannel()) - require.Equal(t, 0.4849529004202015, vault.GetUpdateRollout()) + cert, key := vault.GetBridgeTLSCert() + // Check the keys were found and collected. + require.Equal(t, "-----BEGIN CERTIFICATE-----", string(cert)) + require.Equal(t, "-----BEGIN RSA PRIVATE KEY-----", string(key)) +} - // Check that the app settings have been migrated. - require.False(t, vault.GetFirstStart()) - require.Equal(t, "blablabla", vault.GetColorScheme()) - require.Equal(t, "2.3.0+git", vault.GetLastVersion().String()) - require.True(t, vault.GetAutostart()) - - // Check that the other app settings have been migrated. - require.False(t, vault.GetProxyAllowed()) - require.False(t, vault.GetShowAllMail()) - - // Check that the cookies have been migrated. - jar, err := cookiejar.New(nil) +func TestMigratePrefsToVaultWithoutKeys(t *testing.T) { + // Create a new vault. + vault, corrupt, err := vault.New(t.TempDir(), t.TempDir(), []byte("my secret key")) require.NoError(t, err) + require.False(t, corrupt) - cookies, err := cookies.NewCookieJar(jar, vault) - require.NoError(t, err) + // load the old prefs file. + configDir := filepath.Join("testdata", "without_keys") - url, err := url.Parse("https://api.protonmail.ch") - require.NoError(t, err) + // Migrate the old prefs file to the new vault. + require.NoError(t, migrateOldSettingsWithDir(configDir, vault)) - // There should be a cookie for the API. - require.NotEmpty(t, cookies.Cookies(url)) + // Migrate the old prefs file to the new vault. + require.NoError(t, migrateOldSettingsWithDir(configDir, vault)) + + // Check Json Settings + validateJSONPrefs(t, vault) + + // Check the keys were found and collected. + cert, key := vault.GetBridgeTLSCert() + require.NotEqual(t, []byte("-----BEGIN CERTIFICATE-----"), cert) + require.NotEqual(t, []byte("-----BEGIN RSA PRIVATE KEY-----"), key) } func TestKeychainMigration(t *testing.T) { @@ -99,7 +97,7 @@ func TestKeychainMigration(t *testing.T) { oldCacheDir := filepath.Join(tmpDir, "protonmail", "bridge") require.NoError(t, os.MkdirAll(oldCacheDir, 0o700)) - oldPrefs, err := os.ReadFile(filepath.Join("testdata", "prefs.json")) + oldPrefs, err := os.ReadFile(filepath.Join("testdata", "without_keys", "protonmail", "bridge", "prefs.json")) require.NoError(t, err) require.NoError(t, os.WriteFile( @@ -194,3 +192,38 @@ func TestUserMigration(t *testing.T) { require.Equal(t, vault.CombinedMode, u.AddressMode()) })) } + +func validateJSONPrefs(t *testing.T, vault *vault.Vault) { + // Check that the IMAP and SMTP prefs are migrated. + require.Equal(t, 2143, vault.GetIMAPPort()) + require.Equal(t, 2025, vault.GetSMTPPort()) + require.True(t, vault.GetSMTPSSL()) + + // Check that the update channel is migrated. + require.True(t, vault.GetAutoUpdate()) + require.Equal(t, updater.EarlyChannel, vault.GetUpdateChannel()) + require.Equal(t, 0.4849529004202015, vault.GetUpdateRollout()) + + // Check that the app settings have been migrated. + require.False(t, vault.GetFirstStart()) + require.Equal(t, "blablabla", vault.GetColorScheme()) + require.Equal(t, "2.3.0+git", vault.GetLastVersion().String()) + require.True(t, vault.GetAutostart()) + + // Check that the other app settings have been migrated. + require.False(t, vault.GetProxyAllowed()) + require.False(t, vault.GetShowAllMail()) + + // Check that the cookies have been migrated. + jar, err := cookiejar.New(nil) + require.NoError(t, err) + + cookies, err := cookies.NewCookieJar(jar, vault) + require.NoError(t, err) + + url, err := url.Parse("https://api.protonmail.ch") + require.NoError(t, err) + + // There should be a cookie for the API. + require.NotEmpty(t, cookies.Cookies(url)) +} diff --git a/internal/app/testdata/with_keys/protonmail/bridge/cert.pem b/internal/app/testdata/with_keys/protonmail/bridge/cert.pem new file mode 100644 index 00000000..75f3c322 --- /dev/null +++ b/internal/app/testdata/with_keys/protonmail/bridge/cert.pem @@ -0,0 +1 @@ +-----BEGIN CERTIFICATE----- \ No newline at end of file diff --git a/internal/app/testdata/with_keys/protonmail/bridge/key.pem b/internal/app/testdata/with_keys/protonmail/bridge/key.pem new file mode 100644 index 00000000..f05debd2 --- /dev/null +++ b/internal/app/testdata/with_keys/protonmail/bridge/key.pem @@ -0,0 +1 @@ +-----BEGIN RSA PRIVATE KEY----- \ No newline at end of file diff --git a/internal/app/testdata/prefs.json b/internal/app/testdata/with_keys/protonmail/bridge/prefs.json similarity index 100% rename from internal/app/testdata/prefs.json rename to internal/app/testdata/with_keys/protonmail/bridge/prefs.json diff --git a/internal/app/testdata/without_keys/protonmail/bridge/prefs.json b/internal/app/testdata/without_keys/protonmail/bridge/prefs.json new file mode 100644 index 00000000..b6a16d46 --- /dev/null +++ b/internal/app/testdata/without_keys/protonmail/bridge/prefs.json @@ -0,0 +1,31 @@ +{ + "allow_proxy": "false", + "attachment_workers": "16", + "autostart": "true", + "autoupdate": "true", + "cache_compression": "true", + "cache_concurrent_read": "16", + "cache_concurrent_write": "16", + "cache_enabled": "true", + "cache_location": "/home/user/.config/protonmail/bridge/cache/c11/messages", + "cache_min_free_abs": "250000000", + "cache_min_free_rat": "", + "color_scheme": "blablabla", + "cookies": "{\"https://api.protonmail.ch\":[{\"Name\":\"Session-Id\",\"Value\":\"blablablablablablablablabla\",\"Path\":\"/\",\"Domain\":\"protonmail.ch\",\"Expires\":\"2023-02-19T00:20:40.269424437+01:00\",\"RawExpires\":\"\",\"MaxAge\":7776000,\"Secure\":true,\"HttpOnly\":true,\"SameSite\":0,\"Raw\":\"Session-Id=blablablablablablablablabla; Domain=protonmail.ch; Path=/; HttpOnly; Secure; Max-Age=7776000\",\"Unparsed\":null},{\"Name\":\"Tag\",\"Value\":\"default\",\"Path\":\"/\",\"Domain\":\"\",\"Expires\":\"2023-02-19T00:20:40.269428627+01:00\",\"RawExpires\":\"\",\"MaxAge\":7776000,\"Secure\":true,\"HttpOnly\":false,\"SameSite\":0,\"Raw\":\"Tag=default; Path=/; Secure; Max-Age=7776000\",\"Unparsed\":null}],\"https://protonmail.com\":[{\"Name\":\"Session-Id\",\"Value\":\"blablablablablablablablabla\",\"Path\":\"/\",\"Domain\":\"protonmail.com\",\"Expires\":\"2023-02-19T00:20:18.315084712+01:00\",\"RawExpires\":\"\",\"MaxAge\":7776000,\"Secure\":true,\"HttpOnly\":true,\"SameSite\":0,\"Raw\":\"Session-Id=Y3q2Mh-ClvqL6LWeYdfyPgAAABI; Domain=protonmail.com; Path=/; HttpOnly; Secure; Max-Age=7776000\",\"Unparsed\":null},{\"Name\":\"Tag\",\"Value\":\"redirect\",\"Path\":\"/\",\"Domain\":\"\",\"Expires\":\"2023-02-19T00:20:18.315087646+01:00\",\"RawExpires\":\"\",\"MaxAge\":7776000,\"Secure\":true,\"HttpOnly\":false,\"SameSite\":0,\"Raw\":\"Tag=redirect; Path=/; Secure; Max-Age=7776000\",\"Unparsed\":null}]}", + "fetch_workers": "16", + "first_time_start": "false", + "first_time_start_gui": "true", + "imap_workers": "16", + "is_all_mail_visible": "false", + "last_heartbeat": "325", + "last_used_version": "2.3.0+git", + "preferred_keychain": "secret-service", + "rebranding_migrated": "true", + "report_outgoing_email_without_encryption": "false", + "rollout": "0.4849529004202015", + "user_port_api": "1042", + "update_channel": "early", + "user_port_imap": "2143", + "user_port_smtp": "2025", + "user_ssl_smtp": "true" +} \ No newline at end of file diff --git a/internal/vault/certs.go b/internal/vault/certs.go index 75294293..24be5f38 100644 --- a/internal/vault/certs.go +++ b/internal/vault/certs.go @@ -53,6 +53,14 @@ func (vault *Vault) SetBridgeTLSCertPath(certPath, keyPath string) error { }) } +// SetBridgeTLSCertKey sets the path to PEM-encoded certificates for the bridge. +func (vault *Vault) SetBridgeTLSCertKey(cert, key []byte) error { + return vault.mod(func(data *Data) { + data.Certs.Bridge.Cert = cert + data.Certs.Bridge.Key = key + }) +} + func (vault *Vault) GetCertsInstalled() bool { return vault.get().Certs.Installed } From 74203e07a42930ace0391a341ef510e3599abb59 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Wed, 22 Mar 2023 13:19:15 +0100 Subject: [PATCH 13/54] fix(GODT-2513): Scanner Crash in Gluon Gluon MR: https://github.com/ProtonMail/gluon/pull/330 --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 389b343d..4f78c989 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/0xAX/notificator v0.0.0-20220220101646-ee9b8921e557 github.com/Masterminds/semver/v3 v3.2.0 - github.com/ProtonMail/gluon v0.15.1-0.20230321074233-2d09826346c1 + github.com/ProtonMail/gluon v0.15.1-0.20230322121010-574da2df3546 github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a github.com/ProtonMail/go-proton-api v0.4.1-0.20230321105122-1945ba8a46f9 github.com/ProtonMail/gopenpgp/v2 v2.5.2 diff --git a/go.sum b/go.sum index 99e41542..d8365eb1 100644 --- a/go.sum +++ b/go.sum @@ -30,6 +30,8 @@ github.com/ProtonMail/docker-credential-helpers v1.1.0 h1:+kvUIpwWcbtP3WFv5sSvkF github.com/ProtonMail/docker-credential-helpers v1.1.0/go.mod h1:mK0aBveCxhnQ756AmaTfXMZDeULvheYVhF/MWMErN5g= github.com/ProtonMail/gluon v0.15.1-0.20230321074233-2d09826346c1 h1:zVKqnKO/vTMrVw1dleGsj1JlY9jbhK890X0htvGCbjY= github.com/ProtonMail/gluon v0.15.1-0.20230321074233-2d09826346c1/go.mod h1:yA4hk6CJw0BMo+YL8Y3ckCYs5L20sysu9xseshwY3QI= +github.com/ProtonMail/gluon v0.15.1-0.20230322121010-574da2df3546 h1:eJ8gO99EjpuGoUDI0R2VZSzQ7SGPD0ggTbjJaA0xtzE= +github.com/ProtonMail/gluon v0.15.1-0.20230322121010-574da2df3546/go.mod h1:yA4hk6CJw0BMo+YL8Y3ckCYs5L20sysu9xseshwY3QI= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:D+aZah+k14Gn6kmL7eKxoo/4Dr/lK3ChBcwce2+SQP4= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4= github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= From f1fb525dc8cb8b37c3f703fc7f446f6a666dbc32 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Thu, 23 Mar 2023 13:39:20 +0100 Subject: [PATCH 14/54] fix(GODT-2504): Fix missing attachments in imported message https://github.com/ProtonMail/go-proton-api/pull/64 --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 4f78c989..d8a836cf 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/Masterminds/semver/v3 v3.2.0 github.com/ProtonMail/gluon v0.15.1-0.20230322121010-574da2df3546 github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a - github.com/ProtonMail/go-proton-api v0.4.1-0.20230321105122-1945ba8a46f9 + github.com/ProtonMail/go-proton-api v0.4.1-0.20230323120945-5a6ef5a2ecdd github.com/ProtonMail/gopenpgp/v2 v2.5.2 github.com/PuerkitoBio/goquery v1.8.1 github.com/abiosoft/ishell v2.0.0+incompatible diff --git a/go.sum b/go.sum index d8365eb1..0f43a368 100644 --- a/go.sum +++ b/go.sum @@ -44,6 +44,8 @@ github.com/ProtonMail/go-mime v0.0.0-20221031134845-8fd9bc37cf08 h1:dS7r5z4iGS0q github.com/ProtonMail/go-mime v0.0.0-20221031134845-8fd9bc37cf08/go.mod h1:qRZgbeASl2a9OwmsV85aWwRqic0NHPh+9ewGAzb4cgM= github.com/ProtonMail/go-proton-api v0.4.1-0.20230321105122-1945ba8a46f9 h1:RyOYt/rc3hQtIKFUDJObah2g8wouIFVTorou5mmIHQI= github.com/ProtonMail/go-proton-api v0.4.1-0.20230321105122-1945ba8a46f9/go.mod h1:4AXhqhB+AGVasVIlift9Lr1Btxg5S83xXPiyiT7mKUc= +github.com/ProtonMail/go-proton-api v0.4.1-0.20230323120945-5a6ef5a2ecdd h1:Y/XKWw0s7DDJn5R1lJmsREeGyumLcn/RDcvLozYnB88= +github.com/ProtonMail/go-proton-api v0.4.1-0.20230323120945-5a6ef5a2ecdd/go.mod h1:4AXhqhB+AGVasVIlift9Lr1Btxg5S83xXPiyiT7mKUc= github.com/ProtonMail/go-srp v0.0.5 h1:xhUioxZgDbCnpo9JehyFhwwsn9JLWkUGfB0oiKXgiGg= github.com/ProtonMail/go-srp v0.0.5/go.mod h1:06iYHtLXW8vjLtccWj++x3MKy65sIT8yZd7nrJF49rs= github.com/ProtonMail/gopenpgp/v2 v2.5.2 h1:97SjlWNAxXl9P22lgwgrZRshQdiEfAht0g3ZoiA1GCw= From ef1940d22747ece6e0064a7fc72bae50c6071d10 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Mon, 27 Mar 2023 08:31:47 +0200 Subject: [PATCH 15/54] fix(GODT-2508): Handle Address Updated for none-existing address If we receive an address update and the address does not exist, attempt to create it. --- go.mod | 2 +- go.sum | 4 ++++ internal/bridge/user_event_test.go | 18 ++++++++++++++++++ internal/user/events.go | 15 +++++++++++++-- 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index d8a836cf..931bbcc0 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/Masterminds/semver/v3 v3.2.0 github.com/ProtonMail/gluon v0.15.1-0.20230322121010-574da2df3546 github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a - github.com/ProtonMail/go-proton-api v0.4.1-0.20230323120945-5a6ef5a2ecdd + github.com/ProtonMail/go-proton-api v0.4.1-0.20230327062918-71c20587e0fc github.com/ProtonMail/gopenpgp/v2 v2.5.2 github.com/PuerkitoBio/goquery v1.8.1 github.com/abiosoft/ishell v2.0.0+incompatible diff --git a/go.sum b/go.sum index 0f43a368..c693df2c 100644 --- a/go.sum +++ b/go.sum @@ -46,6 +46,10 @@ github.com/ProtonMail/go-proton-api v0.4.1-0.20230321105122-1945ba8a46f9 h1:RyOY github.com/ProtonMail/go-proton-api v0.4.1-0.20230321105122-1945ba8a46f9/go.mod h1:4AXhqhB+AGVasVIlift9Lr1Btxg5S83xXPiyiT7mKUc= github.com/ProtonMail/go-proton-api v0.4.1-0.20230323120945-5a6ef5a2ecdd h1:Y/XKWw0s7DDJn5R1lJmsREeGyumLcn/RDcvLozYnB88= github.com/ProtonMail/go-proton-api v0.4.1-0.20230323120945-5a6ef5a2ecdd/go.mod h1:4AXhqhB+AGVasVIlift9Lr1Btxg5S83xXPiyiT7mKUc= +github.com/ProtonMail/go-proton-api v0.4.1-0.20230324123811-83e98cb35c9a h1:sKcw8YlNxqO9iDDYdbZNVUCqk6Ta6liyfFBUR0Lai7o= +github.com/ProtonMail/go-proton-api v0.4.1-0.20230324123811-83e98cb35c9a/go.mod h1:4AXhqhB+AGVasVIlift9Lr1Btxg5S83xXPiyiT7mKUc= +github.com/ProtonMail/go-proton-api v0.4.1-0.20230327062918-71c20587e0fc h1:D0F4mxNVwIzYcjt8SEuIh4EzJhWgWw1f4eNc1iWrXnQ= +github.com/ProtonMail/go-proton-api v0.4.1-0.20230327062918-71c20587e0fc/go.mod h1:4AXhqhB+AGVasVIlift9Lr1Btxg5S83xXPiyiT7mKUc= github.com/ProtonMail/go-srp v0.0.5 h1:xhUioxZgDbCnpo9JehyFhwwsn9JLWkUGfB0oiKXgiGg= github.com/ProtonMail/go-srp v0.0.5/go.mod h1:06iYHtLXW8vjLtccWj++x3MKy65sIT8yZd7nrJF49rs= github.com/ProtonMail/gopenpgp/v2 v2.5.2 h1:97SjlWNAxXl9P22lgwgrZRshQdiEfAht0g3ZoiA1GCw= diff --git a/internal/bridge/user_event_test.go b/internal/bridge/user_event_test.go index 3f08afe8..a80592d3 100644 --- a/internal/bridge/user_event_test.go +++ b/internal/bridge/user_event_test.go @@ -329,6 +329,24 @@ func TestBridge_User_AddressEvents_NoBadEvent(t *testing.T) { }) } +func TestBridge_User_AddressEventUpdatedForAddressThatDoesNotExist_NoBadEvent(t *testing.T) { + withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, storeKey []byte) { + // Create a user. + userID, _, err := s.CreateUser("user", password) + require.NoError(t, err) + + withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, _ *bridge.Mocks) { + userLoginAndSync(ctx, t, bridge, "user", password) + }) + + withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, _ *bridge.Mocks) { + _, err := s.CreateAddressAsUpdate(userID, "another@pm.me", password) + require.NoError(t, err) + userContinueEventProcess(ctx, t, s, bridge) + }) + }) +} + func TestBridge_User_Network_NoBadEvents(t *testing.T) { withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, storeKey []byte) { retVal := int32(0) diff --git a/internal/user/events.go b/internal/user/events.go index 72131a3b..f980454a 100644 --- a/internal/user/events.go +++ b/internal/user/events.go @@ -170,6 +170,16 @@ func (user *User) handleAddressEvents(ctx context.Context, addressEvents []proto case proton.EventUpdate, proton.EventUpdateFlags: if err := user.handleUpdateAddressEvent(ctx, event); err != nil { + if errors.Is(err, ErrAddressDoesNotExist) { + logrus.Debugf("Address %v does not exist, will try create instead", event.Address.ID) + if createErr := user.handleCreateAddressEvent(ctx, event); createErr != nil { + user.reportError("Failed to apply address update event (with create)", createErr) + return fmt.Errorf("failed to handle update address event (with create): %w", createErr) + } + + return nil + } + user.reportError("Failed to apply address update event", err) return fmt.Errorf("failed to handle update address event: %w", err) } @@ -245,6 +255,8 @@ func (user *User) handleCreateAddressEvent(ctx context.Context, event proton.Add }, user.apiAddrsLock, user.apiLabelsLock, user.updateChLock) } +var ErrAddressDoesNotExist = errors.New("address does not exist") + func (user *User) handleUpdateAddressEvent(_ context.Context, event proton.AddressEvent) error { //nolint:unparam return safe.LockRet(func() error { user.log.WithFields(logrus.Fields{ @@ -254,8 +266,7 @@ func (user *User) handleUpdateAddressEvent(_ context.Context, event proton.Addre oldAddr, ok := user.apiAddrs[event.Address.ID] if !ok { - user.log.Debugf("Address %q does not exist", event.Address.ID) - return nil + return ErrAddressDoesNotExist } user.apiAddrs[event.Address.ID] = event.Address From 421da99cd881e86d2d3bdcff5d7bca7de86a09a3 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Mon, 27 Mar 2023 09:44:51 +0200 Subject: [PATCH 16/54] fix(GODT-2524): Preserve old vault values Keep the record of old vault settings alive to avoid issues when one downgrades from a 3.1 release to a 3.0.x release. --- internal/vault/types_settings.go | 21 +++++++++++++++++++++ internal/vault/types_user.go | 6 ++++++ 2 files changed, 27 insertions(+) diff --git a/internal/vault/types_settings.go b/internal/vault/types_settings.go index bb6946a3..8f83423f 100644 --- a/internal/vault/types_settings.go +++ b/internal/vault/types_settings.go @@ -19,6 +19,7 @@ package vault import ( "math/rand" + "runtime" "github.com/ProtonMail/proton-bridge/v3/internal/updater" ) @@ -44,11 +45,29 @@ type Settings struct { FirstStart bool MaxSyncMemory uint64 + + // **WARNING**: These entry can't be removed until they vault has proper migration support. + SyncWorkers int + SyncAttPool int } const DefaultMaxSyncMemory = 2 * 1024 * uint64(1024*1024) +func GetDefaultSyncWorkerCount() int { + const minSyncWorkers = 16 + + syncWorkers := runtime.NumCPU() * 4 + + if syncWorkers < minSyncWorkers { + syncWorkers = minSyncWorkers + } + + return syncWorkers +} + func newDefaultSettings(gluonDir string) Settings { + syncWorkers := GetDefaultSyncWorkerCount() + return Settings{ GluonDir: gluonDir, @@ -70,5 +89,7 @@ func newDefaultSettings(gluonDir string) Settings { FirstStart: true, MaxSyncMemory: DefaultMaxSyncMemory, + SyncWorkers: syncWorkers, + SyncAttPool: syncWorkers, } } diff --git a/internal/vault/types_user.go b/internal/vault/types_user.go index af1958e3..a41085fb 100644 --- a/internal/vault/types_user.go +++ b/internal/vault/types_user.go @@ -17,6 +17,8 @@ package vault +import "github.com/ProtonMail/gluon/imap" + // UserData holds information about a single bridge user. // The user may or may not be logged in. type UserData struct { @@ -35,6 +37,9 @@ type UserData struct { SyncStatus SyncStatus EventID string + + // **WARNING**: This value can't be removed until we have vault migration support. + UIDValidity map[string]imap.UID } type AddressMode int @@ -76,6 +81,7 @@ func newDefaultUser(userID, username, primaryEmail, authUID, authRef string, key GluonKey: newRandomToken(32), GluonIDs: make(map[string]string), + UIDValidity: make(map[string]imap.UID), BridgePass: newRandomToken(16), AddressMode: CombinedMode, From 7124e7c9a0b6b2f37ba479e6ed704aa59ba69766 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Mon, 27 Mar 2023 16:07:54 +0200 Subject: [PATCH 17/54] fix(GODT-2514): Apply Retry-After to 503 https://github.com/ProtonMail/go-proton-api/pull/67 --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 931bbcc0..2f7d8c93 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/Masterminds/semver/v3 v3.2.0 github.com/ProtonMail/gluon v0.15.1-0.20230322121010-574da2df3546 github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a - github.com/ProtonMail/go-proton-api v0.4.1-0.20230327062918-71c20587e0fc + github.com/ProtonMail/go-proton-api v0.4.1-0.20230327135835-2751384cef6f github.com/ProtonMail/gopenpgp/v2 v2.5.2 github.com/PuerkitoBio/goquery v1.8.1 github.com/abiosoft/ishell v2.0.0+incompatible diff --git a/go.sum b/go.sum index c693df2c..909d47fe 100644 --- a/go.sum +++ b/go.sum @@ -50,6 +50,8 @@ github.com/ProtonMail/go-proton-api v0.4.1-0.20230324123811-83e98cb35c9a h1:sKcw github.com/ProtonMail/go-proton-api v0.4.1-0.20230324123811-83e98cb35c9a/go.mod h1:4AXhqhB+AGVasVIlift9Lr1Btxg5S83xXPiyiT7mKUc= github.com/ProtonMail/go-proton-api v0.4.1-0.20230327062918-71c20587e0fc h1:D0F4mxNVwIzYcjt8SEuIh4EzJhWgWw1f4eNc1iWrXnQ= github.com/ProtonMail/go-proton-api v0.4.1-0.20230327062918-71c20587e0fc/go.mod h1:4AXhqhB+AGVasVIlift9Lr1Btxg5S83xXPiyiT7mKUc= +github.com/ProtonMail/go-proton-api v0.4.1-0.20230327135835-2751384cef6f h1:lqf3DlFQMvfDi7zGVKTlciyxXfvkoi6CCISu9nx8nak= +github.com/ProtonMail/go-proton-api v0.4.1-0.20230327135835-2751384cef6f/go.mod h1:4AXhqhB+AGVasVIlift9Lr1Btxg5S83xXPiyiT7mKUc= github.com/ProtonMail/go-srp v0.0.5 h1:xhUioxZgDbCnpo9JehyFhwwsn9JLWkUGfB0oiKXgiGg= github.com/ProtonMail/go-srp v0.0.5/go.mod h1:06iYHtLXW8vjLtccWj++x3MKy65sIT8yZd7nrJF49rs= github.com/ProtonMail/gopenpgp/v2 v2.5.2 h1:97SjlWNAxXl9P22lgwgrZRshQdiEfAht0g3ZoiA1GCw= From aa957f3314a1e49b7ef76c1433e3438151666fd1 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Tue, 28 Mar 2023 14:25:32 +0200 Subject: [PATCH 18/54] test: Disable TestBridge503DuringEventDoesNotCauseBadEvent Changes to GPA 503 handling is now causing GPA client to treat this as context cancelled rather than producing 503. To be re-enabled as part of GODT-2527. --- internal/bridge/user_event_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/bridge/user_event_test.go b/internal/bridge/user_event_test.go index a80592d3..f3e4b64d 100644 --- a/internal/bridge/user_event_test.go +++ b/internal/bridge/user_event_test.go @@ -783,7 +783,8 @@ func TestBridge_User_HandleParentLabelRename(t *testing.T) { }) } -func TestBridge503DuringEventDoesNotCauseBadEvent(t *testing.T) { +// TBD: GODT-2527. +func _TestBridge503DuringEventDoesNotCauseBadEvent(t *testing.T) { //nolint:unused,deadcode withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, storeKey []byte) { // Create a user. userID, addrID, err := s.CreateUser("user", password) From 86fd7961a19ab66c9a54d39f289660bde7e4a955 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Wed, 29 Mar 2023 14:49:36 +0200 Subject: [PATCH 19/54] fix(GODT-2526): Fix high memory usage with fetch/search https://github.com/ProtonMail/gluon/pull/333 --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 2f7d8c93..8e93ee44 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/0xAX/notificator v0.0.0-20220220101646-ee9b8921e557 github.com/Masterminds/semver/v3 v3.2.0 - github.com/ProtonMail/gluon v0.15.1-0.20230322121010-574da2df3546 + github.com/ProtonMail/gluon v0.15.1-0.20230329124608-19b8f7b4e7b0 github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a github.com/ProtonMail/go-proton-api v0.4.1-0.20230327135835-2751384cef6f github.com/ProtonMail/gopenpgp/v2 v2.5.2 diff --git a/go.sum b/go.sum index 909d47fe..3d09459d 100644 --- a/go.sum +++ b/go.sum @@ -32,6 +32,8 @@ github.com/ProtonMail/gluon v0.15.1-0.20230321074233-2d09826346c1 h1:zVKqnKO/vTM github.com/ProtonMail/gluon v0.15.1-0.20230321074233-2d09826346c1/go.mod h1:yA4hk6CJw0BMo+YL8Y3ckCYs5L20sysu9xseshwY3QI= github.com/ProtonMail/gluon v0.15.1-0.20230322121010-574da2df3546 h1:eJ8gO99EjpuGoUDI0R2VZSzQ7SGPD0ggTbjJaA0xtzE= github.com/ProtonMail/gluon v0.15.1-0.20230322121010-574da2df3546/go.mod h1:yA4hk6CJw0BMo+YL8Y3ckCYs5L20sysu9xseshwY3QI= +github.com/ProtonMail/gluon v0.15.1-0.20230329124608-19b8f7b4e7b0 h1:FASrdEaNRJSHFjrOZ5WO4CKuYZb2zoCyFNqplrsZmOQ= +github.com/ProtonMail/gluon v0.15.1-0.20230329124608-19b8f7b4e7b0/go.mod h1:yA4hk6CJw0BMo+YL8Y3ckCYs5L20sysu9xseshwY3QI= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:D+aZah+k14Gn6kmL7eKxoo/4Dr/lK3ChBcwce2+SQP4= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4= github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= From 0a53dc1da79fc61a873ca78b5c1faf3260438610 Mon Sep 17 00:00:00 2001 From: Xavier Michelon Date: Thu, 23 Mar 2023 16:55:35 +0100 Subject: [PATCH 20/54] feat(GODT-2523): use software QML rendering backend by default on Windows. (cherry picked from commit 934749b278e95a9d69818ddf6b45ee7bb896af03) (cherry picked from commit 7448b814e8e6da90335b8db465fd64e3d4f08bdd) --- internal/frontend/bridge-gui/bridge-gui/Settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/frontend/bridge-gui/bridge-gui/Settings.cpp b/internal/frontend/bridge-gui/bridge-gui/Settings.cpp index e7acb259..270ac1dd 100644 --- a/internal/frontend/bridge-gui/bridge-gui/Settings.cpp +++ b/internal/frontend/bridge-gui/bridge-gui/Settings.cpp @@ -44,7 +44,7 @@ Settings::Settings() /// \return The value for the 'Use software renderer' setting. //**************************************************************************************************************************************************** bool Settings::useSoftwareRenderer() const { - return settings_.value(keyUseSoftwareRenderer, false).toBool(); + return settings_.value(keyUseSoftwareRenderer, onWindows()).toBool(); } From 132322936204e2e2c3db0a302086ab80267a77d6 Mon Sep 17 00:00:00 2001 From: Xavier Michelon Date: Mon, 3 Apr 2023 15:18:16 +0200 Subject: [PATCH 21/54] feat(GODT-2239): introduce GoogleTest unit tests for bridgepp. --- .../bridge-gui/bridgepp/CMakeLists.txt | 35 +++++++ .../bridgepp/Test/Exception/TestException.cpp | 95 +++++++++++++++++++ .../bridgepp/bridgepp/BridgeUtils.h | 2 +- .../bridgepp/bridgepp/Exception/Exception.cpp | 9 ++ .../bridgepp/bridgepp/Exception/Exception.h | 1 + .../bridgepp/bridgepp/Log/LogUtils.cpp | 4 +- 6 files changed, 143 insertions(+), 3 deletions(-) create mode 100644 internal/frontend/bridge-gui/bridgepp/Test/Exception/TestException.cpp diff --git a/internal/frontend/bridge-gui/bridgepp/CMakeLists.txt b/internal/frontend/bridge-gui/bridgepp/CMakeLists.txt index af03519a..12df7a85 100644 --- a/internal/frontend/bridge-gui/bridgepp/CMakeLists.txt +++ b/internal/frontend/bridge-gui/bridgepp/CMakeLists.txt @@ -160,3 +160,38 @@ target_link_libraries(bridgepp ) target_precompile_headers(bridgepp PRIVATE Pch.h) + +#***************************************************************************************************************************************************** +# GoogleTest +#***************************************************************************************************************************************************** + +if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.24.0") + cmake_policy(SET CMP0135 NEW) # avoid warning DOWNLOAD_EXTRACT_TIMESTAMP +endif() + +include(FetchContent) +FetchContent_Declare( + googletest + URL https://github.com/google/googletest/archive/b796f7d44681514f58a683a3a71ff17c94edb0c1.zip +) + +# For Windows: Prevent overriding the parent project's compiler/linker settings +set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) + +FetchContent_MakeAvailable(googletest) + +enable_testing() + +#***************************************************************************************************************************************************** +# Tests +#***************************************************************************************************************************************************** +add_executable(bridgepp-test Test/Exception/TestException.cpp) +add_dependencies(bridgepp-test bridgepp) +target_precompile_headers(bridgepp-test PRIVATE Pch.h) +target_link_libraries(bridgepp-test + GTest::gtest_main + bridgepp + ) + +include(GoogleTest) +gtest_discover_tests(bridgepp-test) diff --git a/internal/frontend/bridge-gui/bridgepp/Test/Exception/TestException.cpp b/internal/frontend/bridge-gui/bridgepp/Test/Exception/TestException.cpp new file mode 100644 index 00000000..9c006f56 --- /dev/null +++ b/internal/frontend/bridge-gui/bridgepp/Test/Exception/TestException.cpp @@ -0,0 +1,95 @@ +// Copyright (c) 2023 Proton AG +// +// This file is part of Proton Mail 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 . + +#include +#include + + +using namespace bridgepp; + + +namespace { + QString const testQWhat = "What"; + QString const testDetails = "Some details"; + QString const testFunction = "function"; + QByteArray const testAttachment = QString("Some data").toLocal8Bit(); + Exception const testException(testQWhat, testDetails, testFunction, testAttachment); +} + + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +TEST(Exceptions, ExceptionConstructor) { + // Default exception + Exception const emptyException; + EXPECT_TRUE(emptyException.qwhat().isEmpty()); + EXPECT_EQ(strlen(emptyException.what()), 0); + EXPECT_EQ(emptyException.attachment().size(), 0); + EXPECT_TRUE(emptyException.details().isEmpty()); + EXPECT_TRUE(emptyException.detailedWhat().isEmpty()); + + // Fully detailed exception + EXPECT_EQ(testException.qwhat(), testQWhat); + EXPECT_EQ(QString::fromLocal8Bit(testException.what()), testQWhat); + EXPECT_EQ(testException.details(), testDetails); + EXPECT_EQ(testException.attachment(), testAttachment); + QString const detailed = testException.detailedWhat(); + EXPECT_TRUE(detailed.contains(testQWhat)); + EXPECT_TRUE(detailed.contains(testFunction)); + EXPECT_TRUE(detailed.contains(testDetails)); +} + + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +TEST(Exceptions, ExceptionCopyMoveConstructors) { + Exception const e(testQWhat, testDetails, testFunction, testAttachment); + + // Check copy-constructor + Exception eCopied(e); + EXPECT_EQ(eCopied.qwhat(), testQWhat); + EXPECT_EQ(eCopied.details(), testDetails); + EXPECT_EQ(eCopied.function(), testFunction); + EXPECT_EQ(eCopied.attachment(), testAttachment); + + // Check move-constructor + Exception eMoved(std::move(eCopied)); + EXPECT_EQ(eMoved.qwhat(), testQWhat); + EXPECT_EQ(eMoved.details(), testDetails); + EXPECT_EQ(eMoved.function(), testFunction); + EXPECT_EQ(eMoved.attachment(), testAttachment); +} + + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +TEST(Exceptions, ExceptionThrow) { + std::function t = []() { throw testException; }; + EXPECT_THROW(t(), Exception); + EXPECT_THROW(t(), std::exception); + bool caught = false; + try { + t(); + } catch (Exception const &e) { + caught = true; + EXPECT_EQ(e.detailedWhat(), testException.detailedWhat()); + } + EXPECT_TRUE(caught); +} diff --git a/internal/frontend/bridge-gui/bridgepp/bridgepp/BridgeUtils.h b/internal/frontend/bridge-gui/bridgepp/bridgepp/BridgeUtils.h index 280a0de9..1ca92901 100644 --- a/internal/frontend/bridge-gui/bridgepp/bridgepp/BridgeUtils.h +++ b/internal/frontend/bridge-gui/bridgepp/bridgepp/BridgeUtils.h @@ -20,7 +20,7 @@ #define BRIDGE_PP_TESTER_BRIDGE_UTILS_H -#include +#include "User/User.h" namespace bridgepp { diff --git a/internal/frontend/bridge-gui/bridgepp/bridgepp/Exception/Exception.cpp b/internal/frontend/bridge-gui/bridgepp/bridgepp/Exception/Exception.cpp index dc614b88..db43cac0 100644 --- a/internal/frontend/bridge-gui/bridgepp/bridgepp/Exception/Exception.cpp +++ b/internal/frontend/bridge-gui/bridgepp/bridgepp/Exception/Exception.cpp @@ -87,6 +87,14 @@ QString Exception::details() const noexcept { } +//**************************************************************************************************************************************************** +/// \return The function that threw the exception. +//**************************************************************************************************************************************************** +QString Exception::function() const noexcept { + return function_; +} + + //**************************************************************************************************************************************************** /// \return The attachment for the exception. //**************************************************************************************************************************************************** @@ -109,4 +117,5 @@ QString Exception::detailedWhat() const { return result; } + } // namespace bridgepp diff --git a/internal/frontend/bridge-gui/bridgepp/bridgepp/Exception/Exception.h b/internal/frontend/bridge-gui/bridgepp/bridgepp/Exception/Exception.h index 21a1689d..3b78821f 100644 --- a/internal/frontend/bridge-gui/bridgepp/bridgepp/Exception/Exception.h +++ b/internal/frontend/bridge-gui/bridgepp/bridgepp/Exception/Exception.h @@ -42,6 +42,7 @@ public: // member functions QString qwhat() const noexcept; ///< Return the description of the exception as a QString const char *what() const noexcept override; ///< Return the description of the exception as C style string QString details() const noexcept; ///< Return the details for the exception + QString function() const noexcept; ///< Return the function that threw the exception. QByteArray attachment() const noexcept; ///< Return the attachment for the exception. QString detailedWhat() const; ///< Return the detailed description of the message (i.e. including the function name and the details). diff --git a/internal/frontend/bridge-gui/bridgepp/bridgepp/Log/LogUtils.cpp b/internal/frontend/bridge-gui/bridgepp/bridgepp/Log/LogUtils.cpp index ee3780b2..eb825792 100644 --- a/internal/frontend/bridge-gui/bridgepp/bridgepp/Log/LogUtils.cpp +++ b/internal/frontend/bridge-gui/bridgepp/bridgepp/Log/LogUtils.cpp @@ -17,8 +17,8 @@ #include "LogUtils.h" -#include -#include +#include "../BridgeUtils.h" +#include "../Exception/Exception.h" namespace bridgepp { From 3735d4b32746500ad26296ad12ac8ec349fddade Mon Sep 17 00:00:00 2001 From: Xavier Michelon Date: Wed, 5 Apr 2023 10:13:49 +0200 Subject: [PATCH 22/54] feat(GODT-2239): unit tests for BridgeUtils.cpp in bridgepp. --- .../bridge-gui/bridgepp/CMakeLists.txt | 5 +- .../Test/Exception/TestBridgeUtils.cpp | 111 ++++++++++++++++++ 2 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 internal/frontend/bridge-gui/bridgepp/Test/Exception/TestBridgeUtils.cpp diff --git a/internal/frontend/bridge-gui/bridgepp/CMakeLists.txt b/internal/frontend/bridge-gui/bridgepp/CMakeLists.txt index 12df7a85..9c5eb38f 100644 --- a/internal/frontend/bridge-gui/bridgepp/CMakeLists.txt +++ b/internal/frontend/bridge-gui/bridgepp/CMakeLists.txt @@ -185,7 +185,10 @@ enable_testing() #***************************************************************************************************************************************************** # Tests #***************************************************************************************************************************************************** -add_executable(bridgepp-test Test/Exception/TestException.cpp) +add_executable(bridgepp-test + Test/Exception/TestBridgeUtils.cpp + Test/Exception/TestException.cpp + ) add_dependencies(bridgepp-test bridgepp) target_precompile_headers(bridgepp-test PRIVATE Pch.h) target_link_libraries(bridgepp-test diff --git a/internal/frontend/bridge-gui/bridgepp/Test/Exception/TestBridgeUtils.cpp b/internal/frontend/bridge-gui/bridgepp/Test/Exception/TestBridgeUtils.cpp new file mode 100644 index 00000000..a990eb66 --- /dev/null +++ b/internal/frontend/bridge-gui/bridgepp/Test/Exception/TestBridgeUtils.cpp @@ -0,0 +1,111 @@ +// Copyright (c) 2023 Proton AG +// +// This file is part of Proton Mail 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 . + + +#include +#include + + +using namespace bridgepp; + + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +TEST(BridgeUtils, OS) { +#ifdef Q_OS_MACOS + EXPECT_EQ(os(), OS::MacOS); + EXPECT_FALSE(onLinux()); + EXPECT_TRUE(onMacOS()); + EXPECT_FALSE(onWindows()); + EXPECT_EQ(goos(), "darwin"); + return; +#endif + +#ifdef Q_OS_WIN + EXPECT_EQ(os(), OS::Windows); + EXPECT_FALSE(onLinux()); + EXPECT_FALSE(onMacOS()); + EXPECT_TRUE(onWindows()); + EXPECT_EQ(goos(), "windows"); + return; +#endif + +#ifdef Q_OS_LINUX + EXPECT_EQ(os(), OS::Linux); + EXPECT_TRUE(onLinux()); + EXPECT_FALSE(onMacOS()); + EXPECT_FALSE(onWindows()); + EXPECT_EQ(goos(), "linux"); + return; +#endif + + EXPECT_TRUE(false); // should be unreachable. +} + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +TEST(BridgeUtils, UserFolders) { + typedef QString (*dirFunction)(); + QList functions = { userConfigDir, userCacheDir, userDataDir, sentryCacheDir }; + QString path; + for (dirFunction f: functions) { + EXPECT_NO_THROW(path = f()); + EXPECT_FALSE(path.isEmpty()); + EXPECT_TRUE(QDir(path).exists()); + } +} + + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +TEST(BridgeUtils, Random) { + qint32 repeatCount = 1000; + qint32 const maxValue = 5; + for (qint32 i = 0; i < repeatCount; ++i) { + qint64 n = 0; + EXPECT_NO_THROW(n = randN(maxValue)); + EXPECT_TRUE((n >= 0) && (n < maxValue)); + QString name; + EXPECT_NO_THROW(name = randomFirstName()); + EXPECT_FALSE(name.isEmpty()); + EXPECT_NO_THROW(name = randomLastName()); + EXPECT_FALSE(name.isEmpty()); + EXPECT_NO_THROW(randomUser()); + } +} + + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +TEST(BridgeUtils, ElideLongString) { + std::function const test = [](QString const &input, qint32 maxLength, QString const &expected) -> bool { + QString output; + EXPECT_NO_THROW(output = elideLongString(input, maxLength)); + return output == expected; + }; + + EXPECT_TRUE(test( "", 0, "")); + EXPECT_TRUE(test("1234", 4, "1234")); + EXPECT_TRUE(test("123", 2, "...")); + EXPECT_TRUE(test("1234567890", 8, "12...90")); + EXPECT_TRUE(test("1234567890", 10, "1234567890")); + EXPECT_TRUE(test("1234567890", 100, "1234567890")); +} From a8cb0012e1e65ddf5e3d991679803d4703a2a138 Mon Sep 17 00:00:00 2001 From: Gjorgji Slamkov Date: Tue, 28 Mar 2023 17:55:19 +0200 Subject: [PATCH 23/54] test: add missing double quotes in test During integration test training, it was noticed that double-quotes were missing after a specific regex. Added them both in the *.feature and bdd_test.go files where applicable. --- tests/bdd_test.go | 2 +- tests/features/imap/message/drafts.feature | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/bdd_test.go b/tests/bdd_test.go index f67caa70..125cb656 100644 --- a/tests/bdd_test.go +++ b/tests/bdd_test.go @@ -121,7 +121,7 @@ func TestFeatures(testingT *testing.T) { ctx.Step(`^the address "([^"]*)" of account "([^"]*)" has the following messages in "([^"]*)":$`, s.theAddressOfAccountHasTheFollowingMessagesInMailbox) ctx.Step(`^the address "([^"]*)" of account "([^"]*)" has (\d+) messages in "([^"]*)"$`, s.theAddressOfAccountHasMessagesInMailbox) ctx.Step(`^the following fields were changed in draft (\d+) for address "([^"]*)" of account "([^"]*)":$`, s.theFollowingFieldsWereChangedInDraftForAddressOfAccount) - ctx.Step(`^draft (\d+) for address "([^"]*)" of account "([^"]*) was moved to trash$`, s.drafAtIndexWasMovedToTrashForAddressOfAccount) + ctx.Step(`^draft (\d+) for address "([^"]*)" of account "([^"]*)" was moved to trash$`, s.drafAtIndexWasMovedToTrashForAddressOfAccount) // === REPORTER === ctx.Step(`^test skips reporter checks$`, s.skipReporterChecks) diff --git a/tests/features/imap/message/drafts.feature b/tests/features/imap/message/drafts.feature index 6f185418..e4644d43 100644 --- a/tests/features/imap/message/drafts.feature +++ b/tests/features/imap/message/drafts.feature @@ -45,7 +45,7 @@ Feature: IMAP Draft messages And IMAP client "1" eventually sees 1 messages in "Drafts" Scenario: Draft moved to trash remotely - When draft 1 for address "[user:user]@[domain]" of account "[user:user] was moved to trash + When draft 1 for address "[user:user]@[domain]" of account "[user:user]" was moved to trash Then IMAP client "1" eventually sees the following messages in "Trash": | body | | This is a dra | From c7ae2393508ba25ce5040fd16cf9cebc0f91a562 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Wed, 12 Apr 2023 10:14:43 +0200 Subject: [PATCH 24/54] fix(GODT-2573): Handle invalid header fields in message Requires updating Gluon and GPA https://github.com/ProtonMail/gluon/pull/336 https://github.com/ProtonMail/go-proton-api/pull/74 --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index bf6d139b..032ad293 100644 --- a/go.mod +++ b/go.mod @@ -5,9 +5,9 @@ go 1.18 require ( github.com/0xAX/notificator v0.0.0-20220220101646-ee9b8921e557 github.com/Masterminds/semver/v3 v3.2.0 - github.com/ProtonMail/gluon v0.15.1-0.20230406114115-7eae5cb3ec21 + github.com/ProtonMail/gluon v0.16.0 github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a - github.com/ProtonMail/go-proton-api v0.4.1-0.20230406143739-c7596e170799 + github.com/ProtonMail/go-proton-api v0.4.1-0.20230412081244-5a5a86b435ab github.com/ProtonMail/gopenpgp/v2 v2.5.2 github.com/PuerkitoBio/goquery v1.8.1 github.com/abiosoft/ishell v2.0.0+incompatible diff --git a/go.sum b/go.sum index ac09618d..07d08fa2 100644 --- a/go.sum +++ b/go.sum @@ -28,8 +28,8 @@ github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf h1:yc9daCCYUefEs github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf/go.mod h1:o0ESU9p83twszAU8LBeJKFAAMX14tISa0yk4Oo5TOqo= github.com/ProtonMail/docker-credential-helpers v1.1.0 h1:+kvUIpwWcbtP3WFv5sSvkFn/XLzSqPOB5AAthuk9xPk= github.com/ProtonMail/docker-credential-helpers v1.1.0/go.mod h1:mK0aBveCxhnQ756AmaTfXMZDeULvheYVhF/MWMErN5g= -github.com/ProtonMail/gluon v0.15.1-0.20230406114115-7eae5cb3ec21 h1:wucP8WmL9iT8TMw32HaUH0dcYFdNBNnQML5JJNy5yn4= -github.com/ProtonMail/gluon v0.15.1-0.20230406114115-7eae5cb3ec21/go.mod h1:yA4hk6CJw0BMo+YL8Y3ckCYs5L20sysu9xseshwY3QI= +github.com/ProtonMail/gluon v0.16.0 h1:zFUAJoZmcTo2xQ5ipWx6UPweCTm+OiR24dJFLUSgtp8= +github.com/ProtonMail/gluon v0.16.0/go.mod h1:yA4hk6CJw0BMo+YL8Y3ckCYs5L20sysu9xseshwY3QI= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:D+aZah+k14Gn6kmL7eKxoo/4Dr/lK3ChBcwce2+SQP4= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4= github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= @@ -40,8 +40,8 @@ github.com/ProtonMail/go-message v0.0.0-20210611055058-fabeff2ec753 h1:I8IsYA297 github.com/ProtonMail/go-message v0.0.0-20210611055058-fabeff2ec753/go.mod h1:NBAn21zgCJ/52WLDyed18YvYFm5tEoeDauubFqLokM4= github.com/ProtonMail/go-mime v0.0.0-20221031134845-8fd9bc37cf08 h1:dS7r5z4iGS0qCjM7UwWdsEMzQesUQbGcXdSm2/tWboA= github.com/ProtonMail/go-mime v0.0.0-20221031134845-8fd9bc37cf08/go.mod h1:qRZgbeASl2a9OwmsV85aWwRqic0NHPh+9ewGAzb4cgM= -github.com/ProtonMail/go-proton-api v0.4.1-0.20230406143739-c7596e170799 h1:slk4Drrkij1EVTnFOlIDyJsfjt69tnw8w2g1NMb253U= -github.com/ProtonMail/go-proton-api v0.4.1-0.20230406143739-c7596e170799/go.mod h1:kis4GD6FHp1ZWnenSBepldt8ai+vYalDPeey9yGwyXk= +github.com/ProtonMail/go-proton-api v0.4.1-0.20230412081244-5a5a86b435ab h1:N99MTb645tfUoG2iEsskAp3uq1xLGmaLgQ3lYsqyMaU= +github.com/ProtonMail/go-proton-api v0.4.1-0.20230412081244-5a5a86b435ab/go.mod h1:Sj1MPL7pt+tf1SDdPyKhWcZvT43t87RADF79cbEi7xg= github.com/ProtonMail/go-srp v0.0.5 h1:xhUioxZgDbCnpo9JehyFhwwsn9JLWkUGfB0oiKXgiGg= github.com/ProtonMail/go-srp v0.0.5/go.mod h1:06iYHtLXW8vjLtccWj++x3MKy65sIT8yZd7nrJF49rs= github.com/ProtonMail/gopenpgp/v2 v2.5.2 h1:97SjlWNAxXl9P22lgwgrZRshQdiEfAht0g3ZoiA1GCw= From 3928ed08f66306d3947d2ba96c1821851a058e23 Mon Sep 17 00:00:00 2001 From: Romain Le Jeune Date: Thu, 13 Apr 2023 08:06:48 +0000 Subject: [PATCH 25/54] feat(GODT-2554): Compute telemetry availability from API UserSettings. --- internal/bridge/bridge.go | 12 ++++++++++++ internal/user/user.go | 10 ++++++++++ internal/user/user_test.go | 17 +++++++++++++++++ tests/bdd_test.go | 3 +++ tests/bridge_test.go | 16 ++++++++++++++++ tests/features/user/telemetry.feature | 18 ++++++++++++++++++ tests/user_test.go | 12 ++++++++++++ 7 files changed, 88 insertions(+) create mode 100644 tests/features/user/telemetry.feature diff --git a/internal/bridge/bridge.go b/internal/bridge/bridge.go index f675cbe7..915e197e 100644 --- a/internal/bridge/bridge.go +++ b/internal/bridge/bridge.go @@ -477,6 +477,18 @@ func (bridge *Bridge) Close(ctx context.Context) { bridge.watchers = nil } +func (bridge *Bridge) ComputeTelemetry() bool { + var telemetry = true + + safe.RLock(func() { + for _, user := range bridge.users { + telemetry = telemetry && user.IsTelemetryEnabled(context.Background()) + } + }, bridge.usersLock) + + return telemetry +} + func (bridge *Bridge) publish(event events.Event) { bridge.watchersLock.RLock() defer bridge.watchersLock.RUnlock() diff --git a/internal/user/user.go b/internal/user/user.go index 71a46236..25dc72cb 100644 --- a/internal/user/user.go +++ b/internal/user/user.go @@ -591,6 +591,16 @@ func (user *User) Close() { } } +// IsTelemetryEnabled check if the telemetry is enabled or disabled for this user. +func (user *User) IsTelemetryEnabled(ctx context.Context) bool { + settings, err := user.client.GetUserSettings(ctx) + if err != nil { + user.log.WithError(err).Warn("Failed to retrieve API user Settings") + return false + } + return settings.Telemetry == proton.SettingEnabled +} + // initUpdateCh initializes the user's update channels in the given address mode. // It is assumed that user.apiAddrs and user.updateCh are already locked. func (user *User) initUpdateCh(mode vault.AddressMode) { diff --git a/internal/user/user_test.go b/internal/user/user_test.go index c0888147..cf3388d5 100644 --- a/internal/user/user_test.go +++ b/internal/user/user_test.go @@ -80,6 +80,23 @@ func TestUser_AddressMode(t *testing.T) { }) } +func TestUser_Telemetry(t *testing.T) { + withAPI(t, context.Background(), func(ctx context.Context, s *server.Server, m *proton.Manager) { + withAccount(t, s, "username", "password", []string{}, func(string, []string) { + withUser(t, ctx, s, m, "username", "password", func(user *User) { + // By default, user should have Telemetry enabled. + telemetry := user.IsTelemetryEnabled(ctx) + require.Equal(t, true, telemetry) + + user.client.Close() + // If telemetry cannot be retrieved it is disabled. + telemetry = user.IsTelemetryEnabled(ctx) + require.Equal(t, false, telemetry) + }) + }) + }) +} + func withAPI(_ testing.TB, ctx context.Context, fn func(context.Context, *server.Server, *proton.Manager)) { //nolint:revive server := server.New() defer server.Close() diff --git a/tests/bdd_test.go b/tests/bdd_test.go index 125cb656..cad4a1fc 100644 --- a/tests/bdd_test.go +++ b/tests/bdd_test.go @@ -153,6 +153,8 @@ func TestFeatures(testingT *testing.T) { ctx.Step(`^bridge sends an update not available event$`, s.bridgeSendsAnUpdateNotAvailableEvent) ctx.Step(`^bridge sends a forced update event$`, s.bridgeSendsAForcedUpdateEvent) ctx.Step(`^bridge reports a message with "([^"]*)"$`, s.bridgeReportsMessage) + ctx.Step(`^bridge telemetry feature is enabled$`, s.bridgeTelemetryFeatureEnabled) + ctx.Step(`^bridge telemetry feature is disabled$`, s.bridgeTelemetryFeatureDisabled) // ==== FRONTEND ==== ctx.Step(`^frontend sees that bridge is version "([^"]*)"$`, s.frontendSeesThatBridgeIsVersion) @@ -166,6 +168,7 @@ func TestFeatures(testingT *testing.T) { ctx.Step(`^user "([^"]*)" is listed but not connected$`, s.userIsListedButNotConnected) ctx.Step(`^user "([^"]*)" is not listed$`, s.userIsNotListed) ctx.Step(`^user "([^"]*)" finishes syncing$`, s.userFinishesSyncing) + ctx.Step(`^user "([^"]*)" has telemetry set to (\d+)$`, s.userHasTelemetrySetTo) // ==== IMAP ==== ctx.Step(`^user "([^"]*)" connects IMAP client "([^"]*)"$`, s.userConnectsIMAPClient) diff --git a/tests/bridge_test.go b/tests/bridge_test.go index 45f6e67a..14632013 100644 --- a/tests/bridge_test.go +++ b/tests/bridge_test.go @@ -284,6 +284,22 @@ func (s *scenario) bridgeReportsMessage(message string) error { return nil } +func (s *scenario) bridgeTelemetryFeatureEnabled() error { + return s.checkTelemetry(true) +} + +func (s *scenario) bridgeTelemetryFeatureDisabled() error { + return s.checkTelemetry(false) +} + +func (s *scenario) checkTelemetry(expect bool) error { + res := s.t.bridge.ComputeTelemetry() + if res != expect { + return fmt.Errorf("expected telemetry feature %v but got %v ", expect, res) + } + return nil +} + func (s *scenario) theUserHidesAllMail() error { return s.t.bridge.SetShowAllMail(false) } diff --git a/tests/features/user/telemetry.feature b/tests/features/user/telemetry.feature new file mode 100644 index 00000000..9fd7ff64 --- /dev/null +++ b/tests/features/user/telemetry.feature @@ -0,0 +1,18 @@ +Feature: Bridge send usage metrics + Background: + Given there exists an account with username "[user:user1]" and password "password" + And there exists an account with username "[user:user2]" and password "password" + And bridge starts + + + Scenario: Telemetry availability - No user + Then bridge telemetry feature is enabled + + Scenario: Telemetry availability - Multi user + When the user logs in with username "[user:user1]" and password "password" + And user "[user:user1]" finishes syncing + Then bridge telemetry feature is enabled + When the user logs in with username "[user:user2]" and password "password" + And user "[user:user2]" finishes syncing + When user "[user:user2]" has telemetry set to 0 + Then bridge telemetry feature is disabled diff --git a/tests/user_test.go b/tests/user_test.go index 3be34f5f..17542987 100644 --- a/tests/user_test.go +++ b/tests/user_test.go @@ -414,6 +414,18 @@ func (s *scenario) userFinishesSyncing(username string) error { return s.bridgeSendsSyncStartedAndFinishedEventsForUser(username) } +func (s *scenario) userHasTelemetrySetTo(username string, telemetry int) error { + return s.t.withClientPass(context.Background(), username, s.t.getUserByName(username).userPass, func(ctx context.Context, c *proton.Client) error { + var req proton.SetTelemetryReq + req.Telemetry = proton.SettingsBool(telemetry) + _, err := c.SetUserSettingsTelemetry(ctx, req) + if err != nil { + return err + } + return nil + }) +} + func (s *scenario) addAdditionalAddressToAccount(username, address string, disabled bool) error { userID := s.t.getUserByName(username).getUserID() From b0c3faa22803d3f3a63cfaa55436c17ea48e969d Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Thu, 13 Apr 2023 11:25:16 +0200 Subject: [PATCH 26/54] fix(GODT-2574): Fix label/unlabel of large amounts of messages Requires update to GPA: https://github.com/ProtonMail/go-proton-api/pull/75 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 032ad293..3c24a0f4 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,7 @@ require ( github.com/Masterminds/semver/v3 v3.2.0 github.com/ProtonMail/gluon v0.16.0 github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a - github.com/ProtonMail/go-proton-api v0.4.1-0.20230412081244-5a5a86b435ab + github.com/ProtonMail/go-proton-api v0.4.1-0.20230413090743-ad45d30ed45c github.com/ProtonMail/gopenpgp/v2 v2.5.2 github.com/PuerkitoBio/goquery v1.8.1 github.com/abiosoft/ishell v2.0.0+incompatible diff --git a/go.sum b/go.sum index 07d08fa2..c1fd1906 100644 --- a/go.sum +++ b/go.sum @@ -40,8 +40,8 @@ github.com/ProtonMail/go-message v0.0.0-20210611055058-fabeff2ec753 h1:I8IsYA297 github.com/ProtonMail/go-message v0.0.0-20210611055058-fabeff2ec753/go.mod h1:NBAn21zgCJ/52WLDyed18YvYFm5tEoeDauubFqLokM4= github.com/ProtonMail/go-mime v0.0.0-20221031134845-8fd9bc37cf08 h1:dS7r5z4iGS0qCjM7UwWdsEMzQesUQbGcXdSm2/tWboA= github.com/ProtonMail/go-mime v0.0.0-20221031134845-8fd9bc37cf08/go.mod h1:qRZgbeASl2a9OwmsV85aWwRqic0NHPh+9ewGAzb4cgM= -github.com/ProtonMail/go-proton-api v0.4.1-0.20230412081244-5a5a86b435ab h1:N99MTb645tfUoG2iEsskAp3uq1xLGmaLgQ3lYsqyMaU= -github.com/ProtonMail/go-proton-api v0.4.1-0.20230412081244-5a5a86b435ab/go.mod h1:Sj1MPL7pt+tf1SDdPyKhWcZvT43t87RADF79cbEi7xg= +github.com/ProtonMail/go-proton-api v0.4.1-0.20230413090743-ad45d30ed45c h1:0aR0lmalexKojhLNQp7ObS7X8bT/ACzb/CcSOLdrN4Y= +github.com/ProtonMail/go-proton-api v0.4.1-0.20230413090743-ad45d30ed45c/go.mod h1:Sj1MPL7pt+tf1SDdPyKhWcZvT43t87RADF79cbEi7xg= github.com/ProtonMail/go-srp v0.0.5 h1:xhUioxZgDbCnpo9JehyFhwwsn9JLWkUGfB0oiKXgiGg= github.com/ProtonMail/go-srp v0.0.5/go.mod h1:06iYHtLXW8vjLtccWj++x3MKy65sIT8yZd7nrJF49rs= github.com/ProtonMail/gopenpgp/v2 v2.5.2 h1:97SjlWNAxXl9P22lgwgrZRshQdiEfAht0g3ZoiA1GCw= From ff44a3d6df1d36d4ac37de341a628e47463053a4 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Thu, 13 Apr 2023 14:28:53 +0200 Subject: [PATCH 27/54] test(GODT-2550): Verify IMAP ID is set properly --- internal/bridge/bridge_test.go | 52 ++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/internal/bridge/bridge_test.go b/internal/bridge/bridge_test.go index b6191a3d..8fcfa447 100644 --- a/internal/bridge/bridge_test.go +++ b/internal/bridge/bridge_test.go @@ -49,6 +49,7 @@ import ( "github.com/ProtonMail/proton-bridge/v3/internal/vault" "github.com/ProtonMail/proton-bridge/v3/tests" "github.com/bradenaw/juniper/xslices" + imapid "github.com/emersion/go-imap-id" "github.com/emersion/go-imap/client" "github.com/stretchr/testify/require" ) @@ -170,6 +171,57 @@ func TestBridge_UserAgent(t *testing.T) { }) } +func TestBridge_UserAgentFromIMAPID(t *testing.T) { + withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, vaultKey []byte) { + var ( + calls []server.Call + lock sync.Mutex + ) + + s.AddCallWatcher(func(call server.Call) { + lock.Lock() + defer lock.Unlock() + + calls = append(calls, call) + }) + + withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(b *bridge.Bridge, mocks *bridge.Mocks) { + imapClient, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) + require.NoError(t, err) + defer func() { _ = imapClient.Logout() }() + + idClient := imapid.NewClient(imapClient) + + // Set IMAP ID before Login to have the value capture in the Login API Call. + _, err = idClient.ID(imapid.ID{ + imapid.FieldName: "MyFancyClient", + imapid.FieldVersion: "0.1.2", + }) + + require.NoError(t, err) + + // Login the user. + userID, err := b.LoginFull(context.Background(), username, password, nil, nil) + require.NoError(t, err) + + info, err := b.GetUserInfo(userID) + require.NoError(t, err) + require.True(t, info.State == bridge.Connected) + + require.NoError(t, imapClient.Login(info.Addresses[0], string(info.BridgePass))) + + lock.Lock() + defer lock.Unlock() + + userAgent := calls[len(calls)-1].RequestHeader.Get("User-Agent") + + // Assert that the user agent was sent to the API. + require.Contains(t, userAgent, b.GetCurrentUserAgent()) + require.Contains(t, userAgent, "MyFancyClient/0.1.2") + }) + }) +} + func TestBridge_Cookies(t *testing.T) { withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, vaultKey []byte) { var ( From 2191dc70dc45104d88277c31a32e429fd5999d02 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Thu, 13 Apr 2023 15:02:41 +0200 Subject: [PATCH 28/54] fix(GODT-2550): Announce IMAP ID Capability https://github.com/ProtonMail/gluon/pull/337 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 3c24a0f4..323b2167 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/0xAX/notificator v0.0.0-20220220101646-ee9b8921e557 github.com/Masterminds/semver/v3 v3.2.0 - github.com/ProtonMail/gluon v0.16.0 + github.com/ProtonMail/gluon v0.16.1-0.20230413125952-3e8cc8bcee8b github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a github.com/ProtonMail/go-proton-api v0.4.1-0.20230413090743-ad45d30ed45c github.com/ProtonMail/gopenpgp/v2 v2.5.2 diff --git a/go.sum b/go.sum index c1fd1906..f3833f62 100644 --- a/go.sum +++ b/go.sum @@ -28,8 +28,8 @@ github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf h1:yc9daCCYUefEs github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf/go.mod h1:o0ESU9p83twszAU8LBeJKFAAMX14tISa0yk4Oo5TOqo= github.com/ProtonMail/docker-credential-helpers v1.1.0 h1:+kvUIpwWcbtP3WFv5sSvkFn/XLzSqPOB5AAthuk9xPk= github.com/ProtonMail/docker-credential-helpers v1.1.0/go.mod h1:mK0aBveCxhnQ756AmaTfXMZDeULvheYVhF/MWMErN5g= -github.com/ProtonMail/gluon v0.16.0 h1:zFUAJoZmcTo2xQ5ipWx6UPweCTm+OiR24dJFLUSgtp8= -github.com/ProtonMail/gluon v0.16.0/go.mod h1:yA4hk6CJw0BMo+YL8Y3ckCYs5L20sysu9xseshwY3QI= +github.com/ProtonMail/gluon v0.16.1-0.20230413125952-3e8cc8bcee8b h1:prDIhq/FUCYVmNVNnJUiflSny6n6pWHIF851ulaEiyg= +github.com/ProtonMail/gluon v0.16.1-0.20230413125952-3e8cc8bcee8b/go.mod h1:yA4hk6CJw0BMo+YL8Y3ckCYs5L20sysu9xseshwY3QI= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:D+aZah+k14Gn6kmL7eKxoo/4Dr/lK3ChBcwce2+SQP4= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4= github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= From d6760d6f5008f813a2bb5b5491bacb7b46ffe7f0 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Fri, 14 Apr 2023 09:48:39 +0200 Subject: [PATCH 29/54] chore(GODT-2551): Store and Recover Last User Agent from Vault --- internal/bridge/bridge.go | 2 ++ internal/bridge/bridge_test.go | 35 ++++++++++++++++++++++++++++++++ internal/bridge/identifier.go | 16 +++++++++++++++ internal/bridge/imap.go | 12 +---------- internal/bridge/types.go | 2 ++ internal/bridge/user.go | 2 +- internal/useragent/useragent.go | 14 +++++++++++++ internal/vault/settings.go | 19 +++++++++++++++++ internal/vault/settings_test.go | 8 ++++++++ internal/vault/types_settings.go | 5 +++++ 10 files changed, 103 insertions(+), 12 deletions(-) diff --git a/internal/bridge/bridge.go b/internal/bridge/bridge.go index 915e197e..11993d7c 100644 --- a/internal/bridge/bridge.go +++ b/internal/bridge/bridge.go @@ -237,6 +237,8 @@ func newBridge( return nil, fmt.Errorf("failed to save last version indicator: %w", err) } + identifier.SetClientString(vault.GetLastUserAgent()) + imapServer, err := newIMAPServer( gluonCacheDir, gluonDataDir, diff --git a/internal/bridge/bridge_test.go b/internal/bridge/bridge_test.go index 8fcfa447..67615609 100644 --- a/internal/bridge/bridge_test.go +++ b/internal/bridge/bridge_test.go @@ -171,6 +171,41 @@ func TestBridge_UserAgent(t *testing.T) { }) } +func TestBridge_UserAgent_Persistence(t *testing.T) { + withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, vaultKey []byte) { + withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(b *bridge.Bridge, mocks *bridge.Mocks) { + currentUserAgent := b.GetCurrentUserAgent() + require.Contains(t, currentUserAgent, vault.DefaultUserAgent) + + imapClient, err := client.Dial(fmt.Sprintf("%v:%v", constants.Host, b.GetIMAPPort())) + require.NoError(t, err) + defer func() { _ = imapClient.Logout() }() + + idClient := imapid.NewClient(imapClient) + + // Set IMAP ID before Login to have the value capture in the Login API Call. + _, err = idClient.ID(imapid.ID{ + imapid.FieldName: "MyFancyClient", + imapid.FieldVersion: "0.1.2", + }) + + require.NoError(t, err) + + // Login the user. + _, err = b.LoginFull(context.Background(), username, password, nil, nil) + require.NoError(t, err) + + // Assert that the user agent then contains the platform. + require.Contains(t, b.GetCurrentUserAgent(), "MyFancyClient/0.1.2") + }) + + withBridge(ctx, t, s.GetHostURL(), netCtl, locator, vaultKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) { + currentUserAgent := bridge.GetCurrentUserAgent() + require.Contains(t, currentUserAgent, "MyFancyClient/0.1.2") + }) + }) +} + func TestBridge_UserAgentFromIMAPID(t *testing.T) { withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, vaultKey []byte) { var ( diff --git a/internal/bridge/identifier.go b/internal/bridge/identifier.go index 4cad4822..2fa46727 100644 --- a/internal/bridge/identifier.go +++ b/internal/bridge/identifier.go @@ -17,6 +17,8 @@ package bridge +import "github.com/sirupsen/logrus" + func (bridge *Bridge) GetCurrentUserAgent() string { return bridge.identifier.GetUserAgent() } @@ -24,3 +26,17 @@ func (bridge *Bridge) GetCurrentUserAgent() string { func (bridge *Bridge) SetCurrentPlatform(platform string) { bridge.identifier.SetPlatform(platform) } + +func (bridge *Bridge) setUserAgent(name, version string) { + currentUserAgent := bridge.identifier.GetClientString() + + bridge.identifier.SetClient(name, version) + + newUserAgent := bridge.identifier.GetClientString() + + if currentUserAgent != newUserAgent { + if err := bridge.vault.SetLastUserAgent(newUserAgent); err != nil { + logrus.WithError(err).Error("Failed to write new user agent to vault") + } + } +} diff --git a/internal/bridge/imap.go b/internal/bridge/imap.go index bdd51845..760ba6b0 100644 --- a/internal/bridge/imap.go +++ b/internal/bridge/imap.go @@ -41,11 +41,6 @@ import ( "github.com/sirupsen/logrus" ) -const ( - defaultClientName = "UnknownClient" - defaultClientVersion = "0.0.1" -) - func (bridge *Bridge) serveIMAP() error { port, err := func() (int, error) { if bridge.imapServer == nil { @@ -249,11 +244,6 @@ func (bridge *Bridge) handleIMAPEvent(event imapEvents.Event) { }).Info("Received mailbox message count") } - case imapEvents.SessionAdded: - if !bridge.identifier.HasClient() { - bridge.identifier.SetClient(defaultClientName, defaultClientVersion) - } - case imapEvents.IMAPID: logrus.WithFields(logrus.Fields{ "sessionID": event.SessionID, @@ -262,7 +252,7 @@ func (bridge *Bridge) handleIMAPEvent(event imapEvents.Event) { }).Info("Received IMAP ID") if event.IMAPID.Name != "" && event.IMAPID.Version != "" { - bridge.identifier.SetClient(event.IMAPID.Name, event.IMAPID.Version) + bridge.setUserAgent(event.IMAPID.Name, event.IMAPID.Version) } case imapEvents.LoginFailed: diff --git a/internal/bridge/types.go b/internal/bridge/types.go index 3e779817..958f19a3 100644 --- a/internal/bridge/types.go +++ b/internal/bridge/types.go @@ -38,6 +38,8 @@ type Identifier interface { HasClient() bool SetClient(name, version string) SetPlatform(platform string) + SetClientString(client string) + GetClientString() string } type ProxyController interface { diff --git a/internal/bridge/user.go b/internal/bridge/user.go index 5f2a2f1e..c5c58175 100644 --- a/internal/bridge/user.go +++ b/internal/bridge/user.go @@ -550,7 +550,7 @@ func (bridge *Bridge) addUserWithVault( // As such, if we find this ID in the context, we should use it to update our user agent. client.AddPreRequestHook(func(_ *resty.Client, r *resty.Request) error { if imapID, ok := imap.GetIMAPIDFromContext(r.Context()); ok { - bridge.identifier.SetClient(imapID.Name, imapID.Version) + bridge.setUserAgent(imapID.Name, imapID.Version) } return nil diff --git a/internal/useragent/useragent.go b/internal/useragent/useragent.go index 12dc8a32..1e8b87bc 100644 --- a/internal/useragent/useragent.go +++ b/internal/useragent/useragent.go @@ -44,6 +44,20 @@ func (ua *UserAgent) SetClient(name, version string) { ua.client = fmt.Sprintf("%v/%v", name, regexp.MustCompile(`(.*) \((.*)\)`).ReplaceAllString(version, "$1-$2")) } +func (ua *UserAgent) SetClientString(client string) { + ua.lock.Lock() + defer ua.lock.Unlock() + + ua.client = client +} + +func (ua *UserAgent) GetClientString() string { + ua.lock.RLock() + defer ua.lock.RUnlock() + + return ua.client +} + func (ua *UserAgent) HasClient() bool { ua.lock.RLock() defer ua.lock.RUnlock() diff --git a/internal/vault/settings.go b/internal/vault/settings.go index 9967e307..af080222 100644 --- a/internal/vault/settings.go +++ b/internal/vault/settings.go @@ -225,3 +225,22 @@ func (vault *Vault) SetMaxSyncMemory(maxMemory uint64) error { data.Settings.MaxSyncMemory = maxMemory }) } + +// GetLastUserAgent returns the last user agent recorded by bridge. +func (vault *Vault) GetLastUserAgent() string { + v := vault.get().Settings.LastUserAgent + + // Handle case where there may be no value. + if len(v) == 0 { + v = DefaultUserAgent + } + + return v +} + +// SetLastUserAgent store the last user agent recorded by bridge. +func (vault *Vault) SetLastUserAgent(userAgent string) error { + return vault.mod(func(data *Data) { + data.Settings.LastUserAgent = userAgent + }) +} diff --git a/internal/vault/settings_test.go b/internal/vault/settings_test.go index cc4e1b77..1de09929 100644 --- a/internal/vault/settings_test.go +++ b/internal/vault/settings_test.go @@ -216,3 +216,11 @@ func TestVault_Settings_MaxSyncMemory(t *testing.T) { // Check the default first start value. require.Equal(t, vault.DefaultMaxSyncMemory, s.GetMaxSyncMemory()) } + +func TestVault_Settings_LastUserAgent(t *testing.T) { + // create a new test vault. + s := newVault(t) + + // Check the default first start value. + require.Equal(t, vault.DefaultUserAgent, s.GetLastUserAgent()) +} diff --git a/internal/vault/types_settings.go b/internal/vault/types_settings.go index 8f83423f..2c385ff3 100644 --- a/internal/vault/types_settings.go +++ b/internal/vault/types_settings.go @@ -46,12 +46,15 @@ type Settings struct { MaxSyncMemory uint64 + LastUserAgent string + // **WARNING**: These entry can't be removed until they vault has proper migration support. SyncWorkers int SyncAttPool int } const DefaultMaxSyncMemory = 2 * 1024 * uint64(1024*1024) +const DefaultUserAgent = "UnknownClient/0.0.1" func GetDefaultSyncWorkerCount() int { const minSyncWorkers = 16 @@ -91,5 +94,7 @@ func newDefaultSettings(gluonDir string) Settings { MaxSyncMemory: DefaultMaxSyncMemory, SyncWorkers: syncWorkers, SyncAttPool: syncWorkers, + + LastUserAgent: DefaultUserAgent, } } From 7bb925b6d7fa0c2bdc3652ee6607e6db67c9e083 Mon Sep 17 00:00:00 2001 From: Jakub Date: Wed, 12 Apr 2023 11:52:03 +0200 Subject: [PATCH 30/54] feat(GODT-2502): Improve logs. --- internal/app/app.go | 8 ++++++++ internal/bridge/imap.go | 5 ++++- internal/bridge/smtp.go | 5 ++++- internal/bridge/user.go | 2 +- internal/user/sync.go | 2 +- 5 files changed, 18 insertions(+), 4 deletions(-) diff --git a/internal/app/app.go b/internal/app/app.go index 3ee0d038..b39c5862 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -244,6 +244,14 @@ func run(c *cli.Context) error { } } + logrus.WithFields(logrus.Fields{ + "lastVersion": v.GetLastVersion().String(), + "showAllMail": v.GetShowAllMail(), + "updateCh": v.GetUpdateChannel(), + "rollout": v.GetUpdateRollout(), + "DoH": v.GetProxyAllowed(), + }).Info("Vault loaded") + // Load the cookies from the vault. return withCookieJar(v, func(cookieJar http.CookieJar) error { // Create a new bridge instance. diff --git a/internal/bridge/imap.go b/internal/bridge/imap.go index 760ba6b0..a5d94fe0 100644 --- a/internal/bridge/imap.go +++ b/internal/bridge/imap.go @@ -47,7 +47,10 @@ func (bridge *Bridge) serveIMAP() error { return 0, fmt.Errorf("no IMAP server instance running") } - logrus.Info("Starting IMAP server") + logrus.WithFields(logrus.Fields{ + "port": bridge.vault.GetIMAPPort(), + "ssl": bridge.vault.GetIMAPSSL(), + }).Info("Starting IMAP server") imapListener, err := newListener(bridge.vault.GetIMAPPort(), bridge.vault.GetIMAPSSL(), bridge.tlsConfig) if err != nil { diff --git a/internal/bridge/smtp.go b/internal/bridge/smtp.go index b6d95158..9b88b811 100644 --- a/internal/bridge/smtp.go +++ b/internal/bridge/smtp.go @@ -33,7 +33,10 @@ import ( func (bridge *Bridge) serveSMTP() error { port, err := func() (int, error) { - logrus.Info("Starting SMTP server") + logrus.WithFields(logrus.Fields{ + "port": bridge.vault.GetSMTPPort(), + "ssl": bridge.vault.GetSMTPSSL(), + }).Info("Starting SMTP server") smtpListener, err := newListener(bridge.vault.GetSMTPPort(), bridge.vault.GetSMTPSSL(), bridge.tlsConfig) if err != nil { diff --git a/internal/bridge/user.go b/internal/bridge/user.go index c5c58175..907b8594 100644 --- a/internal/bridge/user.go +++ b/internal/bridge/user.go @@ -399,7 +399,7 @@ func (bridge *Bridge) loadUsers(ctx context.Context) error { return nil } - log.Info("Loading connected user") + log.WithField("mode", user.AddressMode()).Info("Loading connected user") bridge.publish(events.UserLoading{ UserID: user.UserID(), diff --git a/internal/user/sync.go b/internal/user/sync.go index 03515645..d3da5d8f 100644 --- a/internal/user/sync.go +++ b/internal/user/sync.go @@ -262,7 +262,7 @@ func (user *User) syncMessages( syncStartTime := time.Now() defer func() { logrus.WithField("duration", time.Since(syncStartTime)).Info("Message sync completed") }() - logrus.WithFields(logrus.Fields{ + user.log.WithFields(logrus.Fields{ "messages": len(messageIDs), "numCPU": runtime.NumCPU(), }).Info("Starting message sync") From 8093bbf5f6cc4305d26197ad68cc5e36d251b36c Mon Sep 17 00:00:00 2001 From: Jakub Date: Fri, 14 Apr 2023 10:10:58 +0200 Subject: [PATCH 31/54] feat(GODT-2502): Additional info. --- internal/app/app.go | 1 + internal/bridge/smtp_backend.go | 9 ++++++++- internal/user/user.go | 6 ++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/internal/app/app.go b/internal/app/app.go index b39c5862..3da35193 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -248,6 +248,7 @@ func run(c *cli.Context) error { "lastVersion": v.GetLastVersion().String(), "showAllMail": v.GetShowAllMail(), "updateCh": v.GetUpdateChannel(), + "autoUpdate": v.GetAutoUpdate(), "rollout": v.GetUpdateRollout(), "DoH": v.GetProxyAllowed(), }).Info("Vault loaded") diff --git a/internal/bridge/smtp_backend.go b/internal/bridge/smtp_backend.go index f5db750f..d48f3923 100644 --- a/internal/bridge/smtp_backend.go +++ b/internal/bridge/smtp_backend.go @@ -23,6 +23,7 @@ import ( "github.com/ProtonMail/proton-bridge/v3/internal/safe" "github.com/emersion/go-smtp" + "github.com/sirupsen/logrus" ) type smtpBackend struct { @@ -85,7 +86,7 @@ func (s *smtpSession) Rcpt(to string) error { } func (s *smtpSession) Data(r io.Reader) error { - return safe.RLockRet(func() error { + err := safe.RLockRet(func() error { user, ok := s.users[s.userID] if !ok { return ErrNoSuchUser @@ -93,4 +94,10 @@ func (s *smtpSession) Data(r io.Reader) error { return user.SendMail(s.authID, s.from, s.to, r) }, s.usersLock) + + if err != nil { + logrus.WithField("pkg", "smtp").WithError(err).Error("Send mail failed.") + } + + return err } diff --git a/internal/user/user.go b/internal/user/user.go index 25dc72cb..b3d4cd0b 100644 --- a/internal/user/user.go +++ b/internal/user/user.go @@ -119,6 +119,12 @@ func New( return nil, fmt.Errorf("failed to get labels: %w", err) } + logrus.WithFields(logrus.Fields{ + "userID": apiUser.ID, + "numAddr": len(apiAddrs), + "numLabels": len(apiLabels), + }).Info("Creating user object") + // Create the user object. user := &User{ log: logrus.WithField("userID", apiUser.ID), From 4e7a669260842cc8004281bb4b1df96deb404bd7 Mon Sep 17 00:00:00 2001 From: Jakub Date: Fri, 14 Apr 2023 10:47:39 +0200 Subject: [PATCH 32/54] chore: Bridge Quebec 3.1.2 changelog. --- Changelog.md | 20 ++++++++++++++++++++ Makefile | 2 +- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Changelog.md b/Changelog.md index 804010e5..4f68ff72 100644 --- a/Changelog.md +++ b/Changelog.md @@ -2,6 +2,26 @@ Changelog [format](http://keepachangelog.com/en/1.0.0/) +## [Bridge 3.1.2] Quebec + +### Changed +* GODT-2502: Improve logs. +* GODT-2551: Store and Recover Last User Agent from Vault. +* GODT-2550: Verify IMAP ID is set properly. +* GODT-2554: Compute telemetry availability from API UserSettings. +* Add missing double quotes in test. +* GODT-2239: Unit tests for BridgeUtils.cpp in bridgepp. +* Replace go-rfc5322 with gluon's rfc5322 parser. +* GODT-2483: Install cert without external tool on macOS. + +### Fixed +* GODT-2550: Announce IMAP ID Capability. +* GODT-2574: Fix label/unlabel of large amounts of messages. +* GODT-2573: Handle invalid header fields in message. +* GODT-2573: Crash on null update. +* GODT-2407: Replace invalid email addresses with emtpy for new Drafts. + + ## [Bridge 3.1.1] Quebec ### Fixed diff --git a/Makefile b/Makefile index d004f1f0..50b250d5 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,7 @@ ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) .PHONY: build build-gui build-nogui build-launcher versioner hasher # Keep version hardcoded so app build works also without Git repository. -BRIDGE_APP_VERSION?=3.1.1+git +BRIDGE_APP_VERSION?=3.1.2+git APP_VERSION:=${BRIDGE_APP_VERSION} APP_FULL_NAME:=Proton Mail Bridge APP_VENDOR:=Proton AG From 54b209f9e1d50d2e48045ff17b70dd6bff886c98 Mon Sep 17 00:00:00 2001 From: Romain LE JEUNE Date: Wed, 12 Apr 2023 08:31:35 +0200 Subject: [PATCH 33/54] fix(GODT-2337): filter reply-to on draft. --- internal/bridge/user_event_test.go | 59 +++++++++++++++++++++ pkg/message/build.go | 2 +- tests/bdd_test.go | 1 + tests/features/imap/message/drafts.feature | 2 + tests/features/smtp/send/send_reply.feature | 26 ++++----- tests/imap_test.go | 9 +++- tests/types_test.go | 13 +++-- 7 files changed, 93 insertions(+), 19 deletions(-) diff --git a/internal/bridge/user_event_test.go b/internal/bridge/user_event_test.go index 9c5bcaff..fa69ea1f 100644 --- a/internal/bridge/user_event_test.go +++ b/internal/bridge/user_event_test.go @@ -451,6 +451,65 @@ func TestBridge_User_DropConn_NoBadEvent(t *testing.T) { }, server.WithListener(dropListener)) } +func TestBridge_User_UpdateDraft(t *testing.T) { + withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, storeKey []byte) { + // Create a bridge user. + _, _, err := s.CreateUser("user", password) + require.NoError(t, err) + + // Initially sync the user. + withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) { + userLoginAndSync(ctx, t, bridge, "user", password) + }) + + withClient(ctx, t, s, "user", password, func(ctx context.Context, c *proton.Client) { + user, err := c.GetUser(ctx) + require.NoError(t, err) + + addrs, err := c.GetAddresses(ctx) + require.NoError(t, err) + + salts, err := c.GetSalts(ctx) + require.NoError(t, err) + + keyPass, err := salts.SaltForKey(password, user.Keys.Primary().ID) + require.NoError(t, err) + + _, addrKRs, err := proton.Unlock(user, addrs, keyPass, async.NoopPanicHandler{}) + require.NoError(t, err) + + // Create a draft (generating a "create draft message" event). + draft, err := c.CreateDraft(ctx, addrKRs[addrs[0].ID], proton.CreateDraftReq{ + Message: proton.DraftTemplate{ + Subject: "subject", + Sender: &mail.Address{Name: "sender", Address: addrs[0].Email}, + Body: "body", + MIMEType: rfc822.TextPlain, + }, + }) + require.NoError(t, err) + require.Empty(t, draft.ReplyTos) + + // Process those events + withBridge(ctx, t, s.GetHostURL(), netCtl, locator, storeKey, func(bridge *bridge.Bridge, mocks *bridge.Mocks) { + userContinueEventProcess(ctx, t, s, bridge) + }) + + // Update the draft (generating an "update draft message" event). + draft2, err := c.UpdateDraft(ctx, draft.ID, addrKRs[addrs[0].ID], proton.UpdateDraftReq{ + Message: proton.DraftTemplate{ + Subject: "subject 2", + Sender: &mail.Address{Name: "sender", Address: addrs[0].Email}, + Body: "body 2", + MIMEType: rfc822.TextPlain, + }, + }) + require.NoError(t, err) + require.Empty(t, draft2.ReplyTos) + }) + }) +} + func TestBridge_User_UpdateDraftAndCreateOtherMessage(t *testing.T) { withEnv(t, func(ctx context.Context, s *server.Server, netCtl *proton.NetCtl, locator bridge.Locator, storeKey []byte) { // Create a bridge user. diff --git a/pkg/message/build.go b/pkg/message/build.go index b67503e2..5e7e44bb 100644 --- a/pkg/message/build.go +++ b/pkg/message/build.go @@ -441,7 +441,7 @@ func getMessageHeader(msg proton.Message, opts JobOptions) message.Header { hdr.Set("From", msg.Sender.String()) } - if len(msg.ReplyTos) > 0 { + if len(msg.ReplyTos) > 0 && !msg.IsDraft() { if !(len(msg.ReplyTos) == 1 && addressEmpty(msg.ReplyTos[0])) { hdr.Set("Reply-To", toAddressList(msg.ReplyTos)) } diff --git a/tests/bdd_test.go b/tests/bdd_test.go index cad4a1fc..d854fb12 100644 --- a/tests/bdd_test.go +++ b/tests/bdd_test.go @@ -209,6 +209,7 @@ func TestFeatures(testingT *testing.T) { ctx.Step(`^IMAP client "([^"]*)" appends "([^"]*)" to "([^"]*)"$`, s.imapClientAppendsToMailbox) ctx.Step(`^IMAP clients "([^"]*)" and "([^"]*)" move message with subject "([^"]*)" of "([^"]*)" to "([^"]*)" by ([^"]*) ([^"]*) ([^"]*)`, s.imapClientsMoveMessageWithSubjectUserFromToByOrderedOperations) ctx.Step(`^IMAP client "([^"]*)" sees header "([^"]*)" in message with subject "([^"]*)" in "([^"]*)"$`, s.imapClientSeesHeaderInMessageWithSubject) + ctx.Step(`^IMAP client "([^"]*)" does not see header "([^"]*)" in message with subject "([^"]*)" in "([^"]*)"$`, s.imapClientDoesNotSeeHeaderInMessageWithSubject) // ==== SMTP ==== ctx.Step(`^user "([^"]*)" connects SMTP client "([^"]*)"$`, s.userConnectsSMTPClient) diff --git a/tests/features/imap/message/drafts.feature b/tests/features/imap/message/drafts.feature index e4644d43..2c8e6ae7 100644 --- a/tests/features/imap/message/drafts.feature +++ b/tests/features/imap/message/drafts.feature @@ -34,6 +34,7 @@ Feature: IMAP Draft messages | to | subject | body | | someone@example.com | Basic Draft | This is a draft, but longer | And IMAP client "1" eventually sees 1 messages in "Drafts" + And IMAP client "1" does not see header "Reply-To" in message with subject "Basic Draft" in "Drafts" Scenario: Draft edited remotely When the following fields were changed in draft 1 for address "[user:user]@[domain]" of account "[user:user]": @@ -43,6 +44,7 @@ Feature: IMAP Draft messages | to | subject | body | | someone@example.com | Basic Draft | This is a draft body, but longer | And IMAP client "1" eventually sees 1 messages in "Drafts" + And IMAP client "1" does not see header "Reply-To" in message with subject "Basic Draft" in "Drafts" Scenario: Draft moved to trash remotely When draft 1 for address "[user:user]@[domain]" of account "[user:user]" was moved to trash diff --git a/tests/features/smtp/send/send_reply.feature b/tests/features/smtp/send/send_reply.feature index 47f9acf4..a3c17143 100644 --- a/tests/features/smtp/send/send_reply.feature +++ b/tests/features/smtp/send/send_reply.feature @@ -5,9 +5,9 @@ Feature: SMTP send reply And there exists an account with username "[user:user2]" and password "password" And bridge starts And the user logs in with username "[user:user1]" and password "password" + And user "[user:user1]" finishes syncing And user "[user:user1]" connects and authenticates SMTP client "1" And user "[user:user1]" connects and authenticates IMAP client "1" - And user "[user:user1]" finishes syncing @long-black Scenario: Reply with In-Reply-To but no References @@ -33,8 +33,8 @@ Feature: SMTP send reply And user "[user:user2]" finishes syncing # User2 receive the message. Then IMAP client "2" eventually sees the following messages in "INBOX": - | from | subject | message-id | - | [user:user1]@[domain] | Please Reply | | + | from | subject | message-id | reply-to | + | [user:user1]@[domain] | Please Reply | | [user:user1]@[domain] | # User2 reply to it. When SMTP client "2" sends the following message from "[user:user2]@[domain]" to "[user:user1]@[domain]": """ @@ -53,8 +53,8 @@ Feature: SMTP send reply | [user:user2]@[domain] | [user:user1]@[domain] | FW - Please Reply | | | # User1 receive the reply.| And IMAP client "1" eventually sees the following messages in "INBOX": - | from | subject | body | in-reply-to | references | - | [user:user2]@[domain] | FW - Please Reply | Heya | | | + | from | subject | body | in-reply-to | references | reply-to | + | [user:user2]@[domain] | FW - Please Reply | Heya | | | [user:user2]@[domain] | @long-black Scenario: Reply with References but no In-Reply-To @@ -80,8 +80,8 @@ Feature: SMTP send reply And user "[user:user2]" finishes syncing # User2 receive the message. Then IMAP client "2" eventually sees the following messages in "INBOX": - | from | subject | message-id | - | [user:user1]@[domain] | Please Reply | | + | from | subject | message-id | reply-to | + | [user:user1]@[domain] | Please Reply | | [user:user1]@[domain] | # User2 reply to it. When SMTP client "2" sends the following message from "[user:user2]@[domain]" to "[user:user1]@[domain]": """ @@ -100,8 +100,8 @@ Feature: SMTP send reply | [user:user2]@[domain] | [user:user1]@[domain] | FW - Please Reply | | | # User1 receive the reply.| And IMAP client "1" eventually sees the following messages in "INBOX": - | from | subject | body | in-reply-to | references | - | [user:user2]@[domain] | FW - Please Reply | Heya | | | + | from | subject | body | in-reply-to | references | reply-to | + | [user:user2]@[domain] | FW - Please Reply | Heya | | | [user:user2]@[domain] | @long-black @@ -128,8 +128,8 @@ Feature: SMTP send reply And user "[user:user2]" finishes syncing # User2 receive the message. Then IMAP client "2" eventually sees the following messages in "INBOX": - | from | subject | message-id | - | [user:user1]@[domain] | Please Reply | | + | from | subject | message-id | reply-to | + | [user:user1]@[domain] | Please Reply | | [user:user1]@[domain] | # User2 reply to it. When SMTP client "2" sends the following message from "[user:user2]@[domain]" to "[user:user1]@[domain]": """ @@ -149,5 +149,5 @@ Feature: SMTP send reply | [user:user2]@[domain] | [user:user1]@[domain] | FW - Please Reply | | | # User1 receive the reply.| And IMAP client "1" eventually sees the following messages in "INBOX": - | from | subject | body | in-reply-to | references | - | [user:user2]@[domain] | FW - Please Reply | Heya | | | \ No newline at end of file + | from | subject | body | in-reply-to | references | reply-to | + | [user:user2]@[domain] | FW - Please Reply | Heya | | | [user:user2]@[domain] | \ No newline at end of file diff --git a/tests/imap_test.go b/tests/imap_test.go index 8cae5707..155b6e37 100644 --- a/tests/imap_test.go +++ b/tests/imap_test.go @@ -297,7 +297,6 @@ func (s *scenario) imapClientSeesTheFollowingMessagesInMailbox(clientID, mailbox if err != nil { return err } - return matchMessages(haveMessages, wantMessages) } @@ -575,6 +574,14 @@ func (s *scenario) imapClientSeesHeaderInMessageWithSubject(clientID, headerStri return fmt.Errorf("could not find message with given subject '%v'", subject) } +func (s *scenario) imapClientDoesNotSeeHeaderInMessageWithSubject(clientID, headerString, subject, mailbox string) error { + err := s.imapClientSeesHeaderInMessageWithSubject(clientID, headerString, subject, mailbox) + if err == nil { + return fmt.Errorf("message header contains '%v'", headerString) + } + return nil +} + func clientList(client *client.Client) []*imap.MailboxInfo { resCh := make(chan *imap.MailboxInfo) diff --git a/tests/types_test.go b/tests/types_test.go index c59b13dc..183637d6 100644 --- a/tests/types_test.go +++ b/tests/types_test.go @@ -43,10 +43,11 @@ type Message struct { MessageID string `bdd:"message-id"` Date string `bdd:"date"` - From string `bdd:"from"` - To string `bdd:"to"` - CC string `bdd:"cc"` - BCC string `bdd:"bcc"` + From string `bdd:"from"` + To string `bdd:"to"` + CC string `bdd:"cc"` + BCC string `bdd:"bcc"` + ReplyTo string `bdd:"reply-to"` Unread bool `bdd:"unread"` Deleted bool `bdd:"deleted"` @@ -158,6 +159,10 @@ func newMessageFromIMAP(msg *imap.Message) Message { message.BCC = msg.Envelope.Bcc[0].Address() } + if len(msg.Envelope.ReplyTo) > 0 { + message.ReplyTo = msg.Envelope.ReplyTo[0].Address() + } + return message } From 3ddd88e1278d92adbe667154bcd1bf3d3639fd30 Mon Sep 17 00:00:00 2001 From: Xavier Michelon Date: Thu, 6 Apr 2023 15:08:41 +0200 Subject: [PATCH 34/54] feat(GODT-2538): implement smart picking of default IMAP/SMTP ports --- internal/vault/types_settings.go | 7 +- pkg/ports/ports.go | 11 +-- pkg/ports/ports_test.go | 18 ++++- tests/bdd_test.go | 5 +- tests/bridge_test.go | 36 +++++++++ tests/ctx_test.go | 10 +++ tests/features/bridge/default_ports.feature | 24 ++++++ tests/features/{ => bridge}/updates.feature | 0 utils/port-blocker/port-blocker.go | 83 +++++++++++++++++++++ 9 files changed, 182 insertions(+), 12 deletions(-) create mode 100644 tests/features/bridge/default_ports.feature rename tests/features/{ => bridge}/updates.feature (100%) create mode 100644 utils/port-blocker/port-blocker.go diff --git a/internal/vault/types_settings.go b/internal/vault/types_settings.go index 2c385ff3..68c3e6f1 100644 --- a/internal/vault/types_settings.go +++ b/internal/vault/types_settings.go @@ -22,6 +22,7 @@ import ( "runtime" "github.com/ProtonMail/proton-bridge/v3/internal/updater" + "github.com/ProtonMail/proton-bridge/v3/pkg/ports" ) type Settings struct { @@ -70,12 +71,14 @@ func GetDefaultSyncWorkerCount() int { func newDefaultSettings(gluonDir string) Settings { syncWorkers := GetDefaultSyncWorkerCount() + imapPort := ports.FindFreePortFrom(1143) + smtpPort := ports.FindFreePortFrom(1025, imapPort) return Settings{ GluonDir: gluonDir, - IMAPPort: 1143, - SMTPPort: 1025, + IMAPPort: imapPort, + SMTPPort: smtpPort, IMAPSSL: false, SMTPSSL: false, diff --git a/pkg/ports/ports.go b/pkg/ports/ports.go index d5cfbaff..212a3d42 100644 --- a/pkg/ports/ports.go +++ b/pkg/ports/ports.go @@ -22,6 +22,7 @@ import ( "net" "github.com/ProtonMail/proton-bridge/v3/internal/constants" + "golang.org/x/exp/slices" ) const ( @@ -43,19 +44,19 @@ func IsPortFree(port int) bool { func isOccupied(port string) bool { // Try to create server at port. - dummyserver, err := net.Listen("tcp", port) + dummyServer, err := net.Listen("tcp", port) if err != nil { return true } - _ = dummyserver.Close() + _ = dummyServer.Close() return false } -// FindFreePortFrom finds first empty port, starting with `startPort`. -func FindFreePortFrom(startPort int) int { +// FindFreePortFrom finds first empty port, starting with `startPort`, and excluding ports listed in exclude. +func FindFreePortFrom(startPort int, exclude ...int) int { loopedOnce := false freePort := startPort - for !IsPortFree(freePort) { + for slices.Contains(exclude, freePort) || !IsPortFree(freePort) { freePort++ if freePort >= maxPortNumber { freePort = 1 diff --git a/pkg/ports/ports_test.go b/pkg/ports/ports_test.go index a88bbce2..53276be7 100644 --- a/pkg/ports/ports_test.go +++ b/pkg/ports/ports_test.go @@ -32,12 +32,12 @@ func TestFreePort(t *testing.T) { } func TestOccupiedPort(t *testing.T) { - dummyserver, err := net.Listen("tcp", ":"+strconv.Itoa(testPort)) + dummyServer, err := net.Listen("tcp", ":"+strconv.Itoa(testPort)) require.NoError(t, err) require.True(t, !IsPortFree(testPort), "port should be occupied") - _ = dummyserver.Close() + _ = dummyServer.Close() } func TestFindFreePortFromDirectly(t *testing.T) { @@ -46,11 +46,21 @@ func TestFindFreePortFromDirectly(t *testing.T) { } func TestFindFreePortFromNextOne(t *testing.T) { - dummyserver, err := net.Listen("tcp", ":"+strconv.Itoa(testPort)) + dummyServer, err := net.Listen("tcp", ":"+strconv.Itoa(testPort)) require.NoError(t, err) foundPort := FindFreePortFrom(testPort) require.Equal(t, testPort+1, foundPort) - _ = dummyserver.Close() + _ = dummyServer.Close() +} + +func TestFindFreePortExcluding(t *testing.T) { + dummyServer, err := net.Listen("tcp", ":"+strconv.Itoa(testPort)) + require.NoError(t, err) + + foundPort := FindFreePortFrom(testPort, testPort+1, testPort+2) + require.Equal(t, testPort+3, foundPort) + + _ = dummyServer.Close() } diff --git a/tests/bdd_test.go b/tests/bdd_test.go index d854fb12..90c8f817 100644 --- a/tests/bdd_test.go +++ b/tests/bdd_test.go @@ -107,7 +107,10 @@ func TestFeatures(testingT *testing.T) { ctx.Step(`^the header in the "([^"]*)" request to "([^"]*)" has "([^"]*)" set to "([^"]*)"$`, s.theHeaderInTheRequestToHasSetTo) ctx.Step(`^the body in the "([^"]*)" request to "([^"]*)" is:$`, s.theBodyInTheRequestToIs) ctx.Step(`^the API requires bridge version at least "([^"]*)"$`, s.theAPIRequiresBridgeVersion) - + ctx.Step(`^the network port (\d+) is busy$`, s.networkPortIsBusy) + ctx.Step(`^the network port range (\d+)-(\d+) is busy$`, s.networkPortRangeIsBusy) + ctx.Step(`^bridge IMAP port is (\d+)`, s.bridgeIMAPPortIs) + ctx.Step(`^bridge SMTP port is (\d+)`, s.bridgeSMTPPortIs) // ==== SETUP ==== ctx.Step(`^there exists an account with username "([^"]*)" and password "([^"]*)"$`, s.thereExistsAnAccountWithUsernameAndPassword) ctx.Step(`^there exists a disabled account with username "([^"]*)" and password "([^"]*)"$`, s.thereExistsAnAccountWithUsernameAndPasswordWithDisablePrimary) diff --git a/tests/bridge_test.go b/tests/bridge_test.go index 14632013..40a4667e 100644 --- a/tests/bridge_test.go +++ b/tests/bridge_test.go @@ -21,7 +21,9 @@ import ( "context" "errors" "fmt" + "net" "os" + "strconv" "time" "github.com/Masterminds/semver/v3" @@ -307,3 +309,37 @@ func (s *scenario) theUserHidesAllMail() error { func (s *scenario) theUserShowsAllMail() error { return s.t.bridge.SetShowAllMail(true) } + +func (s *scenario) networkPortIsBusy(port int) { + if listener, err := net.Listen("tcp", "127.0.0.1:"+strconv.Itoa(port)); err == nil { // we ignore errors. Most likely port is already busy. + s.t.dummyListeners = append(s.t.dummyListeners, listener) + } +} + +func (s *scenario) networkPortRangeIsBusy(startPort, endPort int) { + if startPort > endPort { + startPort, endPort = endPort, startPort + } + + for port := startPort; port <= endPort; port++ { + s.networkPortIsBusy(port) + } +} + +func (s *scenario) bridgeIMAPPortIs(expectedPort int) error { + actualPort := s.t.bridge.GetIMAPPort() + if actualPort != expectedPort { + return fmt.Errorf("expected IMAP port to be %v but got %v", expectedPort, actualPort) + } + + return nil +} + +func (s *scenario) bridgeSMTPPortIs(expectedPort int) error { + actualPort := s.t.bridge.GetSMTPPort() + if actualPort != expectedPort { + return fmt.Errorf("expected SMTP port to be %v but got %v", expectedPort, actualPort) + } + + return nil +} diff --git a/tests/ctx_test.go b/tests/ctx_test.go index 13bff820..004ab501 100644 --- a/tests/ctx_test.go +++ b/tests/ctx_test.go @@ -20,6 +20,7 @@ package tests import ( "context" "fmt" + "net" "net/smtp" "net/url" "regexp" @@ -160,6 +161,9 @@ type testCtx struct { // errors holds test-related errors encountered while running test steps. errors [][]error errorsLock sync.RWMutex + + // This slice contains the dummy listeners that are intended to block network ports. + dummyListeners []net.Listener } type imapClient struct { @@ -437,6 +441,12 @@ func (t *testCtx) close(ctx context.Context) { } } + for _, listener := range t.dummyListeners { + if err := listener.Close(); err != nil { + logrus.WithError(err).Errorf("Failed to close dummy listener %v", listener.Addr()) + } + } + t.api.Close() t.events.close() t.reporter.close() diff --git a/tests/features/bridge/default_ports.feature b/tests/features/bridge/default_ports.feature new file mode 100644 index 00000000..4c7f3703 --- /dev/null +++ b/tests/features/bridge/default_ports.feature @@ -0,0 +1,24 @@ +Feature: Bridge picks default ports wisely + + Scenario: bridge picks ports for IMAP and SMTP using default values. + When bridge starts + Then bridge IMAP port is 1143 + Then bridge SMTP port is 1025 + + Scenario: bridge picks ports for IMAP wisely when default port is busy. + When the network port 1143 is busy + And bridge starts + Then bridge IMAP port is 1144 + Then bridge SMTP port is 1025 + + Scenario: bridge picks ports for SMTP wisely when default port is busy. + When the network port range 1025-1030 is busy + And bridge starts + Then bridge IMAP port is 1143 + Then bridge SMTP port is 1031 + + Scenario: bridge picks ports for IMAP SMTP wisely when default ports are busy. + When the network port range 1025-1200 is busy + And bridge starts + Then bridge IMAP port is 1201 + Then bridge SMTP port is 1202 diff --git a/tests/features/updates.feature b/tests/features/bridge/updates.feature similarity index 100% rename from tests/features/updates.feature rename to tests/features/bridge/updates.feature diff --git a/utils/port-blocker/port-blocker.go b/utils/port-blocker/port-blocker.go new file mode 100644 index 00000000..9a358f44 --- /dev/null +++ b/utils/port-blocker/port-blocker.go @@ -0,0 +1,83 @@ +// Copyright (c) 2023 Proton AG +// +// This file is part of Proton Mail 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 . + +// port-blocker is a command-line that ensure a port or range of ports is occupied by creating listeners. +package main + +import ( + "fmt" + "net" + "os" + "strconv" +) + +func main() { + argCount := len(os.Args) + if (len(os.Args) < 2) || (argCount > 3) { + exitWithUsage("Invalid number of arguments.") + } + + startPort := parsePort(os.Args[1]) + endPort := startPort + if argCount == 3 { + endPort = parsePort(os.Args[2]) + } + + runBlocker(startPort, endPort) +} + +func parsePort(portString string) int { + result, err := strconv.Atoi(portString) + if err != nil { + exitWithUsage(fmt.Sprintf("Invalid port '%v'.", portString)) + } + + if (result < 1024) || (result > 65535) { // ports below 1024 are reserved. + exitWithUsage("Ports must be in the range [1024-65535].") + } + + return result +} + +func exitWithUsage(message string) { + fmt.Printf("Usage: port-blocker []\n") + if len(message) > 0 { + fmt.Println(message) + } + os.Exit(1) +} + +func runBlocker(startPort, endPort int) { + if endPort < startPort { + exitWithUsage("startPort must be less than or equal to endPort.") + } + + for port := startPort; port <= endPort; port++ { + listener, err := net.Listen("tcp", "127.0.0.1:"+strconv.Itoa(port)) + if err != nil { + fmt.Printf("Port %v is already blocked. Skipping.\n", port) + } else { + //goland:noinspection GoDeferInLoop + defer func() { + _ = listener.Close() + }() + } + } + + fmt.Println("Blocking requested ports. Press enter to exit.") + _, _ = fmt.Scanln() +} From c000ee8a3c2047fb88dd727298b4853d6d65c146 Mon Sep 17 00:00:00 2001 From: Xavier Michelon Date: Mon, 17 Apr 2023 18:43:17 +0200 Subject: [PATCH 35/54] feat(GODT-2239): bridgepp worker/overseer unit tests. --- .../bridge-gui/bridgepp/CMakeLists.txt | 6 +- .../Test/{Exception => }/TestBridgeUtils.cpp | 0 .../Test/{Exception => }/TestException.cpp | 0 .../bridge-gui/bridgepp/Test/TestWorker.cpp | 215 ++++++++++++++++++ .../bridge-gui/bridgepp/Test/TestWorker.h | 88 +++++++ 5 files changed, 306 insertions(+), 3 deletions(-) rename internal/frontend/bridge-gui/bridgepp/Test/{Exception => }/TestBridgeUtils.cpp (100%) rename internal/frontend/bridge-gui/bridgepp/Test/{Exception => }/TestException.cpp (100%) create mode 100644 internal/frontend/bridge-gui/bridgepp/Test/TestWorker.cpp create mode 100644 internal/frontend/bridge-gui/bridgepp/Test/TestWorker.h diff --git a/internal/frontend/bridge-gui/bridgepp/CMakeLists.txt b/internal/frontend/bridge-gui/bridgepp/CMakeLists.txt index 9c5eb38f..fafd1c25 100644 --- a/internal/frontend/bridge-gui/bridgepp/CMakeLists.txt +++ b/internal/frontend/bridge-gui/bridgepp/CMakeLists.txt @@ -186,9 +186,9 @@ enable_testing() # Tests #***************************************************************************************************************************************************** add_executable(bridgepp-test - Test/Exception/TestBridgeUtils.cpp - Test/Exception/TestException.cpp - ) + Test/TestBridgeUtils.cpp + Test/TestException.cpp + Test/TestWorker.cpp Test/TestWorker.h) add_dependencies(bridgepp-test bridgepp) target_precompile_headers(bridgepp-test PRIVATE Pch.h) target_link_libraries(bridgepp-test diff --git a/internal/frontend/bridge-gui/bridgepp/Test/Exception/TestBridgeUtils.cpp b/internal/frontend/bridge-gui/bridgepp/Test/TestBridgeUtils.cpp similarity index 100% rename from internal/frontend/bridge-gui/bridgepp/Test/Exception/TestBridgeUtils.cpp rename to internal/frontend/bridge-gui/bridgepp/Test/TestBridgeUtils.cpp diff --git a/internal/frontend/bridge-gui/bridgepp/Test/Exception/TestException.cpp b/internal/frontend/bridge-gui/bridgepp/Test/TestException.cpp similarity index 100% rename from internal/frontend/bridge-gui/bridgepp/Test/Exception/TestException.cpp rename to internal/frontend/bridge-gui/bridgepp/Test/TestException.cpp diff --git a/internal/frontend/bridge-gui/bridgepp/Test/TestWorker.cpp b/internal/frontend/bridge-gui/bridgepp/Test/TestWorker.cpp new file mode 100644 index 00000000..6f6eb5bb --- /dev/null +++ b/internal/frontend/bridge-gui/bridgepp/Test/TestWorker.cpp @@ -0,0 +1,215 @@ +// Copyright (c) 2023 Proton AG +// +// This file is part of Proton Mail 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 . + +// clazy:excludeall=lambda-in-connect + +#include "TestWorker.h" +#include +#include + + +using namespace bridgepp; + + +namespace { + + +qint32 dummyArgc = 1; ///< A dummy int value because QCoreApplication constructor requires a reference to it. + + +} + + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +Workers::Workers() + : testing::Test() + , app_(dummyArgc, nullptr) { +} + + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +void Workers::SetUp() { + Test::SetUp(); + + EXPECT_NO_THROW(worker_ = new TestWorker); + + QObject::connect(worker_, &TestWorker::started, [&]() { results_.started = true; }); + QObject::connect(worker_, &TestWorker::finished, [&]() { results_.finished = true; }); + QObject::connect(worker_, &TestWorker::finished, &loop_, &QEventLoop::quit); + QObject::connect(worker_, &TestWorker::error, [&] { results_.error = true; }); + QObject::connect(worker_, &TestWorker::error, &loop_, &QEventLoop::quit); + QObject::connect(worker_, &TestWorker::error, [&] { results_.error = true; }); + QObject::connect(worker_, &TestWorker::error, &loop_, &QEventLoop::quit); + QObject::connect(worker_, &TestWorker::cancelled, [&] { results_.cancelled = true; }); + QObject::connect(worker_, &TestWorker::cancelled, &loop_, &QEventLoop::quit); + + overseer_ = std::make_unique(worker_, nullptr); +} + + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +void Workers::TearDown() { + EXPECT_NO_FATAL_FAILURE(overseer_.reset()); + Test::TearDown(); +} + + +//**************************************************************************************************************************************************** +/// \param[in] lifetimeMs The lifetime of the worker in milliseconds. +/// \param[in] willSucceed Will the worker succeed (emit finished) or fail (emit error). +//**************************************************************************************************************************************************** +TestWorker::TestWorker() + : Worker(nullptr) { +} + + +//**************************************************************************************************************************************************** +/// \param[in] lifetimeMs The lifetime of the worker in milliseconds. +//**************************************************************************************************************************************************** +void TestWorker::setLifetime(qint64 lifetimeMs) { + lifetimeMs_ = lifetimeMs; +} + + +//**************************************************************************************************************************************************** +/// \param[in] willSucceed Will the worker succeed? +//**************************************************************************************************************************************************** +void TestWorker::setWillSucceed(bool willSucceed) { + willSucceed_ = willSucceed; +} + + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +void TestWorker::run() { + emit started(); + + QElapsedTimer timer; + timer.start(); + while (true) { + if (cancelled_.loadRelaxed()) { + emit cancelled(); + return; + } + if (timer.elapsed() >= lifetimeMs_) { + break; + } + } + + if (willSucceed_) { + emit finished(); + } else { + emit error(QString()); + } +} + + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +void TestWorker::cancel() { + cancelled_.storeRelaxed(1); +} + + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +TEST_F(Workers, SuccessfulWorker) { + worker_->setLifetime(10); + worker_->setWillSucceed(true); + + EXPECT_NO_THROW(overseer_->startWorker(false)); + EXPECT_NO_THROW(loop_.exec()); + + EXPECT_TRUE(results_.started); + EXPECT_TRUE(results_.finished); + EXPECT_FALSE(results_.error); + EXPECT_FALSE(results_.cancelled); + + EXPECT_TRUE(overseer_->worker() != nullptr); // overseer started without autorelease. +} + + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +TEST_F(Workers, ErrorWorker) { + worker_->setLifetime(10); + worker_->setWillSucceed(false); + + EXPECT_NO_THROW(overseer_->startWorker(true)); + EXPECT_NO_THROW(loop_.exec()); + + EXPECT_TRUE(results_.started); + EXPECT_FALSE(results_.finished); + EXPECT_TRUE(results_.error); + EXPECT_FALSE(results_.cancelled); + + EXPECT_TRUE(overseer_->worker() == nullptr); // overseer started with autorelease. +} + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +TEST_F(Workers, CancelledWorker) { + worker_->setLifetime(10000); + worker_->setWillSucceed(true); + EXPECT_NO_THROW(overseer_->startWorker(false)); + EXPECT_NO_THROW(QTimer::singleShot(10, [&]() { worker_->cancel(); })); + + EXPECT_NO_THROW(loop_.exec()); + + EXPECT_TRUE(results_.started); + EXPECT_FALSE(results_.finished); + EXPECT_FALSE(results_.error); + EXPECT_TRUE(results_.cancelled); +} + + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +TEST_F(Workers, Wait) { + worker_->setLifetime(10000); + worker_->setWillSucceed(true); + overseer_->startWorker(true); + + bool isFinished = false; + EXPECT_NO_THROW(isFinished = overseer_->isFinished()); + EXPECT_FALSE(isFinished); + + EXPECT_NO_THROW(isFinished = overseer_->wait(10)); + EXPECT_FALSE(isFinished); + + worker_->cancel(); + + EXPECT_NO_THROW(isFinished = overseer_->wait(10000)); + EXPECT_TRUE(isFinished); + + EXPECT_NO_THROW(isFinished = overseer_->isFinished()); + EXPECT_TRUE(isFinished); +} + + diff --git a/internal/frontend/bridge-gui/bridgepp/Test/TestWorker.h b/internal/frontend/bridge-gui/bridgepp/Test/TestWorker.h new file mode 100644 index 00000000..abfde90c --- /dev/null +++ b/internal/frontend/bridge-gui/bridgepp/Test/TestWorker.h @@ -0,0 +1,88 @@ +// Copyright (c) 2023 Proton AG +// +// This file is part of Proton Mail 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 . + + +#ifndef BRIDGE_GUI_TEST_WORKER_H +#define BRIDGE_GUI_TEST_WORKER_H + + +#include +#include + + +//**************************************************************************************************************************************************** +/// \brief Test worker class. +/// +/// This worker simply waits: +/// - For a specified amount of time and will succeed (emit finished()) or fail (emit error()) based on its parameters. +/// - to be cancelled (and will emit cancelled in that case). +//**************************************************************************************************************************************************** +class TestWorker : public bridgepp::Worker { +Q_OBJECT +public: // member functions. + TestWorker(); ///< Default constructor. + TestWorker(TestWorker const &) = delete; ///< Disabled copy-constructor. + TestWorker(TestWorker &&) = delete; ///< Disabled assignment copy-constructor. + ~TestWorker() override = default; ///< Destructor. + TestWorker &operator=(TestWorker const &) = delete; ///< Disabled assignment operator. + TestWorker &operator=(TestWorker &&) = delete; ///< Disabled move assignment operator. + void setLifetime(qint64 lifetimeMs); ///< Set the lifetime of the worker. + void setWillSucceed(bool willSucceed); ///< Set if the worker will succeed. + void run() override; ///< Run the worker. + void cancel(); ///< Cancel the worker. + +private: // data members + qint64 lifetimeMs_ { 10 }; ///< The lifetime of the worker in milliseconds. + bool willSucceed_ { true }; ///< Will the worker succeed? + QAtomicInteger cancelled_; ///< Has the worker been cancelled. +}; + + +//**************************************************************************************************************************************************** +/// \brief Fixture class for worker tests. +//**************************************************************************************************************************************************** +class Workers : public testing::Test { +public: // member functions. + Workers(); ///< Default constructor. + Workers(Workers const &) = delete; ///< Disabled copy-constructor. + Workers(Workers &&) = delete; ///< Disabled assignment copy-constructor. + ~Workers() = default; ///< Destructor. + Workers &operator=(Workers const &) = delete; ///< Disabled assignment operator. + Workers &operator=(Workers &&) = delete; ///< Disabled move assignment operator. + +protected: // member functions. + void SetUp() override; ///< Setup the fixture. + void TearDown() override; ///< Tear down the fixture. + +protected: // data type + struct Results { + bool started { false }; + bool finished { false }; + bool error { false }; + bool cancelled { false }; + }; ///< Test results data type + +protected: // data members + QCoreApplication app_; ///< The Qt application required for event loop. + bridgepp::UPOverseer overseer_; ///< The overseer for the worker. + TestWorker *worker_ { nullptr }; ///< The worker. + QEventLoop loop_; ///< The event loop. + Results results_; ///< The test results. +}; + + +#endif //BRIDGE_GUI_TEST_WORKER_H From f4631c4bc9344c81638fafd3c50ab34e991eec25 Mon Sep 17 00:00:00 2001 From: Xavier Michelon Date: Tue, 18 Apr 2023 11:10:16 +0200 Subject: [PATCH 36/54] feat(GODT-2555): add local telemetry settings. feat(GODT-2555): add 'TelemetryDisabled' settings to vault. feat(GODT-2555): CLI and GUI implementation. feat(GODT-2555): implemented setting in bridge-gui-tester. feat(GODT-2555): added unit tests. feat(GODT-2555): feature tests. --- internal/bridge/bridge.go | 4 + internal/bridge/settings.go | 8 + .../bridge-gui-tester/GRPCQtProxy.cpp | 8 + .../bridge-gui-tester/GRPCQtProxy.h | 2 + .../bridge-gui-tester/GRPCService.cpp | 23 + .../bridge-gui-tester/GRPCService.h | 2 + .../bridge-gui-tester/Tabs/SettingsTab.cpp | 16 + .../bridge-gui-tester/Tabs/SettingsTab.h | 2 + .../bridge-gui-tester/Tabs/SettingsTab.ui | 7 + .../bridge-gui/bridge-gui/QMLBackend.cpp | 25 +- .../bridge-gui/bridge-gui/QMLBackend.h | 4 + .../bridge-gui/qml/GeneralSettings.qml | 13 + .../bridgepp/bridgepp/GRPC/GRPCClient.cpp | 19 +- .../bridgepp/bridgepp/GRPC/GRPCClient.h | 2 + .../bridgepp/bridgepp/GRPC/bridge.grpc.pb.cc | 274 +++-- .../bridgepp/bridgepp/GRPC/bridge.grpc.pb.h | 1094 +++++++++++------ .../bridgepp/bridgepp/GRPC/bridge.pb.cc | 162 +-- internal/frontend/cli/frontend.go | 17 + internal/frontend/cli/system.go | 32 + internal/frontend/grpc/bridge.pb.go | 567 ++++----- internal/frontend/grpc/bridge.proto | 2 + internal/frontend/grpc/bridge_grpc.pb.go | 369 +++--- internal/frontend/grpc/service_methods.go | 17 + internal/vault/settings.go | 12 + internal/vault/settings_test.go | 14 + internal/vault/types_settings.go | 22 +- tests/bdd_test.go | 2 + tests/bridge_test.go | 8 + tests/features/user/telemetry.feature | 12 + 29 files changed, 1700 insertions(+), 1039 deletions(-) diff --git a/internal/bridge/bridge.go b/internal/bridge/bridge.go index 11993d7c..4a9efa1e 100644 --- a/internal/bridge/bridge.go +++ b/internal/bridge/bridge.go @@ -483,6 +483,10 @@ func (bridge *Bridge) ComputeTelemetry() bool { var telemetry = true safe.RLock(func() { + if bridge.GetTelemetryDisabled() { + telemetry = false + return + } for _, user := range bridge.users { telemetry = telemetry && user.IsTelemetryEnabled(context.Background()) } diff --git a/internal/bridge/settings.go b/internal/bridge/settings.go index 8c262cc9..1b38f323 100644 --- a/internal/bridge/settings.go +++ b/internal/bridge/settings.go @@ -271,6 +271,14 @@ func (bridge *Bridge) SetAutoUpdate(autoUpdate bool) error { return nil } +func (bridge *Bridge) GetTelemetryDisabled() bool { + return bridge.vault.GetTelemetryDisabled() +} + +func (bridge *Bridge) SetTelemetryDisabled(isDisabled bool) error { + return bridge.vault.SetTelemetryDisabled(isDisabled) +} + func (bridge *Bridge) GetUpdateChannel() updater.Channel { return bridge.vault.GetUpdateChannel() } diff --git a/internal/frontend/bridge-gui/bridge-gui-tester/GRPCQtProxy.cpp b/internal/frontend/bridge-gui/bridge-gui-tester/GRPCQtProxy.cpp index ecd8e38d..205e0bbd 100644 --- a/internal/frontend/bridge-gui/bridge-gui-tester/GRPCQtProxy.cpp +++ b/internal/frontend/bridge-gui/bridge-gui-tester/GRPCQtProxy.cpp @@ -39,6 +39,7 @@ void GRPCQtProxy::connectSignals() { connect(this, &GRPCQtProxy::setIsAutostartOnReceived, &settingsTab, &SettingsTab::setIsAutostartOn); connect(this, &GRPCQtProxy::setIsBetaEnabledReceived, &settingsTab, &SettingsTab::setIsBetaEnabled); connect(this, &GRPCQtProxy::setIsAllMailVisibleReceived, &settingsTab, &SettingsTab::setIsAllMailVisible); + connect(this, &GRPCQtProxy::setIsTelemetryDisabledReceived, &settingsTab, &SettingsTab::setIsTelemetryDisabled); connect(this, &GRPCQtProxy::setColorSchemeNameReceived, &settingsTab, &SettingsTab::setColorSchemeName); connect(this, &GRPCQtProxy::reportBugReceived, &settingsTab, &SettingsTab::setBugReport); connect(this, &GRPCQtProxy::exportTLSCertificatesReceived, &settingsTab, &SettingsTab::exportTLSCertificates); @@ -89,6 +90,13 @@ void GRPCQtProxy::setIsAllMailVisible(bool visible) { } +//**************************************************************************************************************************************************** +/// \param[in] isDisabled Is telemetry disabled? +//**************************************************************************************************************************************************** +void GRPCQtProxy::setIsTelemetryDisabled(bool isDisabled) { + emit setIsTelemetryDisabledReceived(isDisabled); +} + //**************************************************************************************************************************************************** /// \param[in] name The color scheme. //**************************************************************************************************************************************************** diff --git a/internal/frontend/bridge-gui/bridge-gui-tester/GRPCQtProxy.h b/internal/frontend/bridge-gui/bridge-gui-tester/GRPCQtProxy.h index 783cee0b..2f799eae 100644 --- a/internal/frontend/bridge-gui/bridge-gui-tester/GRPCQtProxy.h +++ b/internal/frontend/bridge-gui/bridge-gui-tester/GRPCQtProxy.h @@ -41,6 +41,7 @@ public: // member functions. void setIsAutostartOn(bool on); ///< Forwards a SetIsAutostartOn call via a Qt signal. void setIsBetaEnabled(bool enabled); ///< Forwards a SetIsBetaEnabled call via a Qt signal. void setIsAllMailVisible(bool visible); ///< Forwards a SetIsAllMailVisible call via a Qt signal. + void setIsTelemetryDisabled(bool isDisabled); ///< Forwards a SetIsTelemetryDisabled call via a Qt signal. void setColorSchemeName(QString const &name); ///< Forward a SetColorSchemeName call via a Qt Signal void reportBug(QString const &osType, QString const &osVersion, QString const &emailClient, QString const &address, QString const &description, bool includeLogs); ///< Forwards a ReportBug call via a Qt signal. @@ -62,6 +63,7 @@ signals: void setIsAutostartOnReceived(bool on); ///< Forwards a SetIsAutostartOn call via a Qt signal. void setIsBetaEnabledReceived(bool enabled); ///< Forwards a SetIsBetaEnabled call via a Qt signal. void setIsAllMailVisibleReceived(bool enabled); ///< Forwards a SetIsBetaEnabled call via a Qt signal. + void setIsTelemetryDisabledReceived(bool isDisabled); ///< Forwards a SetIsTelemetryDisabled call via a Qt signal. void setColorSchemeNameReceived(QString const &name); ///< Forward a SetColorScheme call via a Qt Signal void reportBugReceived(QString const &osType, QString const &osVersion, QString const &emailClient, QString const &address, QString const &description, bool includeLogs); ///< Signal for the ReportBug gRPC call diff --git a/internal/frontend/bridge-gui/bridge-gui-tester/GRPCService.cpp b/internal/frontend/bridge-gui/bridge-gui-tester/GRPCService.cpp index 74682adf..a0833b4c 100644 --- a/internal/frontend/bridge-gui/bridge-gui-tester/GRPCService.cpp +++ b/internal/frontend/bridge-gui/bridge-gui-tester/GRPCService.cpp @@ -192,6 +192,28 @@ Status GRPCService::IsAllMailVisible(ServerContext *, Empty const *request, Bool } +//**************************************************************************************************************************************************** +/// \param[in] request The request. +/// \return The status for the call. +//**************************************************************************************************************************************************** +grpc::Status GRPCService::SetIsTelemetryDisabled(::grpc::ServerContext *, ::google::protobuf::BoolValue const *request, ::google::protobuf::Empty *) { + app().log().debug(__FUNCTION__); + qtProxy_.setIsTelemetryDisabledReceived(request->value()); + return Status::OK; +} + + +//**************************************************************************************************************************************************** +/// \param[out] response The response. +/// \return The status for the call. +//**************************************************************************************************************************************************** +grpc::Status GRPCService::IsTelemetryDisabled(::grpc::ServerContext *, ::google::protobuf::Empty const *, ::google::protobuf::BoolValue *response) { + app().log().debug(__FUNCTION__); + response->set_value(app().mainWindow().settingsTab().isTelemetryDisabled()); + return Status::OK; +} + + //**************************************************************************************************************************************************** /// \return The status for the call. //**************************************************************************************************************************************************** @@ -820,3 +842,4 @@ void GRPCService::finishLogin() { qtProxy_.sendDelayedEvent(newLoginFinishedEvent(user->id(), alreadyExist)); } + diff --git a/internal/frontend/bridge-gui/bridge-gui-tester/GRPCService.h b/internal/frontend/bridge-gui/bridge-gui-tester/GRPCService.h index 0c03809b..da5aa6c2 100644 --- a/internal/frontend/bridge-gui/bridge-gui-tester/GRPCService.h +++ b/internal/frontend/bridge-gui/bridge-gui-tester/GRPCService.h @@ -51,6 +51,8 @@ public: // member functions. grpc::Status IsBetaEnabled(::grpc::ServerContext *, ::google::protobuf::Empty const *, ::google::protobuf::BoolValue *response) override; grpc::Status SetIsAllMailVisible(::grpc::ServerContext *context, ::google::protobuf::BoolValue const *request, ::google::protobuf::Empty *response) override; grpc::Status IsAllMailVisible(::grpc::ServerContext *context, ::google::protobuf::Empty const *request, ::google::protobuf::BoolValue *response) override; + grpc::Status SetIsTelemetryDisabled(::grpc::ServerContext *, ::google::protobuf::BoolValue const *request, ::google::protobuf::Empty *response) override; + grpc::Status IsTelemetryDisabled(::grpc::ServerContext *, ::google::protobuf::Empty const *request, ::google::protobuf::BoolValue *response) override; grpc::Status TriggerReset(::grpc::ServerContext *, ::google::protobuf::Empty const *, ::google::protobuf::Empty *) override; grpc::Status Version(::grpc::ServerContext *, ::google::protobuf::Empty const *, ::google::protobuf::StringValue *response) override; grpc::Status LogsPath(::grpc::ServerContext *, ::google::protobuf::Empty const *, ::google::protobuf::StringValue *response) override; diff --git a/internal/frontend/bridge-gui/bridge-gui-tester/Tabs/SettingsTab.cpp b/internal/frontend/bridge-gui/bridge-gui-tester/Tabs/SettingsTab.cpp index e22d1055..a3d56a5a 100644 --- a/internal/frontend/bridge-gui/bridge-gui-tester/Tabs/SettingsTab.cpp +++ b/internal/frontend/bridge-gui/bridge-gui-tester/Tabs/SettingsTab.cpp @@ -202,6 +202,22 @@ void SettingsTab::setIsAllMailVisible(bool visible) { } +//**************************************************************************************************************************************************** +/// \return the value for the 'Disabled Telemetry' check. +//**************************************************************************************************************************************************** +bool SettingsTab::isTelemetryDisabled() const { + return ui_.checkIsTelemetryDisabled->isChecked(); +} + + +//**************************************************************************************************************************************************** +/// \param[in] isDisabled The new value for the 'Disable Telemetry' check box. +//**************************************************************************************************************************************************** +void SettingsTab::setIsTelemetryDisabled(bool isDisabled) { + ui_.checkIsTelemetryDisabled->setChecked(isDisabled); +} + + //**************************************************************************************************************************************************** /// \return The delay to apply before sending automatically generated events. //**************************************************************************************************************************************************** diff --git a/internal/frontend/bridge-gui/bridge-gui-tester/Tabs/SettingsTab.h b/internal/frontend/bridge-gui/bridge-gui-tester/Tabs/SettingsTab.h index 6dc4074d..2d082fc8 100644 --- a/internal/frontend/bridge-gui/bridge-gui-tester/Tabs/SettingsTab.h +++ b/internal/frontend/bridge-gui/bridge-gui-tester/Tabs/SettingsTab.h @@ -45,6 +45,7 @@ public: // member functions. bool isAutostartOn() const; ///< Get the value for the 'Autostart' check. bool isBetaEnabled() const; ///< Get the value for the 'Beta Enabled' check. bool isAllMailVisible() const; ///< Get the value for the 'All Mail Visible' check. + bool isTelemetryDisabled() const; ///< Get the value for the 'Disable Telemetry' check box. QString colorSchemeName() const; ///< Get the value of the 'Use Dark Theme' checkbox. qint32 eventDelayMs() const; ///< Get the delay for sending automatically generated events. QString logsPath() const; ///< Get the content of the 'Logs Path' edit. @@ -74,6 +75,7 @@ public slots: void setIsAutostartOn(bool on); ///< Set the value for the 'Autostart' check box. void setIsBetaEnabled(bool enabled); ///< Set the value for the 'Beta Enabled' check box. void setIsAllMailVisible(bool visible); ///< Set the value for the 'All Mail Visible' check box. + void setIsTelemetryDisabled(bool isDisabled); ///< Set the value for the 'Disable Telemetry' check box. void setColorSchemeName(QString const &name); ///< Set the value for the 'Use Dark Theme' check box. void setBugReport(QString const &osType, QString const &osVersion, QString const &emailClient, QString const &address, QString const &description, bool includeLogs); ///< Set the content of the bug report box. diff --git a/internal/frontend/bridge-gui/bridge-gui-tester/Tabs/SettingsTab.ui b/internal/frontend/bridge-gui/bridge-gui-tester/Tabs/SettingsTab.ui index c83bc278..7fb5b74e 100644 --- a/internal/frontend/bridge-gui/bridge-gui-tester/Tabs/SettingsTab.ui +++ b/internal/frontend/bridge-gui/bridge-gui-tester/Tabs/SettingsTab.ui @@ -170,6 +170,13 @@ + + + + Disable Telemetry + + + diff --git a/internal/frontend/bridge-gui/bridge-gui/QMLBackend.cpp b/internal/frontend/bridge-gui/bridge-gui/QMLBackend.cpp index 5671245a..eab26749 100644 --- a/internal/frontend/bridge-gui/bridge-gui/QMLBackend.cpp +++ b/internal/frontend/bridge-gui/bridge-gui/QMLBackend.cpp @@ -24,7 +24,6 @@ #include #include #include -#include #define HANDLE_EXCEPTION(x) try { x } \ @@ -335,6 +334,18 @@ bool QMLBackend::isAllMailVisible() const { } +//**************************************************************************************************************************************************** +/// \return The value for the 'isAllMailVisible' property. +//**************************************************************************************************************************************************** +bool QMLBackend::isTelemetryDisabled() const { + HANDLE_EXCEPTION_RETURN_BOOL( + bool v; + app().grpc().isTelemetryDisabled(v); + return v; + ) +} + + //**************************************************************************************************************************************************** /// \return The value for the 'colorSchemeName' property. //**************************************************************************************************************************************************** @@ -569,6 +580,18 @@ void QMLBackend::changeIsAllMailVisible(bool isVisible) { } +//**************************************************************************************************************************************************** +/// \param[in] isDisabled The new state of the 'Is telemetry disabled property'. +//**************************************************************************************************************************************************** +void QMLBackend::toggleIsTelemetryDisabled(bool isDisabled) { + HANDLE_EXCEPTION( + app().grpc().setIsTelemetryDisabled(isDisabled); + emit isTelemetryDisabledChanged(isDisabled); + ) +} + + + //**************************************************************************************************************************************************** /// \param[in] scheme the scheme name //**************************************************************************************************************************************************** diff --git a/internal/frontend/bridge-gui/bridge-gui/QMLBackend.h b/internal/frontend/bridge-gui/bridge-gui/QMLBackend.h index 80754c6f..2afbc8ee 100644 --- a/internal/frontend/bridge-gui/bridge-gui/QMLBackend.h +++ b/internal/frontend/bridge-gui/bridge-gui/QMLBackend.h @@ -67,6 +67,7 @@ public: // Qt/QML properties. Note that the NOTIFY-er signal is required even fo Q_PROPERTY(bool isAutostartOn READ isAutostartOn NOTIFY isAutostartOnChanged) Q_PROPERTY(bool isBetaEnabled READ isBetaEnabled NOTIFY isBetaEnabledChanged) Q_PROPERTY(bool isAllMailVisible READ isAllMailVisible NOTIFY isAllMailVisibleChanged) + Q_PROPERTY(bool isTelemetryDisabled READ isTelemetryDisabled NOTIFY isTelemetryDisabledChanged) Q_PROPERTY(QString colorSchemeName READ colorSchemeName NOTIFY colorSchemeNameChanged) Q_PROPERTY(QUrl diskCachePath READ diskCachePath NOTIFY diskCachePathChanged) Q_PROPERTY(bool useSSLForIMAP READ useSSLForIMAP WRITE setUseSSLForIMAP NOTIFY useSSLForIMAPChanged) @@ -99,6 +100,7 @@ public: // Qt/QML properties. Note that the NOTIFY-er signal is required even fo bool isAutostartOn() const; ///< Getter for the 'isAutostartOn' property. bool isBetaEnabled() const; ///< Getter for the 'isBetaEnabled' property. bool isAllMailVisible() const; ///< Getter for the 'isAllMailVisible' property. + bool isTelemetryDisabled() const; ///< Getter for the 'isTelemetryDisabled' property. QString colorSchemeName() const; ///< Getter for the 'colorSchemeName' property. QUrl diskCachePath() const; ///< Getter for the 'diskCachePath' property. void setUseSSLForIMAP(bool value); ///< Setter for the 'useSSLForIMAP' property. @@ -129,6 +131,7 @@ signals: // Signal used by the Qt property system. Many of them are unused but r void isAutomaticUpdateOnChanged(bool value); /// To be forwarded to Bridge void toggleAutostart(bool active); ///< Slot for the autostart toggle. void toggleBeta(bool active); ///< Slot for the beta toggle. void changeIsAllMailVisible(bool isVisible); ///< Slot for the changing of 'All Mail' visibility. + void toggleIsTelemetryDisabled(bool isDisabled); ///< Slot for toggling telemetry on/off. void changeColorScheme(QString const &scheme); ///< Slot for the change of the theme. void setDiskCachePath(QUrl const &path) const; ///< Slot for the change of the disk cache path. void login(QString const &username, QString const &password) const; ///< Slot for the login button (initial login). diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/GeneralSettings.qml b/internal/frontend/bridge-gui/bridge-gui/qml/GeneralSettings.qml index 86b75e72..7d6860da 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/GeneralSettings.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/GeneralSettings.qml @@ -169,6 +169,19 @@ SettingsView { Layout.fillWidth: true } + SettingsItem { + id: telemetry + Layout.fillWidth: true + checked: !Backend.isTelemetryDisabled + colorScheme: root.colorScheme + description: qsTr("Help us improve Proton services by sending anonymous usage statistics.") + text: qsTr("Collect usage diagnostics") + type: SettingsItem.Toggle + visible: root._isAdvancedShown + + onClicked: Backend.toggleIsTelemetryDisabled(telemetry.checked) + } + SettingsItem { id: ports visible: root._isAdvancedShown diff --git a/internal/frontend/bridge-gui/bridgepp/bridgepp/GRPC/GRPCClient.cpp b/internal/frontend/bridge-gui/bridgepp/bridgepp/GRPC/GRPCClient.cpp index 350b78bd..34038c49 100644 --- a/internal/frontend/bridge-gui/bridgepp/bridgepp/GRPC/GRPCClient.cpp +++ b/internal/frontend/bridge-gui/bridgepp/bridgepp/GRPC/GRPCClient.cpp @@ -19,7 +19,6 @@ #include "GRPCClient.h" #include "GRPCUtils.h" #include "GRPCErrors.h" -#include "../BridgeUtils.h" #include "../Exception/Exception.h" #include "../ProcessMonitor.h" #include "../Log/LogUtils.h" @@ -295,6 +294,24 @@ grpc::Status GRPCClient::isAllMailVisible(bool &outIsVisible) { } +//**************************************************************************************************************************************************** +/// \param[out] outIsDisabled The value for the property +/// \return The status for the gRPC call. +//**************************************************************************************************************************************************** +grpc::Status GRPCClient::isTelemetryDisabled(bool &outIsDisabled) { + return this->logGRPCCallStatus(this->getBool(&Bridge::Stub::IsTelemetryDisabled, outIsDisabled), __FUNCTION__); +} + + +//**************************************************************************************************************************************************** +/// \param[out] isDisabled The new value for the property +/// \return The status for the gRPC call. +//**************************************************************************************************************************************************** +grpc::Status GRPCClient::setIsTelemetryDisabled(bool isDisabled) { + return this->logGRPCCallStatus(this->setBool(&Bridge::Stub::SetIsTelemetryDisabled, isDisabled), __FUNCTION__); +} + + //**************************************************************************************************************************************************** /// \param[in] isVisible The new value for the property. /// \return The status for the gRPC call. diff --git a/internal/frontend/bridge-gui/bridgepp/bridgepp/GRPC/GRPCClient.h b/internal/frontend/bridge-gui/bridgepp/bridgepp/GRPC/GRPCClient.h index 6a8a1a21..6485ce80 100644 --- a/internal/frontend/bridge-gui/bridgepp/bridgepp/GRPC/GRPCClient.h +++ b/internal/frontend/bridge-gui/bridgepp/bridgepp/GRPC/GRPCClient.h @@ -71,6 +71,8 @@ public: // member functions. grpc::Status setIsBetaEnabled(bool enabled); ///< Performs the 'setIsBetaEnabled' gRPC call. grpc::Status isAllMailVisible(bool &outIsVisible); ///< Performs the "isAllMailVisible" gRPC call. grpc::Status setIsAllMailVisible(bool isVisible); ///< Performs the 'setIsAllMailVisible' gRPC call. + grpc::Status isTelemetryDisabled(bool &outIsDisabled); ///< Performs the 'setIsTelemetryDisabled' gRPC call. + grpc::Status setIsTelemetryDisabled(bool isDisabled); ///< Performs the 'isTelemetryDisabled' gRPC call. grpc::Status colorSchemeName(QString &outName); ///< Performs the "colorSchemeName' gRPC call. grpc::Status setColorSchemeName(QString const &name); ///< Performs the "setColorSchemeName' gRPC call. grpc::Status currentEmailClient(QString &outName); ///< Performs the 'currentEmailClient' gRPC call. diff --git a/internal/frontend/bridge-gui/bridgepp/bridgepp/GRPC/bridge.grpc.pb.cc b/internal/frontend/bridge-gui/bridgepp/bridgepp/GRPC/bridge.grpc.pb.cc index b8270a02..53beac31 100644 --- a/internal/frontend/bridge-gui/bridgepp/bridgepp/GRPC/bridge.grpc.pb.cc +++ b/internal/frontend/bridge-gui/bridgepp/bridgepp/GRPC/bridge.grpc.pb.cc @@ -34,6 +34,8 @@ static const char* Bridge_method_names[] = { "/grpc.Bridge/IsBetaEnabled", "/grpc.Bridge/SetIsAllMailVisible", "/grpc.Bridge/IsAllMailVisible", + "/grpc.Bridge/SetIsTelemetryDisabled", + "/grpc.Bridge/IsTelemetryDisabled", "/grpc.Bridge/GoOs", "/grpc.Bridge/TriggerReset", "/grpc.Bridge/Version", @@ -98,49 +100,51 @@ Bridge::Stub::Stub(const std::shared_ptr< ::grpc::ChannelInterface>& channel, co , rpcmethod_IsBetaEnabled_(Bridge_method_names[9], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) , rpcmethod_SetIsAllMailVisible_(Bridge_method_names[10], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) , rpcmethod_IsAllMailVisible_(Bridge_method_names[11], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_GoOs_(Bridge_method_names[12], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_TriggerReset_(Bridge_method_names[13], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_Version_(Bridge_method_names[14], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_LogsPath_(Bridge_method_names[15], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_LicensePath_(Bridge_method_names[16], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_ReleaseNotesPageLink_(Bridge_method_names[17], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_DependencyLicensesLink_(Bridge_method_names[18], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_LandingPageLink_(Bridge_method_names[19], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_SetColorSchemeName_(Bridge_method_names[20], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_ColorSchemeName_(Bridge_method_names[21], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_CurrentEmailClient_(Bridge_method_names[22], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_ReportBug_(Bridge_method_names[23], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_ExportTLSCertificates_(Bridge_method_names[24], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_ForceLauncher_(Bridge_method_names[25], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_SetMainExecutable_(Bridge_method_names[26], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_Login_(Bridge_method_names[27], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_Login2FA_(Bridge_method_names[28], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_Login2Passwords_(Bridge_method_names[29], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_LoginAbort_(Bridge_method_names[30], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_CheckUpdate_(Bridge_method_names[31], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_InstallUpdate_(Bridge_method_names[32], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_SetIsAutomaticUpdateOn_(Bridge_method_names[33], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_IsAutomaticUpdateOn_(Bridge_method_names[34], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_DiskCachePath_(Bridge_method_names[35], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_SetDiskCachePath_(Bridge_method_names[36], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_SetIsDoHEnabled_(Bridge_method_names[37], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_IsDoHEnabled_(Bridge_method_names[38], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_MailServerSettings_(Bridge_method_names[39], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_SetMailServerSettings_(Bridge_method_names[40], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_Hostname_(Bridge_method_names[41], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_IsPortFree_(Bridge_method_names[42], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_AvailableKeychains_(Bridge_method_names[43], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_SetCurrentKeychain_(Bridge_method_names[44], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_CurrentKeychain_(Bridge_method_names[45], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_GetUserList_(Bridge_method_names[46], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_GetUser_(Bridge_method_names[47], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_SetUserSplitMode_(Bridge_method_names[48], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_SendBadEventUserFeedback_(Bridge_method_names[49], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_LogoutUser_(Bridge_method_names[50], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_RemoveUser_(Bridge_method_names[51], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_ConfigureUserAppleMail_(Bridge_method_names[52], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) - , rpcmethod_RunEventStream_(Bridge_method_names[53], options.suffix_for_stats(),::grpc::internal::RpcMethod::SERVER_STREAMING, channel) - , rpcmethod_StopEventStream_(Bridge_method_names[54], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_SetIsTelemetryDisabled_(Bridge_method_names[12], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_IsTelemetryDisabled_(Bridge_method_names[13], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_GoOs_(Bridge_method_names[14], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_TriggerReset_(Bridge_method_names[15], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_Version_(Bridge_method_names[16], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_LogsPath_(Bridge_method_names[17], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_LicensePath_(Bridge_method_names[18], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_ReleaseNotesPageLink_(Bridge_method_names[19], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_DependencyLicensesLink_(Bridge_method_names[20], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_LandingPageLink_(Bridge_method_names[21], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_SetColorSchemeName_(Bridge_method_names[22], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_ColorSchemeName_(Bridge_method_names[23], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_CurrentEmailClient_(Bridge_method_names[24], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_ReportBug_(Bridge_method_names[25], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_ExportTLSCertificates_(Bridge_method_names[26], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_ForceLauncher_(Bridge_method_names[27], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_SetMainExecutable_(Bridge_method_names[28], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_Login_(Bridge_method_names[29], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_Login2FA_(Bridge_method_names[30], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_Login2Passwords_(Bridge_method_names[31], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_LoginAbort_(Bridge_method_names[32], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_CheckUpdate_(Bridge_method_names[33], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_InstallUpdate_(Bridge_method_names[34], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_SetIsAutomaticUpdateOn_(Bridge_method_names[35], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_IsAutomaticUpdateOn_(Bridge_method_names[36], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_DiskCachePath_(Bridge_method_names[37], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_SetDiskCachePath_(Bridge_method_names[38], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_SetIsDoHEnabled_(Bridge_method_names[39], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_IsDoHEnabled_(Bridge_method_names[40], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_MailServerSettings_(Bridge_method_names[41], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_SetMailServerSettings_(Bridge_method_names[42], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_Hostname_(Bridge_method_names[43], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_IsPortFree_(Bridge_method_names[44], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_AvailableKeychains_(Bridge_method_names[45], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_SetCurrentKeychain_(Bridge_method_names[46], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_CurrentKeychain_(Bridge_method_names[47], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_GetUserList_(Bridge_method_names[48], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_GetUser_(Bridge_method_names[49], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_SetUserSplitMode_(Bridge_method_names[50], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_SendBadEventUserFeedback_(Bridge_method_names[51], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_LogoutUser_(Bridge_method_names[52], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_RemoveUser_(Bridge_method_names[53], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_ConfigureUserAppleMail_(Bridge_method_names[54], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) + , rpcmethod_RunEventStream_(Bridge_method_names[55], options.suffix_for_stats(),::grpc::internal::RpcMethod::SERVER_STREAMING, channel) + , rpcmethod_StopEventStream_(Bridge_method_names[56], options.suffix_for_stats(),::grpc::internal::RpcMethod::NORMAL_RPC, channel) {} ::grpc::Status Bridge::Stub::CheckTokens(::grpc::ClientContext* context, const ::google::protobuf::StringValue& request, ::google::protobuf::StringValue* response) { @@ -419,6 +423,52 @@ void Bridge::Stub::async::IsAllMailVisible(::grpc::ClientContext* context, const return result; } +::grpc::Status Bridge::Stub::SetIsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::BoolValue& request, ::google::protobuf::Empty* response) { + return ::grpc::internal::BlockingUnaryCall< ::google::protobuf::BoolValue, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(channel_.get(), rpcmethod_SetIsTelemetryDisabled_, context, request, response); +} + +void Bridge::Stub::async::SetIsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::BoolValue* request, ::google::protobuf::Empty* response, std::function f) { + ::grpc::internal::CallbackUnaryCall< ::google::protobuf::BoolValue, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(stub_->channel_.get(), stub_->rpcmethod_SetIsTelemetryDisabled_, context, request, response, std::move(f)); +} + +void Bridge::Stub::async::SetIsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::BoolValue* request, ::google::protobuf::Empty* response, ::grpc::ClientUnaryReactor* reactor) { + ::grpc::internal::ClientCallbackUnaryFactory::Create< ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(stub_->channel_.get(), stub_->rpcmethod_SetIsTelemetryDisabled_, context, request, response, reactor); +} + +::grpc::ClientAsyncResponseReader< ::google::protobuf::Empty>* Bridge::Stub::PrepareAsyncSetIsTelemetryDisabledRaw(::grpc::ClientContext* context, const ::google::protobuf::BoolValue& request, ::grpc::CompletionQueue* cq) { + return ::grpc::internal::ClientAsyncResponseReaderHelper::Create< ::google::protobuf::Empty, ::google::protobuf::BoolValue, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(channel_.get(), cq, rpcmethod_SetIsTelemetryDisabled_, context, request); +} + +::grpc::ClientAsyncResponseReader< ::google::protobuf::Empty>* Bridge::Stub::AsyncSetIsTelemetryDisabledRaw(::grpc::ClientContext* context, const ::google::protobuf::BoolValue& request, ::grpc::CompletionQueue* cq) { + auto* result = + this->PrepareAsyncSetIsTelemetryDisabledRaw(context, request, cq); + result->StartCall(); + return result; +} + +::grpc::Status Bridge::Stub::IsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::google::protobuf::BoolValue* response) { + return ::grpc::internal::BlockingUnaryCall< ::google::protobuf::Empty, ::google::protobuf::BoolValue, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(channel_.get(), rpcmethod_IsTelemetryDisabled_, context, request, response); +} + +void Bridge::Stub::async::IsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::BoolValue* response, std::function f) { + ::grpc::internal::CallbackUnaryCall< ::google::protobuf::Empty, ::google::protobuf::BoolValue, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(stub_->channel_.get(), stub_->rpcmethod_IsTelemetryDisabled_, context, request, response, std::move(f)); +} + +void Bridge::Stub::async::IsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::BoolValue* response, ::grpc::ClientUnaryReactor* reactor) { + ::grpc::internal::ClientCallbackUnaryFactory::Create< ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(stub_->channel_.get(), stub_->rpcmethod_IsTelemetryDisabled_, context, request, response, reactor); +} + +::grpc::ClientAsyncResponseReader< ::google::protobuf::BoolValue>* Bridge::Stub::PrepareAsyncIsTelemetryDisabledRaw(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) { + return ::grpc::internal::ClientAsyncResponseReaderHelper::Create< ::google::protobuf::BoolValue, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(channel_.get(), cq, rpcmethod_IsTelemetryDisabled_, context, request); +} + +::grpc::ClientAsyncResponseReader< ::google::protobuf::BoolValue>* Bridge::Stub::AsyncIsTelemetryDisabledRaw(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) { + auto* result = + this->PrepareAsyncIsTelemetryDisabledRaw(context, request, cq); + result->StartCall(); + return result; +} + ::grpc::Status Bridge::Stub::GoOs(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::google::protobuf::StringValue* response) { return ::grpc::internal::BlockingUnaryCall< ::google::protobuf::Empty, ::google::protobuf::StringValue, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>(channel_.get(), rpcmethod_GoOs_, context, request, response); } @@ -1525,22 +1575,22 @@ Bridge::Service::Service() { AddMethod(new ::grpc::internal::RpcServiceMethod( Bridge_method_names[12], ::grpc::internal::RpcMethod::NORMAL_RPC, - new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::Empty, ::google::protobuf::StringValue, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( + new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::BoolValue, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, ::grpc::ServerContext* ctx, - const ::google::protobuf::Empty* req, - ::google::protobuf::StringValue* resp) { - return service->GoOs(ctx, req, resp); + const ::google::protobuf::BoolValue* req, + ::google::protobuf::Empty* resp) { + return service->SetIsTelemetryDisabled(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( Bridge_method_names[13], ::grpc::internal::RpcMethod::NORMAL_RPC, - new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::Empty, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( + new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::Empty, ::google::protobuf::BoolValue, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, ::grpc::ServerContext* ctx, const ::google::protobuf::Empty* req, - ::google::protobuf::Empty* resp) { - return service->TriggerReset(ctx, req, resp); + ::google::protobuf::BoolValue* resp) { + return service->IsTelemetryDisabled(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( Bridge_method_names[14], @@ -1550,17 +1600,17 @@ Bridge::Service::Service() { ::grpc::ServerContext* ctx, const ::google::protobuf::Empty* req, ::google::protobuf::StringValue* resp) { - return service->Version(ctx, req, resp); + return service->GoOs(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( Bridge_method_names[15], ::grpc::internal::RpcMethod::NORMAL_RPC, - new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::Empty, ::google::protobuf::StringValue, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( + new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::Empty, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, ::grpc::ServerContext* ctx, const ::google::protobuf::Empty* req, - ::google::protobuf::StringValue* resp) { - return service->LogsPath(ctx, req, resp); + ::google::protobuf::Empty* resp) { + return service->TriggerReset(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( Bridge_method_names[16], @@ -1570,7 +1620,7 @@ Bridge::Service::Service() { ::grpc::ServerContext* ctx, const ::google::protobuf::Empty* req, ::google::protobuf::StringValue* resp) { - return service->LicensePath(ctx, req, resp); + return service->Version(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( Bridge_method_names[17], @@ -1580,7 +1630,7 @@ Bridge::Service::Service() { ::grpc::ServerContext* ctx, const ::google::protobuf::Empty* req, ::google::protobuf::StringValue* resp) { - return service->ReleaseNotesPageLink(ctx, req, resp); + return service->LogsPath(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( Bridge_method_names[18], @@ -1590,7 +1640,7 @@ Bridge::Service::Service() { ::grpc::ServerContext* ctx, const ::google::protobuf::Empty* req, ::google::protobuf::StringValue* resp) { - return service->DependencyLicensesLink(ctx, req, resp); + return service->LicensePath(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( Bridge_method_names[19], @@ -1600,17 +1650,17 @@ Bridge::Service::Service() { ::grpc::ServerContext* ctx, const ::google::protobuf::Empty* req, ::google::protobuf::StringValue* resp) { - return service->LandingPageLink(ctx, req, resp); + return service->ReleaseNotesPageLink(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( Bridge_method_names[20], ::grpc::internal::RpcMethod::NORMAL_RPC, - new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::StringValue, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( + new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::Empty, ::google::protobuf::StringValue, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, ::grpc::ServerContext* ctx, - const ::google::protobuf::StringValue* req, - ::google::protobuf::Empty* resp) { - return service->SetColorSchemeName(ctx, req, resp); + const ::google::protobuf::Empty* req, + ::google::protobuf::StringValue* resp) { + return service->DependencyLicensesLink(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( Bridge_method_names[21], @@ -1620,11 +1670,31 @@ Bridge::Service::Service() { ::grpc::ServerContext* ctx, const ::google::protobuf::Empty* req, ::google::protobuf::StringValue* resp) { - return service->ColorSchemeName(ctx, req, resp); + return service->LandingPageLink(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( Bridge_method_names[22], ::grpc::internal::RpcMethod::NORMAL_RPC, + new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::StringValue, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( + [](Bridge::Service* service, + ::grpc::ServerContext* ctx, + const ::google::protobuf::StringValue* req, + ::google::protobuf::Empty* resp) { + return service->SetColorSchemeName(ctx, req, resp); + }, this))); + AddMethod(new ::grpc::internal::RpcServiceMethod( + Bridge_method_names[23], + ::grpc::internal::RpcMethod::NORMAL_RPC, + new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::Empty, ::google::protobuf::StringValue, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( + [](Bridge::Service* service, + ::grpc::ServerContext* ctx, + const ::google::protobuf::Empty* req, + ::google::protobuf::StringValue* resp) { + return service->ColorSchemeName(ctx, req, resp); + }, this))); + AddMethod(new ::grpc::internal::RpcServiceMethod( + Bridge_method_names[24], + ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::Empty, ::google::protobuf::StringValue, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, ::grpc::ServerContext* ctx, @@ -1633,7 +1703,7 @@ Bridge::Service::Service() { return service->CurrentEmailClient(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[23], + Bridge_method_names[25], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::grpc::ReportBugRequest, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1643,7 +1713,7 @@ Bridge::Service::Service() { return service->ReportBug(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[24], + Bridge_method_names[26], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::StringValue, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1653,7 +1723,7 @@ Bridge::Service::Service() { return service->ExportTLSCertificates(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[25], + Bridge_method_names[27], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::StringValue, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1663,7 +1733,7 @@ Bridge::Service::Service() { return service->ForceLauncher(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[26], + Bridge_method_names[28], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::StringValue, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1673,7 +1743,7 @@ Bridge::Service::Service() { return service->SetMainExecutable(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[27], + Bridge_method_names[29], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::grpc::LoginRequest, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1683,7 +1753,7 @@ Bridge::Service::Service() { return service->Login(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[28], + Bridge_method_names[30], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::grpc::LoginRequest, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1693,7 +1763,7 @@ Bridge::Service::Service() { return service->Login2FA(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[29], + Bridge_method_names[31], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::grpc::LoginRequest, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1703,7 +1773,7 @@ Bridge::Service::Service() { return service->Login2Passwords(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[30], + Bridge_method_names[32], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::grpc::LoginAbortRequest, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1713,7 +1783,7 @@ Bridge::Service::Service() { return service->LoginAbort(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[31], + Bridge_method_names[33], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::Empty, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1723,7 +1793,7 @@ Bridge::Service::Service() { return service->CheckUpdate(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[32], + Bridge_method_names[34], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::Empty, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1733,7 +1803,7 @@ Bridge::Service::Service() { return service->InstallUpdate(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[33], + Bridge_method_names[35], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::BoolValue, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1743,7 +1813,7 @@ Bridge::Service::Service() { return service->SetIsAutomaticUpdateOn(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[34], + Bridge_method_names[36], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::Empty, ::google::protobuf::BoolValue, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1753,7 +1823,7 @@ Bridge::Service::Service() { return service->IsAutomaticUpdateOn(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[35], + Bridge_method_names[37], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::Empty, ::google::protobuf::StringValue, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1763,7 +1833,7 @@ Bridge::Service::Service() { return service->DiskCachePath(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[36], + Bridge_method_names[38], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::StringValue, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1773,7 +1843,7 @@ Bridge::Service::Service() { return service->SetDiskCachePath(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[37], + Bridge_method_names[39], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::BoolValue, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1783,7 +1853,7 @@ Bridge::Service::Service() { return service->SetIsDoHEnabled(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[38], + Bridge_method_names[40], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::Empty, ::google::protobuf::BoolValue, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1793,7 +1863,7 @@ Bridge::Service::Service() { return service->IsDoHEnabled(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[39], + Bridge_method_names[41], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::Empty, ::grpc::ImapSmtpSettings, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1803,7 +1873,7 @@ Bridge::Service::Service() { return service->MailServerSettings(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[40], + Bridge_method_names[42], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::grpc::ImapSmtpSettings, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1813,7 +1883,7 @@ Bridge::Service::Service() { return service->SetMailServerSettings(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[41], + Bridge_method_names[43], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::Empty, ::google::protobuf::StringValue, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1823,7 +1893,7 @@ Bridge::Service::Service() { return service->Hostname(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[42], + Bridge_method_names[44], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::Int32Value, ::google::protobuf::BoolValue, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1833,7 +1903,7 @@ Bridge::Service::Service() { return service->IsPortFree(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[43], + Bridge_method_names[45], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::Empty, ::grpc::AvailableKeychainsResponse, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1843,7 +1913,7 @@ Bridge::Service::Service() { return service->AvailableKeychains(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[44], + Bridge_method_names[46], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::StringValue, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1853,7 +1923,7 @@ Bridge::Service::Service() { return service->SetCurrentKeychain(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[45], + Bridge_method_names[47], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::Empty, ::google::protobuf::StringValue, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1863,7 +1933,7 @@ Bridge::Service::Service() { return service->CurrentKeychain(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[46], + Bridge_method_names[48], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::Empty, ::grpc::UserListResponse, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1873,7 +1943,7 @@ Bridge::Service::Service() { return service->GetUserList(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[47], + Bridge_method_names[49], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::StringValue, ::grpc::User, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1883,7 +1953,7 @@ Bridge::Service::Service() { return service->GetUser(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[48], + Bridge_method_names[50], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::grpc::UserSplitModeRequest, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1893,7 +1963,7 @@ Bridge::Service::Service() { return service->SetUserSplitMode(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[49], + Bridge_method_names[51], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::grpc::UserBadEventFeedbackRequest, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1903,7 +1973,7 @@ Bridge::Service::Service() { return service->SendBadEventUserFeedback(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[50], + Bridge_method_names[52], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::StringValue, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1913,7 +1983,7 @@ Bridge::Service::Service() { return service->LogoutUser(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[51], + Bridge_method_names[53], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::StringValue, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1923,7 +1993,7 @@ Bridge::Service::Service() { return service->RemoveUser(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[52], + Bridge_method_names[54], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::grpc::ConfigureAppleMailRequest, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -1933,7 +2003,7 @@ Bridge::Service::Service() { return service->ConfigureUserAppleMail(ctx, req, resp); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[53], + Bridge_method_names[55], ::grpc::internal::RpcMethod::SERVER_STREAMING, new ::grpc::internal::ServerStreamingHandler< Bridge::Service, ::grpc::EventStreamRequest, ::grpc::StreamEvent>( [](Bridge::Service* service, @@ -1943,7 +2013,7 @@ Bridge::Service::Service() { return service->RunEventStream(ctx, req, writer); }, this))); AddMethod(new ::grpc::internal::RpcServiceMethod( - Bridge_method_names[54], + Bridge_method_names[56], ::grpc::internal::RpcMethod::NORMAL_RPC, new ::grpc::internal::RpcMethodHandler< Bridge::Service, ::google::protobuf::Empty, ::google::protobuf::Empty, ::grpc::protobuf::MessageLite, ::grpc::protobuf::MessageLite>( [](Bridge::Service* service, @@ -2041,6 +2111,20 @@ Bridge::Service::~Service() { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } +::grpc::Status Bridge::Service::SetIsTelemetryDisabled(::grpc::ServerContext* context, const ::google::protobuf::BoolValue* request, ::google::protobuf::Empty* response) { + (void) context; + (void) request; + (void) response; + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); +} + +::grpc::Status Bridge::Service::IsTelemetryDisabled(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::BoolValue* response) { + (void) context; + (void) request; + (void) response; + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); +} + ::grpc::Status Bridge::Service::GoOs(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::StringValue* response) { (void) context; (void) request; diff --git a/internal/frontend/bridge-gui/bridgepp/bridgepp/GRPC/bridge.grpc.pb.h b/internal/frontend/bridge-gui/bridgepp/bridgepp/GRPC/bridge.grpc.pb.h index 9d24b1b0..86387cc3 100644 --- a/internal/frontend/bridge-gui/bridgepp/bridgepp/GRPC/bridge.grpc.pb.h +++ b/internal/frontend/bridge-gui/bridgepp/bridgepp/GRPC/bridge.grpc.pb.h @@ -141,6 +141,20 @@ class Bridge final { std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::BoolValue>> PrepareAsyncIsAllMailVisible(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) { return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::BoolValue>>(PrepareAsyncIsAllMailVisibleRaw(context, request, cq)); } + virtual ::grpc::Status SetIsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::BoolValue& request, ::google::protobuf::Empty* response) = 0; + std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::Empty>> AsyncSetIsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::BoolValue& request, ::grpc::CompletionQueue* cq) { + return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::Empty>>(AsyncSetIsTelemetryDisabledRaw(context, request, cq)); + } + std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::Empty>> PrepareAsyncSetIsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::BoolValue& request, ::grpc::CompletionQueue* cq) { + return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::Empty>>(PrepareAsyncSetIsTelemetryDisabledRaw(context, request, cq)); + } + virtual ::grpc::Status IsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::google::protobuf::BoolValue* response) = 0; + std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::BoolValue>> AsyncIsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) { + return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::BoolValue>>(AsyncIsTelemetryDisabledRaw(context, request, cq)); + } + std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::BoolValue>> PrepareAsyncIsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) { + return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::BoolValue>>(PrepareAsyncIsTelemetryDisabledRaw(context, request, cq)); + } virtual ::grpc::Status GoOs(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::google::protobuf::StringValue* response) = 0; std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::StringValue>> AsyncGoOs(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) { return std::unique_ptr< ::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::StringValue>>(AsyncGoOsRaw(context, request, cq)); @@ -481,6 +495,10 @@ class Bridge final { virtual void SetIsAllMailVisible(::grpc::ClientContext* context, const ::google::protobuf::BoolValue* request, ::google::protobuf::Empty* response, ::grpc::ClientUnaryReactor* reactor) = 0; virtual void IsAllMailVisible(::grpc::ClientContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::BoolValue* response, std::function) = 0; virtual void IsAllMailVisible(::grpc::ClientContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::BoolValue* response, ::grpc::ClientUnaryReactor* reactor) = 0; + virtual void SetIsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::BoolValue* request, ::google::protobuf::Empty* response, std::function) = 0; + virtual void SetIsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::BoolValue* request, ::google::protobuf::Empty* response, ::grpc::ClientUnaryReactor* reactor) = 0; + virtual void IsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::BoolValue* response, std::function) = 0; + virtual void IsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::BoolValue* response, ::grpc::ClientUnaryReactor* reactor) = 0; virtual void GoOs(::grpc::ClientContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::StringValue* response, std::function) = 0; virtual void GoOs(::grpc::ClientContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::StringValue* response, ::grpc::ClientUnaryReactor* reactor) = 0; virtual void TriggerReset(::grpc::ClientContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::Empty* response, std::function) = 0; @@ -604,6 +622,10 @@ class Bridge final { virtual ::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::Empty>* PrepareAsyncSetIsAllMailVisibleRaw(::grpc::ClientContext* context, const ::google::protobuf::BoolValue& request, ::grpc::CompletionQueue* cq) = 0; virtual ::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::BoolValue>* AsyncIsAllMailVisibleRaw(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) = 0; virtual ::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::BoolValue>* PrepareAsyncIsAllMailVisibleRaw(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) = 0; + virtual ::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::Empty>* AsyncSetIsTelemetryDisabledRaw(::grpc::ClientContext* context, const ::google::protobuf::BoolValue& request, ::grpc::CompletionQueue* cq) = 0; + virtual ::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::Empty>* PrepareAsyncSetIsTelemetryDisabledRaw(::grpc::ClientContext* context, const ::google::protobuf::BoolValue& request, ::grpc::CompletionQueue* cq) = 0; + virtual ::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::BoolValue>* AsyncIsTelemetryDisabledRaw(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) = 0; + virtual ::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::BoolValue>* PrepareAsyncIsTelemetryDisabledRaw(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) = 0; virtual ::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::StringValue>* AsyncGoOsRaw(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) = 0; virtual ::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::StringValue>* PrepareAsyncGoOsRaw(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) = 0; virtual ::grpc::ClientAsyncResponseReaderInterface< ::google::protobuf::Empty>* AsyncTriggerResetRaw(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) = 0; @@ -779,6 +801,20 @@ class Bridge final { std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::google::protobuf::BoolValue>> PrepareAsyncIsAllMailVisible(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) { return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::google::protobuf::BoolValue>>(PrepareAsyncIsAllMailVisibleRaw(context, request, cq)); } + ::grpc::Status SetIsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::BoolValue& request, ::google::protobuf::Empty* response) override; + std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::google::protobuf::Empty>> AsyncSetIsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::BoolValue& request, ::grpc::CompletionQueue* cq) { + return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::google::protobuf::Empty>>(AsyncSetIsTelemetryDisabledRaw(context, request, cq)); + } + std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::google::protobuf::Empty>> PrepareAsyncSetIsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::BoolValue& request, ::grpc::CompletionQueue* cq) { + return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::google::protobuf::Empty>>(PrepareAsyncSetIsTelemetryDisabledRaw(context, request, cq)); + } + ::grpc::Status IsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::google::protobuf::BoolValue* response) override; + std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::google::protobuf::BoolValue>> AsyncIsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) { + return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::google::protobuf::BoolValue>>(AsyncIsTelemetryDisabledRaw(context, request, cq)); + } + std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::google::protobuf::BoolValue>> PrepareAsyncIsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) { + return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::google::protobuf::BoolValue>>(PrepareAsyncIsTelemetryDisabledRaw(context, request, cq)); + } ::grpc::Status GoOs(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::google::protobuf::StringValue* response) override; std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::google::protobuf::StringValue>> AsyncGoOs(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) { return std::unique_ptr< ::grpc::ClientAsyncResponseReader< ::google::protobuf::StringValue>>(AsyncGoOsRaw(context, request, cq)); @@ -1109,6 +1145,10 @@ class Bridge final { void SetIsAllMailVisible(::grpc::ClientContext* context, const ::google::protobuf::BoolValue* request, ::google::protobuf::Empty* response, ::grpc::ClientUnaryReactor* reactor) override; void IsAllMailVisible(::grpc::ClientContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::BoolValue* response, std::function) override; void IsAllMailVisible(::grpc::ClientContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::BoolValue* response, ::grpc::ClientUnaryReactor* reactor) override; + void SetIsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::BoolValue* request, ::google::protobuf::Empty* response, std::function) override; + void SetIsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::BoolValue* request, ::google::protobuf::Empty* response, ::grpc::ClientUnaryReactor* reactor) override; + void IsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::BoolValue* response, std::function) override; + void IsTelemetryDisabled(::grpc::ClientContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::BoolValue* response, ::grpc::ClientUnaryReactor* reactor) override; void GoOs(::grpc::ClientContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::StringValue* response, std::function) override; void GoOs(::grpc::ClientContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::StringValue* response, ::grpc::ClientUnaryReactor* reactor) override; void TriggerReset(::grpc::ClientContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::Empty* response, std::function) override; @@ -1229,6 +1269,10 @@ class Bridge final { ::grpc::ClientAsyncResponseReader< ::google::protobuf::Empty>* PrepareAsyncSetIsAllMailVisibleRaw(::grpc::ClientContext* context, const ::google::protobuf::BoolValue& request, ::grpc::CompletionQueue* cq) override; ::grpc::ClientAsyncResponseReader< ::google::protobuf::BoolValue>* AsyncIsAllMailVisibleRaw(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) override; ::grpc::ClientAsyncResponseReader< ::google::protobuf::BoolValue>* PrepareAsyncIsAllMailVisibleRaw(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) override; + ::grpc::ClientAsyncResponseReader< ::google::protobuf::Empty>* AsyncSetIsTelemetryDisabledRaw(::grpc::ClientContext* context, const ::google::protobuf::BoolValue& request, ::grpc::CompletionQueue* cq) override; + ::grpc::ClientAsyncResponseReader< ::google::protobuf::Empty>* PrepareAsyncSetIsTelemetryDisabledRaw(::grpc::ClientContext* context, const ::google::protobuf::BoolValue& request, ::grpc::CompletionQueue* cq) override; + ::grpc::ClientAsyncResponseReader< ::google::protobuf::BoolValue>* AsyncIsTelemetryDisabledRaw(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) override; + ::grpc::ClientAsyncResponseReader< ::google::protobuf::BoolValue>* PrepareAsyncIsTelemetryDisabledRaw(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) override; ::grpc::ClientAsyncResponseReader< ::google::protobuf::StringValue>* AsyncGoOsRaw(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) override; ::grpc::ClientAsyncResponseReader< ::google::protobuf::StringValue>* PrepareAsyncGoOsRaw(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) override; ::grpc::ClientAsyncResponseReader< ::google::protobuf::Empty>* AsyncTriggerResetRaw(::grpc::ClientContext* context, const ::google::protobuf::Empty& request, ::grpc::CompletionQueue* cq) override; @@ -1328,6 +1372,8 @@ class Bridge final { const ::grpc::internal::RpcMethod rpcmethod_IsBetaEnabled_; const ::grpc::internal::RpcMethod rpcmethod_SetIsAllMailVisible_; const ::grpc::internal::RpcMethod rpcmethod_IsAllMailVisible_; + const ::grpc::internal::RpcMethod rpcmethod_SetIsTelemetryDisabled_; + const ::grpc::internal::RpcMethod rpcmethod_IsTelemetryDisabled_; const ::grpc::internal::RpcMethod rpcmethod_GoOs_; const ::grpc::internal::RpcMethod rpcmethod_TriggerReset_; const ::grpc::internal::RpcMethod rpcmethod_Version_; @@ -1391,6 +1437,8 @@ class Bridge final { virtual ::grpc::Status IsBetaEnabled(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::BoolValue* response); virtual ::grpc::Status SetIsAllMailVisible(::grpc::ServerContext* context, const ::google::protobuf::BoolValue* request, ::google::protobuf::Empty* response); virtual ::grpc::Status IsAllMailVisible(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::BoolValue* response); + virtual ::grpc::Status SetIsTelemetryDisabled(::grpc::ServerContext* context, const ::google::protobuf::BoolValue* request, ::google::protobuf::Empty* response); + virtual ::grpc::Status IsTelemetryDisabled(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::BoolValue* response); virtual ::grpc::Status GoOs(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::StringValue* response); virtual ::grpc::Status TriggerReset(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::Empty* response); virtual ::grpc::Status Version(::grpc::ServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::StringValue* response); @@ -1685,12 +1733,52 @@ class Bridge final { } }; template + class WithAsyncMethod_SetIsTelemetryDisabled : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} + public: + WithAsyncMethod_SetIsTelemetryDisabled() { + ::grpc::Service::MarkMethodAsync(12); + } + ~WithAsyncMethod_SetIsTelemetryDisabled() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status SetIsTelemetryDisabled(::grpc::ServerContext* /*context*/, const ::google::protobuf::BoolValue* /*request*/, ::google::protobuf::Empty* /*response*/) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + void RequestSetIsTelemetryDisabled(::grpc::ServerContext* context, ::google::protobuf::BoolValue* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { + ::grpc::Service::RequestAsyncUnary(12, context, request, response, new_call_cq, notification_cq, tag); + } + }; + template + class WithAsyncMethod_IsTelemetryDisabled : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} + public: + WithAsyncMethod_IsTelemetryDisabled() { + ::grpc::Service::MarkMethodAsync(13); + } + ~WithAsyncMethod_IsTelemetryDisabled() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status IsTelemetryDisabled(::grpc::ServerContext* /*context*/, const ::google::protobuf::Empty* /*request*/, ::google::protobuf::BoolValue* /*response*/) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + void RequestIsTelemetryDisabled(::grpc::ServerContext* context, ::google::protobuf::Empty* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::BoolValue>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { + ::grpc::Service::RequestAsyncUnary(13, context, request, response, new_call_cq, notification_cq, tag); + } + }; + template class WithAsyncMethod_GoOs : public BaseClass { private: void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_GoOs() { - ::grpc::Service::MarkMethodAsync(12); + ::grpc::Service::MarkMethodAsync(14); } ~WithAsyncMethod_GoOs() override { BaseClassMustBeDerivedFromService(this); @@ -1701,7 +1789,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestGoOs(::grpc::ServerContext* context, ::google::protobuf::Empty* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::StringValue>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(12, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(14, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -1710,7 +1798,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_TriggerReset() { - ::grpc::Service::MarkMethodAsync(13); + ::grpc::Service::MarkMethodAsync(15); } ~WithAsyncMethod_TriggerReset() override { BaseClassMustBeDerivedFromService(this); @@ -1721,7 +1809,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestTriggerReset(::grpc::ServerContext* context, ::google::protobuf::Empty* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(13, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(15, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -1730,7 +1818,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_Version() { - ::grpc::Service::MarkMethodAsync(14); + ::grpc::Service::MarkMethodAsync(16); } ~WithAsyncMethod_Version() override { BaseClassMustBeDerivedFromService(this); @@ -1741,7 +1829,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestVersion(::grpc::ServerContext* context, ::google::protobuf::Empty* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::StringValue>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(14, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(16, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -1750,7 +1838,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_LogsPath() { - ::grpc::Service::MarkMethodAsync(15); + ::grpc::Service::MarkMethodAsync(17); } ~WithAsyncMethod_LogsPath() override { BaseClassMustBeDerivedFromService(this); @@ -1761,7 +1849,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestLogsPath(::grpc::ServerContext* context, ::google::protobuf::Empty* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::StringValue>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(15, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(17, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -1770,7 +1858,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_LicensePath() { - ::grpc::Service::MarkMethodAsync(16); + ::grpc::Service::MarkMethodAsync(18); } ~WithAsyncMethod_LicensePath() override { BaseClassMustBeDerivedFromService(this); @@ -1781,7 +1869,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestLicensePath(::grpc::ServerContext* context, ::google::protobuf::Empty* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::StringValue>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(16, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(18, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -1790,7 +1878,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_ReleaseNotesPageLink() { - ::grpc::Service::MarkMethodAsync(17); + ::grpc::Service::MarkMethodAsync(19); } ~WithAsyncMethod_ReleaseNotesPageLink() override { BaseClassMustBeDerivedFromService(this); @@ -1801,7 +1889,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestReleaseNotesPageLink(::grpc::ServerContext* context, ::google::protobuf::Empty* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::StringValue>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(17, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(19, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -1810,7 +1898,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_DependencyLicensesLink() { - ::grpc::Service::MarkMethodAsync(18); + ::grpc::Service::MarkMethodAsync(20); } ~WithAsyncMethod_DependencyLicensesLink() override { BaseClassMustBeDerivedFromService(this); @@ -1821,7 +1909,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestDependencyLicensesLink(::grpc::ServerContext* context, ::google::protobuf::Empty* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::StringValue>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(18, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(20, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -1830,7 +1918,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_LandingPageLink() { - ::grpc::Service::MarkMethodAsync(19); + ::grpc::Service::MarkMethodAsync(21); } ~WithAsyncMethod_LandingPageLink() override { BaseClassMustBeDerivedFromService(this); @@ -1841,7 +1929,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestLandingPageLink(::grpc::ServerContext* context, ::google::protobuf::Empty* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::StringValue>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(19, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(21, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -1850,7 +1938,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_SetColorSchemeName() { - ::grpc::Service::MarkMethodAsync(20); + ::grpc::Service::MarkMethodAsync(22); } ~WithAsyncMethod_SetColorSchemeName() override { BaseClassMustBeDerivedFromService(this); @@ -1861,7 +1949,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestSetColorSchemeName(::grpc::ServerContext* context, ::google::protobuf::StringValue* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(20, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(22, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -1870,7 +1958,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_ColorSchemeName() { - ::grpc::Service::MarkMethodAsync(21); + ::grpc::Service::MarkMethodAsync(23); } ~WithAsyncMethod_ColorSchemeName() override { BaseClassMustBeDerivedFromService(this); @@ -1881,7 +1969,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestColorSchemeName(::grpc::ServerContext* context, ::google::protobuf::Empty* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::StringValue>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(21, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(23, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -1890,7 +1978,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_CurrentEmailClient() { - ::grpc::Service::MarkMethodAsync(22); + ::grpc::Service::MarkMethodAsync(24); } ~WithAsyncMethod_CurrentEmailClient() override { BaseClassMustBeDerivedFromService(this); @@ -1901,7 +1989,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestCurrentEmailClient(::grpc::ServerContext* context, ::google::protobuf::Empty* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::StringValue>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(22, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(24, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -1910,7 +1998,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_ReportBug() { - ::grpc::Service::MarkMethodAsync(23); + ::grpc::Service::MarkMethodAsync(25); } ~WithAsyncMethod_ReportBug() override { BaseClassMustBeDerivedFromService(this); @@ -1921,7 +2009,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestReportBug(::grpc::ServerContext* context, ::grpc::ReportBugRequest* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(23, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(25, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -1930,7 +2018,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_ExportTLSCertificates() { - ::grpc::Service::MarkMethodAsync(24); + ::grpc::Service::MarkMethodAsync(26); } ~WithAsyncMethod_ExportTLSCertificates() override { BaseClassMustBeDerivedFromService(this); @@ -1941,7 +2029,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestExportTLSCertificates(::grpc::ServerContext* context, ::google::protobuf::StringValue* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(24, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(26, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -1950,7 +2038,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_ForceLauncher() { - ::grpc::Service::MarkMethodAsync(25); + ::grpc::Service::MarkMethodAsync(27); } ~WithAsyncMethod_ForceLauncher() override { BaseClassMustBeDerivedFromService(this); @@ -1961,7 +2049,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestForceLauncher(::grpc::ServerContext* context, ::google::protobuf::StringValue* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(25, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(27, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -1970,7 +2058,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_SetMainExecutable() { - ::grpc::Service::MarkMethodAsync(26); + ::grpc::Service::MarkMethodAsync(28); } ~WithAsyncMethod_SetMainExecutable() override { BaseClassMustBeDerivedFromService(this); @@ -1981,7 +2069,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestSetMainExecutable(::grpc::ServerContext* context, ::google::protobuf::StringValue* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(26, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(28, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -1990,7 +2078,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_Login() { - ::grpc::Service::MarkMethodAsync(27); + ::grpc::Service::MarkMethodAsync(29); } ~WithAsyncMethod_Login() override { BaseClassMustBeDerivedFromService(this); @@ -2001,7 +2089,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestLogin(::grpc::ServerContext* context, ::grpc::LoginRequest* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(27, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(29, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2010,7 +2098,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_Login2FA() { - ::grpc::Service::MarkMethodAsync(28); + ::grpc::Service::MarkMethodAsync(30); } ~WithAsyncMethod_Login2FA() override { BaseClassMustBeDerivedFromService(this); @@ -2021,7 +2109,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestLogin2FA(::grpc::ServerContext* context, ::grpc::LoginRequest* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(28, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(30, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2030,7 +2118,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_Login2Passwords() { - ::grpc::Service::MarkMethodAsync(29); + ::grpc::Service::MarkMethodAsync(31); } ~WithAsyncMethod_Login2Passwords() override { BaseClassMustBeDerivedFromService(this); @@ -2041,7 +2129,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestLogin2Passwords(::grpc::ServerContext* context, ::grpc::LoginRequest* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(29, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(31, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2050,7 +2138,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_LoginAbort() { - ::grpc::Service::MarkMethodAsync(30); + ::grpc::Service::MarkMethodAsync(32); } ~WithAsyncMethod_LoginAbort() override { BaseClassMustBeDerivedFromService(this); @@ -2061,7 +2149,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestLoginAbort(::grpc::ServerContext* context, ::grpc::LoginAbortRequest* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(30, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(32, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2070,7 +2158,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_CheckUpdate() { - ::grpc::Service::MarkMethodAsync(31); + ::grpc::Service::MarkMethodAsync(33); } ~WithAsyncMethod_CheckUpdate() override { BaseClassMustBeDerivedFromService(this); @@ -2081,7 +2169,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestCheckUpdate(::grpc::ServerContext* context, ::google::protobuf::Empty* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(31, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(33, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2090,7 +2178,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_InstallUpdate() { - ::grpc::Service::MarkMethodAsync(32); + ::grpc::Service::MarkMethodAsync(34); } ~WithAsyncMethod_InstallUpdate() override { BaseClassMustBeDerivedFromService(this); @@ -2101,7 +2189,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestInstallUpdate(::grpc::ServerContext* context, ::google::protobuf::Empty* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(32, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(34, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2110,7 +2198,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_SetIsAutomaticUpdateOn() { - ::grpc::Service::MarkMethodAsync(33); + ::grpc::Service::MarkMethodAsync(35); } ~WithAsyncMethod_SetIsAutomaticUpdateOn() override { BaseClassMustBeDerivedFromService(this); @@ -2121,7 +2209,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestSetIsAutomaticUpdateOn(::grpc::ServerContext* context, ::google::protobuf::BoolValue* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(33, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(35, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2130,7 +2218,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_IsAutomaticUpdateOn() { - ::grpc::Service::MarkMethodAsync(34); + ::grpc::Service::MarkMethodAsync(36); } ~WithAsyncMethod_IsAutomaticUpdateOn() override { BaseClassMustBeDerivedFromService(this); @@ -2141,7 +2229,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestIsAutomaticUpdateOn(::grpc::ServerContext* context, ::google::protobuf::Empty* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::BoolValue>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(34, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(36, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2150,7 +2238,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_DiskCachePath() { - ::grpc::Service::MarkMethodAsync(35); + ::grpc::Service::MarkMethodAsync(37); } ~WithAsyncMethod_DiskCachePath() override { BaseClassMustBeDerivedFromService(this); @@ -2161,7 +2249,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestDiskCachePath(::grpc::ServerContext* context, ::google::protobuf::Empty* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::StringValue>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(35, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(37, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2170,7 +2258,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_SetDiskCachePath() { - ::grpc::Service::MarkMethodAsync(36); + ::grpc::Service::MarkMethodAsync(38); } ~WithAsyncMethod_SetDiskCachePath() override { BaseClassMustBeDerivedFromService(this); @@ -2181,7 +2269,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestSetDiskCachePath(::grpc::ServerContext* context, ::google::protobuf::StringValue* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(36, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(38, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2190,7 +2278,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_SetIsDoHEnabled() { - ::grpc::Service::MarkMethodAsync(37); + ::grpc::Service::MarkMethodAsync(39); } ~WithAsyncMethod_SetIsDoHEnabled() override { BaseClassMustBeDerivedFromService(this); @@ -2201,7 +2289,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestSetIsDoHEnabled(::grpc::ServerContext* context, ::google::protobuf::BoolValue* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(37, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(39, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2210,7 +2298,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_IsDoHEnabled() { - ::grpc::Service::MarkMethodAsync(38); + ::grpc::Service::MarkMethodAsync(40); } ~WithAsyncMethod_IsDoHEnabled() override { BaseClassMustBeDerivedFromService(this); @@ -2221,7 +2309,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestIsDoHEnabled(::grpc::ServerContext* context, ::google::protobuf::Empty* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::BoolValue>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(38, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(40, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2230,7 +2318,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_MailServerSettings() { - ::grpc::Service::MarkMethodAsync(39); + ::grpc::Service::MarkMethodAsync(41); } ~WithAsyncMethod_MailServerSettings() override { BaseClassMustBeDerivedFromService(this); @@ -2241,7 +2329,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestMailServerSettings(::grpc::ServerContext* context, ::google::protobuf::Empty* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ImapSmtpSettings>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(39, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(41, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2250,7 +2338,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_SetMailServerSettings() { - ::grpc::Service::MarkMethodAsync(40); + ::grpc::Service::MarkMethodAsync(42); } ~WithAsyncMethod_SetMailServerSettings() override { BaseClassMustBeDerivedFromService(this); @@ -2261,7 +2349,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestSetMailServerSettings(::grpc::ServerContext* context, ::grpc::ImapSmtpSettings* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(40, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(42, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2270,7 +2358,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_Hostname() { - ::grpc::Service::MarkMethodAsync(41); + ::grpc::Service::MarkMethodAsync(43); } ~WithAsyncMethod_Hostname() override { BaseClassMustBeDerivedFromService(this); @@ -2281,7 +2369,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestHostname(::grpc::ServerContext* context, ::google::protobuf::Empty* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::StringValue>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(41, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(43, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2290,7 +2378,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_IsPortFree() { - ::grpc::Service::MarkMethodAsync(42); + ::grpc::Service::MarkMethodAsync(44); } ~WithAsyncMethod_IsPortFree() override { BaseClassMustBeDerivedFromService(this); @@ -2301,7 +2389,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestIsPortFree(::grpc::ServerContext* context, ::google::protobuf::Int32Value* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::BoolValue>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(42, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(44, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2310,7 +2398,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_AvailableKeychains() { - ::grpc::Service::MarkMethodAsync(43); + ::grpc::Service::MarkMethodAsync(45); } ~WithAsyncMethod_AvailableKeychains() override { BaseClassMustBeDerivedFromService(this); @@ -2321,7 +2409,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestAvailableKeychains(::grpc::ServerContext* context, ::google::protobuf::Empty* request, ::grpc::ServerAsyncResponseWriter< ::grpc::AvailableKeychainsResponse>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(43, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(45, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2330,7 +2418,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_SetCurrentKeychain() { - ::grpc::Service::MarkMethodAsync(44); + ::grpc::Service::MarkMethodAsync(46); } ~WithAsyncMethod_SetCurrentKeychain() override { BaseClassMustBeDerivedFromService(this); @@ -2341,7 +2429,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestSetCurrentKeychain(::grpc::ServerContext* context, ::google::protobuf::StringValue* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(44, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(46, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2350,7 +2438,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_CurrentKeychain() { - ::grpc::Service::MarkMethodAsync(45); + ::grpc::Service::MarkMethodAsync(47); } ~WithAsyncMethod_CurrentKeychain() override { BaseClassMustBeDerivedFromService(this); @@ -2361,7 +2449,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestCurrentKeychain(::grpc::ServerContext* context, ::google::protobuf::Empty* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::StringValue>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(45, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(47, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2370,7 +2458,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_GetUserList() { - ::grpc::Service::MarkMethodAsync(46); + ::grpc::Service::MarkMethodAsync(48); } ~WithAsyncMethod_GetUserList() override { BaseClassMustBeDerivedFromService(this); @@ -2381,7 +2469,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestGetUserList(::grpc::ServerContext* context, ::google::protobuf::Empty* request, ::grpc::ServerAsyncResponseWriter< ::grpc::UserListResponse>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(46, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(48, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2390,7 +2478,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_GetUser() { - ::grpc::Service::MarkMethodAsync(47); + ::grpc::Service::MarkMethodAsync(49); } ~WithAsyncMethod_GetUser() override { BaseClassMustBeDerivedFromService(this); @@ -2401,7 +2489,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestGetUser(::grpc::ServerContext* context, ::google::protobuf::StringValue* request, ::grpc::ServerAsyncResponseWriter< ::grpc::User>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(47, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(49, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2410,7 +2498,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_SetUserSplitMode() { - ::grpc::Service::MarkMethodAsync(48); + ::grpc::Service::MarkMethodAsync(50); } ~WithAsyncMethod_SetUserSplitMode() override { BaseClassMustBeDerivedFromService(this); @@ -2421,7 +2509,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestSetUserSplitMode(::grpc::ServerContext* context, ::grpc::UserSplitModeRequest* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(48, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(50, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2430,7 +2518,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_SendBadEventUserFeedback() { - ::grpc::Service::MarkMethodAsync(49); + ::grpc::Service::MarkMethodAsync(51); } ~WithAsyncMethod_SendBadEventUserFeedback() override { BaseClassMustBeDerivedFromService(this); @@ -2441,7 +2529,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestSendBadEventUserFeedback(::grpc::ServerContext* context, ::grpc::UserBadEventFeedbackRequest* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(49, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(51, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2450,7 +2538,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_LogoutUser() { - ::grpc::Service::MarkMethodAsync(50); + ::grpc::Service::MarkMethodAsync(52); } ~WithAsyncMethod_LogoutUser() override { BaseClassMustBeDerivedFromService(this); @@ -2461,7 +2549,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestLogoutUser(::grpc::ServerContext* context, ::google::protobuf::StringValue* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(50, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(52, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2470,7 +2558,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_RemoveUser() { - ::grpc::Service::MarkMethodAsync(51); + ::grpc::Service::MarkMethodAsync(53); } ~WithAsyncMethod_RemoveUser() override { BaseClassMustBeDerivedFromService(this); @@ -2481,7 +2569,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestRemoveUser(::grpc::ServerContext* context, ::google::protobuf::StringValue* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(51, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(53, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2490,7 +2578,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_ConfigureUserAppleMail() { - ::grpc::Service::MarkMethodAsync(52); + ::grpc::Service::MarkMethodAsync(54); } ~WithAsyncMethod_ConfigureUserAppleMail() override { BaseClassMustBeDerivedFromService(this); @@ -2501,7 +2589,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestConfigureUserAppleMail(::grpc::ServerContext* context, ::grpc::ConfigureAppleMailRequest* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(52, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(54, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -2510,7 +2598,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_RunEventStream() { - ::grpc::Service::MarkMethodAsync(53); + ::grpc::Service::MarkMethodAsync(55); } ~WithAsyncMethod_RunEventStream() override { BaseClassMustBeDerivedFromService(this); @@ -2521,7 +2609,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestRunEventStream(::grpc::ServerContext* context, ::grpc::EventStreamRequest* request, ::grpc::ServerAsyncWriter< ::grpc::StreamEvent>* writer, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncServerStreaming(53, context, request, writer, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncServerStreaming(55, context, request, writer, new_call_cq, notification_cq, tag); } }; template @@ -2530,7 +2618,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithAsyncMethod_StopEventStream() { - ::grpc::Service::MarkMethodAsync(54); + ::grpc::Service::MarkMethodAsync(56); } ~WithAsyncMethod_StopEventStream() override { BaseClassMustBeDerivedFromService(this); @@ -2541,10 +2629,10 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestStopEventStream(::grpc::ServerContext* context, ::google::protobuf::Empty* request, ::grpc::ServerAsyncResponseWriter< ::google::protobuf::Empty>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(54, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(56, context, request, response, new_call_cq, notification_cq, tag); } }; - typedef WithAsyncMethod_CheckTokens > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > AsyncService; + typedef WithAsyncMethod_CheckTokens > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > AsyncService; template class WithCallbackMethod_CheckTokens : public BaseClass { private: @@ -2870,18 +2958,72 @@ class Bridge final { ::grpc::CallbackServerContext* /*context*/, const ::google::protobuf::Empty* /*request*/, ::google::protobuf::BoolValue* /*response*/) { return nullptr; } }; template + class WithCallbackMethod_SetIsTelemetryDisabled : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} + public: + WithCallbackMethod_SetIsTelemetryDisabled() { + ::grpc::Service::MarkMethodCallback(12, + new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::BoolValue, ::google::protobuf::Empty>( + [this]( + ::grpc::CallbackServerContext* context, const ::google::protobuf::BoolValue* request, ::google::protobuf::Empty* response) { return this->SetIsTelemetryDisabled(context, request, response); }));} + void SetMessageAllocatorFor_SetIsTelemetryDisabled( + ::grpc::MessageAllocator< ::google::protobuf::BoolValue, ::google::protobuf::Empty>* allocator) { + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(12); + static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::BoolValue, ::google::protobuf::Empty>*>(handler) + ->SetMessageAllocator(allocator); + } + ~WithCallbackMethod_SetIsTelemetryDisabled() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status SetIsTelemetryDisabled(::grpc::ServerContext* /*context*/, const ::google::protobuf::BoolValue* /*request*/, ::google::protobuf::Empty* /*response*/) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + virtual ::grpc::ServerUnaryReactor* SetIsTelemetryDisabled( + ::grpc::CallbackServerContext* /*context*/, const ::google::protobuf::BoolValue* /*request*/, ::google::protobuf::Empty* /*response*/) { return nullptr; } + }; + template + class WithCallbackMethod_IsTelemetryDisabled : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} + public: + WithCallbackMethod_IsTelemetryDisabled() { + ::grpc::Service::MarkMethodCallback(13, + new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::BoolValue>( + [this]( + ::grpc::CallbackServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::BoolValue* response) { return this->IsTelemetryDisabled(context, request, response); }));} + void SetMessageAllocatorFor_IsTelemetryDisabled( + ::grpc::MessageAllocator< ::google::protobuf::Empty, ::google::protobuf::BoolValue>* allocator) { + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(13); + static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::BoolValue>*>(handler) + ->SetMessageAllocator(allocator); + } + ~WithCallbackMethod_IsTelemetryDisabled() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status IsTelemetryDisabled(::grpc::ServerContext* /*context*/, const ::google::protobuf::Empty* /*request*/, ::google::protobuf::BoolValue* /*response*/) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + virtual ::grpc::ServerUnaryReactor* IsTelemetryDisabled( + ::grpc::CallbackServerContext* /*context*/, const ::google::protobuf::Empty* /*request*/, ::google::protobuf::BoolValue* /*response*/) { return nullptr; } + }; + template class WithCallbackMethod_GoOs : public BaseClass { private: void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_GoOs() { - ::grpc::Service::MarkMethodCallback(12, + ::grpc::Service::MarkMethodCallback(14, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::StringValue* response) { return this->GoOs(context, request, response); }));} void SetMessageAllocatorFor_GoOs( ::grpc::MessageAllocator< ::google::protobuf::Empty, ::google::protobuf::StringValue>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(12); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(14); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>*>(handler) ->SetMessageAllocator(allocator); } @@ -2902,13 +3044,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_TriggerReset() { - ::grpc::Service::MarkMethodCallback(13, + ::grpc::Service::MarkMethodCallback(15, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::Empty>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::Empty* response) { return this->TriggerReset(context, request, response); }));} void SetMessageAllocatorFor_TriggerReset( ::grpc::MessageAllocator< ::google::protobuf::Empty, ::google::protobuf::Empty>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(13); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(15); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::Empty>*>(handler) ->SetMessageAllocator(allocator); } @@ -2929,13 +3071,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_Version() { - ::grpc::Service::MarkMethodCallback(14, + ::grpc::Service::MarkMethodCallback(16, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::StringValue* response) { return this->Version(context, request, response); }));} void SetMessageAllocatorFor_Version( ::grpc::MessageAllocator< ::google::protobuf::Empty, ::google::protobuf::StringValue>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(14); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(16); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>*>(handler) ->SetMessageAllocator(allocator); } @@ -2956,13 +3098,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_LogsPath() { - ::grpc::Service::MarkMethodCallback(15, + ::grpc::Service::MarkMethodCallback(17, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::StringValue* response) { return this->LogsPath(context, request, response); }));} void SetMessageAllocatorFor_LogsPath( ::grpc::MessageAllocator< ::google::protobuf::Empty, ::google::protobuf::StringValue>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(15); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(17); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>*>(handler) ->SetMessageAllocator(allocator); } @@ -2983,13 +3125,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_LicensePath() { - ::grpc::Service::MarkMethodCallback(16, + ::grpc::Service::MarkMethodCallback(18, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::StringValue* response) { return this->LicensePath(context, request, response); }));} void SetMessageAllocatorFor_LicensePath( ::grpc::MessageAllocator< ::google::protobuf::Empty, ::google::protobuf::StringValue>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(16); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(18); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>*>(handler) ->SetMessageAllocator(allocator); } @@ -3010,13 +3152,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_ReleaseNotesPageLink() { - ::grpc::Service::MarkMethodCallback(17, + ::grpc::Service::MarkMethodCallback(19, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::StringValue* response) { return this->ReleaseNotesPageLink(context, request, response); }));} void SetMessageAllocatorFor_ReleaseNotesPageLink( ::grpc::MessageAllocator< ::google::protobuf::Empty, ::google::protobuf::StringValue>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(17); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(19); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>*>(handler) ->SetMessageAllocator(allocator); } @@ -3037,13 +3179,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_DependencyLicensesLink() { - ::grpc::Service::MarkMethodCallback(18, + ::grpc::Service::MarkMethodCallback(20, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::StringValue* response) { return this->DependencyLicensesLink(context, request, response); }));} void SetMessageAllocatorFor_DependencyLicensesLink( ::grpc::MessageAllocator< ::google::protobuf::Empty, ::google::protobuf::StringValue>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(18); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(20); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>*>(handler) ->SetMessageAllocator(allocator); } @@ -3064,13 +3206,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_LandingPageLink() { - ::grpc::Service::MarkMethodCallback(19, + ::grpc::Service::MarkMethodCallback(21, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::StringValue* response) { return this->LandingPageLink(context, request, response); }));} void SetMessageAllocatorFor_LandingPageLink( ::grpc::MessageAllocator< ::google::protobuf::Empty, ::google::protobuf::StringValue>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(19); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(21); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>*>(handler) ->SetMessageAllocator(allocator); } @@ -3091,13 +3233,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_SetColorSchemeName() { - ::grpc::Service::MarkMethodCallback(20, + ::grpc::Service::MarkMethodCallback(22, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::StringValue* request, ::google::protobuf::Empty* response) { return this->SetColorSchemeName(context, request, response); }));} void SetMessageAllocatorFor_SetColorSchemeName( ::grpc::MessageAllocator< ::google::protobuf::StringValue, ::google::protobuf::Empty>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(20); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(22); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>*>(handler) ->SetMessageAllocator(allocator); } @@ -3118,13 +3260,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_ColorSchemeName() { - ::grpc::Service::MarkMethodCallback(21, + ::grpc::Service::MarkMethodCallback(23, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::StringValue* response) { return this->ColorSchemeName(context, request, response); }));} void SetMessageAllocatorFor_ColorSchemeName( ::grpc::MessageAllocator< ::google::protobuf::Empty, ::google::protobuf::StringValue>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(21); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(23); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>*>(handler) ->SetMessageAllocator(allocator); } @@ -3145,13 +3287,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_CurrentEmailClient() { - ::grpc::Service::MarkMethodCallback(22, + ::grpc::Service::MarkMethodCallback(24, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::StringValue* response) { return this->CurrentEmailClient(context, request, response); }));} void SetMessageAllocatorFor_CurrentEmailClient( ::grpc::MessageAllocator< ::google::protobuf::Empty, ::google::protobuf::StringValue>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(22); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(24); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>*>(handler) ->SetMessageAllocator(allocator); } @@ -3172,13 +3314,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_ReportBug() { - ::grpc::Service::MarkMethodCallback(23, + ::grpc::Service::MarkMethodCallback(25, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ReportBugRequest, ::google::protobuf::Empty>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ReportBugRequest* request, ::google::protobuf::Empty* response) { return this->ReportBug(context, request, response); }));} void SetMessageAllocatorFor_ReportBug( ::grpc::MessageAllocator< ::grpc::ReportBugRequest, ::google::protobuf::Empty>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(23); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(25); static_cast<::grpc::internal::CallbackUnaryHandler< ::grpc::ReportBugRequest, ::google::protobuf::Empty>*>(handler) ->SetMessageAllocator(allocator); } @@ -3199,13 +3341,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_ExportTLSCertificates() { - ::grpc::Service::MarkMethodCallback(24, + ::grpc::Service::MarkMethodCallback(26, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::StringValue* request, ::google::protobuf::Empty* response) { return this->ExportTLSCertificates(context, request, response); }));} void SetMessageAllocatorFor_ExportTLSCertificates( ::grpc::MessageAllocator< ::google::protobuf::StringValue, ::google::protobuf::Empty>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(24); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(26); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>*>(handler) ->SetMessageAllocator(allocator); } @@ -3226,13 +3368,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_ForceLauncher() { - ::grpc::Service::MarkMethodCallback(25, + ::grpc::Service::MarkMethodCallback(27, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::StringValue* request, ::google::protobuf::Empty* response) { return this->ForceLauncher(context, request, response); }));} void SetMessageAllocatorFor_ForceLauncher( ::grpc::MessageAllocator< ::google::protobuf::StringValue, ::google::protobuf::Empty>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(25); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(27); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>*>(handler) ->SetMessageAllocator(allocator); } @@ -3253,13 +3395,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_SetMainExecutable() { - ::grpc::Service::MarkMethodCallback(26, + ::grpc::Service::MarkMethodCallback(28, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::StringValue* request, ::google::protobuf::Empty* response) { return this->SetMainExecutable(context, request, response); }));} void SetMessageAllocatorFor_SetMainExecutable( ::grpc::MessageAllocator< ::google::protobuf::StringValue, ::google::protobuf::Empty>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(26); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(28); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>*>(handler) ->SetMessageAllocator(allocator); } @@ -3280,13 +3422,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_Login() { - ::grpc::Service::MarkMethodCallback(27, + ::grpc::Service::MarkMethodCallback(29, new ::grpc::internal::CallbackUnaryHandler< ::grpc::LoginRequest, ::google::protobuf::Empty>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::LoginRequest* request, ::google::protobuf::Empty* response) { return this->Login(context, request, response); }));} void SetMessageAllocatorFor_Login( ::grpc::MessageAllocator< ::grpc::LoginRequest, ::google::protobuf::Empty>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(27); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(29); static_cast<::grpc::internal::CallbackUnaryHandler< ::grpc::LoginRequest, ::google::protobuf::Empty>*>(handler) ->SetMessageAllocator(allocator); } @@ -3307,13 +3449,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_Login2FA() { - ::grpc::Service::MarkMethodCallback(28, + ::grpc::Service::MarkMethodCallback(30, new ::grpc::internal::CallbackUnaryHandler< ::grpc::LoginRequest, ::google::protobuf::Empty>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::LoginRequest* request, ::google::protobuf::Empty* response) { return this->Login2FA(context, request, response); }));} void SetMessageAllocatorFor_Login2FA( ::grpc::MessageAllocator< ::grpc::LoginRequest, ::google::protobuf::Empty>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(28); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(30); static_cast<::grpc::internal::CallbackUnaryHandler< ::grpc::LoginRequest, ::google::protobuf::Empty>*>(handler) ->SetMessageAllocator(allocator); } @@ -3334,13 +3476,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_Login2Passwords() { - ::grpc::Service::MarkMethodCallback(29, + ::grpc::Service::MarkMethodCallback(31, new ::grpc::internal::CallbackUnaryHandler< ::grpc::LoginRequest, ::google::protobuf::Empty>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::LoginRequest* request, ::google::protobuf::Empty* response) { return this->Login2Passwords(context, request, response); }));} void SetMessageAllocatorFor_Login2Passwords( ::grpc::MessageAllocator< ::grpc::LoginRequest, ::google::protobuf::Empty>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(29); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(31); static_cast<::grpc::internal::CallbackUnaryHandler< ::grpc::LoginRequest, ::google::protobuf::Empty>*>(handler) ->SetMessageAllocator(allocator); } @@ -3361,13 +3503,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_LoginAbort() { - ::grpc::Service::MarkMethodCallback(30, + ::grpc::Service::MarkMethodCallback(32, new ::grpc::internal::CallbackUnaryHandler< ::grpc::LoginAbortRequest, ::google::protobuf::Empty>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::LoginAbortRequest* request, ::google::protobuf::Empty* response) { return this->LoginAbort(context, request, response); }));} void SetMessageAllocatorFor_LoginAbort( ::grpc::MessageAllocator< ::grpc::LoginAbortRequest, ::google::protobuf::Empty>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(30); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(32); static_cast<::grpc::internal::CallbackUnaryHandler< ::grpc::LoginAbortRequest, ::google::protobuf::Empty>*>(handler) ->SetMessageAllocator(allocator); } @@ -3388,13 +3530,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_CheckUpdate() { - ::grpc::Service::MarkMethodCallback(31, + ::grpc::Service::MarkMethodCallback(33, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::Empty>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::Empty* response) { return this->CheckUpdate(context, request, response); }));} void SetMessageAllocatorFor_CheckUpdate( ::grpc::MessageAllocator< ::google::protobuf::Empty, ::google::protobuf::Empty>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(31); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(33); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::Empty>*>(handler) ->SetMessageAllocator(allocator); } @@ -3415,13 +3557,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_InstallUpdate() { - ::grpc::Service::MarkMethodCallback(32, + ::grpc::Service::MarkMethodCallback(34, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::Empty>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::Empty* response) { return this->InstallUpdate(context, request, response); }));} void SetMessageAllocatorFor_InstallUpdate( ::grpc::MessageAllocator< ::google::protobuf::Empty, ::google::protobuf::Empty>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(32); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(34); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::Empty>*>(handler) ->SetMessageAllocator(allocator); } @@ -3442,13 +3584,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_SetIsAutomaticUpdateOn() { - ::grpc::Service::MarkMethodCallback(33, + ::grpc::Service::MarkMethodCallback(35, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::BoolValue, ::google::protobuf::Empty>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::BoolValue* request, ::google::protobuf::Empty* response) { return this->SetIsAutomaticUpdateOn(context, request, response); }));} void SetMessageAllocatorFor_SetIsAutomaticUpdateOn( ::grpc::MessageAllocator< ::google::protobuf::BoolValue, ::google::protobuf::Empty>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(33); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(35); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::BoolValue, ::google::protobuf::Empty>*>(handler) ->SetMessageAllocator(allocator); } @@ -3469,13 +3611,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_IsAutomaticUpdateOn() { - ::grpc::Service::MarkMethodCallback(34, + ::grpc::Service::MarkMethodCallback(36, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::BoolValue>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::BoolValue* response) { return this->IsAutomaticUpdateOn(context, request, response); }));} void SetMessageAllocatorFor_IsAutomaticUpdateOn( ::grpc::MessageAllocator< ::google::protobuf::Empty, ::google::protobuf::BoolValue>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(34); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(36); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::BoolValue>*>(handler) ->SetMessageAllocator(allocator); } @@ -3496,13 +3638,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_DiskCachePath() { - ::grpc::Service::MarkMethodCallback(35, + ::grpc::Service::MarkMethodCallback(37, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::StringValue* response) { return this->DiskCachePath(context, request, response); }));} void SetMessageAllocatorFor_DiskCachePath( ::grpc::MessageAllocator< ::google::protobuf::Empty, ::google::protobuf::StringValue>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(35); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(37); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>*>(handler) ->SetMessageAllocator(allocator); } @@ -3523,13 +3665,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_SetDiskCachePath() { - ::grpc::Service::MarkMethodCallback(36, + ::grpc::Service::MarkMethodCallback(38, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::StringValue* request, ::google::protobuf::Empty* response) { return this->SetDiskCachePath(context, request, response); }));} void SetMessageAllocatorFor_SetDiskCachePath( ::grpc::MessageAllocator< ::google::protobuf::StringValue, ::google::protobuf::Empty>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(36); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(38); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>*>(handler) ->SetMessageAllocator(allocator); } @@ -3550,13 +3692,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_SetIsDoHEnabled() { - ::grpc::Service::MarkMethodCallback(37, + ::grpc::Service::MarkMethodCallback(39, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::BoolValue, ::google::protobuf::Empty>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::BoolValue* request, ::google::protobuf::Empty* response) { return this->SetIsDoHEnabled(context, request, response); }));} void SetMessageAllocatorFor_SetIsDoHEnabled( ::grpc::MessageAllocator< ::google::protobuf::BoolValue, ::google::protobuf::Empty>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(37); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(39); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::BoolValue, ::google::protobuf::Empty>*>(handler) ->SetMessageAllocator(allocator); } @@ -3577,13 +3719,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_IsDoHEnabled() { - ::grpc::Service::MarkMethodCallback(38, + ::grpc::Service::MarkMethodCallback(40, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::BoolValue>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::BoolValue* response) { return this->IsDoHEnabled(context, request, response); }));} void SetMessageAllocatorFor_IsDoHEnabled( ::grpc::MessageAllocator< ::google::protobuf::Empty, ::google::protobuf::BoolValue>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(38); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(40); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::BoolValue>*>(handler) ->SetMessageAllocator(allocator); } @@ -3604,13 +3746,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_MailServerSettings() { - ::grpc::Service::MarkMethodCallback(39, + ::grpc::Service::MarkMethodCallback(41, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::grpc::ImapSmtpSettings>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::Empty* request, ::grpc::ImapSmtpSettings* response) { return this->MailServerSettings(context, request, response); }));} void SetMessageAllocatorFor_MailServerSettings( ::grpc::MessageAllocator< ::google::protobuf::Empty, ::grpc::ImapSmtpSettings>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(39); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(41); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::grpc::ImapSmtpSettings>*>(handler) ->SetMessageAllocator(allocator); } @@ -3631,13 +3773,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_SetMailServerSettings() { - ::grpc::Service::MarkMethodCallback(40, + ::grpc::Service::MarkMethodCallback(42, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ImapSmtpSettings, ::google::protobuf::Empty>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ImapSmtpSettings* request, ::google::protobuf::Empty* response) { return this->SetMailServerSettings(context, request, response); }));} void SetMessageAllocatorFor_SetMailServerSettings( ::grpc::MessageAllocator< ::grpc::ImapSmtpSettings, ::google::protobuf::Empty>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(40); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(42); static_cast<::grpc::internal::CallbackUnaryHandler< ::grpc::ImapSmtpSettings, ::google::protobuf::Empty>*>(handler) ->SetMessageAllocator(allocator); } @@ -3658,13 +3800,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_Hostname() { - ::grpc::Service::MarkMethodCallback(41, + ::grpc::Service::MarkMethodCallback(43, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::StringValue* response) { return this->Hostname(context, request, response); }));} void SetMessageAllocatorFor_Hostname( ::grpc::MessageAllocator< ::google::protobuf::Empty, ::google::protobuf::StringValue>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(41); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(43); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>*>(handler) ->SetMessageAllocator(allocator); } @@ -3685,13 +3827,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_IsPortFree() { - ::grpc::Service::MarkMethodCallback(42, + ::grpc::Service::MarkMethodCallback(44, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Int32Value, ::google::protobuf::BoolValue>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::Int32Value* request, ::google::protobuf::BoolValue* response) { return this->IsPortFree(context, request, response); }));} void SetMessageAllocatorFor_IsPortFree( ::grpc::MessageAllocator< ::google::protobuf::Int32Value, ::google::protobuf::BoolValue>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(42); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(44); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Int32Value, ::google::protobuf::BoolValue>*>(handler) ->SetMessageAllocator(allocator); } @@ -3712,13 +3854,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_AvailableKeychains() { - ::grpc::Service::MarkMethodCallback(43, + ::grpc::Service::MarkMethodCallback(45, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::grpc::AvailableKeychainsResponse>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::Empty* request, ::grpc::AvailableKeychainsResponse* response) { return this->AvailableKeychains(context, request, response); }));} void SetMessageAllocatorFor_AvailableKeychains( ::grpc::MessageAllocator< ::google::protobuf::Empty, ::grpc::AvailableKeychainsResponse>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(43); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(45); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::grpc::AvailableKeychainsResponse>*>(handler) ->SetMessageAllocator(allocator); } @@ -3739,13 +3881,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_SetCurrentKeychain() { - ::grpc::Service::MarkMethodCallback(44, + ::grpc::Service::MarkMethodCallback(46, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::StringValue* request, ::google::protobuf::Empty* response) { return this->SetCurrentKeychain(context, request, response); }));} void SetMessageAllocatorFor_SetCurrentKeychain( ::grpc::MessageAllocator< ::google::protobuf::StringValue, ::google::protobuf::Empty>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(44); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(46); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>*>(handler) ->SetMessageAllocator(allocator); } @@ -3766,13 +3908,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_CurrentKeychain() { - ::grpc::Service::MarkMethodCallback(45, + ::grpc::Service::MarkMethodCallback(47, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::StringValue* response) { return this->CurrentKeychain(context, request, response); }));} void SetMessageAllocatorFor_CurrentKeychain( ::grpc::MessageAllocator< ::google::protobuf::Empty, ::google::protobuf::StringValue>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(45); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(47); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>*>(handler) ->SetMessageAllocator(allocator); } @@ -3793,13 +3935,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_GetUserList() { - ::grpc::Service::MarkMethodCallback(46, + ::grpc::Service::MarkMethodCallback(48, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::grpc::UserListResponse>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::Empty* request, ::grpc::UserListResponse* response) { return this->GetUserList(context, request, response); }));} void SetMessageAllocatorFor_GetUserList( ::grpc::MessageAllocator< ::google::protobuf::Empty, ::grpc::UserListResponse>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(46); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(48); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::grpc::UserListResponse>*>(handler) ->SetMessageAllocator(allocator); } @@ -3820,13 +3962,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_GetUser() { - ::grpc::Service::MarkMethodCallback(47, + ::grpc::Service::MarkMethodCallback(49, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::StringValue, ::grpc::User>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::StringValue* request, ::grpc::User* response) { return this->GetUser(context, request, response); }));} void SetMessageAllocatorFor_GetUser( ::grpc::MessageAllocator< ::google::protobuf::StringValue, ::grpc::User>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(47); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(49); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::StringValue, ::grpc::User>*>(handler) ->SetMessageAllocator(allocator); } @@ -3847,13 +3989,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_SetUserSplitMode() { - ::grpc::Service::MarkMethodCallback(48, + ::grpc::Service::MarkMethodCallback(50, new ::grpc::internal::CallbackUnaryHandler< ::grpc::UserSplitModeRequest, ::google::protobuf::Empty>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::UserSplitModeRequest* request, ::google::protobuf::Empty* response) { return this->SetUserSplitMode(context, request, response); }));} void SetMessageAllocatorFor_SetUserSplitMode( ::grpc::MessageAllocator< ::grpc::UserSplitModeRequest, ::google::protobuf::Empty>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(48); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(50); static_cast<::grpc::internal::CallbackUnaryHandler< ::grpc::UserSplitModeRequest, ::google::protobuf::Empty>*>(handler) ->SetMessageAllocator(allocator); } @@ -3874,13 +4016,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_SendBadEventUserFeedback() { - ::grpc::Service::MarkMethodCallback(49, + ::grpc::Service::MarkMethodCallback(51, new ::grpc::internal::CallbackUnaryHandler< ::grpc::UserBadEventFeedbackRequest, ::google::protobuf::Empty>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::UserBadEventFeedbackRequest* request, ::google::protobuf::Empty* response) { return this->SendBadEventUserFeedback(context, request, response); }));} void SetMessageAllocatorFor_SendBadEventUserFeedback( ::grpc::MessageAllocator< ::grpc::UserBadEventFeedbackRequest, ::google::protobuf::Empty>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(49); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(51); static_cast<::grpc::internal::CallbackUnaryHandler< ::grpc::UserBadEventFeedbackRequest, ::google::protobuf::Empty>*>(handler) ->SetMessageAllocator(allocator); } @@ -3901,13 +4043,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_LogoutUser() { - ::grpc::Service::MarkMethodCallback(50, + ::grpc::Service::MarkMethodCallback(52, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::StringValue* request, ::google::protobuf::Empty* response) { return this->LogoutUser(context, request, response); }));} void SetMessageAllocatorFor_LogoutUser( ::grpc::MessageAllocator< ::google::protobuf::StringValue, ::google::protobuf::Empty>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(50); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(52); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>*>(handler) ->SetMessageAllocator(allocator); } @@ -3928,13 +4070,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_RemoveUser() { - ::grpc::Service::MarkMethodCallback(51, + ::grpc::Service::MarkMethodCallback(53, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::StringValue* request, ::google::protobuf::Empty* response) { return this->RemoveUser(context, request, response); }));} void SetMessageAllocatorFor_RemoveUser( ::grpc::MessageAllocator< ::google::protobuf::StringValue, ::google::protobuf::Empty>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(51); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(53); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>*>(handler) ->SetMessageAllocator(allocator); } @@ -3955,13 +4097,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_ConfigureUserAppleMail() { - ::grpc::Service::MarkMethodCallback(52, + ::grpc::Service::MarkMethodCallback(54, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ConfigureAppleMailRequest, ::google::protobuf::Empty>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ConfigureAppleMailRequest* request, ::google::protobuf::Empty* response) { return this->ConfigureUserAppleMail(context, request, response); }));} void SetMessageAllocatorFor_ConfigureUserAppleMail( ::grpc::MessageAllocator< ::grpc::ConfigureAppleMailRequest, ::google::protobuf::Empty>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(52); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(54); static_cast<::grpc::internal::CallbackUnaryHandler< ::grpc::ConfigureAppleMailRequest, ::google::protobuf::Empty>*>(handler) ->SetMessageAllocator(allocator); } @@ -3982,7 +4124,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_RunEventStream() { - ::grpc::Service::MarkMethodCallback(53, + ::grpc::Service::MarkMethodCallback(55, new ::grpc::internal::CallbackServerStreamingHandler< ::grpc::EventStreamRequest, ::grpc::StreamEvent>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::EventStreamRequest* request) { return this->RunEventStream(context, request); })); @@ -4004,13 +4146,13 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithCallbackMethod_StopEventStream() { - ::grpc::Service::MarkMethodCallback(54, + ::grpc::Service::MarkMethodCallback(56, new ::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::Empty>( [this]( ::grpc::CallbackServerContext* context, const ::google::protobuf::Empty* request, ::google::protobuf::Empty* response) { return this->StopEventStream(context, request, response); }));} void SetMessageAllocatorFor_StopEventStream( ::grpc::MessageAllocator< ::google::protobuf::Empty, ::google::protobuf::Empty>* allocator) { - ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(54); + ::grpc::internal::MethodHandler* const handler = ::grpc::Service::GetHandler(56); static_cast<::grpc::internal::CallbackUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::Empty>*>(handler) ->SetMessageAllocator(allocator); } @@ -4025,7 +4167,7 @@ class Bridge final { virtual ::grpc::ServerUnaryReactor* StopEventStream( ::grpc::CallbackServerContext* /*context*/, const ::google::protobuf::Empty* /*request*/, ::google::protobuf::Empty* /*response*/) { return nullptr; } }; - typedef WithCallbackMethod_CheckTokens > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > CallbackService; + typedef WithCallbackMethod_CheckTokens > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > CallbackService; typedef CallbackService ExperimentalCallbackService; template class WithGenericMethod_CheckTokens : public BaseClass { @@ -4232,12 +4374,46 @@ class Bridge final { } }; template + class WithGenericMethod_SetIsTelemetryDisabled : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} + public: + WithGenericMethod_SetIsTelemetryDisabled() { + ::grpc::Service::MarkMethodGeneric(12); + } + ~WithGenericMethod_SetIsTelemetryDisabled() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status SetIsTelemetryDisabled(::grpc::ServerContext* /*context*/, const ::google::protobuf::BoolValue* /*request*/, ::google::protobuf::Empty* /*response*/) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + }; + template + class WithGenericMethod_IsTelemetryDisabled : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} + public: + WithGenericMethod_IsTelemetryDisabled() { + ::grpc::Service::MarkMethodGeneric(13); + } + ~WithGenericMethod_IsTelemetryDisabled() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status IsTelemetryDisabled(::grpc::ServerContext* /*context*/, const ::google::protobuf::Empty* /*request*/, ::google::protobuf::BoolValue* /*response*/) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + }; + template class WithGenericMethod_GoOs : public BaseClass { private: void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_GoOs() { - ::grpc::Service::MarkMethodGeneric(12); + ::grpc::Service::MarkMethodGeneric(14); } ~WithGenericMethod_GoOs() override { BaseClassMustBeDerivedFromService(this); @@ -4254,7 +4430,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_TriggerReset() { - ::grpc::Service::MarkMethodGeneric(13); + ::grpc::Service::MarkMethodGeneric(15); } ~WithGenericMethod_TriggerReset() override { BaseClassMustBeDerivedFromService(this); @@ -4271,7 +4447,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_Version() { - ::grpc::Service::MarkMethodGeneric(14); + ::grpc::Service::MarkMethodGeneric(16); } ~WithGenericMethod_Version() override { BaseClassMustBeDerivedFromService(this); @@ -4288,7 +4464,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_LogsPath() { - ::grpc::Service::MarkMethodGeneric(15); + ::grpc::Service::MarkMethodGeneric(17); } ~WithGenericMethod_LogsPath() override { BaseClassMustBeDerivedFromService(this); @@ -4305,7 +4481,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_LicensePath() { - ::grpc::Service::MarkMethodGeneric(16); + ::grpc::Service::MarkMethodGeneric(18); } ~WithGenericMethod_LicensePath() override { BaseClassMustBeDerivedFromService(this); @@ -4322,7 +4498,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_ReleaseNotesPageLink() { - ::grpc::Service::MarkMethodGeneric(17); + ::grpc::Service::MarkMethodGeneric(19); } ~WithGenericMethod_ReleaseNotesPageLink() override { BaseClassMustBeDerivedFromService(this); @@ -4339,7 +4515,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_DependencyLicensesLink() { - ::grpc::Service::MarkMethodGeneric(18); + ::grpc::Service::MarkMethodGeneric(20); } ~WithGenericMethod_DependencyLicensesLink() override { BaseClassMustBeDerivedFromService(this); @@ -4356,7 +4532,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_LandingPageLink() { - ::grpc::Service::MarkMethodGeneric(19); + ::grpc::Service::MarkMethodGeneric(21); } ~WithGenericMethod_LandingPageLink() override { BaseClassMustBeDerivedFromService(this); @@ -4373,7 +4549,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_SetColorSchemeName() { - ::grpc::Service::MarkMethodGeneric(20); + ::grpc::Service::MarkMethodGeneric(22); } ~WithGenericMethod_SetColorSchemeName() override { BaseClassMustBeDerivedFromService(this); @@ -4390,7 +4566,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_ColorSchemeName() { - ::grpc::Service::MarkMethodGeneric(21); + ::grpc::Service::MarkMethodGeneric(23); } ~WithGenericMethod_ColorSchemeName() override { BaseClassMustBeDerivedFromService(this); @@ -4407,7 +4583,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_CurrentEmailClient() { - ::grpc::Service::MarkMethodGeneric(22); + ::grpc::Service::MarkMethodGeneric(24); } ~WithGenericMethod_CurrentEmailClient() override { BaseClassMustBeDerivedFromService(this); @@ -4424,7 +4600,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_ReportBug() { - ::grpc::Service::MarkMethodGeneric(23); + ::grpc::Service::MarkMethodGeneric(25); } ~WithGenericMethod_ReportBug() override { BaseClassMustBeDerivedFromService(this); @@ -4441,7 +4617,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_ExportTLSCertificates() { - ::grpc::Service::MarkMethodGeneric(24); + ::grpc::Service::MarkMethodGeneric(26); } ~WithGenericMethod_ExportTLSCertificates() override { BaseClassMustBeDerivedFromService(this); @@ -4458,7 +4634,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_ForceLauncher() { - ::grpc::Service::MarkMethodGeneric(25); + ::grpc::Service::MarkMethodGeneric(27); } ~WithGenericMethod_ForceLauncher() override { BaseClassMustBeDerivedFromService(this); @@ -4475,7 +4651,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_SetMainExecutable() { - ::grpc::Service::MarkMethodGeneric(26); + ::grpc::Service::MarkMethodGeneric(28); } ~WithGenericMethod_SetMainExecutable() override { BaseClassMustBeDerivedFromService(this); @@ -4492,7 +4668,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_Login() { - ::grpc::Service::MarkMethodGeneric(27); + ::grpc::Service::MarkMethodGeneric(29); } ~WithGenericMethod_Login() override { BaseClassMustBeDerivedFromService(this); @@ -4509,7 +4685,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_Login2FA() { - ::grpc::Service::MarkMethodGeneric(28); + ::grpc::Service::MarkMethodGeneric(30); } ~WithGenericMethod_Login2FA() override { BaseClassMustBeDerivedFromService(this); @@ -4526,7 +4702,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_Login2Passwords() { - ::grpc::Service::MarkMethodGeneric(29); + ::grpc::Service::MarkMethodGeneric(31); } ~WithGenericMethod_Login2Passwords() override { BaseClassMustBeDerivedFromService(this); @@ -4543,7 +4719,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_LoginAbort() { - ::grpc::Service::MarkMethodGeneric(30); + ::grpc::Service::MarkMethodGeneric(32); } ~WithGenericMethod_LoginAbort() override { BaseClassMustBeDerivedFromService(this); @@ -4560,7 +4736,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_CheckUpdate() { - ::grpc::Service::MarkMethodGeneric(31); + ::grpc::Service::MarkMethodGeneric(33); } ~WithGenericMethod_CheckUpdate() override { BaseClassMustBeDerivedFromService(this); @@ -4577,7 +4753,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_InstallUpdate() { - ::grpc::Service::MarkMethodGeneric(32); + ::grpc::Service::MarkMethodGeneric(34); } ~WithGenericMethod_InstallUpdate() override { BaseClassMustBeDerivedFromService(this); @@ -4594,7 +4770,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_SetIsAutomaticUpdateOn() { - ::grpc::Service::MarkMethodGeneric(33); + ::grpc::Service::MarkMethodGeneric(35); } ~WithGenericMethod_SetIsAutomaticUpdateOn() override { BaseClassMustBeDerivedFromService(this); @@ -4611,7 +4787,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_IsAutomaticUpdateOn() { - ::grpc::Service::MarkMethodGeneric(34); + ::grpc::Service::MarkMethodGeneric(36); } ~WithGenericMethod_IsAutomaticUpdateOn() override { BaseClassMustBeDerivedFromService(this); @@ -4628,7 +4804,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_DiskCachePath() { - ::grpc::Service::MarkMethodGeneric(35); + ::grpc::Service::MarkMethodGeneric(37); } ~WithGenericMethod_DiskCachePath() override { BaseClassMustBeDerivedFromService(this); @@ -4645,7 +4821,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_SetDiskCachePath() { - ::grpc::Service::MarkMethodGeneric(36); + ::grpc::Service::MarkMethodGeneric(38); } ~WithGenericMethod_SetDiskCachePath() override { BaseClassMustBeDerivedFromService(this); @@ -4662,7 +4838,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_SetIsDoHEnabled() { - ::grpc::Service::MarkMethodGeneric(37); + ::grpc::Service::MarkMethodGeneric(39); } ~WithGenericMethod_SetIsDoHEnabled() override { BaseClassMustBeDerivedFromService(this); @@ -4679,7 +4855,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_IsDoHEnabled() { - ::grpc::Service::MarkMethodGeneric(38); + ::grpc::Service::MarkMethodGeneric(40); } ~WithGenericMethod_IsDoHEnabled() override { BaseClassMustBeDerivedFromService(this); @@ -4696,7 +4872,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_MailServerSettings() { - ::grpc::Service::MarkMethodGeneric(39); + ::grpc::Service::MarkMethodGeneric(41); } ~WithGenericMethod_MailServerSettings() override { BaseClassMustBeDerivedFromService(this); @@ -4713,7 +4889,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_SetMailServerSettings() { - ::grpc::Service::MarkMethodGeneric(40); + ::grpc::Service::MarkMethodGeneric(42); } ~WithGenericMethod_SetMailServerSettings() override { BaseClassMustBeDerivedFromService(this); @@ -4730,7 +4906,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_Hostname() { - ::grpc::Service::MarkMethodGeneric(41); + ::grpc::Service::MarkMethodGeneric(43); } ~WithGenericMethod_Hostname() override { BaseClassMustBeDerivedFromService(this); @@ -4747,7 +4923,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_IsPortFree() { - ::grpc::Service::MarkMethodGeneric(42); + ::grpc::Service::MarkMethodGeneric(44); } ~WithGenericMethod_IsPortFree() override { BaseClassMustBeDerivedFromService(this); @@ -4764,7 +4940,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_AvailableKeychains() { - ::grpc::Service::MarkMethodGeneric(43); + ::grpc::Service::MarkMethodGeneric(45); } ~WithGenericMethod_AvailableKeychains() override { BaseClassMustBeDerivedFromService(this); @@ -4781,7 +4957,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_SetCurrentKeychain() { - ::grpc::Service::MarkMethodGeneric(44); + ::grpc::Service::MarkMethodGeneric(46); } ~WithGenericMethod_SetCurrentKeychain() override { BaseClassMustBeDerivedFromService(this); @@ -4798,7 +4974,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_CurrentKeychain() { - ::grpc::Service::MarkMethodGeneric(45); + ::grpc::Service::MarkMethodGeneric(47); } ~WithGenericMethod_CurrentKeychain() override { BaseClassMustBeDerivedFromService(this); @@ -4815,7 +4991,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_GetUserList() { - ::grpc::Service::MarkMethodGeneric(46); + ::grpc::Service::MarkMethodGeneric(48); } ~WithGenericMethod_GetUserList() override { BaseClassMustBeDerivedFromService(this); @@ -4832,7 +5008,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_GetUser() { - ::grpc::Service::MarkMethodGeneric(47); + ::grpc::Service::MarkMethodGeneric(49); } ~WithGenericMethod_GetUser() override { BaseClassMustBeDerivedFromService(this); @@ -4849,7 +5025,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_SetUserSplitMode() { - ::grpc::Service::MarkMethodGeneric(48); + ::grpc::Service::MarkMethodGeneric(50); } ~WithGenericMethod_SetUserSplitMode() override { BaseClassMustBeDerivedFromService(this); @@ -4866,7 +5042,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_SendBadEventUserFeedback() { - ::grpc::Service::MarkMethodGeneric(49); + ::grpc::Service::MarkMethodGeneric(51); } ~WithGenericMethod_SendBadEventUserFeedback() override { BaseClassMustBeDerivedFromService(this); @@ -4883,7 +5059,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_LogoutUser() { - ::grpc::Service::MarkMethodGeneric(50); + ::grpc::Service::MarkMethodGeneric(52); } ~WithGenericMethod_LogoutUser() override { BaseClassMustBeDerivedFromService(this); @@ -4900,7 +5076,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_RemoveUser() { - ::grpc::Service::MarkMethodGeneric(51); + ::grpc::Service::MarkMethodGeneric(53); } ~WithGenericMethod_RemoveUser() override { BaseClassMustBeDerivedFromService(this); @@ -4917,7 +5093,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_ConfigureUserAppleMail() { - ::grpc::Service::MarkMethodGeneric(52); + ::grpc::Service::MarkMethodGeneric(54); } ~WithGenericMethod_ConfigureUserAppleMail() override { BaseClassMustBeDerivedFromService(this); @@ -4934,7 +5110,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_RunEventStream() { - ::grpc::Service::MarkMethodGeneric(53); + ::grpc::Service::MarkMethodGeneric(55); } ~WithGenericMethod_RunEventStream() override { BaseClassMustBeDerivedFromService(this); @@ -4951,7 +5127,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithGenericMethod_StopEventStream() { - ::grpc::Service::MarkMethodGeneric(54); + ::grpc::Service::MarkMethodGeneric(56); } ~WithGenericMethod_StopEventStream() override { BaseClassMustBeDerivedFromService(this); @@ -5203,12 +5379,52 @@ class Bridge final { } }; template + class WithRawMethod_SetIsTelemetryDisabled : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} + public: + WithRawMethod_SetIsTelemetryDisabled() { + ::grpc::Service::MarkMethodRaw(12); + } + ~WithRawMethod_SetIsTelemetryDisabled() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status SetIsTelemetryDisabled(::grpc::ServerContext* /*context*/, const ::google::protobuf::BoolValue* /*request*/, ::google::protobuf::Empty* /*response*/) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + void RequestSetIsTelemetryDisabled(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { + ::grpc::Service::RequestAsyncUnary(12, context, request, response, new_call_cq, notification_cq, tag); + } + }; + template + class WithRawMethod_IsTelemetryDisabled : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} + public: + WithRawMethod_IsTelemetryDisabled() { + ::grpc::Service::MarkMethodRaw(13); + } + ~WithRawMethod_IsTelemetryDisabled() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status IsTelemetryDisabled(::grpc::ServerContext* /*context*/, const ::google::protobuf::Empty* /*request*/, ::google::protobuf::BoolValue* /*response*/) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + void RequestIsTelemetryDisabled(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { + ::grpc::Service::RequestAsyncUnary(13, context, request, response, new_call_cq, notification_cq, tag); + } + }; + template class WithRawMethod_GoOs : public BaseClass { private: void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_GoOs() { - ::grpc::Service::MarkMethodRaw(12); + ::grpc::Service::MarkMethodRaw(14); } ~WithRawMethod_GoOs() override { BaseClassMustBeDerivedFromService(this); @@ -5219,7 +5435,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestGoOs(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(12, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(14, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5228,7 +5444,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_TriggerReset() { - ::grpc::Service::MarkMethodRaw(13); + ::grpc::Service::MarkMethodRaw(15); } ~WithRawMethod_TriggerReset() override { BaseClassMustBeDerivedFromService(this); @@ -5239,7 +5455,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestTriggerReset(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(13, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(15, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5248,7 +5464,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_Version() { - ::grpc::Service::MarkMethodRaw(14); + ::grpc::Service::MarkMethodRaw(16); } ~WithRawMethod_Version() override { BaseClassMustBeDerivedFromService(this); @@ -5259,7 +5475,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestVersion(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(14, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(16, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5268,7 +5484,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_LogsPath() { - ::grpc::Service::MarkMethodRaw(15); + ::grpc::Service::MarkMethodRaw(17); } ~WithRawMethod_LogsPath() override { BaseClassMustBeDerivedFromService(this); @@ -5279,7 +5495,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestLogsPath(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(15, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(17, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5288,7 +5504,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_LicensePath() { - ::grpc::Service::MarkMethodRaw(16); + ::grpc::Service::MarkMethodRaw(18); } ~WithRawMethod_LicensePath() override { BaseClassMustBeDerivedFromService(this); @@ -5299,7 +5515,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestLicensePath(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(16, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(18, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5308,7 +5524,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_ReleaseNotesPageLink() { - ::grpc::Service::MarkMethodRaw(17); + ::grpc::Service::MarkMethodRaw(19); } ~WithRawMethod_ReleaseNotesPageLink() override { BaseClassMustBeDerivedFromService(this); @@ -5319,7 +5535,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestReleaseNotesPageLink(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(17, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(19, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5328,7 +5544,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_DependencyLicensesLink() { - ::grpc::Service::MarkMethodRaw(18); + ::grpc::Service::MarkMethodRaw(20); } ~WithRawMethod_DependencyLicensesLink() override { BaseClassMustBeDerivedFromService(this); @@ -5339,7 +5555,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestDependencyLicensesLink(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(18, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(20, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5348,7 +5564,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_LandingPageLink() { - ::grpc::Service::MarkMethodRaw(19); + ::grpc::Service::MarkMethodRaw(21); } ~WithRawMethod_LandingPageLink() override { BaseClassMustBeDerivedFromService(this); @@ -5359,7 +5575,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestLandingPageLink(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(19, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(21, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5368,7 +5584,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_SetColorSchemeName() { - ::grpc::Service::MarkMethodRaw(20); + ::grpc::Service::MarkMethodRaw(22); } ~WithRawMethod_SetColorSchemeName() override { BaseClassMustBeDerivedFromService(this); @@ -5379,7 +5595,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestSetColorSchemeName(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(20, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(22, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5388,7 +5604,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_ColorSchemeName() { - ::grpc::Service::MarkMethodRaw(21); + ::grpc::Service::MarkMethodRaw(23); } ~WithRawMethod_ColorSchemeName() override { BaseClassMustBeDerivedFromService(this); @@ -5399,7 +5615,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestColorSchemeName(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(21, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(23, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5408,7 +5624,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_CurrentEmailClient() { - ::grpc::Service::MarkMethodRaw(22); + ::grpc::Service::MarkMethodRaw(24); } ~WithRawMethod_CurrentEmailClient() override { BaseClassMustBeDerivedFromService(this); @@ -5419,7 +5635,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestCurrentEmailClient(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(22, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(24, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5428,7 +5644,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_ReportBug() { - ::grpc::Service::MarkMethodRaw(23); + ::grpc::Service::MarkMethodRaw(25); } ~WithRawMethod_ReportBug() override { BaseClassMustBeDerivedFromService(this); @@ -5439,7 +5655,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestReportBug(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(23, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(25, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5448,7 +5664,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_ExportTLSCertificates() { - ::grpc::Service::MarkMethodRaw(24); + ::grpc::Service::MarkMethodRaw(26); } ~WithRawMethod_ExportTLSCertificates() override { BaseClassMustBeDerivedFromService(this); @@ -5459,7 +5675,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestExportTLSCertificates(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(24, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(26, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5468,7 +5684,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_ForceLauncher() { - ::grpc::Service::MarkMethodRaw(25); + ::grpc::Service::MarkMethodRaw(27); } ~WithRawMethod_ForceLauncher() override { BaseClassMustBeDerivedFromService(this); @@ -5479,7 +5695,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestForceLauncher(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(25, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(27, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5488,7 +5704,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_SetMainExecutable() { - ::grpc::Service::MarkMethodRaw(26); + ::grpc::Service::MarkMethodRaw(28); } ~WithRawMethod_SetMainExecutable() override { BaseClassMustBeDerivedFromService(this); @@ -5499,7 +5715,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestSetMainExecutable(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(26, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(28, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5508,7 +5724,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_Login() { - ::grpc::Service::MarkMethodRaw(27); + ::grpc::Service::MarkMethodRaw(29); } ~WithRawMethod_Login() override { BaseClassMustBeDerivedFromService(this); @@ -5519,7 +5735,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestLogin(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(27, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(29, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5528,7 +5744,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_Login2FA() { - ::grpc::Service::MarkMethodRaw(28); + ::grpc::Service::MarkMethodRaw(30); } ~WithRawMethod_Login2FA() override { BaseClassMustBeDerivedFromService(this); @@ -5539,7 +5755,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestLogin2FA(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(28, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(30, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5548,7 +5764,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_Login2Passwords() { - ::grpc::Service::MarkMethodRaw(29); + ::grpc::Service::MarkMethodRaw(31); } ~WithRawMethod_Login2Passwords() override { BaseClassMustBeDerivedFromService(this); @@ -5559,7 +5775,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestLogin2Passwords(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(29, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(31, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5568,7 +5784,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_LoginAbort() { - ::grpc::Service::MarkMethodRaw(30); + ::grpc::Service::MarkMethodRaw(32); } ~WithRawMethod_LoginAbort() override { BaseClassMustBeDerivedFromService(this); @@ -5579,7 +5795,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestLoginAbort(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(30, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(32, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5588,7 +5804,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_CheckUpdate() { - ::grpc::Service::MarkMethodRaw(31); + ::grpc::Service::MarkMethodRaw(33); } ~WithRawMethod_CheckUpdate() override { BaseClassMustBeDerivedFromService(this); @@ -5599,7 +5815,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestCheckUpdate(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(31, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(33, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5608,7 +5824,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_InstallUpdate() { - ::grpc::Service::MarkMethodRaw(32); + ::grpc::Service::MarkMethodRaw(34); } ~WithRawMethod_InstallUpdate() override { BaseClassMustBeDerivedFromService(this); @@ -5619,7 +5835,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestInstallUpdate(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(32, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(34, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5628,7 +5844,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_SetIsAutomaticUpdateOn() { - ::grpc::Service::MarkMethodRaw(33); + ::grpc::Service::MarkMethodRaw(35); } ~WithRawMethod_SetIsAutomaticUpdateOn() override { BaseClassMustBeDerivedFromService(this); @@ -5639,7 +5855,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestSetIsAutomaticUpdateOn(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(33, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(35, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5648,7 +5864,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_IsAutomaticUpdateOn() { - ::grpc::Service::MarkMethodRaw(34); + ::grpc::Service::MarkMethodRaw(36); } ~WithRawMethod_IsAutomaticUpdateOn() override { BaseClassMustBeDerivedFromService(this); @@ -5659,7 +5875,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestIsAutomaticUpdateOn(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(34, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(36, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5668,7 +5884,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_DiskCachePath() { - ::grpc::Service::MarkMethodRaw(35); + ::grpc::Service::MarkMethodRaw(37); } ~WithRawMethod_DiskCachePath() override { BaseClassMustBeDerivedFromService(this); @@ -5679,7 +5895,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestDiskCachePath(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(35, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(37, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5688,7 +5904,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_SetDiskCachePath() { - ::grpc::Service::MarkMethodRaw(36); + ::grpc::Service::MarkMethodRaw(38); } ~WithRawMethod_SetDiskCachePath() override { BaseClassMustBeDerivedFromService(this); @@ -5699,7 +5915,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestSetDiskCachePath(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(36, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(38, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5708,7 +5924,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_SetIsDoHEnabled() { - ::grpc::Service::MarkMethodRaw(37); + ::grpc::Service::MarkMethodRaw(39); } ~WithRawMethod_SetIsDoHEnabled() override { BaseClassMustBeDerivedFromService(this); @@ -5719,7 +5935,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestSetIsDoHEnabled(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(37, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(39, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5728,7 +5944,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_IsDoHEnabled() { - ::grpc::Service::MarkMethodRaw(38); + ::grpc::Service::MarkMethodRaw(40); } ~WithRawMethod_IsDoHEnabled() override { BaseClassMustBeDerivedFromService(this); @@ -5739,7 +5955,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestIsDoHEnabled(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(38, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(40, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5748,7 +5964,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_MailServerSettings() { - ::grpc::Service::MarkMethodRaw(39); + ::grpc::Service::MarkMethodRaw(41); } ~WithRawMethod_MailServerSettings() override { BaseClassMustBeDerivedFromService(this); @@ -5759,7 +5975,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestMailServerSettings(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(39, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(41, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5768,7 +5984,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_SetMailServerSettings() { - ::grpc::Service::MarkMethodRaw(40); + ::grpc::Service::MarkMethodRaw(42); } ~WithRawMethod_SetMailServerSettings() override { BaseClassMustBeDerivedFromService(this); @@ -5779,7 +5995,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestSetMailServerSettings(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(40, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(42, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5788,7 +6004,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_Hostname() { - ::grpc::Service::MarkMethodRaw(41); + ::grpc::Service::MarkMethodRaw(43); } ~WithRawMethod_Hostname() override { BaseClassMustBeDerivedFromService(this); @@ -5799,7 +6015,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestHostname(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(41, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(43, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5808,7 +6024,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_IsPortFree() { - ::grpc::Service::MarkMethodRaw(42); + ::grpc::Service::MarkMethodRaw(44); } ~WithRawMethod_IsPortFree() override { BaseClassMustBeDerivedFromService(this); @@ -5819,7 +6035,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestIsPortFree(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(42, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(44, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5828,7 +6044,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_AvailableKeychains() { - ::grpc::Service::MarkMethodRaw(43); + ::grpc::Service::MarkMethodRaw(45); } ~WithRawMethod_AvailableKeychains() override { BaseClassMustBeDerivedFromService(this); @@ -5839,7 +6055,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestAvailableKeychains(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(43, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(45, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5848,7 +6064,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_SetCurrentKeychain() { - ::grpc::Service::MarkMethodRaw(44); + ::grpc::Service::MarkMethodRaw(46); } ~WithRawMethod_SetCurrentKeychain() override { BaseClassMustBeDerivedFromService(this); @@ -5859,7 +6075,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestSetCurrentKeychain(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(44, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(46, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5868,7 +6084,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_CurrentKeychain() { - ::grpc::Service::MarkMethodRaw(45); + ::grpc::Service::MarkMethodRaw(47); } ~WithRawMethod_CurrentKeychain() override { BaseClassMustBeDerivedFromService(this); @@ -5879,7 +6095,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestCurrentKeychain(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(45, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(47, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5888,7 +6104,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_GetUserList() { - ::grpc::Service::MarkMethodRaw(46); + ::grpc::Service::MarkMethodRaw(48); } ~WithRawMethod_GetUserList() override { BaseClassMustBeDerivedFromService(this); @@ -5899,7 +6115,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestGetUserList(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(46, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(48, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5908,7 +6124,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_GetUser() { - ::grpc::Service::MarkMethodRaw(47); + ::grpc::Service::MarkMethodRaw(49); } ~WithRawMethod_GetUser() override { BaseClassMustBeDerivedFromService(this); @@ -5919,7 +6135,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestGetUser(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(47, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(49, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5928,7 +6144,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_SetUserSplitMode() { - ::grpc::Service::MarkMethodRaw(48); + ::grpc::Service::MarkMethodRaw(50); } ~WithRawMethod_SetUserSplitMode() override { BaseClassMustBeDerivedFromService(this); @@ -5939,7 +6155,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestSetUserSplitMode(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(48, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(50, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5948,7 +6164,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_SendBadEventUserFeedback() { - ::grpc::Service::MarkMethodRaw(49); + ::grpc::Service::MarkMethodRaw(51); } ~WithRawMethod_SendBadEventUserFeedback() override { BaseClassMustBeDerivedFromService(this); @@ -5959,7 +6175,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestSendBadEventUserFeedback(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(49, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(51, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5968,7 +6184,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_LogoutUser() { - ::grpc::Service::MarkMethodRaw(50); + ::grpc::Service::MarkMethodRaw(52); } ~WithRawMethod_LogoutUser() override { BaseClassMustBeDerivedFromService(this); @@ -5979,7 +6195,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestLogoutUser(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(50, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(52, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -5988,7 +6204,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_RemoveUser() { - ::grpc::Service::MarkMethodRaw(51); + ::grpc::Service::MarkMethodRaw(53); } ~WithRawMethod_RemoveUser() override { BaseClassMustBeDerivedFromService(this); @@ -5999,7 +6215,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestRemoveUser(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(51, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(53, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -6008,7 +6224,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_ConfigureUserAppleMail() { - ::grpc::Service::MarkMethodRaw(52); + ::grpc::Service::MarkMethodRaw(54); } ~WithRawMethod_ConfigureUserAppleMail() override { BaseClassMustBeDerivedFromService(this); @@ -6019,7 +6235,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestConfigureUserAppleMail(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(52, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(54, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -6028,7 +6244,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_RunEventStream() { - ::grpc::Service::MarkMethodRaw(53); + ::grpc::Service::MarkMethodRaw(55); } ~WithRawMethod_RunEventStream() override { BaseClassMustBeDerivedFromService(this); @@ -6039,7 +6255,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestRunEventStream(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncWriter< ::grpc::ByteBuffer>* writer, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncServerStreaming(53, context, request, writer, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncServerStreaming(55, context, request, writer, new_call_cq, notification_cq, tag); } }; template @@ -6048,7 +6264,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawMethod_StopEventStream() { - ::grpc::Service::MarkMethodRaw(54); + ::grpc::Service::MarkMethodRaw(56); } ~WithRawMethod_StopEventStream() override { BaseClassMustBeDerivedFromService(this); @@ -6059,7 +6275,7 @@ class Bridge final { return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); } void RequestStopEventStream(::grpc::ServerContext* context, ::grpc::ByteBuffer* request, ::grpc::ServerAsyncResponseWriter< ::grpc::ByteBuffer>* response, ::grpc::CompletionQueue* new_call_cq, ::grpc::ServerCompletionQueue* notification_cq, void *tag) { - ::grpc::Service::RequestAsyncUnary(54, context, request, response, new_call_cq, notification_cq, tag); + ::grpc::Service::RequestAsyncUnary(56, context, request, response, new_call_cq, notification_cq, tag); } }; template @@ -6327,12 +6543,56 @@ class Bridge final { ::grpc::CallbackServerContext* /*context*/, const ::grpc::ByteBuffer* /*request*/, ::grpc::ByteBuffer* /*response*/) { return nullptr; } }; template + class WithRawCallbackMethod_SetIsTelemetryDisabled : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} + public: + WithRawCallbackMethod_SetIsTelemetryDisabled() { + ::grpc::Service::MarkMethodRawCallback(12, + new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( + [this]( + ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->SetIsTelemetryDisabled(context, request, response); })); + } + ~WithRawCallbackMethod_SetIsTelemetryDisabled() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status SetIsTelemetryDisabled(::grpc::ServerContext* /*context*/, const ::google::protobuf::BoolValue* /*request*/, ::google::protobuf::Empty* /*response*/) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + virtual ::grpc::ServerUnaryReactor* SetIsTelemetryDisabled( + ::grpc::CallbackServerContext* /*context*/, const ::grpc::ByteBuffer* /*request*/, ::grpc::ByteBuffer* /*response*/) { return nullptr; } + }; + template + class WithRawCallbackMethod_IsTelemetryDisabled : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} + public: + WithRawCallbackMethod_IsTelemetryDisabled() { + ::grpc::Service::MarkMethodRawCallback(13, + new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( + [this]( + ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->IsTelemetryDisabled(context, request, response); })); + } + ~WithRawCallbackMethod_IsTelemetryDisabled() override { + BaseClassMustBeDerivedFromService(this); + } + // disable synchronous version of this method + ::grpc::Status IsTelemetryDisabled(::grpc::ServerContext* /*context*/, const ::google::protobuf::Empty* /*request*/, ::google::protobuf::BoolValue* /*response*/) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + virtual ::grpc::ServerUnaryReactor* IsTelemetryDisabled( + ::grpc::CallbackServerContext* /*context*/, const ::grpc::ByteBuffer* /*request*/, ::grpc::ByteBuffer* /*response*/) { return nullptr; } + }; + template class WithRawCallbackMethod_GoOs : public BaseClass { private: void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_GoOs() { - ::grpc::Service::MarkMethodRawCallback(12, + ::grpc::Service::MarkMethodRawCallback(14, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->GoOs(context, request, response); })); @@ -6354,7 +6614,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_TriggerReset() { - ::grpc::Service::MarkMethodRawCallback(13, + ::grpc::Service::MarkMethodRawCallback(15, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->TriggerReset(context, request, response); })); @@ -6376,7 +6636,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_Version() { - ::grpc::Service::MarkMethodRawCallback(14, + ::grpc::Service::MarkMethodRawCallback(16, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->Version(context, request, response); })); @@ -6398,7 +6658,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_LogsPath() { - ::grpc::Service::MarkMethodRawCallback(15, + ::grpc::Service::MarkMethodRawCallback(17, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->LogsPath(context, request, response); })); @@ -6420,7 +6680,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_LicensePath() { - ::grpc::Service::MarkMethodRawCallback(16, + ::grpc::Service::MarkMethodRawCallback(18, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->LicensePath(context, request, response); })); @@ -6442,7 +6702,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_ReleaseNotesPageLink() { - ::grpc::Service::MarkMethodRawCallback(17, + ::grpc::Service::MarkMethodRawCallback(19, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->ReleaseNotesPageLink(context, request, response); })); @@ -6464,7 +6724,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_DependencyLicensesLink() { - ::grpc::Service::MarkMethodRawCallback(18, + ::grpc::Service::MarkMethodRawCallback(20, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->DependencyLicensesLink(context, request, response); })); @@ -6486,7 +6746,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_LandingPageLink() { - ::grpc::Service::MarkMethodRawCallback(19, + ::grpc::Service::MarkMethodRawCallback(21, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->LandingPageLink(context, request, response); })); @@ -6508,7 +6768,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_SetColorSchemeName() { - ::grpc::Service::MarkMethodRawCallback(20, + ::grpc::Service::MarkMethodRawCallback(22, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->SetColorSchemeName(context, request, response); })); @@ -6530,7 +6790,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_ColorSchemeName() { - ::grpc::Service::MarkMethodRawCallback(21, + ::grpc::Service::MarkMethodRawCallback(23, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->ColorSchemeName(context, request, response); })); @@ -6552,7 +6812,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_CurrentEmailClient() { - ::grpc::Service::MarkMethodRawCallback(22, + ::grpc::Service::MarkMethodRawCallback(24, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->CurrentEmailClient(context, request, response); })); @@ -6574,7 +6834,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_ReportBug() { - ::grpc::Service::MarkMethodRawCallback(23, + ::grpc::Service::MarkMethodRawCallback(25, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->ReportBug(context, request, response); })); @@ -6596,7 +6856,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_ExportTLSCertificates() { - ::grpc::Service::MarkMethodRawCallback(24, + ::grpc::Service::MarkMethodRawCallback(26, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->ExportTLSCertificates(context, request, response); })); @@ -6618,7 +6878,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_ForceLauncher() { - ::grpc::Service::MarkMethodRawCallback(25, + ::grpc::Service::MarkMethodRawCallback(27, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->ForceLauncher(context, request, response); })); @@ -6640,7 +6900,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_SetMainExecutable() { - ::grpc::Service::MarkMethodRawCallback(26, + ::grpc::Service::MarkMethodRawCallback(28, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->SetMainExecutable(context, request, response); })); @@ -6662,7 +6922,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_Login() { - ::grpc::Service::MarkMethodRawCallback(27, + ::grpc::Service::MarkMethodRawCallback(29, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->Login(context, request, response); })); @@ -6684,7 +6944,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_Login2FA() { - ::grpc::Service::MarkMethodRawCallback(28, + ::grpc::Service::MarkMethodRawCallback(30, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->Login2FA(context, request, response); })); @@ -6706,7 +6966,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_Login2Passwords() { - ::grpc::Service::MarkMethodRawCallback(29, + ::grpc::Service::MarkMethodRawCallback(31, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->Login2Passwords(context, request, response); })); @@ -6728,7 +6988,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_LoginAbort() { - ::grpc::Service::MarkMethodRawCallback(30, + ::grpc::Service::MarkMethodRawCallback(32, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->LoginAbort(context, request, response); })); @@ -6750,7 +7010,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_CheckUpdate() { - ::grpc::Service::MarkMethodRawCallback(31, + ::grpc::Service::MarkMethodRawCallback(33, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->CheckUpdate(context, request, response); })); @@ -6772,7 +7032,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_InstallUpdate() { - ::grpc::Service::MarkMethodRawCallback(32, + ::grpc::Service::MarkMethodRawCallback(34, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->InstallUpdate(context, request, response); })); @@ -6794,7 +7054,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_SetIsAutomaticUpdateOn() { - ::grpc::Service::MarkMethodRawCallback(33, + ::grpc::Service::MarkMethodRawCallback(35, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->SetIsAutomaticUpdateOn(context, request, response); })); @@ -6816,7 +7076,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_IsAutomaticUpdateOn() { - ::grpc::Service::MarkMethodRawCallback(34, + ::grpc::Service::MarkMethodRawCallback(36, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->IsAutomaticUpdateOn(context, request, response); })); @@ -6838,7 +7098,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_DiskCachePath() { - ::grpc::Service::MarkMethodRawCallback(35, + ::grpc::Service::MarkMethodRawCallback(37, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->DiskCachePath(context, request, response); })); @@ -6860,7 +7120,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_SetDiskCachePath() { - ::grpc::Service::MarkMethodRawCallback(36, + ::grpc::Service::MarkMethodRawCallback(38, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->SetDiskCachePath(context, request, response); })); @@ -6882,7 +7142,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_SetIsDoHEnabled() { - ::grpc::Service::MarkMethodRawCallback(37, + ::grpc::Service::MarkMethodRawCallback(39, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->SetIsDoHEnabled(context, request, response); })); @@ -6904,7 +7164,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_IsDoHEnabled() { - ::grpc::Service::MarkMethodRawCallback(38, + ::grpc::Service::MarkMethodRawCallback(40, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->IsDoHEnabled(context, request, response); })); @@ -6926,7 +7186,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_MailServerSettings() { - ::grpc::Service::MarkMethodRawCallback(39, + ::grpc::Service::MarkMethodRawCallback(41, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->MailServerSettings(context, request, response); })); @@ -6948,7 +7208,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_SetMailServerSettings() { - ::grpc::Service::MarkMethodRawCallback(40, + ::grpc::Service::MarkMethodRawCallback(42, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->SetMailServerSettings(context, request, response); })); @@ -6970,7 +7230,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_Hostname() { - ::grpc::Service::MarkMethodRawCallback(41, + ::grpc::Service::MarkMethodRawCallback(43, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->Hostname(context, request, response); })); @@ -6992,7 +7252,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_IsPortFree() { - ::grpc::Service::MarkMethodRawCallback(42, + ::grpc::Service::MarkMethodRawCallback(44, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->IsPortFree(context, request, response); })); @@ -7014,7 +7274,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_AvailableKeychains() { - ::grpc::Service::MarkMethodRawCallback(43, + ::grpc::Service::MarkMethodRawCallback(45, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->AvailableKeychains(context, request, response); })); @@ -7036,7 +7296,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_SetCurrentKeychain() { - ::grpc::Service::MarkMethodRawCallback(44, + ::grpc::Service::MarkMethodRawCallback(46, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->SetCurrentKeychain(context, request, response); })); @@ -7058,7 +7318,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_CurrentKeychain() { - ::grpc::Service::MarkMethodRawCallback(45, + ::grpc::Service::MarkMethodRawCallback(47, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->CurrentKeychain(context, request, response); })); @@ -7080,7 +7340,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_GetUserList() { - ::grpc::Service::MarkMethodRawCallback(46, + ::grpc::Service::MarkMethodRawCallback(48, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->GetUserList(context, request, response); })); @@ -7102,7 +7362,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_GetUser() { - ::grpc::Service::MarkMethodRawCallback(47, + ::grpc::Service::MarkMethodRawCallback(49, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->GetUser(context, request, response); })); @@ -7124,7 +7384,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_SetUserSplitMode() { - ::grpc::Service::MarkMethodRawCallback(48, + ::grpc::Service::MarkMethodRawCallback(50, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->SetUserSplitMode(context, request, response); })); @@ -7146,7 +7406,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_SendBadEventUserFeedback() { - ::grpc::Service::MarkMethodRawCallback(49, + ::grpc::Service::MarkMethodRawCallback(51, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->SendBadEventUserFeedback(context, request, response); })); @@ -7168,7 +7428,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_LogoutUser() { - ::grpc::Service::MarkMethodRawCallback(50, + ::grpc::Service::MarkMethodRawCallback(52, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->LogoutUser(context, request, response); })); @@ -7190,7 +7450,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_RemoveUser() { - ::grpc::Service::MarkMethodRawCallback(51, + ::grpc::Service::MarkMethodRawCallback(53, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->RemoveUser(context, request, response); })); @@ -7212,7 +7472,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_ConfigureUserAppleMail() { - ::grpc::Service::MarkMethodRawCallback(52, + ::grpc::Service::MarkMethodRawCallback(54, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->ConfigureUserAppleMail(context, request, response); })); @@ -7234,7 +7494,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_RunEventStream() { - ::grpc::Service::MarkMethodRawCallback(53, + ::grpc::Service::MarkMethodRawCallback(55, new ::grpc::internal::CallbackServerStreamingHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const::grpc::ByteBuffer* request) { return this->RunEventStream(context, request); })); @@ -7256,7 +7516,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithRawCallbackMethod_StopEventStream() { - ::grpc::Service::MarkMethodRawCallback(54, + ::grpc::Service::MarkMethodRawCallback(56, new ::grpc::internal::CallbackUnaryHandler< ::grpc::ByteBuffer, ::grpc::ByteBuffer>( [this]( ::grpc::CallbackServerContext* context, const ::grpc::ByteBuffer* request, ::grpc::ByteBuffer* response) { return this->StopEventStream(context, request, response); })); @@ -7597,12 +7857,66 @@ class Bridge final { virtual ::grpc::Status StreamedIsAllMailVisible(::grpc::ServerContext* context, ::grpc::ServerUnaryStreamer< ::google::protobuf::Empty,::google::protobuf::BoolValue>* server_unary_streamer) = 0; }; template + class WithStreamedUnaryMethod_SetIsTelemetryDisabled : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} + public: + WithStreamedUnaryMethod_SetIsTelemetryDisabled() { + ::grpc::Service::MarkMethodStreamed(12, + new ::grpc::internal::StreamedUnaryHandler< + ::google::protobuf::BoolValue, ::google::protobuf::Empty>( + [this](::grpc::ServerContext* context, + ::grpc::ServerUnaryStreamer< + ::google::protobuf::BoolValue, ::google::protobuf::Empty>* streamer) { + return this->StreamedSetIsTelemetryDisabled(context, + streamer); + })); + } + ~WithStreamedUnaryMethod_SetIsTelemetryDisabled() override { + BaseClassMustBeDerivedFromService(this); + } + // disable regular version of this method + ::grpc::Status SetIsTelemetryDisabled(::grpc::ServerContext* /*context*/, const ::google::protobuf::BoolValue* /*request*/, ::google::protobuf::Empty* /*response*/) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + // replace default version of method with streamed unary + virtual ::grpc::Status StreamedSetIsTelemetryDisabled(::grpc::ServerContext* context, ::grpc::ServerUnaryStreamer< ::google::protobuf::BoolValue,::google::protobuf::Empty>* server_unary_streamer) = 0; + }; + template + class WithStreamedUnaryMethod_IsTelemetryDisabled : public BaseClass { + private: + void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} + public: + WithStreamedUnaryMethod_IsTelemetryDisabled() { + ::grpc::Service::MarkMethodStreamed(13, + new ::grpc::internal::StreamedUnaryHandler< + ::google::protobuf::Empty, ::google::protobuf::BoolValue>( + [this](::grpc::ServerContext* context, + ::grpc::ServerUnaryStreamer< + ::google::protobuf::Empty, ::google::protobuf::BoolValue>* streamer) { + return this->StreamedIsTelemetryDisabled(context, + streamer); + })); + } + ~WithStreamedUnaryMethod_IsTelemetryDisabled() override { + BaseClassMustBeDerivedFromService(this); + } + // disable regular version of this method + ::grpc::Status IsTelemetryDisabled(::grpc::ServerContext* /*context*/, const ::google::protobuf::Empty* /*request*/, ::google::protobuf::BoolValue* /*response*/) override { + abort(); + return ::grpc::Status(::grpc::StatusCode::UNIMPLEMENTED, ""); + } + // replace default version of method with streamed unary + virtual ::grpc::Status StreamedIsTelemetryDisabled(::grpc::ServerContext* context, ::grpc::ServerUnaryStreamer< ::google::protobuf::Empty,::google::protobuf::BoolValue>* server_unary_streamer) = 0; + }; + template class WithStreamedUnaryMethod_GoOs : public BaseClass { private: void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_GoOs() { - ::grpc::Service::MarkMethodStreamed(12, + ::grpc::Service::MarkMethodStreamed(14, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this](::grpc::ServerContext* context, @@ -7629,7 +7943,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_TriggerReset() { - ::grpc::Service::MarkMethodStreamed(13, + ::grpc::Service::MarkMethodStreamed(15, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::Empty>( [this](::grpc::ServerContext* context, @@ -7656,7 +7970,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_Version() { - ::grpc::Service::MarkMethodStreamed(14, + ::grpc::Service::MarkMethodStreamed(16, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this](::grpc::ServerContext* context, @@ -7683,7 +7997,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_LogsPath() { - ::grpc::Service::MarkMethodStreamed(15, + ::grpc::Service::MarkMethodStreamed(17, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this](::grpc::ServerContext* context, @@ -7710,7 +8024,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_LicensePath() { - ::grpc::Service::MarkMethodStreamed(16, + ::grpc::Service::MarkMethodStreamed(18, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this](::grpc::ServerContext* context, @@ -7737,7 +8051,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_ReleaseNotesPageLink() { - ::grpc::Service::MarkMethodStreamed(17, + ::grpc::Service::MarkMethodStreamed(19, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this](::grpc::ServerContext* context, @@ -7764,7 +8078,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_DependencyLicensesLink() { - ::grpc::Service::MarkMethodStreamed(18, + ::grpc::Service::MarkMethodStreamed(20, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this](::grpc::ServerContext* context, @@ -7791,7 +8105,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_LandingPageLink() { - ::grpc::Service::MarkMethodStreamed(19, + ::grpc::Service::MarkMethodStreamed(21, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this](::grpc::ServerContext* context, @@ -7818,7 +8132,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_SetColorSchemeName() { - ::grpc::Service::MarkMethodStreamed(20, + ::grpc::Service::MarkMethodStreamed(22, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>( [this](::grpc::ServerContext* context, @@ -7845,7 +8159,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_ColorSchemeName() { - ::grpc::Service::MarkMethodStreamed(21, + ::grpc::Service::MarkMethodStreamed(23, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this](::grpc::ServerContext* context, @@ -7872,7 +8186,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_CurrentEmailClient() { - ::grpc::Service::MarkMethodStreamed(22, + ::grpc::Service::MarkMethodStreamed(24, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this](::grpc::ServerContext* context, @@ -7899,7 +8213,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_ReportBug() { - ::grpc::Service::MarkMethodStreamed(23, + ::grpc::Service::MarkMethodStreamed(25, new ::grpc::internal::StreamedUnaryHandler< ::grpc::ReportBugRequest, ::google::protobuf::Empty>( [this](::grpc::ServerContext* context, @@ -7926,7 +8240,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_ExportTLSCertificates() { - ::grpc::Service::MarkMethodStreamed(24, + ::grpc::Service::MarkMethodStreamed(26, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>( [this](::grpc::ServerContext* context, @@ -7953,7 +8267,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_ForceLauncher() { - ::grpc::Service::MarkMethodStreamed(25, + ::grpc::Service::MarkMethodStreamed(27, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>( [this](::grpc::ServerContext* context, @@ -7980,7 +8294,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_SetMainExecutable() { - ::grpc::Service::MarkMethodStreamed(26, + ::grpc::Service::MarkMethodStreamed(28, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>( [this](::grpc::ServerContext* context, @@ -8007,7 +8321,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_Login() { - ::grpc::Service::MarkMethodStreamed(27, + ::grpc::Service::MarkMethodStreamed(29, new ::grpc::internal::StreamedUnaryHandler< ::grpc::LoginRequest, ::google::protobuf::Empty>( [this](::grpc::ServerContext* context, @@ -8034,7 +8348,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_Login2FA() { - ::grpc::Service::MarkMethodStreamed(28, + ::grpc::Service::MarkMethodStreamed(30, new ::grpc::internal::StreamedUnaryHandler< ::grpc::LoginRequest, ::google::protobuf::Empty>( [this](::grpc::ServerContext* context, @@ -8061,7 +8375,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_Login2Passwords() { - ::grpc::Service::MarkMethodStreamed(29, + ::grpc::Service::MarkMethodStreamed(31, new ::grpc::internal::StreamedUnaryHandler< ::grpc::LoginRequest, ::google::protobuf::Empty>( [this](::grpc::ServerContext* context, @@ -8088,7 +8402,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_LoginAbort() { - ::grpc::Service::MarkMethodStreamed(30, + ::grpc::Service::MarkMethodStreamed(32, new ::grpc::internal::StreamedUnaryHandler< ::grpc::LoginAbortRequest, ::google::protobuf::Empty>( [this](::grpc::ServerContext* context, @@ -8115,7 +8429,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_CheckUpdate() { - ::grpc::Service::MarkMethodStreamed(31, + ::grpc::Service::MarkMethodStreamed(33, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::Empty>( [this](::grpc::ServerContext* context, @@ -8142,7 +8456,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_InstallUpdate() { - ::grpc::Service::MarkMethodStreamed(32, + ::grpc::Service::MarkMethodStreamed(34, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::Empty>( [this](::grpc::ServerContext* context, @@ -8169,7 +8483,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_SetIsAutomaticUpdateOn() { - ::grpc::Service::MarkMethodStreamed(33, + ::grpc::Service::MarkMethodStreamed(35, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::BoolValue, ::google::protobuf::Empty>( [this](::grpc::ServerContext* context, @@ -8196,7 +8510,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_IsAutomaticUpdateOn() { - ::grpc::Service::MarkMethodStreamed(34, + ::grpc::Service::MarkMethodStreamed(36, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::BoolValue>( [this](::grpc::ServerContext* context, @@ -8223,7 +8537,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_DiskCachePath() { - ::grpc::Service::MarkMethodStreamed(35, + ::grpc::Service::MarkMethodStreamed(37, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this](::grpc::ServerContext* context, @@ -8250,7 +8564,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_SetDiskCachePath() { - ::grpc::Service::MarkMethodStreamed(36, + ::grpc::Service::MarkMethodStreamed(38, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>( [this](::grpc::ServerContext* context, @@ -8277,7 +8591,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_SetIsDoHEnabled() { - ::grpc::Service::MarkMethodStreamed(37, + ::grpc::Service::MarkMethodStreamed(39, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::BoolValue, ::google::protobuf::Empty>( [this](::grpc::ServerContext* context, @@ -8304,7 +8618,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_IsDoHEnabled() { - ::grpc::Service::MarkMethodStreamed(38, + ::grpc::Service::MarkMethodStreamed(40, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::BoolValue>( [this](::grpc::ServerContext* context, @@ -8331,7 +8645,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_MailServerSettings() { - ::grpc::Service::MarkMethodStreamed(39, + ::grpc::Service::MarkMethodStreamed(41, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::Empty, ::grpc::ImapSmtpSettings>( [this](::grpc::ServerContext* context, @@ -8358,7 +8672,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_SetMailServerSettings() { - ::grpc::Service::MarkMethodStreamed(40, + ::grpc::Service::MarkMethodStreamed(42, new ::grpc::internal::StreamedUnaryHandler< ::grpc::ImapSmtpSettings, ::google::protobuf::Empty>( [this](::grpc::ServerContext* context, @@ -8385,7 +8699,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_Hostname() { - ::grpc::Service::MarkMethodStreamed(41, + ::grpc::Service::MarkMethodStreamed(43, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this](::grpc::ServerContext* context, @@ -8412,7 +8726,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_IsPortFree() { - ::grpc::Service::MarkMethodStreamed(42, + ::grpc::Service::MarkMethodStreamed(44, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::Int32Value, ::google::protobuf::BoolValue>( [this](::grpc::ServerContext* context, @@ -8439,7 +8753,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_AvailableKeychains() { - ::grpc::Service::MarkMethodStreamed(43, + ::grpc::Service::MarkMethodStreamed(45, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::Empty, ::grpc::AvailableKeychainsResponse>( [this](::grpc::ServerContext* context, @@ -8466,7 +8780,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_SetCurrentKeychain() { - ::grpc::Service::MarkMethodStreamed(44, + ::grpc::Service::MarkMethodStreamed(46, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>( [this](::grpc::ServerContext* context, @@ -8493,7 +8807,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_CurrentKeychain() { - ::grpc::Service::MarkMethodStreamed(45, + ::grpc::Service::MarkMethodStreamed(47, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::StringValue>( [this](::grpc::ServerContext* context, @@ -8520,7 +8834,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_GetUserList() { - ::grpc::Service::MarkMethodStreamed(46, + ::grpc::Service::MarkMethodStreamed(48, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::Empty, ::grpc::UserListResponse>( [this](::grpc::ServerContext* context, @@ -8547,7 +8861,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_GetUser() { - ::grpc::Service::MarkMethodStreamed(47, + ::grpc::Service::MarkMethodStreamed(49, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::StringValue, ::grpc::User>( [this](::grpc::ServerContext* context, @@ -8574,7 +8888,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_SetUserSplitMode() { - ::grpc::Service::MarkMethodStreamed(48, + ::grpc::Service::MarkMethodStreamed(50, new ::grpc::internal::StreamedUnaryHandler< ::grpc::UserSplitModeRequest, ::google::protobuf::Empty>( [this](::grpc::ServerContext* context, @@ -8601,7 +8915,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_SendBadEventUserFeedback() { - ::grpc::Service::MarkMethodStreamed(49, + ::grpc::Service::MarkMethodStreamed(51, new ::grpc::internal::StreamedUnaryHandler< ::grpc::UserBadEventFeedbackRequest, ::google::protobuf::Empty>( [this](::grpc::ServerContext* context, @@ -8628,7 +8942,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_LogoutUser() { - ::grpc::Service::MarkMethodStreamed(50, + ::grpc::Service::MarkMethodStreamed(52, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>( [this](::grpc::ServerContext* context, @@ -8655,7 +8969,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_RemoveUser() { - ::grpc::Service::MarkMethodStreamed(51, + ::grpc::Service::MarkMethodStreamed(53, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::StringValue, ::google::protobuf::Empty>( [this](::grpc::ServerContext* context, @@ -8682,7 +8996,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_ConfigureUserAppleMail() { - ::grpc::Service::MarkMethodStreamed(52, + ::grpc::Service::MarkMethodStreamed(54, new ::grpc::internal::StreamedUnaryHandler< ::grpc::ConfigureAppleMailRequest, ::google::protobuf::Empty>( [this](::grpc::ServerContext* context, @@ -8709,7 +9023,7 @@ class Bridge final { void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithStreamedUnaryMethod_StopEventStream() { - ::grpc::Service::MarkMethodStreamed(54, + ::grpc::Service::MarkMethodStreamed(56, new ::grpc::internal::StreamedUnaryHandler< ::google::protobuf::Empty, ::google::protobuf::Empty>( [this](::grpc::ServerContext* context, @@ -8730,14 +9044,14 @@ class Bridge final { // replace default version of method with streamed unary virtual ::grpc::Status StreamedStopEventStream(::grpc::ServerContext* context, ::grpc::ServerUnaryStreamer< ::google::protobuf::Empty,::google::protobuf::Empty>* server_unary_streamer) = 0; }; - typedef WithStreamedUnaryMethod_CheckTokens > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > StreamedUnaryService; + typedef WithStreamedUnaryMethod_CheckTokens > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > StreamedUnaryService; template class WithSplitStreamingMethod_RunEventStream : public BaseClass { private: void BaseClassMustBeDerivedFromService(const Service* /*service*/) {} public: WithSplitStreamingMethod_RunEventStream() { - ::grpc::Service::MarkMethodStreamed(53, + ::grpc::Service::MarkMethodStreamed(55, new ::grpc::internal::SplitServerStreamingHandler< ::grpc::EventStreamRequest, ::grpc::StreamEvent>( [this](::grpc::ServerContext* context, @@ -8759,7 +9073,7 @@ class Bridge final { virtual ::grpc::Status StreamedRunEventStream(::grpc::ServerContext* context, ::grpc::ServerSplitStreamer< ::grpc::EventStreamRequest,::grpc::StreamEvent>* server_split_streamer) = 0; }; typedef WithSplitStreamingMethod_RunEventStream SplitStreamedService; - typedef WithStreamedUnaryMethod_CheckTokens > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > StreamedService; + typedef WithStreamedUnaryMethod_CheckTokens > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > StreamedService; }; } // namespace grpc diff --git a/internal/frontend/bridge-gui/bridgepp/bridgepp/GRPC/bridge.pb.cc b/internal/frontend/bridge-gui/bridgepp/bridgepp/GRPC/bridge.pb.cc index eabd0aae..9d8a5043 100644 --- a/internal/frontend/bridge-gui/bridgepp/bridgepp/GRPC/bridge.pb.cc +++ b/internal/frontend/bridge-gui/bridgepp/bridgepp/GRPC/bridge.pb.cc @@ -1673,7 +1673,7 @@ const char descriptor_table_protodef_bridge_2eproto[] PROTOBUF_SECTION_VARIABLE( "!SMTP_CONNECTION_MODE_CHANGE_ERROR\020\005*S\n\t" "ErrorCode\022\021\n\rUNKNOWN_ERROR\020\000\022\031\n\025TLS_CERT" "_EXPORT_ERROR\020\001\022\030\n\024TLS_KEY_EXPORT_ERROR\020" - "\0022\360\035\n\006Bridge\022I\n\013CheckTokens\022\034.google.pro" + "\0022\211\037\n\006Bridge\022I\n\013CheckTokens\022\034.google.pro" "tobuf.StringValue\032\034.google.protobuf.Stri" "ngValue\022\?\n\013AddLogEntry\022\030.grpc.AddLogEntr" "yRequest\032\026.google.protobuf.Empty\022:\n\010GuiR" @@ -1693,84 +1693,88 @@ const char descriptor_table_protodef_bridge_2eproto[] PROTOBUF_SECTION_VARIABLE( "\n\023SetIsAllMailVisible\022\032.google.protobuf." "BoolValue\032\026.google.protobuf.Empty\022F\n\020IsA" "llMailVisible\022\026.google.protobuf.Empty\032\032." - "google.protobuf.BoolValue\022<\n\004GoOs\022\026.goog" - "le.protobuf.Empty\032\034.google.protobuf.Stri" - "ngValue\022>\n\014TriggerReset\022\026.google.protobu" - "f.Empty\032\026.google.protobuf.Empty\022\?\n\007Versi" - "on\022\026.google.protobuf.Empty\032\034.google.prot" - "obuf.StringValue\022@\n\010LogsPath\022\026.google.pr" - "otobuf.Empty\032\034.google.protobuf.StringVal" - "ue\022C\n\013LicensePath\022\026.google.protobuf.Empt" - "y\032\034.google.protobuf.StringValue\022L\n\024Relea" - "seNotesPageLink\022\026.google.protobuf.Empty\032" - "\034.google.protobuf.StringValue\022N\n\026Depende" - "ncyLicensesLink\022\026.google.protobuf.Empty\032" - "\034.google.protobuf.StringValue\022G\n\017Landing" - "PageLink\022\026.google.protobuf.Empty\032\034.googl" - "e.protobuf.StringValue\022J\n\022SetColorScheme" - "Name\022\034.google.protobuf.StringValue\032\026.goo" - "gle.protobuf.Empty\022G\n\017ColorSchemeName\022\026." - "google.protobuf.Empty\032\034.google.protobuf." - "StringValue\022J\n\022CurrentEmailClient\022\026.goog" - "le.protobuf.Empty\032\034.google.protobuf.Stri" - "ngValue\022;\n\tReportBug\022\026.grpc.ReportBugReq" - "uest\032\026.google.protobuf.Empty\022M\n\025ExportTL" - "SCertificates\022\034.google.protobuf.StringVa" - "lue\032\026.google.protobuf.Empty\022E\n\rForceLaun" - "cher\022\034.google.protobuf.StringValue\032\026.goo" - "gle.protobuf.Empty\022I\n\021SetMainExecutable\022" - "\034.google.protobuf.StringValue\032\026.google.p" - "rotobuf.Empty\0223\n\005Login\022\022.grpc.LoginReque" - "st\032\026.google.protobuf.Empty\0226\n\010Login2FA\022\022" - ".grpc.LoginRequest\032\026.google.protobuf.Emp" - "ty\022=\n\017Login2Passwords\022\022.grpc.LoginReques" - "t\032\026.google.protobuf.Empty\022=\n\nLoginAbort\022" - "\027.grpc.LoginAbortRequest\032\026.google.protob" - "uf.Empty\022=\n\013CheckUpdate\022\026.google.protobu" - "f.Empty\032\026.google.protobuf.Empty\022\?\n\rInsta" - "llUpdate\022\026.google.protobuf.Empty\032\026.googl" - "e.protobuf.Empty\022L\n\026SetIsAutomaticUpdate" - "On\022\032.google.protobuf.BoolValue\032\026.google." - "protobuf.Empty\022I\n\023IsAutomaticUpdateOn\022\026." - "google.protobuf.Empty\032\032.google.protobuf." - "BoolValue\022E\n\rDiskCachePath\022\026.google.prot" + "google.protobuf.BoolValue\022L\n\026SetIsTeleme" + "tryDisabled\022\032.google.protobuf.BoolValue\032" + "\026.google.protobuf.Empty\022I\n\023IsTelemetryDi" + "sabled\022\026.google.protobuf.Empty\032\032.google." + "protobuf.BoolValue\022<\n\004GoOs\022\026.google.prot" "obuf.Empty\032\034.google.protobuf.StringValue" - "\022H\n\020SetDiskCachePath\022\034.google.protobuf.S" - "tringValue\032\026.google.protobuf.Empty\022E\n\017Se" - "tIsDoHEnabled\022\032.google.protobuf.BoolValu" - "e\032\026.google.protobuf.Empty\022B\n\014IsDoHEnable" - "d\022\026.google.protobuf.Empty\032\032.google.proto" - "buf.BoolValue\022D\n\022MailServerSettings\022\026.go" - "ogle.protobuf.Empty\032\026.grpc.ImapSmtpSetti" - "ngs\022G\n\025SetMailServerSettings\022\026.grpc.Imap" - "SmtpSettings\032\026.google.protobuf.Empty\022@\n\010" - "Hostname\022\026.google.protobuf.Empty\032\034.googl" - "e.protobuf.StringValue\022E\n\nIsPortFree\022\033.g" - "oogle.protobuf.Int32Value\032\032.google.proto" - "buf.BoolValue\022N\n\022AvailableKeychains\022\026.go" - "ogle.protobuf.Empty\032 .grpc.AvailableKeyc" - "hainsResponse\022J\n\022SetCurrentKeychain\022\034.go" - "ogle.protobuf.StringValue\032\026.google.proto" - "buf.Empty\022G\n\017CurrentKeychain\022\026.google.pr" - "otobuf.Empty\032\034.google.protobuf.StringVal" - "ue\022=\n\013GetUserList\022\026.google.protobuf.Empt" - "y\032\026.grpc.UserListResponse\0223\n\007GetUser\022\034.g" - "oogle.protobuf.StringValue\032\n.grpc.User\022F" - "\n\020SetUserSplitMode\022\032.grpc.UserSplitModeR" - "equest\032\026.google.protobuf.Empty\022U\n\030SendBa" - "dEventUserFeedback\022!.grpc.UserBadEventFe" - "edbackRequest\032\026.google.protobuf.Empty\022B\n" - "\nLogoutUser\022\034.google.protobuf.StringValu" - "e\032\026.google.protobuf.Empty\022B\n\nRemoveUser\022" - "\034.google.protobuf.StringValue\032\026.google.p" - "rotobuf.Empty\022Q\n\026ConfigureUserAppleMail\022" - "\037.grpc.ConfigureAppleMailRequest\032\026.googl" - "e.protobuf.Empty\022\?\n\016RunEventStream\022\030.grp" - "c.EventStreamRequest\032\021.grpc.StreamEvent0" - "\001\022A\n\017StopEventStream\022\026.google.protobuf.E" - "mpty\032\026.google.protobuf.EmptyB6Z4github.c" - "om/ProtonMail/proton-bridge/v3/internal/" - "grpcb\006proto3" + "\022>\n\014TriggerReset\022\026.google.protobuf.Empty" + "\032\026.google.protobuf.Empty\022\?\n\007Version\022\026.go" + "ogle.protobuf.Empty\032\034.google.protobuf.St" + "ringValue\022@\n\010LogsPath\022\026.google.protobuf." + "Empty\032\034.google.protobuf.StringValue\022C\n\013L" + "icensePath\022\026.google.protobuf.Empty\032\034.goo" + "gle.protobuf.StringValue\022L\n\024ReleaseNotes" + "PageLink\022\026.google.protobuf.Empty\032\034.googl" + "e.protobuf.StringValue\022N\n\026DependencyLice" + "nsesLink\022\026.google.protobuf.Empty\032\034.googl" + "e.protobuf.StringValue\022G\n\017LandingPageLin" + "k\022\026.google.protobuf.Empty\032\034.google.proto" + "buf.StringValue\022J\n\022SetColorSchemeName\022\034." + "google.protobuf.StringValue\032\026.google.pro" + "tobuf.Empty\022G\n\017ColorSchemeName\022\026.google." + "protobuf.Empty\032\034.google.protobuf.StringV" + "alue\022J\n\022CurrentEmailClient\022\026.google.prot" + "obuf.Empty\032\034.google.protobuf.StringValue" + "\022;\n\tReportBug\022\026.grpc.ReportBugRequest\032\026." + "google.protobuf.Empty\022M\n\025ExportTLSCertif" + "icates\022\034.google.protobuf.StringValue\032\026.g" + "oogle.protobuf.Empty\022E\n\rForceLauncher\022\034." + "google.protobuf.StringValue\032\026.google.pro" + "tobuf.Empty\022I\n\021SetMainExecutable\022\034.googl" + "e.protobuf.StringValue\032\026.google.protobuf" + ".Empty\0223\n\005Login\022\022.grpc.LoginRequest\032\026.go" + "ogle.protobuf.Empty\0226\n\010Login2FA\022\022.grpc.L" + "oginRequest\032\026.google.protobuf.Empty\022=\n\017L" + "ogin2Passwords\022\022.grpc.LoginRequest\032\026.goo" + "gle.protobuf.Empty\022=\n\nLoginAbort\022\027.grpc." + "LoginAbortRequest\032\026.google.protobuf.Empt" + "y\022=\n\013CheckUpdate\022\026.google.protobuf.Empty" + "\032\026.google.protobuf.Empty\022\?\n\rInstallUpdat" + "e\022\026.google.protobuf.Empty\032\026.google.proto" + "buf.Empty\022L\n\026SetIsAutomaticUpdateOn\022\032.go" + "ogle.protobuf.BoolValue\032\026.google.protobu" + "f.Empty\022I\n\023IsAutomaticUpdateOn\022\026.google." + "protobuf.Empty\032\032.google.protobuf.BoolVal" + "ue\022E\n\rDiskCachePath\022\026.google.protobuf.Em" + "pty\032\034.google.protobuf.StringValue\022H\n\020Set" + "DiskCachePath\022\034.google.protobuf.StringVa" + "lue\032\026.google.protobuf.Empty\022E\n\017SetIsDoHE" + "nabled\022\032.google.protobuf.BoolValue\032\026.goo" + "gle.protobuf.Empty\022B\n\014IsDoHEnabled\022\026.goo" + "gle.protobuf.Empty\032\032.google.protobuf.Boo" + "lValue\022D\n\022MailServerSettings\022\026.google.pr" + "otobuf.Empty\032\026.grpc.ImapSmtpSettings\022G\n\025" + "SetMailServerSettings\022\026.grpc.ImapSmtpSet" + "tings\032\026.google.protobuf.Empty\022@\n\010Hostnam" + "e\022\026.google.protobuf.Empty\032\034.google.proto" + "buf.StringValue\022E\n\nIsPortFree\022\033.google.p" + "rotobuf.Int32Value\032\032.google.protobuf.Boo" + "lValue\022N\n\022AvailableKeychains\022\026.google.pr" + "otobuf.Empty\032 .grpc.AvailableKeychainsRe" + "sponse\022J\n\022SetCurrentKeychain\022\034.google.pr" + "otobuf.StringValue\032\026.google.protobuf.Emp" + "ty\022G\n\017CurrentKeychain\022\026.google.protobuf." + "Empty\032\034.google.protobuf.StringValue\022=\n\013G" + "etUserList\022\026.google.protobuf.Empty\032\026.grp" + "c.UserListResponse\0223\n\007GetUser\022\034.google.p" + "rotobuf.StringValue\032\n.grpc.User\022F\n\020SetUs" + "erSplitMode\022\032.grpc.UserSplitModeRequest\032" + "\026.google.protobuf.Empty\022U\n\030SendBadEventU" + "serFeedback\022!.grpc.UserBadEventFeedbackR" + "equest\032\026.google.protobuf.Empty\022B\n\nLogout" + "User\022\034.google.protobuf.StringValue\032\026.goo" + "gle.protobuf.Empty\022B\n\nRemoveUser\022\034.googl" + "e.protobuf.StringValue\032\026.google.protobuf" + ".Empty\022Q\n\026ConfigureUserAppleMail\022\037.grpc." + "ConfigureAppleMailRequest\032\026.google.proto" + "buf.Empty\022\?\n\016RunEventStream\022\030.grpc.Event" + "StreamRequest\032\021.grpc.StreamEvent0\001\022A\n\017St" + "opEventStream\022\026.google.protobuf.Empty\032\026." + "google.protobuf.EmptyB6Z4github.com/Prot" + "onMail/proton-bridge/v3/internal/grpcb\006p" + "roto3" ; static const ::_pbi::DescriptorTable* const descriptor_table_bridge_2eproto_deps[2] = { &::descriptor_table_google_2fprotobuf_2fempty_2eproto, @@ -1778,7 +1782,7 @@ static const ::_pbi::DescriptorTable* const descriptor_table_bridge_2eproto_deps }; static ::_pbi::once_flag descriptor_table_bridge_2eproto_once; const ::_pbi::DescriptorTable descriptor_table_bridge_2eproto = { - false, false, 10532, descriptor_table_protodef_bridge_2eproto, + false, false, 10685, descriptor_table_protodef_bridge_2eproto, "bridge.proto", &descriptor_table_bridge_2eproto_once, descriptor_table_bridge_2eproto_deps, 2, 64, schemas, file_default_instances, TableStruct_bridge_2eproto::offsets, diff --git a/internal/frontend/cli/frontend.go b/internal/frontend/cli/frontend.go index bd08cc00..4422e427 100644 --- a/internal/frontend/cli/frontend.go +++ b/internal/frontend/cli/frontend.go @@ -289,6 +289,23 @@ func New( }) fe.AddCmd(badEventCmd) + // Telemetry commands + telemetryCmd := &ishell.Cmd{ + Name: "telemetry", + Help: "choose whether usage diagnostics are collected or not", + } + telemetryCmd.AddCmd(&ishell.Cmd{ + Name: "enable", + Help: "Usage diagnostics collection will be enabled", + Func: fe.enableTelemetry, + }) + telemetryCmd.AddCmd(&ishell.Cmd{ + Name: "disable", + Help: "Usage diagnostics collection will be disabled", + Func: fe.disableTelemetry, + }) + fe.AddCmd(telemetryCmd) + go fe.watchEvents(eventCh) go func() { diff --git a/internal/frontend/cli/system.go b/internal/frontend/cli/system.go index dc1b12ca..956523f5 100644 --- a/internal/frontend/cli/system.go +++ b/internal/frontend/cli/system.go @@ -195,6 +195,38 @@ func (f *frontendCLI) showAllMail(c *ishell.Context) { } } +func (f *frontendCLI) enableTelemetry(_ *ishell.Context) { + if !f.bridge.GetTelemetryDisabled() { + f.Println("Usage diagnostics collection is enabled.") + return + } + + f.Println("Usage diagnostics collection is disabled right now.") + + if f.yesNoQuestion("Do you want to enable usage diagnostics collection") { + if err := f.bridge.SetTelemetryDisabled(false); err != nil { + f.printAndLogError(err) + return + } + } +} + +func (f *frontendCLI) disableTelemetry(_ *ishell.Context) { + if f.bridge.GetTelemetryDisabled() { + f.Println("Usage diagnostics collection is disabled.") + return + } + + f.Println("Usage diagnostics collection is enabled right now.") + + if f.yesNoQuestion("Do you want to disable usage diagnostics collection") { + if err := f.bridge.SetTelemetryDisabled(true); err != nil { + f.printAndLogError(err) + return + } + } +} + func (f *frontendCLI) setGluonLocation(c *ishell.Context) { if gluonDir := f.bridge.GetGluonCacheDir(); gluonDir != "" { f.Println("The current message cache location is:", gluonDir) diff --git a/internal/frontend/grpc/bridge.pb.go b/internal/frontend/grpc/bridge.pb.go index 5a4680e2..9ccae52b 100644 --- a/internal/frontend/grpc/bridge.pb.go +++ b/internal/frontend/grpc/bridge.pb.go @@ -17,8 +17,8 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.1 -// protoc v3.21.12 +// protoc-gen-go v1.28.0 +// protoc v3.21.3 // source: bridge.proto package grpc @@ -4803,8 +4803,8 @@ var file_bridge_proto_rawDesc = []byte{ 0x4e, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x00, 0x12, 0x19, 0x0a, 0x15, 0x54, 0x4c, 0x53, 0x5f, 0x43, 0x45, 0x52, 0x54, 0x5f, 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x54, 0x4c, 0x53, 0x5f, 0x4b, 0x45, 0x59, 0x5f, - 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x32, 0xf0, - 0x1d, 0x0a, 0x06, 0x42, 0x72, 0x69, 0x64, 0x67, 0x65, 0x12, 0x49, 0x0a, 0x0b, 0x43, 0x68, 0x65, + 0x45, 0x58, 0x50, 0x4f, 0x52, 0x54, 0x5f, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x02, 0x32, 0x89, + 0x1f, 0x0a, 0x06, 0x42, 0x72, 0x69, 0x64, 0x67, 0x65, 0x12, 0x49, 0x0a, 0x0b, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x73, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, @@ -4855,199 +4855,208 @@ var file_bridge_proto_rawDesc = []byte{ 0x6c, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, - 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x3c, 0x0a, 0x04, 0x47, 0x6f, 0x4f, 0x73, 0x12, 0x16, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x12, 0x3e, 0x0a, 0x0c, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x52, - 0x65, 0x73, 0x65, 0x74, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, + 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4c, 0x0a, 0x16, 0x53, 0x65, 0x74, 0x49, 0x73, 0x54, + 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x74, 0x72, 0x79, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, + 0x12, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, - 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3f, 0x0a, 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x6d, 0x70, 0x74, 0x79, 0x12, 0x49, 0x0a, 0x13, 0x49, 0x73, 0x54, 0x65, 0x6c, 0x65, 0x6d, 0x65, + 0x74, 0x72, 0x79, 0x44, 0x69, 0x73, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x16, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x1a, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, + 0x3c, 0x0a, 0x04, 0x47, 0x6f, 0x4f, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, + 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x3e, 0x0a, + 0x0c, 0x54, 0x72, 0x69, 0x67, 0x67, 0x65, 0x72, 0x52, 0x65, 0x73, 0x65, 0x74, 0x12, 0x16, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3f, 0x0a, + 0x07, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x40, + 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x73, 0x50, 0x61, 0x74, 0x68, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x12, 0x43, 0x0a, 0x0b, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x40, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x73, 0x50, 0x61, 0x74, - 0x68, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, - 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x43, 0x0a, 0x0b, 0x4c, 0x69, 0x63, 0x65, 0x6e, - 0x73, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4c, 0x0a, 0x14, - 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x4e, 0x6f, 0x74, 0x65, 0x73, 0x50, 0x61, 0x67, 0x65, - 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, - 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4e, 0x0a, 0x16, 0x44, 0x65, - 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, 0x79, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, - 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, - 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x47, 0x0a, 0x0f, 0x4c, 0x61, - 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x16, 0x2e, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4c, 0x0a, 0x14, 0x52, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, + 0x4e, 0x6f, 0x74, 0x65, 0x73, 0x50, 0x61, 0x67, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x12, 0x4a, 0x0a, 0x12, 0x53, 0x65, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x53, - 0x63, 0x68, 0x65, 0x6d, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, - 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, - 0x47, 0x0a, 0x0f, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x4e, 0x61, - 0x6d, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, - 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4a, 0x0a, 0x12, 0x43, 0x75, 0x72, 0x72, - 0x65, 0x6e, 0x74, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x16, + 0x6c, 0x75, 0x65, 0x12, 0x4e, 0x0a, 0x16, 0x44, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x65, 0x6e, 0x63, + 0x79, 0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x73, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x16, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x12, 0x47, 0x0a, 0x0f, 0x4c, 0x61, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x50, 0x61, + 0x67, 0x65, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x12, 0x3b, 0x0a, 0x09, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x42, 0x75, - 0x67, 0x12, 0x16, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x42, - 0x75, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x12, 0x4d, 0x0a, 0x15, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x54, 0x4c, 0x53, 0x43, 0x65, - 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, + 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4a, 0x0a, 0x12, + 0x53, 0x65, 0x74, 0x43, 0x6f, 0x6c, 0x6f, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x4e, 0x61, + 0x6d, 0x65, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x47, 0x0a, 0x0f, 0x43, 0x6f, 0x6c, 0x6f, + 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x12, 0x4a, 0x0a, 0x12, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x45, 0x6d, 0x61, 0x69, + 0x6c, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, + 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x3b, 0x0a, + 0x09, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x42, 0x75, 0x67, 0x12, 0x16, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x42, 0x75, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x4d, 0x0a, 0x15, 0x45, 0x78, + 0x70, 0x6f, 0x72, 0x74, 0x54, 0x4c, 0x53, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63, 0x61, + 0x74, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x45, 0x0a, 0x0d, 0x46, 0x6f, 0x72, + 0x63, 0x65, 0x4c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x12, 0x45, 0x0a, 0x0d, 0x46, 0x6f, 0x72, 0x63, 0x65, 0x4c, 0x61, 0x75, 0x6e, 0x63, 0x68, 0x65, - 0x72, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, - 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x49, 0x0a, 0x11, 0x53, 0x65, 0x74, 0x4d, 0x61, - 0x69, 0x6e, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x1c, 0x2e, 0x67, - 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, - 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, - 0x74, 0x79, 0x12, 0x33, 0x0a, 0x05, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x12, 0x2e, 0x67, 0x72, + 0x12, 0x49, 0x0a, 0x11, 0x53, 0x65, 0x74, 0x4d, 0x61, 0x69, 0x6e, 0x45, 0x78, 0x65, 0x63, 0x75, + 0x74, 0x61, 0x62, 0x6c, 0x65, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x33, 0x0a, 0x05, 0x4c, + 0x6f, 0x67, 0x69, 0x6e, 0x12, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x67, 0x69, + 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x12, 0x36, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x32, 0x46, 0x41, 0x12, 0x12, 0x2e, 0x67, + 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3d, 0x0a, 0x0f, 0x4c, 0x6f, 0x67, 0x69, + 0x6e, 0x32, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x73, 0x12, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x36, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x69, 0x6e, - 0x32, 0x46, 0x41, 0x12, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, - 0x3d, 0x0a, 0x0f, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x32, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, - 0x64, 0x73, 0x12, 0x12, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3d, - 0x0a, 0x0a, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x41, 0x62, 0x6f, 0x72, 0x74, 0x12, 0x17, 0x2e, 0x67, - 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x67, 0x69, 0x6e, 0x41, 0x62, 0x6f, 0x72, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3d, 0x0a, - 0x0b, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x16, 0x2e, 0x67, + 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3d, 0x0a, 0x0a, 0x4c, 0x6f, 0x67, 0x69, 0x6e, + 0x41, 0x62, 0x6f, 0x72, 0x74, 0x12, 0x17, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x4c, 0x6f, 0x67, + 0x69, 0x6e, 0x41, 0x62, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3d, 0x0a, 0x0b, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x55, + 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3f, 0x0a, 0x0d, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, + 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x4c, 0x0a, 0x16, 0x53, 0x65, 0x74, 0x49, 0x73, 0x41, + 0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4f, 0x6e, + 0x12, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, - 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3f, 0x0a, 0x0d, - 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6c, 0x6c, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x16, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x4c, 0x0a, - 0x16, 0x53, 0x65, 0x74, 0x49, 0x73, 0x41, 0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x4f, 0x6e, 0x12, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x49, 0x0a, 0x13, 0x49, - 0x73, 0x41, 0x75, 0x74, 0x6f, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x4f, 0x6e, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, - 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x45, 0x0a, 0x0d, 0x44, 0x69, 0x73, 0x6b, 0x43, 0x61, - 0x63, 0x68, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, - 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x48, 0x0a, - 0x10, 0x53, 0x65, 0x74, 0x44, 0x69, 0x73, 0x6b, 0x43, 0x61, 0x63, 0x68, 0x65, 0x50, 0x61, 0x74, - 0x68, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, - 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, - 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x45, 0x0a, 0x0f, 0x53, 0x65, 0x74, 0x49, 0x73, - 0x44, 0x6f, 0x48, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, - 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x42, - 0x0a, 0x0c, 0x49, 0x73, 0x44, 0x6f, 0x48, 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x16, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x12, 0x44, 0x0a, 0x12, 0x4d, 0x61, 0x69, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, - 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, - 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, - 0x1a, 0x16, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6d, 0x61, 0x70, 0x53, 0x6d, 0x74, 0x70, - 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x47, 0x0a, 0x15, 0x53, 0x65, 0x74, 0x4d, - 0x61, 0x69, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, - 0x73, 0x12, 0x16, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x49, 0x6d, 0x61, 0x70, 0x53, 0x6d, 0x74, - 0x70, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x12, 0x40, 0x0a, 0x08, 0x48, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x2e, - 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, - 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, - 0x6c, 0x75, 0x65, 0x12, 0x45, 0x0a, 0x0a, 0x49, 0x73, 0x50, 0x6f, 0x72, 0x74, 0x46, 0x72, 0x65, - 0x65, 0x12, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x1a, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x4e, 0x0a, 0x12, 0x41, 0x76, - 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x73, + 0x6d, 0x70, 0x74, 0x79, 0x12, 0x49, 0x0a, 0x13, 0x49, 0x73, 0x41, 0x75, 0x74, 0x6f, 0x6d, 0x61, + 0x74, 0x69, 0x63, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4f, 0x6e, 0x12, 0x16, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x1a, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, + 0x45, 0x0a, 0x0d, 0x44, 0x69, 0x73, 0x6b, 0x43, 0x61, 0x63, 0x68, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x20, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, - 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x63, 0x68, 0x61, 0x69, - 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x12, 0x53, 0x65, - 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x63, 0x68, 0x61, 0x69, 0x6e, - 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x16, + 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, + 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x48, 0x0a, 0x10, 0x53, 0x65, 0x74, 0x44, 0x69, 0x73, + 0x6b, 0x43, 0x61, 0x63, 0x68, 0x65, 0x50, 0x61, 0x74, 0x68, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x12, 0x45, 0x0a, 0x0f, 0x53, 0x65, 0x74, 0x49, 0x73, 0x44, 0x6f, 0x48, 0x45, 0x6e, 0x61, 0x62, + 0x6c, 0x65, 0x64, 0x12, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, + 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x42, 0x0a, 0x0c, 0x49, 0x73, 0x44, 0x6f, 0x48, + 0x45, 0x6e, 0x61, 0x62, 0x6c, 0x65, 0x64, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, + 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, + 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x44, 0x0a, 0x12, 0x4d, + 0x61, 0x69, 0x6c, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x72, 0x70, 0x63, + 0x2e, 0x49, 0x6d, 0x61, 0x70, 0x53, 0x6d, 0x74, 0x70, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, + 0x73, 0x12, 0x47, 0x0a, 0x15, 0x53, 0x65, 0x74, 0x4d, 0x61, 0x69, 0x6c, 0x53, 0x65, 0x72, 0x76, + 0x65, 0x72, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, 0x67, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x72, 0x70, + 0x63, 0x2e, 0x49, 0x6d, 0x61, 0x70, 0x53, 0x6d, 0x74, 0x70, 0x53, 0x65, 0x74, 0x74, 0x69, 0x6e, + 0x67, 0x73, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x40, 0x0a, 0x08, 0x48, 0x6f, + 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x47, 0x0a, 0x0f, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, - 0x74, 0x4b, 0x65, 0x79, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x45, 0x0a, 0x0a, + 0x49, 0x73, 0x50, 0x6f, 0x72, 0x74, 0x46, 0x72, 0x65, 0x65, 0x12, 0x1b, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x49, 0x6e, 0x74, + 0x33, 0x32, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x1a, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x42, 0x6f, 0x6f, 0x6c, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x12, 0x4e, 0x0a, 0x12, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, 0x6c, 0x65, + 0x4b, 0x65, 0x79, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, - 0x3d, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x73, - 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, - 0x0a, 0x07, 0x47, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x79, 0x1a, 0x20, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x41, 0x76, 0x61, 0x69, 0x6c, 0x61, 0x62, + 0x6c, 0x65, 0x4b, 0x65, 0x79, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x12, 0x4a, 0x0a, 0x12, 0x53, 0x65, 0x74, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, + 0x74, 0x4b, 0x65, 0x79, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, - 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x0a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x55, - 0x73, 0x65, 0x72, 0x12, 0x46, 0x0a, 0x10, 0x53, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x70, - 0x6c, 0x69, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x1a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x55, - 0x73, 0x65, 0x72, 0x53, 0x70, 0x6c, 0x69, 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, + 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, + 0x47, 0x0a, 0x0f, 0x43, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x63, 0x68, 0x61, + 0x69, 0x6e, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, + 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x3d, 0x0a, 0x0b, 0x47, 0x65, 0x74, 0x55, + 0x73, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, + 0x16, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x33, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x55, 0x73, + 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x1a, 0x0a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x12, 0x46, 0x0a, 0x10, + 0x53, 0x65, 0x74, 0x55, 0x73, 0x65, 0x72, 0x53, 0x70, 0x6c, 0x69, 0x74, 0x4d, 0x6f, 0x64, 0x65, + 0x12, 0x1a, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x53, 0x70, 0x6c, 0x69, + 0x74, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, + 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, + 0x6d, 0x70, 0x74, 0x79, 0x12, 0x55, 0x0a, 0x18, 0x53, 0x65, 0x6e, 0x64, 0x42, 0x61, 0x64, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x55, 0x73, 0x65, 0x72, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, + 0x12, 0x21, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x42, 0x61, 0x64, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x46, 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x55, 0x0a, 0x18, 0x53, - 0x65, 0x6e, 0x64, 0x42, 0x61, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x55, 0x73, 0x65, 0x72, 0x46, - 0x65, 0x65, 0x64, 0x62, 0x61, 0x63, 0x6b, 0x12, 0x21, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x55, - 0x73, 0x65, 0x72, 0x42, 0x61, 0x64, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x46, 0x65, 0x65, 0x64, 0x62, - 0x61, 0x63, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, - 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, - 0x74, 0x79, 0x12, 0x42, 0x0a, 0x0a, 0x4c, 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x55, 0x73, 0x65, 0x72, - 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, - 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x16, + 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x42, 0x0a, 0x0a, 0x4c, + 0x6f, 0x67, 0x6f, 0x75, 0x74, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, + 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, + 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, + 0x42, 0x0a, 0x0a, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x55, 0x73, 0x65, 0x72, 0x12, 0x1c, 0x2e, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, + 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x12, 0x51, 0x0a, 0x16, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, + 0x55, 0x73, 0x65, 0x72, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x4d, 0x61, 0x69, 0x6c, 0x12, 0x1f, 0x2e, + 0x67, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x41, 0x70, + 0x70, 0x6c, 0x65, 0x4d, 0x61, 0x69, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x42, 0x0a, 0x0a, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, - 0x55, 0x73, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, - 0x75, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x51, 0x0a, 0x16, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x75, 0x72, 0x65, 0x55, 0x73, 0x65, 0x72, 0x41, 0x70, 0x70, 0x6c, 0x65, - 0x4d, 0x61, 0x69, 0x6c, 0x12, 0x1f, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x75, 0x72, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x65, 0x4d, 0x61, 0x69, 0x6c, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3f, 0x0a, - 0x0e, 0x52, 0x75, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, - 0x18, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, - 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x67, 0x72, 0x70, 0x63, - 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, 0x41, - 0x0a, 0x0f, 0x53, 0x74, 0x6f, 0x70, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, - 0x6d, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, - 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x42, 0x36, 0x5a, 0x34, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x4d, 0x61, 0x69, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x6e, 0x2d, 0x62, 0x72, 0x69, 0x64, 0x67, 0x65, 0x2f, 0x76, 0x33, 0x2f, 0x69, 0x6e, 0x74, 0x65, - 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3f, 0x0a, 0x0e, 0x52, 0x75, 0x6e, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x18, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x67, 0x72, 0x70, 0x63, 0x2e, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, + 0x45, 0x76, 0x65, 0x6e, 0x74, 0x30, 0x01, 0x12, 0x41, 0x0a, 0x0f, 0x53, 0x74, 0x6f, 0x70, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x53, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, + 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x36, 0x5a, 0x34, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x4d, + 0x61, 0x69, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x6e, 0x2d, 0x62, 0x72, 0x69, 0x64, 0x67, + 0x65, 0x2f, 0x76, 0x33, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x67, 0x72, + 0x70, 0x63, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -5214,106 +5223,110 @@ var file_bridge_proto_depIdxs = []int32{ 72, // 69: grpc.Bridge.IsBetaEnabled:input_type -> google.protobuf.Empty 73, // 70: grpc.Bridge.SetIsAllMailVisible:input_type -> google.protobuf.BoolValue 72, // 71: grpc.Bridge.IsAllMailVisible:input_type -> google.protobuf.Empty - 72, // 72: grpc.Bridge.GoOs:input_type -> google.protobuf.Empty - 72, // 73: grpc.Bridge.TriggerReset:input_type -> google.protobuf.Empty - 72, // 74: grpc.Bridge.Version:input_type -> google.protobuf.Empty - 72, // 75: grpc.Bridge.LogsPath:input_type -> google.protobuf.Empty - 72, // 76: grpc.Bridge.LicensePath:input_type -> google.protobuf.Empty - 72, // 77: grpc.Bridge.ReleaseNotesPageLink:input_type -> google.protobuf.Empty - 72, // 78: grpc.Bridge.DependencyLicensesLink:input_type -> google.protobuf.Empty - 72, // 79: grpc.Bridge.LandingPageLink:input_type -> google.protobuf.Empty - 71, // 80: grpc.Bridge.SetColorSchemeName:input_type -> google.protobuf.StringValue - 72, // 81: grpc.Bridge.ColorSchemeName:input_type -> google.protobuf.Empty - 72, // 82: grpc.Bridge.CurrentEmailClient:input_type -> google.protobuf.Empty - 9, // 83: grpc.Bridge.ReportBug:input_type -> grpc.ReportBugRequest - 71, // 84: grpc.Bridge.ExportTLSCertificates:input_type -> google.protobuf.StringValue - 71, // 85: grpc.Bridge.ForceLauncher:input_type -> google.protobuf.StringValue - 71, // 86: grpc.Bridge.SetMainExecutable:input_type -> google.protobuf.StringValue - 10, // 87: grpc.Bridge.Login:input_type -> grpc.LoginRequest - 10, // 88: grpc.Bridge.Login2FA:input_type -> grpc.LoginRequest - 10, // 89: grpc.Bridge.Login2Passwords:input_type -> grpc.LoginRequest - 11, // 90: grpc.Bridge.LoginAbort:input_type -> grpc.LoginAbortRequest - 72, // 91: grpc.Bridge.CheckUpdate:input_type -> google.protobuf.Empty - 72, // 92: grpc.Bridge.InstallUpdate:input_type -> google.protobuf.Empty - 73, // 93: grpc.Bridge.SetIsAutomaticUpdateOn:input_type -> google.protobuf.BoolValue - 72, // 94: grpc.Bridge.IsAutomaticUpdateOn:input_type -> google.protobuf.Empty - 72, // 95: grpc.Bridge.DiskCachePath:input_type -> google.protobuf.Empty - 71, // 96: grpc.Bridge.SetDiskCachePath:input_type -> google.protobuf.StringValue - 73, // 97: grpc.Bridge.SetIsDoHEnabled:input_type -> google.protobuf.BoolValue - 72, // 98: grpc.Bridge.IsDoHEnabled:input_type -> google.protobuf.Empty - 72, // 99: grpc.Bridge.MailServerSettings:input_type -> google.protobuf.Empty - 12, // 100: grpc.Bridge.SetMailServerSettings:input_type -> grpc.ImapSmtpSettings - 72, // 101: grpc.Bridge.Hostname:input_type -> google.protobuf.Empty - 74, // 102: grpc.Bridge.IsPortFree:input_type -> google.protobuf.Int32Value - 72, // 103: grpc.Bridge.AvailableKeychains:input_type -> google.protobuf.Empty - 71, // 104: grpc.Bridge.SetCurrentKeychain:input_type -> google.protobuf.StringValue - 72, // 105: grpc.Bridge.CurrentKeychain:input_type -> google.protobuf.Empty - 72, // 106: grpc.Bridge.GetUserList:input_type -> google.protobuf.Empty - 71, // 107: grpc.Bridge.GetUser:input_type -> google.protobuf.StringValue - 15, // 108: grpc.Bridge.SetUserSplitMode:input_type -> grpc.UserSplitModeRequest - 16, // 109: grpc.Bridge.SendBadEventUserFeedback:input_type -> grpc.UserBadEventFeedbackRequest - 71, // 110: grpc.Bridge.LogoutUser:input_type -> google.protobuf.StringValue - 71, // 111: grpc.Bridge.RemoveUser:input_type -> google.protobuf.StringValue - 18, // 112: grpc.Bridge.ConfigureUserAppleMail:input_type -> grpc.ConfigureAppleMailRequest - 19, // 113: grpc.Bridge.RunEventStream:input_type -> grpc.EventStreamRequest - 72, // 114: grpc.Bridge.StopEventStream:input_type -> google.protobuf.Empty - 71, // 115: grpc.Bridge.CheckTokens:output_type -> google.protobuf.StringValue - 72, // 116: grpc.Bridge.AddLogEntry:output_type -> google.protobuf.Empty - 8, // 117: grpc.Bridge.GuiReady:output_type -> grpc.GuiReadyResponse - 72, // 118: grpc.Bridge.Quit:output_type -> google.protobuf.Empty - 72, // 119: grpc.Bridge.Restart:output_type -> google.protobuf.Empty - 73, // 120: grpc.Bridge.ShowOnStartup:output_type -> google.protobuf.BoolValue - 72, // 121: grpc.Bridge.SetIsAutostartOn:output_type -> google.protobuf.Empty - 73, // 122: grpc.Bridge.IsAutostartOn:output_type -> google.protobuf.BoolValue - 72, // 123: grpc.Bridge.SetIsBetaEnabled:output_type -> google.protobuf.Empty - 73, // 124: grpc.Bridge.IsBetaEnabled:output_type -> google.protobuf.BoolValue - 72, // 125: grpc.Bridge.SetIsAllMailVisible:output_type -> google.protobuf.Empty - 73, // 126: grpc.Bridge.IsAllMailVisible:output_type -> google.protobuf.BoolValue - 71, // 127: grpc.Bridge.GoOs:output_type -> google.protobuf.StringValue - 72, // 128: grpc.Bridge.TriggerReset:output_type -> google.protobuf.Empty - 71, // 129: grpc.Bridge.Version:output_type -> google.protobuf.StringValue - 71, // 130: grpc.Bridge.LogsPath:output_type -> google.protobuf.StringValue - 71, // 131: grpc.Bridge.LicensePath:output_type -> google.protobuf.StringValue - 71, // 132: grpc.Bridge.ReleaseNotesPageLink:output_type -> google.protobuf.StringValue - 71, // 133: grpc.Bridge.DependencyLicensesLink:output_type -> google.protobuf.StringValue - 71, // 134: grpc.Bridge.LandingPageLink:output_type -> google.protobuf.StringValue - 72, // 135: grpc.Bridge.SetColorSchemeName:output_type -> google.protobuf.Empty - 71, // 136: grpc.Bridge.ColorSchemeName:output_type -> google.protobuf.StringValue - 71, // 137: grpc.Bridge.CurrentEmailClient:output_type -> google.protobuf.StringValue - 72, // 138: grpc.Bridge.ReportBug:output_type -> google.protobuf.Empty - 72, // 139: grpc.Bridge.ExportTLSCertificates:output_type -> google.protobuf.Empty - 72, // 140: grpc.Bridge.ForceLauncher:output_type -> google.protobuf.Empty - 72, // 141: grpc.Bridge.SetMainExecutable:output_type -> google.protobuf.Empty - 72, // 142: grpc.Bridge.Login:output_type -> google.protobuf.Empty - 72, // 143: grpc.Bridge.Login2FA:output_type -> google.protobuf.Empty - 72, // 144: grpc.Bridge.Login2Passwords:output_type -> google.protobuf.Empty - 72, // 145: grpc.Bridge.LoginAbort:output_type -> google.protobuf.Empty - 72, // 146: grpc.Bridge.CheckUpdate:output_type -> google.protobuf.Empty - 72, // 147: grpc.Bridge.InstallUpdate:output_type -> google.protobuf.Empty - 72, // 148: grpc.Bridge.SetIsAutomaticUpdateOn:output_type -> google.protobuf.Empty - 73, // 149: grpc.Bridge.IsAutomaticUpdateOn:output_type -> google.protobuf.BoolValue - 71, // 150: grpc.Bridge.DiskCachePath:output_type -> google.protobuf.StringValue - 72, // 151: grpc.Bridge.SetDiskCachePath:output_type -> google.protobuf.Empty - 72, // 152: grpc.Bridge.SetIsDoHEnabled:output_type -> google.protobuf.Empty - 73, // 153: grpc.Bridge.IsDoHEnabled:output_type -> google.protobuf.BoolValue - 12, // 154: grpc.Bridge.MailServerSettings:output_type -> grpc.ImapSmtpSettings - 72, // 155: grpc.Bridge.SetMailServerSettings:output_type -> google.protobuf.Empty - 71, // 156: grpc.Bridge.Hostname:output_type -> google.protobuf.StringValue - 73, // 157: grpc.Bridge.IsPortFree:output_type -> google.protobuf.BoolValue - 13, // 158: grpc.Bridge.AvailableKeychains:output_type -> grpc.AvailableKeychainsResponse - 72, // 159: grpc.Bridge.SetCurrentKeychain:output_type -> google.protobuf.Empty - 71, // 160: grpc.Bridge.CurrentKeychain:output_type -> google.protobuf.StringValue - 17, // 161: grpc.Bridge.GetUserList:output_type -> grpc.UserListResponse - 14, // 162: grpc.Bridge.GetUser:output_type -> grpc.User - 72, // 163: grpc.Bridge.SetUserSplitMode:output_type -> google.protobuf.Empty - 72, // 164: grpc.Bridge.SendBadEventUserFeedback:output_type -> google.protobuf.Empty - 72, // 165: grpc.Bridge.LogoutUser:output_type -> google.protobuf.Empty - 72, // 166: grpc.Bridge.RemoveUser:output_type -> google.protobuf.Empty - 72, // 167: grpc.Bridge.ConfigureUserAppleMail:output_type -> google.protobuf.Empty - 20, // 168: grpc.Bridge.RunEventStream:output_type -> grpc.StreamEvent - 72, // 169: grpc.Bridge.StopEventStream:output_type -> google.protobuf.Empty - 115, // [115:170] is the sub-list for method output_type - 60, // [60:115] is the sub-list for method input_type + 73, // 72: grpc.Bridge.SetIsTelemetryDisabled:input_type -> google.protobuf.BoolValue + 72, // 73: grpc.Bridge.IsTelemetryDisabled:input_type -> google.protobuf.Empty + 72, // 74: grpc.Bridge.GoOs:input_type -> google.protobuf.Empty + 72, // 75: grpc.Bridge.TriggerReset:input_type -> google.protobuf.Empty + 72, // 76: grpc.Bridge.Version:input_type -> google.protobuf.Empty + 72, // 77: grpc.Bridge.LogsPath:input_type -> google.protobuf.Empty + 72, // 78: grpc.Bridge.LicensePath:input_type -> google.protobuf.Empty + 72, // 79: grpc.Bridge.ReleaseNotesPageLink:input_type -> google.protobuf.Empty + 72, // 80: grpc.Bridge.DependencyLicensesLink:input_type -> google.protobuf.Empty + 72, // 81: grpc.Bridge.LandingPageLink:input_type -> google.protobuf.Empty + 71, // 82: grpc.Bridge.SetColorSchemeName:input_type -> google.protobuf.StringValue + 72, // 83: grpc.Bridge.ColorSchemeName:input_type -> google.protobuf.Empty + 72, // 84: grpc.Bridge.CurrentEmailClient:input_type -> google.protobuf.Empty + 9, // 85: grpc.Bridge.ReportBug:input_type -> grpc.ReportBugRequest + 71, // 86: grpc.Bridge.ExportTLSCertificates:input_type -> google.protobuf.StringValue + 71, // 87: grpc.Bridge.ForceLauncher:input_type -> google.protobuf.StringValue + 71, // 88: grpc.Bridge.SetMainExecutable:input_type -> google.protobuf.StringValue + 10, // 89: grpc.Bridge.Login:input_type -> grpc.LoginRequest + 10, // 90: grpc.Bridge.Login2FA:input_type -> grpc.LoginRequest + 10, // 91: grpc.Bridge.Login2Passwords:input_type -> grpc.LoginRequest + 11, // 92: grpc.Bridge.LoginAbort:input_type -> grpc.LoginAbortRequest + 72, // 93: grpc.Bridge.CheckUpdate:input_type -> google.protobuf.Empty + 72, // 94: grpc.Bridge.InstallUpdate:input_type -> google.protobuf.Empty + 73, // 95: grpc.Bridge.SetIsAutomaticUpdateOn:input_type -> google.protobuf.BoolValue + 72, // 96: grpc.Bridge.IsAutomaticUpdateOn:input_type -> google.protobuf.Empty + 72, // 97: grpc.Bridge.DiskCachePath:input_type -> google.protobuf.Empty + 71, // 98: grpc.Bridge.SetDiskCachePath:input_type -> google.protobuf.StringValue + 73, // 99: grpc.Bridge.SetIsDoHEnabled:input_type -> google.protobuf.BoolValue + 72, // 100: grpc.Bridge.IsDoHEnabled:input_type -> google.protobuf.Empty + 72, // 101: grpc.Bridge.MailServerSettings:input_type -> google.protobuf.Empty + 12, // 102: grpc.Bridge.SetMailServerSettings:input_type -> grpc.ImapSmtpSettings + 72, // 103: grpc.Bridge.Hostname:input_type -> google.protobuf.Empty + 74, // 104: grpc.Bridge.IsPortFree:input_type -> google.protobuf.Int32Value + 72, // 105: grpc.Bridge.AvailableKeychains:input_type -> google.protobuf.Empty + 71, // 106: grpc.Bridge.SetCurrentKeychain:input_type -> google.protobuf.StringValue + 72, // 107: grpc.Bridge.CurrentKeychain:input_type -> google.protobuf.Empty + 72, // 108: grpc.Bridge.GetUserList:input_type -> google.protobuf.Empty + 71, // 109: grpc.Bridge.GetUser:input_type -> google.protobuf.StringValue + 15, // 110: grpc.Bridge.SetUserSplitMode:input_type -> grpc.UserSplitModeRequest + 16, // 111: grpc.Bridge.SendBadEventUserFeedback:input_type -> grpc.UserBadEventFeedbackRequest + 71, // 112: grpc.Bridge.LogoutUser:input_type -> google.protobuf.StringValue + 71, // 113: grpc.Bridge.RemoveUser:input_type -> google.protobuf.StringValue + 18, // 114: grpc.Bridge.ConfigureUserAppleMail:input_type -> grpc.ConfigureAppleMailRequest + 19, // 115: grpc.Bridge.RunEventStream:input_type -> grpc.EventStreamRequest + 72, // 116: grpc.Bridge.StopEventStream:input_type -> google.protobuf.Empty + 71, // 117: grpc.Bridge.CheckTokens:output_type -> google.protobuf.StringValue + 72, // 118: grpc.Bridge.AddLogEntry:output_type -> google.protobuf.Empty + 8, // 119: grpc.Bridge.GuiReady:output_type -> grpc.GuiReadyResponse + 72, // 120: grpc.Bridge.Quit:output_type -> google.protobuf.Empty + 72, // 121: grpc.Bridge.Restart:output_type -> google.protobuf.Empty + 73, // 122: grpc.Bridge.ShowOnStartup:output_type -> google.protobuf.BoolValue + 72, // 123: grpc.Bridge.SetIsAutostartOn:output_type -> google.protobuf.Empty + 73, // 124: grpc.Bridge.IsAutostartOn:output_type -> google.protobuf.BoolValue + 72, // 125: grpc.Bridge.SetIsBetaEnabled:output_type -> google.protobuf.Empty + 73, // 126: grpc.Bridge.IsBetaEnabled:output_type -> google.protobuf.BoolValue + 72, // 127: grpc.Bridge.SetIsAllMailVisible:output_type -> google.protobuf.Empty + 73, // 128: grpc.Bridge.IsAllMailVisible:output_type -> google.protobuf.BoolValue + 72, // 129: grpc.Bridge.SetIsTelemetryDisabled:output_type -> google.protobuf.Empty + 73, // 130: grpc.Bridge.IsTelemetryDisabled:output_type -> google.protobuf.BoolValue + 71, // 131: grpc.Bridge.GoOs:output_type -> google.protobuf.StringValue + 72, // 132: grpc.Bridge.TriggerReset:output_type -> google.protobuf.Empty + 71, // 133: grpc.Bridge.Version:output_type -> google.protobuf.StringValue + 71, // 134: grpc.Bridge.LogsPath:output_type -> google.protobuf.StringValue + 71, // 135: grpc.Bridge.LicensePath:output_type -> google.protobuf.StringValue + 71, // 136: grpc.Bridge.ReleaseNotesPageLink:output_type -> google.protobuf.StringValue + 71, // 137: grpc.Bridge.DependencyLicensesLink:output_type -> google.protobuf.StringValue + 71, // 138: grpc.Bridge.LandingPageLink:output_type -> google.protobuf.StringValue + 72, // 139: grpc.Bridge.SetColorSchemeName:output_type -> google.protobuf.Empty + 71, // 140: grpc.Bridge.ColorSchemeName:output_type -> google.protobuf.StringValue + 71, // 141: grpc.Bridge.CurrentEmailClient:output_type -> google.protobuf.StringValue + 72, // 142: grpc.Bridge.ReportBug:output_type -> google.protobuf.Empty + 72, // 143: grpc.Bridge.ExportTLSCertificates:output_type -> google.protobuf.Empty + 72, // 144: grpc.Bridge.ForceLauncher:output_type -> google.protobuf.Empty + 72, // 145: grpc.Bridge.SetMainExecutable:output_type -> google.protobuf.Empty + 72, // 146: grpc.Bridge.Login:output_type -> google.protobuf.Empty + 72, // 147: grpc.Bridge.Login2FA:output_type -> google.protobuf.Empty + 72, // 148: grpc.Bridge.Login2Passwords:output_type -> google.protobuf.Empty + 72, // 149: grpc.Bridge.LoginAbort:output_type -> google.protobuf.Empty + 72, // 150: grpc.Bridge.CheckUpdate:output_type -> google.protobuf.Empty + 72, // 151: grpc.Bridge.InstallUpdate:output_type -> google.protobuf.Empty + 72, // 152: grpc.Bridge.SetIsAutomaticUpdateOn:output_type -> google.protobuf.Empty + 73, // 153: grpc.Bridge.IsAutomaticUpdateOn:output_type -> google.protobuf.BoolValue + 71, // 154: grpc.Bridge.DiskCachePath:output_type -> google.protobuf.StringValue + 72, // 155: grpc.Bridge.SetDiskCachePath:output_type -> google.protobuf.Empty + 72, // 156: grpc.Bridge.SetIsDoHEnabled:output_type -> google.protobuf.Empty + 73, // 157: grpc.Bridge.IsDoHEnabled:output_type -> google.protobuf.BoolValue + 12, // 158: grpc.Bridge.MailServerSettings:output_type -> grpc.ImapSmtpSettings + 72, // 159: grpc.Bridge.SetMailServerSettings:output_type -> google.protobuf.Empty + 71, // 160: grpc.Bridge.Hostname:output_type -> google.protobuf.StringValue + 73, // 161: grpc.Bridge.IsPortFree:output_type -> google.protobuf.BoolValue + 13, // 162: grpc.Bridge.AvailableKeychains:output_type -> grpc.AvailableKeychainsResponse + 72, // 163: grpc.Bridge.SetCurrentKeychain:output_type -> google.protobuf.Empty + 71, // 164: grpc.Bridge.CurrentKeychain:output_type -> google.protobuf.StringValue + 17, // 165: grpc.Bridge.GetUserList:output_type -> grpc.UserListResponse + 14, // 166: grpc.Bridge.GetUser:output_type -> grpc.User + 72, // 167: grpc.Bridge.SetUserSplitMode:output_type -> google.protobuf.Empty + 72, // 168: grpc.Bridge.SendBadEventUserFeedback:output_type -> google.protobuf.Empty + 72, // 169: grpc.Bridge.LogoutUser:output_type -> google.protobuf.Empty + 72, // 170: grpc.Bridge.RemoveUser:output_type -> google.protobuf.Empty + 72, // 171: grpc.Bridge.ConfigureUserAppleMail:output_type -> google.protobuf.Empty + 20, // 172: grpc.Bridge.RunEventStream:output_type -> grpc.StreamEvent + 72, // 173: grpc.Bridge.StopEventStream:output_type -> google.protobuf.Empty + 117, // [117:174] is the sub-list for method output_type + 60, // [60:117] is the sub-list for method input_type 60, // [60:60] is the sub-list for extension type_name 60, // [60:60] is the sub-list for extension extendee 0, // [0:60] is the sub-list for field type_name diff --git a/internal/frontend/grpc/bridge.proto b/internal/frontend/grpc/bridge.proto index e0a9ae9c..2a3e024b 100644 --- a/internal/frontend/grpc/bridge.proto +++ b/internal/frontend/grpc/bridge.proto @@ -42,6 +42,8 @@ service Bridge { rpc IsBetaEnabled(google.protobuf.Empty) returns (google.protobuf.BoolValue); rpc SetIsAllMailVisible(google.protobuf.BoolValue) returns (google.protobuf.Empty); rpc IsAllMailVisible(google.protobuf.Empty) returns (google.protobuf.BoolValue); + rpc SetIsTelemetryDisabled(google.protobuf.BoolValue) returns (google.protobuf.Empty); + rpc IsTelemetryDisabled(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); diff --git a/internal/frontend/grpc/bridge_grpc.pb.go b/internal/frontend/grpc/bridge_grpc.pb.go index 0b6a3d4f..fdddee0e 100644 --- a/internal/frontend/grpc/bridge_grpc.pb.go +++ b/internal/frontend/grpc/bridge_grpc.pb.go @@ -1,24 +1,7 @@ -// 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 . - // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: -// - protoc-gen-go-grpc v1.3.0 -// - protoc v3.21.12 +// - protoc-gen-go-grpc v1.2.0 +// - protoc v3.21.3 // source: bridge.proto package grpc @@ -37,64 +20,6 @@ import ( // Requires gRPC-Go v1.32.0 or later. const _ = grpc.SupportPackageIsVersion7 -const ( - Bridge_CheckTokens_FullMethodName = "/grpc.Bridge/CheckTokens" - Bridge_AddLogEntry_FullMethodName = "/grpc.Bridge/AddLogEntry" - Bridge_GuiReady_FullMethodName = "/grpc.Bridge/GuiReady" - Bridge_Quit_FullMethodName = "/grpc.Bridge/Quit" - Bridge_Restart_FullMethodName = "/grpc.Bridge/Restart" - Bridge_ShowOnStartup_FullMethodName = "/grpc.Bridge/ShowOnStartup" - Bridge_SetIsAutostartOn_FullMethodName = "/grpc.Bridge/SetIsAutostartOn" - Bridge_IsAutostartOn_FullMethodName = "/grpc.Bridge/IsAutostartOn" - Bridge_SetIsBetaEnabled_FullMethodName = "/grpc.Bridge/SetIsBetaEnabled" - Bridge_IsBetaEnabled_FullMethodName = "/grpc.Bridge/IsBetaEnabled" - Bridge_SetIsAllMailVisible_FullMethodName = "/grpc.Bridge/SetIsAllMailVisible" - Bridge_IsAllMailVisible_FullMethodName = "/grpc.Bridge/IsAllMailVisible" - Bridge_GoOs_FullMethodName = "/grpc.Bridge/GoOs" - Bridge_TriggerReset_FullMethodName = "/grpc.Bridge/TriggerReset" - Bridge_Version_FullMethodName = "/grpc.Bridge/Version" - Bridge_LogsPath_FullMethodName = "/grpc.Bridge/LogsPath" - Bridge_LicensePath_FullMethodName = "/grpc.Bridge/LicensePath" - Bridge_ReleaseNotesPageLink_FullMethodName = "/grpc.Bridge/ReleaseNotesPageLink" - Bridge_DependencyLicensesLink_FullMethodName = "/grpc.Bridge/DependencyLicensesLink" - Bridge_LandingPageLink_FullMethodName = "/grpc.Bridge/LandingPageLink" - Bridge_SetColorSchemeName_FullMethodName = "/grpc.Bridge/SetColorSchemeName" - Bridge_ColorSchemeName_FullMethodName = "/grpc.Bridge/ColorSchemeName" - Bridge_CurrentEmailClient_FullMethodName = "/grpc.Bridge/CurrentEmailClient" - Bridge_ReportBug_FullMethodName = "/grpc.Bridge/ReportBug" - Bridge_ExportTLSCertificates_FullMethodName = "/grpc.Bridge/ExportTLSCertificates" - Bridge_ForceLauncher_FullMethodName = "/grpc.Bridge/ForceLauncher" - Bridge_SetMainExecutable_FullMethodName = "/grpc.Bridge/SetMainExecutable" - Bridge_Login_FullMethodName = "/grpc.Bridge/Login" - Bridge_Login2FA_FullMethodName = "/grpc.Bridge/Login2FA" - Bridge_Login2Passwords_FullMethodName = "/grpc.Bridge/Login2Passwords" - Bridge_LoginAbort_FullMethodName = "/grpc.Bridge/LoginAbort" - Bridge_CheckUpdate_FullMethodName = "/grpc.Bridge/CheckUpdate" - Bridge_InstallUpdate_FullMethodName = "/grpc.Bridge/InstallUpdate" - Bridge_SetIsAutomaticUpdateOn_FullMethodName = "/grpc.Bridge/SetIsAutomaticUpdateOn" - Bridge_IsAutomaticUpdateOn_FullMethodName = "/grpc.Bridge/IsAutomaticUpdateOn" - Bridge_DiskCachePath_FullMethodName = "/grpc.Bridge/DiskCachePath" - Bridge_SetDiskCachePath_FullMethodName = "/grpc.Bridge/SetDiskCachePath" - Bridge_SetIsDoHEnabled_FullMethodName = "/grpc.Bridge/SetIsDoHEnabled" - Bridge_IsDoHEnabled_FullMethodName = "/grpc.Bridge/IsDoHEnabled" - Bridge_MailServerSettings_FullMethodName = "/grpc.Bridge/MailServerSettings" - Bridge_SetMailServerSettings_FullMethodName = "/grpc.Bridge/SetMailServerSettings" - Bridge_Hostname_FullMethodName = "/grpc.Bridge/Hostname" - Bridge_IsPortFree_FullMethodName = "/grpc.Bridge/IsPortFree" - Bridge_AvailableKeychains_FullMethodName = "/grpc.Bridge/AvailableKeychains" - Bridge_SetCurrentKeychain_FullMethodName = "/grpc.Bridge/SetCurrentKeychain" - Bridge_CurrentKeychain_FullMethodName = "/grpc.Bridge/CurrentKeychain" - Bridge_GetUserList_FullMethodName = "/grpc.Bridge/GetUserList" - Bridge_GetUser_FullMethodName = "/grpc.Bridge/GetUser" - Bridge_SetUserSplitMode_FullMethodName = "/grpc.Bridge/SetUserSplitMode" - Bridge_SendBadEventUserFeedback_FullMethodName = "/grpc.Bridge/SendBadEventUserFeedback" - Bridge_LogoutUser_FullMethodName = "/grpc.Bridge/LogoutUser" - Bridge_RemoveUser_FullMethodName = "/grpc.Bridge/RemoveUser" - Bridge_ConfigureUserAppleMail_FullMethodName = "/grpc.Bridge/ConfigureUserAppleMail" - Bridge_RunEventStream_FullMethodName = "/grpc.Bridge/RunEventStream" - Bridge_StopEventStream_FullMethodName = "/grpc.Bridge/StopEventStream" -) - // BridgeClient is the client API for Bridge service. // // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. @@ -112,6 +37,8 @@ type BridgeClient interface { IsBetaEnabled(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.BoolValue, error) SetIsAllMailVisible(ctx context.Context, in *wrapperspb.BoolValue, opts ...grpc.CallOption) (*emptypb.Empty, error) IsAllMailVisible(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.BoolValue, error) + SetIsTelemetryDisabled(ctx context.Context, in *wrapperspb.BoolValue, opts ...grpc.CallOption) (*emptypb.Empty, error) + IsTelemetryDisabled(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.BoolValue, error) GoOs(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.StringValue, error) TriggerReset(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error) Version(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.StringValue, error) @@ -174,7 +101,7 @@ func NewBridgeClient(cc grpc.ClientConnInterface) BridgeClient { func (c *bridgeClient) CheckTokens(ctx context.Context, in *wrapperspb.StringValue, opts ...grpc.CallOption) (*wrapperspb.StringValue, error) { out := new(wrapperspb.StringValue) - err := c.cc.Invoke(ctx, Bridge_CheckTokens_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/CheckTokens", in, out, opts...) if err != nil { return nil, err } @@ -183,7 +110,7 @@ func (c *bridgeClient) CheckTokens(ctx context.Context, in *wrapperspb.StringVal func (c *bridgeClient) AddLogEntry(ctx context.Context, in *AddLogEntryRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_AddLogEntry_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/AddLogEntry", in, out, opts...) if err != nil { return nil, err } @@ -192,7 +119,7 @@ func (c *bridgeClient) AddLogEntry(ctx context.Context, in *AddLogEntryRequest, func (c *bridgeClient) GuiReady(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GuiReadyResponse, error) { out := new(GuiReadyResponse) - err := c.cc.Invoke(ctx, Bridge_GuiReady_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/GuiReady", in, out, opts...) if err != nil { return nil, err } @@ -201,7 +128,7 @@ func (c *bridgeClient) GuiReady(ctx context.Context, in *emptypb.Empty, opts ... func (c *bridgeClient) Quit(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_Quit_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/Quit", in, out, opts...) if err != nil { return nil, err } @@ -210,7 +137,7 @@ func (c *bridgeClient) Quit(ctx context.Context, in *emptypb.Empty, opts ...grpc func (c *bridgeClient) Restart(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_Restart_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/Restart", in, out, opts...) if err != nil { return nil, err } @@ -219,7 +146,7 @@ func (c *bridgeClient) Restart(ctx context.Context, in *emptypb.Empty, opts ...g func (c *bridgeClient) ShowOnStartup(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.BoolValue, error) { out := new(wrapperspb.BoolValue) - err := c.cc.Invoke(ctx, Bridge_ShowOnStartup_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/ShowOnStartup", in, out, opts...) if err != nil { return nil, err } @@ -228,7 +155,7 @@ func (c *bridgeClient) ShowOnStartup(ctx context.Context, in *emptypb.Empty, opt func (c *bridgeClient) SetIsAutostartOn(ctx context.Context, in *wrapperspb.BoolValue, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_SetIsAutostartOn_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/SetIsAutostartOn", in, out, opts...) if err != nil { return nil, err } @@ -237,7 +164,7 @@ func (c *bridgeClient) SetIsAutostartOn(ctx context.Context, in *wrapperspb.Bool func (c *bridgeClient) IsAutostartOn(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.BoolValue, error) { out := new(wrapperspb.BoolValue) - err := c.cc.Invoke(ctx, Bridge_IsAutostartOn_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/IsAutostartOn", in, out, opts...) if err != nil { return nil, err } @@ -246,7 +173,7 @@ func (c *bridgeClient) IsAutostartOn(ctx context.Context, in *emptypb.Empty, opt func (c *bridgeClient) SetIsBetaEnabled(ctx context.Context, in *wrapperspb.BoolValue, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_SetIsBetaEnabled_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/SetIsBetaEnabled", in, out, opts...) if err != nil { return nil, err } @@ -255,7 +182,7 @@ func (c *bridgeClient) SetIsBetaEnabled(ctx context.Context, in *wrapperspb.Bool func (c *bridgeClient) IsBetaEnabled(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.BoolValue, error) { out := new(wrapperspb.BoolValue) - err := c.cc.Invoke(ctx, Bridge_IsBetaEnabled_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/IsBetaEnabled", in, out, opts...) if err != nil { return nil, err } @@ -264,7 +191,7 @@ func (c *bridgeClient) IsBetaEnabled(ctx context.Context, in *emptypb.Empty, opt func (c *bridgeClient) SetIsAllMailVisible(ctx context.Context, in *wrapperspb.BoolValue, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_SetIsAllMailVisible_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/SetIsAllMailVisible", in, out, opts...) if err != nil { return nil, err } @@ -273,7 +200,25 @@ func (c *bridgeClient) SetIsAllMailVisible(ctx context.Context, in *wrapperspb.B func (c *bridgeClient) IsAllMailVisible(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.BoolValue, error) { out := new(wrapperspb.BoolValue) - err := c.cc.Invoke(ctx, Bridge_IsAllMailVisible_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/IsAllMailVisible", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *bridgeClient) SetIsTelemetryDisabled(ctx context.Context, in *wrapperspb.BoolValue, opts ...grpc.CallOption) (*emptypb.Empty, error) { + out := new(emptypb.Empty) + err := c.cc.Invoke(ctx, "/grpc.Bridge/SetIsTelemetryDisabled", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *bridgeClient) IsTelemetryDisabled(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.BoolValue, error) { + out := new(wrapperspb.BoolValue) + err := c.cc.Invoke(ctx, "/grpc.Bridge/IsTelemetryDisabled", in, out, opts...) if err != nil { return nil, err } @@ -282,7 +227,7 @@ func (c *bridgeClient) IsAllMailVisible(ctx context.Context, in *emptypb.Empty, func (c *bridgeClient) GoOs(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.StringValue, error) { out := new(wrapperspb.StringValue) - err := c.cc.Invoke(ctx, Bridge_GoOs_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/GoOs", in, out, opts...) if err != nil { return nil, err } @@ -291,7 +236,7 @@ func (c *bridgeClient) GoOs(ctx context.Context, in *emptypb.Empty, opts ...grpc func (c *bridgeClient) TriggerReset(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_TriggerReset_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/TriggerReset", in, out, opts...) if err != nil { return nil, err } @@ -300,7 +245,7 @@ func (c *bridgeClient) TriggerReset(ctx context.Context, in *emptypb.Empty, opts func (c *bridgeClient) Version(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.StringValue, error) { out := new(wrapperspb.StringValue) - err := c.cc.Invoke(ctx, Bridge_Version_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/Version", in, out, opts...) if err != nil { return nil, err } @@ -309,7 +254,7 @@ func (c *bridgeClient) Version(ctx context.Context, in *emptypb.Empty, opts ...g func (c *bridgeClient) LogsPath(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.StringValue, error) { out := new(wrapperspb.StringValue) - err := c.cc.Invoke(ctx, Bridge_LogsPath_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/LogsPath", in, out, opts...) if err != nil { return nil, err } @@ -318,7 +263,7 @@ func (c *bridgeClient) LogsPath(ctx context.Context, in *emptypb.Empty, opts ... func (c *bridgeClient) LicensePath(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.StringValue, error) { out := new(wrapperspb.StringValue) - err := c.cc.Invoke(ctx, Bridge_LicensePath_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/LicensePath", in, out, opts...) if err != nil { return nil, err } @@ -327,7 +272,7 @@ func (c *bridgeClient) LicensePath(ctx context.Context, in *emptypb.Empty, opts func (c *bridgeClient) ReleaseNotesPageLink(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.StringValue, error) { out := new(wrapperspb.StringValue) - err := c.cc.Invoke(ctx, Bridge_ReleaseNotesPageLink_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/ReleaseNotesPageLink", in, out, opts...) if err != nil { return nil, err } @@ -336,7 +281,7 @@ func (c *bridgeClient) ReleaseNotesPageLink(ctx context.Context, in *emptypb.Emp func (c *bridgeClient) DependencyLicensesLink(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.StringValue, error) { out := new(wrapperspb.StringValue) - err := c.cc.Invoke(ctx, Bridge_DependencyLicensesLink_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/DependencyLicensesLink", in, out, opts...) if err != nil { return nil, err } @@ -345,7 +290,7 @@ func (c *bridgeClient) DependencyLicensesLink(ctx context.Context, in *emptypb.E func (c *bridgeClient) LandingPageLink(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.StringValue, error) { out := new(wrapperspb.StringValue) - err := c.cc.Invoke(ctx, Bridge_LandingPageLink_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/LandingPageLink", in, out, opts...) if err != nil { return nil, err } @@ -354,7 +299,7 @@ func (c *bridgeClient) LandingPageLink(ctx context.Context, in *emptypb.Empty, o func (c *bridgeClient) SetColorSchemeName(ctx context.Context, in *wrapperspb.StringValue, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_SetColorSchemeName_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/SetColorSchemeName", in, out, opts...) if err != nil { return nil, err } @@ -363,7 +308,7 @@ func (c *bridgeClient) SetColorSchemeName(ctx context.Context, in *wrapperspb.St func (c *bridgeClient) ColorSchemeName(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.StringValue, error) { out := new(wrapperspb.StringValue) - err := c.cc.Invoke(ctx, Bridge_ColorSchemeName_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/ColorSchemeName", in, out, opts...) if err != nil { return nil, err } @@ -372,7 +317,7 @@ func (c *bridgeClient) ColorSchemeName(ctx context.Context, in *emptypb.Empty, o func (c *bridgeClient) CurrentEmailClient(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.StringValue, error) { out := new(wrapperspb.StringValue) - err := c.cc.Invoke(ctx, Bridge_CurrentEmailClient_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/CurrentEmailClient", in, out, opts...) if err != nil { return nil, err } @@ -381,7 +326,7 @@ func (c *bridgeClient) CurrentEmailClient(ctx context.Context, in *emptypb.Empty func (c *bridgeClient) ReportBug(ctx context.Context, in *ReportBugRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_ReportBug_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/ReportBug", in, out, opts...) if err != nil { return nil, err } @@ -390,7 +335,7 @@ func (c *bridgeClient) ReportBug(ctx context.Context, in *ReportBugRequest, opts func (c *bridgeClient) ExportTLSCertificates(ctx context.Context, in *wrapperspb.StringValue, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_ExportTLSCertificates_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/ExportTLSCertificates", in, out, opts...) if err != nil { return nil, err } @@ -399,7 +344,7 @@ func (c *bridgeClient) ExportTLSCertificates(ctx context.Context, in *wrapperspb func (c *bridgeClient) ForceLauncher(ctx context.Context, in *wrapperspb.StringValue, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_ForceLauncher_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/ForceLauncher", in, out, opts...) if err != nil { return nil, err } @@ -408,7 +353,7 @@ func (c *bridgeClient) ForceLauncher(ctx context.Context, in *wrapperspb.StringV func (c *bridgeClient) SetMainExecutable(ctx context.Context, in *wrapperspb.StringValue, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_SetMainExecutable_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/SetMainExecutable", in, out, opts...) if err != nil { return nil, err } @@ -417,7 +362,7 @@ func (c *bridgeClient) SetMainExecutable(ctx context.Context, in *wrapperspb.Str func (c *bridgeClient) Login(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_Login_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/Login", in, out, opts...) if err != nil { return nil, err } @@ -426,7 +371,7 @@ func (c *bridgeClient) Login(ctx context.Context, in *LoginRequest, opts ...grpc func (c *bridgeClient) Login2FA(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_Login2FA_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/Login2FA", in, out, opts...) if err != nil { return nil, err } @@ -435,7 +380,7 @@ func (c *bridgeClient) Login2FA(ctx context.Context, in *LoginRequest, opts ...g func (c *bridgeClient) Login2Passwords(ctx context.Context, in *LoginRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_Login2Passwords_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/Login2Passwords", in, out, opts...) if err != nil { return nil, err } @@ -444,7 +389,7 @@ func (c *bridgeClient) Login2Passwords(ctx context.Context, in *LoginRequest, op func (c *bridgeClient) LoginAbort(ctx context.Context, in *LoginAbortRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_LoginAbort_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/LoginAbort", in, out, opts...) if err != nil { return nil, err } @@ -453,7 +398,7 @@ func (c *bridgeClient) LoginAbort(ctx context.Context, in *LoginAbortRequest, op func (c *bridgeClient) CheckUpdate(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_CheckUpdate_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/CheckUpdate", in, out, opts...) if err != nil { return nil, err } @@ -462,7 +407,7 @@ func (c *bridgeClient) CheckUpdate(ctx context.Context, in *emptypb.Empty, opts func (c *bridgeClient) InstallUpdate(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_InstallUpdate_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/InstallUpdate", in, out, opts...) if err != nil { return nil, err } @@ -471,7 +416,7 @@ func (c *bridgeClient) InstallUpdate(ctx context.Context, in *emptypb.Empty, opt func (c *bridgeClient) SetIsAutomaticUpdateOn(ctx context.Context, in *wrapperspb.BoolValue, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_SetIsAutomaticUpdateOn_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/SetIsAutomaticUpdateOn", in, out, opts...) if err != nil { return nil, err } @@ -480,7 +425,7 @@ func (c *bridgeClient) SetIsAutomaticUpdateOn(ctx context.Context, in *wrappersp func (c *bridgeClient) IsAutomaticUpdateOn(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.BoolValue, error) { out := new(wrapperspb.BoolValue) - err := c.cc.Invoke(ctx, Bridge_IsAutomaticUpdateOn_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/IsAutomaticUpdateOn", in, out, opts...) if err != nil { return nil, err } @@ -489,7 +434,7 @@ func (c *bridgeClient) IsAutomaticUpdateOn(ctx context.Context, in *emptypb.Empt func (c *bridgeClient) DiskCachePath(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.StringValue, error) { out := new(wrapperspb.StringValue) - err := c.cc.Invoke(ctx, Bridge_DiskCachePath_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/DiskCachePath", in, out, opts...) if err != nil { return nil, err } @@ -498,7 +443,7 @@ func (c *bridgeClient) DiskCachePath(ctx context.Context, in *emptypb.Empty, opt func (c *bridgeClient) SetDiskCachePath(ctx context.Context, in *wrapperspb.StringValue, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_SetDiskCachePath_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/SetDiskCachePath", in, out, opts...) if err != nil { return nil, err } @@ -507,7 +452,7 @@ func (c *bridgeClient) SetDiskCachePath(ctx context.Context, in *wrapperspb.Stri func (c *bridgeClient) SetIsDoHEnabled(ctx context.Context, in *wrapperspb.BoolValue, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_SetIsDoHEnabled_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/SetIsDoHEnabled", in, out, opts...) if err != nil { return nil, err } @@ -516,7 +461,7 @@ func (c *bridgeClient) SetIsDoHEnabled(ctx context.Context, in *wrapperspb.BoolV func (c *bridgeClient) IsDoHEnabled(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.BoolValue, error) { out := new(wrapperspb.BoolValue) - err := c.cc.Invoke(ctx, Bridge_IsDoHEnabled_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/IsDoHEnabled", in, out, opts...) if err != nil { return nil, err } @@ -525,7 +470,7 @@ func (c *bridgeClient) IsDoHEnabled(ctx context.Context, in *emptypb.Empty, opts func (c *bridgeClient) MailServerSettings(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*ImapSmtpSettings, error) { out := new(ImapSmtpSettings) - err := c.cc.Invoke(ctx, Bridge_MailServerSettings_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/MailServerSettings", in, out, opts...) if err != nil { return nil, err } @@ -534,7 +479,7 @@ func (c *bridgeClient) MailServerSettings(ctx context.Context, in *emptypb.Empty func (c *bridgeClient) SetMailServerSettings(ctx context.Context, in *ImapSmtpSettings, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_SetMailServerSettings_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/SetMailServerSettings", in, out, opts...) if err != nil { return nil, err } @@ -543,7 +488,7 @@ func (c *bridgeClient) SetMailServerSettings(ctx context.Context, in *ImapSmtpSe func (c *bridgeClient) Hostname(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.StringValue, error) { out := new(wrapperspb.StringValue) - err := c.cc.Invoke(ctx, Bridge_Hostname_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/Hostname", in, out, opts...) if err != nil { return nil, err } @@ -552,7 +497,7 @@ func (c *bridgeClient) Hostname(ctx context.Context, in *emptypb.Empty, opts ... func (c *bridgeClient) IsPortFree(ctx context.Context, in *wrapperspb.Int32Value, opts ...grpc.CallOption) (*wrapperspb.BoolValue, error) { out := new(wrapperspb.BoolValue) - err := c.cc.Invoke(ctx, Bridge_IsPortFree_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/IsPortFree", in, out, opts...) if err != nil { return nil, err } @@ -561,7 +506,7 @@ func (c *bridgeClient) IsPortFree(ctx context.Context, in *wrapperspb.Int32Value func (c *bridgeClient) AvailableKeychains(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*AvailableKeychainsResponse, error) { out := new(AvailableKeychainsResponse) - err := c.cc.Invoke(ctx, Bridge_AvailableKeychains_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/AvailableKeychains", in, out, opts...) if err != nil { return nil, err } @@ -570,7 +515,7 @@ func (c *bridgeClient) AvailableKeychains(ctx context.Context, in *emptypb.Empty func (c *bridgeClient) SetCurrentKeychain(ctx context.Context, in *wrapperspb.StringValue, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_SetCurrentKeychain_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/SetCurrentKeychain", in, out, opts...) if err != nil { return nil, err } @@ -579,7 +524,7 @@ func (c *bridgeClient) SetCurrentKeychain(ctx context.Context, in *wrapperspb.St func (c *bridgeClient) CurrentKeychain(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*wrapperspb.StringValue, error) { out := new(wrapperspb.StringValue) - err := c.cc.Invoke(ctx, Bridge_CurrentKeychain_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/CurrentKeychain", in, out, opts...) if err != nil { return nil, err } @@ -588,7 +533,7 @@ func (c *bridgeClient) CurrentKeychain(ctx context.Context, in *emptypb.Empty, o func (c *bridgeClient) GetUserList(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*UserListResponse, error) { out := new(UserListResponse) - err := c.cc.Invoke(ctx, Bridge_GetUserList_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/GetUserList", in, out, opts...) if err != nil { return nil, err } @@ -597,7 +542,7 @@ func (c *bridgeClient) GetUserList(ctx context.Context, in *emptypb.Empty, opts func (c *bridgeClient) GetUser(ctx context.Context, in *wrapperspb.StringValue, opts ...grpc.CallOption) (*User, error) { out := new(User) - err := c.cc.Invoke(ctx, Bridge_GetUser_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/GetUser", in, out, opts...) if err != nil { return nil, err } @@ -606,7 +551,7 @@ func (c *bridgeClient) GetUser(ctx context.Context, in *wrapperspb.StringValue, func (c *bridgeClient) SetUserSplitMode(ctx context.Context, in *UserSplitModeRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_SetUserSplitMode_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/SetUserSplitMode", in, out, opts...) if err != nil { return nil, err } @@ -615,7 +560,7 @@ func (c *bridgeClient) SetUserSplitMode(ctx context.Context, in *UserSplitModeRe func (c *bridgeClient) SendBadEventUserFeedback(ctx context.Context, in *UserBadEventFeedbackRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_SendBadEventUserFeedback_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/SendBadEventUserFeedback", in, out, opts...) if err != nil { return nil, err } @@ -624,7 +569,7 @@ func (c *bridgeClient) SendBadEventUserFeedback(ctx context.Context, in *UserBad func (c *bridgeClient) LogoutUser(ctx context.Context, in *wrapperspb.StringValue, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_LogoutUser_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/LogoutUser", in, out, opts...) if err != nil { return nil, err } @@ -633,7 +578,7 @@ func (c *bridgeClient) LogoutUser(ctx context.Context, in *wrapperspb.StringValu func (c *bridgeClient) RemoveUser(ctx context.Context, in *wrapperspb.StringValue, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_RemoveUser_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/RemoveUser", in, out, opts...) if err != nil { return nil, err } @@ -642,7 +587,7 @@ func (c *bridgeClient) RemoveUser(ctx context.Context, in *wrapperspb.StringValu func (c *bridgeClient) ConfigureUserAppleMail(ctx context.Context, in *ConfigureAppleMailRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_ConfigureUserAppleMail_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/ConfigureUserAppleMail", in, out, opts...) if err != nil { return nil, err } @@ -650,7 +595,7 @@ func (c *bridgeClient) ConfigureUserAppleMail(ctx context.Context, in *Configure } func (c *bridgeClient) RunEventStream(ctx context.Context, in *EventStreamRequest, opts ...grpc.CallOption) (Bridge_RunEventStreamClient, error) { - stream, err := c.cc.NewStream(ctx, &Bridge_ServiceDesc.Streams[0], Bridge_RunEventStream_FullMethodName, opts...) + stream, err := c.cc.NewStream(ctx, &Bridge_ServiceDesc.Streams[0], "/grpc.Bridge/RunEventStream", opts...) if err != nil { return nil, err } @@ -683,7 +628,7 @@ func (x *bridgeRunEventStreamClient) Recv() (*StreamEvent, error) { func (c *bridgeClient) StopEventStream(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*emptypb.Empty, error) { out := new(emptypb.Empty) - err := c.cc.Invoke(ctx, Bridge_StopEventStream_FullMethodName, in, out, opts...) + err := c.cc.Invoke(ctx, "/grpc.Bridge/StopEventStream", in, out, opts...) if err != nil { return nil, err } @@ -707,6 +652,8 @@ type BridgeServer interface { IsBetaEnabled(context.Context, *emptypb.Empty) (*wrapperspb.BoolValue, error) SetIsAllMailVisible(context.Context, *wrapperspb.BoolValue) (*emptypb.Empty, error) IsAllMailVisible(context.Context, *emptypb.Empty) (*wrapperspb.BoolValue, error) + SetIsTelemetryDisabled(context.Context, *wrapperspb.BoolValue) (*emptypb.Empty, error) + IsTelemetryDisabled(context.Context, *emptypb.Empty) (*wrapperspb.BoolValue, error) GoOs(context.Context, *emptypb.Empty) (*wrapperspb.StringValue, error) TriggerReset(context.Context, *emptypb.Empty) (*emptypb.Empty, error) Version(context.Context, *emptypb.Empty) (*wrapperspb.StringValue, error) @@ -800,6 +747,12 @@ func (UnimplementedBridgeServer) SetIsAllMailVisible(context.Context, *wrappersp func (UnimplementedBridgeServer) IsAllMailVisible(context.Context, *emptypb.Empty) (*wrapperspb.BoolValue, error) { return nil, status.Errorf(codes.Unimplemented, "method IsAllMailVisible not implemented") } +func (UnimplementedBridgeServer) SetIsTelemetryDisabled(context.Context, *wrapperspb.BoolValue) (*emptypb.Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method SetIsTelemetryDisabled not implemented") +} +func (UnimplementedBridgeServer) IsTelemetryDisabled(context.Context, *emptypb.Empty) (*wrapperspb.BoolValue, error) { + return nil, status.Errorf(codes.Unimplemented, "method IsTelemetryDisabled not implemented") +} func (UnimplementedBridgeServer) GoOs(context.Context, *emptypb.Empty) (*wrapperspb.StringValue, error) { return nil, status.Errorf(codes.Unimplemented, "method GoOs not implemented") } @@ -952,7 +905,7 @@ func _Bridge_CheckTokens_Handler(srv interface{}, ctx context.Context, dec func( } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_CheckTokens_FullMethodName, + FullMethod: "/grpc.Bridge/CheckTokens", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).CheckTokens(ctx, req.(*wrapperspb.StringValue)) @@ -970,7 +923,7 @@ func _Bridge_AddLogEntry_Handler(srv interface{}, ctx context.Context, dec func( } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_AddLogEntry_FullMethodName, + FullMethod: "/grpc.Bridge/AddLogEntry", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).AddLogEntry(ctx, req.(*AddLogEntryRequest)) @@ -988,7 +941,7 @@ func _Bridge_GuiReady_Handler(srv interface{}, ctx context.Context, dec func(int } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_GuiReady_FullMethodName, + FullMethod: "/grpc.Bridge/GuiReady", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).GuiReady(ctx, req.(*emptypb.Empty)) @@ -1006,7 +959,7 @@ func _Bridge_Quit_Handler(srv interface{}, ctx context.Context, dec func(interfa } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_Quit_FullMethodName, + FullMethod: "/grpc.Bridge/Quit", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).Quit(ctx, req.(*emptypb.Empty)) @@ -1024,7 +977,7 @@ func _Bridge_Restart_Handler(srv interface{}, ctx context.Context, dec func(inte } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_Restart_FullMethodName, + FullMethod: "/grpc.Bridge/Restart", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).Restart(ctx, req.(*emptypb.Empty)) @@ -1042,7 +995,7 @@ func _Bridge_ShowOnStartup_Handler(srv interface{}, ctx context.Context, dec fun } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_ShowOnStartup_FullMethodName, + FullMethod: "/grpc.Bridge/ShowOnStartup", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).ShowOnStartup(ctx, req.(*emptypb.Empty)) @@ -1060,7 +1013,7 @@ func _Bridge_SetIsAutostartOn_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_SetIsAutostartOn_FullMethodName, + FullMethod: "/grpc.Bridge/SetIsAutostartOn", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).SetIsAutostartOn(ctx, req.(*wrapperspb.BoolValue)) @@ -1078,7 +1031,7 @@ func _Bridge_IsAutostartOn_Handler(srv interface{}, ctx context.Context, dec fun } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_IsAutostartOn_FullMethodName, + FullMethod: "/grpc.Bridge/IsAutostartOn", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).IsAutostartOn(ctx, req.(*emptypb.Empty)) @@ -1096,7 +1049,7 @@ func _Bridge_SetIsBetaEnabled_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_SetIsBetaEnabled_FullMethodName, + FullMethod: "/grpc.Bridge/SetIsBetaEnabled", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).SetIsBetaEnabled(ctx, req.(*wrapperspb.BoolValue)) @@ -1114,7 +1067,7 @@ func _Bridge_IsBetaEnabled_Handler(srv interface{}, ctx context.Context, dec fun } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_IsBetaEnabled_FullMethodName, + FullMethod: "/grpc.Bridge/IsBetaEnabled", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).IsBetaEnabled(ctx, req.(*emptypb.Empty)) @@ -1132,7 +1085,7 @@ func _Bridge_SetIsAllMailVisible_Handler(srv interface{}, ctx context.Context, d } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_SetIsAllMailVisible_FullMethodName, + FullMethod: "/grpc.Bridge/SetIsAllMailVisible", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).SetIsAllMailVisible(ctx, req.(*wrapperspb.BoolValue)) @@ -1150,7 +1103,7 @@ func _Bridge_IsAllMailVisible_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_IsAllMailVisible_FullMethodName, + FullMethod: "/grpc.Bridge/IsAllMailVisible", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).IsAllMailVisible(ctx, req.(*emptypb.Empty)) @@ -1158,6 +1111,42 @@ func _Bridge_IsAllMailVisible_Handler(srv interface{}, ctx context.Context, dec return interceptor(ctx, in, info, handler) } +func _Bridge_SetIsTelemetryDisabled_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(wrapperspb.BoolValue) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BridgeServer).SetIsTelemetryDisabled(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.Bridge/SetIsTelemetryDisabled", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BridgeServer).SetIsTelemetryDisabled(ctx, req.(*wrapperspb.BoolValue)) + } + return interceptor(ctx, in, info, handler) +} + +func _Bridge_IsTelemetryDisabled_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(emptypb.Empty) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(BridgeServer).IsTelemetryDisabled(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/grpc.Bridge/IsTelemetryDisabled", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(BridgeServer).IsTelemetryDisabled(ctx, req.(*emptypb.Empty)) + } + return interceptor(ctx, in, info, handler) +} + func _Bridge_GoOs_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(emptypb.Empty) if err := dec(in); err != nil { @@ -1168,7 +1157,7 @@ func _Bridge_GoOs_Handler(srv interface{}, ctx context.Context, dec func(interfa } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_GoOs_FullMethodName, + FullMethod: "/grpc.Bridge/GoOs", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).GoOs(ctx, req.(*emptypb.Empty)) @@ -1186,7 +1175,7 @@ func _Bridge_TriggerReset_Handler(srv interface{}, ctx context.Context, dec func } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_TriggerReset_FullMethodName, + FullMethod: "/grpc.Bridge/TriggerReset", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).TriggerReset(ctx, req.(*emptypb.Empty)) @@ -1204,7 +1193,7 @@ func _Bridge_Version_Handler(srv interface{}, ctx context.Context, dec func(inte } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_Version_FullMethodName, + FullMethod: "/grpc.Bridge/Version", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).Version(ctx, req.(*emptypb.Empty)) @@ -1222,7 +1211,7 @@ func _Bridge_LogsPath_Handler(srv interface{}, ctx context.Context, dec func(int } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_LogsPath_FullMethodName, + FullMethod: "/grpc.Bridge/LogsPath", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).LogsPath(ctx, req.(*emptypb.Empty)) @@ -1240,7 +1229,7 @@ func _Bridge_LicensePath_Handler(srv interface{}, ctx context.Context, dec func( } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_LicensePath_FullMethodName, + FullMethod: "/grpc.Bridge/LicensePath", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).LicensePath(ctx, req.(*emptypb.Empty)) @@ -1258,7 +1247,7 @@ func _Bridge_ReleaseNotesPageLink_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_ReleaseNotesPageLink_FullMethodName, + FullMethod: "/grpc.Bridge/ReleaseNotesPageLink", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).ReleaseNotesPageLink(ctx, req.(*emptypb.Empty)) @@ -1276,7 +1265,7 @@ func _Bridge_DependencyLicensesLink_Handler(srv interface{}, ctx context.Context } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_DependencyLicensesLink_FullMethodName, + FullMethod: "/grpc.Bridge/DependencyLicensesLink", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).DependencyLicensesLink(ctx, req.(*emptypb.Empty)) @@ -1294,7 +1283,7 @@ func _Bridge_LandingPageLink_Handler(srv interface{}, ctx context.Context, dec f } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_LandingPageLink_FullMethodName, + FullMethod: "/grpc.Bridge/LandingPageLink", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).LandingPageLink(ctx, req.(*emptypb.Empty)) @@ -1312,7 +1301,7 @@ func _Bridge_SetColorSchemeName_Handler(srv interface{}, ctx context.Context, de } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_SetColorSchemeName_FullMethodName, + FullMethod: "/grpc.Bridge/SetColorSchemeName", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).SetColorSchemeName(ctx, req.(*wrapperspb.StringValue)) @@ -1330,7 +1319,7 @@ func _Bridge_ColorSchemeName_Handler(srv interface{}, ctx context.Context, dec f } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_ColorSchemeName_FullMethodName, + FullMethod: "/grpc.Bridge/ColorSchemeName", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).ColorSchemeName(ctx, req.(*emptypb.Empty)) @@ -1348,7 +1337,7 @@ func _Bridge_CurrentEmailClient_Handler(srv interface{}, ctx context.Context, de } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_CurrentEmailClient_FullMethodName, + FullMethod: "/grpc.Bridge/CurrentEmailClient", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).CurrentEmailClient(ctx, req.(*emptypb.Empty)) @@ -1366,7 +1355,7 @@ func _Bridge_ReportBug_Handler(srv interface{}, ctx context.Context, dec func(in } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_ReportBug_FullMethodName, + FullMethod: "/grpc.Bridge/ReportBug", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).ReportBug(ctx, req.(*ReportBugRequest)) @@ -1384,7 +1373,7 @@ func _Bridge_ExportTLSCertificates_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_ExportTLSCertificates_FullMethodName, + FullMethod: "/grpc.Bridge/ExportTLSCertificates", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).ExportTLSCertificates(ctx, req.(*wrapperspb.StringValue)) @@ -1402,7 +1391,7 @@ func _Bridge_ForceLauncher_Handler(srv interface{}, ctx context.Context, dec fun } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_ForceLauncher_FullMethodName, + FullMethod: "/grpc.Bridge/ForceLauncher", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).ForceLauncher(ctx, req.(*wrapperspb.StringValue)) @@ -1420,7 +1409,7 @@ func _Bridge_SetMainExecutable_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_SetMainExecutable_FullMethodName, + FullMethod: "/grpc.Bridge/SetMainExecutable", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).SetMainExecutable(ctx, req.(*wrapperspb.StringValue)) @@ -1438,7 +1427,7 @@ func _Bridge_Login_Handler(srv interface{}, ctx context.Context, dec func(interf } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_Login_FullMethodName, + FullMethod: "/grpc.Bridge/Login", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).Login(ctx, req.(*LoginRequest)) @@ -1456,7 +1445,7 @@ func _Bridge_Login2FA_Handler(srv interface{}, ctx context.Context, dec func(int } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_Login2FA_FullMethodName, + FullMethod: "/grpc.Bridge/Login2FA", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).Login2FA(ctx, req.(*LoginRequest)) @@ -1474,7 +1463,7 @@ func _Bridge_Login2Passwords_Handler(srv interface{}, ctx context.Context, dec f } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_Login2Passwords_FullMethodName, + FullMethod: "/grpc.Bridge/Login2Passwords", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).Login2Passwords(ctx, req.(*LoginRequest)) @@ -1492,7 +1481,7 @@ func _Bridge_LoginAbort_Handler(srv interface{}, ctx context.Context, dec func(i } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_LoginAbort_FullMethodName, + FullMethod: "/grpc.Bridge/LoginAbort", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).LoginAbort(ctx, req.(*LoginAbortRequest)) @@ -1510,7 +1499,7 @@ func _Bridge_CheckUpdate_Handler(srv interface{}, ctx context.Context, dec func( } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_CheckUpdate_FullMethodName, + FullMethod: "/grpc.Bridge/CheckUpdate", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).CheckUpdate(ctx, req.(*emptypb.Empty)) @@ -1528,7 +1517,7 @@ func _Bridge_InstallUpdate_Handler(srv interface{}, ctx context.Context, dec fun } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_InstallUpdate_FullMethodName, + FullMethod: "/grpc.Bridge/InstallUpdate", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).InstallUpdate(ctx, req.(*emptypb.Empty)) @@ -1546,7 +1535,7 @@ func _Bridge_SetIsAutomaticUpdateOn_Handler(srv interface{}, ctx context.Context } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_SetIsAutomaticUpdateOn_FullMethodName, + FullMethod: "/grpc.Bridge/SetIsAutomaticUpdateOn", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).SetIsAutomaticUpdateOn(ctx, req.(*wrapperspb.BoolValue)) @@ -1564,7 +1553,7 @@ func _Bridge_IsAutomaticUpdateOn_Handler(srv interface{}, ctx context.Context, d } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_IsAutomaticUpdateOn_FullMethodName, + FullMethod: "/grpc.Bridge/IsAutomaticUpdateOn", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).IsAutomaticUpdateOn(ctx, req.(*emptypb.Empty)) @@ -1582,7 +1571,7 @@ func _Bridge_DiskCachePath_Handler(srv interface{}, ctx context.Context, dec fun } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_DiskCachePath_FullMethodName, + FullMethod: "/grpc.Bridge/DiskCachePath", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).DiskCachePath(ctx, req.(*emptypb.Empty)) @@ -1600,7 +1589,7 @@ func _Bridge_SetDiskCachePath_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_SetDiskCachePath_FullMethodName, + FullMethod: "/grpc.Bridge/SetDiskCachePath", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).SetDiskCachePath(ctx, req.(*wrapperspb.StringValue)) @@ -1618,7 +1607,7 @@ func _Bridge_SetIsDoHEnabled_Handler(srv interface{}, ctx context.Context, dec f } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_SetIsDoHEnabled_FullMethodName, + FullMethod: "/grpc.Bridge/SetIsDoHEnabled", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).SetIsDoHEnabled(ctx, req.(*wrapperspb.BoolValue)) @@ -1636,7 +1625,7 @@ func _Bridge_IsDoHEnabled_Handler(srv interface{}, ctx context.Context, dec func } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_IsDoHEnabled_FullMethodName, + FullMethod: "/grpc.Bridge/IsDoHEnabled", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).IsDoHEnabled(ctx, req.(*emptypb.Empty)) @@ -1654,7 +1643,7 @@ func _Bridge_MailServerSettings_Handler(srv interface{}, ctx context.Context, de } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_MailServerSettings_FullMethodName, + FullMethod: "/grpc.Bridge/MailServerSettings", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).MailServerSettings(ctx, req.(*emptypb.Empty)) @@ -1672,7 +1661,7 @@ func _Bridge_SetMailServerSettings_Handler(srv interface{}, ctx context.Context, } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_SetMailServerSettings_FullMethodName, + FullMethod: "/grpc.Bridge/SetMailServerSettings", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).SetMailServerSettings(ctx, req.(*ImapSmtpSettings)) @@ -1690,7 +1679,7 @@ func _Bridge_Hostname_Handler(srv interface{}, ctx context.Context, dec func(int } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_Hostname_FullMethodName, + FullMethod: "/grpc.Bridge/Hostname", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).Hostname(ctx, req.(*emptypb.Empty)) @@ -1708,7 +1697,7 @@ func _Bridge_IsPortFree_Handler(srv interface{}, ctx context.Context, dec func(i } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_IsPortFree_FullMethodName, + FullMethod: "/grpc.Bridge/IsPortFree", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).IsPortFree(ctx, req.(*wrapperspb.Int32Value)) @@ -1726,7 +1715,7 @@ func _Bridge_AvailableKeychains_Handler(srv interface{}, ctx context.Context, de } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_AvailableKeychains_FullMethodName, + FullMethod: "/grpc.Bridge/AvailableKeychains", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).AvailableKeychains(ctx, req.(*emptypb.Empty)) @@ -1744,7 +1733,7 @@ func _Bridge_SetCurrentKeychain_Handler(srv interface{}, ctx context.Context, de } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_SetCurrentKeychain_FullMethodName, + FullMethod: "/grpc.Bridge/SetCurrentKeychain", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).SetCurrentKeychain(ctx, req.(*wrapperspb.StringValue)) @@ -1762,7 +1751,7 @@ func _Bridge_CurrentKeychain_Handler(srv interface{}, ctx context.Context, dec f } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_CurrentKeychain_FullMethodName, + FullMethod: "/grpc.Bridge/CurrentKeychain", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).CurrentKeychain(ctx, req.(*emptypb.Empty)) @@ -1780,7 +1769,7 @@ func _Bridge_GetUserList_Handler(srv interface{}, ctx context.Context, dec func( } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_GetUserList_FullMethodName, + FullMethod: "/grpc.Bridge/GetUserList", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).GetUserList(ctx, req.(*emptypb.Empty)) @@ -1798,7 +1787,7 @@ func _Bridge_GetUser_Handler(srv interface{}, ctx context.Context, dec func(inte } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_GetUser_FullMethodName, + FullMethod: "/grpc.Bridge/GetUser", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).GetUser(ctx, req.(*wrapperspb.StringValue)) @@ -1816,7 +1805,7 @@ func _Bridge_SetUserSplitMode_Handler(srv interface{}, ctx context.Context, dec } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_SetUserSplitMode_FullMethodName, + FullMethod: "/grpc.Bridge/SetUserSplitMode", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).SetUserSplitMode(ctx, req.(*UserSplitModeRequest)) @@ -1834,7 +1823,7 @@ func _Bridge_SendBadEventUserFeedback_Handler(srv interface{}, ctx context.Conte } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_SendBadEventUserFeedback_FullMethodName, + FullMethod: "/grpc.Bridge/SendBadEventUserFeedback", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).SendBadEventUserFeedback(ctx, req.(*UserBadEventFeedbackRequest)) @@ -1852,7 +1841,7 @@ func _Bridge_LogoutUser_Handler(srv interface{}, ctx context.Context, dec func(i } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_LogoutUser_FullMethodName, + FullMethod: "/grpc.Bridge/LogoutUser", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).LogoutUser(ctx, req.(*wrapperspb.StringValue)) @@ -1870,7 +1859,7 @@ func _Bridge_RemoveUser_Handler(srv interface{}, ctx context.Context, dec func(i } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_RemoveUser_FullMethodName, + FullMethod: "/grpc.Bridge/RemoveUser", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).RemoveUser(ctx, req.(*wrapperspb.StringValue)) @@ -1888,7 +1877,7 @@ func _Bridge_ConfigureUserAppleMail_Handler(srv interface{}, ctx context.Context } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_ConfigureUserAppleMail_FullMethodName, + FullMethod: "/grpc.Bridge/ConfigureUserAppleMail", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).ConfigureUserAppleMail(ctx, req.(*ConfigureAppleMailRequest)) @@ -1927,7 +1916,7 @@ func _Bridge_StopEventStream_Handler(srv interface{}, ctx context.Context, dec f } info := &grpc.UnaryServerInfo{ Server: srv, - FullMethod: Bridge_StopEventStream_FullMethodName, + FullMethod: "/grpc.Bridge/StopEventStream", } handler := func(ctx context.Context, req interface{}) (interface{}, error) { return srv.(BridgeServer).StopEventStream(ctx, req.(*emptypb.Empty)) @@ -1990,6 +1979,14 @@ var Bridge_ServiceDesc = grpc.ServiceDesc{ MethodName: "IsAllMailVisible", Handler: _Bridge_IsAllMailVisible_Handler, }, + { + MethodName: "SetIsTelemetryDisabled", + Handler: _Bridge_SetIsTelemetryDisabled_Handler, + }, + { + MethodName: "IsTelemetryDisabled", + Handler: _Bridge_IsTelemetryDisabled_Handler, + }, { MethodName: "GoOs", Handler: _Bridge_GoOs_Handler, diff --git a/internal/frontend/grpc/service_methods.go b/internal/frontend/grpc/service_methods.go index 0a4321ec..a49e698a 100644 --- a/internal/frontend/grpc/service_methods.go +++ b/internal/frontend/grpc/service_methods.go @@ -214,6 +214,23 @@ func (s *Service) IsAllMailVisible(ctx context.Context, _ *emptypb.Empty) (*wrap return wrapperspb.Bool(s.bridge.GetShowAllMail()), nil } +func (s *Service) SetIsTelemetryDisabled(_ context.Context, isDisabled *wrapperspb.BoolValue) (*emptypb.Empty, error) { + s.log.WithField("isEnabled", isDisabled.Value).Debug("SetIsTelemetryDisabled") + + if err := s.bridge.SetTelemetryDisabled(isDisabled.Value); err != nil { + s.log.WithError(err).Error("Failed to set telemetry status") + return nil, status.Errorf(codes.Internal, "failed to set telemetry status: %v", err) + } + + return &emptypb.Empty{}, nil +} + +func (s *Service) IsTelemetryDisabled(_ context.Context, _ *emptypb.Empty) (*wrapperspb.BoolValue, error) { + s.log.Debug("IsTelemetryDisabled") + + return wrapperspb.Bool(s.bridge.GetTelemetryDisabled()), nil +} + func (s *Service) GoOs(ctx context.Context, _ *emptypb.Empty) (*wrapperspb.StringValue, error) { s.log.Debug("GoOs") // TO-DO We can probably get rid of this and use QSysInfo::product name diff --git a/internal/vault/settings.go b/internal/vault/settings.go index af080222..e09bdc06 100644 --- a/internal/vault/settings.go +++ b/internal/vault/settings.go @@ -184,6 +184,18 @@ func (vault *Vault) SetAutoUpdate(autoUpdate bool) error { }) } +// GetTelemetryDisabled checks whether telemetry is disabled. +func (vault *Vault) GetTelemetryDisabled() bool { + return vault.get().Settings.TelemetryDisabled +} + +// SetTelemetryDisabled sets whether telemetry is disabled. +func (vault *Vault) SetTelemetryDisabled(telemetryDisabled bool) error { + return vault.mod(func(data *Data) { + data.Settings.TelemetryDisabled = telemetryDisabled + }) +} + // GetLastVersion returns the last version of the bridge that was run. func (vault *Vault) GetLastVersion() *semver.Version { return semver.MustParse(vault.get().Settings.LastVersion) diff --git a/internal/vault/settings_test.go b/internal/vault/settings_test.go index 1de09929..3996b9ae 100644 --- a/internal/vault/settings_test.go +++ b/internal/vault/settings_test.go @@ -153,6 +153,20 @@ func TestVault_Settings_ShowAllMail(t *testing.T) { require.Equal(t, false, s.GetShowAllMail()) } +func TestVault_Settings_TelemetryDisabled(t *testing.T) { + // create a new test vault. + s := newVault(t) + + // Check the default show all mail setting. + require.Equal(t, false, s.GetTelemetryDisabled()) + + // Modify the show all mail setting. + require.NoError(t, s.SetTelemetryDisabled(true)) + + // Check the new show all mail setting. + require.Equal(t, true, s.GetTelemetryDisabled()) +} + func TestVault_Settings_Autostart(t *testing.T) { // create a new test vault. s := newVault(t) diff --git a/internal/vault/types_settings.go b/internal/vault/types_settings.go index 68c3e6f1..7139c40a 100644 --- a/internal/vault/types_settings.go +++ b/internal/vault/types_settings.go @@ -36,11 +36,12 @@ type Settings struct { UpdateChannel updater.Channel UpdateRollout float64 - ColorScheme string - ProxyAllowed bool - ShowAllMail bool - Autostart bool - AutoUpdate bool + ColorScheme string + ProxyAllowed bool + ShowAllMail bool + Autostart bool + AutoUpdate bool + TelemetryDisabled bool LastVersion string FirstStart bool @@ -85,11 +86,12 @@ func newDefaultSettings(gluonDir string) Settings { UpdateChannel: updater.DefaultUpdateChannel, UpdateRollout: rand.Float64(), //nolint:gosec - ColorScheme: "", - ProxyAllowed: false, - ShowAllMail: true, - Autostart: true, - AutoUpdate: true, + ColorScheme: "", + ProxyAllowed: false, + ShowAllMail: true, + Autostart: true, + AutoUpdate: true, + TelemetryDisabled: false, LastVersion: "0.0.0", FirstStart: true, diff --git a/tests/bdd_test.go b/tests/bdd_test.go index 90c8f817..da93420f 100644 --- a/tests/bdd_test.go +++ b/tests/bdd_test.go @@ -144,6 +144,8 @@ func TestFeatures(testingT *testing.T) { ctx.Step(`^the user reports a bug$`, s.theUserReportsABug) ctx.Step(`^the user hides All Mail$`, s.theUserHidesAllMail) ctx.Step(`^the user shows All Mail$`, s.theUserShowsAllMail) + ctx.Step(`^the user disables telemetry in bridge settings$`, s.theUserDisablesTelemetryInBridgeSettings) + ctx.Step(`^the user enables telemetry in bridge settings$`, s.theUserEnablesTelemetryInBridgeSettings) ctx.Step(`^bridge sends a connection up event$`, s.bridgeSendsAConnectionUpEvent) ctx.Step(`^bridge sends a connection down event$`, s.bridgeSendsAConnectionDownEvent) ctx.Step(`^bridge sends a deauth event for user "([^"]*)"$`, s.bridgeSendsADeauthEventForUser) diff --git a/tests/bridge_test.go b/tests/bridge_test.go index 40a4667e..ca5b5522 100644 --- a/tests/bridge_test.go +++ b/tests/bridge_test.go @@ -310,6 +310,14 @@ func (s *scenario) theUserShowsAllMail() error { return s.t.bridge.SetShowAllMail(true) } +func (s *scenario) theUserDisablesTelemetryInBridgeSettings() error { + return s.t.bridge.SetTelemetryDisabled(true) +} + +func (s *scenario) theUserEnablesTelemetryInBridgeSettings() error { + return s.t.bridge.SetTelemetryDisabled(false) +} + func (s *scenario) networkPortIsBusy(port int) { if listener, err := net.Listen("tcp", "127.0.0.1:"+strconv.Itoa(port)); err == nil { // we ignore errors. Most likely port is already busy. s.t.dummyListeners = append(s.t.dummyListeners, listener) diff --git a/tests/features/user/telemetry.feature b/tests/features/user/telemetry.feature index 9fd7ff64..12cea910 100644 --- a/tests/features/user/telemetry.feature +++ b/tests/features/user/telemetry.feature @@ -7,6 +7,12 @@ Feature: Bridge send usage metrics Scenario: Telemetry availability - No user Then bridge telemetry feature is enabled + When the user disables telemetry in bridge settings + Then bridge telemetry feature is disabled + When the user enables telemetry in bridge settings + Then bridge telemetry feature is enabled + + Scenario: Telemetry availability - Multi user When the user logs in with username "[user:user1]" and password "password" @@ -16,3 +22,9 @@ Feature: Bridge send usage metrics And user "[user:user2]" finishes syncing When user "[user:user2]" has telemetry set to 0 Then bridge telemetry feature is disabled + When user "[user:user2]" has telemetry set to 1 + Then bridge telemetry feature is enabled + When the user disables telemetry in bridge settings + Then bridge telemetry feature is disabled + When the user enables telemetry in bridge settings + Then bridge telemetry feature is enabled \ No newline at end of file From ad4e853a8af9fc67d0a55ad51221933df6bcfaaa Mon Sep 17 00:00:00 2001 From: Xavier Michelon Date: Thu, 20 Apr 2023 07:53:54 +0200 Subject: [PATCH 37/54] feat(GODT-2555): fixed minor issue spotted during review. --- internal/bridge/bridge.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/bridge/bridge.go b/internal/bridge/bridge.go index 4a9efa1e..9cf32662 100644 --- a/internal/bridge/bridge.go +++ b/internal/bridge/bridge.go @@ -480,13 +480,13 @@ func (bridge *Bridge) Close(ctx context.Context) { } func (bridge *Bridge) ComputeTelemetry() bool { + if bridge.GetTelemetryDisabled() { + return false + } + var telemetry = true safe.RLock(func() { - if bridge.GetTelemetryDisabled() { - telemetry = false - return - } for _, user := range bridge.users { telemetry = telemetry && user.IsTelemetryEnabled(context.Background()) } From 95741c6d6362da1cda72bbeec6f2d2c5ed9c5334 Mon Sep 17 00:00:00 2001 From: Xavier Michelon Date: Thu, 20 Apr 2023 09:01:57 +0200 Subject: [PATCH 38/54] fix(GODT-2581): Update outdated link to bridge homepage in CLI 'manual' command. --- internal/frontend/cli/system.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/frontend/cli/system.go b/internal/frontend/cli/system.go index 956523f5..1290d0fa 100644 --- a/internal/frontend/cli/system.go +++ b/internal/frontend/cli/system.go @@ -40,7 +40,7 @@ func (f *frontendCLI) printLogDir(c *ishell.Context) { } func (f *frontendCLI) printManual(c *ishell.Context) { - f.Println("More instructions about the Bridge can be found at\n\n https://protonmail.com/bridge") + f.Println("More instructions about the Bridge can be found at\n\n https://proton.me/mail/bridge") } func (f *frontendCLI) printCredits(c *ishell.Context) { From 3b297fa37bf5eff3cb598809c1482179b98ce3a8 Mon Sep 17 00:00:00 2001 From: Xavier Michelon Date: Thu, 20 Apr 2023 10:40:19 +0200 Subject: [PATCH 39/54] feat(GODT-2580): updated link to support website in GUI. --- internal/frontend/bridge-gui/bridge-gui/qml/HelpView.qml | 2 +- .../bridge-gui/bridge-gui/qml/Notifications/Notifications.qml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/HelpView.qml b/internal/frontend/bridge-gui/bridge-gui/qml/HelpView.qml index 432c48af..d4ad546a 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/HelpView.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/HelpView.qml @@ -41,7 +41,7 @@ SettingsView { actionIcon: "/qml/icons/ic-external-link.svg" description: qsTr("Get help setting up your client with our instructions and FAQs.") type: SettingsItem.PrimaryButton - onClicked: {Qt.openUrlExternally("https://proton.me/support/mail")} + onClicked: {Qt.openUrlExternally("https://proton.me/support/bridge")} Layout.fillWidth: true } diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/Notifications/Notifications.qml b/internal/frontend/bridge-gui/bridge-gui/qml/Notifications/Notifications.qml index 36886073..f13642b7 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/Notifications/Notifications.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/Notifications/Notifications.qml @@ -988,7 +988,7 @@ QtObject { type: Notification.NotificationType.Danger group: Notifications.Group.Dialogs | Notifications.Group.Configuration - property var supportLink: "https://proton.me/support/mail" + property var supportLink: "https://proton.me/support/bridge" Connections { From ce5a559926e947f43c34977cfe3c8974b9b819de Mon Sep 17 00:00:00 2001 From: Xavier Michelon Date: Fri, 21 Apr 2023 10:20:32 +0200 Subject: [PATCH 40/54] feat(GODT-2586): Two-columns layout for account details. --- .../bridge-gui/bridge-gui/qml/AccountView.qml | 184 +++++++++--------- .../bridge-gui/qml/Configuration.qml | 2 - .../bridge-gui/bridge-gui/qml/MainWindow.qml | 19 +- 3 files changed, 97 insertions(+), 108 deletions(-) diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/AccountView.qml b/internal/frontend/bridge-gui/bridge-gui/qml/AccountView.qml index 7466cbcd..fa9702a8 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/AccountView.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/AccountView.qml @@ -27,67 +27,55 @@ Item { property var notifications property var user - signal showSignIn() + signal showSignIn + signal showSetupGuide(var user, string address) - property int _leftMargin: 64 - property int _rightMargin: 64 + property int _contentWidth: 640 property int _topMargin: 32 - property int _detailsTopMargin: 25 - property int _bottomMargin: 12 + property int _detailsMargin: 25 property int _spacing: 20 - property int _lineWidth: 1 - - ScrollView { - id: scrollView - clip: true + property int _lineThickness: 1 + property bool _connected: root.user ? root.user.state === EUserState.Connected : false + Rectangle { anchors.fill: parent - Component.onCompleted: contentItem.boundsBehavior = Flickable.StopAtBounds // Disable the springy effect when scroll reaches top/bottom. + color: root.colorScheme.background_weak - Item { - // can't use parent here because parent is not ScrollView (Flickable inside contentItem inside ScrollView) - width: scrollView.availableWidth - height: scrollView.availableHeight - - implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin - // do not set implicitWidth because implicit width of ColumnLayout will be equal to maximum implicit width of - // internal items. And if one of internal items would be a Text or Label - implicit width of those is always - // equal to non-wrapped text (i.e. one line only). That will lead to enabling horizontal scroll when not needed - implicitWidth: width + ScrollView { + id: scrollView + anchors.fill: parent + Component.onCompleted: contentItem.boundsBehavior = Flickable.StopAtBounds ColumnLayout { + id: topLevelColumnLayout + anchors.fill: parent spacing: 0 - anchors.fill: parent - Rectangle { - id: topRectangle + id: topArea color: root.colorScheme.background_norm - - implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin - implicitWidth: children[0].implicitWidth + children[0].anchors.leftMargin + children[0].anchors.rightMargin - + clip: true Layout.fillWidth: true + implicitHeight: childrenRect.height ColumnLayout { - spacing: root._spacing + id: topLayout + width: _contentWidth + anchors.horizontalCenter: parent.horizontalCenter + spacing: _spacing - anchors.fill: parent - anchors.leftMargin: root._leftMargin - anchors.rightMargin: root._rightMargin - anchors.topMargin: root._topMargin - anchors.bottomMargin: root._bottomMargin - - RowLayout { // account delegate with action buttons + RowLayout { + // account delegate with action buttons Layout.fillWidth: true + Layout.topMargin: _topMargin AccountDelegate { Layout.fillWidth: true colorScheme: root.colorScheme user: root.user type: AccountDelegate.LargeView - enabled: root.user ? (root.user.state === EUserState.Connected) : false + enabled: _connected } Button { @@ -95,10 +83,11 @@ Item { colorScheme: root.colorScheme text: qsTr("Sign out") secondary: true - visible: root.user ? (root.user.state === EUserState.Connected) : false + visible: _connected onClicked: { - if (!root.user) return - root.user.logout() + if (!root.user) + return; + root.user.logout(); } } @@ -109,8 +98,9 @@ Item { secondary: true visible: root.user ? (root.user.state === EUserState.SignedOut) : false onClicked: { - if (!root.user) return - root.showSignIn() + if (!root.user) + return; + root.showSignIn(); } } @@ -120,8 +110,9 @@ Item { icon.source: "/qml/icons/ic-trash.svg" secondary: true onClicked: { - if (!root.user) return - root.notifications.askDeleteAccount(root.user) + if (!root.user) + return; + root.notifications.askDeleteAccount(root.user); } visible: root.user ? root.user.state !== EUserState.Locked : false } @@ -129,7 +120,7 @@ Item { Rectangle { Layout.fillWidth: true - height: root._lineWidth + height: root._lineThickness color: root.colorScheme.border_weak } @@ -139,12 +130,12 @@ Item { actionText: qsTr("Configure") description: qsTr("Using the mailbox details below (re)configure your client.") type: SettingsItem.Button - enabled: root.user ? root.user.state === EUserState.Connected : false - visible: root.user ? !root.user.splitMode || root.user.addresses.length==1 : false + visible: _connected && (!root.user.splitMode) || (root.user.addresses.length === 1) showSeparator: splitMode.visible onClicked: { - if (!root.user) return - root.showSetupGuide(root.user, user.addresses[0]) + if (!root.user) + return; + root.showSetupGuide(root.user, user.addresses[0]); } Layout.fillWidth: true @@ -157,15 +148,14 @@ Item { description: qsTr("Setup multiple email addresses individually.") type: SettingsItem.Toggle checked: root.user ? root.user.splitMode : false - visible: root.user ? root.user.addresses.length > 1 : false - enabled: root.user ? (root.user.state === EUserState.Connected) : false + visible: _connected && root.user.addresses.length > 1 showSeparator: addressSelector.visible onClicked: { - if (!splitMode.checked){ - root.notifications.askEnableSplitMode(user) + if (!splitMode.checked) { + root.notifications.askEnableSplitMode(user); } else { - addressSelector.currentIndex = 0 - root.user.toggleSplitMode(!splitMode.checked) + addressSelector.currentIndex = 0; + root.user.toggleSplitMode(!splitMode.checked); } } @@ -174,8 +164,8 @@ Item { RowLayout { Layout.fillWidth: true - enabled: root.user ? (root.user.state === EUserState.Connected) : false - visible: root.user ? root.user.splitMode : false + Layout.bottomMargin: _spacing + visible: _connected && root.user.splitMode ComboBox { id: addressSelector @@ -189,60 +179,68 @@ Item { text: qsTr("Configure") secondary: true onClicked: { - if (!root.user) return - root.showSetupGuide(root.user, addressSelector.displayText) + if (!root.user) + return; + root.showSetupGuide(root.user, addressSelector.displayText); } } } + + Rectangle { + height: 0 + } // just for some extra space before separator } } Rectangle { + id: bottomArea + Layout.fillWidth: true + implicitHeight: bottomLayout.implicitHeight color: root.colorScheme.background_weak - implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin - implicitWidth: children[0].implicitWidth + children[0].anchors.leftMargin + children[0].anchors.rightMargin - - Layout.fillWidth: true - ColumnLayout { - id: configuration - - anchors.fill: parent - anchors.leftMargin: root._leftMargin - anchors.rightMargin: root._rightMargin - anchors.topMargin: root._detailsTopMargin - anchors.bottomMargin: root._spacing - - spacing: root._spacing - visible: root.user ? (root.user.state === EUserState.Connected) : false - - property string currentAddress: addressSelector.displayText + id: bottomLayout + width: _contentWidth + anchors.horizontalCenter: parent.horizontalCenter + spacing: _spacing + visible: _connected Label { + Layout.topMargin: _detailsMargin colorScheme: root.colorScheme text: qsTr("Mailbox details") type: Label.Body_semibold } - Configuration { - colorScheme: root.colorScheme - title: qsTr("IMAP") - hostname: Backend.hostname - port: Backend.imapPort.toString() - username: configuration.currentAddress - password: root.user ? root.user.password : "" - security : Backend.useSSLForIMAP ? "SSL" : "STARTTLS" - } + RowLayout { + id: configuration + spacing: _spacing + Layout.fillWidth: true + Layout.fillHeight: true - Configuration { - colorScheme: root.colorScheme - title: qsTr("SMTP") - hostname : Backend.hostname - port : Backend.smtpPort.toString() - username : configuration.currentAddress - password : root.user ? root.user.password : "" - security : Backend.useSSLForSMTP ? "SSL" : "STARTTLS" + property string currentAddress: addressSelector.displayText + + Configuration { + Layout.fillWidth: true + colorScheme: root.colorScheme + title: qsTr("IMAP") + hostname: Backend.hostname + port: Backend.imapPort.toString() + username: configuration.currentAddress + password: root.user ? root.user.password : "" + security: Backend.useSSLForIMAP ? "SSL" : "STARTTLS" + } + + Configuration { + Layout.fillWidth: true + colorScheme: root.colorScheme + title: qsTr("SMTP") + hostname: Backend.hostname + port: Backend.smtpPort.toString() + username: configuration.currentAddress + password: root.user ? root.user.password : "" + security: Backend.useSSLForSMTP ? "SSL" : "STARTTLS" + } } } } diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/Configuration.qml b/internal/frontend/bridge-gui/bridge-gui/qml/Configuration.qml index 1ba9ebe4..84121e81 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/Configuration.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/Configuration.qml @@ -61,8 +61,6 @@ Rectangle { type: Label.Body_semibold } - Item{} - ConfigurationItem{ colorScheme: root.colorScheme; label: qsTr("Hostname") ; value: root.hostname } ConfigurationItem{ colorScheme: root.colorScheme; label: qsTr("Port") ; value: root.port } ConfigurationItem{ colorScheme: root.colorScheme; label: qsTr("Username") ; value: root.username } diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/MainWindow.qml b/internal/frontend/bridge-gui/bridge-gui/qml/MainWindow.qml index 491206ad..877eaf9f 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/MainWindow.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/MainWindow.qml @@ -28,25 +28,18 @@ import "tests" ApplicationWindow { id: root - - width: 960 - height: 576 - + colorScheme: ProtonStyle.currentStyle visible: true - minimumHeight: contentLayout.implicitHeight - minimumWidth: contentLayout.implicitWidth - colorScheme: ProtonStyle.currentStyle + property int _defaultWidth: 1080 + property int _defaultHeight: 780 + width: _defaultWidth + height: _defaultHeight + minimumWidth: _defaultWidth property var notifications - // This is needed because on MacOS if first window shown is not transparent - - // all other windows of application will not have transparent background (black - // instead of transparency). In our case that mean that if MainWindow will be - // shown before StatusWindow - StatusWindow will not have transparent corners. - color: "transparent" - // show Setup Guide on every new user Connections { target: Backend.users From fed503501d49a02eeb1333a917b2c784a659da92 Mon Sep 17 00:00:00 2001 From: Jakub Date: Thu, 20 Apr 2023 15:24:16 +0200 Subject: [PATCH 41/54] feat(GODT-2575): Add dev info to cookies. --- internal/app/app.go | 24 ++++++++++++ internal/bridge/api_qa.go | 9 +++++ internal/sentry/lang_default.go | 32 ++++++++++++++++ internal/sentry/lang_windows.go | 67 +++++++++++++++++++++++++++++++++ internal/sentry/reporter.go | 15 +++++--- 5 files changed, 142 insertions(+), 5 deletions(-) create mode 100644 internal/sentry/lang_default.go create mode 100644 internal/sentry/lang_windows.go diff --git a/internal/app/app.go b/internal/app/app.go index 3da35193..a2c1cb46 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -22,6 +22,7 @@ import ( "math/rand" "net/http" "net/http/cookiejar" + "net/url" "os" "path/filepath" "runtime" @@ -35,6 +36,7 @@ import ( "github.com/ProtonMail/proton-bridge/v3/internal/crash" "github.com/ProtonMail/proton-bridge/v3/internal/events" "github.com/ProtonMail/proton-bridge/v3/internal/focus" + "github.com/ProtonMail/proton-bridge/v3/internal/frontend/theme" "github.com/ProtonMail/proton-bridge/v3/internal/locations" "github.com/ProtonMail/proton-bridge/v3/internal/logging" "github.com/ProtonMail/proton-bridge/v3/internal/sentry" @@ -426,6 +428,10 @@ func withCookieJar(vault *vault.Vault, fn func(http.CookieJar) error) error { return fmt.Errorf("could not create cookie jar: %w", err) } + if err := setDeviceCookies(persister); err != nil { + return fmt.Errorf("could not set device cookies: %w", err) + } + // Persist the cookies to the vault when we close. defer func() { logrus.Debug("Persisting cookies") @@ -437,3 +443,21 @@ func withCookieJar(vault *vault.Vault, fn func(http.CookieJar) error) error { return fn(persister) } + +func setDeviceCookies(jar *cookies.Jar) error { + url, err := url.Parse(constants.APIHost) + if err != nil { + return err + } + + for name, value := range map[string]string{ + "hhn": sentry.GetProtectedHostname(), + "tz": sentry.GetTimeZone(), + "lng": sentry.GetSystemLang(), + "clr": string(theme.DefaultTheme()), + } { + jar.SetCookies(url, []*http.Cookie{{Name: name, Value: value, Secure: true}}) + } + + return nil +} diff --git a/internal/bridge/api_qa.go b/internal/bridge/api_qa.go index db342811..6bdcd6d4 100644 --- a/internal/bridge/api_qa.go +++ b/internal/bridge/api_qa.go @@ -20,6 +20,7 @@ package bridge import ( + "crypto/tls" "net/http" "os" @@ -36,6 +37,14 @@ func newAPIOptions( transport http.RoundTripper, panicHandler async.PanicHandler, ) []proton.Option { + + if allow := os.Getenv("BRIDGE_ALLOW_PROXY"); allow != "" { + transport = &http.Transport{ + Proxy: http.ProxyFromEnvironment, + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + } + } + opt := defaultAPIOptions(apiURL, version, cookieJar, transport, panicHandler) if host := os.Getenv("BRIDGE_API_HOST"); host != "" { diff --git a/internal/sentry/lang_default.go b/internal/sentry/lang_default.go new file mode 100644 index 00000000..a0ae29ec --- /dev/null +++ b/internal/sentry/lang_default.go @@ -0,0 +1,32 @@ +// Copyright (c) 2023 Proton AG +// +// This file is part of Proton Mail 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 . + +//go:build !windows +// +build !windows + +package sentry + +import "os" + +func GetSystemLang() string { + lang := os.Getenv("LC_ALL") + if lang == "" { + lang = os.Getenv("LANG") + } + + return lang +} diff --git a/internal/sentry/lang_windows.go b/internal/sentry/lang_windows.go new file mode 100644 index 00000000..55abba85 --- /dev/null +++ b/internal/sentry/lang_windows.go @@ -0,0 +1,67 @@ +// Copyright (c) 2023 Proton AG +// +// This file is part of Proton Mail 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 . + +//go:build windows +// +build windows + +package sentry + +import ( + "syscall" + "unsafe" +) + +const ( + defaultLocaleUser = "GetUserDefaultLocaleName" // https://learn.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getuserdefaultlocalename + defaultLocaleSystem = "GetSystemDefaultLocaleName" // https://learn.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getsystemdefaultlocalename + localeNameMaxLength = 85 // https://learn.microsoft.com/en-us/windows/win32/intl/locale-name-constants +) + +func getLocale(dll *syscall.DLL, procName string) (string, error) { + proc, err := dll.FindProc(procName) + if err != nil { + return "errProc", err + } + + b := make([]uint16, localeNameMaxLength) + + r, _, err := proc.Call(uintptr(unsafe.Pointer(&b[0])), uintptr(localeNameMaxLength)) + if r == 0 || err != nil { + return "errCall", err + } + + return syscall.UTF16ToString(b), nil +} + +func GetSystemLang() string { + dll, err := syscall.LoadDLL("kernel32") + if err != nil { + return "errDll" + } + + defer func() { + _ = dll.Release() + }() + + if lang, err := getLocale(dll, defaultLocaleUser); err == nil { + return lang + } + + lang, _ := getLocale(dll, defaultLocaleSystem) + + return lang +} diff --git a/internal/sentry/reporter.go b/internal/sentry/reporter.go index 055e55b7..1ceb084c 100644 --- a/internal/sentry/reporter.go +++ b/internal/sentry/reporter.go @@ -18,7 +18,6 @@ package sentry import ( - "crypto/sha256" "errors" "fmt" "log" @@ -29,6 +28,7 @@ import ( "github.com/Masterminds/semver/v3" "github.com/ProtonMail/gluon/reporter" "github.com/ProtonMail/proton-bridge/v3/internal/constants" + "github.com/ProtonMail/proton-bridge/v3/pkg/algo" "github.com/ProtonMail/proton-bridge/v3/pkg/restarter" "github.com/getsentry/sentry-go" "github.com/sirupsen/logrus" @@ -50,7 +50,7 @@ func init() { //nolint:gochecknoinits Release: constants.AppVersion(appVersion), BeforeSend: EnhanceSentryEvent, Transport: sentrySyncTransport, - ServerName: getProtectedHostname(), + ServerName: GetProtectedHostname(), Environment: constants.BuildEnv, MaxBreadcrumbs: 50, } @@ -61,7 +61,7 @@ func init() { //nolint:gochecknoinits sentry.ConfigureScope(func(scope *sentry.Scope) { scope.SetFingerprint([]string{"{{ default }}"}) - scope.SetUser(sentry.User{ID: getProtectedHostname()}) + scope.SetUser(sentry.User{ID: GetProtectedHostname()}) }) sentry.Logger = log.New( @@ -81,12 +81,17 @@ type Identifier interface { GetUserAgent() string } -func getProtectedHostname() string { +func GetProtectedHostname() string { hostname, err := os.Hostname() if err != nil { return "Unknown" } - return fmt.Sprintf("%x", sha256.Sum256([]byte(hostname))) + return algo.HashBase64SHA256(hostname) +} + +func GetTimeZone() string { + zone, offset := time.Now().Zone() + return fmt.Sprintf("%s%+d", zone, offset/3600) } // NewReporter creates new sentry reporter with appName and appVersion to report. From 6ddaa94bc0182bab340b8f6ec8e421218c5ab12f Mon Sep 17 00:00:00 2001 From: Xavier Michelon Date: Mon, 24 Apr 2023 17:05:07 +0200 Subject: [PATCH 42/54] fix(GODT-2589): update BUILDS.md. --- BUILDS.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/BUILDS.md b/BUILDS.md index 8f43485c..eb4abc7a 100644 --- a/BUILDS.md +++ b/BUILDS.md @@ -6,9 +6,12 @@ * Go 1.18 * Bash with basic build utils: make, gcc, sed, find, grep, ... - For Windows, it is recommended to use MinGW 64bit shell from [MSYS2](https://www.msys2.org/) -* GCC (linux), msvc (windows) or Xcode (macOS) -* Windres (windows) -* libglvnd and libsecret development files (linux) +* GCC (Linux), msvc (Windows) or Xcode (macOS) +* Windres (Windows) +* libglvnd and libsecret development files (Linux) +* pkg-config (Linux) +* cmake, ninja-build and Qt 6 are required to build the graphical user interface. On Linux, +the Mesa OpenGL development files are also needed. To enable the sending of crash reports using Sentry please set the `DSN_SENTRY` environment variable with the client key of your sentry project before build. From 0f621d0aadc1a55161f5a0d1cb7c637ba871a959 Mon Sep 17 00:00:00 2001 From: Romain LE JEUNE Date: Tue, 18 Apr 2023 08:49:47 +0200 Subject: [PATCH 43/54] feat(GODT-2552): Init telemetry heartbeat. --- internal/bridge/bridge.go | 25 ++--- internal/bridge/heartbeat.go | 67 +++++++++++++ internal/bridge/settings.go | 26 +++++ internal/bridge/user.go | 12 +++ internal/telemetry/heartbeat.go | 144 +++++++++++++++++++++++++++ internal/telemetry/heartbeat_type.go | 64 ++++++++++++ pkg/keychain/helper_darwin.go | 2 +- pkg/keychain/helper_linux.go | 6 +- pkg/keychain/helper_windows.go | 2 +- pkg/keychain/keychain.go | 6 +- 10 files changed, 330 insertions(+), 24 deletions(-) create mode 100644 internal/bridge/heartbeat.go create mode 100644 internal/telemetry/heartbeat.go create mode 100644 internal/telemetry/heartbeat_type.go diff --git a/internal/bridge/bridge.go b/internal/bridge/bridge.go index 9cf32662..f633cb0b 100644 --- a/internal/bridge/bridge.go +++ b/internal/bridge/bridge.go @@ -41,8 +41,10 @@ import ( "github.com/ProtonMail/proton-bridge/v3/internal/focus" "github.com/ProtonMail/proton-bridge/v3/internal/safe" "github.com/ProtonMail/proton-bridge/v3/internal/sentry" + "github.com/ProtonMail/proton-bridge/v3/internal/telemetry" "github.com/ProtonMail/proton-bridge/v3/internal/user" "github.com/ProtonMail/proton-bridge/v3/internal/vault" + "github.com/ProtonMail/proton-bridge/v3/pkg/keychain" "github.com/bradenaw/juniper/xslices" "github.com/emersion/go-smtp" "github.com/go-resty/resty/v2" @@ -78,6 +80,9 @@ type Bridge struct { updater Updater installCh chan installJob + // heartbeat is the telemetry heartbeat for metrics. + heartbeat telemetry.Heartbeat + // curVersion is the current version of the bridge, // newVersion is the version that was installed by the updater. curVersion *semver.Version @@ -278,6 +283,8 @@ func newBridge( updater: updater, installCh: make(chan installJob), + heartbeat: telemetry.NewHeartbeat(1143, 1025, gluonCacheDir, keychain.DefaultHelper), + curVersion: curVersion, newVersion: curVersion, newVersionLock: safe.NewRWMutex(), @@ -423,6 +430,8 @@ func (bridge *Bridge) init(tlsReporter TLSReporter) error { }) }) + // init telemetry + bridge.initHeartbeat() return nil } @@ -479,22 +488,6 @@ func (bridge *Bridge) Close(ctx context.Context) { bridge.watchers = nil } -func (bridge *Bridge) ComputeTelemetry() bool { - if bridge.GetTelemetryDisabled() { - return false - } - - var telemetry = true - - safe.RLock(func() { - for _, user := range bridge.users { - telemetry = telemetry && user.IsTelemetryEnabled(context.Background()) - } - }, bridge.usersLock) - - return telemetry -} - func (bridge *Bridge) publish(event events.Event) { bridge.watchersLock.RLock() defer bridge.watchersLock.RUnlock() diff --git a/internal/bridge/heartbeat.go b/internal/bridge/heartbeat.go new file mode 100644 index 00000000..c7ed4b20 --- /dev/null +++ b/internal/bridge/heartbeat.go @@ -0,0 +1,67 @@ +// Copyright (c) 2023 Proton AG +// +// This file is part of Proton Mail 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 . + +package bridge + +import ( + "context" + + "github.com/ProtonMail/proton-bridge/v3/internal/safe" + "github.com/ProtonMail/proton-bridge/v3/internal/vault" +) + +func (bridge *Bridge) ComputeTelemetry() bool { + var telemetry = true + + safe.RLock(func() { + for _, user := range bridge.users { + telemetry = telemetry && user.IsTelemetryEnabled(context.Background()) + } + }, bridge.usersLock) + + return telemetry +} + +func (bridge *Bridge) initHeartbeat() { + safe.RLock(func() { + var splitMode = false + for _, user := range bridge.users { + if user.GetAddressMode() == vault.SplitMode { + splitMode = true + break + } + } + bridge.heartbeat.SetNbAccount(len(bridge.users)) + bridge.heartbeat.SetSplitMode(splitMode) + }, bridge.usersLock) + + bridge.heartbeat.SetRollout(bridge.GetUpdateRollout()) + bridge.heartbeat.SetAutoStart(bridge.GetAutostart()) + bridge.heartbeat.SetAutoUpdate(bridge.GetAutoUpdate()) + bridge.heartbeat.SetBeta(bridge.GetUpdateChannel()) + bridge.heartbeat.SetDoh(bridge.GetProxyAllowed()) + bridge.heartbeat.SetShowAllMail(bridge.GetShowAllMail()) + bridge.heartbeat.SetIMAPConnectionMode(bridge.GetIMAPSSL()) + bridge.heartbeat.SetSMTPConnectionMode(bridge.GetSMTPSSL()) + bridge.heartbeat.SetIMAPPort(bridge.GetIMAPPort()) + bridge.heartbeat.SetSMTPPort(bridge.GetSMTPPort()) + bridge.heartbeat.SetCacheLocation(bridge.GetGluonCacheDir()) + if val, err := bridge.GetKeychainApp(); err != nil { + bridge.heartbeat.SetKeyChainPref(val) + } + bridge.heartbeat.SetPrevVersion(bridge.GetLastVersion().String()) +} diff --git a/internal/bridge/settings.go b/internal/bridge/settings.go index 1b38f323..0da85403 100644 --- a/internal/bridge/settings.go +++ b/internal/bridge/settings.go @@ -46,6 +46,8 @@ func (bridge *Bridge) SetKeychainApp(helper string) error { return err } + bridge.heartbeat.SetKeyChainPref(helper) + return vault.SetHelper(vaultDir, helper) } @@ -62,6 +64,8 @@ func (bridge *Bridge) SetIMAPPort(newPort int) error { return err } + bridge.heartbeat.SetIMAPPort(newPort) + return bridge.restartIMAP() } @@ -78,6 +82,8 @@ func (bridge *Bridge) SetIMAPSSL(newSSL bool) error { return err } + bridge.heartbeat.SetIMAPConnectionMode(newSSL) + return bridge.restartIMAP() } @@ -94,6 +100,8 @@ func (bridge *Bridge) SetSMTPPort(newPort int) error { return err } + bridge.heartbeat.SetSMTPPort(newPort) + return bridge.restartSMTP() } @@ -110,6 +118,8 @@ func (bridge *Bridge) SetSMTPSSL(newSSL bool) error { return err } + bridge.heartbeat.SetSMTPConnectionMode(newSSL) + return bridge.restartSMTP() } @@ -141,6 +151,8 @@ func (bridge *Bridge) SetGluonDir(ctx context.Context, newGluonDir string) error } } + bridge.heartbeat.SetCacheLocation(newGluonDir) + gluonDataDir, err := bridge.GetGluonDataDir() if err != nil { return fmt.Errorf("failed to get Gluon Database directory: %w", err) @@ -207,6 +219,8 @@ func (bridge *Bridge) SetProxyAllowed(allowed bool) error { bridge.proxyCtl.DisallowProxy() } + bridge.heartbeat.SetDoh(allowed) + return bridge.vault.SetProxyAllowed(allowed) } @@ -220,6 +234,8 @@ func (bridge *Bridge) SetShowAllMail(show bool) error { user.SetShowAllMail(show) } + bridge.heartbeat.SetShowAllMail(show) + return bridge.vault.SetShowAllMail(show) }, bridge.usersLock) } @@ -233,6 +249,8 @@ func (bridge *Bridge) SetAutostart(autostart bool) error { if err := bridge.vault.SetAutostart(autostart); err != nil { return err } + + bridge.heartbeat.SetAutoStart(autostart) } var err error @@ -253,6 +271,10 @@ func (bridge *Bridge) SetAutostart(autostart bool) error { return err } +func (bridge *Bridge) GetUpdateRollout() float64 { + return bridge.vault.GetUpdateRollout() +} + func (bridge *Bridge) GetAutoUpdate() bool { return bridge.vault.GetAutoUpdate() } @@ -266,6 +288,8 @@ func (bridge *Bridge) SetAutoUpdate(autoUpdate bool) error { return err } + bridge.heartbeat.SetAutoUpdate(autoUpdate) + bridge.goUpdate() return nil @@ -292,6 +316,8 @@ func (bridge *Bridge) SetUpdateChannel(channel updater.Channel) error { return err } + bridge.heartbeat.SetBeta(channel) + bridge.goUpdate() return nil diff --git a/internal/bridge/user.go b/internal/bridge/user.go index 907b8594..4bb2a455 100644 --- a/internal/bridge/user.go +++ b/internal/bridge/user.go @@ -295,6 +295,15 @@ func (bridge *Bridge) SetAddressMode(ctx context.Context, userID string, mode va AddressMode: mode, }) + var splitMode = false + for _, user := range bridge.users { + if user.GetAddressMode() == vault.SplitMode { + splitMode = true + break + } + } + bridge.heartbeat.SetSplitMode(splitMode) + return nil }, bridge.usersLock) } @@ -559,6 +568,7 @@ func (bridge *Bridge) addUserWithVault( // Finally, save the user in the bridge. safe.Lock(func() { bridge.users[apiUser.ID] = user + bridge.heartbeat.SetNbAccount(len(bridge.users)) }, bridge.usersLock) return nil @@ -614,6 +624,8 @@ func (bridge *Bridge) logoutUser(ctx context.Context, user *user.User, withAPI, logrus.WithError(err).Error("Failed to logout user") } + bridge.heartbeat.SetNbAccount(len(bridge.users)) + user.Close() } diff --git a/internal/telemetry/heartbeat.go b/internal/telemetry/heartbeat.go new file mode 100644 index 00000000..5ee58fd2 --- /dev/null +++ b/internal/telemetry/heartbeat.go @@ -0,0 +1,144 @@ +// Copyright (c) 2023 Proton AG +// +// This file is part of Proton Mail 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 . + +package telemetry + +import ( + "github.com/ProtonMail/proton-bridge/v3/internal/updater" +) + +func NewHeartbeat(imapPort, smtpPort int, cacheDir, keychain string) Heartbeat { + heartbeat := Heartbeat{ + Metrics: HeartbeatData{ + MeasurementGroup: "bridge.amy.usage", + Event: "bridge_heartbeat", + }, + DefaultIMAPPort: imapPort, + DefaultSMTPPort: smtpPort, + DefaultCache: cacheDir, + DefaultKeychain: keychain, + } + return heartbeat +} + +func (heartbeat *Heartbeat) SetRollout(val float64) { + heartbeat.Metrics.Values.Rollout = int(val * 100) +} + +func (heartbeat *Heartbeat) SetNbAccount(val int) { + heartbeat.Metrics.Values.NbAccount = val +} + +func (heartbeat *Heartbeat) SetAutoUpdate(val bool) { + if val { + heartbeat.Metrics.Dimensions.AutoUpdate = dimensionON + } else { + heartbeat.Metrics.Dimensions.AutoUpdate = dimensionOFF + } +} + +func (heartbeat *Heartbeat) SetAutoStart(val bool) { + if val { + heartbeat.Metrics.Dimensions.AutoStart = dimensionON + } else { + heartbeat.Metrics.Dimensions.AutoStart = dimensionOFF + } +} + +func (heartbeat *Heartbeat) SetBeta(val updater.Channel) { + if val == updater.EarlyChannel { + heartbeat.Metrics.Dimensions.Beta = dimensionON + } else { + heartbeat.Metrics.Dimensions.Beta = dimensionOFF + } +} + +func (heartbeat *Heartbeat) SetDoh(val bool) { + if val { + heartbeat.Metrics.Dimensions.Doh = dimensionON + } else { + heartbeat.Metrics.Dimensions.Doh = dimensionOFF + } +} + +func (heartbeat *Heartbeat) SetSplitMode(val bool) { + if val { + heartbeat.Metrics.Dimensions.SplitMode = dimensionON + } else { + heartbeat.Metrics.Dimensions.SplitMode = dimensionOFF + } +} + +func (heartbeat *Heartbeat) SetShowAllMail(val bool) { + if val { + heartbeat.Metrics.Dimensions.ShowAllMail = dimensionON + } else { + heartbeat.Metrics.Dimensions.ShowAllMail = dimensionOFF + } +} + +func (heartbeat *Heartbeat) SetIMAPConnectionMode(val bool) { + if val { + heartbeat.Metrics.Dimensions.IMAPConnectionMode = dimensionSSL + } else { + heartbeat.Metrics.Dimensions.IMAPConnectionMode = dimensionStartTLS + } +} + +func (heartbeat *Heartbeat) SetSMTPConnectionMode(val bool) { + if val { + heartbeat.Metrics.Dimensions.SMTPConnectionMode = dimensionSSL + } else { + heartbeat.Metrics.Dimensions.SMTPConnectionMode = dimensionStartTLS + } +} + +func (heartbeat *Heartbeat) SetIMAPPort(val int) { + if val == heartbeat.DefaultIMAPPort { + heartbeat.Metrics.Dimensions.IMAPPort = dimensionDefault + } else { + heartbeat.Metrics.Dimensions.IMAPPort = dimensionCustom + } +} + +func (heartbeat *Heartbeat) SetSMTPPort(val int) { + if val == heartbeat.DefaultSMTPPort { + heartbeat.Metrics.Dimensions.SMTPPort = dimensionDefault + } else { + heartbeat.Metrics.Dimensions.SMTPPort = dimensionCustom + } +} + +func (heartbeat *Heartbeat) SetCacheLocation(val string) { + if val != heartbeat.DefaultCache { + heartbeat.Metrics.Dimensions.CacheLocation = dimensionDefault + } else { + heartbeat.Metrics.Dimensions.CacheLocation = dimensionCustom + } +} + +func (heartbeat *Heartbeat) SetKeyChainPref(val string) { + if val != heartbeat.DefaultKeychain { + heartbeat.Metrics.Dimensions.KeychainPref = dimensionDefault + } else { + heartbeat.Metrics.Dimensions.KeychainPref = dimensionCustom + } +} + +func (heartbeat *Heartbeat) SetPrevVersion(val string) { + heartbeat.Metrics.Dimensions.PrevVersion = val +} diff --git a/internal/telemetry/heartbeat_type.go b/internal/telemetry/heartbeat_type.go new file mode 100644 index 00000000..604c5a38 --- /dev/null +++ b/internal/telemetry/heartbeat_type.go @@ -0,0 +1,64 @@ +// Copyright (c) 2023 Proton AG +// +// This file is part of Proton Mail 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 . + +package telemetry + +const ( + dimensionON = "on" + dimensionOFF = "off" + dimensionDefault = "default" + dimensionCustom = "custom" + dimensionSSL = "ssl" + dimensionStartTLS = "starttls" +) + +type HeartbeatValues struct { + Rollout int `json:"rollout"` + NbAccount int `json:"nb_account"` +} + +type HeartbeatDimensions struct { + AutoUpdate string `json:"auto_update"` + AutoStart string `json:"auto_start"` + Beta string `json:"beta"` + Doh string `json:"doh"` + SplitMode string `json:"split_mode"` + ShowAllMail string `json:"show_all_mail"` + IMAPConnectionMode string `json:"imap_connection_mode"` + SMTPConnectionMode string `json:"smtp_connection_mode"` + IMAPPort string `json:"imap_port"` + SMTPPort string `json:"smtp_port"` + CacheLocation string `json:"cache_location"` + KeychainPref string `json:"keychain_pref"` + PrevVersion string `json:"prev_version"` +} + +type HeartbeatData struct { + MeasurementGroup string + Event string + Values HeartbeatValues + Dimensions HeartbeatDimensions +} + +type Heartbeat struct { + Metrics HeartbeatData + + DefaultIMAPPort int + DefaultSMTPPort int + DefaultCache string + DefaultKeychain string +} diff --git a/pkg/keychain/helper_darwin.go b/pkg/keychain/helper_darwin.go index 2e36c9d2..9faae613 100644 --- a/pkg/keychain/helper_darwin.go +++ b/pkg/keychain/helper_darwin.go @@ -38,7 +38,7 @@ func init() { //nolint:gochecknoinits Helpers[MacOSKeychain] = newMacOSHelper // Use MacOSKeychain by default. - defaultHelper = MacOSKeychain + DefaultHelper = MacOSKeychain } func parseError(original error) error { diff --git a/pkg/keychain/helper_linux.go b/pkg/keychain/helper_linux.go index 3c31736d..ea146fc7 100644 --- a/pkg/keychain/helper_linux.go +++ b/pkg/keychain/helper_linux.go @@ -48,14 +48,14 @@ func init() { //nolint:gochecknoinits Helpers[Pass] = newPassHelper } - defaultHelper = SecretServiceDBus + DefaultHelper = SecretServiceDBus // If Pass is available, use it by default. // Otherwise, if SecretService is available, use it by default. if _, ok := Helpers[Pass]; ok { - defaultHelper = Pass + DefaultHelper = Pass } else if _, ok := Helpers[SecretService]; ok { - defaultHelper = SecretService + DefaultHelper = SecretService } } diff --git a/pkg/keychain/helper_windows.go b/pkg/keychain/helper_windows.go index 6eb2dd06..b4b8ccbd 100644 --- a/pkg/keychain/helper_windows.go +++ b/pkg/keychain/helper_windows.go @@ -31,7 +31,7 @@ func init() { //nolint:gochecknoinits Helpers[WindowsCredentials] = newWinCredHelper // Use WindowsCredentials by default. - defaultHelper = WindowsCredentials + DefaultHelper = WindowsCredentials } func newWinCredHelper(string) (credentials.Helper, error) { diff --git a/pkg/keychain/keychain.go b/pkg/keychain/keychain.go index 251477c9..57b895c9 100644 --- a/pkg/keychain/keychain.go +++ b/pkg/keychain/keychain.go @@ -42,8 +42,8 @@ var ( // Helpers holds all discovered keychain helpers. It is populated in init(). Helpers map[string]helperConstructor //nolint:gochecknoglobals - // defaultHelper is the default helper to use if the user hasn't yet set a preference. - defaultHelper string //nolint:gochecknoglobals + // DefaultHelper is the default helper to use if the user hasn't yet set a preference. + DefaultHelper string //nolint:gochecknoglobals ) // NewKeychain creates a new native keychain. @@ -55,7 +55,7 @@ func NewKeychain(preferred, keychainName string) (*Keychain, error) { // If the preferred keychain is unsupported, fallback to the default one. if _, ok := Helpers[preferred]; !ok { - preferred = defaultHelper + preferred = DefaultHelper } // Load the user's preferred keychain helper. From b250d49af8efbb9865e3d6d54bb0fc422f7eb1c2 Mon Sep 17 00:00:00 2001 From: Romain LE JEUNE Date: Tue, 18 Apr 2023 16:52:15 +0200 Subject: [PATCH 44/54] feat(GODT-2552): Send first heartbeat. --- internal/bridge/bridge.go | 3 +- internal/bridge/heartbeat.go | 50 +++++++++- internal/telemetry/heartbeat.go | 95 +++++++++++-------- .../{heartbeat_type.go => types_heartbeat.go} | 25 ++++- internal/user/user.go | 25 +++++ internal/vault/settings.go | 13 +++ internal/vault/types_settings.go | 6 +- tests/bridge_test.go | 2 +- 8 files changed, 169 insertions(+), 50 deletions(-) rename internal/telemetry/{heartbeat_type.go => types_heartbeat.go} (82%) diff --git a/internal/bridge/bridge.go b/internal/bridge/bridge.go index f633cb0b..2d3ebb16 100644 --- a/internal/bridge/bridge.go +++ b/internal/bridge/bridge.go @@ -283,8 +283,6 @@ func newBridge( updater: updater, installCh: make(chan installJob), - heartbeat: telemetry.NewHeartbeat(1143, 1025, gluonCacheDir, keychain.DefaultHelper), - curVersion: curVersion, newVersion: curVersion, newVersionLock: safe.NewRWMutex(), @@ -309,6 +307,7 @@ func newBridge( } bridge.smtpServer = newSMTPServer(bridge, tlsConfig, logSMTP) + bridge.heartbeat = telemetry.NewHeartbeat(bridge, 1143, 1025, gluonCacheDir, keychain.DefaultHelper) return bridge, nil } diff --git a/internal/bridge/heartbeat.go b/internal/bridge/heartbeat.go index c7ed4b20..da75f3a6 100644 --- a/internal/bridge/heartbeat.go +++ b/internal/bridge/heartbeat.go @@ -19,21 +19,61 @@ package bridge import ( "context" + "encoding/json" + "time" + "github.com/ProtonMail/gluon/reporter" "github.com/ProtonMail/proton-bridge/v3/internal/safe" + "github.com/ProtonMail/proton-bridge/v3/internal/telemetry" "github.com/ProtonMail/proton-bridge/v3/internal/vault" + "github.com/sirupsen/logrus" ) -func (bridge *Bridge) ComputeTelemetry() bool { - var telemetry = true +func (bridge *Bridge) IsTelemetryAvailable() bool { + var flag = true safe.RLock(func() { for _, user := range bridge.users { - telemetry = telemetry && user.IsTelemetryEnabled(context.Background()) + flag = flag && user.IsTelemetryEnabled(context.Background()) } }, bridge.usersLock) - return telemetry + return flag +} + +func (bridge *Bridge) SendHeartbeat(heartbeat *telemetry.HeartbeatData) bool { + data, err := json.Marshal(heartbeat) + if err != nil { + if err := bridge.reporter.ReportMessageWithContext("Cannot parse heartbeat data.", reporter.Context{ + "error": err, + }); err != nil { + logrus.WithError(err).Error("Failed to parse heartbeat data.") + } + return false + } + + var sent = false + + safe.RLock(func() { + if len(bridge.users) > 0 { + for _, user := range bridge.users { + if err := user.SendTelemetry(context.Background(), data); err == nil { + sent = true + break + } + } + } + }, bridge.usersLock) + + return sent +} + +func (bridge *Bridge) GetLastHeartbeatSent() time.Time { + return bridge.vault.GetLastHeartbeatSent() +} + +func (bridge *Bridge) SetLastHeartbeatSent(timestamp time.Time) error { + return bridge.vault.SetLastHeartbeatSent(timestamp) } func (bridge *Bridge) initHeartbeat() { @@ -64,4 +104,6 @@ func (bridge *Bridge) initHeartbeat() { bridge.heartbeat.SetKeyChainPref(val) } bridge.heartbeat.SetPrevVersion(bridge.GetLastVersion().String()) + + bridge.heartbeat.StartSending() } diff --git a/internal/telemetry/heartbeat.go b/internal/telemetry/heartbeat.go index 5ee58fd2..505621c8 100644 --- a/internal/telemetry/heartbeat.go +++ b/internal/telemetry/heartbeat.go @@ -18,127 +18,148 @@ package telemetry import ( + "time" + "github.com/ProtonMail/proton-bridge/v3/internal/updater" + "github.com/sirupsen/logrus" ) -func NewHeartbeat(imapPort, smtpPort int, cacheDir, keychain string) Heartbeat { +func NewHeartbeat(manager HeartbeatManager, imapPort, smtpPort int, cacheDir, keychain string) Heartbeat { heartbeat := Heartbeat{ - Metrics: HeartbeatData{ + log: logrus.WithField("pkg", "telemetry"), + manager: manager, + metrics: HeartbeatData{ MeasurementGroup: "bridge.amy.usage", Event: "bridge_heartbeat", }, - DefaultIMAPPort: imapPort, - DefaultSMTPPort: smtpPort, - DefaultCache: cacheDir, - DefaultKeychain: keychain, + defaultIMAPPort: imapPort, + defaultSMTPPort: smtpPort, + defaultCache: cacheDir, + defaultKeychain: keychain, } return heartbeat } func (heartbeat *Heartbeat) SetRollout(val float64) { - heartbeat.Metrics.Values.Rollout = int(val * 100) + heartbeat.metrics.Values.Rollout = int(val * 100) } func (heartbeat *Heartbeat) SetNbAccount(val int) { - heartbeat.Metrics.Values.NbAccount = val + heartbeat.metrics.Values.NbAccount = val } func (heartbeat *Heartbeat) SetAutoUpdate(val bool) { if val { - heartbeat.Metrics.Dimensions.AutoUpdate = dimensionON + heartbeat.metrics.Dimensions.AutoUpdate = dimensionON } else { - heartbeat.Metrics.Dimensions.AutoUpdate = dimensionOFF + heartbeat.metrics.Dimensions.AutoUpdate = dimensionOFF } } func (heartbeat *Heartbeat) SetAutoStart(val bool) { if val { - heartbeat.Metrics.Dimensions.AutoStart = dimensionON + heartbeat.metrics.Dimensions.AutoStart = dimensionON } else { - heartbeat.Metrics.Dimensions.AutoStart = dimensionOFF + heartbeat.metrics.Dimensions.AutoStart = dimensionOFF } } func (heartbeat *Heartbeat) SetBeta(val updater.Channel) { if val == updater.EarlyChannel { - heartbeat.Metrics.Dimensions.Beta = dimensionON + heartbeat.metrics.Dimensions.Beta = dimensionON } else { - heartbeat.Metrics.Dimensions.Beta = dimensionOFF + heartbeat.metrics.Dimensions.Beta = dimensionOFF } } func (heartbeat *Heartbeat) SetDoh(val bool) { if val { - heartbeat.Metrics.Dimensions.Doh = dimensionON + heartbeat.metrics.Dimensions.Doh = dimensionON } else { - heartbeat.Metrics.Dimensions.Doh = dimensionOFF + heartbeat.metrics.Dimensions.Doh = dimensionOFF } } func (heartbeat *Heartbeat) SetSplitMode(val bool) { if val { - heartbeat.Metrics.Dimensions.SplitMode = dimensionON + heartbeat.metrics.Dimensions.SplitMode = dimensionON } else { - heartbeat.Metrics.Dimensions.SplitMode = dimensionOFF + heartbeat.metrics.Dimensions.SplitMode = dimensionOFF } } func (heartbeat *Heartbeat) SetShowAllMail(val bool) { if val { - heartbeat.Metrics.Dimensions.ShowAllMail = dimensionON + heartbeat.metrics.Dimensions.ShowAllMail = dimensionON } else { - heartbeat.Metrics.Dimensions.ShowAllMail = dimensionOFF + heartbeat.metrics.Dimensions.ShowAllMail = dimensionOFF } } func (heartbeat *Heartbeat) SetIMAPConnectionMode(val bool) { if val { - heartbeat.Metrics.Dimensions.IMAPConnectionMode = dimensionSSL + heartbeat.metrics.Dimensions.IMAPConnectionMode = dimensionSSL } else { - heartbeat.Metrics.Dimensions.IMAPConnectionMode = dimensionStartTLS + heartbeat.metrics.Dimensions.IMAPConnectionMode = dimensionStartTLS } } func (heartbeat *Heartbeat) SetSMTPConnectionMode(val bool) { if val { - heartbeat.Metrics.Dimensions.SMTPConnectionMode = dimensionSSL + heartbeat.metrics.Dimensions.SMTPConnectionMode = dimensionSSL } else { - heartbeat.Metrics.Dimensions.SMTPConnectionMode = dimensionStartTLS + heartbeat.metrics.Dimensions.SMTPConnectionMode = dimensionStartTLS } } func (heartbeat *Heartbeat) SetIMAPPort(val int) { - if val == heartbeat.DefaultIMAPPort { - heartbeat.Metrics.Dimensions.IMAPPort = dimensionDefault + if val == heartbeat.defaultIMAPPort { + heartbeat.metrics.Dimensions.IMAPPort = dimensionDefault } else { - heartbeat.Metrics.Dimensions.IMAPPort = dimensionCustom + heartbeat.metrics.Dimensions.IMAPPort = dimensionCustom } } func (heartbeat *Heartbeat) SetSMTPPort(val int) { - if val == heartbeat.DefaultSMTPPort { - heartbeat.Metrics.Dimensions.SMTPPort = dimensionDefault + if val == heartbeat.defaultSMTPPort { + heartbeat.metrics.Dimensions.SMTPPort = dimensionDefault } else { - heartbeat.Metrics.Dimensions.SMTPPort = dimensionCustom + heartbeat.metrics.Dimensions.SMTPPort = dimensionCustom } } func (heartbeat *Heartbeat) SetCacheLocation(val string) { - if val != heartbeat.DefaultCache { - heartbeat.Metrics.Dimensions.CacheLocation = dimensionDefault + if val != heartbeat.defaultCache { + heartbeat.metrics.Dimensions.CacheLocation = dimensionDefault } else { - heartbeat.Metrics.Dimensions.CacheLocation = dimensionCustom + heartbeat.metrics.Dimensions.CacheLocation = dimensionCustom } } func (heartbeat *Heartbeat) SetKeyChainPref(val string) { - if val != heartbeat.DefaultKeychain { - heartbeat.Metrics.Dimensions.KeychainPref = dimensionDefault + if val != heartbeat.defaultKeychain { + heartbeat.metrics.Dimensions.KeychainPref = dimensionDefault } else { - heartbeat.Metrics.Dimensions.KeychainPref = dimensionCustom + heartbeat.metrics.Dimensions.KeychainPref = dimensionCustom } } func (heartbeat *Heartbeat) SetPrevVersion(val string) { - heartbeat.Metrics.Dimensions.PrevVersion = val + heartbeat.metrics.Dimensions.PrevVersion = val +} + +func (heartbeat *Heartbeat) StartSending() { + if heartbeat.manager.IsTelemetryAvailable() { + lastSent := heartbeat.manager.GetLastHeartbeatSent() + now := time.Now() + if now.Year() >= lastSent.Year() && now.YearDay() > lastSent.YearDay() { + if !heartbeat.manager.SendHeartbeat(&heartbeat.metrics) { + heartbeat.log.WithFields(logrus.Fields{ + "metrics": heartbeat.metrics, + }).Error("Failed to send heartbeat") + } else if err := heartbeat.manager.SetLastHeartbeatSent(now); err != nil { + heartbeat.log.WithError(err).Warn("Cannot save last heartbeat sent to the vault.") + } + } + } } diff --git a/internal/telemetry/heartbeat_type.go b/internal/telemetry/types_heartbeat.go similarity index 82% rename from internal/telemetry/heartbeat_type.go rename to internal/telemetry/types_heartbeat.go index 604c5a38..ed9d2828 100644 --- a/internal/telemetry/heartbeat_type.go +++ b/internal/telemetry/types_heartbeat.go @@ -17,6 +17,12 @@ package telemetry +import ( + "time" + + "github.com/sirupsen/logrus" +) + const ( dimensionON = "on" dimensionOFF = "off" @@ -26,6 +32,13 @@ const ( dimensionStartTLS = "starttls" ) +type HeartbeatManager interface { + IsTelemetryAvailable() bool + SendHeartbeat(heartbeat *HeartbeatData) bool + GetLastHeartbeatSent() time.Time + SetLastHeartbeatSent(time.Time) error +} + type HeartbeatValues struct { Rollout int `json:"rollout"` NbAccount int `json:"nb_account"` @@ -55,10 +68,12 @@ type HeartbeatData struct { } type Heartbeat struct { - Metrics HeartbeatData + log *logrus.Entry + manager HeartbeatManager + metrics HeartbeatData - DefaultIMAPPort int - DefaultSMTPPort int - DefaultCache string - DefaultKeychain string + defaultIMAPPort int + defaultSMTPPort int + defaultCache string + defaultKeychain string } diff --git a/internal/user/user.go b/internal/user/user.go index b3d4cd0b..f82d3fd8 100644 --- a/internal/user/user.go +++ b/internal/user/user.go @@ -607,6 +607,31 @@ func (user *User) IsTelemetryEnabled(ctx context.Context) bool { return settings.Telemetry == proton.SettingEnabled } +// SendTelemetry send telemetry request. +func (user *User) SendTelemetry(ctx context.Context, data []byte) error { + var req proton.SendStatsReq + if err := json.Unmarshal(data, &req); err != nil { + user.log.WithError(err).Warn("Failed to send telemetry.") + if err := user.reporter.ReportMessageWithContext("Failed to send telemetry.", reporter.Context{ + "error": err, + }); err != nil { + logrus.WithError(err).Error("Failed to report telemetry sending error") + } + return err + } + err := user.client.SendDataEvent(ctx, req) + if err != nil { + user.log.WithError(err).Warn("Failed to send telemetry.") + if err := user.reporter.ReportMessageWithContext("Failed to send telemetry.", reporter.Context{ + "error": err, + }); err != nil { + logrus.WithError(err).Error("Failed to report telemetry sending error") + } + return err + } + return nil +} + // initUpdateCh initializes the user's update channels in the given address mode. // It is assumed that user.apiAddrs and user.updateCh are already locked. func (user *User) initUpdateCh(mode vault.AddressMode) { diff --git a/internal/vault/settings.go b/internal/vault/settings.go index e09bdc06..f625825e 100644 --- a/internal/vault/settings.go +++ b/internal/vault/settings.go @@ -20,6 +20,7 @@ package vault import ( "math" "math/rand" + "time" "github.com/Masterminds/semver/v3" "github.com/ProtonMail/proton-bridge/v3/internal/updater" @@ -256,3 +257,15 @@ func (vault *Vault) SetLastUserAgent(userAgent string) error { data.Settings.LastUserAgent = userAgent }) } + +// GetLastHeartbeatSent returns the last time heartbeat was sent. +func (vault *Vault) GetLastHeartbeatSent() time.Time { + return vault.get().Settings.LastHeartbeatSent +} + +// SetLastHeartbeatSent store the last time heartbeat was sent. +func (vault *Vault) SetLastHeartbeatSent(timestamp time.Time) error { + return vault.mod(func(data *Data) { + data.Settings.LastHeartbeatSent = timestamp + }) +} diff --git a/internal/vault/types_settings.go b/internal/vault/types_settings.go index 7139c40a..d6961673 100644 --- a/internal/vault/types_settings.go +++ b/internal/vault/types_settings.go @@ -20,6 +20,7 @@ package vault import ( "math/rand" "runtime" + "time" "github.com/ProtonMail/proton-bridge/v3/internal/updater" "github.com/ProtonMail/proton-bridge/v3/pkg/ports" @@ -50,6 +51,8 @@ type Settings struct { LastUserAgent string + LastHeartbeatSent time.Time + // **WARNING**: These entry can't be removed until they vault has proper migration support. SyncWorkers int SyncAttPool int @@ -100,6 +103,7 @@ func newDefaultSettings(gluonDir string) Settings { SyncWorkers: syncWorkers, SyncAttPool: syncWorkers, - LastUserAgent: DefaultUserAgent, + LastUserAgent: DefaultUserAgent, + LastHeartbeatSent: time.Time{}, } } diff --git a/tests/bridge_test.go b/tests/bridge_test.go index ca5b5522..87c719e9 100644 --- a/tests/bridge_test.go +++ b/tests/bridge_test.go @@ -295,7 +295,7 @@ func (s *scenario) bridgeTelemetryFeatureDisabled() error { } func (s *scenario) checkTelemetry(expect bool) error { - res := s.t.bridge.ComputeTelemetry() + res := s.t.bridge.IsTelemetryAvailable() if res != expect { return fmt.Errorf("expected telemetry feature %v but got %v ", expect, res) } From 67b5e7f96a1e64169be529fc1f11e082e8270bff Mon Sep 17 00:00:00 2001 From: Romain LE JEUNE Date: Tue, 18 Apr 2023 18:59:14 +0200 Subject: [PATCH 45/54] feat(GODT-2552): Add unit test. --- Makefile | 1 + internal/telemetry/heartbeat.go | 10 +-- internal/telemetry/heartbeat_test.go | 97 +++++++++++++++++++++++++++ internal/telemetry/mocks/mocks.go | 92 +++++++++++++++++++++++++ internal/telemetry/types_heartbeat.go | 2 +- 5 files changed, 196 insertions(+), 6 deletions(-) create mode 100644 internal/telemetry/heartbeat_test.go create mode 100644 internal/telemetry/mocks/mocks.go diff --git a/Makefile b/Makefile index 50b250d5..5ea783fd 100644 --- a/Makefile +++ b/Makefile @@ -256,6 +256,7 @@ mocks: mockgen --package mocks github.com/ProtonMail/gluon/async PanicHandler > internal/bridge/mocks/async_mocks.go mockgen --package mocks github.com/ProtonMail/gluon/reporter Reporter > internal/bridge/mocks/gluon_mocks.go mockgen --package mocks github.com/ProtonMail/proton-bridge/v3/internal/updater Downloader,Installer > internal/updater/mocks/mocks.go + mockgen --package mocks github.com/ProtonMail/proton-bridge/v3/internal/telemetry HeartbeatManager > internal/telemetry/mocks/mocks.go lint: gofiles lint-golang lint-license lint-dependencies lint-changelog diff --git a/internal/telemetry/heartbeat.go b/internal/telemetry/heartbeat.go index 505621c8..6b6c7458 100644 --- a/internal/telemetry/heartbeat.go +++ b/internal/telemetry/heartbeat.go @@ -29,7 +29,7 @@ func NewHeartbeat(manager HeartbeatManager, imapPort, smtpPort int, cacheDir, ke log: logrus.WithField("pkg", "telemetry"), manager: manager, metrics: HeartbeatData{ - MeasurementGroup: "bridge.amy.usage", + MeasurementGroup: "bridge.any.usage", Event: "bridge_heartbeat", }, defaultIMAPPort: imapPort, @@ -41,7 +41,7 @@ func NewHeartbeat(manager HeartbeatManager, imapPort, smtpPort int, cacheDir, ke } func (heartbeat *Heartbeat) SetRollout(val float64) { - heartbeat.metrics.Values.Rollout = int(val * 100) + heartbeat.metrics.Dimensions.Rollout = int(val * 100) } func (heartbeat *Heartbeat) SetNbAccount(val int) { @@ -129,7 +129,7 @@ func (heartbeat *Heartbeat) SetSMTPPort(val int) { } func (heartbeat *Heartbeat) SetCacheLocation(val string) { - if val != heartbeat.defaultCache { + if val == heartbeat.defaultCache { heartbeat.metrics.Dimensions.CacheLocation = dimensionDefault } else { heartbeat.metrics.Dimensions.CacheLocation = dimensionCustom @@ -137,7 +137,7 @@ func (heartbeat *Heartbeat) SetCacheLocation(val string) { } func (heartbeat *Heartbeat) SetKeyChainPref(val string) { - if val != heartbeat.defaultKeychain { + if val == heartbeat.defaultKeychain { heartbeat.metrics.Dimensions.KeychainPref = dimensionDefault } else { heartbeat.metrics.Dimensions.KeychainPref = dimensionCustom @@ -152,7 +152,7 @@ func (heartbeat *Heartbeat) StartSending() { if heartbeat.manager.IsTelemetryAvailable() { lastSent := heartbeat.manager.GetLastHeartbeatSent() now := time.Now() - if now.Year() >= lastSent.Year() && now.YearDay() > lastSent.YearDay() { + if now.Year() > lastSent.Year() || (now.Year() == lastSent.Year() && now.YearDay() > lastSent.YearDay()) { if !heartbeat.manager.SendHeartbeat(&heartbeat.metrics) { heartbeat.log.WithFields(logrus.Fields{ "metrics": heartbeat.metrics, diff --git a/internal/telemetry/heartbeat_test.go b/internal/telemetry/heartbeat_test.go new file mode 100644 index 00000000..b08931c0 --- /dev/null +++ b/internal/telemetry/heartbeat_test.go @@ -0,0 +1,97 @@ +// Copyright (c) 2023 Proton AG +// +// This file is part of Proton Mail 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 . + +package telemetry_test + +import ( + "testing" + "time" + + "github.com/ProtonMail/proton-bridge/v3/internal/telemetry" + "github.com/ProtonMail/proton-bridge/v3/internal/telemetry/mocks" + "github.com/golang/mock/gomock" +) + +func TestHeartbeat_default_heartbeat(t *testing.T) { + withHeartbeat(t, 1143, 1025, "/tmp", "defaultKeychain", func(hb *telemetry.Heartbeat, mock *mocks.MockHeartbeatManager) { + data := telemetry.HeartbeatData{ + MeasurementGroup: "bridge.any.usage", + Event: "bridge_heartbeat", + Values: telemetry.HeartbeatValues{ + NbAccount: 1, + }, + Dimensions: telemetry.HeartbeatDimensions{ + AutoUpdate: "on", + AutoStart: "on", + Beta: "off", + Doh: "off", + SplitMode: "off", + ShowAllMail: "off", + IMAPConnectionMode: "ssl", + SMTPConnectionMode: "ssl", + IMAPPort: "default", + SMTPPort: "default", + CacheLocation: "default", + KeychainPref: "default", + PrevVersion: "1.2.3", + Rollout: 10, + }, + } + + mock.EXPECT().IsTelemetryAvailable().Return(true) + mock.EXPECT().GetLastHeartbeatSent().Return(time.Date(2022, 6, 4, 0, 0, 0, 0, time.UTC)) + mock.EXPECT().SendHeartbeat(&data).Return(true) + mock.EXPECT().SetLastHeartbeatSent(gomock.Any()).Return(nil) + + hb.StartSending() + }) +} + +func TestHeartbeat_already_sent_heartbeat(t *testing.T) { + withHeartbeat(t, 1143, 1025, "/tmp", "defaultKeychain", func(hb *telemetry.Heartbeat, mock *mocks.MockHeartbeatManager) { + mock.EXPECT().IsTelemetryAvailable().Return(true) + mock.EXPECT().GetLastHeartbeatSent().Return(time.Now().Truncate(24 * time.Hour)) + + hb.StartSending() + }) +} + +func withHeartbeat(t *testing.T, imap, smtp int, cache, keychain string, tests func(hb *telemetry.Heartbeat, mock *mocks.MockHeartbeatManager)) { + ctl := gomock.NewController(t) + defer ctl.Finish() + + manager := mocks.NewMockHeartbeatManager(ctl) + heartbeat := telemetry.NewHeartbeat(manager, imap, smtp, cache, keychain) + + heartbeat.SetRollout(0.1) + heartbeat.SetNbAccount(1) + heartbeat.SetSplitMode(false) + heartbeat.SetAutoStart(true) + heartbeat.SetAutoUpdate(true) + heartbeat.SetBeta("stable") + heartbeat.SetDoh(false) + heartbeat.SetShowAllMail(false) + heartbeat.SetIMAPConnectionMode(true) + heartbeat.SetSMTPConnectionMode(true) + heartbeat.SetIMAPPort(1143) + heartbeat.SetSMTPPort(1025) + heartbeat.SetCacheLocation("/tmp") + heartbeat.SetKeyChainPref("defaultKeychain") + heartbeat.SetPrevVersion("1.2.3") + + tests(&heartbeat, manager) +} diff --git a/internal/telemetry/mocks/mocks.go b/internal/telemetry/mocks/mocks.go new file mode 100644 index 00000000..be5251e2 --- /dev/null +++ b/internal/telemetry/mocks/mocks.go @@ -0,0 +1,92 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ProtonMail/proton-bridge/v3/internal/telemetry (interfaces: HeartbeatManager) + +// Package mocks is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + time "time" + + telemetry "github.com/ProtonMail/proton-bridge/v3/internal/telemetry" + gomock "github.com/golang/mock/gomock" +) + +// MockHeartbeatManager is a mock of HeartbeatManager interface. +type MockHeartbeatManager struct { + ctrl *gomock.Controller + recorder *MockHeartbeatManagerMockRecorder +} + +// MockHeartbeatManagerMockRecorder is the mock recorder for MockHeartbeatManager. +type MockHeartbeatManagerMockRecorder struct { + mock *MockHeartbeatManager +} + +// NewMockHeartbeatManager creates a new mock instance. +func NewMockHeartbeatManager(ctrl *gomock.Controller) *MockHeartbeatManager { + mock := &MockHeartbeatManager{ctrl: ctrl} + mock.recorder = &MockHeartbeatManagerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockHeartbeatManager) EXPECT() *MockHeartbeatManagerMockRecorder { + return m.recorder +} + +// GetLastHeartbeatSent mocks base method. +func (m *MockHeartbeatManager) GetLastHeartbeatSent() time.Time { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLastHeartbeatSent") + ret0, _ := ret[0].(time.Time) + return ret0 +} + +// GetLastHeartbeatSent indicates an expected call of GetLastHeartbeatSent. +func (mr *MockHeartbeatManagerMockRecorder) GetLastHeartbeatSent() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLastHeartbeatSent", reflect.TypeOf((*MockHeartbeatManager)(nil).GetLastHeartbeatSent)) +} + +// IsTelemetryAvailable mocks base method. +func (m *MockHeartbeatManager) IsTelemetryAvailable() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsTelemetryAvailable") + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsTelemetryAvailable indicates an expected call of IsTelemetryAvailable. +func (mr *MockHeartbeatManagerMockRecorder) IsTelemetryAvailable() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsTelemetryAvailable", reflect.TypeOf((*MockHeartbeatManager)(nil).IsTelemetryAvailable)) +} + +// SendHeartbeat mocks base method. +func (m *MockHeartbeatManager) SendHeartbeat(arg0 *telemetry.HeartbeatData) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SendHeartbeat", arg0) + ret0, _ := ret[0].(bool) + return ret0 +} + +// SendHeartbeat indicates an expected call of SendHeartbeat. +func (mr *MockHeartbeatManagerMockRecorder) SendHeartbeat(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendHeartbeat", reflect.TypeOf((*MockHeartbeatManager)(nil).SendHeartbeat), arg0) +} + +// SetLastHeartbeatSent mocks base method. +func (m *MockHeartbeatManager) SetLastHeartbeatSent(arg0 time.Time) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetLastHeartbeatSent", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetLastHeartbeatSent indicates an expected call of SetLastHeartbeatSent. +func (mr *MockHeartbeatManagerMockRecorder) SetLastHeartbeatSent(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLastHeartbeatSent", reflect.TypeOf((*MockHeartbeatManager)(nil).SetLastHeartbeatSent), arg0) +} diff --git a/internal/telemetry/types_heartbeat.go b/internal/telemetry/types_heartbeat.go index ed9d2828..e41a9c2d 100644 --- a/internal/telemetry/types_heartbeat.go +++ b/internal/telemetry/types_heartbeat.go @@ -40,7 +40,6 @@ type HeartbeatManager interface { } type HeartbeatValues struct { - Rollout int `json:"rollout"` NbAccount int `json:"nb_account"` } @@ -58,6 +57,7 @@ type HeartbeatDimensions struct { CacheLocation string `json:"cache_location"` KeychainPref string `json:"keychain_pref"` PrevVersion string `json:"prev_version"` + Rollout int `json:"rollout"` } type HeartbeatData struct { From d88bee68c6f37bd174e9a98de0f73594abdc0c67 Mon Sep 17 00:00:00 2001 From: Romain LE JEUNE Date: Thu, 20 Apr 2023 21:14:11 +0200 Subject: [PATCH 46/54] feat(GODT-2552): Add functional test. --- internal/app/app.go | 2 + internal/bridge/bridge.go | 4 -- internal/bridge/heartbeat.go | 9 +++- internal/bridge/user.go | 3 ++ internal/telemetry/heartbeat.go | 2 +- internal/telemetry/heartbeat_test.go | 4 +- tests/bdd_test.go | 6 +++ tests/ctx_bridge_test.go | 2 + tests/ctx_heartbeat_test.go | 72 +++++++++++++++++++++++++ tests/ctx_test.go | 38 ++++++------- tests/features/bridge/heartbeat.feature | 47 ++++++++++++++++ tests/heartbeat_test.go | 70 ++++++++++++++++++++++++ 12 files changed, 232 insertions(+), 27 deletions(-) create mode 100644 tests/ctx_heartbeat_test.go create mode 100644 tests/features/bridge/heartbeat.feature create mode 100644 tests/heartbeat_test.go diff --git a/internal/app/app.go b/internal/app/app.go index a2c1cb46..dcd963d1 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -268,6 +268,8 @@ func run(c *cli.Context) error { logrus.Warn("The vault is corrupt and has been wiped") b.PushError(bridge.ErrVaultCorrupt) } + // Start telemetry heartbeat process + b.StartHeartbeat(b) // Run the frontend. return runFrontend(c, crashHandler, restarter, locations, b, eventCh, quitCh, c.Int(flagParentPID)) diff --git a/internal/bridge/bridge.go b/internal/bridge/bridge.go index 2d3ebb16..4af1571f 100644 --- a/internal/bridge/bridge.go +++ b/internal/bridge/bridge.go @@ -44,7 +44,6 @@ import ( "github.com/ProtonMail/proton-bridge/v3/internal/telemetry" "github.com/ProtonMail/proton-bridge/v3/internal/user" "github.com/ProtonMail/proton-bridge/v3/internal/vault" - "github.com/ProtonMail/proton-bridge/v3/pkg/keychain" "github.com/bradenaw/juniper/xslices" "github.com/emersion/go-smtp" "github.com/go-resty/resty/v2" @@ -307,7 +306,6 @@ func newBridge( } bridge.smtpServer = newSMTPServer(bridge, tlsConfig, logSMTP) - bridge.heartbeat = telemetry.NewHeartbeat(bridge, 1143, 1025, gluonCacheDir, keychain.DefaultHelper) return bridge, nil } @@ -429,8 +427,6 @@ func (bridge *Bridge) init(tlsReporter TLSReporter) error { }) }) - // init telemetry - bridge.initHeartbeat() return nil } diff --git a/internal/bridge/heartbeat.go b/internal/bridge/heartbeat.go index da75f3a6..4fc3afcd 100644 --- a/internal/bridge/heartbeat.go +++ b/internal/bridge/heartbeat.go @@ -26,6 +26,7 @@ import ( "github.com/ProtonMail/proton-bridge/v3/internal/safe" "github.com/ProtonMail/proton-bridge/v3/internal/telemetry" "github.com/ProtonMail/proton-bridge/v3/internal/vault" + "github.com/ProtonMail/proton-bridge/v3/pkg/keychain" "github.com/sirupsen/logrus" ) @@ -76,7 +77,9 @@ func (bridge *Bridge) SetLastHeartbeatSent(timestamp time.Time) error { return bridge.vault.SetLastHeartbeatSent(timestamp) } -func (bridge *Bridge) initHeartbeat() { +func (bridge *Bridge) StartHeartbeat(manager telemetry.HeartbeatManager) { + bridge.heartbeat = telemetry.NewHeartbeat(manager, 1143, 1025, bridge.GetGluonCacheDir(), keychain.DefaultHelper) + safe.RLock(func() { var splitMode = false for _, user := range bridge.users { @@ -102,8 +105,10 @@ func (bridge *Bridge) initHeartbeat() { bridge.heartbeat.SetCacheLocation(bridge.GetGluonCacheDir()) if val, err := bridge.GetKeychainApp(); err != nil { bridge.heartbeat.SetKeyChainPref(val) + } else { + bridge.heartbeat.SetKeyChainPref(keychain.DefaultHelper) } bridge.heartbeat.SetPrevVersion(bridge.GetLastVersion().String()) - bridge.heartbeat.StartSending() + bridge.heartbeat.TrySending() } diff --git a/internal/bridge/user.go b/internal/bridge/user.go index 4bb2a455..2c34a878 100644 --- a/internal/bridge/user.go +++ b/internal/bridge/user.go @@ -571,6 +571,9 @@ func (bridge *Bridge) addUserWithVault( bridge.heartbeat.SetNbAccount(len(bridge.users)) }, bridge.usersLock) + // As we need at least one user to send heartbeat, try to send it. + bridge.heartbeat.TrySending() + return nil } diff --git a/internal/telemetry/heartbeat.go b/internal/telemetry/heartbeat.go index 6b6c7458..8d8c8f2d 100644 --- a/internal/telemetry/heartbeat.go +++ b/internal/telemetry/heartbeat.go @@ -148,7 +148,7 @@ func (heartbeat *Heartbeat) SetPrevVersion(val string) { heartbeat.metrics.Dimensions.PrevVersion = val } -func (heartbeat *Heartbeat) StartSending() { +func (heartbeat *Heartbeat) TrySending() { if heartbeat.manager.IsTelemetryAvailable() { lastSent := heartbeat.manager.GetLastHeartbeatSent() now := time.Now() diff --git a/internal/telemetry/heartbeat_test.go b/internal/telemetry/heartbeat_test.go index b08931c0..7c8b4fb1 100644 --- a/internal/telemetry/heartbeat_test.go +++ b/internal/telemetry/heartbeat_test.go @@ -57,7 +57,7 @@ func TestHeartbeat_default_heartbeat(t *testing.T) { mock.EXPECT().SendHeartbeat(&data).Return(true) mock.EXPECT().SetLastHeartbeatSent(gomock.Any()).Return(nil) - hb.StartSending() + hb.TrySending() }) } @@ -66,7 +66,7 @@ func TestHeartbeat_already_sent_heartbeat(t *testing.T) { mock.EXPECT().IsTelemetryAvailable().Return(true) mock.EXPECT().GetLastHeartbeatSent().Return(time.Now().Truncate(24 * time.Hour)) - hb.StartSending() + hb.TrySending() }) } diff --git a/tests/bdd_test.go b/tests/bdd_test.go index da93420f..e560b7a8 100644 --- a/tests/bdd_test.go +++ b/tests/bdd_test.go @@ -231,6 +231,12 @@ func TestFeatures(testingT *testing.T) { ctx.Step(`^SMTP client "([^"]*)" sends RSET$`, s.smtpClientSendsReset) ctx.Step(`^SMTP client "([^"]*)" sends the following message from "([^"]*)" to "([^"]*)":$`, s.smtpClientSendsTheFollowingMessageFromTo) ctx.Step(`^SMTP client "([^"]*)" logs out$`, s.smtpClientLogsOut) + + // ==== TELEMETRY ==== + ctx.Step(`^bridge eventually sends the following heartbeat:$`, s.bridgeEventuallySendsTheFollowingHeartbeat) + ctx.Step(`^bridge needs to send heartbeat$`, s.bridgeNeedsToSendHeartbeat) + ctx.Step(`^bridge do not need to send heartbeat$`, s.bridgeDoNotNeedToSendHeartbeat) + ctx.Step(`^heartbeat is not whitelisted$`, s.heartbeatIsNotwhitelisted) }, Options: &godog.Options{ Format: "pretty", diff --git a/tests/ctx_bridge_test.go b/tests/ctx_bridge_test.go index 92cdf0e1..de4ed616 100644 --- a/tests/ctx_bridge_test.go +++ b/tests/ctx_bridge_test.go @@ -174,6 +174,8 @@ func (t *testCtx) initBridge() (<-chan events.Event, error) { } t.bridge = bridge + t.heartbeat.setBridge(bridge) + bridge.StartHeartbeat(t.heartbeat) return t.events.collectFrom(eventCh), nil } diff --git a/tests/ctx_heartbeat_test.go b/tests/ctx_heartbeat_test.go new file mode 100644 index 00000000..fc543cff --- /dev/null +++ b/tests/ctx_heartbeat_test.go @@ -0,0 +1,72 @@ +package tests + +import ( + "errors" + "testing" + "time" + + "github.com/ProtonMail/proton-bridge/v3/internal/bridge" + "github.com/ProtonMail/proton-bridge/v3/internal/telemetry" + "github.com/stretchr/testify/assert" +) + +type heartbeatRecorder struct { + heartbeat telemetry.HeartbeatData + bridge *bridge.Bridge + reject bool + assert *assert.Assertions +} + +func newHeartbeatRecorder(tb testing.TB) *heartbeatRecorder { + return &heartbeatRecorder{ + heartbeat: telemetry.HeartbeatData{}, + bridge: nil, + reject: false, + assert: assert.New(tb), + } +} + +func (hb *heartbeatRecorder) setBridge(bridge *bridge.Bridge) { + hb.bridge = bridge +} + +func (hb *heartbeatRecorder) GetLastHeartbeatSent() time.Time { + if hb.bridge == nil { + return time.Now() + } + return hb.bridge.GetLastHeartbeatSent() +} + +func (hb *heartbeatRecorder) IsTelemetryAvailable() bool { + if hb.bridge == nil { + return false + } + return hb.bridge.IsTelemetryAvailable() +} + +func (hb *heartbeatRecorder) SendHeartbeat(metrics *telemetry.HeartbeatData) bool { + if hb.bridge == nil { + return false + } + + if len(hb.bridge.GetUserIDs()) == 0 { + return false + } + + if hb.reject { + return false + } + hb.heartbeat = *metrics + return true +} + +func (hb *heartbeatRecorder) SetLastHeartbeatSent(timestamp time.Time) error { + if hb.bridge == nil { + return errors.New("no bridge initialized") + } + return hb.bridge.SetLastHeartbeatSent(timestamp) +} + +func (hb *heartbeatRecorder) rejectSend() { + hb.reject = true +} diff --git a/tests/ctx_test.go b/tests/ctx_test.go index 004ab501..369e865f 100644 --- a/tests/ctx_test.go +++ b/tests/ctx_test.go @@ -122,15 +122,16 @@ func newTestAddr(addrID, email string) *testAddr { type testCtx struct { // These are the objects supporting the test. - dir string - api API - netCtl *proton.NetCtl - locator *locations.Locations - storeKey []byte - version *semver.Version - mocks *bridge.Mocks - events *eventCollector - reporter *reportRecorder + dir string + api API + netCtl *proton.NetCtl + locator *locations.Locations + storeKey []byte + version *semver.Version + mocks *bridge.Mocks + events *eventCollector + reporter *reportRecorder + heartbeat *heartbeatRecorder // bridge holds the bridge app under test. bridge *bridge.Bridge @@ -180,15 +181,16 @@ func newTestCtx(tb testing.TB) *testCtx { dir := tb.TempDir() t := &testCtx{ - dir: dir, - api: newTestAPI(), - netCtl: proton.NewNetCtl(), - locator: locations.New(bridge.NewTestLocationsProvider(dir), "config-name"), - storeKey: []byte("super-secret-store-key"), - version: defaultVersion, - mocks: bridge.NewMocks(tb, defaultVersion, defaultVersion), - events: newEventCollector(), - reporter: newReportRecorder(tb), + dir: dir, + api: newTestAPI(), + netCtl: proton.NewNetCtl(), + locator: locations.New(bridge.NewTestLocationsProvider(dir), "config-name"), + storeKey: []byte("super-secret-store-key"), + version: defaultVersion, + mocks: bridge.NewMocks(tb, defaultVersion, defaultVersion), + events: newEventCollector(), + reporter: newReportRecorder(tb), + heartbeat: newHeartbeatRecorder(tb), userByID: make(map[string]*testUser), userUUIDByName: make(map[string]string), diff --git a/tests/features/bridge/heartbeat.feature b/tests/features/bridge/heartbeat.feature new file mode 100644 index 00000000..a1ce7372 --- /dev/null +++ b/tests/features/bridge/heartbeat.feature @@ -0,0 +1,47 @@ +Feature: Send Telemetry Heartbeat + Background: + Given there exists an account with username "[user:user1]" and password "password" + And bridge starts + + + Scenario: Send at first start - one user + Then bridge telemetry feature is enabled + And bridge needs to send heartbeat + When the user logs in with username "[user:user1]" and password "password" + And user "[user:user1]" finishes syncing + Then bridge eventually sends the following heartbeat: + """ + { + "MeasurementGroup": "bridge.any.usage", + "Event": "bridge_heartbeat", + "Values": { + "nb_account": 1 + }, + "Dimensions": { + "auto_update": "on", + "auto_start": "on", + "beta": "off", + "doh": "off", + "split_mode": "off", + "show_all_mail": "on", + "imap_connection_mode": "starttls", + "smtp_connection_mode": "starttls", + "imap_port": "default", + "smtp_port": "default", + "cache_location": "default", + "keychain_pref": "default", + "prev_version": "0.0.0", + "rollout": 42 + } + } + """ + And bridge do not need to send heartbeat + + Scenario: GroupMeasurement rejected by API + Given heartbeat is not whitelisted + Then bridge telemetry feature is enabled + And bridge needs to send heartbeat + When the user logs in with username "[user:user1]" and password "password" + And user "[user:user1]" finishes syncing + Then bridge needs to send heartbeat + diff --git a/tests/heartbeat_test.go b/tests/heartbeat_test.go new file mode 100644 index 00000000..075f7112 --- /dev/null +++ b/tests/heartbeat_test.go @@ -0,0 +1,70 @@ +package tests + +import ( + "encoding/json" + "errors" + "fmt" + "time" + + "github.com/ProtonMail/proton-bridge/v3/internal/telemetry" + "github.com/cucumber/godog" + "github.com/sirupsen/logrus" +) + +func (s *scenario) bridgeEventuallySendsTheFollowingHeartbeat(text *godog.DocString) error { + return eventually(func() error { + err := s.bridgeSendsTheFollowingHeartbeat(text) + logrus.WithError(err).Trace("Matching eventually") + return err + }) +} + +func (s *scenario) bridgeSendsTheFollowingHeartbeat(text *godog.DocString) error { + var wantHeartbeat telemetry.HeartbeatData + err := json.Unmarshal([]byte(text.Content), &wantHeartbeat) + if err != nil { + return err + } + + return matchHeartbeat(s.t.heartbeat.heartbeat, wantHeartbeat) +} + +func (s *scenario) bridgeNeedsToSendHeartbeat() error { + last := s.t.heartbeat.GetLastHeartbeatSent() + if !isAnotherDay(last, time.Now()) { + return fmt.Errorf("heartbeat already sent at %s", last) + } + return nil +} + +func (s *scenario) bridgeDoNotNeedToSendHeartbeat() error { + last := s.t.heartbeat.GetLastHeartbeatSent() + if isAnotherDay(last, time.Now()) { + return fmt.Errorf("heartbeat needs to be sent - last %s", last) + } + return nil +} + +func (s *scenario) heartbeatIsNotwhitelisted() error { + s.t.heartbeat.rejectSend() + return nil +} + +func matchHeartbeat(have, want telemetry.HeartbeatData) error { + if have == (telemetry.HeartbeatData{}) { + return errors.New("no heartbeat send (yet)") + } + + // Ignore rollout number + want.Dimensions.Rollout = have.Dimensions.Rollout + + if have != want { + return fmt.Errorf("missing heartbeat: have %#v, want %#v", have, want) + } + + return nil +} + +func isAnotherDay(last, now time.Time) bool { + return now.Year() > last.Year() || (now.Year() == last.Year() && now.YearDay() > last.YearDay()) +} From 4adc6d60b97aa7eeebfb6a2e566f24c5ec45826a Mon Sep 17 00:00:00 2001 From: Romain LE JEUNE Date: Thu, 20 Apr 2023 21:43:18 +0200 Subject: [PATCH 47/54] feat(GODT-2552): Fix unit test. --- Makefile | 1 + internal/bridge/bridge_test.go | 3 + internal/bridge/heartbeat.go | 3 + internal/bridge/mocks.go | 7 +- internal/bridge/mocks/telemetry_mocks.go | 92 ++++++++++++++++++++++++ tests/ctx_heartbeat_test.go | 17 +++++ tests/features/user/telemetry.feature | 1 - tests/heartbeat_test.go | 17 +++++ 8 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 internal/bridge/mocks/telemetry_mocks.go diff --git a/Makefile b/Makefile index 5ea783fd..e3587b15 100644 --- a/Makefile +++ b/Makefile @@ -257,6 +257,7 @@ mocks: mockgen --package mocks github.com/ProtonMail/gluon/reporter Reporter > internal/bridge/mocks/gluon_mocks.go mockgen --package mocks github.com/ProtonMail/proton-bridge/v3/internal/updater Downloader,Installer > internal/updater/mocks/mocks.go mockgen --package mocks github.com/ProtonMail/proton-bridge/v3/internal/telemetry HeartbeatManager > internal/telemetry/mocks/mocks.go + cp internal/telemetry/mocks/mocks.go internal/bridge/mocks/telemetry_mocks.go lint: gofiles lint-golang lint-license lint-dependencies lint-changelog diff --git a/internal/bridge/bridge_test.go b/internal/bridge/bridge_test.go index 67615609..65939daa 100644 --- a/internal/bridge/bridge_test.go +++ b/internal/bridge/bridge_test.go @@ -823,6 +823,9 @@ func withBridgeNoMocks( require.NoError(t, err) require.Empty(t, bridge.GetErrors()) + // Start the Heartbeat process. + bridge.StartHeartbeat(mocks.Heartbeat) + // Wait for bridge to finish loading users. waitForEvent(t, eventCh, events.AllUsersLoaded{}) // Wait for bridge to start the IMAP server. diff --git a/internal/bridge/heartbeat.go b/internal/bridge/heartbeat.go index 4fc3afcd..eb37503d 100644 --- a/internal/bridge/heartbeat.go +++ b/internal/bridge/heartbeat.go @@ -32,6 +32,9 @@ import ( func (bridge *Bridge) IsTelemetryAvailable() bool { var flag = true + if bridge.GetTelemetryDisabled() { + return false + } safe.RLock(func() { for _, user := range bridge.users { diff --git a/internal/bridge/mocks.go b/internal/bridge/mocks.go index 6f5c943f..1c7bf934 100644 --- a/internal/bridge/mocks.go +++ b/internal/bridge/mocks.go @@ -24,6 +24,7 @@ type Mocks struct { CrashHandler *mocks.MockPanicHandler Reporter *mocks.MockReporter + Heartbeat *mocks.MockHeartbeatManager } func NewMocks(tb testing.TB, version, minAuto *semver.Version) *Mocks { @@ -39,14 +40,18 @@ func NewMocks(tb testing.TB, version, minAuto *semver.Version) *Mocks { CrashHandler: mocks.NewMockPanicHandler(ctl), Reporter: mocks.NewMockReporter(ctl), + Heartbeat: mocks.NewMockHeartbeatManager(ctl), } // When getting the TLS issue channel, we want to return the test channel. mocks.TLSReporter.EXPECT().GetTLSIssueCh().Return(mocks.TLSIssueCh).AnyTimes() - // This is called at he end of any go-routine: + // This is called at the end of any go-routine: mocks.CrashHandler.EXPECT().HandlePanic(gomock.Any()).AnyTimes() + // this is called at start of heartbeat process. + mocks.Heartbeat.EXPECT().IsTelemetryAvailable().AnyTimes() + return mocks } diff --git a/internal/bridge/mocks/telemetry_mocks.go b/internal/bridge/mocks/telemetry_mocks.go new file mode 100644 index 00000000..be5251e2 --- /dev/null +++ b/internal/bridge/mocks/telemetry_mocks.go @@ -0,0 +1,92 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/ProtonMail/proton-bridge/v3/internal/telemetry (interfaces: HeartbeatManager) + +// Package mocks is a generated GoMock package. +package mocks + +import ( + reflect "reflect" + time "time" + + telemetry "github.com/ProtonMail/proton-bridge/v3/internal/telemetry" + gomock "github.com/golang/mock/gomock" +) + +// MockHeartbeatManager is a mock of HeartbeatManager interface. +type MockHeartbeatManager struct { + ctrl *gomock.Controller + recorder *MockHeartbeatManagerMockRecorder +} + +// MockHeartbeatManagerMockRecorder is the mock recorder for MockHeartbeatManager. +type MockHeartbeatManagerMockRecorder struct { + mock *MockHeartbeatManager +} + +// NewMockHeartbeatManager creates a new mock instance. +func NewMockHeartbeatManager(ctrl *gomock.Controller) *MockHeartbeatManager { + mock := &MockHeartbeatManager{ctrl: ctrl} + mock.recorder = &MockHeartbeatManagerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockHeartbeatManager) EXPECT() *MockHeartbeatManagerMockRecorder { + return m.recorder +} + +// GetLastHeartbeatSent mocks base method. +func (m *MockHeartbeatManager) GetLastHeartbeatSent() time.Time { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLastHeartbeatSent") + ret0, _ := ret[0].(time.Time) + return ret0 +} + +// GetLastHeartbeatSent indicates an expected call of GetLastHeartbeatSent. +func (mr *MockHeartbeatManagerMockRecorder) GetLastHeartbeatSent() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLastHeartbeatSent", reflect.TypeOf((*MockHeartbeatManager)(nil).GetLastHeartbeatSent)) +} + +// IsTelemetryAvailable mocks base method. +func (m *MockHeartbeatManager) IsTelemetryAvailable() bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "IsTelemetryAvailable") + ret0, _ := ret[0].(bool) + return ret0 +} + +// IsTelemetryAvailable indicates an expected call of IsTelemetryAvailable. +func (mr *MockHeartbeatManagerMockRecorder) IsTelemetryAvailable() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsTelemetryAvailable", reflect.TypeOf((*MockHeartbeatManager)(nil).IsTelemetryAvailable)) +} + +// SendHeartbeat mocks base method. +func (m *MockHeartbeatManager) SendHeartbeat(arg0 *telemetry.HeartbeatData) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SendHeartbeat", arg0) + ret0, _ := ret[0].(bool) + return ret0 +} + +// SendHeartbeat indicates an expected call of SendHeartbeat. +func (mr *MockHeartbeatManagerMockRecorder) SendHeartbeat(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SendHeartbeat", reflect.TypeOf((*MockHeartbeatManager)(nil).SendHeartbeat), arg0) +} + +// SetLastHeartbeatSent mocks base method. +func (m *MockHeartbeatManager) SetLastHeartbeatSent(arg0 time.Time) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SetLastHeartbeatSent", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// SetLastHeartbeatSent indicates an expected call of SetLastHeartbeatSent. +func (mr *MockHeartbeatManagerMockRecorder) SetLastHeartbeatSent(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetLastHeartbeatSent", reflect.TypeOf((*MockHeartbeatManager)(nil).SetLastHeartbeatSent), arg0) +} diff --git a/tests/ctx_heartbeat_test.go b/tests/ctx_heartbeat_test.go index fc543cff..babf4f9e 100644 --- a/tests/ctx_heartbeat_test.go +++ b/tests/ctx_heartbeat_test.go @@ -1,3 +1,20 @@ +// Copyright (c) 2023 Proton AG +// +// This file is part of Proton Mail 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 . + package tests import ( diff --git a/tests/features/user/telemetry.feature b/tests/features/user/telemetry.feature index 12cea910..ff98029b 100644 --- a/tests/features/user/telemetry.feature +++ b/tests/features/user/telemetry.feature @@ -13,7 +13,6 @@ Feature: Bridge send usage metrics Then bridge telemetry feature is enabled - Scenario: Telemetry availability - Multi user When the user logs in with username "[user:user1]" and password "password" And user "[user:user1]" finishes syncing diff --git a/tests/heartbeat_test.go b/tests/heartbeat_test.go index 075f7112..65faa254 100644 --- a/tests/heartbeat_test.go +++ b/tests/heartbeat_test.go @@ -1,3 +1,20 @@ +// Copyright (c) 2023 Proton AG +// +// This file is part of Proton Mail 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 . + package tests import ( From d3fc9a50f624cfcdf7c5bb3e7051ac693d036592 Mon Sep 17 00:00:00 2001 From: Romain LE JEUNE Date: Fri, 21 Apr 2023 10:06:01 +0200 Subject: [PATCH 48/54] feat(GODT-2556): Add functional test for Heartbeat Init and telemetry availability. --- internal/app/app.go | 1 + internal/bridge/heartbeat.go | 30 +++++---- internal/bridge/settings.go | 9 ++- internal/telemetry/heartbeat.go | 8 ++- tests/bdd_test.go | 11 +++- tests/bridge_test.go | 23 ++++++- tests/ctx_bridge_test.go | 4 ++ tests/features/bridge/heartbeat.feature | 85 ++++++++++++++++++++++++- 8 files changed, 150 insertions(+), 21 deletions(-) diff --git a/internal/app/app.go b/internal/app/app.go index dcd963d1..16487e51 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -268,6 +268,7 @@ func run(c *cli.Context) error { logrus.Warn("The vault is corrupt and has been wiped") b.PushError(bridge.ErrVaultCorrupt) } + // Start telemetry heartbeat process b.StartHeartbeat(b) diff --git a/internal/bridge/heartbeat.go b/internal/bridge/heartbeat.go index eb37503d..508a237b 100644 --- a/internal/bridge/heartbeat.go +++ b/internal/bridge/heartbeat.go @@ -83,18 +83,6 @@ func (bridge *Bridge) SetLastHeartbeatSent(timestamp time.Time) error { func (bridge *Bridge) StartHeartbeat(manager telemetry.HeartbeatManager) { bridge.heartbeat = telemetry.NewHeartbeat(manager, 1143, 1025, bridge.GetGluonCacheDir(), keychain.DefaultHelper) - safe.RLock(func() { - var splitMode = false - for _, user := range bridge.users { - if user.GetAddressMode() == vault.SplitMode { - splitMode = true - break - } - } - bridge.heartbeat.SetNbAccount(len(bridge.users)) - bridge.heartbeat.SetSplitMode(splitMode) - }, bridge.usersLock) - bridge.heartbeat.SetRollout(bridge.GetUpdateRollout()) bridge.heartbeat.SetAutoStart(bridge.GetAutostart()) bridge.heartbeat.SetAutoUpdate(bridge.GetAutoUpdate()) @@ -113,5 +101,21 @@ func (bridge *Bridge) StartHeartbeat(manager telemetry.HeartbeatManager) { } bridge.heartbeat.SetPrevVersion(bridge.GetLastVersion().String()) - bridge.heartbeat.TrySending() + safe.RLock(func() { + var splitMode = false + for _, user := range bridge.users { + if user.GetAddressMode() == vault.SplitMode { + splitMode = true + break + } + } + var nbAccount = len(bridge.users) + bridge.heartbeat.SetNbAccount(nbAccount) + bridge.heartbeat.SetSplitMode(splitMode) + + // Do not try to send if there is no user yet. + if nbAccount > 0 { + bridge.heartbeat.TrySending() + } + }, bridge.usersLock) } diff --git a/internal/bridge/settings.go b/internal/bridge/settings.go index 0da85403..f5ebae26 100644 --- a/internal/bridge/settings.go +++ b/internal/bridge/settings.go @@ -300,7 +300,14 @@ func (bridge *Bridge) GetTelemetryDisabled() bool { } func (bridge *Bridge) SetTelemetryDisabled(isDisabled bool) error { - return bridge.vault.SetTelemetryDisabled(isDisabled) + if err := bridge.vault.SetTelemetryDisabled(isDisabled); err != nil { + return err + } + // If telemetry is re-enabled locally, try to send the heartbeat. + if !isDisabled { + bridge.heartbeat.TrySending() + } + return nil } func (bridge *Bridge) GetUpdateChannel() updater.Channel { diff --git a/internal/telemetry/heartbeat.go b/internal/telemetry/heartbeat.go index 8d8c8f2d..c2a7b888 100644 --- a/internal/telemetry/heartbeat.go +++ b/internal/telemetry/heartbeat.go @@ -157,7 +157,13 @@ func (heartbeat *Heartbeat) TrySending() { heartbeat.log.WithFields(logrus.Fields{ "metrics": heartbeat.metrics, }).Error("Failed to send heartbeat") - } else if err := heartbeat.manager.SetLastHeartbeatSent(now); err != nil { + return + } + heartbeat.log.WithFields(logrus.Fields{ + "metrics": heartbeat.metrics, + }).Debug("Heartbeat sent") + + if err := heartbeat.manager.SetLastHeartbeatSent(now); err != nil { heartbeat.log.WithError(err).Warn("Cannot save last heartbeat sent to the vault.") } } diff --git a/tests/bdd_test.go b/tests/bdd_test.go index e560b7a8..92a73bed 100644 --- a/tests/bdd_test.go +++ b/tests/bdd_test.go @@ -135,9 +135,14 @@ func TestFeatures(testingT *testing.T) { ctx.Step(`^bridge stops$`, s.bridgeStops) ctx.Step(`^bridge is version "([^"]*)" and the latest available version is "([^"]*)" reachable from "([^"]*)"$`, s.bridgeVersionIsAndTheLatestAvailableVersionIsReachableFrom) ctx.Step(`^the user has disabled automatic updates$`, s.theUserHasDisabledAutomaticUpdates) + ctx.Step(`^the user has disabled automatic start`, s.theUserHasDisabledAutomaticStart) + ctx.Step(`^the user has enabled alternative routing`, s.theUserHasEnabledAlternativeRouting) + ctx.Step(`^the user set IMAP mode to SSL`, s.theUserSetIMAPModeToSSL) + ctx.Step(`^the user set SMTP mode to SSL`, s.theUserSetSMTPModeToSSL) ctx.Step(`^the user changes the IMAP port to (\d+)$`, s.theUserChangesTheIMAPPortTo) ctx.Step(`^the user changes the SMTP port to (\d+)$`, s.theUserChangesTheSMTPPortTo) ctx.Step(`^the user sets the address mode of user "([^"]*)" to "([^"]*)"$`, s.theUserSetsTheAddressModeOfUserTo) + ctx.Step(`^the user changes the default keychain application`, s.theUserChangesTheDefaultKeychainApplication) ctx.Step(`^the user changes the gluon path$`, s.theUserChangesTheGluonPath) ctx.Step(`^the user deletes the gluon files$`, s.theUserDeletesTheGluonFiles) ctx.Step(`^the user deletes the gluon cache$`, s.theUserDeletesTheGluonCache) @@ -234,9 +239,9 @@ func TestFeatures(testingT *testing.T) { // ==== TELEMETRY ==== ctx.Step(`^bridge eventually sends the following heartbeat:$`, s.bridgeEventuallySendsTheFollowingHeartbeat) - ctx.Step(`^bridge needs to send heartbeat$`, s.bridgeNeedsToSendHeartbeat) - ctx.Step(`^bridge do not need to send heartbeat$`, s.bridgeDoNotNeedToSendHeartbeat) - ctx.Step(`^heartbeat is not whitelisted$`, s.heartbeatIsNotwhitelisted) + ctx.Step(`^bridge needs to send heartbeat`, s.bridgeNeedsToSendHeartbeat) + ctx.Step(`^bridge do not need to send heartbeat`, s.bridgeDoNotNeedToSendHeartbeat) + ctx.Step(`^heartbeat is not whitelisted`, s.heartbeatIsNotwhitelisted) }, Options: &godog.Options{ Format: "pretty", diff --git a/tests/bridge_test.go b/tests/bridge_test.go index 87c719e9..7d3edd14 100644 --- a/tests/bridge_test.go +++ b/tests/bridge_test.go @@ -80,6 +80,10 @@ func (s *scenario) theUserSetsTheAddressModeOfUserTo(user, mode string) error { } } +func (s *scenario) theUserChangesTheDefaultKeychainApplication() error { + return s.t.bridge.SetKeychainApp("CustomKeychainApp") +} + func (s *scenario) theUserChangesTheGluonPath() error { gluonDir, err := os.MkdirTemp(s.t.dir, "gluon") if err != nil { @@ -118,7 +122,6 @@ func (s *scenario) theUserHasDisabledAutomaticUpdates() error { started = true } - if err := s.t.bridge.SetAutoUpdate(false); err != nil { return err } @@ -128,10 +131,26 @@ func (s *scenario) theUserHasDisabledAutomaticUpdates() error { return err } } - return nil } +func (s *scenario) theUserHasDisabledAutomaticStart() error { + return s.t.bridge.SetAutostart(false) +} + +func (s *scenario) theUserHasEnabledAlternativeRouting() error { + s.t.expectProxyCtlAllowProxy() + return s.t.bridge.SetProxyAllowed(true) +} + +func (s *scenario) theUserSetIMAPModeToSSL() error { + return s.t.bridge.SetIMAPSSL(true) +} + +func (s *scenario) theUserSetSMTPModeToSSL() error { + return s.t.bridge.SetSMTPSSL(true) +} + func (s *scenario) theUserReportsABug() error { return s.t.bridge.ReportBug(context.Background(), "osType", "osVersion", "description", "username", "email", "client", false) } diff --git a/tests/ctx_bridge_test.go b/tests/ctx_bridge_test.go index de4ed616..0afe93d7 100644 --- a/tests/ctx_bridge_test.go +++ b/tests/ctx_bridge_test.go @@ -175,6 +175,7 @@ func (t *testCtx) initBridge() (<-chan events.Event, error) { t.bridge = bridge t.heartbeat.setBridge(bridge) + bridge.StartHeartbeat(t.heartbeat) return t.events.collectFrom(eventCh), nil @@ -344,6 +345,9 @@ func (t *testCtx) closeFrontendClient() error { return nil } +func (t *testCtx) expectProxyCtlAllowProxy() { + t.mocks.ProxyCtl.EXPECT().AllowProxy() +} type mockRestarter struct{} diff --git a/tests/features/bridge/heartbeat.feature b/tests/features/bridge/heartbeat.feature index a1ce7372..3675cd38 100644 --- a/tests/features/bridge/heartbeat.feature +++ b/tests/features/bridge/heartbeat.feature @@ -4,7 +4,7 @@ Feature: Send Telemetry Heartbeat And bridge starts - Scenario: Send at first start - one user + Scenario: Send at first start - one user default settings Then bridge telemetry feature is enabled And bridge needs to send heartbeat When the user logs in with username "[user:user1]" and password "password" @@ -37,6 +37,89 @@ Feature: Send Telemetry Heartbeat """ And bridge do not need to send heartbeat + + Scenario: Send at first start - one user modified settings + Then bridge telemetry feature is enabled + And bridge needs to send heartbeat + When the user has disabled automatic updates + And the user has disabled automatic start + And the user has enabled alternative routing + And the user hides All Mail + And the user set IMAP mode to SSL + And the user set SMTP mode to SSL + And the user changes the IMAP port to 42695 + And the user changes the SMTP port to 56942 + And the user changes the gluon path + And the user changes the default keychain application + When the user logs in with username "[user:user1]" and password "password" + And user "[user:user1]" finishes syncing + Then bridge eventually sends the following heartbeat: + """ + { + "MeasurementGroup": "bridge.any.usage", + "Event": "bridge_heartbeat", + "Values": { + "nb_account": 1 + }, + "Dimensions": { + "auto_update": "off", + "auto_start": "off", + "beta": "off", + "doh": "on", + "split_mode": "off", + "show_all_mail": "off", + "imap_connection_mode": "ssl", + "smtp_connection_mode": "ssl", + "imap_port": "custom", + "smtp_port": "custom", + "cache_location": "custom", + "keychain_pref": "custom", + "prev_version": "0.0.0", + "rollout": 42 + } + } + """ + And bridge do not need to send heartbeat + + + Scenario: Send at first start - one user telemetry disabled + Then bridge telemetry feature is enabled + And bridge needs to send heartbeat + When the user disables telemetry in bridge settings + And the user logs in with username "[user:user1]" and password "password" + And user "[user:user1]" finishes syncing + And bridge needs to send heartbeat + Then the user sets the address mode of user "[user:user1]" to "split" + And the user enables telemetry in bridge settings + Then bridge eventually sends the following heartbeat: + """ + { + "MeasurementGroup": "bridge.any.usage", + "Event": "bridge_heartbeat", + "Values": { + "nb_account": 1 + }, + "Dimensions": { + "auto_update": "on", + "auto_start": "on", + "beta": "off", + "doh": "off", + "split_mode": "on", + "show_all_mail": "on", + "imap_connection_mode": "starttls", + "smtp_connection_mode": "starttls", + "imap_port": "default", + "smtp_port": "default", + "cache_location": "default", + "keychain_pref": "default", + "prev_version": "0.0.0", + "rollout": 42 + } + } + """ + And bridge do not need to send heartbeat + + Scenario: GroupMeasurement rejected by API Given heartbeat is not whitelisted Then bridge telemetry feature is enabled From 00adb8bc2275d84ab0c1b8672614bc904fa0bd0b Mon Sep 17 00:00:00 2001 From: Romain LE JEUNE Date: Fri, 21 Apr 2023 11:26:36 +0200 Subject: [PATCH 49/54] feat(GODT-2552): Fix review comment + use only string for Heartbeat Dimension. --- internal/bridge/heartbeat.go | 10 ++++------ internal/telemetry/heartbeat.go | 3 ++- internal/telemetry/heartbeat_test.go | 2 +- internal/telemetry/types_heartbeat.go | 2 +- tests/features/bridge/heartbeat.feature | 7 +++---- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/internal/bridge/heartbeat.go b/internal/bridge/heartbeat.go index 508a237b..1a8e0399 100644 --- a/internal/bridge/heartbeat.go +++ b/internal/bridge/heartbeat.go @@ -59,12 +59,10 @@ func (bridge *Bridge) SendHeartbeat(heartbeat *telemetry.HeartbeatData) bool { var sent = false safe.RLock(func() { - if len(bridge.users) > 0 { - for _, user := range bridge.users { - if err := user.SendTelemetry(context.Background(), data); err == nil { - sent = true - break - } + for _, user := range bridge.users { + if err := user.SendTelemetry(context.Background(), data); err == nil { + sent = true + break } } }, bridge.usersLock) diff --git a/internal/telemetry/heartbeat.go b/internal/telemetry/heartbeat.go index c2a7b888..3852a78d 100644 --- a/internal/telemetry/heartbeat.go +++ b/internal/telemetry/heartbeat.go @@ -18,6 +18,7 @@ package telemetry import ( + "strconv" "time" "github.com/ProtonMail/proton-bridge/v3/internal/updater" @@ -41,7 +42,7 @@ func NewHeartbeat(manager HeartbeatManager, imapPort, smtpPort int, cacheDir, ke } func (heartbeat *Heartbeat) SetRollout(val float64) { - heartbeat.metrics.Dimensions.Rollout = int(val * 100) + heartbeat.metrics.Dimensions.Rollout = strconv.Itoa(int(val * 100)) } func (heartbeat *Heartbeat) SetNbAccount(val int) { diff --git a/internal/telemetry/heartbeat_test.go b/internal/telemetry/heartbeat_test.go index 7c8b4fb1..046b0d18 100644 --- a/internal/telemetry/heartbeat_test.go +++ b/internal/telemetry/heartbeat_test.go @@ -48,7 +48,7 @@ func TestHeartbeat_default_heartbeat(t *testing.T) { CacheLocation: "default", KeychainPref: "default", PrevVersion: "1.2.3", - Rollout: 10, + Rollout: "10", }, } diff --git a/internal/telemetry/types_heartbeat.go b/internal/telemetry/types_heartbeat.go index e41a9c2d..a10f42b1 100644 --- a/internal/telemetry/types_heartbeat.go +++ b/internal/telemetry/types_heartbeat.go @@ -57,7 +57,7 @@ type HeartbeatDimensions struct { CacheLocation string `json:"cache_location"` KeychainPref string `json:"keychain_pref"` PrevVersion string `json:"prev_version"` - Rollout int `json:"rollout"` + Rollout string `json:"rollout"` } type HeartbeatData struct { diff --git a/tests/features/bridge/heartbeat.feature b/tests/features/bridge/heartbeat.feature index 3675cd38..9584f800 100644 --- a/tests/features/bridge/heartbeat.feature +++ b/tests/features/bridge/heartbeat.feature @@ -31,7 +31,7 @@ Feature: Send Telemetry Heartbeat "cache_location": "default", "keychain_pref": "default", "prev_version": "0.0.0", - "rollout": 42 + "rollout": "42" } } """ @@ -75,7 +75,7 @@ Feature: Send Telemetry Heartbeat "cache_location": "custom", "keychain_pref": "custom", "prev_version": "0.0.0", - "rollout": 42 + "rollout": "42" } } """ @@ -113,7 +113,7 @@ Feature: Send Telemetry Heartbeat "cache_location": "default", "keychain_pref": "default", "prev_version": "0.0.0", - "rollout": 42 + "rollout": "42" } } """ @@ -127,4 +127,3 @@ Feature: Send Telemetry Heartbeat When the user logs in with username "[user:user1]" and password "password" And user "[user:user1]" finishes syncing Then bridge needs to send heartbeat - From 3ef3ab72edb684c48e53062d9b1199dc832bc2bc Mon Sep 17 00:00:00 2001 From: Romain Le Jeune Date: Mon, 24 Apr 2023 12:45:12 +0000 Subject: [PATCH 50/54] feat(GODT-2553): Try to send telemetry every hour. --- internal/bridge/bridge.go | 3 +++ internal/bridge/heartbeat.go | 11 ++++++++++- internal/bridge/settings.go | 2 +- internal/bridge/user.go | 2 +- internal/telemetry/heartbeat.go | 2 +- internal/user/user.go | 15 +++++---------- 6 files changed, 21 insertions(+), 14 deletions(-) diff --git a/internal/bridge/bridge.go b/internal/bridge/bridge.go index 4af1571f..29a87b1f 100644 --- a/internal/bridge/bridge.go +++ b/internal/bridge/bridge.go @@ -130,6 +130,9 @@ type Bridge struct { // goUpdate triggers a check/install of updates. goUpdate func() + // goHeartbeat triggers a check/sending if heartbeat is needed. + goHeartbeat func() + uidValidityGenerator imap.UIDValidityGenerator } diff --git a/internal/bridge/heartbeat.go b/internal/bridge/heartbeat.go index 1a8e0399..a24fad96 100644 --- a/internal/bridge/heartbeat.go +++ b/internal/bridge/heartbeat.go @@ -30,6 +30,8 @@ import ( "github.com/sirupsen/logrus" ) +const HeartbeatCheckInterval = time.Hour + func (bridge *Bridge) IsTelemetryAvailable() bool { var flag = true if bridge.GetTelemetryDisabled() { @@ -81,6 +83,13 @@ func (bridge *Bridge) SetLastHeartbeatSent(timestamp time.Time) error { func (bridge *Bridge) StartHeartbeat(manager telemetry.HeartbeatManager) { bridge.heartbeat = telemetry.NewHeartbeat(manager, 1143, 1025, bridge.GetGluonCacheDir(), keychain.DefaultHelper) + // Check for heartbeat when triggered. + bridge.goHeartbeat = bridge.tasks.PeriodicOrTrigger(HeartbeatCheckInterval, 0, func(ctx context.Context) { + logrus.Debug("Checking for heartbeat") + + bridge.heartbeat.TrySending() + }) + bridge.heartbeat.SetRollout(bridge.GetUpdateRollout()) bridge.heartbeat.SetAutoStart(bridge.GetAutostart()) bridge.heartbeat.SetAutoUpdate(bridge.GetAutoUpdate()) @@ -113,7 +122,7 @@ func (bridge *Bridge) StartHeartbeat(manager telemetry.HeartbeatManager) { // Do not try to send if there is no user yet. if nbAccount > 0 { - bridge.heartbeat.TrySending() + defer bridge.goHeartbeat() } }, bridge.usersLock) } diff --git a/internal/bridge/settings.go b/internal/bridge/settings.go index f5ebae26..dd727316 100644 --- a/internal/bridge/settings.go +++ b/internal/bridge/settings.go @@ -305,7 +305,7 @@ func (bridge *Bridge) SetTelemetryDisabled(isDisabled bool) error { } // If telemetry is re-enabled locally, try to send the heartbeat. if !isDisabled { - bridge.heartbeat.TrySending() + defer bridge.goHeartbeat() } return nil } diff --git a/internal/bridge/user.go b/internal/bridge/user.go index 2c34a878..526850b1 100644 --- a/internal/bridge/user.go +++ b/internal/bridge/user.go @@ -572,7 +572,7 @@ func (bridge *Bridge) addUserWithVault( }, bridge.usersLock) // As we need at least one user to send heartbeat, try to send it. - bridge.heartbeat.TrySending() + defer bridge.goHeartbeat() return nil } diff --git a/internal/telemetry/heartbeat.go b/internal/telemetry/heartbeat.go index 3852a78d..00036e05 100644 --- a/internal/telemetry/heartbeat.go +++ b/internal/telemetry/heartbeat.go @@ -162,7 +162,7 @@ func (heartbeat *Heartbeat) TrySending() { } heartbeat.log.WithFields(logrus.Fields{ "metrics": heartbeat.metrics, - }).Debug("Heartbeat sent") + }).Info("Heartbeat sent") if err := heartbeat.manager.SetLastHeartbeatSent(now); err != nil { heartbeat.log.WithError(err).Warn("Cannot save last heartbeat sent to the vault.") diff --git a/internal/user/user.go b/internal/user/user.go index f82d3fd8..d8418330 100644 --- a/internal/user/user.go +++ b/internal/user/user.go @@ -601,7 +601,7 @@ func (user *User) Close() { func (user *User) IsTelemetryEnabled(ctx context.Context) bool { settings, err := user.client.GetUserSettings(ctx) if err != nil { - user.log.WithError(err).Warn("Failed to retrieve API user Settings") + user.log.WithError(err).Error("Failed to retrieve API user Settings") return false } return settings.Telemetry == proton.SettingEnabled @@ -611,22 +611,17 @@ func (user *User) IsTelemetryEnabled(ctx context.Context) bool { func (user *User) SendTelemetry(ctx context.Context, data []byte) error { var req proton.SendStatsReq if err := json.Unmarshal(data, &req); err != nil { - user.log.WithError(err).Warn("Failed to send telemetry.") - if err := user.reporter.ReportMessageWithContext("Failed to send telemetry.", reporter.Context{ + user.log.WithError(err).Error("Failed to build telemetry request.") + if err := user.reporter.ReportMessageWithContext("Failed to build telemetry request.", reporter.Context{ "error": err, }); err != nil { - logrus.WithError(err).Error("Failed to report telemetry sending error") + logrus.WithError(err).Error("Failed to report telemetry request build error") } return err } err := user.client.SendDataEvent(ctx, req) if err != nil { - user.log.WithError(err).Warn("Failed to send telemetry.") - if err := user.reporter.ReportMessageWithContext("Failed to send telemetry.", reporter.Context{ - "error": err, - }); err != nil { - logrus.WithError(err).Error("Failed to report telemetry sending error") - } + user.log.WithError(err).Error("Failed to send telemetry.") return err } return nil From 7383d65cb29239eba08c648f15e690755d95e696 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Tue, 25 Apr 2023 10:24:51 +0200 Subject: [PATCH 51/54] fix(GODT-2582): Dedup recovered messages folder https://github.com/ProtonMail/gluon/pull/338 https://github.com/ProtonMail/gluon/pull/339 https://github.com/ProtonMail/gluon/pull/340 --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 323b2167..be328af5 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/0xAX/notificator v0.0.0-20220220101646-ee9b8921e557 github.com/Masterminds/semver/v3 v3.2.0 - github.com/ProtonMail/gluon v0.16.1-0.20230413125952-3e8cc8bcee8b + github.com/ProtonMail/gluon v0.16.1-0.20230425073628-8ec759b512f1 github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a github.com/ProtonMail/go-proton-api v0.4.1-0.20230413090743-ad45d30ed45c github.com/ProtonMail/gopenpgp/v2 v2.5.2 diff --git a/go.sum b/go.sum index f3833f62..77661b36 100644 --- a/go.sum +++ b/go.sum @@ -30,6 +30,8 @@ github.com/ProtonMail/docker-credential-helpers v1.1.0 h1:+kvUIpwWcbtP3WFv5sSvkF github.com/ProtonMail/docker-credential-helpers v1.1.0/go.mod h1:mK0aBveCxhnQ756AmaTfXMZDeULvheYVhF/MWMErN5g= github.com/ProtonMail/gluon v0.16.1-0.20230413125952-3e8cc8bcee8b h1:prDIhq/FUCYVmNVNnJUiflSny6n6pWHIF851ulaEiyg= github.com/ProtonMail/gluon v0.16.1-0.20230413125952-3e8cc8bcee8b/go.mod h1:yA4hk6CJw0BMo+YL8Y3ckCYs5L20sysu9xseshwY3QI= +github.com/ProtonMail/gluon v0.16.1-0.20230425073628-8ec759b512f1 h1:6YTRwn95hnTymOz5g+MbikfJXYE4xGJkIgTLm0t/1w8= +github.com/ProtonMail/gluon v0.16.1-0.20230425073628-8ec759b512f1/go.mod h1:yA4hk6CJw0BMo+YL8Y3ckCYs5L20sysu9xseshwY3QI= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:D+aZah+k14Gn6kmL7eKxoo/4Dr/lK3ChBcwce2+SQP4= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4= github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= From e9629aca47157aa4e0761937cb38ccc71b18974f Mon Sep 17 00:00:00 2001 From: Xavier Michelon Date: Sat, 21 Jan 2023 20:20:59 +0100 Subject: [PATCH 52/54] feat(GODT-2517): replace status window with native tray icon context menu. feat(GODT-2517): show main windows on left click (Linux & Windows). feat(GODT-2517): removed old QML status window. feat(GODT-2517): polishing. feat(GODT-2517): renaming + removal of dead code (v2 tests). --- .../bridge-gui/bridge-gui/CMakeLists.txt | 1 + .../bridge-gui/bridge-gui/QMLBackend.cpp | 60 +- .../bridge-gui/bridge-gui/QMLBackend.h | 12 +- .../bridge-gui/bridge-gui/Resources.qrc | 16 +- .../bridge-gui/bridge-gui/TrayIcon.cpp | 250 +++++ .../frontend/bridge-gui/bridge-gui/TrayIcon.h | 70 ++ .../bridge-gui/bridge-gui/qml/Bridge.qml | 221 +--- .../bridge-gui/qml/BridgeTest/UserControl.qml | 315 ------ .../bridge-gui/qml/BridgeTest/UserList.qml | 101 -- .../bridge-gui/qml/BridgeTest/UserModel.qml | 28 - .../bridge-gui/bridge-gui/qml/Bridge_test.qml | 982 ------------------ .../bridge-gui/bridge-gui/qml/MainWindow.qml | 21 +- .../qml/Notifications/Notifications.qml | 46 +- .../bridge-gui/qml/StatusWindow.qml | 352 ------- .../bridge-gui/qml/icons/ic-dot.svg | 7 + 15 files changed, 461 insertions(+), 2021 deletions(-) create mode 100644 internal/frontend/bridge-gui/bridge-gui/TrayIcon.cpp create mode 100644 internal/frontend/bridge-gui/bridge-gui/TrayIcon.h delete mode 100644 internal/frontend/bridge-gui/bridge-gui/qml/BridgeTest/UserControl.qml delete mode 100644 internal/frontend/bridge-gui/bridge-gui/qml/BridgeTest/UserList.qml delete mode 100644 internal/frontend/bridge-gui/bridge-gui/qml/BridgeTest/UserModel.qml delete mode 100644 internal/frontend/bridge-gui/bridge-gui/qml/Bridge_test.qml delete mode 100644 internal/frontend/bridge-gui/bridge-gui/qml/StatusWindow.qml create mode 100644 internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-dot.svg diff --git a/internal/frontend/bridge-gui/bridge-gui/CMakeLists.txt b/internal/frontend/bridge-gui/bridge-gui/CMakeLists.txt index e491356f..77f06e49 100644 --- a/internal/frontend/bridge-gui/bridge-gui/CMakeLists.txt +++ b/internal/frontend/bridge-gui/bridge-gui/CMakeLists.txt @@ -114,6 +114,7 @@ add_executable(bridge-gui EventStreamWorker.cpp EventStreamWorker.h LogUtils.cpp LogUtils.h main.cpp + TrayIcon.cpp TrayIcon.h Pch.h QMLBackend.cpp QMLBackend.h UserList.cpp UserList.h diff --git a/internal/frontend/bridge-gui/bridge-gui/QMLBackend.cpp b/internal/frontend/bridge-gui/bridge-gui/QMLBackend.cpp index eab26749..2435426c 100644 --- a/internal/frontend/bridge-gui/bridge-gui/QMLBackend.cpp +++ b/internal/frontend/bridge-gui/bridge-gui/QMLBackend.cpp @@ -49,6 +49,9 @@ QMLBackend::QMLBackend() /// \param[in] serviceConfig //**************************************************************************************************************************************************** void QMLBackend::init(GRPCConfig const &serviceConfig) { + trayIcon_.reset(new TrayIcon()); + this->setNormalTrayIcon(); + connect(this, &QMLBackend::fatalError, &app(), &AppController::onFatalError); users_ = new UserList(this); @@ -99,6 +102,14 @@ bool QMLBackend::waitForEventStreamReaderToFinish(qint32 timeoutMs) { } +//**************************************************************************************************************************************************** +/// \return The list of users +//**************************************************************************************************************************************************** +UserList const &QMLBackend::users() const { + return *users_; +} + + //**************************************************************************************************************************************************** /// \return The build year as a string (e.g. 2023) //**************************************************************************************************************************************************** @@ -591,7 +602,6 @@ void QMLBackend::toggleIsTelemetryDisabled(bool isDisabled) { } - //**************************************************************************************************************************************************** /// \param[in] scheme the scheme name //**************************************************************************************************************************************************** @@ -861,6 +871,49 @@ void QMLBackend::sendBadEventUserFeedback(QString const &userID, bool doResync) } +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +void QMLBackend::setNormalTrayIcon() { + if (trayIcon_) { + trayIcon_->setState(TrayIcon::State::Normal, tr("Connected"), ":/qml/icons/ic-connected.svg"); + } +} + + +//**************************************************************************************************************************************************** +/// \param[in] stateString A string describing the state. +/// \param[in] statusIcon The path of the status icon. +//**************************************************************************************************************************************************** +void QMLBackend::setErrorTrayIcon(QString const &stateString, QString const &statusIcon) { + if (trayIcon_) { + trayIcon_->setState(TrayIcon::State::Error, stateString, statusIcon); + } +} + + +//**************************************************************************************************************************************************** +/// \param[in] stateString A string describing the state. +/// \param[in] statusIcon The path of the status icon. +//**************************************************************************************************************************************************** +void QMLBackend::setWarnTrayIcon(QString const &stateString, QString const &statusIcon) { + if (trayIcon_) { + trayIcon_->setState(TrayIcon::State::Warn, stateString, statusIcon); + } +} + + +//**************************************************************************************************************************************************** +/// \param[in] stateString A string describing the state. +/// \param[in] statusIcon The path of the status icon. +//**************************************************************************************************************************************************** +void QMLBackend::setUpdateTrayIcon(QString const &stateString, QString const &statusIcon) { + if (trayIcon_) { + trayIcon_->setState(TrayIcon::State::Update, stateString, statusIcon); + } +} + + //**************************************************************************************************************************************************** /// \param[in] imapPort The IMAP port. /// \param[in] smtpPort The SMTP port. @@ -915,7 +968,7 @@ void QMLBackend::onLoginAlreadyLoggedIn(QString const &userID) { //**************************************************************************************************************************************************** /// \param[in] userID The userID. //**************************************************************************************************************************************************** -void QMLBackend::onUserBadEvent(QString const &userID, QString const& ) { +void QMLBackend::onUserBadEvent(QString const &userID, QString const &) { HANDLE_EXCEPTION( if (badEventDisplayQueue_.contains(userID)) { app().log().error("Received 'bad event' for a user that is already in the queue."); @@ -944,8 +997,9 @@ void QMLBackend::onIMAPLoginFailed(QString const &username) { if ((!user) || (user->state() != UserState::SignedOut)) { // We want to pop-up only if a signed-out user has been detected return; } - if (user->isInIMAPLoginFailureCooldown()) + if (user->isInIMAPLoginFailureCooldown()) { return; + } user->startImapLoginFailureCooldown(60 * 60 * 1000); // 1 hour cooldown during which we will not display this notification to this user again. emit selectUser(user->id()); emit imapLoginWhileSignedOut(username); diff --git a/internal/frontend/bridge-gui/bridge-gui/QMLBackend.h b/internal/frontend/bridge-gui/bridge-gui/QMLBackend.h index 2afbc8ee..afde837e 100644 --- a/internal/frontend/bridge-gui/bridge-gui/QMLBackend.h +++ b/internal/frontend/bridge-gui/bridge-gui/QMLBackend.h @@ -22,6 +22,7 @@ #include "MacOS/DockIcon.h" #include "BuildConfig.h" +#include "TrayIcon.h" #include "UserList.h" #include #include @@ -43,6 +44,7 @@ public: // member functions. QMLBackend &operator=(QMLBackend &&) = delete; ///< Disabled move assignment operator. void init(GRPCConfig const &serviceConfig); ///< Initialize the backend. bool waitForEventStreamReaderToFinish(qint32 timeoutMs); ///< Wait for the event stream reader to finish. + UserList const& users() const; ///< Return the list of users // invokable methods can be called from QML. They generally return a value, which slots cannot do. Q_INVOKABLE static QString buildYear(); ///< Return the application build year. @@ -178,6 +180,10 @@ public slots: // slot for signals received from QML -> To be forwarded to Bridge void onVersionChanged(); ///< Slot for the version change signal. void setMailServerSettings(int imapPort, int smtpPort, bool useSSLForIMAP, bool useSSLForSMTP) const; ///< Forwards a connection mode change request from QML to gRPC void sendBadEventUserFeedback(QString const &userID, bool doResync); ///< Slot the providing user feedback for a bad event. + void setNormalTrayIcon(); ///< Set the tray icon to normal. + void setErrorTrayIcon(QString const& stateString, QString const &statusIcon); ///< Set the tray icon to 'error' state. + void setWarnTrayIcon(QString const& stateString, QString const &statusIcon); ///< Set the tray icon to 'warn' state. + void setUpdateTrayIcon(QString const& stateString, QString const &statusIcon); ///< Set the tray icon to 'update' state. public slots: // slot for signals received from gRPC that need transformation instead of simple forwarding void onMailServerSettingsChanged(int imapPort, int smtpPort, bool useSSLForIMAP, bool useSSLForSMTP); ///< Slot for the ConnectionModeChanged gRPC event. @@ -237,8 +243,10 @@ signals: // Signals received from the Go backend, to be forwarded to QML void bugReportSendError(); ///< Signal for the 'bugReportSendError' gRPC stream event. void showMainWindow(); ///< Signal for the 'showMainWindow' gRPC stream event. void hideMainWindow(); ///< Signal for the 'hideMainWindow' gRPC stream event. + void showHelp(); ///< Signal for the 'showHelp' event (from the context menu). + void showSettings(); ///< Signal for the 'showHelp' event (from the context menu). + void selectUser(QString const& userID); ///< Signal emitted in order to selected a user with a given ID in the list. void genericError(QString const &title, QString const &description); ///< Signal for the 'genericError' gRPC stream event. - void selectUser(QString const); ///< Signal that request the given user account to be displayed. void imapLoginWhileSignedOut(QString const& username); ///< Signal for the notification of IMAP login attempt on a signed out account. // This signal is emitted when an exception is intercepted is calls triggered by QML. QML engine would intercept the exception otherwise. @@ -261,7 +269,7 @@ private: // data members bool useSSLForIMAP_ { false }; ///< The cached value for useSSLForIMAP. bool useSSLForSMTP_ { false }; ///< The cached value for useSSLForSMTP. QList badEventDisplayQueue_; ///< THe queue for displaying 'bad event feedback request dialog'. - + std::unique_ptr trayIcon_; friend class AppController; }; diff --git a/internal/frontend/bridge-gui/bridge-gui/Resources.qrc b/internal/frontend/bridge-gui/bridge-gui/Resources.qrc index 640fbbb7..f5a078f5 100644 --- a/internal/frontend/bridge-gui/bridge-gui/Resources.qrc +++ b/internal/frontend/bridge-gui/bridge-gui/Resources.qrc @@ -5,11 +5,7 @@ qml/AccountView.qml qml/Banner.qml qml/Bridge.qml - qml/Bridge_test.qml qml/bridgeqml.qmlproject - qml/BridgeTest/UserControl.qml - qml/BridgeTest/UserList.qml - qml/BridgeTest/UserModel.qml qml/BugReportView.qml qml/Configuration.qml qml/ConfigurationItem.qml @@ -28,6 +24,7 @@ qml/icons/ic-connected.svg qml/icons/ic-copy.svg qml/icons/ic-cross-close.svg + qml/icons/ic-dot.svg qml/icons/ic-drive.svg qml/icons/ic-exclamation-circle-filled.svg qml/icons/ic-external-link.svg @@ -104,17 +101,6 @@ qml/ConnectionModeSettings.qml qml/SplashScreen.qml qml/Status.qml - qml/StatusWindow.qml - qml/tests/Buttons.qml - qml/tests/ButtonsColumn.qml - qml/tests/CheckBoxes.qml - qml/tests/ComboBoxes.qml - qml/tests/RadioButtons.qml - qml/tests/Switches.qml - qml/tests/Test.qml - qml/tests/TestComponents.qml - qml/tests/TextAreas.qml - qml/tests/TextFields.qml qml/WelcomeGuide.qml diff --git a/internal/frontend/bridge-gui/bridge-gui/TrayIcon.cpp b/internal/frontend/bridge-gui/bridge-gui/TrayIcon.cpp new file mode 100644 index 00000000..2a16c740 --- /dev/null +++ b/internal/frontend/bridge-gui/bridge-gui/TrayIcon.cpp @@ -0,0 +1,250 @@ +// Copyright (c) 2023 Proton AG +// +// This file is part of Proton Mail 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 . + + +#include "TrayIcon.h" +#include "QMLBackend.h" +#include +#include + + +using namespace bridgepp; + + +namespace { + + +QColor const normalColor(30, 168, 133); /// The normal state color. +QColor const errorColor(220, 50, 81); ///< The error state color. +QColor const warnColor(255, 153, 0); ///< The warn state color. +QColor const updateColor(35, 158, 206); ///< The warn state color. +QColor const greyColor(112, 109, 107); ///< The grey color. + + +//**************************************************************************************************************************************************** +/// \brief Create a single resolution icon from an image. Throw an exception in case of failure. +//**************************************************************************************************************************************************** +QIcon loadIconFromImage(QString const &path) { + QPixmap const pixmap(path); + if (pixmap.isNull()) { + throw Exception(QString("Could create icon from image '%1'.").arg(path)); + } + return QIcon(pixmap); +} + + +//**************************************************************************************************************************************************** +/// \brief Retrieve the color associated with a tray icon state. +/// +/// \param[in] state The state. +/// \return The color associated with a given tray icon state. +//**************************************************************************************************************************************************** +QColor stateColor(TrayIcon::State state) { + switch (state) { + case TrayIcon::State::Normal: + return normalColor; + case TrayIcon::State::Error: + return errorColor; + case TrayIcon::State::Warn: + return warnColor; + case TrayIcon::State::Update: + return updateColor; + default: + app().log().error(QString("Unknown tray icon state %1.").arg(static_cast(state))); + return normalColor; + } +} + + +//**************************************************************************************************************************************************** +/// \brief Return the text identifying a state in resource file names. +/// +/// \param[in] state The state. +/// \param[in] The text identifying the state in resource file names. +//**************************************************************************************************************************************************** +QString stateText(TrayIcon::State state) { + switch (state) { + case TrayIcon::State::Normal: + return "norm"; + case TrayIcon::State::Error: + return "error"; + case TrayIcon::State::Warn: + return "warn"; + case TrayIcon::State::Update: + return "update"; + default: + app().log().error(QString("Unknown tray icon state %1.").arg(static_cast(state))); + return "norm"; + } +} + + +} // anonymous namespace + + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +TrayIcon::TrayIcon() + : QSystemTrayIcon() + , menu_(new QMenu) { + + this->generateDotIcons(); + this->setContextMenu(menu_.get()); + + connect(menu_.get(), &QMenu::aboutToShow, this, &TrayIcon::onMenuAboutToShow); + connect(this, &TrayIcon::selectUser, &app().backend(), &QMLBackend::selectUser); + connect(this, &TrayIcon::activated, this, &TrayIcon::onActivated); + + this->show(); + this->setState(State::Normal, QString(), QString()); +} + + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +void TrayIcon::onMenuAboutToShow() { + this->refreshContextMenu(); +} + + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +void TrayIcon::onUserClicked() { + try { + auto action = dynamic_cast(this->sender()); + if (!action) { + throw Exception("Could not retrieve context menu action."); + } + + QString const &userID = action->data().toString(); + if (userID.isNull()) { + throw Exception("Could not retrieve context menu's selected user."); + } + + emit selectUser(userID); + } catch (Exception const &e) { + app().log().error(e.qwhat()); + } +} + + +//**************************************************************************************************************************************************** +/// \param[in] reason The icon activation reason. +//**************************************************************************************************************************************************** +void TrayIcon::onActivated(QSystemTrayIcon::ActivationReason reason) { + if ((QSystemTrayIcon::Trigger == reason) && !onMacOS()) { + app().backend().showMainWindow(); + } +} + + +//**************************************************************************************************************************************************** +// +//**************************************************************************************************************************************************** +void TrayIcon::generateDotIcons() { + QPixmap dotSVG(":/qml/icons/ic-dot.svg"); + struct IconColor { + QIcon &icon; + QColor color; + }; + for (auto pair: QList {{ greenDot_, normalColor }, { greyDot_, greyColor }, { orangeDot_, warnColor }}) { + QPixmap p = dotSVG; + QPainter painter(&p); + painter.setCompositionMode(QPainter::CompositionMode_SourceIn); + painter.fillRect(p.rect(), pair.color); + painter.end(); + pair.icon = QIcon(p); + } +} + + +//**************************************************************************************************************************************************** +/// \param[in] state The state. +/// \param[in] stateString A string describing the state. +/// \param[in] statusIconPath The status icon path. +/// \param[in] statusIconColor The color for the status icon in hex. +//**************************************************************************************************************************************************** +void TrayIcon::setState(TrayIcon::State state, QString const &stateString, QString const &statusIconPath) { + stateString_ = stateString; + state_ = state; + QString const style = onMacOS() ? "mono" : "color"; + QString const text = stateText(state); + + + QIcon icon = loadIconFromImage(QString(":/qml/icons/systray-%1-%2.png").arg(style, text)); + icon.setIsMask(true); + this->setIcon(icon); + + this->generateStatusIcon(statusIconPath, stateColor(state)); +} + + +//**************************************************************************************************************************************************** +/// \param[in] svgPath The path of the SVG file for the icon. +/// \param[in] color The color to apply to the icon. +//**************************************************************************************************************************************************** +void TrayIcon::generateStatusIcon(QString const &svgPath, QColor const &color) { + // We use the SVG path as pixmap mask and fill it with the appropriate color + QString resourcePath = svgPath; + resourcePath.replace(QRegularExpression(R"(^\.\/)"), ":/qml/"); // QML resource path are a bit different from the Qt resources path. + QPixmap pixmap(resourcePath); + QPainter painter(&pixmap); + painter.setCompositionMode(QPainter::CompositionMode_SourceIn); + painter.fillRect(pixmap.rect(), color); + painter.end(); + statusIcon_ = QIcon(pixmap); +} + + +//********************************************************************************************************************** +// +//********************************************************************************************************************** +void TrayIcon::refreshContextMenu() { + if (!menu_) { + app().log().error("Native tray icon context menu is null."); + return; + } + + menu_->clear(); + menu_->addAction(statusIcon_, stateString_, &app().backend(), &QMLBackend::showMainWindow); + menu_->addSeparator(); + UserList const &users = app().backend().users(); + qint32 const userCount = users.count(); + for (qint32 i = 0; i < userCount; i++) { + User const &user = *users.get(i); + UserState const state = user.state(); + auto action = new QAction(user.primaryEmailOrUsername()); + action->setIcon((UserState::Connected == state) ? greenDot_ : (UserState::Locked == state ? orangeDot_ : greyDot_)); + action->setData(user.id()); + connect(action, &QAction::triggered, this, &TrayIcon::onUserClicked); + if (i < 10) { + action->setShortcut(QKeySequence(QString("Ctrl+%1").arg((i + 1) % 10))); + } + menu_->addAction(action); + } + if (userCount) { + menu_->addSeparator(); + } + menu_->addAction(tr("&Open Bridge"), QKeySequence("Ctrl+O"), &app().backend(), &QMLBackend::showMainWindow); + menu_->addAction(tr("&Help"), QKeySequence("Ctrl+F1"), &app().backend(), &QMLBackend::showHelp); + menu_->addAction(tr("&Settings"), QKeySequence("Ctrl+,"), &app().backend(), &QMLBackend::showSettings); + menu_->addSeparator(); + menu_->addAction(tr("&Quit Bridge"), QKeySequence("Ctrl+Q"), &app().backend(), &QMLBackend::quit); +} diff --git a/internal/frontend/bridge-gui/bridge-gui/TrayIcon.h b/internal/frontend/bridge-gui/bridge-gui/TrayIcon.h new file mode 100644 index 00000000..8517ec8f --- /dev/null +++ b/internal/frontend/bridge-gui/bridge-gui/TrayIcon.h @@ -0,0 +1,70 @@ +// Copyright (c) 2023 Proton AG +// +// This file is part of Proton Mail 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 . + + +#ifndef BRIDGE_GUI_NATIVE_TRAY_ICON_H +#define BRIDGE_GUI_NATIVE_TRAY_ICON_H + + +//********************************************************************************************************************** +/// \brief A native tray icon. +//********************************************************************************************************************** +class TrayIcon: public QSystemTrayIcon { +Q_OBJECT +public: // typedef enum + enum class State { + Normal, + Error, + Warn, + Update, + }; ///< Enumeration for the state. + +public: // data members + TrayIcon(); ///< Default constructor. + ~TrayIcon() override = default; ///< Destructor. + TrayIcon(TrayIcon const&) = delete; ///< Disabled copy-constructor. + TrayIcon(TrayIcon&&) = delete; ///< Disabled assignment copy-constructor. + TrayIcon& operator=(TrayIcon const&) = delete; ///< Disabled assignment operator. + TrayIcon& operator=(TrayIcon&&) = delete; ///< Disabled move assignment operator. + void setState(State state, QString const& stateString, QString const &statusIconPath); ///< Set the state of the icon + +signals: + void selectUser(QString const& userID); ///< Signal for selecting a user with a given userID + +private slots: + void onMenuAboutToShow(); ///< Slot called before the context menu is shown. + void onUserClicked(); ///< Slot triggered when clicking on a user in the context menu. + static void onActivated(QSystemTrayIcon::ActivationReason reason); ///< Slot for the activation of the system tray icon. + +private: // member functions. + void generateDotIcons(); ///< generate the colored dot icons used for user status. + void generateStatusIcon(QString const &svgPath, QColor const& color); ///< Generate the status icon. + void refreshContextMenu(); ///< Refresh the context menu. + +private: // data members + State state_ { State::Normal }; ///< The state of the tray icon. + QString stateString_; ///< The current state string. + std::unique_ptr menu_; ///< The context menu for the tray icon. Not owned by the tray icon. + QIcon statusIcon_; ///< The path of the status icon displayed in the context menu. + QIcon greenDot_; ///< The green dot icon. + QIcon greyDot_; ///< The grey dot icon. + QIcon orangeDot_; ///< The orange dot icon. +}; + + + +#endif //BRIDGE_GUI_NATIVE_TRAY_ICON_H diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/Bridge.qml b/internal/frontend/bridge-gui/bridge-gui/qml/Bridge.qml index 8d116b3a..3e377ad7 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/Bridge.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/Bridge.qml @@ -26,11 +26,8 @@ import Notifications QtObject { id: root - function isInInterval(num, lower_limit, upper_limit) { - return lower_limit <= num && num <= upper_limit - } - function bound(num, lower_limit, upper_limit) { - return Math.max(lower_limit, Math.min(upper_limit, num)) + function bound(num, lowerLimit, upperLimit) { + return Math.max(lowerLimit, Math.min(upperLimit, num)) } property var title: Backend.appname @@ -38,10 +35,30 @@ QtObject { property Notifications _notifications: Notifications { id: notifications frontendMain: mainWindow - frontendStatus: statusWindow - frontendTray: trayIcon } + property NotificationFilter _trayNotificationFilter: NotificationFilter { + id: trayNotificationFilter + source: root._notifications ? root._notifications.all : undefined + onTopmostChanged: { + if (topmost) { + switch (topmost.type) { + case Notification.NotificationType.Danger: + Backend.setErrorTrayIcon(topmost.brief, topmost.icon) + return + case Notification.NotificationType.Warning: + Backend.setWarnTrayIcon(topmost.brief, topmost.icon) + return + case Notification.NotificationType.Info: + Backend.setUpdateTrayIcon(topmost.brief, topmost.icon) + return + } + } + Backend.setNormalTrayIcon() + } + } + + property MainWindow _mainWindow: MainWindow { id: mainWindow visible: false @@ -66,190 +83,6 @@ QtObject { } } - property StatusWindow _statusWindow: StatusWindow { - id: statusWindow - visible: false - - title: root.title - notifications: root._notifications - - onShowMainWindow: { - mainWindow.showAndRise() - } - - onShowHelp: { - mainWindow.showHelp() - mainWindow.showAndRise() - } - - onShowSettings: { - mainWindow.showSettings() - mainWindow.showAndRise() - } - - onSelectUser: function(userID) { - mainWindow.selectUser(userID) - mainWindow.showAndRise() - } - - onQuit: { - mainWindow.hide() - trayIcon.visible = false - Backend.quit() - } - - property rect screenRect - property rect iconRect - - // use binding from function with width and height as arguments so it will be recalculated every time width and height are changed - property point position: getPosition(width, height) - x: position.x - y: position.y - - function getPosition(_width, _height) { - if (screenRect.width === 0 || screenRect.height === 0) { - return Qt.point(0, 0) - } - - var _x = 0 - var _y = 0 - - // fit above - _y = iconRect.top - height - if (isInInterval(_y, screenRect.top, screenRect.bottom - height)) { - // position preferably in the horizontal center but bound to the screen rect - _x = bound(iconRect.left + (iconRect.width - width)/2, screenRect.left, screenRect.right - width) - return Qt.point(_x, _y) - } - - // fit below - _y = iconRect.bottom - if (isInInterval(_y, screenRect.top, screenRect.bottom - height)) { - // position preferably in the horizontal center but bound to the screen rect - _x = bound(iconRect.left + (iconRect.width - width)/2, screenRect.left, screenRect.right - width) - return Qt.point(_x, _y) - } - - // fit to the left - _x = iconRect.left - width - if (isInInterval(_x, screenRect.left, screenRect.right - width)) { - // position preferably in the vertical center but bound to the screen rect - _y = bound(iconRect.top + (iconRect.height - height)/2, screenRect.top, screenRect.bottom - height) - return Qt.point(_x, _y) - } - - // fit to the right - _x = iconRect.right - if (isInInterval(_x, screenRect.left, screenRect.right - width)) { - // position preferably in the vertical center but bound to the screen rect - _y = bound(iconRect.top + (iconRect.height - height)/2, screenRect.top, screenRect.bottom - height) - return Qt.point(_x, _y) - } - - // Fallback: position status window right above icon and let window manager decide. - console.warn("Can't position status window: screenRect =", screenRect, "iconRect =", iconRect) - _x = bound(iconRect.left + (iconRect.width - width)/2, screenRect.left, screenRect.right - width) - _y = bound(iconRect.top + (iconRect.height - height)/2, screenRect.top, screenRect.bottom - height) - return Qt.point(_x, _y) - } - } - - property SystemTrayIcon _trayIcon: SystemTrayIcon { - id: trayIcon - visible: true - icon.source: getTrayIconPath() - icon.mask: true // make sure that systems like macOS will use proper color - tooltip: `${root.title} v${Backend.version}` - onActivated: function(reason) { - function calcStatusWindowPosition() { - // On some platforms (X11 / Plasma) Qt does not provide icon position and geometry info. - // In this case we rely on cursor position - var iconRect = Qt.rect(geometry.x, geometry.y, geometry.width, geometry.height) - if (geometry.width == 0 && geometry.height == 0) { - var mousePos = Backend.getCursorPos() - iconRect.x = mousePos.x - iconRect.y = mousePos.y - iconRect.width = 0 - iconRect.height = 0 - } - - // Find screen - var screen - for (var i in Qt.application.screens) { - var _screen = Qt.application.screens[i] - if ( - isInInterval(iconRect.x, _screen.virtualX, _screen.virtualX + _screen.width) && - isInInterval(iconRect.y, _screen.virtualY, _screen.virtualY + _screen.height) - ) { - screen = _screen - break - } - } - if (!screen) { - // Fallback to primary screen - screen = Qt.application.screens[0] - } - - // In case we used mouse to detect icon position - we want to make a fake icon rectangle from a point - if (iconRect.width == 0 && iconRect.height == 0) { - iconRect.x = bound(iconRect.x - 16, screen.virtualX, screen.virtualX + screen.width - 32) - iconRect.y = bound(iconRect.y - 16, screen.virtualY, screen.virtualY + screen.height - 32) - iconRect.width = 32 - iconRect.height = 32 - } - - statusWindow.screenRect = Qt.rect(screen.virtualX, screen.virtualY, screen.width, screen.height) - statusWindow.iconRect = iconRect - } - - function toggleWindow(win) { - if (win.visible) { - win.close() - } else { - win.showAndRise() - } - } - - - switch (reason) { - case SystemTrayIcon.Unknown: - break; - case SystemTrayIcon.Context: - case SystemTrayIcon.Trigger: - case SystemTrayIcon.DoubleClick: - case SystemTrayIcon.MiddleClick: - calcStatusWindowPosition() - toggleWindow(statusWindow) - break; - default: - break; - } - } - - property NotificationFilter _systrayfilter: NotificationFilter { - source: root._notifications ? root._notifications.all : undefined - } - - function getTrayIconPath() { - var color = Backend.goos == "darwin" ? "mono" : "color" - - var level = "norm" - if (_systrayfilter.topmost) { - switch (_systrayfilter.topmost.type) { - case Notification.NotificationType.Danger: - level = "error" - break; - case Notification.NotificationType.Warning: - level = "warn" - break; - case Notification.NotificationType.Info: - level = "update" - break; - } - } - return `qrc:/qml/icons/systray-${color}-${level}.png` - } - } Component.onCompleted: { if (!Backend) { @@ -266,7 +99,7 @@ QtObject { var c = Backend.users.count var u = Backend.users.get(0) // DEBUG - if (c != 0) { + if (c !== 0) { console.log("users non zero", c) console.log("first user", u ) } @@ -290,7 +123,7 @@ QtObject { } function setColorScheme() { - if (Backend.colorSchemeName == "light") ProtonStyle.currentStyle = ProtonStyle.lightStyle - if (Backend.colorSchemeName == "dark") ProtonStyle.currentStyle = ProtonStyle.darkStyle + if (Backend.colorSchemeName === "light") ProtonStyle.currentStyle = ProtonStyle.lightStyle + if (Backend.colorSchemeName === "dark") ProtonStyle.currentStyle = ProtonStyle.darkStyle } } diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/BridgeTest/UserControl.qml b/internal/frontend/bridge-gui/bridge-gui/qml/BridgeTest/UserControl.qml deleted file mode 100644 index 349087ae..00000000 --- a/internal/frontend/bridge-gui/bridge-gui/qml/BridgeTest/UserControl.qml +++ /dev/null @@ -1,315 +0,0 @@ -// Copyright (c) 2023 Proton AG -// -// This file is part of Proton Mail 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 . - -import QtQml -import QtQuick -import QtQuick.Layouts -import QtQuick.Controls - -import Proton - -ColumnLayout { - id: root - - property var user - property var userIndex - - spacing : 5 - - Layout.fillHeight: true - //Layout.fillWidth: true - - property ColorScheme colorScheme - - TextField { - colorScheme: root.colorScheme - Layout.fillWidth: true - - text: user !== undefined ? user.username : "" - - onEditingFinished: { - user.username = text - } - } - - ColumnLayout { - Layout.fillWidth: true - - Switch { - id: userLoginSwitch - colorScheme: root.colorScheme - - text: "LoggedIn" - enabled: user !== undefined && user.username.length > 0 - - checked: user ? root.user.state == EUserState.Connected : false - - onCheckedChanged: { - if (!user) { - return - } - - if (checked) { - if (user === Backend.loginUser) { - var newUserObject = Backend.userComponent.createObject(Backend, {username: user.username, loggedIn: true, setupGuideSeen: user.setupGuideSeen}) - Backend.users.append( { object: newUserObject } ) - - user.username = "" - user.resetLoginRequests() - return - } - - user.state = EUserState.Connected - user.resetLoginRequests() - return - } else { - user.state = EUserState.SignedOut - user.resetLoginRequests() - } - } - } - - Switch { - colorScheme: root.colorScheme - - text: "Setup guide seen" - enabled: user !== undefined && user.username.length > 0 - - checked: user ? user.setupGuideSeen : false - - onCheckedChanged: { - if (!user) { - return - } - - user.setupGuideSeen = checked - } - } - } - - - RowLayout { - Layout.fillWidth: true - - Label { - colorScheme: root.colorScheme - id: loginLabel - text: "Login:" - - Layout.preferredWidth: Math.max(loginLabel.implicitWidth, faLabel.implicitWidth, passLabel.implicitWidth) - } - - Button { - colorScheme: root.colorScheme - text: "name/pass error" - enabled: user !== undefined //&& user.isLoginRequested && !user.isLogin2FARequested && !user.isLogin2PasswordProvided - - onClicked: { - Backend.loginUsernamePasswordError("") - user.resetLoginRequests() - } - } - - Button { - colorScheme: root.colorScheme - text: "free user error" - enabled: user !== undefined //&& user.isLoginRequested - onClicked: { - Backend.loginFreeUserError() - user.resetLoginRequests() - } - } - - Button { - colorScheme: root.colorScheme - text: "connection error" - enabled: user !== undefined //&& user.isLoginRequested - onClicked: { - Backend.loginConnectionError("") - user.resetLoginRequests() - } - } - } - - RowLayout { - Layout.fillWidth: true - - Label { - colorScheme: root.colorScheme - id: faLabel - text: "2FA:" - - Layout.preferredWidth: Math.max(loginLabel.implicitWidth, faLabel.implicitWidth, passLabel.implicitWidth) - } - - Button { - colorScheme: root.colorScheme - text: "request" - - enabled: user !== undefined //&& user.isLoginRequested && !user.isLogin2FARequested && !user.isLogin2PasswordRequested - onClicked: { - Backend.login2FARequested(user.username) - user.isLogin2FARequested = true - } - } - - Button { - colorScheme: root.colorScheme - text: "error" - - enabled: user !== undefined //&& user.isLogin2FAProvided && !(user.isLogin2PasswordRequested && !user.isLogin2PasswordProvided) - onClicked: { - Backend.login2FAError("") - user.isLogin2FAProvided = false - } - } - - Button { - colorScheme: root.colorScheme - text: "Abort" - - enabled: user !== undefined //&& user.isLogin2FAProvided && !(user.isLogin2PasswordRequested && !user.isLogin2PasswordProvided) - onClicked: { - Backend.login2FAErrorAbort("") - user.resetLoginRequests() - } - } - } - - RowLayout { - Layout.fillWidth: true - - Label { - colorScheme: root.colorScheme - id: passLabel - text: "2 Password:" - - Layout.preferredWidth: Math.max(loginLabel.implicitWidth, faLabel.implicitWidth, passLabel.implicitWidth) - } - - Button { - colorScheme: root.colorScheme - text: "request" - - enabled: user !== undefined //&& user.isLoginRequested && !user.isLogin2PasswordRequested && !(user.isLogin2FARequested && !user.isLogin2FAProvided) - onClicked: { - Backend.login2PasswordRequested("") - user.isLogin2PasswordRequested = true - } - } - - Button { - colorScheme: root.colorScheme - text: "error" - - enabled: user !== undefined //&& user.isLogin2PasswordProvided && !(user.isLogin2FARequested && !user.isLogin2FAProvided) - onClicked: { - Backend.login2PasswordError("") - - user.isLogin2PasswordProvided = false - } - } - - Button { - colorScheme: root.colorScheme - text: "Abort" - - enabled: user !== undefined //&& user.isLogin2PasswordProvided && !(user.isLogin2FARequested && !user.isLogin2FAProvided) - onClicked: { - Backend.login2PasswordErrorAbort("") - user.resetLoginRequests() - } - } - } - - RowLayout { - Button { - colorScheme: root.colorScheme - text: "Login Finished" - - onClicked: { - Backend.loginFinished(0+loginFinishedIndex.text) - user.resetLoginRequests() - } - } - TextField { - id: loginFinishedIndex - colorScheme: root.colorScheme - label: "Index:" - text: root.userIndex - } - } - - RowLayout { - Button { - colorScheme: root.colorScheme - text: "Already logged in" - - onClicked: { - Backend.loginAlreadyLoggedIn(0+loginAlreadyLoggedInIndex.text) - user.resetLoginRequests() - } - } - TextField { - id: loginAlreadyLoggedInIndex - colorScheme: root.colorScheme - label: "Index:" - text: root.userIndex - } - } - - RowLayout { - TextField { - colorScheme: root.colorScheme - label: "used:" - text: user && user.usedBytes ? user.usedBytes : 0 - onEditingFinished: { - user.usedBytes = parseFloat(text) - } - implicitWidth: 200 - } - TextField { - colorScheme: root.colorScheme - label: "total:" - text: user && user.totalBytes ? user.totalBytes : 0 - onEditingFinished: { - user.totalBytes = parseFloat(text) - } - implicitWidth: 200 - } - } - - RowLayout { - Label {colorScheme: root.colorScheme; text: "Split mode"} - Toggle { colorScheme: root.colorScheme; checked: user ? user.splitMode : false; onClicked: {user.splitMode = !user.splitMode}} - Button { colorScheme: root.colorScheme; text: "Toggle Finished"; onClicked: {user.toggleSplitModeFinished()}} - } - - TextArea { // TODO: this is causing binding loop on implicitWidth - colorScheme: root.colorScheme - text: user && user.addresses ? user.addresses.join("\n") : "user@protonmail.com" - Layout.fillWidth: true - - onEditingFinished: { - user.addresses = text.split("\n") - } - } - - Item { - Layout.fillHeight: true - } -} diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/BridgeTest/UserList.qml b/internal/frontend/bridge-gui/bridge-gui/qml/BridgeTest/UserList.qml deleted file mode 100644 index 92b50335..00000000 --- a/internal/frontend/bridge-gui/bridge-gui/qml/BridgeTest/UserList.qml +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright (c) 2023 Proton AG -// -// This file is part of Proton Mail 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 . - -import QtQuick -import QtQuick.Layouts -import QtQuick.Controls - -import Proton - -ColumnLayout { - id: root - - property ColorScheme colorScheme - - property alias currentIndex: usersListView.currentIndex - ListView { - id: usersListView - Layout.fillHeight: true - Layout.preferredWidth: 200 - - model: Backend.usersTest - highlightFollowsCurrentItem: true - - delegate: Item { - - implicitHeight: children[0].implicitHeight + anchors.topMargin + anchors.bottomMargin - implicitWidth: children[0].implicitWidth + anchors.leftMargin + anchors.rightMargin - - width: usersListView.width - - anchors.margins: 10 - - Label { - colorScheme: root.colorScheme - text: modelData.username - anchors.margins: 10 - anchors.fill: parent - - MouseArea { - anchors.fill: parent - onClicked: { - usersListView.currentIndex = index - } - } - } - } - - highlight: Rectangle { - color: root.colorScheme.interaction_default_active - } - } - - RowLayout { - Layout.fillWidth: true - - Button { - colorScheme: root.colorScheme - - text: "+" - - onClicked: { - var newUserObject = Backend.userComponent.createObject(Backend) - newUserObject.username = Backend.loginUser.username.length > 0 ? Backend.loginUser.username : "test@protonmail.com" - newUserObject.state = EUserState.Connected - newUserObject.setupGuideSeen = true // Backend.loginUser.setupGuideSeen - - Backend.loginUser.username = "" - Backend.loginUser.state = EUserState.SignedOut - Backend.loginUser.setupGuideSeen = false - - Backend.users.append( { object: newUserObject } ) - } - } - Button { - colorScheme: root.colorScheme - text: "-" - - enabled: usersListView.currentIndex != 0 - - onClicked: { - // var userObject = Backend.users.get(usersListView.currentIndex - 1) - Backend.users.remove(usersListView.currentIndex - 1) - // userObject.deleteLater() - } - } - } -} diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/BridgeTest/UserModel.qml b/internal/frontend/bridge-gui/bridge-gui/qml/BridgeTest/UserModel.qml deleted file mode 100644 index a8099aa7..00000000 --- a/internal/frontend/bridge-gui/bridge-gui/qml/BridgeTest/UserModel.qml +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2023 Proton AG -// -// This file is part of Proton Mail 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 . - -import QtQml.Models - -ListModel { - // overriding get method to ignore any role and return directly object itself - function get(row) { - if (row < 0 || row >= count) { - return undefined - } - return data(index(row, 0), Qt.DisplayRole) - } -} diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/Bridge_test.qml b/internal/frontend/bridge-gui/bridge-gui/qml/Bridge_test.qml deleted file mode 100644 index 8ca4e750..00000000 --- a/internal/frontend/bridge-gui/bridge-gui/qml/Bridge_test.qml +++ /dev/null @@ -1,982 +0,0 @@ -// Copyright (c) 2023 Proton AG -// -// This file is part of Proton Mail 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 . - -import QtQml -import QtQuick -import QtQuick.Window -import QtQuick.Layouts -import QtQuick.Controls - -import QtQml.Models - -import Qt.labs.platform - -import Proton - -import "./BridgeTest" -import BridgePreview - -import Notifications - -Window { - id: root - - x: 10 - y: 10 - width: 800 - height: 800 - - property ColorScheme colorScheme: ProtonStyle.darkStyle - - flags : Qt.Window | Qt.Dialog - visible : true - title : "Bridge Test GUI" - - // This is needed because on MacOS if first window shown is not transparent - - // all other windows of application will not have transparent background (black - // instead of transparency). In our case that mean that if BridgeTest will be - // shown before StatusWindow - StatusWindow will not have transparent corners. - color: "transparent" - - function getCursorPos() { - return BridgePreview.getCursorPos() - } - - function restart() { - root.quit() - console.log("Restarting....") - root.openBridge() - } - - function openBridge() { - bridge = bridgeComponent.createObject() - var showSetupGuide = false - if (showSetupGuide) { - var newUserObject = root.userComponent.createObject(root) - newUserObject.username = "LerooooyJenkins@protonmail.com" - newUserObject.state = EUserState.Connected - newUserObject.setupGuideSeen = false - root.users.append( { object: newUserObject } ) - } - } - - - function quit() { - if (bridge !== undefined && bridge !== null) { - bridge.destroy() - } - } - - function guiReady() { - console.log("Gui Ready") - } - - function _log(msg, color) { - logTextArea.text += "

" + msg + "

" - logTextArea.text += "\n" - } - - function log(msg) { - console.log(msg) - _log(msg, root.colorScheme.signal_info) - } - - function error(msg) { - console.error(msg) - _log(msg, root.colorScheme.signal_danger) - } - - // No user object should be put in this list until a successful login - property var users: UserModel { - id: _users - - onRowsInserted: { - for (var i = first; i <= last; i++) { - _usersTest.insert(i + 1, { object: get(i) } ) - } - } - - onRowsRemoved: { - _usersTest.remove(first + 1, first - last + 1) - } - - onRowsMoved: { - _usersTest.move(start + 1, row + 1, end - start + 1) - } - - onDataChanged: { - for (var i = topLeft.row; i <= bottomRight.row; i++) { - _usersTest.set(i + 1, { object: get(i) } ) - } - } - } - - // this list is used on test gui: it contains same users list as users above + fake user to represent login request of new user on pos 0 - property var usersTest: UserModel { - id: _usersTest - } - - property var userComponent: Component { - id: _userComponent - - QtObject { - property string username: "" - property bool loggedIn: false - property bool splitMode: false - - property bool setupGuideSeen: true - - property var usedBytes: 5350*1024*1024 - property var totalBytes: 20*1024*1024*1024 - property string avatarText: "jd" - - property string password: "SMj975NnEYYsqu55GGmlpv" - property var addresses: [ - "jaanedoe@protonmail.com", - "jane@pm.me", - "jdoe@pm.me" - ] - - signal loginUsernamePasswordError() - signal loginFreeUserError() - signal loginConnectionError() - signal login2FARequested() - signal login2FAError() - signal login2FAErrorAbort() - signal login2PasswordRequested() - signal login2PasswordError() - signal login2PasswordErrorAbort() - - // Test purpose only: - property bool isFakeUser: this === root.loginUser - - function userSignal(msg) { - if (isFakeUser) { - return - } - - root.log("<- User (" + username + "): " + msg) - } - - function toggleSplitMode(makeActive) { - userSignal("toggle split mode "+makeActive) - } - signal toggleSplitModeFinished() - - function configureAppleMail(address){ - userSignal("configure apple mail "+address) - } - - function logout(){ - userSignal("logout") - loggedIn = false - } - function remove(){ - console.log("remove this", users.count) - for (var i=0; i usersListView.currentIndex) && usersListView.currentIndex != -1) ? root.usersTest.get(usersListView.currentIndex) : undefined - userIndex: usersListView.currentIndex - 1 // -1 because 0 index is fake user - } - } - - RowLayout { - id: notificationsTab - spacing: 5 - - ColumnLayout { - spacing: 5 - - Switch { - text: "Internet connection" - colorScheme: root.colorScheme - checked: true - onCheckedChanged: { - checked ? root.internetOn() : root.internetOff() - } - } - - Button { - text: "Update manual ready" - colorScheme: root.colorScheme - onClicked: { - root.updateManualReady("3.14.1592") - } - } - - Button { - text: "Update manual done" - colorScheme: root.colorScheme - onClicked: { - root.updateManualRestartNeeded() - } - } - - Button { - text: "Update manual error" - colorScheme: root.colorScheme - onClicked: { - root.updateManualError() - } - } - - Button { - text: "Update force" - colorScheme: root.colorScheme - onClicked: { - root.updateForce("3.14.1592") - } - } - - Button { - text: "Update force error" - colorScheme: root.colorScheme - onClicked: { - root.updateForceError() - } - } - - Button { - text: "Update silent done" - colorScheme: root.colorScheme - onClicked: { - root.updateSilentRestartNeeded() - } - } - - Button { - text: "Update silent error" - colorScheme: root.colorScheme - onClicked: { - root.updateSilentError() - } - } - - Button { - text: "Update is latest version" - colorScheme: root.colorScheme - onClicked: { - root.updateIsLatestVersion() - } - } - - Button { - text: "Bug report send OK" - colorScheme: root.colorScheme - onClicked: { - root.reportBugFinished() - root.bugReportSendSuccess() - } - - } - } - - ColumnLayout { - spacing: 5 - - Button { - text: "Bug report send error" - colorScheme: root.colorScheme - onClicked: { - root.reportBugFinished() - root.bugReportSendError() - } - } - - Button { - text: "Cache anavailable" - colorScheme: root.colorScheme - onClicked: { - root.cacheUnavailable() - } - } - - Button { - text: "Cache can't move" - colorScheme: root.colorScheme - onClicked: { - root.cacheCantMove() - } - } - - Button { - text: "Cache location change success" - onClicked: { - root.cacheLocationChangeSuccess() - } - colorScheme: root.colorScheme - } - - Button { - text: "Disk full" - colorScheme: root.colorScheme - onClicked: { - root.diskFull() - } - } - - Button { - text: "No keychain" - colorScheme: root.colorScheme - onClicked: { - root.notifyHasNoKeychain() - } - } - - Button { - text: "Rebuild keychain" - colorScheme: root.colorScheme - onClicked: { - root.notifyRebuildKeychain() - } - } - - Button { - text: "Address changed" - colorScheme: root.colorScheme - onClicked: { - root.addressChanged("p@v.el") - } - } - - Button { - text: "Address changed + Logout" - colorScheme: root.colorScheme - onClicked: { - root.addressChangedLogout("p@v.el") - } - } - } - } - - TextArea { - id: logTextArea - colorScheme: root.colorScheme - Layout.fillHeight: true - Layout.fillWidth: true - - Layout.preferredWidth: 400 - Layout.preferredHeight: 200 - - textFormat: TextEdit.RichText - //readOnly: true - } - - ScrollView { - id: settingsTab - ColumnLayout { - RowLayout { - Label {colorScheme : root.colorScheme ; text : "GOOS : "} - Button {colorScheme : root.colorScheme ; text : "Linux" ; onClicked : root.goos = "linux" ; enabled: root.goos != "linux"} - Button {colorScheme : root.colorScheme ; text : "Windows" ; onClicked : root.goos = "windows" ; enabled: root.goos != "windows"} - Button {colorScheme : root.colorScheme ; text : "macOS" ; onClicked : root.goos = "darwin" ; enabled: root.goos != "darwin"} - } - RowLayout { - Label {colorScheme: root.colorScheme; text: "Automatic updates:"} - Toggle {colorScheme: root.colorScheme; checked: root.isAutomaticUpdateOn; onClicked: root.isAutomaticUpdateOn = !root.isAutomaticUpdateOn} - } - RowLayout { - Label {colorScheme: root.colorScheme; text: "Autostart:"} - Toggle {colorScheme: root.colorScheme; checked: root.isAutostartOn; onClicked: root.isAutostartOn = !root.isAutostartOn} - Button {colorScheme: root.colorScheme; text: "Toggle finished"; onClicked: root.toggleAutostartFinished()} - } - RowLayout { - Label {colorScheme: root.colorScheme; text: "Beta:"} - Toggle {colorScheme: root.colorScheme; checked: root.isBetaEnabled; onClicked: root.isBetaEnabled = !root.isBetaEnabled} - } - RowLayout { - Label {colorScheme: root.colorScheme; text: "DoH:"} - Toggle {colorScheme: root.colorScheme; checked: root.isDoHEnabled; onClicked: root.isDoHEnabled = !root.isDoHEnabled} - } - RowLayout { - Label {colorScheme: root.colorScheme; text: "All Mail disabled:"} - Toggle {colorScheme: root.colorScheme; checked: root.isAllMailVisible; onClicked: root.isAllMailVisible = !root.isAllMailVisible} - } - RowLayout { - Label {colorScheme: root.colorScheme; text: "Ports:"} - TextField { - colorScheme:root.colorScheme - label: "IMAP" - text: root.portIMAP - onEditingFinished: root.portIMAP = this.text*1 - validator: IntValidator {bottom: 1; top: 65536} - } - TextField { - colorScheme:root.colorScheme - label: "SMTP" - text: root.portSMTP - onEditingFinished: root.portSMTP = this.text*1 - validator: IntValidator {bottom: 1; top: 65536} - } - Button {colorScheme: root.colorScheme; text: "Change finished"; onClicked: root.changePortFinished()} - } - RowLayout { - Label {colorScheme: root.colorScheme; text: "SMTP using SSL:"} - Toggle {colorScheme: root.colorScheme; checked: root.useSSLForSMTP; onClicked: root.useSSLForSMTP = !root.useSSLForSMTP} - } - RowLayout { - Label {colorScheme: root.colorScheme; text: "Local cache:"} - Toggle {colorScheme: root.colorScheme; checked: root.isDiskCacheEnabled; onClicked: root.isDiskCacheEnabled = !root.isDiskCacheEnabled} - TextField { - colorScheme:root.colorScheme - label: "Path" - text: root.diskCachePath.toString().replace("file://", "") - implicitWidth: 160 - onEditingFinished: { - root.diskCachePath = Qt.resolvedUrl("file://"+text) - } - } - Button {colorScheme: root.colorScheme; text: "Change finished"; onClicked: root.changeLocalCacheFinished()} - } - RowLayout { - Label {colorScheme: root.colorScheme; text: "Reset:"} - Button {colorScheme: root.colorScheme; text: "Finished"; onClicked: root.resetFinished()} - } - RowLayout { - Label {colorScheme: root.colorScheme; text: "Check update:"} - Button {colorScheme: root.colorScheme; text: "Finished"; onClicked: root.checkUpdatesFinished()} - } - } - } - } - } - - property Bridge bridge - - property string goos: "darwin" - - property bool showOnStartup: true // this actually needs to be false, but since we use Bridge_test for testing purpose - lets default this to true just for convenience - property bool dockIconVisible: false - - // this signals are used only when trying to login with new user (i.e. not in users model) - signal loginUsernamePasswordError(string errorMsg) - signal loginFreeUserError() - signal loginConnectionError(string errorMsg) - signal login2FARequested(string username) - signal login2FAError(string errorMsg) - signal login2FAErrorAbort(string errorMsg) - signal login2PasswordRequested() - signal login2PasswordError(string errorMsg) - signal login2PasswordErrorAbort(string errorMsg) - signal loginFinished(int index) - signal loginAlreadyLoggedIn(int index) - - signal internetOff() - signal internetOn() - - signal updateManualReady(var version) - signal updateManualRestartNeeded() - signal updateManualError() - signal updateForce(var version) - signal updateForceError() - signal updateSilentRestartNeeded() - signal updateSilentError() - signal updateIsLatestVersion() - function checkUpdates(){ - console.log("check updates") - } - signal checkUpdatesFinished() - function installUpdate() { - console.log("manuall install update triggered") - } - - - property bool isDiskCacheEnabled: true - // Qt.resolvedUrl("file:///C:/Users/user/AppData/Roaming/protonmail/bridge-v3/cache/c11/messages") - property url diskCachePath: StandardPaths.standardLocations(StandardPaths.HomeLocation)[0] - signal cacheUnavailable() - signal cacheCantMove() - signal cacheLocationChangeSuccess() - signal diskFull() - function changeLocalCache(enableDiskCache, diskCachePath) { - console.debug("-> disk cache", enableDiskCache, diskCachePath) - } - signal changeLocalCacheFinished() - - - // Settings - property bool isAutomaticUpdateOn : true - function toggleAutomaticUpdate(makeItActive) { - console.debug("-> silent updates", makeItActive, root.isAutomaticUpdateOn) - var callback = function () { - root.isAutomaticUpdateOn = makeItActive; - console.debug("-> CHANGED silent updates", makeItActive, root.isAutomaticUpdateOn) - } - atimer.onTriggered.connect(callback) - atimer.restart() - } - - Timer { - id: atimer - interval: 2000 - running: false - repeat: false - } - - property bool isAutostartOn : true // Example of settings with loading state - function toggleAutostart(makeItActive) { - console.debug("-> autostart", makeItActive, root.isAutostartOn) - } - signal toggleAutostartFinished() - - property bool isBetaEnabled : false - function toggleBeta(makeItActive){ - console.debug("-> beta", makeItActive, root.isBetaEnabled) - root.isBetaEnabled = makeItActive - } - - property bool isDoHEnabled : true - function toggleDoH(makeItActive){ - console.debug("-> DoH", makeItActive, root.isDoHEnabled) - root.isDoHEnabled = makeItActive - } - - property bool isAllMailVisible : true - function changeIsAllMailVisible(isVisible){ - console.debug("-> All Mail Visible", isVisible, root.isAllMailVisible) - root.isAllMailVisible = isVisible - } - - - property bool useSSLForSMTP: false - function toggleUseSSLForSMTP(makeItActive){ - console.debug("-> SMTP SSL", makeItActive, root.useSSLForSMTP) - } - signal toggleUseSSLFinished() - - property string hostname: "127.0.0.1" - property int portIMAP: 1143 - property int portSMTP: 1025 - function changePorts(imapPort, smtpPort){ - console.debug("-> ports", imapPort, smtpPort) - } - function isPortFree(port){ - if (port == portIMAP) return false - if (port == portSMTP) return false - if (port == 12345) return false - return true - } - signal changePortFinished() - signal imapPortStartupError() - signal smtpPortStartupError() - - function triggerReset() { - console.debug("-> trigger reset") - } - signal resetFinished() - - property string version: "2.0.X-BridePreview" - property url logsPath: StandardPaths.standardLocations(StandardPaths.HomeLocation)[0] - property url licensePath: StandardPaths.standardLocations(StandardPaths.HomeLocation)[0] - property url releaseNotesLink: Qt.resolvedUrl("https://proton.me/download/bridge/early_releases.html") - property url dependencyLicensesLink: Qt.resolvedUrl("https://github.com/ProtonMail/proton-bridge/v3/blob/master/COPYING_NOTES.md#dependencies") - property url landingPageLink: Qt.resolvedUrl("https://proton.me/mail/bridge#download") - - property string colorSchemeName: "light" - function changeColorScheme(newScheme){ - root.colorSchemeName = newScheme - } - - - property string currentEmailClient: "" // "Apple Mail 14.0" - function updateCurrentMailClient(){ - currentEmailClient = "Apple Mail 14.0" - } - - function reportBug(description,address,emailClient,includeLogs){ - console.log("report bug") - console.log(" description",description) - console.log(" address",address) - console.log(" emailClient",emailClient) - console.log(" includeLogs",includeLogs) - } - signal reportBugFinished() - signal bugReportSendSuccess() - signal bugReportSendError() - - property var availableKeychain: ["gnome-keyring", "pass", "macos-keychain", "windows-credentials"] - property string currentKeychain: availableKeychain[0] - function changeKeychain(wantedKeychain){ - console.log("Changing keychain from", root.currentKeychain, "to", wantedKeychain) - root.currentKeychain = wantedKeychain - root.changeKeychainFinished() - } - signal changeKeychainFinished() - signal notifyHasNoKeychain() - signal notifyRebuildKeychain() - - signal noActiveKeyForRecipient(string email) - signal showMainWindow() - - signal addressChanged(string address) - signal addressChangedLogout(string address) - signal userDisconnected(string username) - signal apiCertIssue() - - property bool showSplashScreen: false - - - function login(username, password) { - root.log("-> login(" + username + ", " + password + ")") - - loginUser.username = username - loginUser.isLoginRequested = true - } - - function login2FA(username, code) { - root.log("-> login2FA(" + username + ", " + code + ")") - - loginUser.isLogin2FAProvided = true - } - - function login2Password(username, password) { - root.log("-> login2FA(" + username + ", " + password + ")") - - loginUser.isLogin2PasswordProvided = true - } - - function loginAbort(username) { - root.log("-> loginAbort(" + username + ")") - - loginUser.resetLoginRequests() - } - - - onLoginUsernamePasswordError: { - console.debug("<- loginUsernamePasswordError") - } - onLoginFreeUserError: { - console.debug("<- loginFreeUserError") - } - onLoginConnectionError: { - console.debug("<- loginConnectionError") - } - onLogin2FARequested: { - console.debug("<- login2FARequested", username) - } - onLogin2FAError: { - console.debug("<- login2FAError") - } - onLogin2FAErrorAbort: { - console.debug("<- login2FAErrorAbort") - } - onLogin2PasswordRequested: { - console.debug("<- login2PasswordRequested") - } - onLogin2PasswordError: { - console.debug("<- login2PasswordError") - } - onLogin2PasswordErrorAbort: { - console.debug("<- login2PasswordErrorAbort") - } - onLoginFinished: { - console.debug("<- loginFinished", index) - } - onLoginAlreadyLoggedIn: { - console.debug("<- loginAlreadyLoggedIn", index) - } - - onInternetOff: { - console.debug("<- internetOff") - } - onInternetOn: { - console.debug("<- internetOn") - } - - Component { - id: bridgeComponent - - Bridge { - backend: root - - } - } - - onClosing: { - Qt.quit() - } -} diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/MainWindow.qml b/internal/frontend/bridge-gui/bridge-gui/qml/MainWindow.qml index 877eaf9f..9295d7f5 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/MainWindow.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/MainWindow.qml @@ -24,8 +24,6 @@ import QtQuick.Controls import Proton import Notifications -import "tests" - ApplicationWindow { id: root colorScheme: ProtonStyle.currentStyle @@ -79,10 +77,6 @@ ApplicationWindow { root.showAndRise() } - function onSelectUser(userID) { - root.selectUser(userID) - } - function onLoginFinished(index, wasSignedOut) { var user = Backend.users.get(index) if (user && !wasSignedOut) { @@ -90,6 +84,21 @@ ApplicationWindow { } console.debug("Login finished", index) } + + function onShowHelp() { + root.showHelp() + root.showAndRise() + } + + function onShowSettings() { + root.showSettings() + root.showAndRise() + } + + function onSelectUser(userID) { + contentWrapper.selectUser(userID) + root.showAndRise() + } } StackLayout { diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/Notifications/Notifications.qml b/internal/frontend/bridge-gui/bridge-gui/qml/Notifications/Notifications.qml index f13642b7..1431aa36 100644 --- a/internal/frontend/bridge-gui/bridge-gui/qml/Notifications/Notifications.qml +++ b/internal/frontend/bridge-gui/bridge-gui/qml/Notifications/Notifications.qml @@ -24,8 +24,6 @@ QtObject { id: root property MainWindow frontendMain - property StatusWindow frontendStatus - property SystemTrayIcon frontendTray signal askEnableBeta() signal askEnableSplitMode(var user) @@ -140,7 +138,7 @@ QtObject { property Notification imapPortChangeError: Notification { description: qsTr("The IMAP port could not be changed.") - brief: qsTr("IMAP port change error") + brief: qsTr("IMAP port error") icon: "./icons/ic-alert.svg" type: Notification.NotificationType.Danger group: Notifications.Group.Connection @@ -156,7 +154,7 @@ QtObject { property Notification smtpPortChangeError: Notification { description: qsTr("The SMTP port could not be changed.") - brief: qsTr("SMTP port change error") + brief: qsTr("SMTP port error") icon: "./icons/ic-alert.svg" type: Notification.NotificationType.Danger group: Notifications.Group.Connection @@ -172,7 +170,7 @@ QtObject { property Notification imapConnectionModeChangeError: Notification { description: qsTr("The IMAP connection mode could not be changed.") - brief: qsTr("IMAP Connection mode change error") + brief: qsTr("IMAP Connection mode error") icon: "./icons/ic-alert.svg" type: Notification.NotificationType.Danger group: Notifications.Group.Connection @@ -196,7 +194,7 @@ QtObject { property Notification smtpConnectionModeChangeError: Notification { description: qsTr("The SMTP connection mode could not be changed.") - brief: qsTr("SMTP Connection mode change error") + brief: qsTr("SMTP Connection mode error") icon: "./icons/ic-alert.svg" type: Notification.NotificationType.Danger group: Notifications.Group.Connection @@ -227,7 +225,7 @@ QtObject { var link = Backend.releaseNotesLink return `${descr} ${text}` } - brief: qsTr("Update available.") + brief: qsTr("Update available") icon: "./icons/ic-info-circle-filled.svg" type: Notification.NotificationType.Info group: Notifications.Group.Update | Notifications.Group.Dialogs @@ -514,7 +512,7 @@ QtObject { // login property Notification loginConnectionError: Notification { description: qsTr("Bridge is not able to contact the server, please check your internet connection.") - brief: description + brief: qsTr("Connection error") icon: "./icons/ic-exclamation-circle-filled.svg" type: Notification.NotificationType.Danger group: Notifications.Group.Configuration @@ -538,7 +536,7 @@ QtObject { property Notification onlyPaidUsers: Notification { description: qsTr("Bridge is exclusive to our paid plans. Upgrade your account to use Bridge.") - brief: description + brief: qsTr("Upgrade your account") icon: "./icons/ic-exclamation-circle-filled.svg" type: Notification.NotificationType.Danger group: Notifications.Group.Configuration @@ -562,7 +560,7 @@ QtObject { property Notification alreadyLoggedIn: Notification { description: qsTr("This account is already signed in.") - brief: description + brief: qsTr("Already signed in") icon: "./icons/ic-exclamation-circle-filled.svg" type: Notification.NotificationType.Info group: Notifications.Group.Configuration @@ -587,7 +585,7 @@ QtObject { // Bug reports property Notification bugReportSendSuccess: Notification { description: qsTr("Thank you for the report. We'll get back to you as soon as we can.") - brief: description + brief: qsTr("Report sent") icon: "./icons/ic-info-circle-filled.svg" type: Notification.NotificationType.Success group: Notifications.Group.Configuration @@ -611,7 +609,7 @@ QtObject { property Notification bugReportSendError: Notification { description: qsTr("Report could not be sent. Try again or email us directly.") - brief: description + brief: qsTr("Error sending report") icon: "./icons/ic-exclamation-circle-filled.svg" type: Notification.NotificationType.Danger group: Notifications.Group.Configuration @@ -634,8 +632,8 @@ QtObject { // Cache property Notification cacheUnavailable: Notification { title: qsTr("Cache location is unavailable") - description: qsTr("Check the directory or change it in your settings.") - brief: qsTr("The current cache location is unavailable. Check the directory or change it in your settings.") + description: qsTr("The current cache location is unavailable. Check the directory or change it in your settings.") + brief: title icon: "./icons/ic-exclamation-circle-filled.svg" type: Notification.NotificationType.Warning group: Notifications.Group.Configuration | Notifications.Group.Dialogs @@ -725,7 +723,7 @@ QtObject { // Other property Notification accountChanged: Notification { description: qsTr("The address list for .... account has changed. You need to reconfigure your email client.") - brief: qsTr("The address list for your account has changed. Reconfigure your email client.") + brief: qsTr("Address list changed") icon: "./icons/ic-exclamation-circle-filled.svg" type: Notification.NotificationType.Danger group: Notifications.Group.Configuration @@ -742,7 +740,7 @@ QtObject { property Notification diskFull: Notification { title: qsTr("Your disk is almost full") description: qsTr("Quit Bridge and free disk space or disable the local cache (not recommended).") - brief: qsTr("Your disk is almost full. Free disk space or disable the local cache.") + brief: title icon: "./icons/ic-exclamation-circle-filled.svg" type: Notification.NotificationType.Warning group: Notifications.Group.Configuration | Notifications.Group.Dialogs @@ -948,8 +946,8 @@ QtObject { property Notification noKeychain: Notification { title: qsTr("No keychain available") - description: qsTr("Bridge is not able to detect a supported password manager (pass or secret-service). Please install and setup supported password manager and restart the application.") brief: title + description: qsTr("Bridge is not able to detect a supported password manager (pass or secret-service). Please install and setup supported password manager and restart the application.") icon: "./icons/ic-exclamation-circle-filled.svg" type: Notification.NotificationType.Danger group: Notifications.Group.Dialogs | Notifications.Group.Configuration @@ -982,8 +980,8 @@ QtObject { property Notification rebuildKeychain: Notification { title: qsTr("Your macOS keychain might be corrupted") - description: qsTr("Bridge is not able to access your macOS keychain. Please consult the instructions on our support page.") brief: title + description: qsTr("Bridge is not able to access your macOS keychain. Please consult the instructions on our support page.") icon: "./icons/ic-exclamation-circle-filled.svg" type: Notification.NotificationType.Danger group: Notifications.Group.Dialogs | Notifications.Group.Configuration @@ -1014,8 +1012,8 @@ QtObject { property Notification addressChanged: Notification { title: qsTr("Address list changes") + brief: title description: qsTr("The address list for your account has changed. You might need to reconfigure your email client.") - brief: description icon: "./icons/ic-exclamation-circle-filled.svg" type: Notification.NotificationType.Warning group: Notifications.Group.Configuration @@ -1047,11 +1045,11 @@ QtObject { property Notification apiCertIssue: Notification { title: qsTr("Unable to establish a \nsecure connection to \nProton servers") + brief: qsTr("Cannot establish secure connection") description: qsTr("Bridge cannot verify the authenticity of Proton servers on your current network due to a TLS certificate error. " + "Start Bridge again after ensuring your connection is secure and/or connecting to a VPN. Learn more about TLS pinning " + "here.") - brief: title icon: "./icons/ic-exclamation-circle-filled.svg" type: Notification.NotificationType.Danger group: Notifications.Group.Dialogs | Notifications.Group.Connection @@ -1078,6 +1076,7 @@ QtObject { property Notification noActiveKeyForRecipient: Notification { title: qsTr("Unable to send \nencrypted message") + brief: title description: "#PlaceholderText#" icon: "./icons/ic-exclamation-circle-filled.svg" type: Notification.NotificationType.Danger @@ -1174,8 +1173,9 @@ QtObject { } property Notification genericError: Notification { - title: "#PlaceholderText#" - description: "#PlaceholderText#" + title: "" + brief: title + description: "" icon: "./icons/ic-exclamation-circle-filled.svg" type: Notification.NotificationType.Danger group: Notifications.Group.Dialogs @@ -1201,7 +1201,7 @@ QtObject { property Notification genericQuestion: Notification { title: "" - brief: "" + brief: title description: "" type: Notification.NotificationType.Warning group: Notifications.Group.Dialogs diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/StatusWindow.qml b/internal/frontend/bridge-gui/bridge-gui/qml/StatusWindow.qml deleted file mode 100644 index 2269acaa..00000000 --- a/internal/frontend/bridge-gui/bridge-gui/qml/StatusWindow.qml +++ /dev/null @@ -1,352 +0,0 @@ -// Copyright (c) 2023 Proton AG -// -// This file is part of Proton Mail 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 . - -import QtQml -import QtQuick -import QtQuick.Window -import QtQuick.Layouts -import QtQuick.Controls - -import Proton -import Notifications - -Window { - id: root - - height: contentLayout.implicitHeight - width: contentLayout.implicitWidth - - flags: (Qt.platform.os === "linux" ? Qt.Tool : 0) | Qt.FramelessWindowHint | Qt.NoDropShadowWindowHint | Qt.WindowStaysOnTopHint | Qt.WA_TranslucentBackground - color: "transparent" - - property ColorScheme colorScheme: ProtonStyle.currentStyle - - property var notifications - - signal showMainWindow() - signal showHelp() - signal showSettings() - signal selectUser(string userID) - signal quit() - - MouseArea { - id: mouseArea - anchors.fill: parent - hoverEnabled: true - } - - function enableHoverOnOpenBridgeButton() { - openBridgeButton.hoverEnabled = true - mouseArea.positionChanged.disconnect(enableHoverOnOpenBridgeButton) - } - - onVisibleChanged: { - if (visible) { // GODT-1479 To avoid a visual glitch where the 'Open bridge button' would appear hovered when the status windows opens, - // we've disabled hover on it when it was last closed. Re-enabling hover here will not work on all platforms. so we temporarily connect - // mouse move event over the window's mouseArea to a function that will re-enable hover on the open bridge button. - openBridgeButton.focus = false - mouseArea.positionChanged.connect(enableHoverOnOpenBridgeButton) - } else { - menu.close() - } - } - - ColumnLayout { - id: contentLayout - - Layout.minimumHeight: 201 - - anchors.fill: parent - spacing: 0 - - ColumnLayout { - Layout.minimumWidth: 448 - Layout.fillWidth: true - spacing: 0 - - Item { - implicitHeight: 12 - Layout.fillWidth: true - clip: true - Rectangle { - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - height: parent.height * 2 - radius: ProtonStyle.dialog_radius - - color: { - if (!statusItem.activeNotification) { - return root.colorScheme.signal_success - } - - switch (statusItem.activeNotification.type) { - case Notification.NotificationType.Danger: - return root.colorScheme.signal_danger - case Notification.NotificationType.Warning: - return root.colorScheme.signal_warning - case Notification.NotificationType.Success: - return root.colorScheme.signal_success - case Notification.NotificationType.Info: - return root.colorScheme.signal_info - } - } - } - } - - Rectangle { - Layout.fillWidth: true - - implicitHeight: children[0].implicitHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin - implicitWidth: children[0].implicitWidth + children[0].anchors.leftMargin + children[0].anchors.rightMargin - - color: colorScheme.background_norm - - RowLayout { - anchors.fill: parent - - anchors.topMargin: 8 - anchors.bottomMargin: 8 - anchors.leftMargin: 24 - anchors.rightMargin: 24 - - spacing: 8 - - Status { - id: statusItem - - Layout.fillWidth: true - - Layout.topMargin: 12 - Layout.bottomMargin: 12 - - colorScheme: root.colorScheme - notifications: root.notifications - - notificationWhitelist: Notifications.Group.Connection | Notifications.Group.Update | Notifications.Group.Configuration - } - - Button { - colorScheme: root.colorScheme - secondary: true - - Layout.topMargin: 12 - Layout.bottomMargin: 12 - - visible: statusItem.activeNotification && statusItem.activeNotification.action.length > 0 - action: statusItem.activeNotification && statusItem.activeNotification.action.length > 0 ? statusItem.activeNotification.action[0] : null - } - } - } - - Rectangle { - Layout.fillWidth: true - height: 1 - color: root.colorScheme.background_norm - - Rectangle { - anchors.fill: parent - anchors.leftMargin: 24 - anchors.rightMargin: 24 - color: root.colorScheme.border_norm - } - } - } - - Rectangle { - Layout.fillWidth: true - Layout.fillHeight: true - - Layout.maximumHeight: accountListView.count ? - accountListView.contentHeight / accountListView.count * 3 + accountListView.anchors.topMargin + accountListView.anchors.bottomMargin : - Number.POSITIVE_INFINITY - - color: root.colorScheme.background_norm - clip: true - - implicitHeight: children[0].contentHeight + children[0].anchors.topMargin + children[0].anchors.bottomMargin - implicitWidth: children[0].contentWidth + children[0].anchors.leftMargin + children[0].anchors.rightMargin - - ListView { - id: accountListView - - model: Backend.users - anchors.fill: parent - - anchors.topMargin: 8 - anchors.bottomMargin: 8 - anchors.leftMargin: 24 - anchors.rightMargin: 24 - - interactive: contentHeight > parent.height - snapMode: ListView.SnapToItem - boundsBehavior: Flickable.StopAtBounds - - spacing: 4 - - delegate: Item { - id: viewItem - width: ListView.view.width - - implicitHeight: children[0].implicitHeight - implicitWidth: children[0].implicitWidth - - property var user: Backend.users.get(index) - - RowLayout { - spacing: 0 - anchors.fill: parent - - AccountDelegate { - Layout.fillWidth: true - - Layout.topMargin: 12 - Layout.bottomMargin: 12 - - user: viewItem.user - colorScheme: root.colorScheme - } - - Button { - Layout.topMargin: 12 - Layout.bottomMargin: 12 - - colorScheme: root.colorScheme - visible: viewItem.user ? (viewItem.user.state === EUserState.SignedOut) : false - text: qsTr("Sign in") - onClicked: { - root.selectUser(viewItem.user.id) // selectUser will show login screen if user is in SignedOut state. - root.close() - } - } - } - } - } - } - - Item { - Layout.fillWidth: true - - implicitHeight: children[1].implicitHeight + children[1].anchors.topMargin + children[1].anchors.bottomMargin - implicitWidth: children[1].implicitWidth + children[1].anchors.leftMargin + children[1].anchors.rightMargin - - // background: - clip: true - Rectangle { - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - height: parent.height * 2 - radius: ProtonStyle.dialog_radius - - color: root.colorScheme.background_weak - } - - RowLayout { - anchors.fill: parent - anchors.margins: 8 - spacing: 0 - - Button { - id: openBridgeButton - colorScheme: root.colorScheme - secondary: true - text: qsTr("Open Bridge") - - borderless: true - labelType: Label.LabelType.Caption_semibold - - onClicked: { - // GODT-1479: we disable hover for the button to avoid a visual glitch where the button is - // wrongly hovered when re-opening the status window after clicking - hoverEnabled = false; - root.showMainWindow() - root.close() - } - } - - Item { - Layout.fillWidth: true - } - - Button { - colorScheme: root.colorScheme - secondary: true - icon.source: "/qml/icons/ic-three-dots-vertical.svg" - borderless: true - checkable: true - - onClicked: { - menu.open() - } - - Menu { - id: menu - colorScheme: root.colorScheme - modal: true - - y: 0 - height - - MenuItem { - colorScheme: root.colorScheme - text: qsTr("Help") - onClicked: { - root.showHelp() - root.close() - } - } - MenuItem { - colorScheme: root.colorScheme - text: qsTr("Settings") - onClicked: { - root.showSettings() - root.close() - } - } - MenuItem { - colorScheme: root.colorScheme - text: qsTr("Quit Bridge") - onClicked: { - root.close() - root.quit() - } - } - - onClosed: { - parent.checked = false - } - onOpened: { - parent.checked = true - } - } - } - } - } - } - - onActiveChanged: { - if (!active) root.close() - } - - function showAndRise() { - root.show() - root.raise() - if (!root.active) { - root.requestActivate() - } - } -} diff --git a/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-dot.svg b/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-dot.svg new file mode 100644 index 00000000..d025c3ef --- /dev/null +++ b/internal/frontend/bridge-gui/bridge-gui/qml/icons/ic-dot.svg @@ -0,0 +1,7 @@ + + + + + + + From f9a0c35daa7217d4bebd8d8d93a8720336eeec04 Mon Sep 17 00:00:00 2001 From: Leander Beernaert Date: Tue, 25 Apr 2023 13:46:40 +0200 Subject: [PATCH 53/54] fix(GODT-2588): Always perma-delete from Drafts/Trash --- internal/user/imap.go | 28 ++----------------- .../imap/message/delete_from_trash.feature | 6 ++-- 2 files changed, 5 insertions(+), 29 deletions(-) diff --git a/internal/user/imap.go b/internal/user/imap.go index 86a4cf5b..6d329e95 100644 --- a/internal/user/imap.go +++ b/internal/user/imap.go @@ -400,32 +400,8 @@ func (conn *imapConnector) RemoveMessagesFromMailbox(ctx context.Context, messag } if mailboxID == proton.TrashLabel || mailboxID == proton.DraftsLabel { - var metadata []proton.MessageMetadata - - // There's currently no limit on how many IDs we can filter on, - // but to be nice to API, let's chunk it by 150. - for _, messageIDs := range xslices.Chunk(messageIDs, 150) { - m, err := conn.client.GetMessageMetadata(ctx, proton.MessageFilter{ - ID: mapTo[imap.MessageID, string](messageIDs), - }) - if err != nil { - return err - } - - // If a message is not preset in any other label other than AllMail, AllDrafts and AllSent, it can be - // permanently deleted. - m = xslices.Filter(m, func(m proton.MessageMetadata) bool { - labelsThatMatter := xslices.Filter(m.LabelIDs, func(id string) bool { - return id != proton.AllDraftsLabel && id != proton.AllMailLabel && id != proton.AllSentLabel - }) - return len(labelsThatMatter) == 0 - }) - - metadata = append(metadata, m...) - } - - if err := conn.client.DeleteMessage(ctx, xslices.Map(metadata, func(m proton.MessageMetadata) string { - return m.ID + if err := conn.client.DeleteMessage(ctx, xslices.Map(messageIDs, func(m imap.MessageID) string { + return string(m) })...); err != nil { return err } diff --git a/tests/features/imap/message/delete_from_trash.feature b/tests/features/imap/message/delete_from_trash.feature index fdc5105e..7d80ece4 100644 --- a/tests/features/imap/message/delete_from_trash.feature +++ b/tests/features/imap/message/delete_from_trash.feature @@ -6,7 +6,7 @@ Feature: IMAP remove messages from Trash | mbox | folder | | label | label | - Scenario Outline: Message in Trash and some other label is not permanently deleted + Scenario Outline: Message in Trash and some other label is permanently deleted Given the address "[user:user]@[domain]" of account "[user:user]" has the following messages in "Trash": | from | to | subject | body | | john.doe@mail.com | [user:user]@[domain] | foo | hello | @@ -26,8 +26,8 @@ Feature: IMAP remove messages from Trash When IMAP client "1" expunges Then it succeeds And IMAP client "1" eventually sees 1 messages in "Trash" - And IMAP client "1" eventually sees 2 messages in "All Mail" - And IMAP client "1" eventually sees 1 messages in "Labels/label" + And IMAP client "1" eventually sees 1 messages in "All Mail" + And IMAP client "1" eventually sees 0 messages in "Labels/label" Scenario Outline: Message in Trash only is permanently deleted Given the address "[user:user]@[domain]" of account "[user:user]" has the following messages in "Trash": From 59a944a06cf01e7c20e21647761b0a280fbbeb06 Mon Sep 17 00:00:00 2001 From: Romain Le Jeune Date: Wed, 26 Apr 2023 08:47:47 +0000 Subject: [PATCH 54/54] feat(GODT-2496): Bump gopenPGP to 2.7.1-proton. --- go.mod | 18 +- go.sum | 39 +- pkg/message/build_test.go | 42 +- ...ed-embedded-message-rfc822-with-pubkey.eml | 464 ++++++++++-------- .../pgp-mime-body-signed-html-with-pubkey.eml | 235 ++++----- ...gned-multipart-alternative-with-pubkey.eml | 304 ++++++------ ...mime-body-signed-plaintext-with-pubkey.eml | 198 ++++---- 7 files changed, 656 insertions(+), 644 deletions(-) diff --git a/go.mod b/go.mod index be328af5..74f26400 100644 --- a/go.mod +++ b/go.mod @@ -7,8 +7,8 @@ require ( github.com/Masterminds/semver/v3 v3.2.0 github.com/ProtonMail/gluon v0.16.1-0.20230425073628-8ec759b512f1 github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a - github.com/ProtonMail/go-proton-api v0.4.1-0.20230413090743-ad45d30ed45c - github.com/ProtonMail/gopenpgp/v2 v2.5.2 + github.com/ProtonMail/go-proton-api v0.4.1-0.20230426081144-f77778bae1be + github.com/ProtonMail/gopenpgp/v2 v2.7.1-proton github.com/PuerkitoBio/goquery v1.8.1 github.com/abiosoft/ishell v2.0.0+incompatible github.com/allan-simon/go-singleinstance v0.0.0-20210120080615-d0997106ab37 @@ -43,9 +43,9 @@ require ( github.com/vmihailenco/msgpack/v5 v5.3.5 go.uber.org/goleak v1.2.1 golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb - golang.org/x/net v0.7.0 - golang.org/x/sys v0.5.0 - golang.org/x/text v0.7.0 + golang.org/x/net v0.8.0 + golang.org/x/sys v0.6.0 + golang.org/x/text v0.8.0 google.golang.org/grpc v1.53.0 google.golang.org/protobuf v1.28.1 howett.net/plist v1.0.0 @@ -55,8 +55,8 @@ require ( ariga.io/atlas v0.9.1-0.20230119145809-92243f7c55cb // indirect entgo.io/ent v0.11.8 // indirect github.com/ProtonMail/bcrypt v0.0.0-20211005172633-e235017c1baf // indirect - github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 // indirect - github.com/ProtonMail/go-mime v0.0.0-20221031134845-8fd9bc37cf08 // indirect + github.com/ProtonMail/go-crypto v0.0.0-20230322105811-d73448b7e800 // indirect + github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f // indirect github.com/ProtonMail/go-srp v0.0.5 // indirect github.com/abiosoft/readline v0.0.0-20180607040430-155bce2042db // indirect github.com/agext/levenshtein v1.2.3 // indirect @@ -116,10 +116,10 @@ require ( github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect github.com/zclconf/go-cty v1.12.1 // indirect golang.org/x/arch v0.2.0 // indirect - golang.org/x/crypto v0.6.0 // indirect + golang.org/x/crypto v0.7.0 // indirect golang.org/x/mod v0.8.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/tools v0.3.1-0.20221202221704-aa9f4b2f3d57 // indirect + golang.org/x/tools v0.6.0 // indirect google.golang.org/genproto v0.0.0-20230221151758-ace64dc21148 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/go.sum b/go.sum index 77661b36..8006ce16 100644 --- a/go.sum +++ b/go.sum @@ -35,19 +35,18 @@ github.com/ProtonMail/gluon v0.16.1-0.20230425073628-8ec759b512f1/go.mod h1:yA4h github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a h1:D+aZah+k14Gn6kmL7eKxoo/4Dr/lK3ChBcwce2+SQP4= github.com/ProtonMail/go-autostart v0.0.0-20210130080809-00ed301c8e9a/go.mod h1:oTGdE7/DlWIr23G0IKW3OXK9wZ5Hw1GGiaJFccTvZi4= github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo= -github.com/ProtonMail/go-crypto v0.0.0-20230124153114-0acdc8ae009b/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g= -github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8 h1:wPbRQzjjwFc0ih8puEVAOFGELsn1zoIIYdxvML7mDxA= -github.com/ProtonMail/go-crypto v0.0.0-20230217124315-7d5c6f04bbb8/go.mod h1:I0gYDMZ6Z5GRU7l58bNFSkPTFN6Yl12dsUlAZ8xy98g= +github.com/ProtonMail/go-crypto v0.0.0-20230322105811-d73448b7e800 h1:o8/VQLSiuRkkSAfVOpFCG1GnTsWxFIOPLvJ2O7hJcFg= +github.com/ProtonMail/go-crypto v0.0.0-20230322105811-d73448b7e800/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE= github.com/ProtonMail/go-message v0.0.0-20210611055058-fabeff2ec753 h1:I8IsYA297x0QLU80G5I6aLYUu3JYNSpo8j5fkXtFDW0= github.com/ProtonMail/go-message v0.0.0-20210611055058-fabeff2ec753/go.mod h1:NBAn21zgCJ/52WLDyed18YvYFm5tEoeDauubFqLokM4= -github.com/ProtonMail/go-mime v0.0.0-20221031134845-8fd9bc37cf08 h1:dS7r5z4iGS0qCjM7UwWdsEMzQesUQbGcXdSm2/tWboA= -github.com/ProtonMail/go-mime v0.0.0-20221031134845-8fd9bc37cf08/go.mod h1:qRZgbeASl2a9OwmsV85aWwRqic0NHPh+9ewGAzb4cgM= -github.com/ProtonMail/go-proton-api v0.4.1-0.20230413090743-ad45d30ed45c h1:0aR0lmalexKojhLNQp7ObS7X8bT/ACzb/CcSOLdrN4Y= -github.com/ProtonMail/go-proton-api v0.4.1-0.20230413090743-ad45d30ed45c/go.mod h1:Sj1MPL7pt+tf1SDdPyKhWcZvT43t87RADF79cbEi7xg= +github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f h1:tCbYj7/299ekTTXpdwKYF8eBlsYsDVoggDAuAjoK66k= +github.com/ProtonMail/go-mime v0.0.0-20230322103455-7d82a3887f2f/go.mod h1:gcr0kNtGBqin9zDW9GOHcVntrwnjrK+qdJ06mWYBybw= +github.com/ProtonMail/go-proton-api v0.4.1-0.20230426081144-f77778bae1be h1:TNHnEyUQDf97CRGCFWLxg7I5ASSEMO3TN2lbNw2cD6U= +github.com/ProtonMail/go-proton-api v0.4.1-0.20230426081144-f77778bae1be/go.mod h1:UkrG9gN2o9mzdx/an0XRc6a4s5Haef1A7Eyd2iXlw28= github.com/ProtonMail/go-srp v0.0.5 h1:xhUioxZgDbCnpo9JehyFhwwsn9JLWkUGfB0oiKXgiGg= github.com/ProtonMail/go-srp v0.0.5/go.mod h1:06iYHtLXW8vjLtccWj++x3MKy65sIT8yZd7nrJF49rs= -github.com/ProtonMail/gopenpgp/v2 v2.5.2 h1:97SjlWNAxXl9P22lgwgrZRshQdiEfAht0g3ZoiA1GCw= -github.com/ProtonMail/gopenpgp/v2 v2.5.2/go.mod h1:52qDaCnto6r+CoWbuU50T77XQt99lIs46HtHtvgFO3o= +github.com/ProtonMail/gopenpgp/v2 v2.7.1-proton h1:YS6M20yvjCJPR1r4ADW5TPn6rahs4iAyZaACei86bEc= +github.com/ProtonMail/gopenpgp/v2 v2.7.1-proton/go.mod h1:S1lYsaGHykYpxxh2SnJL6ypcAlANKj5NRSY6HxKryKQ= github.com/PuerkitoBio/goquery v1.8.1 h1:uQxhNlArOIdbrH1tr0UXwdVFgDcZDrZVdcpygAcwmWM= github.com/PuerkitoBio/goquery v1.8.1/go.mod h1:Q8ICL1kNUJ2sXGoAhPGUdYDJvgQgHzJsnnd3H7Ho5jQ= github.com/abiosoft/ishell v2.0.0+incompatible h1:zpwIuEHc37EzrsIYah3cpevrIc8Oma7oZPxr03tlmmw= @@ -435,12 +434,11 @@ golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc= -golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= +golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A= +golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= -golang.org/x/exp v0.0.0-20190731235908-ec7cb31e5a56/go.mod h1:JhuoJpWY28nO4Vef9tZUw9qufEGTyX1+7lmHxV5q5G4= golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= golang.org/x/exp v0.0.0-20230213192124-5e25df0256eb h1:PaBZQdo+iSDyHT053FjUCgZQ/9uqVwPOcl7KSWhKn6w= @@ -456,7 +454,6 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= -golang.org/x/mobile v0.0.0-20221110043201-43a038452099/go.mod h1:aAjjkJNdrh3PMckS4B10TGS2nag27cbKR1y2BpUxsiY= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -483,8 +480,10 @@ golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210916014120-12bc252f5db8/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -495,7 +494,6 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -527,11 +525,13 @@ golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= @@ -539,8 +539,9 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.5-0.20201125200606-c27b9fd57aec/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68= +golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -564,8 +565,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.3.1-0.20221202221704-aa9f4b2f3d57 h1:/X0t/E4VxbZE7MLS7auvE7YICHeVvbIa9vkOVvYW/24= -golang.org/x/tools v0.3.1-0.20221202221704-aa9f4b2f3d57/go.mod h1:/rWhSS2+zyEVwoJf8YAX6L2f0ntZ7Kn/mGgAWcipA5k= +golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pkg/message/build_test.go b/pkg/message/build_test.go index 41d52936..58c2ee9b 100644 --- a/pkg/message/build_test.go +++ b/pkg/message/build_test.go @@ -431,7 +431,7 @@ func TestBuildSignedPlainEncryptedMessageWithPubKey(t *testing.T) { section(t, res). expectDate(is(`Wed, 01 Jan 2020 00:00:00 +0000`)). expectContentType(is(`multipart/signed`)). - expectContentTypeParam(`micalg`, is(`pgp-sha256`)). + expectContentTypeParam(`micalg`, is(`SHA-256`)). expectContentTypeParam(`protocol`, is(`application/pgp-signature`)) section(t, res, 1). @@ -439,7 +439,7 @@ func TestBuildSignedPlainEncryptedMessageWithPubKey(t *testing.T) { expectContentTypeParam(`protected-headers`, is(`v1`)). expectHeader(`Subject`, is(`simple plaintext body`)). expectHeader(`From`, is(`"pm.bridge.qa" `)). - expectHeader(`To`, is(`schizofrenic@pm.me`)). + expectHeader(`To`, is("\"InfernalBridgeTester@proton.me\" ")). expectSection(verifiesAgainst(section(t, res, 1, 1, 2).pubKey(), section(t, res, 2).signature())) section(t, res, 1, 1). @@ -477,7 +477,7 @@ func TestBuildSignedHTMLEncryptedMessageWithPubKey(t *testing.T) { section(t, res). expectDate(is(`Wed, 01 Jan 2020 00:00:00 +0000`)). expectContentType(is(`multipart/signed`)). - expectContentTypeParam(`micalg`, is(`pgp-sha256`)). + expectContentTypeParam(`micalg`, is(`SHA-256`)). expectContentTypeParam(`protocol`, is(`application/pgp-signature`)) section(t, res, 1). @@ -485,7 +485,7 @@ func TestBuildSignedHTMLEncryptedMessageWithPubKey(t *testing.T) { expectContentTypeParam(`protected-headers`, is(`v1`)). expectHeader(`Subject`, is(`simple html body`)). expectHeader(`From`, is(`"pm.bridge.qa" `)). - expectHeader(`To`, is(`schizofrenic@pm.me`)). + expectHeader(`To`, is("\"InfernalBridgeTester@proton.me\" ")). expectSection(verifiesAgainst(section(t, res, 1, 1, 2).pubKey(), section(t, res, 2).signature())) section(t, res, 1, 1). @@ -524,7 +524,7 @@ func TestBuildSignedMultipartAlternativeEncryptedMessageWithPubKey(t *testing.T) section(t, res). expectDate(is(`Wed, 01 Jan 2020 00:00:00 +0000`)). expectContentType(is(`multipart/signed`)). - expectContentTypeParam(`micalg`, is(`pgp-sha256`)). + expectContentTypeParam(`micalg`, is(`SHA-256`)). expectContentTypeParam(`protocol`, is(`application/pgp-signature`)) section(t, res, 1). @@ -532,8 +532,8 @@ func TestBuildSignedMultipartAlternativeEncryptedMessageWithPubKey(t *testing.T) expectContentTypeParam(`protected-headers`, is(`v1`)). expectHeader(`Subject`, is(`Alternative`)). expectHeader(`From`, is(`"pm.bridge.qa" `)). - expectHeader(`To`, is(`schizofrenic@pm.me`)). - expectSection(verifiesAgainst(section(t, res, 1, 1, 3).pubKey(), section(t, res, 2).signature())) + expectHeader(`To`, is("\"InfernalBridgeTester@proton.me\" ")). + expectSection(verifiesAgainst(section(t, res, 1, 1, 2).pubKey(), section(t, res, 2).signature())) section(t, res, 1, 1). expectContentType(is(`multipart/mixed`)) @@ -549,17 +549,11 @@ func TestBuildSignedMultipartAlternativeEncryptedMessageWithPubKey(t *testing.T) section(t, res, 1, 1, 1, 2). expectContentType(is(`text/html`)). - expectBody(contains(`This Rich formated text`)). + expectBody(contains(`This Rich formated text`)). expectBody(contains(`What kind of shoes do ninjas wear`)). expectBody(contains(`How does a penguin build its house`)) section(t, res, 1, 1, 2). - expectContentType(is(`application/pdf`)). - expectTransferEncoding(is(`base64`)). - expectContentTypeParam(`name`, is(`minimal.pdf`)). - expectContentDispositionParam(`filename`, is(`minimal.pdf`)) - - section(t, res, 1, 1, 3). expectContentType(is(`application/pgp-keys`)). expectContentTypeParam(`name`, is(`OpenPGP_0x161C0875822359F7.asc`)). expectContentDisposition(is(`attachment`)). @@ -587,16 +581,16 @@ func TestBuildSignedEmbeddedMessageRFC822EncryptedMessageWithPubKey(t *testing.T section(t, res). expectDate(is(`Wed, 01 Jan 2020 00:00:00 +0000`)). expectContentType(is(`multipart/signed`)). - expectContentTypeParam(`micalg`, is(`pgp-sha256`)). + expectContentTypeParam(`micalg`, is(`SHA-256`)). expectContentTypeParam(`protocol`, is(`application/pgp-signature`)) section(t, res, 1). expectContentType(is(`multipart/mixed`)). expectContentTypeParam(`protected-headers`, is(`v1`)). - expectHeader(`Subject`, is(`Fwd: HTML with attachment external PGP`)). + expectHeader(`Subject`, is(`Fwd: simple html body`)). expectHeader(`From`, is(`"pm.bridge.qa" `)). - expectHeader(`To`, is(`schizofrenic@pm.me`)). - expectSection(verifiesAgainst(section(t, res, 1, 1, 2).pubKey(), section(t, res, 2).signature())) + expectHeader(`To`, is("\"InfernalBridgeTester@proton.me\" ")). + expectSection(verifiesAgainst(section(t, res, 1, 1, 3).pubKey(), section(t, res, 2).signature())) section(t, res, 1, 1). expectContentType(is(`multipart/mixed`)) @@ -605,17 +599,17 @@ func TestBuildSignedEmbeddedMessageRFC822EncryptedMessageWithPubKey(t *testing.T expectContentType(is(`text/plain`)) section(t, res, 1, 1, 2). + expectContentType(is(`message/rfc822`)). + expectContentTypeParam(`name`, is(`simple html body.eml`)). + expectContentDisposition(is(`attachment`)). + expectContentDispositionParam(`filename`, is(`simple html body.eml`)) + + section(t, res, 1, 1, 3). expectContentType(is(`application/pgp-keys`)). expectContentTypeParam(`name`, is(`OpenPGP_0x161C0875822359F7.asc`)). expectContentDisposition(is(`attachment`)). expectContentDispositionParam(`filename`, is(`OpenPGP_0x161C0875822359F7.asc`)) - section(t, res, 1, 1, 3). - expectContentType(is(`message/rfc822`)). - expectContentTypeParam(`name`, is(`HTML with attachment external PGP.eml`)). - expectContentDisposition(is(`attachment`)). - expectContentDispositionParam(`filename`, is(`HTML with attachment external PGP.eml`)) - section(t, res, 2). expectContentType(is(`application/pgp-signature`)). expectContentTypeParam(`name`, is(`OpenPGP_signature.asc`)). diff --git a/pkg/message/testdata/pgp-mime-body-signed-embedded-message-rfc822-with-pubkey.eml b/pkg/message/testdata/pgp-mime-body-signed-embedded-message-rfc822-with-pubkey.eml index 69a0c258..47219822 100644 --- a/pkg/message/testdata/pgp-mime-body-signed-embedded-message-rfc822-with-pubkey.eml +++ b/pkg/message/testdata/pgp-mime-body-signed-embedded-message-rfc822-with-pubkey.eml @@ -1,212 +1,252 @@ -Content-Type: multipart/signed; micalg=pgp-sha256; - protocol="application/pgp-signature"; - boundary="Rrmlds5vN3IeeCVjbnepHmuVgyROSBjsS" - -This is an OpenPGP/MIME signed message (RFC 4880 and 3156) ---Rrmlds5vN3IeeCVjbnepHmuVgyROSBjsS -Content-Type: multipart/mixed; boundary="avFkF0LAPYPXcFHcnsgGmACbGIPeVDdYc"; - protected-headers="v1" -Subject: Fwd: HTML with attachment external PGP -From: "pm.bridge.qa" -To: schizofrenic@pm.me -Message-ID: <7c04869b-c470-116f-b8e5-8b4fd5e1195d@gmail.com> -References: -In-Reply-To: - ---avFkF0LAPYPXcFHcnsgGmACbGIPeVDdYc -Content-Type: multipart/mixed; - boundary="------------2F19EE9A8A1A6F779F5D14AF" -Content-Language: en-US - -This is a multi-part message in MIME format. ---------------2F19EE9A8A1A6F779F5D14AF -Content-Type: text/plain; charset=utf-8; format=flowed -Content-Transfer-Encoding: quoted-printable - - - ---------------2F19EE9A8A1A6F779F5D14AF -Content-Type: application/pgp-keys; - name="OpenPGP_0x161C0875822359F7.asc" -Content-Transfer-Encoding: quoted-printable -Content-Disposition: attachment; - filename="OpenPGP_0x161C0875822359F7.asc" - ------BEGIN PGP PUBLIC KEY BLOCK----- - -xsBNBFxlUPwBCACx954Ey4SD88f8DSKFw9BaZNXrNwYxNYSgqaqOGHQ0WllF3mstEhTfuxxCZ= -pDh -I5IhWCXUNxanzsFkn88mRDwFRVl2sf2aAG4/P/p1381oh2kd0UElMRQaQGzoCadQMaQOL9WYT= -f4S -PWSCzjrPyKgjq5FbqjbF/ndu376na9L+tnsEXyL6RrI6aZhjWG73xlqxS65dzTIYzsyM/P97x= -Snd -NvlvWtGvLlpFkzxfAEGpVzfOYVYFKoc8rGmUDwrDWYfk5JczRDDogJnY+BNMZf9pjSqk6rTyB= -OfN -H5fpU8r7A5Q7l+HVakvMUQ9DzDWJtg2ru1Y8hexnJOF68avO4+a1ABEBAAHNKEJyaWRnZSBLe= -XUt -RWh5aiA8cG0uYnJpZGdlLnFhQGdtYWlsLmNvbT7CwJQEEwEIAD4CGwMFCwkIBwIGFQoJCAsCB= -BYC -AwECHgECF4AWIQRc5gl5cC8oW/Mo+bEWHAh1giNZ9wUCYC32ygUJB4sMzgAKCRAWHAh1giNZ9= -/K8 -B/4qs84Ii/zKH+q+C8vwO4jUJkOM73qD0pgB7zBs651zWbpgopyol1YUKNpFaHlx/Qch7RDI7= -Vcz -1+60/KZJSJR19/N2EDVbCUdh8ueioUp9X/218YWV2TRJNxTnljd4FAn7smZnXuP1TsLjQ6sKO= -V0U -u6JoiG6LZFXqDgxYpA++58Rkl6xaY6R71VkmVQlbEKtubX9AjHydq97Y+Jvn11XzWZaKhv4L7= -6Pa -4tMKXvvrKh1oywMmh6mZJo+5ZA/ABTkr45cwlTPYqGTS9+uvOHt+PH/oYwwJB4ls2cIAUldSj= -TVQ -IsseYz3LlbcCfKJiiCFxeHOQXA5J6zNLKOT58TsczsBNBFxlUPwBCADh2HsX23yVnJt9fxFz3= -D07 -kCBNvu4HQfps6h1rgNxGhE32VmpESHebvIB5xjL6xKbIqqRa3x/7KDVBNJvca0gUsqEt5kzYF= -88F -yf2NBcejpIbcP7BS/g+C6KOowYj+Et26T6GdwFXExUcl80JvoX8yHQOfvJpdiBRbjyB8UqfCa= -knm -3c7dNuXmhflz/w3aBj32q9ZyGqA1NpHCpLyVAlvSNQ/pat/rGUCPZ9duw4KhUUqEmatQPVFPk= -utT -ouEZQbMK+i+chOH3AsKCuNDfvCDwirnsSqIJmAgl1lC4de+bsWYCMqN9ei99hOCRUyhZ3g3sr= -8RB -owVAdcvjZxeIDKALABEBAAHCwHwEGAEIACYCGwwWIQRc5gl5cC8oW/Mo+bEWHAh1giNZ9wUCY= -C32 -lAUJB4sMmAAKCRAWHAh1giNZ9+Y2B/9rTKZaKviae+ummXNumXcrKvbkAAvfuLpKUn53FlQLm= -L6H -jB++lJnPWvVSzdZxdv8FiPP3d632XHKUrkQRQM/9byRDXDommi7Qttx7YCkhd4JLVYqJqpnAQ= -xI5 -RMkXiZNWyr1lz8JOM1XvDk1M7sJwPMWews8VOIE03E1nt7AsQGnvHtadgEnQaufrYNX3hFA8S= -osO -HSnedcys6yrzCSIGCqCD9VHbnMtS4DOv0XJGh2hwc8omzH0KZA517dyKBorJRwadcVauGXDKx= -Etv -Im4rl94PR/3An1Mj6HeeVVpLqDQ5Jb9J90BahWeQ53FzRa4EQzYCw0nLnxcsT1ZEEP5u -=3Dv/1p ------END PGP PUBLIC KEY BLOCK----- - ---------------2F19EE9A8A1A6F779F5D14AF -Content-Type: message/rfc822; - name="HTML with attachment external PGP.eml" -Content-Transfer-Encoding: 7bit -Content-Disposition: attachment; - filename="HTML with attachment external PGP.eml" - -Delivered-To: pm.bridge.qa@gmail.com -Received: by 2002:a17:906:a051:0:0:0:0 with SMTP id bg17csp66709ejb; - Wed, 24 Mar 2021 22:03:32 -0700 (PDT) -X-Google-Smtp-Source: ABdhPJxllBuHnnJzKWy77R291tZbVFVk0iahkLm1TQsluEYTvyAXdOWB/zp1y10e60UlGGZYH3YF -X-Received: by 2002:a05:6000:118c:: with SMTP id g12mr6758087wrx.353.1616648612550; - Wed, 24 Mar 2021 22:03:32 -0700 (PDT) -ARC-Seal: i=1; a=rsa-sha256; t=1616648612; cv=none; - d=google.com; s=arc-20160816; - b=Jf4vmKEoeJQ3rIDMbI2twiDkfn50ejNnqIbs2nkaFruITcw6XhvhbcfV9HLC80Yt8E - tfN7TV9qoBneSWzfSJ+Sqw31hBKKtKpMhuqZT9GPzBN5gdMJKj5ISAQ8Lgm9zvR3Zbjn - N0nOzCu/oT1amMMm+48hpKj8VL2tydjvNG+g/a5lk1Aw7JdqIKV6t1XhsyyYaa1O+NFC - rQThdalcQj2NjoZWba1mjZSzI7B7hJdZg5d+jado2TPMQXe2kz2wGmr3+/JcKvPJjrSA - S+jzhpjcd7ZnctkzTfpsdlBJAGKoDBnSvQc3eMJ/AgRHFc+5ks5nRDt/1DowSjQ7i7rp - 4a+g== -ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; - h=mime-version:message-id:subject:reply-to:from:to:dkim-signature - :date; - bh=vmJ0JT+IfeO4idMYP7zPvldBkdONjKTXWTp7ly/B9qk=; - b=f8VY+ajsE/XNYrqD666FM0WCtNEQtUyU/Zh3pFCI9sFrMnAui4Qp9Gs1fe/8HLxt2v - /C4l4eHELvPBv4vX0KtUvOlRZYPZbLZCNdtTcFtiuZEKUHWx370p7yyMWcmSMdlUbq4J - NrKMPGfaYiZe5Rt3MyD5RKm4RJpqvep34VCHMYtoFQP/0Po4/1JMDw0Fy6SXUJ54rBRw - bmzqNNBkonda3YghhK3WNrxTxzZ8I7KW9YdpENNS9ewJLeVtFQKdiLZwz5EpMZxOxG0I - LW0jRtDlmZnqRe7bvTAo51IuLf9okHRI8PRiK0UHl+4Vr5Igq4mub7Ee8pC/Nz3Yj29G - KODw== -ARC-Authentication-Results: i=1; mx.google.com; - dkim=pass header.i=@protonmail.com header.s=protonmail header.b=EX07e46H; - spf=pass (google.com: domain of bridge-test-user@protonmail.com designates 185.70.40.22 as permitted sender) smtp.mailfrom=bridge-test-user@protonmail.com; - dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=protonmail.com -Return-Path: -Received: from mail2.protonmail.ch (mail2.protonmail.ch. [185.70.40.22]) - by mx.google.com with ESMTPS id g6si2999785wrr.110.2021.03.24.22.03.32 - for - (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); - Wed, 24 Mar 2021 22:03:32 -0700 (PDT) -Received-SPF: pass (google.com: domain of bridge-test-user@protonmail.com designates 185.70.40.22 as permitted sender) client-ip=185.70.40.22; -Authentication-Results: mx.google.com; - dkim=pass header.i=@protonmail.com header.s=protonmail header.b=EX07e46H; - spf=pass (google.com: domain of bridge-test-user@protonmail.com designates 185.70.40.22 as permitted sender) smtp.mailfrom=bridge-test-user@protonmail.com; - dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=protonmail.com -Date: Thu, 25 Mar 2021 05:03:27 +0000 -DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=protonmail.com; - s=protonmail; t=1616648611; - bh=vmJ0JT+IfeO4idMYP7zPvldBkdONjKTXWTp7ly/B9qk=; - h=Date:To:From:Reply-To:Subject:From; - b=EX07e46H5/HmotAWZ69I4qa5jCVRao/p3KEM3eQn/AQ8s+cLMaR5b2ozdHrPCsTw5 - i5b1DLUHZHBf+6Ven47WJfKNwLUfkAGD2P0aI/dAk/h/h0Bg4Ni85pv+uPpRHLNQKv - T3VnDP9MSwl6IUJu5zoM2EC70MLoiHS07lxhM2pw= -To: External Bridge -From: Bridge Test -Reply-To: Bridge Test -Subject: HTML with attachment external PGP -Message-ID: -MIME-Version: 1.0 -Content-Type: multipart/mixed; - boundary="b1_LCxIUvb0rqBufdwR4JNxMg4ZDMI8x7pRG0vEHGHYwA" -X-Spam-Status: No, score=-1.2 required=10.0 tests=ALL_TRUSTED,DKIM_SIGNED, - DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,HTML_MESSAGE - shortcircuit=no autolearn=disabled version=3.4.4 -X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on - mailout.protonmail.ch - -This is a multi-part message in MIME format. - ---b1_LCxIUvb0rqBufdwR4JNxMg4ZDMI8x7pRG0vEHGHYwA -Content-Type: multipart/alternative; - boundary="b2_LCxIUvb0rqBufdwR4JNxMg4ZDMI8x7pRG0vEHGHYwA" - ---b2_LCxIUvb0rqBufdwR4JNxMg4ZDMI8x7pRG0vEHGHYwA -Content-Type: text/plain; charset=utf-8 -Content-Transfer-Encoding: base64 - -VGhpcyBpcyBib2R5IG9mIEhUTUwgbWFpbCB3aXRoIGF0dGFjaG1lbnQ= - ---b2_LCxIUvb0rqBufdwR4JNxMg4ZDMI8x7pRG0vEHGHYwA -Content-Type: text/html; charset=utf-8 -Content-Transfer-Encoding: base64 - -PGh0bWw+PGhlYWQ+PC9oZWFkPjxib2R5PlRoaXMgaXMgYm9keSBvZiA8Yj5IVE1MIG1haWw8L2I+ -IHdpdGggYXR0YWNobWVudA0KPC9ib2R5PjwvaHRtbD4= - - ---b2_LCxIUvb0rqBufdwR4JNxMg4ZDMI8x7pRG0vEHGHYwA-- - ---b1_LCxIUvb0rqBufdwR4JNxMg4ZDMI8x7pRG0vEHGHYwA -Content-Type: image/png; name=outline-light-instagram-48.png -Content-Transfer-Encoding: base64 -Content-Disposition: attachment; filename=outline-light-instagram-48.png - -iVBORw0KGgoAAAANSUhEUgAAADAAAAAwBAMAAAClLOS0AAAALVBMVEUAAAD///////////////// -//////////////////////////////////////+hSKubAAAADnRSTlMAgO8QQM+/IJ9gj1AwcIQd -OXUAAAGdSURBVDjLXJC9SgNBFIVPXDURTYhgIQghINgowyLYCAYtRFAIgtYhpAjYhC0srCRW6YIg -WNpoHVSsg/gEii+Qnfxq4DyDc3cyMfrBwl2+O+fOHTi8p7LS5RUf/9gpMKL7iT9sK47Q95ggpkzv -1cvRcsGYNMYsmP+zKN27NR2vcDyTNVdfkOuuniNPMWafvIbljt+YoMEvW8y7lt+ARwhvrgPjhA0I -BTng7S1GLPlypBvtIBPidY4YBDJFdtnkscQ5JGaGqxC9i7jSDwcwnB8qHWBaQjw1ABI8wYgtVoG6 -9pFkH8iZIiJeulFt4JLvJq8I5N2GMWYbHWDWzM3JZTMdeSWla0kW86FcuI0mfStiNKQ/AhEeh8h0 -YUTffFwrMTT5oSwdojIQ0UKcocgAKRH1HiqhFQmmJa5qRaYHNbRiSsOgslY0NdixItUTUWlZkedP -HXVyAgAIA1F0wP5btQZPIyTwvAqa/Fl4oacuP+e4XHAjSYpkQkxSiMX+T7FPoZJToSStzED70HCy -KE3NGCg4jJrC6Ti7AFwZLhnW0gMbzFZc0RmmeAAAAABJRU5ErkJggg== - ---b1_LCxIUvb0rqBufdwR4JNxMg4ZDMI8x7pRG0vEHGHYwA-- - - ---------------2F19EE9A8A1A6F779F5D14AF-- - ---avFkF0LAPYPXcFHcnsgGmACbGIPeVDdYc-- - ---Rrmlds5vN3IeeCVjbnepHmuVgyROSBjsS -Content-Type: application/pgp-signature; name="OpenPGP_signature.asc" -Content-Description: OpenPGP digital signature -Content-Disposition: attachment; filename="OpenPGP_signature" - ------BEGIN PGP SIGNATURE----- - -wsB5BAABCAAjFiEEXOYJeXAvKFvzKPmxFhwIdYIjWfcFAmBciIAFAwAAAAAACgkQFhwIdYIjWfcN -ZQf+NzAoEJRTSW5JFNgSGkwLsH89wAbw3wEt4PYuZaa+35xBuU8Sojm1oLOyuPkIasQf98Iu5P1o -8cokViEa6wm+ZZpcFMi6T2/3+UNlSm81Epm7GrFyjAFTWrdTPLb4k4x47sz77RoTp/UEwm/7fVI5 -gMYhQyIYaocXHmDk61UshWE9q/Po6qjHBnnWS8YBnhUS9lK8uimpfRO9UQ9bIUjIYDGDPAtBoYnb -X9V4SjBvbbdNrgoVaDxPw6HYCb3RhzRXunr5Icdnjfbc2H40/FayVi/p7GzFh+8zv/TzRxMkHo72 -DBsONaC7r8bxQ9BwJvpmWufqL7ZXHfVXQ6z+M43e1Q== -=Stx+ ------END PGP SIGNATURE----- - ---Rrmlds5vN3IeeCVjbnepHmuVgyROSBjsS-- +Content-Type: multipart/signed; + boundary=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855; + micalg=SHA-256; protocol="application/pgp-signature" + +--e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +Content-Type: multipart/mixed; boundary="------------6sNRIgaKOJHTghuLxPUzlxn1"; + protected-headers="v1" +From: "pm.bridge.qa" +To: "InfernalBridgeTester@proton.me" +Message-ID: <3f60022f-1ff2-9792-926b-a556cc39195d@gmail.com> +Subject: Fwd: simple html body +References: <1655e652-1abc-575f-6e03-5bbf119afbfa@gmail.com> +In-Reply-To: <1655e652-1abc-575f-6e03-5bbf119afbfa@gmail.com> + +--------------6sNRIgaKOJHTghuLxPUzlxn1 +Content-Type: multipart/mixed; boundary="------------Z0a0IncIqoVlOIpOfcALEK5P" + +--------------Z0a0IncIqoVlOIpOfcALEK5P +Content-Type: text/plain; charset=UTF-8; format=flowed +Content-Transfer-Encoding: base64 + +DQo= +--------------Z0a0IncIqoVlOIpOfcALEK5P +Content-Type: message/rfc822; name="simple html body.eml" +Content-Disposition: attachment; filename="simple html body.eml" +Content-Transfer-Encoding: 7bit + +Message-ID: <1655e652-1abc-575f-6e03-5bbf119afbfa@gmail.com> +Date: Tue, 25 Apr 2023 17:12:15 +0200 +MIME-Version: 1.0 +User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 + Thunderbird/102.10.0 +Content-Language: en-US +To: "InfernalBridgeTester@proton.me" +From: "pm.bridge.qa" +Subject: simple html body +Autocrypt: addr=pm.bridge.qa@gmail.com; keydata= + xsBNBFxlUPwBCACx954Ey4SD88f8DSKFw9BaZNXrNwYxNYSgqaqOGHQ0WllF3mstEhTfuxxC + ZpDhI5IhWCXUNxanzsFkn88mRDwFRVl2sf2aAG4/P/p1381oh2kd0UElMRQaQGzoCadQMaQO + L9WYTf4SPWSCzjrPyKgjq5FbqjbF/ndu376na9L+tnsEXyL6RrI6aZhjWG73xlqxS65dzTIY + zsyM/P97xSndNvlvWtGvLlpFkzxfAEGpVzfOYVYFKoc8rGmUDwrDWYfk5JczRDDogJnY+BNM + Zf9pjSqk6rTyBOfNH5fpU8r7A5Q7l+HVakvMUQ9DzDWJtg2ru1Y8hexnJOF68avO4+a1ABEB + AAHNKEJyaWRnZSBLeXUtRWh5aiA8cG0uYnJpZGdlLnFhQGdtYWlsLmNvbT7CwI4EEwEIADgC + GwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQRc5gl5cC8oW/Mo+bEWHAh1giNZ9wUCZEfU + zQAKCRAWHAh1giNZ9872B/4mM6cXErSSYK6/apGUVebg9QiP1RhFlLE/kg7BW3FaSP/yTUZN + ZdX7WPnEVyaa5Dk4xRZiB47Yc5myspwc+JEJ3YDAHq+4n/D74TF1kUCzP+QVsWcn40UqX9gH + bO01O/DYtoxMOljEgkfQjEZcRoHuUhCUzldFf8aV+uZKiOXhrPYCwsilnh0RAmDV7fLoOfKX + MLiKXE8wM/5Bax+dk2AmEM4bOTIo58GGDDqseIg03ocrW7vPegmxiLUwmsHIIDwTq6qZ0CVx + bt2uv4cCyNz/0pmRzG7p8192Evdu8JOuLSj3pI1X00Ub326yay3BBUnsL4PJIGoly8hnLb5N + 3cyNzsBNBFxlUPwBCADh2HsX23yVnJt9fxFz3D07kCBNvu4HQfps6h1rgNxGhE32VmpESHeb + vIB5xjL6xKbIqqRa3x/7KDVBNJvca0gUsqEt5kzYF88Fyf2NBcejpIbcP7BS/g+C6KOowYj+ + Et26T6GdwFXExUcl80JvoX8yHQOfvJpdiBRbjyB8UqfCaknm3c7dNuXmhflz/w3aBj32q9Zy + GqA1NpHCpLyVAlvSNQ/pat/rGUCPZ9duw4KhUUqEmatQPVFPkutTouEZQbMK+i+chOH3AsKC + uNDfvCDwirnsSqIJmAgl1lC4de+bsWYCMqN9ei99hOCRUyhZ3g3sr8RBowVAdcvjZxeIDKAL + ABEBAAHCwHYEGAEIACACGwwWIQRc5gl5cC8oW/Mo+bEWHAh1giNZ9wUCZEfUugAKCRAWHAh1 + giNZ9ycfB/97iOFFeYSFB5CqOxsyo9TjHve0BOzfGyLh632+sUQEw3qqwVreAqrjVa/wnLFW + 67Pbf4GBn6ZnaIMIq4rv6d4wnDZ4b18yQkITErWvU+3thpeZS/NUeWlLZlXFauDhCdPpAq5T + nw7+5lq0pe2BEcNBF4IRoBRs7UQVhr/QpN+xawbnQUM1oIOMljTWuQZtPo75OsltQn59+OTn + 7ZYQD4Q3Sn0vPAzFbPBa4fostzbx8ktTGWfhBctQrpwS06VqoSowr8RFY9S+ssjCK+Hlq2t8 + ZC0CBL1aU1AAPqcAOfrw9rin0rN1dH07g1uDeZ9SnyLuee5QN7r3VY8b9tiOJV9m +Content-Type: multipart/signed; micalg=pgp-sha256; + protocol="application/pgp-signature"; + boundary="------------Kh8bXWpcGJrKDmQHlv9QWtgJ" + +This is an OpenPGP/MIME signed message (RFC 4880 and 3156) +--------------Kh8bXWpcGJrKDmQHlv9QWtgJ +Content-Type: multipart/mixed; boundary="------------iFRY0nd000IWAcfqrg6ZdUuF"; + protected-headers="v1" +From: "pm.bridge.qa" +To: "InfernalBridgeTester@proton.me" +Message-ID: <1655e652-1abc-575f-6e03-5bbf119afbfa@gmail.com> +Subject: simple html body + +--------------iFRY0nd000IWAcfqrg6ZdUuF +Content-Type: multipart/mixed; boundary="------------0tRoF00iqRv70TBczVNfagKk" + +--------------0tRoF00iqRv70TBczVNfagKk +Content-Type: text/html; charset=UTF-8 +Content-Transfer-Encoding: quoted-printable + + + + + + + +

+

And this is HTML
+

+
    +
  • Do I enjoy making courthouse puns? + Guilty.=3D3DE2=3D3D80=3D3D9=3D + 4 @=3D3D baddadjokes
  • +
  • Can February March? No, but April May. =3D3DE2=3D3D80=3D= +3D94@Bear=3D3D + dedMOGuy
  • +
+


+

+

+ +

+ + +--------------0tRoF00iqRv70TBczVNfagKk +Content-Type: application/pgp-keys; name="OpenPGP_0x161C0875822359F7.asc" +Content-Disposition: attachment; filename="OpenPGP_0x161C0875822359F7.asc" +Content-Description: OpenPGP public key +Content-Transfer-Encoding: quoted-printable + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +xsBNBFxlUPwBCACx954Ey4SD88f8DSKFw9BaZNXrNwYxNYSgqaqOGHQ0WllF3mst +EhTfuxxCZpDhI5IhWCXUNxanzsFkn88mRDwFRVl2sf2aAG4/P/p1381oh2kd0UEl +MRQaQGzoCadQMaQOL9WYTf4SPWSCzjrPyKgjq5FbqjbF/ndu376na9L+tnsEXyL6 +RrI6aZhjWG73xlqxS65dzTIYzsyM/P97xSndNvlvWtGvLlpFkzxfAEGpVzfOYVYF +Koc8rGmUDwrDWYfk5JczRDDogJnY+BNMZf9pjSqk6rTyBOfNH5fpU8r7A5Q7l+HV +akvMUQ9DzDWJtg2ru1Y8hexnJOF68avO4+a1ABEBAAHNKEJyaWRnZSBLeXUtRWh5 +aiA8cG0uYnJpZGdlLnFhQGdtYWlsLmNvbT7CwI4EEwEIADgCGwMFCwkIBwIGFQoJ +CAsCBBYCAwECHgECF4AWIQRc5gl5cC8oW/Mo+bEWHAh1giNZ9wUCZEfUzQAKCRAW +HAh1giNZ9872B/4mM6cXErSSYK6/apGUVebg9QiP1RhFlLE/kg7BW3FaSP/yTUZN +ZdX7WPnEVyaa5Dk4xRZiB47Yc5myspwc+JEJ3YDAHq+4n/D74TF1kUCzP+QVsWcn +40UqX9gHbO01O/DYtoxMOljEgkfQjEZcRoHuUhCUzldFf8aV+uZKiOXhrPYCwsil +nh0RAmDV7fLoOfKXMLiKXE8wM/5Bax+dk2AmEM4bOTIo58GGDDqseIg03ocrW7vP +egmxiLUwmsHIIDwTq6qZ0CVxbt2uv4cCyNz/0pmRzG7p8192Evdu8JOuLSj3pI1X +00Ub326yay3BBUnsL4PJIGoly8hnLb5N3cyNwsCUBBMBCAA+FiEEXOYJeXAvKFvz +KPmxFhwIdYIjWfcFAlxlUPwCGwMFCQPCZwAFCwkIBwIGFQoJCAsCBBYCAwECHgEC +F4AACgkQFhwIdYIjWfeQzgf+NWseR+UvrJ7I1CFd6M2+RmyIC1QTQ+uyJIhIBQfC +vBhueU9GUPWR6a6GWsb2DGCMkBM2aHoTCcf46fq87VspYb3+b0JsKfRFxBa2cuNH +Ey6PK3xHBDnYFtSZaRB7QMQMfYVin5oyHq8mOd4mImOKfpGhuuhq1hrT8sOhVxRY +Nl/2Hanya7tEJlVyAAEwtN4QVCqiRjjD7kBQ+mgxdDFo62X+sl4Zz2BFlZks+c1+ +LRWwaQZvGgf2tm2NqZhC04CKc2Gg5j7wNJBPVh/FVluxY27D2hV6v9/cTvXDGo8J +pnZ28CnQqiiaKEU83BGwcUlcr4G5YApHyIPujaxffE2R887ATQRcZVD8AQgA4dh7 +F9t8lZybfX8Rc9w9O5AgTb7uB0H6bOoda4DcRoRN9lZqREh3m7yAecYy+sSmyKqk +Wt8f+yg1QTSb3GtIFLKhLeZM2BfPBcn9jQXHo6SG3D+wUv4PguijqMGI/hLduk+h +ncBVxMVHJfNCb6F/Mh0Dn7yaXYgUW48gfFKnwmpJ5t3O3Tbl5oX5c/8N2gY99qvW +chqgNTaRwqS8lQJb0jUP6Wrf6xlAj2fXbsOCoVFKhJmrUD1RT5LrU6LhGUGzCvov +nITh9wLCgrjQ37wg8Iq57EqiCZgIJdZQuHXvm7FmAjKjfXovfYTgkVMoWd4N7K/E +QaMFQHXL42cXiAygCwARAQABwsB2BBgBCAAgAhsMFiEEXOYJeXAvKFvzKPmxFhwI +dYIjWfcFAmRH1LoACgkQFhwIdYIjWfcnHwf/e4jhRXmEhQeQqjsbMqPU4x73tATs +3xsi4et9vrFEBMN6qsFa3gKq41Wv8JyxVuuz23+BgZ+mZ2iDCKuK7+neMJw2eG9f +MkJCExK1r1Pt7YaXmUvzVHlpS2ZVxWrg4QnT6QKuU58O/uZatKXtgRHDQReCEaAU +bO1EFYa/0KTfsWsG50FDNaCDjJY01rkGbT6O+TrJbUJ+ffjk5+2WEA+EN0p9LzwM +xWzwWuH6LLc28fJLUxln4QXLUK6cEtOlaqEqMK/ERWPUvrLIwivh5atrfGQtAgS9 +WlNQAD6nADn68Pa4p9KzdXR9O4Nbg3mfUp8i7nnuUDe691WPG/bYjiVfZsLAfAQY +AQgAJhYhBFzmCXlwLyhb8yj5sRYcCHWCI1n3BQJcZVD8AhsMBQkDwmcAAAoJEBYc +CHWCI1n3rhcH/iCB0ZV861H0RKJ2F7bXEyCLR2ncBFUCnFo3muSrN9NXTojz2vwv +zexRBpZzaRJoksBkvH+ofuZ1iK7ycZO23dnukvPwGQsz3QiITjVeB6ZR0250MG1q +A5yZRlZCsCbGJb4/2e8Ey8BbblHn49Zta4l2Ex5NpNNQ8FYoqXhXu5Bd2F/wX/Bp +5gkZegfE3H9Dw4QjP82Mt0RZSBg9RMGCk6nNfEuze1Up+IOdtqzf3/Z8J5XxLzN2 +s8WPmDwJDwvxJRtto8U+ulv4ElcwlA+wYiKAq7cRCKGM/si5ClkUNgb319grUrBU +6h8SuYtgnD84965xRiVAgtH4wCPN544N8CE=3D +=3DNmqc +-----END PGP PUBLIC KEY BLOCK----- + +--------------0tRoF00iqRv70TBczVNfagKk-- + +--------------iFRY0nd000IWAcfqrg6ZdUuF-- + +--------------Kh8bXWpcGJrKDmQHlv9QWtgJ +Content-Type: application/pgp-signature; name="OpenPGP_signature.asc" +Content-Description: OpenPGP digital signature +Content-Disposition: attachment; filename="OpenPGP_signature" + +-----BEGIN PGP SIGNATURE----- + +wsB5BAABCAAjFiEEXOYJeXAvKFvzKPmxFhwIdYIjWfcFAmRH7c8FAwAAAAAACgkQFhwIdYIjWffG +uQgAlK68JzT/9NLOg4SZPUbVaEdlbru6ebX1Lwaj93FZEKfmiEZ4heuYfq4yVw1JI/CGhHa1wxUJ +M6+Tg+0lqIslG1rTposgIziugMBhEWXYWXBwDdvu+9T2eqo0se3h+oXueVlRihowfuPcP9jvt6p3 +DR+pu+hJ/D42DarJrn8v0CMm3PyLNHodyKLmEtZrzP4ok9Wal850xZ3Tmu5dL3v300wPGJaxrn8o +4OeHRUodE43UijUrFKNoEfhqzY8HsMKIdF8Bi6+XiA0sHwcaUqJsaczBqgmbJbPqG8N4CokiUnUu +4QDmClWa0rG4I5rrx4PrTbzAt7cGIb8N3ACNI7vI/Q== +=Llod +-----END PGP SIGNATURE----- + +--------------Kh8bXWpcGJrKDmQHlv9QWtgJ-- +--------------Z0a0IncIqoVlOIpOfcALEK5P +Content-Type: application/pgp-keys; name="OpenPGP_0x161C0875822359F7.asc" +Content-Disposition: attachment; filename="OpenPGP_0x161C0875822359F7.asc" +Content-Description: OpenPGP public key +Content-Transfer-Encoding: quoted-printable + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +xsBNBFxlUPwBCACx954Ey4SD88f8DSKFw9BaZNXrNwYxNYSgqaqOGHQ0WllF3mst +EhTfuxxCZpDhI5IhWCXUNxanzsFkn88mRDwFRVl2sf2aAG4/P/p1381oh2kd0UEl +MRQaQGzoCadQMaQOL9WYTf4SPWSCzjrPyKgjq5FbqjbF/ndu376na9L+tnsEXyL6 +RrI6aZhjWG73xlqxS65dzTIYzsyM/P97xSndNvlvWtGvLlpFkzxfAEGpVzfOYVYF +Koc8rGmUDwrDWYfk5JczRDDogJnY+BNMZf9pjSqk6rTyBOfNH5fpU8r7A5Q7l+HV +akvMUQ9DzDWJtg2ru1Y8hexnJOF68avO4+a1ABEBAAHNKEJyaWRnZSBLeXUtRWh5 +aiA8cG0uYnJpZGdlLnFhQGdtYWlsLmNvbT7CwI4EEwEIADgCGwMFCwkIBwIGFQoJ +CAsCBBYCAwECHgECF4AWIQRc5gl5cC8oW/Mo+bEWHAh1giNZ9wUCZEfUzQAKCRAW +HAh1giNZ9872B/4mM6cXErSSYK6/apGUVebg9QiP1RhFlLE/kg7BW3FaSP/yTUZN +ZdX7WPnEVyaa5Dk4xRZiB47Yc5myspwc+JEJ3YDAHq+4n/D74TF1kUCzP+QVsWcn +40UqX9gHbO01O/DYtoxMOljEgkfQjEZcRoHuUhCUzldFf8aV+uZKiOXhrPYCwsil +nh0RAmDV7fLoOfKXMLiKXE8wM/5Bax+dk2AmEM4bOTIo58GGDDqseIg03ocrW7vP +egmxiLUwmsHIIDwTq6qZ0CVxbt2uv4cCyNz/0pmRzG7p8192Evdu8JOuLSj3pI1X +00Ub326yay3BBUnsL4PJIGoly8hnLb5N3cyNwsCUBBMBCAA+FiEEXOYJeXAvKFvz +KPmxFhwIdYIjWfcFAlxlUPwCGwMFCQPCZwAFCwkIBwIGFQoJCAsCBBYCAwECHgEC +F4AACgkQFhwIdYIjWfeQzgf+NWseR+UvrJ7I1CFd6M2+RmyIC1QTQ+uyJIhIBQfC +vBhueU9GUPWR6a6GWsb2DGCMkBM2aHoTCcf46fq87VspYb3+b0JsKfRFxBa2cuNH +Ey6PK3xHBDnYFtSZaRB7QMQMfYVin5oyHq8mOd4mImOKfpGhuuhq1hrT8sOhVxRY +Nl/2Hanya7tEJlVyAAEwtN4QVCqiRjjD7kBQ+mgxdDFo62X+sl4Zz2BFlZks+c1+ +LRWwaQZvGgf2tm2NqZhC04CKc2Gg5j7wNJBPVh/FVluxY27D2hV6v9/cTvXDGo8J +pnZ28CnQqiiaKEU83BGwcUlcr4G5YApHyIPujaxffE2R887ATQRcZVD8AQgA4dh7 +F9t8lZybfX8Rc9w9O5AgTb7uB0H6bOoda4DcRoRN9lZqREh3m7yAecYy+sSmyKqk +Wt8f+yg1QTSb3GtIFLKhLeZM2BfPBcn9jQXHo6SG3D+wUv4PguijqMGI/hLduk+h +ncBVxMVHJfNCb6F/Mh0Dn7yaXYgUW48gfFKnwmpJ5t3O3Tbl5oX5c/8N2gY99qvW +chqgNTaRwqS8lQJb0jUP6Wrf6xlAj2fXbsOCoVFKhJmrUD1RT5LrU6LhGUGzCvov +nITh9wLCgrjQ37wg8Iq57EqiCZgIJdZQuHXvm7FmAjKjfXovfYTgkVMoWd4N7K/E +QaMFQHXL42cXiAygCwARAQABwsB2BBgBCAAgAhsMFiEEXOYJeXAvKFvzKPmxFhwI +dYIjWfcFAmRH1LoACgkQFhwIdYIjWfcnHwf/e4jhRXmEhQeQqjsbMqPU4x73tATs +3xsi4et9vrFEBMN6qsFa3gKq41Wv8JyxVuuz23+BgZ+mZ2iDCKuK7+neMJw2eG9f +MkJCExK1r1Pt7YaXmUvzVHlpS2ZVxWrg4QnT6QKuU58O/uZatKXtgRHDQReCEaAU +bO1EFYa/0KTfsWsG50FDNaCDjJY01rkGbT6O+TrJbUJ+ffjk5+2WEA+EN0p9LzwM +xWzwWuH6LLc28fJLUxln4QXLUK6cEtOlaqEqMK/ERWPUvrLIwivh5atrfGQtAgS9 +WlNQAD6nADn68Pa4p9KzdXR9O4Nbg3mfUp8i7nnuUDe691WPG/bYjiVfZsLAfAQY +AQgAJhYhBFzmCXlwLyhb8yj5sRYcCHWCI1n3BQJcZVD8AhsMBQkDwmcAAAoJEBYc +CHWCI1n3rhcH/iCB0ZV861H0RKJ2F7bXEyCLR2ncBFUCnFo3muSrN9NXTojz2vwv +zexRBpZzaRJoksBkvH+ofuZ1iK7ycZO23dnukvPwGQsz3QiITjVeB6ZR0250MG1q +A5yZRlZCsCbGJb4/2e8Ey8BbblHn49Zta4l2Ex5NpNNQ8FYoqXhXu5Bd2F/wX/Bp +5gkZegfE3H9Dw4QjP82Mt0RZSBg9RMGCk6nNfEuze1Up+IOdtqzf3/Z8J5XxLzN2 +s8WPmDwJDwvxJRtto8U+ulv4ElcwlA+wYiKAq7cRCKGM/si5ClkUNgb319grUrBU +6h8SuYtgnD84965xRiVAgtH4wCPN544N8CE=3D +=3DNmqc +-----END PGP PUBLIC KEY BLOCK----- + +--------------Z0a0IncIqoVlOIpOfcALEK5P-- + +--------------6sNRIgaKOJHTghuLxPUzlxn1-- + +--e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +Content-Description: OpenPGP digital signature +Content-Disposition: attachment; filename=OpenPGP_signature +Content-Type: application/pgp-signature; name=OpenPGP_signature.asc + +-----BEGIN PGP SIGNATURE----- +Version: GopenPGP 2.7.1 +Comment: https://gopenpgp.org + +wsB5BAABCAAjFiEEXOYJeXAvKFvzKPmxFhwIdYIjWfcFAmRIzW4FAwAAAAAACgkQ +FhwIdYIjWfe84QgAj1mf/g/jvobkik9RRvyUCN3InyHBqcwMOgyVDmd4U5uh/DVZ +sZ8kFU+/koEfr/8+Y7ataenEG5pY2f4krZNzc85VzjwniK1xcjxDW86UFa/ud/2Q +OD7eqJUQO1UpuQ/xe4gbfy3BKvTp5u09UjcBDnZ/lHASSREpfGBhk37Y2lkb5iIP +4KR7DOi1S1MFrdDPgKp59B9mk2ZMSC1Njzido9Zm/2tdYldAI66uMQiMgB2iv7yn +FMGxKzewt2OxZWKVmNaAzzvrQw7AYfIr70NbwnK75Gmh1CkwLadNpzSRMCqW5BP6 +TsypxeGfXuQi0upWT2E3YpIvtkOrHRGXY9jXNw== +=5Yce +-----END PGP SIGNATURE----- +--e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855-- diff --git a/pkg/message/testdata/pgp-mime-body-signed-html-with-pubkey.eml b/pkg/message/testdata/pgp-mime-body-signed-html-with-pubkey.eml index 9f530e7f..3191731e 100644 --- a/pkg/message/testdata/pgp-mime-body-signed-html-with-pubkey.eml +++ b/pkg/message/testdata/pgp-mime-body-signed-html-with-pubkey.eml @@ -1,116 +1,119 @@ -Content-Type: multipart/signed; micalg=pgp-sha256; - protocol="application/pgp-signature"; - boundary="pavrbLYh8Q4RWBboYnVxY3mNBBzan1Zz4" - -This is an OpenPGP/MIME signed message (RFC 4880 and 3156) ---pavrbLYh8Q4RWBboYnVxY3mNBBzan1Zz4 -Content-Type: multipart/mixed; boundary="avFoFILZo8SdHM1Pc1OUviN4UKQh16HyR"; - protected-headers="v1" -Subject: simple html body -From: "pm.bridge.qa" -To: schizofrenic@pm.me -Message-ID: - ---avFoFILZo8SdHM1Pc1OUviN4UKQh16HyR -Content-Type: multipart/mixed; - boundary="------------9EAE2E1A715ACB9849E5C4E3" -Content-Language: en-US - -This is a multi-part message in MIME format. ---------------9EAE2E1A715ACB9849E5C4E3 -Content-Type: text/html; charset=utf-8 -Content-Transfer-Encoding: quoted-printable - - - - - - - - And this is HTML
-
    -
  • Do I enjoy making courthouse puns? Guilty.=E2=80=94 @= -baddadjokes
  • -
  • Can February March? No, but April May. =E2=80=94@Bear= -dedMOGuy
  • -
- - - ---------------9EAE2E1A715ACB9849E5C4E3 -Content-Type: application/pgp-keys; - name="OpenPGP_0x161C0875822359F7.asc" -Content-Transfer-Encoding: quoted-printable -Content-Disposition: attachment; - filename="OpenPGP_0x161C0875822359F7.asc" - ------BEGIN PGP PUBLIC KEY BLOCK----- - -xsBNBFxlUPwBCACx954Ey4SD88f8DSKFw9BaZNXrNwYxNYSgqaqOGHQ0WllF3mstEhTfuxxCZ= -pDh -I5IhWCXUNxanzsFkn88mRDwFRVl2sf2aAG4/P/p1381oh2kd0UElMRQaQGzoCadQMaQOL9WYT= -f4S -PWSCzjrPyKgjq5FbqjbF/ndu376na9L+tnsEXyL6RrI6aZhjWG73xlqxS65dzTIYzsyM/P97x= -Snd -NvlvWtGvLlpFkzxfAEGpVzfOYVYFKoc8rGmUDwrDWYfk5JczRDDogJnY+BNMZf9pjSqk6rTyB= -OfN -H5fpU8r7A5Q7l+HVakvMUQ9DzDWJtg2ru1Y8hexnJOF68avO4+a1ABEBAAHNKEJyaWRnZSBLe= -XUt -RWh5aiA8cG0uYnJpZGdlLnFhQGdtYWlsLmNvbT7CwJQEEwEIAD4CGwMFCwkIBwIGFQoJCAsCB= -BYC -AwECHgECF4AWIQRc5gl5cC8oW/Mo+bEWHAh1giNZ9wUCYC32ygUJB4sMzgAKCRAWHAh1giNZ9= -/K8 -B/4qs84Ii/zKH+q+C8vwO4jUJkOM73qD0pgB7zBs651zWbpgopyol1YUKNpFaHlx/Qch7RDI7= -Vcz -1+60/KZJSJR19/N2EDVbCUdh8ueioUp9X/218YWV2TRJNxTnljd4FAn7smZnXuP1TsLjQ6sKO= -V0U -u6JoiG6LZFXqDgxYpA++58Rkl6xaY6R71VkmVQlbEKtubX9AjHydq97Y+Jvn11XzWZaKhv4L7= -6Pa -4tMKXvvrKh1oywMmh6mZJo+5ZA/ABTkr45cwlTPYqGTS9+uvOHt+PH/oYwwJB4ls2cIAUldSj= -TVQ -IsseYz3LlbcCfKJiiCFxeHOQXA5J6zNLKOT58TsczsBNBFxlUPwBCADh2HsX23yVnJt9fxFz3= -D07 -kCBNvu4HQfps6h1rgNxGhE32VmpESHebvIB5xjL6xKbIqqRa3x/7KDVBNJvca0gUsqEt5kzYF= -88F -yf2NBcejpIbcP7BS/g+C6KOowYj+Et26T6GdwFXExUcl80JvoX8yHQOfvJpdiBRbjyB8UqfCa= -knm -3c7dNuXmhflz/w3aBj32q9ZyGqA1NpHCpLyVAlvSNQ/pat/rGUCPZ9duw4KhUUqEmatQPVFPk= -utT -ouEZQbMK+i+chOH3AsKCuNDfvCDwirnsSqIJmAgl1lC4de+bsWYCMqN9ei99hOCRUyhZ3g3sr= -8RB -owVAdcvjZxeIDKALABEBAAHCwHwEGAEIACYCGwwWIQRc5gl5cC8oW/Mo+bEWHAh1giNZ9wUCY= -C32 -lAUJB4sMmAAKCRAWHAh1giNZ9+Y2B/9rTKZaKviae+ummXNumXcrKvbkAAvfuLpKUn53FlQLm= -L6H -jB++lJnPWvVSzdZxdv8FiPP3d632XHKUrkQRQM/9byRDXDommi7Qttx7YCkhd4JLVYqJqpnAQ= -xI5 -RMkXiZNWyr1lz8JOM1XvDk1M7sJwPMWews8VOIE03E1nt7AsQGnvHtadgEnQaufrYNX3hFA8S= -osO -HSnedcys6yrzCSIGCqCD9VHbnMtS4DOv0XJGh2hwc8omzH0KZA517dyKBorJRwadcVauGXDKx= -Etv -Im4rl94PR/3An1Mj6HeeVVpLqDQ5Jb9J90BahWeQ53FzRa4EQzYCw0nLnxcsT1ZEEP5u -=3Dv/1p ------END PGP PUBLIC KEY BLOCK----- - ---------------9EAE2E1A715ACB9849E5C4E3-- - ---avFoFILZo8SdHM1Pc1OUviN4UKQh16HyR-- - ---pavrbLYh8Q4RWBboYnVxY3mNBBzan1Zz4 -Content-Type: application/pgp-signature; name="OpenPGP_signature.asc" -Content-Description: OpenPGP digital signature -Content-Disposition: attachment; filename="OpenPGP_signature" - ------BEGIN PGP SIGNATURE----- - -wsB5BAABCAAjFiEEXOYJeXAvKFvzKPmxFhwIdYIjWfcFAmBa9hAFAwAAAAAACgkQFhwIdYIjWffL -1AgApF18AVOPEm9y5R+d0NQmxqhSwAtvaqCwqQpG3mArIYK3Y0zrDkPQZZl/3emW8LWht7ZyYCAb -NZo7HoYxjLy3yxAOPUl/Pc0nJpEqk/wAZT58yOnzv8DU5Q9o+444FfTMJpcrcH/M5cXYyqRtVhas -k5wu5u2DEgSO3Kj/5l7lThb+CUgRC6wSiOuUkqGEWLiAguCdd88XDkLMbwrDnOu3PbhcA8o1msns -PfkBdq3mFjp4M8M4ha+D2MxmV6tBv1E7snWf/spBVb9fHIa7zI4ZS6shpzGHCnJarO0Jco0Qh3IZ -ZVfwhtJeFsmdqSm6DLvCmQWAYk2fDOZDMVKqe9IbUA== -=pkS0 ------END PGP SIGNATURE----- - ---pavrbLYh8Q4RWBboYnVxY3mNBBzan1Zz4-- +Content-Type: multipart/signed; + boundary=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855; + micalg=SHA-256; protocol="application/pgp-signature" + +--e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +Content-Type: multipart/mixed; boundary="------------iFRY0nd000IWAcfqrg6ZdUuF"; + protected-headers="v1" +From: "pm.bridge.qa" +To: "InfernalBridgeTester@proton.me" +Message-ID: <1655e652-1abc-575f-6e03-5bbf119afbfa@gmail.com> +Subject: simple html body + +--------------iFRY0nd000IWAcfqrg6ZdUuF +Content-Type: multipart/mixed; boundary="------------0tRoF00iqRv70TBczVNfagKk" + +--------------0tRoF00iqRv70TBczVNfagKk +Content-Type: text/html; charset=UTF-8 +Content-Transfer-Encoding: quoted-printable + + + + + + + +

+

And this is HTML
+

+
    +
  • Do I enjoy making courthouse puns? + Guilty.=3D3DE2=3D3D80=3D3D9=3D + 4 @=3D3D baddadjokes
  • +
  • Can February March? No, but April May. =3D3DE2=3D3D80=3D= +3D94@Bear=3D3D + dedMOGuy
  • +
+


+

+

+ +

+ + +--------------0tRoF00iqRv70TBczVNfagKk +Content-Type: application/pgp-keys; name="OpenPGP_0x161C0875822359F7.asc" +Content-Disposition: attachment; filename="OpenPGP_0x161C0875822359F7.asc" +Content-Description: OpenPGP public key +Content-Transfer-Encoding: quoted-printable + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +xsBNBFxlUPwBCACx954Ey4SD88f8DSKFw9BaZNXrNwYxNYSgqaqOGHQ0WllF3mst +EhTfuxxCZpDhI5IhWCXUNxanzsFkn88mRDwFRVl2sf2aAG4/P/p1381oh2kd0UEl +MRQaQGzoCadQMaQOL9WYTf4SPWSCzjrPyKgjq5FbqjbF/ndu376na9L+tnsEXyL6 +RrI6aZhjWG73xlqxS65dzTIYzsyM/P97xSndNvlvWtGvLlpFkzxfAEGpVzfOYVYF +Koc8rGmUDwrDWYfk5JczRDDogJnY+BNMZf9pjSqk6rTyBOfNH5fpU8r7A5Q7l+HV +akvMUQ9DzDWJtg2ru1Y8hexnJOF68avO4+a1ABEBAAHNKEJyaWRnZSBLeXUtRWh5 +aiA8cG0uYnJpZGdlLnFhQGdtYWlsLmNvbT7CwI4EEwEIADgCGwMFCwkIBwIGFQoJ +CAsCBBYCAwECHgECF4AWIQRc5gl5cC8oW/Mo+bEWHAh1giNZ9wUCZEfUzQAKCRAW +HAh1giNZ9872B/4mM6cXErSSYK6/apGUVebg9QiP1RhFlLE/kg7BW3FaSP/yTUZN +ZdX7WPnEVyaa5Dk4xRZiB47Yc5myspwc+JEJ3YDAHq+4n/D74TF1kUCzP+QVsWcn +40UqX9gHbO01O/DYtoxMOljEgkfQjEZcRoHuUhCUzldFf8aV+uZKiOXhrPYCwsil +nh0RAmDV7fLoOfKXMLiKXE8wM/5Bax+dk2AmEM4bOTIo58GGDDqseIg03ocrW7vP +egmxiLUwmsHIIDwTq6qZ0CVxbt2uv4cCyNz/0pmRzG7p8192Evdu8JOuLSj3pI1X +00Ub326yay3BBUnsL4PJIGoly8hnLb5N3cyNwsCUBBMBCAA+FiEEXOYJeXAvKFvz +KPmxFhwIdYIjWfcFAlxlUPwCGwMFCQPCZwAFCwkIBwIGFQoJCAsCBBYCAwECHgEC +F4AACgkQFhwIdYIjWfeQzgf+NWseR+UvrJ7I1CFd6M2+RmyIC1QTQ+uyJIhIBQfC +vBhueU9GUPWR6a6GWsb2DGCMkBM2aHoTCcf46fq87VspYb3+b0JsKfRFxBa2cuNH +Ey6PK3xHBDnYFtSZaRB7QMQMfYVin5oyHq8mOd4mImOKfpGhuuhq1hrT8sOhVxRY +Nl/2Hanya7tEJlVyAAEwtN4QVCqiRjjD7kBQ+mgxdDFo62X+sl4Zz2BFlZks+c1+ +LRWwaQZvGgf2tm2NqZhC04CKc2Gg5j7wNJBPVh/FVluxY27D2hV6v9/cTvXDGo8J +pnZ28CnQqiiaKEU83BGwcUlcr4G5YApHyIPujaxffE2R887ATQRcZVD8AQgA4dh7 +F9t8lZybfX8Rc9w9O5AgTb7uB0H6bOoda4DcRoRN9lZqREh3m7yAecYy+sSmyKqk +Wt8f+yg1QTSb3GtIFLKhLeZM2BfPBcn9jQXHo6SG3D+wUv4PguijqMGI/hLduk+h +ncBVxMVHJfNCb6F/Mh0Dn7yaXYgUW48gfFKnwmpJ5t3O3Tbl5oX5c/8N2gY99qvW +chqgNTaRwqS8lQJb0jUP6Wrf6xlAj2fXbsOCoVFKhJmrUD1RT5LrU6LhGUGzCvov +nITh9wLCgrjQ37wg8Iq57EqiCZgIJdZQuHXvm7FmAjKjfXovfYTgkVMoWd4N7K/E +QaMFQHXL42cXiAygCwARAQABwsB2BBgBCAAgAhsMFiEEXOYJeXAvKFvzKPmxFhwI +dYIjWfcFAmRH1LoACgkQFhwIdYIjWfcnHwf/e4jhRXmEhQeQqjsbMqPU4x73tATs +3xsi4et9vrFEBMN6qsFa3gKq41Wv8JyxVuuz23+BgZ+mZ2iDCKuK7+neMJw2eG9f +MkJCExK1r1Pt7YaXmUvzVHlpS2ZVxWrg4QnT6QKuU58O/uZatKXtgRHDQReCEaAU +bO1EFYa/0KTfsWsG50FDNaCDjJY01rkGbT6O+TrJbUJ+ffjk5+2WEA+EN0p9LzwM +xWzwWuH6LLc28fJLUxln4QXLUK6cEtOlaqEqMK/ERWPUvrLIwivh5atrfGQtAgS9 +WlNQAD6nADn68Pa4p9KzdXR9O4Nbg3mfUp8i7nnuUDe691WPG/bYjiVfZsLAfAQY +AQgAJhYhBFzmCXlwLyhb8yj5sRYcCHWCI1n3BQJcZVD8AhsMBQkDwmcAAAoJEBYc +CHWCI1n3rhcH/iCB0ZV861H0RKJ2F7bXEyCLR2ncBFUCnFo3muSrN9NXTojz2vwv +zexRBpZzaRJoksBkvH+ofuZ1iK7ycZO23dnukvPwGQsz3QiITjVeB6ZR0250MG1q +A5yZRlZCsCbGJb4/2e8Ey8BbblHn49Zta4l2Ex5NpNNQ8FYoqXhXu5Bd2F/wX/Bp +5gkZegfE3H9Dw4QjP82Mt0RZSBg9RMGCk6nNfEuze1Up+IOdtqzf3/Z8J5XxLzN2 +s8WPmDwJDwvxJRtto8U+ulv4ElcwlA+wYiKAq7cRCKGM/si5ClkUNgb319grUrBU +6h8SuYtgnD84965xRiVAgtH4wCPN544N8CE=3D +=3DNmqc +-----END PGP PUBLIC KEY BLOCK----- + +--------------0tRoF00iqRv70TBczVNfagKk-- + +--------------iFRY0nd000IWAcfqrg6ZdUuF-- + +--e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +Content-Description: OpenPGP digital signature +Content-Disposition: attachment; filename=OpenPGP_signature +Content-Type: application/pgp-signature; name=OpenPGP_signature.asc + +-----BEGIN PGP SIGNATURE----- +Version: GopenPGP 2.7.1 +Comment: https://gopenpgp.org + +wsB5BAABCAAjFiEEXOYJeXAvKFvzKPmxFhwIdYIjWfcFAmRH7c8FAwAAAAAACgkQ +FhwIdYIjWffGuQgAlK68JzT/9NLOg4SZPUbVaEdlbru6ebX1Lwaj93FZEKfmiEZ4 +heuYfq4yVw1JI/CGhHa1wxUJM6+Tg+0lqIslG1rTposgIziugMBhEWXYWXBwDdvu ++9T2eqo0se3h+oXueVlRihowfuPcP9jvt6p3DR+pu+hJ/D42DarJrn8v0CMm3PyL +NHodyKLmEtZrzP4ok9Wal850xZ3Tmu5dL3v300wPGJaxrn8o4OeHRUodE43UijUr +FKNoEfhqzY8HsMKIdF8Bi6+XiA0sHwcaUqJsaczBqgmbJbPqG8N4CokiUnUu4QDm +ClWa0rG4I5rrx4PrTbzAt7cGIb8N3ACNI7vI/Q== +=Llod +-----END PGP SIGNATURE----- +--e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855-- diff --git a/pkg/message/testdata/pgp-mime-body-signed-multipart-alternative-with-pubkey.eml b/pkg/message/testdata/pgp-mime-body-signed-multipart-alternative-with-pubkey.eml index cfbf3434..3476abf3 100644 --- a/pkg/message/testdata/pgp-mime-body-signed-multipart-alternative-with-pubkey.eml +++ b/pkg/message/testdata/pgp-mime-body-signed-multipart-alternative-with-pubkey.eml @@ -1,161 +1,143 @@ -Content-Type: multipart/signed; micalg=pgp-sha256; - protocol="application/pgp-signature"; - boundary="MHEDFShwcX18dyE3X7RXujo5fjpgdjHNM" - -This is an OpenPGP/MIME signed message (RFC 4880 and 3156) ---MHEDFShwcX18dyE3X7RXujo5fjpgdjHNM -Content-Type: multipart/mixed; boundary="FBBl2LNv76z8UkvHhSkT9vLwVwxqV8378"; - protected-headers="v1" -Subject: Alternative -From: "pm.bridge.qa" -To: schizofrenic@pm.me -Message-ID: <753d0314-0286-2c88-2abb-f8080ac7a4cb@gmail.com> - ---FBBl2LNv76z8UkvHhSkT9vLwVwxqV8378 -Content-Type: multipart/mixed; - boundary="------------F97C8ED4878E94675762AE43" -Content-Language: en-US - -This is a multi-part message in MIME format. ---------------F97C8ED4878E94675762AE43 -Content-Type: multipart/alternative; - boundary="------------041318B15DD3FA540FED32C6" - - ---------------041318B15DD3FA540FED32C6 -Content-Type: text/plain; charset=utf-8; format=flowed -Content-Transfer-Encoding: quoted-printable - -This Rich formated text - - * /What kind of shoes do ninjas wear? /*Sneakers!* - * /How does a penguin build its house?/**_/*Igloos it together.*/_ - - - - ---------------041318B15DD3FA540FED32C6 -Content-Type: text/html; charset=utf-8 -Content-Transfer-Encoding: quoted-printable - - - - - - - -

This Rich formated text

-
    -
  • What kind of shoes do ninjas wear? Sneakers!
  • = - -
  • How does a penguin build its house? Iglo= -os - it together.
  • -
-


-

-


-

- - - ---------------041318B15DD3FA540FED32C6-- - ---------------F97C8ED4878E94675762AE43 -Content-Type: application/pdf; - name="minimal.pdf" -Content-Transfer-Encoding: base64 -Content-Disposition: attachment; - filename="minimal.pdf" - -JVBERi0xLjEKJcKlwrHDqwoKMSAwIG9iagogIDw8IC9UeXBlIC9DYXRhbG9nCiAgICAgL1Bh -Z2VzIDIgMCBSCiAgPj4KZW5kb2JqCgoyIDAgb2JqCiAgPDwgL1R5cGUgL1BhZ2VzCiAgICAg -L0tpZHMgWzMgMCBSXQogICAgIC9Db3VudCAxCiAgICAgL01lZGlhQm94IFswIDAgMzAwIDE0 -NF0KICA+PgplbmRvYmoKCjMgMCBvYmoKICA8PCAgL1R5cGUgL1BhZ2UKICAgICAgL1BhcmVu -dCAyIDAgUgogICAgICAvUmVzb3VyY2VzCiAgICAgICA8PCAvRm9udAogICAgICAgICAgIDw8 -IC9GMQogICAgICAgICAgICAgICA8PCAvVHlwZSAvRm9udAogICAgICAgICAgICAgICAgICAv -U3VidHlwZSAvVHlwZTEKICAgICAgICAgICAgICAgICAgL0Jhc2VGb250IC9UaW1lcy1Sb21h -bgogICAgICAgICAgICAgICA+PgogICAgICAgICAgID4+CiAgICAgICA+PgogICAgICAvQ29u -dGVudHMgNCAwIFIKICA+PgplbmRvYmoKCjQgMCBvYmoKICA8PCAvTGVuZ3RoIDU1ID4+CnN0 -cmVhbQogIEJUCiAgICAvRjEgMTggVGYKICAgIDAgMCBUZAogICAgKEhlbGxvIFdvcmxkKSBU -agogIEVUCmVuZHN0cmVhbQplbmRvYmoKCnhyZWYKMCA1CjAwMDAwMDAwMDAgNjU1MzUgZiAK -MDAwMDAwMDAxOCAwMDAwMCBuIAowMDAwMDAwMDc3IDAwMDAwIG4gCjAwMDAwMDAxNzggMDAw -MDAgbiAKMDAwMDAwMDQ1NyAwMDAwMCBuIAp0cmFpbGVyCiAgPDwgIC9Sb290IDEgMCBSCiAg -ICAgIC9TaXplIDUKICA+PgpzdGFydHhyZWYKNTY1CiUlRU9GCg== ---------------F97C8ED4878E94675762AE43 -Content-Type: application/pgp-keys; - name="OpenPGP_0x161C0875822359F7.asc" -Content-Transfer-Encoding: quoted-printable -Content-Disposition: attachment; - filename="OpenPGP_0x161C0875822359F7.asc" - ------BEGIN PGP PUBLIC KEY BLOCK----- - -xsBNBFxlUPwBCACx954Ey4SD88f8DSKFw9BaZNXrNwYxNYSgqaqOGHQ0WllF3mstEhTfuxxCZ= -pDh -I5IhWCXUNxanzsFkn88mRDwFRVl2sf2aAG4/P/p1381oh2kd0UElMRQaQGzoCadQMaQOL9WYT= -f4S -PWSCzjrPyKgjq5FbqjbF/ndu376na9L+tnsEXyL6RrI6aZhjWG73xlqxS65dzTIYzsyM/P97x= -Snd -NvlvWtGvLlpFkzxfAEGpVzfOYVYFKoc8rGmUDwrDWYfk5JczRDDogJnY+BNMZf9pjSqk6rTyB= -OfN -H5fpU8r7A5Q7l+HVakvMUQ9DzDWJtg2ru1Y8hexnJOF68avO4+a1ABEBAAHNKEJyaWRnZSBLe= -XUt -RWh5aiA8cG0uYnJpZGdlLnFhQGdtYWlsLmNvbT7CwJQEEwEIAD4CGwMFCwkIBwIGFQoJCAsCB= -BYC -AwECHgECF4AWIQRc5gl5cC8oW/Mo+bEWHAh1giNZ9wUCYC32ygUJB4sMzgAKCRAWHAh1giNZ9= -/K8 -B/4qs84Ii/zKH+q+C8vwO4jUJkOM73qD0pgB7zBs651zWbpgopyol1YUKNpFaHlx/Qch7RDI7= -Vcz -1+60/KZJSJR19/N2EDVbCUdh8ueioUp9X/218YWV2TRJNxTnljd4FAn7smZnXuP1TsLjQ6sKO= -V0U -u6JoiG6LZFXqDgxYpA++58Rkl6xaY6R71VkmVQlbEKtubX9AjHydq97Y+Jvn11XzWZaKhv4L7= -6Pa -4tMKXvvrKh1oywMmh6mZJo+5ZA/ABTkr45cwlTPYqGTS9+uvOHt+PH/oYwwJB4ls2cIAUldSj= -TVQ -IsseYz3LlbcCfKJiiCFxeHOQXA5J6zNLKOT58TsczsBNBFxlUPwBCADh2HsX23yVnJt9fxFz3= -D07 -kCBNvu4HQfps6h1rgNxGhE32VmpESHebvIB5xjL6xKbIqqRa3x/7KDVBNJvca0gUsqEt5kzYF= -88F -yf2NBcejpIbcP7BS/g+C6KOowYj+Et26T6GdwFXExUcl80JvoX8yHQOfvJpdiBRbjyB8UqfCa= -knm -3c7dNuXmhflz/w3aBj32q9ZyGqA1NpHCpLyVAlvSNQ/pat/rGUCPZ9duw4KhUUqEmatQPVFPk= -utT -ouEZQbMK+i+chOH3AsKCuNDfvCDwirnsSqIJmAgl1lC4de+bsWYCMqN9ei99hOCRUyhZ3g3sr= -8RB -owVAdcvjZxeIDKALABEBAAHCwHwEGAEIACYCGwwWIQRc5gl5cC8oW/Mo+bEWHAh1giNZ9wUCY= -C32 -lAUJB4sMmAAKCRAWHAh1giNZ9+Y2B/9rTKZaKviae+ummXNumXcrKvbkAAvfuLpKUn53FlQLm= -L6H -jB++lJnPWvVSzdZxdv8FiPP3d632XHKUrkQRQM/9byRDXDommi7Qttx7YCkhd4JLVYqJqpnAQ= -xI5 -RMkXiZNWyr1lz8JOM1XvDk1M7sJwPMWews8VOIE03E1nt7AsQGnvHtadgEnQaufrYNX3hFA8S= -osO -HSnedcys6yrzCSIGCqCD9VHbnMtS4DOv0XJGh2hwc8omzH0KZA517dyKBorJRwadcVauGXDKx= -Etv -Im4rl94PR/3An1Mj6HeeVVpLqDQ5Jb9J90BahWeQ53FzRa4EQzYCw0nLnxcsT1ZEEP5u -=3Dv/1p ------END PGP PUBLIC KEY BLOCK----- - ---------------F97C8ED4878E94675762AE43-- - ---FBBl2LNv76z8UkvHhSkT9vLwVwxqV8378-- - ---MHEDFShwcX18dyE3X7RXujo5fjpgdjHNM -Content-Type: application/pgp-signature; name="OpenPGP_signature.asc" -Content-Description: OpenPGP digital signature -Content-Disposition: attachment; filename="OpenPGP_signature" - ------BEGIN PGP SIGNATURE----- - -wsB5BAABCAAjFiEEXOYJeXAvKFvzKPmxFhwIdYIjWfcFAmBciUoFAwAAAAAACgkQFhwIdYIjWfez -rgf+NZCibnCUTovpWRVRiiPQtBPGeHUPEwz2xq2zz4AaqrHC2v4mYUIPe6am7INk8fkBLsa8Dj/A -UN/28Qh7tNb7JsXtHDT4PIoXszukQ8VIRbe09mSkkP6jR4WzNR166d6n3rSxzHpviOyQldjjpOMr -Zl7LxmgGr4ojsgCf6pvurWwCCOGJqbSusrD6JVv6DsmPmmQeBmnlTK/0oG9pnlNkugpNB1WS2K5d -RY6+kWkSrxbq95HrgILpHip8Y/+ITWvQocm14PBIAAdW8Hr7iFQLETFJ/KDA+VP19Bt8n4Kitdi8 -DPqMsV0oOhATqBjnD63AePJ0VWg8R1z6GEK5A+WOpg== -=Bc6p ------END PGP SIGNATURE----- - ---MHEDFShwcX18dyE3X7RXujo5fjpgdjHNM-- +Content-Type: multipart/signed; + boundary=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855; + micalg=SHA-256; protocol="application/pgp-signature" + +--e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +Content-Type: multipart/mixed; boundary="------------8730PPHC3FpcshavBTup7Fxz"; + protected-headers="v1" +From: "pm.bridge.qa" +To: "InfernalBridgeTester@proton.me" +Message-ID: <5dce90f2-f1e5-eecb-672e-f39def728f44@gmail.com> +Subject: Alternative + +--------------8730PPHC3FpcshavBTup7Fxz +Content-Type: multipart/mixed; boundary="------------CCuN7f3eLVIM0a1fSlNjk0pq" + +--------------CCuN7f3eLVIM0a1fSlNjk0pq +Content-Type: multipart/alternative; + boundary="------------5kz0EAFr3j63ikmxfQPRt0bq" + +--------------5kz0EAFr3j63ikmxfQPRt0bq +Content-Type: text/plain; charset=UTF-8; format=flowed +Content-Transfer-Encoding: base64 + +VGhpcyBSaWNoIGZvcm1hdGVkIHRleHQNCg0KICAqIFdoYXQga2luZCBvZiBzaG9lcyBkbyBu +aW5qYXMgd2Vhcj8gKlNuZWFrZXJzISoNCiAgKiBIb3cgZG9lcyBhIHBlbmd1aW4gYnVpbGQg +aXRzIGhvdXNlPyAqSWdsb29zIGl0IHRvZ2V0aGVyKg0KDQpUaGlzIFJpY2ggZm9ybWF0ZWQg +dGV4dA0KDQogICogL1doYXQga2luZCBvZiBzaG9lcyBkbyBuaW5qYXMgd2Vhcj8gLypTbmVh +a2VycyEqDQogICogL0hvdyBkb2VzIGEgcGVuZ3VpbiBidWlsZCBpdHMgaG91c2U/LyoqXy8q +SWdsb29zIGl0IHRvZ2V0aGVyLiovXw0KDQoNCg0K +--------------5kz0EAFr3j63ikmxfQPRt0bq +Content-Type: text/html; charset=UTF-8 +Content-Transfer-Encoding: quoted-printable + + + + + + + +

This Rich formated text
+

+
    +
  • What kind of shoes do ninjas wear? Sneakers!
  • +
  • How does a penguin build its house? Igloos it together +
+

+

This Rich formated + text

+
    +
  • What kind of shoes do ninjas wear? Sneakers!
  • = + +
  • How does a penguin build its house? Iglo= +os + it together.
  • +
+


+

+


+

+

+ +

+ + + +--------------5kz0EAFr3j63ikmxfQPRt0bq-- +--------------CCuN7f3eLVIM0a1fSlNjk0pq +Content-Type: application/pgp-keys; name="OpenPGP_0x161C0875822359F7.asc" +Content-Disposition: attachment; filename="OpenPGP_0x161C0875822359F7.asc" +Content-Description: OpenPGP public key +Content-Transfer-Encoding: quoted-printable + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +xsBNBFxlUPwBCACx954Ey4SD88f8DSKFw9BaZNXrNwYxNYSgqaqOGHQ0WllF3mst +EhTfuxxCZpDhI5IhWCXUNxanzsFkn88mRDwFRVl2sf2aAG4/P/p1381oh2kd0UEl +MRQaQGzoCadQMaQOL9WYTf4SPWSCzjrPyKgjq5FbqjbF/ndu376na9L+tnsEXyL6 +RrI6aZhjWG73xlqxS65dzTIYzsyM/P97xSndNvlvWtGvLlpFkzxfAEGpVzfOYVYF +Koc8rGmUDwrDWYfk5JczRDDogJnY+BNMZf9pjSqk6rTyBOfNH5fpU8r7A5Q7l+HV +akvMUQ9DzDWJtg2ru1Y8hexnJOF68avO4+a1ABEBAAHNKEJyaWRnZSBLeXUtRWh5 +aiA8cG0uYnJpZGdlLnFhQGdtYWlsLmNvbT7CwI4EEwEIADgCGwMFCwkIBwIGFQoJ +CAsCBBYCAwECHgECF4AWIQRc5gl5cC8oW/Mo+bEWHAh1giNZ9wUCZEfUzQAKCRAW +HAh1giNZ9872B/4mM6cXErSSYK6/apGUVebg9QiP1RhFlLE/kg7BW3FaSP/yTUZN +ZdX7WPnEVyaa5Dk4xRZiB47Yc5myspwc+JEJ3YDAHq+4n/D74TF1kUCzP+QVsWcn +40UqX9gHbO01O/DYtoxMOljEgkfQjEZcRoHuUhCUzldFf8aV+uZKiOXhrPYCwsil +nh0RAmDV7fLoOfKXMLiKXE8wM/5Bax+dk2AmEM4bOTIo58GGDDqseIg03ocrW7vP +egmxiLUwmsHIIDwTq6qZ0CVxbt2uv4cCyNz/0pmRzG7p8192Evdu8JOuLSj3pI1X +00Ub326yay3BBUnsL4PJIGoly8hnLb5N3cyNwsCUBBMBCAA+FiEEXOYJeXAvKFvz +KPmxFhwIdYIjWfcFAlxlUPwCGwMFCQPCZwAFCwkIBwIGFQoJCAsCBBYCAwECHgEC +F4AACgkQFhwIdYIjWfeQzgf+NWseR+UvrJ7I1CFd6M2+RmyIC1QTQ+uyJIhIBQfC +vBhueU9GUPWR6a6GWsb2DGCMkBM2aHoTCcf46fq87VspYb3+b0JsKfRFxBa2cuNH +Ey6PK3xHBDnYFtSZaRB7QMQMfYVin5oyHq8mOd4mImOKfpGhuuhq1hrT8sOhVxRY +Nl/2Hanya7tEJlVyAAEwtN4QVCqiRjjD7kBQ+mgxdDFo62X+sl4Zz2BFlZks+c1+ +LRWwaQZvGgf2tm2NqZhC04CKc2Gg5j7wNJBPVh/FVluxY27D2hV6v9/cTvXDGo8J +pnZ28CnQqiiaKEU83BGwcUlcr4G5YApHyIPujaxffE2R887ATQRcZVD8AQgA4dh7 +F9t8lZybfX8Rc9w9O5AgTb7uB0H6bOoda4DcRoRN9lZqREh3m7yAecYy+sSmyKqk +Wt8f+yg1QTSb3GtIFLKhLeZM2BfPBcn9jQXHo6SG3D+wUv4PguijqMGI/hLduk+h +ncBVxMVHJfNCb6F/Mh0Dn7yaXYgUW48gfFKnwmpJ5t3O3Tbl5oX5c/8N2gY99qvW +chqgNTaRwqS8lQJb0jUP6Wrf6xlAj2fXbsOCoVFKhJmrUD1RT5LrU6LhGUGzCvov +nITh9wLCgrjQ37wg8Iq57EqiCZgIJdZQuHXvm7FmAjKjfXovfYTgkVMoWd4N7K/E +QaMFQHXL42cXiAygCwARAQABwsB2BBgBCAAgAhsMFiEEXOYJeXAvKFvzKPmxFhwI +dYIjWfcFAmRH1LoACgkQFhwIdYIjWfcnHwf/e4jhRXmEhQeQqjsbMqPU4x73tATs +3xsi4et9vrFEBMN6qsFa3gKq41Wv8JyxVuuz23+BgZ+mZ2iDCKuK7+neMJw2eG9f +MkJCExK1r1Pt7YaXmUvzVHlpS2ZVxWrg4QnT6QKuU58O/uZatKXtgRHDQReCEaAU +bO1EFYa/0KTfsWsG50FDNaCDjJY01rkGbT6O+TrJbUJ+ffjk5+2WEA+EN0p9LzwM +xWzwWuH6LLc28fJLUxln4QXLUK6cEtOlaqEqMK/ERWPUvrLIwivh5atrfGQtAgS9 +WlNQAD6nADn68Pa4p9KzdXR9O4Nbg3mfUp8i7nnuUDe691WPG/bYjiVfZsLAfAQY +AQgAJhYhBFzmCXlwLyhb8yj5sRYcCHWCI1n3BQJcZVD8AhsMBQkDwmcAAAoJEBYc +CHWCI1n3rhcH/iCB0ZV861H0RKJ2F7bXEyCLR2ncBFUCnFo3muSrN9NXTojz2vwv +zexRBpZzaRJoksBkvH+ofuZ1iK7ycZO23dnukvPwGQsz3QiITjVeB6ZR0250MG1q +A5yZRlZCsCbGJb4/2e8Ey8BbblHn49Zta4l2Ex5NpNNQ8FYoqXhXu5Bd2F/wX/Bp +5gkZegfE3H9Dw4QjP82Mt0RZSBg9RMGCk6nNfEuze1Up+IOdtqzf3/Z8J5XxLzN2 +s8WPmDwJDwvxJRtto8U+ulv4ElcwlA+wYiKAq7cRCKGM/si5ClkUNgb319grUrBU +6h8SuYtgnD84965xRiVAgtH4wCPN544N8CE=3D +=3DNmqc +-----END PGP PUBLIC KEY BLOCK----- + +--------------CCuN7f3eLVIM0a1fSlNjk0pq-- + +--------------8730PPHC3FpcshavBTup7Fxz-- + +--e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +Content-Description: OpenPGP digital signature +Content-Disposition: attachment; filename=OpenPGP_signature +Content-Type: application/pgp-signature; name=OpenPGP_signature.asc + +-----BEGIN PGP SIGNATURE----- +Version: GopenPGP 2.7.1 +Comment: https://gopenpgp.org + +wsB5BAABCAAjFiEEXOYJeXAvKFvzKPmxFhwIdYIjWfcFAmRH94EFAwAAAAAACgkQ +FhwIdYIjWfcFfgf/XHYGr9+DcntW0TLe6dO82xhLuO6HFmQnnChnfNHKA5U6pOeU +5wJoEFL2O4WEU1hbuf5K0wpgPi8ZF+r966bCUTt+tYT/p7sKV0OXYJjtPYxiL+ju +RaNZgK3rIDyi2DNjbRXSV1Y7H2S3pMLAwPio7ovNpe3OgfkAgFDdiG+NnXl8CzqN +suhMwqJbLJRWlEaX7UdbcLimpNtPIU7wtr4YV0NIsqt3EV7AeHnVI9cHJMLvF5tB +VrnkxXbdO3xEylUB+MNmX5NDIrCg5Iwwq4NMk6qaMK80J9XSxERln56SJVN/+tIu +TZFgwBWM/n48prGXrEo8TPk5UkrVYhLXl/ndTg== +=FIoh +-----END PGP SIGNATURE----- +--e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855-- diff --git a/pkg/message/testdata/pgp-mime-body-signed-plaintext-with-pubkey.eml b/pkg/message/testdata/pgp-mime-body-signed-plaintext-with-pubkey.eml index 99a7d84e..7218ff61 100644 --- a/pkg/message/testdata/pgp-mime-body-signed-plaintext-with-pubkey.eml +++ b/pkg/message/testdata/pgp-mime-body-signed-plaintext-with-pubkey.eml @@ -1,103 +1,95 @@ -Content-Type: multipart/signed; micalg=pgp-sha256; - protocol="application/pgp-signature"; - boundary="x4FrOFG2PnNJvlbzxe80NPwxzh2yUHABp" - -This is an OpenPGP/MIME signed message (RFC 4880 and 3156) ---x4FrOFG2PnNJvlbzxe80NPwxzh2yUHABp -Content-Type: multipart/mixed; boundary="bBln6dwDJTLkin5LPHkHBQudqRLwIzTUH"; - protected-headers="v1" -Subject: simple plaintext body -From: "pm.bridge.qa" -To: schizofrenic@pm.me -Message-ID: - ---bBln6dwDJTLkin5LPHkHBQudqRLwIzTUH -Content-Type: multipart/mixed; - boundary="------------1B34C666A4C2FB03E0324F1A" -Content-Language: en-US - -This is a multi-part message in MIME format. ---------------1B34C666A4C2FB03E0324F1A -Content-Type: text/plain; charset=utf-8; format=flowed -Content-Transfer-Encoding: quoted-printable - -Why don't crabs give to charity? Because they're shellfish. - - - ---------------1B34C666A4C2FB03E0324F1A -Content-Type: application/pgp-keys; - name="OpenPGP_0x161C0875822359F7.asc" -Content-Transfer-Encoding: quoted-printable -Content-Disposition: attachment; - filename="OpenPGP_0x161C0875822359F7.asc" - ------BEGIN PGP PUBLIC KEY BLOCK----- - -xsBNBFxlUPwBCACx954Ey4SD88f8DSKFw9BaZNXrNwYxNYSgqaqOGHQ0WllF3mstEhTfuxxCZ= -pDh -I5IhWCXUNxanzsFkn88mRDwFRVl2sf2aAG4/P/p1381oh2kd0UElMRQaQGzoCadQMaQOL9WYT= -f4S -PWSCzjrPyKgjq5FbqjbF/ndu376na9L+tnsEXyL6RrI6aZhjWG73xlqxS65dzTIYzsyM/P97x= -Snd -NvlvWtGvLlpFkzxfAEGpVzfOYVYFKoc8rGmUDwrDWYfk5JczRDDogJnY+BNMZf9pjSqk6rTyB= -OfN -H5fpU8r7A5Q7l+HVakvMUQ9DzDWJtg2ru1Y8hexnJOF68avO4+a1ABEBAAHNKEJyaWRnZSBLe= -XUt -RWh5aiA8cG0uYnJpZGdlLnFhQGdtYWlsLmNvbT7CwJQEEwEIAD4CGwMFCwkIBwIGFQoJCAsCB= -BYC -AwECHgECF4AWIQRc5gl5cC8oW/Mo+bEWHAh1giNZ9wUCYC32ygUJB4sMzgAKCRAWHAh1giNZ9= -/K8 -B/4qs84Ii/zKH+q+C8vwO4jUJkOM73qD0pgB7zBs651zWbpgopyol1YUKNpFaHlx/Qch7RDI7= -Vcz -1+60/KZJSJR19/N2EDVbCUdh8ueioUp9X/218YWV2TRJNxTnljd4FAn7smZnXuP1TsLjQ6sKO= -V0U -u6JoiG6LZFXqDgxYpA++58Rkl6xaY6R71VkmVQlbEKtubX9AjHydq97Y+Jvn11XzWZaKhv4L7= -6Pa -4tMKXvvrKh1oywMmh6mZJo+5ZA/ABTkr45cwlTPYqGTS9+uvOHt+PH/oYwwJB4ls2cIAUldSj= -TVQ -IsseYz3LlbcCfKJiiCFxeHOQXA5J6zNLKOT58TsczsBNBFxlUPwBCADh2HsX23yVnJt9fxFz3= -D07 -kCBNvu4HQfps6h1rgNxGhE32VmpESHebvIB5xjL6xKbIqqRa3x/7KDVBNJvca0gUsqEt5kzYF= -88F -yf2NBcejpIbcP7BS/g+C6KOowYj+Et26T6GdwFXExUcl80JvoX8yHQOfvJpdiBRbjyB8UqfCa= -knm -3c7dNuXmhflz/w3aBj32q9ZyGqA1NpHCpLyVAlvSNQ/pat/rGUCPZ9duw4KhUUqEmatQPVFPk= -utT -ouEZQbMK+i+chOH3AsKCuNDfvCDwirnsSqIJmAgl1lC4de+bsWYCMqN9ei99hOCRUyhZ3g3sr= -8RB -owVAdcvjZxeIDKALABEBAAHCwHwEGAEIACYCGwwWIQRc5gl5cC8oW/Mo+bEWHAh1giNZ9wUCY= -C32 -lAUJB4sMmAAKCRAWHAh1giNZ9+Y2B/9rTKZaKviae+ummXNumXcrKvbkAAvfuLpKUn53FlQLm= -L6H -jB++lJnPWvVSzdZxdv8FiPP3d632XHKUrkQRQM/9byRDXDommi7Qttx7YCkhd4JLVYqJqpnAQ= -xI5 -RMkXiZNWyr1lz8JOM1XvDk1M7sJwPMWews8VOIE03E1nt7AsQGnvHtadgEnQaufrYNX3hFA8S= -osO -HSnedcys6yrzCSIGCqCD9VHbnMtS4DOv0XJGh2hwc8omzH0KZA517dyKBorJRwadcVauGXDKx= -Etv -Im4rl94PR/3An1Mj6HeeVVpLqDQ5Jb9J90BahWeQ53FzRa4EQzYCw0nLnxcsT1ZEEP5u -=3Dv/1p ------END PGP PUBLIC KEY BLOCK----- - ---------------1B34C666A4C2FB03E0324F1A-- - ---bBln6dwDJTLkin5LPHkHBQudqRLwIzTUH-- - ---x4FrOFG2PnNJvlbzxe80NPwxzh2yUHABp -Content-Type: application/pgp-signature; name="OpenPGP_signature.asc" -Content-Description: OpenPGP digital signature -Content-Disposition: attachment; filename="OpenPGP_signature" - ------BEGIN PGP SIGNATURE----- - -wsB5BAABCAAjFiEEXOYJeXAvKFvzKPmxFhwIdYIjWfcFAmBa9YIFAwAAAAAACgkQFhwIdYIjWfem -vQgAjUMAaxL7D6fRtFBqLjdQGr7PkDBigeQD9ax17CJFld7Zfo2dAYUzYJRi0HP0Kn1YCSBppF0w -5/P8458H2sqfPC32ptbDCZ/seL0Rpt/gRx6yufbz7wQC0iUZxqxBq2Ox9PGZYSCrTO837lAVYxUo -aMnDL/K9ohAGIyTZVv31z+r3LLWQsFpfpB5hJFqsjQXA9IGKSQIkWbaeE+0wveJSwqxdTwYvsHs2 -xjBw+s8tRHO/whP4pvzL185fGsHAb8x9a9oyoDVcszhw5xBpiWW37mI58qkQ6g+4wTarreuXGTp3 -RKgPupoYOMJja90yh3TWovcmuZz6QOgne5Rbn3s+Vg== -=hUb8 ------END PGP SIGNATURE----- - ---x4FrOFG2PnNJvlbzxe80NPwxzh2yUHABp-- +Content-Type: multipart/signed; + boundary=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855; + micalg=SHA-256; protocol="application/pgp-signature" + +--e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +Content-Type: multipart/mixed; boundary="------------bhHlRtbq4tEzp2NgVmAJ4AbV"; + protected-headers="v1" +From: "pm.bridge.qa" +To: "InfernalBridgeTester@proton.me" +Message-ID: <9bb09a2a-1442-9439-f53f-490df7e46331@gmail.com> +Subject: simple plaintext body + +--------------bhHlRtbq4tEzp2NgVmAJ4AbV +Content-Type: multipart/mixed; boundary="------------FHzf8jBNv06d9SowGc7KOjXr" + +--------------FHzf8jBNv06d9SowGc7KOjXr +Content-Type: text/plain; charset=UTF-8; format=flowed +Content-Transfer-Encoding: base64 + +V2h5IGRvbid0IGNyYWJzIGdpdmUgdG8gY2hhcml0eT8gQmVjYXVzZSB0aGV5J3JlIHNoZWxs +ZmlzaC4NCg0K +--------------FHzf8jBNv06d9SowGc7KOjXr +Content-Type: application/pgp-keys; name="OpenPGP_0x161C0875822359F7.asc" +Content-Disposition: attachment; filename="OpenPGP_0x161C0875822359F7.asc" +Content-Description: OpenPGP public key +Content-Transfer-Encoding: quoted-printable + +-----BEGIN PGP PUBLIC KEY BLOCK----- + +xsBNBFxlUPwBCACx954Ey4SD88f8DSKFw9BaZNXrNwYxNYSgqaqOGHQ0WllF3mst +EhTfuxxCZpDhI5IhWCXUNxanzsFkn88mRDwFRVl2sf2aAG4/P/p1381oh2kd0UEl +MRQaQGzoCadQMaQOL9WYTf4SPWSCzjrPyKgjq5FbqjbF/ndu376na9L+tnsEXyL6 +RrI6aZhjWG73xlqxS65dzTIYzsyM/P97xSndNvlvWtGvLlpFkzxfAEGpVzfOYVYF +Koc8rGmUDwrDWYfk5JczRDDogJnY+BNMZf9pjSqk6rTyBOfNH5fpU8r7A5Q7l+HV +akvMUQ9DzDWJtg2ru1Y8hexnJOF68avO4+a1ABEBAAHNKEJyaWRnZSBLeXUtRWh5 +aiA8cG0uYnJpZGdlLnFhQGdtYWlsLmNvbT7CwI4EEwEIADgCGwMFCwkIBwIGFQoJ +CAsCBBYCAwECHgECF4AWIQRc5gl5cC8oW/Mo+bEWHAh1giNZ9wUCZEfUzQAKCRAW +HAh1giNZ9872B/4mM6cXErSSYK6/apGUVebg9QiP1RhFlLE/kg7BW3FaSP/yTUZN +ZdX7WPnEVyaa5Dk4xRZiB47Yc5myspwc+JEJ3YDAHq+4n/D74TF1kUCzP+QVsWcn +40UqX9gHbO01O/DYtoxMOljEgkfQjEZcRoHuUhCUzldFf8aV+uZKiOXhrPYCwsil +nh0RAmDV7fLoOfKXMLiKXE8wM/5Bax+dk2AmEM4bOTIo58GGDDqseIg03ocrW7vP +egmxiLUwmsHIIDwTq6qZ0CVxbt2uv4cCyNz/0pmRzG7p8192Evdu8JOuLSj3pI1X +00Ub326yay3BBUnsL4PJIGoly8hnLb5N3cyNwsCUBBMBCAA+FiEEXOYJeXAvKFvz +KPmxFhwIdYIjWfcFAlxlUPwCGwMFCQPCZwAFCwkIBwIGFQoJCAsCBBYCAwECHgEC +F4AACgkQFhwIdYIjWfeQzgf+NWseR+UvrJ7I1CFd6M2+RmyIC1QTQ+uyJIhIBQfC +vBhueU9GUPWR6a6GWsb2DGCMkBM2aHoTCcf46fq87VspYb3+b0JsKfRFxBa2cuNH +Ey6PK3xHBDnYFtSZaRB7QMQMfYVin5oyHq8mOd4mImOKfpGhuuhq1hrT8sOhVxRY +Nl/2Hanya7tEJlVyAAEwtN4QVCqiRjjD7kBQ+mgxdDFo62X+sl4Zz2BFlZks+c1+ +LRWwaQZvGgf2tm2NqZhC04CKc2Gg5j7wNJBPVh/FVluxY27D2hV6v9/cTvXDGo8J +pnZ28CnQqiiaKEU83BGwcUlcr4G5YApHyIPujaxffE2R887ATQRcZVD8AQgA4dh7 +F9t8lZybfX8Rc9w9O5AgTb7uB0H6bOoda4DcRoRN9lZqREh3m7yAecYy+sSmyKqk +Wt8f+yg1QTSb3GtIFLKhLeZM2BfPBcn9jQXHo6SG3D+wUv4PguijqMGI/hLduk+h +ncBVxMVHJfNCb6F/Mh0Dn7yaXYgUW48gfFKnwmpJ5t3O3Tbl5oX5c/8N2gY99qvW +chqgNTaRwqS8lQJb0jUP6Wrf6xlAj2fXbsOCoVFKhJmrUD1RT5LrU6LhGUGzCvov +nITh9wLCgrjQ37wg8Iq57EqiCZgIJdZQuHXvm7FmAjKjfXovfYTgkVMoWd4N7K/E +QaMFQHXL42cXiAygCwARAQABwsB2BBgBCAAgAhsMFiEEXOYJeXAvKFvzKPmxFhwI +dYIjWfcFAmRH1LoACgkQFhwIdYIjWfcnHwf/e4jhRXmEhQeQqjsbMqPU4x73tATs +3xsi4et9vrFEBMN6qsFa3gKq41Wv8JyxVuuz23+BgZ+mZ2iDCKuK7+neMJw2eG9f +MkJCExK1r1Pt7YaXmUvzVHlpS2ZVxWrg4QnT6QKuU58O/uZatKXtgRHDQReCEaAU +bO1EFYa/0KTfsWsG50FDNaCDjJY01rkGbT6O+TrJbUJ+ffjk5+2WEA+EN0p9LzwM +xWzwWuH6LLc28fJLUxln4QXLUK6cEtOlaqEqMK/ERWPUvrLIwivh5atrfGQtAgS9 +WlNQAD6nADn68Pa4p9KzdXR9O4Nbg3mfUp8i7nnuUDe691WPG/bYjiVfZsLAfAQY +AQgAJhYhBFzmCXlwLyhb8yj5sRYcCHWCI1n3BQJcZVD8AhsMBQkDwmcAAAoJEBYc +CHWCI1n3rhcH/iCB0ZV861H0RKJ2F7bXEyCLR2ncBFUCnFo3muSrN9NXTojz2vwv +zexRBpZzaRJoksBkvH+ofuZ1iK7ycZO23dnukvPwGQsz3QiITjVeB6ZR0250MG1q +A5yZRlZCsCbGJb4/2e8Ey8BbblHn49Zta4l2Ex5NpNNQ8FYoqXhXu5Bd2F/wX/Bp +5gkZegfE3H9Dw4QjP82Mt0RZSBg9RMGCk6nNfEuze1Up+IOdtqzf3/Z8J5XxLzN2 +s8WPmDwJDwvxJRtto8U+ulv4ElcwlA+wYiKAq7cRCKGM/si5ClkUNgb319grUrBU +6h8SuYtgnD84965xRiVAgtH4wCPN544N8CE=3D +=3DNmqc +-----END PGP PUBLIC KEY BLOCK----- + +--------------FHzf8jBNv06d9SowGc7KOjXr-- + +--------------bhHlRtbq4tEzp2NgVmAJ4AbV-- + +--e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +Content-Description: OpenPGP digital signature +Content-Disposition: attachment; filename=OpenPGP_signature +Content-Type: application/pgp-signature; name=OpenPGP_signature.asc + +-----BEGIN PGP SIGNATURE----- +Comment: https://gopenpgp.org +Version: GopenPGP 2.7.1 + +wsB5BAABCAAjFiEEXOYJeXAvKFvzKPmxFhwIdYIjWfcFAmRH6MwFAwAAAAAACgkQ +FhwIdYIjWfdX5Qf/W2hFY5PiCrRTvcXGASc2RBLXmCh/mn0tTNUsGtyq/MhcNKfR +9bSFCb3xz9q26MAJDHtO/Vm0lUjre42rLMkEIDIdJT960HIClELzmgglwFbVgdqy +T0Psma8ySQpZ2LxZ1oleCXeXaxm4DOwQP+COfb5+FmLTA2z1djLA3HjFPNKglcUr +atzCTvlt2yqwrx6aeqTxcFezPkl1o+kdqjMCMP0LFFuImuor0vaCFUz76hgNC3kk +CflcYGPJIVH7D06UXkLKC5vnJZ+Pidn4K5sMkF3nXBlourmSU2cZFTNUUdHNAxi8 +s9XTavfQxm4fyLPyGcgNpdM6PhZW9r+lZkr66w== +=se49 +-----END PGP SIGNATURE----- +--e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855--