GODT-1553: RPC definition and mocks

WIP: updates

WIP: cache on disk and autostart.

WIP: mail, keychain and more.

WIP: updated grpc version in go mod file.

WIP: user list.

WIP: RPC service placeholder

WIP: test C++ RPC client skeleton.

Other: missing license script update.

WIP: use Qt test framework.

WIP: test for app and login calls.

WIP: test for update & cache on disk calls.

WIP: tests for mail settings calls.

WIP: all client tests.

WIP: linter fixes.

WIP: fix missing license link.

WIP: update dependency_license script for gRPC and protobuf.

WIP: removed unused file.

WIP: app & login event streaming tests.

WIP: update event stream tests.

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

4
.gitignore vendored
View File

@ -31,3 +31,7 @@ vendor-cache
cmd/Desktop-Bridge/deploy
cmd/Import-Export/deploy
proton-bridge
# Jetbrains (CLion, Golang) cmake build dirs
cmake-build-*/
cmake-build-*/

View File

@ -68,7 +68,6 @@ Proton Mail Bridge includes the following 3rd party software:
* [aurora](https://github.com/logrusorgru/aurora) available under [license](https://github.com/logrusorgru/aurora/blob/master/LICENSE)
* [go-runewidth](https://github.com/mattn/go-runewidth) available under [license](https://github.com/mattn/go-runewidth/blob/master/LICENSE)
* [dns](https://github.com/miekg/dns) available under [license](https://github.com/miekg/dns/blob/master/LICENSE)
* [pretty](https://github.com/niemeyer/pretty) available under [license](https://github.com/niemeyer/pretty/blob/master/LICENSE)
* [jsondiff](https://github.com/nsf/jsondiff) available under [license](https://github.com/nsf/jsondiff/blob/master/LICENSE)
* [tablewriter](https://github.com/olekukonko/tablewriter) available under [license](https://github.com/olekukonko/tablewriter/blob/master/LICENSE)
* [errors](https://github.com/pkg/errors) available under [license](https://github.com/pkg/errors/blob/master/LICENSE)
@ -85,6 +84,8 @@ Proton Mail Bridge includes the following 3rd party software:
* [net](https://golang.org/x/net) available under [license](https://cs.opensource.google/go/x/net/+/master:LICENSE)
* [sys](https://golang.org/x/sys) available under [license](https://cs.opensource.google/go/x/sys/+/master:LICENSE)
* [text](https://golang.org/x/text) available under [license](https://cs.opensource.google/go/x/text/+/master:LICENSE)
* [grpc](https://google.golang.org/grpc) available under [license](https://github.com/grpc/grpc-go/blob/master/LICENSE)
* [protobuf](https://google.golang.org/protobuf) available under [license](https://github.com/protocolbuffers/protobuf/blob/main/LICENSE)
* [plist](https://howett.net/plist) available under [license](https://github.com/DHowett/go-plist/blob/main/LICENSE)
* [docker-credential-helpers](https://github.com/ProtonMail/docker-credential-helpers) available under [license](https://github.com/ProtonMail/docker-credential-helpers/blob/master/LICENSE)
* [go-imap](https://github.com/ProtonMail/go-imap) available under [license](https://github.com/ProtonMail/go-imap/blob/master/LICENSE)

9
go.mod
View File

@ -45,8 +45,8 @@ require (
github.com/go-resty/resty/v2 v2.6.0
github.com/godbus/dbus v4.1.0+incompatible
github.com/golang/mock v1.4.4
github.com/google/go-cmp v0.5.5
github.com/google/uuid v1.1.1
github.com/google/go-cmp v0.5.6
github.com/google/uuid v1.1.2
github.com/hashicorp/go-multierror v1.1.0
github.com/jameskeane/bcrypt v0.0.0-20120420032655-c3cd44c1e20f // indirect
github.com/jaytaylor/html2text v0.0.0-20200412013138-3577fbdbcff7
@ -55,7 +55,6 @@ require (
github.com/logrusorgru/aurora v2.0.3+incompatible
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/miekg/dns v1.1.41
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce
github.com/olekukonko/tablewriter v0.0.4 // indirect
github.com/pkg/errors v0.9.1
@ -65,8 +64,6 @@ require (
github.com/ssor/bom v0.0.0-20170718123548-6386211fdfcf // indirect
github.com/stretchr/testify v1.7.0
github.com/therecipe/qt v0.0.0-20200701200531-7f61353ee73e
github.com/therecipe/qt/internal/binding/files/docs/5.12.0 v0.0.0-20200904063919-c0c124a5770d // indirect
github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20200904063919-c0c124a5770d // indirect
github.com/urfave/cli/v2 v2.2.0
github.com/vmihailenco/msgpack/v5 v5.1.3
go.etcd.io/bbolt v1.3.6
@ -74,6 +71,8 @@ require (
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4
golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b
golang.org/x/text v0.3.7
google.golang.org/grpc v1.46.2
google.golang.org/protobuf v1.28.0
howett.net/plist v1.0.0
)

94
go.sum
View File

@ -72,6 +72,7 @@ github.com/allan-simon/go-singleinstance v0.0.0-20160830203053-79edcfdc2dfc h1:m
github.com/allan-simon/go-singleinstance v0.0.0-20160830203053-79edcfdc2dfc/go.mod h1:qqsTQiwdyqxU05iDCsi0oN3P4nrVxAmn8xCtODDSf/U=
github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/antlr/antlr4 v0.0.0-20201029161626-9a95f0cc3d7c h1:j/C2kxPfyE0d87/ggAjIsCV5Cdkqmjb+O0W8W+1J+IY=
github.com/antlr/antlr4 v0.0.0-20201029161626-9a95f0cc3d7c/go.mod h1:T7PbCXFs94rrTttyxjbyT5+/1V8T2TYDejxUfHJjw1Y=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
@ -83,12 +84,20 @@ github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
@ -150,6 +159,12 @@ github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594 h1:IbFBtwo
github.com/emersion/go-textwrapper v0.0.0-20200911093747-65d896831594/go.mod h1:aqO8z8wPrjkscevZJFVE1wXJrLpC5LtJG7fqLOsPb2U=
github.com/emersion/go-vcard v0.0.0-20190105225839-8856043f13c5 h1:n9qx98xiS5V4x2WIpPC2rr9mUM5ri9r/YhCEKbhCHro=
github.com/emersion/go-vcard v0.0.0-20190105225839-8856043f13c5/go.mod h1:WIi9g8OKJQHXtQbx7GExlo6UAFaui9WDMYabJ+Be4WI=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/etcd-io/bbolt v1.3.3/go.mod h1:ZF2nL25h33cCyBtcyWeZ2/I3HQOfTP+0PIEvHjkjCrw=
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
@ -196,22 +211,38 @@ github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/gomodule/redigo v1.7.1-0.20190724094224-574c33c3df38/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@ -222,6 +253,7 @@ github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
@ -281,11 +313,6 @@ github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYb
github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE=
github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro=
github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8=
github.com/keybase/go-keychain v0.0.0-20200502122510-cda31fe0c86d h1:gVjhBCfVGl32RIBooOANzfw+0UqX8HU+yPlMv8vypcg=
github.com/keybase/go-keychain v0.0.0-20200502122510-cda31fe0c86d/go.mod h1:W6EbaYmb4RldPn0N3gvVHjY1wmU59kbymhW9NATWhwY=
github.com/keybase/go-keychain v0.0.0-20211119201326-e02f34051621 h1:aMQ7pA4f06yOVXSulygyGvy4xA94fyzjUGs0iqQdMOI=
github.com/keybase/go-keychain v0.0.0-20211119201326-e02f34051621/go.mod h1:enrU/ug069Om7vWxuFE6nikLI2BZNwevMiGSo43Kt5w=
github.com/keybase/go.dbus v0.0.0-20200324223359-a94be52c0b03/go.mod h1:a8clEhrrGV/d76/f9r2I41BwANMihfZYV9C223vaxqE=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
@ -349,7 +376,6 @@ github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5Vgl
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce h1:RPclfga2SEJmgMmz2k+Mg7cowZ8yv4Trqw9UsJby758=
github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce/go.mod h1:uFMI8w+ref4v2r9jz+c9i1IfIttS/OkmLfrk1jne5hs=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
@ -373,6 +399,7 @@ github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXP
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
@ -384,6 +411,7 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
github.com/ricochet2200/go-disk-usage/du v0.0.0-20210707232629-ac9918953285 h1:d54EL9l+XteliUfUCGsEwwuk65dmmxX85VXF+9T6+50=
github.com/ricochet2200/go-disk-usage/du v0.0.0-20210707232629-ac9918953285/go.mod h1:fxIDly1xtudczrZeOOlfaUvd2OPb2qZAPuWdU2BsBTk=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
@ -433,10 +461,6 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
github.com/therecipe/qt v0.0.0-20200701200531-7f61353ee73e h1:G0DQ/TRQyrEZjtLlLwevFjaRiG8eeCMlq9WXQ2OO2bk=
github.com/therecipe/qt v0.0.0-20200701200531-7f61353ee73e/go.mod h1:SUUR2j3aE1z6/g76SdD6NwACEpvCxb3fvG82eKbD6us=
github.com/therecipe/qt/internal/binding/files/docs/5.12.0 v0.0.0-20200904063919-c0c124a5770d h1:hAZyEG2swPRWjF0kqqdGERXUazYnRJdAk4a58f14z7Y=
github.com/therecipe/qt/internal/binding/files/docs/5.12.0 v0.0.0-20200904063919-c0c124a5770d/go.mod h1:7m8PDYDEtEVqfjoUQc2UrFqhG0CDmoVJjRlQxexndFc=
github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20200904063919-c0c124a5770d h1:AJRoBel/g9cDS+yE8BcN3E+TDD/xNAguG21aoR8DAIE=
github.com/therecipe/qt/internal/binding/files/docs/5.13.0 v0.0.0-20200904063919-c0c124a5770d/go.mod h1:mH55Ek7AZcdns5KPp99O0bg+78el64YCYWHiQKrOdt4=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
@ -468,6 +492,7 @@ go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
@ -482,8 +507,8 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 h1:7I4JAnoQBe7ZtJcBaYHi5UtiO8tQHbUSXxL+pnGRANg=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA=
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
@ -532,9 +557,10 @@ golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20211008194852-3b03d305991f h1:1scJEYZBaF48BaG6tYbtxmLcXqwYGSfGcMoStTqkkIw=
golang.org/x/net v0.0.0-20211008194852-3b03d305991f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4 h1:HVyaeDAYux4pnY+D/SiwmLOR36ewZ4iGQIIrtnuCjFA=
@ -542,6 +568,7 @@ golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su
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=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -576,8 +603,11 @@ golang.org/x/sys v0.0.0-20191025021431-6c3a3bfe00ae/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -587,14 +617,12 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320 h1:0jf+tOCoZ3LyutmCOWpVni1chK4VfFLhRsDK7MhqGRY=
golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b h1:2n253B2r0pYSmEV+UNCQoPfU/FiaizQEK5Gu4Bq4JE8=
golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b/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 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
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=
@ -620,6 +648,7 @@ golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3
golang.org/x/tools v0.0.0-20190420181800-aa740d480789/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
@ -628,12 +657,12 @@ golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191112195655-aa38f8e97acc/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69 h1:yBHHx+XZqXJBm6Exke3N7V9gnlsyXxoCPEb1yVenjfk=
golang.org/x/tools v0.0.0-20200117012304-6edc0a871e69/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
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 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
@ -652,13 +681,36 @@ google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
google.golang.org/grpc v1.46.2 h1:u+MLGgVf7vRdjEYZ8wDFhAVNmhkbJ5hmrA1LMWK1CAQ=
google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
@ -674,6 +726,7 @@ gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
@ -683,6 +736,7 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0=
howett.net/plist v1.0.0 h1:7CrbWYbPPO/PyNy38b2EB/+gYbjCe2DXBxgtOOZbSQM=

View File

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

File diff suppressed because it is too large Load Diff

View File

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

File diff suppressed because it is too large Load Diff

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

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

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

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

View File

@ -0,0 +1,25 @@
// Copyright (c) 2022 Proton AG
//
// This file is part of Proton Mail Bridge.Bridge.
//
// Proton Mail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Proton Mail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#include "RpcClient.h"
#include <QtCore>
#include <QtTest>
QTEST_MAIN(RpcClient) // This macro will generate the main() function

View File

@ -0,0 +1,66 @@
cmake_minimum_required(VERSION 3.22)
project(BridgeRpcClientTest VERSION 0.1 LANGUAGES CXX)
if (NOT DEFINED ENV{QTDIR})
message(FATAL_ERROR "QTDIR needs to be defined and point to the root of your Qt folder. (e.g. /Users/MyName/Qt/6.3/clang_64).")
endif()
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOMATIC ON)
find_package(Protobuf CONFIG REQUIRED)
message(STATUS "Using protobuf ${Protobuf_VERSION}")
find_package(gRPC CONFIG REQUIRED)
message(STATUS "Using gRPC ${gRPC_VERSION}")
find_package(Qt6 COMPONENTS Core Test REQUIRED)
find_program(PROTOC_EXE protoc)
find_program(GRPC_CPP_PLUGIN grpc_cpp_plugin)
set(PROTO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../internal/rpc")
set(PROTO_FILE "${PROTO_DIR}/bridge_rpc.proto")
set(GRPC_OUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/rpc")
set(PROTO_CPP_FILE "${GRPC_OUT_DIR}/bridge_rpc.pb.cc")
set(PROTO_H_FILE "${GRPC_OUT_DIR}/bridge_rpc.pb.h")
set(GRPC_CPP_FILE "${GRPC_OUT_DIR}/bridge_rpc.grpc.pb.cc")
set(GRPC_H_FILE "${GRPC_OUT_DIR}/bridge_rpc.grpc.pb.h")
add_custom_command(
OUTPUT
${PROTO_CPP_FILE}
${PROTO_H_FILE}
${GRPC_CPP_FILE}
${GRPC_H_FILE}
COMMAND
${PROTOC_EXE}
ARGS
--proto_path=${PROTO_DIR}
--plugin=protoc-gen-grpc="${GRPC_CPP_PLUGIN}"
--cpp_out=${GRPC_OUT_DIR}
--grpc_out=${GRPC_OUT_DIR}
${PROTO_FILE}
DEPENDS
${PROTO_FILE}
COMMENT "Generating gPRC/Protobuf C++ code"
)
add_executable(BridgeRpcClientTest
BridgeRpcClientTest.cpp
RpcClient.cpp RpcClient.h
Exception.cpp Exception.h
${PROTO_CPP_FILE}
${PROTO_H_FILE}
${GRPC_CPP_FILE}
${GRPC_H_FILE}
)
target_link_libraries(BridgeRpcClientTest
Qt::Core Qt::Test
protobuf::libprotobuf
gRPC::grpc++ gRPC::grpc++_reflection
)

View File

@ -0,0 +1,67 @@
// Copyright (c) 2022 Proton AG
//
// This file is part of Proton Mail Bridge.Bridge.
//
// Proton Mail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Proton Mail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#include "Exception.h"
//**********************************************************************************************************************
/// \param[in] what A description of the exception
//**********************************************************************************************************************
Exception::Exception(QString what) noexcept
: std::exception()
, what_(std::move(what))
{
}
//**********************************************************************************************************************
/// \param[in] ref The Exception to copy from
//**********************************************************************************************************************
Exception::Exception(Exception const& ref) noexcept
: std::exception(ref)
, what_(ref.what_)
{
}
//**********************************************************************************************************************
/// \param[in] ref The Exception to copy from
//**********************************************************************************************************************
Exception::Exception(Exception&& ref) noexcept
: std::exception(ref)
, what_(ref.what_)
{
}
//**********************************************************************************************************************
/// \return a string describing the exception
//**********************************************************************************************************************
QString const& Exception::qwhat() const noexcept
{
return what_;
}
//**********************************************************************************************************************
/// \return A pointer to the description string of the exception.
//**********************************************************************************************************************
const char* Exception::what() const noexcept
{
return what_.toLocal8Bit().constData();
}

View File

@ -0,0 +1,44 @@
// Copyright (c) 2022 Proton AG
//
// This file is part of Proton Mail Bridge.Bridge.
//
// Proton Mail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Proton Mail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#ifndef BRIDGE_RPC_CLIENT_TEST_EXCEPTION_H
#define BRIDGE_RPC_CLIENT_TEST_EXCEPTION_H
#include <QtCore>
#include <stdexcept>
//**********************************************************************************************************************
/// \brief Exception class
//**********************************************************************************************************************
class Exception: public std::exception
{
public: // member functions
explicit Exception(QString what = QString()) noexcept; ///< Constructor
Exception(Exception const& ref) noexcept; ///< copy constructor
Exception(Exception&& ref) noexcept; ///< copy constructor
Exception& operator=(Exception const&) = delete; ///< Disabled assignment operator
Exception& operator=(Exception&&) = delete; ///< Disabled assignment operator
~Exception() noexcept = default; ///< Destructor
QString const& 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
private: // data members
QString const what_; ///< The description of the exception
};
#endif //BRIDGE_RPC_CLIENT_TEST_EXCEPTION_H

View File

@ -0,0 +1,925 @@
// Copyright (c) 2022 Proton AG
//
// This file is part of Proton Mail Bridge.Bridge.
//
// Proton Mail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Proton Mail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#pragma clang diagnostic push
#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
#include "RpcClient.h"
#include <QtTest>
using namespace google::protobuf;
using namespace bridgerpc;
using namespace grpc;
namespace
{
// \todo Decide where to store this certificate.
std::string cert = R"(-----BEGIN CERTIFICATE-----
MIIC5TCCAc2gAwIBAgIJAJL2PajH8kFjMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
BAMMCWxvY2FsaG9zdDAeFw0yMjA1MTAwNjEzMzdaFw0yMjA2MDkwNjEzMzdaMBQx
EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
ggEBAKyb48XL+08YI8m4X/eeD9TQshV+vybKbU7MOG7BnH3Hv7kUH0aVP7OPnU51
eYRgUu+bkJ8qWhxD7wOLVJBcU5T1lgd+k6St83ix25P02nUc3UeU4MCxMwhjMjYu
R5F9bfSG0UlCCGAEjjmGh+CfnZkS+rgCwE/xGswFnVrynTMvrLQyN02dz/r4zJPp
yyVhTOmjdsUDs0zGDbubLf+ypR8VCXg55qYMw7Abpe+rx3BF+NCEjKlATjMeIZNx
iS0dl0OGjJZ+bfHGhnPiQxP8HxyJ0NjFNtWgblQev2sHmIq65Rry3RP1gbDAW3sk
MiIfjbnp4gGspYrmHWeWXH8g6WMCAwEAAaM6MDgwFAYDVR0RBA0wC4IJbG9jYWxo
b3N0MAsGA1UdDwQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG9w0B
AQsFAAOCAQEAO2WDYnzy9SkaS9VU2jw3nd9MEaILZsXFcVU2+52TKwRBty7b0A1x
zyxT6nT0pN0Im7DcT5/TvwFuVBJUTFs4c2gW09WUvtfuN8HVFOeX/1Pt10lMPJjR
I+wTAUQrXJHt57JE9x13gQEOW/mGUDNuoUH2cE9C1f+TrO0LaRj8dubS/gHMuV1i
aTyxu7hgbLAYq0NGD86CSOwvUvTvs6o628xvfmqqdzlpWIlQq18t2GZYFVWjrISY
LWw3OCormKSASOPrW1FXhrgwoyDXHNmZT1MHL3Rh9U5qyCwV5kDAcY956sc9lD3G
XHtSxOHLE1eDKGCUKRcYop/99inTGjJ6Xg==
-----END CERTIFICATE-----)";
Empty empty; // A protobuf empty message reused for the sake of simplicity
}
//**********************************************************************************************************************
/// \brief Help class that manage a client context. Provided context cannot be re-used, the underlying context is freed
/// and re-allocated at every call to get() (or at destruction).
//**********************************************************************************************************************
class Ctx
{
public: // member functions
Ctx()
{} ///< Default constructor.
Ctx(Ctx const &) = delete; ///< Disabled copy-constructor.
Ctx(Ctx &&) = delete; ///< Disabled assignment copy-constructor.
~Ctx() = default; ///< Destructor.
Ctx &operator=(Ctx const &) = delete; ///< Disabled assignment operator.
Ctx &operator=(Ctx &&) = delete; ///< Disabled move assignment operator.
ClientContext *get()
{
ctx_ = std::make_unique<ClientContext>();
return ctx_.get();
} ///< Release the previous context, if any and allocate a new one
private: // data members
std::unique_ptr<ClientContext> ctx_{nullptr};
};
//**********************************************************************************************************************
//
//**********************************************************************************************************************
RpcClient::RpcClient()
: QObject(nullptr)
{
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::initTestCase()
{
SslCredentialsOptions opts;
opts.pem_root_certs += cert;
channel_ = CreateChannel("localhost:9292", grpc::SslCredentials(opts));
QVERIFY2(channel_, "Channel creation failed.");
stub_ = bridgerpc::BridgeRpc::NewStub(channel_);
QVERIFY2(stub_, "Stub creation failed.");
QVERIFY2(channel_->WaitForConnected(gpr_time_add(gpr_now(GPR_CLOCK_REALTIME),
gpr_time_from_seconds(10, GPR_TIMESPAN))), "Connection to the RPC server failed.");
QVERIFY2(channel_ && stub_ && (channel_->GetState(true) == GRPC_CHANNEL_READY), "connection check failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testGetCursorPos()
{
Ctx ctx;
PointResponse resp;
Status s = stub_->GetCursorPos(ctx.get(), empty, &resp);
QVERIFY2(s.ok(), "GetCursorPos failed.");
QVERIFY2(resp.x() == 100, "Invalid x value");
QVERIFY2(resp.y() == 200, "Invalid y value");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testGuiReady()
{
Ctx ctx;
QVERIFY2(stub_->GuiReady(ctx.get(), empty, &empty).ok(), "GuiReady failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testQuit()
{
Ctx ctx;
QVERIFY2(stub_->Quit(ctx.get(), empty, &empty).ok(), "Quit failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testRestart()
{
Ctx ctx;
QVERIFY2(stub_->Restart(ctx.get(), empty, &empty).ok(), "Restart failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testShowOnStartup()
{
Ctx ctx;
BoolValue showOnStartup;
QVERIFY2(stub_->ShowOnStartup(ctx.get(), empty, &showOnStartup).ok(), "ShowOnStartup failed.");
bool const newValue = !showOnStartup.value();
showOnStartup.set_value(newValue);
QVERIFY2(stub_->SetShowOnStartup(ctx.get(), showOnStartup, &empty).ok(), "SetShowOnStartup failed.");
QVERIFY2(stub_->ShowOnStartup(ctx.get(), empty, &showOnStartup).ok(), "ShowOnStartup failed.");
QVERIFY2(showOnStartup.value() == newValue, "ShowOnStartup failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testShowSplashScreen()
{
Ctx ctx;
BoolValue showSplashScreen;
QVERIFY2(stub_->ShowSplashScreen(ctx.get(), empty, &showSplashScreen).ok(), "ShowSplashScreen failed.");
bool const newValue = !showSplashScreen.value();
showSplashScreen.set_value(newValue);
QVERIFY2(stub_->SetShowSplashScreen(ctx.get(), showSplashScreen, &empty).ok(), "SetShowSplashScreen failed.");
QVERIFY2(stub_->ShowOnStartup(ctx.get(), empty, &showSplashScreen).ok(), "ShowSplashScreen failed.");
QVERIFY2(showSplashScreen.value() == newValue, "ShowSplashScreen failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testDockIconVisible()
{
Ctx ctx;
BoolValue dockIconVisible;
QVERIFY2(stub_->DockIconVisible(ctx.get(), empty, &dockIconVisible).ok(), "DockIconVisible failed.");
bool const newValue = !dockIconVisible.value();
dockIconVisible.set_value(newValue);
QVERIFY2(stub_->SetDockIconVisible(ctx.get(), dockIconVisible, &empty).ok(), "SetShowSplashScreen failed.");
QVERIFY2(stub_->DockIconVisible(ctx.get(), empty, &dockIconVisible).ok(), "DockIconVisible failed.");
QVERIFY2(dockIconVisible.value() == newValue, "DockIconVisible failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testIsFirstGuiStart()
{
Ctx ctx;
BoolValue isFirst;
QVERIFY2(stub_->IsFirstGuiStart(ctx.get(), empty, &isFirst).ok(), "IsFirstGuiStart failed.");
bool const newValue = !isFirst.value();
isFirst.set_value(newValue);
QVERIFY2(stub_->SetIsFirstGuiStart(ctx.get(), isFirst, &empty).ok(), "SetIsFirstGuiStart failed.");
QVERIFY2(stub_->IsFirstGuiStart(ctx.get(), empty, &isFirst).ok(), "IsFirstGuiStart failed.");
QVERIFY2(isFirst.value() == newValue, "IsFirstGuiStart failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testIsAutostartOn()
{
Ctx ctx;
BoolValue isOn;
QVERIFY2(stub_->IsAutostartOn(ctx.get(), empty, &isOn).ok(), "IsAutostartOn failed.");
bool const newValue = !isOn.value();
isOn.set_value(newValue);
QVERIFY2(stub_->SetIsAutostartOn(ctx.get(), isOn, &empty).ok(), "SetIsAutostartOn failed.");
QVERIFY2(stub_->IsAutostartOn(ctx.get(), empty, &isOn).ok(), "IsAutostartOn failed.");
QVERIFY2(isOn.value() == newValue, "IsAutostartOn failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testIsBetaEnabled()
{
Ctx ctx;
BoolValue isOn;
QVERIFY2(stub_->IsBetaEnabled(ctx.get(), empty, &isOn).ok(), "IsBetaEnabled failed.");
bool const newValue = !isOn.value();
isOn.set_value(newValue);
QVERIFY2(stub_->SetIsBetaEnabled(ctx.get(), isOn, &empty).ok(), "SetIsBetaEnabled failed.");
QVERIFY2(stub_->IsBetaEnabled(ctx.get(), empty, &isOn).ok(), "IsBetaEnabled failed.");
QVERIFY2(isOn.value() == newValue, "IsBetaEnabled failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testGoOs()
{
Ctx ctx;
StringValue goos;
QVERIFY2(stub_->GoOs(ctx.get(), empty, &goos).ok(), "GoOs failed.");
QVERIFY2(goos.value().length() > 0, "Invalid GoOs value.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testTriggerReset()
{
Ctx ctx;
QVERIFY2(stub_->TriggerReset(ctx.get(), empty, &empty).ok(), "TriggerReset failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testVersion()
{
Ctx ctx;
StringValue version;
QVERIFY2(stub_->Version(ctx.get(), empty, &version).ok(), "Version failed.");
QVERIFY2(version.value().length() > 0, "Invalid version number.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testLogPath()
{
Ctx ctx;
StringValue logPath;
QVERIFY2(stub_->LogPath(ctx.get(), empty, &logPath).ok(), "LogPath failed.");
QVERIFY2(logPath.value().length() > 0, "Invalid LogPath.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testLicensePath()
{
Ctx ctx;
StringValue licensePath;
QVERIFY2(stub_->LicensePath(ctx.get(), empty, &licensePath).ok(), "LicensePath failed.");
QVERIFY2(licensePath.value().length() > 0, "Invalid LicensePath.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testReleaseNotesLink()
{
Ctx ctx;
StringValue link;
QVERIFY2(stub_->ReleaseNotesLink(ctx.get(), empty, &link).ok(), "ReleaseNotesLink failed.");
QVERIFY2(link.value().length() > 0, "Invalid ReleaseNotesLink.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testLandingPageLink()
{
Ctx ctx;
StringValue link;
QVERIFY2(stub_->LandingPageLink(ctx.get(), empty, &link).ok(), "LandingPageLink failed.");
QVERIFY2(link.value().length() > 0, "Invalid LandingPageLink.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testColorScheme()
{
Ctx ctx;
StringValue name;
string const schemeName = "dummyColors";
name.set_value(schemeName);
QVERIFY2(stub_->SetColorSchemeName(ctx.get(), name, &empty).ok(), "SetColorSchemeName failed.");
QVERIFY2(stub_->ColorSchemeName(ctx.get(), empty, &name).ok(), "ColorSchemeName failed.");
QVERIFY2(name.value() == schemeName, "ColorSchemeName failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testCurrentEmailClient()
{
Ctx ctx;
StringValue name;
string const clientName = "dummyClient";
name.set_value(clientName);
QVERIFY2(stub_->SetCurrentEmailClient(ctx.get(), name, &empty).ok(), "SeturrentEmailClient failed.");
QVERIFY2(stub_->CurrentEmailClient(ctx.get(), empty, &name).ok(), "CurrentEmailClient failed.");
QVERIFY2(name.value() == clientName, "CurrentEmailClient failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testReportBug()
{
Ctx ctx;
ReportBugRequest report;
report.set_description("dummy description");
report.set_address("dummy@proton.me");
report.set_emailclient("dummyClient");
report.set_includelogs(true);
QVERIFY2(stub_->ReportBug(ctx.get(), report, &empty).ok(), "ReportBug failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testLogin()
{
Ctx ctx;
LoginRequest login;
login.set_username("dummyuser");
login.set_password("dummypassword");
QVERIFY2(stub_->Login(ctx.get(), login, &empty).ok(), "Login failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testLogin2FA()
{
Ctx ctx;
LoginRequest login;
login.set_username("dummyuser");
login.set_password("dummypassword");
QVERIFY2(stub_->Login2FA(ctx.get(), login, &empty).ok(), "Login2FA failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testLogin2Passwords()
{
Ctx ctx;
LoginRequest login;
login.set_username("dummyuser");
login.set_password("dummypassword");
QVERIFY2(stub_->Login2Passwords(ctx.get(), login, &empty).ok(), "Login2Passwords failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testLoginAbort()
{
Ctx ctx;
LoginAbortRequest loginAbort;
loginAbort.set_username("dummyuser");
QVERIFY2(stub_->LoginAbort(ctx.get(), loginAbort, &empty).ok(), "loginAbort failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testCheckUpdate()
{
Ctx ctx;
QVERIFY2(stub_->CheckUpdate(ctx.get(), empty, &empty).ok(), "CheckUpdate failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testInstallUpdate()
{
Ctx ctx;
QVERIFY2(stub_->InstallUpdate(ctx.get(), empty, &empty).ok(), "InstallUpdate failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testIsAutomaticUpdateOn()
{
Ctx ctx;
BoolValue isOn;
QVERIFY2(stub_->IsAutomaticUpdateOn(ctx.get(), empty, &isOn).ok(), "IsAutomaticUpdateOn failed.");
bool newValue = !isOn.value();
isOn.set_value(newValue);
QVERIFY2(stub_->SetIsAutomaticUpdateOn(ctx.get(), isOn, &empty).ok(), "SetIsAutomaticUpdateOn failed.");
QVERIFY2(stub_->IsAutomaticUpdateOn(ctx.get(), empty, &isOn).ok(), "IsAutomaticUpdateOn failed.");
QVERIFY2(isOn.value() == newValue, "IsAutomaticUpdateOn failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testIsCacheOnDiskEnabled()
{
Ctx ctx;
BoolValue isEnabled;
QVERIFY2(stub_->IsCacheOnDiskEnabled(ctx.get(), empty, &isEnabled).ok(), "IsCacheOnDiskEnabled failed.");
bool const newValue = !isEnabled.value();
isEnabled.set_value(newValue);
QVERIFY2(stub_->SetIsCacheOnDiskEnabled(ctx.get(), isEnabled, &empty).ok(), "SetIsCacheOnDiskEnabled failed.");
QVERIFY2(stub_->IsCacheOnDiskEnabled(ctx.get(), empty, &isEnabled).ok(), "IsCacheOnDiskEnabled failed.");
QVERIFY2(isEnabled.value() == newValue, "IsCacheOnDiskEnabled failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testDiskCachePath()
{
Ctx ctx;
string const dummyPath = "/dummy/path";
StringValue path;
path.set_value(dummyPath);
QVERIFY2(stub_->SetDiskCachePath(ctx.get(), path, &empty).ok(), "SetDiskCachePath failed.");
QVERIFY2(stub_->DiskCachePath(ctx.get(), empty, &path).ok(), "DiskCachePath failed.");
QVERIFY2(path.value() == dummyPath, "DiskCachePath failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testChangeLocalCache()
{
Ctx ctx;
BoolValue isEnabled;
QVERIFY2(stub_->IsCacheOnDiskEnabled(ctx.get(), empty, &isEnabled).ok(), "IsCacheOnDiskEnabled failed.");
bool const newEnabled = !isEnabled.value();
string const dummyPath = "/another/dummy/path";
ChangeLocalCacheRequest request;
request.set_enablediskcache(newEnabled);
request.set_diskcachepath(dummyPath);
QVERIFY2(stub_->ChangeLocalCache(ctx.get(), request, &empty).ok(), "ChangeLocalCache failed.");
QVERIFY2(stub_->IsCacheOnDiskEnabled(ctx.get(), empty, &isEnabled).ok(), "IsCacheOnDiskEnabled failed.");
QVERIFY2(isEnabled.value() == newEnabled, "IsCacheOnDiskEnabled readback failed.");
StringValue path;
QVERIFY2(stub_->DiskCachePath(ctx.get(), empty, &path).ok(), "DiskCachePath failed.");
QVERIFY2(path.value() == dummyPath, "DiskCachePath failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testIsDohEnabled()
{
Ctx ctx;
BoolValue isEnabled;
QVERIFY2(stub_->IsDoHEnabled(ctx.get(), empty, &isEnabled).ok(), "IsDoHEnabled failed.");
bool const newValue = !isEnabled.value();
isEnabled.set_value(newValue);
QVERIFY2(stub_->SetIsDoHEnabled(ctx.get(), isEnabled, &empty).ok(), "SetIsDoHEnabled failed.");
QVERIFY2(stub_->IsDoHEnabled(ctx.get(), empty, &isEnabled).ok(), "IsDoHEnabled failed.");
QVERIFY2(isEnabled.value() == newValue, "IsDoHEnabled failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testUseSslForSmtp()
{
Ctx ctx;
BoolValue useSsl;
QVERIFY2(stub_->UseSslForSmtp(ctx.get(), empty, &useSsl).ok(), "UseSslForSmtp failed.");
bool const newValue = !useSsl.value();
useSsl.set_value(newValue);
QVERIFY2(stub_->SetUseSslForSmtp(ctx.get(), useSsl, &empty).ok(), "SetUseSslForSmtp failed.");
QVERIFY2(stub_->UseSslForSmtp(ctx.get(), empty, &useSsl).ok(), "UseSslForSmtp failed.");
QVERIFY2(useSsl.value() == newValue, "UseSslForSmtp failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testHostname()
{
Ctx ctx;
StringValue hostname;
QVERIFY2(stub_->Hostname(ctx.get(), empty, &hostname).ok(), "Hostname failed.");
QVERIFY2(hostname.value().length() > 0, "Hostname failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testImapPort()
{
Ctx ctx;
Int32Value port;
QVERIFY2(stub_->ImapPort(ctx.get(), empty, &port).ok(), "ImapPort failed.");
qint16 const newValue = qint16(port.value()) + 1;
port.set_value(qint32(newValue));
QVERIFY2(stub_->SetImapPort(ctx.get(), port, &empty).ok(), "SetImapPort failed.");
QVERIFY2(stub_->ImapPort(ctx.get(), empty, &port).ok(), "ImapPort failed.");
QVERIFY2(qint16(port.value()) == newValue, "ImapPort failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testSmtpPort()
{
Ctx ctx;
Int32Value port;
QVERIFY2(stub_->SmtpPort(ctx.get(), empty, &port).ok(), "SmtpPort failed.");
qint16 const newValue = qint16(port.value()) + 1;
port.set_value(qint32(newValue));
QVERIFY2(stub_->SetSmtpPort(ctx.get(), port, &empty).ok(), "SetSmtpPort failed.");
QVERIFY2(stub_->SmtpPort(ctx.get(), empty, &port).ok(), "SmtpPort failed.");
QVERIFY2(qint16(port.value()) == newValue, "SmtpPort failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testChangePorts()
{
Ctx ctx;
ChangePortsRequest request;
const qint32 imapPort = 2143, smtpPort = 2025;
request.set_imapport(imapPort);
request.set_smtpport(smtpPort);
QVERIFY2(stub_->ChangePorts(ctx.get(), request, &empty).ok(), "");
Int32Value port;
QVERIFY2(stub_->ImapPort(ctx.get(), empty, &port).ok(), "ImapPort failed.");
QVERIFY2(port.value() == imapPort, "ImapPort failed readback.");
QVERIFY2(stub_->SmtpPort(ctx.get(), empty, &port).ok(), "SmtpPort failed.");
QVERIFY2(port.value() == smtpPort, "SmtpPort failed readback.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testIsPortFree()
{
Ctx ctx;
Int32Value port;
port.set_value(143);
BoolValue isFree;
QVERIFY2(stub_->IsPortFree(ctx.get(), port, &isFree).ok(), "IsPortFree failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testKeychain()
{
Ctx ctx;
AvailableKeychainsResponse resp;
QVERIFY2(stub_->AvailableKeychains(ctx.get(), empty, &resp).ok(), "AvailableKeychains failed.");
QVERIFY2(resp.keychains().size() > 0, "AvailableKeychains returned an invalid result.");
string const newKeychain = resp.keychains().at(resp.keychains_size() - 1);
StringValue keychain;
keychain.set_value(newKeychain);
QVERIFY2(stub_->SetCurrentKeychain(ctx.get(), keychain, &empty).ok(), "SetCurrentKeychain failed.");
QVERIFY2(stub_->CurrentKeychain(ctx.get(), empty, &keychain).ok(), "CurrentKeychain failed.");
QVERIFY2(newKeychain == keychain.value(), "CurrentKeychain readback failed.");
}
//**********************************************************************************************************************
//
//**********************************************************************************************************************
void RpcClient::testUser()
{
Ctx ctx;
UserListResponse users;
QVERIFY2(stub_->GetUserList(ctx.get(), empty, &users).ok(), "GetUserList failed.");
QVERIFY2(users.users_size() > 0, "GetUserList returned an invalid value.");
std::string const userID = users.users(0).id();
UserSplitModeRequest splitModeRequest;
splitModeRequest.set_userid(userID);
splitModeRequest.set_active(true);
QVERIFY2(stub_->SetUserSplitMode(ctx.get(), splitModeRequest, &empty).ok(), "SetUserSplitMode failed");
ConfigureAppleMailRequest appleMailRequest;
appleMailRequest.set_userid(userID);
appleMailRequest.set_address("dummy@proton.ch");
QVERIFY2(stub_->ConfigureUserAppleMail(ctx.get(), appleMailRequest, &empty).ok(), "ConfigureUserAppleMail failed.");
StringValue stringValue;
stringValue.set_value(userID);
QVERIFY2(stub_->LogoutUser(ctx.get(), stringValue, &empty).ok(), "LogoutUser failed.");
QVERIFY2(stub_->RemoveUser(ctx.get(), stringValue, &empty).ok(), "RemoveUser failed.");
}
void checkAppEvents(ClientReader<StreamEvent>& reader)
{
QList<AppEvent::EventCase> expected = {
AppEvent::kInternetStatus,
AppEvent::kAutostartFinished,
AppEvent::kResetFinished,
AppEvent::kReportBugFinished,
AppEvent::kReportBugSuccess,
AppEvent::kReportBugError,
AppEvent::kShowMainWindow,
};
StreamEvent event;
while (reader.Read(&event)) {
QVERIFY2(event.event_case() == StreamEvent::kApp, "Received invalid event while waiting for app event.");
AppEvent const& appEvent = event.app();
AppEvent::EventCase const eventCase = appEvent.event_case();
QVERIFY2(expected.size() > 0, "Empty expected app event list.");
QVERIFY2(eventCase == expected.front(), "Unexpected app event received.");
expected.pop_front();
if (expected.isEmpty())
return;
}
QFAIL("Stream ended while waiting for app events.");
}
void checkLoginEvents(ClientReader<StreamEvent>& reader)
{
QList<LoginEvent::EventCase> expected = {
LoginEvent::kError,
LoginEvent::kTfaRequested,
LoginEvent::kTwoPasswordRequested,
LoginEvent::kFinished,
};
StreamEvent event;
while (reader.Read(&event))
{
QVERIFY2(event.event_case() == StreamEvent::kLogin, "Received invalid event while waiting for login event.");
LoginEvent const& loginEvent = event.login();
LoginEvent::EventCase const eventCase = loginEvent.event_case();
QVERIFY2(expected.size() > 0, "Empty expected login event list.");
QVERIFY2(eventCase == expected.front(), "Unexpected login event received.");
expected.pop_front();
if (expected.isEmpty())
return;
}
QFAIL("Stream ended while waiting for login events.");
}
void checkUpdateEvents(ClientReader<StreamEvent>& reader)
{
QList<UpdateEvent::EventCase> expected = {
UpdateEvent::kError,
UpdateEvent::kManualReady,
UpdateEvent::kManualRestartNeeded,
UpdateEvent::kForce,
UpdateEvent::kSilentRestartNeeded,
UpdateEvent::kIsLatestVersion,
UpdateEvent::kCheckFinished
};
StreamEvent event;
while (reader.Read(&event))
{
QVERIFY2(event.event_case() == StreamEvent::kUpdate, "Received invalid event while waiting for update event.");
UpdateEvent const& updateEvent = event.update();
UpdateEvent::EventCase const eventCase = updateEvent.event_case();
QVERIFY2(expected.size() > 0, "Empty expected update event list.");
QVERIFY2(eventCase == expected.front(), "Unexpected update event received.");
expected.pop_front();
if (expected.isEmpty())
return;
}
QFAIL("Stream ended while waiting for update events.");
}
void checkCacheEvents(ClientReader<StreamEvent>& reader)
{
QList<CacheEvent::EventCase> expected = {
CacheEvent::kError,
CacheEvent::kLocationChangedSuccess,
CacheEvent::kChangeLocalCacheFinished,
};
StreamEvent event;
while (reader.Read(&event))
{
QVERIFY2(event.event_case() == StreamEvent::kCache, "Received invalid event while waiting for cache event.");
CacheEvent const& cacheEvent = event.cache();
CacheEvent::EventCase const eventCase = cacheEvent.event_case();
QVERIFY2(expected.size() > 0, "Empty expected cache event list.");
QVERIFY2(eventCase == expected.front(), "Unexpected cache event received.");
expected.pop_front();
if (expected.isEmpty())
return;
}
QFAIL("Stream ended while waiting for cache events.");
}
void checkMailsSettingsEvents(ClientReader<StreamEvent>& reader)
{
QList<MailSettingsEvent::EventCase> expected = {
MailSettingsEvent::kError,
MailSettingsEvent::kUseSslForSmtpFinished,
MailSettingsEvent::kChangePortsFinished,
};
StreamEvent event;
while (reader.Read(&event))
{
QVERIFY2(event.event_case() == StreamEvent::kMailSettings, "Received invalid event while waiting for mail settings event.");
MailSettingsEvent const& mailSettingsEvent = event.mailsettings();
MailSettingsEvent::EventCase const eventCase = mailSettingsEvent.event_case();
QVERIFY2(expected.size() > 0, "Empty expected mail settings event list.");
QVERIFY2(eventCase == expected.front(), "Unexpected mail settings event received.");
expected.pop_front();
if (expected.isEmpty())
return;
}
QFAIL("Stream ended while waiting for mail settings events.");
}
void checkKeychainEvents(ClientReader<StreamEvent>& reader)
{
QList<KeychainEvent::EventCase> expected = {
KeychainEvent::kChangeKeychainFinished,
KeychainEvent::kHasNoKeychain,
KeychainEvent::kRebuildKeychain,
};
StreamEvent event;
while (reader.Read(&event))
{
QVERIFY2(event.event_case() == StreamEvent::kKeychain, "Received invalid event while waiting for keychain event.");
KeychainEvent const& keychainEvent = event.keychain();
KeychainEvent::EventCase const eventCase = keychainEvent.event_case();
QVERIFY2(expected.size() > 0, "Empty expected keychain event list.");
QVERIFY2(eventCase == expected.front(), "Unexpected keychain event received.");
expected.pop_front();
if (expected.isEmpty())
return;
}
QFAIL("Stream ended while waiting for keychain events.");
}
void checkMailEvents(ClientReader<StreamEvent>& reader)
{
QList<MailEvent::EventCase> expected = {
MailEvent::kNoActiveKeyForRecipientEvent,
MailEvent::kAddressChanged,
MailEvent::kAddressChangedLogout,
MailEvent::kApiCertIssue,
};
StreamEvent event;
while (reader.Read(&event))
{
QVERIFY2(event.event_case() == StreamEvent::kMail, "Received invalid event while waiting for mail event.");
MailEvent const& mailEvent = event.mail();
MailEvent::EventCase const eventCase = mailEvent.event_case();
QVERIFY2(expected.size() > 0, "Empty expected mail event list.");
QVERIFY2(eventCase == expected.front(), "Unexpected mail event received.");
expected.pop_front();
if (expected.isEmpty())
return;
}
QFAIL("Stream ended while waiting for mail events.");
}
void checkUserEvents(ClientReader<StreamEvent>& reader)
{
QList<UserEvent::EventCase> expected = {
UserEvent::kToggleSplitModeFinished,
UserEvent::kUserDisconnected,
UserEvent::kUserChanged,
};
StreamEvent event;
while (reader.Read(&event))
{
QVERIFY2(event.event_case() == StreamEvent::kUser, "Received invalid event while waiting for user event.");
UserEvent const& userEvent = event.user();
UserEvent::EventCase const eventCase = userEvent.event_case();
QVERIFY2(expected.size() > 0, "Empty expected user event list.");
QVERIFY2(eventCase == expected.front(), "Unexpected user event received.");
expected.pop_front();
if (expected.isEmpty())
return;
}
QFAIL("Stream ended while waiting for user events.");
}
void RpcClient::testStream()
{
Ctx ctx;
std::unique_ptr<ClientReader<StreamEvent>> reader = stub_->GetEvents(ctx.get(), empty);
QVERIFY2(reader, "Could not instanciate event stream reader");
checkAppEvents(*reader);
checkLoginEvents(*reader);
checkUpdateEvents(*reader);
checkCacheEvents(*reader);
checkMailsSettingsEvents(*reader);
checkKeychainEvents(*reader);
checkMailEvents(*reader);
checkUserEvents(*reader);
}
#pragma clang diagnostic pop

View File

@ -0,0 +1,98 @@
// Copyright (c) 2022 Proton AG
//
// This file is part of Proton Mail Bridge.Bridge.
//
// Proton Mail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Proton Mail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#ifndef BRIDGE_RPC_CLIENT_TEST_RPC_CLIENT_H
#define BRIDGE_RPC_CLIENT_TEST_RPC_CLIENT_H
#include "rpc/bridge_rpc.grpc.pb.h"
#include "grpc++/grpc++.h"
#include <QtCore>
//**********************************************************************************************************************
/// \brief Rpc Client class.
//**********************************************************************************************************************
class RpcClient: public QObject
{
Q_OBJECT
public: // member functions
explicit RpcClient(); ///< Default constructor.
RpcClient(RpcClient const &) = delete; ///< Disabled copy-constructor.
RpcClient(RpcClient &&) = delete; ///< Disabled assignment copy-constructor.
~RpcClient() override = default; ///< Destructor.
RpcClient &operator=(RpcClient const &) = delete; ///< Disabled assignment operator.
RpcClient &operator=(RpcClient &&) = delete; ///< Disabled move assignment operator.
private slots:
#pragma clang diagnostic push
#pragma ide diagnostic ignored "OCUnusedGlobalDeclarationInspection"
void initTestCase(); ///< Check if the connection with the RPC server is established.
void testGetCursorPos(); ///< Test the GetCursorPos call.
void testGuiReady(); ///< Test the GuiReady call.
void testQuit(); ///< Test the Quit call.
void testRestart(); ///< Test the Restart call.
void testShowOnStartup(); ///< Test the ShowOnStartup calls.
void testShowSplashScreen(); ///< Test the ShowSplashScreen calls.
void testDockIconVisible(); ///< Test the DockIconVisible calls.
void testIsFirstGuiStart(); ///< Test the IsFirstGuiStart calls.
void testIsAutostartOn(); ///< Test the IsAutostartOn calls.
void testIsBetaEnabled(); ///< Test the IsBetaEnabled calls.
void testGoOs(); ///< Test the GoOs call.
void testTriggerReset(); ///< Test the TriggerReset call.
void testVersion(); ///< Test the Version call.
void testLogPath(); ///< Test the LogPath call.
void testLicensePath(); ///< Test the LicensePath call.
void testReleaseNotesLink(); ///< Test the ReleastNotesLink call.
void testLandingPageLink(); ///< Test the LandingPageLink call.
void testColorScheme(); ///< Test the ColorScheme calls.
void testCurrentEmailClient(); ///< Test the CurrentEmailClient calls.
void testReportBug(); ///< Test the ReportBug call.
void testLogin(); ///< Test the Login call.
void testLogin2FA(); ///< Test the Login2FA call.
void testLogin2Passwords(); ///< Test the Login2Passwords call.
void testLoginAbort(); ///< Test the LoginAbort call.
void testCheckUpdate(); ///< Test the CheckUpdate call.
void testInstallUpdate(); ///< Test the CheckUpdate call.
void testIsAutomaticUpdateOn(); ///< Test the IsAutomaticUpdateOn calls.
void testIsCacheOnDiskEnabled(); ///< Test the IsCacheOnDiskEnabled calls.
void testDiskCachePath(); ///< Test the DiskCachePath calls.
void testChangeLocalCache(); ///< Test the ChangeLocalPath calls.
void testIsDohEnabled(); ///< Test the IsDohEnabled calls.
void testUseSslForSmtp(); ///< Test the UseSslForSmtp calls.
void testHostname(); ///< Test the Hostname call.
void testImapPort(); ///< Test the ImapPort calls.
void testSmtpPort(); ///< Test the SmtpPort calls.
void testChangePorts(); ///< Test the ChangePorts call.
void testIsPortFree(); ///< Test the IsPortFree call.
void testKeychain(); ///< Test the keychains related calls.
void testUser(); ///< Test the user related calls.
void testStream(); ///< Test the server to client stream
#pragma clang diagnostic pop
private: // data members
std::shared_ptr<grpc::Channel> channel_ { nullptr }; ///< The gRPC channel.
std::shared_ptr<bridgerpc::BridgeRpc::Stub> stub_ { nullptr }; ///< The gRPC stub (a.k.a. client).
};
#endif //BRIDGE_RPC_CLIENT_TEST_RPC_CLIENT_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -55,6 +55,8 @@ generate_dep_licenses(){
sed -i -r '/go.etcd.io\/bbolt/s|^(.*)$|\1 available under [license](https://github.com/etcd-io/bbolt/blob/master/LICENSE) |g' "$tmpDepLicenses"
sed -i -r '/howett.net\/plist/s|^(.*)$|\1 available under [license](https://github.com/DHowett/go-plist/blob/main/LICENSE) |g' "$tmpDepLicenses"
sed -i -r '/golang.org\/x/s|^(.*golang.org/x/([^)]+).*)$|\1 available under [license](https://cs.opensource.google/go/x/\2/+/master:LICENSE) |g' "$tmpDepLicenses"
sed -i -r '/google.golang.org\/grpc/s|^(.*)$|\1 available under [license](https://github.com/grpc/grpc-go/blob/master/LICENSE) |g' "$tmpDepLicenses"
sed -i -r '/google.golang.org\/protobuf/s|^(.*)$|\1 available under [license](https://github.com/protocolbuffers/protobuf/blob/main/LICENSE) |g' "$tmpDepLicenses"
}
check_dependecies(){

View File

@ -1,3 +1,20 @@
// Copyright (c) 2022 Proton AG
//
// This file is part of Proton Mail Bridge.Bridge.
//
// Proton Mail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Proton Mail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#include "main.h"
extern "C" DLL_EXPORT BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)

View File

@ -1,3 +1,20 @@
// Copyright (c) 2022 Proton AG
//
// This file is part of Proton Mail Bridge.Bridge.
//
// Proton Mail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Proton Mail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Proton Mail Bridge. If not, see <https://www.gnu.org/licenses/>.
#ifndef __MAIN_H__
#define __MAIN_H__

View File

@ -23,7 +23,12 @@ MISSING_FILES=$(find . \
-not -path "./vendor-cache/*" \
-not -path "./.cache/*" \
-not -name "*mock*.go" \
-regextype posix-egrep -regex ".*\.go|.*\.qml|.*\.sh|.*\.py" \
-not -path "*/cmake-build-*/*" \
-not -name "*.pb.go" \
-not -name "*.pb.h" \
-not -name "*.pb.cc" \
-not -name "*_moc.h" \
-regextype posix-egrep -regex ".*\.go|.*\.qml|.*\.sh|.*\.py|.*\.cpp|.*\.cc|.*\.h|.*\.hpp|.*\.m" \
-exec grep -L "Copyright (c) ${YEAR} Proton AG" {} \;)
for f in ${MISSING_FILES}