mirror of
https://github.com/netbirdio/netbird.git
synced 2026-07-30 01:42:36 -04:00
67 lines
1.9 KiB
Go
67 lines
1.9 KiB
Go
package cmd
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"google.golang.org/genproto/googleapis/rpc/errdetails"
|
|
gstatus "google.golang.org/grpc/status"
|
|
|
|
"github.com/netbirdio/netbird/client/internal/ipcauth"
|
|
)
|
|
|
|
// daemonCallError prepares a daemon error for display. A refusal the daemon
|
|
// raised because the operation needs root/administrator is already guidance
|
|
// written for the user, so it is surfaced on its own instead of buried under the
|
|
// gRPC envelope and the name of the RPC that hit it. Anything else is wrapped
|
|
// with context as usual.
|
|
func daemonCallError(context string, err error) error {
|
|
if guidance, ok := privilegeGuidance(err); ok {
|
|
return errors.New(guidance)
|
|
}
|
|
return fmt.Errorf("%s: %w", context, err)
|
|
}
|
|
|
|
// privilegeGuidance renders the daemon's privilege refusal as a summary and the
|
|
// command that performs the operation with the privileges it needs. It reports
|
|
// false for any other error.
|
|
func privilegeGuidance(err error) (string, bool) {
|
|
info, ok := privilegeErrorInfo(err)
|
|
if !ok {
|
|
return "", false
|
|
}
|
|
|
|
summary := info.GetMetadata()[ipcauth.ErrorMetaSummary]
|
|
command := info.GetMetadata()[ipcauth.ErrorMetaCommand]
|
|
if summary == "" {
|
|
// Detail without a summary: fall back to the status message, which
|
|
// carries the same text.
|
|
summary = strings.TrimSpace(gstatus.Convert(err).Message())
|
|
}
|
|
if command == "" {
|
|
return summary, true
|
|
}
|
|
|
|
return fmt.Sprintf("%s\n\n %s\n", summary, command), true
|
|
}
|
|
|
|
// privilegeErrorInfo returns the daemon's privilege-refusal detail, if the error
|
|
// carries one.
|
|
func privilegeErrorInfo(err error) (*errdetails.ErrorInfo, bool) {
|
|
if err == nil {
|
|
return nil, false
|
|
}
|
|
|
|
for _, detail := range gstatus.Convert(err).Details() {
|
|
info, ok := detail.(*errdetails.ErrorInfo)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if info.GetReason() == ipcauth.ErrorReasonPrivilegeRequired && info.GetDomain() == ipcauth.ErrorDomain {
|
|
return info, true
|
|
}
|
|
}
|
|
return nil, false
|
|
}
|