From ba1646a0c399c1c07cf39a1ee8a74b5f5cee6272 Mon Sep 17 00:00:00 2001 From: Yang Luo Date: Fri, 31 Dec 2021 00:36:36 +0800 Subject: [PATCH] Add cert pages. --- controllers/cert.go | 116 +++++++++++++++ object/adapter.go | 5 + object/cert.go | 146 +++++++++++++++++++ routers/router.go | 6 + web/package.json | 1 + web/src/App.js | 14 +- web/src/CertEditPage.js | 254 +++++++++++++++++++++++++++++++++ web/src/CertListPage.js | 230 +++++++++++++++++++++++++++++ web/src/backend/CertBackend.js | 56 ++++++++ web/yarn.lock | 5 + 10 files changed, 832 insertions(+), 1 deletion(-) create mode 100644 controllers/cert.go create mode 100644 object/cert.go create mode 100644 web/src/CertEditPage.js create mode 100644 web/src/CertListPage.js create mode 100644 web/src/backend/CertBackend.js diff --git a/controllers/cert.go b/controllers/cert.go new file mode 100644 index 00000000..583b5383 --- /dev/null +++ b/controllers/cert.go @@ -0,0 +1,116 @@ +// Copyright 2021 The casbin Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package controllers + +import ( + "encoding/json" + + "github.com/astaxie/beego/utils/pagination" + "github.com/casbin/casdoor/object" + "github.com/casbin/casdoor/util" +) + +// GetCerts +// @Title GetCerts +// @Tag Cert API +// @Description get certs +// @Param owner query string true "The owner of certs" +// @Success 200 {array} object.Cert The Response object +// @router /get-certs [get] +func (c *ApiController) GetCerts() { + owner := c.Input().Get("owner") + limit := c.Input().Get("pageSize") + page := c.Input().Get("p") + field := c.Input().Get("field") + value := c.Input().Get("value") + sortField := c.Input().Get("sortField") + sortOrder := c.Input().Get("sortOrder") + if limit == "" || page == "" { + c.Data["json"] = object.GetMaskedCerts(object.GetCerts(owner)) + c.ServeJSON() + } else { + limit := util.ParseInt(limit) + paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetCertCount(owner, field, value))) + certs := object.GetMaskedCerts(object.GetPaginationCerts(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)) + c.ResponseOk(certs, paginator.Nums()) + } +} + +// @Title GetCert +// @Tag Cert API +// @Description get cert +// @Param id query string true "The id of the cert" +// @Success 200 {object} object.Cert The Response object +// @router /get-cert [get] +func (c *ApiController) GetCert() { + id := c.Input().Get("id") + + c.Data["json"] = object.GetMaskedCert(object.GetCert(id)) + c.ServeJSON() +} + +// @Title UpdateCert +// @Tag Cert API +// @Description update cert +// @Param id query string true "The id of the cert" +// @Param body body object.Cert true "The details of the cert" +// @Success 200 {object} controllers.Response The Response object +// @router /update-cert [post] +func (c *ApiController) UpdateCert() { + id := c.Input().Get("id") + + var cert object.Cert + err := json.Unmarshal(c.Ctx.Input.RequestBody, &cert) + if err != nil { + panic(err) + } + + c.Data["json"] = wrapActionResponse(object.UpdateCert(id, &cert)) + c.ServeJSON() +} + +// @Title AddCert +// @Tag Cert API +// @Description add cert +// @Param body body object.Cert true "The details of the cert" +// @Success 200 {object} controllers.Response The Response object +// @router /add-cert [post] +func (c *ApiController) AddCert() { + var cert object.Cert + err := json.Unmarshal(c.Ctx.Input.RequestBody, &cert) + if err != nil { + panic(err) + } + + c.Data["json"] = wrapActionResponse(object.AddCert(&cert)) + c.ServeJSON() +} + +// @Title DeleteCert +// @Tag Cert API +// @Description delete cert +// @Param body body object.Cert true "The details of the cert" +// @Success 200 {object} controllers.Response The Response object +// @router /delete-cert [post] +func (c *ApiController) DeleteCert() { + var cert object.Cert + err := json.Unmarshal(c.Ctx.Input.RequestBody, &cert) + if err != nil { + panic(err) + } + + c.Data["json"] = wrapActionResponse(object.DeleteCert(&cert)) + c.ServeJSON() +} diff --git a/object/adapter.go b/object/adapter.go index 313b957d..a5637cac 100644 --- a/object/adapter.go +++ b/object/adapter.go @@ -145,6 +145,11 @@ func (a *Adapter) createTable() { panic(err) } + err = a.Engine.Sync2(new(Cert)) + if err != nil { + panic(err) + } + err = a.Engine.Sync2(new(Ldap)) if err != nil { panic(err) diff --git a/object/cert.go b/object/cert.go new file mode 100644 index 00000000..0f04a06d --- /dev/null +++ b/object/cert.go @@ -0,0 +1,146 @@ +// Copyright 2021 The casbin Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package object + +import ( + "fmt" + + "github.com/casbin/casdoor/util" + "xorm.io/core" +) + +type Cert struct { + Owner string `xorm:"varchar(100) notnull pk" json:"owner"` + Name string `xorm:"varchar(100) notnull pk" json:"name"` + CreatedTime string `xorm:"varchar(100)" json:"createdTime"` + + DisplayName string `xorm:"varchar(100)" json:"displayName"` + Scope string `xorm:"varchar(100)" json:"scope"` + Type string `xorm:"varchar(100)" json:"type"` + CryptoAlgorithm string `xorm:"varchar(100)" json:"cryptoAlgorithm"` + BitSize int `json:"bitSize"` + ExpireInYears int `json:"expireInYears"` + + PublicKey string `xorm:"mediumtext" json:"publicKey"` + PrivateKey string `xorm:"mediumtext" json:"privateKey"` +} + +func GetMaskedCert(cert *Cert) *Cert { + if cert == nil { + return nil + } + + return cert +} + +func GetMaskedCerts(certs []*Cert) []*Cert { + for _, cert := range certs { + cert = GetMaskedCert(cert) + } + return certs +} + +func GetCertCount(owner, field, value string) int { + session := adapter.Engine.Where("owner=?", owner) + if field != "" && value != "" { + session = session.And(fmt.Sprintf("%s like ?", util.SnakeString(field)), fmt.Sprintf("%%%s%%", value)) + } + count, err := session.Count(&Cert{}) + if err != nil { + panic(err) + } + + return int(count) +} + +func GetCerts(owner string) []*Cert { + certs := []*Cert{} + err := adapter.Engine.Desc("created_time").Find(&certs, &Cert{Owner: owner}) + if err != nil { + panic(err) + } + + return certs +} + +func GetPaginationCerts(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Cert { + certs := []*Cert{} + session := GetSession(owner, offset, limit, field, value, sortField, sortOrder) + err := session.Find(&certs) + if err != nil { + panic(err) + } + + return certs +} + +func getCert(owner string, name string) *Cert { + if owner == "" || name == "" { + return nil + } + + cert := Cert{Owner: owner, Name: name} + existed, err := adapter.Engine.Get(&cert) + if err != nil { + panic(err) + } + + if existed { + return &cert + } else { + return nil + } +} + +func GetCert(id string) *Cert { + owner, name := util.GetOwnerAndNameFromId(id) + return getCert(owner, name) +} + +func UpdateCert(id string, cert *Cert) bool { + owner, name := util.GetOwnerAndNameFromId(id) + if getCert(owner, name) == nil { + return false + } + + affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(cert) + if err != nil { + panic(err) + } + + return affected != 0 +} + +func AddCert(cert *Cert) bool { + affected, err := adapter.Engine.Insert(cert) + if err != nil { + panic(err) + } + + return affected != 0 +} + +func DeleteCert(cert *Cert) bool { + affected, err := adapter.Engine.ID(core.PK{cert.Owner, cert.Name}).Delete(&Cert{}) + if err != nil { + panic(err) + } + + return affected != 0 +} + +func (p *Cert) GetId() string { + return fmt.Sprintf("%s/%s", p.Owner, p.Name) +} diff --git a/routers/router.go b/routers/router.go index 5b4aca78..d0cf384b 100644 --- a/routers/router.go +++ b/routers/router.go @@ -128,6 +128,12 @@ func initAPI() { beego.Router("/api/add-syncer", &controllers.ApiController{}, "POST:AddSyncer") beego.Router("/api/delete-syncer", &controllers.ApiController{}, "POST:DeleteSyncer") + beego.Router("/api/get-certs", &controllers.ApiController{}, "GET:GetCerts") + beego.Router("/api/get-cert", &controllers.ApiController{}, "GET:GetCert") + beego.Router("/api/update-cert", &controllers.ApiController{}, "POST:UpdateCert") + beego.Router("/api/add-cert", &controllers.ApiController{}, "POST:AddCert") + beego.Router("/api/delete-cert", &controllers.ApiController{}, "POST:DeleteCert") + beego.Router("/api/send-email", &controllers.ApiController{}, "POST:SendEmail") beego.Router("/api/send-sms", &controllers.ApiController{}, "POST:SendSms") diff --git a/web/package.json b/web/package.json index 4acdf558..1b4bda08 100644 --- a/web/package.json +++ b/web/package.json @@ -13,6 +13,7 @@ "codemirror": "^5.61.1", "copy-to-clipboard": "^3.3.1", "craco-less": "^1.17.1", + "file-saver": "^2.0.5", "i18n-iso-countries": "^7.0.0", "i18next": "^19.8.9", "moment": "^2.29.1", diff --git a/web/src/App.js b/web/src/App.js index e569c4ea..f8c9fe9b 100644 --- a/web/src/App.js +++ b/web/src/App.js @@ -28,7 +28,6 @@ import ProviderEditPage from "./ProviderEditPage"; import ApplicationListPage from "./ApplicationListPage"; import ApplicationEditPage from "./ApplicationEditPage"; import ResourceListPage from "./ResourceListPage"; -// import ResourceEditPage from "./ResourceEditPage"; import LdapEditPage from "./LdapEditPage"; import LdapSyncPage from "./LdapSyncPage"; import TokenListPage from "./TokenListPage"; @@ -38,6 +37,8 @@ import WebhookListPage from "./WebhookListPage"; import WebhookEditPage from "./WebhookEditPage"; import SyncerListPage from "./SyncerListPage"; import SyncerEditPage from "./SyncerEditPage"; +import CertListPage from "./CertListPage"; +import CertEditPage from "./CertEditPage"; import AccountPage from "./account/AccountPage"; import HomePage from "./basic/HomePage"; import CustomGithubCorner from "./CustomGithubCorner"; @@ -115,6 +116,8 @@ class App extends Component { this.setState({ selectedMenuKey: '/webhooks' }); } else if (uri.includes('/syncers')) { this.setState({ selectedMenuKey: '/syncers' }); + } else if (uri.includes('/certs')) { + this.setState({ selectedMenuKey: '/certs' }); } else if (uri.includes('/signup')) { this.setState({ selectedMenuKey: '/signup' }); } else if (uri.includes('/login')) { @@ -376,6 +379,13 @@ class App extends Component { ); + res.push( + + + {i18next.t("general:Certs")} + + + ); res.push( @@ -440,6 +450,8 @@ class App extends Component { this.renderLoginIfNotLoggedIn()}/> this.renderLoginIfNotLoggedIn()}/> this.renderLoginIfNotLoggedIn()}/> + this.renderLoginIfNotLoggedIn()}/> + this.renderLoginIfNotLoggedIn()}/> this.renderLoginIfNotLoggedIn()}/> }/> { + this.setState({ + cert: cert, + }); + }); + } + + parseCertField(key, value) { + if (["port"].includes(key)) { + value = Setting.myParseInt(value); + } + return value; + } + + updateCertField(key, value) { + value = this.parseCertField(key, value); + + let cert = this.state.cert; + cert[key] = value; + this.setState({ + cert: cert, + }); + } + + renderCert() { + return ( + + {i18next.t("cert:Edit Cert")}     + + + + } style={(Setting.isMobile())? {margin: '5px'}:{}} type="inner"> + + + {Setting.getLabel(i18next.t("general:Name"), i18next.t("general:Name - Tooltip"))} : + + + { + this.updateCertField('name', e.target.value); + }} /> + + + + + {Setting.getLabel(i18next.t("general:Display name"), i18next.t("general:Display name - Tooltip"))} : + + + { + this.updateCertField('displayName', e.target.value); + }} /> + + + + + {Setting.getLabel(i18next.t("cert:Scope"), i18next.t("cert:Scope - Tooltip"))} : + + + + + + + + {Setting.getLabel(i18next.t("cert:Type"), i18next.t("cert:Type - Tooltip"))} : + + + + + + + + {Setting.getLabel(i18next.t("cert:Crypto algorithm"), i18next.t("cert:Crypto algorithm - Tooltip"))} : + + + + + + + + {Setting.getLabel(i18next.t("cert:Bit size"), i18next.t("cert:Bit size - Tooltip"))} : + + + { + this.updateCertField('bitSize', value); + }} /> + + + + + {Setting.getLabel(i18next.t("cert:Expire in years"), i18next.t("cert:Expire in years - Tooltip"))} : + + + { + this.updateCertField('expireInYears', value); + }} /> + + + + + {Setting.getLabel(i18next.t("cert:Public key"), i18next.t("cert:Public key - Tooltip"))} : + + + + +