diff --git a/models/auth/oauth2.go b/models/auth/oauth2.go
index ad1d80e25a85..73c250d4af8a 100644
--- a/models/auth/oauth2.go
+++ b/models/auth/oauth2.go
@@ -10,6 +10,7 @@ import (
"encoding/base32"
"encoding/base64"
"fmt"
+ "net"
"net/url"
"strings"
@@ -56,6 +57,18 @@ func (app *OAuth2Application) PrimaryRedirectURI() string {
// ContainsRedirectURI checks if redirectURI is allowed for app
func (app *OAuth2Application) ContainsRedirectURI(redirectURI string) bool {
+ uri, err := url.Parse(redirectURI)
+ // ignore port for http loopback uris following https://datatracker.ietf.org/doc/html/rfc8252#section-7.3
+ if err == nil && uri.Scheme == "http" && uri.Port() != "" {
+ ip := net.ParseIP(uri.Hostname())
+ if ip != nil && ip.IsLoopback() {
+ // strip port
+ uri.Host = uri.Hostname()
+ if util.IsStringInSlice(uri.String(), app.RedirectURIs, true) {
+ return true
+ }
+ }
+ }
return util.IsStringInSlice(redirectURI, app.RedirectURIs, true)
}
diff --git a/models/auth/oauth2_test.go b/models/auth/oauth2_test.go
index 3b2ba8c8f18c..3815cb3b2c19 100644
--- a/models/auth/oauth2_test.go
+++ b/models/auth/oauth2_test.go
@@ -43,6 +43,26 @@ func TestOAuth2Application_ContainsRedirectURI(t *testing.T) {
assert.False(t, app.ContainsRedirectURI("d"))
}
+func TestOAuth2Application_ContainsRedirectURI_WithPort(t *testing.T) {
+ app := &auth_model.OAuth2Application{
+ RedirectURIs: []string{"http://127.0.0.1/", "http://::1/", "http://192.168.0.1/", "http://intranet/", "https://127.0.0.1/"},
+ }
+
+ // http loopback uris should ignore port
+ // https://datatracker.ietf.org/doc/html/rfc8252#section-7.3
+ assert.True(t, app.ContainsRedirectURI("http://127.0.0.1:3456/"))
+ assert.True(t, app.ContainsRedirectURI("http://127.0.0.1/"))
+ assert.True(t, app.ContainsRedirectURI("http://[::1]:3456/"))
+
+ // not http
+ assert.False(t, app.ContainsRedirectURI("https://127.0.0.1:3456/"))
+ // not loopback
+ assert.False(t, app.ContainsRedirectURI("http://192.168.0.1:9954/"))
+ assert.False(t, app.ContainsRedirectURI("http://intranet:3456/"))
+ // unparseable
+ assert.False(t, app.ContainsRedirectURI(":"))
+}
+
func TestOAuth2Application_ValidateClientSecret(t *testing.T) {
assert.NoError(t, unittest.PrepareTestDatabase())
app := unittest.AssertExistsAndLoadBean(t, &auth_model.OAuth2Application{ID: 1})
diff --git a/options/locale/locale_cs-CZ.ini b/options/locale/locale_cs-CZ.ini
index 406dd78d7070..80f0b12661a1 100644
--- a/options/locale/locale_cs-CZ.ini
+++ b/options/locale/locale_cs-CZ.ini
@@ -1898,6 +1898,7 @@ settings.confirm_delete=Smazat repozitář
settings.add_collaborator=Přidat spolupracovníka
settings.add_collaborator_success=Spolupracovník byl přidán.
settings.add_collaborator_inactive_user=Nelze přidat neaktivního uživatele jako spolupracovníka.
+settings.add_collaborator_owner=Vlastníka nelze přidat jako spolupracovníka.
settings.add_collaborator_duplicate=Spolupracovník je již přidán k tomuto repozitáři.
settings.delete_collaborator=Odstranit
settings.collaborator_deletion=Odstranit spolupracovníka
diff --git a/options/locale/locale_pt-BR.ini b/options/locale/locale_pt-BR.ini
index b8117f65c990..6d6885e17fd5 100644
--- a/options/locale/locale_pt-BR.ini
+++ b/options/locale/locale_pt-BR.ini
@@ -1898,6 +1898,7 @@ settings.confirm_delete=Excluir repositório
settings.add_collaborator=Adicionar colaborador
settings.add_collaborator_success=O colaborador foi adicionado.
settings.add_collaborator_inactive_user=Não é possível adicionar um usuário inativo como colaborador.
+settings.add_collaborator_owner=Não é possível adicionar um proprietário como um colaborador.
settings.add_collaborator_duplicate=O colaborador já está adicionado a este repositório.
settings.delete_collaborator=Remover
settings.collaborator_deletion=Remover colaborador
diff --git a/options/locale/locale_pt-PT.ini b/options/locale/locale_pt-PT.ini
index 34595baa995c..2dbe266b2d53 100644
--- a/options/locale/locale_pt-PT.ini
+++ b/options/locale/locale_pt-PT.ini
@@ -1898,6 +1898,7 @@ settings.confirm_delete=Eliminar repositório
settings.add_collaborator=Adicionar colaborador
settings.add_collaborator_success=O colaborador foi adicionado.
settings.add_collaborator_inactive_user=Não é possível adicionar um utilizador desabilitado como colaborador.
+settings.add_collaborator_owner=Não é possível adicionar um proprietário como um colaborador.
settings.add_collaborator_duplicate=O colaborador já tinha sido adicionado a este repositório.
settings.delete_collaborator=Remover
settings.collaborator_deletion=Remover colaborador
diff --git a/routers/web/auth/oauth.go b/routers/web/auth/oauth.go
index b400fdac8c39..d145150535e6 100644
--- a/routers/web/auth/oauth.go
+++ b/routers/web/auth/oauth.go
@@ -645,7 +645,7 @@ func handleRefreshToken(ctx *context.Context, form forms.AccessTokenForm, server
if err != nil {
handleAccessTokenError(ctx, AccessTokenError{
ErrorCode: AccessTokenErrorCodeUnauthorizedClient,
- ErrorDescription: "client is not authorized",
+ ErrorDescription: "unable to parse refresh token",
})
return
}
@@ -688,14 +688,14 @@ func handleAuthorizationCode(ctx *context.Context, form forms.AccessTokenForm, s
if !app.ValidateClientSecret([]byte(form.ClientSecret)) {
handleAccessTokenError(ctx, AccessTokenError{
ErrorCode: AccessTokenErrorCodeUnauthorizedClient,
- ErrorDescription: "client is not authorized",
+ ErrorDescription: "invalid client secret",
})
return
}
if form.RedirectURI != "" && !app.ContainsRedirectURI(form.RedirectURI) {
handleAccessTokenError(ctx, AccessTokenError{
ErrorCode: AccessTokenErrorCodeUnauthorizedClient,
- ErrorDescription: "client is not authorized",
+ ErrorDescription: "unexpected redirect URI",
})
return
}
@@ -711,7 +711,7 @@ func handleAuthorizationCode(ctx *context.Context, form forms.AccessTokenForm, s
if !authorizationCode.ValidateCodeChallenge(form.CodeVerifier) {
handleAccessTokenError(ctx, AccessTokenError{
ErrorCode: AccessTokenErrorCodeUnauthorizedClient,
- ErrorDescription: "client is not authorized",
+ ErrorDescription: "failed PKCE code challenge",
})
return
}
diff --git a/web_src/less/_base.less b/web_src/less/_base.less
index 3c0b24a634e5..a2c27acfdf09 100644
--- a/web_src/less/_base.less
+++ b/web_src/less/_base.less
@@ -158,6 +158,7 @@
--color-tooltip-bg: #000000f0;
--color-tooltip-text: #ffffff;
--color-header-bar: #ffffff;
+ --color-label-active-bg: #d0d0d0;
/* backgrounds */
--checkbox-mask-checked: url('data:image/svg+xml;utf8,');
--checkbox-mask-indeterminate: url('data:image/svg+xml;utf8,');
@@ -393,6 +394,12 @@ a.commit-statuses-trigger {
background: var(--color-grey);
}
+.ui.active.label {
+ background: var(--color-label-active-bg);
+ border-color: var(--color-label-active-bg);
+ color: var(--color-text-dark);
+}
+
.ui.link.menu .item:hover,
.ui.menu .dropdown.item:hover,
.ui.menu .link.item:hover,
@@ -478,11 +485,21 @@ a.commit-statuses-trigger {
color: var(--color-text-light-2);
}
+.ui.list .list > .item .header,
+.ui.list > .item .header {
+ color: var(--color-text-dark);
+}
+
.ui.list .list > .item > .content,
.ui.list > .item > .content {
color: var(--color-text);
}
+.ui.list .list > .item .description,
+.ui.list > .item .description {
+ color: var(--color-text);
+}
+
.ui.secondary.menu .dropdown.item:hover,
.ui.secondary.menu .link.item:hover,
.ui.secondary.menu a.item:hover {
@@ -704,6 +721,12 @@ a.ui.card:hover,
border-top-color: var(--color-secondary-alpha-50);
}
+.ui.ui.ui.ui.table tr.active,
+.ui.ui.table td.active {
+ color: var(--color-text);
+ background: var(--color-active);
+}
+
.ui.ui.selectable.table > tbody > tr:hover,
.ui.table tbody tr td.selectable:hover {
color: var(--color-text);
@@ -726,11 +749,22 @@ a.ui.card:hover,
}
.ui.modal > .header {
+ color: var(--color-text-dark);
+ background: var(--color-secondary-bg);
border-color: var(--color-secondary);
border-top-left-radius: var(--border-radius);
border-top-right-radius: var(--border-radius);
}
+.ui.modal > .content {
+ background: var(--color-body);
+}
+
+.ui.modal > .actions {
+ background: var(--color-secondary-bg);
+ border-color: var(--color-secondary);
+}
+
.ui.modal > .close.inside,
.ui.fullscreen.modal > .close {
top: 11px; /* align modal close icon, for example admin notices */
@@ -1591,6 +1625,7 @@ i.icon.centerlock {
.ui.labels a.label:hover,
a.ui.label:hover {
background: var(--color-hover);
+ border-color: var(--color-hover);
color: var(--color-text);
}
@@ -1615,7 +1650,7 @@ a.ui.label:hover {
padding-left: 10px;
padding-right: 10px;
text-align: right !important;
- color: rgba(27, 31, 35, .3);
+ color: var(--color-text-light-1);
width: 1%;
font-family: var(--fonts-monospace);
diff --git a/web_src/less/themes/theme-arc-green.less b/web_src/less/themes/theme-arc-green.less
index 754177d6035f..7ebcb87d9d17 100644
--- a/web_src/less/themes/theme-arc-green.less
+++ b/web_src/less/themes/theme-arc-green.less
@@ -118,7 +118,7 @@
--color-menu: #2e323e;
--color-card: #2e323e;
--color-markup-table-row: #ffffff06;
- --color-markup-code-block: #292d39;
+ --color-markup-code-block: #ffffff0d;
--color-button: #353846;
--color-code-bg: #2a2e3a;
--color-code-sidebar-bg: #2e323e;
@@ -133,6 +133,7 @@
--color-reaction-bg: #ffffff12;
--color-reaction-active-bg: var(--color-primary-alpha-40);
--color-header-bar: #2e323e;
+ --color-label-active-bg: #4c525e;
}
::-webkit-calendar-picker-indicator {
@@ -228,11 +229,6 @@ a.ui.basic.green.label:hover {
background-color: #a0cc75;
}
-.repository .navbar .active.item,
-.repository .navbar .active.item:hover {
- border-color: transparent !important;
-}
-
.repository .diff-stats li {
border-color: var(--color-secondary);
}
@@ -247,37 +243,11 @@ a.ui.basic.green.label:hover {
background-color: #984646;
}
-.ui.list .list > .item .header,
-.ui.list > .item .header {
- color: #dedede;
-}
-
-.ui.list .list > .item .description,
-.ui.list > .item .description {
- color: var(--color-secondary-dark-6);
-}
-
-.lines-num {
- color: var(--color-secondary-dark-6) !important;
- border-color: var(--color-secondary) !important;
-}
-
.lines-code.active,
.lines-code .active {
background: #534d1b !important;
}
-.ui.ui.ui.ui.table tr.active,
-.ui.ui.table td.active {
- color: #dbdbdb;
-}
-
-.ui.active.label {
- background: #393d4a;
- border-color: #393d4a;
- color: #dbdbdb;
-}
-
.ui.header .sub.header {
color: var(--color-secondary-dark-6);
}
@@ -286,20 +256,6 @@ a.ui.basic.green.label:hover {
border-bottom: 1px solid var(--color-secondary);
}
-.ui.modal > .header {
- background: var(--color-secondary);
- color: #dbdbdb;
-}
-
-.ui.modal > .actions {
- background: var(--color-secondary);
- border-color: var(--color-secondary);
-}
-
-.ui.modal > .content {
- background: #383c4a;
-}
-
.minicolors-panel {
background: var(--color-secondary) !important;
border-color: #6a737d !important;