feat: sdk migration in progress

This commit is contained in:
allanice001
2025-11-02 13:19:30 +00:00
commit 0d10d42442
492 changed files with 71067 additions and 0 deletions

View File

@@ -0,0 +1,35 @@
package keys
import (
"encoding/base64"
"errors"
"strings"
)
func decode32ByteKey(s string) ([]byte, error) {
try := func(enc *base64.Encoding, v string) ([]byte, bool) {
if b, err := enc.DecodeString(v); err == nil && len(b) == 32 {
return b, true
}
return nil, false
}
// Try raw (no padding) variants first
if b, ok := try(base64.RawURLEncoding, s); ok {
return b, nil
}
if b, ok := try(base64.RawStdEncoding, s); ok {
return b, nil
}
// Try padded variants (add padding if missing)
pad := func(v string) string { return v + strings.Repeat("=", (4-len(v)%4)%4) }
if b, ok := try(base64.URLEncoding, pad(s)); ok {
return b, nil
}
if b, ok := try(base64.StdEncoding, pad(s)); ok {
return b, nil
}
return nil, errors.New("key must be 32 bytes in base64/base64url")
}

5
internal/keys/export.go Normal file
View File

@@ -0,0 +1,5 @@
package keys
func Decrypt(encKeyB64, enc string) ([]byte, error) {
return decryptAESGCM(encKeyB64, enc)
}

149
internal/keys/keys.go Normal file
View File

@@ -0,0 +1,149 @@
package keys
import (
"bytes"
"crypto/aes"
"crypto/cipher"
"crypto/ed25519"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"errors"
"fmt"
"time"
"github.com/glueops/autoglue/internal/models"
"github.com/google/uuid"
"gorm.io/gorm"
)
type GenOpts struct {
Alg string // "RS256"|"RS384"|"RS512"|"EdDSA"
Bits int // RSA bits (2048/3072/4096). ignored for EdDSA
KID string // optional; if empty we generate one
NBF *time.Time
EXP *time.Time
}
func GenerateAndStore(db *gorm.DB, encKeyB64 string, opts GenOpts) (*models.SigningKey, error) {
if opts.KID == "" {
opts.KID = uuid.NewString()
}
var pubPEM, privPEM []byte
var alg = opts.Alg
switch alg {
case "RS256", "RS384", "RS512":
if opts.Bits == 0 {
opts.Bits = 3072
}
priv, err := rsa.GenerateKey(rand.Reader, opts.Bits)
if err != nil {
return nil, err
}
privDER := x509.MarshalPKCS1PrivateKey(priv)
privPEM = pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: privDER})
pubDER := x509.MarshalPKCS1PublicKey(&priv.PublicKey)
pubPEM = pem.EncodeToMemory(&pem.Block{Type: "RSA PUBLIC KEY", Bytes: pubDER})
case "EdDSA":
pub, priv, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
return nil, err
}
privDER, err := x509.MarshalPKCS8PrivateKey(priv)
if err != nil {
return nil, err
}
privPEM = pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: privDER})
pubDER, err := x509.MarshalPKIXPublicKey(pub)
if err != nil {
return nil, err
}
pubPEM = pem.EncodeToMemory(&pem.Block{Type: "PUBLIC KEY", Bytes: pubDER})
default:
return nil, fmt.Errorf("unsupported alg: %s", alg)
}
privateOut := string(privPEM)
if encKeyB64 != "" {
enc, err := encryptAESGCM(encKeyB64, privPEM)
if err != nil {
return nil, err
}
privateOut = enc
}
rec := models.SigningKey{
Kid: opts.KID,
Alg: alg,
Use: "sig",
IsActive: true,
PublicPEM: string(pubPEM),
PrivatePEM: privateOut,
NotBefore: opts.NBF,
ExpiresAt: opts.EXP,
}
if err := db.Create(&rec).Error; err != nil {
return nil, err
}
return &rec, nil
}
func encryptAESGCM(b64 string, plaintext []byte) (string, error) {
key, err := decode32ByteKey(b64)
if err != nil {
return "", err
}
if len(key) != 32 {
return "", errors.New("JWT_PRIVATE_ENC_KEY must be 32 bytes (base64url)")
}
block, err := aes.NewCipher(key)
if err != nil {
return "", err
}
aead, err := cipher.NewGCM(block)
if err != nil {
return "", err
}
nonce := make([]byte, aead.NonceSize())
if _, err = rand.Read(nonce); err != nil {
return "", err
}
out := aead.Seal(nonce, nonce, plaintext, nil)
return "enc:aesgcm:" + base64.RawStdEncoding.EncodeToString(out), nil
}
func decryptAESGCM(b64 string, enc string) ([]byte, error) {
if !bytes.HasPrefix([]byte(enc), []byte("enc:aesgcm:")) {
return nil, errors.New("not encrypted")
}
key, err := decode32ByteKey(b64)
if err != nil {
return nil, err
}
blob, err := base64.RawStdEncoding.DecodeString(enc[len("enc:aesgcm:"):])
if err != nil {
return nil, err
}
block, err := aes.NewCipher(key)
if err != nil {
return nil, err
}
aead, err := cipher.NewGCM(block)
if err != nil {
return nil, err
}
nonceSize := aead.NonceSize()
if len(blob) < nonceSize {
return nil, errors.New("ciphertext too short")
}
nonce, ct := blob[:nonceSize], blob[nonceSize:]
return aead.Open(nil, nonce, ct, nil)
}