mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-25 08:20:30 +08:00
Compare commits
28 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4dd67a8dcb | ||
![]() |
deed857788 | ||
![]() |
802995ed16 | ||
![]() |
b14554a5ba | ||
![]() |
4665ffa759 | ||
![]() |
f914e8e929 | ||
![]() |
dc33b41107 | ||
![]() |
ee8dd23a56 | ||
![]() |
08d0269e30 | ||
![]() |
8e5cd18c91 | ||
![]() |
32b4d98c2a | ||
![]() |
2ea58cd639 | ||
![]() |
45d2745b67 | ||
![]() |
cba338eef2 | ||
![]() |
c428de6e42 | ||
![]() |
9bca6bb72e | ||
![]() |
cd966116d4 | ||
![]() |
9abf1b9d73 | ||
![]() |
6aaba6debd | ||
![]() |
77565712e0 | ||
![]() |
d025259db7 | ||
![]() |
aafdc546fa | ||
![]() |
539ca2d731 | ||
![]() |
ea326b3513 | ||
![]() |
98ef766fb4 | ||
![]() |
e94ada9ea2 | ||
![]() |
4ea482223d | ||
![]() |
d55ae7d1d2 |
@@ -68,7 +68,7 @@ m = (r.subOwner == p.subOwner || p.subOwner == "*") && \
|
||||
|
||||
Enforcer.ClearPolicy()
|
||||
|
||||
//if len(Enforcer.GetPolicy()) == 0 {
|
||||
// if len(Enforcer.GetPolicy()) == 0 {
|
||||
if true {
|
||||
ruleText := `
|
||||
p, built-in, *, *, *, *, *
|
||||
@@ -83,7 +83,7 @@ p, *, *, GET, /api/get-account, *, *
|
||||
p, *, *, GET, /api/userinfo, *, *
|
||||
p, *, *, *, /api/login/oauth, *, *
|
||||
p, *, *, GET, /api/get-application, *, *
|
||||
p, *, *, GET, /api/get-applications, *, *
|
||||
p, *, *, GET, /api/get-organization-applications, *, *
|
||||
p, *, *, GET, /api/get-user, *, *
|
||||
p, *, *, GET, /api/get-user-application, *, *
|
||||
p, *, *, GET, /api/get-resources, *, *
|
||||
@@ -92,7 +92,6 @@ p, *, *, POST, /api/buy-product, *, *
|
||||
p, *, *, GET, /api/get-payment, *, *
|
||||
p, *, *, POST, /api/update-payment, *, *
|
||||
p, *, *, POST, /api/invoice-payment, *, *
|
||||
p, *, *, GET, /api/get-providers, *, *
|
||||
p, *, *, POST, /api/notify-payment, *, *
|
||||
p, *, *, POST, /api/unlink, *, *
|
||||
p, *, *, POST, /api/set-password, *, *
|
||||
|
@@ -31,8 +31,7 @@ import (
|
||||
|
||||
const AliyunCaptchaVerifyUrl = "http://afs.aliyuncs.com"
|
||||
|
||||
type AliyunCaptchaProvider struct {
|
||||
}
|
||||
type AliyunCaptchaProvider struct{}
|
||||
|
||||
func NewAliyunCaptchaProvider() *AliyunCaptchaProvider {
|
||||
captcha := &AliyunCaptchaProvider{}
|
||||
|
@@ -16,8 +16,7 @@ package captcha
|
||||
|
||||
import "github.com/casdoor/casdoor/object"
|
||||
|
||||
type DefaultCaptchaProvider struct {
|
||||
}
|
||||
type DefaultCaptchaProvider struct{}
|
||||
|
||||
func NewDefaultCaptchaProvider() *DefaultCaptchaProvider {
|
||||
captcha := &DefaultCaptchaProvider{}
|
||||
|
81
captcha/geetest.go
Normal file
81
captcha/geetest.go
Normal file
@@ -0,0 +1,81 @@
|
||||
// Copyright 2022 The Casdoor 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 captcha
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/casdoor/casdoor/util"
|
||||
)
|
||||
|
||||
const GEETESTCaptchaVerifyUrl = "http://gcaptcha4.geetest.com/validate"
|
||||
|
||||
type GEETESTCaptchaProvider struct{}
|
||||
|
||||
func NewGEETESTCaptchaProvider() *GEETESTCaptchaProvider {
|
||||
captcha := &GEETESTCaptchaProvider{}
|
||||
return captcha
|
||||
}
|
||||
|
||||
func (captcha *GEETESTCaptchaProvider) VerifyCaptcha(token, clientSecret string) (bool, error) {
|
||||
pathData, err := url.ParseQuery(token)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
signToken := util.GetHmacSha256(clientSecret, pathData["lot_number"][0])
|
||||
|
||||
formData := make(url.Values)
|
||||
formData["lot_number"] = []string{pathData["lot_number"][0]}
|
||||
formData["captcha_output"] = []string{pathData["captcha_output"][0]}
|
||||
formData["pass_token"] = []string{pathData["pass_token"][0]}
|
||||
formData["gen_time"] = []string{pathData["gen_time"][0]}
|
||||
formData["sign_token"] = []string{signToken}
|
||||
captchaId := pathData["captcha_id"][0]
|
||||
|
||||
cli := http.Client{Timeout: time.Second * 5}
|
||||
resp, err := cli.PostForm(fmt.Sprintf("%s?captcha_id=%s", GEETESTCaptchaVerifyUrl, captchaId), formData)
|
||||
if err != nil || resp.StatusCode != 200 {
|
||||
return false, err
|
||||
}
|
||||
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
type captchaResponse struct {
|
||||
Result string `json:"result"`
|
||||
Reason string `json:"reason"`
|
||||
}
|
||||
captchaResp := &captchaResponse{}
|
||||
err = json.Unmarshal(body, captchaResp)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if captchaResp.Result == "success" {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, errors.New(captchaResp.Reason)
|
||||
}
|
@@ -25,8 +25,7 @@ import (
|
||||
|
||||
const HCaptchaVerifyUrl = "https://hcaptcha.com/siteverify"
|
||||
|
||||
type HCaptchaProvider struct {
|
||||
}
|
||||
type HCaptchaProvider struct{}
|
||||
|
||||
func NewHCaptchaProvider() *HCaptchaProvider {
|
||||
captcha := &HCaptchaProvider{}
|
||||
|
@@ -27,6 +27,8 @@ func GetCaptchaProvider(captchaType string) CaptchaProvider {
|
||||
return NewHCaptchaProvider()
|
||||
} else if captchaType == "Aliyun Captcha" {
|
||||
return NewAliyunCaptchaProvider()
|
||||
} else if captchaType == "GEETEST" {
|
||||
return NewGEETESTCaptchaProvider()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@@ -25,8 +25,7 @@ import (
|
||||
|
||||
const ReCaptchaVerifyUrl = "https://recaptcha.net/recaptcha/api/siteverify"
|
||||
|
||||
type ReCaptchaProvider struct {
|
||||
}
|
||||
type ReCaptchaProvider struct{}
|
||||
|
||||
func NewReCaptchaProvider() *ReCaptchaProvider {
|
||||
captcha := &ReCaptchaProvider{}
|
||||
|
@@ -48,8 +48,8 @@ func GetConfigInt64(key string) (int64, error) {
|
||||
}
|
||||
|
||||
func init() {
|
||||
//this array contains the beego configuration items that may be modified via env
|
||||
var presetConfigItems = []string{"httpport", "appname"}
|
||||
// this array contains the beego configuration items that may be modified via env
|
||||
presetConfigItems := []string{"httpport", "appname"}
|
||||
for _, key := range presetConfigItems {
|
||||
if value, ok := os.LookupEnv(key); ok {
|
||||
beego.AppConfig.Set(key, value)
|
||||
|
@@ -32,7 +32,7 @@ func TestGetConfString(t *testing.T) {
|
||||
{"Should be return value", "key", "value"},
|
||||
}
|
||||
|
||||
//do some set up job
|
||||
// do some set up job
|
||||
|
||||
os.Setenv("appname", "casbin")
|
||||
os.Setenv("key", "value")
|
||||
@@ -58,7 +58,7 @@ func TestGetConfInt(t *testing.T) {
|
||||
{"Should be return 8000", "verificationCodeTimeout", 10},
|
||||
}
|
||||
|
||||
//do some set up job
|
||||
// do some set up job
|
||||
os.Setenv("httpport", "8001")
|
||||
|
||||
err := beego.LoadAppConfig("ini", "app.conf")
|
||||
|
@@ -94,6 +94,29 @@ func (c *ApiController) GetUserApplication() {
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// GetOrganizationApplications
|
||||
// @Title GetOrganizationApplications
|
||||
// @Tag Application API
|
||||
// @Description get the detail of the organization's application
|
||||
// @Param organization query string true "The organization name"
|
||||
// @Success 200 {array} object.Application The Response object
|
||||
// @router /get-organization-applications [get]
|
||||
func (c *ApiController) GetOrganizationApplications() {
|
||||
userId := c.GetSessionUsername()
|
||||
owner := c.Input().Get("owner")
|
||||
organization := c.Input().Get("organization")
|
||||
|
||||
if organization == "" {
|
||||
c.ResponseError("Parameter organization is missing")
|
||||
return
|
||||
}
|
||||
|
||||
var applications []*object.Application
|
||||
applications = object.GetApplicationsByOrganizationName(owner, organization)
|
||||
c.Data["json"] = object.GetMaskedApplications(applications, userId)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
// UpdateApplication
|
||||
// @Title UpdateApplication
|
||||
// @Tag Application API
|
||||
|
@@ -44,7 +44,6 @@ func tokenToResponse(token *object.Token) *Response {
|
||||
return &Response{Status: "error", Msg: "fail to get accessToken", Data: token.AccessToken}
|
||||
}
|
||||
return &Response{Status: "ok", Msg: "", Data: token.AccessToken}
|
||||
|
||||
}
|
||||
|
||||
// HandleLoggedIn ...
|
||||
@@ -86,7 +85,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
||||
// The prompt page needs the user to be signed in
|
||||
c.SetSessionUsername(userId)
|
||||
}
|
||||
} else if form.Type == ResponseTypeToken || form.Type == ResponseTypeIdToken { //implicit flow
|
||||
} else if form.Type == ResponseTypeToken || form.Type == ResponseTypeIdToken { // implicit flow
|
||||
if !object.IsGrantTypeValid(form.Type, application.GrantTypes) {
|
||||
resp = &Response{Status: "error", Msg: fmt.Sprintf("error: grant_type: %s is not supported in this application", form.Type), Data: ""}
|
||||
} else {
|
||||
@@ -94,7 +93,6 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
||||
token, _ := object.GetTokenByUser(application, user, scope, c.Ctx.Request.Host)
|
||||
resp = tokenToResponse(token)
|
||||
}
|
||||
|
||||
} else if form.Type == ResponseTypeSaml { // saml flow
|
||||
res, redirectUrl, err := object.GetSamlResponse(application, user, form.SamlRequest, c.Ctx.Request.Host)
|
||||
if err != nil {
|
||||
@@ -103,7 +101,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
|
||||
}
|
||||
resp = &Response{Status: "ok", Msg: "", Data: res, Data2: redirectUrl}
|
||||
} else if form.Type == ResponseTypeCas {
|
||||
//not oauth but CAS SSO protocol
|
||||
// not oauth but CAS SSO protocol
|
||||
service := c.Input().Get("service")
|
||||
resp = wrapErrorResponse(nil)
|
||||
if service != "" {
|
||||
@@ -430,7 +428,7 @@ func (c *ApiController) Login() {
|
||||
} else if provider.Category == "SAML" {
|
||||
resp = &Response{Status: "error", Msg: "The account does not exist"}
|
||||
}
|
||||
//resp = &Response{Status: "ok", Msg: "", Data: res}
|
||||
// resp = &Response{Status: "ok", Msg: "", Data: res}
|
||||
} else { // form.Method != "signup"
|
||||
userId := c.GetSessionUsername()
|
||||
if userId == "" {
|
||||
|
@@ -44,14 +44,13 @@ func (c *RootController) CasValidate() {
|
||||
return
|
||||
}
|
||||
if ok, response, issuedService, _ := object.GetCasTokenByTicket(ticket); ok {
|
||||
//check whether service is the one for which we previously issued token
|
||||
// check whether service is the one for which we previously issued token
|
||||
if issuedService == service {
|
||||
c.Ctx.Output.Body([]byte(fmt.Sprintf("yes\n%s\n", response.User)))
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
//token not found
|
||||
// token not found
|
||||
c.Ctx.Output.Body([]byte("no\n"))
|
||||
}
|
||||
|
||||
@@ -83,39 +82,39 @@ func (c *RootController) CasP3ServiceAndProxyValidate() {
|
||||
Xmlns: "http://www.yale.edu/tp/cas",
|
||||
}
|
||||
|
||||
//check whether all required parameters are met
|
||||
// check whether all required parameters are met
|
||||
if service == "" || ticket == "" {
|
||||
c.sendCasAuthenticationResponseErr(InvalidRequest, "service and ticket must exist", format)
|
||||
return
|
||||
}
|
||||
ok, response, issuedService, userId := object.GetCasTokenByTicket(ticket)
|
||||
//find the token
|
||||
// find the token
|
||||
if ok {
|
||||
//check whether service is the one for which we previously issued token
|
||||
// check whether service is the one for which we previously issued token
|
||||
if strings.HasPrefix(service, issuedService) {
|
||||
serviceResponse.Success = response
|
||||
} else {
|
||||
//service not match
|
||||
// service not match
|
||||
c.sendCasAuthenticationResponseErr(InvalidService, fmt.Sprintf("service %s and %s does not match", service, issuedService), format)
|
||||
return
|
||||
}
|
||||
} else {
|
||||
//token not found
|
||||
// token not found
|
||||
c.sendCasAuthenticationResponseErr(InvalidTicket, fmt.Sprintf("Ticket %s not recognized", ticket), format)
|
||||
return
|
||||
}
|
||||
|
||||
if pgtUrl != "" && serviceResponse.Failure == nil {
|
||||
//that means we are in proxy web flow
|
||||
// that means we are in proxy web flow
|
||||
pgt := object.StoreCasTokenForPgt(serviceResponse.Success, service, userId)
|
||||
pgtiou := serviceResponse.Success.ProxyGrantingTicket
|
||||
//todo: check whether it is https
|
||||
// todo: check whether it is https
|
||||
pgtUrlObj, err := url.Parse(pgtUrl)
|
||||
if pgtUrlObj.Scheme != "https" {
|
||||
c.sendCasAuthenticationResponseErr(InvalidProxyCallback, "callback is not https", format)
|
||||
return
|
||||
}
|
||||
//make a request to pgturl passing pgt and pgtiou
|
||||
// make a request to pgturl passing pgt and pgtiou
|
||||
if err != nil {
|
||||
c.sendCasAuthenticationResponseErr(InteralError, err.Error(), format)
|
||||
return
|
||||
@@ -133,7 +132,7 @@ func (c *RootController) CasP3ServiceAndProxyValidate() {
|
||||
|
||||
resp, err := http.DefaultClient.Do(request)
|
||||
if err != nil || !(resp.StatusCode >= 200 && resp.StatusCode < 400) {
|
||||
//failed to send request
|
||||
// failed to send request
|
||||
c.sendCasAuthenticationResponseErr(InvalidProxyCallback, err.Error(), format)
|
||||
return
|
||||
}
|
||||
@@ -184,7 +183,6 @@ func (c *RootController) CasProxy() {
|
||||
c.Data["xml"] = serviceResponse
|
||||
c.ServeXML()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func (c *RootController) SamlValidate() {
|
||||
|
88
controllers/enforcer.go
Normal file
88
controllers/enforcer.go
Normal file
@@ -0,0 +1,88 @@
|
||||
// Copyright 2022 The Casdoor 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/casdoor/casdoor/object"
|
||||
)
|
||||
|
||||
func (c *ApiController) Enforce() {
|
||||
userId := c.GetSessionUsername()
|
||||
if userId == "" {
|
||||
c.ResponseError("Please sign in first")
|
||||
return
|
||||
}
|
||||
|
||||
var permissionRule object.PermissionRule
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permissionRule)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.Data["json"] = object.Enforce(userId, &permissionRule)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
func (c *ApiController) BatchEnforce() {
|
||||
userId := c.GetSessionUsername()
|
||||
if userId == "" {
|
||||
c.ResponseError("Please sign in first")
|
||||
return
|
||||
}
|
||||
|
||||
var permissionRules []object.PermissionRule
|
||||
err := json.Unmarshal(c.Ctx.Input.RequestBody, &permissionRules)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
c.Data["json"] = object.BatchEnforce(userId, permissionRules)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
func (c *ApiController) GetAllObjects() {
|
||||
userId := c.GetSessionUsername()
|
||||
if userId == "" {
|
||||
c.ResponseError("Please sign in first")
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = object.GetAllObjects(userId)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
func (c *ApiController) GetAllActions() {
|
||||
userId := c.GetSessionUsername()
|
||||
if userId == "" {
|
||||
c.ResponseError("Please sign in first")
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = object.GetAllActions(userId)
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
func (c *ApiController) GetAllRoles() {
|
||||
userId := c.GetSessionUsername()
|
||||
if userId == "" {
|
||||
c.ResponseError("Please sign in first")
|
||||
return
|
||||
}
|
||||
|
||||
c.Data["json"] = object.GetAllRoles(userId)
|
||||
c.ServeJSON()
|
||||
}
|
@@ -30,7 +30,7 @@ type LdapServer struct {
|
||||
}
|
||||
|
||||
type LdapResp struct {
|
||||
//Groups []LdapRespGroup `json:"groups"`
|
||||
// Groups []LdapRespGroup `json:"groups"`
|
||||
Users []object.LdapRespUser `json:"users"`
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ func (c *ApiController) GetLdapUser() {
|
||||
Uid: user.Uid,
|
||||
Cn: user.Cn,
|
||||
GroupId: user.GidNumber,
|
||||
//GroupName: groupsMap[user.GidNumber].Cn,
|
||||
// GroupName: groupsMap[user.GidNumber].Cn,
|
||||
Uuid: user.Uuid,
|
||||
Email: util.GetMaxLenStr(user.Mail, user.Email, user.EmailAddress),
|
||||
Phone: util.GetMaxLenStr(user.TelephoneNumber, user.Mobile, user.MobileTelephoneNumber),
|
||||
|
@@ -58,7 +58,10 @@ func (c *ApiController) GetProducts() {
|
||||
func (c *ApiController) GetProduct() {
|
||||
id := c.Input().Get("id")
|
||||
|
||||
c.Data["json"] = object.GetProduct(id)
|
||||
product := object.GetProduct(id)
|
||||
object.ExtendProductWithProviders(product)
|
||||
|
||||
c.Data["json"] = product
|
||||
c.ServeJSON()
|
||||
}
|
||||
|
||||
|
@@ -16,6 +16,7 @@ package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/astaxie/beego/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
|
@@ -16,6 +16,7 @@ package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/astaxie/beego/utils/pagination"
|
||||
"github.com/casdoor/casdoor/object"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
|
@@ -24,7 +24,6 @@ func NewArgon2idCredManager() *Argon2idCredManager {
|
||||
}
|
||||
|
||||
func (cm *Argon2idCredManager) GetHashedPassword(password string, userSalt string, organizationSalt string) string {
|
||||
|
||||
hash, err := argon2id.CreateHash(password, argon2id.DefaultParams)
|
||||
if err != nil {
|
||||
return ""
|
||||
|
@@ -17,6 +17,7 @@ package cred
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
|
||||
"golang.org/x/crypto/pbkdf2"
|
||||
)
|
||||
|
||||
@@ -36,4 +37,4 @@ func (cm *Pbkdf2SaltCredManager) GetHashedPassword(password string, userSalt str
|
||||
|
||||
func (cm *Pbkdf2SaltCredManager) IsPasswordCorrect(plainPwd string, hashedPwd string, userSalt string, organizationSalt string) bool {
|
||||
return hashedPwd == cm.GetHashedPassword(plainPwd, userSalt, organizationSalt)
|
||||
}
|
||||
}
|
||||
|
2
go.mod
2
go.mod
@@ -14,6 +14,7 @@ require (
|
||||
github.com/casdoor/goth v1.69.0-FIX2
|
||||
github.com/casdoor/oss v1.2.0
|
||||
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc
|
||||
github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b
|
||||
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df
|
||||
github.com/go-ldap/ldap/v3 v3.3.0
|
||||
@@ -23,6 +24,7 @@ require (
|
||||
github.com/google/uuid v1.2.0
|
||||
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
|
||||
github.com/lestrrat-go/jwx v0.9.0
|
||||
github.com/lib/pq v1.8.0
|
||||
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
|
||||
github.com/qiangmzsx/string-adapter/v2 v2.1.0
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
|
2
go.sum
2
go.sum
@@ -125,6 +125,7 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f h1:q/DpyjJjZs94bziQ7YkBmIlpqbVP7yw179rnzoNVX1M=
|
||||
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f/go.mod h1:QGrK8vMWWHQYQ3QU9bw9Y9OPNfxccGzfb41qjvVeXtY=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc h1:VRRKCwnzqk8QCaRC4os14xoKDdbHqqlJtJA0oc1ZAjg=
|
||||
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
|
||||
github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b h1:L63RATZFZuFMXy6ixnKmv3eNAXwYQF6HW1vd4IYsQqQ=
|
||||
github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b/go.mod h1:EYSpSkwoEcryMmQGfhol2IiB3IMN9IIIaNd/wcAQMGQ=
|
||||
@@ -173,6 +174,7 @@ github.com/goji/httpauth v0.0.0-20160601135302-2da839ab0f4d/go.mod h1:nnjvkQ9ptG
|
||||
github.com/golang-jwt/jwt/v4 v4.1.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||
github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU=
|
||||
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
|
||||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
|
@@ -59,12 +59,12 @@ func (idp *AdfsIdProvider) SetHttpClient(client *http.Client) {
|
||||
}
|
||||
|
||||
func (idp *AdfsIdProvider) getConfig(hostUrl string) *oauth2.Config {
|
||||
var endpoint = oauth2.Endpoint{
|
||||
endpoint := oauth2.Endpoint{
|
||||
AuthURL: fmt.Sprintf("%s/adfs/oauth2/authorize", hostUrl),
|
||||
TokenURL: fmt.Sprintf("%s/adfs/oauth2/token", hostUrl),
|
||||
}
|
||||
|
||||
var config = &oauth2.Config{
|
||||
config := &oauth2.Config{
|
||||
Endpoint: endpoint,
|
||||
}
|
||||
|
||||
|
@@ -56,12 +56,12 @@ func (idp *AlipayIdProvider) SetHttpClient(client *http.Client) {
|
||||
|
||||
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
|
||||
func (idp *AlipayIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
|
||||
var endpoint = oauth2.Endpoint{
|
||||
endpoint := oauth2.Endpoint{
|
||||
AuthURL: "https://openauth.alipay.com/oauth2/publicAppAuthorize.htm",
|
||||
TokenURL: "https://openapi.alipay.com/gateway.do",
|
||||
}
|
||||
|
||||
var config = &oauth2.Config{
|
||||
config := &oauth2.Config{
|
||||
Scopes: []string{"", ""},
|
||||
Endpoint: endpoint,
|
||||
ClientID: clientId,
|
||||
@@ -206,7 +206,6 @@ func (idp *AlipayIdProvider) postWithBody(body interface{}, targetUrl string) ([
|
||||
return nil, err
|
||||
}
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@@ -46,12 +46,12 @@ func (idp *BaiduIdProvider) SetHttpClient(client *http.Client) {
|
||||
}
|
||||
|
||||
func (idp *BaiduIdProvider) getConfig() *oauth2.Config {
|
||||
var endpoint = oauth2.Endpoint{
|
||||
endpoint := oauth2.Endpoint{
|
||||
AuthURL: "https://openapi.baidu.com/oauth/2.0/authorize",
|
||||
TokenURL: "https://openapi.baidu.com/oauth/2.0/token",
|
||||
}
|
||||
|
||||
var config = &oauth2.Config{
|
||||
config := &oauth2.Config{
|
||||
Scopes: []string{"email"},
|
||||
Endpoint: endpoint,
|
||||
}
|
||||
|
@@ -47,12 +47,12 @@ func (idp *BilibiliIdProvider) SetHttpClient(client *http.Client) {
|
||||
|
||||
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
|
||||
func (idp *BilibiliIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
|
||||
var endpoint = oauth2.Endpoint{
|
||||
endpoint := oauth2.Endpoint{
|
||||
TokenURL: "https://api.bilibili.com/x/account-oauth2/v1/token",
|
||||
AuthURL: "http://member.bilibili.com/arcopen/fn/user/account/info",
|
||||
}
|
||||
|
||||
var config = &oauth2.Config{
|
||||
config := &oauth2.Config{
|
||||
Scopes: []string{"", ""},
|
||||
Endpoint: endpoint,
|
||||
ClientID: clientId,
|
||||
@@ -104,7 +104,6 @@ func (idp *BilibiliIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||
}
|
||||
|
||||
data, err := idp.postWithBody(pTokenParams, idp.Config.Endpoint.TokenURL)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -167,7 +166,6 @@ func (idp *BilibiliIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro
|
||||
userInfoUrl := fmt.Sprintf("%s?%s", idp.Config.Endpoint.AuthURL, params.Encode())
|
||||
|
||||
resp, err := idp.Client.Get(userInfoUrl)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@@ -72,7 +72,6 @@ func (idp *CasdoorIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -82,7 +81,7 @@ func (idp *CasdoorIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//check if token is expired
|
||||
// check if token is expired
|
||||
if pToken.ExpiresIn <= 0 {
|
||||
return nil, fmt.Errorf("%s", pToken.AccessToken)
|
||||
}
|
||||
@@ -91,7 +90,6 @@ func (idp *CasdoorIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||
Expiry: time.Unix(time.Now().Unix()+int64(pToken.ExpiresIn), 0),
|
||||
}
|
||||
return token, nil
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -125,7 +123,7 @@ func (idp *CasdoorIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//add accesstoken to bearer token
|
||||
// add accesstoken to bearer token
|
||||
request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", accessToken))
|
||||
resp, err := idp.Client.Do(request)
|
||||
if err != nil {
|
||||
@@ -155,5 +153,4 @@ func (idp *CasdoorIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error
|
||||
AvatarUrl: cdUserinfo.AvatarUrl,
|
||||
}
|
||||
return userInfo, nil
|
||||
|
||||
}
|
||||
|
@@ -36,7 +36,7 @@ func NewCustomIdProvider(clientId string, clientSecret string, redirectUrl strin
|
||||
idp := &CustomIdProvider{}
|
||||
idp.UserInfoUrl = userInfoUrl
|
||||
|
||||
var config = &oauth2.Config{
|
||||
config := &oauth2.Config{
|
||||
ClientID: clientId,
|
||||
ClientSecret: clientSecret,
|
||||
RedirectURL: redirectUrl,
|
||||
@@ -76,7 +76,7 @@ func (idp *CustomIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
//add accessToken to request header
|
||||
// add accessToken to request header
|
||||
request.Header.Add("Authorization", fmt.Sprintf("Bearer %s", accessToken))
|
||||
resp, err := idp.Client.Do(request)
|
||||
if err != nil {
|
||||
|
@@ -48,12 +48,12 @@ func (idp *DingTalkIdProvider) SetHttpClient(client *http.Client) {
|
||||
|
||||
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
|
||||
func (idp *DingTalkIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
|
||||
var endpoint = oauth2.Endpoint{
|
||||
endpoint := oauth2.Endpoint{
|
||||
AuthURL: "https://api.dingtalk.com/v1.0/contact/users/me",
|
||||
TokenURL: "https://api.dingtalk.com/v1.0/oauth2/userAccessToken",
|
||||
}
|
||||
|
||||
var config = &oauth2.Config{
|
||||
config := &oauth2.Config{
|
||||
// DingTalk not allow to set scopes,here it is just a placeholder,
|
||||
// convenient to use later
|
||||
Scopes: []string{"", ""},
|
||||
|
@@ -42,12 +42,12 @@ func (idp *DouyinIdProvider) SetHttpClient(client *http.Client) {
|
||||
}
|
||||
|
||||
func (idp *DouyinIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
|
||||
var endpoint = oauth2.Endpoint{
|
||||
endpoint := oauth2.Endpoint{
|
||||
TokenURL: "https://open.douyin.com/oauth/access_token",
|
||||
AuthURL: "https://open.douyin.com/platform/oauth/connect",
|
||||
}
|
||||
|
||||
var config = &oauth2.Config{
|
||||
config := &oauth2.Config{
|
||||
Scopes: []string{"user_info"},
|
||||
Endpoint: endpoint,
|
||||
ClientID: clientId,
|
||||
|
@@ -46,11 +46,11 @@ func (idp *FacebookIdProvider) SetHttpClient(client *http.Client) {
|
||||
|
||||
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
|
||||
func (idp *FacebookIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
|
||||
var endpoint = oauth2.Endpoint{
|
||||
endpoint := oauth2.Endpoint{
|
||||
TokenURL: "https://graph.facebook.com/oauth/access_token",
|
||||
}
|
||||
|
||||
var config = &oauth2.Config{
|
||||
config := &oauth2.Config{
|
||||
Scopes: []string{"email,public_profile"},
|
||||
Endpoint: endpoint,
|
||||
ClientID: clientId,
|
||||
@@ -62,9 +62,9 @@ func (idp *FacebookIdProvider) getConfig(clientId string, clientSecret string, r
|
||||
}
|
||||
|
||||
type FacebookAccessToken struct {
|
||||
AccessToken string `json:"access_token"` //Interface call credentials
|
||||
TokenType string `json:"token_type"` //Access token type
|
||||
ExpiresIn int64 `json:"expires_in"` //access_token interface call credential timeout time, unit (seconds)
|
||||
AccessToken string `json:"access_token"` // Interface call credentials
|
||||
TokenType string `json:"token_type"` // Access token type
|
||||
ExpiresIn int64 `json:"expires_in"` // access_token interface call credential timeout time, unit (seconds)
|
||||
}
|
||||
|
||||
type FacebookCheckToken struct {
|
||||
|
@@ -49,11 +49,11 @@ func (idp *GiteeIdProvider) SetHttpClient(client *http.Client) {
|
||||
|
||||
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
|
||||
func (idp *GiteeIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
|
||||
var endpoint = oauth2.Endpoint{
|
||||
endpoint := oauth2.Endpoint{
|
||||
TokenURL: "https://gitee.com/oauth/token",
|
||||
}
|
||||
|
||||
var config = &oauth2.Config{
|
||||
config := &oauth2.Config{
|
||||
Scopes: []string{"user_info emails"},
|
||||
|
||||
Endpoint: endpoint,
|
||||
|
@@ -49,12 +49,12 @@ func (idp *GithubIdProvider) SetHttpClient(client *http.Client) {
|
||||
}
|
||||
|
||||
func (idp *GithubIdProvider) getConfig() *oauth2.Config {
|
||||
var endpoint = oauth2.Endpoint{
|
||||
endpoint := oauth2.Endpoint{
|
||||
AuthURL: "https://github.com/login/oauth/authorize",
|
||||
TokenURL: "https://github.com/login/oauth/access_token",
|
||||
}
|
||||
|
||||
var config = &oauth2.Config{
|
||||
config := &oauth2.Config{
|
||||
Scopes: []string{"user:email", "read:user"},
|
||||
Endpoint: endpoint,
|
||||
}
|
||||
@@ -93,7 +93,6 @@ func (idp *GithubIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||
}
|
||||
|
||||
return token, nil
|
||||
|
||||
}
|
||||
|
||||
//{
|
||||
|
@@ -46,11 +46,11 @@ func (idp *GitlabIdProvider) SetHttpClient(client *http.Client) {
|
||||
|
||||
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
|
||||
func (idp *GitlabIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
|
||||
var endpoint = oauth2.Endpoint{
|
||||
endpoint := oauth2.Endpoint{
|
||||
TokenURL: "https://gitlab.com/oauth/token",
|
||||
}
|
||||
|
||||
var config = &oauth2.Config{
|
||||
config := &oauth2.Config{
|
||||
Scopes: []string{"read_user+profile"},
|
||||
Endpoint: endpoint,
|
||||
ClientID: clientId,
|
||||
|
@@ -47,12 +47,12 @@ func (idp *GoogleIdProvider) SetHttpClient(client *http.Client) {
|
||||
}
|
||||
|
||||
func (idp *GoogleIdProvider) getConfig() *oauth2.Config {
|
||||
var endpoint = oauth2.Endpoint{
|
||||
endpoint := oauth2.Endpoint{
|
||||
AuthURL: "https://accounts.google.com/o/oauth2/auth",
|
||||
TokenURL: "https://accounts.google.com/o/oauth2/token",
|
||||
}
|
||||
|
||||
var config = &oauth2.Config{
|
||||
config := &oauth2.Config{
|
||||
Scopes: []string{"profile", "email"},
|
||||
Endpoint: endpoint,
|
||||
}
|
||||
|
12
idp/goth.go
12
idp/goth.go
@@ -207,7 +207,7 @@ func NewGothIdProvider(providerType string, clientId string, clientSecret string
|
||||
return &idp
|
||||
}
|
||||
|
||||
//Goth's idp all implement the Client method, but since the goth.Provider interface does not provide to modify idp's client method, reflection is required
|
||||
// Goth's idp all implement the Client method, but since the goth.Provider interface does not provide to modify idp's client method, reflection is required
|
||||
func (idp *GothIdProvider) SetHttpClient(client *http.Client) {
|
||||
idpClient := reflect.ValueOf(idp.Provider).Elem().FieldByName("HTTPClient")
|
||||
idpClient.Set(reflect.ValueOf(client))
|
||||
@@ -225,8 +225,8 @@ func (idp *GothIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
//Need to construct variables supported by goth
|
||||
//to call the function to obtain accessToken
|
||||
// Need to construct variables supported by goth
|
||||
// to call the function to obtain accessToken
|
||||
value = url.Values{}
|
||||
value.Add("code", code)
|
||||
}
|
||||
@@ -235,7 +235,7 @@ func (idp *GothIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
//Get ExpiresAt's value
|
||||
// Get ExpiresAt's value
|
||||
valueOfExpire := reflect.ValueOf(idp.Session).Elem().FieldByName("ExpiresAt")
|
||||
if valueOfExpire.IsValid() {
|
||||
expireAt = valueOfExpire.Interface().(time.Time)
|
||||
@@ -264,8 +264,8 @@ func getUser(gothUser goth.User, provider string) *UserInfo {
|
||||
Email: gothUser.Email,
|
||||
AvatarUrl: gothUser.AvatarURL,
|
||||
}
|
||||
//Some idp return an empty Name
|
||||
//so construct the Name with firstname and lastname or nickname
|
||||
// Some idp return an empty Name
|
||||
// so construct the Name with firstname and lastname or nickname
|
||||
if user.Username == "" {
|
||||
if gothUser.FirstName != "" && gothUser.LastName != "" {
|
||||
user.Username = getName(gothUser.FirstName, gothUser.LastName)
|
||||
|
@@ -43,7 +43,7 @@ func (idp *InfoflowInternalIdProvider) SetHttpClient(client *http.Client) {
|
||||
}
|
||||
|
||||
func (idp *InfoflowInternalIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
|
||||
var config = &oauth2.Config{
|
||||
config := &oauth2.Config{
|
||||
ClientID: clientId,
|
||||
ClientSecret: clientSecret,
|
||||
RedirectURL: redirectUrl,
|
||||
@@ -139,7 +139,7 @@ type InfoflowInternalUserInfo struct {
|
||||
|
||||
// get more detail via: https://qy.baidu.com/doc/index.html#/inner_serverapi/contacts?id=%e8%8e%b7%e5%8f%96%e6%88%90%e5%91%98
|
||||
func (idp *InfoflowInternalIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
||||
//Get userid first
|
||||
// Get userid first
|
||||
accessToken := token.AccessToken
|
||||
code := token.Extra("code").(string)
|
||||
resp, err := idp.Client.Get(fmt.Sprintf("https://qy.im.baidu.com/api/user/getuserinfo?access_token=%s&code=%s&agentid=%s", accessToken, code, idp.AgentId))
|
||||
@@ -159,7 +159,7 @@ func (idp *InfoflowInternalIdProvider) GetUserInfo(token *oauth2.Token) (*UserIn
|
||||
if userResp.Errcode != 0 {
|
||||
return nil, fmt.Errorf("userIdResp.Errcode = %d, userIdResp.Errmsg = %s", userResp.Errcode, userResp.Errmsg)
|
||||
}
|
||||
//Use userid and accesstoken to get user information
|
||||
// Use userid and accesstoken to get user information
|
||||
resp, err = idp.Client.Get(fmt.Sprintf("https://api.im.baidu.com/api/user/get?access_token=%s&userid=%s", accessToken, userResp.UserId))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@@ -47,7 +47,7 @@ func (idp *InfoflowIdProvider) SetHttpClient(client *http.Client) {
|
||||
}
|
||||
|
||||
func (idp *InfoflowIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
|
||||
var config = &oauth2.Config{
|
||||
config := &oauth2.Config{
|
||||
ClientID: clientId,
|
||||
ClientSecret: clientSecret,
|
||||
RedirectURL: redirectUrl,
|
||||
@@ -136,7 +136,7 @@ type InfoflowUserInfo struct {
|
||||
|
||||
// get more detail via: https://qy.baidu.com/doc/index.html#/third_serverapi/contacts?id=%e8%8e%b7%e5%8f%96%e6%88%90%e5%91%98
|
||||
func (idp *InfoflowIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
||||
//Get userid first
|
||||
// Get userid first
|
||||
accessToken := token.AccessToken
|
||||
code := token.Extra("code").(string)
|
||||
resp, err := idp.Client.Get(fmt.Sprintf("https://api.im.baidu.com/api/user/getuserinfo?access_token=%s&code=%s&agentid=%s", accessToken, code, idp.AgentId))
|
||||
@@ -156,7 +156,7 @@ func (idp *InfoflowIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro
|
||||
if userResp.Errcode != 0 {
|
||||
return nil, fmt.Errorf("userIdResp.Errcode = %d, userIdResp.Errmsg = %s", userResp.Errcode, userResp.Errmsg)
|
||||
}
|
||||
//Use userid and accesstoken to get user information
|
||||
// Use userid and accesstoken to get user information
|
||||
resp, err = idp.Client.Get(fmt.Sprintf("https://api.im.baidu.com/api/user/get?access_token=%s&userid=%s", accessToken, userResp.UserId))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@@ -45,11 +45,11 @@ func (idp *LarkIdProvider) SetHttpClient(client *http.Client) {
|
||||
|
||||
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
|
||||
func (idp *LarkIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
|
||||
var endpoint = oauth2.Endpoint{
|
||||
endpoint := oauth2.Endpoint{
|
||||
TokenURL: "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
|
||||
}
|
||||
|
||||
var config = &oauth2.Config{
|
||||
config := &oauth2.Config{
|
||||
Scopes: []string{},
|
||||
Endpoint: endpoint,
|
||||
ClientID: clientId,
|
||||
|
@@ -47,11 +47,11 @@ func (idp *LinkedInIdProvider) SetHttpClient(client *http.Client) {
|
||||
|
||||
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
|
||||
func (idp *LinkedInIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
|
||||
var endpoint = oauth2.Endpoint{
|
||||
endpoint := oauth2.Endpoint{
|
||||
TokenURL: "https://www.linkedIn.com/oauth/v2/accessToken",
|
||||
}
|
||||
|
||||
var config = &oauth2.Config{
|
||||
config := &oauth2.Config{
|
||||
Scopes: []string{"email,public_profile"},
|
||||
Endpoint: endpoint,
|
||||
ClientID: clientId,
|
||||
@@ -63,8 +63,8 @@ func (idp *LinkedInIdProvider) getConfig(clientId string, clientSecret string, r
|
||||
}
|
||||
|
||||
type LinkedInAccessToken struct {
|
||||
AccessToken string `json:"access_token"` //Interface call credentials
|
||||
ExpiresIn int64 `json:"expires_in"` //access_token interface call credential timeout time, unit (seconds)
|
||||
AccessToken string `json:"access_token"` // Interface call credentials
|
||||
ExpiresIn int64 `json:"expires_in"` // access_token interface call credential timeout time, unit (seconds)
|
||||
}
|
||||
|
||||
// GetToken use code get access_token (*operation of getting code ought to be done in front)
|
||||
|
@@ -48,12 +48,12 @@ func (idp *OktaIdProvider) SetHttpClient(client *http.Client) {
|
||||
}
|
||||
|
||||
func (idp *OktaIdProvider) getConfig(hostUrl string, clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
|
||||
var endpoint = oauth2.Endpoint{
|
||||
endpoint := oauth2.Endpoint{
|
||||
TokenURL: fmt.Sprintf("%s/v1/token", hostUrl),
|
||||
AuthURL: fmt.Sprintf("%s/v1/authorize", hostUrl),
|
||||
}
|
||||
|
||||
var config = &oauth2.Config{
|
||||
config := &oauth2.Config{
|
||||
// openid is required for authentication requests
|
||||
// get more details via: https://developer.okta.com/docs/reference/api/oidc/#reserved-scopes
|
||||
Scopes: []string{"openid", "profile", "email"},
|
||||
|
@@ -48,11 +48,11 @@ func (idp *QqIdProvider) SetHttpClient(client *http.Client) {
|
||||
}
|
||||
|
||||
func (idp *QqIdProvider) getConfig() *oauth2.Config {
|
||||
var endpoint = oauth2.Endpoint{
|
||||
endpoint := oauth2.Endpoint{
|
||||
TokenURL: "https://graph.qq.com/oauth2.0/token",
|
||||
}
|
||||
|
||||
var config = &oauth2.Config{
|
||||
config := &oauth2.Config{
|
||||
Scopes: []string{"get_user_info"},
|
||||
Endpoint: endpoint,
|
||||
}
|
||||
|
@@ -47,11 +47,11 @@ func (idp *WeChatIdProvider) SetHttpClient(client *http.Client) {
|
||||
|
||||
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
|
||||
func (idp *WeChatIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
|
||||
var endpoint = oauth2.Endpoint{
|
||||
endpoint := oauth2.Endpoint{
|
||||
TokenURL: "https://graph.qq.com/oauth2.0/token",
|
||||
}
|
||||
|
||||
var config = &oauth2.Config{
|
||||
config := &oauth2.Config{
|
||||
Scopes: []string{"snsapi_login"},
|
||||
Endpoint: endpoint,
|
||||
ClientID: clientId,
|
||||
@@ -63,12 +63,12 @@ func (idp *WeChatIdProvider) getConfig(clientId string, clientSecret string, red
|
||||
}
|
||||
|
||||
type WechatAccessToken struct {
|
||||
AccessToken string `json:"access_token"` //Interface call credentials
|
||||
ExpiresIn int64 `json:"expires_in"` //access_token interface call credential timeout time, unit (seconds)
|
||||
RefreshToken string `json:"refresh_token"` //User refresh access_token
|
||||
Openid string `json:"openid"` //Unique ID of authorized user
|
||||
Scope string `json:"scope"` //The scope of user authorization, separated by commas. (,)
|
||||
Unionid string `json:"unionid"` //This field will appear if and only if the website application has been authorized by the user's UserInfo.
|
||||
AccessToken string `json:"access_token"` // Interface call credentials
|
||||
ExpiresIn int64 `json:"expires_in"` // access_token interface call credential timeout time, unit (seconds)
|
||||
RefreshToken string `json:"refresh_token"` // User refresh access_token
|
||||
Openid string `json:"openid"` // Unique ID of authorized user
|
||||
Scope string `json:"scope"` // The scope of user authorization, separated by commas. (,)
|
||||
Unionid string `json:"unionid"` // This field will appear if and only if the website application has been authorized by the user's UserInfo.
|
||||
}
|
||||
|
||||
// GetToken use code get access_token (*operation of getting code ought to be done in front)
|
||||
|
@@ -42,7 +42,7 @@ func (idp *WeChatMiniProgramIdProvider) SetHttpClient(client *http.Client) {
|
||||
}
|
||||
|
||||
func (idp *WeChatMiniProgramIdProvider) getConfig(clientId string, clientSecret string) *oauth2.Config {
|
||||
var config = &oauth2.Config{
|
||||
config := &oauth2.Config{
|
||||
ClientID: clientId,
|
||||
ClientSecret: clientSecret,
|
||||
}
|
||||
@@ -78,5 +78,4 @@ func (idp *WeChatMiniProgramIdProvider) GetSessionByCode(code string) (*WeChatMi
|
||||
return nil, fmt.Errorf("err: %s", session.Errmsg)
|
||||
}
|
||||
return &session, nil
|
||||
|
||||
}
|
||||
|
@@ -24,7 +24,7 @@ import (
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
//This idp is using wecom internal application api as idp
|
||||
// This idp is using wecom internal application api as idp
|
||||
type WeComInternalIdProvider struct {
|
||||
Client *http.Client
|
||||
Config *oauth2.Config
|
||||
@@ -44,7 +44,7 @@ func (idp *WeComInternalIdProvider) SetHttpClient(client *http.Client) {
|
||||
}
|
||||
|
||||
func (idp *WeComInternalIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
|
||||
var config = &oauth2.Config{
|
||||
config := &oauth2.Config{
|
||||
ClientID: clientId,
|
||||
ClientSecret: clientSecret,
|
||||
RedirectURL: redirectUrl,
|
||||
@@ -115,7 +115,7 @@ type WecomInternalUserInfo struct {
|
||||
}
|
||||
|
||||
func (idp *WeComInternalIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, error) {
|
||||
//Get userid first
|
||||
// Get userid first
|
||||
accessToken := token.AccessToken
|
||||
code := token.Extra("code").(string)
|
||||
resp, err := idp.Client.Get(fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo?access_token=%s&code=%s", accessToken, code))
|
||||
@@ -138,7 +138,7 @@ func (idp *WeComInternalIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo,
|
||||
if userResp.OpenId != "" {
|
||||
return nil, fmt.Errorf("not an internal user")
|
||||
}
|
||||
//Use userid and accesstoken to get user information
|
||||
// Use userid and accesstoken to get user information
|
||||
resp, err = idp.Client.Get(fmt.Sprintf("https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=%s&userid=%s", accessToken, userResp.UserId))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@@ -46,11 +46,11 @@ func (idp *WeComIdProvider) SetHttpClient(client *http.Client) {
|
||||
|
||||
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
|
||||
func (idp *WeComIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
|
||||
var endpoint = oauth2.Endpoint{
|
||||
endpoint := oauth2.Endpoint{
|
||||
TokenURL: "https://graph.qq.com/oauth2.0/token",
|
||||
}
|
||||
|
||||
var config = &oauth2.Config{
|
||||
config := &oauth2.Config{
|
||||
Scopes: []string{"snsapi_login"},
|
||||
Endpoint: endpoint,
|
||||
ClientID: clientId,
|
||||
|
@@ -48,11 +48,11 @@ func (idp *WeiBoIdProvider) SetHttpClient(client *http.Client) {
|
||||
|
||||
// getConfig return a point of Config, which describes a typical 3-legged OAuth2 flow
|
||||
func (idp *WeiBoIdProvider) getConfig(clientId string, clientSecret string, redirectUrl string) *oauth2.Config {
|
||||
var endpoint = oauth2.Endpoint{
|
||||
endpoint := oauth2.Endpoint{
|
||||
TokenURL: "https://api.weibo.com/oauth2/access_token",
|
||||
}
|
||||
|
||||
var config = &oauth2.Config{
|
||||
config := &oauth2.Config{
|
||||
Scopes: []string{""},
|
||||
Endpoint: endpoint,
|
||||
ClientID: clientId,
|
||||
|
8
main.go
8
main.go
@@ -42,9 +42,9 @@ func main() {
|
||||
proxy.InitHttpClient()
|
||||
authz.InitAuthz()
|
||||
|
||||
util.SafeGoroutine(func() {object.RunSyncUsersJob()})
|
||||
util.SafeGoroutine(func() { object.RunSyncUsersJob() })
|
||||
|
||||
//beego.DelStaticPath("/static")
|
||||
// beego.DelStaticPath("/static")
|
||||
beego.SetStaticPath("/static", "web/build/static")
|
||||
beego.BConfig.WebConfig.DirectoryIndex = true
|
||||
beego.SetStaticPath("/swagger", "swagger")
|
||||
@@ -66,14 +66,14 @@ func main() {
|
||||
beego.BConfig.WebConfig.Session.SessionProviderConfig = conf.GetConfigString("redisEndpoint")
|
||||
}
|
||||
beego.BConfig.WebConfig.Session.SessionCookieLifeTime = 3600 * 24 * 30
|
||||
//beego.BConfig.WebConfig.Session.SessionCookieSameSite = http.SameSiteNoneMode
|
||||
// beego.BConfig.WebConfig.Session.SessionCookieSameSite = http.SameSiteNoneMode
|
||||
|
||||
err := logs.SetLogger("file", `{"filename":"logs/casdoor.log","maxdays":99999,"perm":"0770"}`)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
port := beego.AppConfig.DefaultInt("httpport", 8000)
|
||||
//logs.SetLevel(logs.LevelInformational)
|
||||
// logs.SetLevel(logs.LevelInformational)
|
||||
logs.SetLogFuncCall(false)
|
||||
beego.Run(fmt.Sprintf(":%v", port))
|
||||
}
|
||||
|
@@ -21,10 +21,10 @@ import (
|
||||
"github.com/astaxie/beego"
|
||||
"github.com/casdoor/casdoor/conf"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
//_ "github.com/denisenkom/go-mssqldb" // db = mssql
|
||||
_ "github.com/go-sql-driver/mysql" // db = mysql
|
||||
//_ "github.com/lib/pq" // db = postgres
|
||||
//_ "github.com/mattn/go-sqlite3" // db = sqlite3
|
||||
_ "github.com/denisenkom/go-mssqldb" // db = mssql
|
||||
_ "github.com/go-sql-driver/mysql" // db = mysql
|
||||
_ "github.com/lib/pq" // db = postgres
|
||||
//_ "github.com/mattn/go-sqlite3" // db = sqlite3
|
||||
"xorm.io/core"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
@@ -317,7 +317,7 @@ func (application *Application) GetId() string {
|
||||
}
|
||||
|
||||
func CheckRedirectUriValid(application *Application, redirectUri string) bool {
|
||||
var validUri = false
|
||||
validUri := false
|
||||
for _, tmpUri := range application.RedirectUris {
|
||||
if strings.Contains(redirectUri, tmpUri) {
|
||||
validUri = true
|
||||
|
@@ -182,7 +182,7 @@ func CheckUserPassword(organization string, username string, password string) (*
|
||||
}
|
||||
|
||||
if user.Ldap != "" {
|
||||
//ONLY for ldap users
|
||||
// ONLY for ldap users
|
||||
return checkLdapUserPassword(user, password)
|
||||
} else {
|
||||
msg := CheckPassword(user, password)
|
||||
|
@@ -56,7 +56,7 @@ type ldapUser struct {
|
||||
Uid string
|
||||
Cn string
|
||||
GidNumber string
|
||||
//Gcn string
|
||||
// Gcn string
|
||||
Uuid string
|
||||
Mail string
|
||||
Email string
|
||||
@@ -73,7 +73,7 @@ type LdapRespUser struct {
|
||||
Uid string `json:"uid"`
|
||||
Cn string `json:"cn"`
|
||||
GroupId string `json:"groupId"`
|
||||
//GroupName string `json:"groupName"`
|
||||
// GroupName string `json:"groupName"`
|
||||
Uuid string `json:"uuid"`
|
||||
Email string `json:"email"`
|
||||
Phone string `json:"phone"`
|
||||
@@ -208,11 +208,15 @@ func GetLdapConn(host string, port int, adminUser string, adminPasswd string) (*
|
||||
|
||||
func (l *ldapConn) GetLdapUsers(baseDn string) ([]ldapUser, error) {
|
||||
SearchFilter := "(objectClass=posixAccount)"
|
||||
SearchAttributes := []string{"uidNumber", "uid", "cn", "gidNumber", "entryUUID", "mail", "email",
|
||||
"emailAddress", "telephoneNumber", "mobile", "mobileTelephoneNumber", "registeredAddress", "postalAddress"}
|
||||
SearchAttributes := []string{
|
||||
"uidNumber", "uid", "cn", "gidNumber", "entryUUID", "mail", "email",
|
||||
"emailAddress", "telephoneNumber", "mobile", "mobileTelephoneNumber", "registeredAddress", "postalAddress",
|
||||
}
|
||||
SearchFilterMsAD := "(objectClass=user)"
|
||||
SearchAttributesMsAD := []string{"uidNumber", "sAMAccountName", "cn", "gidNumber", "entryUUID", "mail", "email",
|
||||
"emailAddress", "telephoneNumber", "mobile", "mobileTelephoneNumber", "registeredAddress", "postalAddress"}
|
||||
SearchAttributesMsAD := []string{
|
||||
"uidNumber", "sAMAccountName", "cn", "gidNumber", "entryUUID", "mail", "email",
|
||||
"emailAddress", "telephoneNumber", "mobile", "mobileTelephoneNumber", "registeredAddress", "postalAddress",
|
||||
}
|
||||
var searchReq *goldap.SearchRequest
|
||||
if l.IsAD {
|
||||
searchReq = goldap.NewSearchRequest(baseDn,
|
||||
@@ -459,7 +463,7 @@ func CheckLdapUuidExist(owner string, uuids []string) []string {
|
||||
}
|
||||
}
|
||||
|
||||
for uuid, _ := range existUuidSet {
|
||||
for uuid := range existUuidSet {
|
||||
existUuids = append(existUuids, uuid)
|
||||
}
|
||||
return existUuids
|
||||
|
@@ -31,7 +31,7 @@ func GetLdapAutoSynchronizer() *LdapAutoSynchronizer {
|
||||
return globalLdapAutoSynchronizer
|
||||
}
|
||||
|
||||
//start autosync for specified ldap, old existing autosync goroutine will be ceased
|
||||
// start autosync for specified ldap, old existing autosync goroutine will be ceased
|
||||
func (l *LdapAutoSynchronizer) StartAutoSync(ldapId string) error {
|
||||
l.Lock()
|
||||
defer l.Unlock()
|
||||
@@ -48,7 +48,7 @@ func (l *LdapAutoSynchronizer) StartAutoSync(ldapId string) error {
|
||||
stopChan := make(chan struct{})
|
||||
l.ldapIdToStopChan[ldapId] = stopChan
|
||||
logs.Info(fmt.Sprintf("autoSync started for %s", ldap.Id))
|
||||
util.SafeGoroutine(func() {l.syncRoutine(ldap, stopChan)})
|
||||
util.SafeGoroutine(func() { l.syncRoutine(ldap, stopChan) })
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ func (l *LdapAutoSynchronizer) StopAutoSync(ldapId string) {
|
||||
}
|
||||
}
|
||||
|
||||
//autosync goroutine
|
||||
// autosync goroutine
|
||||
func (l *LdapAutoSynchronizer) syncRoutine(ldap *Ldap, stopChan chan struct{}) {
|
||||
ticker := time.NewTicker(time.Duration(ldap.AutoSync) * time.Minute)
|
||||
defer ticker.Stop()
|
||||
@@ -74,7 +74,7 @@ func (l *LdapAutoSynchronizer) syncRoutine(ldap *Ldap, stopChan chan struct{}) {
|
||||
}
|
||||
|
||||
UpdateLdapSyncTime(ldap.Id)
|
||||
//fetch all users
|
||||
// fetch all users
|
||||
conn, err := GetLdapConn(ldap.Host, ldap.Port, ldap.Admin, ldap.Passwd)
|
||||
if err != nil {
|
||||
logs.Warning(fmt.Sprintf("autoSync failed for %s, error %s", ldap.Id, err))
|
||||
@@ -93,10 +93,9 @@ func (l *LdapAutoSynchronizer) syncRoutine(ldap *Ldap, stopChan chan struct{}) {
|
||||
logs.Info(fmt.Sprintf("ldap autosync success, %d new users, %d existing users", len(users)-len(*existed), len(*existed)))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//start all autosync goroutine for existing ldap servers in each organizations
|
||||
// start all autosync goroutine for existing ldap servers in each organizations
|
||||
func (l *LdapAutoSynchronizer) LdapAutoSynchronizerStartUpAll() {
|
||||
organizations := []*Organization{}
|
||||
err := adapter.Engine.Desc("created_time").Find(&organizations)
|
||||
|
@@ -27,8 +27,8 @@ type Model struct {
|
||||
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
|
||||
DisplayName string `xorm:"varchar(100)" json:"displayName"`
|
||||
|
||||
ModelText string `xorm:"mediumtext" json:"modelText"`
|
||||
IsEnabled bool `json:"isEnabled"`
|
||||
ModelText string `xorm:"mediumtext" json:"modelText"`
|
||||
IsEnabled bool `json:"isEnabled"`
|
||||
}
|
||||
|
||||
func GetModelCount(owner, field, value string) int {
|
||||
|
@@ -93,9 +93,9 @@ func GetOidcDiscovery(host string) OidcDiscovery {
|
||||
func GetJsonWebKeySet() (jose.JSONWebKeySet, error) {
|
||||
certs := GetCerts("admin")
|
||||
jwks := jose.JSONWebKeySet{}
|
||||
//follows the protocol rfc 7517(draft)
|
||||
//link here: https://self-issued.info/docs/draft-ietf-jose-json-web-key.html
|
||||
//or https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key
|
||||
// follows the protocol rfc 7517(draft)
|
||||
// link here: https://self-issued.info/docs/draft-ietf-jose-json-web-key.html
|
||||
// or https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key
|
||||
for _, cert := range certs {
|
||||
certPemBlock := []byte(cert.Certificate)
|
||||
certDerBlock, _ := pem.Decode(certPemBlock)
|
||||
|
@@ -16,12 +16,7 @@ package object
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/casbin/casbin/v2"
|
||||
"github.com/casbin/casbin/v2/model"
|
||||
xormadapter "github.com/casbin/xorm-adapter/v2"
|
||||
"github.com/casdoor/casdoor/conf"
|
||||
"github.com/casdoor/casdoor/util"
|
||||
"xorm.io/core"
|
||||
)
|
||||
@@ -45,13 +40,13 @@ type Permission struct {
|
||||
}
|
||||
|
||||
type PermissionRule struct {
|
||||
PType string `xorm:"varchar(100) index not null default ''"`
|
||||
V0 string `xorm:"varchar(100) index not null default ''"`
|
||||
V1 string `xorm:"varchar(100) index not null default ''"`
|
||||
V2 string `xorm:"varchar(100) index not null default ''"`
|
||||
V3 string `xorm:"varchar(100) index not null default ''"`
|
||||
V4 string `xorm:"varchar(100) index not null default ''"`
|
||||
V5 string `xorm:"varchar(100) index not null default ''"`
|
||||
Ptype string `xorm:"varchar(100) index not null default ''" json:"ptype"`
|
||||
V0 string `xorm:"varchar(100) index not null default ''" json:"v0"`
|
||||
V1 string `xorm:"varchar(100) index not null default ''" json:"v1"`
|
||||
V2 string `xorm:"varchar(100) index not null default ''" json:"v2"`
|
||||
V3 string `xorm:"varchar(100) index not null default ''" json:"v3"`
|
||||
V4 string `xorm:"varchar(100) index not null default ''" json:"v4"`
|
||||
V5 string `xorm:"varchar(100) index not null default ''" json:"v5"`
|
||||
}
|
||||
|
||||
func GetPermissionCount(owner, field, value string) int {
|
||||
@@ -158,78 +153,6 @@ func (permission *Permission) GetId() string {
|
||||
return fmt.Sprintf("%s/%s", permission.Owner, permission.Name)
|
||||
}
|
||||
|
||||
func getEnforcer(permission *Permission) *casbin.Enforcer {
|
||||
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
|
||||
adapter, err := xormadapter.NewAdapterWithTableName(conf.GetConfigString("driverName"), conf.GetBeegoConfDataSourceName()+conf.GetConfigString("dbName"), "permission_rule", tableNamePrefix, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
modelText := `
|
||||
[request_definition]
|
||||
r = sub, obj, act
|
||||
|
||||
[policy_definition]
|
||||
p = permission, sub, obj, act
|
||||
|
||||
[policy_effect]
|
||||
e = some(where (p.eft == allow))
|
||||
|
||||
[matchers]
|
||||
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act`
|
||||
permissionModel := getModel(permission.Owner, permission.Model)
|
||||
if permissionModel != nil {
|
||||
modelText = permissionModel.ModelText
|
||||
}
|
||||
m, err := model.NewModelFromString(modelText)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
enforcer, err := casbin.NewEnforcer(m, adapter)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = enforcer.LoadFilteredPolicy(xormadapter.Filter{V0: []string{permission.GetId()}})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return enforcer
|
||||
}
|
||||
|
||||
func getPolicies(permission *Permission) [][]string {
|
||||
var policies [][]string
|
||||
for _, user := range permission.Users {
|
||||
for _, resource := range permission.Resources {
|
||||
for _, action := range permission.Actions {
|
||||
policies = append(policies, []string{permission.GetId(), user, resource, strings.ToLower(action)})
|
||||
}
|
||||
}
|
||||
}
|
||||
return policies
|
||||
}
|
||||
|
||||
func addPolicies(permission *Permission) {
|
||||
enforcer := getEnforcer(permission)
|
||||
policies := getPolicies(permission)
|
||||
|
||||
_, err := enforcer.AddPolicies(policies)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func removePolicies(permission *Permission) {
|
||||
enforcer := getEnforcer(permission)
|
||||
|
||||
_, err := enforcer.RemoveFilteredPolicy(0, permission.GetId())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func GetPermissionsByUser(userId string) []*Permission {
|
||||
permissions := []*Permission{}
|
||||
err := adapter.Engine.Where("users like ?", "%"+userId+"%").Find(&permissions)
|
||||
|
162
object/permission_enforcer.go
Normal file
162
object/permission_enforcer.go
Normal file
@@ -0,0 +1,162 @@
|
||||
// Copyright 2021 The Casdoor 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 (
|
||||
"strings"
|
||||
|
||||
"github.com/casbin/casbin/v2"
|
||||
"github.com/casbin/casbin/v2/model"
|
||||
xormadapter "github.com/casbin/xorm-adapter/v2"
|
||||
"github.com/casdoor/casdoor/conf"
|
||||
)
|
||||
|
||||
func getEnforcer(permission *Permission) *casbin.Enforcer {
|
||||
tableNamePrefix := conf.GetConfigString("tableNamePrefix")
|
||||
adapter, err := xormadapter.NewAdapterWithTableName(conf.GetConfigString("driverName"), conf.GetBeegoConfDataSourceName()+conf.GetConfigString("dbName"), "permission_rule", tableNamePrefix, true)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
modelText := `
|
||||
[request_definition]
|
||||
r = sub, obj, act
|
||||
|
||||
[policy_definition]
|
||||
p = permission, sub, obj, act
|
||||
|
||||
[policy_effect]
|
||||
e = some(where (p.eft == allow))
|
||||
|
||||
[matchers]
|
||||
m = r.sub == p.sub && r.obj == p.obj && r.act == p.act`
|
||||
permissionModel := getModel(permission.Owner, permission.Model)
|
||||
if permissionModel != nil {
|
||||
modelText = permissionModel.ModelText
|
||||
}
|
||||
m, err := model.NewModelFromString(modelText)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
enforcer, err := casbin.NewEnforcer(m, adapter)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
err = enforcer.LoadFilteredPolicy(xormadapter.Filter{V0: []string{permission.GetId()}})
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return enforcer
|
||||
}
|
||||
|
||||
func getPolicies(permission *Permission) [][]string {
|
||||
var policies [][]string
|
||||
for _, user := range permission.Users {
|
||||
for _, resource := range permission.Resources {
|
||||
for _, action := range permission.Actions {
|
||||
policies = append(policies, []string{permission.GetId(), user, resource, strings.ToLower(action)})
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, role := range permission.Roles {
|
||||
for _, resource := range permission.Resources {
|
||||
for _, action := range permission.Actions {
|
||||
policies = append(policies, []string{permission.GetId(), role, resource, strings.ToLower(action)})
|
||||
}
|
||||
}
|
||||
}
|
||||
return policies
|
||||
}
|
||||
|
||||
func addPolicies(permission *Permission) {
|
||||
enforcer := getEnforcer(permission)
|
||||
policies := getPolicies(permission)
|
||||
|
||||
_, err := enforcer.AddPolicies(policies)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func removePolicies(permission *Permission) {
|
||||
enforcer := getEnforcer(permission)
|
||||
|
||||
_, err := enforcer.RemoveFilteredPolicy(0, permission.GetId())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func Enforce(userId string, permissionRule *PermissionRule) bool {
|
||||
permission := GetPermission(permissionRule.V0)
|
||||
enforcer := getEnforcer(permission)
|
||||
allow, err := enforcer.Enforce(userId, permissionRule.V2, permissionRule.V3)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return allow
|
||||
}
|
||||
|
||||
func BatchEnforce(userId string, permissionRules []PermissionRule) []bool {
|
||||
var requests [][]interface{}
|
||||
for _, permissionRule := range permissionRules {
|
||||
requests = append(requests, []interface{}{userId, permissionRule.V2, permissionRule.V3})
|
||||
}
|
||||
permission := GetPermission(permissionRules[0].V0)
|
||||
enforcer := getEnforcer(permission)
|
||||
allow, err := enforcer.BatchEnforce(requests)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return allow
|
||||
}
|
||||
|
||||
func getAllValues(userId string, sec string, fieldIndex int) []string {
|
||||
permissions := GetPermissionsByUser(userId)
|
||||
var values []string
|
||||
for _, permission := range permissions {
|
||||
enforcer := getEnforcer(permission)
|
||||
enforcer.ClearPolicy()
|
||||
err := enforcer.LoadFilteredPolicy(xormadapter.Filter{V0: []string{permission.GetId()}, V1: []string{userId}})
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, value := range enforcer.GetModel().GetValuesForFieldInPolicyAllTypes(sec, fieldIndex) {
|
||||
values = append(values, value)
|
||||
}
|
||||
}
|
||||
return values
|
||||
}
|
||||
|
||||
func GetAllObjects(userId string) []string {
|
||||
return getAllValues(userId, "p", 2)
|
||||
}
|
||||
|
||||
func GetAllActions(userId string) []string {
|
||||
return getAllValues(userId, "p", 3)
|
||||
}
|
||||
|
||||
func GetAllRoles(userId string) []string {
|
||||
roles := GetRolesByUser(userId)
|
||||
var res []string
|
||||
for _, role := range roles {
|
||||
res = append(res, role.Name)
|
||||
}
|
||||
return res
|
||||
}
|
@@ -38,6 +38,8 @@ type Product struct {
|
||||
ReturnUrl string `xorm:"varchar(1000)" json:"returnUrl"`
|
||||
|
||||
State string `xorm:"varchar(100)" json:"state"`
|
||||
|
||||
ProviderObjs []*Provider `xorm:"-" json:"providerObjs"`
|
||||
}
|
||||
|
||||
func GetProductCount(owner, field, value string) int {
|
||||
@@ -209,3 +211,14 @@ func BuyProduct(id string, providerName string, user *User, host string) (string
|
||||
|
||||
return payUrl, err
|
||||
}
|
||||
|
||||
func ExtendProductWithProviders(product *Product) {
|
||||
product.ProviderObjs = []*Provider{}
|
||||
|
||||
m := getProviderMap(product.Owner)
|
||||
for _, providerItem := range product.Providers {
|
||||
if provider, ok := m[providerItem]; ok {
|
||||
product.ProviderObjs = append(product.ProviderObjs, provider)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -29,7 +29,7 @@ func init() {
|
||||
var err error
|
||||
logPostOnly, err = conf.GetConfigBool("logPostOnly")
|
||||
if err != nil {
|
||||
//panic(err)
|
||||
// panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -110,7 +110,7 @@ func UpdateResource(id string, resource *Resource) bool {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
//return affected != 0
|
||||
// return affected != 0
|
||||
return true
|
||||
}
|
||||
|
||||
|
@@ -35,7 +35,7 @@ import (
|
||||
uuid "github.com/satori/go.uuid"
|
||||
)
|
||||
|
||||
//returns a saml2 response
|
||||
// returns a saml2 response
|
||||
func NewSamlResponse(user *User, host string, certificate string, destination string, iss string, requestId string, redirectUri []string) (*etree.Element, error) {
|
||||
samlResponse := &etree.Element{
|
||||
Space: "samlp",
|
||||
@@ -100,7 +100,6 @@ func NewSamlResponse(user *User, host string, certificate string, destination st
|
||||
displayName.CreateElement("saml:AttributeValue").CreateAttr("xsi:type", "xs:string").Element().SetText(user.DisplayName)
|
||||
|
||||
return samlResponse, nil
|
||||
|
||||
}
|
||||
|
||||
type X509Key struct {
|
||||
@@ -114,7 +113,7 @@ func (x X509Key) GetKeyPair() (privateKey *rsa.PrivateKey, cert []byte, err erro
|
||||
return privateKey, cert, err
|
||||
}
|
||||
|
||||
//SAML METADATA
|
||||
// SAML METADATA
|
||||
type IdpEntityDescriptor struct {
|
||||
XMLName xml.Name `xml:"EntityDescriptor"`
|
||||
DS string `xml:"xmlns:ds,attr"`
|
||||
@@ -299,7 +298,7 @@ func NewSamlResponse11(user *User, requestID string, host string) *etree.Element
|
||||
Space: "samlp",
|
||||
Tag: "Response",
|
||||
}
|
||||
//create samlresponse
|
||||
// create samlresponse
|
||||
samlResponse.CreateAttr("xmlns:samlp", "urn:oasis:names:tc:SAML:1.0:protocol")
|
||||
samlResponse.CreateAttr("MajorVersion", "1")
|
||||
samlResponse.CreateAttr("MinorVersion", "1")
|
||||
@@ -315,7 +314,7 @@ func NewSamlResponse11(user *User, requestID string, host string) *etree.Element
|
||||
|
||||
samlResponse.CreateElement("samlp:Status").CreateElement("samlp:StatusCode").CreateAttr("Value", "samlp:Success")
|
||||
|
||||
//create assertion which is inside the response
|
||||
// create assertion which is inside the response
|
||||
assertion := samlResponse.CreateElement("saml:Assertion")
|
||||
assertion.CreateAttr("xmlns:saml", "urn:oasis:names:tc:SAML:1.0:assertion")
|
||||
assertion.CreateAttr("MajorVersion", "1")
|
||||
@@ -328,19 +327,19 @@ func NewSamlResponse11(user *User, requestID string, host string) *etree.Element
|
||||
condition.CreateAttr("NotBefore", now)
|
||||
condition.CreateAttr("NotOnOrAfter", expireTime)
|
||||
|
||||
//AuthenticationStatement inside assertion
|
||||
// AuthenticationStatement inside assertion
|
||||
authenticationStatement := assertion.CreateElement("saml:AuthenticationStatement")
|
||||
authenticationStatement.CreateAttr("AuthenticationMethod", "urn:oasis:names:tc:SAML:1.0:am:password")
|
||||
authenticationStatement.CreateAttr("AuthenticationInstant", now)
|
||||
|
||||
//subject inside AuthenticationStatement
|
||||
// subject inside AuthenticationStatement
|
||||
subject := assertion.CreateElement("saml:Subject")
|
||||
//nameIdentifier inside subject
|
||||
// nameIdentifier inside subject
|
||||
nameIdentifier := subject.CreateElement("saml:NameIdentifier")
|
||||
//nameIdentifier.CreateAttr("Format", "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress")
|
||||
// nameIdentifier.CreateAttr("Format", "urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress")
|
||||
nameIdentifier.SetText(user.Name)
|
||||
|
||||
//subjectConfirmation inside subject
|
||||
// subjectConfirmation inside subject
|
||||
subjectConfirmation := subject.CreateElement("saml:SubjectConfirmation")
|
||||
subjectConfirmation.CreateElement("saml:ConfirmationMethod").SetText("urn:oasis:names:tc:SAML:1.0:cm:artifact")
|
||||
|
||||
|
@@ -31,7 +31,7 @@ func init() {
|
||||
var err error
|
||||
isCloudIntranet, err = conf.GetConfigBool("isCloudIntranet")
|
||||
if err != nil {
|
||||
//panic(err)
|
||||
// panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -220,7 +220,7 @@ func DeleteTokenByAceessToken(accessToken string) (bool, *Application) {
|
||||
}
|
||||
|
||||
func GetTokenByAccessToken(accessToken string) *Token {
|
||||
//Check if the accessToken is in the database
|
||||
// Check if the accessToken is in the database
|
||||
token := Token{AccessToken: accessToken}
|
||||
existed, err := adapter.Engine.Get(&token)
|
||||
if err != nil || !existed {
|
||||
@@ -330,7 +330,7 @@ func GetOAuthToken(grantType string, clientId string, clientSecret string, code
|
||||
}
|
||||
}
|
||||
|
||||
//Check if grantType is allowed in the current application
|
||||
// Check if grantType is allowed in the current application
|
||||
|
||||
if !IsGrantTypeValid(grantType, application.GrantTypes) && tag == "" {
|
||||
return &TokenError{
|
||||
@@ -688,7 +688,7 @@ func GetWechatMiniProgramToken(application *Application, code string, host strin
|
||||
ErrorDescription: "the application does not allow to sign up new account",
|
||||
}
|
||||
}
|
||||
//Add new user
|
||||
// Add new user
|
||||
var name string
|
||||
if username != "" {
|
||||
name = username
|
||||
@@ -703,13 +703,16 @@ func GetWechatMiniProgramToken(application *Application, code string, host strin
|
||||
Avatar: avatar,
|
||||
SignupApplication: application.Name,
|
||||
WeChat: openId,
|
||||
WeChatUnionId: unionId,
|
||||
Type: "normal-user",
|
||||
CreatedTime: util.GetCurrentTime(),
|
||||
IsAdmin: false,
|
||||
IsGlobalAdmin: false,
|
||||
IsForbidden: false,
|
||||
IsDeleted: false,
|
||||
Properties: map[string]string{
|
||||
USER_PROPERTIES_WECHAT_OPEN_ID: openId,
|
||||
USER_PROPERTIES_WECHAT_UNION_ID: unionId,
|
||||
},
|
||||
}
|
||||
AddUser(user)
|
||||
}
|
||||
@@ -729,7 +732,7 @@ func GetWechatMiniProgramToken(application *Application, code string, host strin
|
||||
Application: application.Name,
|
||||
Organization: user.Owner,
|
||||
User: user.Name,
|
||||
Code: session.SessionKey, //a trick, because miniprogram does not use the code, so use the code field to save the session_key
|
||||
Code: session.SessionKey, // a trick, because miniprogram does not use the code, so use the code field to save the session_key
|
||||
AccessToken: accessToken,
|
||||
RefreshToken: refreshToken,
|
||||
ExpiresIn: application.ExpireInHours * 60,
|
||||
|
@@ -88,7 +88,7 @@ type CasAnyAttribute struct {
|
||||
|
||||
type CasAuthenticationSuccessWrapper struct {
|
||||
AuthenticationSuccess *CasAuthenticationSuccess // the token we issued
|
||||
Service string //to which service this token is issued
|
||||
Service string // to which service this token is issued
|
||||
UserId string
|
||||
}
|
||||
|
||||
@@ -116,10 +116,10 @@ type Saml11AssertionArtifact struct {
|
||||
InnerXML string `xml:",innerxml"`
|
||||
}
|
||||
|
||||
//st is short for service ticket
|
||||
// st is short for service ticket
|
||||
var stToServiceResponse sync.Map
|
||||
|
||||
//pgt is short for proxy granting ticket
|
||||
// pgt is short for proxy granting ticket
|
||||
var pgtToServiceResponse sync.Map
|
||||
|
||||
func StoreCasTokenForPgt(token *CasAuthenticationSuccess, service, userId string) string {
|
||||
@@ -262,12 +262,11 @@ func GetValidationBySaml(samlRequest string, host string) (string, string, error
|
||||
return "", "", fmt.Errorf("err: %s", err.Error())
|
||||
}
|
||||
return xmlStr, service, nil
|
||||
|
||||
}
|
||||
|
||||
func (c *CasAuthenticationSuccess) DeepCopy() CasAuthenticationSuccess {
|
||||
res := *c
|
||||
//copy proxy
|
||||
// copy proxy
|
||||
if c.Proxies != nil {
|
||||
tmp := c.Proxies.DeepCopy()
|
||||
res.Proxies = &tmp
|
||||
@@ -307,7 +306,6 @@ func (c *CasAttributes) DeepCopy() CasAttributes {
|
||||
res.ExtraAttributes[i] = &tmp
|
||||
}
|
||||
return res
|
||||
|
||||
}
|
||||
|
||||
func (c *CasUserAttributes) DeepCopy() CasUserAttributes {
|
||||
@@ -316,11 +314,11 @@ func (c *CasUserAttributes) DeepCopy() CasUserAttributes {
|
||||
Attributes: make([]*CasNamedAttribute, len(c.Attributes)),
|
||||
}
|
||||
for i, a := range c.AnyAttributes {
|
||||
var tmp = *a
|
||||
tmp := *a
|
||||
res.AnyAttributes[i] = &tmp
|
||||
}
|
||||
for i, a := range c.Attributes {
|
||||
var tmp = *a
|
||||
tmp := *a
|
||||
res.Attributes[i] = &tmp
|
||||
}
|
||||
return res
|
||||
|
@@ -24,6 +24,11 @@ import (
|
||||
"xorm.io/core"
|
||||
)
|
||||
|
||||
const (
|
||||
USER_PROPERTIES_WECHAT_UNION_ID = "wechatUnionId"
|
||||
USER_PROPERTIES_WECHAT_OPEN_ID = "wechatOpenId"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
|
||||
Name string `xorm:"varchar(100) notnull pk" json:"name"`
|
||||
@@ -73,32 +78,31 @@ type User struct {
|
||||
LastSigninTime string `xorm:"varchar(100)" json:"lastSigninTime"`
|
||||
LastSigninIp string `xorm:"varchar(100)" json:"lastSigninIp"`
|
||||
|
||||
GitHub string `xorm:"github varchar(100)" json:"github"`
|
||||
Google string `xorm:"varchar(100)" json:"google"`
|
||||
QQ string `xorm:"qq varchar(100)" json:"qq"`
|
||||
WeChat string `xorm:"wechat varchar(100)" json:"wechat"`
|
||||
WeChatUnionId string `xorm:"varchar(100)" json:"unionId"`
|
||||
Facebook string `xorm:"facebook varchar(100)" json:"facebook"`
|
||||
DingTalk string `xorm:"dingtalk varchar(100)" json:"dingtalk"`
|
||||
Weibo string `xorm:"weibo varchar(100)" json:"weibo"`
|
||||
Gitee string `xorm:"gitee varchar(100)" json:"gitee"`
|
||||
LinkedIn string `xorm:"linkedin varchar(100)" json:"linkedin"`
|
||||
Wecom string `xorm:"wecom varchar(100)" json:"wecom"`
|
||||
Lark string `xorm:"lark varchar(100)" json:"lark"`
|
||||
Gitlab string `xorm:"gitlab varchar(100)" json:"gitlab"`
|
||||
Adfs string `xorm:"adfs varchar(100)" json:"adfs"`
|
||||
Baidu string `xorm:"baidu varchar(100)" json:"baidu"`
|
||||
Alipay string `xorm:"alipay varchar(100)" json:"alipay"`
|
||||
Casdoor string `xorm:"casdoor varchar(100)" json:"casdoor"`
|
||||
Infoflow string `xorm:"infoflow varchar(100)" json:"infoflow"`
|
||||
Apple string `xorm:"apple varchar(100)" json:"apple"`
|
||||
AzureAD string `xorm:"azuread varchar(100)" json:"azuread"`
|
||||
Slack string `xorm:"slack varchar(100)" json:"slack"`
|
||||
Steam string `xorm:"steam varchar(100)" json:"steam"`
|
||||
Bilibili string `xorm:"bilibili varchar(100)" json:"bilibili"`
|
||||
Okta string `xorm:"okta varchar(100)" json:"okta"`
|
||||
Douyin string `xorm:"douyin varchar(100)" json:"douyin"`
|
||||
Custom string `xorm:"custom varchar(100)" json:"custom"`
|
||||
GitHub string `xorm:"github varchar(100)" json:"github"`
|
||||
Google string `xorm:"varchar(100)" json:"google"`
|
||||
QQ string `xorm:"qq varchar(100)" json:"qq"`
|
||||
WeChat string `xorm:"wechat varchar(100)" json:"wechat"`
|
||||
Facebook string `xorm:"facebook varchar(100)" json:"facebook"`
|
||||
DingTalk string `xorm:"dingtalk varchar(100)" json:"dingtalk"`
|
||||
Weibo string `xorm:"weibo varchar(100)" json:"weibo"`
|
||||
Gitee string `xorm:"gitee varchar(100)" json:"gitee"`
|
||||
LinkedIn string `xorm:"linkedin varchar(100)" json:"linkedin"`
|
||||
Wecom string `xorm:"wecom varchar(100)" json:"wecom"`
|
||||
Lark string `xorm:"lark varchar(100)" json:"lark"`
|
||||
Gitlab string `xorm:"gitlab varchar(100)" json:"gitlab"`
|
||||
Adfs string `xorm:"adfs varchar(100)" json:"adfs"`
|
||||
Baidu string `xorm:"baidu varchar(100)" json:"baidu"`
|
||||
Alipay string `xorm:"alipay varchar(100)" json:"alipay"`
|
||||
Casdoor string `xorm:"casdoor varchar(100)" json:"casdoor"`
|
||||
Infoflow string `xorm:"infoflow varchar(100)" json:"infoflow"`
|
||||
Apple string `xorm:"apple varchar(100)" json:"apple"`
|
||||
AzureAD string `xorm:"azuread varchar(100)" json:"azuread"`
|
||||
Slack string `xorm:"slack varchar(100)" json:"slack"`
|
||||
Steam string `xorm:"steam varchar(100)" json:"steam"`
|
||||
Bilibili string `xorm:"bilibili varchar(100)" json:"bilibili"`
|
||||
Okta string `xorm:"okta varchar(100)" json:"okta"`
|
||||
Douyin string `xorm:"douyin varchar(100)" json:"douyin"`
|
||||
Custom string `xorm:"custom varchar(100)" json:"custom"`
|
||||
|
||||
WebauthnCredentials []webauthn.Credential `xorm:"webauthnCredentials blob" json:"webauthnCredentials"`
|
||||
|
||||
@@ -243,7 +247,7 @@ func getUserByWechatId(wechatOpenId string, wechatUnionId string) *User {
|
||||
wechatUnionId = wechatOpenId
|
||||
}
|
||||
user := &User{}
|
||||
existed, err := adapter.Engine.Where("wechat = ? OR wechat = ? OR unionid = ?", wechatOpenId, wechatUnionId, wechatUnionId).Get(user)
|
||||
existed, err := adapter.Engine.Where("wechat = ? OR wechat = ?", wechatOpenId, wechatUnionId).Get(user)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -417,6 +421,10 @@ func AddUser(user *User) bool {
|
||||
}
|
||||
|
||||
organization := GetOrganizationByUser(user)
|
||||
if organization == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
user.UpdateUserPassword(organization)
|
||||
|
||||
user.UpdateUserHash()
|
||||
|
@@ -46,7 +46,7 @@ func NewAlipayPaymentProvider(appId string, appCertificate string, appPrivateKey
|
||||
}
|
||||
|
||||
func (pp *AlipayPaymentProvider) Pay(providerName string, productName string, payerName string, paymentName string, productDisplayName string, price float64, returnUrl string, notifyUrl string) (string, error) {
|
||||
//pp.Client.DebugSwitch = gopay.DebugOn
|
||||
// pp.Client.DebugSwitch = gopay.DebugOn
|
||||
|
||||
bm := gopay.BodyMap{}
|
||||
|
||||
|
@@ -25,8 +25,10 @@ import (
|
||||
"golang.org/x/net/proxy"
|
||||
)
|
||||
|
||||
var DefaultHttpClient *http.Client
|
||||
var ProxyHttpClient *http.Client
|
||||
var (
|
||||
DefaultHttpClient *http.Client
|
||||
ProxyHttpClient *http.Client
|
||||
)
|
||||
|
||||
func InitHttpClient() {
|
||||
// not use proxy
|
||||
|
@@ -78,7 +78,7 @@ func getObject(ctx *context.Context) (string, string) {
|
||||
var obj Object
|
||||
err := json.Unmarshal(body, &obj)
|
||||
if err != nil {
|
||||
//panic(err)
|
||||
// panic(err)
|
||||
return "", ""
|
||||
}
|
||||
|
||||
|
@@ -71,5 +71,4 @@ func AutoSigninFilter(ctx *context.Context) {
|
||||
setSessionUser(ctx, userId)
|
||||
return
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -30,19 +30,18 @@ func init() {
|
||||
}
|
||||
|
||||
func initAPI() {
|
||||
ns :=
|
||||
beego.NewNamespace("/",
|
||||
beego.NSNamespace("/api",
|
||||
beego.NSInclude(
|
||||
&controllers.ApiController{},
|
||||
),
|
||||
ns := beego.NewNamespace("/",
|
||||
beego.NSNamespace("/api",
|
||||
beego.NSInclude(
|
||||
&controllers.ApiController{},
|
||||
),
|
||||
beego.NSNamespace("",
|
||||
beego.NSInclude(
|
||||
&controllers.RootController{},
|
||||
),
|
||||
),
|
||||
beego.NSNamespace("",
|
||||
beego.NSInclude(
|
||||
&controllers.RootController{},
|
||||
),
|
||||
)
|
||||
),
|
||||
)
|
||||
beego.AddNamespace(ns)
|
||||
|
||||
beego.Router("/api/signup", &controllers.ApiController{}, "POST:Signup")
|
||||
@@ -84,6 +83,12 @@ func initAPI() {
|
||||
beego.Router("/api/add-permission", &controllers.ApiController{}, "POST:AddPermission")
|
||||
beego.Router("/api/delete-permission", &controllers.ApiController{}, "POST:DeletePermission")
|
||||
|
||||
beego.Router("/api/enforce", &controllers.ApiController{}, "POST:Enforce")
|
||||
beego.Router("/api/batch-enforce", &controllers.ApiController{}, "POST:BatchEnforce")
|
||||
beego.Router("/api/get-all-objects", &controllers.ApiController{}, "GET:GetAllObjects")
|
||||
beego.Router("/api/get-all-actions", &controllers.ApiController{}, "GET:GetAllActions")
|
||||
beego.Router("/api/get-all-roles", &controllers.ApiController{}, "GET:GetAllRoles")
|
||||
|
||||
beego.Router("/api/get-models", &controllers.ApiController{}, "GET:GetModels")
|
||||
beego.Router("/api/get-model", &controllers.ApiController{}, "GET:GetModel")
|
||||
beego.Router("/api/update-model", &controllers.ApiController{}, "POST:UpdateModel")
|
||||
@@ -116,6 +121,7 @@ func initAPI() {
|
||||
beego.Router("/api/get-applications", &controllers.ApiController{}, "GET:GetApplications")
|
||||
beego.Router("/api/get-application", &controllers.ApiController{}, "GET:GetApplication")
|
||||
beego.Router("/api/get-user-application", &controllers.ApiController{}, "GET:GetUserApplication")
|
||||
beego.Router("/api/get-organization-applications", &controllers.ApiController{}, "GET:GetOrganizationApplications")
|
||||
beego.Router("/api/update-application", &controllers.ApiController{}, "POST:UpdateApplication")
|
||||
beego.Router("/api/add-application", &controllers.ApiController{}, "POST:AddApplication")
|
||||
beego.Router("/api/delete-application", &controllers.ApiController{}, "POST:DeleteApplication")
|
||||
@@ -195,5 +201,4 @@ func initAPI() {
|
||||
beego.Router("/api/webauthn/signup/finish", &controllers.ApiController{}, "Post:WebAuthnSignupFinish")
|
||||
beego.Router("/api/webauthn/signin/begin", &controllers.ApiController{}, "Get:WebAuthnSigninBegin")
|
||||
beego.Router("/api/webauthn/signin/finish", &controllers.ApiController{}, "Post:WebAuthnSigninFinish")
|
||||
|
||||
}
|
||||
|
@@ -1291,6 +1291,35 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/get-organization-applications": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Application API"
|
||||
],
|
||||
"description": "get the detail of the organization's application",
|
||||
"operationId": "ApiController.GetOrganizationApplications",
|
||||
"parameters": [
|
||||
{
|
||||
"in": "query",
|
||||
"name": "organization",
|
||||
"description": "The organization name",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "The Response object",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/object.Application"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/get-organizations": {
|
||||
"get": {
|
||||
"tags": [
|
||||
@@ -1853,6 +1882,24 @@
|
||||
"description": "The id of the user",
|
||||
"required": true,
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "owner",
|
||||
"description": "The owner of the user",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "email",
|
||||
"description": "The email of the user",
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"in": "query",
|
||||
"name": "phone",
|
||||
"description": "The phone of the user",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
@@ -3220,11 +3267,11 @@
|
||||
}
|
||||
},
|
||||
"definitions": {
|
||||
"2127.0xc000427560.false": {
|
||||
"2200.0xc0003f8480.false": {
|
||||
"title": "false",
|
||||
"type": "object"
|
||||
},
|
||||
"2161.0xc000427590.false": {
|
||||
"2235.0xc0003f84b0.false": {
|
||||
"title": "false",
|
||||
"type": "object"
|
||||
},
|
||||
@@ -3342,10 +3389,10 @@
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/definitions/2127.0xc000427560.false"
|
||||
"$ref": "#/definitions/2200.0xc0003f8480.false"
|
||||
},
|
||||
"data2": {
|
||||
"$ref": "#/definitions/2161.0xc000427590.false"
|
||||
"$ref": "#/definitions/2235.0xc0003f84b0.false"
|
||||
},
|
||||
"msg": {
|
||||
"type": "string"
|
||||
@@ -3549,6 +3596,9 @@
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
},
|
||||
"certificate": {
|
||||
"type": "string"
|
||||
},
|
||||
"createdTime": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -3571,9 +3621,6 @@
|
||||
"privateKey": {
|
||||
"type": "string"
|
||||
},
|
||||
"certificate": {
|
||||
"type": "string"
|
||||
},
|
||||
"scope": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -4585,6 +4632,12 @@
|
||||
"permanentAvatar": {
|
||||
"type": "string"
|
||||
},
|
||||
"permissions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/object.Permission"
|
||||
}
|
||||
},
|
||||
"phone": {
|
||||
"type": "string"
|
||||
},
|
||||
@@ -4606,6 +4659,12 @@
|
||||
"region": {
|
||||
"type": "string"
|
||||
},
|
||||
"roles": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/object.Role"
|
||||
}
|
||||
},
|
||||
"score": {
|
||||
"type": "integer",
|
||||
"format": "int64"
|
||||
|
@@ -837,6 +837,25 @@ paths:
|
||||
description: The Response object
|
||||
schema:
|
||||
$ref: '#/definitions/object.Organization'
|
||||
/api/get-organization-applications:
|
||||
get:
|
||||
tags:
|
||||
- Application API
|
||||
description: get the detail of the organization's application
|
||||
operationId: ApiController.GetOrganizationApplications
|
||||
parameters:
|
||||
- in: query
|
||||
name: organization
|
||||
description: The organization name
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: The Response object
|
||||
schema:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/object.Application'
|
||||
/api/get-organizations:
|
||||
get:
|
||||
tags:
|
||||
@@ -1209,6 +1228,18 @@ paths:
|
||||
description: The id of the user
|
||||
required: true
|
||||
type: string
|
||||
- in: query
|
||||
name: owner
|
||||
description: The owner of the user
|
||||
type: string
|
||||
- in: query
|
||||
name: email
|
||||
description: The email of the user
|
||||
type: string
|
||||
- in: query
|
||||
name: phone
|
||||
description: The phone of the user
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: The Response object
|
||||
@@ -2108,10 +2139,10 @@ paths:
|
||||
schema:
|
||||
$ref: '#/definitions/Response'
|
||||
definitions:
|
||||
2127.0xc000427560.false:
|
||||
2200.0xc0003f8480.false:
|
||||
title: "false"
|
||||
type: object
|
||||
2161.0xc000427590.false:
|
||||
2235.0xc0003f84b0.false:
|
||||
title: "false"
|
||||
type: object
|
||||
Response:
|
||||
@@ -2192,9 +2223,9 @@ definitions:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: '#/definitions/2127.0xc000427560.false'
|
||||
$ref: '#/definitions/2200.0xc0003f8480.false'
|
||||
data2:
|
||||
$ref: '#/definitions/2161.0xc000427590.false'
|
||||
$ref: '#/definitions/2235.0xc0003f84b0.false'
|
||||
msg:
|
||||
type: string
|
||||
name:
|
||||
@@ -2331,6 +2362,8 @@ definitions:
|
||||
bitSize:
|
||||
type: integer
|
||||
format: int64
|
||||
certificate:
|
||||
type: string
|
||||
createdTime:
|
||||
type: string
|
||||
cryptoAlgorithm:
|
||||
@@ -2346,8 +2379,6 @@ definitions:
|
||||
type: string
|
||||
privateKey:
|
||||
type: string
|
||||
certificate:
|
||||
type: string
|
||||
scope:
|
||||
type: string
|
||||
type:
|
||||
@@ -3027,6 +3058,10 @@ definitions:
|
||||
type: string
|
||||
permanentAvatar:
|
||||
type: string
|
||||
permissions:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/object.Permission'
|
||||
phone:
|
||||
type: string
|
||||
preHash:
|
||||
@@ -3041,6 +3076,10 @@ definitions:
|
||||
format: int64
|
||||
region:
|
||||
type: string
|
||||
roles:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/definitions/object.Role'
|
||||
score:
|
||||
type: integer
|
||||
format: int64
|
||||
|
@@ -17,7 +17,9 @@ package util
|
||||
import (
|
||||
"crypto/hmac"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
func GetHmacSha1(keyStr, value string) string {
|
||||
@@ -28,3 +30,10 @@ func GetHmacSha1(keyStr, value string) string {
|
||||
|
||||
return res
|
||||
}
|
||||
|
||||
func GetHmacSha256(key string, data string) string {
|
||||
mac := hmac.New(sha256.New, []byte(key))
|
||||
mac.Write([]byte(data))
|
||||
|
||||
return hex.EncodeToString(mac.Sum(nil))
|
||||
}
|
||||
|
@@ -32,7 +32,7 @@ func GetIPInfo(clientIP string) string {
|
||||
res := ""
|
||||
for i := range ips {
|
||||
ip := strings.TrimSpace(ips[i])
|
||||
//desc := GetDescFromIP(ip)
|
||||
// desc := GetDescFromIP(ip)
|
||||
ipstr := fmt.Sprintf("%s: %s", ip, "")
|
||||
if i != len(ips)-1 {
|
||||
res += ipstr + " -> "
|
||||
|
@@ -19,8 +19,10 @@ import (
|
||||
"regexp"
|
||||
)
|
||||
|
||||
var rePhoneCn *regexp.Regexp
|
||||
var rePhone *regexp.Regexp
|
||||
var (
|
||||
rePhoneCn *regexp.Regexp
|
||||
rePhone *regexp.Regexp
|
||||
)
|
||||
|
||||
func init() {
|
||||
// https://learnku.com/articles/31543
|
||||
|
@@ -69,7 +69,7 @@ func BoolToString(b bool) string {
|
||||
return "0"
|
||||
}
|
||||
|
||||
//CamelToSnakeCase This function transform camelcase in snakecase LoremIpsum in lorem_ipsum
|
||||
// CamelToSnakeCase This function transform camelcase in snakecase LoremIpsum in lorem_ipsum
|
||||
func CamelToSnakeCase(camel string) string {
|
||||
var buf bytes.Buffer
|
||||
for _, c := range camel {
|
||||
@@ -177,7 +177,7 @@ func ReadStringFromPath(path string) string {
|
||||
}
|
||||
|
||||
func WriteStringToPath(s string, path string) {
|
||||
err := ioutil.WriteFile(path, []byte(s), 0644)
|
||||
err := ioutil.WriteFile(path, []byte(s), 0o644)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
@@ -15,9 +15,10 @@
|
||||
package util
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestParseInt(t *testing.T) {
|
||||
@@ -245,4 +246,3 @@ func TestSnakeString(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -31,7 +31,6 @@ func Test_GetCurrentTime(t *testing.T) {
|
||||
|
||||
types := reflect.TypeOf(test).Kind()
|
||||
assert.Equal(t, types, reflect.String, "GetCurrentUnixTime should be return string")
|
||||
|
||||
}
|
||||
|
||||
func Test_GetCurrentUnixTime_Shoud_Return_String(t *testing.T) {
|
||||
@@ -41,7 +40,6 @@ func Test_GetCurrentUnixTime_Shoud_Return_String(t *testing.T) {
|
||||
}
|
||||
|
||||
func Test_IsTokenExpired(t *testing.T) {
|
||||
|
||||
type input struct {
|
||||
createdTime string
|
||||
expiresIn int
|
||||
|
@@ -17,11 +17,12 @@
|
||||
"version": "detect"
|
||||
}
|
||||
},
|
||||
"plugins": ["unused-imports"],
|
||||
"extends": ["eslint:recommended", "plugin:react/recommended"],
|
||||
"rules": {
|
||||
// "eqeqeq": "error",
|
||||
"semi": ["error", "always"],
|
||||
// "indent": ["error", 2],
|
||||
"indent": ["error", 2],
|
||||
// follow antd's style guide
|
||||
"quotes": ["error", "double"],
|
||||
"jsx-quotes": ["error", "prefer-double"],
|
||||
@@ -41,23 +42,60 @@
|
||||
"space-before-function-paren": ["error", "never"],
|
||||
"no-trailing-spaces": ["error", { "ignoreComments": true }],
|
||||
"eol-last": ["error", "always"],
|
||||
// "no-var": ["error"],
|
||||
"no-var": ["error"],
|
||||
"prefer-const": [
|
||||
"error",
|
||||
{
|
||||
"destructuring": "all"
|
||||
}
|
||||
],
|
||||
"curly": ["error", "all"],
|
||||
"brace-style": ["error", "1tbs", { "allowSingleLine": true }],
|
||||
"no-mixed-spaces-and-tabs": "error",
|
||||
"sort-imports": ["error", {
|
||||
"ignoreDeclarationSort": true
|
||||
}],
|
||||
|
||||
"sort-imports": [
|
||||
"error",
|
||||
{
|
||||
"ignoreDeclarationSort": true
|
||||
}
|
||||
],
|
||||
"no-multiple-empty-lines": [
|
||||
"error",
|
||||
{ "max": 1, "maxBOF": 0, "maxEOF": 0 }
|
||||
],
|
||||
"space-unary-ops": ["error", { "words": true, "nonwords": false }],
|
||||
"space-infix-ops": "error",
|
||||
"key-spacing": ["error", { "beforeColon": false, "afterColon": true }],
|
||||
"comma-style": ["error", "last"],
|
||||
"comma-dangle": [
|
||||
"error",
|
||||
{
|
||||
"arrays": "always-multiline",
|
||||
"objects": "always-multiline",
|
||||
"imports": "never",
|
||||
"exports": "never",
|
||||
"functions": "never"
|
||||
}
|
||||
],
|
||||
"no-multi-spaces": ["error", { "ignoreEOLComments": true }],
|
||||
"unused-imports/no-unused-imports": "error",
|
||||
"unused-imports/no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
"vars": "all",
|
||||
"varsIgnorePattern": "^_",
|
||||
"args": "none",
|
||||
"argsIgnorePattern": "^_"
|
||||
}
|
||||
],
|
||||
|
||||
"react/prop-types": "off",
|
||||
"react/display-name": "off",
|
||||
"react/react-in-jsx-scope": "off",
|
||||
|
||||
// don't use strict mod now, otherwise there are a lot of errors in the codebase
|
||||
"no-unused-vars": "warn",
|
||||
"no-unused-vars": "off",
|
||||
"react/no-deprecated": "warn",
|
||||
"no-case-declarations": "warn",
|
||||
"no-case-declarations": "off",
|
||||
"react/jsx-key": "warn"
|
||||
}
|
||||
}
|
||||
|
@@ -34,7 +34,7 @@ module.exports = {
|
||||
"/cas/validate": {
|
||||
target: "http://localhost:8000",
|
||||
changeOrigin: true,
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
|
@@ -12,13 +12,16 @@
|
||||
"antd": "^4.15.5",
|
||||
"codemirror": "^5.61.1",
|
||||
"copy-to-clipboard": "^3.3.1",
|
||||
"core-js": "^3.21.1",
|
||||
"craco-less": "^1.17.1",
|
||||
"eslint-plugin-unused-imports": "^2.0.0",
|
||||
"file-saver": "^2.0.5",
|
||||
"i18n-iso-countries": "^7.0.0",
|
||||
"i18next": "^19.8.9",
|
||||
"moment": "^2.29.1",
|
||||
"qs": "^6.10.2",
|
||||
"react": "^17.0.2",
|
||||
"react-app-polyfill": "^3.0.0",
|
||||
"react-codemirror2": "^7.2.1",
|
||||
"react-cropper": "^2.1.7",
|
||||
"react-device-detect": "^1.14.0",
|
||||
@@ -29,9 +32,7 @@
|
||||
"react-i18next": "^11.8.7",
|
||||
"react-router-dom": "^5.2.0",
|
||||
"react-scripts": "4.0.3",
|
||||
"react-social-login-buttons": "^3.4.0",
|
||||
"react-app-polyfill": "^3.0.0",
|
||||
"core-js": "^3.21.1"
|
||||
"react-social-login-buttons": "^3.4.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "cross-env PORT=7001 craco start",
|
||||
@@ -39,7 +40,8 @@
|
||||
"test": "craco test",
|
||||
"eject": "craco eject",
|
||||
"crowdin:sync": "crowdin upload && crowdin download",
|
||||
"preinstall": "node -e \"if (process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('Use yarn for installing: https://yarnpkg.com/en/docs/install')\""
|
||||
"preinstall": "node -e \"if (process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('Use yarn for installing: https://yarnpkg.com/en/docs/install')\"",
|
||||
"fix": "eslint --fix ."
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "react-app"
|
||||
@@ -61,6 +63,18 @@
|
||||
"devDependencies": {
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^7.11.0",
|
||||
"eslint-plugin-react": "^7.30.1"
|
||||
"eslint-plugin-react": "^7.30.1",
|
||||
"husky": "^4.3.8",
|
||||
"lint-staged": "^13.0.3"
|
||||
},
|
||||
"lint-staged": {
|
||||
"src/**/*.{js,jsx,css,sass,ts,tsx}": [
|
||||
"yarn fix"
|
||||
]
|
||||
},
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -38,7 +38,7 @@ class AccountTable extends React.Component {
|
||||
}
|
||||
|
||||
addRow(table) {
|
||||
let row = {name: Setting.getNewRowNameForTable(table, "Please select an account item"), visible: true};
|
||||
const row = {name: Setting.getNewRowNameForTable(table, "Please select an account item"), visible: true, viewRule: "Public", modifyRule: "Self"};
|
||||
if (table === undefined) {
|
||||
table = [];
|
||||
}
|
||||
@@ -116,7 +116,7 @@ class AccountTable extends React.Component {
|
||||
}
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("provider:visible"),
|
||||
@@ -129,7 +129,7 @@ class AccountTable extends React.Component {
|
||||
this.updateField(table, index, "visible", checked);
|
||||
}} />
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("organization:viewRule"),
|
||||
@@ -141,7 +141,7 @@ class AccountTable extends React.Component {
|
||||
return null;
|
||||
}
|
||||
|
||||
let options = [
|
||||
const options = [
|
||||
{id: "Public", name: "Public"},
|
||||
{id: "Self", name: "Self"},
|
||||
{id: "Admin", name: "Admin"},
|
||||
@@ -156,7 +156,7 @@ class AccountTable extends React.Component {
|
||||
}
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("organization:modifyRule"),
|
||||
@@ -191,7 +191,7 @@ class AccountTable extends React.Component {
|
||||
}
|
||||
</Select>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Action"),
|
||||
@@ -211,7 +211,7 @@ class AccountTable extends React.Component {
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -182,7 +182,7 @@ class App extends Component {
|
||||
}
|
||||
|
||||
setLanguage(account) {
|
||||
let language = account?.language;
|
||||
const language = account?.language;
|
||||
if (language !== "" && language !== i18next.language) {
|
||||
Setting.setLanguage(language);
|
||||
}
|
||||
@@ -238,11 +238,11 @@ class App extends Component {
|
||||
const owner = this.state.account.owner;
|
||||
|
||||
this.setState({
|
||||
account: null
|
||||
account: null,
|
||||
});
|
||||
|
||||
Setting.showMessage("success", "Logged out successfully");
|
||||
let redirectUri = res.data2;
|
||||
const redirectUri = res.data2;
|
||||
if (redirectUri !== null && redirectUri !== undefined && redirectUri !== "") {
|
||||
Setting.goToLink(redirectUri);
|
||||
} else if (owner !== "built-in") {
|
||||
@@ -258,7 +258,7 @@ class App extends Component {
|
||||
|
||||
onUpdateAccount(account) {
|
||||
this.setState({
|
||||
account: account
|
||||
account: account,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -322,7 +322,7 @@ class App extends Component {
|
||||
}
|
||||
|
||||
renderAccount() {
|
||||
let res = [];
|
||||
const res = [];
|
||||
|
||||
if (this.state.account === undefined) {
|
||||
return null;
|
||||
@@ -349,7 +349,7 @@ class App extends Component {
|
||||
}
|
||||
|
||||
renderMenu() {
|
||||
let res = [];
|
||||
const res = [];
|
||||
|
||||
if (this.state.account === null || this.state.account === undefined) {
|
||||
return [];
|
||||
@@ -566,7 +566,7 @@ class App extends Component {
|
||||
renderContent() {
|
||||
if (!Setting.isMobile()) {
|
||||
return (
|
||||
<div style={{display: "flex", flex: "auto", width:"100%", flexDirection: "column"}}>
|
||||
<div style={{display: "flex", flex: "auto", width: "100%", flexDirection: "column"}}>
|
||||
<Layout style={{display: "flex", alignItems: "stretch"}}>
|
||||
<Header style={{padding: "0", marginBottom: "3px"}}>
|
||||
{
|
||||
@@ -668,7 +668,7 @@ class App extends Component {
|
||||
renderPage() {
|
||||
if (this.isDoorPages()) {
|
||||
return (
|
||||
<div>
|
||||
<div style={{position: "relative", minHeight: "100vh"}}>
|
||||
<Switch>
|
||||
<Route exact path="/signup" render={(props) => this.renderHomeIfLoggedIn(<SignupPage account={this.state.account} {...props} />)} />
|
||||
<Route exact path="/signup/:applicationName" render={(props) => this.renderHomeIfLoggedIn(<SignupPage account={this.state.account} {...props} onUpdateAccount={(account) => {this.onUpdateAccount(account);}} />)} />
|
||||
|
@@ -120,7 +120,7 @@ class ApplicationEditPage extends React.Component {
|
||||
updateApplicationField(key, value) {
|
||||
value = this.parseApplicationField(key, value);
|
||||
|
||||
let application = this.state.application;
|
||||
const application = this.state.application;
|
||||
application[key] = value;
|
||||
this.setState({
|
||||
application: application,
|
||||
@@ -156,7 +156,7 @@ class ApplicationEditPage extends React.Component {
|
||||
<Button style={{marginLeft: "20px"}} type="primary" onClick={() => this.submitApplicationEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} onClick={() => this.deleteApplication()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
} style={(Setting.isMobile())? {margin: "5px"}:{}} type="inner">
|
||||
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
|
||||
<Row style={{marginTop: "10px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Name"), i18next.t("general:Name - Tooltip"))} :
|
||||
@@ -181,7 +181,7 @@ class ApplicationEditPage extends React.Component {
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Logo"), i18next.t("general:Logo - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} style={(Setting.isMobile()) ? {maxWidth: "100%"} :{}}>
|
||||
<Col span={22} style={(Setting.isMobile()) ? {maxWidth: "100%"} : {}}>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 1}>
|
||||
{Setting.getLabel(i18next.t("general:URL"), i18next.t("general:URL - Tooltip"))} :
|
||||
@@ -566,8 +566,8 @@ class ApplicationEditPage extends React.Component {
|
||||
|
||||
renderSignupSigninPreview() {
|
||||
let signUpUrl = `/signup/${this.state.application.name}`;
|
||||
let signInUrl = `/login/oauth/authorize?client_id=${this.state.application.clientId}&response_type=code&redirect_uri=${this.state.application.redirectUris[0]}&scope=read&state=casdoor`;
|
||||
let maskStyle = {position: "absolute", top: "0px", left: "0px", zIndex: 10, height: "100%", width: "100%", background: "rgba(0,0,0,0.4)"};
|
||||
const signInUrl = `/login/oauth/authorize?client_id=${this.state.application.clientId}&response_type=code&redirect_uri=${this.state.application.redirectUris[0]}&scope=read&state=casdoor`;
|
||||
const maskStyle = {position: "absolute", top: "0px", left: "0px", zIndex: 10, height: "100%", width: "100%", background: "rgba(0,0,0,0.4)"};
|
||||
if (!this.state.application.enablePassword) {
|
||||
signUpUrl = signInUrl.replace("/login/oauth/authorize", "/signup/oauth/authorize");
|
||||
}
|
||||
@@ -583,7 +583,7 @@ class ApplicationEditPage extends React.Component {
|
||||
{i18next.t("application:Copy signup page URL")}
|
||||
</Button>
|
||||
<br />
|
||||
<div style={{position: "relative", width: "90%", border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", alignItems:"center", overflow:"auto", flexDirection:"column", flex: "auto"}}>
|
||||
<div style={{position: "relative", width: "90%", border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", alignItems: "center", overflow: "auto", flexDirection: "column", flex: "auto"}}>
|
||||
{
|
||||
this.state.application.enablePassword ? (
|
||||
<SignupPage application={this.state.application} />
|
||||
@@ -603,7 +603,7 @@ class ApplicationEditPage extends React.Component {
|
||||
{i18next.t("application:Copy signin page URL")}
|
||||
</Button>
|
||||
<br />
|
||||
<div style={{position: "relative", width: "90%", border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", alignItems:"center", overflow:"auto", flexDirection:"column", flex: "auto"}}>
|
||||
<div style={{position: "relative", width: "90%", border: "1px solid rgb(217,217,217)", boxShadow: "10px 10px 5px #888888", alignItems: "center", overflow: "auto", flexDirection: "column", flex: "auto"}}>
|
||||
<LoginPage type={"login"} mode={"signin"} application={this.state.application} />
|
||||
<div style={maskStyle}></div>
|
||||
</div>
|
||||
@@ -613,8 +613,8 @@ class ApplicationEditPage extends React.Component {
|
||||
}
|
||||
|
||||
renderPromptPreview() {
|
||||
let promptUrl = `/prompt/${this.state.application.name}`;
|
||||
let maskStyle = {position: "absolute", top: "0px", left: "0px", zIndex: 10, height: "100%", width: "100%", background: "rgba(0,0,0,0.4)"};
|
||||
const promptUrl = `/prompt/${this.state.application.name}`;
|
||||
const maskStyle = {position: "absolute", top: "0px", left: "0px", zIndex: 10, height: "100%", width: "100%", background: "rgba(0,0,0,0.4)"};
|
||||
return (
|
||||
<Col span={11}>
|
||||
<Button style={{marginBottom: "10px"}} type="primary" shape="round" icon={<CopyOutlined />} onClick={() => {
|
||||
@@ -634,7 +634,7 @@ class ApplicationEditPage extends React.Component {
|
||||
}
|
||||
|
||||
submitApplicationEdit(willExist) {
|
||||
let application = Setting.deepCopy(this.state.application);
|
||||
const application = Setting.deepCopy(this.state.application);
|
||||
ApplicationBackend.updateApplication(this.state.application.owner, this.state.applicationName, application)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
|
@@ -99,7 +99,7 @@ class ApplicationListPage extends BaseListPage {
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Created time"),
|
||||
@@ -109,7 +109,7 @@ class ApplicationListPage extends BaseListPage {
|
||||
sorter: true,
|
||||
render: (text, record, index) => {
|
||||
return Setting.getFormattedDate(text);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Display name"),
|
||||
@@ -130,7 +130,7 @@ class ApplicationListPage extends BaseListPage {
|
||||
<img src={text} alt={text} width={150} />
|
||||
</a>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Organization"),
|
||||
@@ -145,7 +145,7 @@ class ApplicationListPage extends BaseListPage {
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Providers"),
|
||||
@@ -222,7 +222,7 @@ class ApplicationListPage extends BaseListPage {
|
||||
</Popconfirm>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -250,8 +250,8 @@ class ApplicationListPage extends BaseListPage {
|
||||
}
|
||||
|
||||
fetch = (params = {}) => {
|
||||
let field = params.searchedColumn, value = params.searchText;
|
||||
let sortField = params.sortField, sortOrder = params.sortOrder;
|
||||
const field = params.searchedColumn, value = params.searchText;
|
||||
const sortField = params.sortField, sortOrder = params.sortOrder;
|
||||
this.setState({loading: true});
|
||||
ApplicationBackend.getApplications("admin", params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
|
||||
.then((res) => {
|
||||
|
@@ -57,7 +57,7 @@ class CertEditPage extends React.Component {
|
||||
updateCertField(key, value) {
|
||||
value = this.parseCertField(key, value);
|
||||
|
||||
let cert = this.state.cert;
|
||||
const cert = this.state.cert;
|
||||
cert[key] = value;
|
||||
this.setState({
|
||||
cert: cert,
|
||||
@@ -73,7 +73,7 @@ class CertEditPage extends React.Component {
|
||||
<Button style={{marginLeft: "20px"}} type="primary" onClick={() => this.submitCertEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} onClick={() => this.deleteCert()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
} style={(Setting.isMobile())? {margin: "5px"}:{}} type="inner">
|
||||
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
|
||||
<Row style={{marginTop: "10px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Name"), i18next.t("general:Name - Tooltip"))} :
|
||||
@@ -214,7 +214,7 @@ class CertEditPage extends React.Component {
|
||||
}
|
||||
|
||||
submitCertEdit(willExist) {
|
||||
let cert = Setting.deepCopy(this.state.cert);
|
||||
const cert = Setting.deepCopy(this.state.cert);
|
||||
CertBackend.updateCert(this.state.cert.owner, this.state.certName, cert)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
|
@@ -82,7 +82,7 @@ class CertListPage extends BaseListPage {
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Created time"),
|
||||
@@ -92,7 +92,7 @@ class CertListPage extends BaseListPage {
|
||||
sorter: true,
|
||||
render: (text, record, index) => {
|
||||
return Setting.getFormattedDate(text);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Display name"),
|
||||
@@ -169,7 +169,7 @@ class CertListPage extends BaseListPage {
|
||||
</Popconfirm>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -198,7 +198,7 @@ class CertListPage extends BaseListPage {
|
||||
|
||||
fetch = (params = {}) => {
|
||||
let field = params.searchedColumn, value = params.searchText;
|
||||
let sortField = params.sortField, sortOrder = params.sortOrder;
|
||||
const sortField = params.sortField, sortOrder = params.sortOrder;
|
||||
if (params.category !== undefined && params.category !== null) {
|
||||
field = "category";
|
||||
value = params.category;
|
||||
|
@@ -103,7 +103,7 @@ export const CropperDiv = (props) => {
|
||||
onCancel={handleCancel}
|
||||
width={600}
|
||||
footer={
|
||||
[<Button block type="primary" onClick={handleOk}>{i18next.t("user:Set new profile picture")}</Button>]
|
||||
[<Button block key="submit" type="primary" onClick={handleOk}>{i18next.t("user:Set new profile picture")}</Button>]
|
||||
}
|
||||
>
|
||||
<Col style={{margin: "0px auto 40px auto", width: 1000, height: 300}}>
|
||||
|
@@ -42,7 +42,7 @@ class LdapEditPage extends React.Component {
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.setState({
|
||||
ldap: res.data
|
||||
ldap: res.data,
|
||||
});
|
||||
} else {
|
||||
Setting.showMessage("error", res.msg);
|
||||
@@ -71,7 +71,7 @@ class LdapEditPage extends React.Component {
|
||||
return (
|
||||
<span style={{
|
||||
color: "#faad14",
|
||||
marginLeft: "20px"
|
||||
marginLeft: "20px",
|
||||
}}>{i18next.t("ldap:The Auto Sync option will sync all users to specify organization")}</span>
|
||||
);
|
||||
}
|
||||
|
@@ -23,7 +23,7 @@ class LdapListPage extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
ldaps: null
|
||||
ldaps: null,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ class LdapListPage extends React.Component {
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Organization"),
|
||||
@@ -79,7 +79,7 @@ class LdapListPage extends React.Component {
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("ldap:Server"),
|
||||
@@ -89,7 +89,7 @@ class LdapListPage extends React.Component {
|
||||
sorter: (a, b) => a.host.localeCompare(b.host),
|
||||
render: (text, record, index) => {
|
||||
return `${text}:${record.port}`;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("ldap:Base DN"),
|
||||
@@ -114,7 +114,7 @@ class LdapListPage extends React.Component {
|
||||
render: (text, record, index) => {
|
||||
return text === 0 ? (<span style={{color: "#faad14"}}>Disable</span>) : (
|
||||
<span style={{color: "#52c41a"}}>{text + " mins"}</span>);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("ldap:Last Sync"),
|
||||
@@ -124,7 +124,7 @@ class LdapListPage extends React.Component {
|
||||
sorter: (a, b) => a.lastSync.localeCompare(b.lastSync),
|
||||
render: (text, record, index) => {
|
||||
return text;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Action"),
|
||||
@@ -148,7 +148,7 @@ class LdapListPage extends React.Component {
|
||||
</Popconfirm>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -35,7 +35,7 @@ class LdapSyncPage extends React.Component {
|
||||
}
|
||||
|
||||
syncUsers() {
|
||||
let selectedUsers = this.state.selectedUsers;
|
||||
const selectedUsers = this.state.selectedUsers;
|
||||
if (selectedUsers === null || selectedUsers.length === 0) {
|
||||
Setting.showMessage("error", "Please select al least 1 user first");
|
||||
return;
|
||||
@@ -44,10 +44,10 @@ class LdapSyncPage extends React.Component {
|
||||
LdapBackend.syncUsers(this.state.ldap.owner, this.state.ldap.id, selectedUsers)
|
||||
.then((res => {
|
||||
if (res.status === "ok") {
|
||||
let exist = res.data.exist;
|
||||
let failed = res.data.failed;
|
||||
let existUser = [];
|
||||
let failedUser = [];
|
||||
const exist = res.data.exist;
|
||||
const failed = res.data.failed;
|
||||
const existUser = [];
|
||||
const failedUser = [];
|
||||
|
||||
if ((!exist || exist.length === 0) && (!failed || failed.length === 0)) {
|
||||
Setting.goToLink(`/organizations/${this.state.ldap.owner}/users`);
|
||||
@@ -87,7 +87,6 @@ class LdapSyncPage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
getLdapUser(ldap) {
|
||||
LdapBackend.getLdapUser(ldap)
|
||||
.then((res) => {
|
||||
@@ -104,7 +103,7 @@ class LdapSyncPage extends React.Component {
|
||||
}
|
||||
|
||||
getExistUsers(owner, users) {
|
||||
let uuidArray = [];
|
||||
const uuidArray = [];
|
||||
users.forEach(elem => {
|
||||
uuidArray.push(elem.uuid);
|
||||
});
|
||||
@@ -120,11 +119,11 @@ class LdapSyncPage extends React.Component {
|
||||
}
|
||||
|
||||
buildValArray(data, key) {
|
||||
let valTypesArray = [];
|
||||
const valTypesArray = [];
|
||||
|
||||
if (data !== null && data.length > 0) {
|
||||
data.forEach(elem => {
|
||||
let val = elem[key];
|
||||
const val = elem[key];
|
||||
if (!valTypesArray.includes(val)) {
|
||||
valTypesArray.push(val);
|
||||
}
|
||||
@@ -134,10 +133,10 @@ class LdapSyncPage extends React.Component {
|
||||
}
|
||||
|
||||
buildFilter(data, key) {
|
||||
let filterArray = [];
|
||||
const filterArray = [];
|
||||
|
||||
if (data !== null && data.length > 0) {
|
||||
let valArray = this.buildValArray(data, key);
|
||||
const valArray = this.buildValArray(data, key);
|
||||
valArray.forEach(elem => {
|
||||
filterArray.push({
|
||||
text: elem,
|
||||
|
@@ -48,7 +48,7 @@ class LdapTable extends React.Component {
|
||||
passwd: "123",
|
||||
baseDn: "ou=People,dc=example,dc=com",
|
||||
autosync: 0,
|
||||
lastSync: ""
|
||||
lastSync: "",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -104,7 +104,7 @@ class LdapTable extends React.Component {
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("ldap:Server"),
|
||||
@@ -114,7 +114,7 @@ class LdapTable extends React.Component {
|
||||
sorter: (a, b) => a.host.localeCompare(b.host),
|
||||
render: (text, record, index) => {
|
||||
return `${text}:${record.port}`;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("ldap:Base DN"),
|
||||
@@ -132,7 +132,7 @@ class LdapTable extends React.Component {
|
||||
render: (text, record, index) => {
|
||||
return text === 0 ? (<span style={{color: "#faad14"}}>Disable</span>) : (
|
||||
<span style={{color: "#52c41a"}}>{text + " mins"}</span>);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("ldap:Last Sync"),
|
||||
@@ -142,7 +142,7 @@ class LdapTable extends React.Component {
|
||||
sorter: (a, b) => a.lastSync.localeCompare(b.lastSync),
|
||||
render: (text, record, index) => {
|
||||
return text;
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Action"),
|
||||
@@ -166,7 +166,7 @@ class LdapTable extends React.Component {
|
||||
</Popconfirm>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
|
@@ -81,7 +81,7 @@ class ModelEditPage extends React.Component {
|
||||
updateModelField(key, value) {
|
||||
value = this.parseModelField(key, value);
|
||||
|
||||
let model = this.state.model;
|
||||
const model = this.state.model;
|
||||
model[key] = value;
|
||||
this.setState({
|
||||
model: model,
|
||||
@@ -97,7 +97,7 @@ class ModelEditPage extends React.Component {
|
||||
<Button style={{marginLeft: "20px"}} type="primary" onClick={() => this.submitModelEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} onClick={() => this.deleteModel()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
} style={(Setting.isMobile())? {margin: "5px"}:{}} type="inner">
|
||||
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
|
||||
<Row style={{marginTop: "10px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Organization"), i18next.t("general:Organization - Tooltip"))} :
|
||||
@@ -155,7 +155,7 @@ class ModelEditPage extends React.Component {
|
||||
}
|
||||
|
||||
submitModelEdit(willExist) {
|
||||
let model = Setting.deepCopy(this.state.model);
|
||||
const model = Setting.deepCopy(this.state.model);
|
||||
ModelBackend.updateModel(this.state.organizationName, this.state.modelName, model)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
|
@@ -76,7 +76,7 @@ class ModelListPage extends BaseListPage {
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Name"),
|
||||
@@ -92,7 +92,7 @@ class ModelListPage extends BaseListPage {
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Created time"),
|
||||
@@ -102,7 +102,7 @@ class ModelListPage extends BaseListPage {
|
||||
sorter: true,
|
||||
render: (text, record, index) => {
|
||||
return Setting.getFormattedDate(text);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Display name"),
|
||||
@@ -122,7 +122,7 @@ class ModelListPage extends BaseListPage {
|
||||
return (
|
||||
<Switch disabled checkedChildren="ON" unCheckedChildren="OFF" checked={text} />
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Action"),
|
||||
@@ -143,7 +143,7 @@ class ModelListPage extends BaseListPage {
|
||||
</Popconfirm>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -174,7 +174,7 @@ class ModelListPage extends BaseListPage {
|
||||
|
||||
fetch = (params = {}) => {
|
||||
let field = params.searchedColumn, value = params.searchText;
|
||||
let sortField = params.sortField, sortOrder = params.sortOrder;
|
||||
const sortField = params.sortField, sortOrder = params.sortOrder;
|
||||
if (params.type !== undefined && params.type !== null) {
|
||||
field = "type";
|
||||
value = params.type;
|
||||
|
@@ -60,7 +60,7 @@ class OrganizationEditPage extends React.Component {
|
||||
}
|
||||
}
|
||||
this.setState({
|
||||
ldaps: resdata
|
||||
ldaps: resdata,
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -75,7 +75,7 @@ class OrganizationEditPage extends React.Component {
|
||||
updateOrganizationField(key, value) {
|
||||
value = this.parseOrganizationField(key, value);
|
||||
|
||||
let organization = this.state.organization;
|
||||
const organization = this.state.organization;
|
||||
organization[key] = value;
|
||||
this.setState({
|
||||
organization: organization,
|
||||
@@ -91,7 +91,7 @@ class OrganizationEditPage extends React.Component {
|
||||
<Button style={{marginLeft: "20px"}} type="primary" onClick={() => this.submitOrganizationEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} onClick={() => this.deleteOrganization()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
} style={(Setting.isMobile())? {margin: "5px"}:{}} type="inner">
|
||||
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
|
||||
<Row style={{marginTop: "10px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Name"), i18next.t("general:Name - Tooltip"))} :
|
||||
@@ -283,7 +283,7 @@ class OrganizationEditPage extends React.Component {
|
||||
}
|
||||
|
||||
submitOrganizationEdit(willExist) {
|
||||
let organization = Setting.deepCopy(this.state.organization);
|
||||
const organization = Setting.deepCopy(this.state.organization);
|
||||
OrganizationBackend.updateOrganization(this.state.organization.owner, this.state.organizationName, organization)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
|
@@ -112,7 +112,7 @@ class OrganizationListPage extends BaseListPage {
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Created time"),
|
||||
@@ -122,7 +122,7 @@ class OrganizationListPage extends BaseListPage {
|
||||
sorter: true,
|
||||
render: (text, record, index) => {
|
||||
return Setting.getFormattedDate(text);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Display name"),
|
||||
@@ -143,7 +143,7 @@ class OrganizationListPage extends BaseListPage {
|
||||
<img src={text} alt={text} width={40} />
|
||||
</a>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("organization:Website URL"),
|
||||
@@ -158,7 +158,7 @@ class OrganizationListPage extends BaseListPage {
|
||||
{text}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Password type"),
|
||||
@@ -192,7 +192,7 @@ class OrganizationListPage extends BaseListPage {
|
||||
<img src={text} alt={text} width={40} />
|
||||
</a>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("organization:Soft deletion"),
|
||||
@@ -204,7 +204,7 @@ class OrganizationListPage extends BaseListPage {
|
||||
return (
|
||||
<Switch disabled checkedChildren="ON" unCheckedChildren="OFF" checked={text} />
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Action"),
|
||||
@@ -226,7 +226,7 @@ class OrganizationListPage extends BaseListPage {
|
||||
</Popconfirm>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -266,7 +266,7 @@ class OrganizationListPage extends BaseListPage {
|
||||
|
||||
fetch = (params = {}) => {
|
||||
let field = params.searchedColumn, value = params.searchText;
|
||||
let sortField = params.sortField, sortOrder = params.sortOrder;
|
||||
const sortField = params.sortField, sortOrder = params.sortOrder;
|
||||
if (params.passwordType !== undefined && params.passwordType !== null) {
|
||||
field = "passwordType";
|
||||
value = params.passwordType;
|
||||
|
@@ -54,7 +54,7 @@ export const PasswordModal = (props) => {
|
||||
});
|
||||
};
|
||||
|
||||
let hasOldPassword = user.password !== "";
|
||||
const hasOldPassword = user.password !== "";
|
||||
|
||||
return (
|
||||
<Row>
|
||||
|
@@ -60,7 +60,7 @@ class PaymentEditPage extends React.Component {
|
||||
updatePaymentField(key, value) {
|
||||
value = this.parsePaymentField(key, value);
|
||||
|
||||
let payment = this.state.payment;
|
||||
const payment = this.state.payment;
|
||||
payment[key] = value;
|
||||
this.setState({
|
||||
payment: payment,
|
||||
@@ -152,7 +152,7 @@ class PaymentEditPage extends React.Component {
|
||||
<Button style={{marginLeft: "20px"}} type="primary" onClick={() => this.submitPaymentEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} onClick={() => this.deletePayment()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
} style={(Setting.isMobile())? {margin: "5px"}:{}} type="inner">
|
||||
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
|
||||
<Row style={{marginTop: "10px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Organization"), i18next.t("general:Organization - Tooltip"))} :
|
||||
@@ -440,7 +440,7 @@ class PaymentEditPage extends React.Component {
|
||||
return;
|
||||
}
|
||||
|
||||
let payment = Setting.deepCopy(this.state.payment);
|
||||
const payment = Setting.deepCopy(this.state.payment);
|
||||
PaymentBackend.updatePayment(this.state.payment.owner, this.state.paymentName, payment)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
|
@@ -89,7 +89,7 @@ class PaymentListPage extends BaseListPage {
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:User"),
|
||||
@@ -104,7 +104,7 @@ class PaymentListPage extends BaseListPage {
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Name"),
|
||||
@@ -120,7 +120,7 @@ class PaymentListPage extends BaseListPage {
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Created time"),
|
||||
@@ -130,7 +130,7 @@ class PaymentListPage extends BaseListPage {
|
||||
sorter: true,
|
||||
render: (text, record, index) => {
|
||||
return Setting.getFormattedDate(text);
|
||||
}
|
||||
},
|
||||
},
|
||||
// {
|
||||
// title: i18next.t("general:Display name"),
|
||||
@@ -154,7 +154,7 @@ class PaymentListPage extends BaseListPage {
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("payment:Type"),
|
||||
@@ -163,12 +163,12 @@ class PaymentListPage extends BaseListPage {
|
||||
width: "140px",
|
||||
align: "center",
|
||||
filterMultiple: false,
|
||||
filters: Setting.getProviderTypeOptions("Payment").map((o) => {return {text:o.id, value:o.name};}),
|
||||
filters: Setting.getProviderTypeOptions("Payment").map((o) => {return {text: o.id, value: o.name};}),
|
||||
sorter: true,
|
||||
render: (text, record, index) => {
|
||||
record.category = "Payment";
|
||||
return Provider.getProviderLogoWidget(record);
|
||||
}
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("payment:Product"),
|
||||
@@ -221,7 +221,7 @@ class PaymentListPage extends BaseListPage {
|
||||
</Popconfirm>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
@@ -250,7 +250,7 @@ class PaymentListPage extends BaseListPage {
|
||||
|
||||
fetch = (params = {}) => {
|
||||
let field = params.searchedColumn, value = params.searchText;
|
||||
let sortField = params.sortField, sortOrder = params.sortOrder;
|
||||
const sortField = params.sortField, sortOrder = params.sortOrder;
|
||||
if (params.type !== undefined && params.type !== null) {
|
||||
field = "type";
|
||||
value = params.type;
|
||||
|
@@ -67,7 +67,7 @@ class PaymentResultPage extends React.Component {
|
||||
Setting.goToLink(payment.returnUrl);
|
||||
}}>
|
||||
{i18next.t("payment:Return to Website")}
|
||||
</Button>
|
||||
</Button>,
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
@@ -83,7 +83,7 @@ class PaymentResultPage extends React.Component {
|
||||
title={`${i18next.t("payment:The payment is still under processing")}: ${payment.productDisplayName}, ${i18next.t("payment:the current state is")}: ${payment.state}, ${i18next.t("payment:please wait for a few seconds...")}`}
|
||||
subTitle={i18next.t("payment:Please click the below button to return to the original website")}
|
||||
extra={[
|
||||
<Spin size="large" tip={i18next.t("payment:Processing...")} />,
|
||||
<Spin key="returnUrl" size="large" tip={i18next.t("payment:Processing...")} />,
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
@@ -103,7 +103,7 @@ class PaymentResultPage extends React.Component {
|
||||
Setting.goToLink(payment.returnUrl);
|
||||
}}>
|
||||
{i18next.t("payment:Return to Website")}
|
||||
</Button>
|
||||
</Button>,
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
@@ -116,7 +116,7 @@ class PermissionEditPage extends React.Component {
|
||||
updatePermissionField(key, value) {
|
||||
value = this.parsePermissionField(key, value);
|
||||
|
||||
let permission = this.state.permission;
|
||||
const permission = this.state.permission;
|
||||
permission[key] = value;
|
||||
this.setState({
|
||||
permission: permission,
|
||||
@@ -132,7 +132,7 @@ class PermissionEditPage extends React.Component {
|
||||
<Button style={{marginLeft: "20px"}} type="primary" onClick={() => this.submitPermissionEdit(true)}>{i18next.t("general:Save & Exit")}</Button>
|
||||
{this.state.mode === "add" ? <Button style={{marginLeft: "20px"}} onClick={() => this.deletePermission()}>{i18next.t("general:Cancel")}</Button> : null}
|
||||
</div>
|
||||
} style={(Setting.isMobile())? {margin: "5px"}:{}} type="inner">
|
||||
} style={(Setting.isMobile()) ? {margin: "5px"} : {}} type="inner">
|
||||
<Row style={{marginTop: "10px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("general:Organization"), i18next.t("general:Organization - Tooltip"))} :
|
||||
@@ -288,7 +288,7 @@ class PermissionEditPage extends React.Component {
|
||||
}
|
||||
|
||||
submitPermissionEdit(willExist) {
|
||||
let permission = Setting.deepCopy(this.state.permission);
|
||||
const permission = Setting.deepCopy(this.state.permission);
|
||||
PermissionBackend.updatePermission(this.state.organizationName, this.state.permissionName, permission)
|
||||
.then((res) => {
|
||||
if (res.msg === "") {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user