Allow creation of OAuth2 applications for orgs (#18084)
Adds the settings pages to create OAuth2 apps also to the org settings and allows to create apps for orgs. Refactoring: the oauth2 related templates are shared for instance-wide/org/user, and the backend code uses `OAuth2CommonHandlers` to share code for instance-wide/org/user. Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
This commit is contained in:
parent
97f3f1988b
commit
a813c9d8f3
File diff suppressed because one or more lines are too long
|
@ -225,7 +225,8 @@ func updateOAuth2Application(ctx context.Context, app *OAuth2Application) error
|
|||
|
||||
func deleteOAuth2Application(ctx context.Context, id, userid int64) error {
|
||||
sess := db.GetEngine(ctx)
|
||||
if deleted, err := sess.Delete(&OAuth2Application{ID: id, UID: userid}); err != nil {
|
||||
// the userid could be 0 if the app is instance-wide
|
||||
if deleted, err := sess.Where(builder.Eq{"id": id, "uid": userid}).Delete(&OAuth2Application{}); err != nil {
|
||||
return err
|
||||
} else if deleted == 0 {
|
||||
return ErrOAuthApplicationNotFound{ID: id}
|
||||
|
@ -476,7 +477,7 @@ func GetOAuth2GrantsByUserID(ctx context.Context, uid int64) ([]*OAuth2Grant, er
|
|||
|
||||
// RevokeOAuth2Grant deletes the grant with grantID and userID
|
||||
func RevokeOAuth2Grant(ctx context.Context, grantID, userID int64) error {
|
||||
_, err := db.DeleteByBean(ctx, &OAuth2Grant{ID: grantID, UserID: userID})
|
||||
_, err := db.GetEngine(ctx).Where(builder.Eq{"id": grantID, "user_id": userID}).Delete(&OAuth2Grant{})
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
93
routers/web/org/setting_oauth2.go
Normal file
93
routers/web/org/setting_oauth2.go
Normal file
|
@ -0,0 +1,93 @@
|
|||
// Copyright 2022 The Gitea 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 org
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
user_setting "code.gitea.io/gitea/routers/web/user/setting"
|
||||
)
|
||||
|
||||
const (
|
||||
tplSettingsApplications base.TplName = "org/settings/applications"
|
||||
tplSettingsOAuthApplicationEdit base.TplName = "org/settings/applications_oauth2_edit"
|
||||
)
|
||||
|
||||
func newOAuth2CommonHandlers(org *context.Organization) *user_setting.OAuth2CommonHandlers {
|
||||
return &user_setting.OAuth2CommonHandlers{
|
||||
OwnerID: org.Organization.ID,
|
||||
BasePathList: fmt.Sprintf("%s/org/%s/settings/applications", setting.AppSubURL, org.Organization.Name),
|
||||
BasePathEditPrefix: fmt.Sprintf("%s/org/%s/settings/applications/oauth2", setting.AppSubURL, org.Organization.Name),
|
||||
TplAppEdit: tplSettingsOAuthApplicationEdit,
|
||||
}
|
||||
}
|
||||
|
||||
// Applications render org applications page (for org, at the moment, there are only OAuth2 applications)
|
||||
func Applications(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("settings.applications")
|
||||
ctx.Data["PageIsOrgSettings"] = true
|
||||
ctx.Data["PageIsSettingsApplications"] = true
|
||||
|
||||
apps, err := auth.GetOAuth2ApplicationsByUserID(ctx, ctx.Org.Organization.ID)
|
||||
if err != nil {
|
||||
ctx.ServerError("GetOAuth2ApplicationsByUserID", err)
|
||||
return
|
||||
}
|
||||
ctx.Data["Applications"] = apps
|
||||
|
||||
ctx.HTML(http.StatusOK, tplSettingsApplications)
|
||||
}
|
||||
|
||||
// OAuthApplicationsPost response for adding an oauth2 application
|
||||
func OAuthApplicationsPost(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("settings.applications")
|
||||
ctx.Data["PageIsOrgSettings"] = true
|
||||
ctx.Data["PageIsSettingsApplications"] = true
|
||||
|
||||
oa := newOAuth2CommonHandlers(ctx.Org)
|
||||
oa.AddApp(ctx)
|
||||
}
|
||||
|
||||
// OAuth2ApplicationShow displays the given application
|
||||
func OAuth2ApplicationShow(ctx *context.Context) {
|
||||
ctx.Data["PageIsOrgSettings"] = true
|
||||
ctx.Data["PageIsSettingsApplications"] = true
|
||||
|
||||
oa := newOAuth2CommonHandlers(ctx.Org)
|
||||
oa.EditShow(ctx)
|
||||
}
|
||||
|
||||
// OAuth2ApplicationEdit response for editing oauth2 application
|
||||
func OAuth2ApplicationEdit(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("settings.applications")
|
||||
ctx.Data["PageIsOrgSettings"] = true
|
||||
ctx.Data["PageIsSettingsApplications"] = true
|
||||
|
||||
oa := newOAuth2CommonHandlers(ctx.Org)
|
||||
oa.EditSave(ctx)
|
||||
}
|
||||
|
||||
// OAuthApplicationsRegenerateSecret handles the post request for regenerating the secret
|
||||
func OAuthApplicationsRegenerateSecret(ctx *context.Context) {
|
||||
ctx.Data["Title"] = ctx.Tr("settings")
|
||||
ctx.Data["PageIsOrgSettings"] = true
|
||||
ctx.Data["PageIsSettingsApplications"] = true
|
||||
|
||||
oa := newOAuth2CommonHandlers(ctx.Org)
|
||||
oa.RegenerateSecret(ctx)
|
||||
}
|
||||
|
||||
// DeleteOAuth2Application deletes the given oauth2 application
|
||||
func DeleteOAuth2Application(ctx *context.Context) {
|
||||
oa := newOAuth2CommonHandlers(ctx.Org)
|
||||
oa.DeleteApp(ctx)
|
||||
}
|
||||
|
||||
// TODO: revokes the grant with the given id
|
|
@ -5,79 +5,40 @@
|
|||
package setting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/log"
|
||||
"code.gitea.io/gitea/modules/setting"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
"code.gitea.io/gitea/services/forms"
|
||||
)
|
||||
|
||||
const (
|
||||
tplSettingsOAuthApplications base.TplName = "user/settings/applications_oauth2_edit"
|
||||
tplSettingsOAuthApplicationEdit base.TplName = "user/settings/applications_oauth2_edit"
|
||||
)
|
||||
|
||||
func newOAuth2CommonHandlers(userID int64) *OAuth2CommonHandlers {
|
||||
return &OAuth2CommonHandlers{
|
||||
OwnerID: userID,
|
||||
BasePathList: setting.AppSubURL + "/user/settings/applications",
|
||||
BasePathEditPrefix: setting.AppSubURL + "/user/settings/applications/oauth2",
|
||||
TplAppEdit: tplSettingsOAuthApplicationEdit,
|
||||
}
|
||||
}
|
||||
|
||||
// OAuthApplicationsPost response for adding a oauth2 application
|
||||
func OAuthApplicationsPost(ctx *context.Context) {
|
||||
form := web.GetForm(ctx).(*forms.EditOAuth2ApplicationForm)
|
||||
ctx.Data["Title"] = ctx.Tr("settings")
|
||||
ctx.Data["PageIsSettingsApplications"] = true
|
||||
|
||||
if ctx.HasError() {
|
||||
loadApplicationsData(ctx)
|
||||
|
||||
ctx.HTML(http.StatusOK, tplSettingsApplications)
|
||||
return
|
||||
}
|
||||
// TODO validate redirect URI
|
||||
app, err := auth.CreateOAuth2Application(ctx, auth.CreateOAuth2ApplicationOptions{
|
||||
Name: form.Name,
|
||||
RedirectURIs: []string{form.RedirectURI},
|
||||
UserID: ctx.Doer.ID,
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("CreateOAuth2Application", err)
|
||||
return
|
||||
}
|
||||
ctx.Flash.Success(ctx.Tr("settings.create_oauth2_application_success"))
|
||||
ctx.Data["App"] = app
|
||||
ctx.Data["ClientSecret"], err = app.GenerateClientSecret()
|
||||
if err != nil {
|
||||
ctx.ServerError("GenerateClientSecret", err)
|
||||
return
|
||||
}
|
||||
ctx.HTML(http.StatusOK, tplSettingsOAuthApplications)
|
||||
oa := newOAuth2CommonHandlers(ctx.Doer.ID)
|
||||
oa.AddApp(ctx)
|
||||
}
|
||||
|
||||
// OAuthApplicationsEdit response for editing oauth2 application
|
||||
func OAuthApplicationsEdit(ctx *context.Context) {
|
||||
form := web.GetForm(ctx).(*forms.EditOAuth2ApplicationForm)
|
||||
ctx.Data["Title"] = ctx.Tr("settings")
|
||||
ctx.Data["PageIsSettingsApplications"] = true
|
||||
|
||||
if ctx.HasError() {
|
||||
loadApplicationsData(ctx)
|
||||
|
||||
ctx.HTML(http.StatusOK, tplSettingsApplications)
|
||||
return
|
||||
}
|
||||
// TODO validate redirect URI
|
||||
var err error
|
||||
if ctx.Data["App"], err = auth.UpdateOAuth2Application(auth.UpdateOAuth2ApplicationOptions{
|
||||
ID: ctx.ParamsInt64("id"),
|
||||
Name: form.Name,
|
||||
RedirectURIs: []string{form.RedirectURI},
|
||||
UserID: ctx.Doer.ID,
|
||||
}); err != nil {
|
||||
ctx.ServerError("UpdateOAuth2Application", err)
|
||||
return
|
||||
}
|
||||
ctx.Flash.Success(ctx.Tr("settings.update_oauth2_application_success"))
|
||||
ctx.HTML(http.StatusOK, tplSettingsOAuthApplications)
|
||||
oa := newOAuth2CommonHandlers(ctx.Doer.ID)
|
||||
oa.EditSave(ctx)
|
||||
}
|
||||
|
||||
// OAuthApplicationsRegenerateSecret handles the post request for regenerating the secret
|
||||
|
@ -85,75 +46,24 @@ func OAuthApplicationsRegenerateSecret(ctx *context.Context) {
|
|||
ctx.Data["Title"] = ctx.Tr("settings")
|
||||
ctx.Data["PageIsSettingsApplications"] = true
|
||||
|
||||
app, err := auth.GetOAuth2ApplicationByID(ctx, ctx.ParamsInt64("id"))
|
||||
if err != nil {
|
||||
if auth.IsErrOAuthApplicationNotFound(err) {
|
||||
ctx.NotFound("Application not found", err)
|
||||
return
|
||||
}
|
||||
ctx.ServerError("GetOAuth2ApplicationByID", err)
|
||||
return
|
||||
}
|
||||
if app.UID != ctx.Doer.ID {
|
||||
ctx.NotFound("Application not found", nil)
|
||||
return
|
||||
}
|
||||
ctx.Data["App"] = app
|
||||
ctx.Data["ClientSecret"], err = app.GenerateClientSecret()
|
||||
if err != nil {
|
||||
ctx.ServerError("GenerateClientSecret", err)
|
||||
return
|
||||
}
|
||||
ctx.Flash.Success(ctx.Tr("settings.update_oauth2_application_success"))
|
||||
ctx.HTML(http.StatusOK, tplSettingsOAuthApplications)
|
||||
oa := newOAuth2CommonHandlers(ctx.Doer.ID)
|
||||
oa.RegenerateSecret(ctx)
|
||||
}
|
||||
|
||||
// OAuth2ApplicationShow displays the given application
|
||||
func OAuth2ApplicationShow(ctx *context.Context) {
|
||||
app, err := auth.GetOAuth2ApplicationByID(ctx, ctx.ParamsInt64("id"))
|
||||
if err != nil {
|
||||
if auth.IsErrOAuthApplicationNotFound(err) {
|
||||
ctx.NotFound("Application not found", err)
|
||||
return
|
||||
}
|
||||
ctx.ServerError("GetOAuth2ApplicationByID", err)
|
||||
return
|
||||
}
|
||||
if app.UID != ctx.Doer.ID {
|
||||
ctx.NotFound("Application not found", nil)
|
||||
return
|
||||
}
|
||||
ctx.Data["App"] = app
|
||||
ctx.HTML(http.StatusOK, tplSettingsOAuthApplications)
|
||||
oa := newOAuth2CommonHandlers(ctx.Doer.ID)
|
||||
oa.EditShow(ctx)
|
||||
}
|
||||
|
||||
// DeleteOAuth2Application deletes the given oauth2 application
|
||||
func DeleteOAuth2Application(ctx *context.Context) {
|
||||
if err := auth.DeleteOAuth2Application(ctx.FormInt64("id"), ctx.Doer.ID); err != nil {
|
||||
ctx.ServerError("DeleteOAuth2Application", err)
|
||||
return
|
||||
}
|
||||
log.Trace("OAuth2 Application deleted: %s", ctx.Doer.Name)
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("settings.remove_oauth2_application_success"))
|
||||
ctx.JSON(http.StatusOK, map[string]interface{}{
|
||||
"redirect": setting.AppSubURL + "/user/settings/applications",
|
||||
})
|
||||
oa := newOAuth2CommonHandlers(ctx.Doer.ID)
|
||||
oa.DeleteApp(ctx)
|
||||
}
|
||||
|
||||
// RevokeOAuth2Grant revokes the grant with the given id
|
||||
func RevokeOAuth2Grant(ctx *context.Context) {
|
||||
if ctx.Doer.ID == 0 || ctx.FormInt64("id") == 0 {
|
||||
ctx.ServerError("RevokeOAuth2Grant", fmt.Errorf("user id or grant id is zero"))
|
||||
return
|
||||
}
|
||||
if err := auth.RevokeOAuth2Grant(ctx, ctx.FormInt64("id"), ctx.Doer.ID); err != nil {
|
||||
ctx.ServerError("RevokeOAuth2Grant", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("settings.revoke_oauth2_grant_success"))
|
||||
ctx.JSON(http.StatusOK, map[string]interface{}{
|
||||
"redirect": setting.AppSubURL + "/user/settings/applications",
|
||||
})
|
||||
oa := newOAuth2CommonHandlers(ctx.Doer.ID)
|
||||
oa.RevokeGrant(ctx)
|
||||
}
|
||||
|
|
150
routers/web/user/setting/oauth2_common.go
Normal file
150
routers/web/user/setting/oauth2_common.go
Normal file
|
@ -0,0 +1,150 @@
|
|||
// Copyright 2019 The Gitea 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 setting
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"code.gitea.io/gitea/models/auth"
|
||||
"code.gitea.io/gitea/modules/base"
|
||||
"code.gitea.io/gitea/modules/context"
|
||||
"code.gitea.io/gitea/modules/web"
|
||||
"code.gitea.io/gitea/services/forms"
|
||||
)
|
||||
|
||||
type OAuth2CommonHandlers struct {
|
||||
OwnerID int64 // 0 for instance-wide, otherwise OrgID or UserID
|
||||
BasePathList string // the base URL for the application list page, eg: "/user/setting/applications"
|
||||
BasePathEditPrefix string // the base URL for the application edit page, will be appended with app id, eg: "/user/setting/applications/oauth2"
|
||||
TplAppEdit base.TplName // the template for the application edit page
|
||||
}
|
||||
|
||||
func (oa *OAuth2CommonHandlers) renderEditPage(ctx *context.Context) {
|
||||
app := ctx.Data["App"].(*auth.OAuth2Application)
|
||||
ctx.Data["FormActionPath"] = fmt.Sprintf("%s/%d", oa.BasePathEditPrefix, app.ID)
|
||||
ctx.HTML(http.StatusOK, oa.TplAppEdit)
|
||||
}
|
||||
|
||||
// AddApp adds an oauth2 application
|
||||
func (oa *OAuth2CommonHandlers) AddApp(ctx *context.Context) {
|
||||
form := web.GetForm(ctx).(*forms.EditOAuth2ApplicationForm)
|
||||
if ctx.HasError() {
|
||||
// go to the application list page
|
||||
ctx.Redirect(oa.BasePathList)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO validate redirect URI
|
||||
app, err := auth.CreateOAuth2Application(ctx, auth.CreateOAuth2ApplicationOptions{
|
||||
Name: form.Name,
|
||||
RedirectURIs: []string{form.RedirectURI},
|
||||
UserID: oa.OwnerID,
|
||||
})
|
||||
if err != nil {
|
||||
ctx.ServerError("CreateOAuth2Application", err)
|
||||
return
|
||||
}
|
||||
|
||||
// render the edit page with secret
|
||||
ctx.Flash.Success(ctx.Tr("settings.create_oauth2_application_success"), true)
|
||||
ctx.Data["App"] = app
|
||||
ctx.Data["ClientSecret"], err = app.GenerateClientSecret()
|
||||
if err != nil {
|
||||
ctx.ServerError("GenerateClientSecret", err)
|
||||
return
|
||||
}
|
||||
oa.renderEditPage(ctx)
|
||||
}
|
||||
|
||||
// EditShow displays the given application
|
||||
func (oa *OAuth2CommonHandlers) EditShow(ctx *context.Context) {
|
||||
app, err := auth.GetOAuth2ApplicationByID(ctx, ctx.ParamsInt64("id"))
|
||||
if err != nil {
|
||||
if auth.IsErrOAuthApplicationNotFound(err) {
|
||||
ctx.NotFound("Application not found", err)
|
||||
return
|
||||
}
|
||||
ctx.ServerError("GetOAuth2ApplicationByID", err)
|
||||
return
|
||||
}
|
||||
if app.UID != oa.OwnerID {
|
||||
ctx.NotFound("Application not found", nil)
|
||||
return
|
||||
}
|
||||
ctx.Data["App"] = app
|
||||
oa.renderEditPage(ctx)
|
||||
}
|
||||
|
||||
// EditSave saves the oauth2 application
|
||||
func (oa *OAuth2CommonHandlers) EditSave(ctx *context.Context) {
|
||||
form := web.GetForm(ctx).(*forms.EditOAuth2ApplicationForm)
|
||||
|
||||
if ctx.HasError() {
|
||||
oa.renderEditPage(ctx)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO validate redirect URI
|
||||
var err error
|
||||
if ctx.Data["App"], err = auth.UpdateOAuth2Application(auth.UpdateOAuth2ApplicationOptions{
|
||||
ID: ctx.ParamsInt64("id"),
|
||||
Name: form.Name,
|
||||
RedirectURIs: []string{form.RedirectURI},
|
||||
UserID: oa.OwnerID,
|
||||
}); err != nil {
|
||||
ctx.ServerError("UpdateOAuth2Application", err)
|
||||
return
|
||||
}
|
||||
ctx.Flash.Success(ctx.Tr("settings.update_oauth2_application_success"))
|
||||
ctx.Redirect(oa.BasePathList)
|
||||
}
|
||||
|
||||
// RegenerateSecret regenerates the secret
|
||||
func (oa *OAuth2CommonHandlers) RegenerateSecret(ctx *context.Context) {
|
||||
app, err := auth.GetOAuth2ApplicationByID(ctx, ctx.ParamsInt64("id"))
|
||||
if err != nil {
|
||||
if auth.IsErrOAuthApplicationNotFound(err) {
|
||||
ctx.NotFound("Application not found", err)
|
||||
return
|
||||
}
|
||||
ctx.ServerError("GetOAuth2ApplicationByID", err)
|
||||
return
|
||||
}
|
||||
if app.UID != oa.OwnerID {
|
||||
ctx.NotFound("Application not found", nil)
|
||||
return
|
||||
}
|
||||
ctx.Data["App"] = app
|
||||
ctx.Data["ClientSecret"], err = app.GenerateClientSecret()
|
||||
if err != nil {
|
||||
ctx.ServerError("GenerateClientSecret", err)
|
||||
return
|
||||
}
|
||||
ctx.Flash.Success(ctx.Tr("settings.update_oauth2_application_success"), true)
|
||||
oa.renderEditPage(ctx)
|
||||
}
|
||||
|
||||
// DeleteApp deletes the given oauth2 application
|
||||
func (oa *OAuth2CommonHandlers) DeleteApp(ctx *context.Context) {
|
||||
if err := auth.DeleteOAuth2Application(ctx.ParamsInt64("id"), oa.OwnerID); err != nil {
|
||||
ctx.ServerError("DeleteOAuth2Application", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("settings.remove_oauth2_application_success"))
|
||||
ctx.JSON(http.StatusOK, map[string]interface{}{"redirect": oa.BasePathList})
|
||||
}
|
||||
|
||||
// RevokeGrant revokes the grant
|
||||
func (oa *OAuth2CommonHandlers) RevokeGrant(ctx *context.Context) {
|
||||
if err := auth.RevokeOAuth2Grant(ctx, ctx.ParamsInt64("grantId"), oa.OwnerID); err != nil {
|
||||
ctx.ServerError("RevokeOAuth2Grant", err)
|
||||
return
|
||||
}
|
||||
|
||||
ctx.Flash.Success(ctx.Tr("settings.revoke_oauth2_grant_success"))
|
||||
ctx.JSON(http.StatusOK, map[string]interface{}{"redirect": oa.BasePathList})
|
||||
}
|
|
@ -427,8 +427,8 @@ func RegisterRoutes(m *web.Route) {
|
|||
m.Post("/{id}", bindIgnErr(forms.EditOAuth2ApplicationForm{}), user_setting.OAuthApplicationsEdit)
|
||||
m.Post("/{id}/regenerate_secret", user_setting.OAuthApplicationsRegenerateSecret)
|
||||
m.Post("", bindIgnErr(forms.EditOAuth2ApplicationForm{}), user_setting.OAuthApplicationsPost)
|
||||
m.Post("/delete", user_setting.DeleteOAuth2Application)
|
||||
m.Post("/revoke", user_setting.RevokeOAuth2Grant)
|
||||
m.Post("/{id}/delete", user_setting.DeleteOAuth2Application)
|
||||
m.Post("/{id}/revoke/{grantId}", user_setting.RevokeOAuth2Grant)
|
||||
})
|
||||
m.Combo("/applications").Get(user_setting.Applications).
|
||||
Post(bindIgnErr(forms.NewAccessTokenForm{}), user_setting.ApplicationsPost)
|
||||
|
@ -662,6 +662,20 @@ func RegisterRoutes(m *web.Route) {
|
|||
Post(bindIgnErr(forms.UpdateOrgSettingForm{}), org.SettingsPost)
|
||||
m.Post("/avatar", bindIgnErr(forms.AvatarForm{}), org.SettingsAvatar)
|
||||
m.Post("/avatar/delete", org.SettingsDeleteAvatar)
|
||||
m.Group("/applications", func() {
|
||||
m.Get("", org.Applications)
|
||||
m.Post("/oauth2", bindIgnErr(forms.EditOAuth2ApplicationForm{}), org.OAuthApplicationsPost)
|
||||
m.Group("/oauth2/{id}", func() {
|
||||
m.Combo("").Get(org.OAuth2ApplicationShow).Post(bindIgnErr(forms.EditOAuth2ApplicationForm{}), org.OAuth2ApplicationEdit)
|
||||
m.Post("/regenerate_secret", org.OAuthApplicationsRegenerateSecret)
|
||||
m.Post("/delete", org.DeleteOAuth2Application)
|
||||
})
|
||||
}, func(ctx *context.Context) {
|
||||
if !setting.OAuth2.Enable {
|
||||
ctx.Error(http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
})
|
||||
|
||||
m.Group("/hooks", func() {
|
||||
m.Get("", org.Webhooks)
|
||||
|
@ -702,6 +716,8 @@ func RegisterRoutes(m *web.Route) {
|
|||
})
|
||||
|
||||
m.Route("/delete", "GET,POST", org.SettingsDelete)
|
||||
}, func(ctx *context.Context) {
|
||||
ctx.Data["EnableOAuth2"] = setting.OAuth2.Enable
|
||||
})
|
||||
}, context.OrgAssignment(true, true))
|
||||
}, reqSignIn)
|
||||
|
|
18
templates/org/settings/applications.tmpl
Normal file
18
templates/org/settings/applications.tmpl
Normal file
|
@ -0,0 +1,18 @@
|
|||
{{template "base/head" .}}
|
||||
<div class="page-content organization settings options">
|
||||
{{template "org/header" .}}
|
||||
<div class="ui container">
|
||||
<div class="ui grid">
|
||||
{{template "org/settings/navbar" .}}
|
||||
<div class="twelve wide column content">
|
||||
{{template "base/alert" .}}
|
||||
<h4 class="ui top attached header">
|
||||
{{.locale.Tr "settings.applications"}}
|
||||
</h4>
|
||||
|
||||
{{template "user/settings/applications_oauth2_list" .}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{template "base/footer" .}}
|
7
templates/org/settings/applications_oauth2_edit.tmpl
Normal file
7
templates/org/settings/applications_oauth2_edit.tmpl
Normal file
|
@ -0,0 +1,7 @@
|
|||
{{template "base/head" .}}
|
||||
<div class="page-content organization settings options">
|
||||
{{template "org/header" .}}
|
||||
|
||||
{{template "user/settings/applications_oauth2_edit_form" .}}
|
||||
</div>
|
||||
{{template "base/footer" .}}
|
|
@ -12,6 +12,11 @@
|
|||
<a class="{{if .PageIsOrgSettingsLabels}}active{{end}} item" href="{{.OrgLink}}/settings/labels">
|
||||
{{.locale.Tr "repo.labels"}}
|
||||
</a>
|
||||
{{if .EnableOAuth2}}
|
||||
<a class="{{if .PageIsSettingsApplications}}active{{end}} item" href="{{.OrgLink}}/settings/applications">
|
||||
{{.locale.Tr "settings.applications"}}
|
||||
</a>
|
||||
{{end}}
|
||||
<a class="{{if .PageIsSettingsDelete}}active{{end}} item" href="{{.OrgLink}}/settings/delete">
|
||||
{{.locale.Tr "org.settings.delete"}}
|
||||
</a>
|
||||
|
|
|
@ -1,59 +1,6 @@
|
|||
<h4 class="ui top attached header">
|
||||
{{.locale.Tr "settings.manage_oauth2_applications"}}
|
||||
</h4>
|
||||
<div class="ui attached segment">
|
||||
<div class="ui key list">
|
||||
<div class="item">
|
||||
{{.locale.Tr "settings.oauth2_application_create_description"}}
|
||||
</div>
|
||||
{{range $app := .Applications}}
|
||||
<div class="item">
|
||||
<div class="right floated content">
|
||||
<a href="{{$.Link}}/oauth2/{{$app.ID}}" class="ui primary tiny button">
|
||||
{{svg "octicon-pencil" 16 "mr-2"}}
|
||||
{{$.locale.Tr "settings.oauth2_application_edit"}}
|
||||
</a>
|
||||
<button class="ui red tiny button delete-button" data-modal-id="remove-gitea-oauth2-application"
|
||||
data-url="{{AppSubUrl}}/user/settings/applications/oauth2/delete"
|
||||
data-id="{{$app.ID}}">
|
||||
{{svg "octicon-trash" 16 "mr-2"}}
|
||||
{{$.locale.Tr "settings.delete_key"}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="content">
|
||||
<strong>{{$app.Name}}</strong>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui attached bottom segment">
|
||||
<h5 class="ui top header">
|
||||
{{.locale.Tr "settings.create_oauth2_application"}}
|
||||
</h5>
|
||||
<form class="ui form ignore-dirty" action="{{.Link}}/oauth2" method="post">
|
||||
{{.CsrfTokenHtml}}
|
||||
<div class="field {{if .Err_AppName}}error{{end}}">
|
||||
<label for="application-name">{{.locale.Tr "settings.oauth2_application_name"}}</label>
|
||||
<input id="application-name" name="application_name" value="{{.application_name}}" required>
|
||||
</div>
|
||||
<div class="field {{if .Err_RedirectURI}}error{{end}}">
|
||||
<label for="redirect-uri">{{.locale.Tr "settings.oauth2_redirect_uri"}}</label>
|
||||
<input type="url" name="redirect_uri" id="redirect-uri">
|
||||
</div>
|
||||
<button class="ui green button">
|
||||
{{.locale.Tr "settings.create_oauth2_application_button"}}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="ui small basic delete modal" id="remove-gitea-oauth2-application">
|
||||
<div class="ui icon header">
|
||||
{{svg "octicon-trash"}}
|
||||
{{.locale.Tr "settings.remove_oauth2_application"}}
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>{{.locale.Tr "settings.oauth2_application_remove_description"}}</p>
|
||||
</div>
|
||||
{{template "base/delete_modal_actions" .}}
|
||||
</div>
|
||||
{{template "user/settings/applications_oauth2_list" .}}
|
||||
|
||||
|
|
|
@ -1,68 +1,8 @@
|
|||
{{template "base/head" .}}
|
||||
<div class="page-content user settings applications">
|
||||
{{template "user/settings/navbar" .}}
|
||||
<div class="ui container">
|
||||
{{template "base/alert" .}}
|
||||
<h4 class="ui top attached header">
|
||||
{{.locale.Tr "settings.edit_oauth2_application"}}
|
||||
</h4>
|
||||
<div class="ui attached segment">
|
||||
<p>{{.locale.Tr "settings.oauth2_application_create_description"}}</p>
|
||||
</div>
|
||||
<div class="ui attached segment form ignore-dirty">
|
||||
{{.CsrfTokenHtml}}
|
||||
<div class="field">
|
||||
<label for="client-id">{{.locale.Tr "settings.oauth2_client_id"}}</label>
|
||||
<input id="client-id" readonly value="{{.App.ClientID}}">
|
||||
</div>
|
||||
{{if .ClientSecret}}
|
||||
<div class="field">
|
||||
<label for="client-secret">{{.locale.Tr "settings.oauth2_client_secret"}}</label>
|
||||
<input id="client-secret" type="text" readonly value="{{.ClientSecret}}">
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="field">
|
||||
<label for="client-secret">{{.locale.Tr "settings.oauth2_client_secret"}}</label>
|
||||
<input id="client-secret" type="password" readonly value="averysecuresecret">
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="item">
|
||||
<!-- TODO add regenerate secret functionality */ -->
|
||||
{{.locale.Tr "settings.oauth2_regenerate_secret_hint"}}
|
||||
<form class="ui form ignore-dirty" action="{{AppSubUrl}}/user/settings/applications/oauth2/{{.App.ID}}/regenerate_secret" method="post">
|
||||
{{.CsrfTokenHtml}}
|
||||
<a href="#" onclick="event.target.parentNode.submit()">{{.locale.Tr "settings.oauth2_regenerate_secret"}}</a>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui attached bottom segment">
|
||||
<form class="ui form ignore-dirty" action="{{AppSubUrl}}/user/settings/applications/oauth2/{{.App.ID}}" method="post">
|
||||
{{.CsrfTokenHtml}}
|
||||
<div class="field {{if .Err_AppName}}error{{end}}">
|
||||
<label for="application-name">{{.locale.Tr "settings.oauth2_application_name"}}</label>
|
||||
<input id="application-name" value="{{.App.Name}}" name="application_name" required>
|
||||
</div>
|
||||
<div class="field {{if .Err_RedirectURI}}error{{end}}">
|
||||
<label for="redirect-uri">{{.locale.Tr "settings.oauth2_redirect_uri"}}</label>
|
||||
<input type="url" name="redirect_uri" value="{{.App.PrimaryRedirectURI}}" id="redirect-uri">
|
||||
</div>
|
||||
<button class="ui green button">
|
||||
{{.locale.Tr "settings.save_application"}}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="ui small basic delete modal" id="delete-oauth2-application">
|
||||
<div class="ui icon header">
|
||||
{{svg "octicon-trash"}}
|
||||
{{.locale.Tr "settings.remove_oauth2_application"}}
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>{{.locale.Tr "settings.remove_oauth2_application_desc"}}</p>
|
||||
</div>
|
||||
{{template "base/delete_modal_actions" .}}
|
||||
{{template "user/settings/applications_oauth2_edit_form" .}}
|
||||
</div>
|
||||
|
||||
{{template "base/footer" .}}
|
||||
|
|
51
templates/user/settings/applications_oauth2_edit_form.tmpl
Normal file
51
templates/user/settings/applications_oauth2_edit_form.tmpl
Normal file
|
@ -0,0 +1,51 @@
|
|||
<div class="ui container">
|
||||
{{template "base/alert" .}}
|
||||
<h4 class="ui top attached header">
|
||||
{{.locale.Tr "settings.edit_oauth2_application"}}
|
||||
</h4>
|
||||
<div class="ui attached segment">
|
||||
<p>{{.locale.Tr "settings.oauth2_application_create_description"}}</p>
|
||||
</div>
|
||||
<div class="ui attached segment form ignore-dirty">
|
||||
{{.CsrfTokenHtml}}
|
||||
<div class="field">
|
||||
<label for="client-id">{{.locale.Tr "settings.oauth2_client_id"}}</label>
|
||||
<input id="client-id" readonly value="{{.App.ClientID}}">
|
||||
</div>
|
||||
{{if .ClientSecret}}
|
||||
<div class="field">
|
||||
<label for="client-secret">{{.locale.Tr "settings.oauth2_client_secret"}}</label>
|
||||
<input id="client-secret" type="text" readonly value="{{.ClientSecret}}">
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="field">
|
||||
<label for="client-secret">{{.locale.Tr "settings.oauth2_client_secret"}}</label>
|
||||
<input id="client-secret" type="password" readonly value="averysecuresecret">
|
||||
</div>
|
||||
{{end}}
|
||||
<div class="item">
|
||||
<!-- TODO add regenerate secret functionality */ -->
|
||||
<form class="ui form ignore-dirty" action="{{.FormActionPath}}/regenerate_secret" method="post">
|
||||
{{.CsrfTokenHtml}}
|
||||
{{.locale.Tr "settings.oauth2_regenerate_secret_hint"}}
|
||||
<button class="ui tertiary button" type="submit">{{.locale.Tr "settings.oauth2_regenerate_secret"}}</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui attached bottom segment">
|
||||
<form class="ui form ignore-dirty" action="{{.FormActionPath}}" method="post">
|
||||
{{.CsrfTokenHtml}}
|
||||
<div class="field {{if .Err_AppName}}error{{end}}">
|
||||
<label for="application-name">{{.locale.Tr "settings.oauth2_application_name"}}</label>
|
||||
<input id="application-name" value="{{.App.Name}}" name="application_name" required>
|
||||
</div>
|
||||
<div class="field {{if .Err_RedirectURI}}error{{end}}">
|
||||
<label for="redirect-uri">{{.locale.Tr "settings.oauth2_redirect_uri"}}</label>
|
||||
<input type="url" name="redirect_uri" value="{{.App.PrimaryRedirectURI}}" id="redirect-uri">
|
||||
</div>
|
||||
<button class="ui green button">
|
||||
{{.locale.Tr "settings.save_application"}}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
55
templates/user/settings/applications_oauth2_list.tmpl
Normal file
55
templates/user/settings/applications_oauth2_list.tmpl
Normal file
|
@ -0,0 +1,55 @@
|
|||
<div class="ui attached segment">
|
||||
<div class="ui key list">
|
||||
<div class="item">
|
||||
{{.locale.Tr "settings.oauth2_application_create_description"}}
|
||||
</div>
|
||||
{{range $app := .Applications}}
|
||||
<div class="item">
|
||||
<div class="right floated content">
|
||||
<a href="{{$.Link}}/oauth2/{{$app.ID}}" class="ui primary tiny button">
|
||||
{{svg "octicon-pencil" 16 "mr-2"}}
|
||||
{{$.locale.Tr "settings.oauth2_application_edit"}}
|
||||
</a>
|
||||
<button class="ui red tiny button delete-button" data-modal-id="remove-gitea-oauth2-application"
|
||||
data-url="{{$.Link}}/oauth2/{{$app.ID}}/delete">
|
||||
{{svg "octicon-trash" 16 "mr-2"}}
|
||||
{{$.locale.Tr "settings.delete_key"}}
|
||||
</button>
|
||||
</div>
|
||||
<div class="content">
|
||||
<strong>{{$app.Name}}</strong>
|
||||
</div>
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="ui attached bottom segment">
|
||||
<h5 class="ui top header">
|
||||
{{.locale.Tr "settings.create_oauth2_application"}}
|
||||
</h5>
|
||||
<form class="ui form ignore-dirty" action="{{.Link}}/oauth2" method="post">
|
||||
{{.CsrfTokenHtml}}
|
||||
<div class="field {{if .Err_AppName}}error{{end}}">
|
||||
<label for="application-name">{{.locale.Tr "settings.oauth2_application_name"}}</label>
|
||||
<input id="application-name" name="application_name" value="{{.application_name}}" required>
|
||||
</div>
|
||||
<div class="field {{if .Err_RedirectURI}}error{{end}}">
|
||||
<label for="redirect-uri">{{.locale.Tr "settings.oauth2_redirect_uri"}}</label>
|
||||
<input type="url" name="redirect_uri" id="redirect-uri">
|
||||
</div>
|
||||
<button class="ui green button">
|
||||
{{.locale.Tr "settings.create_oauth2_application_button"}}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="ui small basic delete modal" id="remove-gitea-oauth2-application">
|
||||
<div class="ui icon header">
|
||||
{{svg "octicon-trash"}}
|
||||
{{.locale.Tr "settings.remove_oauth2_application"}}
|
||||
</div>
|
||||
<div class="content">
|
||||
<p>{{.locale.Tr "settings.oauth2_application_remove_description"}}</p>
|
||||
</div>
|
||||
{{template "base/delete_modal_actions" .}}
|
||||
</div>
|
|
@ -10,8 +10,7 @@
|
|||
<div class="item">
|
||||
<div class="right floated content">
|
||||
<button class="ui red tiny button delete-button" data-modal-id="revoke-gitea-oauth2-grant"
|
||||
data-url="{{AppSubUrl}}/user/settings/applications/oauth2/revoke"
|
||||
data-id="{{$grant.ID}}">
|
||||
data-url="{{AppSubUrl}}/user/settings/applications/oauth2/{{$grant.ApplicationID}}/revoke/{{$grant.ID}}">
|
||||
{{$.locale.Tr "settings.revoke_key"}}
|
||||
</button>
|
||||
</div>
|
||||
|
|
|
@ -1804,7 +1804,9 @@ a.ui.label:hover {
|
|||
border: 1px solid var(--color-light-border);
|
||||
color: var(--color-text);
|
||||
}
|
||||
|
||||
.ui.tertiary.button {
|
||||
border: none;
|
||||
}
|
||||
.page-content .ui.button {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue