Skip to content

Commit

Permalink
Return better errors for unavailable error codes (#2336)
Browse files Browse the repository at this point in the history
If we can determine that the error from login is due to a connect
unavailable error, we should return more details to aid in
troubleshooting. Update wrapError to return a better error message in
case of a TLS certificate error (could be a MITM attack or an untrusted
certificate).
  • Loading branch information
pkwarren committed Aug 2, 2023
1 parent 4ed6eb6 commit 3bd5bea
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 1 deletion.
6 changes: 5 additions & 1 deletion private/buf/bufcli/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,11 @@ func wrapError(err error) error {
if dnsError := (&net.DNSError{}); errors.As(err, &dnsError) && dnsError.IsNotFound {
return fmt.Errorf(`%s Are you sure "%s" is a valid remote address?`, msg, dnsError.Name)
}

// If the unavailable error wraps a tls.CertificateVerificationError, show a more specific error message
// to the user to aid in troubleshooting.
if tlsErr := wrappedTLSError(err); tlsErr != nil {
return fmt.Errorf("tls certificate verification: %w", tlsErr)
}
return errors.New(msg)
}
return fmt.Errorf("Failure: %s", connectErr.Message())
Expand Down
36 changes: 36 additions & 0 deletions private/buf/bufcli/errors_tls_go119.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Copyright 2020-2023 Buf Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build !go1.20

package bufcli

import (
"errors"
"strings"
)

// wrappedTLSError returns an unwrapped TLS error or nil if the error is another type of error.
// This method is a workaround until we can switch to use errors.As(err, *tls.CertificateVerificationError),
// which is a new error type introduced in Go 1.20. This can be removed when we upgrade to support Go 1.20/1.21+.
func wrappedTLSError(err error) error {
wrapped := errors.Unwrap(err)
if wrapped == nil {
return nil
}
if strings.HasPrefix(wrapped.Error(), "x509:") && strings.HasSuffix(wrapped.Error(), "certificate is not trusted") {
return wrapped
}
return nil
}
30 changes: 30 additions & 0 deletions private/buf/bufcli/errors_tls_go120.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2020-2023 Buf Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//go:build go1.20

package bufcli

import (
"crypto/tls"
"errors"
)

// wrappedTLSError returns an unwrapped TLS error or nil if the error is another type of error.
func wrappedTLSError(err error) error {
if tlsErr := (&tls.CertificateVerificationError{}); errors.As(err, &tlsErr) {
return tlsErr
}
return nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,9 @@ func inner(
authnService := connectclient.Make(clientConfig, remote, registryv1alpha1connect.NewAuthnServiceClient)
resp, err := authnService.GetCurrentUser(ctx, connect.NewRequest(&registryv1alpha1.GetCurrentUserRequest{}))
if err != nil {
if connectErr := new(connect.Error); errors.As(err, &connectErr) && connectErr.Code() == connect.CodeUnavailable {
return connectErr
}
// We don't want to use the default error from wrapError here if the error
// an unauthenticated error.
return errors.New("invalid token provided")
Expand Down

0 comments on commit 3bd5bea

Please sign in to comment.