Compare commits

..

55 Commits

Author SHA1 Message Date
longxu0509
b38f2218a3 feat: add basic MySQL sync functionality (#1575)
* feat: add sync module to bi-sync mysql

* feat: fix the delay problem

* feat: fix go mod

* feat: fix the varchar(100) parse error

* fix: fix go.mod space inconsistency

* fix: fix go.mod space inconsistency

* fix: use sql builder instead of concatenation

* fix: remove serverId

* fix: fix file is not `gofumpt`-ed (gofumpt) error
2023-02-28 16:48:06 +08:00
Yaodong Yu
afd3c4ed25 fix: fix bug form country code init error (#1591) 2023-02-27 22:07:28 +08:00
Yaodong Yu
5caceb4ae2 feat: fix bug that signup country code is undefined (#1590)
* feat: fix signup country code is undefined

* refactor: valid phone number in CN
2023-02-27 20:10:59 +08:00
Gucheng Wang
f5672357e6 fix resetting phone bug 2023-02-25 15:46:54 +08:00
Gucheng Wang
181e7c8c7d Refactor out getCountryCodeOption() 2023-02-25 15:25:47 +08:00
Gucheng Wang
36c5a9d09b Sort country list 2023-02-25 15:08:08 +08:00
Gucheng Wang
9acb3c499e Can search country code 2023-02-25 14:57:23 +08:00
Gucheng Wang
0e9a3b0f30 don't update provider in preview 2023-02-25 12:31:08 +08:00
Gucheng Wang
d104a292e7 fix normal user phone edit control 2023-02-25 11:47:34 +08:00
Gucheng Wang
8fbd5b1a74 disable demo prompt for get-organizations API 2023-02-25 11:01:48 +08:00
Gucheng Wang
f5a05ac534 improve application homepage 2023-02-25 10:50:50 +08:00
Gucheng Wang
05fade1d05 fix role list link error 2023-02-25 09:39:19 +08:00
Gucheng Wang
8aefa02036 fix message length 2023-02-25 08:36:24 +08:00
Yaodong Yu
3b6ec3e7c4 feat: improve saml idp err message (#1584) 2023-02-24 21:20:57 +08:00
Yang Luo
910816c7a3 Fix bug in GetLanguage() 2023-02-24 20:17:23 +08:00
Yaodong Yu
412a8b5da7 fix: init name is inconsistent with frontend (#1583) 2023-02-24 14:28:34 +08:00
Yaodong Yu
8ebd16a14e feat: fix resetting email and phone bug (#1579) 2023-02-23 18:06:13 +08:00
Gucheng Wang
44ec854465 Refactor getClientIdLabel() and getClientSecretLabel() 2023-02-23 17:57:46 +08:00
imp2002
26e87b0d98 feat: fix compatibility with lower version browsers like Chrome 87 (#1578) 2023-02-22 20:57:57 +08:00
Gucheng Wang
7e0ea0b8d9 Fix missing accountItem crash bug 2023-02-22 12:16:05 +08:00
Gucheng Wang
ace8e9da06 Refactor getAppIdRow() 2023-02-22 12:10:55 +08:00
Yaodong Yu
aac8714d72 feat: handle aliyun SMS response error (#1577) 2023-02-21 20:08:23 +08:00
Yaodong Yu
e71e41b343 feat: fix captcha none type bug (#1572) 2023-02-19 16:56:51 +08:00
Yang Luo
6131286cbd Add getBuiltInAccountItems() 2023-02-19 09:45:06 +08:00
Yang Luo
3bda8fb9dc Remove Migrator_1_245_0_PR_1557 2023-02-19 09:38:57 +08:00
github-actions[bot]
11f55a474c refactor: New Crowdin translations (#1440)
* refactor: New Crowdin translations by Github Action

* refactor: New Crowdin Backend translations by Github Action

---------

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2023-02-18 23:46:44 +08:00
Yang Luo
4806e76cf6 Fix demo mode default login 2023-02-18 23:43:22 +08:00
Yang Luo
edbd3d4018 Add i18n banner 2023-02-18 18:09:43 +08:00
Yang Luo
3f0a741e6c Improve i18n languages 2023-02-18 17:35:36 +08:00
Yang Luo
d273fdd670 Use username as saml:NameID 2023-02-18 16:42:45 +08:00
Yang Luo
3ae81716b9 Fix getLdaps() GET 2023-02-18 16:27:47 +08:00
Yang Luo
3a70f4e788 Add Setting.isResponseDenied() 2023-02-18 16:21:12 +08:00
Yang Luo
842d4865b2 Fix router error message's i18n 2023-02-18 16:11:23 +08:00
imp2002
19fb7273bb fix: detect access denied by response message for demo mode (#1565)
fix: detect access denied by response message for demo mode
2023-02-18 12:12:54 +08:00
Yaodong Yu
943bd82731 feat: fix migrator_1_245_0_PR_1557.go (#1564) 2023-02-18 10:58:14 +08:00
Yaodong Yu
f2f962b893 fix: refactor functions and code (#1559) 2023-02-18 09:31:58 +08:00
Yaodong Yu
eb72c9f273 feat: support multiple country codes for sending SMS (#1557)
* feat: support multiple country code

* feat: improve UI

* feat: migrate accountItem

* fix: Aliyun compatible

* fix: phone validate

* fix: typo
2023-02-16 22:53:28 +08:00
Yang Luo
4605938f8e Refactor FetchFilter.js code 2023-02-16 22:50:08 +08:00
imp2002
14fa914e6f feat: add IsDemoMode for frontend (#1555)
* feat: add `IsDemoMode` for frontend

* fix: add i18n

* fix: support autologin and go same page

* fix: use i18n for button text
2023-02-16 20:36:30 +08:00
Yaodong Yu
e877045671 feat: fix CAS login crash bug (#1549) 2023-02-14 16:52:15 +08:00
jakiuncle
29f1ec08a2 fix: fix CI error by auto waiting for localhost:7001 to start up (#1548) 2023-02-14 14:50:58 +08:00
June
389744a27d feat: change claims to claimsWithoutThirdIdp when gen token (#1552) 2023-02-14 09:33:46 +08:00
June
dc7b66822d feat: change token ExpiresIn to second (#1550) 2023-02-14 09:18:30 +08:00
Yaodong Yu
efacf8226c fix: session Id error (#1554) 2023-02-13 22:58:26 +08:00
Zayn Xie
6beb68dcce fix: some bugs in session module when testing single-log-in (#1547)
Co-authored-by: Zayn Xie <84443886+xiaoniuren99@users.noreply.github.com>
2023-02-13 18:16:31 +08:00
Yang Luo
c9b990a319 Add removeExtraSessionIds() 2023-02-12 21:11:16 +08:00
Yang Luo
eedcde3aa5 Refactor session.go 2023-02-12 21:06:08 +08:00
Yaodong Yu
950a274b23 fix: region don't display in userEditPage (#1544) 2023-02-12 18:56:56 +08:00
Yang Luo
478bd05db4 Improve error handling in migrator 2023-02-12 10:39:20 +08:00
Zayn Xie
9256791420 feat: app session control and db migrate (#1539)
* feat: integrate application session management into Casdoor's session management (#774) && standardized the database migration process (#1533)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774)

* feat: integrate application session management into Casdoor's session management (#774) && standardized the database migration process

* feat: integrate application session management into Casdoor's session management (#774) && standardized the database migration process

* feat: integrate application session management into Casdoor's session management (#774) && standardized the database migration process

---------

Co-authored-by: Zayn Xie <84443886+xiaoniuren99@users.noreply.github.com>

* fix: migrate err

* fix: migrate err

* feat: app session control and db migrate

* feat: app session control and db migrate

* feat: app session control and db migrate

---------

Co-authored-by: Zayn Xie <84443886+xiaoniuren99@users.noreply.github.com>
2023-02-12 09:33:24 +08:00
Yang Luo
6f2ef32d02 Update xorm.io/core to v0.7.3 2023-02-11 17:46:34 +08:00
hsluoyz
8b8c866fd2 feat: replace gomail and disable the Email username check for Mailtrap (#1538) 2023-02-11 15:59:23 +08:00
June
6f7230e949 feat: support refresh token on GetOAuthToken (#1536) 2023-02-10 23:52:13 +08:00
wht
9558bb4167 feat: fix file name length problem (#1534) 2023-02-10 20:27:20 +08:00
imp2002
04567babf8 feat: fix click MenuItem blank part invalid bug (#1535) 2023-02-10 18:11:15 +08:00
133 changed files with 2870 additions and 771 deletions

View File

@@ -97,21 +97,20 @@ jobs:
- uses: actions/setup-node@v2 - uses: actions/setup-node@v2
with: with:
node-version: 16 node-version: 16
- name: back start
run: nohup go run ./main.go &
working-directory: ./
- name: front install - name: front install
run: yarn install run: yarn install
working-directory: ./web working-directory: ./web
- name: front start - name: front start
run: nohup yarn start & run: nohup yarn start &
working-directory: ./web working-directory: ./web
- name: back start - uses: cypress-io/github-action@v4
run: nohup go run ./main.go & with:
working-directory: ./ working-directory: ./web
- name: Sleep for starting wait-on: 'http://localhost:7001'
run: sleep 90s wait-on-timeout: 180
shell: bash
- name: e2e
run: npx cypress run --spec "**/e2e/**.cy.js"
working-directory: ./web
- uses: actions/upload-artifact@v3 - uses: actions/upload-artifact@v3
if: failure() if: failure()

View File

@@ -20,9 +20,9 @@ import (
"github.com/casbin/casbin/v2" "github.com/casbin/casbin/v2"
"github.com/casbin/casbin/v2/model" "github.com/casbin/casbin/v2/model"
xormadapter "github.com/casbin/xorm-adapter/v3"
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/object" "github.com/casdoor/casdoor/object"
xormadapter "github.com/casdoor/xorm-adapter/v3"
stringadapter "github.com/qiangmzsx/string-adapter/v2" stringadapter "github.com/qiangmzsx/string-adapter/v2"
) )

View File

@@ -21,19 +21,21 @@ type CaptchaProvider interface {
} }
func GetCaptchaProvider(captchaType string) CaptchaProvider { func GetCaptchaProvider(captchaType string) CaptchaProvider {
if captchaType == "Default" { switch captchaType {
case "Default":
return NewDefaultCaptchaProvider() return NewDefaultCaptchaProvider()
} else if captchaType == "reCAPTCHA" { case "reCAPTCHA":
return NewReCaptchaProvider() return NewReCaptchaProvider()
} else if captchaType == "hCaptcha" { case "Aliyun Captcha":
return NewHCaptchaProvider()
} else if captchaType == "Aliyun Captcha" {
return NewAliyunCaptchaProvider() return NewAliyunCaptchaProvider()
} else if captchaType == "GEETEST" { case "hCaptcha":
return NewHCaptchaProvider()
case "GEETEST":
return NewGEETESTCaptchaProvider() return NewGEETESTCaptchaProvider()
} else if captchaType == "Cloudflare Turnstile" { case "Cloudflare Turnstile":
return NewCloudflareTurnstileProvider() return NewCloudflareTurnstileProvider()
} }
return nil return nil
} }

View File

@@ -20,5 +20,5 @@ staticBaseUrl = "https://cdn.casbin.org"
isDemoMode = false isDemoMode = false
batchSize = 100 batchSize = 100
ldapServerPort = 389 ldapServerPort = 389
languages = en,zh,es,fr,de,ja,ko,ru languages = en,zh,es,fr,de,ja,ko,ru,vi
quota = {"organization": -1, "user": -1, "application": -1, "provider": -1} quota = {"organization": -1, "user": -1, "application": -1, "provider": -1}

View File

@@ -105,6 +105,23 @@ func GetConfigDataSourceName() string {
return dataSourceName return dataSourceName
} }
func GetLanguage(language string) string {
if language == "" || language == "*" {
return "en"
}
if len(language) < 2 {
return "en"
}
language = language[0:2]
if strings.Contains(GetConfigString("languages"), language) {
return language
} else {
return "en"
}
}
func IsDemoMode() bool { func IsDemoMode() bool {
return strings.ToLower(GetConfigString("isDemoMode")) == "true" return strings.ToLower(GetConfigString("isDemoMode")) == "true"
} }

View File

@@ -58,7 +58,7 @@ type RequestForm struct {
EmailCode string `json:"emailCode"` EmailCode string `json:"emailCode"`
PhoneCode string `json:"phoneCode"` PhoneCode string `json:"phoneCode"`
PhonePrefix string `json:"phonePrefix"` CountryCode string `json:"countryCode"`
AutoSignin bool `json:"autoSignin"` AutoSignin bool `json:"autoSignin"`
@@ -121,7 +121,7 @@ func (c *ApiController) Signup() {
} }
organization := object.GetOrganization(fmt.Sprintf("%s/%s", "admin", form.Organization)) organization := object.GetOrganization(fmt.Sprintf("%s/%s", "admin", form.Organization))
msg := object.CheckUserSignup(application, organization, form.Username, form.Password, form.Name, form.FirstName, form.LastName, form.Email, form.Phone, form.Affiliation, c.GetAcceptLanguage()) msg := object.CheckUserSignup(application, organization, form.Username, form.Password, form.Name, form.FirstName, form.LastName, form.Email, form.Phone, form.CountryCode, form.Affiliation, c.GetAcceptLanguage())
if msg != "" { if msg != "" {
c.ResponseError(msg) c.ResponseError(msg)
return return
@@ -137,7 +137,7 @@ func (c *ApiController) Signup() {
var checkPhone string var checkPhone string
if application.IsSignupItemVisible("Phone") && form.Phone != "" { if application.IsSignupItemVisible("Phone") && form.Phone != "" {
checkPhone = fmt.Sprintf("+%s%s", form.PhonePrefix, form.Phone) checkPhone, _ = util.GetE164Number(form.Phone, form.CountryCode)
checkResult := object.CheckVerificationCode(checkPhone, form.PhoneCode, c.GetAcceptLanguage()) checkResult := object.CheckVerificationCode(checkPhone, form.PhoneCode, c.GetAcceptLanguage())
if len(checkResult) != 0 { if len(checkResult) != 0 {
c.ResponseError(c.T("account:Phone: %s"), checkResult) c.ResponseError(c.T("account:Phone: %s"), checkResult)
@@ -179,6 +179,7 @@ func (c *ApiController) Signup() {
Avatar: organization.DefaultAvatar, Avatar: organization.DefaultAvatar,
Email: form.Email, Email: form.Email,
Phone: form.Phone, Phone: form.Phone,
CountryCode: form.CountryCode,
Address: []string{}, Address: []string{},
Affiliation: form.Affiliation, Affiliation: form.Affiliation,
IdCard: form.IdCard, IdCard: form.IdCard,
@@ -254,7 +255,10 @@ func (c *ApiController) Logout() {
if accessToken == "" && redirectUri == "" { if accessToken == "" && redirectUri == "" {
c.ClearUserSession() c.ClearUserSession()
object.DeleteSessionId(user, c.Ctx.Input.CruSession.SessionID()) // TODO https://github.com/casdoor/casdoor/pull/1494#discussion_r1095675265
owner, username := util.GetOwnerAndNameFromId(user)
object.DeleteSessionId(util.GetSessionId(owner, username, object.CasdoorApplication), c.Ctx.Input.CruSession.SessionID())
util.LogInfo(c.Ctx, "API: [%s] logged out", user) util.LogInfo(c.Ctx, "API: [%s] logged out", user)
application := c.GetSessionApplication() application := c.GetSessionApplication()
@@ -291,7 +295,8 @@ func (c *ApiController) Logout() {
} }
c.ClearUserSession() c.ClearUserSession()
object.DeleteSessionId(user, c.Ctx.Input.CruSession.SessionID()) // TODO https://github.com/casdoor/casdoor/pull/1494#discussion_r1095675265
object.DeleteSessionId(util.GetSessionId(object.CasdoorOrganization, object.CasdoorApplication, user), c.Ctx.Input.CruSession.SessionID())
util.LogInfo(c.Ctx, "API: [%s] logged out", user) util.LogInfo(c.Ctx, "API: [%s] logged out", user)
c.Ctx.Redirect(http.StatusFound, fmt.Sprintf("%s?state=%s", strings.TrimRight(redirectUri, "/"), state)) c.Ctx.Redirect(http.StatusFound, fmt.Sprintf("%s?state=%s", strings.TrimRight(redirectUri, "/"), state))

View File

@@ -139,8 +139,13 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
}) })
} }
if resp.Status == "ok" { if resp.Status == "ok" && user.Owner == object.CasdoorOrganization && application.Name == object.CasdoorApplication {
object.SetSession(user.GetId(), c.Ctx.Input.CruSession.SessionID()) object.AddSession(&object.Session{
Owner: user.Owner,
Name: user.Name,
Application: application.Name,
SessionId: []string{c.Ctx.Input.CruSession.SessionID()},
})
} }
return resp return resp
@@ -258,34 +263,32 @@ func (c *ApiController) Login() {
checkDest = form.Username checkDest = form.Username
} else { } else {
verificationCodeType = "phone" verificationCodeType = "phone"
if len(form.PhonePrefix) == 0 {
responseText := fmt.Sprintf(c.T("auth:%s No phone prefix"), verificationCodeType)
c.ResponseError(responseText)
return
}
if user != nil && util.GetMaskedPhone(user.Phone) == form.Username { if user != nil && util.GetMaskedPhone(user.Phone) == form.Username {
form.Username = user.Phone form.Username = user.Phone
} }
checkDest = fmt.Sprintf("+%s%s", form.PhonePrefix, form.Username)
} }
user = object.GetUserByFields(form.Organization, form.Username)
if user == nil { if user = object.GetUserByFields(form.Organization, form.Username); user == nil {
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(form.Organization, form.Username))) c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(form.Organization, form.Username)))
return return
} }
if verificationCodeType == "phone" {
form.CountryCode = user.GetCountryCode(form.CountryCode)
var ok bool
if checkDest, ok = util.GetE164Number(form.Username, form.CountryCode); !ok {
c.ResponseError(fmt.Sprintf(c.T("verification:Phone number is invalid in your region %s"), form.CountryCode))
return
}
}
checkResult = object.CheckSigninCode(user, checkDest, form.Code, c.GetAcceptLanguage()) checkResult = object.CheckSigninCode(user, checkDest, form.Code, c.GetAcceptLanguage())
if len(checkResult) != 0 { if len(checkResult) != 0 {
responseText := fmt.Sprintf("%s - %s", verificationCodeType, checkResult) c.ResponseError(fmt.Sprintf("%s - %s", verificationCodeType, checkResult))
c.ResponseError(responseText)
return return
} }
// disable the verification code // disable the verification code
if strings.Contains(form.Username, "@") { object.DisableVerificationCode(checkDest)
object.DisableVerificationCode(form.Username)
} else {
object.DisableVerificationCode(fmt.Sprintf("+%s%s", form.PhonePrefix, form.Username))
}
} else { } else {
application := object.GetApplication(fmt.Sprintf("admin/%s", form.Application)) application := object.GetApplication(fmt.Sprintf("admin/%s", form.Application))
if application == nil { if application == nil {

View File

@@ -18,9 +18,9 @@ import (
"encoding/json" "encoding/json"
"github.com/beego/beego/utils/pagination" "github.com/beego/beego/utils/pagination"
xormadapter "github.com/casbin/xorm-adapter/v3"
"github.com/casdoor/casdoor/object" "github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
xormadapter "github.com/casdoor/xorm-adapter/v3"
) )
func (c *ApiController) GetCasbinAdapters() { func (c *ApiController) GetCasbinAdapters() {

View File

@@ -51,7 +51,7 @@ type LdapSyncResp struct {
func (c *ApiController) GetLdapUser() { func (c *ApiController) GetLdapUser() {
ldapServer := LdapServer{} ldapServer := LdapServer{}
err := json.Unmarshal(c.Ctx.Input.RequestBody, &ldapServer) err := json.Unmarshal(c.Ctx.Input.RequestBody, &ldapServer)
if err != nil || util.IsStrsEmpty(ldapServer.Host, ldapServer.Admin, ldapServer.Passwd, ldapServer.BaseDn) { if err != nil || util.IsStringsEmpty(ldapServer.Host, ldapServer.Admin, ldapServer.Passwd, ldapServer.BaseDn) {
c.ResponseError(c.T("general:Missing parameter")) c.ResponseError(c.T("general:Missing parameter"))
return return
} }
@@ -104,7 +104,7 @@ func (c *ApiController) GetLdapUser() {
// GetLdaps // GetLdaps
// @Tag Account API // @Tag Account API
// @Title GetLdaps // @Title GetLdaps
// @router /get-ldaps [post] // @router /get-ldaps [get]
func (c *ApiController) GetLdaps() { func (c *ApiController) GetLdaps() {
owner := c.Input().Get("owner") owner := c.Input().Get("owner")
@@ -115,11 +115,11 @@ func (c *ApiController) GetLdaps() {
// GetLdap // GetLdap
// @Tag Account API // @Tag Account API
// @Title GetLdap // @Title GetLdap
// @router /get-ldap [post] // @router /get-ldap [get]
func (c *ApiController) GetLdap() { func (c *ApiController) GetLdap() {
id := c.Input().Get("id") id := c.Input().Get("id")
if util.IsStrsEmpty(id) { if util.IsStringsEmpty(id) {
c.ResponseError(c.T("general:Missing parameter")) c.ResponseError(c.T("general:Missing parameter"))
return return
} }
@@ -140,7 +140,7 @@ func (c *ApiController) AddLdap() {
return return
} }
if util.IsStrsEmpty(ldap.Owner, ldap.ServerName, ldap.Host, ldap.Admin, ldap.Passwd, ldap.BaseDn) { if util.IsStringsEmpty(ldap.Owner, ldap.ServerName, ldap.Host, ldap.Admin, ldap.Passwd, ldap.BaseDn) {
c.ResponseError(c.T("general:Missing parameter")) c.ResponseError(c.T("general:Missing parameter"))
return return
} }
@@ -170,7 +170,7 @@ func (c *ApiController) AddLdap() {
func (c *ApiController) UpdateLdap() { func (c *ApiController) UpdateLdap() {
var ldap object.Ldap var ldap object.Ldap
err := json.Unmarshal(c.Ctx.Input.RequestBody, &ldap) err := json.Unmarshal(c.Ctx.Input.RequestBody, &ldap)
if err != nil || util.IsStrsEmpty(ldap.Owner, ldap.ServerName, ldap.Host, ldap.Admin, ldap.Passwd, ldap.BaseDn) { if err != nil || util.IsStringsEmpty(ldap.Owner, ldap.ServerName, ldap.Host, ldap.Admin, ldap.Passwd, ldap.BaseDn) {
c.ResponseError(c.T("general:Missing parameter")) c.ResponseError(c.T("general:Missing parameter"))
return return
} }

View File

@@ -180,6 +180,7 @@ func (c *ApiController) UploadResource() {
fileType, _ = util.GetOwnerAndNameFromId(mimeType) fileType, _ = util.GetOwnerAndNameFromId(mimeType)
} }
fullFilePath = object.GetTruncatedPath(provider, fullFilePath, 175)
if tag != "avatar" && tag != "termsOfUse" { if tag != "avatar" && tag != "termsOfUse" {
ext := filepath.Ext(filepath.Base(fullFilePath)) ext := filepath.Ext(filepath.Base(fullFilePath))
index := len(fullFilePath) - len(ext) index := len(fullFilePath) - len(ext)

View File

@@ -80,7 +80,7 @@ func (c *ApiController) SendEmail() {
c.ResponseOk() c.ResponseOk()
} }
if util.IsStrsEmpty(emailForm.Title, emailForm.Content, emailForm.Sender) { if util.IsStringsEmpty(emailForm.Title, emailForm.Content, emailForm.Sender) {
c.ResponseError(fmt.Sprintf(c.T("service:Empty parameters for emailForm: %v"), emailForm)) c.ResponseError(fmt.Sprintf(c.T("service:Empty parameters for emailForm: %v"), emailForm))
return return
} }
@@ -130,13 +130,13 @@ func (c *ApiController) SendSms() {
return return
} }
org := object.GetOrganization(smsForm.OrgId)
var invalidReceivers []string var invalidReceivers []string
for idx, receiver := range smsForm.Receivers { for idx, receiver := range smsForm.Receivers {
if !util.IsPhoneCnValid(receiver) { // The receiver phone format: E164 like +8613854673829 +441932567890
if !util.IsPhoneValid(receiver, "") {
invalidReceivers = append(invalidReceivers, receiver) invalidReceivers = append(invalidReceivers, receiver)
} else { } else {
smsForm.Receivers[idx] = fmt.Sprintf("+%s%s", org.PhonePrefix, receiver) smsForm.Receivers[idx] = receiver
} }
} }

View File

@@ -22,29 +22,10 @@ import (
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
) )
// DeleteSession
// @Title DeleteSession
// @Tag Session API
// @Description Delete session by userId
// @Param id query string true "The id ( owner/name )(owner/name) of user."
// @Success 200 {array} string The Response object
// @router /delete-session [post]
func (c *ApiController) DeleteSession() {
var session object.Session
err := json.Unmarshal(c.Ctx.Input.RequestBody, &session)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteSession(util.GetId(session.Owner, session.Name)))
c.ServeJSON()
}
// GetSessions // GetSessions
// @Title GetSessions // @Title GetSessions
// @Tag Session API // @Tag Session API
// @Description Get organization user sessions // @Description Get organization user sessions.
// @Param owner query string true "The organization name" // @Param owner query string true "The organization name"
// @Success 200 {array} string The Response object // @Success 200 {array} string The Response object
// @router /get-sessions [get] // @router /get-sessions [get]
@@ -66,3 +47,93 @@ func (c *ApiController) GetSessions() {
c.ResponseOk(sessions, paginator.Nums()) c.ResponseOk(sessions, paginator.Nums())
} }
} }
// GetSingleSession
// @Title GetSingleSession
// @Tag Session API
// @Description Get session for one user in one application.
// @Param id query string true "The id(organization/application/user) of session"
// @Success 200 {array} string The Response object
// @router /get-session [get]
func (c *ApiController) GetSingleSession() {
id := c.Input().Get("sessionPkId")
c.Data["json"] = object.GetSingleSession(id)
c.ServeJSON()
}
// UpdateSession
// @Title UpdateSession
// @Tag Session API
// @Description Update session for one user in one application.
// @Param id query string true "The id(organization/application/user) of session"
// @Success 200 {array} string The Response object
// @router /update-session [post]
func (c *ApiController) UpdateSession() {
var session object.Session
err := json.Unmarshal(c.Ctx.Input.RequestBody, &session)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateSession(util.GetSessionId(session.Owner, session.Name, session.Application), &session))
c.ServeJSON()
}
// AddSession
// @Title AddSession
// @Tag Session API
// @Description Add session for one user in one application. If there are other existing sessions, join the session into the list.
// @Param id query string true "The id(organization/application/user) of session"
// @Param sessionId query string true "sessionId to be added"
// @Success 200 {array} string The Response object
// @router /add-session [post]
func (c *ApiController) AddSession() {
var session object.Session
err := json.Unmarshal(c.Ctx.Input.RequestBody, &session)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddSession(&session))
c.ServeJSON()
}
// DeleteSession
// @Title DeleteSession
// @Tag Session API
// @Description Delete session for one user in one application.
// @Param id query string true "The id(organization/application/user) of session"
// @Success 200 {array} string The Response object
// @router /delete-session [post]
func (c *ApiController) DeleteSession() {
var session object.Session
err := json.Unmarshal(c.Ctx.Input.RequestBody, &session)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteSession(util.GetSessionId(session.Owner, session.Name, session.Application)))
c.ServeJSON()
}
// IsSessionDuplicated
// @Title IsSessionDuplicated
// @Tag Session API
// @Description Check if there are other different sessions for one user in one application.
// @Param id query string true "The id(organization/application/user) of session"
// @Param sessionId query string true "sessionId to be checked"
// @Success 200 {array} string The Response object
// @router /is-session-duplicated [get]
func (c *ApiController) IsSessionDuplicated() {
id := c.Input().Get("sessionPkId")
sessionId := c.Input().Get("sessionId")
isUserSessionDuplicated := object.IsSessionDuplicated(id, sessionId)
c.Data["json"] = &Response{Status: "ok", Msg: "", Data: isUserSessionDuplicated}
c.ServeJSON()
}

View File

@@ -172,6 +172,7 @@ func (c *ApiController) GetOAuthCode() {
// @router /login/oauth/access_token [post] // @router /login/oauth/access_token [post]
func (c *ApiController) GetOAuthToken() { func (c *ApiController) GetOAuthToken() {
grantType := c.Input().Get("grant_type") grantType := c.Input().Get("grant_type")
refreshToken := c.Input().Get("refresh_token")
clientId := c.Input().Get("client_id") clientId := c.Input().Get("client_id")
clientSecret := c.Input().Get("client_secret") clientSecret := c.Input().Get("client_secret")
code := c.Input().Get("code") code := c.Input().Get("code")
@@ -192,6 +193,7 @@ func (c *ApiController) GetOAuthToken() {
clientId = tokenRequest.ClientId clientId = tokenRequest.ClientId
clientSecret = tokenRequest.ClientSecret clientSecret = tokenRequest.ClientSecret
grantType = tokenRequest.GrantType grantType = tokenRequest.GrantType
refreshToken = tokenRequest.RefreshToken
code = tokenRequest.Code code = tokenRequest.Code
verifier = tokenRequest.Verifier verifier = tokenRequest.Verifier
scope = tokenRequest.Scope scope = tokenRequest.Scope
@@ -203,7 +205,7 @@ func (c *ApiController) GetOAuthToken() {
} }
host := c.Ctx.Request.Host host := c.Ctx.Request.Host
c.Data["json"] = object.GetOAuthToken(grantType, clientId, clientSecret, code, verifier, scope, username, password, host, tag, avatar, c.GetAcceptLanguage()) c.Data["json"] = object.GetOAuthToken(grantType, clientId, clientSecret, code, verifier, scope, username, password, host, refreshToken, tag, avatar, c.GetAcceptLanguage())
c.SetTokenErrorHttpStatus() c.SetTokenErrorHttpStatus()
c.ServeJSON() c.ServeJSON()
} }

View File

@@ -62,6 +62,10 @@ func checkPermissionForUpdateUser(userId string, newUser object.User, c *ApiCont
item := object.GetAccountItemByName("Phone", organization) item := object.GetAccountItemByName("Phone", organization)
itemsChanged = append(itemsChanged, item) itemsChanged = append(itemsChanged, item)
} }
if oldUser.CountryCode != newUser.CountryCode {
item := object.GetAccountItemByName("Country code", organization)
itemsChanged = append(itemsChanged, item)
}
if oldUser.Region != newUser.Region { if oldUser.Region != newUser.Region {
item := object.GetAccountItemByName("Country/Region", organization) item := object.GetAccountItemByName("Country/Region", organization)
itemsChanged = append(itemsChanged, item) itemsChanged = append(itemsChanged, item)

View File

@@ -17,7 +17,6 @@ package controllers
import ( import (
"fmt" "fmt"
"strconv" "strconv"
"strings"
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/i18n" "github.com/casdoor/casdoor/i18n"
@@ -56,11 +55,8 @@ func (c *ApiController) T(error string) string {
// GetAcceptLanguage ... // GetAcceptLanguage ...
func (c *ApiController) GetAcceptLanguage() string { func (c *ApiController) GetAcceptLanguage() string {
lang := c.Ctx.Request.Header.Get("Accept-Language") language := c.Ctx.Request.Header.Get("Accept-Language")
if lang == "" || !strings.Contains(conf.GetConfigString("languages"), lang[0:2]) { return conf.GetLanguage(language)
lang = "en"
}
return lang[0:2]
} }
// SetTokenErrorHttpStatus ... // SetTokenErrorHttpStatus ...

View File

@@ -24,6 +24,13 @@ import (
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
) )
const (
SignupVerification = "signup"
ResetVerification = "reset"
LoginVerification = "login"
ForgetVerification = "forget"
)
func (c *ApiController) getCurrentUser() *object.User { func (c *ApiController) getCurrentUser() *object.User {
var user *object.User var user *object.User
userId := c.GetSessionUsername() userId := c.GetSessionUsername()
@@ -42,18 +49,15 @@ func (c *ApiController) getCurrentUser() *object.User {
func (c *ApiController) SendVerificationCode() { func (c *ApiController) SendVerificationCode() {
destType := c.Ctx.Request.Form.Get("type") destType := c.Ctx.Request.Form.Get("type")
dest := c.Ctx.Request.Form.Get("dest") dest := c.Ctx.Request.Form.Get("dest")
countryCode := c.Ctx.Request.Form.Get("countryCode")
checkType := c.Ctx.Request.Form.Get("checkType") checkType := c.Ctx.Request.Form.Get("checkType")
checkId := c.Ctx.Request.Form.Get("checkId") checkId := c.Ctx.Request.Form.Get("checkId")
checkKey := c.Ctx.Request.Form.Get("checkKey") checkKey := c.Ctx.Request.Form.Get("checkKey")
checkUser := c.Ctx.Request.Form.Get("checkUser")
applicationId := c.Ctx.Request.Form.Get("applicationId") applicationId := c.Ctx.Request.Form.Get("applicationId")
method := c.Ctx.Request.Form.Get("method") method := c.Ctx.Request.Form.Get("method")
checkUser := c.Ctx.Request.Form.Get("checkUser")
remoteAddr := util.GetIPFromRequest(c.Ctx.Request) remoteAddr := util.GetIPFromRequest(c.Ctx.Request)
if destType == "" {
c.ResponseError(c.T("general:Missing parameter") + ": type.")
return
}
if dest == "" { if dest == "" {
c.ResponseError(c.T("general:Missing parameter") + ": dest.") c.ResponseError(c.T("general:Missing parameter") + ": dest.")
return return
@@ -62,98 +66,104 @@ func (c *ApiController) SendVerificationCode() {
c.ResponseError(c.T("general:Missing parameter") + ": applicationId.") c.ResponseError(c.T("general:Missing parameter") + ": applicationId.")
return return
} }
if !strings.Contains(applicationId, "/") {
c.ResponseError(c.T("verification:Wrong parameter") + ": applicationId.")
return
}
if checkType == "" { if checkType == "" {
c.ResponseError(c.T("general:Missing parameter") + ": checkType.") c.ResponseError(c.T("general:Missing parameter") + ": checkType.")
return return
} }
if !strings.Contains(applicationId, "/") {
c.ResponseError(c.T("verification:Wrong parameter") + ": applicationId.")
return
}
captchaProvider := captcha.GetCaptchaProvider(checkType) if checkType != "none" {
if captchaProvider != nil {
if checkKey == "" { if checkKey == "" {
c.ResponseError(c.T("general:Missing parameter") + ": checkKey.") c.ResponseError(c.T("general:Missing parameter") + ": checkKey.")
return return
} }
isHuman, err := captchaProvider.VerifyCaptcha(checkKey, checkId)
if err != nil { if captchaProvider := captcha.GetCaptchaProvider(checkType); captchaProvider == nil {
c.ResponseError(c.T("general:don't support captchaProvider: ") + checkType)
return
} else if isHuman, err := captchaProvider.VerifyCaptcha(checkKey, checkId); err != nil {
c.ResponseError(err.Error()) c.ResponseError(err.Error())
return return
} } else if !isHuman {
if !isHuman {
c.ResponseError(c.T("verification:Turing test failed.")) c.ResponseError(c.T("verification:Turing test failed."))
return return
} }
} }
user := c.getCurrentUser()
application := object.GetApplication(applicationId) application := object.GetApplication(applicationId)
organization := object.GetOrganization(fmt.Sprintf("%s/%s", application.Owner, application.Organization)) organization := object.GetOrganization(util.GetId(application.Owner, application.Organization))
if organization == nil { if organization == nil {
c.ResponseError(c.T("verification:Organization does not exist")) c.ResponseError(c.T("verification:Organization does not exist"))
return return
} }
if checkUser == "true" && user == nil && object.GetUserByFields(organization.Name, dest) == nil { var user *object.User
c.ResponseError(c.T("general:Please login first")) // checkUser != "", means method is ForgetVerification
return if checkUser != "" {
owner := application.Organization
user = object.GetUser(util.GetId(owner, checkUser))
} }
sendResp := errors.New("invalid dest type") sendResp := errors.New("invalid dest type")
if user == nil && checkUser != "" && checkUser != "true" {
name := application.Organization
user = object.GetUser(fmt.Sprintf("%s/%s", name, checkUser))
}
switch destType { switch destType {
case "email": case "email":
if user != nil && util.GetMaskedEmail(user.Email) == dest {
dest = user.Email
}
if !util.IsEmailValid(dest) { if !util.IsEmailValid(dest) {
c.ResponseError(c.T("verification:Email is invalid")) c.ResponseError(c.T("verification:Email is invalid"))
return return
} }
userByEmail := object.GetUserByEmail(organization.Name, dest) if method == LoginVerification || method == ForgetVerification {
if userByEmail == nil && method != "signup" && method != "reset" { if user != nil && util.GetMaskedEmail(user.Email) == dest {
c.ResponseError(c.T("verification:the user does not exist, please sign up first")) dest = user.Email
return }
user = object.GetUserByEmail(organization.Name, dest)
if user == nil {
c.ResponseError(c.T("verification:the user does not exist, please sign up first"))
return
}
} else if method == ResetVerification {
user = c.getCurrentUser()
} }
provider := application.GetEmailProvider() provider := application.GetEmailProvider()
sendResp = object.SendVerificationCodeToEmail(organization, user, provider, remoteAddr, dest) sendResp = object.SendVerificationCodeToEmail(organization, user, provider, remoteAddr, dest)
case "phone": case "phone":
if user != nil && util.GetMaskedPhone(user.Phone) == dest { if method == LoginVerification || method == ForgetVerification {
dest = user.Phone if user != nil && util.GetMaskedPhone(user.Phone) == dest {
} dest = user.Phone
if !util.IsPhoneCnValid(dest) { }
c.ResponseError(c.T("verification:Phone number is invalid"))
return if user = object.GetUserByPhone(organization.Name, dest); user == nil {
c.ResponseError(c.T("verification:the user does not exist, please sign up first"))
return
}
countryCode = user.GetCountryCode(countryCode)
} else if method == ResetVerification {
if user = c.getCurrentUser(); user != nil {
countryCode = user.GetCountryCode(countryCode)
}
} }
userByPhone := object.GetUserByPhone(organization.Name, dest)
if userByPhone == nil && method != "signup" && method != "reset" {
c.ResponseError(c.T("verification:the user does not exist, please sign up first"))
return
}
dest = fmt.Sprintf("+%s%s", organization.PhonePrefix, dest)
provider := application.GetSmsProvider() provider := application.GetSmsProvider()
sendResp = object.SendVerificationCodeToPhone(organization, user, provider, remoteAddr, dest) if phone, ok := util.GetE164Number(dest, countryCode); !ok {
c.ResponseError(fmt.Sprintf(c.T("verification:Phone number is invalid in your region %s"), countryCode))
return
} else {
sendResp = object.SendVerificationCodeToPhone(organization, user, provider, remoteAddr, phone)
}
} }
if sendResp != nil { if sendResp != nil {
c.Data["json"] = Response{Status: "error", Msg: sendResp.Error()} c.ResponseError(sendResp.Error())
} else { } else {
c.Data["json"] = Response{Status: "ok"} c.ResponseOk()
} }
c.ServeJSON()
} }
// ResetEmailOrPhone ... // ResetEmailOrPhone ...
@@ -169,7 +179,8 @@ func (c *ApiController) ResetEmailOrPhone() {
destType := c.Ctx.Request.Form.Get("type") destType := c.Ctx.Request.Form.Get("type")
dest := c.Ctx.Request.Form.Get("dest") dest := c.Ctx.Request.Form.Get("dest")
code := c.Ctx.Request.Form.Get("code") code := c.Ctx.Request.Form.Get("code")
if len(dest) == 0 || len(code) == 0 || len(destType) == 0 {
if util.IsStringsEmpty(destType, dest, code) {
c.ResponseError(c.T("general:Missing parameter")) c.ResponseError(c.T("general:Missing parameter"))
return return
} }
@@ -177,7 +188,7 @@ func (c *ApiController) ResetEmailOrPhone() {
checkDest := dest checkDest := dest
organization := object.GetOrganizationByUser(user) organization := object.GetOrganizationByUser(user)
if destType == "phone" { if destType == "phone" {
if object.HasUserByField(user.Owner, "phone", user.Phone) { if object.HasUserByField(user.Owner, "phone", dest) {
c.ResponseError(c.T("check:Phone already exists")) c.ResponseError(c.T("check:Phone already exists"))
return return
} }
@@ -192,14 +203,12 @@ func (c *ApiController) ResetEmailOrPhone() {
c.ResponseError(errMsg) c.ResponseError(errMsg)
return return
} }
if checkDest, ok = util.GetE164Number(dest, user.GetCountryCode("")); !ok {
phonePrefix := "86" c.ResponseError(fmt.Sprintf(c.T("verification:Phone number is invalid in your region %s"), user.CountryCode))
if organization != nil && organization.PhonePrefix != "" { return
phonePrefix = organization.PhonePrefix
} }
checkDest = fmt.Sprintf("+%s%s", phonePrefix, dest)
} else if destType == "email" { } else if destType == "email" {
if object.HasUserByField(user.Owner, "email", user.Email) { if object.HasUserByField(user.Owner, "email", dest) {
c.ResponseError(c.T("check:Email already exists")) c.ResponseError(c.T("check:Email already exists"))
return return
} }
@@ -215,8 +224,8 @@ func (c *ApiController) ResetEmailOrPhone() {
return return
} }
} }
if ret := object.CheckVerificationCode(checkDest, code, c.GetAcceptLanguage()); len(ret) != 0 { if msg := object.CheckVerificationCode(checkDest, code, c.GetAcceptLanguage()); len(msg) != 0 {
c.ResponseError(ret) c.ResponseError(msg)
return return
} }
@@ -233,8 +242,7 @@ func (c *ApiController) ResetEmailOrPhone() {
} }
object.DisableVerificationCode(checkDest) object.DisableVerificationCode(checkDest)
c.Data["json"] = Response{Status: "ok"} c.ResponseOk()
c.ServeJSON()
} }
// VerifyCaptcha ... // VerifyCaptcha ...

22
go.mod
View File

@@ -3,56 +3,58 @@ module github.com/casdoor/casdoor
go 1.16 go 1.16
require ( require (
github.com/Masterminds/squirrel v1.5.3
github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b
github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387 github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387
github.com/aliyun/alibaba-cloud-sdk-go v1.62.188 // indirect
github.com/aws/aws-sdk-go v1.44.4 github.com/aws/aws-sdk-go v1.44.4
github.com/beego/beego v1.12.11 github.com/beego/beego v1.12.11
github.com/beevik/etree v1.1.0 github.com/beevik/etree v1.1.0
github.com/casbin/casbin/v2 v2.30.1 github.com/casbin/casbin/v2 v2.30.1
github.com/casbin/xorm-adapter/v3 v3.0.1 github.com/casdoor/go-sms-sender v0.5.2
github.com/casdoor/go-sms-sender v0.5.1 github.com/casdoor/gomail/v2 v2.0.1
github.com/casdoor/oss v1.2.0 github.com/casdoor/oss v1.2.0
github.com/casdoor/xorm-adapter/v3 v3.0.4
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
github.com/denisenkom/go-mssqldb v0.9.0 github.com/denisenkom/go-mssqldb v0.9.0
github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b
github.com/forestmgy/ldapserver v1.1.0 github.com/forestmgy/ldapserver v1.1.0
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df
github.com/go-ldap/ldap/v3 v3.3.0 github.com/go-ldap/ldap/v3 v3.3.0
github.com/go-mysql-org/go-mysql v1.7.0
github.com/go-pay/gopay v1.5.72 github.com/go-pay/gopay v1.5.72
github.com/go-sql-driver/mysql v1.5.0 github.com/go-sql-driver/mysql v1.6.0
github.com/golang-jwt/jwt/v4 v4.2.0 github.com/golang-jwt/jwt/v4 v4.2.0
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-cmp v0.5.8 // indirect github.com/google/go-cmp v0.5.8 // indirect
github.com/google/uuid v1.2.0 github.com/google/uuid v1.3.0
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
github.com/lestrrat-go/jwx v1.2.21 github.com/lestrrat-go/jwx v1.2.21
github.com/lib/pq v1.8.0 github.com/lib/pq v1.8.0
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3 github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3
github.com/markbates/goth v1.75.2 github.com/markbates/goth v1.75.2
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
github.com/nyaruka/phonenumbers v1.1.5
github.com/qiangmzsx/string-adapter/v2 v2.1.0 github.com/qiangmzsx/string-adapter/v2 v2.1.0
github.com/robfig/cron/v3 v3.0.1 github.com/robfig/cron/v3 v3.0.1
github.com/russellhaering/gosaml2 v0.6.0 github.com/russellhaering/gosaml2 v0.6.0
github.com/russellhaering/goxmldsig v1.1.1 github.com/russellhaering/goxmldsig v1.1.1
github.com/satori/go.uuid v1.2.0 github.com/satori/go.uuid v1.2.0
github.com/shirou/gopsutil v3.21.11+incompatible github.com/shirou/gopsutil v3.21.11+incompatible
github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/stretchr/testify v1.8.0 github.com/stretchr/testify v1.8.0
github.com/tealeg/xlsx v1.0.5 github.com/tealeg/xlsx v1.0.5
github.com/thanhpk/randstr v1.0.4 github.com/thanhpk/randstr v1.0.4
github.com/tklauser/go-sysconf v0.3.10 // indirect github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/xorm-io/core v0.7.4
github.com/xorm-io/xorm v1.1.6
github.com/yusufpapurcu/wmi v1.2.2 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 golang.org/x/crypto v0.0.0-20220214200702-86341886e292
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/square/go-jose.v2 v2.6.0
gopkg.in/yaml.v2 v2.3.0 // indirect gopkg.in/yaml.v2 v2.3.0 // indirect
modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84 modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84
xorm.io/builder v0.3.12 // indirect
xorm.io/core v0.7.2
xorm.io/xorm v1.1.2
) )

118
go.sum
View File

@@ -58,7 +58,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= github.com/Masterminds/squirrel v1.5.3 h1:YPpoceAcxuzIljlr5iWpNKaql7hLeG1KLSrhvdHpkZc=
github.com/Masterminds/squirrel v1.5.3/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b h1:EgJ6N2S0h1WfFIjU5/VVHWbMSVYXAluop97Qxpr/lfQ= github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b h1:EgJ6N2S0h1WfFIjU5/VVHWbMSVYXAluop97Qxpr/lfQ=
github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b/go.mod h1:3SAoF0F5EbcOuBD5WT9nYkbIJieBS84cUQXADbXeBsU= github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b/go.mod h1:3SAoF0F5EbcOuBD5WT9nYkbIJieBS84cUQXADbXeBsU=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@@ -69,11 +70,11 @@ github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387 h1:loy0fjI90v
github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387/go.mod h1:GuR5j/NW7AU7tDAQUDGCtpiPxWIOy/c3kiRDnlwiCHc= github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387/go.mod h1:GuR5j/NW7AU7tDAQUDGCtpiPxWIOy/c3kiRDnlwiCHc=
github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc= github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk= github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1075 h1:Z0SzZttfYI/raZ5O9WF3cezZJTSW4Yz4Kow9uWdyRwg=
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1075/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA= github.com/aliyun/alibaba-cloud-sdk-go v1.61.1075/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA=
github.com/aliyun/alibaba-cloud-sdk-go v1.62.188 h1:8lIVcOlHW+fKCGMEf6nuGTTEFOt/EZJPZ8oq0kTlhGk=
github.com/aliyun/alibaba-cloud-sdk-go v1.62.188/go.mod h1:Api2AkmMgGaSUAhmk76oaFObkoeCPc/bKAqcyplPODs=
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible h1:9gWa46nstkJ9miBReJcN8Gq34cBFbzSpQZVVT9N09TM= github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible h1:9gWa46nstkJ9miBReJcN8Gq34cBFbzSpQZVVT9N09TM=
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
github.com/aws/aws-sdk-go v1.44.4 h1:ePN0CVJMdiz2vYUcJH96eyxRrtKGSDMgyhP6rah2OgE= github.com/aws/aws-sdk-go v1.44.4 h1:ePN0CVJMdiz2vYUcJH96eyxRrtKGSDMgyhP6rah2OgE=
github.com/aws/aws-sdk-go v1.44.4/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go v1.44.4/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
@@ -85,6 +86,8 @@ github.com/beego/goyaml2 v0.0.0-20130207012346-5545475820dd/go.mod h1:1b+Y/CofkY
github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU= github.com/beego/x2j v0.0.0-20131220205130-a0352aadc542/go.mod h1:kSeGC/p1AbBiEp5kat81+DSQrZenVBZXklMLaELspWU=
github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs= github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@@ -96,12 +99,14 @@ github.com/casbin/casbin/v2 v2.1.0/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n
github.com/casbin/casbin/v2 v2.28.3/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= github.com/casbin/casbin/v2 v2.28.3/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
github.com/casbin/casbin/v2 v2.30.1 h1:P5HWadDL7olwUXNdcuKUBk+x75Y2eitFxYTcLNKeKF0= github.com/casbin/casbin/v2 v2.30.1 h1:P5HWadDL7olwUXNdcuKUBk+x75Y2eitFxYTcLNKeKF0=
github.com/casbin/casbin/v2 v2.30.1/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= github.com/casbin/casbin/v2 v2.30.1/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
github.com/casbin/xorm-adapter/v3 v3.0.1 h1:0l0zkYxo6cNuIdrBZgFxlje1TRvmheYa/zIp+sGPK58= github.com/casdoor/go-sms-sender v0.5.2 h1:LRjqoXBAOsH4yxXeJ7kINMesyoyEx5pEoiJz9d7lGJA=
github.com/casbin/xorm-adapter/v3 v3.0.1/go.mod h1:1BL7rHEDXrxO+vQdSo/ZaWKRivXl7YTos67GdMYcd20= github.com/casdoor/go-sms-sender v0.5.2/go.mod h1:kBykbqwgRDXbXdMAIxmZKinVM1WjdqEbej5LAbUbcfI=
github.com/casdoor/go-sms-sender v0.5.1 h1:1/Wp1OLkVAVY4lEGQhekSNetSAWhnPcxYPV7xpCZgC0= github.com/casdoor/gomail/v2 v2.0.1 h1:J+FG6x80s9e5lBHUn8Sv0Y56mud34KiWih5YdmudR/w=
github.com/casdoor/go-sms-sender v0.5.1/go.mod h1:kBykbqwgRDXbXdMAIxmZKinVM1WjdqEbej5LAbUbcfI= github.com/casdoor/gomail/v2 v2.0.1/go.mod h1:VnGPslEAtpix5FjHisR/WKB1qvZDBaujbikxDe9d+2Q=
github.com/casdoor/oss v1.2.0 h1:ozLAE+nnNdFQBWbzH8U9spzaO8h8NrB57lBcdyMUUQ8= github.com/casdoor/oss v1.2.0 h1:ozLAE+nnNdFQBWbzH8U9spzaO8h8NrB57lBcdyMUUQ8=
github.com/casdoor/oss v1.2.0/go.mod h1:qii35VBuxnR/uEuYSKpS0aJ8htQFOcCVsZ4FHgHLuss= github.com/casdoor/oss v1.2.0/go.mod h1:qii35VBuxnR/uEuYSKpS0aJ8htQFOcCVsZ4FHgHLuss=
github.com/casdoor/xorm-adapter/v3 v3.0.4 h1:vB04Ao8n2jA7aFBI9F+gGXo9+Aa1IQP6mTdo50913DM=
github.com/casdoor/xorm-adapter/v3 v3.0.4/go.mod h1:4WTcUw+bTgBylGHeGHzTtBvuTXRS23dtwzFLl9tsgFM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -118,6 +123,9 @@ github.com/couchbase/gomemcached v0.1.2-0.20201224031647-c432ccf49f32/go.mod h1:
github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs= github.com/couchbase/goutils v0.0.0-20210118111533-e33d3ffb5401/go.mod h1:BQwMFlJzDjFDG3DJUdU0KORxn88UlsOULuxLExMh3Hs=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY= github.com/cupcake/rdb v0.0.0-20161107195141-43ba34106c76/go.mod h1:vYwsqCOLxGiisLwp9rITslkFNpZD5rz43tf41QFkTWY=
github.com/cznic/mathutil v0.0.0-20181122101859-297441e03548/go.mod h1:e6NPNENfs9mPDVNRekM7lKScauxd5kXTr1Mfyig6TDM=
github.com/cznic/sortutil v0.0.0-20181122101858-f5f958428db8/go.mod h1:q2w6Bg5jeox1B+QkJ6Wp/+Vn0G/bo3f1uY7Fn3vivIQ=
github.com/cznic/strutil v0.0.0-20171016134553-529a34b1c186/go.mod h1:AHHPPPXTw0h6pVabbcbyGRK1DckRn7r/STdZEeIDzZc=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
@@ -126,7 +134,6 @@ github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f/go.mod h1:QGrK8vMWW
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d h1:1iy2qD6JEhHKKhUOA9IWs7mjco7lnw2qx8FsRI2wirE= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d h1:1iy2qD6JEhHKKhUOA9IWs7mjco7lnw2qx8FsRI2wirE=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE=
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/denisenkom/go-mssqldb v0.9.0 h1:RSohk2RsiZqLZ0zCjtfn3S4Gp4exhpBWHyQ7D0yGjAk= github.com/denisenkom/go-mssqldb v0.9.0 h1:RSohk2RsiZqLZ0zCjtfn3S4Gp4exhpBWHyQ7D0yGjAk=
github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/denisenkom/go-mssqldb v0.9.0/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 h1:L63RATZFZuFMXy6ixnKmv3eNAXwYQF6HW1vd4IYsQqQ=
@@ -154,14 +161,14 @@ github.com/go-asn1-ber/asn1-ber v1.5.1/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkPro
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df h1:Bao6dhmbTA1KFVxmJ6nBoMuOJit2yjEgLJpIMYpop0E=
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df/go.mod h1:GJr+FCSXshIwgHBtLglIg9M2l2kQSi6QjVAngtzI08Y=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-ldap/ldap/v3 v3.3.0 h1:lwx+SJpgOHd8tG6SumBQZXCmNX51zM8B1cfxJ5gv4tQ= github.com/go-ldap/ldap/v3 v3.3.0 h1:lwx+SJpgOHd8tG6SumBQZXCmNX51zM8B1cfxJ5gv4tQ=
github.com/go-ldap/ldap/v3 v3.3.0/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg= github.com/go-ldap/ldap/v3 v3.3.0/go.mod h1:iYS1MdmrmceOJ1QOTnRXrIs7i3kloqtmGQjRvjKpyMg=
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-mysql-org/go-mysql v1.7.0 h1:qE5FTRb3ZeTQmlk3pjE+/m2ravGxxRDrVDTyDe9tvqI=
github.com/go-mysql-org/go-mysql v1.7.0/go.mod h1:9cRWLtuXNKhamUPMkrDVzBhaomGvqLRLtBiyjvjc4pk=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-pay/gopay v1.5.72 h1:3zm64xMBhJBa8rXbm//q5UiGgOa4WO5XYEnU394N2Zw= github.com/go-pay/gopay v1.5.72 h1:3zm64xMBhJBa8rXbm//q5UiGgOa4WO5XYEnU394N2Zw=
@@ -174,8 +181,9 @@ github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl
github.com/go-playground/validator/v10 v10.8.0/go.mod h1:9JhgTzTaE31GZDpH/HSvHiRJrJ3iKAgqqH0Bl/Ocjdk= github.com/go-playground/validator/v10 v10.8.0/go.mod h1:9JhgTzTaE31GZDpH/HSvHiRJrJ3iKAgqqH0Bl/Ocjdk=
github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA= github.com/go-redis/redis v6.14.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/goccy/go-json v0.9.6 h1:5/4CtRQdtsX0sal8fdVhTaiMN01Ri8BExZZ8iRmHQ6E= github.com/goccy/go-json v0.9.6 h1:5/4CtRQdtsX0sal8fdVhTaiMN01Ri8BExZZ8iRmHQ6E=
github.com/goccy/go-json v0.9.6/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.9.6/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
@@ -250,8 +258,9 @@ github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hf
github.com/google/pprof v0.0.0-20200905233945-acf8798be1f7/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= github.com/google/pprof v0.0.0-20200905233945-acf8798be1f7/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.2.0 h1:qJYtXnJRWmpe7m/3XlyhrsLrEURqHRM2kxzoxXqyUDs=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
@@ -270,6 +279,7 @@ github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uG
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da h1:FjHUJJ7oBW4G/9j1KzlHaXL09LyMVM9rupS39lncbXk=
github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4= github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4=
github.com/jinzhu/configor v1.2.1 h1:OKk9dsR8i6HPOCZR8BcMtcEImAFjIhbJFZNyn5GCZko= github.com/jinzhu/configor v1.2.1 h1:OKk9dsR8i6HPOCZR8BcMtcEImAFjIhbJFZNyn5GCZko=
github.com/jinzhu/configor v1.2.1/go.mod h1:nX89/MOmDba7ZX7GCyU/VIaQ2Ar2aizBl2d3JLF/rDc= github.com/jinzhu/configor v1.2.1/go.mod h1:nX89/MOmDba7ZX7GCyU/VIaQ2Ar2aizBl2d3JLF/rDc=
@@ -278,6 +288,7 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo= github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8= github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U= github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
github.com/jmoiron/sqlx v1.3.3/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jonboulle/clockwork v0.2.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ= github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9qUBdQ=
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
@@ -306,6 +317,10 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ= github.com/ledisdb/ledisdb v0.0.0-20200510135210-d35789ec47e6/go.mod h1:n931TsDuKuq+uX4v1fulaMbA/7ZLLhjc85h7chZGBCQ=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A= github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A=
@@ -321,6 +336,7 @@ github.com/lestrrat-go/jwx v1.2.21/go.mod h1:9cfxnOH7G1gN75CaJP2hKGcxFEx5sPh1abR
github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4= github.com/lestrrat-go/option v1.0.0 h1:WqAWL8kh8VcSoD6xjSH34/1m8yxluXQbDeKNfvFeEO4=
github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.7.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg= github.com/lib/pq v1.8.0 h1:9xohqzkUwzR4Ga4ivdTcawVS89YSDVxXMa3xJX3cGzg=
github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lib/pq v1.8.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
@@ -337,7 +353,6 @@ github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.14.0/go.mod h1:JIl7NbARA7phWnGvh0LKTyg7S9BA+6gx71ShQilpsus=
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U= github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
@@ -357,6 +372,8 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ=
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U=
github.com/nyaruka/phonenumbers v1.1.5 h1:vYy2DI+z5hdaemqVzXYJ4CVyK92IG484CirEY+40GTo=
github.com/nyaruka/phonenumbers v1.1.5/go.mod h1:yShPJHDSH3aTKzCbXyVxNpbl2kA+F+Ne5Pun/MvFRos=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU= github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
@@ -364,8 +381,19 @@ github.com/onsi/ginkgo v1.12.0/go.mod h1:oUhWkIvk5aDxtKvDDuw8gItl8pKl42LzjC9KZE0
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ= github.com/onsi/gomega v1.7.1 h1:K0jcRCwNQM3vFGh1ppMtDh/+7ApJrjldlX8fA0jDTLQ=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A=
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU=
github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8 h1:USx2/E1bX46VG32FIw034Au6seQ2fY9NEILmNh/UlQg=
github.com/pingcap/check v0.0.0-20190102082844-67f458068fc8/go.mod h1:B1+S9LNcuMyLH/4HMTViQOJevkGiik3wW2AN9zb2fNQ=
github.com/pingcap/errors v0.11.0/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 h1:+FZIDR/D97YOPik4N4lPDaUcLDF/EQPogxtlHB2ZZRM=
github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63/go.mod h1:X2r9ueLEUZgtx2cIogM0v4Zj5uvvzhuuiu7Pn8HzMPg=
github.com/pingcap/log v0.0.0-20210625125904-98ed8e2eb1c7 h1:k2BbABz9+TNpYRwsCCFS8pEEnFVOdbgEjL/kTlLuzZQ=
github.com/pingcap/log v0.0.0-20210625125904-98ed8e2eb1c7/go.mod h1:8AanEdAHATuRurdGxZXBz0At+9avep+ub7U1AGYLIMM=
github.com/pingcap/tidb/parser v0.0.0-20221126021158-6b02a5d8ba7d h1:1DyyRrgYeNjqPkgjrdEsaIbX+kHpuTTk5ZOCtrcRFcQ=
github.com/pingcap/tidb/parser v0.0.0-20221126021158-6b02a5d8ba7d/go.mod h1:ElJiub4lRy6UZDb+0JHDkGEdr6aOli+ykhyej7VCLoI=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -413,7 +441,14 @@ github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644 h1:X+yvsM2yrEktyI
github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg= github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw= github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 h1:xT+JlYxNGqyT+XcU8iUrN18JYed2TvG9yN5ULG2jATM=
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
github.com/siddontang/go-log v0.0.0-20180807004314-8d05993dda07/go.mod h1:yFdBgwXP24JziuRl2NMUahT7nGLNOKi1SIiFxMttVD4=
github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed h1:KMgQoLJGCq1IoZpLZE3AIffh9veYWoVlsvA4ib55TMM=
github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed/go.mod h1:yFdBgwXP24JziuRl2NMUahT7nGLNOKi1SIiFxMttVD4=
github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s= github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s=
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA= github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
@@ -450,12 +485,22 @@ github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ= github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
github.com/twilio/twilio-go v0.26.0 h1:wFW4oTe3/LKt6bvByP7eio8JsjtaLHjMQKOUEzQry7U= github.com/twilio/twilio-go v0.26.0 h1:wFW4oTe3/LKt6bvByP7eio8JsjtaLHjMQKOUEzQry7U=
github.com/twilio/twilio-go v0.26.0/go.mod h1:lz62Hopu4vicpQ056H5TJ0JE4AP0rS3sQ35/ejmgOwE= github.com/twilio/twilio-go v0.26.0/go.mod h1:lz62Hopu4vicpQ056H5TJ0JE4AP0rS3sQ35/ejmgOwE=
github.com/uber/jaeger-client-go v2.30.0+incompatible h1:D6wyKGCecFaSRUpo8lCVbaOOb6ThwMmTEbhRwtKR97o=
github.com/uber/jaeger-client-go v2.30.0+incompatible/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
github.com/uber/jaeger-lib v2.4.1+incompatible h1:td4jdvLcExb4cBISKIpHuGoVXh+dVKhn2Um6rjCsSsg=
github.com/uber/jaeger-lib v2.4.1+incompatible/go.mod h1:ComeNDZlWwrWnDv8aPp0Ba6+uUTzImX/AauajbLI56U=
github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ= github.com/ugorji/go v0.0.0-20171122102828-84cb69a8af83/go.mod h1:hnLbHMwcvSihnDhEfx2/BzKp2xb0Y+ErdfYcrs9tkJQ=
github.com/volcengine/volc-sdk-golang v1.0.19 h1:jJp+aJgK0e//rZ9I0K2Y7ufJwvuZRo/AQsYDynXMNgA= github.com/volcengine/volc-sdk-golang v1.0.19 h1:jJp+aJgK0e//rZ9I0K2Y7ufJwvuZRo/AQsYDynXMNgA=
github.com/volcengine/volc-sdk-golang v1.0.19/go.mod h1:+GGi447k4p1I5PNdbpG2GLaF0Ui9vIInTojMM0IfSS4= github.com/volcengine/volc-sdk-golang v1.0.19/go.mod h1:+GGi447k4p1I5PNdbpG2GLaF0Ui9vIInTojMM0IfSS4=
github.com/wendal/errors v0.0.0-20181209125328-7f31f4b264ec/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc= github.com/wendal/errors v0.0.0-20181209125328-7f31f4b264ec/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xorm-io/builder v0.3.13 h1:J4oZxt4Gjgm/Si9iKazfzYwHB/ijEOD9EHInyjOSX+M=
github.com/xorm-io/builder v0.3.13/go.mod h1:24o5riRwzre2WvjmN+LM4YpUtJg7W8MdvJ8H57rvrJA=
github.com/xorm-io/core v0.7.4 h1:qIznlqqmYNEb03ewzRXCrNkbbxpkgc/44nVF8yoFV7Y=
github.com/xorm-io/core v0.7.4/go.mod h1:GueyhafDnkB0KK0fXX/dEhr/P1EAGW0GLmoNDUEE1Mo=
github.com/xorm-io/xorm v1.1.6 h1:s4fDpUXJx8Zr/PBovXNaadn+v1P3h/U3iV4OxAkWS8s=
github.com/xorm-io/xorm v1.1.6/go.mod h1:7nsSUdmgLIcqHSSaKOzbVQiZtzIzbpGf1GGSYp6DD70=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -470,6 +515,19 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/goleak v1.1.10 h1:z+mqJhf6ss6BSfSM671tgKyZBFPTTJM+HLxnhPC3wu0=
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.18.1 h1:CSUJ2mjFszzEWt4CdKISEuChVIXGBn3lAPwkRGyVrc4=
go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -488,6 +546,7 @@ golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.0.0-20220208233918-bba287dce954/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220208233918-bba287dce954/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE= golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/exp v0.0.0-20181106170214-d68db9428509/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -509,6 +568,7 @@ golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHl
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY= golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
@@ -520,7 +580,6 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo= golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -661,6 +720,8 @@ golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgw
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -689,6 +750,7 @@ golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20200929161345-d7fc70abf50f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20200929161345-d7fc70abf50f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20201125231158-b5590deeca9b/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs= golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -789,12 +851,13 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
gopkg.in/natefinch/lumberjack.v2 v2.0.0 h1:1Lc07Kr7qY4U2YPouBjpCLxpiyxIVoxqXgkXLknAOE8=
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI=
gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
@@ -821,38 +884,41 @@ modernc.org/cc/v3 v3.31.5-0.20210308123301-7a3e9dab9009 h1:u0oCo5b9wyLr++HF3AN9J
modernc.org/cc/v3 v3.31.5-0.20210308123301-7a3e9dab9009/go.mod h1:0R6jl1aZlIl2avnYfbfHBS1QB6/f+16mihBObaBC878= modernc.org/cc/v3 v3.31.5-0.20210308123301-7a3e9dab9009/go.mod h1:0R6jl1aZlIl2avnYfbfHBS1QB6/f+16mihBObaBC878=
modernc.org/ccgo/v3 v3.9.0 h1:JbcEIqjw4Agf+0g3Tc85YvfYqkkFOv6xBwS4zkfqSoA= modernc.org/ccgo/v3 v3.9.0 h1:JbcEIqjw4Agf+0g3Tc85YvfYqkkFOv6xBwS4zkfqSoA=
modernc.org/ccgo/v3 v3.9.0/go.mod h1:nQbgkn8mwzPdp4mm6BT6+p85ugQ7FrGgIcYaE7nSrpY= modernc.org/ccgo/v3 v3.9.0/go.mod h1:nQbgkn8mwzPdp4mm6BT6+p85ugQ7FrGgIcYaE7nSrpY=
modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8=
modernc.org/golex v1.0.1/go.mod h1:QCA53QtsT1NdGkaZZkF5ezFwk4IXh4BGNafAARTC254=
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM= modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM= modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/lex v1.0.0/go.mod h1:G6rxMTy3cH2iA0iXL/HRRv4Znu8MK4higxph/lE7ypk=
modernc.org/lexer v1.0.0/go.mod h1:F/Dld0YKYdZCLQ7bD0USbWL4YKCyTDRDHiDTOs0q0vk=
modernc.org/libc v1.7.13-0.20210308123627-12f642a52bb8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w= modernc.org/libc v1.7.13-0.20210308123627-12f642a52bb8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/libc v1.8.0 h1:Pp4uv9g0csgBMpGPABKtkieF6O5MGhfGo6ZiOdlYfR8= modernc.org/libc v1.8.0 h1:Pp4uv9g0csgBMpGPABKtkieF6O5MGhfGo6ZiOdlYfR8=
modernc.org/libc v1.8.0/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w= modernc.org/libc v1.8.0/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.2.2 h1:+yFk8hBprV+4c0U9GjFtL+dV3N8hOJ8JCituQcMShFY=
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E= modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8=
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.0.4 h1:utMBrFcpnQDdNsmM6asmyH/FM9TqLPS7XF7otpJmrwM= modernc.org/memory v1.0.4 h1:utMBrFcpnQDdNsmM6asmyH/FM9TqLPS7XF7otpJmrwM=
modernc.org/memory v1.0.4/go.mod h1:nV2OApxradM3/OVbs2/0OsP6nPfakXpi50C7dcoHXlc= modernc.org/memory v1.0.4/go.mod h1:nV2OApxradM3/OVbs2/0OsP6nPfakXpi50C7dcoHXlc=
modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A= modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A=
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0= modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/parser v1.0.0/go.mod h1:H20AntYJ2cHHL6MHthJ8LZzXCdDCHMWt1KZXtIMjejA=
modernc.org/parser v1.0.2/go.mod h1:TXNq3HABP3HMaqLK7brD1fLA/LfN0KS6JxZn71QdDqs=
modernc.org/scanner v1.0.1/go.mod h1:OIzD2ZtjYk6yTuyqZr57FmifbM9fIH74SumloSsajuE=
modernc.org/sortutil v1.0.0/go.mod h1:1QO0q8IlIlmjBIwm6t/7sof874+xCfZouyqZMLIAtxM=
modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84 h1:rgEUzE849tFlHSoeCrKyS9cZAljC+DY7MdMHKq6R6sY= modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84 h1:rgEUzE849tFlHSoeCrKyS9cZAljC+DY7MdMHKq6R6sY=
modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84/go.mod h1:PGzq6qlhyYjL6uVbSgS6WoF7ZopTW/sI7+7p+mb4ZVU= modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84/go.mod h1:PGzq6qlhyYjL6uVbSgS6WoF7ZopTW/sI7+7p+mb4ZVU=
modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
modernc.org/strutil v1.1.0 h1:+1/yCzZxY2pZwwrsbH+4T7BQMoLQ9QiBshRC9eicYsc= modernc.org/strutil v1.1.0 h1:+1/yCzZxY2pZwwrsbH+4T7BQMoLQ9QiBshRC9eicYsc=
modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs= modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
modernc.org/tcl v1.5.0 h1:euZSUNfE0Fd4W8VqXI1Ly1v7fqDJoBuAV88Ea+SnaSs= modernc.org/tcl v1.5.0 h1:euZSUNfE0Fd4W8VqXI1Ly1v7fqDJoBuAV88Ea+SnaSs=
modernc.org/tcl v1.5.0/go.mod h1:gb57hj4pO8fRrK54zveIfFXBaMHK3SKJNWcmRw1cRzc= modernc.org/tcl v1.5.0/go.mod h1:gb57hj4pO8fRrK54zveIfFXBaMHK3SKJNWcmRw1cRzc=
modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk= modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM= modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/y v1.0.1/go.mod h1:Ho86I+LVHEI+LYXoUKlmOMAM1JTXOCfj8qi1T8PsClE=
modernc.org/z v1.0.1-0.20210308123920-1f282aa71362/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA= modernc.org/z v1.0.1-0.20210308123920-1f282aa71362/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
modernc.org/z v1.0.1 h1:WyIDpEpAIx4Hel6q/Pcgj/VhaQV5XPJ2I6ryIYbjnpc= modernc.org/z v1.0.1 h1:WyIDpEpAIx4Hel6q/Pcgj/VhaQV5XPJ2I6ryIYbjnpc=
modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA= modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
xorm.io/builder v0.3.7/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/builder v0.3.8/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/builder v0.3.12 h1:ASZYX7fQmy+o8UJdhlLHSW57JDOkM8DNhcAF5d0LiJM=
xorm.io/builder v0.3.12/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/core v0.7.2 h1:mEO22A2Z7a3fPaZMk6gKL/jMD80iiyNwRrX5HOv3XLw=
xorm.io/core v0.7.2/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM=
xorm.io/xorm v1.0.3/go.mod h1:uF9EtbhODq5kNWxMbnBEj8hRRZnlcNSz2t2N7HW/+A4=
xorm.io/xorm v1.1.2 h1:bje+1KZvK3m5AHtZNfUDlKEEyuw/IRHT+an0CLIG5TU=
xorm.io/xorm v1.1.2/go.mod h1:Cb0DKYTHbyECMaSfgRnIZp5aiUgQozxcJJ0vzcLGJSg=

View File

@@ -30,24 +30,26 @@ func TestGenerateI18nFrontend(t *testing.T) {
enData := parseEnData("frontend") enData := parseEnData("frontend")
writeI18nFile("frontend", "en", enData) writeI18nFile("frontend", "en", enData)
applyToOtherLanguage("frontend", "de", enData) applyToOtherLanguage("frontend", "zh", enData)
applyToOtherLanguage("frontend", "es", enData) applyToOtherLanguage("frontend", "es", enData)
applyToOtherLanguage("frontend", "fr", enData) applyToOtherLanguage("frontend", "fr", enData)
applyToOtherLanguage("frontend", "de", enData)
applyToOtherLanguage("frontend", "ja", enData) applyToOtherLanguage("frontend", "ja", enData)
applyToOtherLanguage("frontend", "ko", enData) applyToOtherLanguage("frontend", "ko", enData)
applyToOtherLanguage("frontend", "ru", enData) applyToOtherLanguage("frontend", "ru", enData)
applyToOtherLanguage("frontend", "zh", enData) applyToOtherLanguage("frontend", "vi", enData)
} }
func TestGenerateI18nBackend(t *testing.T) { func TestGenerateI18nBackend(t *testing.T) {
enData := parseEnData("backend") enData := parseEnData("backend")
writeI18nFile("backend", "en", enData) writeI18nFile("backend", "en", enData)
applyToOtherLanguage("backend", "de", enData) applyToOtherLanguage("backend", "zh", enData)
applyToOtherLanguage("backend", "es", enData) applyToOtherLanguage("backend", "es", enData)
applyToOtherLanguage("backend", "fr", enData) applyToOtherLanguage("backend", "fr", enData)
applyToOtherLanguage("backend", "de", enData)
applyToOtherLanguage("backend", "ja", enData) applyToOtherLanguage("backend", "ja", enData)
applyToOtherLanguage("backend", "ko", enData) applyToOtherLanguage("backend", "ko", enData)
applyToOtherLanguage("backend", "ru", enData) applyToOtherLanguage("backend", "ru", enData)
applyToOtherLanguage("backend", "zh", enData) applyToOtherLanguage("backend", "vi", enData)
} }

View File

@@ -9,7 +9,6 @@
"The application does not allow to sign up new account": "The application does not allow to sign up new account" "The application does not allow to sign up new account": "The application does not allow to sign up new account"
}, },
"auth": { "auth": {
"%s No phone prefix": "%s No phone prefix",
"Challenge method should be S256": "Challenge method should be S256", "Challenge method should be S256": "Challenge method should be S256",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s", "Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s", "Failed to login in: %s": "Failed to login in: %s",
@@ -55,15 +54,17 @@
"Username cannot contain white spaces": "Username cannot contain white spaces", "Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit", "Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Benutzername muss mindestens 2 Zeichen lang sein",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances", "password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s" "unsupported password type: %s": "unsupported password type: %s"
}, },
"general": { "general": {
"Missing parameter": "Missing parameter", "Missing parameter": "Missing parameter",
"Please login first": "Please login first", "Please login first": "Please login first",
"The user: %s doesn't exist": "The user: %s doesn't exist" "The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: "
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist" "Ldap server exist": "Ldap server exist"
@@ -130,7 +131,7 @@
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Organization does not exist": "Organization does not exist", "Organization does not exist": "Organization does not exist",
"Phone number is invalid": "Phone number is invalid", "Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",

View File

@@ -9,7 +9,6 @@
"The application does not allow to sign up new account": "The application does not allow to sign up new account" "The application does not allow to sign up new account": "The application does not allow to sign up new account"
}, },
"auth": { "auth": {
"%s No phone prefix": "%s No phone prefix",
"Challenge method should be S256": "Challenge method should be S256", "Challenge method should be S256": "Challenge method should be S256",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s", "Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s", "Failed to login in: %s": "Failed to login in: %s",
@@ -57,13 +56,15 @@
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances", "password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s" "unsupported password type: %s": "unsupported password type: %s"
}, },
"general": { "general": {
"Missing parameter": "Missing parameter", "Missing parameter": "Missing parameter",
"Please login first": "Please login first", "Please login first": "Please login first",
"The user: %s doesn't exist": "The user: %s doesn't exist" "The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: "
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist" "Ldap server exist": "Ldap server exist"
@@ -130,7 +131,7 @@
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Organization does not exist": "Organization does not exist", "Organization does not exist": "Organization does not exist",
"Phone number is invalid": "Phone number is invalid", "Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",

View File

@@ -9,7 +9,6 @@
"The application does not allow to sign up new account": "The application does not allow to sign up new account" "The application does not allow to sign up new account": "The application does not allow to sign up new account"
}, },
"auth": { "auth": {
"%s No phone prefix": "%s No phone prefix",
"Challenge method should be S256": "Challenge method should be S256", "Challenge method should be S256": "Challenge method should be S256",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s", "Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s", "Failed to login in: %s": "Failed to login in: %s",
@@ -57,13 +56,15 @@
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances", "password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s" "unsupported password type: %s": "unsupported password type: %s"
}, },
"general": { "general": {
"Missing parameter": "Missing parameter", "Missing parameter": "Missing parameter",
"Please login first": "Please login first", "Please login first": "Please login first",
"The user: %s doesn't exist": "The user: %s doesn't exist" "The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: "
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist" "Ldap server exist": "Ldap server exist"
@@ -130,7 +131,7 @@
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Organization does not exist": "Organization does not exist", "Organization does not exist": "Organization does not exist",
"Phone number is invalid": "Phone number is invalid", "Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",

View File

@@ -9,7 +9,6 @@
"The application does not allow to sign up new account": "The application does not allow to sign up new account" "The application does not allow to sign up new account": "The application does not allow to sign up new account"
}, },
"auth": { "auth": {
"%s No phone prefix": "%s No phone prefix",
"Challenge method should be S256": "Challenge method should be S256", "Challenge method should be S256": "Challenge method should be S256",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s", "Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s", "Failed to login in: %s": "Failed to login in: %s",
@@ -57,13 +56,15 @@
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances", "password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s" "unsupported password type: %s": "unsupported password type: %s"
}, },
"general": { "general": {
"Missing parameter": "Missing parameter", "Missing parameter": "Missing parameter",
"Please login first": "Please login first", "Please login first": "Please login first",
"The user: %s doesn't exist": "The user: %s doesn't exist" "The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: "
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist" "Ldap server exist": "Ldap server exist"
@@ -130,7 +131,7 @@
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Organization does not exist": "Organization does not exist", "Organization does not exist": "Organization does not exist",
"Phone number is invalid": "Phone number is invalid", "Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",

View File

@@ -9,7 +9,6 @@
"The application does not allow to sign up new account": "The application does not allow to sign up new account" "The application does not allow to sign up new account": "The application does not allow to sign up new account"
}, },
"auth": { "auth": {
"%s No phone prefix": "%s No phone prefix",
"Challenge method should be S256": "Challenge method should be S256", "Challenge method should be S256": "Challenge method should be S256",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s", "Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s", "Failed to login in: %s": "Failed to login in: %s",
@@ -57,13 +56,15 @@
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances", "password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s" "unsupported password type: %s": "unsupported password type: %s"
}, },
"general": { "general": {
"Missing parameter": "Missing parameter", "Missing parameter": "Missing parameter",
"Please login first": "Please login first", "Please login first": "Please login first",
"The user: %s doesn't exist": "The user: %s doesn't exist" "The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: "
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist" "Ldap server exist": "Ldap server exist"
@@ -130,7 +131,7 @@
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Organization does not exist": "Organization does not exist", "Organization does not exist": "Organization does not exist",
"Phone number is invalid": "Phone number is invalid", "Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",

View File

@@ -9,7 +9,6 @@
"The application does not allow to sign up new account": "The application does not allow to sign up new account" "The application does not allow to sign up new account": "The application does not allow to sign up new account"
}, },
"auth": { "auth": {
"%s No phone prefix": "%s No phone prefix",
"Challenge method should be S256": "Challenge method should be S256", "Challenge method should be S256": "Challenge method should be S256",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s", "Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s", "Failed to login in: %s": "Failed to login in: %s",
@@ -57,13 +56,15 @@
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances", "password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s" "unsupported password type: %s": "unsupported password type: %s"
}, },
"general": { "general": {
"Missing parameter": "Missing parameter", "Missing parameter": "Missing parameter",
"Please login first": "Please login first", "Please login first": "Please login first",
"The user: %s doesn't exist": "The user: %s doesn't exist" "The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: "
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist" "Ldap server exist": "Ldap server exist"
@@ -130,7 +131,7 @@
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Organization does not exist": "Organization does not exist", "Organization does not exist": "Organization does not exist",
"Phone number is invalid": "Phone number is invalid", "Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",

View File

@@ -9,7 +9,6 @@
"The application does not allow to sign up new account": "The application does not allow to sign up new account" "The application does not allow to sign up new account": "The application does not allow to sign up new account"
}, },
"auth": { "auth": {
"%s No phone prefix": "%s No phone prefix",
"Challenge method should be S256": "Challenge method should be S256", "Challenge method should be S256": "Challenge method should be S256",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s", "Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s", "Failed to login in: %s": "Failed to login in: %s",
@@ -57,13 +56,15 @@
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances", "password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s" "unsupported password type: %s": "unsupported password type: %s"
}, },
"general": { "general": {
"Missing parameter": "Missing parameter", "Missing parameter": "Missing parameter",
"Please login first": "Please login first", "Please login first": "Please login first",
"The user: %s doesn't exist": "The user: %s doesn't exist" "The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: "
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist" "Ldap server exist": "Ldap server exist"
@@ -130,7 +131,7 @@
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Organization does not exist": "Organization does not exist", "Organization does not exist": "Organization does not exist",
"Phone number is invalid": "Phone number is invalid", "Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",

147
i18n/locales/vi/data.json Normal file
View File

@@ -0,0 +1,147 @@
{
"account": {
"Email: %s": "Email: %s",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Invalid information": "Invalid information",
"Phone: %s": "Phone: %s",
"Please sign out first before signing in": "Please sign out first before signing in",
"Please sign out first before signing up": "Please sign out first before signing up",
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
"The provider type: %s is not supported": "The provider type: %s is not supported",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"Turing test failed.": "Turing test failed.",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
},
"check": {
"Affiliation cannot be blank": "Affiliation cannot be blank",
"DisplayName cannot be blank": "DisplayName cannot be blank",
"DisplayName is not valid real name": "DisplayName is not valid real name",
"Email already exists": "Email already exists",
"Email cannot be empty": "Email cannot be empty",
"Email is invalid": "Email is invalid",
"Empty username.": "Empty username.",
"FirstName cannot be blank": "FirstName cannot be blank",
"LastName cannot be blank": "LastName cannot be blank",
"Ldap user name or password incorrect": "Ldap user name or password incorrect",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Session outdated, please login again": "Session outdated, please login again",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s"
},
"general": {
"Missing parameter": "Missing parameter",
"Please login first": "Please login first",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: "
},
"ldap": {
"Ldap server exist": "Ldap server exist"
},
"link": {
"Please link first": "Please link first",
"This application has no providers": "This application has no providers",
"This application has no providers of type": "This application has no providers of type",
"This provider can't be unlinked": "This provider can't be unlinked",
"You are not the global admin, you can't unlink other users": "You are not the global admin, you can't unlink other users",
"You can't unlink yourself, you are not a member of any application": "You can't unlink yourself, you are not a member of any application"
},
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s."
},
"provider": {
"Invalid application id": "Invalid application id",
"the provider: %s does not exist": "the provider: %s does not exist"
},
"resource": {
"User is nil for tag: avatar": "User is nil for tag: avatar",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
},
"saml": {
"Application %s not found": "Application %s not found"
},
"saml_sp": {
"provider %s's category is not SAML": "provider %s's category is not SAML"
},
"service": {
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
},
"storage": {
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported"
},
"token": {
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space.",
"New password must have at least 6 characters": "New password must have at least 6 characters"
},
"user_upload": {
"Failed to import users": "Failed to import users"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
"The provider: %s is not found": "The provider: %s is not found"
},
"verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Email is invalid": "Email is invalid",
"Invalid captcha provider.": "Invalid captcha provider.",
"Organization does not exist": "Organization does not exist",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
"Unknown type": "Unknown type",
"Wrong parameter": "Wrong parameter",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

View File

@@ -9,7 +9,6 @@
"The application does not allow to sign up new account": "该应用不允许注册新用户" "The application does not allow to sign up new account": "该应用不允许注册新用户"
}, },
"auth": { "auth": {
"%s No phone prefix": "%s 无此手机号前缀",
"Challenge method should be S256": "Challenge 方法应该为 S256", "Challenge method should be S256": "Challenge 方法应该为 S256",
"Failed to create user, user information is invalid: %s": "创建用户失败,用户信息无效: %s", "Failed to create user, user information is invalid: %s": "创建用户失败,用户信息无效: %s",
"Failed to login in: %s": "登录失败: %s", "Failed to login in: %s": "登录失败: %s",
@@ -57,13 +56,15 @@
"Username is too long (maximum is 39 characters).": "用户名过长最大允许长度为39个字符", "Username is too long (maximum is 39 characters).": "用户名过长最大允许长度为39个字符",
"Username must have at least 2 characters": "用户名至少要有2个字符", "Username must have at least 2 characters": "用户名至少要有2个字符",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "密码错误次数已达上限,请在 %d 分后重试", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "密码错误次数已达上限,请在 %d 分后重试",
"Your region is not allow to signup by phone": "所在地区不支持手机号注册",
"password or code is incorrect, you have %d remaining chances": "密码错误,您还有 %d 次尝试的机会", "password or code is incorrect, you have %d remaining chances": "密码错误,您还有 %d 次尝试的机会",
"unsupported password type: %s": "不支持的密码类型: %s" "unsupported password type: %s": "不支持的密码类型: %s"
}, },
"general": { "general": {
"Missing parameter": "缺少参数", "Missing parameter": "缺少参数",
"Please login first": "请先登录", "Please login first": "请先登录",
"The user: %s doesn't exist": "用户: %s 不存在" "The user: %s doesn't exist": "用户: %s 不存在",
"don't support captchaProvider: ": "不支持验证码提供商: "
}, },
"ldap": { "ldap": {
"Ldap server exist": "LDAP服务器已存在" "Ldap server exist": "LDAP服务器已存在"
@@ -130,7 +131,7 @@
"Email is invalid": "非法的邮箱", "Email is invalid": "非法的邮箱",
"Invalid captcha provider.": "非法的验证码提供商", "Invalid captcha provider.": "非法的验证码提供商",
"Organization does not exist": "组织不存在", "Organization does not exist": "组织不存在",
"Phone number is invalid": "非法的手机号码", "Phone number is invalid in your region %s": "您所在地区的电话号码无效 %s",
"Turing test failed.": "验证码还未发送", "Turing test failed.": "验证码还未发送",
"Unable to get the email modify rule.": "无法获取邮箱修改规则", "Unable to get the email modify rule.": "无法获取邮箱修改规则",
"Unable to get the phone modify rule.": "无法获取手机号修改规则", "Unable to get the phone modify rule.": "无法获取手机号修改规则",

View File

@@ -7,7 +7,7 @@
"websiteUrl": "", "websiteUrl": "",
"favicon": "", "favicon": "",
"passwordType": "", "passwordType": "",
"phonePrefix": "", "countryCodes": [""],
"defaultAvatar": "", "defaultAvatar": "",
"tags": [""] "tags": [""]
} }
@@ -107,6 +107,7 @@
"avatar": "", "avatar": "",
"email": "", "email": "",
"phone": "", "phone": "",
"countryCode": "",
"address": [], "address": [],
"affiliation": "", "affiliation": "",
"tag": "", "tag": "",

View File

@@ -35,7 +35,10 @@ func main() {
createDatabase := flag.Bool("createDatabase", false, "true if you need Casdoor to create database") createDatabase := flag.Bool("createDatabase", false, "true if you need Casdoor to create database")
flag.Parse() flag.Parse()
object.InitAdapter(*createDatabase) object.InitAdapter()
object.DoMigration()
object.CreateTables(*createDatabase)
object.InitDb() object.InitDb()
object.InitFromFile() object.InitFromFile()
object.InitDefaultStorageProvider() object.InitDefaultStorageProvider()

View File

@@ -19,15 +19,15 @@ import (
"runtime" "runtime"
"github.com/beego/beego" "github.com/beego/beego"
xormadapter "github.com/casbin/xorm-adapter/v3"
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
xormadapter "github.com/casdoor/xorm-adapter/v3"
_ "github.com/denisenkom/go-mssqldb" // db = mssql _ "github.com/denisenkom/go-mssqldb" // db = mssql
_ "github.com/go-sql-driver/mysql" // db = mysql _ "github.com/go-sql-driver/mysql" // db = mysql
_ "github.com/lib/pq" // db = postgres _ "github.com/lib/pq" // db = postgres
_ "modernc.org/sqlite" // db = sqlite "github.com/xorm-io/core"
"xorm.io/core" "github.com/xorm-io/xorm"
"xorm.io/xorm" _ "modernc.org/sqlite" // db = sqlite
) )
var adapter *Adapter var adapter *Adapter
@@ -40,12 +40,16 @@ func InitConfig() {
beego.BConfig.WebConfig.Session.SessionOn = true beego.BConfig.WebConfig.Session.SessionOn = true
InitAdapter(true) InitAdapter()
MigrateDatabase() DoMigration()
CreateTables(true)
} }
func InitAdapter(createDatabase bool) { func InitAdapter() {
adapter = NewAdapter(conf.GetConfigString("driverName"), conf.GetConfigDataSourceName(), conf.GetConfigString("dbName")) adapter = NewAdapter(conf.GetConfigString("driverName"), conf.GetConfigDataSourceName(), conf.GetConfigString("dbName"))
}
func CreateTables(createDatabase bool) {
if createDatabase { if createDatabase {
adapter.CreateDatabase() adapter.CreateDatabase()
} }

View File

@@ -21,7 +21,7 @@ import (
"github.com/casdoor/casdoor/idp" "github.com/casdoor/casdoor/idp"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type SignupItem struct { type SignupItem struct {

View File

@@ -20,9 +20,9 @@ import (
"github.com/casbin/casbin/v2" "github.com/casbin/casbin/v2"
"github.com/casbin/casbin/v2/model" "github.com/casbin/casbin/v2/model"
xormadapter "github.com/casbin/xorm-adapter/v3"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" xormadapter "github.com/casdoor/xorm-adapter/v3"
"github.com/xorm-io/core"
) )
type CasbinAdapter struct { type CasbinAdapter struct {

View File

@@ -18,7 +18,7 @@ import (
"fmt" "fmt"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type Cert struct { type Cert struct {

View File

@@ -42,7 +42,7 @@ func init() {
reFieldWhiteList, _ = regexp.Compile(`^[A-Za-z0-9]+$`) reFieldWhiteList, _ = regexp.Compile(`^[A-Za-z0-9]+$`)
} }
func CheckUserSignup(application *Application, organization *Organization, username string, password string, displayName string, firstName string, lastName string, email string, phone string, affiliation string, lang string) string { func CheckUserSignup(application *Application, organization *Organization, username string, password string, displayName string, firstName string, lastName string, email string, phone string, countryCode string, affiliation string, lang string) string {
if organization == nil { if organization == nil {
return i18n.Translate(lang, "check:Organization does not exist") return i18n.Translate(lang, "check:Organization does not exist")
} }
@@ -107,7 +107,9 @@ func CheckUserSignup(application *Application, organization *Organization, usern
if HasUserByField(organization.Name, "phone", phone) { if HasUserByField(organization.Name, "phone", phone) {
return i18n.Translate(lang, "check:Phone already exists") return i18n.Translate(lang, "check:Phone already exists")
} else if organization.PhonePrefix == "86" && !util.IsPhoneCnValid(phone) { } else if !util.IsPhoneAllowInRegin(countryCode, organization.CountryCodes) {
return i18n.Translate(lang, "check:Your region is not allow to signup by phone")
} else if !util.IsPhoneValid(phone, countryCode) {
return i18n.Translate(lang, "check:Phone number is invalid") return i18n.Translate(lang, "check:Phone number is invalid")
} }
} }

View File

@@ -19,7 +19,7 @@ package object
import ( import (
"crypto/tls" "crypto/tls"
"github.com/go-gomail/gomail" "github.com/casdoor/gomail/v2"
) )
func getDialer(provider *Provider) *gomail.Dialer { func getDialer(provider *Provider) *gomail.Dialer {
@@ -45,6 +45,10 @@ func SendEmail(provider *Provider, title string, content string, dest string, se
message.SetHeader("Subject", title) message.SetHeader("Subject", title)
message.SetBody("text/html", content) message.SetBody("text/html", content)
if provider.Type == "Mailtrap" {
message.SkipUsernameCheck = true
}
return dialer.DialAndSend(message) return dialer.DialAndSend(message)
} }

View File

@@ -34,13 +34,44 @@ func InitDb() {
initBuiltInApplication() initBuiltInApplication()
initBuiltInCert() initBuiltInCert()
initBuiltInLdap() initBuiltInLdap()
} else {
MigrateDatabase()
} }
initWebAuthn() initWebAuthn()
} }
func getBuiltInAccountItems() []*AccountItem {
return []*AccountItem{
{Name: "Organization", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "ID", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
{Name: "Name", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "Display name", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Avatar", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "User type", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "Password", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
{Name: "Email", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Phone", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Country code", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "Country/Region", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Location", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Affiliation", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Title", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Homepage", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Bio", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Tag", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "Signup application", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "Roles", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
{Name: "Permissions", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
{Name: "3rd-party logins", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
{Name: "Properties", Visible: false, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is global admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is forbidden", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is deleted", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "WebAuthn credentials", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
{Name: "Managed accounts", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
}
}
func initBuiltInOrganization() bool { func initBuiltInOrganization() bool {
organization := getOrganization("admin", "built-in") organization := getOrganization("admin", "built-in")
if organization != nil { if organization != nil {
@@ -55,40 +86,12 @@ func initBuiltInOrganization() bool {
WebsiteUrl: "https://example.com", WebsiteUrl: "https://example.com",
Favicon: fmt.Sprintf("%s/img/casbin/favicon.ico", conf.GetConfigString("staticBaseUrl")), Favicon: fmt.Sprintf("%s/img/casbin/favicon.ico", conf.GetConfigString("staticBaseUrl")),
PasswordType: "plain", PasswordType: "plain",
PhonePrefix: "86", CountryCodes: []string{"CN"},
DefaultAvatar: fmt.Sprintf("%s/img/casbin.svg", conf.GetConfigString("staticBaseUrl")), DefaultAvatar: fmt.Sprintf("%s/img/casbin.svg", conf.GetConfigString("staticBaseUrl")),
Tags: []string{}, Tags: []string{},
Languages: []string{"en", "zh", "es", "fr", "de", "ja", "ko", "ru"}, Languages: []string{"en", "zh", "es", "fr", "de", "ja", "ko", "ru", "vi"},
InitScore: 2000, InitScore: 2000,
AccountItems: []*AccountItem{ AccountItems: getBuiltInAccountItems(),
{Name: "Organization", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "ID", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
{Name: "Name", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "Display name", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Avatar", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "User type", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "Password", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
{Name: "Email", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Phone", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Country/Region", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Location", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Affiliation", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Title", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Homepage", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Bio", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Tag", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "Signup application", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "Roles", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
{Name: "Permissions", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
{Name: "3rd-party logins", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
{Name: "Properties", Visible: false, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is global admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is forbidden", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is deleted", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "WebAuthn credentials", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
{Name: "Managed accounts", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
},
} }
AddOrganization(organization) AddOrganization(organization)
return false return false
@@ -111,6 +114,7 @@ func initBuiltInUser() {
Avatar: fmt.Sprintf("%s/img/casbin.svg", conf.GetConfigString("staticBaseUrl")), Avatar: fmt.Sprintf("%s/img/casbin.svg", conf.GetConfigString("staticBaseUrl")),
Email: "admin@example.com", Email: "admin@example.com",
Phone: "12345678910", Phone: "12345678910",
CountryCode: "CN",
Address: []string{}, Address: []string{},
Affiliation: "Example Inc.", Affiliation: "Example Inc.",
Tag: "staff", Tag: "staff",

View File

@@ -179,33 +179,7 @@ func initDefinedOrganization(organization *Organization) {
return return
} }
organization.CreatedTime = util.GetCurrentTime() organization.CreatedTime = util.GetCurrentTime()
organization.AccountItems = []*AccountItem{ organization.AccountItems = getBuiltInAccountItems()
{Name: "Organization", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "ID", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
{Name: "Name", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "Display name", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Avatar", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "User type", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "Password", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
{Name: "Email", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Phone", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Country/Region", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Location", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Affiliation", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Title", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Homepage", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Bio", Visible: true, ViewRule: "Public", ModifyRule: "Self"},
{Name: "Tag", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "Signup application", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
{Name: "Roles", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
{Name: "Permissions", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
{Name: "3rd-party logins", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
{Name: "Properties", Visible: false, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is global admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is forbidden", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
{Name: "Is deleted", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
}
AddOrganization(organization) AddOrganization(organization)
} }

View File

@@ -329,7 +329,7 @@ func GetLdaps(owner string) []*Ldap {
} }
func GetLdap(id string) *Ldap { func GetLdap(id string) *Ldap {
if util.IsStrsEmpty(id) { if util.IsStringsEmpty(id) {
return nil return nil
} }

47
object/migrator.go Normal file
View File

@@ -0,0 +1,47 @@
// Copyright 2023 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 "github.com/xorm-io/xorm/migrate"
type Migrator interface {
IsMigrationNeeded() bool
DoMigration() *migrate.Migration
}
func DoMigration() {
migrators := []Migrator{
&Migrator_1_101_0_PR_1083{},
&Migrator_1_235_0_PR_1530{},
&Migrator_1_240_0_PR_1539{},
// more migrators add here in chronological order...
}
migrations := []*migrate.Migration{}
for _, migrator := range migrators {
if migrator.IsMigrationNeeded() {
migrations = append(migrations, migrator.DoMigration())
}
}
options := &migrate.Options{
TableName: "migration",
IDColumnName: "id",
}
m := migrate.New(adapter.Engine, options, migrations)
m.Migrate()
}

View File

@@ -10,51 +10,36 @@
// distributed under the License is distributed on an "AS IS" BASIS, // distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License.package object // limitations under the License.
package object package object
import ( import (
"strings" "strings"
xormadapter "github.com/casbin/xorm-adapter/v3" "github.com/xorm-io/xorm"
"xorm.io/xorm" "github.com/xorm-io/xorm/migrate"
"xorm.io/xorm/migrate"
) )
func MigrateDatabase() { type Migrator_1_101_0_PR_1083 struct{}
migrations := []*migrate.Migration{
MigrateCasbinRule(),
MigratePermissionRule(),
}
m := migrate.New(adapter.Engine, migrate.DefaultOptions, migrations) func (*Migrator_1_101_0_PR_1083) IsMigrationNeeded() bool {
m.Migrate() exist1, _ := adapter.Engine.IsTableExist("model")
exist2, _ := adapter.Engine.IsTableExist("permission")
exist3, _ := adapter.Engine.IsTableExist("permission_rule")
if exist1 && exist2 && exist3 {
return true
}
return false
} }
func MigrateCasbinRule() *migrate.Migration { func (*Migrator_1_101_0_PR_1083) DoMigration() *migrate.Migration {
migration := migrate.Migration{
ID: "20221015CasbinRule--fill ptype field with p",
Migrate: func(engine *xorm.Engine) error {
_, err := engine.Cols("ptype").Update(&xormadapter.CasbinRule{
Ptype: "p",
})
return err
},
Rollback: func(engine *xorm.Engine) error {
return engine.DropTables(&xormadapter.CasbinRule{})
},
}
return &migration
}
func MigratePermissionRule() *migrate.Migration {
migration := migrate.Migration{ migration := migrate.Migration{
ID: "20230209MigratePermissionRule--Use V5 instead of V1 to store permissionID", ID: "20230209MigratePermissionRule--Use V5 instead of V1 to store permissionID",
Migrate: func(engine *xorm.Engine) error { Migrate: func(engine *xorm.Engine) error {
models := []*Model{} models := []*Model{}
err := engine.Find(&models, &Model{}) err := engine.Table("model").Find(&models, &Model{})
if err != nil { if err != nil {
panic(err) panic(err)
} }

View File

@@ -0,0 +1,49 @@
// Copyright 2023 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 (
xormadapter "github.com/casdoor/xorm-adapter/v3"
"github.com/xorm-io/xorm"
"github.com/xorm-io/xorm/migrate"
)
type Migrator_1_235_0_PR_1530 struct{}
func (*Migrator_1_235_0_PR_1530) IsMigrationNeeded() bool {
exist, _ := adapter.Engine.IsTableExist("casbin_rule")
if exist {
return true
}
return false
}
func (*Migrator_1_235_0_PR_1530) DoMigration() *migrate.Migration {
migration := migrate.Migration{
ID: "20221015CasbinRule--fill ptype field with p",
Migrate: func(engine *xorm.Engine) error {
_, err := engine.Cols("ptype").Update(&xormadapter.CasbinRule{
Ptype: "p",
})
return err
},
Rollback: func(engine *xorm.Engine) error {
return engine.DropTables(&xormadapter.CasbinRule{})
},
}
return &migration
}

View File

@@ -0,0 +1,141 @@
// Copyright 2023 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 (
"errors"
"github.com/xorm-io/xorm"
"github.com/xorm-io/xorm/migrate"
)
type Migrator_1_240_0_PR_1539 struct{}
func (*Migrator_1_240_0_PR_1539) IsMigrationNeeded() bool {
exist, _ := adapter.Engine.IsTableExist("session")
err := adapter.Engine.Table("session").Find(&[]*Session{})
if exist && err != nil {
return true
}
return false
}
func (*Migrator_1_240_0_PR_1539) DoMigration() *migrate.Migration {
migration := migrate.Migration{
ID: "20230211MigrateSession--Create a new field 'application' for table `session`",
Migrate: func(engine *xorm.Engine) error {
if alreadyCreated, _ := engine.IsTableExist("session_tmp"); alreadyCreated {
return errors.New("there is already a table called 'session_tmp', please rename or delete it for casdoor version migration and restart")
}
type oldSession struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
SessionId []string `json:"sessionId"`
}
tx := engine.NewSession()
defer tx.Close()
err := tx.Begin()
if err != nil {
return err
}
err = tx.Table("session_tmp").CreateTable(&Session{})
if err != nil {
return err
}
oldSessions := []*oldSession{}
newSessions := []*Session{}
err = tx.Table("session").Find(&oldSessions)
if err != nil {
return err
}
for _, oldSession := range oldSessions {
newApplication := "null"
if oldSession.Owner == "built-in" {
newApplication = "app-built-in"
}
newSessions = append(newSessions, &Session{
Owner: oldSession.Owner,
Name: oldSession.Name,
Application: newApplication,
CreatedTime: oldSession.CreatedTime,
SessionId: oldSession.SessionId,
})
}
rollbackFlag := false
_, err = tx.Table("session_tmp").Insert(newSessions)
count1, _ := tx.Table("session_tmp").Count()
count2, _ := tx.Table("session").Count()
if err != nil || count1 != count2 {
rollbackFlag = true
}
delete := &Session{
Application: "null",
}
_, err = tx.Table("session_tmp").Delete(*delete)
if err != nil {
rollbackFlag = true
}
if rollbackFlag {
tx.DropTable("session_tmp")
return errors.New("there is something wrong with data migration for table `session`, if there is a table called `session_tmp` not created by you in casdoor, please drop it, then restart anyhow")
}
err = tx.DropTable("session")
if err != nil {
return errors.New("fail to drop table `session` for casdoor, please drop it and rename the table `session_tmp` to `session` manually and restart")
}
// Already drop table `session`
// Can't find an api from xorm for altering table name
err = tx.Table("session").CreateTable(&Session{})
if err != nil {
return errors.New("there is something wrong with data migration for table `session`, please restart")
}
sessions := []*Session{}
tx.Table("session_tmp").Find(&sessions)
_, err = tx.Table("session").Insert(sessions)
if err != nil {
return errors.New("there is something wrong with data migration for table `session`, please drop table `session` and rename table `session_tmp` to `session` and restart")
}
err = tx.DropTable("session_tmp")
if err != nil {
return errors.New("fail to drop table `session_tmp` for casdoor, please drop it manually and restart")
}
tx.Commit()
return nil
},
}
return &migration
}

View File

@@ -19,7 +19,7 @@ import (
"github.com/casbin/casbin/v2/model" "github.com/casbin/casbin/v2/model"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type Model struct { type Model struct {

View File

@@ -21,7 +21,7 @@ import (
"github.com/casdoor/casdoor/cred" "github.com/casdoor/casdoor/cred"
"github.com/casdoor/casdoor/i18n" "github.com/casdoor/casdoor/i18n"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type AccountItem struct { type AccountItem struct {
@@ -49,7 +49,7 @@ type Organization struct {
Favicon string `xorm:"varchar(100)" json:"favicon"` Favicon string `xorm:"varchar(100)" json:"favicon"`
PasswordType string `xorm:"varchar(100)" json:"passwordType"` PasswordType string `xorm:"varchar(100)" json:"passwordType"`
PasswordSalt string `xorm:"varchar(100)" json:"passwordSalt"` PasswordSalt string `xorm:"varchar(100)" json:"passwordSalt"`
PhonePrefix string `xorm:"varchar(10)" json:"phonePrefix"` CountryCodes []string `xorm:"varchar(200)" json:"countryCodes"`
DefaultAvatar string `xorm:"varchar(100)" json:"defaultAvatar"` DefaultAvatar string `xorm:"varchar(100)" json:"defaultAvatar"`
DefaultApplication string `xorm:"varchar(100)" json:"defaultApplication"` DefaultApplication string `xorm:"varchar(100)" json:"defaultApplication"`
Tags []string `xorm:"mediumtext" json:"tags"` Tags []string `xorm:"mediumtext" json:"tags"`
@@ -211,6 +211,10 @@ func GetAccountItemByName(name string, organization *Organization) *AccountItem
} }
func CheckAccountItemModifyRule(accountItem *AccountItem, user *User, lang string) (bool, string) { func CheckAccountItemModifyRule(accountItem *AccountItem, user *User, lang string) (bool, string) {
if accountItem == nil {
return true, ""
}
switch accountItem.ModifyRule { switch accountItem.ModifyRule {
case "Admin": case "Admin":
if user == nil || !user.IsAdmin && !user.IsGlobalAdmin { if user == nil || !user.IsAdmin && !user.IsGlobalAdmin {

View File

@@ -19,7 +19,7 @@ import (
"net/http" "net/http"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type Payment struct { type Payment struct {
@@ -43,7 +43,7 @@ type Payment struct {
PayUrl string `xorm:"varchar(2000)" json:"payUrl"` PayUrl string `xorm:"varchar(2000)" json:"payUrl"`
ReturnUrl string `xorm:"varchar(1000)" json:"returnUrl"` ReturnUrl string `xorm:"varchar(1000)" json:"returnUrl"`
State string `xorm:"varchar(100)" json:"state"` State string `xorm:"varchar(100)" json:"state"`
Message string `xorm:"varchar(1000)" json:"message"` Message string `xorm:"varchar(2000)" json:"message"`
PersonName string `xorm:"varchar(100)" json:"personName"` PersonName string `xorm:"varchar(100)" json:"personName"`
PersonIdCard string `xorm:"varchar(100)" json:"personIdCard"` PersonIdCard string `xorm:"varchar(100)" json:"personIdCard"`

View File

@@ -18,7 +18,7 @@ import (
"fmt" "fmt"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type Permission struct { type Permission struct {

View File

@@ -21,8 +21,8 @@ import (
"github.com/casbin/casbin/v2" "github.com/casbin/casbin/v2"
"github.com/casbin/casbin/v2/config" "github.com/casbin/casbin/v2/config"
"github.com/casbin/casbin/v2/model" "github.com/casbin/casbin/v2/model"
xormadapter "github.com/casbin/xorm-adapter/v3"
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
xormadapter "github.com/casdoor/xorm-adapter/v3"
) )
func getEnforcer(permission *Permission) *casbin.Enforcer { func getEnforcer(permission *Permission) *casbin.Enforcer {

View File

@@ -18,7 +18,7 @@ import (
"fmt" "fmt"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type Product struct { type Product struct {

View File

@@ -20,7 +20,7 @@ import (
"github.com/casdoor/casdoor/i18n" "github.com/casdoor/casdoor/i18n"
"github.com/casdoor/casdoor/pp" "github.com/casdoor/casdoor/pp"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type Provider struct { type Provider struct {

View File

@@ -18,7 +18,7 @@ import (
"fmt" "fmt"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type Resource struct { type Resource struct {

View File

@@ -19,7 +19,7 @@ import (
"strings" "strings"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type Role struct { type Role struct {

View File

@@ -64,7 +64,7 @@ func NewSamlResponse(user *User, host string, certificate string, destination st
assertion.CreateAttr("IssueInstant", now) assertion.CreateAttr("IssueInstant", now)
assertion.CreateElement("saml:Issuer").SetText(host) assertion.CreateElement("saml:Issuer").SetText(host)
subject := assertion.CreateElement("saml:Subject") subject := assertion.CreateElement("saml:Subject")
subject.CreateElement("saml:NameID").SetText(user.Email) subject.CreateElement("saml:NameID").SetText(user.Name)
subjectConfirmation := subject.CreateElement("saml:SubjectConfirmation") subjectConfirmation := subject.CreateElement("saml:SubjectConfirmation")
subjectConfirmation.CreateAttr("Method", "urn:oasis:names:tc:SAML:2.0:cm:bearer") subjectConfirmation.CreateAttr("Method", "urn:oasis:names:tc:SAML:2.0:cm:bearer")
subjectConfirmationData := subjectConfirmation.CreateElement("saml:SubjectConfirmationData") subjectConfirmationData := subjectConfirmation.CreateElement("saml:SubjectConfirmationData")
@@ -230,16 +230,20 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
// base64 decode // base64 decode
defated, err := base64.StdEncoding.DecodeString(samlRequest) defated, err := base64.StdEncoding.DecodeString(samlRequest)
if err != nil { if err != nil {
return "", "", method, fmt.Errorf("err: %s", err.Error()) return "", "", method, fmt.Errorf("err: Failed to decode SAML request , %s", err.Error())
} }
// decompress // decompress
var buffer bytes.Buffer var buffer bytes.Buffer
rdr := flate.NewReader(bytes.NewReader(defated)) rdr := flate.NewReader(bytes.NewReader(defated))
io.Copy(&buffer, rdr) _, err = io.Copy(&buffer, rdr)
if err != nil {
return "", "", "", err
}
var authnRequest saml.AuthnRequest var authnRequest saml.AuthnRequest
err = xml.Unmarshal(buffer.Bytes(), &authnRequest) err = xml.Unmarshal(buffer.Bytes(), &authnRequest)
if err != nil { if err != nil {
return "", "", method, fmt.Errorf("err: %s", err.Error()) return "", "", method, fmt.Errorf("err: Failed to unmarshal AuthnRequest, please check the SAML request. %s", err.Error())
} }
// verify samlRequest // verify samlRequest
@@ -252,14 +256,15 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
block, _ := pem.Decode([]byte(cert.Certificate)) block, _ := pem.Decode([]byte(cert.Certificate))
certificate := base64.StdEncoding.EncodeToString(block.Bytes) certificate := base64.StdEncoding.EncodeToString(block.Bytes)
_, originBackend := getOriginFromHost(host)
// redirect Url (Assertion Consumer Url) // redirect Url (Assertion Consumer Url)
if application.SamlReplyUrl != "" { if application.SamlReplyUrl != "" {
method = "POST" method = "POST"
authnRequest.AssertionConsumerServiceURL = application.SamlReplyUrl authnRequest.AssertionConsumerServiceURL = application.SamlReplyUrl
} else if authnRequest.AssertionConsumerServiceURL == "" {
return "", "", "", fmt.Errorf("err: SAML request don't has attribute 'AssertionConsumerServiceURL' in <samlp:AuthnRequest>")
} }
_, originBackend := getOriginFromHost(host)
// build signedResponse // build signedResponse
samlResponse, _ := NewSamlResponse(user, originBackend, certificate, authnRequest.AssertionConsumerServiceURL, authnRequest.Issuer.Url, authnRequest.ID, application.RedirectUris) samlResponse, _ := NewSamlResponse(user, originBackend, certificate, authnRequest.AssertionConsumerServiceURL, authnRequest.Issuer.Url, authnRequest.ID, application.RedirectUris)
randomKeyStore := &X509Key{ randomKeyStore := &X509Key{
@@ -279,7 +284,7 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
doc.SetRoot(samlResponse) doc.SetRoot(samlResponse)
xmlBytes, err := doc.WriteToBytes() xmlBytes, err := doc.WriteToBytes()
if err != nil { if err != nil {
return "", "", method, fmt.Errorf("err: %s", err.Error()) return "", "", method, fmt.Errorf("err: Failed to serializes the SAML request into bytes, %s", err.Error())
} }
// compress // compress
@@ -287,15 +292,21 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
flated := bytes.NewBuffer(nil) flated := bytes.NewBuffer(nil)
writer, err := flate.NewWriter(flated, flate.DefaultCompression) writer, err := flate.NewWriter(flated, flate.DefaultCompression)
if err != nil { if err != nil {
return "", "", method, fmt.Errorf("err: %s", err.Error()) return "", "", method, err
}
_, err = writer.Write(xmlBytes)
if err != nil {
return "", "", "", err
}
err = writer.Close()
if err != nil {
return "", "", "", err
} }
writer.Write(xmlBytes)
writer.Close()
xmlBytes = flated.Bytes() xmlBytes = flated.Bytes()
} }
// base64 encode // base64 encode
res := base64.StdEncoding.EncodeToString(xmlBytes) res := base64.StdEncoding.EncodeToString(xmlBytes)
return res, authnRequest.AssertionConsumerServiceURL, method, nil return res, authnRequest.AssertionConsumerServiceURL, method, err
} }
// NewSamlResponse11 return a saml1.1 response(not 2.0) // NewSamlResponse11 return a saml1.1 response(not 2.0)
@@ -359,7 +370,10 @@ func NewSamlResponse11(user *User, requestID string, host string) *etree.Element
data, _ := json.Marshal(user) data, _ := json.Marshal(user)
tmp := map[string]string{} tmp := map[string]string{}
json.Unmarshal(data, &tmp) err := json.Unmarshal(data, &tmp)
if err != nil {
panic(err)
}
for k, v := range tmp { for k, v := range tmp {
if v != "" { if v != "" {

View File

@@ -15,84 +15,27 @@
package object package object
import ( import (
"fmt"
"github.com/beego/beego" "github.com/beego/beego"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
)
var (
CasdoorApplication = "app-built-in"
CasdoorOrganization = "built-in"
) )
type Session struct { type Session struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"` Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"` Name string `xorm:"varchar(100) notnull pk" json:"name"`
Application string `xorm:"varchar(100) notnull pk" json:"application"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"` CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
SessionId []string `json:"sessionId"` SessionId []string `json:"sessionId"`
} }
func SetSession(id string, sessionId string) {
owner, name := util.GetOwnerAndNameFromIdNoCheck(id)
session := &Session{Owner: owner, Name: name}
get, err := adapter.Engine.Get(session)
if err != nil {
panic(err)
}
session.SessionId = append(session.SessionId, sessionId)
if get {
_, err = adapter.Engine.ID(core.PK{owner, name}).Update(session)
} else {
session.CreatedTime = util.GetCurrentTime()
_, err = adapter.Engine.Insert(session)
}
if err != nil {
panic(err)
}
}
func DeleteSession(id string) bool {
owner, name := util.GetOwnerAndNameFromIdNoCheck(id)
session := &Session{Owner: owner, Name: name}
_, err := adapter.Engine.ID(core.PK{owner, name}).Get(session)
if err != nil {
return false
}
DeleteBeegoSession(session.SessionId)
affected, err := adapter.Engine.ID(core.PK{owner, name}).Delete(session)
return affected != 0
}
func DeleteSessionId(id string, sessionId string) bool {
owner, name := util.GetOwnerAndNameFromId(id)
session := &Session{Owner: owner, Name: name}
_, err := adapter.Engine.ID(core.PK{owner, name}).Get(session)
if err != nil {
return false
}
DeleteBeegoSession([]string{sessionId})
session.SessionId = util.DeleteVal(session.SessionId, sessionId)
if len(session.SessionId) < 1 {
affected, _ := adapter.Engine.ID(core.PK{owner, name}).Delete(session)
return affected != 0
} else {
affected, _ := adapter.Engine.ID(core.PK{owner, name}).Update(session)
return affected != 0
}
}
func DeleteBeegoSession(sessionIds []string) {
for _, sessionId := range sessionIds {
err := beego.GlobalSessions.GetProvider().SessionDestroy(sessionId)
if err != nil {
return
}
}
}
func GetSessions(owner string) []*Session { func GetSessions(owner string) []*Session {
sessions := []*Session{} sessions := []*Session{}
var err error var err error
@@ -128,3 +71,131 @@ func GetSessionCount(owner, field, value string) int {
return int(count) return int(count)
} }
func GetSingleSession(id string) *Session {
owner, name, application := util.GetOwnerAndNameAndOtherFromId(id)
session := Session{Owner: owner, Name: name, Application: application}
get, err := adapter.Engine.Get(&session)
if err != nil {
panic(err)
}
if !get {
return nil
}
return &session
}
func UpdateSession(id string, session *Session) bool {
owner, name, application := util.GetOwnerAndNameAndOtherFromId(id)
if GetSingleSession(id) == nil {
return false
}
affected, err := adapter.Engine.ID(core.PK{owner, name, application}).Update(session)
if err != nil {
panic(err)
}
return affected != 0
}
func removeExtraSessionIds(session *Session) {
if len(session.SessionId) > 100 {
session.SessionId = session.SessionId[(len(session.SessionId) - 100):]
}
}
func AddSession(session *Session) bool {
dbSession := GetSingleSession(session.GetId())
if dbSession == nil {
session.CreatedTime = util.GetCurrentTime()
affected, err := adapter.Engine.Insert(session)
if err != nil {
panic(err)
}
return affected != 0
} else {
m := make(map[string]struct{})
for _, v := range dbSession.SessionId {
m[v] = struct{}{}
}
for _, v := range session.SessionId {
if _, exists := m[v]; !exists {
dbSession.SessionId = append(dbSession.SessionId, v)
}
}
removeExtraSessionIds(dbSession)
return UpdateSession(dbSession.GetId(), dbSession)
}
}
func DeleteSession(id string) bool {
owner, name, application := util.GetOwnerAndNameAndOtherFromId(id)
if owner == CasdoorOrganization && application == CasdoorApplication {
session := GetSingleSession(id)
if session != nil {
DeleteBeegoSession(session.SessionId)
}
}
affected, err := adapter.Engine.ID(core.PK{owner, name, application}).Delete(&Session{})
if err != nil {
panic(err)
}
return affected != 0
}
func DeleteSessionId(id string, sessionId string) bool {
session := GetSingleSession(id)
if session == nil {
return false
}
owner, _, application := util.GetOwnerAndNameAndOtherFromId(id)
if owner == CasdoorOrganization && application == CasdoorApplication {
DeleteBeegoSession([]string{sessionId})
}
session.SessionId = util.DeleteVal(session.SessionId, sessionId)
if len(session.SessionId) == 0 {
return DeleteSession(id)
} else {
return UpdateSession(id, session)
}
}
func DeleteBeegoSession(sessionIds []string) {
for _, sessionId := range sessionIds {
err := beego.GlobalSessions.GetProvider().SessionDestroy(sessionId)
if err != nil {
return
}
}
}
func (session *Session) GetId() string {
return fmt.Sprintf("%s/%s/%s", session.Owner, session.Name, session.Application)
}
func IsSessionDuplicated(id string, sessionId string) bool {
session := GetSingleSession(id)
if session == nil {
return false
} else {
if len(session.SessionId) > 1 {
return true
} else if len(session.SessionId) < 1 {
return false
} else {
return session.SessionId[0] != sessionId
}
}
}

View File

@@ -14,7 +14,11 @@
package object package object
import "github.com/casdoor/go-sms-sender" import (
"strings"
"github.com/casdoor/go-sms-sender"
)
func SendSms(provider *Provider, content string, phoneNumbers ...string) error { func SendSms(provider *Provider, content string, phoneNumbers ...string) error {
client, err := go_sms_sender.NewSmsClient(provider.Type, provider.ClientId, provider.ClientSecret, provider.SignName, provider.TemplateCode, provider.AppId) client, err := go_sms_sender.NewSmsClient(provider.Type, provider.ClientId, provider.ClientSecret, provider.SignName, provider.TemplateCode, provider.AppId)
@@ -25,6 +29,12 @@ func SendSms(provider *Provider, content string, phoneNumbers ...string) error {
return err return err
} }
if provider.Type == go_sms_sender.Aliyun {
for i, number := range phoneNumbers {
phoneNumbers[i] = strings.TrimPrefix(number, "+")
}
}
params := map[string]string{} params := map[string]string{}
if provider.Type == go_sms_sender.TencentCloud { if provider.Type == go_sms_sender.TencentCloud {
params["0"] = content params["0"] = content

View File

@@ -18,6 +18,7 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"net/url" "net/url"
"path/filepath"
"strings" "strings"
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
@@ -54,6 +55,25 @@ func escapePath(path string) string {
return res return res
} }
func GetTruncatedPath(provider *Provider, fullFilePath string, limit int) string {
pathPrefix := util.UrlJoin(util.GetUrlPath(provider.Domain), provider.PathPrefix)
dir, file := filepath.Split(fullFilePath)
ext := filepath.Ext(file)
fileName := strings.TrimSuffix(file, ext)
for {
escapedString := escapePath(escapePath(fullFilePath))
if len(escapedString) < limit-len(pathPrefix) {
break
}
rs := []rune(fileName)
fileName = string(rs[0 : len(rs)-1])
fullFilePath = dir + fileName + ext
}
return fullFilePath
}
func GetUploadFileUrl(provider *Provider, fullFilePath string, hasTimestamp bool) (string, string) { func GetUploadFileUrl(provider *Provider, fullFilePath string, hasTimestamp bool) (string, string) {
escapedPath := util.UrlJoin(provider.PathPrefix, escapePath(fullFilePath)) escapedPath := util.UrlJoin(provider.PathPrefix, escapePath(fullFilePath))
objectKey := util.UrlJoin(util.GetUrlPath(provider.Domain), escapedPath) objectKey := util.UrlJoin(util.GetUrlPath(provider.Domain), escapedPath)

View File

@@ -18,7 +18,7 @@ import (
"fmt" "fmt"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type TableColumn struct { type TableColumn struct {

View File

@@ -20,7 +20,7 @@ import (
"time" "time"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type OriginalUser = User type OriginalUser = User

View File

@@ -23,11 +23,11 @@ import (
"github.com/casdoor/casdoor/i18n" "github.com/casdoor/casdoor/i18n"
"github.com/casdoor/casdoor/idp" "github.com/casdoor/casdoor/idp"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
const ( const (
hourMinutes = 60 hourSeconds = int(time.Hour / time.Second)
InvalidRequest = "invalid_request" InvalidRequest = "invalid_request"
InvalidClient = "invalid_client" InvalidClient = "invalid_client"
InvalidGrant = "invalid_grant" InvalidGrant = "invalid_grant"
@@ -306,7 +306,7 @@ func GetOAuthCode(userId string, clientId string, responseType string, redirectU
Code: util.GenerateClientId(), Code: util.GenerateClientId(),
AccessToken: accessToken, AccessToken: accessToken,
RefreshToken: refreshToken, RefreshToken: refreshToken,
ExpiresIn: application.ExpireInHours * hourMinutes, ExpiresIn: application.ExpireInHours * hourSeconds,
Scope: scope, Scope: scope,
TokenType: "Bearer", TokenType: "Bearer",
CodeChallenge: challenge, CodeChallenge: challenge,
@@ -321,7 +321,7 @@ func GetOAuthCode(userId string, clientId string, responseType string, redirectU
} }
} }
func GetOAuthToken(grantType string, clientId string, clientSecret string, code string, verifier string, scope string, username string, password string, host string, tag string, avatar string, lang string) interface{} { func GetOAuthToken(grantType string, clientId string, clientSecret string, code string, verifier string, scope string, username string, password string, host string, refreshToken string, tag string, avatar string, lang string) interface{} {
application := GetApplicationByClientId(clientId) application := GetApplicationByClientId(clientId)
if application == nil { if application == nil {
return &TokenError{ return &TokenError{
@@ -348,6 +348,8 @@ func GetOAuthToken(grantType string, clientId string, clientSecret string, code
token, tokenError = GetPasswordToken(application, username, password, scope, host) token, tokenError = GetPasswordToken(application, username, password, scope, host)
case "client_credentials": // Client Credentials Grant case "client_credentials": // Client Credentials Grant
token, tokenError = GetClientCredentialsToken(application, clientSecret, scope, host) token, tokenError = GetClientCredentialsToken(application, clientSecret, scope, host)
case "refresh_token":
return RefreshToken(grantType, refreshToken, scope, clientId, clientSecret, host)
} }
if tag == "wechat_miniprogram" { if tag == "wechat_miniprogram" {
@@ -440,7 +442,7 @@ func RefreshToken(grantType string, refreshToken string, scope string, clientId
Code: util.GenerateClientId(), Code: util.GenerateClientId(),
AccessToken: newAccessToken, AccessToken: newAccessToken,
RefreshToken: newRefreshToken, RefreshToken: newRefreshToken,
ExpiresIn: application.ExpireInHours * hourMinutes, ExpiresIn: application.ExpireInHours * hourSeconds,
Scope: scope, Scope: scope,
TokenType: "Bearer", TokenType: "Bearer",
} }
@@ -590,7 +592,7 @@ func GetPasswordToken(application *Application, username string, password string
Code: util.GenerateClientId(), Code: util.GenerateClientId(),
AccessToken: accessToken, AccessToken: accessToken,
RefreshToken: refreshToken, RefreshToken: refreshToken,
ExpiresIn: application.ExpireInHours * hourMinutes, ExpiresIn: application.ExpireInHours * hourSeconds,
Scope: scope, Scope: scope,
TokenType: "Bearer", TokenType: "Bearer",
CodeIsUsed: true, CodeIsUsed: true,
@@ -630,7 +632,7 @@ func GetClientCredentialsToken(application *Application, clientSecret string, sc
User: nullUser.Name, User: nullUser.Name,
Code: util.GenerateClientId(), Code: util.GenerateClientId(),
AccessToken: accessToken, AccessToken: accessToken,
ExpiresIn: application.ExpireInHours * hourMinutes, ExpiresIn: application.ExpireInHours * hourSeconds,
Scope: scope, Scope: scope,
TokenType: "Bearer", TokenType: "Bearer",
CodeIsUsed: true, CodeIsUsed: true,
@@ -657,7 +659,7 @@ func GetTokenByUser(application *Application, user *User, scope string, host str
Code: util.GenerateClientId(), Code: util.GenerateClientId(),
AccessToken: accessToken, AccessToken: accessToken,
RefreshToken: refreshToken, RefreshToken: refreshToken,
ExpiresIn: application.ExpireInHours * hourMinutes, ExpiresIn: application.ExpireInHours * hourSeconds,
Scope: scope, Scope: scope,
TokenType: "Bearer", TokenType: "Bearer",
CodeIsUsed: true, CodeIsUsed: true,

View File

@@ -265,8 +265,8 @@ func generateJwtToken(application *Application, user *User, nonce string, scope
claimsWithoutThirdIdp := getClaimsWithoutThirdIdp(claims) claimsWithoutThirdIdp := getClaimsWithoutThirdIdp(claims)
token = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsWithoutThirdIdp) token = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsWithoutThirdIdp)
claims.ExpiresAt = jwt.NewNumericDate(refreshExpireTime) claimsWithoutThirdIdp.ExpiresAt = jwt.NewNumericDate(refreshExpireTime)
claims.TokenType = "refresh-token" claimsWithoutThirdIdp.TokenType = "refresh-token"
refreshToken = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsWithoutThirdIdp) refreshToken = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsWithoutThirdIdp)
} }

View File

@@ -21,7 +21,7 @@ import (
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"github.com/duo-labs/webauthn/webauthn" "github.com/duo-labs/webauthn/webauthn"
"xorm.io/core" "github.com/xorm-io/core"
) )
const ( const (
@@ -46,7 +46,8 @@ type User struct {
PermanentAvatar string `xorm:"varchar(500)" json:"permanentAvatar"` PermanentAvatar string `xorm:"varchar(500)" json:"permanentAvatar"`
Email string `xorm:"varchar(100) index" json:"email"` Email string `xorm:"varchar(100) index" json:"email"`
EmailVerified bool `json:"emailVerified"` EmailVerified bool `json:"emailVerified"`
Phone string `xorm:"varchar(100) index" json:"phone"` Phone string `xorm:"varchar(20) index" json:"phone"`
CountryCode string `xorm:"varchar(6)" json:"countryCode"`
Location string `xorm:"varchar(100)" json:"location"` Location string `xorm:"varchar(100)" json:"location"`
Address []string `json:"address"` Address []string `json:"address"`
Affiliation string `xorm:"varchar(100)" json:"affiliation"` Affiliation string `xorm:"varchar(100)" json:"affiliation"`
@@ -448,13 +449,13 @@ func UpdateUser(id string, user *User, columns []string, isGlobalAdmin bool) boo
if len(columns) == 0 { if len(columns) == 0 {
columns = []string{ columns = []string{
"owner", "display_name", "avatar", "owner", "display_name", "avatar",
"location", "address", "region", "language", "affiliation", "title", "homepage", "bio", "score", "tag", "signup_application", "location", "address", "country_code", "region", "language", "affiliation", "title", "homepage", "bio", "score", "tag", "signup_application",
"is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "managedAccounts", "is_admin", "is_global_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "managedAccounts",
"signin_wrong_times", "last_signin_wrong_time", "signin_wrong_times", "last_signin_wrong_time",
} }
} }
if isGlobalAdmin { if isGlobalAdmin {
columns = append(columns, "name", "email", "phone") columns = append(columns, "name", "email", "phone", "country_code")
} }
affected, err := adapter.Engine.ID(core.PK{owner, name}).Cols(columns...).Update(user) affected, err := adapter.Engine.ID(core.PK{owner, name}).Cols(columns...).Update(user)
@@ -578,7 +579,7 @@ func AddUsersInBatch(users []*User) bool {
func DeleteUser(user *User) bool { func DeleteUser(user *User) bool {
// Forced offline the user first // Forced offline the user first
DeleteSession(user.GetId()) DeleteSession(util.GetSessionId(user.Owner, user.Name, CasdoorApplication))
affected, err := adapter.Engine.ID(core.PK{user.Owner, user.Name}).Delete(&User{}) affected, err := adapter.Engine.ID(core.PK{user.Owner, user.Name}).Delete(&User{})
if err != nil { if err != nil {

View File

@@ -21,7 +21,7 @@ import (
"testing" "testing"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
func updateUserColumn(column string, user *User) bool { func updateUserColumn(column string, user *User) bool {

View File

@@ -20,7 +20,7 @@ import (
"strings" "strings"
"github.com/casdoor/casdoor/idp" "github.com/casdoor/casdoor/idp"
"xorm.io/core" "github.com/xorm-io/core"
) )
func GetUserByField(organizationName string, field string, value string) *User { func GetUserByField(organizationName string, field string, value string) *User {
@@ -170,3 +170,18 @@ func ClearUserOAuthProperties(user *User, providerType string) bool {
return affected != 0 return affected != 0
} }
func (user *User) GetCountryCode(countryCode string) string {
if countryCode != "" {
return countryCode
}
if user != nil && user.CountryCode != "" {
return user.CountryCode
}
if org := GetOrganizationByUser(user); org != nil && len(org.CountryCodes) > 0 {
return org.CountryCodes[0]
}
return ""
}

View File

@@ -23,7 +23,7 @@ import (
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/i18n" "github.com/casdoor/casdoor/i18n"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
const ( const (
@@ -122,11 +122,8 @@ func AddToVerificationRecord(user *User, provider *Provider, remoteAddr, recordT
record.Owner = provider.Owner record.Owner = provider.Owner
record.Name = util.GenerateId() record.Name = util.GenerateId()
record.CreatedTime = util.GetCurrentTime() record.CreatedTime = util.GetCurrentTime()
if user != nil {
record.User = user.GetId()
}
record.Provider = provider.Name
record.Provider = provider.Name
record.Receiver = dest record.Receiver = dest
record.Code = code record.Code = code
record.Time = time.Now().Unix() record.Time = time.Now().Unix()

View File

@@ -18,7 +18,7 @@ import (
"fmt" "fmt"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type Header struct { type Header struct {

View File

@@ -57,7 +57,7 @@ func AutoSigninFilter(ctx *context.Context) {
return return
} }
// "/page?username=abc&password=123" // "/page?username=built-in/admin&password=123"
userId = ctx.Input.Query("username") userId = ctx.Input.Query("username")
password := ctx.Input.Query("password") password := ctx.Input.Query("password")
if userId != "" && password != "" && ctx.Input.Query("grant_type") == "" { if userId != "" && password != "" && ctx.Input.Query("grant_type") == "" {

View File

@@ -19,6 +19,8 @@ import (
"strings" "strings"
"github.com/beego/beego/context" "github.com/beego/beego/context"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/i18n"
"github.com/casdoor/casdoor/object" "github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
) )
@@ -46,8 +48,17 @@ func responseError(ctx *context.Context, error string, data ...interface{}) {
} }
} }
func getAcceptLanguage(ctx *context.Context) string {
language := ctx.Request.Header.Get("Accept-Language")
return conf.GetLanguage(language)
}
func T(ctx *context.Context, error string) string {
return i18n.Translate(getAcceptLanguage(ctx), error)
}
func denyRequest(ctx *context.Context) { func denyRequest(ctx *context.Context) {
responseError(ctx, "Unauthorized operation") responseError(ctx, T(ctx, "auth:Unauthorized operation"))
} }
func getUsernameByClientIdSecret(ctx *context.Context) string { func getUsernameByClientIdSecret(ctx *context.Context) string {

View File

@@ -119,8 +119,8 @@ func initAPI() {
beego.Router("/api/get-captcha", &controllers.ApiController{}, "GET:GetCaptcha") beego.Router("/api/get-captcha", &controllers.ApiController{}, "GET:GetCaptcha")
beego.Router("/api/get-ldap-user", &controllers.ApiController{}, "POST:GetLdapUser") beego.Router("/api/get-ldap-user", &controllers.ApiController{}, "POST:GetLdapUser")
beego.Router("/api/get-ldaps", &controllers.ApiController{}, "POST:GetLdaps") beego.Router("/api/get-ldaps", &controllers.ApiController{}, "GET:GetLdaps")
beego.Router("/api/get-ldap", &controllers.ApiController{}, "POST:GetLdap") beego.Router("/api/get-ldap", &controllers.ApiController{}, "GET:GetLdap")
beego.Router("/api/add-ldap", &controllers.ApiController{}, "POST:AddLdap") beego.Router("/api/add-ldap", &controllers.ApiController{}, "POST:AddLdap")
beego.Router("/api/update-ldap", &controllers.ApiController{}, "POST:UpdateLdap") beego.Router("/api/update-ldap", &controllers.ApiController{}, "POST:UpdateLdap")
beego.Router("/api/delete-ldap", &controllers.ApiController{}, "POST:DeleteLdap") beego.Router("/api/delete-ldap", &controllers.ApiController{}, "POST:DeleteLdap")
@@ -163,7 +163,11 @@ func initAPI() {
beego.Router("/api/add-record", &controllers.ApiController{}, "POST:AddRecord") beego.Router("/api/add-record", &controllers.ApiController{}, "POST:AddRecord")
beego.Router("/api/get-sessions", &controllers.ApiController{}, "GET:GetSessions") beego.Router("/api/get-sessions", &controllers.ApiController{}, "GET:GetSessions")
beego.Router("/api/get-session", &controllers.ApiController{}, "GET:GetSingleSession")
beego.Router("/api/update-session", &controllers.ApiController{}, "POST:UpdateSession")
beego.Router("/api/add-session", &controllers.ApiController{}, "POST:AddSession")
beego.Router("/api/delete-session", &controllers.ApiController{}, "POST:DeleteSession") beego.Router("/api/delete-session", &controllers.ApiController{}, "POST:DeleteSession")
beego.Router("/api/is-session-duplicated", &controllers.ApiController{}, "GET:IsSessionDuplicated")
beego.Router("/api/get-webhooks", &controllers.ApiController{}, "GET:GetWebhooks") beego.Router("/api/get-webhooks", &controllers.ApiController{}, "GET:GetWebhooks")
beego.Router("/api/get-webhook", &controllers.ApiController{}, "GET:GetWebhook") beego.Router("/api/get-webhook", &controllers.ApiController{}, "GET:GetWebhook")

187
sync/bi_sync_mysql.go Normal file
View File

@@ -0,0 +1,187 @@
// Copyright 2023 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 sync
import (
"fmt"
"github.com/go-mysql-org/go-mysql/canal"
"github.com/go-mysql-org/go-mysql/mysql"
"github.com/go-mysql-org/go-mysql/replication"
"github.com/siddontang/go-log/log"
"github.com/xorm-io/xorm"
)
var (
dataSourceName1 string
dataSourceName2 string
engin1 *xorm.Engine
engin2 *xorm.Engine
)
func InitConfig() *canal.Config {
// init dataSource
dataSourceName1 = fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", username1, password1, host1, port1, database1)
dataSourceName2 = fmt.Sprintf("%s:%s@tcp(%s:%d)/%s", username2, password2, host2, port2, database2)
// create engine
engin1, _ = CreateEngine(dataSourceName1)
engin2, _ = CreateEngine(dataSourceName2)
log.Info("init engine success…")
// config canal
cfg := canal.NewDefaultConfig()
cfg.Addr = fmt.Sprintf("%s:%d", host1, port1)
cfg.Password = password1
cfg.User = username1
// We only care table in database1
cfg.Dump.TableDB = database1
// cfg.Dump.Tables = []string{"user"}
log.Info("config canal success…")
return cfg
}
func StartBinlogSync() error {
// init config
config := InitConfig()
c, err := canal.NewCanal(config)
pos, err := c.GetMasterPos()
if err != nil {
return err
}
// Register a handler to handle RowsEvent
c.SetEventHandler(&MyEventHandler{})
// Start canal
c.RunFrom(pos)
return nil
}
type MyEventHandler struct {
canal.DummyEventHandler
}
func OnTableChanged(header *replication.EventHeader, schema string, table string) error {
log.Info("table changed event")
return nil
}
func (h *MyEventHandler) onDDL(header *replication.EventHeader, nextPos mysql.Position, queryEvent *replication.QueryEvent) error {
log.Info("into DDL event")
return nil
}
func (h *MyEventHandler) OnRow(e *canal.RowsEvent) error {
length := len(e.Table.Columns)
columnNames := make([]string, length)
oldColumnValue := make([]interface{}, length)
newColumnValue := make([]interface{}, length)
isChar := make([]bool, len(e.Table.Columns))
for i, col := range e.Table.Columns {
columnNames[i] = col.Name
if col.Type <= 2 {
isChar[i] = false
} else {
isChar[i] = true
}
}
switch e.Action {
case canal.UpdateAction:
for i, row := range e.Rows {
for j, item := range row {
if i%2 == 0 {
if isChar[j] == true {
oldColumnValue[j] = fmt.Sprintf("%s", item)
} else {
oldColumnValue[j] = fmt.Sprintf("%d", item)
}
} else {
if isChar[j] == true {
newColumnValue[j] = fmt.Sprintf("%s", item)
} else {
newColumnValue[j] = fmt.Sprintf("%d", item)
}
}
}
if i%2 == 1 {
updateSql, args, err := GetUpdateSql(e.Table.Schema, e.Table.Name, columnNames, newColumnValue, oldColumnValue)
if err != nil {
return err
}
res, err := engin2.DB().Exec(updateSql, args...)
if err != nil {
return err
}
log.Info(updateSql, args, res)
}
}
case canal.DeleteAction:
for _, row := range e.Rows {
for j, item := range row {
if isChar[j] == true {
oldColumnValue[j] = fmt.Sprintf("%s", item)
} else {
oldColumnValue[j] = fmt.Sprintf("%d", item)
}
}
deleteSql, args, err := GetDeleteSql(e.Table.Schema, e.Table.Name, columnNames, oldColumnValue)
if err != nil {
return err
}
res, err := engin2.DB().Exec(deleteSql, args...)
if err != nil {
return err
}
log.Info(deleteSql, args, res)
}
case canal.InsertAction:
for _, row := range e.Rows {
for j, item := range row {
if isChar[j] == true {
newColumnValue[j] = fmt.Sprintf("%s", item)
} else {
newColumnValue[j] = fmt.Sprintf("%d", item)
}
}
insertSql, args, err := GetInsertSql(e.Table.Schema, e.Table.Name, columnNames, newColumnValue)
if err != nil {
return err
}
res, err := engin2.DB().Exec(insertSql, args...)
if err != nil {
return err
}
log.Info(insertSql, args, res)
}
default:
log.Infof("%v", e.String())
}
return nil
}
func (h *MyEventHandler) String() string {
return "MyEventHandler"
}

17
sync/conf.go Normal file
View File

@@ -0,0 +1,17 @@
package sync
var (
host1 = "127.0.0.1"
port1 = 3306
username1 = "root"
password1 = "123456"
database1 = "db"
)
var (
host2 = "127.0.0.1"
port2 = 3306
username2 = "root"
password2 = "123456"
database2 = "db"
)

72
sync/utils.go Normal file
View File

@@ -0,0 +1,72 @@
// Copyright 2023 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 sync
import (
"log"
"github.com/Masterminds/squirrel"
"github.com/xorm-io/xorm"
)
func GetUpdateSql(schemaName string, tableName string, columnNames []string, newColumnVal []interface{}, oldColumnVal []interface{}) (string, []interface{}, error) {
updateSql := squirrel.Update(schemaName + "." + tableName)
for i, columnName := range columnNames {
updateSql = updateSql.Set(columnName, newColumnVal[i])
}
for i, columnName := range columnNames {
updateSql = updateSql.Where(squirrel.Eq{columnName: oldColumnVal[i]})
}
sql, args, err := updateSql.ToSql()
if err != nil {
return "", nil, err
}
return sql, args, nil
}
func GetInsertSql(schemaName string, tableName string, columnNames []string, columnValue []interface{}) (string, []interface{}, error) {
insertSql := squirrel.Insert(schemaName + "." + tableName).Columns(columnNames...).Values(columnValue...)
return insertSql.ToSql()
}
func GetDeleteSql(schemaName string, tableName string, columnNames []string, columnValue []interface{}) (string, []interface{}, error) {
deleteSql := squirrel.Delete(schemaName + "." + tableName)
for i, columnName := range columnNames {
deleteSql = deleteSql.Where(squirrel.Eq{columnName: columnValue[i]})
}
return deleteSql.ToSql()
}
func CreateEngine(dataSourceName string) (*xorm.Engine, error) {
engine, err := xorm.NewEngine("mysql", dataSourceName)
if err != nil {
return nil, err
}
// ping mysql
err = engine.Ping()
if err != nil {
return nil, err
}
log.Println("mysql connection success……")
return engine, nil
}

View File

@@ -14,6 +14,8 @@
package util package util
import "sort"
func DeleteVal(values []string, val string) []string { func DeleteVal(values []string, val string) []string {
newValues := []string{} newValues := []string{}
for _, v := range values { for _, v := range values {
@@ -23,3 +25,8 @@ func DeleteVal(values []string, val string) []string {
} }
return newValues return newValues
} }
func ContainsString(values []string, val string) bool {
sort.Strings(values)
return sort.SearchStrings(values, val) != len(values)
}

View File

@@ -100,6 +100,15 @@ func GetOwnerAndNameFromIdNoCheck(id string) (string, string) {
return tokens[0], tokens[1] return tokens[0], tokens[1]
} }
func GetOwnerAndNameAndOtherFromId(id string) (string, string, string) {
tokens := strings.Split(id, "/")
if len(tokens) != 3 {
panic(errors.New("GetOwnerAndNameAndOtherFromId() error, wrong token count for ID: " + id))
}
return tokens[0], tokens[1], tokens[2]
}
func GenerateId() string { func GenerateId() string {
return uuid.NewString() return uuid.NewString()
} }
@@ -127,12 +136,16 @@ func GetId(owner, name string) string {
return fmt.Sprintf("%s/%s", owner, name) return fmt.Sprintf("%s/%s", owner, name)
} }
func GetSessionId(owner, name, application string) string {
return fmt.Sprintf("%s/%s/%s", owner, name, application)
}
func GetMd5Hash(text string) string { func GetMd5Hash(text string) string {
hash := md5.Sum([]byte(text)) hash := md5.Sum([]byte(text))
return hex.EncodeToString(hash[:]) return hex.EncodeToString(hash[:])
} }
func IsStrsEmpty(strs ...string) bool { func IsStringsEmpty(strs ...string) bool {
for _, str := range strs { for _, str := range strs {
if len(str) == 0 { if len(str) == 0 {
return true return true
@@ -214,7 +227,7 @@ func IsChinese(str string) bool {
} }
func GetMaskedPhone(phone string) string { func GetMaskedPhone(phone string) string {
return getMaskedPhone(phone) return rePhone.ReplaceAllString(phone, "$1****$2")
} }
func GetMaskedEmail(email string) string { func GetMaskedEmail(email string) string {

View File

@@ -183,7 +183,7 @@ func TestIsStrsEmpty(t *testing.T) {
} }
for _, scenery := range scenarios { for _, scenery := range scenarios {
t.Run(scenery.description, func(t *testing.T) { t.Run(scenery.description, func(t *testing.T) {
actual := IsStrsEmpty(scenery.input...) actual := IsStringsEmpty(scenery.input...)
assert.Equal(t, scenery.expected, actual, "The returned value not is expected") assert.Equal(t, scenery.expected, actual, "The returned value not is expected")
}) })
} }

View File

@@ -14,7 +14,7 @@
package util package util
import xormadapter "github.com/casbin/xorm-adapter/v3" import xormadapter "github.com/casdoor/xorm-adapter/v3"
func CasbinToSlice(casbinRule xormadapter.CasbinRule) []string { func CasbinToSlice(casbinRule xormadapter.CasbinRule) []string {
s := []string{ s := []string{

View File

@@ -31,6 +31,6 @@ func GetCurrentUnixTime() string {
func IsTokenExpired(createdTime string, expiresIn int) bool { func IsTokenExpired(createdTime string, expiresIn int) bool {
createdTimeObj, _ := time.Parse(time.RFC3339, createdTime) createdTimeObj, _ := time.Parse(time.RFC3339, createdTime)
expiresAtObj := createdTimeObj.Add(time.Duration(expiresIn) * time.Minute) expiresAtObj := createdTimeObj.Add(time.Duration(expiresIn) * time.Second)
return time.Now().After(expiresAtObj) return time.Now().After(expiresAtObj)
} }

View File

@@ -56,15 +56,15 @@ func Test_IsTokenExpired(t *testing.T) {
description: "Token emitted now is valid for 60 minutes", description: "Token emitted now is valid for 60 minutes",
input: input{ input: input{
createdTime: time.Now().Format(time.RFC3339), createdTime: time.Now().Format(time.RFC3339),
expiresIn: 60, expiresIn: 3600,
}, },
expected: false, expected: false,
}, },
{ {
description: "Token emitted 60 minutes before now is valid for 60 minutes", description: "Token emitted 60 minutes before now is valid for 61 minutes",
input: input{ input: input{
createdTime: time.Now().Add(-time.Minute * 60).Format(time.RFC3339), createdTime: time.Now().Add(-time.Minute * 60).Format(time.RFC3339),
expiresIn: 61, expiresIn: 3660,
}, },
expected: false, expected: false,
}, },
@@ -72,7 +72,7 @@ func Test_IsTokenExpired(t *testing.T) {
description: "Token emitted 2 hours before now is Expired after 60 minutes", description: "Token emitted 2 hours before now is Expired after 60 minutes",
input: input{ input: input{
createdTime: time.Now().Add(-time.Hour * 2).Format(time.RFC3339), createdTime: time.Now().Add(-time.Hour * 2).Format(time.RFC3339),
expiresIn: 60, expiresIn: 3600,
}, },
expected: true, expected: true,
}, },
@@ -80,23 +80,23 @@ func Test_IsTokenExpired(t *testing.T) {
description: "Token emitted 61 minutes before now is Expired after 60 minutes", description: "Token emitted 61 minutes before now is Expired after 60 minutes",
input: input{ input: input{
createdTime: time.Now().Add(-time.Minute * 61).Format(time.RFC3339), createdTime: time.Now().Add(-time.Minute * 61).Format(time.RFC3339),
expiresIn: 60, expiresIn: 3600,
}, },
expected: true, expected: true,
}, },
{ {
description: "Token emitted 2 hours before now is valid for 120 minutes", description: "Token emitted 2 hours before now is valid for 121 minutes",
input: input{ input: input{
createdTime: time.Now().Add(-time.Hour * 2).Format(time.RFC3339), createdTime: time.Now().Add(-time.Hour * 2).Format(time.RFC3339),
expiresIn: 121, expiresIn: 7260,
}, },
expected: false, expected: false,
}, },
{ {
description: "Token emitted 159 minutes before now is Expired after 60 minutes", description: "Token emitted 159 minutes before now is Expired after 120 minutes",
input: input{ input: input{
createdTime: time.Now().Add(-time.Minute * 159).Format(time.RFC3339), createdTime: time.Now().Add(-time.Minute * 159).Format(time.RFC3339),
expiresIn: 120, expiresIn: 7200,
}, },
expected: true, expected: true,
}, },

View File

@@ -17,16 +17,13 @@ package util
import ( import (
"net/mail" "net/mail"
"regexp" "regexp"
"github.com/nyaruka/phonenumbers"
) )
var ( var rePhone *regexp.Regexp
rePhoneCn *regexp.Regexp
rePhone *regexp.Regexp
)
func init() { func init() {
// https://learnku.com/articles/31543
rePhoneCn, _ = regexp.Compile(`^1(3\d|4[5-9]|5[0-35-9]|6[2567]|7[0-8]|8\d|9[0-35-9])\d{8}$`)
rePhone, _ = regexp.Compile("(\\d{3})\\d*(\\d{4})") rePhone, _ = regexp.Compile("(\\d{3})\\d*(\\d{4})")
} }
@@ -35,10 +32,19 @@ func IsEmailValid(email string) bool {
return err == nil return err == nil
} }
func IsPhoneCnValid(phone string) bool { func IsPhoneValid(phone string, countryCode string) bool {
return rePhoneCn.MatchString(phone) phoneNumber, err := phonenumbers.Parse(phone, countryCode)
if err != nil {
return false
}
return phonenumbers.IsValidNumber(phoneNumber)
} }
func getMaskedPhone(phone string) string { func IsPhoneAllowInRegin(countryCode string, allowRegions []string) bool {
return rePhone.ReplaceAllString(phone, "$1****$2") return ContainsString(allowRegions, countryCode)
}
func GetE164Number(phone string, countryCode string) (string, bool) {
phoneNumber, _ := phonenumbers.Parse(phone, countryCode)
return phonenumbers.Format(phoneNumber, phonenumbers.E164), phonenumbers.IsValidNumber(phoneNumber)
} }

View File

@@ -15,7 +15,6 @@ describe("Login test", () => {
"password": "123", "password": "123",
"autoSignin": true, "autoSignin": true,
"type": "login", "type": "login",
"phonePrefix": "86",
}, },
}).then((Response) => { }).then((Response) => {
expect(Response).property("body").property("status").to.equal("ok"); expect(Response).property("body").property("status").to.equal("ok");
@@ -40,7 +39,6 @@ describe("Login test", () => {
"password": "1234", "password": "1234",
"autoSignin": true, "autoSignin": true,
"type": "login", "type": "login",
"phonePrefix": "86",
}, },
}).then((Response) => { }).then((Response) => {
expect(Response).property("body").property("status").to.equal("error"); expect(Response).property("body").property("status").to.equal("error");

View File

@@ -34,7 +34,6 @@ Cypress.Commands.add('login', ()=>{
"password": "123", "password": "123",
"autoSignin": true, "autoSignin": true,
"type": "login", "type": "login",
"phonePrefix": "86",
}, },
}).then((Response) => { }).then((Response) => {
expect(Response).property("body").property("status").to.equal("ok"); expect(Response).property("body").property("status").to.equal("ok");

View File

@@ -3,6 +3,7 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@ant-design/cssinjs": "^1.5.6",
"@ant-design/icons": "^4.7.0", "@ant-design/icons": "^4.7.0",
"@craco/craco": "^6.4.5", "@craco/craco": "^6.4.5",
"@crowdin/cli": "^3.7.10", "@crowdin/cli": "^3.7.10",
@@ -21,6 +22,7 @@
"file-saver": "^2.0.5", "file-saver": "^2.0.5",
"i18n-iso-countries": "^7.0.0", "i18n-iso-countries": "^7.0.0",
"i18next": "^19.8.9", "i18next": "^19.8.9",
"libphonenumber-js": "^1.10.19",
"moment": "^2.29.1", "moment": "^2.29.1",
"qs": "^6.10.2", "qs": "^6.10.2",
"react": "^18.2.0", "react": "^18.2.0",

View File

@@ -78,6 +78,7 @@ class AccountTable extends React.Component {
{name: "Password", displayName: i18next.t("general:Password")}, {name: "Password", displayName: i18next.t("general:Password")},
{name: "Email", displayName: i18next.t("general:Email")}, {name: "Email", displayName: i18next.t("general:Email")},
{name: "Phone", displayName: i18next.t("general:Phone")}, {name: "Phone", displayName: i18next.t("general:Phone")},
{name: "Country code", displayName: i18next.t("user:Country code")},
{name: "Country/Region", displayName: i18next.t("user:Country/Region")}, {name: "Country/Region", displayName: i18next.t("user:Country/Region")},
{name: "Location", displayName: i18next.t("user:Location")}, {name: "Location", displayName: i18next.t("user:Location")},
{name: "Affiliation", displayName: i18next.t("user:Affiliation")}, {name: "Affiliation", displayName: i18next.t("user:Affiliation")},

View File

@@ -261,7 +261,7 @@ class AdapterListPage extends BaseListPage {
searchedColumn: params.searchedColumn, searchedColumn: params.searchedColumn,
}); });
} else { } else {
if (res.msg.includes("Unauthorized")) { if (Setting.isResponseDenied(res)) {
this.setState({ this.setState({
loading: false, loading: false,
isAuthorized: false, isAuthorized: false,

View File

@@ -16,8 +16,9 @@ import React, {Component} from "react";
import "./App.less"; import "./App.less";
import {Helmet} from "react-helmet"; import {Helmet} from "react-helmet";
import * as Setting from "./Setting"; import * as Setting from "./Setting";
import {BarsOutlined, DownOutlined, LogoutOutlined, SettingOutlined} from "@ant-design/icons"; import {StyleProvider} from "@ant-design/cssinjs";
import {Avatar, Button, Card, ConfigProvider, Drawer, Dropdown, FloatButton, Layout, Menu, Result} from "antd"; import {BarsOutlined, DownOutlined, InfoCircleFilled, LogoutOutlined, SettingOutlined} from "@ant-design/icons";
import {Alert, Avatar, Button, Card, ConfigProvider, Drawer, Dropdown, FloatButton, Layout, Menu, Result} from "antd";
import {Link, Redirect, Route, Switch, withRouter} from "react-router-dom"; import {Link, Redirect, Route, Switch, withRouter} from "react-router-dom";
import OrganizationListPage from "./OrganizationListPage"; import OrganizationListPage from "./OrganizationListPage";
import OrganizationEditPage from "./OrganizationEditPage"; import OrganizationEditPage from "./OrganizationEditPage";
@@ -84,8 +85,8 @@ class App extends Component {
uri: null, uri: null,
menuVisible: false, menuVisible: false,
themeAlgorithm: ["default"], themeAlgorithm: ["default"],
themeData: Setting.ThemeDefault, themeData: Conf.ThemeDefault,
logo: this.getLogo(Setting.getAlgorithmNames(Setting.ThemeDefault)), logo: this.getLogo(Setting.getAlgorithmNames(Conf.ThemeDefault)),
}; };
Setting.initServerUrl(); Setting.initServerUrl();
@@ -554,6 +555,13 @@ class App extends Component {
}; };
renderContent() { renderContent() {
const onClick = ({key}) => {
if (key === "/swagger") {
window.open(Setting.isLocalhost() ? `${Setting.ServerUrl}/swagger` : "/swagger", "_blank");
} else {
this.props.history.push(key);
}
};
return ( return (
<Layout id="parent-area"> <Layout id="parent-area">
{/* https://github.com/ant-design/ant-design/issues/40394 ant design bug. If it will be fixed, we can delete the code for control the color of Header*/} {/* https://github.com/ant-design/ant-design/issues/40394 ant design bug. If it will be fixed, we can delete the code for control the color of Header*/}
@@ -580,6 +588,7 @@ class App extends Component {
</Button> </Button>
</React.Fragment> : </React.Fragment> :
<Menu <Menu
onClick={onClick}
items={this.getMenuItems()} items={this.getMenuItems()}
mode={"horizontal"} mode={"horizontal"}
selectedKeys={[this.state.selectedMenuKey]} selectedKeys={[this.state.selectedMenuKey]}
@@ -663,6 +672,9 @@ class App extends Component {
return ( return (
<React.Fragment> <React.Fragment>
{
this.renderBanner()
}
<FloatButton.BackTop /> <FloatButton.BackTop />
<CustomGithubCorner /> <CustomGithubCorner />
{ {
@@ -672,6 +684,32 @@ class App extends Component {
); );
} }
renderBanner() {
if (!Conf.IsDemoMode) {
return null;
}
const language = Setting.getLanguage();
if (language === "en" || language === "zh") {
return null;
}
return (
<Alert type="info" banner showIcon={false} closable message={
<div style={{textAlign: "center"}}>
<InfoCircleFilled style={{color: "rgb(87,52,211)"}} />
&nbsp;&nbsp;
{i18next.t("general:Found some texts still not translated? Please help us translate at")}
&nbsp;
<a target="_blank" rel="noreferrer" href={"https://crowdin.com/project/casdoor-site"}>
Crowdin
</a>
&nbsp;!&nbsp;🙏
</div>
} />
);
}
render() { render() {
return ( return (
<React.Fragment> <React.Fragment>
@@ -692,9 +730,11 @@ class App extends Component {
}, },
algorithm: Setting.getAlgorithm(this.state.themeAlgorithm), algorithm: Setting.getAlgorithm(this.state.themeAlgorithm),
}}> }}>
{ <StyleProvider hashPriority="high">
this.renderPage() {
} this.renderPage()
}
</StyleProvider>
</ConfigProvider> </ConfigProvider>
</React.Fragment> </React.Fragment>
); );

View File

@@ -18,6 +18,7 @@ import {CopyOutlined, LinkOutlined, UploadOutlined} from "@ant-design/icons";
import * as ApplicationBackend from "./backend/ApplicationBackend"; import * as ApplicationBackend from "./backend/ApplicationBackend";
import * as CertBackend from "./backend/CertBackend"; import * as CertBackend from "./backend/CertBackend";
import * as Setting from "./Setting"; import * as Setting from "./Setting";
import * as Conf from "./Conf";
import * as ProviderBackend from "./backend/ProviderBackend"; import * as ProviderBackend from "./backend/ProviderBackend";
import * as OrganizationBackend from "./backend/OrganizationBackend"; import * as OrganizationBackend from "./backend/OrganizationBackend";
import * as ResourceBackend from "./backend/ResourceBackend"; import * as ResourceBackend from "./backend/ResourceBackend";
@@ -717,7 +718,7 @@ class ApplicationEditPage extends React.Component {
<Col span={22} style={{marginTop: "5px"}}> <Col span={22} style={{marginTop: "5px"}}>
<Row> <Row>
<Radio.Group value={this.state.application.themeData?.isEnabled ?? false} onChange={e => { <Radio.Group value={this.state.application.themeData?.isEnabled ?? false} onChange={e => {
const {_, ...theme} = this.state.application.themeData ?? {...Setting.ThemeDefault, isEnabled: false}; const {_, ...theme} = this.state.application.themeData ?? {...Conf.ThemeDefault, isEnabled: false};
this.updateApplicationField("themeData", {...theme, isEnabled: e.target.value}); this.updateApplicationField("themeData", {...theme, isEnabled: e.target.value});
}} > }} >
<Radio.Button value={false}>{i18next.t("application:Follow organization theme")}</Radio.Button> <Radio.Button value={false}>{i18next.t("application:Follow organization theme")}</Radio.Button>
@@ -728,7 +729,7 @@ class ApplicationEditPage extends React.Component {
this.state.application.themeData?.isEnabled ? this.state.application.themeData?.isEnabled ?
<Row style={{marginTop: "20px"}}> <Row style={{marginTop: "20px"}}>
<ThemeEditor themeData={this.state.application.themeData} onThemeChange={(_, nextThemeData) => { <ThemeEditor themeData={this.state.application.themeData} onThemeChange={(_, nextThemeData) => {
const {isEnabled} = this.state.application.themeData ?? {...Setting.ThemeDefault, isEnabled: false}; const {isEnabled} = this.state.application.themeData ?? {...Conf.ThemeDefault, isEnabled: false};
this.updateApplicationField("themeData", {...nextThemeData, isEnabled}); this.updateApplicationField("themeData", {...nextThemeData, isEnabled});
}} /> }} />
</Row> : null </Row> : null
@@ -764,7 +765,7 @@ class ApplicationEditPage extends React.Component {
} }
renderSignupSigninPreview() { renderSignupSigninPreview() {
const themeData = this.state.application.themeData ?? Setting.ThemeDefault; const themeData = this.state.application.themeData ?? Conf.ThemeDefault;
let signUpUrl = `/signup/${this.state.application.name}`; let signUpUrl = `/signup/${this.state.application.name}`;
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 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: "97%", width: "100%", background: "rgba(0,0,0,0.4)"}; const maskStyle = {position: "absolute", top: "0px", left: "0px", zIndex: 10, height: "97%", width: "100%", background: "rgba(0,0,0,0.4)"};
@@ -835,7 +836,7 @@ class ApplicationEditPage extends React.Component {
} }
renderPromptPreview() { renderPromptPreview() {
const themeData = this.state.application.themeData ?? Setting.ThemeDefault; const themeData = this.state.application.themeData ?? Conf.ThemeDefault;
const promptUrl = `/prompt/${this.state.application.name}`; 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)"}; const maskStyle = {position: "absolute", top: "0px", left: "0px", zIndex: 10, height: "100%", width: "100%", background: "rgba(0,0,0,0.4)"};
return ( return (

View File

@@ -287,7 +287,7 @@ class ApplicationListPage extends BaseListPage {
searchedColumn: params.searchedColumn, searchedColumn: params.searchedColumn,
}); });
} else { } else {
if (res.msg.includes("Unauthorized")) { if (Setting.isResponseDenied(res)) {
this.setState({ this.setState({
loading: false, loading: false,
isAuthorized: false, isAuthorized: false,

View File

@@ -228,7 +228,7 @@ class CertListPage extends BaseListPage {
searchedColumn: params.searchedColumn, searchedColumn: params.searchedColumn,
}); });
} else { } else {
if (res.msg.includes("Unauthorized")) { if (Setting.isResponseDenied(res)) {
this.setState({ this.setState({
loading: false, loading: false,
isAuthorized: false, isAuthorized: false,

View File

@@ -14,9 +14,17 @@
export const ShowGithubCorner = false; export const ShowGithubCorner = false;
export const GithubRepo = "https://github.com/casdoor/casdoor"; export const GithubRepo = "https://github.com/casdoor/casdoor";
export const IsDemoMode = false;
export const ForceLanguage = ""; export const ForceLanguage = "";
export const DefaultLanguage = "en"; export const DefaultLanguage = "en";
export const InitThemeAlgorithm = true;
export const EnableExtraPages = true; export const EnableExtraPages = true;
export const InitThemeAlgorithm = true;
export const ThemeDefault = {
themeType: "default",
colorPrimary: "#5734d3",
borderRadius: 6,
isCompact: false,
};

View File

@@ -17,6 +17,7 @@ import {Redirect, Route, Switch} from "react-router-dom";
import {Spin} from "antd"; import {Spin} from "antd";
import i18next from "i18next"; import i18next from "i18next";
import * as Setting from "./Setting"; import * as Setting from "./Setting";
import * as Conf from "./Conf";
import SignupPage from "./auth/SignupPage"; import SignupPage from "./auth/SignupPage";
import SelfLoginPage from "./auth/SelfLoginPage"; import SelfLoginPage from "./auth/SelfLoginPage";
import LoginPage from "./auth/LoginPage"; import LoginPage from "./auth/LoginPage";
@@ -62,7 +63,7 @@ class EntryPage extends React.Component {
application: application, application: application,
}); });
const themeData = application !== null ? Setting.getThemeData(application.organizationObj, application) : Setting.ThemeDefault; const themeData = application !== null ? Setting.getThemeData(application.organizationObj, application) : Conf.ThemeDefault;
this.props.updataThemeData(themeData); this.props.updataThemeData(themeData);
}; };
@@ -82,8 +83,8 @@ class EntryPage extends React.Component {
<Route exact path="/forget/:applicationName" render={(props) => this.renderHomeIfLoggedIn(<ForgetPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} /> <Route exact path="/forget/:applicationName" render={(props) => this.renderHomeIfLoggedIn(<ForgetPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/prompt" render={(props) => this.renderLoginIfNotLoggedIn(<PromptPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} /> <Route exact path="/prompt" render={(props) => this.renderLoginIfNotLoggedIn(<PromptPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/prompt/:applicationName" render={(props) => this.renderLoginIfNotLoggedIn(<PromptPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} /> <Route exact path="/prompt/:applicationName" render={(props) => this.renderLoginIfNotLoggedIn(<PromptPage {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/cas/:owner/:casApplicationName/logout" render={(props) => this.renderHomeIfLoggedIn(<CasLogout {...this.props} application={this.state.application} {...props} />)} /> <Route exact path="/cas/:owner/:casApplicationName/logout" render={(props) => this.renderHomeIfLoggedIn(<CasLogout {...this.props} application={this.state.application} onUpdateApplication={onUpdateApplication} {...props} />)} />
<Route exact path="/cas/:owner/:casApplicationName/login" render={(props) => {return (<LoginPage {...this.props} application={this.state.application} type={"cas"} mode={"signup"} {...props} />);}} /> <Route exact path="/cas/:owner/:casApplicationName/login" render={(props) => {return (<LoginPage {...this.props} application={this.state.application} type={"cas"} mode={"signup"} onUpdateApplication={onUpdateApplication} {...props} />);}} />
</Switch> </Switch>
</div> </div>
); );

View File

@@ -201,7 +201,7 @@ class ModelListPage extends BaseListPage {
searchedColumn: params.searchedColumn, searchedColumn: params.searchedColumn,
}); });
} else { } else {
if (res.msg.includes("Unauthorized")) { if (Setting.isResponseDenied(res)) {
this.setState({ this.setState({
loading: false, loading: false,
isAuthorized: false, isAuthorized: false,

View File

@@ -18,6 +18,7 @@ import * as OrganizationBackend from "./backend/OrganizationBackend";
import * as ApplicationBackend from "./backend/ApplicationBackend"; import * as ApplicationBackend from "./backend/ApplicationBackend";
import * as LdapBackend from "./backend/LdapBackend"; import * as LdapBackend from "./backend/LdapBackend";
import * as Setting from "./Setting"; import * as Setting from "./Setting";
import * as Conf from "./Conf";
import i18next from "i18next"; import i18next from "i18next";
import {LinkOutlined} from "@ant-design/icons"; import {LinkOutlined} from "@ant-design/icons";
import LdapTable from "./LdapTable"; import LdapTable from "./LdapTable";
@@ -183,12 +184,19 @@ class OrganizationEditPage extends React.Component {
</Row> </Row>
<Row style={{marginTop: "20px"}} > <Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> <Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("general:Phone prefix"), i18next.t("general:Phone prefix - Tooltip"))} : {Setting.getLabel(i18next.t("general:Supported country codes"), i18next.t("general:Supported country codes - Tooltip"))} :
</Col> </Col>
<Col span={22} > <Col span={22} >
<Input addonBefore={"+"} value={this.state.organization.phonePrefix} onChange={e => { <Select virtual={false} mode={"multiple"} style={{width: "100%"}} value={this.state.organization.countryCodes ?? []}
this.updateOrganizationField("phonePrefix", e.target.value); onChange={value => {
}} /> this.updateOrganizationField("countryCodes", value);
}}
filterOption={(input, option) => (option?.text ?? "").toLowerCase().includes(input.toLowerCase())}
>
{
Setting.getCountryCodeData().map((country) => Setting.getCountryCodeOption(country))
}
</Select>
</Col> </Col>
</Row> </Row>
<Row style={{marginTop: "20px"}} > <Row style={{marginTop: "20px"}} >
@@ -256,22 +264,13 @@ class OrganizationEditPage extends React.Component {
</Col> </Col>
<Col span={22} > <Col span={22} >
<Select virtual={false} mode="tags" style={{width: "100%"}} <Select virtual={false} mode="tags" style={{width: "100%"}}
value={this.state.organization.languages} options={Setting.Countries.map((item) => {
return Setting.getOption(item.label, item.key);
})}
value={this.state.organization.languages ?? []}
onChange={(value => { onChange={(value => {
this.updateOrganizationField("languages", value); this.updateOrganizationField("languages", value);
})} > })} >
{
[
{value: "en", label: "English"},
{value: "zh", label: "简体中文"},
{value: "es", label: "Español"},
{value: "fr", label: "Français"},
{value: "de", label: "Deutsch"},
{value: "ja", label: "日本語"},
{value: "ko", label: "한국어"},
{value: "ru", label: "Русский"},
].map((item, index) => <Option key={index} value={item.value}>{item.label}</Option>)
}
</Select> </Select>
</Col> </Col>
</Row> </Row>
@@ -324,7 +323,7 @@ class OrganizationEditPage extends React.Component {
<Col span={22} style={{marginTop: "5px"}}> <Col span={22} style={{marginTop: "5px"}}>
<Row> <Row>
<Radio.Group value={this.state.organization.themeData?.isEnabled ?? false} onChange={e => { <Radio.Group value={this.state.organization.themeData?.isEnabled ?? false} onChange={e => {
const {_, ...theme} = this.state.organization.themeData ?? {...Setting.ThemeDefault, isEnabled: false}; const {_, ...theme} = this.state.organization.themeData ?? {...Conf.ThemeDefault, isEnabled: false};
this.updateOrganizationField("themeData", {...theme, isEnabled: e.target.value}); this.updateOrganizationField("themeData", {...theme, isEnabled: e.target.value});
}} > }} >
<Radio.Button value={false}>{i18next.t("organization:Follow global theme")}</Radio.Button> <Radio.Button value={false}>{i18next.t("organization:Follow global theme")}</Radio.Button>
@@ -335,7 +334,7 @@ class OrganizationEditPage extends React.Component {
this.state.organization.themeData?.isEnabled ? this.state.organization.themeData?.isEnabled ?
<Row style={{marginTop: "20px"}}> <Row style={{marginTop: "20px"}}>
<ThemeEditor themeData={this.state.organization.themeData} onThemeChange={(_, nextThemeData) => { <ThemeEditor themeData={this.state.organization.themeData} onThemeChange={(_, nextThemeData) => {
const {isEnabled} = this.state.organization.themeData ?? {...Setting.ThemeDefault, isEnabled: false}; const {isEnabled} = this.state.organization.themeData ?? {...Conf.ThemeDefault, isEnabled: false};
this.updateOrganizationField("themeData", {...nextThemeData, isEnabled}); this.updateOrganizationField("themeData", {...nextThemeData, isEnabled});
}} /> }} />
</Row> : null </Row> : null

View File

@@ -33,11 +33,11 @@ class OrganizationListPage extends BaseListPage {
favicon: `${Setting.StaticBaseUrl}/img/favicon.png`, favicon: `${Setting.StaticBaseUrl}/img/favicon.png`,
passwordType: "plain", passwordType: "plain",
PasswordSalt: "", PasswordSalt: "",
phonePrefix: "86", countryCodes: ["CN"],
defaultAvatar: `${Setting.StaticBaseUrl}/img/casbin.svg`, defaultAvatar: `${Setting.StaticBaseUrl}/img/casbin.svg`,
defaultApplication: "", defaultApplication: "",
tags: [], tags: [],
languages: ["en", "zh", "es", "fr", "de", "ja", "ko", "ru"], languages: Setting.Countries.map(item => item.key),
masterPassword: "", masterPassword: "",
enableSoftDeletion: false, enableSoftDeletion: false,
isProfilePublic: true, isProfilePublic: true,
@@ -284,7 +284,7 @@ class OrganizationListPage extends BaseListPage {
searchedColumn: params.searchedColumn, searchedColumn: params.searchedColumn,
}); });
} else { } else {
if (res.msg.includes("Unauthorized")) { if (Setting.isResponseDenied(res)) {
this.setState({ this.setState({
loading: false, loading: false,
isAuthorized: false, isAuthorized: false,

View File

@@ -279,7 +279,7 @@ class PaymentListPage extends BaseListPage {
searchedColumn: params.searchedColumn, searchedColumn: params.searchedColumn,
}); });
} else { } else {
if (res.msg.includes("Unauthorized")) { if (Setting.isResponseDenied(res)) {
this.setState({ this.setState({
loading: false, loading: false,
isAuthorized: false, isAuthorized: false,

View File

@@ -359,7 +359,7 @@ class PermissionListPage extends BaseListPage {
searchedColumn: params.searchedColumn, searchedColumn: params.searchedColumn,
}); });
} else { } else {
if (res.msg.includes("Unauthorized")) { if (Setting.isResponseDenied(res)) {
this.setState({ this.setState({
loading: false, loading: false,
isAuthorized: false, isAuthorized: false,

View File

@@ -296,7 +296,7 @@ class ProductListPage extends BaseListPage {
searchedColumn: params.searchedColumn, searchedColumn: params.searchedColumn,
}); });
} else { } else {
if (res.msg.includes("Unauthorized")) { if (Setting.isResponseDenied(res)) {
this.setState({ this.setState({
loading: false, loading: false,
isAuthorized: false, isAuthorized: false,

View File

@@ -82,20 +82,20 @@ class ProviderEditPage extends React.Component {
}); });
} }
getClientIdLabel() { getClientIdLabel(provider) {
switch (this.state.provider.category) { switch (provider.category) {
case "Email": case "Email":
return Setting.getLabel(i18next.t("signup:Username"), i18next.t("signup:Username - Tooltip")); return Setting.getLabel(i18next.t("signup:Username"), i18next.t("signup:Username - Tooltip"));
case "SMS": case "SMS":
if (this.state.provider.type === "Volc Engine SMS") { if (provider.type === "Volc Engine SMS") {
return Setting.getLabel(i18next.t("provider:Access key"), i18next.t("provider:Access key - Tooltip")); return Setting.getLabel(i18next.t("provider:Access key"), i18next.t("provider:Access key - Tooltip"));
} else if (this.state.provider.type === "Huawei Cloud SMS") { } else if (provider.type === "Huawei Cloud SMS") {
return Setting.getLabel(i18next.t("provider:App key"), i18next.t("provider:App key - Tooltip")); return Setting.getLabel(i18next.t("provider:App key"), i18next.t("provider:App key - Tooltip"));
} else { } else {
return Setting.getLabel(i18next.t("provider:Client ID"), i18next.t("provider:Client ID - Tooltip")); return Setting.getLabel(i18next.t("provider:Client ID"), i18next.t("provider:Client ID - Tooltip"));
} }
case "Captcha": case "Captcha":
if (this.state.provider.type === "Aliyun Captcha") { if (provider.type === "Aliyun Captcha") {
return Setting.getLabel(i18next.t("provider:Access key"), i18next.t("provider:Access key - Tooltip")); return Setting.getLabel(i18next.t("provider:Access key"), i18next.t("provider:Access key - Tooltip"));
} else { } else {
return Setting.getLabel(i18next.t("provider:Site key"), i18next.t("provider:Site key - Tooltip")); return Setting.getLabel(i18next.t("provider:Site key"), i18next.t("provider:Site key - Tooltip"));
@@ -105,20 +105,20 @@ class ProviderEditPage extends React.Component {
} }
} }
getClientSecretLabel() { getClientSecretLabel(provider) {
switch (this.state.provider.category) { switch (provider.category) {
case "Email": case "Email":
return Setting.getLabel(i18next.t("login:Password"), i18next.t("login:Password - Tooltip")); return Setting.getLabel(i18next.t("login:Password"), i18next.t("login:Password - Tooltip"));
case "SMS": case "SMS":
if (this.state.provider.type === "Volc Engine SMS") { if (provider.type === "Volc Engine SMS") {
return Setting.getLabel(i18next.t("provider:Secret access key"), i18next.t("provider:SecretAccessKey - Tooltip")); return Setting.getLabel(i18next.t("provider:Secret access key"), i18next.t("provider:SecretAccessKey - Tooltip"));
} else if (this.state.provider.type === "Huawei Cloud SMS") { } else if (provider.type === "Huawei Cloud SMS") {
return Setting.getLabel(i18next.t("provider:App secret"), i18next.t("provider:AppSecret - Tooltip")); return Setting.getLabel(i18next.t("provider:App secret"), i18next.t("provider:AppSecret - Tooltip"));
} else { } else {
return Setting.getLabel(i18next.t("provider:Client secret"), i18next.t("provider:Client secret - Tooltip")); return Setting.getLabel(i18next.t("provider:Client secret"), i18next.t("provider:Client secret - Tooltip"));
} }
case "Captcha": case "Captcha":
if (this.state.provider.type === "Aliyun Captcha") { if (provider.type === "Aliyun Captcha") {
return Setting.getLabel(i18next.t("provider:Secret access key"), i18next.t("provider:SecretAccessKey - Tooltip")); return Setting.getLabel(i18next.t("provider:Secret access key"), i18next.t("provider:SecretAccessKey - Tooltip"));
} else { } else {
return Setting.getLabel(i18next.t("provider:Secret key"), i18next.t("provider:Secret key - Tooltip")); return Setting.getLabel(i18next.t("provider:Secret key"), i18next.t("provider:Secret key - Tooltip"));
@@ -128,40 +128,52 @@ class ProviderEditPage extends React.Component {
} }
} }
getAppIdRow() { getAppIdRow(provider) {
let text, tooltip; let text = "";
if (this.state.provider.category === "SMS" && this.state.provider.type === "Tencent Cloud SMS") { let tooltip = "";
text = i18next.t("provider:App ID");
tooltip = i18next.t("provider:App ID - Tooltip"); if (provider.category === "OAuth") {
} else if (this.state.provider.type === "WeCom" && this.state.provider.subType === "Internal") { if (provider.type === "WeCom" && provider.subType === "Internal") {
text = i18next.t("provider:Agent ID"); text = i18next.t("provider:Agent ID");
tooltip = i18next.t("provider:Agent ID - Tooltip"); tooltip = i18next.t("provider:Agent ID - Tooltip");
} else if (this.state.provider.type === "Infoflow") { } else if (provider.type === "Infoflow") {
text = i18next.t("provider:Agent ID"); text = i18next.t("provider:Agent ID");
tooltip = i18next.t("provider:Agent ID - Tooltip"); tooltip = i18next.t("provider:Agent ID - Tooltip");
} else if (this.state.provider.category === "SMS" && this.state.provider.type === "Volc Engine SMS") { }
text = i18next.t("provider:SMS account"); } else if (provider.category === "SMS") {
tooltip = i18next.t("provider:SMS account - Tooltip"); if (provider.type === "Tencent Cloud SMS") {
} else if (this.state.provider.category === "SMS" && this.state.provider.type === "Huawei Cloud SMS") { text = i18next.t("provider:App ID");
text = i18next.t("provider:Channel No."); tooltip = i18next.t("provider:App ID - Tooltip");
tooltip = i18next.t("provider:Channel No. - Tooltip"); } else if (provider.type === "Volc Engine SMS") {
} else if (this.state.provider.category === "Email" && this.state.provider.type === "SUBMAIL") { text = i18next.t("provider:SMS account");
text = i18next.t("provider:App ID"); tooltip = i18next.t("provider:SMS account - Tooltip");
tooltip = i18next.t("provider:App ID - Tooltip"); } else if (provider.type === "Huawei Cloud SMS") {
} else { text = i18next.t("provider:Channel No.");
return null; tooltip = i18next.t("provider:Channel No. - Tooltip");
}
} else if (provider.category === "Email") {
if (provider.type === "SUBMAIL") {
text = i18next.t("provider:App ID");
tooltip = i18next.t("provider:App ID - Tooltip");
}
} }
return <Row style={{marginTop: "20px"}} > if (text === "" && tooltip === "") {
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> return null;
{Setting.getLabel(text, tooltip)} : } else {
</Col> return (
<Col span={22} > <Row style={{marginTop: "20px"}} >
<Input value={this.state.provider.appId} onChange={e => { <Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
this.updateProviderField("appId", e.target.value); {Setting.getLabel(text, tooltip)} :
}} /> </Col>
</Col> <Col span={22} >
</Row>; <Input value={provider.appId} onChange={e => {
this.updateProviderField("appId", e.target.value);
}} />
</Col>
</Row>
);
}
} }
loadSamlConfiguration() { loadSamlConfiguration() {
@@ -404,7 +416,7 @@ class ProviderEditPage extends React.Component {
<React.Fragment> <React.Fragment>
<Row style={{marginTop: "20px"}} > <Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> <Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{this.getClientIdLabel()} {this.getClientIdLabel(this.state.provider)}
</Col> </Col>
<Col span={22} > <Col span={22} >
<Input value={this.state.provider.clientId} onChange={e => { <Input value={this.state.provider.clientId} onChange={e => {
@@ -414,7 +426,7 @@ class ProviderEditPage extends React.Component {
</Row> </Row>
<Row style={{marginTop: "20px"}} > <Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> <Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{this.getClientSecretLabel()} {this.getClientSecretLabel(this.state.provider)}
</Col> </Col>
<Col span={22} > <Col span={22} >
<Input value={this.state.provider.clientSecret} onChange={e => { <Input value={this.state.provider.clientSecret} onChange={e => {
@@ -750,7 +762,7 @@ class ProviderEditPage extends React.Component {
</React.Fragment> </React.Fragment>
) : null ) : null
} }
{this.getAppIdRow()} {this.getAppIdRow(this.state.provider)}
<Row style={{marginTop: "20px"}} > <Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}> <Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
{Setting.getLabel(i18next.t("provider:Provider URL"), i18next.t("provider:Provider URL - Tooltip"))} : {Setting.getLabel(i18next.t("provider:Provider URL"), i18next.t("provider:Provider URL - Tooltip"))} :

View File

@@ -267,7 +267,7 @@ class ProviderListPage extends BaseListPage {
searchedColumn: params.searchedColumn, searchedColumn: params.searchedColumn,
}); });
} else { } else {
if (res.msg.includes("Unauthorized")) { if (Setting.isResponseDenied(res)) {
this.setState({ this.setState({
loading: false, loading: false,
isAuthorized: false, isAuthorized: false,

View File

@@ -17,7 +17,7 @@ import i18next from "i18next";
import React from "react"; import React from "react";
import * as Setting from "./Setting"; import * as Setting from "./Setting";
import * as UserBackend from "./backend/UserBackend"; import * as UserBackend from "./backend/UserBackend";
import {CountDownInput} from "./common/CountDownInput"; import {SendCodeInput} from "./common/SendCodeInput";
import {MailOutlined, PhoneOutlined} from "@ant-design/icons"; import {MailOutlined, PhoneOutlined} from "@ant-design/icons";
export const ResetModal = (props) => { export const ResetModal = (props) => {
@@ -25,7 +25,7 @@ export const ResetModal = (props) => {
const [confirmLoading, setConfirmLoading] = React.useState(false); const [confirmLoading, setConfirmLoading] = React.useState(false);
const [dest, setDest] = React.useState(""); const [dest, setDest] = React.useState("");
const [code, setCode] = React.useState(""); const [code, setCode] = React.useState("");
const {buttonText, destType, application} = props; const {buttonText, destType, application, account} = props;
const showModal = () => { const showModal = () => {
setVisible(true); setVisible(true);
@@ -87,13 +87,13 @@ export const ResetModal = (props) => {
<Row style={{width: "100%", marginBottom: "20px"}}> <Row style={{width: "100%", marginBottom: "20px"}}>
<Input <Input
addonBefore={destType === "email" ? i18next.t("user:New Email") : i18next.t("user:New phone")} addonBefore={destType === "email" ? i18next.t("user:New Email") : i18next.t("user:New phone")}
prefix={destType === "email" ? <MailOutlined /> : <PhoneOutlined />} prefix={destType === "email" ? <React.Fragment><MailOutlined />&nbsp;&nbsp;</React.Fragment> : (<React.Fragment><PhoneOutlined />&nbsp;&nbsp;{`+${Setting.getCountryCode(account.countryCode)}`}&nbsp;</React.Fragment>)}
placeholder={placeholder} placeholder={placeholder}
onChange={e => setDest(e.target.value)} onChange={e => setDest(e.target.value)}
/> />
</Row> </Row>
<Row style={{width: "100%", marginBottom: "20px"}}> <Row style={{width: "100%", marginBottom: "20px"}}>
<CountDownInput <SendCodeInput
textBefore={i18next.t("code:Code You Received")} textBefore={i18next.t("code:Code You Received")}
onChange={setCode} onChange={setCode}
method={"reset"} method={"reset"}

View File

@@ -82,7 +82,7 @@ class RoleListPage extends BaseListPage {
...this.getColumnSearchProps("name"), ...this.getColumnSearchProps("name"),
render: (text, record, index) => { render: (text, record, index) => {
return ( return (
<Link to={`/roles/${text}`}> <Link to={`/roles/${record.owner}/${record.name}`}>
{text} {text}
</Link> </Link>
); );
@@ -232,7 +232,7 @@ class RoleListPage extends BaseListPage {
searchedColumn: params.searchedColumn, searchedColumn: params.searchedColumn,
}); });
} else { } else {
if (res.msg.includes("Unauthorized")) { if (Setting.isResponseDenied(res)) {
this.setState({ this.setState({
loading: false, loading: false,
isAuthorized: false, isAuthorized: false,

View File

@@ -29,7 +29,7 @@ class SelectLanguageBox extends React.Component {
super(props); super(props);
this.state = { this.state = {
classes: props, classes: props,
languages: props.languages ?? ["en", "zh", "es", "fr", "de", "ja", "ko", "ru"], languages: props.languages ?? Setting.Countries.map(item => item.key),
}; };
Setting.Countries.forEach((country) => { Setting.Countries.forEach((country) => {

Some files were not shown because too many files have changed in this diff Show More