Compare commits

...

39 Commits

Author SHA1 Message Date
3ae81716b9 Fix getLdaps() GET 2023-02-18 16:27:47 +08:00
3a70f4e788 Add Setting.isResponseDenied() 2023-02-18 16:21:12 +08:00
842d4865b2 Fix router error message's i18n 2023-02-18 16:11:23 +08:00
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
943bd82731 feat: fix migrator_1_245_0_PR_1557.go (#1564) 2023-02-18 10:58:14 +08:00
f2f962b893 fix: refactor functions and code (#1559) 2023-02-18 09:31:58 +08:00
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
4605938f8e Refactor FetchFilter.js code 2023-02-16 22:50:08 +08:00
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
e877045671 feat: fix CAS login crash bug (#1549) 2023-02-14 16:52:15 +08:00
29f1ec08a2 fix: fix CI error by auto waiting for localhost:7001 to start up (#1548) 2023-02-14 14:50:58 +08:00
389744a27d feat: change claims to claimsWithoutThirdIdp when gen token (#1552) 2023-02-14 09:33:46 +08:00
dc7b66822d feat: change token ExpiresIn to second (#1550) 2023-02-14 09:18:30 +08:00
efacf8226c fix: session Id error (#1554) 2023-02-13 22:58:26 +08:00
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
c9b990a319 Add removeExtraSessionIds() 2023-02-12 21:11:16 +08:00
eedcde3aa5 Refactor session.go 2023-02-12 21:06:08 +08:00
950a274b23 fix: region don't display in userEditPage (#1544) 2023-02-12 18:56:56 +08:00
478bd05db4 Improve error handling in migrator 2023-02-12 10:39:20 +08:00
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
6f2ef32d02 Update xorm.io/core to v0.7.3 2023-02-11 17:46:34 +08:00
8b8c866fd2 feat: replace gomail and disable the Email username check for Mailtrap (#1538) 2023-02-11 15:59:23 +08:00
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
04567babf8 feat: fix click MenuItem blank part invalid bug (#1535) 2023-02-10 18:11:15 +08:00
543b316942 feat: update swagger parameter id description (#1532) 2023-02-10 10:42:16 +08:00
e2b6e8ee6e chore: unify migrate database way (#1530) 2023-02-09 19:28:15 +08:00
wht
e7e0518517 feat: fix the upload file name contains space problem (#1527) 2023-02-07 23:26:17 +08:00
943aa61869 feat: add provider icons and menus (#1522)
* fix: add provider icons(email and captcha) and menus

* fix: add provider icons and menus
2023-02-06 20:28:40 +08:00
wht
fcc75dd3be feat: fix the Unicode filename encoding bug in storage provider (#1518) 2023-02-04 18:09:18 +08:00
8698f4111a feat: add all remaining Goth providers to Casdoor OAuth login (#1484)
* feat: add Amazon support as OAuth 3rd-party login

* refactor: comebine the same URLs

* refactor: use hyper component to create login button

* feat: add all remaining Goth providers to Casdoor OAuth login

* refactor: remove redundant props

* fix: check provider auth url and params
2023-02-04 12:20:18 +08:00
fdccb8b22b feat: Test whether the page can be accessed (#1517)
* feat: add new line

* feat: Test whether the page can be accessed

* feat: Change the e2e order

* feat: add Test Retries

* feat: change yarn.lock

* feat: add new line
2023-02-03 19:59:28 +08:00
19e7d0b0bd refactor: improve code reuse rate (#1515) 2023-02-02 16:43:51 +08:00
f6a502f7ff feat: add user password in ldap server search result (#1513)
* fix: ldap server search return inconsistent cn attribute

* feat: add user password in ldap server search result
2023-02-02 15:33:44 +08:00
b34e16b145 fix: table do not have unique key (#1512) 2023-02-02 13:53:18 +08:00
11b56c340f Add refineUser() in generateJwtToken() 2023-02-02 00:34:56 +08:00
cc6ea1b60e feat: fix application edit page crash and language icon position (#1511)
* fix: widget position and color

* feat: fix applicationEdit crush
2023-02-01 23:11:48 +08:00
95b32d5ebf feat: support customize theme (#1500)
* refactor: simplify functions and improve variable naming

* feat: add themeEditor component

* feat: support customize theme

* chore: resolve conflict and add LICENCE

* chore: format code

* refactor: use icon replace background url

* feat: improve organization and application theme editor
2023-02-01 22:06:40 +08:00
b47baa06e1 fix: remove "Agreement" in edit application error (#1506) 2023-01-31 22:56:19 +08:00
175 changed files with 16468 additions and 13044 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -58,7 +58,7 @@ type RequestForm struct {
EmailCode string `json:"emailCode"`
PhoneCode string `json:"phoneCode"`
PhonePrefix string `json:"phonePrefix"`
CountryCode string `json:"countryCode"`
AutoSignin bool `json:"autoSignin"`
@ -121,7 +121,7 @@ func (c *ApiController) Signup() {
}
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 != "" {
c.ResponseError(msg)
return
@ -137,7 +137,7 @@ func (c *ApiController) Signup() {
var checkPhone string
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())
if len(checkResult) != 0 {
c.ResponseError(c.T("account:Phone: %s"), checkResult)
@ -179,6 +179,7 @@ func (c *ApiController) Signup() {
Avatar: organization.DefaultAvatar,
Email: form.Email,
Phone: form.Phone,
CountryCode: form.CountryCode,
Address: []string{},
Affiliation: form.Affiliation,
IdCard: form.IdCard,
@ -254,7 +255,10 @@ func (c *ApiController) Logout() {
if accessToken == "" && redirectUri == "" {
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)
application := c.GetSessionApplication()
@ -291,7 +295,8 @@ func (c *ApiController) Logout() {
}
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)
c.Ctx.Redirect(http.StatusFound, fmt.Sprintf("%s?state=%s", strings.TrimRight(redirectUri, "/"), state))

View File

@ -63,7 +63,7 @@ func (c *ApiController) GetApplications() {
// @Title GetApplication
// @Tag Application API
// @Description get the detail of an application
// @Param id query string true "The id of the application."
// @Param id query string true "The id ( owner/name ) of the application."
// @Success 200 {object} object.Application The Response object
// @router /get-application [get]
func (c *ApiController) GetApplication() {
@ -78,7 +78,7 @@ func (c *ApiController) GetApplication() {
// @Title GetUserApplication
// @Tag Application API
// @Description get the detail of the user's application
// @Param id query string true "The id of the user"
// @Param id query string true "The id ( owner/name ) of the user"
// @Success 200 {object} object.Application The Response object
// @router /get-user-application [get]
func (c *ApiController) GetUserApplication() {
@ -134,7 +134,7 @@ func (c *ApiController) GetOrganizationApplications() {
// @Title UpdateApplication
// @Tag Application API
// @Description update an application
// @Param id query string true "The id of the application"
// @Param id query string true "The id ( owner/name ) of the application"
// @Param body body object.Application true "The details of the application"
// @Success 200 {object} controllers.Response The Response object
// @router /update-application [post]

View File

@ -139,8 +139,13 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
})
}
if resp.Status == "ok" {
object.SetSession(user.GetId(), c.Ctx.Input.CruSession.SessionID())
if resp.Status == "ok" && user.Owner == object.CasdoorOrganization && application.Name == object.CasdoorApplication {
object.AddSession(&object.Session{
Owner: user.Owner,
Name: user.Name,
Application: application.Name,
SessionId: []string{c.Ctx.Input.CruSession.SessionID()},
})
}
return resp
@ -174,13 +179,36 @@ func (c *ApiController) GetApplicationLogin() {
}
func setHttpClient(idProvider idp.IdProvider, providerType string) {
if providerType == "GitHub" || providerType == "Google" || providerType == "Facebook" || providerType == "LinkedIn" || providerType == "Steam" || providerType == "Line" {
if isProxyProviderType(providerType) {
idProvider.SetHttpClient(proxy.ProxyHttpClient)
} else {
idProvider.SetHttpClient(proxy.DefaultHttpClient)
}
}
func isProxyProviderType(providerType string) bool {
providerTypes := []string{
"GitHub",
"Google",
"Facebook",
"LinkedIn",
"Steam",
"Line",
"Amazon",
"Instagram",
"TikTok",
"Twitter",
"Uber",
"Yahoo",
}
for _, v := range providerTypes {
if strings.EqualFold(v, providerType) {
return true
}
}
return false
}
// Login ...
// @Title Login
// @Tag Login API
@ -235,34 +263,32 @@ func (c *ApiController) Login() {
checkDest = form.Username
} else {
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 {
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)))
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())
if len(checkResult) != 0 {
responseText := fmt.Sprintf("%s - %s", verificationCodeType, checkResult)
c.ResponseError(responseText)
c.ResponseError(fmt.Sprintf("%s - %s", verificationCodeType, checkResult))
return
}
// disable the verification code
if strings.Contains(form.Username, "@") {
object.DisableVerificationCode(form.Username)
} else {
object.DisableVerificationCode(fmt.Sprintf("+%s%s", form.PhonePrefix, form.Username))
}
object.DisableVerificationCode(checkDest)
} else {
application := object.GetApplication(fmt.Sprintf("admin/%s", form.Application))
if application == nil {

View File

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

View File

@ -52,7 +52,7 @@ func (c *ApiController) GetCerts() {
// @Title GetCert
// @Tag Cert API
// @Description get cert
// @Param id query string true "The id of the cert"
// @Param id query string true "The id ( owner/name ) of the cert"
// @Success 200 {object} object.Cert The Response object
// @router /get-cert [get]
func (c *ApiController) GetCert() {
@ -66,7 +66,7 @@ func (c *ApiController) GetCert() {
// @Title UpdateCert
// @Tag Cert API
// @Description update cert
// @Param id query string true "The id of the cert"
// @Param id query string true "The id ( owner/name ) of the cert"
// @Param body body object.Cert true "The details of the cert"
// @Success 200 {object} controllers.Response The Response object
// @router /update-cert [post]

View File

@ -51,7 +51,7 @@ type LdapSyncResp struct {
func (c *ApiController) GetLdapUser() {
ldapServer := 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"))
return
}
@ -104,7 +104,7 @@ func (c *ApiController) GetLdapUser() {
// GetLdaps
// @Tag Account API
// @Title GetLdaps
// @router /get-ldaps [post]
// @router /get-ldaps [get]
func (c *ApiController) GetLdaps() {
owner := c.Input().Get("owner")
@ -115,11 +115,11 @@ func (c *ApiController) GetLdaps() {
// GetLdap
// @Tag Account API
// @Title GetLdap
// @router /get-ldap [post]
// @router /get-ldap [get]
func (c *ApiController) GetLdap() {
id := c.Input().Get("id")
if util.IsStrsEmpty(id) {
if util.IsStringsEmpty(id) {
c.ResponseError(c.T("general:Missing parameter"))
return
}
@ -140,7 +140,7 @@ func (c *ApiController) AddLdap() {
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"))
return
}
@ -170,7 +170,7 @@ func (c *ApiController) AddLdap() {
func (c *ApiController) UpdateLdap() {
var ldap object.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"))
return
}

View File

@ -105,14 +105,34 @@ func handleSearch(w ldapserver.ResponseWriter, m *ldapserver.Message) {
}
for i := 0; i < len(users); i++ {
user := users[i]
dn := fmt.Sprintf("cn=%s,%s", user.DisplayName, string(r.BaseObject()))
dn := fmt.Sprintf("cn=%s,%s", user.Name, string(r.BaseObject()))
e := ldapserver.NewSearchResultEntry(dn)
e.AddAttribute("cn", message.AttributeValue(user.Name))
e.AddAttribute("uid", message.AttributeValue(user.Name))
e.AddAttribute("email", message.AttributeValue(user.Email))
e.AddAttribute("mobile", message.AttributeValue(user.Phone))
e.AddAttribute("userPassword", message.AttributeValue(getUserPasswordWithType(user)))
// e.AddAttribute("postalAddress", message.AttributeValue(user.Address[0]))
w.Write(e)
}
w.Write(res)
}
// get user password with hash type prefix
// TODO not handle salt yet
// @return {md5}5f4dcc3b5aa765d61d8327deb882cf99
func getUserPasswordWithType(user *object.User) string {
org := object.GetOrganizationByUser(user)
if org.PasswordType == "" || org.PasswordType == "plain" {
return user.Password
}
prefix := org.PasswordType
if prefix == "salt" {
prefix = "sha256"
} else if prefix == "md5-salt" {
prefix = "md5"
} else if prefix == "pbkdf2-salt" {
prefix = "pbkdf2"
}
return fmt.Sprintf("{%s}%s", prefix, user.Password)
}

View File

@ -52,7 +52,7 @@ func (c *ApiController) GetModels() {
// @Title GetModel
// @Tag Model API
// @Description get model
// @Param id query string true "The id of the model"
// @Param id query string true "The id ( owner/name ) of the model"
// @Success 200 {object} object.Model The Response object
// @router /get-model [get]
func (c *ApiController) GetModel() {
@ -66,7 +66,7 @@ func (c *ApiController) GetModel() {
// @Title UpdateModel
// @Tag Model API
// @Description update model
// @Param id query string true "The id of the model"
// @Param id query string true "The id ( owner/name ) of the model"
// @Param body body object.Model true "The details of the model"
// @Success 200 {object} controllers.Response The Response object
// @router /update-model [post]

View File

@ -66,7 +66,7 @@ func (c *ApiController) GetOrganization() {
// @Title UpdateOrganization
// @Tag Organization API
// @Description update organization
// @Param id query string true "The id of the organization"
// @Param id query string true "The id ( owner/name ) of the organization"
// @Param body body object.Organization true "The details of the organization"
// @Success 200 {object} controllers.Response The Response object
// @router /update-organization [post]

View File

@ -71,7 +71,7 @@ func (c *ApiController) GetUserPayments() {
// @Title GetPayment
// @Tag Payment API
// @Description get payment
// @Param id query string true "The id of the payment"
// @Param id query string true "The id ( owner/name ) of the payment"
// @Success 200 {object} object.Payment The Response object
// @router /get-payment [get]
func (c *ApiController) GetPayment() {
@ -85,7 +85,7 @@ func (c *ApiController) GetPayment() {
// @Title UpdatePayment
// @Tag Payment API
// @Description update payment
// @Param id query string true "The id of the payment"
// @Param id query string true "The id ( owner/name ) of the payment"
// @Param body body object.Payment true "The details of the payment"
// @Success 200 {object} controllers.Response The Response object
// @router /update-payment [post]
@ -172,7 +172,7 @@ func (c *ApiController) NotifyPayment() {
// @Title InvoicePayment
// @Tag Payment API
// @Description invoice payment
// @Param id query string true "The id of the payment"
// @Param id query string true "The id ( owner/name ) of the payment"
// @Success 200 {object} controllers.Response The Response object
// @router /invoice-payment [post]
func (c *ApiController) InvoicePayment() {

View File

@ -69,7 +69,7 @@ func (c *ApiController) GetPermissionsBySubmitter() {
// @Title GetPermissionsByRole
// @Tag Permission API
// @Description get permissions by role
// @Param id query string true "The id of the role"
// @Param id query string true "The id ( owner/name ) of the role"
// @Success 200 {array} object.Permission The Response object
// @router /get-permissions-by-role [get]
func (c *ApiController) GetPermissionsByRole() {
@ -83,7 +83,7 @@ func (c *ApiController) GetPermissionsByRole() {
// @Title GetPermission
// @Tag Permission API
// @Description get permission
// @Param id query string true "The id of the permission"
// @Param id query string true "The id ( owner/name ) of the permission"
// @Success 200 {object} object.Permission The Response object
// @router /get-permission [get]
func (c *ApiController) GetPermission() {
@ -97,7 +97,7 @@ func (c *ApiController) GetPermission() {
// @Title UpdatePermission
// @Tag Permission API
// @Description update permission
// @Param id query string true "The id of the permission"
// @Param id query string true "The id ( owner/name ) of the permission"
// @Param body body object.Permission true "The details of the permission"
// @Success 200 {object} controllers.Response The Response object
// @router /update-permission [post]

View File

@ -53,7 +53,7 @@ func (c *ApiController) GetProducts() {
// @Title GetProduct
// @Tag Product API
// @Description get product
// @Param id query string true "The id of the product"
// @Param id query string true "The id ( owner/name ) of the product"
// @Success 200 {object} object.Product The Response object
// @router /get-product [get]
func (c *ApiController) GetProduct() {
@ -70,7 +70,7 @@ func (c *ApiController) GetProduct() {
// @Title UpdateProduct
// @Tag Product API
// @Description update product
// @Param id query string true "The id of the product"
// @Param id query string true "The id ( owner/name ) of the product"
// @Param body body object.Product true "The details of the product"
// @Success 200 {object} controllers.Response The Response object
// @router /update-product [post]
@ -130,7 +130,7 @@ func (c *ApiController) DeleteProduct() {
// @Title BuyProduct
// @Tag Product API
// @Description buy product
// @Param id query string true "The id of the product"
// @Param id query string true "The id ( owner/name ) of the product"
// @Param providerName query string true "The name of the provider"
// @Success 200 {object} controllers.Response The Response object
// @router /buy-product [post]

View File

@ -76,7 +76,7 @@ func (c *ApiController) GetGlobalProviders() {
// @Title GetProvider
// @Tag Provider API
// @Description get provider
// @Param id query string true "The id of the provider"
// @Param id query string true "The id ( owner/name ) of the provider"
// @Success 200 {object} object.Provider The Response object
// @router /get-provider [get]
func (c *ApiController) GetProvider() {
@ -89,7 +89,7 @@ func (c *ApiController) GetProvider() {
// @Title UpdateProvider
// @Tag Provider API
// @Description update provider
// @Param id query string true "The id of the provider"
// @Param id query string true "The id ( owner/name ) of the provider"
// @Param body body object.Provider true "The details of the provider"
// @Success 200 {object} controllers.Response The Response object
// @router /update-provider [post]

View File

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

View File

@ -52,7 +52,7 @@ func (c *ApiController) GetRoles() {
// @Title GetRole
// @Tag Role API
// @Description get role
// @Param id query string true "The id of the role"
// @Param id query string true "The id ( owner/name ) of the role"
// @Success 200 {object} object.Role The Response object
// @router /get-role [get]
func (c *ApiController) GetRole() {
@ -66,7 +66,7 @@ func (c *ApiController) GetRole() {
// @Title UpdateRole
// @Tag Role API
// @Description update role
// @Param id query string true "The id of the role"
// @Param id query string true "The id ( owner/name ) of the role"
// @Param body body object.Role true "The details of the role"
// @Success 200 {object} controllers.Response The Response object
// @router /update-role [post]

View File

@ -80,7 +80,7 @@ func (c *ApiController) SendEmail() {
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))
return
}
@ -130,13 +130,13 @@ func (c *ApiController) SendSms() {
return
}
org := object.GetOrganization(smsForm.OrgId)
var invalidReceivers []string
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)
} 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"
)
// DeleteSession
// @Title DeleteSession
// @Tag Session API
// @Description Delete session by userId
// @Param ID query string true "The ID(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
// @Title GetSessions
// @Tag Session API
// @Description Get organization user sessions
// @Description Get organization user sessions.
// @Param owner query string true "The organization name"
// @Success 200 {array} string The Response object
// @router /get-sessions [get]
@ -66,3 +47,93 @@ func (c *ApiController) GetSessions() {
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

@ -52,7 +52,7 @@ func (c *ApiController) GetSyncers() {
// @Title GetSyncer
// @Tag Syncer API
// @Description get syncer
// @Param id query string true "The id of the syncer"
// @Param id query string true "The id ( owner/name ) of the syncer"
// @Success 200 {object} object.Syncer The Response object
// @router /get-syncer [get]
func (c *ApiController) GetSyncer() {
@ -66,7 +66,7 @@ func (c *ApiController) GetSyncer() {
// @Title UpdateSyncer
// @Tag Syncer API
// @Description update syncer
// @Param id query string true "The id of the syncer"
// @Param id query string true "The id ( owner/name ) of the syncer"
// @Param body body object.Syncer true "The details of the syncer"
// @Success 200 {object} controllers.Response The Response object
// @router /update-syncer [post]

View File

@ -29,7 +29,7 @@ type SystemInfo struct {
// @Title GetSystemInfo
// @Tag System API
// @Description get user's system info
// @Param id query string true "The id of the user"
// @Param id query string true "The id ( owner/name ) of the user"
// @Success 200 {object} object.SystemInfo The Response object
// @router /get-system-info [get]
func (c *ApiController) GetSystemInfo() {

View File

@ -54,7 +54,7 @@ func (c *ApiController) GetTokens() {
// @Title GetToken
// @Tag Token API
// @Description get token
// @Param id query string true "The id of token"
// @Param id query string true "The id ( owner/name ) of token"
// @Success 200 {object} object.Token The Response object
// @router /get-token [get]
func (c *ApiController) GetToken() {
@ -68,7 +68,7 @@ func (c *ApiController) GetToken() {
// @Title UpdateToken
// @Tag Token API
// @Description update token
// @Param id query string true "The id of token"
// @Param id query string true "The id ( owner/name ) of token"
// @Param body body object.Token true "Details of the token"
// @Success 200 {object} controllers.Response The Response object
// @router /update-token [post]
@ -128,7 +128,7 @@ func (c *ApiController) DeleteToken() {
// @Title GetOAuthCode
// @Tag Token API
// @Description get OAuth code
// @Param user_id query string true "The id of user"
// @Param id query string true "The id ( owner/name ) of user"
// @Param client_id query string true "OAuth client id"
// @Param response_type query string true "OAuth response type"
// @Param redirect_uri query string true "OAuth redirect URI"
@ -172,6 +172,7 @@ func (c *ApiController) GetOAuthCode() {
// @router /login/oauth/access_token [post]
func (c *ApiController) GetOAuthToken() {
grantType := c.Input().Get("grant_type")
refreshToken := c.Input().Get("refresh_token")
clientId := c.Input().Get("client_id")
clientSecret := c.Input().Get("client_secret")
code := c.Input().Get("code")
@ -192,6 +193,7 @@ func (c *ApiController) GetOAuthToken() {
clientId = tokenRequest.ClientId
clientSecret = tokenRequest.ClientSecret
grantType = tokenRequest.GrantType
refreshToken = tokenRequest.RefreshToken
code = tokenRequest.Code
verifier = tokenRequest.Verifier
scope = tokenRequest.Scope
@ -203,7 +205,7 @@ func (c *ApiController) GetOAuthToken() {
}
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.ServeJSON()
}

View File

@ -80,7 +80,7 @@ func (c *ApiController) GetUsers() {
// @Title GetUser
// @Tag User API
// @Description get user
// @Param id query string true "The id of the user"
// @Param id query string true "The id ( owner/name ) of the user"
// @Param owner query string false "The owner of the user"
// @Param email query string false "The email of the user"
// @Param phone query string false "The phone of the user"
@ -129,7 +129,7 @@ func (c *ApiController) GetUser() {
// @Title UpdateUser
// @Tag User API
// @Description update user
// @Param id query string true "The id of the user"
// @Param id query string true "The id ( owner/name ) of the user"
// @Param body body object.User true "The details of the user"
// @Success 200 {object} controllers.Response The Response object
// @router /update-user [post]

View File

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

View File

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

View File

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

View File

@ -52,7 +52,7 @@ func (c *ApiController) GetWebhooks() {
// @Title GetWebhook
// @Tag Webhook API
// @Description get webhook
// @Param id query string true "The id of the webhook"
// @Param id query string true "The id ( owner/name ) of the webhook"
// @Success 200 {object} object.Webhook The Response object
// @router /get-webhook [get]
func (c *ApiController) GetWebhook() {
@ -66,7 +66,7 @@ func (c *ApiController) GetWebhook() {
// @Title UpdateWebhook
// @Tag Webhook API
// @Description update webhook
// @Param id query string true "The id of the webhook"
// @Param id query string true "The id ( owner/name ) of the webhook"
// @Param body body object.Webhook true "The details of the webhook"
// @Success 200 {object} controllers.Response The Response object
// @router /update-webhook [post]

12
go.mod
View File

@ -9,14 +9,14 @@ require (
github.com/beego/beego v1.12.11
github.com/beevik/etree v1.1.0
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.1
github.com/casdoor/gomail/v2 v2.0.1
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/denisenkom/go-mssqldb v0.9.0
github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b
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-pay/gopay v1.5.72
github.com/go-sql-driver/mysql v1.5.0
@ -30,6 +30,7 @@ require (
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3
github.com/markbates/goth v1.75.2
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/robfig/cron/v3 v3.0.1
github.com/russellhaering/gosaml2 v0.6.0
@ -41,18 +42,15 @@ require (
github.com/tealeg/xlsx v1.0.5
github.com/thanhpk/randstr v1.0.4
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
golang.org/x/crypto v0.0.0-20220214200702-86341886e292
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
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/square/go-jose.v2 v2.6.0
gopkg.in/yaml.v2 v2.3.0 // indirect
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
)

33
go.sum
View File

@ -58,7 +58,6 @@ 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.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw=
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/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/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@ -73,7 +72,6 @@ github.com/aliyun/alibaba-cloud-sdk-go v1.61.1075 h1:Z0SzZttfYI/raZ5O9WF3cezZJTS
github.com/aliyun/alibaba-cloud-sdk-go v1.61.1075/go.mod h1:pUKYbK5JQ+1Dfxk80P0qxGqe5dkxDoabbZS7zOcouyA=
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/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/aws/aws-sdk-go v1.44.4 h1:ePN0CVJMdiz2vYUcJH96eyxRrtKGSDMgyhP6rah2OgE=
github.com/aws/aws-sdk-go v1.44.4/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
@ -96,12 +94,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.30.1 h1:P5HWadDL7olwUXNdcuKUBk+x75Y2eitFxYTcLNKeKF0=
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/casbin/xorm-adapter/v3 v3.0.1/go.mod h1:1BL7rHEDXrxO+vQdSo/ZaWKRivXl7YTos67GdMYcd20=
github.com/casdoor/go-sms-sender v0.5.1 h1:1/Wp1OLkVAVY4lEGQhekSNetSAWhnPcxYPV7xpCZgC0=
github.com/casdoor/go-sms-sender v0.5.1/go.mod h1:kBykbqwgRDXbXdMAIxmZKinVM1WjdqEbej5LAbUbcfI=
github.com/casdoor/gomail/v2 v2.0.1 h1:J+FG6x80s9e5lBHUn8Sv0Y56mud34KiWih5YdmudR/w=
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/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/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@ -126,7 +126,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/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/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/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b h1:L63RATZFZuFMXy6ixnKmv3eNAXwYQF6HW1vd4IYsQqQ=
@ -154,8 +153,6 @@ 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/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-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.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-ldap/ldap/v3 v3.3.0 h1:lwx+SJpgOHd8tG6SumBQZXCmNX51zM8B1cfxJ5gv4tQ=
@ -270,6 +267,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/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
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/jinzhu/configor v1.2.1 h1:OKk9dsR8i6HPOCZR8BcMtcEImAFjIhbJFZNyn5GCZko=
github.com/jinzhu/configor v1.2.1/go.mod h1:nX89/MOmDba7ZX7GCyU/VIaQ2Ar2aizBl2d3JLF/rDc=
@ -337,7 +335,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/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
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 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
@ -357,6 +354,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/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/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.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.0 h1:Iw5WCbBcaAAd0fpRb1c9r5YCylv4XDoCSigm1zLevwU=
@ -456,6 +455,12 @@ github.com/volcengine/volc-sdk-golang v1.0.19/go.mod h1:+GGi447k4p1I5PNdbpG2GLaF
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/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.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@ -520,7 +525,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.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
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-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -789,8 +793,6 @@ 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/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
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.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
@ -847,12 +849,3 @@ 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/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
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

@ -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": {
"%s No phone prefix": "%s No phone prefix",
"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",
@ -57,13 +56,15 @@
"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"
"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"
@ -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",
"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.",

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": {
"%s No phone prefix": "%s No phone prefix",
"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",
@ -57,13 +56,15 @@
"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"
"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"
@ -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",
"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.",

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": {
"%s No phone prefix": "%s No phone prefix",
"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",
@ -57,13 +56,15 @@
"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"
"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"
@ -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",
"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.",

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": {
"%s No phone prefix": "%s No phone prefix",
"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",
@ -57,13 +56,15 @@
"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"
"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"
@ -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",
"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.",

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": {
"%s No phone prefix": "%s No phone prefix",
"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",
@ -57,13 +56,15 @@
"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"
"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"
@ -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",
"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.",

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": {
"%s No phone prefix": "%s No phone prefix",
"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",
@ -57,13 +56,15 @@
"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"
"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"
@ -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",
"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.",

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": {
"%s No phone prefix": "%s No phone prefix",
"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",
@ -57,13 +56,15 @@
"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"
"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"
@ -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",
"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.",

View File

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

View File

@ -25,30 +25,59 @@ import (
"github.com/markbates/goth"
"github.com/markbates/goth/providers/amazon"
"github.com/markbates/goth/providers/apple"
"github.com/markbates/goth/providers/auth0"
"github.com/markbates/goth/providers/azureadv2"
"github.com/markbates/goth/providers/battlenet"
"github.com/markbates/goth/providers/bitbucket"
"github.com/markbates/goth/providers/box"
"github.com/markbates/goth/providers/cloudfoundry"
"github.com/markbates/goth/providers/dailymotion"
"github.com/markbates/goth/providers/deezer"
"github.com/markbates/goth/providers/digitalocean"
"github.com/markbates/goth/providers/discord"
"github.com/markbates/goth/providers/dropbox"
"github.com/markbates/goth/providers/eveonline"
"github.com/markbates/goth/providers/facebook"
"github.com/markbates/goth/providers/fitbit"
"github.com/markbates/goth/providers/gitea"
"github.com/markbates/goth/providers/github"
"github.com/markbates/goth/providers/gitlab"
"github.com/markbates/goth/providers/google"
"github.com/markbates/goth/providers/heroku"
"github.com/markbates/goth/providers/influxcloud"
"github.com/markbates/goth/providers/instagram"
"github.com/markbates/goth/providers/intercom"
"github.com/markbates/goth/providers/kakao"
"github.com/markbates/goth/providers/lastfm"
"github.com/markbates/goth/providers/line"
"github.com/markbates/goth/providers/linkedin"
"github.com/markbates/goth/providers/mailru"
"github.com/markbates/goth/providers/meetup"
"github.com/markbates/goth/providers/microsoftonline"
"github.com/markbates/goth/providers/naver"
"github.com/markbates/goth/providers/nextcloud"
"github.com/markbates/goth/providers/onedrive"
"github.com/markbates/goth/providers/oura"
"github.com/markbates/goth/providers/patreon"
"github.com/markbates/goth/providers/paypal"
"github.com/markbates/goth/providers/salesforce"
"github.com/markbates/goth/providers/shopify"
"github.com/markbates/goth/providers/slack"
"github.com/markbates/goth/providers/soundcloud"
"github.com/markbates/goth/providers/spotify"
"github.com/markbates/goth/providers/steam"
"github.com/markbates/goth/providers/strava"
"github.com/markbates/goth/providers/stripe"
"github.com/markbates/goth/providers/tiktok"
"github.com/markbates/goth/providers/tumblr"
"github.com/markbates/goth/providers/twitter"
"github.com/markbates/goth/providers/twitch"
"github.com/markbates/goth/providers/twitterv2"
"github.com/markbates/goth/providers/typetalk"
"github.com/markbates/goth/providers/uber"
"github.com/markbates/goth/providers/wepay"
"github.com/markbates/goth/providers/xero"
"github.com/markbates/goth/providers/yahoo"
"github.com/markbates/goth/providers/yammer"
"github.com/markbates/goth/providers/yandex"
"github.com/markbates/goth/providers/zoom"
"golang.org/x/oauth2"
@ -77,11 +106,41 @@ func NewGothIdProvider(providerType string, clientId string, clientSecret string
Provider: azureadv2.New(clientId, clientSecret, redirectUrl, azureadv2.ProviderOptions{Tenant: "common"}),
Session: &azureadv2.Session{},
}
case "Auth0":
idp = GothIdProvider{
Provider: auth0.New(clientId, clientSecret, redirectUrl, "casdoor.auth0.com"),
Session: &auth0.Session{},
}
case "BattleNet":
idp = GothIdProvider{
Provider: battlenet.New(clientId, clientSecret, redirectUrl),
Session: &battlenet.Session{},
}
case "Bitbucket":
idp = GothIdProvider{
Provider: bitbucket.New(clientId, clientSecret, redirectUrl),
Session: &bitbucket.Session{},
}
case "Box":
idp = GothIdProvider{
Provider: box.New(clientId, clientSecret, redirectUrl),
Session: &box.Session{},
}
case "CloudFoundry":
idp = GothIdProvider{
Provider: cloudfoundry.New("", clientId, clientSecret, redirectUrl),
Session: &cloudfoundry.Session{},
}
case "Dailymotion":
idp = GothIdProvider{
Provider: dailymotion.New(clientId, clientSecret, redirectUrl),
Session: &dailymotion.Session{},
}
case "Deezer":
idp = GothIdProvider{
Provider: deezer.New(clientId, clientSecret, redirectUrl),
Session: &deezer.Session{},
}
case "DigitalOcean":
idp = GothIdProvider{
Provider: digitalocean.New(clientId, clientSecret, redirectUrl),
@ -97,6 +156,16 @@ func NewGothIdProvider(providerType string, clientId string, clientSecret string
Provider: dropbox.New(clientId, clientSecret, redirectUrl),
Session: &dropbox.Session{},
}
case "EveOnline":
idp = GothIdProvider{
Provider: eveonline.New(clientId, clientSecret, redirectUrl),
Session: &eveonline.Session{},
}
case "Fitbit":
idp = GothIdProvider{
Provider: fitbit.New(clientId, clientSecret, redirectUrl),
Session: &fitbit.Session{},
}
case "Facebook":
idp = GothIdProvider{
Provider: facebook.New(clientId, clientSecret, redirectUrl),
@ -127,16 +196,31 @@ func NewGothIdProvider(providerType string, clientId string, clientSecret string
Provider: heroku.New(clientId, clientSecret, redirectUrl),
Session: &heroku.Session{},
}
case "InfluxCloud":
idp = GothIdProvider{
Provider: influxcloud.New(clientId, clientSecret, redirectUrl),
Session: &influxcloud.Session{},
}
case "Instagram":
idp = GothIdProvider{
Provider: instagram.New(clientId, clientSecret, redirectUrl),
Session: &instagram.Session{},
}
case "Intercom":
idp = GothIdProvider{
Provider: intercom.New(clientId, clientSecret, redirectUrl),
Session: &intercom.Session{},
}
case "Kakao":
idp = GothIdProvider{
Provider: kakao.New(clientId, clientSecret, redirectUrl),
Session: &kakao.Session{},
}
case "Lastfm":
idp = GothIdProvider{
Provider: lastfm.New(clientId, clientSecret, redirectUrl),
Session: &lastfm.Session{},
}
case "Linkedin":
idp = GothIdProvider{
Provider: linkedin.New(clientId, clientSecret, redirectUrl),
@ -147,11 +231,46 @@ func NewGothIdProvider(providerType string, clientId string, clientSecret string
Provider: line.New(clientId, clientSecret, redirectUrl),
Session: &line.Session{},
}
case "Mailru":
idp = GothIdProvider{
Provider: mailru.New(clientId, clientSecret, redirectUrl),
Session: &mailru.Session{},
}
case "Meetup":
idp = GothIdProvider{
Provider: meetup.New(clientId, clientSecret, redirectUrl),
Session: &meetup.Session{},
}
case "MicrosoftOnline":
idp = GothIdProvider{
Provider: microsoftonline.New(clientId, clientSecret, redirectUrl),
Session: &microsoftonline.Session{},
}
case "Naver":
idp = GothIdProvider{
Provider: naver.New(clientId, clientSecret, redirectUrl),
Session: &naver.Session{},
}
case "Nextcloud":
idp = GothIdProvider{
Provider: nextcloud.New(clientId, clientSecret, redirectUrl),
Session: &nextcloud.Session{},
}
case "OneDrive":
idp = GothIdProvider{
Provider: onedrive.New(clientId, clientSecret, redirectUrl),
Session: &onedrive.Session{},
}
case "Oura":
idp = GothIdProvider{
Provider: oura.New(clientId, clientSecret, redirectUrl),
Session: &oura.Session{},
}
case "Patreon":
idp = GothIdProvider{
Provider: patreon.New(clientId, clientSecret, redirectUrl),
Session: &patreon.Session{},
}
case "Paypal":
idp = GothIdProvider{
Provider: paypal.New(clientId, clientSecret, redirectUrl),
@ -172,26 +291,81 @@ func NewGothIdProvider(providerType string, clientId string, clientSecret string
Provider: slack.New(clientId, clientSecret, redirectUrl),
Session: &slack.Session{},
}
case "Soundcloud":
idp = GothIdProvider{
Provider: soundcloud.New(clientId, clientSecret, redirectUrl),
Session: &soundcloud.Session{},
}
case "Spotify":
idp = GothIdProvider{
Provider: spotify.New(clientId, clientSecret, redirectUrl),
Session: &spotify.Session{},
}
case "Steam":
idp = GothIdProvider{
Provider: steam.New(clientSecret, redirectUrl),
Session: &steam.Session{},
}
case "Strava":
idp = GothIdProvider{
Provider: strava.New(clientId, clientSecret, redirectUrl),
Session: &strava.Session{},
}
case "Stripe":
idp = GothIdProvider{
Provider: stripe.New(clientId, clientSecret, redirectUrl),
Session: &stripe.Session{},
}
case "TikTok":
idp = GothIdProvider{
Provider: tiktok.New(clientId, clientSecret, redirectUrl),
Session: &tiktok.Session{},
}
case "Tumblr":
idp = GothIdProvider{
Provider: tumblr.New(clientId, clientSecret, redirectUrl),
Session: &tumblr.Session{},
}
case "Twitch":
idp = GothIdProvider{
Provider: twitch.New(clientId, clientSecret, redirectUrl),
Session: &twitch.Session{},
}
case "Twitter":
idp = GothIdProvider{
Provider: twitter.New(clientId, clientSecret, redirectUrl),
Session: &twitter.Session{},
Provider: twitterv2.New(clientId, clientSecret, redirectUrl),
Session: &twitterv2.Session{},
}
case "Typetalk":
idp = GothIdProvider{
Provider: typetalk.New(clientId, clientSecret, redirectUrl),
Session: &typetalk.Session{},
}
case "Uber":
idp = GothIdProvider{
Provider: uber.New(clientId, clientSecret, redirectUrl),
Session: &uber.Session{},
}
case "Wepay":
idp = GothIdProvider{
Provider: wepay.New(clientId, clientSecret, redirectUrl),
Session: &wepay.Session{},
}
case "Xero":
idp = GothIdProvider{
Provider: xero.New(clientId, clientSecret, redirectUrl),
Session: &xero.Session{},
}
case "Yahoo":
idp = GothIdProvider{
Provider: yahoo.New(clientId, clientSecret, redirectUrl),
Session: &yahoo.Session{},
}
case "Yammer":
idp = GothIdProvider{
Provider: yammer.New(clientId, clientSecret, redirectUrl),
Session: &yammer.Session{},
}
case "Yandex":
idp = GothIdProvider{
Provider: yandex.New(clientId, clientSecret, redirectUrl),
@ -232,6 +406,9 @@ func (idp *GothIdProvider) GetToken(code string) (*oauth2.Token, error) {
// to call the function to obtain accessToken
value = url.Values{}
value.Add("code", code)
if idp.Provider.Name() == "twitterv2" || idp.Provider.Name() == "fitbit" {
value.Add("oauth_verifier", "casdoor-verifier")
}
}
accessToken, err := idp.Session.Authorize(idp.Provider, value)
if err != nil {

View File

@ -98,7 +98,61 @@ func GetIdProvider(typ string, subType string, clientId string, clientSecret str
return nil
}
var gothList = []string{"Apple", "AzureAD", "Slack", "Steam", "Line"}
var gothList = []string{
"Apple",
"AzureAD",
"Slack",
"Steam",
"Line",
"Amazon",
"Auth0",
"BattleNet",
"Bitbucket",
"Box",
"CloudFoundry",
"Dailymotion",
"Deezer",
"DigitalOcean",
"Discord",
"Dropbox",
"EveOnline",
"Fitbit",
"Gitea",
"Heroku",
"InfluxCloud",
"Instagram",
"Intercom",
"Kakao",
"Lastfm",
"Mailru",
"Meetup",
"MicrosoftOnline",
"Naver",
"Nextcloud",
"OneDrive",
"Oura",
"Patreon",
"Paypal",
"SalesForce",
"Shopify",
"Soundcloud",
"Spotify",
"Strava",
"Stripe",
"TikTok",
"Tumblr",
"Twitch",
"Twitter",
"Typetalk",
"Uber",
"VK",
"Wepay",
"Xero",
"Yahoo",
"Yammer",
"Yandex",
"Zoom",
}
func isGothSupport(provider string) bool {
for _, value := range gothList {

View File

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

View File

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

View File

@ -19,16 +19,15 @@ import (
"runtime"
"github.com/beego/beego"
xormadapter "github.com/casbin/xorm-adapter/v3"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/util"
xormadapter "github.com/casdoor/xorm-adapter/v3"
_ "github.com/denisenkom/go-mssqldb" // db = mssql
_ "github.com/go-sql-driver/mysql" // db = mysql
_ "github.com/lib/pq" // db = postgres
_ "modernc.org/sqlite" // db = sqlite
"xorm.io/core"
"xorm.io/xorm"
"xorm.io/xorm/migrate"
"github.com/xorm-io/core"
"github.com/xorm-io/xorm"
_ "modernc.org/sqlite" // db = sqlite
)
var adapter *Adapter
@ -41,12 +40,16 @@ func InitConfig() {
beego.BConfig.WebConfig.Session.SessionOn = true
InitAdapter(true)
initMigrations()
InitAdapter()
DoMigration()
CreateTables(true)
}
func InitAdapter(createDatabase bool) {
func InitAdapter() {
adapter = NewAdapter(conf.GetConfigString("driverName"), conf.GetConfigDataSourceName(), conf.GetConfigString("dbName"))
}
func CreateTables(createDatabase bool) {
if createDatabase {
adapter.CreateDatabase()
}
@ -252,22 +255,3 @@ func GetSession(owner string, offset, limit int, field, value, sortField, sortOr
}
return session
}
func initMigrations() {
migrations := []*migrate.Migration{
{
ID: "20221015CasbinRule--fill ptype field with p",
Migrate: func(tx *xorm.Engine) error {
_, err := tx.Cols("ptype").Update(&xormadapter.CasbinRule{
Ptype: "p",
})
return err
},
Rollback: func(tx *xorm.Engine) error {
return tx.DropTables(&xormadapter.CasbinRule{})
},
},
}
m := migrate.New(adapter.Engine, migrate.DefaultOptions, migrations)
m.Migrate()
}

View File

@ -21,7 +21,7 @@ import (
"github.com/casdoor/casdoor/idp"
"github.com/casdoor/casdoor/util"
"xorm.io/core"
"github.com/xorm-io/core"
)
type SignupItem struct {
@ -57,23 +57,24 @@ type Application struct {
GrantTypes []string `xorm:"varchar(1000)" json:"grantTypes"`
OrganizationObj *Organization `xorm:"-" json:"organizationObj"`
ClientId string `xorm:"varchar(100)" json:"clientId"`
ClientSecret string `xorm:"varchar(100)" json:"clientSecret"`
RedirectUris []string `xorm:"varchar(1000)" json:"redirectUris"`
TokenFormat string `xorm:"varchar(100)" json:"tokenFormat"`
ExpireInHours int `json:"expireInHours"`
RefreshExpireInHours int `json:"refreshExpireInHours"`
SignupUrl string `xorm:"varchar(200)" json:"signupUrl"`
SigninUrl string `xorm:"varchar(200)" json:"signinUrl"`
ForgetUrl string `xorm:"varchar(200)" json:"forgetUrl"`
AffiliationUrl string `xorm:"varchar(100)" json:"affiliationUrl"`
TermsOfUse string `xorm:"varchar(100)" json:"termsOfUse"`
SignupHtml string `xorm:"mediumtext" json:"signupHtml"`
SigninHtml string `xorm:"mediumtext" json:"signinHtml"`
FormCss string `xorm:"text" json:"formCss"`
FormOffset int `json:"formOffset"`
FormSideHtml string `xorm:"mediumtext" json:"formSideHtml"`
FormBackgroundUrl string `xorm:"varchar(200)" json:"formBackgroundUrl"`
ClientId string `xorm:"varchar(100)" json:"clientId"`
ClientSecret string `xorm:"varchar(100)" json:"clientSecret"`
RedirectUris []string `xorm:"varchar(1000)" json:"redirectUris"`
TokenFormat string `xorm:"varchar(100)" json:"tokenFormat"`
ExpireInHours int `json:"expireInHours"`
RefreshExpireInHours int `json:"refreshExpireInHours"`
SignupUrl string `xorm:"varchar(200)" json:"signupUrl"`
SigninUrl string `xorm:"varchar(200)" json:"signinUrl"`
ForgetUrl string `xorm:"varchar(200)" json:"forgetUrl"`
AffiliationUrl string `xorm:"varchar(100)" json:"affiliationUrl"`
TermsOfUse string `xorm:"varchar(100)" json:"termsOfUse"`
SignupHtml string `xorm:"mediumtext" json:"signupHtml"`
SigninHtml string `xorm:"mediumtext" json:"signinHtml"`
ThemeData *ThemeData `xorm:"json" json:"themeData"`
FormCss string `xorm:"text" json:"formCss"`
FormOffset int `json:"formOffset"`
FormSideHtml string `xorm:"mediumtext" json:"formSideHtml"`
FormBackgroundUrl string `xorm:"varchar(200)" json:"formBackgroundUrl"`
}
func GetApplicationCount(owner, field, value string) int {

View File

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

View File

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

View File

@ -42,7 +42,7 @@ func init() {
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 {
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) {
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")
}
}

View File

@ -19,7 +19,7 @@ package object
import (
"crypto/tls"
"github.com/go-gomail/gomail"
"github.com/casdoor/gomail/v2"
)
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.SetBody("text/html", content)
if provider.Type == "Mailtrap" {
message.SkipUsernameCheck = true
}
return dialer.DialAndSend(message)
}

View File

@ -25,8 +25,6 @@ import (
)
func InitDb() {
MigratePermissionRule()
existed := initBuiltInOrganization()
if !existed {
initBuiltInModel()
@ -55,7 +53,7 @@ func initBuiltInOrganization() bool {
WebsiteUrl: "https://example.com",
Favicon: fmt.Sprintf("%s/img/casbin/favicon.ico", conf.GetConfigString("staticBaseUrl")),
PasswordType: "plain",
PhonePrefix: "86",
CountryCodes: []string{"CN"},
DefaultAvatar: fmt.Sprintf("%s/img/casbin.svg", conf.GetConfigString("staticBaseUrl")),
Tags: []string{},
Languages: []string{"en", "zh", "es", "fr", "de", "ja", "ko", "ru"},
@ -70,6 +68,7 @@ func initBuiltInOrganization() bool {
{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: "CountryCode", 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"},
@ -111,6 +110,7 @@ func initBuiltInUser() {
Avatar: fmt.Sprintf("%s/img/casbin.svg", conf.GetConfigString("staticBaseUrl")),
Email: "admin@example.com",
Phone: "12345678910",
CountryCode: "CN",
Address: []string{},
Affiliation: "Example Inc.",
Tag: "staff",

View File

@ -189,6 +189,7 @@ func initDefinedOrganization(organization *Organization) {
{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: "CountryCode", 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"},

View File

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

48
object/migrator.go Normal file
View File

@ -0,0 +1,48 @@
// 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{},
&Migrator_1_245_0_PR_1557{},
// 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

@ -0,0 +1,70 @@
// 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 (
"strings"
"github.com/xorm-io/xorm"
"github.com/xorm-io/xorm/migrate"
)
type Migrator_1_101_0_PR_1083 struct{}
func (*Migrator_1_101_0_PR_1083) IsMigrationNeeded() bool {
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 (*Migrator_1_101_0_PR_1083) DoMigration() *migrate.Migration {
migration := migrate.Migration{
ID: "20230209MigratePermissionRule--Use V5 instead of V1 to store permissionID",
Migrate: func(engine *xorm.Engine) error {
models := []*Model{}
err := engine.Table("model").Find(&models, &Model{})
if err != nil {
panic(err)
}
isHit := false
for _, model := range models {
if strings.Contains(model.ModelText, "permission") {
// update model table
model.ModelText = strings.Replace(model.ModelText, "permission,", "", -1)
UpdateModel(model.GetId(), model)
isHit = true
}
}
if isHit {
// update permission_rule table
sql := "UPDATE `permission_rule`SET V0 = V1, V1 = V2, V2 = V3, V3 = V4, V4 = V5 WHERE V0 IN (SELECT CONCAT(owner, '/', name) AS permission_id FROM `permission`)"
_, err = engine.Exec(sql)
if err != nil {
return err
}
}
return err
},
}
return &migration
}

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

@ -0,0 +1,96 @@
// 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 (
"fmt"
"github.com/casdoor/casdoor/util"
"github.com/nyaruka/phonenumbers"
"github.com/xorm-io/xorm"
"github.com/xorm-io/xorm/migrate"
)
type Migrator_1_245_0_PR_1557 struct{}
func (*Migrator_1_245_0_PR_1557) IsMigrationNeeded() bool {
exist, _ := adapter.Engine.IsTableExist("organization")
if exist {
return true
}
return false
}
func (*Migrator_1_245_0_PR_1557) DoMigration() *migrate.Migration {
migration := migrate.Migration{
ID: "20230215organization--transfer phonePrefix to defaultCountryCode, countryCodes",
Migrate: func(engine *xorm.Engine) error {
err := adapter.Engine.Sync2(new(Organization))
if err != nil {
panic(err)
}
organizations := []*Organization{}
err = engine.Table("organization").Find(&organizations, &Organization{})
if err != nil {
panic(err)
}
for _, organization := range organizations {
organization.AccountItems = []*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"},
}
sql := fmt.Sprintf("select phone_prefix from organization where owner='%s' and name='%s'", organization.Owner, organization.Name)
results, _ := engine.Query(sql)
phonePrefix := util.ParseInt(string(results[0]["phone_prefix"]))
organization.CountryCodes = []string{phonenumbers.GetRegionCodeForCountryCode(phonePrefix)}
UpdateOrganization(util.GetId(organization.Owner, organization.Name), organization)
}
return err
},
}
return &migration
}

View File

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

View File

@ -21,7 +21,7 @@ import (
"github.com/casdoor/casdoor/cred"
"github.com/casdoor/casdoor/i18n"
"github.com/casdoor/casdoor/util"
"xorm.io/core"
"github.com/xorm-io/core"
)
type AccountItem struct {
@ -31,25 +31,34 @@ type AccountItem struct {
ModifyRule string `json:"modifyRule"`
}
type ThemeData struct {
ThemeType string `xorm:"varchar(30)" json:"themeType"`
ColorPrimary string `xorm:"varchar(10)" json:"colorPrimary"`
BorderRadius int `xorm:"int" json:"borderRadius"`
IsCompact bool `xorm:"bool" json:"isCompact"`
IsEnabled bool `xorm:"bool" json:"isEnabled"`
}
type Organization struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
WebsiteUrl string `xorm:"varchar(100)" json:"websiteUrl"`
Favicon string `xorm:"varchar(100)" json:"favicon"`
PasswordType string `xorm:"varchar(100)" json:"passwordType"`
PasswordSalt string `xorm:"varchar(100)" json:"passwordSalt"`
PhonePrefix string `xorm:"varchar(10)" json:"phonePrefix"`
DefaultAvatar string `xorm:"varchar(100)" json:"defaultAvatar"`
DefaultApplication string `xorm:"varchar(100)" json:"defaultApplication"`
Tags []string `xorm:"mediumtext" json:"tags"`
Languages []string `xorm:"varchar(255)" json:"languages"`
MasterPassword string `xorm:"varchar(100)" json:"masterPassword"`
InitScore int `json:"initScore"`
EnableSoftDeletion bool `json:"enableSoftDeletion"`
IsProfilePublic bool `json:"isProfilePublic"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
WebsiteUrl string `xorm:"varchar(100)" json:"websiteUrl"`
Favicon string `xorm:"varchar(100)" json:"favicon"`
PasswordType string `xorm:"varchar(100)" json:"passwordType"`
PasswordSalt string `xorm:"varchar(100)" json:"passwordSalt"`
CountryCodes []string `xorm:"varchar(200)" json:"countryCodes"`
DefaultAvatar string `xorm:"varchar(100)" json:"defaultAvatar"`
DefaultApplication string `xorm:"varchar(100)" json:"defaultApplication"`
Tags []string `xorm:"mediumtext" json:"tags"`
Languages []string `xorm:"varchar(255)" json:"languages"`
ThemeData *ThemeData `xorm:"json" json:"themeData"`
MasterPassword string `xorm:"varchar(100)" json:"masterPassword"`
InitScore int `json:"initScore"`
EnableSoftDeletion bool `json:"enableSoftDeletion"`
IsProfilePublic bool `json:"isProfilePublic"`
AccountItems []*AccountItem `xorm:"varchar(3000)" json:"accountItems"`
}

View File

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

View File

@ -16,10 +16,9 @@ package object
import (
"fmt"
"strings"
"github.com/casdoor/casdoor/util"
"xorm.io/core"
"github.com/xorm-io/core"
)
type Permission struct {
@ -269,33 +268,6 @@ func GetPermissionsBySubmitter(owner string, submitter string) []*Permission {
return permissions
}
func MigratePermissionRule() {
models := []*Model{}
err := adapter.Engine.Find(&models, &Model{})
if err != nil {
panic(err)
}
isHit := false
for _, model := range models {
if strings.Contains(model.ModelText, "permission") {
// update model table
model.ModelText = strings.Replace(model.ModelText, "permission,", "", -1)
UpdateModel(model.GetId(), model)
isHit = true
}
}
if isHit {
// update permission_rule table
sql := "UPDATE `permission_rule`SET V0 = V1, V1 = V2, V2 = V3, V3 = V4, V4 = V5 WHERE V0 IN (SELECT CONCAT(owner, '/', name) AS permission_id FROM `permission`)"
_, err = adapter.Engine.Exec(sql)
if err != nil {
return
}
}
}
func ContainsAsterisk(userId string, users []string) bool {
containsAsterisk := false
group, _ := util.GetOwnerAndNameFromId(userId)

View File

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

View File

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

View File

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

View File

@ -18,12 +18,12 @@ import (
"fmt"
"github.com/casdoor/casdoor/util"
"xorm.io/core"
"github.com/xorm-io/core"
)
type Resource struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"`
Name string `xorm:"varchar(180) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
User string `xorm:"varchar(100)" json:"user"`

View File

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

View File

@ -15,84 +15,27 @@
package object
import (
"fmt"
"github.com/beego/beego"
"github.com/casdoor/casdoor/util"
"xorm.io/core"
"github.com/xorm-io/core"
)
var (
CasdoorApplication = "app-built-in"
CasdoorOrganization = "built-in"
)
type Session struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
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"`
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 {
sessions := []*Session{}
var err error
@ -128,3 +71,131 @@ func GetSessionCount(owner, field, value string) int {
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
import "github.com/casdoor/go-sms-sender"
import (
"strings"
"github.com/casdoor/go-sms-sender"
)
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)
@ -25,6 +29,12 @@ func SendSms(provider *Provider, content string, phoneNumbers ...string) error {
return err
}
if provider.Type == go_sms_sender.Aliyun {
for i, number := range phoneNumbers {
phoneNumbers[i] = strings.TrimPrefix(number, "+")
}
}
params := map[string]string{}
if provider.Type == go_sms_sender.TencentCloud {
params["0"] = content

View File

@ -18,6 +18,7 @@ import (
"bytes"
"fmt"
"net/url"
"path/filepath"
"strings"
"github.com/casdoor/casdoor/conf"
@ -54,6 +55,25 @@ func escapePath(path string) string {
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) {
escapedPath := util.UrlJoin(provider.PathPrefix, escapePath(fullFilePath))
objectKey := util.UrlJoin(util.GetUrlPath(provider.Domain), escapedPath)
@ -74,10 +94,15 @@ func GetUploadFileUrl(provider *Provider, fullFilePath string, hasTimestamp bool
}
fileUrl := util.UrlJoin(host, escapePath(objectKey))
if hasTimestamp {
fileUrl = fmt.Sprintf("%s?t=%s", fileUrl, util.GetCurrentUnixTime())
}
if provider.Type == "Tencent Cloud COS" {
objectKey = escapePath(objectKey)
}
return fileUrl, objectKey
}

View File

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

View File

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

View File

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

View File

@ -174,6 +174,7 @@ func getUserWithoutThirdIdp(user *User) *UserWithoutThirdIdp {
LastSigninWrongTime: user.LastSigninWrongTime,
SigninWrongTimes: user.SigninWrongTimes,
}
return res
}
@ -200,12 +201,32 @@ func getClaimsWithoutThirdIdp(claims Claims) ClaimsWithoutThirdIdp {
return res
}
func refineUser(user *User) *User {
user.Password = ""
if user.Address == nil {
user.Address = []string{}
}
if user.Properties == nil {
user.Properties = map[string]string{}
}
if user.Roles == nil {
user.Roles = []*Role{}
}
if user.Permissions == nil {
user.Permissions = []*Permission{}
}
return user
}
func generateJwtToken(application *Application, user *User, nonce string, scope string, host string) (string, string, string, error) {
nowTime := time.Now()
expireTime := nowTime.Add(time.Duration(application.ExpireInHours) * time.Hour)
refreshExpireTime := nowTime.Add(time.Duration(application.RefreshExpireInHours) * time.Hour)
user.Password = ""
user = refineUser(user)
_, originBackend := getOriginFromHost(host)
name := util.GenerateId()
@ -244,8 +265,8 @@ func generateJwtToken(application *Application, user *User, nonce string, scope
claimsWithoutThirdIdp := getClaimsWithoutThirdIdp(claims)
token = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsWithoutThirdIdp)
claims.ExpiresAt = jwt.NewNumericDate(refreshExpireTime)
claims.TokenType = "refresh-token"
claimsWithoutThirdIdp.ExpiresAt = jwt.NewNumericDate(refreshExpireTime)
claimsWithoutThirdIdp.TokenType = "refresh-token"
refreshToken = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsWithoutThirdIdp)
}

View File

@ -21,7 +21,7 @@ import (
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/util"
"github.com/duo-labs/webauthn/webauthn"
"xorm.io/core"
"github.com/xorm-io/core"
)
const (
@ -46,7 +46,8 @@ type User struct {
PermanentAvatar string `xorm:"varchar(500)" json:"permanentAvatar"`
Email string `xorm:"varchar(100) index" json:"email"`
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"`
Address []string `json:"address"`
Affiliation string `xorm:"varchar(100)" json:"affiliation"`
@ -78,32 +79,80 @@ type User struct {
LastSigninTime string `xorm:"varchar(100)" json:"lastSigninTime"`
LastSigninIp string `xorm:"varchar(100)" json:"lastSigninIp"`
GitHub string `xorm:"github varchar(100)" json:"github"`
Google string `xorm:"varchar(100)" json:"google"`
QQ string `xorm:"qq varchar(100)" json:"qq"`
WeChat string `xorm:"wechat varchar(100)" json:"wechat"`
Facebook string `xorm:"facebook varchar(100)" json:"facebook"`
DingTalk string `xorm:"dingtalk varchar(100)" json:"dingtalk"`
Weibo string `xorm:"weibo varchar(100)" json:"weibo"`
Gitee string `xorm:"gitee varchar(100)" json:"gitee"`
LinkedIn string `xorm:"linkedin varchar(100)" json:"linkedin"`
Wecom string `xorm:"wecom varchar(100)" json:"wecom"`
Lark string `xorm:"lark varchar(100)" json:"lark"`
Gitlab string `xorm:"gitlab varchar(100)" json:"gitlab"`
Adfs string `xorm:"adfs varchar(100)" json:"adfs"`
Baidu string `xorm:"baidu varchar(100)" json:"baidu"`
Alipay string `xorm:"alipay varchar(100)" json:"alipay"`
Casdoor string `xorm:"casdoor varchar(100)" json:"casdoor"`
Infoflow string `xorm:"infoflow varchar(100)" json:"infoflow"`
Apple string `xorm:"apple varchar(100)" json:"apple"`
AzureAD string `xorm:"azuread varchar(100)" json:"azuread"`
Slack string `xorm:"slack varchar(100)" json:"slack"`
Steam string `xorm:"steam varchar(100)" json:"steam"`
Bilibili string `xorm:"bilibili varchar(100)" json:"bilibili"`
Okta string `xorm:"okta varchar(100)" json:"okta"`
Douyin string `xorm:"douyin varchar(100)" json:"douyin"`
Line string `xorm:"line varchar(100)" json:"line"`
Custom string `xorm:"custom varchar(100)" json:"custom"`
GitHub string `xorm:"github varchar(100)" json:"github"`
Google string `xorm:"varchar(100)" json:"google"`
QQ string `xorm:"qq varchar(100)" json:"qq"`
WeChat string `xorm:"wechat varchar(100)" json:"wechat"`
Facebook string `xorm:"facebook varchar(100)" json:"facebook"`
DingTalk string `xorm:"dingtalk varchar(100)" json:"dingtalk"`
Weibo string `xorm:"weibo varchar(100)" json:"weibo"`
Gitee string `xorm:"gitee varchar(100)" json:"gitee"`
LinkedIn string `xorm:"linkedin varchar(100)" json:"linkedin"`
Wecom string `xorm:"wecom varchar(100)" json:"wecom"`
Lark string `xorm:"lark varchar(100)" json:"lark"`
Gitlab string `xorm:"gitlab varchar(100)" json:"gitlab"`
Adfs string `xorm:"adfs varchar(100)" json:"adfs"`
Baidu string `xorm:"baidu varchar(100)" json:"baidu"`
Alipay string `xorm:"alipay varchar(100)" json:"alipay"`
Casdoor string `xorm:"casdoor varchar(100)" json:"casdoor"`
Infoflow string `xorm:"infoflow varchar(100)" json:"infoflow"`
Apple string `xorm:"apple varchar(100)" json:"apple"`
AzureAD string `xorm:"azuread varchar(100)" json:"azuread"`
Slack string `xorm:"slack varchar(100)" json:"slack"`
Steam string `xorm:"steam varchar(100)" json:"steam"`
Bilibili string `xorm:"bilibili varchar(100)" json:"bilibili"`
Okta string `xorm:"okta varchar(100)" json:"okta"`
Douyin string `xorm:"douyin varchar(100)" json:"douyin"`
Line string `xorm:"line varchar(100)" json:"line"`
Amazon string `xorm:"amazon varchar(100)" json:"amazon"`
Auth0 string `xorm:"auth0 varchar(100)" json:"auth0"`
BattleNet string `xorm:"battlenet varchar(100)" json:"battlenet"`
Bitbucket string `xorm:"bitbucket varchar(100)" json:"bitbucket"`
Box string `xorm:"box varchar(100)" json:"box"`
CloudFoundry string `xorm:"cloudfoundry varchar(100)" json:"cloudfoundry"`
Dailymotion string `xorm:"dailymotion varchar(100)" json:"dailymotion"`
Deezer string `xorm:"deezer varchar(100)" json:"deezer"`
DigitalOcean string `xorm:"digitalocean varchar(100)" json:"digitalocean"`
Discord string `xorm:"discord varchar(100)" json:"discord"`
Dropbox string `xorm:"dropbox varchar(100)" json:"dropbox"`
EveOnline string `xorm:"eveonline varchar(100)" json:"eveonline"`
Fitbit string `xorm:"fitbit varchar(100)" json:"fitbit"`
Gitea string `xorm:"gitea varchar(100)" json:"gitea"`
Heroku string `xorm:"heroku varchar(100)" json:"heroku"`
InfluxCloud string `xorm:"influxcloud varchar(100)" json:"influxcloud"`
Instagram string `xorm:"instagram varchar(100)" json:"instagram"`
Intercom string `xorm:"intercom varchar(100)" json:"intercom"`
Kakao string `xorm:"kakao varchar(100)" json:"kakao"`
Lastfm string `xorm:"lastfm varchar(100)" json:"lastfm"`
Mailru string `xorm:"mailru varchar(100)" json:"mailru"`
Meetup string `xorm:"meetup varchar(100)" json:"meetup"`
MicrosoftOnline string `xorm:"microsoftonline varchar(100)" json:"microsoftonline"`
Naver string `xorm:"naver varchar(100)" json:"naver"`
Nextcloud string `xorm:"nextcloud varchar(100)" json:"nextcloud"`
OneDrive string `xorm:"onedrive varchar(100)" json:"onedrive"`
Oura string `xorm:"oura varchar(100)" json:"oura"`
Patreon string `xorm:"patreon varchar(100)" json:"patreon"`
Paypal string `xorm:"paypal varchar(100)" json:"paypal"`
SalesForce string `xorm:"salesforce varchar(100)" json:"salesforce"`
Shopify string `xorm:"shopify varchar(100)" json:"shopify"`
Soundcloud string `xorm:"soundcloud varchar(100)" json:"soundcloud"`
Spotify string `xorm:"spotify varchar(100)" json:"spotify"`
Strava string `xorm:"strava varchar(100)" json:"strava"`
Stripe string `xorm:"stripe varchar(100)" json:"stripe"`
TikTok string `xorm:"tiktok varchar(100)" json:"tiktok"`
Tumblr string `xorm:"tumblr varchar(100)" json:"tumblr"`
Twitch string `xorm:"twitch varchar(100)" json:"twitch"`
Twitter string `xorm:"twitter varchar(100)" json:"twitter"`
Typetalk string `xorm:"typetalk varchar(100)" json:"typetalk"`
Uber string `xorm:"uber varchar(100)" json:"uber"`
VK string `xorm:"vk varchar(100)" json:"vk"`
Wepay string `xorm:"wepay varchar(100)" json:"wepay"`
Xero string `xorm:"xero varchar(100)" json:"xero"`
Yahoo string `xorm:"yahoo varchar(100)" json:"yahoo"`
Yammer string `xorm:"yammer varchar(100)" json:"yammer"`
Yandex string `xorm:"yandex varchar(100)" json:"yandex"`
Zoom string `xorm:"zoom varchar(100)" json:"zoom"`
Custom string `xorm:"custom varchar(100)" json:"custom"`
WebauthnCredentials []webauthn.Credential `xorm:"webauthnCredentials blob" json:"webauthnCredentials"`
@ -406,7 +455,7 @@ func UpdateUser(id string, user *User, columns []string, isGlobalAdmin bool) boo
}
}
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)
@ -530,7 +579,7 @@ func AddUsersInBatch(users []*User) bool {
func DeleteUser(user *User) bool {
// 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{})
if err != nil {

View File

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

View File

@ -20,7 +20,7 @@ import (
"strings"
"github.com/casdoor/casdoor/idp"
"xorm.io/core"
"github.com/xorm-io/core"
)
func GetUserByField(organizationName string, field string, value string) *User {
@ -170,3 +170,18 @@ func ClearUserOAuthProperties(user *User, providerType string) bool {
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/i18n"
"github.com/casdoor/casdoor/util"
"xorm.io/core"
"github.com/xorm-io/core"
)
const (
@ -122,11 +122,8 @@ func AddToVerificationRecord(user *User, provider *Provider, remoteAddr, recordT
record.Owner = provider.Owner
record.Name = util.GenerateId()
record.CreatedTime = util.GetCurrentTime()
if user != nil {
record.User = user.GetId()
}
record.Provider = provider.Name
record.Provider = provider.Name
record.Receiver = dest
record.Code = code
record.Time = time.Now().Unix()

View File

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

View File

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

View File

@ -19,6 +19,8 @@ import (
"strings"
"github.com/beego/beego/context"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/i18n"
"github.com/casdoor/casdoor/object"
"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) {
responseError(ctx, "Unauthorized operation")
responseError(ctx, T(ctx, "auth:Unauthorized operation"))
}
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-ldap-user", &controllers.ApiController{}, "POST:GetLdapUser")
beego.Router("/api/get-ldaps", &controllers.ApiController{}, "POST:GetLdaps")
beego.Router("/api/get-ldap", &controllers.ApiController{}, "POST:GetLdap")
beego.Router("/api/get-ldaps", &controllers.ApiController{}, "GET:GetLdaps")
beego.Router("/api/get-ldap", &controllers.ApiController{}, "GET:GetLdap")
beego.Router("/api/add-ldap", &controllers.ApiController{}, "POST:AddLdap")
beego.Router("/api/update-ldap", &controllers.ApiController{}, "POST:UpdateLdap")
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/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/is-session-duplicated", &controllers.ApiController{}, "GET:IsSessionDuplicated")
beego.Router("/api/get-webhooks", &controllers.ApiController{}, "GET:GetWebhooks")
beego.Router("/api/get-webhook", &controllers.ApiController{}, "GET:GetWebhook")

View File

@ -578,7 +578,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the product",
"description": "The id ( owner/name ) of the product",
"required": true,
"type": "string"
},
@ -894,8 +894,8 @@
"parameters": [
{
"in": "query",
"name": "ID",
"description": "The ID(owner/name) of user.",
"name": "id",
"description": "The id ( owner/name )(owner/name) of user.",
"required": true,
"type": "string"
}
@ -1107,7 +1107,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the application.",
"description": "The id ( owner/name ) of the application.",
"required": true,
"type": "string"
}
@ -1162,7 +1162,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the cert",
"description": "The id ( owner/name ) of the cert",
"required": true,
"type": "string"
}
@ -1340,7 +1340,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the model",
"description": "The id ( owner/name ) of the model",
"required": true,
"type": "string"
}
@ -1479,7 +1479,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the payment",
"description": "The id ( owner/name ) of the payment",
"required": true,
"type": "string"
}
@ -1534,7 +1534,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the permission",
"description": "The id ( owner/name ) of the permission",
"required": true,
"type": "string"
}
@ -1589,7 +1589,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the role",
"description": "The id ( owner/name ) of the role",
"required": true,
"type": "string"
}
@ -1638,7 +1638,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the product",
"description": "The id ( owner/name ) of the product",
"required": true,
"type": "string"
}
@ -1693,7 +1693,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the provider",
"description": "The id ( owner/name ) of the provider",
"required": true,
"type": "string"
}
@ -1840,7 +1840,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the role",
"description": "The id ( owner/name ) of the role",
"required": true,
"type": "string"
}
@ -1966,7 +1966,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the syncer",
"description": "The id ( owner/name ) of the syncer",
"required": true,
"type": "string"
}
@ -2021,7 +2021,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the user",
"description": "The id ( owner/name ) of the user",
"required": true,
"type": "string"
}
@ -2047,7 +2047,7 @@
{
"in": "query",
"name": "id",
"description": "The id of token",
"description": "The id ( owner/name ) of token",
"required": true,
"type": "string"
}
@ -2116,7 +2116,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the user",
"description": "The id ( owner/name ) of the user",
"required": true,
"type": "string"
},
@ -2160,7 +2160,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the user",
"description": "The id ( owner/name ) of the user",
"required": true,
"type": "string"
}
@ -2286,7 +2286,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the webhook",
"description": "The id ( owner/name ) of the webhook",
"required": true,
"type": "string"
}
@ -2341,7 +2341,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the payment",
"description": "The id ( owner/name ) of the payment",
"required": true,
"type": "string"
}
@ -2504,8 +2504,8 @@
"parameters": [
{
"in": "query",
"name": "user_id",
"description": "The id of user",
"name": "id",
"description": "The id ( owner/name ) of user",
"required": true,
"type": "string"
},
@ -2904,7 +2904,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the application",
"description": "The id ( owner/name ) of the application",
"required": true,
"type": "string"
},
@ -2939,7 +2939,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the cert",
"description": "The id ( owner/name ) of the cert",
"required": true,
"type": "string"
},
@ -2982,7 +2982,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the model",
"description": "The id ( owner/name ) of the model",
"required": true,
"type": "string"
},
@ -3017,7 +3017,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the organization",
"description": "The id ( owner/name ) of the organization",
"required": true,
"type": "string"
},
@ -3052,7 +3052,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the payment",
"description": "The id ( owner/name ) of the payment",
"required": true,
"type": "string"
},
@ -3087,7 +3087,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the permission",
"description": "The id ( owner/name ) of the permission",
"required": true,
"type": "string"
},
@ -3122,7 +3122,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the product",
"description": "The id ( owner/name ) of the product",
"required": true,
"type": "string"
},
@ -3157,7 +3157,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the provider",
"description": "The id ( owner/name ) of the provider",
"required": true,
"type": "string"
},
@ -3200,7 +3200,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the role",
"description": "The id ( owner/name ) of the role",
"required": true,
"type": "string"
},
@ -3235,7 +3235,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the syncer",
"description": "The id ( owner/name ) of the syncer",
"required": true,
"type": "string"
},
@ -3270,7 +3270,7 @@
{
"in": "query",
"name": "id",
"description": "The id of token",
"description": "The id ( owner/name ) of token",
"required": true,
"type": "string"
},
@ -3305,7 +3305,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the user",
"description": "The id ( owner/name ) of the user",
"required": true,
"type": "string"
},
@ -3340,7 +3340,7 @@
{
"in": "query",
"name": "id",
"description": "The id of the webhook",
"description": "The id ( owner/name ) of the webhook",
"required": true,
"type": "string"
},
@ -3505,11 +3505,11 @@
}
},
"definitions": {
"2268.0xc0000f9650.false": {
"2346.0xc0001ce990.false": {
"title": "false",
"type": "object"
},
"2302.0xc0000f9680.false": {
"2381.0xc0001ce9c0.false": {
"title": "false",
"type": "object"
},
@ -3636,10 +3636,10 @@
"type": "object",
"properties": {
"data": {
"$ref": "#/definitions/2268.0xc0000f9650.false"
"$ref": "#/definitions/2346.0xc0001ce990.false"
},
"data2": {
"$ref": "#/definitions/2302.0xc0000f9680.false"
"$ref": "#/definitions/2381.0xc0001ce9c0.false"
},
"msg": {
"type": "string"
@ -3846,6 +3846,9 @@
"termsOfUse": {
"type": "string"
},
"themeData": {
"$ref": "#/definitions/object.ThemeData"
},
"tokenFormat": {
"type": "string"
}
@ -4143,6 +4146,9 @@
"type": "string"
}
},
"themeData": {
"$ref": "#/definitions/object.ThemeData"
},
"websiteUrl": {
"type": "string"
}
@ -4727,6 +4733,28 @@
}
}
},
"object.ThemeData": {
"title": "ThemeData",
"type": "object",
"properties": {
"borderRadius": {
"type": "integer",
"format": "int64"
},
"colorPrimary": {
"type": "string"
},
"isCompact": {
"type": "boolean"
},
"isEnabled": {
"type": "boolean"
},
"themeType": {
"type": "string"
}
}
},
"object.Token": {
"title": "Token",
"type": "object",
@ -4836,9 +4864,15 @@
"alipay": {
"type": "string"
},
"amazon": {
"type": "string"
},
"apple": {
"type": "string"
},
"auth0": {
"type": "string"
},
"avatar": {
"type": "string"
},
@ -4848,6 +4882,9 @@
"baidu": {
"type": "string"
},
"battlenet": {
"type": "string"
},
"bilibili": {
"type": "string"
},
@ -4857,9 +4894,18 @@
"birthday": {
"type": "string"
},
"bitbucket": {
"type": "string"
},
"box": {
"type": "string"
},
"casdoor": {
"type": "string"
},
"cloudfoundry": {
"type": "string"
},
"createdIp": {
"type": "string"
},
@ -4869,15 +4915,30 @@
"custom": {
"type": "string"
},
"dailymotion": {
"type": "string"
},
"deezer": {
"type": "string"
},
"digitalocean": {
"type": "string"
},
"dingtalk": {
"type": "string"
},
"discord": {
"type": "string"
},
"displayName": {
"type": "string"
},
"douyin": {
"type": "string"
},
"dropbox": {
"type": "string"
},
"education": {
"type": "string"
},
@ -4887,15 +4948,24 @@
"emailVerified": {
"type": "boolean"
},
"eveonline": {
"type": "string"
},
"facebook": {
"type": "string"
},
"firstName": {
"type": "string"
},
"fitbit": {
"type": "string"
},
"gender": {
"type": "string"
},
"gitea": {
"type": "string"
},
"gitee": {
"type": "string"
},
@ -4911,6 +4981,9 @@
"hash": {
"type": "string"
},
"heroku": {
"type": "string"
},
"homepage": {
"type": "string"
},
@ -4923,9 +4996,18 @@
"idCardType": {
"type": "string"
},
"influxcloud": {
"type": "string"
},
"infoflow": {
"type": "string"
},
"instagram": {
"type": "string"
},
"intercom": {
"type": "string"
},
"isAdmin": {
"type": "boolean"
},
@ -4944,6 +5026,9 @@
"isOnline": {
"type": "boolean"
},
"kakao": {
"type": "string"
},
"karma": {
"type": "integer",
"format": "int64"
@ -4966,6 +5051,9 @@
"lastSigninWrongTime": {
"type": "string"
},
"lastfm": {
"type": "string"
},
"ldap": {
"type": "string"
},
@ -4978,18 +5066,39 @@
"location": {
"type": "string"
},
"mailru": {
"type": "string"
},
"managedAccounts": {
"type": "array",
"items": {
"$ref": "#/definitions/object.ManagedAccount"
}
},
"meetup": {
"type": "string"
},
"microsoftonline": {
"type": "string"
},
"name": {
"type": "string"
},
"naver": {
"type": "string"
},
"nextcloud": {
"type": "string"
},
"okta": {
"type": "string"
},
"onedrive": {
"type": "string"
},
"oura": {
"type": "string"
},
"owner": {
"type": "string"
},
@ -4999,6 +5108,12 @@
"passwordSalt": {
"type": "string"
},
"patreon": {
"type": "string"
},
"paypal": {
"type": "string"
},
"permanentAvatar": {
"type": "string"
},
@ -5035,10 +5150,16 @@
"$ref": "#/definitions/object.Role"
}
},
"salesforce": {
"type": "string"
},
"score": {
"type": "integer",
"format": "int64"
},
"shopify": {
"type": "string"
},
"signinWrongTimes": {
"type": "integer",
"format": "int64"
@ -5049,21 +5170,54 @@
"slack": {
"type": "string"
},
"soundcloud": {
"type": "string"
},
"spotify": {
"type": "string"
},
"steam": {
"type": "string"
},
"strava": {
"type": "string"
},
"stripe": {
"type": "string"
},
"tag": {
"type": "string"
},
"tiktok": {
"type": "string"
},
"title": {
"type": "string"
},
"tumblr": {
"type": "string"
},
"twitch": {
"type": "string"
},
"twitter": {
"type": "string"
},
"type": {
"type": "string"
},
"typetalk": {
"type": "string"
},
"uber": {
"type": "string"
},
"updatedTime": {
"type": "string"
},
"vk": {
"type": "string"
},
"webauthnCredentials": {
"type": "array",
"items": {
@ -5078,6 +5232,24 @@
},
"weibo": {
"type": "string"
},
"wepay": {
"type": "string"
},
"xero": {
"type": "string"
},
"yahoo": {
"type": "string"
},
"yammer": {
"type": "string"
},
"yandex": {
"type": "string"
},
"zoom": {
"type": "string"
}
}
},

View File

@ -375,7 +375,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the product
description: The id ( owner/name ) of the product
required: true
type: string
- in: query
@ -578,8 +578,8 @@ paths:
operationId: ApiController.DeleteSession
parameters:
- in: query
name: ID
description: The ID(owner/name) of user.
name: id
description: The id ( owner/name )(owner/name) of user.
required: true
type: string
responses:
@ -718,7 +718,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the application.
description: The id ( owner/name ) of the application.
required: true
type: string
responses:
@ -754,7 +754,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the cert
description: The id ( owner/name ) of the cert
required: true
type: string
responses:
@ -870,7 +870,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the model
description: The id ( owner/name ) of the model
required: true
type: string
responses:
@ -961,7 +961,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the payment
description: The id ( owner/name ) of the payment
required: true
type: string
responses:
@ -997,7 +997,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the permission
description: The id ( owner/name ) of the permission
required: true
type: string
responses:
@ -1033,7 +1033,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the role
description: The id ( owner/name ) of the role
required: true
type: string
responses:
@ -1065,7 +1065,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the product
description: The id ( owner/name ) of the product
required: true
type: string
responses:
@ -1101,7 +1101,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the provider
description: The id ( owner/name ) of the provider
required: true
type: string
responses:
@ -1197,7 +1197,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the role
description: The id ( owner/name ) of the role
required: true
type: string
responses:
@ -1280,7 +1280,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the syncer
description: The id ( owner/name ) of the syncer
required: true
type: string
responses:
@ -1316,7 +1316,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the user
description: The id ( owner/name ) of the user
required: true
type: string
responses:
@ -1333,7 +1333,7 @@ paths:
parameters:
- in: query
name: id
description: The id of token
description: The id ( owner/name ) of token
required: true
type: string
responses:
@ -1379,7 +1379,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the user
description: The id ( owner/name ) of the user
required: true
type: string
- in: query
@ -1408,7 +1408,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the user
description: The id ( owner/name ) of the user
required: true
type: string
responses:
@ -1491,7 +1491,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the webhook
description: The id ( owner/name ) of the webhook
required: true
type: string
responses:
@ -1527,7 +1527,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the payment
description: The id ( owner/name ) of the payment
required: true
type: string
responses:
@ -1636,8 +1636,8 @@ paths:
operationId: ApiController.GetOAuthCode
parameters:
- in: query
name: user_id
description: The id of user
name: id
description: The id ( owner/name ) of user
required: true
type: string
- in: query
@ -1902,7 +1902,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the application
description: The id ( owner/name ) of the application
required: true
type: string
- in: body
@ -1925,7 +1925,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the cert
description: The id ( owner/name ) of the cert
required: true
type: string
- in: body
@ -1953,7 +1953,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the model
description: The id ( owner/name ) of the model
required: true
type: string
- in: body
@ -1976,7 +1976,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the organization
description: The id ( owner/name ) of the organization
required: true
type: string
- in: body
@ -1999,7 +1999,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the payment
description: The id ( owner/name ) of the payment
required: true
type: string
- in: body
@ -2022,7 +2022,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the permission
description: The id ( owner/name ) of the permission
required: true
type: string
- in: body
@ -2045,7 +2045,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the product
description: The id ( owner/name ) of the product
required: true
type: string
- in: body
@ -2068,7 +2068,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the provider
description: The id ( owner/name ) of the provider
required: true
type: string
- in: body
@ -2096,7 +2096,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the role
description: The id ( owner/name ) of the role
required: true
type: string
- in: body
@ -2119,7 +2119,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the syncer
description: The id ( owner/name ) of the syncer
required: true
type: string
- in: body
@ -2142,7 +2142,7 @@ paths:
parameters:
- in: query
name: id
description: The id of token
description: The id ( owner/name ) of token
required: true
type: string
- in: body
@ -2165,7 +2165,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the user
description: The id ( owner/name ) of the user
required: true
type: string
- in: body
@ -2188,7 +2188,7 @@ paths:
parameters:
- in: query
name: id
description: The id of the webhook
description: The id ( owner/name ) of the webhook
required: true
type: string
- in: body
@ -2293,10 +2293,10 @@ paths:
schema:
$ref: '#/definitions/Response'
definitions:
2268.0xc0000f9650.false:
2346.0xc0001ce990.false:
title: "false"
type: object
2302.0xc0000f9680.false:
2381.0xc0001ce9c0.false:
title: "false"
type: object
Response:
@ -2383,9 +2383,9 @@ definitions:
type: object
properties:
data:
$ref: '#/definitions/2268.0xc0000f9650.false'
$ref: '#/definitions/2346.0xc0001ce990.false'
data2:
$ref: '#/definitions/2302.0xc0000f9680.false'
$ref: '#/definitions/2381.0xc0001ce9c0.false'
msg:
type: string
name:
@ -2524,6 +2524,8 @@ definitions:
type: string
termsOfUse:
type: string
themeData:
$ref: '#/definitions/object.ThemeData'
tokenFormat:
type: string
object.Cert:
@ -2724,6 +2726,8 @@ definitions:
type: array
items:
type: string
themeData:
$ref: '#/definitions/object.ThemeData'
websiteUrl:
type: string
object.Payment:
@ -3115,6 +3119,21 @@ definitions:
type: array
items:
type: string
object.ThemeData:
title: ThemeData
type: object
properties:
borderRadius:
type: integer
format: int64
colorPrimary:
type: string
isCompact:
type: boolean
isEnabled:
type: boolean
themeType:
type: string
object.Token:
title: Token
type: object
@ -3190,46 +3209,74 @@ definitions:
type: string
alipay:
type: string
amazon:
type: string
apple:
type: string
auth0:
type: string
avatar:
type: string
azuread:
type: string
baidu:
type: string
battlenet:
type: string
bilibili:
type: string
bio:
type: string
birthday:
type: string
bitbucket:
type: string
box:
type: string
casdoor:
type: string
cloudfoundry:
type: string
createdIp:
type: string
createdTime:
type: string
custom:
type: string
dailymotion:
type: string
deezer:
type: string
digitalocean:
type: string
dingtalk:
type: string
discord:
type: string
displayName:
type: string
douyin:
type: string
dropbox:
type: string
education:
type: string
email:
type: string
emailVerified:
type: boolean
eveonline:
type: string
facebook:
type: string
firstName:
type: string
fitbit:
type: string
gender:
type: string
gitea:
type: string
gitee:
type: string
github:
@ -3240,6 +3287,8 @@ definitions:
type: string
hash:
type: string
heroku:
type: string
homepage:
type: string
id:
@ -3248,8 +3297,14 @@ definitions:
type: string
idCardType:
type: string
influxcloud:
type: string
infoflow:
type: string
instagram:
type: string
intercom:
type: string
isAdmin:
type: boolean
isDefaultAvatar:
@ -3262,6 +3317,8 @@ definitions:
type: boolean
isOnline:
type: boolean
kakao:
type: string
karma:
type: integer
format: int64
@ -3277,6 +3334,8 @@ definitions:
type: string
lastSigninWrongTime:
type: string
lastfm:
type: string
ldap:
type: string
line:
@ -3285,20 +3344,38 @@ definitions:
type: string
location:
type: string
mailru:
type: string
managedAccounts:
type: array
items:
$ref: '#/definitions/object.ManagedAccount'
meetup:
type: string
microsoftonline:
type: string
name:
type: string
naver:
type: string
nextcloud:
type: string
okta:
type: string
onedrive:
type: string
oura:
type: string
owner:
type: string
password:
type: string
passwordSalt:
type: string
patreon:
type: string
paypal:
type: string
permanentAvatar:
type: string
permissions:
@ -3323,9 +3400,13 @@ definitions:
type: array
items:
$ref: '#/definitions/object.Role'
salesforce:
type: string
score:
type: integer
format: int64
shopify:
type: string
signinWrongTimes:
type: integer
format: int64
@ -3333,16 +3414,38 @@ definitions:
type: string
slack:
type: string
soundcloud:
type: string
spotify:
type: string
steam:
type: string
strava:
type: string
stripe:
type: string
tag:
type: string
tiktok:
type: string
title:
type: string
tumblr:
type: string
twitch:
type: string
twitter:
type: string
type:
type: string
typetalk:
type: string
uber:
type: string
updatedTime:
type: string
vk:
type: string
webauthnCredentials:
type: array
items:
@ -3353,6 +3456,18 @@ definitions:
type: string
weibo:
type: string
wepay:
type: string
xero:
type: string
yahoo:
type: string
yammer:
type: string
yandex:
type: string
zoom:
type: string
object.Userinfo:
title: Userinfo
type: object

View File

@ -14,6 +14,8 @@
package util
import "sort"
func DeleteVal(values []string, val string) []string {
newValues := []string{}
for _, v := range values {
@ -23,3 +25,8 @@ func DeleteVal(values []string, val string) []string {
}
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]
}
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 {
return uuid.NewString()
}
@ -127,12 +136,16 @@ func GetId(owner, name string) string {
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 {
hash := md5.Sum([]byte(text))
return hex.EncodeToString(hash[:])
}
func IsStrsEmpty(strs ...string) bool {
func IsStringsEmpty(strs ...string) bool {
for _, str := range strs {
if len(str) == 0 {
return true
@ -214,7 +227,7 @@ func IsChinese(str string) bool {
}
func GetMaskedPhone(phone string) string {
return getMaskedPhone(phone)
return rePhone.ReplaceAllString(phone, "$1****$2")
}
func GetMaskedEmail(email string) string {

View File

@ -183,7 +183,7 @@ func TestIsStrsEmpty(t *testing.T) {
}
for _, scenery := range scenarios {
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")
})
}

View File

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

View File

@ -31,6 +31,6 @@ func GetCurrentUnixTime() string {
func IsTokenExpired(createdTime string, expiresIn int) bool {
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)
}

View File

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

View File

@ -17,16 +17,13 @@ package util
import (
"net/mail"
"regexp"
"github.com/nyaruka/phonenumbers"
)
var (
rePhoneCn *regexp.Regexp
rePhone *regexp.Regexp
)
var rePhone *regexp.Regexp
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})")
}
@ -35,10 +32,19 @@ func IsEmailValid(email string) bool {
return err == nil
}
func IsPhoneCnValid(phone string) bool {
return rePhoneCn.MatchString(phone)
func IsPhoneValid(phone string, countryCode string) bool {
phoneNumber, err := phonenumbers.Parse(phone, countryCode)
if err != nil {
return false
}
return phonenumbers.IsValidNumber(phoneNumber)
}
func getMaskedPhone(phone string) string {
return rePhone.ReplaceAllString(phone, "$1****$2")
func IsPhoneAllowInRegin(countryCode string, allowRegions []string) bool {
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

@ -1,7 +1,10 @@
module.exports = {
const { defineConfig } = require("cypress");
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
// implement node event listeners here
},
"retries": {
"runMode": 2,
"openMode": 0
}
},
};
});

View File

@ -0,0 +1,16 @@
describe('Test adapter', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
const selector = {
add: ".ant-table-title > div > .ant-btn"
};
it("test adapter", () => {
cy.visit("http://localhost:7001");
cy.visit("http://localhost:7001/adapters");
cy.url().should("eq", "http://localhost:7001/adapters");
cy.get(selector.add).click();
cy.url().should("include","http://localhost:7001/adapters/built-in/")
});
})

View File

@ -0,0 +1,13 @@
describe('Test aplication', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
it("test aplication", () => {
cy.visit("http://localhost:7001");
cy.visit("http://localhost:7001/applications");
cy.url().should("eq", "http://localhost:7001/applications");
cy.visit("http://localhost:7001/applications/built-in/app-built-in");
cy.url().should("eq", "http://localhost:7001/applications/built-in/app-built-in");
});
})

View File

@ -0,0 +1,13 @@
describe('Test certs', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
it("test certs", () => {
cy.visit("http://localhost:7001");
cy.visit("http://localhost:7001/certs");
cy.url().should("eq", "http://localhost:7001/certs");
cy.visit("http://localhost:7001/certs/cert-built-in");
cy.url().should("eq", "http://localhost:7001/certs/cert-built-in");
});
})

View File

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

View File

@ -0,0 +1,13 @@
describe('Test models', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
it("test org", () => {
cy.visit("http://localhost:7001");
cy.visit("http://localhost:7001/models");
cy.url().should("eq", "http://localhost:7001/models");
cy.visit("http://localhost:7001/models/built-in/model-built-in");
cy.url().should("eq", "http://localhost:7001/models/built-in/model-built-in");
});
})

View File

@ -0,0 +1,15 @@
describe('Test Orgnazition', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
it("test org", () => {
cy.visit("http://localhost:7001");
cy.visit("http://localhost:7001/organizations");
cy.url().should("eq", "http://localhost:7001/organizations");
cy.visit("http://localhost:7001/organizations/built-in");
cy.url().should("eq", "http://localhost:7001/organizations/built-in");
cy.visit("http://localhost:7001/organizations/built-in/users");
cy.url().should("eq", "http://localhost:7001/organizations/built-in/users");
});
})

View File

@ -0,0 +1,16 @@
describe('Test payments', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
const selector = {
add: ".ant-table-title > div > .ant-btn"
};
it("test payments", () => {
cy.visit("http://localhost:7001");
cy.visit("http://localhost:7001/payments");
cy.url().should("eq", "http://localhost:7001/payments");
cy.get(selector.add).click();
cy.url().should("include","http://localhost:7001/payments/")
});
})

View File

@ -0,0 +1,13 @@
describe('Test permissions', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
it("test permissions", () => {
cy.visit("http://localhost:7001");
cy.visit("http://localhost:7001/permissions");
cy.url().should("eq", "http://localhost:7001/permissions");
cy.visit("http://localhost:7001/permissions/built-in/permission-built-in");
cy.url().should("eq", "http://localhost:7001/permissions/built-in/permission-built-in");
});
})

View File

@ -0,0 +1,16 @@
describe('Test products', () => {
beforeEach(()=>{
cy.visit("http://localhost:7001");
cy.login();
})
const selector = {
add: ".ant-table-title > div > .ant-btn > span"
};
it("test products", () => {
cy.visit("http://localhost:7001");
cy.visit("http://localhost:7001/products");
cy.url().should("eq", "http://localhost:7001/products");
cy.get(selector.add).click();
cy.url().should("include","http://localhost:7001/products/")
});
})

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