From 6b24adaf8348d637d73f85f62c3e10a7d954f436 Mon Sep 17 00:00:00 2001 From: Lauris BH Date: Tue, 5 Jan 2021 17:46:37 +0200 Subject: [PATCH 01/42] Add simple master key provider for secret encryption --- cmd/generate.go | 51 +++++++++++++++++++++++++ modules/generate/generate.go | 21 ++++++++++ modules/setting/setting.go | 16 ++++++++ modules/web/middleware/binding.go | 7 ++++ options/locale/locale_en-US.ini | 8 ++++ routers/install/install.go | 34 +++++++++++++++++ services/forms/user_form.go | 2 + services/secrets/masterkey.go | 27 +++++++++++++ services/secrets/masterkey_nop.go | 43 +++++++++++++++++++++ services/secrets/masterkey_plain.go | 59 +++++++++++++++++++++++++++++ services/secrets/secrets.go | 42 ++++++++++++++++++++ templates/install.tmpl | 16 ++++++++ 12 files changed, 326 insertions(+) create mode 100644 services/secrets/masterkey.go create mode 100644 services/secrets/masterkey_nop.go create mode 100644 services/secrets/masterkey_plain.go create mode 100644 services/secrets/secrets.go diff --git a/cmd/generate.go b/cmd/generate.go index 35c77a815b1d..aaf1fe7020d2 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -6,10 +6,14 @@ package cmd import ( + "encoding/base64" "fmt" "os" "code.gitea.io/gitea/modules/generate" + "code.gitea.io/gitea/modules/log" + "code.gitea.io/gitea/modules/setting" + "code.gitea.io/gitea/services/secrets" "github.com/mattn/go-isatty" "github.com/urfave/cli" @@ -32,6 +36,7 @@ var ( microcmdGenerateInternalToken, microcmdGenerateLfsJwtSecret, microcmdGenerateSecretKey, + microcmdGenerateMasterKey, }, } @@ -53,6 +58,12 @@ var ( Usage: "Generate a new SECRET_KEY", Action: runGenerateSecretKey, } + + microcmdGenerateMasterKey = cli.Command{ + Name: "MASTER_KEY", + Usage: "Generate a new MASTER_KEY", + Action: runGenerateMasterKey, + } ) func runGenerateInternalToken(c *cli.Context) error { @@ -99,3 +110,43 @@ func runGenerateSecretKey(c *cli.Context) error { return nil } + +func runGenerateMasterKey(c *cli.Context) error { + // Silence the console logger + log.DelNamedLogger("console") + log.DelNamedLogger(log.DEFAULT) + + // Read configuration file + setting.LoadFromExisting() + + providerType := secrets.MasterKeyProviderType(setting.MasterKeyProvider) + if providerType == secrets.MasterKeyProviderTypeNone { + return fmt.Errorf("configured master key provider does not support key generation") + } + + if err := secrets.Init(); err != nil { + return err + } + + scrts, err := secrets.GenerateMasterKey() + if err != nil { + return err + } + + if len(scrts) > 1 { + fmt.Println("Unseal secrets:") + for i, secret := range scrts { + if i > 0 { + fmt.Printf("\n") + } + fmt.Printf("%s\n", base64.StdEncoding.EncodeToString(secret)) + } + } + fmt.Println("Setting changes required:") + fmt.Println("[secrets]") + if providerType == secrets.MasterKeyProviderTypePlain && len(scrts) == 1 { + fmt.Printf("MASTER_KEY = %s\n", base64.StdEncoding.EncodeToString(scrts[0])) + } + + return nil +} diff --git a/modules/generate/generate.go b/modules/generate/generate.go index 326fe8036b44..c28b99d55216 100644 --- a/modules/generate/generate.go +++ b/modules/generate/generate.go @@ -9,6 +9,7 @@ import ( "crypto/rand" "encoding/base64" "io" + "math/big" "time" "code.gitea.io/gitea/modules/util" @@ -67,3 +68,23 @@ func NewSecretKey() (string, error) { return secretKey, nil } + +// NewMasterKey generate a new value intended to be used by MASTER_KEY. +func NewMasterKey() ([]byte, error) { + secretBytes := make([]byte, 32) + _, err := io.ReadFull(rand.Reader, secretBytes) + if err != nil { + return nil, err + } + + return secretBytes, nil +} + +func randomInt(max *big.Int) (int, error) { + rand, err := rand.Int(rand.Reader, max) + if err != nil { + return 0, err + } + + return int(rand.Int64()), nil +} diff --git a/modules/setting/setting.go b/modules/setting/setting.go index 6233437bf5aa..645a66fd8b3b 100644 --- a/modules/setting/setting.go +++ b/modules/setting/setting.go @@ -213,6 +213,8 @@ var ( HMACKey string `ini:"HMAC_KEY"` Allways bool }{} + MasterKeyProvider string + MasterKey []byte // UI settings UI = struct { @@ -953,6 +955,20 @@ func loadFromConf(allowEmpty bool, extraConfig string) { PasswordCheckPwn = sec.Key("PASSWORD_CHECK_PWN").MustBool(false) SuccessfulTokensCacheSize = sec.Key("SUCCESSFUL_TOKENS_CACHE_SIZE").MustInt(20) + // Master key provider configuration + MasterKeyProvider = sec.Key("MASTER_KEY_PROVIDER").MustString("none") + switch MasterKeyProvider { + case "plain": + if MasterKey, err = base64.StdEncoding.DecodeString(sec.Key("MASTER_KEY").MustString("")); err != nil { + log.Fatal("error loading master key: %v", err) + return + } + case "none": + default: + log.Fatal("invalid master key provider type: %v", MasterKeyProvider) + return + } + InternalToken = loadSecret(sec, "INTERNAL_TOKEN_URI", "INTERNAL_TOKEN") cfgdata := sec.Key("PASSWORD_COMPLEXITY").Strings(",") diff --git a/modules/web/middleware/binding.go b/modules/web/middleware/binding.go index 636e655b9e95..d87b26b793df 100644 --- a/modules/web/middleware/binding.go +++ b/modules/web/middleware/binding.go @@ -79,6 +79,11 @@ func GetInclude(field reflect.StructField) string { return getRuleBody(field, "Include(") } +// GetIn get allowed values in form tag +func GetIn(field reflect.StructField) string { + return getRuleBody(field, "In(") +} + // Validate validate TODO: func Validate(errs binding.Errors, data map[string]interface{}, f Form, l translation.Locale) binding.Errors { if errs.Len() == 0 { @@ -131,6 +136,8 @@ func Validate(errs binding.Errors, data map[string]interface{}, f Form, l transl data["ErrorMsg"] = trName + l.Tr("form.url_error", errs[0].Message) case binding.ERR_INCLUDE: data["ErrorMsg"] = trName + l.Tr("form.include_error", GetInclude(field)) + case binding.ERR_IN: + data["ErrorMsg"] = trName + l.Tr("form.in_error", strings.Join(strings.Split(GetIn(field), ","), ", ")) case validation.ErrGlobPattern: data["ErrorMsg"] = trName + l.Tr("form.glob_pattern_error", errs[0].Message) case validation.ErrRegexPattern: diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 1dba1d71d8ff..38f27e70065f 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -176,6 +176,12 @@ app_url_helper = Base address for HTTP(S) clone URLs and email notifications. log_root_path = Log Path log_root_path_helper = Log files will be written to this directory. +security_title = Security Settings +master_key_provider = Master Key Provider +master_key_provider_none = None +master_key_provider_plain = Plain +master_key_provider_helper = Master Key Provider to use to store secret key that will be used for other secret encryption. Use "None" to not encrypt secrets. Use "Plain" to store automatically generated secret in configuration file. + optional_title = Optional Settings email_title = Email Settings smtp_addr = SMTP Host @@ -234,6 +240,7 @@ no_reply_address = Hidden Email Domain no_reply_address_helper = Domain name for users with a hidden email address. For example, the username 'joe' will be logged in Git as 'joe@noreply.example.org' if the hidden email domain is set to 'noreply.example.org'. password_algorithm = Password Hash Algorithm password_algorithm_helper = Set the password hashing algorithm. Algorithms have differing requirements and strength. `argon2` whilst having good characteristics uses a lot of memory and may be inappropriate for small systems. +master_key_failed = Failed to generate master key: %v [home] uname_holder = Username or Email Address @@ -447,6 +454,7 @@ max_size_error = ` must contain at most %s characters.` email_error = ` is not a valid email address.` url_error = `'%s' is not a valid URL.` include_error = ` must contain substring '%s'.` +in_error = ` can contain only specific values: %s.` glob_pattern_error = ` glob pattern is invalid: %s.` regex_pattern_error = ` regex pattern is invalid: %s.` unknown_error = Unknown error: diff --git a/routers/install/install.go b/routers/install/install.go index 890725b9a747..310f0a6bc666 100644 --- a/routers/install/install.go +++ b/routers/install/install.go @@ -7,6 +7,7 @@ package install import ( goctx "context" + "encoding/base64" "fmt" "net/http" "os" @@ -32,6 +33,7 @@ import ( "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/modules/web/middleware" "code.gitea.io/gitea/services/forms" + "code.gitea.io/gitea/services/secrets" "gitea.com/go-chi/session" "gopkg.in/ini.v1" @@ -160,6 +162,7 @@ func Install(ctx *context.Context) { form.DefaultEnableTimetracking = setting.Service.DefaultEnableTimetracking form.NoReplyAddress = setting.Service.NoReplyAddress form.PasswordAlgorithm = setting.PasswordHashAlgo + form.MasterKeyProvider = secrets.MasterKeyProviderTypePlain middleware.AssignForm(form, ctx.Data) ctx.HTML(http.StatusOK, tplInstall) @@ -386,10 +389,40 @@ func SubmitInstall(ctx *context.Context) { log.Error("Failed to load custom conf '%s': %v", setting.CustomConf, err) } } + + // Setup master key provider + cfg.Section("security").Key("MASTER_KEY_PROVIDER").SetValue(string(form.MasterKeyProvider)) + var provider secrets.MasterKeyProvider + switch form.MasterKeyProvider { + case secrets.MasterKeyProviderTypePlain: + provider = secrets.NewPlainMasterKeyProvider() + } + var masterKey []byte + if provider != nil { + if err = provider.Init(); err != nil { + ctx.RenderWithErr(ctx.Tr("install.master_key_failed", err), tplInstall, &form) + return + } + // Generate master key + if _, err = provider.GenerateMasterKey(); err != nil { + ctx.RenderWithErr(ctx.Tr("install.master_key_failed", err), tplInstall, &form) + return + } + masterKey, err = provider.GetMasterKey() + if err != nil { + ctx.RenderWithErr(ctx.Tr("install.master_key_failed", err), tplInstall, &form) + return + } + if form.MasterKeyProvider == secrets.MasterKeyProviderTypePlain { + cfg.Section("security").Key("MASTER_KEY").SetValue(base64.StdEncoding.EncodeToString(masterKey)) + } + } + cfg.Section("database").Key("DB_TYPE").SetValue(setting.Database.Type) cfg.Section("database").Key("HOST").SetValue(setting.Database.Host) cfg.Section("database").Key("NAME").SetValue(setting.Database.Name) cfg.Section("database").Key("USER").SetValue(setting.Database.User) + // TODO: Encrypt secret cfg.Section("database").Key("PASSWD").SetValue(setting.Database.Passwd) cfg.Section("database").Key("SCHEMA").SetValue(setting.Database.Schema) cfg.Section("database").Key("SSL_MODE").SetValue(setting.Database.SSLMode) @@ -431,6 +464,7 @@ func SubmitInstall(ctx *context.Context) { cfg.Section("mailer").Key("SMTP_PORT").SetValue(form.SMTPPort) cfg.Section("mailer").Key("FROM").SetValue(form.SMTPFrom) cfg.Section("mailer").Key("USER").SetValue(form.SMTPUser) + // TODO: Encrypt secret cfg.Section("mailer").Key("PASSWD").SetValue(form.SMTPPasswd) } else { cfg.Section("mailer").Key("ENABLED").SetValue("false") diff --git a/services/forms/user_form.go b/services/forms/user_form.go index 8ce1d85c5778..27d68c50b5c9 100644 --- a/services/forms/user_form.go +++ b/services/forms/user_form.go @@ -14,6 +14,7 @@ import ( "code.gitea.io/gitea/modules/setting" "code.gitea.io/gitea/modules/structs" "code.gitea.io/gitea/modules/web/middleware" + "code.gitea.io/gitea/services/secrets" "gitea.com/go-chi/binding" ) @@ -63,6 +64,7 @@ type InstallForm struct { NoReplyAddress string PasswordAlgorithm string + MasterKeyProvider secrets.MasterKeyProviderType `binding:"Required;In(none,plain)"` AdminName string `binding:"OmitEmpty;AlphaDashDot;MaxSize(30)" locale:"install.admin_name"` AdminPasswd string `binding:"OmitEmpty;MaxSize(255)" locale:"install.admin_password"` diff --git a/services/secrets/masterkey.go b/services/secrets/masterkey.go new file mode 100644 index 000000000000..c69a75b78ab9 --- /dev/null +++ b/services/secrets/masterkey.go @@ -0,0 +1,27 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package secrets + +import ( + "fmt" +) + +// ErrMasterKeySealed is returned when trying to use master key that is sealed +var ErrMasterKeySealed = fmt.Errorf("master key sealed") + +// MasterKeyProvider provides master key used for encryption +type MasterKeyProvider interface { + Init() error + + GenerateMasterKey() ([][]byte, error) + + Unseal(secret []byte) error + + Seal() error + + IsSealed() bool + + GetMasterKey() ([]byte, error) +} diff --git a/services/secrets/masterkey_nop.go b/services/secrets/masterkey_nop.go new file mode 100644 index 000000000000..83d85ab2769c --- /dev/null +++ b/services/secrets/masterkey_nop.go @@ -0,0 +1,43 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package secrets + +type nopMasterKeyProvider struct { +} + +// NewNopMasterKeyProvider returns master key provider that holds no master key and is always unsealed +func NewNopMasterKeyProvider() MasterKeyProvider { + return &nopMasterKeyProvider{} +} + +// Init initializes master key provider +func (k *nopMasterKeyProvider) Init() error { + return nil +} + +// GenerateMasterKey always returns empty master key +func (k *nopMasterKeyProvider) GenerateMasterKey() ([][]byte, error) { + return nil, nil +} + +// Unseal master key by providing unsealing secret +func (k *nopMasterKeyProvider) Unseal(secret []byte) error { + return nil +} + +// Seal master key +func (k *nopMasterKeyProvider) Seal() error { + return nil +} + +// IsSealed always returns false +func (k *nopMasterKeyProvider) IsSealed() bool { + return false +} + +// GetMasterKey returns empty master key +func (k *nopMasterKeyProvider) GetMasterKey() ([]byte, error) { + return nil, nil +} diff --git a/services/secrets/masterkey_plain.go b/services/secrets/masterkey_plain.go new file mode 100644 index 000000000000..6a457c745acf --- /dev/null +++ b/services/secrets/masterkey_plain.go @@ -0,0 +1,59 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package secrets + +import ( + "code.gitea.io/gitea/modules/generate" + "code.gitea.io/gitea/modules/setting" +) + +type plainMasterKeyProvider struct { + key []byte +} + +// NewPlainMasterKeyProvider returns unsecured static master key provider +func NewPlainMasterKeyProvider() MasterKeyProvider { + return &plainMasterKeyProvider{} +} + +// Init initializes master key provider +func (k *plainMasterKeyProvider) Init() error { + return k.Unseal(nil) +} + +// GenerateMasterKey generates a new master key and returns secret or secrets for unsealing +func (k *plainMasterKeyProvider) GenerateMasterKey() ([][]byte, error) { + key, err := generate.NewMasterKey() + if err != nil { + return nil, err + } + k.key = key + return [][]byte{key}, nil +} + +// Unseal master key by providing unsealing secret +func (k *plainMasterKeyProvider) Unseal(secret []byte) error { + k.key = setting.MasterKey + return nil +} + +// Seal master key +func (k *plainMasterKeyProvider) Seal() error { + k.key = nil + return nil +} + +// IsSealed returns if master key is sealed +func (k *plainMasterKeyProvider) IsSealed() bool { + return len(k.key) == 0 +} + +// GetMasterKey returns master key +func (k *plainMasterKeyProvider) GetMasterKey() ([]byte, error) { + if k.IsSealed() { + return nil, ErrMasterKeySealed + } + return k.key, nil +} diff --git a/services/secrets/secrets.go b/services/secrets/secrets.go new file mode 100644 index 000000000000..accaabea2ca1 --- /dev/null +++ b/services/secrets/secrets.go @@ -0,0 +1,42 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package secrets + +import ( + "fmt" + + "code.gitea.io/gitea/modules/setting" +) + +// MasterKeyProviderType is the type of master key provider +type MasterKeyProviderType string + +// Types of master key providers +const ( + MasterKeyProviderTypeNone MasterKeyProviderType = "none" + MasterKeyProviderTypePlain MasterKeyProviderType = "plain" +) + +var ( + masterKey MasterKeyProvider +) + +// Init initializes master key provider based on settings +func Init() error { + switch MasterKeyProviderType(setting.MasterKeyProvider) { + case MasterKeyProviderTypeNone: + masterKey = NewNopMasterKeyProvider() + case MasterKeyProviderTypePlain: + masterKey = NewPlainMasterKeyProvider() + default: + return fmt.Errorf("invalid master key provider %v", setting.MasterKeyProvider) + } + return nil +} + +// GenerateMasterKey generates a new master key and returns secret or secrets for unsealing +func GenerateMasterKey() ([][]byte, error) { + return masterKey.GenerateMasterKey() +} diff --git a/templates/install.tmpl b/templates/install.tmpl index 36f58218d463..b3cfa005f88d 100644 --- a/templates/install.tmpl +++ b/templates/install.tmpl @@ -163,6 +163,22 @@ {{.locale.Tr "install.log_root_path_helper"}} + +

{{.i18n.Tr "install.security_title"}}

+ +
+ + + {{.i18n.Tr "install.master_key_provider_helper"}} +

{{.locale.Tr "install.optional_title"}}

From 47c472a265084b38db3dca4d3311f356036f3b4f Mon Sep 17 00:00:00 2001 From: Lauris BH Date: Thu, 7 Jan 2021 11:31:54 +0200 Subject: [PATCH 02/42] Add AES GCM encryption provider --- cmd/generate.go | 9 ++- services/secrets/encryption.go | 16 +++++ services/secrets/encryption_aes.go | 89 ++++++++++++++++++++++++++ services/secrets/masterkey_nop_test.go | 12 ++++ services/secrets/secrets.go | 58 ++++++++++++++++- 5 files changed, 180 insertions(+), 4 deletions(-) create mode 100644 services/secrets/encryption.go create mode 100644 services/secrets/encryption_aes.go create mode 100644 services/secrets/masterkey_nop_test.go diff --git a/cmd/generate.go b/cmd/generate.go index aaf1fe7020d2..629c948eda3e 100644 --- a/cmd/generate.go +++ b/cmd/generate.go @@ -142,10 +142,13 @@ func runGenerateMasterKey(c *cli.Context) error { fmt.Printf("%s\n", base64.StdEncoding.EncodeToString(secret)) } } - fmt.Println("Setting changes required:") - fmt.Println("[secrets]") + if providerType == secrets.MasterKeyProviderTypePlain && len(scrts) == 1 { - fmt.Printf("MASTER_KEY = %s\n", base64.StdEncoding.EncodeToString(scrts[0])) + fmt.Printf("%s", base64.StdEncoding.EncodeToString(scrts[0])) + + if isatty.IsTerminal(os.Stdout.Fd()) { + fmt.Printf("\n") + } } return nil diff --git a/services/secrets/encryption.go b/services/secrets/encryption.go new file mode 100644 index 000000000000..4cf192ee61e3 --- /dev/null +++ b/services/secrets/encryption.go @@ -0,0 +1,16 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package secrets + +// EncryptionProvider encrypts and decrypts secrets +type EncryptionProvider interface { + Encrypt(secret, key []byte) ([]byte, error) + + EncryptString(secret string, key []byte) (string, error) + + Decrypt(enc, key []byte) ([]byte, error) + + DecryptString(enc string, key []byte) (string, error) +} diff --git a/services/secrets/encryption_aes.go b/services/secrets/encryption_aes.go new file mode 100644 index 000000000000..d34636c7aa67 --- /dev/null +++ b/services/secrets/encryption_aes.go @@ -0,0 +1,89 @@ +// Copyright 2021 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package secrets + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/rand" + "encoding/base64" + "fmt" + "io" +) + +type aesEncryptionProvider struct { +} + +func NewAesEncryptionProvider() EncryptionProvider { + return &aesEncryptionProvider{} +} + +func (e *aesEncryptionProvider) Encrypt(secret, key []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + c, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + nonce := make([]byte, c.NonceSize(), c.NonceSize()+c.Overhead()+len(secret)) + if _, err = io.ReadFull(rand.Reader, nonce); err != nil { + return nil, err + } + out := c.Seal(nil, nonce, secret, nil) + + return append(nonce, out...), nil +} + +func (e *aesEncryptionProvider) EncryptString(secret string, key []byte) (string, error) { + out, err := e.Encrypt([]byte(secret), key) + if err != nil { + return "", err + } + return base64.StdEncoding.EncodeToString(out), nil +} + +func (e *aesEncryptionProvider) Decrypt(enc, key []byte) ([]byte, error) { + block, err := aes.NewCipher(key) + if err != nil { + return nil, err + } + + c, err := cipher.NewGCM(block) + if err != nil { + return nil, err + } + + if len(enc) < c.NonceSize() { + return nil, fmt.Errorf("encrypted value too short") + } + + nonce := enc[:c.NonceSize()] + ciphertext := enc[c.NonceSize():] + + out, err := c.Open(nil, nonce, ciphertext, nil) + if err != nil { + return nil, err + } + + return out, nil +} + +func (e *aesEncryptionProvider) DecryptString(enc string, key []byte) (string, error) { + encb, err := base64.StdEncoding.DecodeString(enc) + if err != nil { + return "", err + } + + out, err := e.Encrypt(encb, key) + if err != nil { + return "", err + } + + return string(out), nil +} diff --git a/services/secrets/masterkey_nop_test.go b/services/secrets/masterkey_nop_test.go new file mode 100644 index 000000000000..09e4587d4dfd --- /dev/null +++ b/services/secrets/masterkey_nop_test.go @@ -0,0 +1,12 @@ +package secrets + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestNopMasterKey_IsSealed(t *testing.T) { + k := NewNopMasterKeyProvider() + assert.False(t, k.IsSealed()) +} diff --git a/services/secrets/secrets.go b/services/secrets/secrets.go index accaabea2ca1..045985578113 100644 --- a/services/secrets/secrets.go +++ b/services/secrets/secrets.go @@ -20,7 +20,8 @@ const ( ) var ( - masterKey MasterKeyProvider + masterKey MasterKeyProvider + encProvider EncryptionProvider ) // Init initializes master key provider based on settings @@ -33,6 +34,9 @@ func Init() error { default: return fmt.Errorf("invalid master key provider %v", setting.MasterKeyProvider) } + + encProvider = NewAesEncryptionProvider() + return nil } @@ -40,3 +44,55 @@ func Init() error { func GenerateMasterKey() ([][]byte, error) { return masterKey.GenerateMasterKey() } + +func Encrypt(secret []byte) ([]byte, error) { + key, err := masterKey.GetMasterKey() + if err != nil { + return nil, err + } + + if len(key) == 0 { + return secret, nil + } + + return encProvider.Encrypt(secret, key) +} + +func EncryptString(secret string) (string, error) { + key, err := masterKey.GetMasterKey() + if err != nil { + return "", err + } + + if len(key) == 0 { + return secret, nil + } + + return encProvider.EncryptString(secret, key) +} + +func Decrypt(enc []byte) ([]byte, error) { + key, err := masterKey.GetMasterKey() + if err != nil { + return nil, err + } + + if len(key) == 0 { + return enc, nil + } + + return encProvider.Decrypt(enc, key) +} + +func DecryptString(enc string) (string, error) { + key, err := masterKey.GetMasterKey() + if err != nil { + return "", err + } + + if len(key) == 0 { + return enc, nil + } + + return encProvider.DecryptString(enc, key) +} From 64a91b45474281e78fe5201432a3a982bbed8931 Mon Sep 17 00:00:00 2001 From: Lunny Xiao Date: Fri, 7 Oct 2022 22:43:56 +0800 Subject: [PATCH 03/42] add models and services --- models/auth/secret.go | 54 ++++++++++++++++++ models/db/search.go | 17 ++++++ routers/web/repo/setting.go | 8 +++ services/secrets/secrets.go | 47 +++++++++++++++ templates/repo/settings/deploy_keys.tmpl | 2 + templates/repo/settings/tokens.tmpl | 73 ++++++++++++++++++++++++ 6 files changed, 201 insertions(+) create mode 100644 models/auth/secret.go create mode 100644 templates/repo/settings/tokens.tmpl diff --git a/models/auth/secret.go b/models/auth/secret.go new file mode 100644 index 000000000000..32b1c48e9ccb --- /dev/null +++ b/models/auth/secret.go @@ -0,0 +1,54 @@ +// Copyright 2022 The Gitea Authors. All rights reserved. +// Use of this source code is governed by a MIT-style +// license that can be found in the LICENSE file. + +package auth + +import ( + "fmt" + "regexp" + + "code.gitea.io/gitea/modules/timeutil" +) + +type ErrSecretNameInvalid struct { + Name string +} + +func (err ErrSecretNameInvalid) Error() string { + return fmt.Sprintf("secret name %s is invalid", err.Name) +} + +type ErrSecretDataInvalid struct { + Data string +} + +func (err ErrSecretDataInvalid) Error() string { + return fmt.Sprintf("secret data %s is invalid", err.Data) +} + +var nameRE = regexp.MustCompile("[^a-zA-Z0-9-_.]+") + +type Secret struct { + ID int64 + UserID int64 `xorm:"index"` + RepoID int64 `xorm:"index"` + Name string + Data string + PullRequest bool + CreatedUnix timeutil.TimeStamp +} + + // Validate validates the required fields and formats. +func (s *Secret) Validate() error { + switch { + case len(s.Name) == 0: + return ErrSecretNameInvalid{Name: s.Name} + case len(s.Data) == 0: + return ErrSecretDataInvalid{Data: s.Data} + case nameRE.MatchString(s.Name): + return ErrSecretNameInvalid{Name: s.Name} + default: + return nil + } +} diff --git a/models/db/search.go b/models/db/search.go index 704a48ed1eb4..f4bbd9d3fafa 100644 --- a/models/db/search.go +++ b/models/db/search.go @@ -4,6 +4,12 @@ package db +import ( + "context" + + "xorm.io/builder" +) + // SearchOrderBy is used to sort the result type SearchOrderBy string @@ -28,3 +34,14 @@ const ( SearchOrderByForks SearchOrderBy = "num_forks ASC" SearchOrderByForksReverse SearchOrderBy = "num_forks DESC" ) + +func FindObjects[Object any](ctx context.Context, cond builder.Cond, opts *ListOptions, objects *[]*Object) error { + sess := GetEngine(ctx).Where(cond) + if opts != nil && opts.PageSize > 0 { + if opts.Page < 1 { + opts.Page = 1 + } + sess.Limit(opts.PageSize, opts.PageSize * (opts.Page - 1)) + } + return sess.Find(objects) +} diff --git a/routers/web/repo/setting.go b/routers/web/repo/setting.go index e7abec0d3e89..db1c1ed00017 100644 --- a/routers/web/repo/setting.go +++ b/routers/web/repo/setting.go @@ -46,6 +46,7 @@ import ( org_service "code.gitea.io/gitea/services/org" repo_service "code.gitea.io/gitea/services/repository" wiki_service "code.gitea.io/gitea/services/wiki" + secret_service "code.gitea.io/gitea/services/secrets" ) const ( @@ -1104,6 +1105,13 @@ func DeployKeys(ctx *context.Context) { } ctx.Data["Deploykeys"] = keys + tokens, err := secret_service.FindRepoSecrets(ctx, ctx.Repo.Repository.ID) + if err != nil { + ctx.ServerError("FindRepoSecrets", err) + return + } + ctx.Data["Tokens"] = tokens + ctx.HTML(http.StatusOK, tplDeployKeys) } diff --git a/services/secrets/secrets.go b/services/secrets/secrets.go index 045985578113..4f113958d42f 100644 --- a/services/secrets/secrets.go +++ b/services/secrets/secrets.go @@ -5,9 +5,14 @@ package secrets import ( + "context" "fmt" + auth_model "code.gitea.io/gitea/models/auth" + "code.gitea.io/gitea/models/db" "code.gitea.io/gitea/modules/setting" + + "xorm.io/builder" ) // MasterKeyProviderType is the type of master key provider @@ -96,3 +101,45 @@ func DecryptString(enc string) (string, error) { return encProvider.DecryptString(enc, key) } + +func InsertRepoSecret(ctx context.Context, repoID int64, key, data string, pullRequest bool) error { + v, err := EncryptString( data) + if err != nil { + return err + } +return db.Insert(ctx, &auth_model.Secret{ + RepoID: repoID, + Name: key, + Data: v, + PullRequest: pullRequest, +}) +} + +func InsertOrgSecret(ctx context.Context, userID int64, key, data string, pullRequest bool) error { + v, err := EncryptString(data) + if err != nil { + return err + } +return db.Insert(ctx, &auth_model.Secret{ + UserID: userID, + Name: key, + Data: v, + PullRequest: pullRequest, +}) +} + +func DeleteSecretByID(ctx context.Context, id int64) error { +_, err := db.DeleteByBean(ctx, &auth_model.Secret{ID: id}) +return err +} + + +func FindRepoSecrets(ctx context.Context,repoID int64) ([]*auth_model.Secret, error) { + var res []*auth_model.Secret + return res, db.FindObjects(ctx, builder.Eq{"repo_id": repoID}, nil,&res) +} + +func FindUserSecrets(ctx context.Context, userID int64) ([]*auth_model.Secret, error) { + var res []*auth_model.Secret + return res, db.FindObjects(ctx, builder.Eq{"user_id": userID}, nil,&res) +} diff --git a/templates/repo/settings/deploy_keys.tmpl b/templates/repo/settings/deploy_keys.tmpl index 2f8a4c6c1e25..1d782e18c9cb 100644 --- a/templates/repo/settings/deploy_keys.tmpl +++ b/templates/repo/settings/deploy_keys.tmpl @@ -75,6 +75,8 @@ {{end}} + + {{template "settings/tokens" .}} - - {{template "settings/tokens" .}} +
+ {{template "repo/settings/secrets" .}} From acc0c124e88a1326d1d30f7f96a0f205b8f1a3ee Mon Sep 17 00:00:00 2001 From: Jason Song Date: Fri, 9 Dec 2022 18:21:16 +0800 Subject: [PATCH 25/42] fix: FindUserSecrets --- routers/web/org/setting.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/web/org/setting.go b/routers/web/org/setting.go index 0a38490e1bfd..751f04e661e1 100644 --- a/routers/web/org/setting.go +++ b/routers/web/org/setting.go @@ -259,7 +259,7 @@ func Secrets(ctx *context.Context) { secrets, err := secret_service.FindUserSecrets(ctx, ctx.Org.Organization.ID) if err != nil { - ctx.ServerError("FindRepoSecrets", err) + ctx.ServerError("FindUserSecrets", err) return } ctx.Data["Secrets"] = secrets From 3183368aa6a1d5ad0e1e2e2597b659444cfc2737 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Tue, 13 Dec 2022 16:22:28 +0800 Subject: [PATCH 26/42] Update templates/org/settings/navbar.tmpl Co-authored-by: delvh --- templates/org/settings/navbar.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/org/settings/navbar.tmpl b/templates/org/settings/navbar.tmpl index c7a81f3a4057..9ac45a855c73 100644 --- a/templates/org/settings/navbar.tmpl +++ b/templates/org/settings/navbar.tmpl @@ -12,7 +12,7 @@ {{.locale.Tr "repo.labels"}} - + {{.locale.Tr "org.settings.secrets"}} {{if .EnableOAuth2}} From e86e30ff30cf01f933623107d41a9983ccc92234 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Tue, 13 Dec 2022 16:49:37 +0800 Subject: [PATCH 27/42] Update options/locale/locale_en-US.ini Co-authored-by: delvh --- options/locale/locale_en-US.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index d71534679bcf..4d8640e6b945 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2071,7 +2071,7 @@ settings.secrets = Secrets settings.add_secret = Add Secret settings.add_secret_success = The secret '%s' has been added. settings.secret_value_content_placeholder = Input any content -settings.secret_desc = Secrets could be visited by repository events +settings.secret_desc = Secrets will be passed to certain actions and cannot be read otherwise. settings.secret_content = Value settings.secret_key = Key settings.no_secret = There are no secrets yet. From e6cee41a48aa0e0609e19e05665633cb7fa0c46d Mon Sep 17 00:00:00 2001 From: Jason Song Date: Tue, 13 Dec 2022 16:57:34 +0800 Subject: [PATCH 28/42] Update options/locale/locale_en-US.ini Co-authored-by: delvh --- options/locale/locale_en-US.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index 4d8640e6b945..105dee9cddde 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -2073,7 +2073,7 @@ settings.add_secret_success = The secret '%s' has been added. settings.secret_value_content_placeholder = Input any content settings.secret_desc = Secrets will be passed to certain actions and cannot be read otherwise. settings.secret_content = Value -settings.secret_key = Key +settings.secret_name = Name settings.no_secret = There are no secrets yet. settings.secret_deletion = Remove secret settings.secret_deletion_desc = Removing a secret will revoke its access to this repository. Continue? From 641d37adc76f54803457473975726825ab12f549 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Tue, 13 Dec 2022 16:24:04 +0800 Subject: [PATCH 29/42] fix: use web.Bind --- routers/web/web.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/web/web.go b/routers/web/web.go index 4031df8b138d..dda65fb848d9 100644 --- a/routers/web/web.go +++ b/routers/web/web.go @@ -776,7 +776,7 @@ func RegisterRoutes(m *web.Route) { m.Group("/secrets", func() { m.Get("", org.Secrets) - m.Post("", bindIgnErr(forms.AddSecretForm{}), org.SecretsPost) + m.Post("", web.Bind(forms.AddSecretForm{}), org.SecretsPost) m.Post("/delete", org.SecretsDelete) }) From 7c82f7abac347a4b1b7b35e3747ea76f86463624 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Tue, 13 Dec 2022 16:25:34 +0800 Subject: [PATCH 30/42] fix: remove PullRequestRead --- services/forms/user_form.go | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/services/forms/user_form.go b/services/forms/user_form.go index 6079dacde2c4..4d9107df84fc 100644 --- a/services/forms/user_form.go +++ b/services/forms/user_form.go @@ -350,14 +350,13 @@ func (f *AddOpenIDForm) Validate(req *http.Request, errs binding.Errors) binding // AddKeyForm form for adding SSH/GPG key type AddKeyForm struct { - Type string `binding:"OmitEmpty"` - Title string `binding:"Required;MaxSize(50)"` - Content string `binding:"Required"` - Signature string `binding:"OmitEmpty"` - KeyID string `binding:"OmitEmpty"` - Fingerprint string `binding:"OmitEmpty"` - IsWritable bool - PullRequestRead bool + Type string `binding:"OmitEmpty"` + Title string `binding:"Required;MaxSize(50)"` + Content string `binding:"Required"` + Signature string `binding:"OmitEmpty"` + KeyID string `binding:"OmitEmpty"` + Fingerprint string `binding:"OmitEmpty"` + IsWritable bool } // Validate validates the fields From f9d58d45b4144dac7da1b9f1333aeef9cb3a870f Mon Sep 17 00:00:00 2001 From: Jason Song Date: Tue, 13 Dec 2022 16:59:20 +0800 Subject: [PATCH 31/42] fix: rename to secret_name --- templates/org/settings/secrets.tmpl | 2 +- templates/repo/settings/secrets.tmpl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/templates/org/settings/secrets.tmpl b/templates/org/settings/secrets.tmpl index b60cd4b2d5c3..b4cdbc0343cf 100644 --- a/templates/org/settings/secrets.tmpl +++ b/templates/org/settings/secrets.tmpl @@ -20,7 +20,7 @@ {{.locale.Tr "repo.settings.secret_desc"}}
- +
diff --git a/templates/repo/settings/secrets.tmpl b/templates/repo/settings/secrets.tmpl index ca33f1e2b64b..f040049a876e 100644 --- a/templates/repo/settings/secrets.tmpl +++ b/templates/repo/settings/secrets.tmpl @@ -13,7 +13,7 @@ {{.locale.Tr "repo.settings.secret_desc"}}
- +
From aa10928182a18633aa05225ddab59b42e643d7de Mon Sep 17 00:00:00 2001 From: Jason Song Date: Tue, 13 Dec 2022 17:07:43 +0800 Subject: [PATCH 32/42] Update templates/org/settings/secrets.tmpl Co-authored-by: delvh --- templates/org/settings/secrets.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/org/settings/secrets.tmpl b/templates/org/settings/secrets.tmpl index b4cdbc0343cf..1756c54baf5e 100644 --- a/templates/org/settings/secrets.tmpl +++ b/templates/org/settings/secrets.tmpl @@ -13,7 +13,7 @@
-
+
{{.CsrfTokenHtml}}
From f7380694e63f6d5c52c6c3568f1f8ae5a236624a Mon Sep 17 00:00:00 2001 From: Jason Song Date: Tue, 13 Dec 2022 17:09:31 +0800 Subject: [PATCH 33/42] Update routers/web/org/setting.go Co-authored-by: delvh --- routers/web/org/setting.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/web/org/setting.go b/routers/web/org/setting.go index 751f04e661e1..011fcf8c65fb 100644 --- a/routers/web/org/setting.go +++ b/routers/web/org/setting.go @@ -271,7 +271,7 @@ func Secrets(ctx *context.Context) { func SecretsPost(ctx *context.Context) { form := web.GetForm(ctx).(*forms.AddSecretForm) if err := secret_service.InsertOrgSecret(ctx, ctx.Org.Organization.ID, form.Title, form.Content); err != nil { - ctx.ServerError("InsertRepoSecret", err) + ctx.ServerError("InsertOrgSecret", err) return } From 5103f1de55622ec6862b04034fb888ba4fcfeccb Mon Sep 17 00:00:00 2001 From: Jason Song Date: Tue, 13 Dec 2022 17:10:10 +0800 Subject: [PATCH 34/42] Update routers/web/org/setting.go Co-authored-by: delvh --- routers/web/org/setting.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routers/web/org/setting.go b/routers/web/org/setting.go index 011fcf8c65fb..6a1b8c2a9150 100644 --- a/routers/web/org/setting.go +++ b/routers/web/org/setting.go @@ -275,7 +275,7 @@ func SecretsPost(ctx *context.Context) { return } - log.Trace("Secret added: %d", ctx.Org.Organization.ID) + log.Trace("Org %d: secret added", ctx.Org.Organization.ID) ctx.Flash.Success(ctx.Tr("repo.settings.add_secret_success", form.Title)) ctx.Redirect(ctx.Org.OrgLink + "/settings/secrets") } From a23241f2e63b4b7ed4d35375f622db7c1bb42677 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Tue, 13 Dec 2022 17:14:08 +0800 Subject: [PATCH 35/42] Update services/secrets/encryption_aes.go Co-authored-by: delvh --- services/secrets/encryption_aes.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/secrets/encryption_aes.go b/services/secrets/encryption_aes.go index 790fe3f32027..d8785ecb95a1 100644 --- a/services/secrets/encryption_aes.go +++ b/services/secrets/encryption_aes.go @@ -58,7 +58,7 @@ func (e *aesEncryptionProvider) Decrypt(enc, key []byte) ([]byte, error) { } if len(enc) < c.NonceSize() { - return nil, fmt.Errorf("encrypted value too short") + return nil, fmt.Errorf("encrypted value has length %d, which is too short for expected %d", len(enc), c.NonceSize()) } nonce := enc[:c.NonceSize()] From 9f8fdaac082a95dda8a33f6de5c196ca0083b68d Mon Sep 17 00:00:00 2001 From: Jason Song Date: Tue, 13 Dec 2022 17:15:37 +0800 Subject: [PATCH 36/42] Update templates/install.tmpl Co-authored-by: delvh --- templates/install.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/install.tmpl b/templates/install.tmpl index e2fd87aadfaa..e8cbdccc659e 100644 --- a/templates/install.tmpl +++ b/templates/install.tmpl @@ -170,7 +170,7 @@ {{.locale.Tr "install.enable_update_checker_helper"}}
- +

{{.locale.Tr "install.security_title"}}

From b32bb7a38954429dbf4dcf31087fc8a7481faed4 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Tue, 13 Dec 2022 17:16:26 +0800 Subject: [PATCH 37/42] Update templates/repo/settings/secrets.tmpl Co-authored-by: delvh --- templates/repo/settings/secrets.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/repo/settings/secrets.tmpl b/templates/repo/settings/secrets.tmpl index f040049a876e..736a2aabcebd 100644 --- a/templates/repo/settings/secrets.tmpl +++ b/templates/repo/settings/secrets.tmpl @@ -6,7 +6,7 @@
-
+
{{.CsrfTokenHtml}}
From a8c192daa4152e373b3ee5345a2b69064378a20d Mon Sep 17 00:00:00 2001 From: Jason Song Date: Wed, 14 Dec 2022 15:18:38 +0800 Subject: [PATCH 38/42] fix: rename to owner --- models/auth/secret.go | 2 +- models/migrations/v1_19/v236.go | 2 +- routers/web/org/setting.go | 8 ++++---- services/secrets/secrets.go | 12 ++++++------ 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/models/auth/secret.go b/models/auth/secret.go index c7c2cbb8bcdb..74a724dc2007 100644 --- a/models/auth/secret.go +++ b/models/auth/secret.go @@ -36,7 +36,7 @@ var nameRE = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9-_.]*$") // Secret represents a secret type Secret struct { ID int64 - UserID int64 `xorm:"index NOTNULL"` + OwnerID int64 `xorm:"index NOTNULL"` RepoID int64 `xorm:"index NOTNULL"` Name string `xorm:"NOTNULL"` Data string `xorm:"LONGTEXT"` // encrypted data, or plaintext data if there's no master key diff --git a/models/migrations/v1_19/v236.go b/models/migrations/v1_19/v236.go index e2f698c57f48..7d071a12eb2c 100644 --- a/models/migrations/v1_19/v236.go +++ b/models/migrations/v1_19/v236.go @@ -12,7 +12,7 @@ import ( func CreateSecretsTable(x *xorm.Engine) error { type Secret struct { ID int64 - UserID int64 `xorm:"index NOTNULL"` + OwnerID int64 `xorm:"index NOTNULL"` RepoID int64 `xorm:"index NOTNULL"` Name string `xorm:"NOTNULL"` Data string `xorm:"LONGTEXT"` diff --git a/routers/web/org/setting.go b/routers/web/org/setting.go index 6a1b8c2a9150..7704c18ad200 100644 --- a/routers/web/org/setting.go +++ b/routers/web/org/setting.go @@ -257,9 +257,9 @@ func Secrets(ctx *context.Context) { ctx.Data["PageIsOrgSettingsSecrets"] = true ctx.Data["RequireTribute"] = true - secrets, err := secret_service.FindUserSecrets(ctx, ctx.Org.Organization.ID) + secrets, err := secret_service.FindOwnerSecrets(ctx, ctx.Org.Organization.ID) if err != nil { - ctx.ServerError("FindUserSecrets", err) + ctx.ServerError("FindOwnerSecrets", err) return } ctx.Data["Secrets"] = secrets @@ -270,8 +270,8 @@ func Secrets(ctx *context.Context) { // SecretsPost add secrets func SecretsPost(ctx *context.Context) { form := web.GetForm(ctx).(*forms.AddSecretForm) - if err := secret_service.InsertOrgSecret(ctx, ctx.Org.Organization.ID, form.Title, form.Content); err != nil { - ctx.ServerError("InsertOrgSecret", err) + if err := secret_service.InsertOwnerSecret(ctx, ctx.Org.Organization.ID, form.Title, form.Content); err != nil { + ctx.ServerError("InsertOwnerSecret", err) return } diff --git a/services/secrets/secrets.go b/services/secrets/secrets.go index 628079e696bc..224785b6b2eb 100644 --- a/services/secrets/secrets.go +++ b/services/secrets/secrets.go @@ -117,15 +117,15 @@ func InsertRepoSecret(ctx context.Context, repoID int64, key, data string) error }) } -func InsertOrgSecret(ctx context.Context, userID int64, key, data string) error { +func InsertOwnerSecret(ctx context.Context, ownerID int64, key, data string) error { v, err := EncryptString(data) if err != nil { return err } return db.Insert(ctx, &auth_model.Secret{ - UserID: userID, - Name: key, - Data: v, + OwnerID: ownerID, + Name: key, + Data: v, }) } @@ -139,7 +139,7 @@ func FindRepoSecrets(ctx context.Context, repoID int64) ([]*auth_model.Secret, e return res, db.FindObjects(ctx, builder.Eq{"repo_id": repoID}, nil, &res) } -func FindUserSecrets(ctx context.Context, userID int64) ([]*auth_model.Secret, error) { +func FindOwnerSecrets(ctx context.Context, ownerID int64) ([]*auth_model.Secret, error) { var res []*auth_model.Secret - return res, db.FindObjects(ctx, builder.Eq{"user_id": userID}, nil, &res) + return res, db.FindObjects(ctx, builder.Eq{"owner_id": ownerID}, nil, &res) } From f1ef5ae58d0bb5913b95fef814acc1f4da414054 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Wed, 14 Dec 2022 15:21:17 +0800 Subject: [PATCH 39/42] fix: remove FindObjects --- models/db/search.go | 18 ------------------ services/secrets/secrets.go | 4 ++-- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/models/db/search.go b/models/db/search.go index ebb8eef22707..f5273cb6f6bf 100644 --- a/models/db/search.go +++ b/models/db/search.go @@ -3,12 +3,6 @@ package db -import ( - "context" - - "xorm.io/builder" -) - // SearchOrderBy is used to sort the result type SearchOrderBy string @@ -33,15 +27,3 @@ const ( SearchOrderByForks SearchOrderBy = "num_forks ASC" SearchOrderByForksReverse SearchOrderBy = "num_forks DESC" ) - -// FindObjects represents a common function to find Objects from database according cond and ListOptions -func FindObjects[Object any](ctx context.Context, cond builder.Cond, opts *ListOptions, objects *[]*Object) error { - sess := GetEngine(ctx).Where(cond) - if opts != nil && opts.PageSize > 0 { - if opts.Page < 1 { - opts.Page = 1 - } - sess.Limit(opts.PageSize, opts.PageSize*(opts.Page-1)) - } - return sess.Find(objects) -} diff --git a/services/secrets/secrets.go b/services/secrets/secrets.go index 224785b6b2eb..1fb9cc140aab 100644 --- a/services/secrets/secrets.go +++ b/services/secrets/secrets.go @@ -136,10 +136,10 @@ func DeleteSecretByID(ctx context.Context, id int64) error { func FindRepoSecrets(ctx context.Context, repoID int64) ([]*auth_model.Secret, error) { var res []*auth_model.Secret - return res, db.FindObjects(ctx, builder.Eq{"repo_id": repoID}, nil, &res) + return res, db.GetEngine(ctx).Where(builder.Eq{"repo_id": repoID}).Find(&res) } func FindOwnerSecrets(ctx context.Context, ownerID int64) ([]*auth_model.Secret, error) { var res []*auth_model.Secret - return res, db.FindObjects(ctx, builder.Eq{"owner_id": ownerID}, nil, &res) + return res, db.GetEngine(ctx).Where(builder.Eq{"owner_id": ownerID}).Find(&res) } From 4a2676e457a8beff97cf17ab4666be78e7880715 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Wed, 14 Dec 2022 15:42:52 +0800 Subject: [PATCH 40/42] fix: add unique index --- models/auth/secret.go | 6 +++--- models/migrations/v1_19/v236.go | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/models/auth/secret.go b/models/auth/secret.go index 74a724dc2007..dfbe1a8a1588 100644 --- a/models/auth/secret.go +++ b/models/auth/secret.go @@ -36,9 +36,9 @@ var nameRE = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9-_.]*$") // Secret represents a secret type Secret struct { ID int64 - OwnerID int64 `xorm:"index NOTNULL"` - RepoID int64 `xorm:"index NOTNULL"` - Name string `xorm:"NOTNULL"` + OwnerID int64 `xorm:"UNIQUE(owner_repo_name) NOTNULL"` + RepoID int64 `xorm:"UNIQUE(owner_repo_name) NOTNULL"` + Name string `xorm:"UNIQUE(owner_repo_name) NOTNULL"` Data string `xorm:"LONGTEXT"` // encrypted data, or plaintext data if there's no master key CreatedUnix timeutil.TimeStamp `xorm:"created NOTNULL"` } diff --git a/models/migrations/v1_19/v236.go b/models/migrations/v1_19/v236.go index 7d071a12eb2c..330df0bc8994 100644 --- a/models/migrations/v1_19/v236.go +++ b/models/migrations/v1_19/v236.go @@ -12,9 +12,9 @@ import ( func CreateSecretsTable(x *xorm.Engine) error { type Secret struct { ID int64 - OwnerID int64 `xorm:"index NOTNULL"` - RepoID int64 `xorm:"index NOTNULL"` - Name string `xorm:"NOTNULL"` + OwnerID int64 `xorm:"UNIQUE(owner_repo_name) NOTNULL"` + RepoID int64 `xorm:"UNIQUE(owner_repo_name) NOTNULL"` + Name string `xorm:"UNIQUE(owner_repo_name) NOTNULL"` Data string `xorm:"LONGTEXT"` CreatedUnix timeutil.TimeStamp `xorm:"created NOTNULL"` } From 5aa55fe2de6b4f8d0b7cd44220c97de8c3c038d3 Mon Sep 17 00:00:00 2001 From: Jason Song Date: Wed, 14 Dec 2022 15:49:06 +0800 Subject: [PATCH 41/42] fix: delete secrets --- services/org/org.go | 5 +++++ services/repository/repository.go | 5 +++++ services/secrets/secrets.go | 10 ++++++++++ 3 files changed, 20 insertions(+) diff --git a/services/org/org.go b/services/org/org.go index e45fb305debe..06c7ced5a1ba 100644 --- a/services/org/org.go +++ b/services/org/org.go @@ -14,6 +14,7 @@ import ( user_model "code.gitea.io/gitea/models/user" "code.gitea.io/gitea/modules/storage" "code.gitea.io/gitea/modules/util" + secret_service "code.gitea.io/gitea/services/secrets" ) // DeleteOrganization completely and permanently deletes everything of organization. @@ -39,6 +40,10 @@ func DeleteOrganization(org *organization.Organization) error { return models.ErrUserOwnPackages{UID: org.ID} } + if err := secret_service.DeleteSecretsByOwnerID(ctx, org.ID); err != nil { + return err + } + if err := organization.DeleteOrganization(ctx, org); err != nil { return fmt.Errorf("DeleteOrganization: %w", err) } diff --git a/services/repository/repository.go b/services/repository/repository.go index 3c3e7e82c3f8..bf4c5fb35b2c 100644 --- a/services/repository/repository.go +++ b/services/repository/repository.go @@ -21,6 +21,7 @@ import ( repo_module "code.gitea.io/gitea/modules/repository" "code.gitea.io/gitea/modules/setting" pull_service "code.gitea.io/gitea/services/pull" + secret_service "code.gitea.io/gitea/services/secrets" ) // CreateRepository creates a repository for the user/organization. @@ -51,6 +52,10 @@ func DeleteRepository(ctx context.Context, doer *user_model.User, repo *repo_mod return err } + if err := secret_service.DeleteSecretsByRepoID(ctx, repo.ID); err != nil { + return err + } + return packages_model.UnlinkRepositoryFromAllPackages(ctx, repo.ID) } diff --git a/services/secrets/secrets.go b/services/secrets/secrets.go index 1fb9cc140aab..4d304e2aca42 100644 --- a/services/secrets/secrets.go +++ b/services/secrets/secrets.go @@ -134,6 +134,16 @@ func DeleteSecretByID(ctx context.Context, id int64) error { return err } +func DeleteSecretsByRepoID(ctx context.Context, repoID int64) error { + _, err := db.DeleteByBean(ctx, &auth_model.Secret{RepoID: repoID}) + return err +} + +func DeleteSecretsByOwnerID(ctx context.Context, ownerID int64) error { + _, err := db.DeleteByBean(ctx, &auth_model.Secret{ID: ownerID}) + return err +} + func FindRepoSecrets(ctx context.Context, repoID int64) ([]*auth_model.Secret, error) { var res []*auth_model.Secret return res, db.GetEngine(ctx).Where(builder.Eq{"repo_id": repoID}).Find(&res) From d1a729b414c8f9b01ffdec16cb69cb112c41100c Mon Sep 17 00:00:00 2001 From: Jason Song Date: Wed, 14 Dec 2022 15:59:57 +0800 Subject: [PATCH 42/42] fix: generate master key with 64 chars --- modules/generate/generate.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/generate/generate.go b/modules/generate/generate.go index 2cb92e9b74b7..2b7423b9d954 100644 --- a/modules/generate/generate.go +++ b/modules/generate/generate.go @@ -69,5 +69,5 @@ func NewSecretKey() (string, error) { // NewMasterKey generate a new value intended to be used by MASTER_KEY. func NewMasterKey() ([]byte, error) { - return util.CryptoRandomBytes(32) + return util.CryptoRandomBytes(64) }