Compare commits

...

75 Commits

Author SHA1 Message Date
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
wht
24a824d394 feat: return the correct error message in the Edit Model (#1504) 2023-01-30 22:19:42 +08:00
75b8357de8 Add properties to UserWithoutThirdIdp 2023-01-29 21:51:01 +08:00
087405dad2 Fix isAllowedInDemoMode() 2023-01-26 17:56:29 +08:00
6a6a1fa920 feat: fix missing phone number prefix in login screen (#1492)
fix: #1489
2023-01-24 23:19:44 +08:00
907d18d2e9 Fix missing roles and permissions in user table 2023-01-23 00:36:55 +08:00
a728e083eb feat: reduce the size of token's user object (#1487)
* fix: Reduce the size of token, especially the user object (#1170)

* fix: Reduce the size of token, especially the user object (#1170)

* fix: Reduce the size of token, especially the user object (#1170)

Co-authored-by: Zayn Xie <84443886+xiaoniuren99@users.noreply.github.com>
2023-01-21 09:30:23 +08:00
457e6208ad feat: terms of use auto selected (#1485) 2023-01-19 20:31:21 +08:00
d10b1347a8 feat: add terms of use in signin page (#1476)
* feat: extract terms of use renderer

* fix: layout

* fix: form styling

* fix: required state

* feat: application terms of use setting

* fix: refactor getTermsOfUseContent

* fix: refactor renderers
2023-01-19 18:39:24 +08:00
f5b7f8cb45 chore(frontend): remove import of the third-party js script (#1436)
Signed-off-by: qwqcode <qwqcode@gmail.com>

Signed-off-by: qwqcode <qwqcode@gmail.com>
2023-01-19 11:31:27 +08:00
5d9b17542f feat: end-user log out (#1356) 2023-01-17 22:57:05 +08:00
0021226a60 fix: check the duplicated Application ClientId (#1481)
* fix: Check the duplicate ClientId and ClientSecret of Application.

* Bug fix
2023-01-17 17:37:20 +08:00
79fc0516dd feat: check username if it's changed (#1482) 2023-01-17 17:08:37 +08:00
a73be11990 feat: update permission when role deleted (#1480) 2023-01-17 17:04:58 +08:00
eddd8acbf4 feat: update permission rule when role updated (#1477) 2023-01-17 10:27:02 +08:00
d0741e3705 feat: fix compatibility issue between Casbin request and model (#1478) 2023-01-15 12:06:10 +08:00
Liu
c66561dc9a feat: support sqlite database without cgo by using the modernc.org/sqlite driver (#1474)
* Refactor: update sqlite go driver to modernc.org/sqlite without cgo

* fix: update sqlite driver to modernc.org/sqlite

* fix: sqlite driver to modernc.org/sqlite

* Update adapter.go

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2023-01-14 20:11:23 +08:00
fcdf1e8dd2 feat: improve Select component performance (#1472) 2023-01-12 23:11:11 +08:00
6d4f94986e feat: fix the bug that "app - global" admin is not allowed to update user (#1468) 2023-01-12 12:29:11 +08:00
9ca686b240 feat: disable role and permission update and checks when updating user (#1466) 2023-01-12 11:40:32 +08:00
c93bc0dda2 fix: add e2e cypress screenshots and videos if failed (#1465)
* feat: location error

* feat: location error

* feat: test error

* feat add e2e

* feat: delete cypress dependency

* feat: Add e2e error feedback
2023-01-11 23:56:09 +08:00
7d25b9cdd8 feat: auto link accounts with the same email (#1464) 2023-01-11 23:19:16 +08:00
ead844131e feat: improve user edit page to fix missing fields and page crash (#1463) 2023-01-11 16:15:06 +08:00
ce2a4bbf6e feat: check uniqueness for email and phone when updating user (#1461)
* fix: check unique field when update user

* Update data.json

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2023-01-10 22:34:08 +08:00
fcb80b800f feat: add refresh token to token login response (#1458)
Signed-off-by: 疯魔慕薇 <kfanjian@gmail.com>

Signed-off-by: 疯魔慕薇 <kfanjian@gmail.com>
2023-01-09 23:33:03 +08:00
6daadf8d3c feat: add e2e test (#1445)
* add cypress

* feat: add crypress ci
2023-01-09 00:16:32 +08:00
090389b86a Fix bug in CheckAccountItemModifyRule() 2023-01-07 13:49:06 +08:00
b566af8e11 Improve i18n 2023-01-06 20:32:18 +08:00
57028c2059 Remove duplicated i18n words 2023-01-06 20:24:14 +08:00
a6e9084973 Remove duplicated i18n words 2023-01-06 20:12:32 +08:00
6fb3e2cd7f Remove check_util i18n words 2023-01-06 19:57:13 +08:00
8b6bde6d82 Remove generate_backend.go 2023-01-06 19:42:47 +08:00
fb2b03f00f Add category to applyToOtherLanguage() 2023-01-06 19:26:00 +08:00
1681138729 Add getAllFilePathsInFolder() 2023-01-06 19:04:38 +08:00
1d8b0a264e feat(login): add code login limit (#1442) 2023-01-06 18:51:43 +08:00
b525210835 feat: destroy session after delete user (#1441)
* fix: destroy session after delete user

* feat: visual session

* fix: go lint

* feat: add translation

* feat: auto flush after offline

* fix: delete one session

* fix: move 403 page to baseListPage
2023-01-06 15:04:13 +08:00
4ab2ca7a25 feat: fix checkPermissionForUpdateUser() logic (#1454)
* fix: fix `checkPermissionForUpdateUser()` logic

* fix: fix `checkPermissionForUpdateUser()` logic
2023-01-06 00:03:40 +08:00
dcf148fb7f fix: add GetMaskedRoles and GetMaskedPermissions when GetAccount (#1456) 2023-01-06 00:02:52 +08:00
c8846f1a2d feat: fix translate bug in UpdateUser() (#1451)
* fix: fix translate error

* fix translate bug in UpdateUser()

* Delete DiscordLoginButton.js
2023-01-04 22:54:50 +08:00
0559298d6c feat: extend user with roles and permissions in GetAccount (#1449) 2023-01-04 20:23:57 +08:00
ddb5e26fcd fix: mask user in get-account response (#1450) 2023-01-04 18:40:36 +08:00
Liu
1f39027b78 fix: convert line endings to LF on checkout for all envs (#1448)
* Convert line endings to LF on checkout for all envs

* fix: convert line endings to LF on checkout for all envs
2023-01-04 18:36:38 +08:00
eae3b0d367 feat: fix saml login failed by using oauth (#1443) 2023-01-03 19:42:12 +08:00
186f0ac97b feat: check permission when update user (#1438)
* feat: check permission when update user

* feat: check permission when update user

* fix: fix organization accountItem modifyRule

* fix: fix organization accountItem modifyRule
2023-01-02 09:27:25 +08:00
308f305c53 feat: add query and fragment response mode declare in OIDC (#1439) 2023-01-01 21:46:12 +08:00
184 changed files with 7181 additions and 2179 deletions

5
.gitattributes vendored
View File

@ -1,2 +1,5 @@
*.go linguist-detectable=true *.go linguist-detectable=true
*.js linguist-detectable=false *.js linguist-detectable=false
# Declare files that will always have LF line endings on checkout.
# Git will always convert line endings to LF on checkout. You should use this for files that must keep LF endings, even on Windows.
*.sh text eol=lf

View File

@ -76,11 +76,58 @@ jobs:
version: latest version: latest
args: --disable-all -c dummy.yml -E=gofumpt --max-same-issues=0 --timeout 5m --modules-download-mode=mod args: --disable-all -c dummy.yml -E=gofumpt --max-same-issues=0 --timeout 5m --modules-download-mode=mod
e2e:
name: e2e-test
runs-on: ubuntu-latest
needs: [ go-tests ]
services:
mysql:
image: mysql:5.7
env:
MYSQL_DATABASE: casdoor
MYSQL_ROOT_PASSWORD: 123456
ports:
- 3306:3306
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
steps:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
go-version: '^1.16.5'
- 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
- 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()
with:
name: cypress-screenshots
path: ./web/cypress/screenshots
- uses: actions/upload-artifact@v3
if: always()
with:
name: cypress-videos
path: ./web/cypress/videos
release-and-push: release-and-push:
name: Release And Push name: Release And Push
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push' if: github.repository == 'casdoor/casdoor' && github.event_name == 'push'
needs: [ frontend, backend, linter ] needs: [ frontend, backend, linter, e2e ]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v2 uses: actions/checkout@v2

View File

@ -20,9 +20,9 @@ import (
"github.com/casbin/casbin/v2" "github.com/casbin/casbin/v2"
"github.com/casbin/casbin/v2/model" "github.com/casbin/casbin/v2/model"
xormadapter "github.com/casbin/xorm-adapter/v3"
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/object" "github.com/casdoor/casdoor/object"
xormadapter "github.com/casdoor/xorm-adapter/v3"
stringadapter "github.com/qiangmzsx/string-adapter/v2" stringadapter "github.com/qiangmzsx/string-adapter/v2"
) )
@ -160,7 +160,7 @@ func IsAllowed(subOwner string, subName string, method string, urlPath string, o
func isAllowedInDemoMode(subOwner string, subName string, method string, urlPath string, objOwner string, objName string) bool { func isAllowedInDemoMode(subOwner string, subName string, method string, urlPath string, objOwner string, objName string) bool {
if method == "POST" { if method == "POST" {
if strings.HasPrefix(urlPath, "/api/login") || urlPath == "/api/logout" || urlPath == "/api/signup" || urlPath == "/api/send-verification-code" { if strings.HasPrefix(urlPath, "/api/login") || urlPath == "/api/logout" || urlPath == "/api/signup" || urlPath == "/api/send-verification-code" || urlPath == "/api/send-email" {
return true return true
} else if urlPath == "/api/update-user" { } else if urlPath == "/api/update-user" {
// Allow ordinary users to update their own information // Allow ordinary users to update their own information

View File

@ -17,6 +17,7 @@ package controllers
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"net/http"
"strconv" "strconv"
"strings" "strings"
@ -238,20 +239,71 @@ func (c *ApiController) Signup() {
// @Title Logout // @Title Logout
// @Tag Login API // @Tag Login API
// @Description logout the current user // @Description logout the current user
// @Param id_token_hint query string false "id_token_hint"
// @Param post_logout_redirect_uri query string false "post_logout_redirect_uri"
// @Param state query string false "state"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /logout [get,post] // @router /logout [get,post]
func (c *ApiController) Logout() { func (c *ApiController) Logout() {
user := c.GetSessionUsername() user := c.GetSessionUsername()
util.LogInfo(c.Ctx, "API: [%s] logged out", user)
application := c.GetSessionApplication() // https://openid.net/specs/openid-connect-rpinitiated-1_0-final.html
c.ClearUserSession() accessToken := c.Input().Get("id_token_hint")
redirectUri := c.Input().Get("post_logout_redirect_uri")
state := c.Input().Get("state")
if application == nil || application.Name == "app-built-in" || application.HomepageUrl == "" { if accessToken == "" && redirectUri == "" {
c.ResponseOk(user) c.ClearUserSession()
// 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()
if application == nil || application.Name == "app-built-in" || application.HomepageUrl == "" {
c.ResponseOk(user)
return
}
c.ResponseOk(user, application.HomepageUrl)
return return
} else {
if redirectUri == "" {
c.ResponseError(c.T("general:Missing parameter") + ": post_logout_redirect_uri")
return
}
if accessToken == "" {
c.ResponseError(c.T("general:Missing parameter") + ": id_token_hint")
return
}
affected, application, token := object.ExpireTokenByAccessToken(accessToken)
if !affected {
c.ResponseError(c.T("token:Token not found, invalid accessToken"))
return
}
if application == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist")), token.Application)
return
}
if application.IsRedirectUriValid(redirectUri) {
if user == "" {
user = util.GetId(token.Organization, token.User)
}
c.ClearUserSession()
// 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))
} else {
c.ResponseError(fmt.Sprintf(c.T("token:Redirect URI: %s doesn't exist in the allowed Redirect URI list"), redirectUri))
return
}
} }
c.ResponseOk(user, application.HomepageUrl)
} }
// GetAccount // GetAccount
@ -271,12 +323,17 @@ func (c *ApiController) GetAccount() {
user = object.ExtendManagedAccountsWithUser(user) user = object.ExtendManagedAccountsWithUser(user)
} }
object.ExtendUserWithRolesAndPermissions(user)
user.Permissions = object.GetMaskedPermissions(user.Permissions)
user.Roles = object.GetMaskedRoles(user.Roles)
organization := object.GetMaskedOrganization(object.GetOrganizationByUser(user)) organization := object.GetMaskedOrganization(object.GetOrganizationByUser(user))
resp := Response{ resp := Response{
Status: "ok", Status: "ok",
Sub: user.Id, Sub: user.Id,
Name: user.Name, Name: user.Name,
Data: user, Data: object.GetMaskedUser(user),
Data2: organization, Data2: organization,
} }
c.Data["json"] = resp c.Data["json"] = resp

View File

@ -63,7 +63,7 @@ func (c *ApiController) GetApplications() {
// @Title GetApplication // @Title GetApplication
// @Tag Application API // @Tag Application API
// @Description get the detail of an application // @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 // @Success 200 {object} object.Application The Response object
// @router /get-application [get] // @router /get-application [get]
func (c *ApiController) GetApplication() { func (c *ApiController) GetApplication() {
@ -78,7 +78,7 @@ func (c *ApiController) GetApplication() {
// @Title GetUserApplication // @Title GetUserApplication
// @Tag Application API // @Tag Application API
// @Description get the detail of the user's application // @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 // @Success 200 {object} object.Application The Response object
// @router /get-user-application [get] // @router /get-user-application [get]
func (c *ApiController) GetUserApplication() { func (c *ApiController) GetUserApplication() {
@ -86,7 +86,7 @@ func (c *ApiController) GetUserApplication() {
id := c.Input().Get("id") id := c.Input().Get("id")
user := object.GetUser(id) user := object.GetUser(id)
if user == nil { if user == nil {
c.ResponseError(fmt.Sprintf(c.T("application:The user: %s doesn't exist"), id)) c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), id))
return return
} }
@ -113,7 +113,7 @@ func (c *ApiController) GetOrganizationApplications() {
sortOrder := c.Input().Get("sortOrder") sortOrder := c.Input().Get("sortOrder")
if organization == "" { if organization == "" {
c.ResponseError(c.T("application:Parameter organization is missing")) c.ResponseError(c.T("general:Missing parameter") + ": organization")
return return
} }
@ -134,7 +134,7 @@ func (c *ApiController) GetOrganizationApplications() {
// @Title UpdateApplication // @Title UpdateApplication
// @Tag Application API // @Tag Application API
// @Description update an application // @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" // @Param body body object.Application true "The details of the application"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /update-application [post] // @router /update-application [post]

View File

@ -52,7 +52,7 @@ func tokenToResponse(token *object.Token) *Response {
if token.AccessToken == "" { if token.AccessToken == "" {
return &Response{Status: "error", Msg: "fail to get accessToken", Data: token.AccessToken} return &Response{Status: "error", Msg: "fail to get accessToken", Data: token.AccessToken}
} }
return &Response{Status: "ok", Msg: "", Data: token.AccessToken} return &Response{Status: "ok", Msg: "", Data: token.AccessToken, Data2: token.RefreshToken}
} }
// HandleLoggedIn ... // HandleLoggedIn ...
@ -103,12 +103,12 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
resp = tokenToResponse(token) resp = tokenToResponse(token)
} }
} else if form.Type == ResponseTypeSaml { // saml flow } else if form.Type == ResponseTypeSaml { // saml flow
res, redirectUrl, err := object.GetSamlResponse(application, user, form.SamlRequest, c.Ctx.Request.Host) res, redirectUrl, method, err := object.GetSamlResponse(application, user, form.SamlRequest, c.Ctx.Request.Host)
if err != nil { if err != nil {
c.ResponseError(err.Error(), nil) c.ResponseError(err.Error(), nil)
return return
} }
resp = &Response{Status: "ok", Msg: "", Data: res, Data2: redirectUrl} resp = &Response{Status: "ok", Msg: "", Data: res, Data2: map[string]string{"redirectUrl": redirectUrl, "method": method}}
} else if form.Type == ResponseTypeCas { } else if form.Type == ResponseTypeCas {
// not oauth but CAS SSO protocol // not oauth but CAS SSO protocol
service := c.Input().Get("service") service := c.Input().Get("service")
@ -139,6 +139,15 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
}) })
} }
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 return resp
} }
@ -170,13 +179,36 @@ func (c *ApiController) GetApplicationLogin() {
} }
func setHttpClient(idProvider idp.IdProvider, providerType string) { 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) idProvider.SetHttpClient(proxy.ProxyHttpClient)
} else { } else {
idProvider.SetHttpClient(proxy.DefaultHttpClient) 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 ... // Login ...
// @Title Login // @Title Login
// @Tag Login API // @Tag Login API
@ -205,7 +237,7 @@ func (c *ApiController) Login() {
if form.Username != "" { if form.Username != "" {
if form.Type == ResponseTypeLogin { if form.Type == ResponseTypeLogin {
if c.GetSessionUsername() != "" { if c.GetSessionUsername() != "" {
c.ResponseError(c.T("auth:Please sign out first before signing in"), c.GetSessionUsername()) c.ResponseError(c.T("account:Please sign out first before signing in"), c.GetSessionUsername())
return return
} }
} }
@ -222,12 +254,13 @@ func (c *ApiController) Login() {
} }
// check result through Email or Phone // check result through Email or Phone
var checkDest string
if strings.Contains(form.Username, "@") { if strings.Contains(form.Username, "@") {
verificationCodeType = "email" verificationCodeType = "email"
if user != nil && util.GetMaskedEmail(user.Email) == form.Username { if user != nil && util.GetMaskedEmail(user.Email) == form.Username {
form.Username = user.Email form.Username = user.Email
} }
checkResult = object.CheckVerificationCode(form.Username, form.Code, c.GetAcceptLanguage()) checkDest = form.Username
} else { } else {
verificationCodeType = "phone" verificationCodeType = "phone"
if len(form.PhonePrefix) == 0 { if len(form.PhonePrefix) == 0 {
@ -238,11 +271,16 @@ func (c *ApiController) Login() {
if user != nil && util.GetMaskedPhone(user.Phone) == form.Username { if user != nil && util.GetMaskedPhone(user.Phone) == form.Username {
form.Username = user.Phone form.Username = user.Phone
} }
checkPhone := fmt.Sprintf("+%s%s", form.PhonePrefix, form.Username) checkDest = fmt.Sprintf("+%s%s", form.PhonePrefix, form.Username)
checkResult = object.CheckVerificationCode(checkPhone, form.Code, c.GetAcceptLanguage())
} }
user = object.GetUserByFields(form.Organization, form.Username)
if user == nil {
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(form.Organization, form.Username)))
return
}
checkResult = object.CheckSigninCode(user, checkDest, form.Code, c.GetAcceptLanguage())
if len(checkResult) != 0 { if len(checkResult) != 0 {
responseText := fmt.Sprintf("%s%s", verificationCodeType, checkResult) responseText := fmt.Sprintf("%s - %s", verificationCodeType, checkResult)
c.ResponseError(responseText) c.ResponseError(responseText)
return return
} }
@ -253,12 +291,6 @@ func (c *ApiController) Login() {
} else { } else {
object.DisableVerificationCode(fmt.Sprintf("+%s%s", form.PhonePrefix, form.Username)) object.DisableVerificationCode(fmt.Sprintf("+%s%s", form.PhonePrefix, form.Username))
} }
user = object.GetUserByFields(form.Organization, form.Username)
if user == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:The user: %s/%s doesn't exist"), form.Organization, form.Username))
return
}
} else { } else {
application := object.GetApplication(fmt.Sprintf("admin/%s", form.Application)) application := object.GetApplication(fmt.Sprintf("admin/%s", form.Application))
if application == nil { if application == nil {
@ -401,54 +433,61 @@ func (c *ApiController) Login() {
return return
} }
// Handle username conflicts if application.EnableLinkWithEmail {
tmpUser := object.GetUser(fmt.Sprintf("%s/%s", application.Organization, userInfo.Username)) // find user that has the same email
if tmpUser != nil { user = object.GetUserByField(application.Organization, "email", userInfo.Email)
uid, err := uuid.NewRandom() }
if user == nil || user.IsDeleted {
// Handle username conflicts
tmpUser := object.GetUser(fmt.Sprintf("%s/%s", application.Organization, userInfo.Username))
if tmpUser != nil {
uid, err := uuid.NewRandom()
if err != nil {
c.ResponseError(err.Error())
return
}
uidStr := strings.Split(uid.String(), "-")
userInfo.Username = fmt.Sprintf("%s_%s", userInfo.Username, uidStr[1])
}
properties := map[string]string{}
properties["no"] = strconv.Itoa(len(object.GetUsers(application.Organization)) + 2)
initScore, err := getInitScore(organization)
if err != nil { if err != nil {
c.ResponseError(err.Error()) c.ResponseError(fmt.Errorf(c.T("account:Get init score failed, error: %w"), err).Error())
return return
} }
uidStr := strings.Split(uid.String(), "-") user = &object.User{
userInfo.Username = fmt.Sprintf("%s_%s", userInfo.Username, uidStr[1]) Owner: application.Organization,
Name: userInfo.Username,
CreatedTime: util.GetCurrentTime(),
Id: util.GenerateId(),
Type: "normal-user",
DisplayName: userInfo.DisplayName,
Avatar: userInfo.AvatarUrl,
Address: []string{},
Email: userInfo.Email,
Score: initScore,
IsAdmin: false,
IsGlobalAdmin: false,
IsForbidden: false,
IsDeleted: false,
SignupApplication: application.Name,
Properties: properties,
}
affected := object.AddUser(user)
if !affected {
c.ResponseError(fmt.Sprintf(c.T("auth:Failed to create user, user information is invalid: %s"), util.StructToJson(user)))
return
}
} }
properties := map[string]string{}
properties["no"] = strconv.Itoa(len(object.GetUsers(application.Organization)) + 2)
initScore, err := getInitScore(organization)
if err != nil {
c.ResponseError(fmt.Errorf(c.T("auth:Get init score failed, error: %w"), err).Error())
return
}
user = &object.User{
Owner: application.Organization,
Name: userInfo.Username,
CreatedTime: util.GetCurrentTime(),
Id: util.GenerateId(),
Type: "normal-user",
DisplayName: userInfo.DisplayName,
Avatar: userInfo.AvatarUrl,
Address: []string{},
Email: userInfo.Email,
Score: initScore,
IsAdmin: false,
IsGlobalAdmin: false,
IsForbidden: false,
IsDeleted: false,
SignupApplication: application.Name,
Properties: properties,
}
// sync info from 3rd-party if possible // sync info from 3rd-party if possible
object.SetUserOAuthProperties(organization, user, provider.Type, userInfo) object.SetUserOAuthProperties(organization, user, provider.Type, userInfo)
affected := object.AddUser(user)
if !affected {
c.ResponseError(fmt.Sprintf(c.T("auth:Failed to create user, user information is invalid: %s"), util.StructToJson(user)))
return
}
object.LinkUserAccount(user, provider.Type, userInfo.Id) object.LinkUserAccount(user, provider.Type, userInfo.Id)
resp = c.HandleLoggedIn(application, user, &form) resp = c.HandleLoggedIn(application, user, &form)
@ -464,13 +503,13 @@ func (c *ApiController) Login() {
record2.User = user.Name record2.User = user.Name
util.SafeGoroutine(func() { object.AddRecord(record2) }) util.SafeGoroutine(func() { object.AddRecord(record2) })
} else if provider.Category == "SAML" { } else if provider.Category == "SAML" {
resp = &Response{Status: "error", Msg: "The account does not exist"} resp = &Response{Status: "error", Msg: fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(application.Organization, userInfo.Id))}
} }
// resp = &Response{Status: "ok", Msg: "", Data: res} // resp = &Response{Status: "ok", Msg: "", Data: res}
} else { // form.Method != "signup" } else { // form.Method != "signup"
userId := c.GetSessionUsername() userId := c.GetSessionUsername()
if userId == "" { if userId == "" {
c.ResponseError(c.T("auth:The account does not exist"), userInfo) c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(application.Organization, userInfo.Id)), userInfo)
return return
} }

View File

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

View File

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

View File

@ -47,7 +47,7 @@ func (c *ApiController) BatchEnforce() {
func (c *ApiController) GetAllObjects() { func (c *ApiController) GetAllObjects() {
userId := c.GetSessionUsername() userId := c.GetSessionUsername()
if userId == "" { if userId == "" {
c.ResponseError(c.T("enforcer:Please sign in first")) c.ResponseError(c.T("general:Please login first"))
return return
} }
@ -58,7 +58,7 @@ func (c *ApiController) GetAllObjects() {
func (c *ApiController) GetAllActions() { func (c *ApiController) GetAllActions() {
userId := c.GetSessionUsername() userId := c.GetSessionUsername()
if userId == "" { if userId == "" {
c.ResponseError(c.T("enforcer:Please sign in first")) c.ResponseError(c.T("general:Please login first"))
return return
} }
@ -69,7 +69,7 @@ func (c *ApiController) GetAllActions() {
func (c *ApiController) GetAllRoles() { func (c *ApiController) GetAllRoles() {
userId := c.GetSessionUsername() userId := c.GetSessionUsername()
if userId == "" { if userId == "" {
c.ResponseError(c.T("enforcer:Please sign in first")) c.ResponseError(c.T("general:Please login first"))
return return
} }

View File

@ -52,7 +52,7 @@ func (c *ApiController) GetLdapUser() {
ldapServer := LdapServer{} ldapServer := LdapServer{}
err := json.Unmarshal(c.Ctx.Input.RequestBody, &ldapServer) err := json.Unmarshal(c.Ctx.Input.RequestBody, &ldapServer)
if err != nil || util.IsStrsEmpty(ldapServer.Host, ldapServer.Admin, ldapServer.Passwd, ldapServer.BaseDn) { if err != nil || util.IsStrsEmpty(ldapServer.Host, ldapServer.Admin, ldapServer.Passwd, ldapServer.BaseDn) {
c.ResponseError(c.T("ldap:Missing parameter")) c.ResponseError(c.T("general:Missing parameter"))
return return
} }
@ -120,7 +120,7 @@ func (c *ApiController) GetLdap() {
id := c.Input().Get("id") id := c.Input().Get("id")
if util.IsStrsEmpty(id) { if util.IsStrsEmpty(id) {
c.ResponseError(c.T("ldap:Missing parameter")) c.ResponseError(c.T("general:Missing parameter"))
return return
} }
@ -136,12 +136,12 @@ func (c *ApiController) AddLdap() {
var ldap object.Ldap var ldap object.Ldap
err := json.Unmarshal(c.Ctx.Input.RequestBody, &ldap) err := json.Unmarshal(c.Ctx.Input.RequestBody, &ldap)
if err != nil { if err != nil {
c.ResponseError(c.T("ldap:Missing parameter")) c.ResponseError(c.T("general:Missing parameter"))
return return
} }
if util.IsStrsEmpty(ldap.Owner, ldap.ServerName, ldap.Host, ldap.Admin, ldap.Passwd, ldap.BaseDn) { if util.IsStrsEmpty(ldap.Owner, ldap.ServerName, ldap.Host, ldap.Admin, ldap.Passwd, ldap.BaseDn) {
c.ResponseError(c.T("ldap:Missing parameter")) c.ResponseError(c.T("general:Missing parameter"))
return return
} }
@ -171,7 +171,7 @@ func (c *ApiController) UpdateLdap() {
var ldap object.Ldap var ldap object.Ldap
err := json.Unmarshal(c.Ctx.Input.RequestBody, &ldap) err := json.Unmarshal(c.Ctx.Input.RequestBody, &ldap)
if err != nil || util.IsStrsEmpty(ldap.Owner, ldap.ServerName, ldap.Host, ldap.Admin, ldap.Passwd, ldap.BaseDn) { if err != nil || util.IsStrsEmpty(ldap.Owner, ldap.ServerName, ldap.Host, ldap.Admin, ldap.Passwd, ldap.BaseDn) {
c.ResponseError(c.T("ldap:Missing parameter")) c.ResponseError(c.T("general:Missing parameter"))
return return
} }

View File

@ -105,14 +105,34 @@ func handleSearch(w ldapserver.ResponseWriter, m *ldapserver.Message) {
} }
for i := 0; i < len(users); i++ { for i := 0; i < len(users); i++ {
user := 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 := ldapserver.NewSearchResultEntry(dn)
e.AddAttribute("cn", message.AttributeValue(user.Name)) e.AddAttribute("cn", message.AttributeValue(user.Name))
e.AddAttribute("uid", message.AttributeValue(user.Name)) e.AddAttribute("uid", message.AttributeValue(user.Name))
e.AddAttribute("email", message.AttributeValue(user.Email)) e.AddAttribute("email", message.AttributeValue(user.Email))
e.AddAttribute("mobile", message.AttributeValue(user.Phone)) e.AddAttribute("mobile", message.AttributeValue(user.Phone))
e.AddAttribute("userPassword", message.AttributeValue(getUserPasswordWithType(user)))
// e.AddAttribute("postalAddress", message.AttributeValue(user.Address[0])) // e.AddAttribute("postalAddress", message.AttributeValue(user.Address[0]))
w.Write(e) w.Write(e)
} }
w.Write(res) 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 // @Title GetModel
// @Tag Model API // @Tag Model API
// @Description get model // @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 // @Success 200 {object} object.Model The Response object
// @router /get-model [get] // @router /get-model [get]
func (c *ApiController) GetModel() { func (c *ApiController) GetModel() {
@ -66,7 +66,7 @@ func (c *ApiController) GetModel() {
// @Title UpdateModel // @Title UpdateModel
// @Tag Model API // @Tag Model API
// @Description update model // @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" // @Param body body object.Model true "The details of the model"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /update-model [post] // @router /update-model [post]
@ -80,7 +80,7 @@ func (c *ApiController) UpdateModel() {
return return
} }
c.Data["json"] = wrapActionResponse(object.UpdateModel(id, &model)) c.Data["json"] = wrapErrorResponse(object.UpdateModelWithCheck(id, &model))
c.ServeJSON() c.ServeJSON()
} }

View File

@ -66,7 +66,7 @@ func (c *ApiController) GetOrganization() {
// @Title UpdateOrganization // @Title UpdateOrganization
// @Tag Organization API // @Tag Organization API
// @Description update organization // @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" // @Param body body object.Organization true "The details of the organization"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /update-organization [post] // @router /update-organization [post]

View File

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

View File

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

View File

@ -53,7 +53,7 @@ func (c *ApiController) GetProducts() {
// @Title GetProduct // @Title GetProduct
// @Tag Product API // @Tag Product API
// @Description get product // @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 // @Success 200 {object} object.Product The Response object
// @router /get-product [get] // @router /get-product [get]
func (c *ApiController) GetProduct() { func (c *ApiController) GetProduct() {
@ -70,7 +70,7 @@ func (c *ApiController) GetProduct() {
// @Title UpdateProduct // @Title UpdateProduct
// @Tag Product API // @Tag Product API
// @Description update product // @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" // @Param body body object.Product true "The details of the product"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /update-product [post] // @router /update-product [post]
@ -130,7 +130,7 @@ func (c *ApiController) DeleteProduct() {
// @Title BuyProduct // @Title BuyProduct
// @Tag Product API // @Tag Product API
// @Description buy product // @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" // @Param providerName query string true "The name of the provider"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /buy-product [post] // @router /buy-product [post]
@ -141,13 +141,13 @@ func (c *ApiController) BuyProduct() {
userId := c.GetSessionUsername() userId := c.GetSessionUsername()
if userId == "" { if userId == "" {
c.ResponseError(c.T("product:Please login first")) c.ResponseError(c.T("general:Please login first"))
return return
} }
user := object.GetUser(userId) user := object.GetUser(userId)
if user == nil { if user == nil {
c.ResponseError(fmt.Sprintf(c.T("product:The user: %s doesn't exist"), userId)) c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), userId))
return return
} }

View File

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

View File

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

View File

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

139
controllers/session.go Normal file
View File

@ -0,0 +1,139 @@
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
"encoding/json"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
// GetSessions
// @Title GetSessions
// @Tag Session API
// @Description Get organization user sessions.
// @Param owner query string true "The organization name"
// @Success 200 {array} string The Response object
// @router /get-sessions [get]
func (c *ApiController) GetSessions() {
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
owner := c.Input().Get("owner")
if limit == "" || page == "" {
c.Data["json"] = object.GetSessions(owner)
c.ServeJSON()
} else {
limit := util.ParseInt(limit)
paginator := pagination.SetPaginator(c.Ctx, limit, int64(object.GetSessionCount(owner, field, value)))
sessions := object.GetPaginationSessions(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
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 // @Title GetSyncer
// @Tag Syncer API // @Tag Syncer API
// @Description get syncer // @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 // @Success 200 {object} object.Syncer The Response object
// @router /get-syncer [get] // @router /get-syncer [get]
func (c *ApiController) GetSyncer() { func (c *ApiController) GetSyncer() {
@ -66,7 +66,7 @@ func (c *ApiController) GetSyncer() {
// @Title UpdateSyncer // @Title UpdateSyncer
// @Tag Syncer API // @Tag Syncer API
// @Description update syncer // @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" // @Param body body object.Syncer true "The details of the syncer"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /update-syncer [post] // @router /update-syncer [post]

View File

@ -29,7 +29,7 @@ type SystemInfo struct {
// @Title GetSystemInfo // @Title GetSystemInfo
// @Tag System API // @Tag System API
// @Description get user's system info // @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 // @Success 200 {object} object.SystemInfo The Response object
// @router /get-system-info [get] // @router /get-system-info [get]
func (c *ApiController) GetSystemInfo() { func (c *ApiController) GetSystemInfo() {
@ -40,7 +40,7 @@ func (c *ApiController) GetSystemInfo() {
user := object.GetUser(id) user := object.GetUser(id)
if user == nil || !user.IsGlobalAdmin { if user == nil || !user.IsGlobalAdmin {
c.ResponseError(c.T("system_info:You are not authorized to access this resource")) c.ResponseError(c.T("auth:Unauthorized operation"))
return return
} }

View File

@ -16,7 +16,6 @@ package controllers
import ( import (
"encoding/json" "encoding/json"
"net/http"
"github.com/beego/beego/utils/pagination" "github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object" "github.com/casdoor/casdoor/object"
@ -55,7 +54,7 @@ func (c *ApiController) GetTokens() {
// @Title GetToken // @Title GetToken
// @Tag Token API // @Tag Token API
// @Description get token // @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 // @Success 200 {object} object.Token The Response object
// @router /get-token [get] // @router /get-token [get]
func (c *ApiController) GetToken() { func (c *ApiController) GetToken() {
@ -69,7 +68,7 @@ func (c *ApiController) GetToken() {
// @Title UpdateToken // @Title UpdateToken
// @Tag Token API // @Tag Token API
// @Description update token // @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" // @Param body body object.Token true "Details of the token"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /update-token [post] // @router /update-token [post]
@ -129,7 +128,7 @@ func (c *ApiController) DeleteToken() {
// @Title GetOAuthCode // @Title GetOAuthCode
// @Tag Token API // @Tag Token API
// @Description get OAuth code // @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 client_id query string true "OAuth client id"
// @Param response_type query string true "OAuth response type" // @Param response_type query string true "OAuth response type"
// @Param redirect_uri query string true "OAuth redirect URI" // @Param redirect_uri query string true "OAuth redirect URI"
@ -150,7 +149,7 @@ func (c *ApiController) GetOAuthCode() {
codeChallenge := c.Input().Get("code_challenge") codeChallenge := c.Input().Get("code_challenge")
if challengeMethod != "S256" && challengeMethod != "null" && challengeMethod != "" { if challengeMethod != "S256" && challengeMethod != "null" && challengeMethod != "" {
c.ResponseError(c.T("token:Challenge method should be S256")) c.ResponseError(c.T("auth:Challenge method should be S256"))
return return
} }
host := c.Ctx.Request.Host host := c.Ctx.Request.Host
@ -173,6 +172,7 @@ func (c *ApiController) GetOAuthCode() {
// @router /login/oauth/access_token [post] // @router /login/oauth/access_token [post]
func (c *ApiController) GetOAuthToken() { func (c *ApiController) GetOAuthToken() {
grantType := c.Input().Get("grant_type") grantType := c.Input().Get("grant_type")
refreshToken := c.Input().Get("refresh_token")
clientId := c.Input().Get("client_id") clientId := c.Input().Get("client_id")
clientSecret := c.Input().Get("client_secret") clientSecret := c.Input().Get("client_secret")
code := c.Input().Get("code") code := c.Input().Get("code")
@ -193,6 +193,7 @@ func (c *ApiController) GetOAuthToken() {
clientId = tokenRequest.ClientId clientId = tokenRequest.ClientId
clientSecret = tokenRequest.ClientSecret clientSecret = tokenRequest.ClientSecret
grantType = tokenRequest.GrantType grantType = tokenRequest.GrantType
refreshToken = tokenRequest.RefreshToken
code = tokenRequest.Code code = tokenRequest.Code
verifier = tokenRequest.Verifier verifier = tokenRequest.Verifier
scope = tokenRequest.Scope scope = tokenRequest.Scope
@ -204,7 +205,7 @@ func (c *ApiController) GetOAuthToken() {
} }
host := c.Ctx.Request.Host host := c.Ctx.Request.Host
c.Data["json"] = object.GetOAuthToken(grantType, clientId, clientSecret, code, verifier, scope, username, password, host, tag, avatar, c.GetAcceptLanguage()) c.Data["json"] = object.GetOAuthToken(grantType, clientId, clientSecret, code, verifier, scope, username, password, host, refreshToken, tag, avatar, c.GetAcceptLanguage())
c.SetTokenErrorHttpStatus() c.SetTokenErrorHttpStatus()
c.ServeJSON() c.ServeJSON()
} }
@ -247,28 +248,6 @@ func (c *ApiController) RefreshToken() {
c.ServeJSON() c.ServeJSON()
} }
// TokenLogout
// @Title TokenLogout
// @Tag Token API
// @Description delete token by AccessToken
// @Param id_token_hint query string true "id_token_hint"
// @Param post_logout_redirect_uri query string false "post_logout_redirect_uri"
// @Param state query string true "state"
// @Success 200 {object} controllers.Response The Response object
// @router /login/oauth/logout [get]
func (c *ApiController) TokenLogout() {
token := c.Input().Get("id_token_hint")
flag, application := object.DeleteTokenByAccessToken(token)
redirectUri := c.Input().Get("post_logout_redirect_uri")
state := c.Input().Get("state")
if application != nil && application.IsRedirectUriValid(redirectUri) {
c.Ctx.Redirect(http.StatusFound, redirectUri+"?state="+state)
return
}
c.Data["json"] = wrapActionResponse(flag)
c.ServeJSON()
}
// IntrospectToken // IntrospectToken
// @Title IntrospectToken // @Title IntrospectToken
// @Description The introspection endpoint is an OAuth 2.0 endpoint that takes a // @Description The introspection endpoint is an OAuth 2.0 endpoint that takes a

View File

@ -80,7 +80,7 @@ func (c *ApiController) GetUsers() {
// @Title GetUser // @Title GetUser
// @Tag User API // @Tag User API
// @Description get user // @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 owner query string false "The owner of the user"
// @Param email query string false "The email of the user" // @Param email query string false "The email of the user"
// @Param phone query string false "The phone of the user" // @Param phone query string false "The phone of the user"
@ -129,7 +129,7 @@ func (c *ApiController) GetUser() {
// @Title UpdateUser // @Title UpdateUser
// @Tag User API // @Tag User API
// @Description update user // @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" // @Param body body object.User true "The details of the user"
// @Success 200 {object} controllers.Response The Response object // @Success 200 {object} controllers.Response The Response object
// @router /update-user [post] // @router /update-user [post]
@ -148,8 +148,8 @@ func (c *ApiController) UpdateUser() {
return return
} }
if user.DisplayName == "" { if msg := object.CheckUpdateUser(object.GetUser(id), &user, c.GetAcceptLanguage()); msg != "" {
c.ResponseError(c.T("user:Display name cannot be empty")) c.ResponseError(msg)
return return
} }
@ -159,6 +159,12 @@ func (c *ApiController) UpdateUser() {
} }
isGlobalAdmin := c.IsGlobalAdmin() isGlobalAdmin := c.IsGlobalAdmin()
if pass, err := checkPermissionForUpdateUser(id, user, c); !pass {
c.ResponseError(err)
return
}
affected := object.UpdateUser(id, &user, columns, isGlobalAdmin) affected := object.UpdateUser(id, &user, columns, isGlobalAdmin)
if affected { if affected {
object.UpdateUserToOriginalDatabase(&user) object.UpdateUserToOriginalDatabase(&user)
@ -236,7 +242,7 @@ func (c *ApiController) GetEmailAndPhone() {
user := object.GetUserByFields(form.Organization, form.Username) user := object.GetUserByFields(form.Organization, form.Username)
if user == nil { if user == nil {
c.ResponseError(fmt.Sprintf(c.T("user:The user: %s/%s doesn't exist"), form.Organization, form.Username)) c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(form.Organization, form.Username)))
return return
} }

135
controllers/user_util.go Normal file
View File

@ -0,0 +1,135 @@
// 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 controllers
import (
"encoding/json"
"github.com/casdoor/casdoor/object"
)
func checkPermissionForUpdateUser(userId string, newUser object.User, c *ApiController) (bool, string) {
oldUser := object.GetUser(userId)
organization := object.GetOrganizationByUser(oldUser)
var itemsChanged []*object.AccountItem
if oldUser.Owner != newUser.Owner {
item := object.GetAccountItemByName("Organization", organization)
itemsChanged = append(itemsChanged, item)
}
if oldUser.Name != newUser.Name {
item := object.GetAccountItemByName("Name", organization)
itemsChanged = append(itemsChanged, item)
}
if oldUser.Id != newUser.Id {
item := object.GetAccountItemByName("ID", organization)
itemsChanged = append(itemsChanged, item)
}
if oldUser.DisplayName != newUser.DisplayName {
item := object.GetAccountItemByName("Display name", organization)
itemsChanged = append(itemsChanged, item)
}
if oldUser.Avatar != newUser.Avatar {
item := object.GetAccountItemByName("Avatar", organization)
itemsChanged = append(itemsChanged, item)
}
if oldUser.Type != newUser.Type {
item := object.GetAccountItemByName("User type", organization)
itemsChanged = append(itemsChanged, item)
}
// The password is *** when not modified
if oldUser.Password != newUser.Password && newUser.Password != "***" {
item := object.GetAccountItemByName("Password", organization)
itemsChanged = append(itemsChanged, item)
}
if oldUser.Email != newUser.Email {
item := object.GetAccountItemByName("Email", organization)
itemsChanged = append(itemsChanged, item)
}
if oldUser.Phone != newUser.Phone {
item := object.GetAccountItemByName("Phone", organization)
itemsChanged = append(itemsChanged, item)
}
if oldUser.Region != newUser.Region {
item := object.GetAccountItemByName("Country/Region", organization)
itemsChanged = append(itemsChanged, item)
}
if oldUser.Location != newUser.Location {
item := object.GetAccountItemByName("Location", organization)
itemsChanged = append(itemsChanged, item)
}
if oldUser.Affiliation != newUser.Affiliation {
item := object.GetAccountItemByName("Affiliation", organization)
itemsChanged = append(itemsChanged, item)
}
if oldUser.Title != newUser.Title {
item := object.GetAccountItemByName("Title", organization)
itemsChanged = append(itemsChanged, item)
}
if oldUser.Homepage != newUser.Homepage {
item := object.GetAccountItemByName("Homepage", organization)
itemsChanged = append(itemsChanged, item)
}
if oldUser.Bio != newUser.Bio {
item := object.GetAccountItemByName("Bio", organization)
itemsChanged = append(itemsChanged, item)
}
if oldUser.Tag != newUser.Tag {
item := object.GetAccountItemByName("Tag", organization)
itemsChanged = append(itemsChanged, item)
}
if oldUser.SignupApplication != newUser.SignupApplication {
item := object.GetAccountItemByName("Signup application", organization)
itemsChanged = append(itemsChanged, item)
}
oldUserPropertiesJson, _ := json.Marshal(oldUser.Properties)
newUserPropertiesJson, _ := json.Marshal(newUser.Properties)
if string(oldUserPropertiesJson) != string(newUserPropertiesJson) {
item := object.GetAccountItemByName("Properties", organization)
itemsChanged = append(itemsChanged, item)
}
if oldUser.IsAdmin != newUser.IsAdmin {
item := object.GetAccountItemByName("Is admin", organization)
itemsChanged = append(itemsChanged, item)
}
if oldUser.IsGlobalAdmin != newUser.IsGlobalAdmin {
item := object.GetAccountItemByName("Is global admin", organization)
itemsChanged = append(itemsChanged, item)
}
if oldUser.IsForbidden != newUser.IsForbidden {
item := object.GetAccountItemByName("Is forbidden", organization)
itemsChanged = append(itemsChanged, item)
}
if oldUser.IsDeleted != newUser.IsDeleted {
item := object.GetAccountItemByName("Is deleted", organization)
itemsChanged = append(itemsChanged, item)
}
currentUser := c.getCurrentUser()
if currentUser == nil && c.IsGlobalAdmin() {
currentUser = &object.User{
IsGlobalAdmin: true,
}
}
for i := range itemsChanged {
if pass, err := object.CheckAccountItemModifyRule(itemsChanged[i], currentUser, c.GetAcceptLanguage()); !pass {
return pass, err
}
}
return true, ""
}

View File

@ -84,7 +84,7 @@ func (c *ApiController) SetTokenErrorHttpStatus() {
func (c *ApiController) RequireSignedIn() (string, bool) { func (c *ApiController) RequireSignedIn() (string, bool) {
userId := c.GetSessionUsername() userId := c.GetSessionUsername()
if userId == "" { if userId == "" {
c.ResponseError(c.T("util:Please login first"), "Please login first") c.ResponseError(c.T("general:Please login first"), "Please login first")
return "", false return "", false
} }
return userId, true return userId, true
@ -100,7 +100,7 @@ func (c *ApiController) RequireSignedInUser() (*object.User, bool) {
user := object.GetUser(userId) user := object.GetUser(userId)
if user == nil { if user == nil {
c.ClearUserSession() c.ClearUserSession()
c.ResponseError(fmt.Sprintf(c.T("util:The user: %s doesn't exist"), userId)) c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), userId))
return nil, false return nil, false
} }
return user, true return user, true

View File

@ -51,15 +51,15 @@ func (c *ApiController) SendVerificationCode() {
remoteAddr := util.GetIPFromRequest(c.Ctx.Request) remoteAddr := util.GetIPFromRequest(c.Ctx.Request)
if destType == "" { if destType == "" {
c.ResponseError(c.T("verification:Missing parameter") + ": type.") c.ResponseError(c.T("general:Missing parameter") + ": type.")
return return
} }
if dest == "" { if dest == "" {
c.ResponseError(c.T("verification:Missing parameter") + ": dest.") c.ResponseError(c.T("general:Missing parameter") + ": dest.")
return return
} }
if applicationId == "" { if applicationId == "" {
c.ResponseError(c.T("verification:Missing parameter") + ": applicationId.") c.ResponseError(c.T("general:Missing parameter") + ": applicationId.")
return return
} }
if !strings.Contains(applicationId, "/") { if !strings.Contains(applicationId, "/") {
@ -67,7 +67,7 @@ func (c *ApiController) SendVerificationCode() {
return return
} }
if checkType == "" { if checkType == "" {
c.ResponseError(c.T("verification:Missing parameter") + ": checkType.") c.ResponseError(c.T("general:Missing parameter") + ": checkType.")
return return
} }
@ -75,7 +75,7 @@ func (c *ApiController) SendVerificationCode() {
if captchaProvider != nil { if captchaProvider != nil {
if checkKey == "" { if checkKey == "" {
c.ResponseError(c.T("verification:Missing parameter") + ": checkKey.") c.ResponseError(c.T("general:Missing parameter") + ": checkKey.")
return return
} }
isHuman, err := captchaProvider.VerifyCaptcha(checkKey, checkId) isHuman, err := captchaProvider.VerifyCaptcha(checkKey, checkId)
@ -99,7 +99,7 @@ func (c *ApiController) SendVerificationCode() {
} }
if checkUser == "true" && user == nil && object.GetUserByFields(organization.Name, dest) == nil { if checkUser == "true" && user == nil && object.GetUserByFields(organization.Name, dest) == nil {
c.ResponseError(c.T("verification:Please login first")) c.ResponseError(c.T("general:Please login first"))
return return
} }
@ -170,14 +170,19 @@ func (c *ApiController) ResetEmailOrPhone() {
dest := c.Ctx.Request.Form.Get("dest") dest := c.Ctx.Request.Form.Get("dest")
code := c.Ctx.Request.Form.Get("code") code := c.Ctx.Request.Form.Get("code")
if len(dest) == 0 || len(code) == 0 || len(destType) == 0 { if len(dest) == 0 || len(code) == 0 || len(destType) == 0 {
c.ResponseError(c.T("verification:Missing parameter")) c.ResponseError(c.T("general:Missing parameter"))
return return
} }
checkDest := dest checkDest := dest
org := object.GetOrganizationByUser(user) organization := object.GetOrganizationByUser(user)
if destType == "phone" { if destType == "phone" {
phoneItem := object.GetAccountItemByName("Phone", org) if object.HasUserByField(user.Owner, "phone", user.Phone) {
c.ResponseError(c.T("check:Phone already exists"))
return
}
phoneItem := object.GetAccountItemByName("Phone", organization)
if phoneItem == nil { if phoneItem == nil {
c.ResponseError(c.T("verification:Unable to get the phone modify rule.")) c.ResponseError(c.T("verification:Unable to get the phone modify rule."))
return return
@ -189,12 +194,17 @@ func (c *ApiController) ResetEmailOrPhone() {
} }
phonePrefix := "86" phonePrefix := "86"
if org != nil && org.PhonePrefix != "" { if organization != nil && organization.PhonePrefix != "" {
phonePrefix = org.PhonePrefix phonePrefix = organization.PhonePrefix
} }
checkDest = fmt.Sprintf("+%s%s", phonePrefix, dest) checkDest = fmt.Sprintf("+%s%s", phonePrefix, dest)
} else if destType == "email" { } else if destType == "email" {
emailItem := object.GetAccountItemByName("Email", org) if object.HasUserByField(user.Owner, "email", user.Email) {
c.ResponseError(c.T("check:Email already exists"))
return
}
emailItem := object.GetAccountItemByName("Email", organization)
if emailItem == nil { if emailItem == nil {
c.ResponseError(c.T("verification:Unable to get the email modify rule.")) c.ResponseError(c.T("verification:Unable to get the email modify rule."))
return return
@ -237,11 +247,11 @@ func (c *ApiController) VerifyCaptcha() {
captchaToken := c.Ctx.Request.Form.Get("captchaToken") captchaToken := c.Ctx.Request.Form.Get("captchaToken")
clientSecret := c.Ctx.Request.Form.Get("clientSecret") clientSecret := c.Ctx.Request.Form.Get("clientSecret")
if captchaToken == "" { if captchaToken == "" {
c.ResponseError(c.T("verification:Missing parameter") + ": captchaToken.") c.ResponseError(c.T("general:Missing parameter") + ": captchaToken.")
return return
} }
if clientSecret == "" { if clientSecret == "" {
c.ResponseError(c.T("verification:Missing parameter") + ": clientSecret.") c.ResponseError(c.T("general:Missing parameter") + ": clientSecret.")
return return
} }

View File

@ -35,7 +35,7 @@ func (c *ApiController) WebAuthnSignupBegin() {
webauthnObj := object.GetWebAuthnObject(c.Ctx.Request.Host) webauthnObj := object.GetWebAuthnObject(c.Ctx.Request.Host)
user := c.getCurrentUser() user := c.getCurrentUser()
if user == nil { if user == nil {
c.ResponseError(c.T("webauthn:Please login first")) c.ResponseError(c.T("general:Please login first"))
return return
} }
@ -66,7 +66,7 @@ func (c *ApiController) WebAuthnSignupFinish() {
webauthnObj := object.GetWebAuthnObject(c.Ctx.Request.Host) webauthnObj := object.GetWebAuthnObject(c.Ctx.Request.Host)
user := c.getCurrentUser() user := c.getCurrentUser()
if user == nil { if user == nil {
c.ResponseError(c.T("webauthn:Please login first")) c.ResponseError(c.T("general:Please login first"))
return return
} }
sessionObj := c.GetSession("registration") sessionObj := c.GetSession("registration")
@ -101,7 +101,7 @@ func (c *ApiController) WebAuthnSigninBegin() {
userName := c.Input().Get("name") userName := c.Input().Get("name")
user := object.GetUserByFields(userOwner, userName) user := object.GetUserByFields(userOwner, userName)
if user == nil { if user == nil {
c.ResponseError(fmt.Sprintf(c.T("webauthn:The user: %s/%s doesn't exist"), userOwner, userName)) c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(userOwner, userName)))
return return
} }
if len(user.WebauthnCredentials) == 0 { if len(user.WebauthnCredentials) == 0 {

View File

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

14
go.mod
View File

@ -9,14 +9,14 @@ require (
github.com/beego/beego v1.12.11 github.com/beego/beego v1.12.11
github.com/beevik/etree v1.1.0 github.com/beevik/etree v1.1.0
github.com/casbin/casbin/v2 v2.30.1 github.com/casbin/casbin/v2 v2.30.1
github.com/casbin/xorm-adapter/v3 v3.0.1
github.com/casdoor/go-sms-sender v0.5.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/oss v1.2.0
github.com/casdoor/xorm-adapter/v3 v3.0.4
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc github.com/denisenkom/go-mssqldb v0.9.0
github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b
github.com/forestmgy/ldapserver v1.1.0 github.com/forestmgy/ldapserver v1.1.0
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df
github.com/go-ldap/ldap/v3 v3.3.0 github.com/go-ldap/ldap/v3 v3.3.0
github.com/go-pay/gopay v1.5.72 github.com/go-pay/gopay v1.5.72
github.com/go-sql-driver/mysql v1.5.0 github.com/go-sql-driver/mysql v1.5.0
@ -41,17 +41,15 @@ require (
github.com/tealeg/xlsx v1.0.5 github.com/tealeg/xlsx v1.0.5
github.com/thanhpk/randstr v1.0.4 github.com/thanhpk/randstr v1.0.4
github.com/tklauser/go-sysconf v0.3.10 // indirect github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/xorm-io/core v0.7.4
github.com/xorm-io/xorm v1.1.6
github.com/yusufpapurcu/wmi v1.2.2 // indirect github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/crypto v0.0.0-20220214200702-86341886e292 golang.org/x/crypto v0.0.0-20220214200702-86341886e292
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914 golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df // indirect
gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/square/go-jose.v2 v2.6.0 gopkg.in/square/go-jose.v2 v2.6.0
gopkg.in/yaml.v2 v2.3.0 // indirect gopkg.in/yaml.v2 v2.3.0 // indirect
xorm.io/builder v0.3.12 // indirect modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84
xorm.io/core v0.7.2
xorm.io/xorm v1.0.5
) )

83
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.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible h1:1G1pk05UrOh0NlF1oeaaix1x8XzrfjIDK47TY0Zehcw=
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc=
github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b h1:EgJ6N2S0h1WfFIjU5/VVHWbMSVYXAluop97Qxpr/lfQ= github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b h1:EgJ6N2S0h1WfFIjU5/VVHWbMSVYXAluop97Qxpr/lfQ=
github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b/go.mod h1:3SAoF0F5EbcOuBD5WT9nYkbIJieBS84cUQXADbXeBsU= github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b/go.mod h1:3SAoF0F5EbcOuBD5WT9nYkbIJieBS84cUQXADbXeBsU=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
@ -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/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 h1:9gWa46nstkJ9miBReJcN8Gq34cBFbzSpQZVVT9N09TM=
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8= github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible/go.mod h1:T/Aws4fEfogEE9v+HPhhw+CntffsBHJ8nXQCwKr0/g8=
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY= github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
github.com/aws/aws-sdk-go v1.44.4 h1:ePN0CVJMdiz2vYUcJH96eyxRrtKGSDMgyhP6rah2OgE= github.com/aws/aws-sdk-go v1.44.4 h1:ePN0CVJMdiz2vYUcJH96eyxRrtKGSDMgyhP6rah2OgE=
github.com/aws/aws-sdk-go v1.44.4/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo= github.com/aws/aws-sdk-go v1.44.4/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
@ -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.28.3/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
github.com/casbin/casbin/v2 v2.30.1 h1:P5HWadDL7olwUXNdcuKUBk+x75Y2eitFxYTcLNKeKF0= github.com/casbin/casbin/v2 v2.30.1 h1:P5HWadDL7olwUXNdcuKUBk+x75Y2eitFxYTcLNKeKF0=
github.com/casbin/casbin/v2 v2.30.1/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg= github.com/casbin/casbin/v2 v2.30.1/go.mod h1:vByNa/Fchek0KZUgG5wEsl7iFsiviAYKRtgrQfcJqHg=
github.com/casbin/xorm-adapter/v3 v3.0.1 h1:0l0zkYxo6cNuIdrBZgFxlje1TRvmheYa/zIp+sGPK58=
github.com/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 h1:1/Wp1OLkVAVY4lEGQhekSNetSAWhnPcxYPV7xpCZgC0=
github.com/casdoor/go-sms-sender v0.5.1/go.mod h1:kBykbqwgRDXbXdMAIxmZKinVM1WjdqEbej5LAbUbcfI= 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 h1:ozLAE+nnNdFQBWbzH8U9spzaO8h8NrB57lBcdyMUUQ8=
github.com/casdoor/oss v1.2.0/go.mod h1:qii35VBuxnR/uEuYSKpS0aJ8htQFOcCVsZ4FHgHLuss= github.com/casdoor/oss v1.2.0/go.mod h1:qii35VBuxnR/uEuYSKpS0aJ8htQFOcCVsZ4FHgHLuss=
github.com/casdoor/xorm-adapter/v3 v3.0.4 h1:vB04Ao8n2jA7aFBI9F+gGXo9+Aa1IQP6mTdo50913DM=
github.com/casdoor/xorm-adapter/v3 v3.0.4/go.mod h1:4WTcUw+bTgBylGHeGHzTtBvuTXRS23dtwzFLl9tsgFM=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@ -126,10 +126,12 @@ github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f/go.mod h1:QGrK8vMWW
github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d h1:1iy2qD6JEhHKKhUOA9IWs7mjco7lnw2qx8FsRI2wirE= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d h1:1iy2qD6JEhHKKhUOA9IWs7mjco7lnw2qx8FsRI2wirE=
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.0-20210816181553-5444fa50b93d/go.mod h1:tmAIfUFEirG/Y8jhZ9M+h36obRZAk/1fcSpXwAVlfqE=
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc h1:VRRKCwnzqk8QCaRC4os14xoKDdbHqqlJtJA0oc1ZAjg= github.com/denisenkom/go-mssqldb v0.9.0 h1:RSohk2RsiZqLZ0zCjtfn3S4Gp4exhpBWHyQ7D0yGjAk=
github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU= github.com/denisenkom/go-mssqldb v0.9.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b h1:L63RATZFZuFMXy6ixnKmv3eNAXwYQF6HW1vd4IYsQqQ= github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b h1:L63RATZFZuFMXy6ixnKmv3eNAXwYQF6HW1vd4IYsQqQ=
github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b/go.mod h1:EYSpSkwoEcryMmQGfhol2IiB3IMN9IIIaNd/wcAQMGQ= github.com/duo-labs/webauthn v0.0.0-20211221191814-a22482edaa3b/go.mod h1:EYSpSkwoEcryMmQGfhol2IiB3IMN9IIIaNd/wcAQMGQ=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M= github.com/edsrzf/mmap-go v0.0.0-20170320065105-0bce6a688712/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI= github.com/elastic/go-elasticsearch/v6 v6.8.5/go.mod h1:UwaDJsD3rWLM5rKNFzv9hgox93HoX8utj1kxD9aFUcI=
github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk= github.com/elazarl/go-bindata-assetfs v1.0.0 h1:G/bYguwHIzWq9ZoyUQqrjTmJbbYn3j3CKKpKinvZLFk=
@ -151,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 v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df h1:Bao6dhmbTA1KFVxmJ6nBoMuOJit2yjEgLJpIMYpop0E=
github.com/go-gomail/gomail v0.0.0-20160411212932-81ebce5c23df/go.mod h1:GJr+FCSXshIwgHBtLglIg9M2l2kQSi6QjVAngtzI08Y=
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
github.com/go-ldap/ldap/v3 v3.3.0 h1:lwx+SJpgOHd8tG6SumBQZXCmNX51zM8B1cfxJ5gv4tQ= github.com/go-ldap/ldap/v3 v3.3.0 h1:lwx+SJpgOHd8tG6SumBQZXCmNX51zM8B1cfxJ5gv4tQ=
@ -231,6 +231,7 @@ github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@ -266,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 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da h1:FjHUJJ7oBW4G/9j1KzlHaXL09LyMVM9rupS39lncbXk=
github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4= github.com/jarcoal/httpmock v0.0.0-20180424175123-9c70cfe4a1da/go.mod h1:ks+b9deReOc7jgqp+e7LuFiCBH6Rm5hL32cLcEAArb4=
github.com/jinzhu/configor v1.2.1 h1:OKk9dsR8i6HPOCZR8BcMtcEImAFjIhbJFZNyn5GCZko= github.com/jinzhu/configor v1.2.1 h1:OKk9dsR8i6HPOCZR8BcMtcEImAFjIhbJFZNyn5GCZko=
github.com/jinzhu/configor v1.2.1/go.mod h1:nX89/MOmDba7ZX7GCyU/VIaQ2Ar2aizBl2d3JLF/rDc= github.com/jinzhu/configor v1.2.1/go.mod h1:nX89/MOmDba7ZX7GCyU/VIaQ2Ar2aizBl2d3JLF/rDc=
@ -279,14 +281,17 @@ github.com/jonboulle/clockwork v0.2.2 h1:UOGuzwb1PwsrDAObMuhUnj0p5ULPj8V/xJ7Kx9q
github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= github.com/jonboulle/clockwork v0.2.2/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8=
github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.5/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 h1:iQTw/8FWTuc7uiaSepXwyf3o52HaUYcV+Tu66S3F5GA=
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
@ -327,8 +332,10 @@ github.com/mattermost/xml-roundtrip-validator v0.0.0-20201208211235-fe770d50d911
github.com/mattermost/xml-roundtrip-validator v0.0.0-20201208211235-fe770d50d911/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To= github.com/mattermost/xml-roundtrip-validator v0.0.0-20201208211235-fe770d50d911/go.mod h1:qccnGMcpgwcNaBnxqpJpWWUiPNr5H3O8eDgGV9gT5To=
github.com/mattn/go-ieproxy v0.0.1 h1:qiyop7gCflfhwCzGyeT0gro3sF9AIg9HU98JORTkqfI= github.com/mattn/go-ieproxy v0.0.1 h1:qiyop7gCflfhwCzGyeT0gro3sF9AIg9HU98JORTkqfI=
github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E= github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
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.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 h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
@ -384,6 +391,8 @@ github.com/qiangmzsx/string-adapter/v2 v2.1.0/go.mod h1:PElPB7b7HnGKTsuADAffFpOQ
github.com/qiniu/dyn v1.3.0/go.mod h1:E8oERcm8TtwJiZvkQPbcAh0RL8jO1G0VXJMW3FAWdkk= github.com/qiniu/dyn v1.3.0/go.mod h1:E8oERcm8TtwJiZvkQPbcAh0RL8jO1G0VXJMW3FAWdkk=
github.com/qiniu/go-sdk/v7 v7.12.1/go.mod h1:btsaOc8CA3hdVloULfFdDgDc+g4f3TDZEFsDY0BLE+w= github.com/qiniu/go-sdk/v7 v7.12.1/go.mod h1:btsaOc8CA3hdVloULfFdDgDc+g4f3TDZEFsDY0BLE+w=
github.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs= github.com/qiniu/x v1.10.5/go.mod h1:03Ni9tj+N2h2aKnAz+6N0Xfl8FwMEDRC2PAlxekASDs=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
@ -444,6 +453,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/wendal/errors v0.0.0-20181209125328-7f31f4b264ec/go.mod h1:Q12BUT7DqIlHRmgv3RskH+UCM/4eqVMgI0EMmlSpAXc=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xorm-io/builder v0.3.13 h1:J4oZxt4Gjgm/Si9iKazfzYwHB/ijEOD9EHInyjOSX+M=
github.com/xorm-io/builder v0.3.13/go.mod h1:24o5riRwzre2WvjmN+LM4YpUtJg7W8MdvJ8H57rvrJA=
github.com/xorm-io/core v0.7.4 h1:qIznlqqmYNEb03ewzRXCrNkbbxpkgc/44nVF8yoFV7Y=
github.com/xorm-io/core v0.7.4/go.mod h1:GueyhafDnkB0KK0fXX/dEhr/P1EAGW0GLmoNDUEE1Mo=
github.com/xorm-io/xorm v1.1.6 h1:s4fDpUXJx8Zr/PBovXNaadn+v1P3h/U3iV4OxAkWS8s=
github.com/xorm-io/xorm v1.1.6/go.mod h1:7nsSUdmgLIcqHSSaKOzbVQiZtzIzbpGf1GGSYp6DD70=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@ -506,8 +521,8 @@ golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzB
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -539,6 +554,7 @@ golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81R
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200927032502-5d4f70055728/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200927032502-5d4f70055728/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@ -561,6 +577,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -585,6 +602,7 @@ golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -599,7 +617,10 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@ -669,10 +690,13 @@ golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE= golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
golang.org/x/tools v0.0.0-20200929161345-d7fc70abf50f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU= golang.org/x/tools v0.0.0-20200929161345-d7fc70abf50f/go.mod h1:z6u4i615ZeAfBE4XtMziQW1fSVJXACjjbWkB/mvPzlU=
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
@ -767,8 +791,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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df h1:n7WqCuqOuCbNr617RXOY0AWRXxgwEyPp2z+p0+hgMuE=
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw=
gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
@ -795,14 +817,33 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
modernc.org/cc/v3 v3.31.5-0.20210308123301-7a3e9dab9009 h1:u0oCo5b9wyLr++HF3AN9JicGhkUxJhMz51+8TIZH9N0=
modernc.org/cc/v3 v3.31.5-0.20210308123301-7a3e9dab9009/go.mod h1:0R6jl1aZlIl2avnYfbfHBS1QB6/f+16mihBObaBC878=
modernc.org/ccgo/v3 v3.9.0 h1:JbcEIqjw4Agf+0g3Tc85YvfYqkkFOv6xBwS4zkfqSoA=
modernc.org/ccgo/v3 v3.9.0/go.mod h1:nQbgkn8mwzPdp4mm6BT6+p85ugQ7FrGgIcYaE7nSrpY=
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/libc v1.7.13-0.20210308123627-12f642a52bb8/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/libc v1.8.0 h1:Pp4uv9g0csgBMpGPABKtkieF6O5MGhfGo6ZiOdlYfR8=
modernc.org/libc v1.8.0/go.mod h1:U1eq8YWr/Kc1RWCMFUWEdkTg8OTcfLw2kY8EDwl039w=
modernc.org/mathutil v1.1.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.2.2 h1:+yFk8hBprV+4c0U9GjFtL+dV3N8hOJ8JCituQcMShFY=
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.0.4 h1:utMBrFcpnQDdNsmM6asmyH/FM9TqLPS7XF7otpJmrwM=
modernc.org/memory v1.0.4/go.mod h1:nV2OApxradM3/OVbs2/0OsP6nPfakXpi50C7dcoHXlc=
modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A=
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84 h1:rgEUzE849tFlHSoeCrKyS9cZAljC+DY7MdMHKq6R6sY=
modernc.org/sqlite v1.10.1-0.20210314190707-798bbeb9bb84/go.mod h1:PGzq6qlhyYjL6uVbSgS6WoF7ZopTW/sI7+7p+mb4ZVU=
modernc.org/strutil v1.1.0 h1:+1/yCzZxY2pZwwrsbH+4T7BQMoLQ9QiBshRC9eicYsc=
modernc.org/strutil v1.1.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
modernc.org/tcl v1.5.0 h1:euZSUNfE0Fd4W8VqXI1Ly1v7fqDJoBuAV88Ea+SnaSs=
modernc.org/tcl v1.5.0/go.mod h1:gb57hj4pO8fRrK54zveIfFXBaMHK3SKJNWcmRw1cRzc=
modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.0.1-0.20210308123920-1f282aa71362/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
modernc.org/z v1.0.1 h1:WyIDpEpAIx4Hel6q/Pcgj/VhaQV5XPJ2I6ryIYbjnpc=
modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0= rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA= rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
xorm.io/builder v0.3.7/go.mod h1:aUW0S9eb9VCaPohFCH3j7czOx1PMW3i1HrSzbLYGBSE=
xorm.io/builder v0.3.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.0.5 h1:LRr5PfOUb4ODPR63YwbowkNDwcolT2LnkwP/TUaMaB0=
xorm.io/xorm v1.0.5/go.mod h1:uF9EtbhODq5kNWxMbnBEj8hRRZnlcNSz2t2N7HW/+A4=

View File

@ -26,16 +26,22 @@ import (
type I18nData map[string]map[string]string type I18nData map[string]map[string]string
var reI18n *regexp.Regexp var (
reI18nFrontend *regexp.Regexp
reI18nBackendObject *regexp.Regexp
reI18nBackendController *regexp.Regexp
)
func init() { func init() {
reI18n, _ = regexp.Compile("i18next.t\\(\"(.*?)\"\\)") reI18nFrontend, _ = regexp.Compile("i18next.t\\(\"(.*?)\"\\)")
reI18nBackendObject, _ = regexp.Compile("i18n.Translate\\((.*?)\"\\)")
reI18nBackendController, _ = regexp.Compile("c.T\\((.*?)\"\\)")
} }
func getAllI18nStrings(fileContent string) []string { func getAllI18nStringsFrontend(fileContent string) []string {
res := []string{} res := []string{}
matches := reI18n.FindAllStringSubmatch(fileContent, -1) matches := reI18nFrontend.FindAllStringSubmatch(fileContent, -1)
if matches == nil { if matches == nil {
return res return res
} }
@ -46,17 +52,39 @@ func getAllI18nStrings(fileContent string) []string {
return res return res
} }
func getAllJsFilePaths() []string { func getAllI18nStringsBackend(fileContent string, isObjectPackage bool) []string {
path := "../web/src"
res := []string{} res := []string{}
err := filepath.Walk(path, if isObjectPackage {
matches := reI18nBackendObject.FindAllStringSubmatch(fileContent, -1)
if matches == nil {
return res
}
for _, match := range matches {
match := strings.SplitN(match[1], ",", 2)
res = append(res, match[1][2:])
}
} else {
matches := reI18nBackendController.FindAllStringSubmatch(fileContent, -1)
if matches == nil {
return res
}
for _, match := range matches {
res = append(res, match[1][1:])
}
}
return res
}
func getAllFilePathsInFolder(folder string, fileSuffix string) []string {
res := []string{}
err := filepath.Walk(folder,
func(path string, info os.FileInfo, err error) error { func(path string, info os.FileInfo, err error) error {
if err != nil { if err != nil {
return err return err
} }
if !strings.HasSuffix(info.Name(), ".js") { if !strings.HasSuffix(info.Name(), fileSuffix) {
return nil return nil
} }
@ -71,12 +99,25 @@ func getAllJsFilePaths() []string {
return res return res
} }
func parseToData() *I18nData { func parseEnData(category string) *I18nData {
var paths []string
if category == "backend" {
paths = getAllFilePathsInFolder("../", ".go")
} else {
paths = getAllFilePathsInFolder("../web/src", ".js")
}
allWords := []string{} allWords := []string{}
paths := getAllJsFilePaths()
for _, path := range paths { for _, path := range paths {
fileContent := util.ReadStringFromPath(path) fileContent := util.ReadStringFromPath(path)
words := getAllI18nStrings(fileContent)
var words []string
if category == "backend" {
isObjectPackage := strings.Contains(path, "object")
words = getAllI18nStringsBackend(fileContent, isObjectPackage)
} else {
words = getAllI18nStringsFrontend(fileContent)
}
allWords = append(allWords, words...) allWords = append(allWords, words...)
} }
fmt.Printf("%v\n", allWords) fmt.Printf("%v\n", allWords)

View File

@ -1,115 +0,0 @@
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package i18n
import (
"os"
"path/filepath"
"regexp"
"strings"
"github.com/casdoor/casdoor/util"
)
var (
reI18nBackendObject *regexp.Regexp
re18nBackendController *regexp.Regexp
)
func init() {
reI18nBackendObject, _ = regexp.Compile("i18n.Translate\\((.*?)\"\\)")
re18nBackendController, _ = regexp.Compile("c.T\\((.*?)\"\\)")
}
func GetAllI18nStrings(fileContent string, path string) []string {
res := []string{}
if strings.Contains(path, "object") {
matches := reI18nBackendObject.FindAllStringSubmatch(fileContent, -1)
if matches == nil {
return res
}
for _, match := range matches {
match := strings.SplitN(match[1], ",", 2)
res = append(res, match[1][2:])
}
} else {
matches := re18nBackendController.FindAllStringSubmatch(fileContent, -1)
if matches == nil {
return res
}
for _, match := range matches {
res = append(res, match[1][1:])
}
}
return res
}
func getAllGoFilePaths() []string {
path := "../"
res := []string{}
err := filepath.Walk(path,
func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if !strings.HasSuffix(info.Name(), ".go") {
return nil
}
res = append(res, path)
// fmt.Println(path, info.Name())
return nil
})
if err != nil {
panic(err)
}
return res
}
func getErrName(paths []string) map[string]string {
ErrName := make(map[string]string)
for i := 0; i < len(paths); i++ {
content := util.ReadStringFromPath(paths[i])
words := GetAllI18nStrings(content, paths[i])
for j := 0; j < len(words); j++ {
ErrName[words[j]] = paths[i]
}
}
return ErrName
}
func getI18nJSONData(errName map[string]string) *I18nData {
data := I18nData{}
for k, v := range errName {
var index int
if strings.Contains(v, "/") {
index = strings.LastIndex(v, "/")
} else {
index = strings.LastIndex(v, "\\")
}
namespace := v[index+1 : len(v)-3]
key := k[len(namespace)+1:]
// fmt.Printf("k=%s,v=%s,namespace=%s,key=%s\n", k, v, namespace, key)
if _, ok := data[namespace]; !ok {
data[namespace] = map[string]string{}
}
data[namespace][key] = key
}
return &data
}

View File

@ -15,50 +15,39 @@
package i18n package i18n
import ( import (
"fmt"
"testing" "testing"
) )
func applyToOtherLanguage(dataEn *I18nData, lang string) { func applyToOtherLanguage(category string, language string, i18nData *I18nData) {
dataOther := readI18nFile(lang) newData := readI18nFile(category, language)
println(dataOther) println(newData)
applyData(dataEn, dataOther) applyData(i18nData, newData)
writeI18nFile(lang, dataEn) writeI18nFile(category, language, i18nData)
} }
func TestGenerateI18nStringsForFrontend(t *testing.T) { func TestGenerateI18nFrontend(t *testing.T) {
dataEn := parseToData() enData := parseEnData("frontend")
writeI18nFile("en", dataEn) writeI18nFile("frontend", "en", enData)
applyToOtherLanguage(dataEn, "de") applyToOtherLanguage("frontend", "de", enData)
applyToOtherLanguage(dataEn, "fr") applyToOtherLanguage("frontend", "es", enData)
applyToOtherLanguage(dataEn, "ja") applyToOtherLanguage("frontend", "fr", enData)
applyToOtherLanguage(dataEn, "ko") applyToOtherLanguage("frontend", "ja", enData)
applyToOtherLanguage(dataEn, "ru") applyToOtherLanguage("frontend", "ko", enData)
applyToOtherLanguage(dataEn, "zh") applyToOtherLanguage("frontend", "ru", enData)
applyToOtherLanguage("frontend", "zh", enData)
} }
func TestGenerateI18nStringsForBackend(t *testing.T) { func TestGenerateI18nBackend(t *testing.T) {
paths := getAllGoFilePaths() enData := parseEnData("backend")
writeI18nFile("backend", "en", enData)
errName := getErrName(paths) applyToOtherLanguage("backend", "de", enData)
applyToOtherLanguage("backend", "es", enData)
dataEn := getI18nJSONData(errName) applyToOtherLanguage("backend", "fr", enData)
applyToOtherLanguage("backend", "ja", enData)
writeI18nFile("backend_en", dataEn) applyToOtherLanguage("backend", "ko", enData)
applyToOtherLanguage("backend", "ru", enData)
applyToOtherLanguage(dataEn, "backend_de") applyToOtherLanguage("backend", "zh", enData)
applyToOtherLanguage(dataEn, "backend_es")
applyToOtherLanguage(dataEn, "backend_fr")
applyToOtherLanguage(dataEn, "backend_ja")
applyToOtherLanguage(dataEn, "backend_ko")
applyToOtherLanguage(dataEn, "backend_ru")
applyToOtherLanguage(dataEn, "backend_zh")
fmt.Println("Total Err Words:", len(errName))
for i := range errName {
fmt.Println(i)
}
} }

View File

@ -4,23 +4,17 @@
"Get init score failed, error: %w": "Get init score failed, error: %w", "Get init score failed, error: %w": "Get init score failed, error: %w",
"Invalid information": "Invalid information", "Invalid information": "Invalid information",
"Phone: %s": "Phone: %s", "Phone: %s": "Phone: %s",
"Please sign out first before signing in": "Please sign out first before signing in",
"Please sign out first before signing up": "Please sign out first before signing up", "Please sign out first before signing up": "Please sign out first before signing up",
"The application does not allow to sign up new account": "The application does not allow to sign up new account" "The application does not allow to sign up new account": "The application does not allow to sign up new account"
}, },
"application": {
"Parameter organization is missing": "Parameter organization is missing",
"The user: %s doesn't exist": "The user: %s doesn't exist"
},
"auth": { "auth": {
"%s No phone prefix": "%s No phone prefix", "%s No phone prefix": "%s No phone prefix",
"Challenge method should be S256": "Challenge method should be S256", "Challenge method should be S256": "Challenge method should be S256",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s", "Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s", "Failed to login in: %s": "Failed to login in: %s",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Invalid token": "Invalid token", "Invalid token": "Invalid token",
"Please sign out first before signing in": "Please sign out first before signing in",
"State expected: %s, but got: %s": "State expected: %s, but got: %s", "State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account does not exist": "The account does not exist",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up", "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support", "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)", "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
@ -29,7 +23,6 @@
"The provider type: %s is not supported": "The provider type: %s is not supported", "The provider type: %s is not supported": "The provider type: %s is not supported",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application", "The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator", "The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s/%s doesn't exist": "The user: %s/%s doesn't exist",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unauthorized operation": "Unauthorized operation", "Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s" "Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s"
@ -54,11 +47,8 @@
"Phone already exists": "Phone already exists", "Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty", "Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid", "Phone number is invalid": "Phone number is invalid",
"Please login first": "Please login first",
"Session outdated, please login again": "Session outdated, please login again", "Session outdated, please login again": "Session outdated, please login again",
"The user doesn't exist": "The user doesn't exist",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator", "The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.", "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"Username already exists": "Username already exists", "Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address", "Username cannot be an email address": "Username cannot be an email address",
@ -66,20 +56,17 @@
"Username cannot start with a digit": "Username cannot start with a digit", "Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You don't have the permission to do this": "You don't have the permission to do this", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"You have entered the wrong password too many times, please wait for %d minutes %d seconds and try again": "You have entered the wrong password too many times, please wait for %d minutes %d seconds and try again", "password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s" "unsupported password type: %s": "unsupported password type: %s"
}, },
"check_util": { "general": {
"You have entered the wrong password too many times, please wait for %d minutes and try again": "You have entered the wrong password too many times, please wait for %d minutes and try again", "Missing parameter": "Missing parameter",
"password is incorrect, you have %d remaining chances": "password is incorrect, you have %d remaining chances" "Please login first": "Please login first",
}, "The user: %s doesn't exist": "The user: %s doesn't exist"
"enforcer": {
"Please sign in first": "Please sign in first"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist", "Ldap server exist": "Ldap server exist"
"Missing parameter": "Missing parameter"
}, },
"link": { "link": {
"Please link first": "Please link first", "Please link first": "Please link first",
@ -94,10 +81,6 @@
"The %s is immutable.": "The %s is immutable.", "The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s." "Unknown modify rule %s.": "Unknown modify rule %s."
}, },
"product": {
"Please login first": "Please login first",
"The user: %s doesn't exist": "The user: %s doesn't exist"
},
"provider": { "provider": {
"Invalid application id": "Invalid application id", "Invalid application id": "Invalid application id",
"the provider: %s does not exist": "the provider: %s does not exist" "the provider: %s does not exist": "the provider: %s does not exist"
@ -121,22 +104,18 @@
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed", "The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported" "The provider type: %s is not supported": "The provider type: %s is not supported"
}, },
"system_info": {
"You are not authorized to access this resource": "You are not authorized to access this resource"
},
"token": { "token": {
"Challenge method should be S256": "Challenge method should be S256",
"Empty clientId or clientSecret": "Empty clientId or clientSecret", "Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application", "Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret", "Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id", "Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list" "Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
}, },
"user": { "user": {
"Display name cannot be empty": "Display name cannot be empty", "Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space.", "New password cannot contain blank space.": "New password cannot contain blank space.",
"New password must have at least 6 characters": "New password must have at least 6 characters", "New password must have at least 6 characters": "New password must have at least 6 characters"
"The user: %s/%s doesn't exist": "The user: %s/%s doesn't exist"
}, },
"user_upload": { "user_upload": {
"Failed to import users": "Failed to import users" "Failed to import users": "Failed to import users"
@ -144,18 +123,14 @@
"util": { "util": {
"No application is found for userId: %s": "No application is found for userId: %s", "No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s", "No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
"Please login first": "Please login first", "The provider: %s is not found": "The provider: %s is not found"
"The provider: %s is not found": "The provider: %s is not found",
"The user: %s doesn't exist": "The user: %s doesn't exist"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Code has not been sent yet!", "Code has not been sent yet!": "Code has not been sent yet!",
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Missing parameter": "Missing parameter",
"Organization does not exist": "Organization does not exist", "Organization does not exist": "Organization does not exist",
"Phone number is invalid": "Phone number is invalid", "Phone number is invalid": "Phone number is invalid",
"Please login first": "Please login first",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
@ -166,8 +141,6 @@
}, },
"webauthn": { "webauthn": {
"Found no credentials for this user": "Found no credentials for this user", "Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first", "Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
"Please login first": "Please login first",
"The user: %s/%s doesn't exist": "The user: %s/%s doesn't exist"
} }
} }

View File

@ -4,23 +4,17 @@
"Get init score failed, error: %w": "Get init score failed, error: %w", "Get init score failed, error: %w": "Get init score failed, error: %w",
"Invalid information": "Invalid information", "Invalid information": "Invalid information",
"Phone: %s": "Phone: %s", "Phone: %s": "Phone: %s",
"Please sign out first before signing in": "Please sign out first before signing in",
"Please sign out first before signing up": "Please sign out first before signing up", "Please sign out first before signing up": "Please sign out first before signing up",
"The application does not allow to sign up new account": "The application does not allow to sign up new account" "The application does not allow to sign up new account": "The application does not allow to sign up new account"
}, },
"application": {
"Parameter organization is missing": "Parameter organization is missing",
"The user: %s doesn't exist": "The user: %s doesn't exist"
},
"auth": { "auth": {
"%s No phone prefix": "%s No phone prefix", "%s No phone prefix": "%s No phone prefix",
"Challenge method should be S256": "Challenge method should be S256", "Challenge method should be S256": "Challenge method should be S256",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s", "Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s", "Failed to login in: %s": "Failed to login in: %s",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Invalid token": "Invalid token", "Invalid token": "Invalid token",
"Please sign out first before signing in": "Please sign out first before signing in",
"State expected: %s, but got: %s": "State expected: %s, but got: %s", "State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account does not exist": "The account does not exist",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up", "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support", "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)", "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
@ -29,7 +23,6 @@
"The provider type: %s is not supported": "The provider type: %s is not supported", "The provider type: %s is not supported": "The provider type: %s is not supported",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application", "The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator", "The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s/%s doesn't exist": "The user: %s/%s doesn't exist",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unauthorized operation": "Unauthorized operation", "Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s" "Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s"
@ -54,11 +47,8 @@
"Phone already exists": "Phone already exists", "Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty", "Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid", "Phone number is invalid": "Phone number is invalid",
"Please login first": "Please login first",
"Session outdated, please login again": "Session outdated, please login again", "Session outdated, please login again": "Session outdated, please login again",
"The user doesn't exist": "The user doesn't exist",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator", "The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.", "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"Username already exists": "Username already exists", "Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address", "Username cannot be an email address": "Username cannot be an email address",
@ -66,20 +56,17 @@
"Username cannot start with a digit": "Username cannot start with a digit", "Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You don't have the permission to do this": "You don't have the permission to do this", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"You have entered the wrong password too many times, please wait for %d minutes %d seconds and try again": "You have entered the wrong password too many times, please wait for %d minutes %d seconds and try again", "password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s" "unsupported password type: %s": "unsupported password type: %s"
}, },
"check_util": { "general": {
"You have entered the wrong password too many times, please wait for %d minutes and try again": "You have entered the wrong password too many times, please wait for %d minutes and try again", "Missing parameter": "Missing parameter",
"password is incorrect, you have %d remaining chances": "password is incorrect, you have %d remaining chances" "Please login first": "Please login first",
}, "The user: %s doesn't exist": "The user: %s doesn't exist"
"enforcer": {
"Please sign in first": "Please sign in first"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist", "Ldap server exist": "Ldap server exist"
"Missing parameter": "Missing parameter"
}, },
"link": { "link": {
"Please link first": "Please link first", "Please link first": "Please link first",
@ -94,10 +81,6 @@
"The %s is immutable.": "The %s is immutable.", "The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s." "Unknown modify rule %s.": "Unknown modify rule %s."
}, },
"product": {
"Please login first": "Please login first",
"The user: %s doesn't exist": "The user: %s doesn't exist"
},
"provider": { "provider": {
"Invalid application id": "Invalid application id", "Invalid application id": "Invalid application id",
"the provider: %s does not exist": "the provider: %s does not exist" "the provider: %s does not exist": "the provider: %s does not exist"
@ -121,22 +104,18 @@
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed", "The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported" "The provider type: %s is not supported": "The provider type: %s is not supported"
}, },
"system_info": {
"You are not authorized to access this resource": "You are not authorized to access this resource"
},
"token": { "token": {
"Challenge method should be S256": "Challenge method should be S256",
"Empty clientId or clientSecret": "Empty clientId or clientSecret", "Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application", "Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret", "Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id", "Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list" "Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
}, },
"user": { "user": {
"Display name cannot be empty": "Display name cannot be empty", "Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space.", "New password cannot contain blank space.": "New password cannot contain blank space.",
"New password must have at least 6 characters": "New password must have at least 6 characters", "New password must have at least 6 characters": "New password must have at least 6 characters"
"The user: %s/%s doesn't exist": "The user: %s/%s doesn't exist"
}, },
"user_upload": { "user_upload": {
"Failed to import users": "Failed to import users" "Failed to import users": "Failed to import users"
@ -144,18 +123,14 @@
"util": { "util": {
"No application is found for userId: %s": "No application is found for userId: %s", "No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s", "No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
"Please login first": "Please login first", "The provider: %s is not found": "The provider: %s is not found"
"The provider: %s is not found": "The provider: %s is not found",
"The user: %s doesn't exist": "The user: %s doesn't exist"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Code has not been sent yet!", "Code has not been sent yet!": "Code has not been sent yet!",
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Missing parameter": "Missing parameter",
"Organization does not exist": "Organization does not exist", "Organization does not exist": "Organization does not exist",
"Phone number is invalid": "Phone number is invalid", "Phone number is invalid": "Phone number is invalid",
"Please login first": "Please login first",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
@ -166,8 +141,6 @@
}, },
"webauthn": { "webauthn": {
"Found no credentials for this user": "Found no credentials for this user", "Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first", "Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
"Please login first": "Please login first",
"The user: %s/%s doesn't exist": "The user: %s/%s doesn't exist"
} }
} }

View File

@ -4,23 +4,17 @@
"Get init score failed, error: %w": "Get init score failed, error: %w", "Get init score failed, error: %w": "Get init score failed, error: %w",
"Invalid information": "Invalid information", "Invalid information": "Invalid information",
"Phone: %s": "Phone: %s", "Phone: %s": "Phone: %s",
"Please sign out first before signing in": "Please sign out first before signing in",
"Please sign out first before signing up": "Please sign out first before signing up", "Please sign out first before signing up": "Please sign out first before signing up",
"The application does not allow to sign up new account": "The application does not allow to sign up new account" "The application does not allow to sign up new account": "The application does not allow to sign up new account"
}, },
"application": {
"Parameter organization is missing": "Parameter organization is missing",
"The user: %s doesn't exist": "The user: %s doesn't exist"
},
"auth": { "auth": {
"%s No phone prefix": "%s No phone prefix", "%s No phone prefix": "%s No phone prefix",
"Challenge method should be S256": "Challenge method should be S256", "Challenge method should be S256": "Challenge method should be S256",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s", "Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s", "Failed to login in: %s": "Failed to login in: %s",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Invalid token": "Invalid token", "Invalid token": "Invalid token",
"Please sign out first before signing in": "Please sign out first before signing in",
"State expected: %s, but got: %s": "State expected: %s, but got: %s", "State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account does not exist": "The account does not exist",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up", "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support", "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)", "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
@ -29,7 +23,6 @@
"The provider type: %s is not supported": "The provider type: %s is not supported", "The provider type: %s is not supported": "The provider type: %s is not supported",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application", "The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator", "The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s/%s doesn't exist": "The user: %s/%s doesn't exist",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unauthorized operation": "Unauthorized operation", "Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s" "Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s"
@ -54,11 +47,8 @@
"Phone already exists": "Phone already exists", "Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty", "Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid", "Phone number is invalid": "Phone number is invalid",
"Please login first": "Please login first",
"Session outdated, please login again": "Session outdated, please login again", "Session outdated, please login again": "Session outdated, please login again",
"The user doesn't exist": "The user doesn't exist",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator", "The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.", "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"Username already exists": "Username already exists", "Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address", "Username cannot be an email address": "Username cannot be an email address",
@ -66,20 +56,17 @@
"Username cannot start with a digit": "Username cannot start with a digit", "Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You don't have the permission to do this": "You don't have the permission to do this", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"You have entered the wrong password too many times, please wait for %d minutes %d seconds and try again": "You have entered the wrong password too many times, please wait for %d minutes %d seconds and try again", "password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s" "unsupported password type: %s": "unsupported password type: %s"
}, },
"check_util": { "general": {
"You have entered the wrong password too many times, please wait for %d minutes and try again": "You have entered the wrong password too many times, please wait for %d minutes and try again", "Missing parameter": "Missing parameter",
"password is incorrect, you have %d remaining chances": "password is incorrect, you have %d remaining chances" "Please login first": "Please login first",
}, "The user: %s doesn't exist": "The user: %s doesn't exist"
"enforcer": {
"Please sign in first": "Please sign in first"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist", "Ldap server exist": "Ldap server exist"
"Missing parameter": "Missing parameter"
}, },
"link": { "link": {
"Please link first": "Please link first", "Please link first": "Please link first",
@ -94,10 +81,6 @@
"The %s is immutable.": "The %s is immutable.", "The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s." "Unknown modify rule %s.": "Unknown modify rule %s."
}, },
"product": {
"Please login first": "Please login first",
"The user: %s doesn't exist": "The user: %s doesn't exist"
},
"provider": { "provider": {
"Invalid application id": "Invalid application id", "Invalid application id": "Invalid application id",
"the provider: %s does not exist": "the provider: %s does not exist" "the provider: %s does not exist": "the provider: %s does not exist"
@ -121,22 +104,18 @@
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed", "The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported" "The provider type: %s is not supported": "The provider type: %s is not supported"
}, },
"system_info": {
"You are not authorized to access this resource": "You are not authorized to access this resource"
},
"token": { "token": {
"Challenge method should be S256": "Challenge method should be S256",
"Empty clientId or clientSecret": "Empty clientId or clientSecret", "Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application", "Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret", "Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id", "Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list" "Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
}, },
"user": { "user": {
"Display name cannot be empty": "Display name cannot be empty", "Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space.", "New password cannot contain blank space.": "New password cannot contain blank space.",
"New password must have at least 6 characters": "New password must have at least 6 characters", "New password must have at least 6 characters": "New password must have at least 6 characters"
"The user: %s/%s doesn't exist": "The user: %s/%s doesn't exist"
}, },
"user_upload": { "user_upload": {
"Failed to import users": "Failed to import users" "Failed to import users": "Failed to import users"
@ -144,18 +123,14 @@
"util": { "util": {
"No application is found for userId: %s": "No application is found for userId: %s", "No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s", "No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
"Please login first": "Please login first", "The provider: %s is not found": "The provider: %s is not found"
"The provider: %s is not found": "The provider: %s is not found",
"The user: %s doesn't exist": "The user: %s doesn't exist"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Code has not been sent yet!", "Code has not been sent yet!": "Code has not been sent yet!",
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Missing parameter": "Missing parameter",
"Organization does not exist": "Organization does not exist", "Organization does not exist": "Organization does not exist",
"Phone number is invalid": "Phone number is invalid", "Phone number is invalid": "Phone number is invalid",
"Please login first": "Please login first",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
@ -166,8 +141,6 @@
}, },
"webauthn": { "webauthn": {
"Found no credentials for this user": "Found no credentials for this user", "Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first", "Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
"Please login first": "Please login first",
"The user: %s/%s doesn't exist": "The user: %s/%s doesn't exist"
} }
} }

View File

@ -4,23 +4,17 @@
"Get init score failed, error: %w": "Get init score failed, error: %w", "Get init score failed, error: %w": "Get init score failed, error: %w",
"Invalid information": "Invalid information", "Invalid information": "Invalid information",
"Phone: %s": "Phone: %s", "Phone: %s": "Phone: %s",
"Please sign out first before signing in": "Please sign out first before signing in",
"Please sign out first before signing up": "Please sign out first before signing up", "Please sign out first before signing up": "Please sign out first before signing up",
"The application does not allow to sign up new account": "The application does not allow to sign up new account" "The application does not allow to sign up new account": "The application does not allow to sign up new account"
}, },
"application": {
"Parameter organization is missing": "Parameter organization is missing",
"The user: %s doesn't exist": "The user: %s doesn't exist"
},
"auth": { "auth": {
"%s No phone prefix": "%s No phone prefix", "%s No phone prefix": "%s No phone prefix",
"Challenge method should be S256": "Challenge method should be S256", "Challenge method should be S256": "Challenge method should be S256",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s", "Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s", "Failed to login in: %s": "Failed to login in: %s",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Invalid token": "Invalid token", "Invalid token": "Invalid token",
"Please sign out first before signing in": "Please sign out first before signing in",
"State expected: %s, but got: %s": "State expected: %s, but got: %s", "State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account does not exist": "The account does not exist",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up", "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support", "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)", "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
@ -29,7 +23,6 @@
"The provider type: %s is not supported": "The provider type: %s is not supported", "The provider type: %s is not supported": "The provider type: %s is not supported",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application", "The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator", "The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s/%s doesn't exist": "The user: %s/%s doesn't exist",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unauthorized operation": "Unauthorized operation", "Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s" "Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s"
@ -54,11 +47,8 @@
"Phone already exists": "Phone already exists", "Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty", "Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid", "Phone number is invalid": "Phone number is invalid",
"Please login first": "Please login first",
"Session outdated, please login again": "Session outdated, please login again", "Session outdated, please login again": "Session outdated, please login again",
"The user doesn't exist": "The user doesn't exist",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator", "The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.", "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"Username already exists": "Username already exists", "Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address", "Username cannot be an email address": "Username cannot be an email address",
@ -66,20 +56,17 @@
"Username cannot start with a digit": "Username cannot start with a digit", "Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You don't have the permission to do this": "You don't have the permission to do this", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"You have entered the wrong password too many times, please wait for %d minutes %d seconds and try again": "You have entered the wrong password too many times, please wait for %d minutes %d seconds and try again", "password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s" "unsupported password type: %s": "unsupported password type: %s"
}, },
"check_util": { "general": {
"You have entered the wrong password too many times, please wait for %d minutes and try again": "You have entered the wrong password too many times, please wait for %d minutes and try again", "Missing parameter": "Missing parameter",
"password is incorrect, you have %d remaining chances": "password is incorrect, you have %d remaining chances" "Please login first": "Please login first",
}, "The user: %s doesn't exist": "The user: %s doesn't exist"
"enforcer": {
"Please sign in first": "Please sign in first"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist", "Ldap server exist": "Ldap server exist"
"Missing parameter": "Missing parameter"
}, },
"link": { "link": {
"Please link first": "Please link first", "Please link first": "Please link first",
@ -94,10 +81,6 @@
"The %s is immutable.": "The %s is immutable.", "The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s." "Unknown modify rule %s.": "Unknown modify rule %s."
}, },
"product": {
"Please login first": "Please login first",
"The user: %s doesn't exist": "The user: %s doesn't exist"
},
"provider": { "provider": {
"Invalid application id": "Invalid application id", "Invalid application id": "Invalid application id",
"the provider: %s does not exist": "the provider: %s does not exist" "the provider: %s does not exist": "the provider: %s does not exist"
@ -121,22 +104,18 @@
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed", "The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported" "The provider type: %s is not supported": "The provider type: %s is not supported"
}, },
"system_info": {
"You are not authorized to access this resource": "You are not authorized to access this resource"
},
"token": { "token": {
"Challenge method should be S256": "Challenge method should be S256",
"Empty clientId or clientSecret": "Empty clientId or clientSecret", "Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application", "Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret", "Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id", "Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list" "Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
}, },
"user": { "user": {
"Display name cannot be empty": "Display name cannot be empty", "Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space.", "New password cannot contain blank space.": "New password cannot contain blank space.",
"New password must have at least 6 characters": "New password must have at least 6 characters", "New password must have at least 6 characters": "New password must have at least 6 characters"
"The user: %s/%s doesn't exist": "The user: %s/%s doesn't exist"
}, },
"user_upload": { "user_upload": {
"Failed to import users": "Failed to import users" "Failed to import users": "Failed to import users"
@ -144,18 +123,14 @@
"util": { "util": {
"No application is found for userId: %s": "No application is found for userId: %s", "No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s", "No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
"Please login first": "Please login first", "The provider: %s is not found": "The provider: %s is not found"
"The provider: %s is not found": "The provider: %s is not found",
"The user: %s doesn't exist": "The user: %s doesn't exist"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Code has not been sent yet!", "Code has not been sent yet!": "Code has not been sent yet!",
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Missing parameter": "Missing parameter",
"Organization does not exist": "Organization does not exist", "Organization does not exist": "Organization does not exist",
"Phone number is invalid": "Phone number is invalid", "Phone number is invalid": "Phone number is invalid",
"Please login first": "Please login first",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
@ -166,8 +141,6 @@
}, },
"webauthn": { "webauthn": {
"Found no credentials for this user": "Found no credentials for this user", "Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first", "Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
"Please login first": "Please login first",
"The user: %s/%s doesn't exist": "The user: %s/%s doesn't exist"
} }
} }

View File

@ -4,23 +4,17 @@
"Get init score failed, error: %w": "Get init score failed, error: %w", "Get init score failed, error: %w": "Get init score failed, error: %w",
"Invalid information": "Invalid information", "Invalid information": "Invalid information",
"Phone: %s": "Phone: %s", "Phone: %s": "Phone: %s",
"Please sign out first before signing in": "Please sign out first before signing in",
"Please sign out first before signing up": "Please sign out first before signing up", "Please sign out first before signing up": "Please sign out first before signing up",
"The application does not allow to sign up new account": "The application does not allow to sign up new account" "The application does not allow to sign up new account": "The application does not allow to sign up new account"
}, },
"application": {
"Parameter organization is missing": "Parameter organization is missing",
"The user: %s doesn't exist": "The user: %s doesn't exist"
},
"auth": { "auth": {
"%s No phone prefix": "%s No phone prefix", "%s No phone prefix": "%s No phone prefix",
"Challenge method should be S256": "Challenge method should be S256", "Challenge method should be S256": "Challenge method should be S256",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s", "Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s", "Failed to login in: %s": "Failed to login in: %s",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Invalid token": "Invalid token", "Invalid token": "Invalid token",
"Please sign out first before signing in": "Please sign out first before signing in",
"State expected: %s, but got: %s": "State expected: %s, but got: %s", "State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account does not exist": "The account does not exist",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up", "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support", "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)", "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
@ -29,7 +23,6 @@
"The provider type: %s is not supported": "The provider type: %s is not supported", "The provider type: %s is not supported": "The provider type: %s is not supported",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application", "The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator", "The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s/%s doesn't exist": "The user: %s/%s doesn't exist",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unauthorized operation": "Unauthorized operation", "Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s" "Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s"
@ -54,11 +47,8 @@
"Phone already exists": "Phone already exists", "Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty", "Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid", "Phone number is invalid": "Phone number is invalid",
"Please login first": "Please login first",
"Session outdated, please login again": "Session outdated, please login again", "Session outdated, please login again": "Session outdated, please login again",
"The user doesn't exist": "The user doesn't exist",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator", "The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.", "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"Username already exists": "Username already exists", "Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address", "Username cannot be an email address": "Username cannot be an email address",
@ -66,20 +56,17 @@
"Username cannot start with a digit": "Username cannot start with a digit", "Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You don't have the permission to do this": "You don't have the permission to do this", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"You have entered the wrong password too many times, please wait for %d minutes %d seconds and try again": "You have entered the wrong password too many times, please wait for %d minutes %d seconds and try again", "password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s" "unsupported password type: %s": "unsupported password type: %s"
}, },
"check_util": { "general": {
"You have entered the wrong password too many times, please wait for %d minutes and try again": "You have entered the wrong password too many times, please wait for %d minutes and try again", "Missing parameter": "Missing parameter",
"password is incorrect, you have %d remaining chances": "password is incorrect, you have %d remaining chances" "Please login first": "Please login first",
}, "The user: %s doesn't exist": "The user: %s doesn't exist"
"enforcer": {
"Please sign in first": "Please sign in first"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist", "Ldap server exist": "Ldap server exist"
"Missing parameter": "Missing parameter"
}, },
"link": { "link": {
"Please link first": "Please link first", "Please link first": "Please link first",
@ -94,10 +81,6 @@
"The %s is immutable.": "The %s is immutable.", "The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s." "Unknown modify rule %s.": "Unknown modify rule %s."
}, },
"product": {
"Please login first": "Please login first",
"The user: %s doesn't exist": "The user: %s doesn't exist"
},
"provider": { "provider": {
"Invalid application id": "Invalid application id", "Invalid application id": "Invalid application id",
"the provider: %s does not exist": "the provider: %s does not exist" "the provider: %s does not exist": "the provider: %s does not exist"
@ -121,22 +104,18 @@
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed", "The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported" "The provider type: %s is not supported": "The provider type: %s is not supported"
}, },
"system_info": {
"You are not authorized to access this resource": "You are not authorized to access this resource"
},
"token": { "token": {
"Challenge method should be S256": "Challenge method should be S256",
"Empty clientId or clientSecret": "Empty clientId or clientSecret", "Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application", "Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret", "Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id", "Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list" "Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
}, },
"user": { "user": {
"Display name cannot be empty": "Display name cannot be empty", "Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space.", "New password cannot contain blank space.": "New password cannot contain blank space.",
"New password must have at least 6 characters": "New password must have at least 6 characters", "New password must have at least 6 characters": "New password must have at least 6 characters"
"The user: %s/%s doesn't exist": "The user: %s/%s doesn't exist"
}, },
"user_upload": { "user_upload": {
"Failed to import users": "Failed to import users" "Failed to import users": "Failed to import users"
@ -144,18 +123,14 @@
"util": { "util": {
"No application is found for userId: %s": "No application is found for userId: %s", "No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s", "No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
"Please login first": "Please login first", "The provider: %s is not found": "The provider: %s is not found"
"The provider: %s is not found": "The provider: %s is not found",
"The user: %s doesn't exist": "The user: %s doesn't exist"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Code has not been sent yet!", "Code has not been sent yet!": "Code has not been sent yet!",
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Missing parameter": "Missing parameter",
"Organization does not exist": "Organization does not exist", "Organization does not exist": "Organization does not exist",
"Phone number is invalid": "Phone number is invalid", "Phone number is invalid": "Phone number is invalid",
"Please login first": "Please login first",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
@ -166,8 +141,6 @@
}, },
"webauthn": { "webauthn": {
"Found no credentials for this user": "Found no credentials for this user", "Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first", "Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
"Please login first": "Please login first",
"The user: %s/%s doesn't exist": "The user: %s/%s doesn't exist"
} }
} }

View File

@ -4,23 +4,17 @@
"Get init score failed, error: %w": "Get init score failed, error: %w", "Get init score failed, error: %w": "Get init score failed, error: %w",
"Invalid information": "Invalid information", "Invalid information": "Invalid information",
"Phone: %s": "Phone: %s", "Phone: %s": "Phone: %s",
"Please sign out first before signing in": "Please sign out first before signing in",
"Please sign out first before signing up": "Please sign out first before signing up", "Please sign out first before signing up": "Please sign out first before signing up",
"The application does not allow to sign up new account": "The application does not allow to sign up new account" "The application does not allow to sign up new account": "The application does not allow to sign up new account"
}, },
"application": {
"Parameter organization is missing": "Parameter organization is missing",
"The user: %s doesn't exist": "The user: %s doesn't exist"
},
"auth": { "auth": {
"%s No phone prefix": "%s No phone prefix", "%s No phone prefix": "%s No phone prefix",
"Challenge method should be S256": "Challenge method should be S256", "Challenge method should be S256": "Challenge method should be S256",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s", "Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s", "Failed to login in: %s": "Failed to login in: %s",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Invalid token": "Invalid token", "Invalid token": "Invalid token",
"Please sign out first before signing in": "Please sign out first before signing in",
"State expected: %s, but got: %s": "State expected: %s, but got: %s", "State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account does not exist": "The account does not exist",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up", "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support", "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)", "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
@ -29,7 +23,6 @@
"The provider type: %s is not supported": "The provider type: %s is not supported", "The provider type: %s is not supported": "The provider type: %s is not supported",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application", "The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator", "The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s/%s doesn't exist": "The user: %s/%s doesn't exist",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unauthorized operation": "Unauthorized operation", "Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s" "Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s"
@ -54,11 +47,8 @@
"Phone already exists": "Phone already exists", "Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty", "Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid", "Phone number is invalid": "Phone number is invalid",
"Please login first": "Please login first",
"Session outdated, please login again": "Session outdated, please login again", "Session outdated, please login again": "Session outdated, please login again",
"The user doesn't exist": "The user doesn't exist",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator", "The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.", "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"Username already exists": "Username already exists", "Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address", "Username cannot be an email address": "Username cannot be an email address",
@ -66,20 +56,17 @@
"Username cannot start with a digit": "Username cannot start with a digit", "Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You don't have the permission to do this": "You don't have the permission to do this", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"You have entered the wrong password too many times, please wait for %d minutes %d seconds and try again": "You have entered the wrong password too many times, please wait for %d minutes %d seconds and try again", "password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s" "unsupported password type: %s": "unsupported password type: %s"
}, },
"check_util": { "general": {
"You have entered the wrong password too many times, please wait for %d minutes and try again": "You have entered the wrong password too many times, please wait for %d minutes and try again", "Missing parameter": "Missing parameter",
"password is incorrect, you have %d remaining chances": "password is incorrect, you have %d remaining chances" "Please login first": "Please login first",
}, "The user: %s doesn't exist": "The user: %s doesn't exist"
"enforcer": {
"Please sign in first": "Please sign in first"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist", "Ldap server exist": "Ldap server exist"
"Missing parameter": "Missing parameter"
}, },
"link": { "link": {
"Please link first": "Please link first", "Please link first": "Please link first",
@ -94,10 +81,6 @@
"The %s is immutable.": "The %s is immutable.", "The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s." "Unknown modify rule %s.": "Unknown modify rule %s."
}, },
"product": {
"Please login first": "Please login first",
"The user: %s doesn't exist": "The user: %s doesn't exist"
},
"provider": { "provider": {
"Invalid application id": "Invalid application id", "Invalid application id": "Invalid application id",
"the provider: %s does not exist": "the provider: %s does not exist" "the provider: %s does not exist": "the provider: %s does not exist"
@ -121,22 +104,18 @@
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed", "The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported" "The provider type: %s is not supported": "The provider type: %s is not supported"
}, },
"system_info": {
"You are not authorized to access this resource": "You are not authorized to access this resource"
},
"token": { "token": {
"Challenge method should be S256": "Challenge method should be S256",
"Empty clientId or clientSecret": "Empty clientId or clientSecret", "Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application", "Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret", "Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id", "Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list" "Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
}, },
"user": { "user": {
"Display name cannot be empty": "Display name cannot be empty", "Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space.", "New password cannot contain blank space.": "New password cannot contain blank space.",
"New password must have at least 6 characters": "New password must have at least 6 characters", "New password must have at least 6 characters": "New password must have at least 6 characters"
"The user: %s/%s doesn't exist": "The user: %s/%s doesn't exist"
}, },
"user_upload": { "user_upload": {
"Failed to import users": "Failed to import users" "Failed to import users": "Failed to import users"
@ -144,18 +123,14 @@
"util": { "util": {
"No application is found for userId: %s": "No application is found for userId: %s", "No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s", "No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
"Please login first": "Please login first", "The provider: %s is not found": "The provider: %s is not found"
"The provider: %s is not found": "The provider: %s is not found",
"The user: %s doesn't exist": "The user: %s doesn't exist"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Code has not been sent yet!", "Code has not been sent yet!": "Code has not been sent yet!",
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Missing parameter": "Missing parameter",
"Organization does not exist": "Organization does not exist", "Organization does not exist": "Organization does not exist",
"Phone number is invalid": "Phone number is invalid", "Phone number is invalid": "Phone number is invalid",
"Please login first": "Please login first",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
@ -166,8 +141,6 @@
}, },
"webauthn": { "webauthn": {
"Found no credentials for this user": "Found no credentials for this user", "Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first", "Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
"Please login first": "Please login first",
"The user: %s/%s doesn't exist": "The user: %s/%s doesn't exist"
} }
} }

View File

@ -4,23 +4,17 @@
"Get init score failed, error: %w": "Get init score failed, error: %w", "Get init score failed, error: %w": "Get init score failed, error: %w",
"Invalid information": "Invalid information", "Invalid information": "Invalid information",
"Phone: %s": "Phone: %s", "Phone: %s": "Phone: %s",
"Please sign out first before signing in": "Please sign out first before signing in",
"Please sign out first before signing up": "Please sign out first before signing up", "Please sign out first before signing up": "Please sign out first before signing up",
"The application does not allow to sign up new account": "The application does not allow to sign up new account" "The application does not allow to sign up new account": "The application does not allow to sign up new account"
}, },
"application": {
"Parameter organization is missing": "Parameter organization is missing",
"The user: %s doesn't exist": "The user: %s doesn't exist"
},
"auth": { "auth": {
"%s No phone prefix": "%s No phone prefix", "%s No phone prefix": "%s No phone prefix",
"Challenge method should be S256": "Challenge method should be S256", "Challenge method should be S256": "Challenge method should be S256",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s", "Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s", "Failed to login in: %s": "Failed to login in: %s",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Invalid token": "Invalid token", "Invalid token": "Invalid token",
"Please sign out first before signing in": "Please sign out first before signing in",
"State expected: %s, but got: %s": "State expected: %s, but got: %s", "State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account does not exist": "The account does not exist",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up", "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support", "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)", "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
@ -29,7 +23,6 @@
"The provider type: %s is not supported": "The provider type: %s is not supported", "The provider type: %s is not supported": "The provider type: %s is not supported",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application", "The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator", "The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s/%s doesn't exist": "The user: %s/%s doesn't exist",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unauthorized operation": "Unauthorized operation", "Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s" "Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s"
@ -54,11 +47,8 @@
"Phone already exists": "Phone already exists", "Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty", "Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid", "Phone number is invalid": "Phone number is invalid",
"Please login first": "Please login first",
"Session outdated, please login again": "Session outdated, please login again", "Session outdated, please login again": "Session outdated, please login again",
"The user doesn't exist": "The user doesn't exist",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator", "The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.", "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"Username already exists": "Username already exists", "Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address", "Username cannot be an email address": "Username cannot be an email address",
@ -66,20 +56,17 @@
"Username cannot start with a digit": "Username cannot start with a digit", "Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).", "Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters", "Username must have at least 2 characters": "Username must have at least 2 characters",
"You don't have the permission to do this": "You don't have the permission to do this", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"You have entered the wrong password too many times, please wait for %d minutes %d seconds and try again": "You have entered the wrong password too many times, please wait for %d minutes %d seconds and try again", "password or code is incorrect, you have %d remaining chances": "password or code is incorrect, you have %d remaining chances",
"unsupported password type: %s": "unsupported password type: %s" "unsupported password type: %s": "unsupported password type: %s"
}, },
"check_util": { "general": {
"You have entered the wrong password too many times, please wait for %d minutes and try again": "You have entered the wrong password too many times, please wait for %d minutes and try again", "Missing parameter": "Missing parameter",
"password is incorrect, you have %d remaining chances": "password is incorrect, you have %d remaining chances" "Please login first": "Please login first",
}, "The user: %s doesn't exist": "The user: %s doesn't exist"
"enforcer": {
"Please sign in first": "Please sign in first"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap server exist", "Ldap server exist": "Ldap server exist"
"Missing parameter": "Missing parameter"
}, },
"link": { "link": {
"Please link first": "Please link first", "Please link first": "Please link first",
@ -94,10 +81,6 @@
"The %s is immutable.": "The %s is immutable.", "The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s." "Unknown modify rule %s.": "Unknown modify rule %s."
}, },
"product": {
"Please login first": "Please login first",
"The user: %s doesn't exist": "The user: %s doesn't exist"
},
"provider": { "provider": {
"Invalid application id": "Invalid application id", "Invalid application id": "Invalid application id",
"the provider: %s does not exist": "the provider: %s does not exist" "the provider: %s does not exist": "the provider: %s does not exist"
@ -121,22 +104,18 @@
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed", "The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported" "The provider type: %s is not supported": "The provider type: %s is not supported"
}, },
"system_info": {
"You are not authorized to access this resource": "You are not authorized to access this resource"
},
"token": { "token": {
"Challenge method should be S256": "Challenge method should be S256",
"Empty clientId or clientSecret": "Empty clientId or clientSecret", "Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application", "Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret", "Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id", "Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list" "Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
}, },
"user": { "user": {
"Display name cannot be empty": "Display name cannot be empty", "Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space.", "New password cannot contain blank space.": "New password cannot contain blank space.",
"New password must have at least 6 characters": "New password must have at least 6 characters", "New password must have at least 6 characters": "New password must have at least 6 characters"
"The user: %s/%s doesn't exist": "The user: %s/%s doesn't exist"
}, },
"user_upload": { "user_upload": {
"Failed to import users": "Failed to import users" "Failed to import users": "Failed to import users"
@ -144,18 +123,14 @@
"util": { "util": {
"No application is found for userId: %s": "No application is found for userId: %s", "No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s", "No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
"Please login first": "Please login first", "The provider: %s is not found": "The provider: %s is not found"
"The provider: %s is not found": "The provider: %s is not found",
"The user: %s doesn't exist": "The user: %s doesn't exist"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "Code has not been sent yet!", "Code has not been sent yet!": "Code has not been sent yet!",
"Email is invalid": "Email is invalid", "Email is invalid": "Email is invalid",
"Invalid captcha provider.": "Invalid captcha provider.", "Invalid captcha provider.": "Invalid captcha provider.",
"Missing parameter": "Missing parameter",
"Organization does not exist": "Organization does not exist", "Organization does not exist": "Organization does not exist",
"Phone number is invalid": "Phone number is invalid", "Phone number is invalid": "Phone number is invalid",
"Please login first": "Please login first",
"Turing test failed.": "Turing test failed.", "Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.", "Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.", "Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
@ -166,8 +141,6 @@
}, },
"webauthn": { "webauthn": {
"Found no credentials for this user": "Found no credentials for this user", "Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first", "Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
"Please login first": "Please login first",
"The user: %s/%s doesn't exist": "The user: %s/%s doesn't exist"
} }
} }

View File

@ -3,34 +3,27 @@
"Email: %s": "邮件: %s", "Email: %s": "邮件: %s",
"Get init score failed, error: %w": "初始化分数失败: %w", "Get init score failed, error: %w": "初始化分数失败: %w",
"Invalid information": "无效信息", "Invalid information": "无效信息",
"Phone: %s": "电话: %s", "Phone: %s": "手机号: %s",
"Please sign out first before signing up": "请在登陆前登出", "Please sign out first before signing in": "请在登录前先退出登录",
"The application does not allow to sign up new account": "该应用不允许注册新账户" "Please sign out first before signing up": "请在注册前先退出登录",
}, "The application does not allow to sign up new account": "该应用不允许注册新用户"
"application": {
"Parameter organization is missing": "Organization参数丢失",
"The user: %s doesn't exist": "用户不存在: %s"
}, },
"auth": { "auth": {
"%s No phone prefix": "%s 无此电话前缀", "%s No phone prefix": "%s 无此手机号前缀",
"Challenge method should be S256": "Challenge 方法应该为 S256", "Challenge method should be S256": "Challenge 方法应该为 S256",
"Failed to create user, user information is invalid: %s": "创建用户失败,用户信息无效: %s", "Failed to create user, user information is invalid: %s": "创建用户失败,用户信息无效: %s",
"Failed to login in: %s": "无法登录: %s", "Failed to login in: %s": "登录失败: %s",
"Get init score failed, error: %w": "初始化分数失败: %w",
"Invalid token": "无效token", "Invalid token": "无效token",
"Please sign out first before signing in": "请在登陆前登出", "State expected: %s, but got: %s": "期望状态为: %s, 实际状态为: %s",
"State expected: %s, but got: %s": "期望状态位: %s, 实际状态为: %s",
"The account does not exist": "账户不存在",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "提供商账户: %s 与用户名: %s (%s) 不存在且 不允许通过 %s 注册新账户, 请使用其他方式注册", "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "提供商账户: %s 与用户名: %s (%s) 不存在且 不允许通过 %s 注册新账户, 请使用其他方式注册",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "提供商账户: %s 与用户名: %s (%s) 不存在且 不允许注册新账户, 请联系IT支持", "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "提供商账户: %s 与用户名: %s (%s) 不存在且 不允许注册新账户, 请联系IT支持",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "提供商账户: %s 与用户名: %s (%s) 已经与其他账户绑定: %s (%s)", "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "提供商账户: %s 与用户名: %s (%s) 已经与其他账户绑定: %s (%s)",
"The application: %s does not exist": "应用 %s 不存在", "The application: %s does not exist": "应用 %s 不存在",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application", "The login method: login with password is not enabled for the application": "该应用禁止采用密码登录方式",
"The provider type: %s is not supported": "不支持该类型的提供商: %s", "The provider type: %s is not supported": "不支持该类型的提供商: %s",
"The provider: %s is not enabled for the application": "提供商: %s 未被启用", "The provider: %s is not enabled for the application": "该应用的提供商: %s 未被启用",
"The user is forbidden to sign in, please contact the administrator": "该用户被禁止登,请联系管理员", "The user is forbidden to sign in, please contact the administrator": "该用户被禁止登,请联系管理员",
"The user: %s/%s doesn't exist": "用户不存在: %s/%s", "Turing test failed.": "人机验证失败",
"Turing test failed.": "真人验证失败",
"Unauthorized operation": "未授权的操作", "Unauthorized operation": "未授权的操作",
"Unknown authentication type (not password or provider), form = %s": "未知的认证类型(非密码或第三方提供商):%s" "Unknown authentication type (not password or provider), form = %s": "未知的认证类型(非密码或第三方提供商):%s"
}, },
@ -38,136 +31,116 @@
"Service %s and %s do not match": "服务 %s 与 %s 不匹配" "Service %s and %s do not match": "服务 %s 与 %s 不匹配"
}, },
"check": { "check": {
"Affiliation cannot be blank": "联系方式不可为空", "Affiliation cannot be blank": "工作单位不可为空",
"DisplayName cannot be blank": "示名称不可为空", "DisplayName cannot be blank": "示名称不可为空",
"DisplayName is not valid real name": "示名称无效", "DisplayName is not valid real name": "示名称必须是真实姓名",
"Email already exists": "该邮箱已存在", "Email already exists": "该邮箱已存在",
"Email cannot be empty": "邮箱不可为空", "Email cannot be empty": "邮箱不可为空",
"Email is invalid": "无效邮箱", "Email is invalid": "无效邮箱",
"Empty username.": "用户名不可为空", "Empty username.": "用户名不可为空",
"FirstName cannot be blank": "名不可以为空", "FirstName cannot be blank": "名不可以为空",
"LastName cannot be blank": "姓不可以为空", "LastName cannot be blank": "姓不可以为空",
"Ldap user name or password incorrect": "Ldap密码错误", "Ldap user name or password incorrect": "LDAP密码错误",
"Multiple accounts with same uid, please check your ldap server": "多个帐户具有相同的uid请检查您的 ldap 服务器", "Multiple accounts with same uid, please check your ldap server": "多个帐户具有相同的uid请检查您的 LDAP 服务器",
"Organization does not exist": "组织不存在", "Organization does not exist": "组织不存在",
"Password must have at least 6 characters": "新密码至少为6位", "Password must have at least 6 characters": "新密码至少为6位",
"Phone already exists": "该电话已存在", "Phone already exists": "该手机号已存在",
"Phone cannot be empty": "电话不可为空", "Phone cannot be empty": "手机号不可为空",
"Phone number is invalid": "无效电话", "Phone number is invalid": "无效手机号",
"Please login first": "请先登录", "Session outdated, please login again": "会话已过期,请重新登录",
"Session outdated, please login again": "Session已过期请重新登陆", "The user is forbidden to sign in, please contact the administrator": "该用户被禁止登录,请联系管理员",
"The user doesn't exist": "用户不存在",
"The user is forbidden to sign in, please contact the administrator": "该用户被禁止登陆,请联系管理员",
"The user: %s doesn't exist": "用户不存在: %s",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "用户名只能包含字母数字字符、下划线或连字符,不能有连续的连字符或下划线,也不能以连字符或下划线开头或结尾", "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "用户名只能包含字母数字字符、下划线或连字符,不能有连续的连字符或下划线,也不能以连字符或下划线开头或结尾",
"Username already exists": "用户名已存在", "Username already exists": "用户名已存在",
"Username cannot be an email address": "用户名不可以是邮箱地址", "Username cannot be an email address": "用户名不可以是邮箱地址",
"Username cannot contain white spaces": "用户名不可以包含空格", "Username cannot contain white spaces": "用户名禁止包含空格",
"Username cannot start with a digit": "用户名禁止使用数字作为第一个字符", "Username cannot start with a digit": "用户名禁止使用数字开头",
"Username is too long (maximum is 39 characters).": "用户名过长最大长度为39个字符", "Username is too long (maximum is 39 characters).": "用户名过长(最大允许长度为39个字符",
"Username must have at least 2 characters": "用户名至少要有2个字符", "Username must have at least 2 characters": "用户名至少要有2个字符",
"You don't have the permission to do this": "用户名至少要有2个字符", "You have entered the wrong password or code too many times, please wait for %d minutes and try again": "密码错误次数已达上限,请在 %d 分后重试",
"You have entered the wrong password too many times, please wait for %d minutes %d seconds and try again": "输入密码错误次数已达上限,请在 %d 分 %d 秒后重试", "password or code is incorrect, you have %d remaining chances": "密码错误,您还有 %d 次尝试的机会",
"unsupported password type: %s": "不支持的密码类型: %s" "unsupported password type: %s": "不支持的密码类型: %s"
}, },
"check_util": { "general": {
"You have entered the wrong password too many times, please wait for %d minutes and try again": "输入密码错误次数已达上限,请在 %d 分后重试", "Missing parameter": "缺少参数",
"password is incorrect, you have %d remaining chances": "密码错误,您还有 %d 次尝试的机会" "Please login first": "请先登录",
}, "The user: %s doesn't exist": "用户: %s 不存在"
"enforcer": {
"Please sign in first": "请先登录"
}, },
"ldap": { "ldap": {
"Ldap server exist": "Ldap服务器已存在", "Ldap server exist": "LDAP服务器已存在"
"Missing parameter": "参数丢失"
}, },
"link": { "link": {
"Please link first": "请先绑定", "Please link first": "请先绑定",
"This application has no providers": "该应用无提供商", "This application has no providers": "该应用无可用的提供商",
"This application has no providers of type": "应用没有该类型的提供商", "This application has no providers of type": "应用没有该类型的提供商",
"This provider can't be unlinked": "该提供商不可被链接", "This provider can't be unlinked": "该提供商被禁止解绑",
"You are not the global admin, you can't unlink other users": "您不是全局管理员,无法取消链接其他用户", "You are not the global admin, you can't unlink other users": "您不是全局管理员,无法解绑其他用户",
"You can't unlink yourself, you are not a member of any application": "您无法取消链接,您不是任何应用程序的成员" "You can't unlink yourself, you are not a member of any application": "您无法自行解绑,您不是任何应用程序的成员"
}, },
"organization": { "organization": {
"Only admin can modify the %s.": "您无法取消链接,您不是任何应用程序的成员", "Only admin can modify the %s.": "仅允许管理员可以修改 %s",
"The %s is immutable.": "%s是不可变的", "The %s is immutable.": "%s 是不可变的",
"Unknown modify rule %s.": "未知的修改规则" "Unknown modify rule %s.": "未知的修改规则: %s"
},
"product": {
"Please login first": "请先登录",
"The user: %s doesn't exist": "用户不存在: %s"
}, },
"provider": { "provider": {
"Invalid application id": "无效的Application ID", "Invalid application id": "无效的应用ID",
"the provider: %s does not exist": "提供商: %s 不存在" "the provider: %s does not exist": "提供商: %s 不存在"
}, },
"resource": { "resource": {
"User is nil for tag: avatar": "用户头像标签为空", "User is nil for tag: avatar": "上传头像时用户为空",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "username或FilePath为空: username = %s, fullFilePath = %s" "Username or fullFilePath is empty: username = %s, fullFilePath = %s": "username或fullFilePath为空: username = %s, fullFilePath = %s"
}, },
"saml": { "saml": {
"Application %s not found": "应用 %s 未找到" "Application %s not found": "未找到应用: %s"
}, },
"saml_sp": { "saml_sp": {
"provider %s's category is not SAML": "提供商 %s类型不是SAML" "provider %s's category is not SAML": "提供商: %s 不是SAML类型"
}, },
"service": { "service": {
"Empty parameters for emailForm: %v": "邮件参数为空: %v", "Empty parameters for emailForm: %v": "邮件参数为空: %v",
"Invalid Email receivers: %s": " 无效的邮箱接收者: %s", "Invalid Email receivers: %s": " 无效的邮箱收件人: %s",
"Invalid phone receivers: %s": "无效的电话接收者: %s" "Invalid phone receivers: %s": "无效的手机短信收信人: %s"
}, },
"storage": { "storage": {
"The objectKey: %s is not allowed": "object key :%s 不被允许", "The objectKey: %s is not allowed": "objectKey: %s 被禁止",
"The provider type: %s is not supported": "提供商类型: %s 尚未支持" "The provider type: %s is not supported": "不支持的提供商类型: %s"
},
"system_info": {
"You are not authorized to access this resource": "您无权获取此资源"
}, },
"token": { "token": {
"Challenge method should be S256": "Challenge 方法应该为 S256",
"Empty clientId or clientSecret": "clientId或clientSecret为空", "Empty clientId or clientSecret": "clientId或clientSecret为空",
"Grant_type: %s is not supported in this application": "应用不支持此授权类型: %s", "Grant_type: %s is not supported in this application": "应用不支持Grant_type: %s",
"Invalid application or wrong clientSecret": "无效应用或错误的clientSecret", "Invalid application or wrong clientSecret": "无效应用或错误的clientSecret",
"Invalid client_id": "无效的ClientId", "Invalid client_id": "无效的ClientId",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "重定向 URI%s 在列表中未找到" "Redirect URI: %s doesn't exist in the allowed Redirect URI list": "重定向 URI%s 在许可跳转列表中未找到",
"Token not found, invalid accessToken": "未查询到对应token, accessToken无效"
}, },
"user": { "user": {
"Display name cannot be empty": "示名称不可为空", "Display name cannot be empty": "示名称不可为空",
"New password cannot contain blank space.": "新密码不可以包含空格", "New password cannot contain blank space.": "新密码不可以包含空格",
"New password must have at least 6 characters": "新密码至少需要6位字符", "New password must have at least 6 characters": "新密码至少需要6位字符"
"The user: %s/%s doesn't exist": "用户不存在: %s/%s"
}, },
"user_upload": { "user_upload": {
"Failed to import users": "导入用户失败" "Failed to import users": "导入用户失败"
}, },
"util": { "util": {
"No application is found for userId: %s": "找不到该用户的应用程序 %s", "No application is found for userId: %s": "未找到用户: %s 的应用",
"No provider for category: %s is found for application: %s": "找不到该用户的应用程序 %s", "No provider for category: %s is found for application: %s": "未找到类别为: %s 的提供商来满足应用: %s",
"Please login first": "请先登录", "The provider: %s is not found": "未找到提供商: %s"
"The provider: %s is not found": "该提供商未找到: %s",
"The user: %s doesn't exist": "用户不存在: %s"
}, },
"verification": { "verification": {
"Code has not been sent yet!": "验证码还未发送", "Code has not been sent yet!": "验证码还未发送",
"Email is invalid": "非法的邮箱", "Email is invalid": "非法的邮箱",
"Invalid captcha provider.": "非法的验证码提供商", "Invalid captcha provider.": "非法的验证码提供商",
"Missing parameter": "参数丢失",
"Organization does not exist": "组织不存在", "Organization does not exist": "组织不存在",
"Phone number is invalid": "非法的电话号码", "Phone number is invalid": "非法的手机号码",
"Please login first": "请先登录",
"Turing test failed.": "验证码还未发送", "Turing test failed.": "验证码还未发送",
"Unable to get the email modify rule.": "无法得到邮箱修改规则", "Unable to get the email modify rule.": "无法获取邮箱修改规则",
"Unable to get the phone modify rule.": "无法得到电话修改规则", "Unable to get the phone modify rule.": "无法获取手机号修改规则",
"Unknown type": "未知类型", "Unknown type": "未知类型",
"Wrong parameter": "参数错误", "Wrong parameter": "参数错误",
"You should verify your code in %d min!": "请在 %d 分钟内输入正确验证码", "You should verify your code in %d min!": "请在 %d 分钟内输入正确验证码",
"the user does not exist, please sign up first": "用户不存在,请先注册" "the user does not exist, please sign up first": "用户不存在,请先注册"
}, },
"webauthn": { "webauthn": {
"Found no credentials for this user": "该用户没有WebAuthn凭据", "Found no credentials for this user": "该用户没有 WebAuthn 凭据",
"Please call WebAuthnSigninBegin first": "请先调用 WebAuthnSigninBegi", "Please call WebAuthnSigninBegin first": "请先调用 WebAuthnSigninBegin"
"Please login first": "请先登录",
"The user: %s/%s doesn't exist": "用户: %s/%s 不存在"
} }
} }

View File

@ -27,18 +27,16 @@ var f embed.FS
var langMap = make(map[string]map[string]map[string]string) // for example : langMap[en][account][Invalid information] = Invalid information var langMap = make(map[string]map[string]map[string]string) // for example : langMap[en][account][Invalid information] = Invalid information
func getI18nFilePath(language string) string { func getI18nFilePath(category string, language string) string {
if strings.Contains(language, "backend") { if category == "backend" {
// change language from 'backend_en' to 'en'
language = language[8:]
return fmt.Sprintf("../i18n/locales/%s/data.json", language) return fmt.Sprintf("../i18n/locales/%s/data.json", language)
} else { } else {
return fmt.Sprintf("../web/src/locales/%s/data.json", language) return fmt.Sprintf("../web/src/locales/%s/data.json", language)
} }
} }
func readI18nFile(language string) *I18nData { func readI18nFile(category string, language string) *I18nData {
s := util.ReadStringFromPath(getI18nFilePath(language)) s := util.ReadStringFromPath(getI18nFilePath(category, language))
data := &I18nData{} data := &I18nData{}
err := util.JsonToStruct(s, data) err := util.JsonToStruct(s, data)
@ -48,13 +46,13 @@ func readI18nFile(language string) *I18nData {
return data return data
} }
func writeI18nFile(language string, data *I18nData) { func writeI18nFile(category string, language string, data *I18nData) {
s := util.StructToJsonFormatted(data) s := util.StructToJsonFormatted(data)
s = strings.ReplaceAll(s, "\\u0026", "&") s = strings.ReplaceAll(s, "\\u0026", "&")
s += "\n" s += "\n"
println(s) println(s)
util.WriteStringToPath(s, getI18nFilePath(language)) util.WriteStringToPath(s, getI18nFilePath(category, language))
} }
func applyData(data1 *I18nData, data2 *I18nData) { func applyData(data1 *I18nData, data2 *I18nData) {

View File

@ -25,30 +25,59 @@ import (
"github.com/markbates/goth" "github.com/markbates/goth"
"github.com/markbates/goth/providers/amazon" "github.com/markbates/goth/providers/amazon"
"github.com/markbates/goth/providers/apple" "github.com/markbates/goth/providers/apple"
"github.com/markbates/goth/providers/auth0"
"github.com/markbates/goth/providers/azureadv2" "github.com/markbates/goth/providers/azureadv2"
"github.com/markbates/goth/providers/battlenet"
"github.com/markbates/goth/providers/bitbucket" "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/digitalocean"
"github.com/markbates/goth/providers/discord" "github.com/markbates/goth/providers/discord"
"github.com/markbates/goth/providers/dropbox" "github.com/markbates/goth/providers/dropbox"
"github.com/markbates/goth/providers/eveonline"
"github.com/markbates/goth/providers/facebook" "github.com/markbates/goth/providers/facebook"
"github.com/markbates/goth/providers/fitbit"
"github.com/markbates/goth/providers/gitea" "github.com/markbates/goth/providers/gitea"
"github.com/markbates/goth/providers/github" "github.com/markbates/goth/providers/github"
"github.com/markbates/goth/providers/gitlab" "github.com/markbates/goth/providers/gitlab"
"github.com/markbates/goth/providers/google" "github.com/markbates/goth/providers/google"
"github.com/markbates/goth/providers/heroku" "github.com/markbates/goth/providers/heroku"
"github.com/markbates/goth/providers/influxcloud"
"github.com/markbates/goth/providers/instagram" "github.com/markbates/goth/providers/instagram"
"github.com/markbates/goth/providers/intercom"
"github.com/markbates/goth/providers/kakao" "github.com/markbates/goth/providers/kakao"
"github.com/markbates/goth/providers/lastfm"
"github.com/markbates/goth/providers/line" "github.com/markbates/goth/providers/line"
"github.com/markbates/goth/providers/linkedin" "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/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/paypal"
"github.com/markbates/goth/providers/salesforce" "github.com/markbates/goth/providers/salesforce"
"github.com/markbates/goth/providers/shopify" "github.com/markbates/goth/providers/shopify"
"github.com/markbates/goth/providers/slack" "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/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/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/yahoo"
"github.com/markbates/goth/providers/yammer"
"github.com/markbates/goth/providers/yandex" "github.com/markbates/goth/providers/yandex"
"github.com/markbates/goth/providers/zoom" "github.com/markbates/goth/providers/zoom"
"golang.org/x/oauth2" "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"}), Provider: azureadv2.New(clientId, clientSecret, redirectUrl, azureadv2.ProviderOptions{Tenant: "common"}),
Session: &azureadv2.Session{}, 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": case "Bitbucket":
idp = GothIdProvider{ idp = GothIdProvider{
Provider: bitbucket.New(clientId, clientSecret, redirectUrl), Provider: bitbucket.New(clientId, clientSecret, redirectUrl),
Session: &bitbucket.Session{}, 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": case "DigitalOcean":
idp = GothIdProvider{ idp = GothIdProvider{
Provider: digitalocean.New(clientId, clientSecret, redirectUrl), Provider: digitalocean.New(clientId, clientSecret, redirectUrl),
@ -97,6 +156,16 @@ func NewGothIdProvider(providerType string, clientId string, clientSecret string
Provider: dropbox.New(clientId, clientSecret, redirectUrl), Provider: dropbox.New(clientId, clientSecret, redirectUrl),
Session: &dropbox.Session{}, 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": case "Facebook":
idp = GothIdProvider{ idp = GothIdProvider{
Provider: facebook.New(clientId, clientSecret, redirectUrl), Provider: facebook.New(clientId, clientSecret, redirectUrl),
@ -127,16 +196,31 @@ func NewGothIdProvider(providerType string, clientId string, clientSecret string
Provider: heroku.New(clientId, clientSecret, redirectUrl), Provider: heroku.New(clientId, clientSecret, redirectUrl),
Session: &heroku.Session{}, Session: &heroku.Session{},
} }
case "InfluxCloud":
idp = GothIdProvider{
Provider: influxcloud.New(clientId, clientSecret, redirectUrl),
Session: &influxcloud.Session{},
}
case "Instagram": case "Instagram":
idp = GothIdProvider{ idp = GothIdProvider{
Provider: instagram.New(clientId, clientSecret, redirectUrl), Provider: instagram.New(clientId, clientSecret, redirectUrl),
Session: &instagram.Session{}, Session: &instagram.Session{},
} }
case "Intercom":
idp = GothIdProvider{
Provider: intercom.New(clientId, clientSecret, redirectUrl),
Session: &intercom.Session{},
}
case "Kakao": case "Kakao":
idp = GothIdProvider{ idp = GothIdProvider{
Provider: kakao.New(clientId, clientSecret, redirectUrl), Provider: kakao.New(clientId, clientSecret, redirectUrl),
Session: &kakao.Session{}, Session: &kakao.Session{},
} }
case "Lastfm":
idp = GothIdProvider{
Provider: lastfm.New(clientId, clientSecret, redirectUrl),
Session: &lastfm.Session{},
}
case "Linkedin": case "Linkedin":
idp = GothIdProvider{ idp = GothIdProvider{
Provider: linkedin.New(clientId, clientSecret, redirectUrl), Provider: linkedin.New(clientId, clientSecret, redirectUrl),
@ -147,11 +231,46 @@ func NewGothIdProvider(providerType string, clientId string, clientSecret string
Provider: line.New(clientId, clientSecret, redirectUrl), Provider: line.New(clientId, clientSecret, redirectUrl),
Session: &line.Session{}, 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": case "MicrosoftOnline":
idp = GothIdProvider{ idp = GothIdProvider{
Provider: microsoftonline.New(clientId, clientSecret, redirectUrl), Provider: microsoftonline.New(clientId, clientSecret, redirectUrl),
Session: &microsoftonline.Session{}, 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": case "Paypal":
idp = GothIdProvider{ idp = GothIdProvider{
Provider: paypal.New(clientId, clientSecret, redirectUrl), Provider: paypal.New(clientId, clientSecret, redirectUrl),
@ -172,26 +291,81 @@ func NewGothIdProvider(providerType string, clientId string, clientSecret string
Provider: slack.New(clientId, clientSecret, redirectUrl), Provider: slack.New(clientId, clientSecret, redirectUrl),
Session: &slack.Session{}, 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": case "Steam":
idp = GothIdProvider{ idp = GothIdProvider{
Provider: steam.New(clientSecret, redirectUrl), Provider: steam.New(clientSecret, redirectUrl),
Session: &steam.Session{}, 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": case "Tumblr":
idp = GothIdProvider{ idp = GothIdProvider{
Provider: tumblr.New(clientId, clientSecret, redirectUrl), Provider: tumblr.New(clientId, clientSecret, redirectUrl),
Session: &tumblr.Session{}, Session: &tumblr.Session{},
} }
case "Twitch":
idp = GothIdProvider{
Provider: twitch.New(clientId, clientSecret, redirectUrl),
Session: &twitch.Session{},
}
case "Twitter": case "Twitter":
idp = GothIdProvider{ idp = GothIdProvider{
Provider: twitter.New(clientId, clientSecret, redirectUrl), Provider: twitterv2.New(clientId, clientSecret, redirectUrl),
Session: &twitter.Session{}, 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": case "Yahoo":
idp = GothIdProvider{ idp = GothIdProvider{
Provider: yahoo.New(clientId, clientSecret, redirectUrl), Provider: yahoo.New(clientId, clientSecret, redirectUrl),
Session: &yahoo.Session{}, Session: &yahoo.Session{},
} }
case "Yammer":
idp = GothIdProvider{
Provider: yammer.New(clientId, clientSecret, redirectUrl),
Session: &yammer.Session{},
}
case "Yandex": case "Yandex":
idp = GothIdProvider{ idp = GothIdProvider{
Provider: yandex.New(clientId, clientSecret, redirectUrl), 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 // to call the function to obtain accessToken
value = url.Values{} value = url.Values{}
value.Add("code", code) 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) accessToken, err := idp.Session.Authorize(idp.Provider, value)
if err != nil { if err != nil {

View File

@ -98,7 +98,61 @@ func GetIdProvider(typ string, subType string, clientId string, clientSecret str
return nil 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 { func isGothSupport(provider string) bool {
for _, value := range gothList { for _, value := range gothList {

View File

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

View File

@ -19,16 +19,15 @@ import (
"runtime" "runtime"
"github.com/beego/beego" "github.com/beego/beego"
xormadapter "github.com/casbin/xorm-adapter/v3"
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
xormadapter "github.com/casdoor/xorm-adapter/v3"
_ "github.com/denisenkom/go-mssqldb" // db = mssql _ "github.com/denisenkom/go-mssqldb" // db = mssql
_ "github.com/go-sql-driver/mysql" // db = mysql _ "github.com/go-sql-driver/mysql" // db = mysql
_ "github.com/lib/pq" // db = postgres _ "github.com/lib/pq" // db = postgres
"xorm.io/xorm/migrate" "github.com/xorm-io/core"
//_ "github.com/mattn/go-sqlite3" // db = sqlite3 "github.com/xorm-io/xorm"
"xorm.io/core" _ "modernc.org/sqlite" // db = sqlite
"xorm.io/xorm"
) )
var adapter *Adapter var adapter *Adapter
@ -41,12 +40,16 @@ func InitConfig() {
beego.BConfig.WebConfig.Session.SessionOn = true beego.BConfig.WebConfig.Session.SessionOn = true
InitAdapter(true) InitAdapter()
initMigrations() DoMigration()
CreateTables(true)
} }
func InitAdapter(createDatabase bool) { func InitAdapter() {
adapter = NewAdapter(conf.GetConfigString("driverName"), conf.GetConfigDataSourceName(), conf.GetConfigString("dbName")) adapter = NewAdapter(conf.GetConfigString("driverName"), conf.GetConfigDataSourceName(), conf.GetConfigString("dbName"))
}
func CreateTables(createDatabase bool) {
if createDatabase { if createDatabase {
adapter.CreateDatabase() adapter.CreateDatabase()
} }
@ -222,6 +225,11 @@ func (a *Adapter) createTable() {
if err != nil { if err != nil {
panic(err) panic(err)
} }
err = a.Engine.Sync2(new(Session))
if err != nil {
panic(err)
}
} }
func GetSession(owner string, offset, limit int, field, value, sortField, sortOrder string) *xorm.Session { func GetSession(owner string, offset, limit int, field, value, sortField, sortOrder string) *xorm.Session {
@ -247,22 +255,3 @@ func GetSession(owner string, offset, limit int, field, value, sortField, sortOr
} }
return session 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/idp"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type SignupItem struct { type SignupItem struct {
@ -50,29 +50,31 @@ type Application struct {
EnableCodeSignin bool `json:"enableCodeSignin"` EnableCodeSignin bool `json:"enableCodeSignin"`
EnableSamlCompress bool `json:"enableSamlCompress"` EnableSamlCompress bool `json:"enableSamlCompress"`
EnableWebAuthn bool `json:"enableWebAuthn"` EnableWebAuthn bool `json:"enableWebAuthn"`
EnableLinkWithEmail bool `json:"enableLinkWithEmail"`
SamlReplyUrl string `xorm:"varchar(100)" json:"samlReplyUrl"` SamlReplyUrl string `xorm:"varchar(100)" json:"samlReplyUrl"`
Providers []*ProviderItem `xorm:"mediumtext" json:"providers"` Providers []*ProviderItem `xorm:"mediumtext" json:"providers"`
SignupItems []*SignupItem `xorm:"varchar(1000)" json:"signupItems"` SignupItems []*SignupItem `xorm:"varchar(1000)" json:"signupItems"`
GrantTypes []string `xorm:"varchar(1000)" json:"grantTypes"` GrantTypes []string `xorm:"varchar(1000)" json:"grantTypes"`
OrganizationObj *Organization `xorm:"-" json:"organizationObj"` OrganizationObj *Organization `xorm:"-" json:"organizationObj"`
ClientId string `xorm:"varchar(100)" json:"clientId"` ClientId string `xorm:"varchar(100)" json:"clientId"`
ClientSecret string `xorm:"varchar(100)" json:"clientSecret"` ClientSecret string `xorm:"varchar(100)" json:"clientSecret"`
RedirectUris []string `xorm:"varchar(1000)" json:"redirectUris"` RedirectUris []string `xorm:"varchar(1000)" json:"redirectUris"`
TokenFormat string `xorm:"varchar(100)" json:"tokenFormat"` TokenFormat string `xorm:"varchar(100)" json:"tokenFormat"`
ExpireInHours int `json:"expireInHours"` ExpireInHours int `json:"expireInHours"`
RefreshExpireInHours int `json:"refreshExpireInHours"` RefreshExpireInHours int `json:"refreshExpireInHours"`
SignupUrl string `xorm:"varchar(200)" json:"signupUrl"` SignupUrl string `xorm:"varchar(200)" json:"signupUrl"`
SigninUrl string `xorm:"varchar(200)" json:"signinUrl"` SigninUrl string `xorm:"varchar(200)" json:"signinUrl"`
ForgetUrl string `xorm:"varchar(200)" json:"forgetUrl"` ForgetUrl string `xorm:"varchar(200)" json:"forgetUrl"`
AffiliationUrl string `xorm:"varchar(100)" json:"affiliationUrl"` AffiliationUrl string `xorm:"varchar(100)" json:"affiliationUrl"`
TermsOfUse string `xorm:"varchar(100)" json:"termsOfUse"` TermsOfUse string `xorm:"varchar(100)" json:"termsOfUse"`
SignupHtml string `xorm:"mediumtext" json:"signupHtml"` SignupHtml string `xorm:"mediumtext" json:"signupHtml"`
SigninHtml string `xorm:"mediumtext" json:"signinHtml"` SigninHtml string `xorm:"mediumtext" json:"signinHtml"`
FormCss string `xorm:"text" json:"formCss"` ThemeData *ThemeData `xorm:"json" json:"themeData"`
FormOffset int `json:"formOffset"` FormCss string `xorm:"text" json:"formCss"`
FormSideHtml string `xorm:"mediumtext" json:"formSideHtml"` FormOffset int `json:"formOffset"`
FormBackgroundUrl string `xorm:"varchar(200)" json:"formBackgroundUrl"` FormSideHtml string `xorm:"mediumtext" json:"formSideHtml"`
FormBackgroundUrl string `xorm:"varchar(200)" json:"formBackgroundUrl"`
} }
func GetApplicationCount(owner, field, value string) int { func GetApplicationCount(owner, field, value string) int {
@ -286,7 +288,8 @@ func GetMaskedApplications(applications []*Application, userId string) []*Applic
func UpdateApplication(id string, application *Application) bool { func UpdateApplication(id string, application *Application) bool {
owner, name := util.GetOwnerAndNameFromId(id) owner, name := util.GetOwnerAndNameFromId(id)
if getApplication(owner, name) == nil { oldApplication := getApplication(owner, name)
if oldApplication == nil {
return false return false
} }
@ -301,6 +304,10 @@ func UpdateApplication(id string, application *Application) bool {
} }
} }
if oldApplication.ClientId != application.ClientId && GetApplicationByClientId(application.ClientId) != nil {
return false
}
for _, providerItem := range application.Providers { for _, providerItem := range application.Providers {
providerItem.Provider = nil providerItem.Provider = nil
} }
@ -324,6 +331,9 @@ func AddApplication(application *Application) bool {
if application.ClientSecret == "" { if application.ClientSecret == "" {
application.ClientSecret = util.GenerateClientSecret() application.ClientSecret = util.GenerateClientSecret()
} }
if GetApplicationByClientId(application.ClientId) != nil {
return false
}
for _, providerItem := range application.Providers { for _, providerItem := range application.Providers {
providerItem.Provider = nil providerItem.Provider = nil
} }

View File

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

View File

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

View File

@ -60,8 +60,8 @@ func CheckUserSignup(application *Application, organization *Organization, usern
if reWhiteSpace.MatchString(username) { if reWhiteSpace.MatchString(username) {
return i18n.Translate(lang, "check:Username cannot contain white spaces") return i18n.Translate(lang, "check:Username cannot contain white spaces")
} }
msg := CheckUsername(username, lang)
if msg != "" { if msg := CheckUsername(username, lang); msg != "" {
return msg return msg
} }
@ -143,11 +143,11 @@ func checkSigninErrorTimes(user *User, lang string) string {
if user.SigninWrongTimes >= SigninWrongTimesLimit { if user.SigninWrongTimes >= SigninWrongTimesLimit {
lastSignWrongTime, _ := time.Parse(time.RFC3339, user.LastSigninWrongTime) lastSignWrongTime, _ := time.Parse(time.RFC3339, user.LastSigninWrongTime)
passedTime := time.Now().UTC().Sub(lastSignWrongTime) passedTime := time.Now().UTC().Sub(lastSignWrongTime)
seconds := int(LastSignWrongTimeDuration.Seconds() - passedTime.Seconds()) minutes := int(LastSignWrongTimeDuration.Minutes() - passedTime.Minutes())
// deny the login if the error times is greater than the limit and the last login time is less than the duration // deny the login if the error times is greater than the limit and the last login time is less than the duration
if seconds > 0 { if minutes > 0 {
return fmt.Sprintf(i18n.Translate(lang, "check:You have entered the wrong password too many times, please wait for %d minutes %d seconds and try again"), seconds/60, seconds%60) return fmt.Sprintf(i18n.Translate(lang, "check:You have entered the wrong password or code too many times, please wait for %d minutes and try again"), minutes)
} }
// reset the error times // reset the error times
@ -229,7 +229,7 @@ func checkLdapUserPassword(user *User, password string, lang string) (*User, str
func CheckUserPassword(organization string, username string, password string, lang string) (*User, string) { func CheckUserPassword(organization string, username string, password string, lang string) (*User, string) {
user := GetUserByFields(organization, username) user := GetUserByFields(organization, username)
if user == nil || user.IsDeleted == true { if user == nil || user.IsDeleted == true {
return nil, i18n.Translate(lang, "check:The user doesn't exist") return nil, fmt.Sprintf(i18n.Translate(lang, "general:The user: %s doesn't exist"), util.GetId(organization, username))
} }
if user.IsForbidden { if user.IsForbidden {
@ -254,13 +254,13 @@ func filterField(field string) bool {
func CheckUserPermission(requestUserId, userId, userOwner string, strict bool, lang string) (bool, error) { func CheckUserPermission(requestUserId, userId, userOwner string, strict bool, lang string) (bool, error) {
if requestUserId == "" { if requestUserId == "" {
return false, fmt.Errorf(i18n.Translate(lang, "check:Please login first")) return false, fmt.Errorf(i18n.Translate(lang, "general:Please login first"))
} }
if userId != "" { if userId != "" {
targetUser := GetUser(userId) targetUser := GetUser(userId)
if targetUser == nil { if targetUser == nil {
return false, fmt.Errorf(i18n.Translate(lang, "check:The user: %s doesn't exist"), userId) return false, fmt.Errorf(i18n.Translate(lang, "general:The user: %s doesn't exist"), userId)
} }
userOwner = targetUser.Owner userOwner = targetUser.Owner
@ -287,7 +287,7 @@ func CheckUserPermission(requestUserId, userId, userOwner string, strict bool, l
} }
} }
return hasPermission, fmt.Errorf(i18n.Translate(lang, "check:You don't have the permission to do this")) return hasPermission, fmt.Errorf(i18n.Translate(lang, "auth:Unauthorized operation"))
} }
func CheckAccessPermission(userId string, application *Application) (bool, error) { func CheckAccessPermission(userId string, application *Application) (bool, error) {
@ -342,6 +342,33 @@ func CheckUsername(username string, lang string) string {
return "" return ""
} }
func CheckUpdateUser(oldUser *User, user *User, lang string) string {
if user.DisplayName == "" {
return i18n.Translate(lang, "user:Display name cannot be empty")
}
if oldUser.Name != user.Name {
if msg := CheckUsername(user.Name, lang); msg != "" {
return msg
}
if HasUserByField(user.Owner, "name", user.Name) {
return i18n.Translate(lang, "check:Username already exists")
}
}
if oldUser.Email != user.Email {
if HasUserByField(user.Name, "email", user.Email) {
return i18n.Translate(lang, "check:Email already exists")
}
}
if oldUser.Phone != user.Phone {
if HasUserByField(user.Owner, "phone", user.Phone) {
return i18n.Translate(lang, "check:Phone already exists")
}
}
return ""
}
func CheckToEnableCaptcha(application *Application) bool { func CheckToEnableCaptcha(application *Application) bool {
if len(application.Providers) == 0 { if len(application.Providers) == 0 {
return false return false

View File

@ -58,9 +58,9 @@ func recordSigninErrorInfo(user *User, lang string) string {
UpdateUser(user.GetId(), user, []string{"signin_wrong_times", "last_signin_wrong_time"}, user.IsGlobalAdmin) UpdateUser(user.GetId(), user, []string{"signin_wrong_times", "last_signin_wrong_time"}, user.IsGlobalAdmin)
leftChances := SigninWrongTimesLimit - user.SigninWrongTimes leftChances := SigninWrongTimesLimit - user.SigninWrongTimes
if leftChances > 0 { if leftChances > 0 {
return fmt.Sprintf(i18n.Translate(lang, "check_util:password is incorrect, you have %d remaining chances"), leftChances) return fmt.Sprintf(i18n.Translate(lang, "check:password or code is incorrect, you have %d remaining chances"), leftChances)
} }
// don't show the chance error message if the user has no chance left // don't show the chance error message if the user has no chance left
return fmt.Sprintf(i18n.Translate(lang, "check_util:You have entered the wrong password too many times, please wait for %d minutes and try again"), int(LastSignWrongTimeDuration.Minutes())) return fmt.Sprintf(i18n.Translate(lang, "check:You have entered the wrong password or code too many times, please wait for %d minutes and try again"), int(LastSignWrongTimeDuration.Minutes()))
} }

View File

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

View File

@ -25,8 +25,6 @@ import (
) )
func InitDb() { func InitDb() {
MigratePermissionRule()
existed := initBuiltInOrganization() existed := initBuiltInOrganization()
if !existed { if !existed {
initBuiltInModel() initBuiltInModel()

47
object/migrator.go Normal file
View File

@ -0,0 +1,47 @@
// Copyright 2023 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import "github.com/xorm-io/xorm/migrate"
type Migrator interface {
IsMigrationNeeded() bool
DoMigration() *migrate.Migration
}
func DoMigration() {
migrators := []Migrator{
&Migrator_1_101_0_PR_1083{},
&Migrator_1_235_0_PR_1530{},
&Migrator_1_240_0_PR_1539{},
// more migrators add here in chronological order...
}
migrations := []*migrate.Migration{}
for _, migrator := range migrators {
if migrator.IsMigrationNeeded() {
migrations = append(migrations, migrator.DoMigration())
}
}
options := &migrate.Options{
TableName: "migration",
IDColumnName: "id",
}
m := migrate.New(adapter.Engine, options, migrations)
m.Migrate()
}

View File

@ -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

@ -19,7 +19,7 @@ import (
"github.com/casbin/casbin/v2/model" "github.com/casbin/casbin/v2/model"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type Model struct { type Model struct {
@ -68,14 +68,14 @@ func getModel(owner string, name string) *Model {
return nil return nil
} }
model := Model{Owner: owner, Name: name} m := Model{Owner: owner, Name: name}
existed, err := adapter.Engine.Get(&model) existed, err := adapter.Engine.Get(&m)
if err != nil { if err != nil {
panic(err) panic(err)
} }
if existed { if existed {
return &model return &m
} else { } else {
return nil return nil
} }
@ -86,6 +86,17 @@ func GetModel(id string) *Model {
return getModel(owner, name) return getModel(owner, name)
} }
func UpdateModelWithCheck(id string, modelObj *Model) error {
// check model grammar
_, err := model.NewModelFromString(modelObj.ModelText)
if err != nil {
return err
}
UpdateModel(id, modelObj)
return nil
}
func UpdateModel(id string, modelObj *Model) bool { func UpdateModel(id string, modelObj *Model) bool {
owner, name := util.GetOwnerAndNameFromId(id) owner, name := util.GetOwnerAndNameFromId(id)
if getModel(owner, name) == nil { if getModel(owner, name) == nil {
@ -98,11 +109,6 @@ func UpdateModel(id string, modelObj *Model) bool {
return false return false
} }
} }
// check model grammar
_, err := model.NewModelFromString(modelObj.ModelText)
if err != nil {
panic(err)
}
affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(modelObj) affected, err := adapter.Engine.ID(core.PK{owner, name}).AllCols().Update(modelObj)
if err != nil { if err != nil {
@ -152,3 +158,7 @@ func modelChangeTrigger(oldName string, newName string) error {
return session.Commit() return session.Commit()
} }
func HasRoleDefinition(m model.Model) bool {
return m["g"] != nil
}

View File

@ -40,6 +40,7 @@ type OidcDiscovery struct {
ClaimsSupported []string `json:"claims_supported"` ClaimsSupported []string `json:"claims_supported"`
RequestParameterSupported bool `json:"request_parameter_supported"` RequestParameterSupported bool `json:"request_parameter_supported"`
RequestObjectSigningAlgValuesSupported []string `json:"request_object_signing_alg_values_supported"` RequestObjectSigningAlgValuesSupported []string `json:"request_object_signing_alg_values_supported"`
EndSessionEndpoint string `json:"end_session_endpoint"`
} }
func getOriginFromHost(host string) (string, string) { func getOriginFromHost(host string) (string, string) {
@ -76,7 +77,7 @@ func GetOidcDiscovery(host string) OidcDiscovery {
JwksUri: fmt.Sprintf("%s/.well-known/jwks", originBackend), JwksUri: fmt.Sprintf("%s/.well-known/jwks", originBackend),
IntrospectionEndpoint: fmt.Sprintf("%s/api/login/oauth/introspect", originBackend), IntrospectionEndpoint: fmt.Sprintf("%s/api/login/oauth/introspect", originBackend),
ResponseTypesSupported: []string{"code", "token", "id_token", "code token", "code id_token", "token id_token", "code token id_token", "none"}, ResponseTypesSupported: []string{"code", "token", "id_token", "code token", "code id_token", "token id_token", "code token id_token", "none"},
ResponseModesSupported: []string{"login", "code", "link"}, ResponseModesSupported: []string{"query", "fragment", "login", "code", "link"},
GrantTypesSupported: []string{"password", "authorization_code"}, GrantTypesSupported: []string{"password", "authorization_code"},
SubjectTypesSupported: []string{"public"}, SubjectTypesSupported: []string{"public"},
IdTokenSigningAlgValuesSupported: []string{"RS256"}, IdTokenSigningAlgValuesSupported: []string{"RS256"},
@ -84,6 +85,7 @@ func GetOidcDiscovery(host string) OidcDiscovery {
ClaimsSupported: []string{"iss", "ver", "sub", "aud", "iat", "exp", "id", "type", "displayName", "avatar", "permanentAvatar", "email", "phone", "location", "affiliation", "title", "homepage", "bio", "tag", "region", "language", "score", "ranking", "isOnline", "isAdmin", "isGlobalAdmin", "isForbidden", "signupApplication", "ldap"}, ClaimsSupported: []string{"iss", "ver", "sub", "aud", "iat", "exp", "id", "type", "displayName", "avatar", "permanentAvatar", "email", "phone", "location", "affiliation", "title", "homepage", "bio", "tag", "region", "language", "score", "ranking", "isOnline", "isAdmin", "isGlobalAdmin", "isForbidden", "signupApplication", "ldap"},
RequestParameterSupported: true, RequestParameterSupported: true,
RequestObjectSigningAlgValuesSupported: []string{"HS256", "HS384", "HS512"}, RequestObjectSigningAlgValuesSupported: []string{"HS256", "HS384", "HS512"},
EndSessionEndpoint: fmt.Sprintf("%s/api/logout", originBackend),
} }
return oidcDiscovery return oidcDiscovery

View File

@ -21,7 +21,7 @@ import (
"github.com/casdoor/casdoor/cred" "github.com/casdoor/casdoor/cred"
"github.com/casdoor/casdoor/i18n" "github.com/casdoor/casdoor/i18n"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type AccountItem struct { type AccountItem struct {
@ -31,25 +31,34 @@ type AccountItem struct {
ModifyRule string `json:"modifyRule"` 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 { type Organization struct {
Owner string `xorm:"varchar(100) notnull pk" json:"owner"` Owner string `xorm:"varchar(100) notnull pk" json:"owner"`
Name string `xorm:"varchar(100) notnull pk" json:"name"` Name string `xorm:"varchar(100) notnull pk" json:"name"`
CreatedTime string `xorm:"varchar(100)" json:"createdTime"` CreatedTime string `xorm:"varchar(100)" json:"createdTime"`
DisplayName string `xorm:"varchar(100)" json:"displayName"` DisplayName string `xorm:"varchar(100)" json:"displayName"`
WebsiteUrl string `xorm:"varchar(100)" json:"websiteUrl"` WebsiteUrl string `xorm:"varchar(100)" json:"websiteUrl"`
Favicon string `xorm:"varchar(100)" json:"favicon"` Favicon string `xorm:"varchar(100)" json:"favicon"`
PasswordType string `xorm:"varchar(100)" json:"passwordType"` PasswordType string `xorm:"varchar(100)" json:"passwordType"`
PasswordSalt string `xorm:"varchar(100)" json:"passwordSalt"` PasswordSalt string `xorm:"varchar(100)" json:"passwordSalt"`
PhonePrefix string `xorm:"varchar(10)" json:"phonePrefix"` PhonePrefix string `xorm:"varchar(10)" json:"phonePrefix"`
DefaultAvatar string `xorm:"varchar(100)" json:"defaultAvatar"` DefaultAvatar string `xorm:"varchar(100)" json:"defaultAvatar"`
DefaultApplication string `xorm:"varchar(100)" json:"defaultApplication"` DefaultApplication string `xorm:"varchar(100)" json:"defaultApplication"`
Tags []string `xorm:"mediumtext" json:"tags"` Tags []string `xorm:"mediumtext" json:"tags"`
Languages []string `xorm:"varchar(255)" json:"languages"` Languages []string `xorm:"varchar(255)" json:"languages"`
MasterPassword string `xorm:"varchar(100)" json:"masterPassword"` ThemeData *ThemeData `xorm:"json" json:"themeData"`
InitScore int `json:"initScore"` MasterPassword string `xorm:"varchar(100)" json:"masterPassword"`
EnableSoftDeletion bool `json:"enableSoftDeletion"` InitScore int `json:"initScore"`
IsProfilePublic bool `json:"isProfilePublic"` EnableSoftDeletion bool `json:"enableSoftDeletion"`
IsProfilePublic bool `json:"isProfilePublic"`
AccountItems []*AccountItem `xorm:"varchar(3000)" json:"accountItems"` AccountItems []*AccountItem `xorm:"varchar(3000)" json:"accountItems"`
} }
@ -204,7 +213,7 @@ func GetAccountItemByName(name string, organization *Organization) *AccountItem
func CheckAccountItemModifyRule(accountItem *AccountItem, user *User, lang string) (bool, string) { func CheckAccountItemModifyRule(accountItem *AccountItem, user *User, lang string) (bool, string) {
switch accountItem.ModifyRule { switch accountItem.ModifyRule {
case "Admin": case "Admin":
if !(user.IsAdmin || user.IsGlobalAdmin) { if user == nil || !user.IsAdmin && !user.IsGlobalAdmin {
return false, fmt.Sprintf(i18n.Translate(lang, "organization:Only admin can modify the %s."), accountItem.Name) return false, fmt.Sprintf(i18n.Translate(lang, "organization:Only admin can modify the %s."), accountItem.Name)
} }
case "Immutable": case "Immutable":

View File

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

View File

@ -16,10 +16,9 @@ package object
import ( import (
"fmt" "fmt"
"strings"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type Permission struct { type Permission struct {
@ -57,6 +56,40 @@ type PermissionRule struct {
Id string `xorm:"varchar(100) index not null default ''" json:"id"` Id string `xorm:"varchar(100) index not null default ''" json:"id"`
} }
const (
builtInAvailableField = 5 // Casdoor built-in adapter, use V5 to filter permission, so has 5 available field
builtInAdapter = "permission_rule"
)
func (p *Permission) GetId() string {
return util.GetId(p.Owner, p.Name)
}
func (p *PermissionRule) GetRequest(adapterName string, permissionId string) ([]interface{}, error) {
request := []interface{}{p.V0, p.V1, p.V2}
if p.V3 != "" {
request = append(request, p.V3)
}
if p.V4 != "" {
request = append(request, p.V4)
}
if adapterName == builtInAdapter {
if p.V5 != "" {
return nil, fmt.Errorf("too many parameters. The maximum parameter number cannot exceed %d", builtInAvailableField)
}
request = append(request, permissionId)
return request, nil
} else {
if p.V5 != "" {
request = append(request, p.V5)
}
return request, nil
}
}
func GetPermissionCount(owner, field, value string) int { func GetPermissionCount(owner, field, value string) int {
session := GetSession(owner, -1, -1, field, value, "", "") session := GetSession(owner, -1, -1, field, value, "", "")
count, err := session.Count(&Permission{}) count, err := session.Count(&Permission{})
@ -115,19 +148,25 @@ func GetPermission(id string) *Permission {
func checkPermissionValid(permission *Permission) { func checkPermissionValid(permission *Permission) {
enforcer := getEnforcer(permission) enforcer := getEnforcer(permission)
enforcer.EnableAutoSave(false) enforcer.EnableAutoSave(false)
policies, groupingPolicies := getPolicies(permission)
policies := getPolicies(permission)
_, err := enforcer.AddPolicies(policies)
if err != nil {
panic(err)
}
if !HasRoleDefinition(enforcer.GetModel()) {
permission.Roles = []string{}
return
}
groupingPolicies := getGroupingPolicies(permission)
if len(groupingPolicies) > 0 { if len(groupingPolicies) > 0 {
_, err := enforcer.AddGroupingPolicies(groupingPolicies) _, err := enforcer.AddGroupingPolicies(groupingPolicies)
if err != nil { if err != nil {
panic(err) panic(err)
} }
} }
_, err := enforcer.AddPolicies(policies)
if err != nil {
panic(err)
}
} }
func UpdatePermission(id string, permission *Permission) bool { func UpdatePermission(id string, permission *Permission) bool {
@ -144,6 +183,7 @@ func UpdatePermission(id string, permission *Permission) bool {
} }
if affected != 0 { if affected != 0 {
removeGroupingPolicies(oldPermission)
removePolicies(oldPermission) removePolicies(oldPermission)
if oldPermission.Adapter != "" && oldPermission.Adapter != permission.Adapter { if oldPermission.Adapter != "" && oldPermission.Adapter != permission.Adapter {
isEmpty, _ := adapter.Engine.IsTableEmpty(oldPermission.Adapter) isEmpty, _ := adapter.Engine.IsTableEmpty(oldPermission.Adapter)
@ -154,6 +194,7 @@ func UpdatePermission(id string, permission *Permission) bool {
} }
} }
} }
addGroupingPolicies(permission)
addPolicies(permission) addPolicies(permission)
} }
@ -167,6 +208,7 @@ func AddPermission(permission *Permission) bool {
} }
if affected != 0 { if affected != 0 {
addGroupingPolicies(permission)
addPolicies(permission) addPolicies(permission)
} }
@ -180,6 +222,7 @@ func DeletePermission(permission *Permission) bool {
} }
if affected != 0 { if affected != 0 {
removeGroupingPolicies(permission)
removePolicies(permission) removePolicies(permission)
if permission.Adapter != "" && permission.Adapter != "permission_rule" { if permission.Adapter != "" && permission.Adapter != "permission_rule" {
isEmpty, _ := adapter.Engine.IsTableEmpty(permission.Adapter) isEmpty, _ := adapter.Engine.IsTableEmpty(permission.Adapter)
@ -195,10 +238,6 @@ func DeletePermission(permission *Permission) bool {
return affected != 0 return affected != 0
} }
func (permission *Permission) GetId() string {
return fmt.Sprintf("%s/%s", permission.Owner, permission.Name)
}
func GetPermissionsByUser(userId string) []*Permission { func GetPermissionsByUser(userId string) []*Permission {
permissions := []*Permission{} permissions := []*Permission{}
err := adapter.Engine.Where("users like ?", "%"+userId+"%").Find(&permissions) err := adapter.Engine.Where("users like ?", "%"+userId+"%").Find(&permissions)
@ -229,33 +268,6 @@ func GetPermissionsBySubmitter(owner string, submitter string) []*Permission {
return permissions 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 { func ContainsAsterisk(userId string, users []string) bool {
containsAsterisk := false containsAsterisk := false
group, _ := util.GetOwnerAndNameFromId(userId) group, _ := util.GetOwnerAndNameFromId(userId)
@ -269,3 +281,12 @@ func ContainsAsterisk(userId string, users []string) bool {
return containsAsterisk return containsAsterisk
} }
func GetMaskedPermissions(permissions []*Permission) []*Permission {
for _, permission := range permissions {
permission.Users = nil
permission.Submitter = ""
}
return permissions
}

View File

@ -15,12 +15,14 @@
package object package object
import ( import (
"fmt"
"strings" "strings"
"github.com/casbin/casbin/v2" "github.com/casbin/casbin/v2"
"github.com/casbin/casbin/v2/config"
"github.com/casbin/casbin/v2/model" "github.com/casbin/casbin/v2/model"
xormadapter "github.com/casbin/xorm-adapter/v3"
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
xormadapter "github.com/casdoor/xorm-adapter/v3"
) )
func getEnforcer(permission *Permission) *casbin.Enforcer { func getEnforcer(permission *Permission) *casbin.Enforcer {
@ -36,47 +38,48 @@ func getEnforcer(permission *Permission) *casbin.Enforcer {
panic(err) panic(err)
} }
modelText := `
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act, "", "", permissionId
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act`
permissionModel := getModel(permission.Owner, permission.Model) permissionModel := getModel(permission.Owner, permission.Model)
m := model.Model{}
if permissionModel != nil { if permissionModel != nil {
modelText = permissionModel.ModelText m, err = GetBuiltInModel(permissionModel.ModelText)
} else {
m, err = GetBuiltInModel("")
} }
m, err := model.NewModelFromString(modelText)
if err != nil { if err != nil {
panic(err) panic(err)
} }
policyFilter := xormadapter.Filter{}
if !HasRoleDefinition(m) {
policyFilter.Ptype = []string{"p"}
err = adapter.LoadFilteredPolicy(m, policyFilter)
if err != nil {
panic(err)
}
}
enforcer, err := casbin.NewEnforcer(m, adapter) enforcer, err := casbin.NewEnforcer(m, adapter)
if err != nil { if err != nil {
panic(err) panic(err)
} }
// load Policy with a specific Permission // load Policy with a specific Permission
enforcer.LoadFilteredPolicy(xormadapter.Filter{ policyFilter.V5 = []string{permission.GetId()}
V5: []string{permission.Owner + "/" + permission.Name}, err = enforcer.LoadFilteredPolicy(policyFilter)
}) if err != nil {
panic(err)
}
return enforcer return enforcer
} }
func getPolicies(permission *Permission) ([][]string, [][]string) { func getPolicies(permission *Permission) [][]string {
var policies [][]string var policies [][]string
var groupingPolicies [][]string
permissionId := permission.Owner + "/" + permission.Name permissionId := permission.GetId()
domainExist := len(permission.Domains) > 0 domainExist := len(permission.Domains) > 0
for _, user := range permission.Users { for _, user := range permission.Users {
for _, resource := range permission.Resources { for _, resource := range permission.Resources {
for _, action := range permission.Actions { for _, action := range permission.Actions {
@ -90,26 +93,8 @@ func getPolicies(permission *Permission) ([][]string, [][]string) {
} }
} }
} }
for _, role := range permission.Roles { for _, role := range permission.Roles {
roleObj := GetRole(role)
for _, subUser := range roleObj.Users {
if domainExist {
for _, domain := range permission.Domains {
groupingPolicies = append(groupingPolicies, []string{subUser, domain, role, "", "", permissionId})
}
} else {
groupingPolicies = append(groupingPolicies, []string{subUser, role, "", "", "", permissionId})
}
}
for _, subRole := range roleObj.Roles {
if domainExist {
for _, domain := range permission.Domains {
groupingPolicies = append(groupingPolicies, []string{subRole, domain, role, "", "", permissionId})
}
} else {
groupingPolicies = append(groupingPolicies, []string{subRole, role, "", "", "", permissionId})
}
}
for _, resource := range permission.Resources { for _, resource := range permission.Resources {
for _, action := range permission.Actions { for _, action := range permission.Actions {
if domainExist { if domainExist {
@ -122,19 +107,49 @@ func getPolicies(permission *Permission) ([][]string, [][]string) {
} }
} }
} }
return policies, groupingPolicies
return policies
}
func getGroupingPolicies(permission *Permission) [][]string {
var groupingPolicies [][]string
domainExist := len(permission.Domains) > 0
permissionId := permission.GetId()
for _, role := range permission.Roles {
roleObj := GetRole(role)
if roleObj == nil {
continue
}
for _, subUser := range roleObj.Users {
if domainExist {
for _, domain := range permission.Domains {
groupingPolicies = append(groupingPolicies, []string{subUser, domain, role, "", "", permissionId})
}
} else {
groupingPolicies = append(groupingPolicies, []string{subUser, role, "", "", "", permissionId})
}
}
for _, subRole := range roleObj.Roles {
if domainExist {
for _, domain := range permission.Domains {
groupingPolicies = append(groupingPolicies, []string{subRole, domain, role, "", "", permissionId})
}
} else {
groupingPolicies = append(groupingPolicies, []string{subRole, role, "", "", "", permissionId})
}
}
}
return groupingPolicies
} }
func addPolicies(permission *Permission) { func addPolicies(permission *Permission) {
enforcer := getEnforcer(permission) enforcer := getEnforcer(permission)
policies, groupingPolicies := getPolicies(permission) policies := getPolicies(permission)
if len(groupingPolicies) > 0 {
_, err := enforcer.AddGroupingPolicies(groupingPolicies)
if err != nil {
panic(err)
}
}
_, err := enforcer.AddPolicies(policies) _, err := enforcer.AddPolicies(policies)
if err != nil { if err != nil {
@ -142,9 +157,21 @@ func addPolicies(permission *Permission) {
} }
} }
func removePolicies(permission *Permission) { func addGroupingPolicies(permission *Permission) {
enforcer := getEnforcer(permission) enforcer := getEnforcer(permission)
policies, groupingPolicies := getPolicies(permission) groupingPolicies := getGroupingPolicies(permission)
if len(groupingPolicies) > 0 {
_, err := enforcer.AddGroupingPolicies(groupingPolicies)
if err != nil {
panic(err)
}
}
}
func removeGroupingPolicies(permission *Permission) {
enforcer := getEnforcer(permission)
groupingPolicies := getGroupingPolicies(permission)
if len(groupingPolicies) > 0 { if len(groupingPolicies) > 0 {
_, err := enforcer.RemoveGroupingPolicies(groupingPolicies) _, err := enforcer.RemoveGroupingPolicies(groupingPolicies)
@ -152,6 +179,11 @@ func removePolicies(permission *Permission) {
panic(err) panic(err)
} }
} }
}
func removePolicies(permission *Permission) {
enforcer := getEnforcer(permission)
policies := getPolicies(permission)
_, err := enforcer.RemovePolicies(policies) _, err := enforcer.RemovePolicies(policies)
if err != nil { if err != nil {
@ -163,10 +195,8 @@ func Enforce(permissionRule *PermissionRule) bool {
permission := GetPermission(permissionRule.Id) permission := GetPermission(permissionRule.Id)
enforcer := getEnforcer(permission) enforcer := getEnforcer(permission)
request := []interface{}{permissionRule.V0, permissionRule.V1, permissionRule.V2} request, _ := permissionRule.GetRequest(builtInAdapter, permissionRule.Id)
if permissionRule.V3 != "" {
request = append(request, permissionRule.V3)
}
allow, err := enforcer.Enforce(request...) allow, err := enforcer.Enforce(request...)
if err != nil { if err != nil {
panic(err) panic(err)
@ -177,11 +207,8 @@ func Enforce(permissionRule *PermissionRule) bool {
func BatchEnforce(permissionRules []PermissionRule) []bool { func BatchEnforce(permissionRules []PermissionRule) []bool {
var requests [][]interface{} var requests [][]interface{}
for _, permissionRule := range permissionRules { for _, permissionRule := range permissionRules {
if permissionRule.V3 != "" { request, _ := permissionRule.GetRequest(builtInAdapter, permissionRule.Id)
requests = append(requests, []interface{}{permissionRule.V0, permissionRule.V1, permissionRule.V2, permissionRule.V3}) requests = append(requests, request)
} else {
requests = append(requests, []interface{}{permissionRule.V0, permissionRule.V1, permissionRule.V2})
}
} }
permission := GetPermission(permissionRules[0].Id) permission := GetPermission(permissionRules[0].Id)
enforcer := getEnforcer(permission) enforcer := getEnforcer(permission)
@ -226,3 +253,46 @@ func GetAllRoles(userId string) []string {
} }
return res return res
} }
func GetBuiltInModel(modelText string) (model.Model, error) {
if modelText == "" {
modelText = `
[request_definition]
r = sub, obj, act
[policy_definition]
p = sub, obj, act, "", "", permissionId
[role_definition]
g = _, _
[policy_effect]
e = some(where (p.eft == allow))
[matchers]
m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act`
return model.NewModelFromString(modelText)
} else {
cfg, err := config.NewConfigFromText(modelText)
if err != nil {
return nil, err
}
// load [policy_definition]
policyDefinition := strings.Split(cfg.String("policy_definition::p"), ",")
fieldsNum := len(policyDefinition)
if fieldsNum > builtInAvailableField {
panic(fmt.Errorf("the maximum policy_definition field number cannot exceed %d", builtInAvailableField))
}
// filled empty field with "" and V5 with "permissionId"
for i := builtInAvailableField - fieldsNum; i > 0; i-- {
policyDefinition = append(policyDefinition, "")
}
policyDefinition = append(policyDefinition, "permissionId")
m, _ := model.NewModelFromString(modelText)
m.AddDef("p", "p", strings.Join(policyDefinition, ","))
return m, err
}
}

View File

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

View File

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

View File

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

View File

@ -19,7 +19,7 @@ import (
"strings" "strings"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
type Role struct { type Role struct {
@ -95,6 +95,12 @@ func UpdateRole(id string, role *Role) bool {
return false return false
} }
permissions := GetPermissionsByRole(id)
for _, permission := range permissions {
removeGroupingPolicies(permission)
removePolicies(permission)
}
if name != role.Name { if name != role.Name {
err := roleChangeTrigger(name, role.Name) err := roleChangeTrigger(name, role.Name)
if err != nil { if err != nil {
@ -107,6 +113,13 @@ func UpdateRole(id string, role *Role) bool {
panic(err) panic(err)
} }
newRoleID := role.GetId()
permissions = GetPermissionsByRole(newRoleID)
for _, permission := range permissions {
addGroupingPolicies(permission)
addPolicies(permission)
}
return affected != 0 return affected != 0
} }
@ -120,6 +133,13 @@ func AddRole(role *Role) bool {
} }
func DeleteRole(role *Role) bool { func DeleteRole(role *Role) bool {
roleId := role.GetId()
permissions := GetPermissionsByRole(roleId)
for _, permission := range permissions {
permission.Roles = util.DeleteVal(permission.Roles, roleId)
UpdatePermission(permission.GetId(), permission)
}
affected, err := adapter.Engine.ID(core.PK{role.Owner, role.Name}).Delete(&Role{}) affected, err := adapter.Engine.ID(core.PK{role.Owner, role.Name}).Delete(&Role{})
if err != nil { if err != nil {
panic(err) panic(err)
@ -192,3 +212,11 @@ func roleChangeTrigger(oldName string, newName string) error {
return session.Commit() return session.Commit()
} }
func GetMaskedRoles(roles []*Role) []*Role {
for _, role := range roles {
role.Users = nil
}
return roles
}

View File

@ -223,11 +223,14 @@ func GetSamlMeta(application *Application, host string) (*IdpEntityDescriptor, e
// GetSamlResponse generates a SAML2.0 response // GetSamlResponse generates a SAML2.0 response
// parameter samlRequest is saml request in base64 format // parameter samlRequest is saml request in base64 format
func GetSamlResponse(application *Application, user *User, samlRequest string, host string) (string, string, error) { func GetSamlResponse(application *Application, user *User, samlRequest string, host string) (string, string, string, error) {
// request type
method := "GET"
// base64 decode // base64 decode
defated, err := base64.StdEncoding.DecodeString(samlRequest) defated, err := base64.StdEncoding.DecodeString(samlRequest)
if err != nil { if err != nil {
return "", "", fmt.Errorf("err: %s", err.Error()) return "", "", method, fmt.Errorf("err: %s", err.Error())
} }
// decompress // decompress
var buffer bytes.Buffer var buffer bytes.Buffer
@ -236,12 +239,12 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
var authnRequest saml.AuthnRequest var authnRequest saml.AuthnRequest
err = xml.Unmarshal(buffer.Bytes(), &authnRequest) err = xml.Unmarshal(buffer.Bytes(), &authnRequest)
if err != nil { if err != nil {
return "", "", fmt.Errorf("err: %s", err.Error()) return "", "", method, fmt.Errorf("err: %s", err.Error())
} }
// verify samlRequest // verify samlRequest
if isValid := application.IsRedirectUriValid(authnRequest.Issuer.Url); !isValid { if isValid := application.IsRedirectUriValid(authnRequest.Issuer.Url); !isValid {
return "", "", fmt.Errorf("err: Issuer URI: %s doesn't exist in the allowed Redirect URI list", authnRequest.Issuer.Url) return "", "", method, fmt.Errorf("err: Issuer URI: %s doesn't exist in the allowed Redirect URI list", authnRequest.Issuer.Url)
} }
// get certificate string // get certificate string
@ -253,6 +256,7 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
// redirect Url (Assertion Consumer Url) // redirect Url (Assertion Consumer Url)
if application.SamlReplyUrl != "" { if application.SamlReplyUrl != "" {
method = "POST"
authnRequest.AssertionConsumerServiceURL = application.SamlReplyUrl authnRequest.AssertionConsumerServiceURL = application.SamlReplyUrl
} }
@ -275,7 +279,7 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
doc.SetRoot(samlResponse) doc.SetRoot(samlResponse)
xmlBytes, err := doc.WriteToBytes() xmlBytes, err := doc.WriteToBytes()
if err != nil { if err != nil {
return "", "", fmt.Errorf("err: %s", err.Error()) return "", "", method, fmt.Errorf("err: %s", err.Error())
} }
// compress // compress
@ -283,7 +287,7 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
flated := bytes.NewBuffer(nil) flated := bytes.NewBuffer(nil)
writer, err := flate.NewWriter(flated, flate.DefaultCompression) writer, err := flate.NewWriter(flated, flate.DefaultCompression)
if err != nil { if err != nil {
return "", "", fmt.Errorf("err: %s", err.Error()) return "", "", method, fmt.Errorf("err: %s", err.Error())
} }
writer.Write(xmlBytes) writer.Write(xmlBytes)
writer.Close() writer.Close()
@ -291,7 +295,7 @@ func GetSamlResponse(application *Application, user *User, samlRequest string, h
} }
// base64 encode // base64 encode
res := base64.StdEncoding.EncodeToString(xmlBytes) res := base64.StdEncoding.EncodeToString(xmlBytes)
return res, authnRequest.AssertionConsumerServiceURL, nil return res, authnRequest.AssertionConsumerServiceURL, method, nil
} }
// NewSamlResponse11 return a saml1.1 response(not 2.0) // NewSamlResponse11 return a saml1.1 response(not 2.0)

201
object/session.go Normal file
View File

@ -0,0 +1,201 @@
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package object
import (
"fmt"
"github.com/beego/beego"
"github.com/casdoor/casdoor/util"
"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 GetSessions(owner string) []*Session {
sessions := []*Session{}
var err error
if owner != "" {
err = adapter.Engine.Desc("created_time").Where("owner = ?", owner).Find(&sessions)
} else {
err = adapter.Engine.Desc("created_time").Find(&sessions)
}
if err != nil {
panic(err)
}
return sessions
}
func GetPaginationSessions(owner string, offset, limit int, field, value, sortField, sortOrder string) []*Session {
sessions := []*Session{}
session := GetSession(owner, offset, limit, field, value, sortField, sortOrder)
err := session.Find(&sessions)
if err != nil {
panic(err)
}
return sessions
}
func GetSessionCount(owner, field, value string) int {
session := GetSession(owner, -1, -1, field, value, "", "")
count, err := session.Count(&Session{})
if err != nil {
panic(err)
}
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

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

View File

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

View File

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

View File

@ -23,11 +23,11 @@ import (
"github.com/casdoor/casdoor/i18n" "github.com/casdoor/casdoor/i18n"
"github.com/casdoor/casdoor/idp" "github.com/casdoor/casdoor/idp"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
) )
const ( const (
hourSeconds = 3600 hourSeconds = int(time.Hour / time.Second)
InvalidRequest = "invalid_request" InvalidRequest = "invalid_request"
InvalidClient = "invalid_client" InvalidClient = "invalid_client"
InvalidGrant = "invalid_grant" InvalidGrant = "invalid_grant"
@ -204,7 +204,7 @@ func DeleteToken(token *Token) bool {
return affected != 0 return affected != 0
} }
func DeleteTokenByAccessToken(accessToken string) (bool, *Application) { func ExpireTokenByAccessToken(accessToken string) (bool, *Application, *Token) {
token := Token{AccessToken: accessToken} token := Token{AccessToken: accessToken}
existed, err := adapter.Engine.Get(&token) existed, err := adapter.Engine.Get(&token)
if err != nil { if err != nil {
@ -212,15 +212,17 @@ func DeleteTokenByAccessToken(accessToken string) (bool, *Application) {
} }
if !existed { if !existed {
return false, nil return false, nil, nil
} }
application := getApplication(token.Owner, token.Application)
affected, err := adapter.Engine.Where("access_token=?", accessToken).Delete(&Token{}) token.ExpiresIn = 0
affected, err := adapter.Engine.ID(core.PK{token.Owner, token.Name}).Cols("expires_in").Update(&token)
if err != nil { if err != nil {
panic(err) panic(err)
} }
return affected != 0, application application := getApplication(token.Owner, token.Application)
return affected != 0, application, &token
} }
func GetTokenByAccessToken(accessToken string) *Token { func GetTokenByAccessToken(accessToken string) *Token {
@ -265,7 +267,7 @@ func GetOAuthCode(userId string, clientId string, responseType string, redirectU
user := GetUser(userId) user := GetUser(userId)
if user == nil { if user == nil {
return &Code{ return &Code{
Message: fmt.Sprintf("token:The user: %s doesn't exist", userId), Message: fmt.Sprintf("general:The user: %s doesn't exist", userId),
Code: "", Code: "",
} }
} }
@ -319,7 +321,7 @@ func GetOAuthCode(userId string, clientId string, responseType string, redirectU
} }
} }
func GetOAuthToken(grantType string, clientId string, clientSecret string, code string, verifier string, scope string, username string, password string, host string, tag string, avatar string, lang string) interface{} { func GetOAuthToken(grantType string, clientId string, clientSecret string, code string, verifier string, scope string, username string, password string, host string, refreshToken string, tag string, avatar string, lang string) interface{} {
application := GetApplicationByClientId(clientId) application := GetApplicationByClientId(clientId)
if application == nil { if application == nil {
return &TokenError{ return &TokenError{
@ -346,6 +348,8 @@ func GetOAuthToken(grantType string, clientId string, clientSecret string, code
token, tokenError = GetPasswordToken(application, username, password, scope, host) token, tokenError = GetPasswordToken(application, username, password, scope, host)
case "client_credentials": // Client Credentials Grant case "client_credentials": // Client Credentials Grant
token, tokenError = GetClientCredentialsToken(application, clientSecret, scope, host) token, tokenError = GetClientCredentialsToken(application, clientSecret, scope, host)
case "refresh_token":
return RefreshToken(grantType, refreshToken, scope, clientId, clientSecret, host)
} }
if tag == "wechat_miniprogram" { if tag == "wechat_miniprogram" {

View File

@ -36,6 +36,60 @@ type UserShort struct {
Name string `xorm:"varchar(100) notnull pk" json:"name"` Name string `xorm:"varchar(100) notnull pk" json:"name"`
} }
type UserWithoutThirdIdp 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"`
UpdatedTime string `xorm:"varchar(100)" json:"updatedTime"`
Id string `xorm:"varchar(100) index" json:"id"`
Type string `xorm:"varchar(100)" json:"type"`
Password string `xorm:"varchar(100)" json:"password"`
PasswordSalt string `xorm:"varchar(100)" json:"passwordSalt"`
DisplayName string `xorm:"varchar(100)" json:"displayName"`
FirstName string `xorm:"varchar(100)" json:"firstName"`
LastName string `xorm:"varchar(100)" json:"lastName"`
Avatar string `xorm:"varchar(500)" json:"avatar"`
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"`
Location string `xorm:"varchar(100)" json:"location"`
Address []string `json:"address"`
Affiliation string `xorm:"varchar(100)" json:"affiliation"`
Title string `xorm:"varchar(100)" json:"title"`
IdCardType string `xorm:"varchar(100)" json:"idCardType"`
IdCard string `xorm:"varchar(100) index" json:"idCard"`
Homepage string `xorm:"varchar(100)" json:"homepage"`
Bio string `xorm:"varchar(100)" json:"bio"`
Tag string `xorm:"varchar(100)" json:"tag"`
Region string `xorm:"varchar(100)" json:"region"`
Language string `xorm:"varchar(100)" json:"language"`
Gender string `xorm:"varchar(100)" json:"gender"`
Birthday string `xorm:"varchar(100)" json:"birthday"`
Education string `xorm:"varchar(100)" json:"education"`
Score int `json:"score"`
Karma int `json:"karma"`
Ranking int `json:"ranking"`
IsDefaultAvatar bool `json:"isDefaultAvatar"`
IsOnline bool `json:"isOnline"`
IsAdmin bool `json:"isAdmin"`
IsGlobalAdmin bool `json:"isGlobalAdmin"`
IsForbidden bool `json:"isForbidden"`
IsDeleted bool `json:"isDeleted"`
SignupApplication string `xorm:"varchar(100)" json:"signupApplication"`
Hash string `xorm:"varchar(100)" json:"hash"`
PreHash string `xorm:"varchar(100)" json:"preHash"`
CreatedIp string `xorm:"varchar(100)" json:"createdIp"`
LastSigninTime string `xorm:"varchar(100)" json:"lastSigninTime"`
LastSigninIp string `xorm:"varchar(100)" json:"lastSigninIp"`
Ldap string `xorm:"ldap varchar(100)" json:"ldap"`
Properties map[string]string `json:"properties"`
Roles []*Role `xorm:"-" json:"roles"`
Permissions []*Permission `xorm:"-" json:"permissions"`
LastSigninWrongTime string `xorm:"varchar(100)" json:"lastSigninWrongTime"`
SigninWrongTimes int `json:"signinWrongTimes"`
}
type ClaimsShort struct { type ClaimsShort struct {
*UserShort *UserShort
TokenType string `json:"tokenType,omitempty"` TokenType string `json:"tokenType,omitempty"`
@ -44,6 +98,15 @@ type ClaimsShort struct {
jwt.RegisteredClaims jwt.RegisteredClaims
} }
type ClaimsWithoutThirdIdp struct {
*UserWithoutThirdIdp
TokenType string `json:"tokenType,omitempty"`
Nonce string `json:"nonce,omitempty"`
Tag string `json:"tag,omitempty"`
Scope string `json:"scope,omitempty"`
jwt.RegisteredClaims
}
func getShortUser(user *User) *UserShort { func getShortUser(user *User) *UserShort {
res := &UserShort{ res := &UserShort{
Owner: user.Owner, Owner: user.Owner,
@ -52,6 +115,69 @@ func getShortUser(user *User) *UserShort {
return res return res
} }
func getUserWithoutThirdIdp(user *User) *UserWithoutThirdIdp {
res := &UserWithoutThirdIdp{
Owner: user.Owner,
Name: user.Name,
CreatedTime: user.CreatedTime,
UpdatedTime: user.UpdatedTime,
Id: user.Id,
Type: user.Type,
Password: user.Password,
PasswordSalt: user.PasswordSalt,
DisplayName: user.DisplayName,
FirstName: user.FirstName,
LastName: user.LastName,
Avatar: user.Avatar,
PermanentAvatar: user.PermanentAvatar,
Email: user.Email,
EmailVerified: user.EmailVerified,
Phone: user.Phone,
Location: user.Location,
Address: user.Address,
Affiliation: user.Affiliation,
Title: user.Title,
IdCardType: user.IdCardType,
IdCard: user.IdCard,
Homepage: user.Homepage,
Bio: user.Bio,
Tag: user.Tag,
Region: user.Region,
Language: user.Language,
Gender: user.Gender,
Birthday: user.Birthday,
Education: user.Education,
Score: user.Score,
Karma: user.Karma,
Ranking: user.Ranking,
IsDefaultAvatar: user.IsDefaultAvatar,
IsOnline: user.IsOnline,
IsAdmin: user.IsAdmin,
IsGlobalAdmin: user.IsGlobalAdmin,
IsForbidden: user.IsForbidden,
IsDeleted: user.IsDeleted,
SignupApplication: user.SignupApplication,
Hash: user.Hash,
PreHash: user.PreHash,
CreatedIp: user.CreatedIp,
LastSigninTime: user.LastSigninTime,
LastSigninIp: user.LastSigninIp,
Ldap: user.Ldap,
Properties: user.Properties,
Roles: user.Roles,
Permissions: user.Permissions,
LastSigninWrongTime: user.LastSigninWrongTime,
SigninWrongTimes: user.SigninWrongTimes,
}
return res
}
func getShortClaims(claims Claims) ClaimsShort { func getShortClaims(claims Claims) ClaimsShort {
res := ClaimsShort{ res := ClaimsShort{
UserShort: getShortUser(claims.User), UserShort: getShortUser(claims.User),
@ -63,12 +189,44 @@ func getShortClaims(claims Claims) ClaimsShort {
return res return res
} }
func getClaimsWithoutThirdIdp(claims Claims) ClaimsWithoutThirdIdp {
res := ClaimsWithoutThirdIdp{
UserWithoutThirdIdp: getUserWithoutThirdIdp(claims.User),
TokenType: claims.TokenType,
Nonce: claims.Nonce,
Tag: claims.Tag,
Scope: claims.Scope,
RegisteredClaims: claims.RegisteredClaims,
}
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) { func generateJwtToken(application *Application, user *User, nonce string, scope string, host string) (string, string, string, error) {
nowTime := time.Now() nowTime := time.Now()
expireTime := nowTime.Add(time.Duration(application.ExpireInHours) * time.Hour) expireTime := nowTime.Add(time.Duration(application.ExpireInHours) * time.Hour)
refreshExpireTime := nowTime.Add(time.Duration(application.RefreshExpireInHours) * time.Hour) refreshExpireTime := nowTime.Add(time.Duration(application.RefreshExpireInHours) * time.Hour)
user.Password = "" user = refineUser(user)
_, originBackend := getOriginFromHost(host) _, originBackend := getOriginFromHost(host)
name := util.GenerateId() name := util.GenerateId()
@ -104,10 +262,12 @@ func generateJwtToken(application *Application, user *User, nonce string, scope
claimsShort.TokenType = "refresh-token" claimsShort.TokenType = "refresh-token"
refreshToken = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsShort) refreshToken = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsShort)
} else { } else {
token = jwt.NewWithClaims(jwt.SigningMethodRS256, claims) claimsWithoutThirdIdp := getClaimsWithoutThirdIdp(claims)
claims.ExpiresAt = jwt.NewNumericDate(refreshExpireTime)
claims.TokenType = "refresh-token" token = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsWithoutThirdIdp)
refreshToken = jwt.NewWithClaims(jwt.SigningMethodRS256, claims) claimsWithoutThirdIdp.ExpiresAt = jwt.NewNumericDate(refreshExpireTime)
claimsWithoutThirdIdp.TokenType = "refresh-token"
refreshToken = jwt.NewWithClaims(jwt.SigningMethodRS256, claimsWithoutThirdIdp)
} }
cert := getCertByApplication(application) cert := getCertByApplication(application)

View File

@ -21,7 +21,7 @@ import (
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"github.com/duo-labs/webauthn/webauthn" "github.com/duo-labs/webauthn/webauthn"
"xorm.io/core" "github.com/xorm-io/core"
) )
const ( const (
@ -78,32 +78,80 @@ type User struct {
LastSigninTime string `xorm:"varchar(100)" json:"lastSigninTime"` LastSigninTime string `xorm:"varchar(100)" json:"lastSigninTime"`
LastSigninIp string `xorm:"varchar(100)" json:"lastSigninIp"` LastSigninIp string `xorm:"varchar(100)" json:"lastSigninIp"`
GitHub string `xorm:"github varchar(100)" json:"github"` GitHub string `xorm:"github varchar(100)" json:"github"`
Google string `xorm:"varchar(100)" json:"google"` Google string `xorm:"varchar(100)" json:"google"`
QQ string `xorm:"qq varchar(100)" json:"qq"` QQ string `xorm:"qq varchar(100)" json:"qq"`
WeChat string `xorm:"wechat varchar(100)" json:"wechat"` WeChat string `xorm:"wechat varchar(100)" json:"wechat"`
Facebook string `xorm:"facebook varchar(100)" json:"facebook"` Facebook string `xorm:"facebook varchar(100)" json:"facebook"`
DingTalk string `xorm:"dingtalk varchar(100)" json:"dingtalk"` DingTalk string `xorm:"dingtalk varchar(100)" json:"dingtalk"`
Weibo string `xorm:"weibo varchar(100)" json:"weibo"` Weibo string `xorm:"weibo varchar(100)" json:"weibo"`
Gitee string `xorm:"gitee varchar(100)" json:"gitee"` Gitee string `xorm:"gitee varchar(100)" json:"gitee"`
LinkedIn string `xorm:"linkedin varchar(100)" json:"linkedin"` LinkedIn string `xorm:"linkedin varchar(100)" json:"linkedin"`
Wecom string `xorm:"wecom varchar(100)" json:"wecom"` Wecom string `xorm:"wecom varchar(100)" json:"wecom"`
Lark string `xorm:"lark varchar(100)" json:"lark"` Lark string `xorm:"lark varchar(100)" json:"lark"`
Gitlab string `xorm:"gitlab varchar(100)" json:"gitlab"` Gitlab string `xorm:"gitlab varchar(100)" json:"gitlab"`
Adfs string `xorm:"adfs varchar(100)" json:"adfs"` Adfs string `xorm:"adfs varchar(100)" json:"adfs"`
Baidu string `xorm:"baidu varchar(100)" json:"baidu"` Baidu string `xorm:"baidu varchar(100)" json:"baidu"`
Alipay string `xorm:"alipay varchar(100)" json:"alipay"` Alipay string `xorm:"alipay varchar(100)" json:"alipay"`
Casdoor string `xorm:"casdoor varchar(100)" json:"casdoor"` Casdoor string `xorm:"casdoor varchar(100)" json:"casdoor"`
Infoflow string `xorm:"infoflow varchar(100)" json:"infoflow"` Infoflow string `xorm:"infoflow varchar(100)" json:"infoflow"`
Apple string `xorm:"apple varchar(100)" json:"apple"` Apple string `xorm:"apple varchar(100)" json:"apple"`
AzureAD string `xorm:"azuread varchar(100)" json:"azuread"` AzureAD string `xorm:"azuread varchar(100)" json:"azuread"`
Slack string `xorm:"slack varchar(100)" json:"slack"` Slack string `xorm:"slack varchar(100)" json:"slack"`
Steam string `xorm:"steam varchar(100)" json:"steam"` Steam string `xorm:"steam varchar(100)" json:"steam"`
Bilibili string `xorm:"bilibili varchar(100)" json:"bilibili"` Bilibili string `xorm:"bilibili varchar(100)" json:"bilibili"`
Okta string `xorm:"okta varchar(100)" json:"okta"` Okta string `xorm:"okta varchar(100)" json:"okta"`
Douyin string `xorm:"douyin varchar(100)" json:"douyin"` Douyin string `xorm:"douyin varchar(100)" json:"douyin"`
Line string `xorm:"line varchar(100)" json:"line"` Line string `xorm:"line varchar(100)" json:"line"`
Custom string `xorm:"custom varchar(100)" json:"custom"` 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"` WebauthnCredentials []webauthn.Credential `xorm:"webauthnCredentials blob" json:"webauthnCredentials"`
@ -529,6 +577,9 @@ func AddUsersInBatch(users []*User) bool {
} }
func DeleteUser(user *User) bool { func DeleteUser(user *User) bool {
// Forced offline the user first
DeleteSession(util.GetSessionId(user.Owner, user.Name, CasdoorApplication))
affected, err := adapter.Engine.ID(core.PK{user.Owner, user.Name}).Delete(&User{}) affected, err := adapter.Engine.ID(core.PK{user.Owner, user.Name}).Delete(&User{})
if err != nil { if err != nil {
panic(err) panic(err)

View File

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

View File

@ -20,7 +20,7 @@ import (
"strings" "strings"
"github.com/casdoor/casdoor/idp" "github.com/casdoor/casdoor/idp"
"xorm.io/core" "github.com/xorm-io/core"
) )
func GetUserByField(organizationName string, field string, value string) *User { func GetUserByField(organizationName string, field string, value string) *User {

View File

@ -23,7 +23,11 @@ import (
"github.com/casdoor/casdoor/conf" "github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/i18n" "github.com/casdoor/casdoor/i18n"
"github.com/casdoor/casdoor/util" "github.com/casdoor/casdoor/util"
"xorm.io/core" "github.com/xorm-io/core"
)
const (
wrongCode = "wrongCode"
) )
type VerificationRecord struct { type VerificationRecord struct {
@ -167,7 +171,7 @@ func CheckVerificationCode(dest, code, lang string) string {
} }
if record.Code != code { if record.Code != code {
return "Wrong code!" return wrongCode
} }
return "" return ""
@ -186,6 +190,24 @@ func DisableVerificationCode(dest string) {
} }
} }
func CheckSigninCode(user *User, dest, code, lang string) string {
// check the login error times
if msg := checkSigninErrorTimes(user, lang); msg != "" {
return msg
}
result := CheckVerificationCode(dest, code, lang)
switch result {
case "":
resetUserSigninErrorTimes(user)
return ""
case wrongCode:
return recordSigninErrorInfo(user, lang)
default:
return result
}
}
// From Casnode/object/validateCode.go line 116 // From Casnode/object/validateCode.go line 116
var stdNums = []byte("0123456789") var stdNums = []byte("0123456789")

View File

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

View File

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

View File

@ -158,12 +158,17 @@ func initAPI() {
beego.Router("/api/login/oauth/access_token", &controllers.ApiController{}, "POST:GetOAuthToken") beego.Router("/api/login/oauth/access_token", &controllers.ApiController{}, "POST:GetOAuthToken")
beego.Router("/api/login/oauth/refresh_token", &controllers.ApiController{}, "POST:RefreshToken") beego.Router("/api/login/oauth/refresh_token", &controllers.ApiController{}, "POST:RefreshToken")
beego.Router("/api/login/oauth/introspect", &controllers.ApiController{}, "POST:IntrospectToken") beego.Router("/api/login/oauth/introspect", &controllers.ApiController{}, "POST:IntrospectToken")
beego.Router("/api/login/oauth/logout", &controllers.ApiController{}, "GET:TokenLogout")
beego.Router("/api/get-records", &controllers.ApiController{}, "GET:GetRecords") beego.Router("/api/get-records", &controllers.ApiController{}, "GET:GetRecords")
beego.Router("/api/get-records-filter", &controllers.ApiController{}, "POST:GetRecordsByFilter") beego.Router("/api/get-records-filter", &controllers.ApiController{}, "POST:GetRecordsByFilter")
beego.Router("/api/add-record", &controllers.ApiController{}, "POST:AddRecord") beego.Router("/api/add-record", &controllers.ApiController{}, "POST:AddRecord")
beego.Router("/api/get-sessions", &controllers.ApiController{}, "GET:GetSessions")
beego.Router("/api/get-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-webhooks", &controllers.ApiController{}, "GET:GetWebhooks")
beego.Router("/api/get-webhook", &controllers.ApiController{}, "GET:GetWebhook") beego.Router("/api/get-webhook", &controllers.ApiController{}, "GET:GetWebhook")
beego.Router("/api/update-webhook", &controllers.ApiController{}, "POST:UpdateWebhook") beego.Router("/api/update-webhook", &controllers.ApiController{}, "POST:UpdateWebhook")

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

25
util/slice.go Normal file
View File

@ -0,0 +1,25 @@
// Copyright 2022 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package util
func DeleteVal(values []string, val string) []string {
newValues := []string{}
for _, v := range values {
if v != val {
newValues = append(newValues, v)
}
}
return newValues
}

View File

@ -100,6 +100,15 @@ func GetOwnerAndNameFromIdNoCheck(id string) (string, string) {
return tokens[0], tokens[1] return tokens[0], tokens[1]
} }
func GetOwnerAndNameAndOtherFromId(id string) (string, string, string) {
tokens := strings.Split(id, "/")
if len(tokens) != 3 {
panic(errors.New("GetOwnerAndNameAndOtherFromId() error, wrong token count for ID: " + id))
}
return tokens[0], tokens[1], tokens[2]
}
func GenerateId() string { func GenerateId() string {
return uuid.NewString() return uuid.NewString()
} }
@ -127,6 +136,10 @@ func GetId(owner, name string) string {
return fmt.Sprintf("%s/%s", owner, name) return fmt.Sprintf("%s/%s", owner, name)
} }
func GetSessionId(owner, name, application string) string {
return fmt.Sprintf("%s/%s/%s", owner, name, application)
}
func GetMd5Hash(text string) string { func GetMd5Hash(text string) string {
hash := md5.Sum([]byte(text)) hash := md5.Sum([]byte(text))
return hex.EncodeToString(hash[:]) return hex.EncodeToString(hash[:])

View File

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

View File

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

View File

@ -53,50 +53,50 @@ func Test_IsTokenExpired(t *testing.T) {
for _, scenario := range []testCases{ for _, scenario := range []testCases{
{ {
description: "Token emited now is valid for 60 minutes", description: "Token emitted now is valid for 60 minutes",
input: input{ input: input{
createdTime: time.Now().Format(time.RFC3339), createdTime: time.Now().Format(time.RFC3339),
expiresIn: 60, expiresIn: 3600,
}, },
expected: false, expected: false,
}, },
{ {
description: "Token emited 60 minutes before now is valid for 60 minutes", description: "Token emitted 60 minutes before now is valid for 61 minutes",
input: input{ input: input{
createdTime: time.Now().Add(-time.Minute * 60).Format(time.RFC3339), createdTime: time.Now().Add(-time.Minute * 60).Format(time.RFC3339),
expiresIn: 61, expiresIn: 3660,
}, },
expected: false, expected: false,
}, },
{ {
description: "Token emited 2 hours before now is Expired after 60 minutes", description: "Token emitted 2 hours before now is Expired after 60 minutes",
input: input{ input: input{
createdTime: time.Now().Add(-time.Hour * 2).Format(time.RFC3339), createdTime: time.Now().Add(-time.Hour * 2).Format(time.RFC3339),
expiresIn: 60, expiresIn: 3600,
}, },
expected: true, expected: true,
}, },
{ {
description: "Token emited 61 minutes before now is Expired after 60 minutes", description: "Token emitted 61 minutes before now is Expired after 60 minutes",
input: input{ input: input{
createdTime: time.Now().Add(-time.Minute * 61).Format(time.RFC3339), createdTime: time.Now().Add(-time.Minute * 61).Format(time.RFC3339),
expiresIn: 60, expiresIn: 3600,
}, },
expected: true, expected: true,
}, },
{ {
description: "Token emited 2 hours before now is velid for 120 minutes", description: "Token emitted 2 hours before now is valid for 121 minutes",
input: input{ input: input{
createdTime: time.Now().Add(-time.Hour * 2).Format(time.RFC3339), createdTime: time.Now().Add(-time.Hour * 2).Format(time.RFC3339),
expiresIn: 121, expiresIn: 7260,
}, },
expected: false, expected: false,
}, },
{ {
description: "Token emited 159 minutes before now is Expired after 60 minutes", description: "Token emitted 159 minutes before now is Expired after 120 minutes",
input: input{ input: input{
createdTime: time.Now().Add(-time.Minute * 159).Format(time.RFC3339), createdTime: time.Now().Add(-time.Minute * 159).Format(time.RFC3339),
expiresIn: 120, expiresIn: 7200,
}, },
expected: true, expected: true,
}, },

10
web/cypress.config.js Normal file
View File

@ -0,0 +1,10 @@
const { defineConfig } = require("cypress");
module.exports = defineConfig({
e2e: {
"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

@ -0,0 +1,56 @@
describe("Login test", () => {
const selector = {
username: "#input",
password: "#normal_login_password",
loginButton: ".ant-btn",
};
it("Login succeeded", () => {
cy.request({
method: "POST",
url: "http://localhost:7001/api/login",
body: {
"application": "app-built-in",
"organization": "built-in",
"username": "admin",
"password": "123",
"autoSignin": true,
"type": "login",
"phonePrefix": "86",
},
}).then((Response) => {
expect(Response).property("body").property("status").to.equal("ok");
});
});
it("ui Login succeeded", () => {
cy.visit("http://localhost:7001");
cy.get(selector.username).type("admin");
cy.get(selector.password).type("123");
cy.get(selector.loginButton).click();
cy.url().should("eq", "http://localhost:7001/");
});
it("Login failed", () => {
cy.request({
method: "POST",
url: "http://localhost:7001/api/login",
body: {
"application": "app-built-in",
"organization": "built-in",
"username": "admin",
"password": "1234",
"autoSignin": true,
"type": "login",
"phonePrefix": "86",
},
}).then((Response) => {
expect(Response).property("body").property("status").to.equal("error");
});
});
it("ui Login failed", () => {
cy.visit("http://localhost:7001");
cy.get(selector.username).type("admin");
cy.get(selector.password).type("1234");
cy.get(selector.loginButton).click();
cy.url().should("eq", "http://localhost:7001/login");
});
});

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/")
});
})

View File

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

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