mirror of
https://github.com/gravitl/netmaker.git
synced 2024-11-11 01:54:34 +08:00
229 lines
5.6 KiB
Go
229 lines
5.6 KiB
Go
package logic
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"errors"
|
|
"math/big"
|
|
"strings"
|
|
"sync"
|
|
|
|
validator "github.com/go-playground/validator/v10"
|
|
"github.com/gravitl/netmaker/database"
|
|
"github.com/gravitl/netmaker/logger"
|
|
"github.com/gravitl/netmaker/models"
|
|
"github.com/gravitl/netmaker/servercfg"
|
|
)
|
|
|
|
// CreateAccessKey - create access key
|
|
func CreateAccessKey(accesskey models.AccessKey, network models.Network) (models.AccessKey, error) {
|
|
|
|
if accesskey.Name == "" {
|
|
accesskey.Name = genKeyName()
|
|
}
|
|
|
|
if accesskey.Value == "" {
|
|
accesskey.Value = GenKey()
|
|
}
|
|
if accesskey.Uses == 0 {
|
|
accesskey.Uses = 1
|
|
}
|
|
|
|
checkkeys, err := GetKeys(network.NetID)
|
|
if err != nil {
|
|
return models.AccessKey{}, errors.New("could not retrieve network keys")
|
|
}
|
|
|
|
for _, key := range checkkeys {
|
|
if key.Name == accesskey.Name {
|
|
return models.AccessKey{}, errors.New("duplicate AccessKey Name")
|
|
}
|
|
}
|
|
|
|
netID := network.NetID
|
|
|
|
var accessToken models.AccessToken
|
|
|
|
accessToken.APIConnString = servercfg.GetAPIConnString()
|
|
accessToken.ClientConfig.Network = netID
|
|
accessToken.ClientConfig.Key = accesskey.Value
|
|
|
|
tokenjson, err := json.Marshal(accessToken)
|
|
if err != nil {
|
|
return accesskey, err
|
|
}
|
|
|
|
accesskey.AccessString = base64.StdEncoding.EncodeToString([]byte(tokenjson))
|
|
|
|
//validate accesskey
|
|
v := validator.New()
|
|
err = v.Struct(accesskey)
|
|
if err != nil {
|
|
for _, e := range err.(validator.ValidationErrors) {
|
|
logger.Log(1, "validator", e.Error())
|
|
}
|
|
return models.AccessKey{}, err
|
|
}
|
|
|
|
network.AccessKeys = append(network.AccessKeys, accesskey)
|
|
data, err := json.Marshal(&network)
|
|
if err != nil {
|
|
return models.AccessKey{}, err
|
|
}
|
|
if err = database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME); err != nil {
|
|
return models.AccessKey{}, err
|
|
}
|
|
|
|
return accesskey, nil
|
|
}
|
|
|
|
// DeleteKey - deletes a key
|
|
func DeleteKey(keyname, netname string) error {
|
|
network, err := GetParentNetwork(netname)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
//basically, turn the list of access keys into the list of access keys before and after the item
|
|
//have not done any error handling for if there's like...1 item. I think it works? need to test.
|
|
found := false
|
|
var updatedKeys []models.AccessKey
|
|
for _, currentkey := range network.AccessKeys {
|
|
if currentkey.Name == keyname {
|
|
found = true
|
|
} else {
|
|
updatedKeys = append(updatedKeys, currentkey)
|
|
}
|
|
}
|
|
if !found {
|
|
return errors.New("key " + keyname + " does not exist")
|
|
}
|
|
network.AccessKeys = updatedKeys
|
|
data, err := json.Marshal(&network)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GetKeys - fetches keys for network
|
|
func GetKeys(net string) ([]models.AccessKey, error) {
|
|
|
|
record, err := database.FetchRecord(database.NETWORKS_TABLE_NAME, net)
|
|
if err != nil {
|
|
return []models.AccessKey{}, err
|
|
}
|
|
network, err := ParseNetwork(record)
|
|
if err != nil {
|
|
return []models.AccessKey{}, err
|
|
}
|
|
return network.AccessKeys, nil
|
|
}
|
|
|
|
// DecrimentKey - decriments key uses
|
|
func DecrimentKey(networkName string, keyvalue string) {
|
|
|
|
var network models.Network
|
|
|
|
network, err := GetParentNetwork(networkName)
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
for i := len(network.AccessKeys) - 1; i >= 0; i-- {
|
|
|
|
currentkey := network.AccessKeys[i]
|
|
if currentkey.Value == keyvalue {
|
|
network.AccessKeys[i].Uses--
|
|
if network.AccessKeys[i].Uses < 1 {
|
|
network.AccessKeys = append(network.AccessKeys[:i],
|
|
network.AccessKeys[i+1:]...)
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
if newNetworkData, err := json.Marshal(&network); err != nil {
|
|
logger.Log(2, "failed to decrement key")
|
|
return
|
|
} else {
|
|
database.Insert(network.NetID, string(newNetworkData), database.NETWORKS_TABLE_NAME)
|
|
}
|
|
}
|
|
|
|
// IsKeyValid - check if key is valid
|
|
func IsKeyValid(networkname string, keyvalue string) (string, bool) {
|
|
|
|
network, err := GetParentNetwork(networkname)
|
|
if err != nil {
|
|
return "", false
|
|
}
|
|
accesskeys := network.AccessKeys
|
|
|
|
var key models.AccessKey
|
|
foundkey := false
|
|
isvalid := false
|
|
|
|
for i := len(accesskeys) - 1; i >= 0; i-- {
|
|
currentkey := accesskeys[i]
|
|
if currentkey.Value == keyvalue {
|
|
key = currentkey
|
|
foundkey = true
|
|
}
|
|
}
|
|
if foundkey {
|
|
if key.Uses > 0 {
|
|
isvalid = true
|
|
}
|
|
}
|
|
return key.Name, isvalid
|
|
}
|
|
|
|
// RemoveKeySensitiveInfo - remove sensitive key info
|
|
func RemoveKeySensitiveInfo(keys []models.AccessKey) []models.AccessKey {
|
|
var returnKeys []models.AccessKey
|
|
for _, key := range keys {
|
|
key.Value = models.PLACEHOLDER_KEY_TEXT
|
|
key.AccessString = models.PLACEHOLDER_TOKEN_TEXT
|
|
returnKeys = append(returnKeys, key)
|
|
}
|
|
return returnKeys
|
|
}
|
|
|
|
const (
|
|
maxr string = "ff578f57c15bb743beaa77d27637e02b598dffa9aebd15889187fe6eb3bdca516c3fa1a52eabef31f33b4b8c2e5b5524f1aa4f3329393912f40dbbe23d7f39723e0be05b6696b11f8eea0abe365a11d9f2735ac7e5b4e015ab19b35b84893685b37a9a0a62a566d6571d7e00d4241687f5c804f37cde9bf311c0781f51cc007c5a01a94f6cfcecea640b8e9ab7bd43e73e5df5d0e1eeb4d9b6cc44be67b7cad80808b17869561b579ffe0bbdeca5c83139e458000000000000000000000000000000000000000000000000000000000000000"
|
|
)
|
|
|
|
var (
|
|
uno sync.Once
|
|
maxentropy *big.Int
|
|
)
|
|
|
|
func init() {
|
|
uno.Do(func() {
|
|
maxentropy, _ = new(big.Int).SetString(maxr, 16)
|
|
})
|
|
}
|
|
|
|
// == private methods ==
|
|
|
|
func genKeyName() string {
|
|
entropy, _ := rand.Int(rand.Reader, maxentropy)
|
|
return strings.Join([]string{"key", entropy.Text(16)[:16]}, "-")
|
|
}
|
|
|
|
// GenKey - generates random key of length 16
|
|
func GenKey() string {
|
|
entropy, _ := rand.Int(rand.Reader, maxentropy)
|
|
return entropy.Text(16)[:16]
|
|
}
|
|
|
|
// GenPassWord - generates random password of length 64
|
|
func GenPassWord() string {
|
|
entropy, _ := rand.Int(rand.Reader, maxentropy)
|
|
return entropy.Text(62)[:64]
|
|
}
|