github.com/code-to-go/safepool.lib@v0.0.0-20221205180519-ee25e63c226e/pool/token.go (about)

     1  package pool
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/base64"
     6  	"encoding/json"
     7  	"fmt"
     8  	"strings"
     9  
    10  	"github.com/code-to-go/safepool.lib/core"
    11  	"github.com/code-to-go/safepool.lib/security"
    12  )
    13  
    14  type Token struct {
    15  	Config Config
    16  	Host   security.Identity
    17  }
    18  
    19  func EncodeToken(t Token, guest *security.Identity) (string, error) {
    20  	tk, err := json.Marshal(Token{
    21  		Config: t.Config,
    22  		Host:   t.Host.Public(),
    23  	})
    24  	if core.IsErr(err, "cannot marshal config to token: %v") {
    25  		return "", err
    26  	}
    27  
    28  	gk := ""
    29  	if guest != nil {
    30  		gk, err = guest.Public().Base64()
    31  		if core.IsErr(err, "invalid guest key: %v") {
    32  			return "", err
    33  		}
    34  		tk, err = security.EcEncrypt(*guest, tk)
    35  		if core.IsErr(err, "cannot encrypt with guest key: %v") {
    36  			return "", err
    37  		}
    38  	}
    39  
    40  	sig, err := security.Sign(t.Host, tk)
    41  	if core.IsErr(err, "cannot sign with host key: %v") {
    42  		return "", err
    43  	}
    44  
    45  	return fmt.Sprintf("%s:%s:%s", gk,
    46  		base64.StdEncoding.EncodeToString(tk),
    47  		base64.StdEncoding.EncodeToString(sig)), nil
    48  
    49  }
    50  
    51  func DecodeToken(guest *security.Identity, token string) (Token, error) {
    52  	var t Token
    53  	parts := strings.Split(token, ":")
    54  	if len(parts) != 3 {
    55  		return t, ErrInvalidToken
    56  	}
    57  
    58  	gk, tk64, sig64 := parts[0], parts[1], parts[2]
    59  	tk, _ := base64.StdEncoding.DecodeString(tk64)
    60  	sig, _ := base64.StdEncoding.DecodeString(sig64)
    61  	if gk != "" {
    62  		g, err := security.IdentityFromBase64(gk)
    63  		if core.IsErr(err, "cannot decode guest token from base64: %s") {
    64  			return t, ErrInvalidToken
    65  		}
    66  
    67  		if guest == nil || !bytes.Equal(g.EncryptionKey.Public, guest.EncryptionKey.Public) {
    68  			core.IsErr(ErrNotAuthorized, "mismatch between guests keys: %v")
    69  			return t, ErrNotAuthorized
    70  		}
    71  
    72  		tk, err = security.EcDecrypt(*guest, tk)
    73  		if core.IsErr(err, "cannot decrypt guest token with own key: %s") {
    74  			return t, ErrInvalidToken
    75  		}
    76  	}
    77  
    78  	err := json.Unmarshal(tk, &t)
    79  	if core.IsErr(err, "cannot unmarshal token: %s") {
    80  		return t, ErrInvalidToken
    81  	}
    82  
    83  	if !security.Verify(t.Host.Id(), tk, sig) {
    84  		core.IsErr(ErrInvalidSignature, "token has invalid signature: %v")
    85  		return t, ErrInvalidSignature
    86  	}
    87  
    88  	return t, nil
    89  }