aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwxiaoguang <wxiaoguang@gmail.com>2024-05-10 20:07:01 +0800
committerGitHub <noreply@github.com>2024-05-10 20:07:01 +0800
commit7424f27cf30065a1308aa3ba4d75ea82c0af4af9 (patch)
tree3fd5ab5670c1e13a6c6d1e030b9ab5d75b86f9c9
parentb9396a9b852e4fea0e2c39ef3ef2fdfbc9ea248a (diff)
downloadgitea-7424f27cf30065a1308aa3ba4d75ea82c0af4af9.tar.gz
gitea-7424f27cf30065a1308aa3ba4d75ea82c0af4af9.zip
Check if reverse proxy is correctly configured (#30890)
Follow #27011 Follow #30885 --------- Co-authored-by: silverwind <me@silverwind.io> Co-authored-by: Giteabot <teabot@gitea.io>
-rw-r--r--options/locale/locale_en-US.ini1
-rw-r--r--routers/web/admin/admin.go12
-rw-r--r--routers/web/admin/admin_test.go24
-rw-r--r--routers/web/web.go1
-rw-r--r--services/context/base.go3
-rw-r--r--services/contexttest/context_tests.go2
-rw-r--r--templates/admin/self_check.tmpl28
-rw-r--r--web_src/js/bootstrap.js6
-rw-r--r--web_src/js/features/admin/selfcheck.js31
-rw-r--r--web_src/js/features/common-global.js2
-rw-r--r--web_src/js/index.js2
11 files changed, 93 insertions, 19 deletions
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index eef4f5696a..6a08041a7c 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -3320,6 +3320,7 @@ self_check.database_collation_case_insensitive = Database is using a collation %
self_check.database_inconsistent_collation_columns = Database is using collation %s, but these columns are using mismatched collations. It might cause some unexpected problems.
self_check.database_fix_mysql = For MySQL/MariaDB users, you could use the "gitea doctor convert" command to fix the collation problems, or you could also fix the problem by "ALTER ... COLLATE ..." SQLs manually.
self_check.database_fix_mssql = For MSSQL users, you could only fix the problem by "ALTER ... COLLATE ..." SQLs manually at the moment.
+self_check.location_origin_mismatch = Current URL (%[1]s) doesn't match the URL seen by Gitea (%[2]s). If you are using a reverse proxy, please make sure the "Host" and "X-Forwarded-Proto" headers are set correctly.
[action]
create_repo = created repository <a href="%s">%s</a>
diff --git a/routers/web/admin/admin.go b/routers/web/admin/admin.go
index 3dd3c9670f..dee1650b5a 100644
--- a/routers/web/admin/admin.go
+++ b/routers/web/admin/admin.go
@@ -9,12 +9,14 @@ import (
"net/http"
"runtime"
"sort"
+ "strings"
"time"
activities_model "code.gitea.io/gitea/models/activities"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/base"
"code.gitea.io/gitea/modules/graceful"
+ "code.gitea.io/gitea/modules/httplib"
"code.gitea.io/gitea/modules/json"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
@@ -223,6 +225,16 @@ func SelfCheck(ctx *context.Context) {
ctx.HTML(http.StatusOK, tplSelfCheck)
}
+func SelfCheckPost(ctx *context.Context) {
+ var problems []string
+ frontendAppURL := ctx.FormString("location_origin") + setting.AppSubURL + "/"
+ ctxAppURL := httplib.GuessCurrentAppURL(ctx)
+ if !strings.HasPrefix(ctxAppURL, frontendAppURL) {
+ problems = append(problems, ctx.Locale.TrString("admin.self_check.location_origin_mismatch", frontendAppURL, ctxAppURL))
+ }
+ ctx.JSON(http.StatusOK, map[string]any{"problems": problems})
+}
+
func CronTasks(ctx *context.Context) {
ctx.Data["Title"] = ctx.Tr("admin.monitor.cron")
ctx.Data["PageIsAdminMonitorCron"] = true
diff --git a/routers/web/admin/admin_test.go b/routers/web/admin/admin_test.go
index 2b65ab3ea3..782126adf5 100644
--- a/routers/web/admin/admin_test.go
+++ b/routers/web/admin/admin_test.go
@@ -4,8 +4,14 @@
package admin
import (
+ "net/http"
"testing"
+ "code.gitea.io/gitea/modules/json"
+ "code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/test"
+ "code.gitea.io/gitea/services/contexttest"
+
"github.com/stretchr/testify/assert"
)
@@ -66,3 +72,21 @@ func TestShadowPassword(t *testing.T) {
assert.EqualValues(t, k.Result, shadowPassword(k.Provider, k.CfgItem))
}
}
+
+func TestSelfCheckPost(t *testing.T) {
+ defer test.MockVariableValue(&setting.AppURL, "http://config/sub/")()
+ defer test.MockVariableValue(&setting.AppSubURL, "/sub")()
+
+ ctx, resp := contexttest.MockContext(t, "GET http://host/sub/admin/self_check?location_origin=http://frontend")
+ SelfCheckPost(ctx)
+ assert.EqualValues(t, http.StatusOK, resp.Code)
+
+ data := struct {
+ Problems []string `json:"problems"`
+ }{}
+ err := json.Unmarshal(resp.Body.Bytes(), &data)
+ assert.NoError(t, err)
+ assert.Equal(t, []string{
+ ctx.Locale.TrString("admin.self_check.location_origin_mismatch", "http://frontend/sub/", "http://host/sub/"),
+ }, data.Problems)
+}
diff --git a/routers/web/web.go b/routers/web/web.go
index e1482c1e4a..f3b9969059 100644
--- a/routers/web/web.go
+++ b/routers/web/web.go
@@ -686,6 +686,7 @@ func registerRoutes(m *web.Route) {
m.Post("", web.Bind(forms.AdminDashboardForm{}), admin.DashboardPost)
m.Get("/self_check", admin.SelfCheck)
+ m.Post("/self_check", admin.SelfCheckPost)
m.Group("/config", func() {
m.Get("", admin.Config)
diff --git a/services/context/base.go b/services/context/base.go
index 29e62ae389..23f0bcfc33 100644
--- a/services/context/base.go
+++ b/services/context/base.go
@@ -309,7 +309,8 @@ func NewBaseContext(resp http.ResponseWriter, req *http.Request) (b *Base, close
Locale: middleware.Locale(resp, req),
Data: middleware.GetContextData(req.Context()),
}
- b.AppendContextValue(translation.ContextKey, b.Locale)
b.Req = b.Req.WithContext(b)
+ b.AppendContextValue(translation.ContextKey, b.Locale)
+ b.AppendContextValue(httplib.RequestContextKey, b.Req)
return b, b.cleanUp
}
diff --git a/services/contexttest/context_tests.go b/services/contexttest/context_tests.go
index 5624d24058..3c3fa76e3c 100644
--- a/services/contexttest/context_tests.go
+++ b/services/contexttest/context_tests.go
@@ -39,7 +39,7 @@ func mockRequest(t *testing.T, reqPath string) *http.Request {
}
requestURL, err := url.Parse(path)
assert.NoError(t, err)
- req := &http.Request{Method: method, URL: requestURL, Form: maps.Clone(requestURL.Query()), Header: http.Header{}}
+ req := &http.Request{Method: method, Host: requestURL.Host, URL: requestURL, Form: maps.Clone(requestURL.Query()), Header: http.Header{}}
req = req.WithContext(middleware.WithContextData(req.Context()))
return req
}
diff --git a/templates/admin/self_check.tmpl b/templates/admin/self_check.tmpl
index a6c2ac1ac9..b249bf228e 100644
--- a/templates/admin/self_check.tmpl
+++ b/templates/admin/self_check.tmpl
@@ -1,4 +1,4 @@
-{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin config")}}
+{{template "admin/layout_head" (dict "ctxData" . "pageClass" "admin")}}
<div class="admin-setting-content">
<h4 class="ui top attached header">
@@ -6,7 +6,7 @@
</h4>
{{if .StartupProblems}}
- <div class="ui attached segment">
+ <div class="ui attached segment self-check-problem">
<div class="ui warning message">
<div>{{ctx.Locale.Tr "admin.self_check.startup_warnings"}}</div>
<ul class="tw-w-full">{{range .StartupProblems}}<li>{{.}}</li>{{end}}</ul>
@@ -14,8 +14,10 @@
</div>
{{end}}
+ <div class="ui attached segment tw-hidden self-check-problem" id="self-check-by-frontend"></div>
+
{{if .DatabaseCheckHasProblems}}
- <div class="ui attached segment">
+ <div class="ui attached segment self-check-problem">
{{if .DatabaseType.IsMySQL}}
<div class="tw-p-2">{{ctx.Locale.Tr "admin.self_check.database_fix_mysql"}}</div>
{{else if .DatabaseType.IsMSSQL}}
@@ -29,22 +31,22 @@
{{end}}
{{if .DatabaseCheckInconsistentCollationColumns}}
<div class="ui red message">
- {{ctx.Locale.Tr "admin.self_check.database_inconsistent_collation_columns" .DatabaseCheckResult.DatabaseCollation}}
- <ul class="tw-w-full">
- {{range .DatabaseCheckInconsistentCollationColumns}}
- <li>{{.}}</li>
- {{end}}
- </ul>
+ <details>
+ <summary>{{ctx.Locale.Tr "admin.self_check.database_inconsistent_collation_columns" .DatabaseCheckResult.DatabaseCollation}}</summary>
+ <ul class="tw-w-full">
+ {{range .DatabaseCheckInconsistentCollationColumns}}
+ <li>{{.}}</li>
+ {{end}}
+ </ul>
+ </details>
</div>
{{end}}
</div>
{{end}}
-
- {{if and (not .StartupProblems) (not .DatabaseCheckHasProblems)}}
- <div class="ui attached segment">
+ {{/* only shown when there is no visible "self-check-problem" */}}
+ <div class="ui attached segment tw-hidden self-check-no-problem">
{{ctx.Locale.Tr "admin.self_check.no_problem_found"}}
</div>
- {{end}}
</div>
{{template "admin/layout_footer" .}}
diff --git a/web_src/js/bootstrap.js b/web_src/js/bootstrap.js
index 8339b4bd82..26627dfded 100644
--- a/web_src/js/bootstrap.js
+++ b/web_src/js/bootstrap.js
@@ -16,20 +16,20 @@ function shouldIgnoreError(err) {
return false;
}
-export function showGlobalErrorMessage(msg) {
+export function showGlobalErrorMessage(msg, msgType = 'error') {
const msgContainer = document.querySelector('.page-content') ?? document.body;
const msgCompact = msg.replace(/\W/g, '').trim(); // compact the message to a data attribute to avoid too many duplicated messages
let msgDiv = msgContainer.querySelector(`.js-global-error[data-global-error-msg-compact="${msgCompact}"]`);
if (!msgDiv) {
const el = document.createElement('div');
- el.innerHTML = `<div class="ui container negative message center aligned js-global-error tw-mt-[15px] tw-whitespace-pre-line"></div>`;
+ el.innerHTML = `<div class="ui container js-global-error tw-my-[--page-spacing]"><div class="ui ${msgType} message tw-text-center tw-whitespace-pre-line"></div></div>`;
msgDiv = el.childNodes[0];
}
// merge duplicated messages into "the message (count)" format
const msgCount = Number(msgDiv.getAttribute(`data-global-error-msg-count`)) + 1;
msgDiv.setAttribute(`data-global-error-msg-compact`, msgCompact);
msgDiv.setAttribute(`data-global-error-msg-count`, msgCount.toString());
- msgDiv.textContent = msg + (msgCount > 1 ? ` (${msgCount})` : '');
+ msgDiv.querySelector('.ui.message').textContent = msg + (msgCount > 1 ? ` (${msgCount})` : '');
msgContainer.prepend(msgDiv);
}
diff --git a/web_src/js/features/admin/selfcheck.js b/web_src/js/features/admin/selfcheck.js
new file mode 100644
index 0000000000..699395b363
--- /dev/null
+++ b/web_src/js/features/admin/selfcheck.js
@@ -0,0 +1,31 @@
+import {toggleElem} from '../../utils/dom.js';
+import {POST} from '../../modules/fetch.js';
+
+const {appSubUrl} = window.config;
+
+export async function initAdminSelfCheck() {
+ const elCheckByFrontend = document.querySelector('#self-check-by-frontend');
+ if (!elCheckByFrontend) return;
+
+ const elContent = document.querySelector('.page-content.admin .admin-setting-content');
+
+ // send frontend self-check request
+ const resp = await POST(`${appSubUrl}/admin/self_check`, {
+ data: new URLSearchParams({
+ location_origin: window.location.origin,
+ now: Date.now(), // TODO: check time difference between server and client
+ }),
+ });
+ const json = await resp.json();
+ toggleElem(elCheckByFrontend, Boolean(json.problems?.length));
+ for (const problem of json.problems ?? []) {
+ const elProblem = document.createElement('div');
+ elProblem.classList.add('ui', 'warning', 'message');
+ elProblem.textContent = problem;
+ elCheckByFrontend.append(elProblem);
+ }
+
+ // only show the "no problem" if there is no visible "self-check-problem"
+ const hasProblem = Boolean(elContent.querySelectorAll('.self-check-problem:not(.tw-hidden)').length);
+ toggleElem(elContent.querySelector('.self-check-no-problem'), !hasProblem);
+}
diff --git a/web_src/js/features/common-global.js b/web_src/js/features/common-global.js
index 5b8673105d..3b021d4485 100644
--- a/web_src/js/features/common-global.js
+++ b/web_src/js/features/common-global.js
@@ -451,5 +451,5 @@ export function checkAppUrl() {
return;
}
showGlobalErrorMessage(`Your ROOT_URL in app.ini is "${appUrl}", it's unlikely matching the site you are visiting.
-Mismatched ROOT_URL config causes wrong URL links for web UI/mail content/webhook notification/OAuth2 sign-in.`);
+Mismatched ROOT_URL config causes wrong URL links for web UI/mail content/webhook notification/OAuth2 sign-in.`, 'warning');
}
diff --git a/web_src/js/index.js b/web_src/js/index.js
index fc2f6b9b0b..1867556eee 100644
--- a/web_src/js/index.js
+++ b/web_src/js/index.js
@@ -87,6 +87,7 @@ import {initRepoDiffCommitBranchesAndTags} from './features/repo-diff-commit.js'
import {initDirAuto} from './modules/dirauto.js';
import {initRepositorySearch} from './features/repo-search.js';
import {initColorPickers} from './features/colorpicker.js';
+import {initAdminSelfCheck} from './features/admin/selfcheck.js';
// Init Gitea's Fomantic settings
initGiteaFomantic();
@@ -132,6 +133,7 @@ onDomReady(() => {
initAdminEmails();
initAdminUserListSearchForm();
initAdminConfigs();
+ initAdminSelfCheck();
initDashboardRepoList();