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;