2017-02-23 06:12:16 +01:00
|
|
|
package db
|
2016-04-04 01:10:12 +02:00
|
|
|
|
2016-04-08 21:41:20 +02:00
|
|
|
import (
|
2021-08-31 01:02:41 +02:00
|
|
|
"crypto/aes"
|
|
|
|
"crypto/cipher"
|
|
|
|
"crypto/rand"
|
|
|
|
"encoding/base64"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
2016-04-08 21:41:20 +02:00
|
|
|
"strconv"
|
|
|
|
|
|
|
|
"github.com/ansible-semaphore/semaphore/util"
|
|
|
|
)
|
2016-04-07 14:49:34 +02:00
|
|
|
|
2021-08-30 16:24:20 +02:00
|
|
|
const (
|
|
|
|
AccessKeySSH = "ssh"
|
|
|
|
AccessKeyNone = "none"
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2018-03-27 22:12:47 +02:00
|
|
|
// AccessKey represents a key used to access a machine with ansible from semaphore
|
2016-04-04 01:10:12 +02:00
|
|
|
type AccessKey struct {
|
|
|
|
ID int `db:"id" json:"id"`
|
|
|
|
Name string `db:"name" json:"name" binding:"required"`
|
2021-08-30 16:24:20 +02:00
|
|
|
// 'ssh/none'
|
2016-04-04 01:10:12 +02:00
|
|
|
Type string `db:"type" json:"type" binding:"required"`
|
|
|
|
|
|
|
|
ProjectID *int `db:"project_id" json:"project_id"`
|
|
|
|
Secret *string `db:"secret" json:"secret"`
|
2016-06-17 22:16:46 +02:00
|
|
|
|
|
|
|
Removed bool `db:"removed" json:"removed"`
|
2016-04-04 01:10:12 +02:00
|
|
|
}
|
2016-04-07 14:49:34 +02:00
|
|
|
|
2018-03-27 22:12:47 +02:00
|
|
|
// GetPath returns the location of the access key once written to disk
|
2016-04-08 21:41:20 +02:00
|
|
|
func (key AccessKey) GetPath() string {
|
|
|
|
return util.Config.TmpPath + "/access_key_" + strconv.Itoa(key.ID)
|
|
|
|
}
|
2021-08-31 01:02:41 +02:00
|
|
|
|
|
|
|
func (key *AccessKey) EncryptSecret() error {
|
|
|
|
if key.Secret == nil || *key.Secret == "" {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if util.Config.AccessKeyEncryption == "" { // do not encrypt if secret key not specified
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
plaintext := []byte(*key.Secret)
|
|
|
|
|
|
|
|
encryption, err := base64.StdEncoding.DecodeString(util.Config.CookieEncryption)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
c, err := aes.NewCipher(encryption)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
gcm, err := cipher.NewGCM(c)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
nonce := make([]byte, gcm.NonceSize())
|
|
|
|
if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2021-08-31 01:27:15 +02:00
|
|
|
secret := base64.StdEncoding.EncodeToString(gcm.Seal(nonce, nonce, plaintext, nil))
|
2021-08-31 01:02:41 +02:00
|
|
|
|
|
|
|
key.Secret = &secret
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (key AccessKey) DecryptSecret() (string, error) {
|
|
|
|
if key.Secret == nil || *key.Secret == "" {
|
|
|
|
return "", nil
|
|
|
|
}
|
|
|
|
|
|
|
|
ciphertext := []byte(*key.Secret)
|
|
|
|
|
2021-08-31 01:27:15 +02:00
|
|
|
if ciphertext[len(*key.Secret) - 1] == '\n' { // not encrypted string
|
2021-08-31 01:02:41 +02:00
|
|
|
return *key.Secret, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
if util.Config.AccessKeyEncryption == "" { // do not decrypt if secret key not specified
|
|
|
|
return *key.Secret, nil
|
|
|
|
}
|
|
|
|
|
2021-08-31 01:27:15 +02:00
|
|
|
ciphertext, err := base64.StdEncoding.DecodeString(*key.Secret)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
2021-08-31 01:02:41 +02:00
|
|
|
encryption, err := base64.StdEncoding.DecodeString(util.Config.CookieEncryption)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
c, err := aes.NewCipher(encryption)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
gcm, err := cipher.NewGCM(c)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
nonceSize := gcm.NonceSize()
|
|
|
|
if len(ciphertext) < nonceSize {
|
|
|
|
return "", fmt.Errorf("ciphertext too short")
|
|
|
|
}
|
|
|
|
|
|
|
|
nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
|
|
|
|
|
|
|
|
encrypted, err := gcm.Open(nil, nonce, ciphertext, nil)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
return string(encrypted), nil
|
|
|
|
}
|