mirror of
https://github.com/jsiebens/ionscale.git
synced 2026-03-31 15:07:49 +01:00
chore: introduce server key
This commit is contained in:
+23
-24
@@ -3,12 +3,11 @@ package config
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/caddyserver/certmagic"
|
"github.com/caddyserver/certmagic"
|
||||||
"github.com/jsiebens/ionscale/internal/util"
|
"github.com/jsiebens/ionscale/internal/key"
|
||||||
"github.com/mitchellh/go-homedir"
|
"github.com/mitchellh/go-homedir"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"strings"
|
"strings"
|
||||||
"tailscale.com/types/key"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func LoadConfig(path string) (*Config, error) {
|
func LoadConfig(path string) (*Config, error) {
|
||||||
@@ -83,43 +82,43 @@ func defaultConfig() *Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ServerKeys struct {
|
type ServerKeys struct {
|
||||||
SystemAdminKey key.MachinePrivate
|
SystemAdminKey key.ServerPrivate
|
||||||
}
|
}
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
HttpListenAddr string `yaml:"http_listen_addr"`
|
HttpListenAddr string `yaml:"http_listen_addr,omitempty"`
|
||||||
HttpsListenAddr string `yaml:"https_listen_addr"`
|
HttpsListenAddr string `yaml:"https_listen_addr,omitempty"`
|
||||||
MetricsListenAddr string `yaml:"metrics_listen_addr"`
|
MetricsListenAddr string `yaml:"metrics_listen_addr,omitempty"`
|
||||||
ServerUrl string `yaml:"server_url"`
|
ServerUrl string `yaml:"server_url,omitempty"`
|
||||||
Tls Tls `yaml:"tls"`
|
Tls Tls `yaml:"tls,omitempty"`
|
||||||
Logging Logging `yaml:"logging"`
|
Logging Logging `yaml:"logging,omitempty"`
|
||||||
Keys Keys `yaml:"keys"`
|
Keys Keys `yaml:"keys,omitempty"`
|
||||||
Database Database `yaml:"database"`
|
Database Database `yaml:"database,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Tls struct {
|
type Tls struct {
|
||||||
Disable bool `yaml:"disable"`
|
Disable bool `yaml:"disable"`
|
||||||
CertFile string `yaml:"cert_file"`
|
CertFile string `yaml:"cert_file,omitempty"`
|
||||||
KeyFile string `yaml:"key_file"`
|
KeyFile string `yaml:"key_file,omitempty"`
|
||||||
CertMagicDomain string `yaml:"cert_magic_domain"`
|
CertMagicDomain string `yaml:"cert_magic_domain,omitempty"`
|
||||||
CertMagicEmail string `yaml:"cert_magic_email"`
|
CertMagicEmail string `yaml:"cert_magic_email,omitempty"`
|
||||||
CertMagicCA string `yaml:"cert_magic_ca"`
|
CertMagicCA string `yaml:"cert_magic_ca,omitempty"`
|
||||||
CertMagicStoragePath string `yaml:"cert_magic_storage_path"`
|
CertMagicStoragePath string `yaml:"cert_magic_storage_path,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Logging struct {
|
type Logging struct {
|
||||||
Level string `yaml:"level"`
|
Level string `yaml:"level,omitempty"`
|
||||||
Format string `yaml:"format"`
|
Format string `yaml:"format,omitempty"`
|
||||||
File string `yaml:"file"`
|
File string `yaml:"file,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Database struct {
|
type Database struct {
|
||||||
Url string `yaml:"url"`
|
Url string `yaml:"url,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Keys struct {
|
type Keys struct {
|
||||||
SystemAdminKey string `yaml:"system_admin_key"`
|
SystemAdminKey string `yaml:"system_admin_key,omitempty"`
|
||||||
EncryptionKey string `yaml:"encryption_key"`
|
EncryptionKey string `yaml:"encryption_key,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) CreateUrl(format string, a ...interface{}) string {
|
func (c *Config) CreateUrl(format string, a ...interface{}) string {
|
||||||
@@ -128,7 +127,7 @@ func (c *Config) CreateUrl(format string, a ...interface{}) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) ReadServerKeys() (*ServerKeys, error) {
|
func (c *Config) ReadServerKeys() (*ServerKeys, error) {
|
||||||
systemAdminKey, err := util.ParseMachinePrivateKey(c.Keys.SystemAdminKey)
|
systemAdminKey, err := key.ParsePrivateKey(c.Keys.SystemAdminKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error reading system admin key: %v", err)
|
return nil, fmt.Errorf("error reading system admin key: %v", err)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"github.com/hashicorp/go-hclog"
|
"github.com/hashicorp/go-hclog"
|
||||||
"net/http"
|
"net/http"
|
||||||
"tailscale.com/tailcfg"
|
"tailscale.com/tailcfg"
|
||||||
"tailscale.com/types/key"
|
tskey "tailscale.com/types/key"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/jsiebens/ionscale/internal/config"
|
"github.com/jsiebens/ionscale/internal/config"
|
||||||
@@ -106,8 +106,8 @@ func initializeControlKeys(repository domain.Repository) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
keys = &domain.ControlKeys{
|
keys = &domain.ControlKeys{
|
||||||
ControlKey: key.NewMachine(),
|
ControlKey: tskey.NewMachine(),
|
||||||
LegacyControlKey: key.NewMachine(),
|
LegacyControlKey: tskey.NewMachine(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return repository.SetControlKeys(ctx, keys)
|
return repository.SetControlKeys(ctx, keys)
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
package key
|
||||||
|
|
||||||
|
import (
|
||||||
|
crand "crypto/rand"
|
||||||
|
"crypto/subtle"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
|
"golang.org/x/crypto/curve25519"
|
||||||
|
"golang.org/x/crypto/nacl/box"
|
||||||
|
"io"
|
||||||
|
)
|
||||||
|
|
||||||
|
func NewServerKey() ServerPrivate {
|
||||||
|
_, key, err := box.GenerateKey(crand.Reader)
|
||||||
|
if err != nil {
|
||||||
|
panic(fmt.Sprintf("unable create new key: %v", err))
|
||||||
|
}
|
||||||
|
return ServerPrivate{k: *key}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParsePrivateKey(key string) (*ServerPrivate, error) {
|
||||||
|
k := new([32]byte)
|
||||||
|
err := parseHex(k[:], key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &ServerPrivate{k: *k}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ParsePublicKey(key string) (*ServerPublic, error) {
|
||||||
|
k := new([32]byte)
|
||||||
|
err := parseHex(k[:], key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &ServerPublic{k: *k}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseHex(out []byte, v string) error {
|
||||||
|
in := []byte(v)
|
||||||
|
|
||||||
|
if want := len(out) * 2; len(in) != want {
|
||||||
|
return fmt.Errorf("key hex has the wrong size, got %d want %d", len(in), want)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := hex.Decode(out[:], in)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerPrivate struct {
|
||||||
|
k [32]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type ServerPublic struct {
|
||||||
|
k [32]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k ServerPrivate) Public() ServerPublic {
|
||||||
|
var ret ServerPublic
|
||||||
|
curve25519.ScalarBaseMult(&ret.k, &k.k)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k ServerPrivate) Equal(other ServerPrivate) bool {
|
||||||
|
return subtle.ConstantTimeCompare(k.k[:], other.k[:]) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k ServerPrivate) IsZero() bool {
|
||||||
|
return k.Equal(ServerPrivate{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k ServerPrivate) Seal(cleartext []byte) (ciphertext []byte) {
|
||||||
|
if k.IsZero() {
|
||||||
|
panic("can't seal with zero keys")
|
||||||
|
}
|
||||||
|
var nonce [24]byte
|
||||||
|
rand(nonce[:])
|
||||||
|
p := k.Public()
|
||||||
|
return box.Seal(nonce[:], cleartext, &nonce, &p.k, &k.k)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k ServerPrivate) Open(ciphertext []byte) (cleartext []byte, ok bool) {
|
||||||
|
if k.IsZero() {
|
||||||
|
panic("can't open with zero keys")
|
||||||
|
}
|
||||||
|
if len(ciphertext) < 24 {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
var nonce [24]byte
|
||||||
|
copy(nonce[:], ciphertext)
|
||||||
|
p := k.Public()
|
||||||
|
return box.Open(nil, ciphertext[len(nonce):], &nonce, &p.k, &k.k)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k ServerPrivate) String() string {
|
||||||
|
return hex.EncodeToString(k.k[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k ServerPublic) Equal(other ServerPublic) bool {
|
||||||
|
return subtle.ConstantTimeCompare(k.k[:], other.k[:]) == 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k ServerPublic) IsZero() bool {
|
||||||
|
return k.Equal(ServerPublic{})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (k ServerPublic) String() string {
|
||||||
|
return hex.EncodeToString(k.k[:])
|
||||||
|
}
|
||||||
|
|
||||||
|
func rand(b []byte) {
|
||||||
|
if _, err := io.ReadFull(crand.Reader, b[:]); err != nil {
|
||||||
|
panic(fmt.Sprintf("unable to read random bytes from OS: %v", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,16 +6,16 @@ import (
|
|||||||
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/recovery"
|
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/recovery"
|
||||||
"github.com/grpc-ecosystem/go-grpc-prometheus"
|
"github.com/grpc-ecosystem/go-grpc-prometheus"
|
||||||
"github.com/hashicorp/go-hclog"
|
"github.com/hashicorp/go-hclog"
|
||||||
|
"github.com/jsiebens/ionscale/internal/key"
|
||||||
"github.com/jsiebens/ionscale/internal/service"
|
"github.com/jsiebens/ionscale/internal/service"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"tailscale.com/types/key"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
grpc_prometheus.EnableHandlingTimeHistogram()
|
grpc_prometheus.EnableHandlingTimeHistogram()
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGrpcServer(logger hclog.Logger, systemAdminKey key.MachinePrivate) *grpc.Server {
|
func NewGrpcServer(logger hclog.Logger, systemAdminKey key.ServerPrivate) *grpc.Server {
|
||||||
return grpc.NewServer(
|
return grpc.NewServer(
|
||||||
middleware.WithUnaryServerChain(
|
middleware.WithUnaryServerChain(
|
||||||
logging.UnaryServerInterceptor(
|
logging.UnaryServerInterceptor(
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"github.com/jsiebens/ionscale/internal/broker"
|
"github.com/jsiebens/ionscale/internal/broker"
|
||||||
"github.com/jsiebens/ionscale/internal/domain"
|
"github.com/jsiebens/ionscale/internal/domain"
|
||||||
|
"github.com/jsiebens/ionscale/internal/key"
|
||||||
"github.com/jsiebens/ionscale/internal/token"
|
"github.com/jsiebens/ionscale/internal/token"
|
||||||
"github.com/jsiebens/ionscale/internal/version"
|
"github.com/jsiebens/ionscale/internal/version"
|
||||||
"github.com/jsiebens/ionscale/pkg/gen/api"
|
"github.com/jsiebens/ionscale/pkg/gen/api"
|
||||||
@@ -12,7 +13,6 @@ import (
|
|||||||
"google.golang.org/grpc/metadata"
|
"google.golang.org/grpc/metadata"
|
||||||
"google.golang.org/grpc/status"
|
"google.golang.org/grpc/status"
|
||||||
"strings"
|
"strings"
|
||||||
"tailscale.com/types/key"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -44,7 +44,7 @@ func (s *Service) GetVersion(ctx context.Context, req *api.GetVersionRequest) (*
|
|||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UnaryServerTokenAuth(systemAdminKey key.MachinePrivate) func(context.Context, interface{}, *grpc.UnaryServerInfo, grpc.UnaryHandler) (interface{}, error) {
|
func UnaryServerTokenAuth(systemAdminKey key.ServerPrivate) func(context.Context, interface{}, *grpc.UnaryServerInfo, grpc.UnaryHandler) (interface{}, error) {
|
||||||
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
|
||||||
|
|
||||||
if strings.HasSuffix(info.FullMethod, "/GetVersion") {
|
if strings.HasSuffix(info.FullMethod, "/GetVersion") {
|
||||||
@@ -68,7 +68,7 @@ func UnaryServerTokenAuth(systemAdminKey key.MachinePrivate) func(context.Contex
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateAuthorizationToken(systemAdminKey key.MachinePrivate, authorization []string) bool {
|
func validateAuthorizationToken(systemAdminKey key.ServerPrivate, authorization []string) bool {
|
||||||
if len(authorization) != 1 {
|
if len(authorization) != 1 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-11
@@ -5,10 +5,10 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/jsiebens/ionscale/internal/key"
|
||||||
"github.com/jsiebens/ionscale/internal/util"
|
"github.com/jsiebens/ionscale/internal/util"
|
||||||
"github.com/mr-tron/base58"
|
"github.com/mr-tron/base58"
|
||||||
"strings"
|
"strings"
|
||||||
"tailscale.com/types/key"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -29,7 +29,7 @@ func IsSystemAdminToken(token string) bool {
|
|||||||
return strings.HasPrefix(token, systemAdminTokenPrefix)
|
return strings.HasPrefix(token, systemAdminTokenPrefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseSystemAdminToken(privKey key.MachinePrivate, versionedToken string) (*Info, error) {
|
func ParseSystemAdminToken(privKey key.ServerPrivate, versionedToken string) (*Info, error) {
|
||||||
versionedToken = strings.TrimSpace(versionedToken)
|
versionedToken = strings.TrimSpace(versionedToken)
|
||||||
if versionedToken == "" {
|
if versionedToken == "" {
|
||||||
return nil, errors.New("empty token")
|
return nil, errors.New("empty token")
|
||||||
@@ -50,7 +50,7 @@ func ParseSystemAdminToken(privKey key.MachinePrivate, versionedToken string) (*
|
|||||||
|
|
||||||
info := new(Info)
|
info := new(Info)
|
||||||
|
|
||||||
if err := unmarshal(marshaledBlob, info, privKey.Public(), privKey); err != nil {
|
if err := unmarshal(marshaledBlob, info, privKey); err != nil {
|
||||||
return nil, fmt.Errorf("error unmarshaling token info: %w", err)
|
return nil, fmt.Errorf("error unmarshaling token info: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ func ParseSystemAdminToken(privKey key.MachinePrivate, versionedToken string) (*
|
|||||||
return info, nil
|
return info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GenerateSystemAdminToken(privKey key.MachinePrivate) (string, error) {
|
func GenerateSystemAdminToken(privKey key.ServerPrivate) (string, error) {
|
||||||
b, err := util.RandomBytes(nonceLength)
|
b, err := util.RandomBytes(nonceLength)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("error generating random bytes for token nonce: %w", err)
|
return "", fmt.Errorf("error generating random bytes for token nonce: %w", err)
|
||||||
@@ -87,11 +87,11 @@ func GenerateSystemAdminToken(privKey key.MachinePrivate) (string, error) {
|
|||||||
CreationTime: time.Now(),
|
CreationTime: time.Now(),
|
||||||
}
|
}
|
||||||
|
|
||||||
return formatToken(privKey.Public(), privKey, systemAdminTokenPrefix, info)
|
return formatToken(privKey, systemAdminTokenPrefix, info)
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatToken(pubKey key.MachinePublic, privKey key.MachinePrivate, prefix string, v interface{}) (string, error) {
|
func formatToken(privKey key.ServerPrivate, prefix string, v interface{}) (string, error) {
|
||||||
blobInfo, err := marshal(v, pubKey, privKey)
|
blobInfo, err := marshal(v, privKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("error encrypting info: %w", err)
|
return "", fmt.Errorf("error encrypting info: %w", err)
|
||||||
}
|
}
|
||||||
@@ -101,17 +101,17 @@ func formatToken(pubKey key.MachinePublic, privKey key.MachinePrivate, prefix st
|
|||||||
return fmt.Sprintf("%s%s", prefix, encodedMarshaledBlob), nil
|
return fmt.Sprintf("%s%s", prefix, encodedMarshaledBlob), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func marshal(v interface{}, pubKey key.MachinePublic, privKey key.MachinePrivate) ([]byte, error) {
|
func marshal(v interface{}, privKey key.ServerPrivate) ([]byte, error) {
|
||||||
b, err := json.Marshal(v)
|
b, err := json.Marshal(v)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return privKey.SealTo(pubKey, b), nil
|
return privKey.Seal(b), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshal(msg []byte, v interface{}, publicKey key.MachinePublic, privateKey key.MachinePrivate) error {
|
func unmarshal(msg []byte, v interface{}, privateKey key.ServerPrivate) error {
|
||||||
decrypted, ok := privateKey.OpenFrom(publicKey, msg)
|
decrypted, ok := privateKey.Open(msg)
|
||||||
if !ok {
|
if !ok {
|
||||||
return fmt.Errorf("unable to decrypt payload")
|
return fmt.Errorf("unable to decrypt payload")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,19 +3,14 @@ package ionscale
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/jsiebens/ionscale/internal/key"
|
||||||
"github.com/jsiebens/ionscale/internal/token"
|
"github.com/jsiebens/ionscale/internal/token"
|
||||||
"github.com/jsiebens/ionscale/internal/util"
|
|
||||||
"google.golang.org/grpc/credentials"
|
"google.golang.org/grpc/credentials"
|
||||||
"tailscale.com/types/key"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func HasCredentials(systemAdminKey string) bool {
|
|
||||||
return systemAdminKey != ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func LoadClientAuth(systemAdminKey string) (ClientAuth, error) {
|
func LoadClientAuth(systemAdminKey string) (ClientAuth, error) {
|
||||||
if systemAdminKey != "" {
|
if systemAdminKey != "" {
|
||||||
k, err := util.ParseMachinePrivateKey(systemAdminKey)
|
k, err := key.ParsePrivateKey(systemAdminKey)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("invalid system admin key")
|
return nil, fmt.Errorf("invalid system admin key")
|
||||||
}
|
}
|
||||||
@@ -41,7 +36,7 @@ func (m *anonymous) RequireTransportSecurity() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type systemAdminTokenAuth struct {
|
type systemAdminTokenAuth struct {
|
||||||
key key.MachinePrivate
|
key key.ServerPrivate
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *systemAdminTokenAuth) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
|
func (m *systemAdminTokenAuth) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
|
||||||
@@ -57,17 +52,3 @@ func (m *systemAdminTokenAuth) GetRequestMetadata(ctx context.Context, uri ...st
|
|||||||
func (m *systemAdminTokenAuth) RequireTransportSecurity() bool {
|
func (m *systemAdminTokenAuth) RequireTransportSecurity() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
type tokenAuth struct {
|
|
||||||
token string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *tokenAuth) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
|
|
||||||
return map[string]string{
|
|
||||||
"authorization": "Bearer " + m.token,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *tokenAuth) RequireTransportSecurity() bool {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user