accesskeys.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. package logic
  2. import (
  3. "crypto/rand"
  4. "encoding/base64"
  5. "encoding/json"
  6. "errors"
  7. "math/big"
  8. "strings"
  9. "sync"
  10. validator "github.com/go-playground/validator/v10"
  11. "github.com/gravitl/netmaker/database"
  12. "github.com/gravitl/netmaker/logger"
  13. "github.com/gravitl/netmaker/models"
  14. "github.com/gravitl/netmaker/servercfg"
  15. )
  16. // CreateAccessKey - create access key
  17. func CreateAccessKey(accesskey models.AccessKey, network models.Network) (models.AccessKey, error) {
  18. if accesskey.Name == "" {
  19. accesskey.Name = genKeyName()
  20. }
  21. if accesskey.Value == "" {
  22. accesskey.Value = GenKey()
  23. }
  24. if accesskey.Uses == 0 {
  25. accesskey.Uses = 1
  26. }
  27. checkkeys, err := GetKeys(network.NetID)
  28. if err != nil {
  29. return models.AccessKey{}, errors.New("could not retrieve network keys")
  30. }
  31. for _, key := range checkkeys {
  32. if key.Name == accesskey.Name {
  33. return models.AccessKey{}, errors.New("duplicate AccessKey Name")
  34. }
  35. }
  36. netID := network.NetID
  37. var accessToken models.AccessToken
  38. accessToken.APIConnString = servercfg.GetAPIConnString()
  39. accessToken.ClientConfig.Network = netID
  40. accessToken.ClientConfig.Key = accesskey.Value
  41. tokenjson, err := json.Marshal(accessToken)
  42. if err != nil {
  43. return accesskey, err
  44. }
  45. accesskey.AccessString = base64.StdEncoding.EncodeToString([]byte(tokenjson))
  46. //validate accesskey
  47. v := validator.New()
  48. err = v.Struct(accesskey)
  49. if err != nil {
  50. for _, e := range err.(validator.ValidationErrors) {
  51. logger.Log(1, "validator", e.Error())
  52. }
  53. return models.AccessKey{}, err
  54. }
  55. network.AccessKeys = append(network.AccessKeys, accesskey)
  56. data, err := json.Marshal(&network)
  57. if err != nil {
  58. return models.AccessKey{}, err
  59. }
  60. if err = database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME); err != nil {
  61. return models.AccessKey{}, err
  62. }
  63. return accesskey, nil
  64. }
  65. // DeleteKey - deletes a key
  66. func DeleteKey(keyname, netname string) error {
  67. network, err := GetParentNetwork(netname)
  68. if err != nil {
  69. return err
  70. }
  71. //basically, turn the list of access keys into the list of access keys before and after the item
  72. //have not done any error handling for if there's like...1 item. I think it works? need to test.
  73. found := false
  74. var updatedKeys []models.AccessKey
  75. for _, currentkey := range network.AccessKeys {
  76. if currentkey.Name == keyname {
  77. found = true
  78. } else {
  79. updatedKeys = append(updatedKeys, currentkey)
  80. }
  81. }
  82. if !found {
  83. return errors.New("key " + keyname + " does not exist")
  84. }
  85. network.AccessKeys = updatedKeys
  86. data, err := json.Marshal(&network)
  87. if err != nil {
  88. return err
  89. }
  90. if err := database.Insert(network.NetID, string(data), database.NETWORKS_TABLE_NAME); err != nil {
  91. return err
  92. }
  93. return nil
  94. }
  95. // GetKeys - fetches keys for network
  96. func GetKeys(net string) ([]models.AccessKey, error) {
  97. record, err := database.FetchRecord(database.NETWORKS_TABLE_NAME, net)
  98. if err != nil {
  99. return []models.AccessKey{}, err
  100. }
  101. network, err := ParseNetwork(record)
  102. if err != nil {
  103. return []models.AccessKey{}, err
  104. }
  105. return network.AccessKeys, nil
  106. }
  107. // DecrimentKey - decriments key uses
  108. func DecrimentKey(networkName string, keyvalue string) {
  109. var network models.Network
  110. network, err := GetParentNetwork(networkName)
  111. if err != nil {
  112. return
  113. }
  114. for i := len(network.AccessKeys) - 1; i >= 0; i-- {
  115. currentkey := network.AccessKeys[i]
  116. if currentkey.Value == keyvalue {
  117. network.AccessKeys[i].Uses--
  118. if network.AccessKeys[i].Uses < 1 {
  119. network.AccessKeys = append(network.AccessKeys[:i],
  120. network.AccessKeys[i+1:]...)
  121. break
  122. }
  123. }
  124. }
  125. if newNetworkData, err := json.Marshal(&network); err != nil {
  126. logger.Log(2, "failed to decrement key")
  127. return
  128. } else {
  129. database.Insert(network.NetID, string(newNetworkData), database.NETWORKS_TABLE_NAME)
  130. }
  131. }
  132. // IsKeyValid - check if key is valid
  133. func IsKeyValid(networkname string, keyvalue string) (string, bool) {
  134. network, err := GetParentNetwork(networkname)
  135. if err != nil {
  136. return "", false
  137. }
  138. accesskeys := network.AccessKeys
  139. var key models.AccessKey
  140. foundkey := false
  141. isvalid := false
  142. for i := len(accesskeys) - 1; i >= 0; i-- {
  143. currentkey := accesskeys[i]
  144. if currentkey.Value == keyvalue {
  145. key = currentkey
  146. foundkey = true
  147. }
  148. }
  149. if foundkey {
  150. if key.Uses > 0 {
  151. isvalid = true
  152. }
  153. }
  154. return key.Name, isvalid
  155. }
  156. // RemoveKeySensitiveInfo - remove sensitive key info
  157. func RemoveKeySensitiveInfo(keys []models.AccessKey) []models.AccessKey {
  158. var returnKeys []models.AccessKey
  159. for _, key := range keys {
  160. key.Value = models.PLACEHOLDER_KEY_TEXT
  161. key.AccessString = models.PLACEHOLDER_TOKEN_TEXT
  162. returnKeys = append(returnKeys, key)
  163. }
  164. return returnKeys
  165. }
  166. const (
  167. maxr string = "ff578f57c15bb743beaa77d27637e02b598dffa9aebd15889187fe6eb3bdca516c3fa1a52eabef31f33b4b8c2e5b5524f1aa4f3329393912f40dbbe23d7f39723e0be05b6696b11f8eea0abe365a11d9f2735ac7e5b4e015ab19b35b84893685b37a9a0a62a566d6571d7e00d4241687f5c804f37cde9bf311c0781f51cc007c5a01a94f6cfcecea640b8e9ab7bd43e73e5df5d0e1eeb4d9b6cc44be67b7cad80808b17869561b579ffe0bbdeca5c83139e458000000000000000000000000000000000000000000000000000000000000000"
  168. )
  169. var (
  170. uno sync.Once
  171. maxentropy *big.Int
  172. )
  173. func init() {
  174. uno.Do(func() {
  175. maxentropy, _ = new(big.Int).SetString(maxr, 16)
  176. })
  177. }
  178. // == private methods ==
  179. func genKeyName() string {
  180. entropy, _ := rand.Int(rand.Reader, maxentropy)
  181. return strings.Join([]string{"key", entropy.Text(16)[:16]}, "-")
  182. }
  183. // GenKey - generates random key of length 16
  184. func GenKey() string {
  185. entropy, _ := rand.Int(rand.Reader, maxentropy)
  186. return entropy.Text(16)[:16]
  187. }
  188. // GenPassWord - generates random password of length 64
  189. func GenPassWord() string {
  190. entropy, _ := rand.Int(rand.Reader, maxentropy)
  191. return entropy.Text(62)[:64]
  192. }