@@ -2,19 +2,10 @@ package plugin
22
33import (
44 "context"
5- "crypto/ed25519"
6- "crypto/rand"
7- "crypto/tls"
8- "crypto/x509"
9- "fmt"
10- "log"
115 "net"
12- "os"
136
147 "github.com/gotify/plugin-api/v2/generated/protobuf"
158 "google.golang.org/grpc"
16- "google.golang.org/grpc/credentials"
17- "google.golang.org/grpc/peer"
189 "google.golang.org/protobuf/types/known/emptypb"
1910)
2011
@@ -48,237 +39,3 @@ func NewPluginRpc(infraDialer GrpcDialer) *PluginRpc {
4839func (h * PluginRpc ) Serve (listener net.Listener ) error {
4940 return h .pluginServer .Serve (listener )
5041}
51-
52- type ServerVersionInfo struct {
53- Version string
54- Commit string
55- BuildDate string
56- }
57-
58- type infraServerImpl struct {
59- server * ServerMux
60- version ServerVersionInfo
61- protobuf.UnimplementedInfraServer
62- }
63-
64- func (s * infraServerImpl ) GetServerVersion (ctx context.Context , req * emptypb.Empty ) (* protobuf.ServerVersionInfo , error ) {
65- return & protobuf.ServerVersionInfo {
66- Version : s .version .Version ,
67- Commit : s .version .Commit ,
68- BuildDate : s .version .BuildDate ,
69- }, nil
70- }
71-
72- func (s * infraServerImpl ) WhoAmI (ctx context.Context , req * emptypb.Empty ) (* protobuf.Info , error ) {
73- peer , ok := peer .FromContext (ctx )
74- if ! ok {
75- return nil , fmt .Errorf ("no peer in context" )
76- }
77- authInfo := peer .AuthInfo .(* infraTlsAuthInfo )
78- return s .server .GetPluginInfo (authInfo .moduleName )
79- }
80-
81- type PluginConnection struct {
82- info * protobuf.Info
83- conn * grpc.ClientConn
84- }
85-
86- type ServerMux struct {
87- version ServerVersionInfo
88- tlsClient * EphemeralTLSClient
89- infraAddr net.Addr
90- infraListener net.Listener
91- infraServer * grpc.Server
92- pluginDNSToModulePath map [string ]string
93- pluginConnections map [string ]PluginConnection
94- protobuf.UnimplementedInfraServer
95- }
96-
97- func (s * ServerMux ) GetServerVersion (ctx context.Context , req * emptypb.Empty ) (* protobuf.ServerVersionInfo , error ) {
98- return & protobuf.ServerVersionInfo {
99- Version : s .version .Version ,
100- Commit : s .version .Commit ,
101- BuildDate : s .version .BuildDate ,
102- }, nil
103- }
104-
105- func (s * ServerMux ) WhoAmI (ctx context.Context , req * emptypb.Empty ) (* protobuf.Info , error ) {
106- peer , ok := peer .FromContext (ctx )
107- if ! ok {
108- return nil , fmt .Errorf ("no peer in context" )
109- }
110- authInfo := peer .AuthInfo .(* infraTlsAuthInfo )
111- return s .GetPluginInfo (authInfo .moduleName )
112- }
113-
114- type infraTlsCreds struct {
115- pluginDNSToModulePath map [string ]string
116- credentials.TransportCredentials
117- }
118-
119- type infraTlsAuthInfo struct {
120- moduleName string
121- credentials.TLSInfo
122- }
123-
124- func (c * infraTlsCreds ) ServerHandshake (rawConn net.Conn ) (net.Conn , credentials.AuthInfo , error ) {
125- netConn , authInfo , err := c .TransportCredentials .ServerHandshake (rawConn )
126- if err != nil {
127- log .Printf ("ServerHandshake: error %v" , err )
128- rawConn .Close ()
129- return nil , nil , err
130- }
131- protocolInfo := authInfo .(credentials.TLSInfo )
132- serverName := protocolInfo .State .VerifiedChains [0 ][0 ].DNSNames [0 ]
133- moduleName , ok := c .pluginDNSToModulePath [serverName ]
134- if ! ok {
135- log .Printf ("ServerHandshake: unknown server name %s" , serverName )
136- netConn .Close ()
137- rawConn .Close ()
138- return nil , nil , fmt .Errorf ("unknown server name %s" , serverName )
139- }
140-
141- return netConn , & infraTlsAuthInfo {
142- moduleName : moduleName ,
143- TLSInfo : protocolInfo ,
144- }, nil
145- }
146-
147- // NewServerMux creates a server-side mux with an infra server that handles plugin-to-server calls.
148- func NewServerMux (info ServerVersionInfo ) * ServerMux {
149- tlsClient , err := NewEphemeralTLSClient ()
150- if err != nil {
151- panic (err )
152- }
153- _ , infraPriv , err := ed25519 .GenerateKey (rand .Reader )
154- if err != nil {
155- panic (err )
156- }
157- infraCsrBytes , err := x509 .CreateCertificateRequest (rand .Reader , new (x509.CertificateRequest ), infraPriv )
158- if err != nil {
159- panic (err )
160- }
161- infraCsr , err := x509 .ParseCertificateRequest (infraCsrBytes )
162- if err != nil {
163- panic (err )
164- }
165- if err := infraCsr .CheckSignature (); err != nil {
166- panic (err )
167- }
168- infraCert , err := tlsClient .SignCSR (ServerTLSName , infraCsr )
169- if err != nil {
170- panic (err )
171- }
172- infraCertParsed , err := x509 .ParseCertificate (infraCert )
173- if err != nil {
174- panic (err )
175- }
176- caCertPool := x509 .NewCertPool ()
177- caCertPool .AddCert (tlsClient .caCert )
178- infraTlsConfig := & tls.Config {
179- Certificates : []tls.Certificate {
180- {
181- Certificate : [][]byte {infraCert , tlsClient .caCert .Raw },
182- PrivateKey : infraPriv ,
183- Leaf : infraCertParsed ,
184- },
185- },
186- ClientAuth : tls .RequireAndVerifyClientCert ,
187- ClientCAs : caCertPool ,
188- ServerName : ServerTLSName ,
189- }
190-
191- pluginDNSToModulePath := make (map [string ]string )
192- infraServer := grpc .NewServer (grpc .Creds (& infraTlsCreds {
193- pluginDNSToModulePath : pluginDNSToModulePath ,
194- TransportCredentials : credentials .NewTLS (infraTlsConfig ),
195- }))
196-
197- listener , err := newListener ()
198- if err != nil {
199- panic (err )
200- }
201- mux := & ServerMux {
202- version : info ,
203- tlsClient : tlsClient ,
204- infraAddr : listener .Addr (),
205- infraListener : listener ,
206- infraServer : infraServer ,
207- pluginDNSToModulePath : pluginDNSToModulePath ,
208- pluginConnections : make (map [string ]PluginConnection ),
209- }
210- protobuf .RegisterInfraServer (infraServer , & infraServerImpl {
211- server : mux ,
212- version : info ,
213- })
214-
215- go infraServer .Serve (listener )
216-
217- return mux
218- }
219-
220- // InfraAddr returns the address of the infra server for plugin-to-server callbacks.
221- func (s * ServerMux ) InfraAddr () net.Addr {
222- return s .infraAddr
223- }
224-
225- // CACert returns the CA certificate for mutual TLS authentication.
226- func (s * ServerMux ) CACert () * x509.Certificate {
227- return s .tlsClient .caCert
228- }
229-
230- // SignPluginCSR signs a certificate request for a plugin.
231- func (s * ServerMux ) SignPluginCSR (moduleName string , csr * x509.CertificateRequest ) ([]byte , error ) {
232- return s .tlsClient .SignPluginCSR (moduleName , csr )
233- }
234-
235- func (s * ServerMux ) RegisterPlugin (target string , moduleName string ) (* grpc.ClientConn , error ) {
236- grpcConn , err := grpc .NewClient (target , grpc .WithTransportCredentials (credentials .NewTLS (s .tlsClient .ClientTLSConfig (moduleName ))))
237- if err != nil {
238- return nil , err
239- }
240- if _ , exists := s .pluginDNSToModulePath [buildPluginTLSName (moduleName )]; exists {
241- return nil , fmt .Errorf ("plugin %s already registered" , moduleName )
242- }
243- s .pluginDNSToModulePath [buildPluginTLSName (moduleName )] = moduleName
244- pluginClient := protobuf .NewPluginClient (grpcConn )
245- pluginInfo , err := pluginClient .GetPluginInfo (context .Background (), & emptypb.Empty {})
246- if err != nil {
247- return nil , err
248- }
249- s .pluginConnections [moduleName ] = PluginConnection {
250- info : pluginInfo ,
251- conn : grpcConn ,
252- }
253- return grpcConn , nil
254- }
255-
256- // GetPluginInfo returns the info of a plugin.
257- func (s * ServerMux ) GetPluginInfo (moduleName string ) (* protobuf.Info , error ) {
258- conn , ok := s .pluginConnections [moduleName ]
259- if ! ok {
260- return nil , fmt .Errorf ("plugin %s not registered" , moduleName )
261- }
262- return conn .info , nil
263- }
264-
265- // GetPluginConnection returns the connection to the plugin for Server-to-Plugin calls.
266- func (s * ServerMux ) GetPluginConnection (moduleName string ) (* grpc.ClientConn , error ) {
267- conn , ok := s .pluginConnections [moduleName ]
268- if ! ok {
269- return nil , fmt .Errorf ("plugin %s not registered" , moduleName )
270- }
271- return conn .conn , nil
272- }
273-
274- func (s * ServerMux ) Close () error {
275- for _ , conn := range s .pluginConnections {
276- conn .conn .Close ()
277- }
278- s .infraServer .GracefulStop ()
279- if s .infraAddr .Network () == "unix" {
280- os .Remove (s .infraAddr .String ())
281- }
282- s .infraListener .Close ()
283- return nil
284- }
0 commit comments