syncfeatures: add support for TLS

Until now syncfeatures could only connect to insecure endpoints. This CL
allows it to connect to gRPC endpoints with server-side TLS
authentication.

Bug: twpowertools:62
Change-Id: I1d0fd6bcf2aead47c152f66a10be538f6655ca7c
diff --git a/cmd/syncfeatures/syncfeatures.go b/cmd/syncfeatures/syncfeatures.go
index 2f8ba50..a4f97d8 100644
--- a/cmd/syncfeatures/syncfeatures.go
+++ b/cmd/syncfeatures/syncfeatures.go
@@ -8,14 +8,18 @@
 	"os"
 
 	"google.golang.org/grpc"
+	"google.golang.org/grpc/credentials"
 	"google.golang.org/grpc/metadata"
 
+	"github.com/johnsiilver/getcert"
+
 	pb "gomodules.avm99963.com/twpt-server/api_proto"
 )
 
 var (
 	grpcEndpoint = flag.String("grpcEndpoint", "", "gRPC endpoint address.")
 	jwt          = flag.String("jwt", "", "JWT credentials.")
+	insecure     = flag.Bool("insecure", false, "Set if the connection to the gRPC endpoint is insecure.")
 )
 
 type Features map[string]Feature
@@ -45,7 +49,18 @@
 func main() {
 	flag.Parse()
 
-	conn, err := grpc.Dial(*grpcEndpoint, grpc.WithInsecure())
+	var err error
+	var conn *grpc.ClientConn
+
+	if *insecure {
+		conn, err = grpc.Dial(*grpcEndpoint, grpc.WithInsecure())
+	} else {
+		tlsCert, _, err2 := getcert.FromTLSServer(*grpcEndpoint, false)
+		if err2 != nil {
+			log.Fatalf("error while retrieving public certificate: %v\n", err2)
+		}
+		conn, err = grpc.Dial(*grpcEndpoint, grpc.WithTransportCredentials(credentials.NewServerTLSFromCert(&tlsCert)))
+	}
 	if err != nil {
 		log.Fatalf("error while connecting to gRPC endpoint: %v\n", err)
 	}
diff --git a/go.mod b/go.mod
index 35d81e7..b1b3e67 100644
--- a/go.mod
+++ b/go.mod
@@ -6,6 +6,7 @@
 	github.com/Masterminds/semver/v3 v3.1.1
 	github.com/ReneKroon/ttlcache/v2 v2.8.0
 	github.com/go-sql-driver/mysql v1.6.0
+	github.com/johnsiilver/getcert v0.0.0-20201005022436-57fe9706afac // indirect
 	google.golang.org/api v0.54.0
 	google.golang.org/grpc v1.40.0
 	google.golang.org/protobuf v1.27.1
diff --git a/go.sum b/go.sum
index d3f627d..0527107 100644
--- a/go.sum
+++ b/go.sum
@@ -151,6 +151,8 @@
 github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/johnsiilver/getcert v0.0.0-20201005022436-57fe9706afac h1:8GdKJzd6GksrZ1HhOBNTCrxDiF78oYNcSeMoWcntegQ=
+github.com/johnsiilver/getcert v0.0.0-20201005022436-57fe9706afac/go.mod h1:4mUbFuzKgo8VxDZsJVxZYMYen77v5ybZgR3tm1tuInU=
 github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
@@ -190,6 +192,7 @@
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=