Browse Source

conf: overhaul security settings

ᴜɴᴋɴᴡᴏɴ 4 years ago
parent
commit
286fbc07e9

+ 21 - 15
conf/app.ini

@@ -146,6 +146,27 @@ SSL_MODE = disable
 ; For "sqlite3" only, make sure to use absolute path.
 PATH = data/gogs.db
 
+[security]
+; Whether to show the install page, set this to "true" to bypass it.
+INSTALL_LOCK = false
+; The secret to encrypt cookie values, 2FA code, etc.
+; !!CHANGE THIS TO KEEP YOUR USER DATA SAFE!!
+SECRET_KEY = !#@FDEWREWR&*(
+; The days remembered for auto-login.
+LOGIN_REMEMBER_DAYS = 7
+; The cookie name to stoed auto-login information.
+COOKIE_REMEMBER_NAME = gogs_incredible
+; The cookie name to stored logged in username.
+COOKIE_USERNAME = gogs_awesome
+; Whether to set secure cookie.
+COOKIE_SECURE = false
+; The HTTP header for reverse proxy authentication via username.
+REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER
+; Whether to set cookie to indicate user login status.
+ENABLE_LOGIN_STATUS_COOKIE = false
+; The cookie name to store user login status.
+LOGIN_STATUS_COOKIE_NAME = login_status
+
 ; Attachment settings for releases
 [release.attachment]
 ; Whether attachments are enabled. Defaults to `true`
@@ -184,21 +205,6 @@ ACCESS_CONTROL_ALLOW_ORIGIN =
 ; Disable regular (non-admin) users to create organizations
 DISABLE_REGULAR_ORG_CREATION = false
 
-[security]
-INSTALL_LOCK = false
-; !!CHANGE THIS TO KEEP YOUR USER DATA SAFE!!
-SECRET_KEY = !#@FDEWREWR&*(
-; Auto-login remember days
-LOGIN_REMEMBER_DAYS = 7
-COOKIE_USERNAME = gogs_awesome
-COOKIE_REMEMBER_NAME = gogs_incredible
-COOKIE_SECURE = false
-; Reverse proxy authentication header name of user name
-REVERSE_PROXY_AUTHENTICATION_USER = X-WEBAUTH-USER
-; Enable to set cookie to indicate user login status
-ENABLE_LOGIN_STATUS_COOKIE = false
-LOGIN_STATUS_COOKIE_NAME = login_status
-
 [service]
 ACTIVE_CODE_LIVE_MINUTES = 180
 RESET_PASSWD_CODE_LIVE_MINUTES = 180

+ 9 - 1
conf/locale/locale_en-US.ini

@@ -1226,8 +1226,16 @@ config.db.ssl_mode_helper = (for "postgres" only)
 config.db.path = Path
 config.db.path_helper = (for "sqlite3"only)
 
+config.security_config = Security configuration
+config.security.login_remember_days = Login remember days
+config.security.cookie_remember_name = Remember cookie
+config.security.cookie_username = Username cookie
+config.security.cookie_secure = Enable secure cookie
+config.security.reverse_proxy_auth_user = Reverse proxy authentication header
+config.security.enable_login_status_cookie = Enable login status cookie
+config.security.login_status_cookie_name = Login status cookie
+
 config.log_file_root_path = Log File Root Path
-config.reverse_auth_user = Reverse Authentication User
 
 config.http_config = HTTP Configuration
 config.http_access_control_allow_origin = Access Control Allow Origin

File diff suppressed because it is too large
+ 2 - 2
internal/assets/conf/conf_gen.go


File diff suppressed because it is too large
+ 1 - 1
internal/assets/templates/templates_gen.go


+ 2 - 2
internal/auth/auth.go

@@ -13,9 +13,9 @@ import (
 	"gopkg.in/macaron.v1"
 	log "unknwon.dev/clog/v2"
 
+	"gogs.io/gogs/internal/conf"
 	"gogs.io/gogs/internal/db"
 	"gogs.io/gogs/internal/db/errors"
-	"gogs.io/gogs/internal/conf"
 	"gogs.io/gogs/internal/tool"
 )
 
@@ -91,7 +91,7 @@ func SignedInUser(ctx *macaron.Context, sess session.Store) (_ *db.User, isBasic
 
 	if uid <= 0 {
 		if conf.Service.EnableReverseProxyAuth {
-			webAuthUser := ctx.Req.Header.Get(conf.ReverseProxyAuthUser)
+			webAuthUser := ctx.Req.Header.Get(conf.Security.ReverseProxyAuthenticationUser)
 			if len(webAuthUser) > 0 {
 				u, err := db.GetUserByName(webAuthUser)
 				if err != nil {

+ 1 - 1
internal/cmd/web.go

@@ -143,7 +143,7 @@ func newMacaron() *macaron.Macaron {
 	}))
 	m.Use(session.Sessioner(conf.SessionConfig))
 	m.Use(csrf.Csrfer(csrf.Options{
-		Secret:     conf.SecretKey,
+		Secret:     conf.Security.SecretKey,
 		Cookie:     conf.CSRFCookieName,
 		SetCookie:  true,
 		Header:     "X-Csrf-Token",

+ 17 - 44
internal/conf/conf.go

@@ -5,6 +5,7 @@
 package conf
 
 import (
+	"fmt"
 	"net/mail"
 	"net/url"
 	"os"
@@ -27,7 +28,6 @@ import (
 
 	"gogs.io/gogs/internal/assets/conf"
 	"gogs.io/gogs/internal/osutil"
-	"gogs.io/gogs/internal/user"
 )
 
 func init() {
@@ -192,30 +192,27 @@ func Init(customConf string) error {
 	}
 	Database.Path = ensureAbs(Database.Path)
 
-	handleDeprecated()
+	// *******************************
+	// ----- Security settings -----
+	// *******************************
 
-	// TODO
+	if err = File.Section("security").MapTo(&Security); err != nil {
+		return errors.Wrap(err, "mapping [security] section")
+	}
 
-	sec := File.Section("security")
-	InstallLock = sec.Key("INSTALL_LOCK").MustBool()
-	SecretKey = sec.Key("SECRET_KEY").String()
-	LoginRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt()
-	CookieUserName = sec.Key("COOKIE_USERNAME").String()
-	CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").String()
-	CookieSecure = sec.Key("COOKIE_SECURE").MustBool(false)
-	ReverseProxyAuthUser = sec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER")
-	EnableLoginStatusCookie = sec.Key("ENABLE_LOGIN_STATUS_COOKIE").MustBool(false)
-	LoginStatusCookieName = sec.Key("LOGIN_STATUS_COOKIE_NAME").MustString("login_status")
-
-	// Does not check run user when the install lock is off.
-	if InstallLock {
-		currentUser, match := IsRunUserMatchCurrentUser(App.RunUser)
+	// Check run user when the install is locked.
+	if Security.InstallLock {
+		currentUser, match := CheckRunUser(App.RunUser)
 		if !match {
-			log.Fatal("The user configured to run Gogs is %q, but the current user is %q", App.RunUser, currentUser)
+			return fmt.Errorf("user configured to run Gogs is %q, but the current user is %q", App.RunUser, currentUser)
 		}
 	}
 
-	sec = File.Section("attachment")
+	handleDeprecated()
+
+	// TODO
+
+	sec := File.Section("attachment")
 	AttachmentPath = sec.Key("PATH").MustString(filepath.Join(Server.AppDataPath, "attachments"))
 	if !filepath.IsAbs(AttachmentPath) {
 		AttachmentPath = path.Join(workDir, AttachmentPath)
@@ -342,17 +339,6 @@ var (
 		AccessControlAllowOrigin string
 	}
 
-	// Security settings
-	InstallLock             bool
-	SecretKey               string
-	LoginRememberDays       int
-	CookieUserName          string
-	CookieRememberName      string
-	CookieSecure            bool
-	ReverseProxyAuthUser    string
-	EnableLoginStatusCookie bool
-	LoginStatusCookieName   string
-
 	// Database settings
 	UseSQLite3    bool
 	UseMySQL      bool
@@ -539,19 +525,6 @@ func DateLang(lang string) string {
 	return "en"
 }
 
-// IsRunUserMatchCurrentUser returns false if configured run user does not match
-// actual user that runs the app. The first return value is the actual user name.
-// This check is ignored under Windows since SSH remote login is not the main
-// method to login on Windows.
-func IsRunUserMatchCurrentUser(runUser string) (string, bool) {
-	if IsWindowsRuntime() {
-		return "", true
-	}
-
-	currentUser := user.CurrentUsername()
-	return currentUser, runUser == currentUser
-}
-
 // InitLogging initializes the logging service of the application.
 func InitLogging() {
 	LogRootPath = File.Section("log").Key("ROOT_PATH").MustString(filepath.Join(WorkDir(), "log"))
@@ -585,7 +558,7 @@ func InitLogging() {
 			return
 		}
 
-		level := levelMappings[sec.Key("LEVEL").MustString("trace")]
+		level := levelMappings[strings.ToLower(sec.Key("LEVEL").MustString("trace"))]
 		buffer := sec.Key("BUFFER_LEN").MustInt64(100)
 		c := new(config)
 		switch mode {

+ 13 - 0
internal/conf/static.go

@@ -139,6 +139,19 @@ var (
 		// Deprecated: Use Password instead, will be removed in 0.13.
 		Passwd string
 	}
+
+	// Security settings
+	Security struct {
+		InstallLock                    bool
+		SecretKey                      string
+		LoginRememberDays              int
+		CookieRememberName             string
+		CookieUsername                 string
+		CookieSecure                   bool
+		ReverseProxyAuthenticationUser string
+		EnableLoginStatusCookie        bool
+		LoginStatusCookieName          string
+	}
 )
 
 // handleDeprecated transfers deprecated values to the new ones when set.

+ 13 - 0
internal/conf/utils.go

@@ -10,6 +10,7 @@ import (
 
 	"github.com/pkg/errors"
 
+	"gogs.io/gogs/internal/osutil"
 	"gogs.io/gogs/internal/process"
 )
 
@@ -34,3 +35,15 @@ func ensureAbs(path string) string {
 	}
 	return filepath.Join(WorkDir(), path)
 }
+
+// CheckRunUser returns false if configured run user does not match actual user that
+// runs the app. The first return value is the actual user name. This check is ignored
+// under Windows since SSH remote login is not the main method to login on Windows.
+func CheckRunUser(runUser string) (string, bool) {
+	if IsWindowsRuntime() {
+		return "", true
+	}
+
+	currentUser := osutil.CurrentUsername()
+	return currentUser, runUser == currentUser
+}

+ 2 - 2
internal/context/auth.go

@@ -27,7 +27,7 @@ type ToggleOptions struct {
 func Toggle(options *ToggleOptions) macaron.Handler {
 	return func(c *Context) {
 		// Cannot view any page before installation.
-		if !conf.InstallLock {
+		if !conf.Security.InstallLock {
 			c.Redirect(conf.Server.Subpath + "/install")
 			return
 		}
@@ -80,7 +80,7 @@ func Toggle(options *ToggleOptions) macaron.Handler {
 
 		// Redirect to log in page if auto-signin info is provided and has not signed in.
 		if !options.SignOutRequired && !c.IsLogged && !auth.IsAPIPath(c.Req.URL.Path) &&
-			len(c.GetCookie(conf.CookieUserName)) > 0 {
+			len(c.GetCookie(conf.Security.CookieUsername)) > 0 {
 			c.SetCookie("redirect_to", url.QueryEscape(conf.Server.Subpath+c.Req.RequestURI), 0, conf.Server.Subpath)
 			c.Redirect(conf.Server.Subpath + "/user/login")
 			return

+ 3 - 3
internal/db/two_factor.go

@@ -15,8 +15,8 @@ import (
 	log "unknwon.dev/clog/v2"
 	"xorm.io/xorm"
 
-	"gogs.io/gogs/internal/db/errors"
 	"gogs.io/gogs/internal/conf"
+	"gogs.io/gogs/internal/db/errors"
 	"gogs.io/gogs/internal/tool"
 )
 
@@ -47,7 +47,7 @@ func (t *TwoFactor) ValidateTOTP(passcode string) (bool, error) {
 	if err != nil {
 		return false, fmt.Errorf("DecodeString: %v", err)
 	}
-	decryptSecret, err := com.AESGCMDecrypt(tool.MD5Bytes(conf.SecretKey), secret)
+	decryptSecret, err := com.AESGCMDecrypt(tool.MD5Bytes(conf.Security.SecretKey), secret)
 	if err != nil {
 		return false, fmt.Errorf("AESGCMDecrypt: %v", err)
 	}
@@ -85,7 +85,7 @@ func NewTwoFactor(userID int64, secret string) error {
 	}
 
 	// Encrypt secret
-	encryptSecret, err := com.AESGCMEncrypt(tool.MD5Bytes(conf.SecretKey), []byte(secret))
+	encryptSecret, err := com.AESGCMEncrypt(tool.MD5Bytes(conf.Security.SecretKey), []byte(secret))
 	if err != nil {
 		return fmt.Errorf("AESGCMEncrypt: %v", err)
 	}

+ 10 - 0
internal/osutil/osutil.go

@@ -16,3 +16,13 @@ func IsFile(path string) bool {
 	}
 	return !f.IsDir()
 }
+
+// CurrentUsername returns the current system user via environment variables.
+func CurrentUsername() string {
+	curUserName := os.Getenv("USER")
+	if len(curUserName) > 0 {
+		return curUserName
+	}
+
+	return os.Getenv("USERNAME")
+}

+ 1 - 1
internal/route/admin/admin.go

@@ -201,9 +201,9 @@ func Config(c *context.Context) {
 	c.Data["SSH"] = conf.SSH
 	c.Data["Repository"] = conf.Repository
 	c.Data["Database"] = conf.Database
+	c.Data["Security"] = conf.Security
 
 	c.Data["LogRootPath"] = conf.LogRootPath
-	c.Data["ReverseProxyAuthUser"] = conf.ReverseProxyAuthUser
 
 	c.Data["HTTP"] = conf.HTTP
 

+ 1 - 1
internal/route/home.go

@@ -32,7 +32,7 @@ func Home(c *context.Context) {
 	}
 
 	// Check auto-login.
-	uname := c.GetCookie(conf.CookieUserName)
+	uname := c.GetCookie(conf.Security.CookieUsername)
 	if len(uname) != 0 {
 		c.Redirect(conf.Server.Subpath + "/user/login")
 		return

+ 6 - 7
internal/route/install.go

@@ -31,7 +31,6 @@ import (
 	"gogs.io/gogs/internal/ssh"
 	"gogs.io/gogs/internal/template/highlight"
 	"gogs.io/gogs/internal/tool"
-	"gogs.io/gogs/internal/user"
 )
 
 const (
@@ -67,7 +66,7 @@ func GlobalInit(customConf string) error {
 	conf.NewServices()
 	mailer.NewContext()
 
-	if conf.InstallLock {
+	if conf.Security.InstallLock {
 		highlight.NewContext()
 		markup.NewSanitizer()
 		if err := db.NewEngine(); err != nil {
@@ -96,7 +95,7 @@ func GlobalInit(customConf string) error {
 	}
 	checkRunMode()
 
-	if !conf.InstallLock {
+	if !conf.Security.InstallLock {
 		return nil
 	}
 
@@ -116,7 +115,7 @@ func GlobalInit(customConf string) error {
 }
 
 func InstallInit(c *context.Context) {
-	if conf.InstallLock {
+	if conf.Security.InstallLock {
 		c.NotFound()
 		return
 	}
@@ -159,7 +158,7 @@ func Install(c *context.Context) {
 	// Note(unknwon): it's hard for Windows users change a running user,
 	// 	so just use current one if config says default.
 	if conf.IsWindowsRuntime() && conf.App.RunUser == "git" {
-		f.RunUser = user.CurrentUsername()
+		f.RunUser = osutil.CurrentUsername()
 	} else {
 		f.RunUser = conf.App.RunUser
 	}
@@ -265,7 +264,7 @@ func InstallPost(c *context.Context, f form.Install) {
 		return
 	}
 
-	currentUser, match := conf.IsRunUserMatchCurrentUser(f.RunUser)
+	currentUser, match := conf.CheckRunUser(f.RunUser)
 	if !match {
 		c.FormErr("RunUser")
 		c.RenderWithErr(c.Tr("install.run_user_not_match", f.RunUser, currentUser), INSTALL, &f)
@@ -406,7 +405,7 @@ func InstallPost(c *context.Context, f form.Install) {
 		}
 		if err := db.CreateUser(u); err != nil {
 			if !db.IsErrUserAlreadyExist(err) {
-				conf.InstallLock = false
+				conf.Security.InstallLock = false
 				c.FormErr("AdminName", "AdminEmail")
 				c.RenderWithErr(c.Tr("install.invalid_admin_setting", err), INSTALL, &f)
 				return

+ 14 - 14
internal/route/user/auth.go

@@ -36,7 +36,7 @@ func AutoLogin(c *context.Context) (bool, error) {
 		return false, nil
 	}
 
-	uname := c.GetCookie(conf.CookieUserName)
+	uname := c.GetCookie(conf.Security.CookieUsername)
 	if len(uname) == 0 {
 		return false, nil
 	}
@@ -45,9 +45,9 @@ func AutoLogin(c *context.Context) (bool, error) {
 	defer func() {
 		if !isSucceed {
 			log.Trace("auto-login cookie cleared: %s", uname)
-			c.SetCookie(conf.CookieUserName, "", -1, conf.Server.Subpath)
-			c.SetCookie(conf.CookieRememberName, "", -1, conf.Server.Subpath)
-			c.SetCookie(conf.LoginStatusCookieName, "", -1, conf.Server.Subpath)
+			c.SetCookie(conf.Security.CookieUsername, "", -1, conf.Server.Subpath)
+			c.SetCookie(conf.Security.CookieRememberName, "", -1, conf.Server.Subpath)
+			c.SetCookie(conf.Security.LoginStatusCookieName, "", -1, conf.Server.Subpath)
 		}
 	}()
 
@@ -59,7 +59,7 @@ func AutoLogin(c *context.Context) (bool, error) {
 		return false, nil
 	}
 
-	if val, ok := c.GetSuperSecureCookie(u.Rands+u.Passwd, conf.CookieRememberName); !ok || val != u.Name {
+	if val, ok := c.GetSuperSecureCookie(u.Rands+u.Passwd, conf.Security.CookieRememberName); !ok || val != u.Name {
 		return false, nil
 	}
 
@@ -67,8 +67,8 @@ func AutoLogin(c *context.Context) (bool, error) {
 	c.Session.Set("uid", u.ID)
 	c.Session.Set("uname", u.Name)
 	c.SetCookie(conf.CSRFCookieName, "", -1, conf.Server.Subpath)
-	if conf.EnableLoginStatusCookie {
-		c.SetCookie(conf.LoginStatusCookieName, "true", 0, conf.Server.Subpath)
+	if conf.Security.EnableLoginStatusCookie {
+		c.SetCookie(conf.Security.LoginStatusCookieName, "true", 0, conf.Server.Subpath)
 	}
 	return true, nil
 }
@@ -119,9 +119,9 @@ func Login(c *context.Context) {
 
 func afterLogin(c *context.Context, u *db.User, remember bool) {
 	if remember {
-		days := 86400 * conf.LoginRememberDays
-		c.SetCookie(conf.CookieUserName, u.Name, days, conf.Server.Subpath, "", conf.CookieSecure, true)
-		c.SetSuperSecureCookie(u.Rands+u.Passwd, conf.CookieRememberName, u.Name, days, conf.Server.Subpath, "", conf.CookieSecure, true)
+		days := 86400 * conf.Security.LoginRememberDays
+		c.SetCookie(conf.Security.CookieUsername, u.Name, days, conf.Server.Subpath, "", conf.Security.CookieSecure, true)
+		c.SetSuperSecureCookie(u.Rands+u.Passwd, conf.Security.CookieRememberName, u.Name, days, conf.Server.Subpath, "", conf.Security.CookieSecure, true)
 	}
 
 	c.Session.Set("uid", u.ID)
@@ -131,8 +131,8 @@ func afterLogin(c *context.Context, u *db.User, remember bool) {
 
 	// Clear whatever CSRF has right now, force to generate a new one
 	c.SetCookie(conf.CSRFCookieName, "", -1, conf.Server.Subpath)
-	if conf.EnableLoginStatusCookie {
-		c.SetCookie(conf.LoginStatusCookieName, "true", 0, conf.Server.Subpath)
+	if conf.Security.EnableLoginStatusCookie {
+		c.SetCookie(conf.Security.LoginStatusCookieName, "true", 0, conf.Server.Subpath)
 	}
 
 	redirectTo, _ := url.QueryUnescape(c.GetCookie("redirect_to"))
@@ -283,8 +283,8 @@ func LoginTwoFactorRecoveryCodePost(c *context.Context) {
 func SignOut(c *context.Context) {
 	c.Session.Flush()
 	c.Session.Destory(c.Context)
-	c.SetCookie(conf.CookieUserName, "", -1, conf.Server.Subpath)
-	c.SetCookie(conf.CookieRememberName, "", -1, conf.Server.Subpath)
+	c.SetCookie(conf.Security.CookieUsername, "", -1, conf.Server.Subpath)
+	c.SetCookie(conf.Security.CookieRememberName, "", -1, conf.Server.Subpath)
 	c.SetCookie(conf.CSRFCookieName, "", -1, conf.Server.Subpath)
 	c.SubURLRedirect("/")
 }

+ 1 - 1
internal/tool/tool.go

@@ -170,7 +170,7 @@ func CreateTimeLimitCode(data string, minutes int, startInf interface{}) string
 
 	// create sha1 encode string
 	sh := sha1.New()
-	_, _ = sh.Write([]byte(data + conf.SecretKey + startStr + endStr + com.ToStr(minutes)))
+	_, _ = sh.Write([]byte(data + conf.Security.SecretKey + startStr + endStr + com.ToStr(minutes)))
 	encoded := hex.EncodeToString(sh.Sum(nil))
 
 	code := fmt.Sprintf("%s%06d%s", startStr, minutes, encoded)

+ 0 - 18
internal/user/user.go

@@ -1,18 +0,0 @@
-// Copyright 2014 The Gogs 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 user
-
-import (
-	"os"
-)
-
-func CurrentUsername() string {
-	curUserName := os.Getenv("USER")
-	if len(curUserName) > 0 {
-		return curUserName
-	}
-
-	return os.Getenv("USERNAME")
-}

+ 23 - 2
templates/admin/config.tmpl

@@ -67,8 +67,6 @@
 
 						<dt>{{.i18n.Tr "admin.config.log_file_root_path"}}</dt>
 						<dd><code>{{.LogRootPath}}</code></dd>
-						<dt>{{.i18n.Tr "admin.config.reverse_auth_user"}}</dt>
-						<dd><code>{{.ReverseProxyAuthUser}}</code></dd>
 					</dl>
 				</div>
 
@@ -182,6 +180,29 @@
 					</dl>
 				</div>
 
+				{{/* Security settings */}}
+				<h4 class="ui top attached header">
+					{{.i18n.Tr "admin.config.security_config"}}
+				</h4>
+				<div class="ui attached table segment">
+					<dl class="dl-horizontal admin-dl-horizontal">
+						<dt>{{.i18n.Tr "admin.config.security.login_remember_days"}}</dt>
+						<dd>{{.Security.LoginRememberDays}}</dd>
+						<dt>{{.i18n.Tr "admin.config.security.cookie_remember_name"}}</dt>
+						<dd>{{.Security.CookieRememberName}}</dd>
+						<dt>{{.i18n.Tr "admin.config.security.cookie_username"}}</dt>
+						<dd>{{.Security.CookieUsername}}</dd>
+						<dt>{{.i18n.Tr "admin.config.security.cookie_secure"}}</dt>
+						<dd><i class="fa fa{{if .Security.CookieSecure}}-check{{end}}-square-o"></i></dd>
+						<dt>{{.i18n.Tr "admin.config.security.reverse_proxy_auth_user"}}</dt>
+						<dd>{{.Security.ReverseProxyAuthenticationUser}}</dd>
+						<dt>{{.i18n.Tr "admin.config.security.enable_login_status_cookie"}}</dt>
+						<dd><i class="fa fa{{if .Security.EnableLoginStatusCookie}}-check{{end}}-square-o"></i></dd>
+						<dt>{{.i18n.Tr "admin.config.security.login_status_cookie_name"}}</dt>
+						<dd>{{.Security.LoginStatusCookieName}}</dd>
+					</dl>
+				</div>
+
 				<!-- HTTP Configuration -->
 				<h4 class="ui top attached header">
 					{{.i18n.Tr "admin.config.http_config"}}

Some files were not shown because too many files changed in this diff