supabase-cli/internal/gen/keys/keys.go

95 lines
2.9 KiB
Go

package keys
import (
"context"
"crypto/sha256"
"encoding/hex"
"fmt"
"os"
"strings"
"github.com/go-errors/errors"
"github.com/go-git/go-git/v5"
"github.com/spf13/afero"
"github.com/supabase/cli/internal/utils"
"github.com/supabase/cli/pkg/config"
)
type CustomName struct {
DbHost string `env:"db.host,default=NEXT_PUBLIC_SUPABASE_URL"`
DbPassword string `env:"db.password,default=SUPABASE_DB_PASSWORD"`
JWTSecret string `env:"db.password,default=SUPABASE_AUTH_JWT_SECRET"`
AnonKey string `env:"auth.anon_key,default=SUPABASE_AUTH_ANON_KEY"`
ServiceRoleKey string `env:"auth.service_role_key,default=SUPABASE_AUTH_SERVICE_ROLE_KEY"`
}
func Run(ctx context.Context, projectRef, format string, names CustomName, fsys afero.Fs) error {
branch := GetGitBranch(fsys)
if err := GenerateSecrets(ctx, projectRef, branch, fsys); err != nil {
return err
}
return utils.EncodeOutput(format, os.Stdout, map[string]string{
names.DbHost: fmt.Sprintf("%s-%s.fly.dev", projectRef, branch),
names.DbPassword: utils.Config.Db.Password,
names.JWTSecret: utils.Config.Auth.JwtSecret,
names.AnonKey: utils.Config.Auth.AnonKey,
names.ServiceRoleKey: utils.Config.Auth.ServiceRoleKey,
})
}
func GenerateSecrets(ctx context.Context, projectRef, branch string, fsys afero.Fs) error {
// Load JWT secret from api
resp, err := utils.GetSupabase().V1GetPostgrestServiceConfigWithResponse(ctx, projectRef)
if err != nil {
return errors.Errorf("failed to get postgrest config: %w", err)
}
if resp.JSON200 == nil {
return errors.New("Unexpected error retrieving JWT secret: " + string(resp.Body))
}
utils.Config.Auth.JwtSecret = *resp.JSON200.JwtSecret
// Generate database password
key := strings.Join([]string{
projectRef,
utils.Config.Auth.JwtSecret,
branch,
}, ":")
hash := sha256.Sum256([]byte(key))
utils.Config.Db.Password = hex.EncodeToString(hash[:])
// Generate JWT tokens
anonToken := config.CustomClaims{
Issuer: "supabase",
Ref: projectRef,
Role: "anon",
}.NewToken()
if utils.Config.Auth.AnonKey, err = anonToken.SignedString([]byte(utils.Config.Auth.JwtSecret)); err != nil {
return errors.Errorf("failed to sign anon key: %w", err)
}
serviceToken := config.CustomClaims{
Issuer: "supabase",
Ref: projectRef,
Role: "service_role",
}.NewToken()
if utils.Config.Auth.ServiceRoleKey, err = serviceToken.SignedString([]byte(utils.Config.Auth.JwtSecret)); err != nil {
return errors.Errorf("failed to sign service_role key: %w", err)
}
return nil
}
func GetGitBranch(fsys afero.Fs) string {
return GetGitBranchOrDefault("main", fsys)
}
func GetGitBranchOrDefault(def string, fsys afero.Fs) string {
head := os.Getenv("GITHUB_HEAD_REF")
if len(head) > 0 {
return head
}
opts := &git.PlainOpenOptions{DetectDotGit: true}
if repo, err := git.PlainOpenWithOptions(".", opts); err == nil {
if ref, err := repo.Head(); err == nil {
return ref.Name().Short()
}
}
return def
}