123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257 |
- package logic
- import (
- "encoding/base64"
- "encoding/json"
- "errors"
- "math/rand"
- "time"
- "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"
- )
- const (
- charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
- )
- // 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")
- }
- }
- privAddr := ""
- if network.IsLocal != "" {
- privAddr = network.LocalRange
- }
- netID := network.NetID
- commsNetID, err := FetchCommsNetID()
- if err != nil {
- return models.AccessKey{}, errors.New("could not retrieve comms netid")
- }
- var accessToken models.AccessToken
- s := servercfg.GetServerConfig()
- servervals := models.ServerConfig{
- GRPCConnString: s.GRPCConnString,
- GRPCSSL: s.GRPCSSL,
- CommsNetwork: commsNetID,
- }
- accessToken.ServerConfig = servervals
- accessToken.ClientConfig.Network = netID
- accessToken.ClientConfig.Key = accesskey.Value
- accessToken.ClientConfig.LocalRange = privAddr
- 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 || network.IsComms == "yes" {
- 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) bool {
- network, err := GetParentNetwork(networkname)
- if err != nil {
- return false
- }
- accesskeys := network.AccessKeys
- if network.IsComms == "yes" {
- accesskeys = getAllAccessKeys()
- }
- 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 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
- }
- // == private methods ==
- func genKeyName() string {
- var seededRand *rand.Rand = rand.New(
- rand.NewSource(time.Now().UnixNano()))
- length := 5
- b := make([]byte, length)
- for i := range b {
- b[i] = charset[seededRand.Intn(len(charset))]
- }
- return "key" + string(b)
- }
- func genKey() string {
- var seededRand *rand.Rand = rand.New(
- rand.NewSource(time.Now().UnixNano()))
- length := 16
- b := make([]byte, length)
- for i := range b {
- b[i] = charset[seededRand.Intn(len(charset))]
- }
- return string(b)
- }
- func getAllAccessKeys() []models.AccessKey {
- var accesskeys = make([]models.AccessKey, 0)
- networks, err := GetNetworks()
- if err != nil {
- return accesskeys
- }
- for i := range networks {
- accesskeys = append(accesskeys, networks[i].AccessKeys...)
- }
- return accesskeys
- }
|