Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions cmd/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (

"github.com/felixge/fgprof"
"github.com/urfave/cli"
ini "gopkg.in/ini.v1"
)

// PIDFile could be set from build tag
Expand Down Expand Up @@ -223,9 +222,10 @@ func setPort(port string) error {
defaultLocalURL += ":" + setting.HTTPPort + "/"

// Save LOCAL_ROOT_URL if port changed
setting.CreateOrAppendToCustomConf("server.LOCAL_ROOT_URL", func(cfg *ini.File) {
cfg.Section("server").Key("LOCAL_ROOT_URL").SetValue(defaultLocalURL)
})
setting.CfgProvider.Section("server").Key("LOCAL_ROOT_URL").SetValue(defaultLocalURL)
if err := setting.CfgProvider.Save(); err != nil {
return fmt.Errorf("Failed to save config file: %v", err)
}
}
return nil
}
Expand Down
3 changes: 1 addition & 2 deletions modules/indexer/issues/indexer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import (
_ "code.gitea.io/gitea/models"

"github.com/stretchr/testify/assert"
"gopkg.in/ini.v1"
)

func TestMain(m *testing.M) {
Expand All @@ -27,7 +26,7 @@ func TestMain(m *testing.M) {

func TestBleveSearchIssues(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
setting.CfgProvider = ini.Empty()
setting.CfgProvider = setting.NewEmptyConfigProvider()

tmpIndexerDir := t.TempDir()

Expand Down
3 changes: 1 addition & 2 deletions modules/indexer/stats/indexer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import (
_ "code.gitea.io/gitea/models"

"github.com/stretchr/testify/assert"
"gopkg.in/ini.v1"
)

func TestMain(m *testing.M) {
Expand All @@ -29,7 +28,7 @@ func TestMain(m *testing.M) {

func TestRepoStatsIndex(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
setting.CfgProvider = ini.Empty()
setting.CfgProvider = setting.NewEmptyConfigProvider()

setting.LoadQueueSettings()

Expand Down
141 changes: 137 additions & 4 deletions modules/setting/config_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,153 @@
package setting

import (
"fmt"
"os"
"path/filepath"

"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/util"

ini "gopkg.in/ini.v1"
)

type ConfigSection interface {
Name() string
MapTo(interface{}) error
HasKey(key string) bool
NewKey(name, value string) (*ini.Key, error)
Key(key string) *ini.Key
Keys() []*ini.Key
ChildSections() []*ini.Section
}

// ConfigProvider represents a config provider
type ConfigProvider interface {
Section(section string) *ini.Section
NewSection(name string) (*ini.Section, error)
GetSection(name string) (*ini.Section, error)
Section(section string) ConfigSection
NewSection(name string) (ConfigSection, error)
GetSection(name string) (ConfigSection, error)
DeleteSection(name string) error
Save() error
}

type iniFileConfigProvider struct {
*ini.File
filepath string // the ini file path
newFile bool // whether the file has not existed previously
allowEmpty bool // whether not finding configuration files is allowed (only true for the tests)
}

// NewEmptyConfigProvider create a new empty config provider
func NewEmptyConfigProvider() ConfigProvider {
cfg := ini.Empty()
cfg.NameMapper = ini.SnackCase
return &iniFileConfigProvider{
File: cfg,
newFile: true,
}
}

func newConfigProviderFromData(bs []byte) (ConfigProvider, error) {
cfg, err := ini.Load(bs)
if err != nil {
return nil, err
}
cfg.NameMapper = ini.SnackCase
return &iniFileConfigProvider{
File: cfg,
newFile: true,
}, nil
}

// newConfigProviderFromFile load configuration from file.
// NOTE: do not print any log except error.
func newConfigProviderFromFile(customConf string, allowEmpty bool, extraConfig string) (*iniFileConfigProvider, error) {
cfg := ini.Empty()
newFile := true

if customConf != "" {
isFile, err := util.IsFile(customConf)
if err != nil {
return nil, fmt.Errorf("unable to check if %s is a file. Error: %v", customConf, err)
}
if isFile {
if err := cfg.Append(customConf); err != nil {
return nil, fmt.Errorf("failed to load custom conf '%s': %v", customConf, err)
}
newFile = false
}
}

if newFile && !allowEmpty {
return nil, fmt.Errorf("unable to find configuration file: %q, please ensure you are running in the correct environment or set the correct configuration file with -c", CustomConf)
}

if extraConfig != "" {
if err := cfg.Append([]byte(extraConfig)); err != nil {
return nil, fmt.Errorf("unable to append more config: %v", err)
}
}

cfg.NameMapper = ini.SnackCase
return &iniFileConfigProvider{
File: cfg,
filepath: customConf,
newFile: newFile,
allowEmpty: allowEmpty,
}, nil
}

func (p *iniFileConfigProvider) Section(section string) ConfigSection {
return p.File.Section(section)
}

func (p *iniFileConfigProvider) NewSection(name string) (ConfigSection, error) {
return p.File.NewSection(name)
}

func (p *iniFileConfigProvider) GetSection(name string) (ConfigSection, error) {
return p.File.GetSection(name)
}

func (p *iniFileConfigProvider) DeleteSection(name string) error {
p.File.DeleteSection(name)
return nil
}

// Save save the content into file
func (p *iniFileConfigProvider) Save() error {
if p.filepath == "" {
if !p.allowEmpty {
return fmt.Errorf("custom config path must not be empty")
}
return nil
}

if p.newFile {
if err := os.MkdirAll(filepath.Dir(CustomConf), os.ModePerm); err != nil {
return fmt.Errorf("failed to create '%s': %v", CustomConf, err)
}
}
if err := p.SaveTo(p.filepath); err != nil {
return fmt.Errorf("failed to save '%s': %v", p.filepath, err)
}

// Change permissions to be more restrictive
fi, err := os.Stat(CustomConf)
if err != nil {
return fmt.Errorf("failed to determine current conf file permissions: %v", err)
}

if fi.Mode().Perm() > 0o600 {
if err = os.Chmod(CustomConf, 0o600); err != nil {
log.Warn("Failed changing conf file permissions to -rw-------. Consider changing them manually.")
}
}
return nil
}

// a file is an implementation ConfigProvider and other implementations are possible, i.e. from docker, k8s, …
var _ ConfigProvider = &ini.File{}
var _ ConfigProvider = &iniFileConfigProvider{}

func mustMapSetting(rootCfg ConfigProvider, sectionName string, setting interface{}) {
if err := rootCfg.Section(sectionName).MapTo(setting); err != nil {
Expand Down
3 changes: 1 addition & 2 deletions modules/setting/cron_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"testing"

"github.com/stretchr/testify/assert"
ini "gopkg.in/ini.v1"
)

func Test_getCronSettings(t *testing.T) {
Expand All @@ -27,7 +26,7 @@ Base = true
Second = white rabbit
Extend = true
`
cfg, err := ini.Load([]byte(iniStr))
cfg, err := newConfigProviderFromData([]byte(iniStr))
assert.NoError(t, err)

extended := &Extended{
Expand Down
13 changes: 6 additions & 7 deletions modules/setting/lfs.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import (

"code.gitea.io/gitea/modules/generate"
"code.gitea.io/gitea/modules/log"

ini "gopkg.in/ini.v1"
)

// LFS represents the configuration for Git LFS
Expand Down Expand Up @@ -38,8 +36,7 @@ func loadLFSFrom(rootCfg ConfigProvider) {
// DEPRECATED should not be removed because users maybe upgrade from lower version to the latest version
// if these are removed, the warning will not be shown
deprecatedSetting(rootCfg, "server", "LFS_CONTENT_PATH", "lfs", "PATH", "v1.19.0")
lfsSec.Key("PATH").MustString(
sec.Key("LFS_CONTENT_PATH").String())
lfsSec.Key("PATH").MustString(sec.Key("LFS_CONTENT_PATH").String())

LFS.Storage = getStorage(rootCfg, "lfs", storageType, lfsSec)

Expand All @@ -62,9 +59,11 @@ func loadLFSFrom(rootCfg ConfigProvider) {
}

// Save secret
CreateOrAppendToCustomConf("server.LFS_JWT_SECRET", func(cfg *ini.File) {
cfg.Section("server").Key("LFS_JWT_SECRET").SetValue(LFS.JWTSecretBase64)
})
sec.Key("LFS_JWT_SECRET").SetValue(LFS.JWTSecretBase64)
if err := rootCfg.Save(); err != nil {
log.Fatal("Error saving JWT Secret for custom config: %v", err)
return
}
}
}
}
8 changes: 3 additions & 5 deletions modules/setting/log.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ import (
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/util"

ini "gopkg.in/ini.v1"
)

var (
Expand Down Expand Up @@ -131,12 +129,12 @@ type LogDescription struct {
SubLogDescriptions []SubLogDescription
}

func getLogLevel(section *ini.Section, key string, defaultValue log.Level) log.Level {
func getLogLevel(section ConfigSection, key string, defaultValue log.Level) log.Level {
value := section.Key(key).MustString(defaultValue.String())
return log.FromString(value)
}

func getStacktraceLogLevel(section *ini.Section, key, defaultValue string) string {
func getStacktraceLogLevel(section ConfigSection, key, defaultValue string) string {
value := section.Key(key).MustString(defaultValue)
return log.FromString(value).String()
}
Expand Down Expand Up @@ -165,7 +163,7 @@ func loadLogFrom(rootCfg ConfigProvider) {
Log.EnableXORMLog = rootCfg.Section("log").Key("ENABLE_XORM_LOG").MustBool(true)
}

func generateLogConfig(sec *ini.Section, name string, defaults defaultLogOptions) (mode, jsonConfig, levelName string) {
func generateLogConfig(sec ConfigSection, name string, defaults defaultLogOptions) (mode, jsonConfig, levelName string) {
level := getLogLevel(sec, "LEVEL", Log.Level)
levelName = level.String()
stacktraceLevelName := getStacktraceLogLevel(sec, "STACKTRACE_LEVEL", Log.StacktraceLogLevel)
Expand Down
3 changes: 1 addition & 2 deletions modules/setting/mailer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@ import (
"testing"

"github.com/stretchr/testify/assert"
ini "gopkg.in/ini.v1"
)

func Test_loadMailerFrom(t *testing.T) {
iniFile := ini.Empty()
iniFile := NewEmptyConfigProvider()
kases := map[string]*Mailer{
"smtp.mydomain.com": {
SMTPAddr: "smtp.mydomain.com",
Expand Down
8 changes: 3 additions & 5 deletions modules/setting/markup.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import (
"strings"

"code.gitea.io/gitea/modules/log"

"gopkg.in/ini.v1"
)

// ExternalMarkupRenderers represents the external markup renderers
Expand Down Expand Up @@ -82,7 +80,7 @@ func loadMarkupFrom(rootCfg ConfigProvider) {
}
}

func newMarkupSanitizer(name string, sec *ini.Section) {
func newMarkupSanitizer(name string, sec ConfigSection) {
rule, ok := createMarkupSanitizerRule(name, sec)
if ok {
if strings.HasPrefix(name, "sanitizer.") {
Expand All @@ -99,7 +97,7 @@ func newMarkupSanitizer(name string, sec *ini.Section) {
}
}

func createMarkupSanitizerRule(name string, sec *ini.Section) (MarkupSanitizerRule, bool) {
func createMarkupSanitizerRule(name string, sec ConfigSection) (MarkupSanitizerRule, bool) {
var rule MarkupSanitizerRule

ok := false
Expand Down Expand Up @@ -141,7 +139,7 @@ func createMarkupSanitizerRule(name string, sec *ini.Section) (MarkupSanitizerRu
return rule, true
}

func newMarkupRenderer(name string, sec *ini.Section) {
func newMarkupRenderer(name string, sec ConfigSection) {
extensionReg := regexp.MustCompile(`\.\w`)

extensions := sec.Key("FILE_EXTENSIONS").Strings(",")
Expand Down
21 changes: 18 additions & 3 deletions modules/setting/oauth2.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
package setting

import (
"encoding/base64"
"math"
"path/filepath"

"code.gitea.io/gitea/modules/generate"
"code.gitea.io/gitea/modules/log"

"gopkg.in/ini.v1"
)

// OAuth2UsernameType is enum describing the way gitea 'name' should be generated from oauth2 data
Expand Down Expand Up @@ -80,7 +80,7 @@ func loadOAuth2ClientFrom(rootCfg ConfigProvider) {
}
}

func parseScopes(sec *ini.Section, name string) []string {
func parseScopes(sec ConfigSection, name string) []string {
parts := sec.Key(name).Strings(" ")
scopes := make([]string, 0, len(parts))
for _, scope := range parts {
Expand Down Expand Up @@ -119,4 +119,19 @@ func loadOAuth2From(rootCfg ConfigProvider) {
if !filepath.IsAbs(OAuth2.JWTSigningPrivateKeyFile) {
OAuth2.JWTSigningPrivateKeyFile = filepath.Join(AppDataPath, OAuth2.JWTSigningPrivateKeyFile)
}

key := make([]byte, 32)
n, err := base64.RawURLEncoding.Decode(key, []byte(OAuth2.JWTSecretBase64))
if err != nil || n != 32 {
key, err = generate.NewJwtSecret()
if err != nil {
log.Fatal("error generating JWT secret: %v", err)
}

secretBase64 := base64.RawURLEncoding.EncodeToString(key)
rootCfg.Section("oauth2").Key("JWT_SECRET").SetValue(secretBase64)
if err := rootCfg.Save(); err != nil {
log.Fatal("save oauth2.JWT_SECRET failed: %v", err)
}
}
}
Loading