github.com/hasnat/dolt/go@v0.0.0-20210628190320-9eb5d843fbb7/libraries/doltcore/creds/creds.go (about)

     1  // Copyright 2019 Dolthub, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package creds
    16  
    17  import (
    18  	"context"
    19  	"crypto/sha512"
    20  	"encoding/base32"
    21  	"errors"
    22  	"time"
    23  
    24  	"golang.org/x/crypto/ed25519"
    25  	"gopkg.in/square/go-jose.v2"
    26  	"gopkg.in/square/go-jose.v2/jwt"
    27  
    28  	"github.com/dolthub/dolt/go/libraries/utils/set"
    29  	"github.com/dolthub/dolt/go/store/util/datetime"
    30  )
    31  
    32  const (
    33  	pubKeySize  = 32
    34  	privKeySize = 64
    35  )
    36  
    37  const (
    38  	B32CharEncoding = "0123456789abcdefghijklmnopqrstuv"
    39  
    40  	B32EncodedPubKeyLen = 52
    41  	B32EncodedKeyIdLen  = 45
    42  
    43  	JWTKIDHeader = "kid"
    44  	JWTAlgHeader = "alg"
    45  )
    46  
    47  var B32CredsByteSet = set.NewByteSet([]byte(B32CharEncoding))
    48  var B32CredsEncoding = base32.NewEncoding(B32CharEncoding).WithPadding(base32.NoPadding)
    49  var EmptyCreds = DoltCreds{}
    50  
    51  var ErrBadB32CredsEncoding = errors.New("bad base32 credentials encoding")
    52  var ErrCredsNotFound = errors.New("credentials not found")
    53  
    54  type DoltCreds struct {
    55  	PubKey  []byte
    56  	PrivKey []byte
    57  	KeyID   []byte
    58  }
    59  
    60  func PubKeyStrToKIDStr(pub string) (string, error) {
    61  	data, err := B32CredsEncoding.DecodeString(pub)
    62  
    63  	if err != nil {
    64  		return "", err
    65  	}
    66  
    67  	return PubKeyToKIDStr(data), nil
    68  }
    69  
    70  func PubKeyToKID(pub []byte) []byte {
    71  	kidBytes := sha512.Sum512_224(pub)
    72  	return kidBytes[:]
    73  }
    74  
    75  func PubKeyToKIDStr(pub []byte) string {
    76  	kidBytes := PubKeyToKID(pub)
    77  	kid := B32CredsEncoding.EncodeToString(kidBytes)
    78  	return kid
    79  }
    80  
    81  func GenerateCredentials() (DoltCreds, error) {
    82  	pub, priv, err := ed25519.GenerateKey(nil)
    83  
    84  	if err == nil {
    85  		kid := PubKeyToKID(pub)
    86  		return DoltCreds{pub, priv, kid}, nil
    87  	}
    88  
    89  	return DoltCreds{}, err
    90  }
    91  
    92  func (dc DoltCreds) HasPrivKey() bool {
    93  	return len(dc.PrivKey) > 0
    94  }
    95  
    96  func (dc DoltCreds) IsPrivKeyValid() bool {
    97  	return len(dc.PrivKey) == privKeySize
    98  }
    99  
   100  func (dc DoltCreds) IsPubKeyValid() bool {
   101  	return len(dc.PubKey) == pubKeySize
   102  }
   103  
   104  func (dc DoltCreds) PubKeyBase32Str() string {
   105  	return B32CredsEncoding.EncodeToString(dc.PubKey)
   106  }
   107  
   108  func (dc DoltCreds) PrivKeyBase32Str() string {
   109  	return B32CredsEncoding.EncodeToString(dc.PubKey)
   110  }
   111  
   112  func (dc DoltCreds) KeyIDBase32Str() string {
   113  	return B32CredsEncoding.EncodeToString(dc.KeyID)
   114  }
   115  
   116  func (dc DoltCreds) Sign(data []byte) []byte {
   117  	return ed25519.Sign(dc.PrivKey, data)
   118  }
   119  
   120  func (dc DoltCreds) toBearerToken() (string, error) {
   121  	b32KIDStr := dc.KeyIDBase32Str()
   122  	key := jose.SigningKey{Algorithm: jose.EdDSA, Key: ed25519.PrivateKey(dc.PrivKey)}
   123  	opts := &jose.SignerOptions{ExtraHeaders: map[jose.HeaderKey]interface{}{
   124  		JWTKIDHeader: b32KIDStr,
   125  	}}
   126  
   127  	signer, err := jose.NewSigner(key, opts)
   128  
   129  	if err != nil {
   130  		return "", err
   131  	}
   132  
   133  	// Shouldn't be hard coded
   134  	jwtBuilder := jwt.Signed(signer)
   135  	jwtBuilder = jwtBuilder.Claims(jwt.Claims{
   136  		Audience: []string{"dolthub-remote-api.liquidata.co"},
   137  		Issuer:   "dolt-client.liquidata.co",
   138  		Subject:  "doltClientCredentials/" + b32KIDStr,
   139  		Expiry:   jwt.NewNumericDate(datetime.Now().Add(30 * time.Second)),
   140  	})
   141  
   142  	return jwtBuilder.CompactSerialize()
   143  }
   144  
   145  func (dc DoltCreds) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
   146  	t, err := dc.toBearerToken()
   147  
   148  	if err != nil {
   149  		return nil, err
   150  	}
   151  
   152  	return map[string]string{
   153  		"authorization": "Bearer " + t,
   154  	}, nil
   155  }
   156  
   157  func (dc DoltCreds) RequireTransportSecurity() bool {
   158  	return false
   159  }