Compare commits

...

703 Commits

Author SHA1 Message Date
9bbe5afb7c feat: use only one salt arg in CredManager.IsPasswordCorrect() (#3936) 2025-07-07 17:56:25 +08:00
b42391c6ce feat: move needUpdatePassword to response's Data3 field to avoid refresh token conflict (#3931) 2025-07-05 22:48:44 +08:00
fb035a5353 feat: CredManager.GetHashedPassword() only contains one salt arg now (#3928) 2025-07-05 18:41:37 +08:00
b1f68a60a4 feat: set createDatabase to false in TestDumpToFile() (#3924) 2025-07-03 22:50:23 +08:00
201d704a31 feat: improve TikTok username generation logic (#3923) 2025-07-03 20:53:15 +08:00
bf91ad6c97 feat: add Internet-Only captcha rule (#3919) 2025-07-03 02:39:06 +08:00
3ccc0339c7 feat: improve CheckToEnableCaptcha() logic 2025-07-03 02:32:07 +08:00
1f2b0a3587 feat: add user's MFA items (#3921) 2025-07-02 23:05:07 +08:00
0b3feb0d5f feat: use Input.OTP to input totp code (#3922) 2025-07-02 18:22:59 +08:00
568c0e2c3d feat: show Organization.PasswordOptions in login UI (#3913) 2025-06-28 22:13:00 +08:00
f4ad2b4034 feat: remove "@" from name's forbidden chars 2025-06-27 18:41:50 +08:00
c9f8727890 feat: fix bug in InitCleanupTokens() (#3910) 2025-06-27 02:08:18 +08:00
e2e3c1fbb8 feat: support Product.SuccessUrl (#3908) 2025-06-26 22:52:07 +08:00
73915ac0a0 feat: fix issue that LDAP user address was not syncing (#3905) 2025-06-26 09:38:16 +08:00
bf9d55ff40 feat: add InitCleanupTokens() (#3903) 2025-06-26 09:31:59 +08:00
b36fb50239 feat: fix check bug to allow logged-in users to buy product (#3897) 2025-06-25 10:49:20 +08:00
4307baa759 feat: fix Tumblr OAuth's wrong scope (#3898) 2025-06-25 09:55:02 +08:00
3964bae1df feat: fix org's LDAP table wrong link (#3900) 2025-06-25 09:51:40 +08:00
d9b97d70be feat: change CRLF to LF for some files 2025-06-24 09:55:00 +08:00
ca224fdd4c feat: add group xlsx upload button (#3885) 2025-06-17 23:43:38 +08:00
37daea2bbc feat: improve error message in ApplicationEditPage (#3886) 2025-06-17 20:06:52 +08:00
af231bf946 feat: add FieldValidationFilter to check object names (#3877) 2025-06-17 16:11:35 +08:00
6dc7b4d533 feat: get-user API respects org's account item's view rules now (#3882) 2025-06-16 20:09:21 +08:00
12cc0f429e feat: remove support for Non trace verification for Alibaba cloud captcha verification (#3881) 2025-06-13 00:36:29 +08:00
8cc22dec91 feat: upgrade Alibaba cloud captcha provider from v1 to v2 (#3879) 2025-06-12 23:02:36 +08:00
0c08ae5365 feat: Add support for email verification logic (#3875) 2025-06-11 19:17:16 +08:00
c3485268d3 feat: fix "Display name cannot be empty" in /update-user API 2025-06-11 00:32:05 +08:00
64a4956c42 feat: improve getMemoryUsage() 2025-06-09 20:08:55 +08:00
855bdf47e8 feat: fix memory usage in sysinfo page (#3870) 2025-06-09 00:31:34 +08:00
de7e322fbb feat: limit the width of the organization.hasPrivilegeConsent popconfirm (#3869) 2025-06-07 00:30:41 +08:00
4cb0cd7c5a feat: add Organization.HasPrivilegeConsent to block add-user API for the "built-in" org (#3864) 2025-06-06 23:05:01 +08:00
c6a50349cc feat: add missing backend i18n texts (#3863) 2025-06-06 00:03:04 +08:00
8a098a4b6e feat: skip node_modules folder when generating i18n (#3862) 2025-06-05 20:51:14 +08:00
09f98fd24a feat: rollback to Beego 1.12.12 to fix Redis session issue 2025-06-04 22:40:54 +08:00
515d209063 feat: update go dependencies (#3855) 2025-06-03 16:38:06 +08:00
4e17dae2c2 feat: fix unable to remove user from group bug (#3847) 2025-05-28 22:29:40 +08:00
0ad4d82d9c feat: fix GetGroups() API bug when parentGroup is in next page (#3843) 2025-05-28 18:31:52 +08:00
731daf5204 feat: allow org admin to change org user's password without old password (#3841) 2025-05-28 01:23:44 +08:00
b6b77da7cf feat: refactor the code in NewSmtpEmailProvider() (#3832) 2025-05-26 20:23:47 +08:00
8b4637aa3a feat: provide a more complete Excel template for uploading users and fix any bugs (#3831) 2025-05-25 21:23:48 +08:00
87506b84e3 feat: support special chars like "+" in username parameter of /api/get-email-and-phone API (#3824) 2025-05-23 17:29:00 +08:00
fed9332246 feat: can configure Domain field in Nextcloud OAuth provider (#3813) 2025-05-23 17:23:34 +08:00
33afc52a0b feat: can redirect user to login page after linking provider in prompt page (#3820) 2025-05-23 07:15:53 +08:00
9035ca365a feat: improve Indonesia i18n translations (#3817) 2025-05-22 20:42:47 +08:00
b97ae72179 feat: use the standard user struct for JWT-Standard to get a correct userinfo (#3809) 2025-05-21 18:54:42 +08:00
9190db1099 feat: fix bug that token endpoint doesn't return 400/401 when type is object.TokenError (#3808) 2025-05-20 10:39:55 +08:00
1173f75794 feat: return HTTP status 400 instead of 200 in GetOAuthToken() (#3807) 2025-05-20 01:05:43 +08:00
086859d1ce feat: change User.Avatar length back to 500 2025-05-18 09:47:56 +08:00
9afaf5d695 feat: increase User.Avatar length to 1000 2025-05-17 19:59:17 +08:00
521f90a603 feat: fix access_token endpoint cannot read clientId in form when using device code flow (#3800) 2025-05-17 18:53:38 +08:00
4260efcfd0 feat: add useIdAsName field for WeCom OAuth provider (#3797) 2025-05-17 02:27:06 +08:00
d772b0b7a8 feat: fix bug that username will be random with useEmailAsUsername enabled (#3793) 2025-05-16 18:40:50 +08:00
702b390da1 feat: fix MFA preference doesn't work bug (#3790) 2025-05-15 21:04:36 +08:00
b15b3b9335 feat: support adapter in app.conf logConfig (#3784) 2025-05-14 08:27:11 +08:00
f8f864c5b9 feat: add logged-in IDP provider info to access token (#3776) 2025-05-11 09:51:51 +08:00
90e790f83c feat: increase Application.SamlReplyUrl from 100 chars to 500 2025-05-10 22:42:40 +08:00
58413246f3 feat: fix bug that db not found error in createDatabaseForPostgres (#3765) 2025-05-05 18:25:58 +08:00
8f307dd907 feat: upgrade go-teams-notify to v2.13.0 2025-05-05 01:02:27 +08:00
fe42b5e0ba feat: improve checkGroupName() (#3759) 2025-05-03 22:47:42 +08:00
383bf44391 feat: support OIDC device flow: "/api/device-auth" (#3757) 2025-04-30 23:42:26 +08:00
36f5de3203 feat: allow jwks to include the certs from non-admin owner (#3749) 2025-04-28 09:31:56 +08:00
eae69c41d7 feat: add object field filter for webhook (#3746) 2025-04-26 22:05:36 +08:00
91057f54f3 feat: add Pbkdf2DjangoCredManager (#3745) 2025-04-25 16:16:50 +08:00
daa7b79915 feat: improve error handling of webauthn login (#3744) 2025-04-24 01:11:24 +08:00
d3a5539dae feat: fix loading status not reset issue when failed to login (#3743) 2025-04-24 00:57:52 +08:00
7d1c614452 feat: use random name as name if user's name is invalid when created by third party provider (#3742) 2025-04-23 21:30:19 +08:00
e2eafa909b feat: fix MODEL_URL in FaceRecognitionModal 2025-04-21 09:10:30 +08:00
56bcef0592 feat: support application.formCss in forget-password page (#3733) 2025-04-19 22:59:21 +08:00
0860cbf343 feat: can specify content type and http body field mapping for Custom HTTP Email provider (#3730) 2025-04-17 01:59:11 +08:00
2f4180b1b6 feat: add missing currencies in plan edit page (#3727) 2025-04-15 16:01:14 +08:00
e3d5619b25 feat: support custom HTTP headers in custom HttpEmailProvider and hide unused fields (#3723) 2025-04-13 23:52:04 +08:00
019fd87b92 feat: fix code comment typos (#3724) 2025-04-13 17:57:37 +08:00
5c41c6c4a5 feat: add BRL currency 2025-04-11 22:24:45 +08:00
b7fafcc62b feat: improve InitFromFile() code order to fix GetOrganizationApplicationCount always returns 0 bug (#3720) 2025-04-11 01:43:54 +08:00
493ceddcd9 feat: improve error handling in system info page 2025-04-11 01:41:27 +08:00
fc618b9bd5 feat: add validation for optional fields in IntrospectionToken for custom token types (#3717) 2025-04-09 22:27:19 +08:00
a00900e405 feat: fix sqlite bug for failed to lookup Client-side Discoverable Credential: user not exist (#3719) 2025-04-09 22:26:47 +08:00
77ef5828dd feat(introspection): return correct active status for expired or revoked tokens (#3716) 2025-04-09 02:00:30 +08:00
c11f013e04 feat: return "Active: false" for expired token in IntrospectToken() (#3714) 2025-04-08 23:20:44 +08:00
b3bafe8402 feat: fix bug that unable to query webauthnCredentials when db is mssql or postgres in GetUserByWebauthID() (#3712) 2025-04-08 17:51:32 +08:00
f04a431d85 feat: Casdoor's LDAP client supports LDAP server's self-signed certificates now (#3709) 2025-04-07 02:02:32 +08:00
952538916d feat: check application existence in object.AddUser() (#3686) 2025-04-05 16:38:20 +08:00
18bb445e71 feat: update github.com/golang-jwt/jwt dependency to v5 (#3708) 2025-04-05 02:05:41 +08:00
cca88e2cb0 feat: fix bug that when email/sms mfa is not preferred, message will send to masked address (#3705) 2025-04-04 01:08:29 +08:00
86c10fe0ab feat: change org.CountryCodes to mediumtext 2025-04-02 20:23:04 +08:00
c1b3bf0f45 feat: set button to loading status immediately after click (#3696) 2025-04-02 01:15:36 +08:00
62bda61af5 feat: can use provider_hint arg to do OAuth redirect automatically (#3698) 2025-04-02 01:15:20 +08:00
b6f943e326 feat: support WebAuthn login without username and upgrade Go to 1.21 (#3695) 2025-04-01 16:35:59 +08:00
2cc5e82d91 feat: support login button loading state (#3694) 2025-04-01 00:57:24 +08:00
e55cd94298 feat: fix issue that user email is still unverified after signup (#3685) 2025-03-29 21:24:01 +08:00
08f7a05e61 feat: fix MFA + LDAP bug in /check-user-password API (#3681) 2025-03-26 22:11:58 +08:00
4bee21f4a3 feat: use StaticBaseUrl in frontend 2025-03-26 21:32:31 +08:00
5417a90223 feat: fix bug that there is already an object named 'casbin_api_rule' in the database (#3680) 2025-03-25 22:24:58 +08:00
131820e34e feat: add application.ForcedRedirectOrigin 2025-03-24 13:42:35 +08:00
2fcbf7cf6c feat: fix apps page grid style (#3679) 2025-03-22 18:19:14 +08:00
14ade8b7e4 feat: fix provider test API's missing owner and name args for auth (#3676) 2025-03-22 17:53:20 +08:00
a11fe59704 feat: support widget items config in org (#3674) 2025-03-21 23:00:07 +08:00
af55d0547f feat: improve frontend i18n strings 2025-03-21 21:03:29 +08:00
81102f8298 feat: fix permission update bug when both org and model are modified (#3671) 2025-03-20 09:05:27 +08:00
141372cb86 feat: support face ID provider (#3666) 2025-03-19 22:57:35 +08:00
15a037ca74 feat: increase frontend build memory to 4096 in Dockerfile (#3672)
297.8 FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory
2025-03-19 10:40:34 +08:00
73c680d56f feat: avoid using body in GET requests for AirwallexClient payment provider (#3669) 2025-03-18 20:04:15 +08:00
aafc16e4f4 feat: fix dynamic width of navbar UI (#3664) 2025-03-16 16:12:58 +08:00
7be026dd1f feat: Support for selecting existing users or scanning a QR code when logging into Dingtalk (#3660) 2025-03-13 21:49:07 +08:00
3e7938e5f6 feat: don't panic when provider not found in Login() API (#3659) 2025-03-13 21:35:51 +08:00
30789138e2 feat: fix faceId loop error caused by async (#3651) 2025-03-11 21:03:04 +08:00
9610ce5b8c feat: can add faceId by uploading images (#3641) 2025-03-09 01:29:25 +08:00
a39a311d2f feat: fix webhook bug in RecordEx JSON (#3642) 2025-03-08 00:20:59 +08:00
08e41ab762 feat: can specify user fields in webhook edit page (#3635) 2025-03-04 14:16:16 +08:00
85ca318e2f feat: can assign default group during signup (#3633) 2025-03-02 22:55:51 +08:00
9032865e60 feat: support mobile background for login page (#3629) 2025-03-01 23:01:15 +08:00
5692522ee0 feat: update user language when the language changed on login page (#3628) 2025-03-01 22:28:20 +08:00
cb1882e589 feat: fix MFA bug, revert PR: "feat: don't send verification code if failed signin limit is reached" (#3627) 2025-03-01 12:58:28 +08:00
41d9422687 feat: increase username limit to 255 chars 2025-03-01 00:44:34 +08:00
3297db688b feat: support shared cert in GetCert() API 2025-02-28 23:02:13 +08:00
cc82d292f0 feat: set frontend origin to 7001 if in dev mode (#3615) 2025-02-26 22:35:50 +08:00
f2e3037bc5 feat: don't send verification code if failed signin limit is reached (#3616) 2025-02-26 22:34:14 +08:00
d986a4a9e0 feat: fix bug that initialize group children as empty array instead of empty string (#3620) 2025-02-26 08:50:09 +08:00
2df3878c15 feat: fix bug that group.HaveChildren is never set to false bug Something isn't working (#3609) 2025-02-22 01:46:35 +08:00
24ab8880cc feat: fix bug that organization might be nil in some case and cause nil point error (#3608) 2025-02-21 23:43:30 +08:00
f26b4853c5 feat: bump Go version to go 1.18 (#3599) 2025-02-21 13:10:17 +08:00
d78e8e9776 feat: fix LDAP filter condition will return nil if error happened (#3604) 2025-02-21 13:09:39 +08:00
d61f9a1856 feat: update antd from 5.2.3 to 5.24.1 (#3593) 2025-02-18 20:54:10 +08:00
aa52af02b3 feat: fix style props of Editor (#3590) 2025-02-17 13:39:49 +08:00
2a5722e45b feat: add detail sidebar for record list page, improve token list page (#3589) 2025-02-16 22:01:25 +08:00
26718bc4a1 feat: update signinUrl storage to include pathname and query parameters only to prevent new tab popup after password reset (#3587) 2025-02-14 20:31:36 +08:00
f8d44e2dca feat: set default CountryCode for user 2025-02-14 16:54:25 +08:00
26eea501be feat: don't use organization.MasterVerificationCode when sending 2025-02-14 16:54:25 +08:00
63b8e857bc feat: update signinUrl storage to include path and query parameters in forced reset password flow (#3583) 2025-02-14 01:32:10 +08:00
81b336b37a feat: replace react-codemirror2 with @uiw/react-codemirror (#3577)
Signed-off-by: WindSpiritSR <simon343riley@gmail.com>
2025-02-14 00:10:33 +08:00
9c39179849 feat: fix bug that user forbidden check will be skipped in OAuth login (#3580) 2025-02-13 13:14:44 +08:00
37d93a5eea feat: update SendgridEmailProvider to support dynamic host/path, add From name field (#3576)
* feat: add fields into UI FromName, Host, Endpoint

* feat: update SendgridEmailProvider support dynamic host/path client init, code convention
2025-02-13 00:51:31 +08:00
e926a07c58 feat: add "User type" to user list page 2025-02-12 21:29:18 +08:00
9c46344e68 feat: improve default org passwordOptions handling 2025-02-12 21:20:32 +08:00
c0ec73dfd3 feat: fix tableNamePrefix doesn't work bug in /get-dashboard API (#3572) 2025-02-11 17:20:45 +08:00
b1b6ebe692 feat(jwt): add azp claim to ID token (#3570)
Added the `azp` (Authorized Party) claim to various JWT token structures
including Claims, ClaimsShort, ClaimsWithoutThirdIdp, and ClaimsStandard.
Updated the generateJwtToken and getClaimsCustom functions to handle the
new claim. This change aligns with the OpenID Connect specification.
2025-02-10 20:44:44 +08:00
a0931e4597 feat: add userTypes to Organization 2025-02-09 17:12:13 +08:00
c181006661 feat: cache theme in signup page (#3568) 2025-02-09 15:12:35 +08:00
2e83e49492 feat: fix bug due to null characters in descriptor when creating a payment intent (#3567) 2025-02-08 19:35:51 +08:00
5661942175 feat: add CLI version cache and proxy support (#3565)
* feat: add CLI version cache mechanism

* feat: add /api/refresh-engines to allowed endpoints in demo mode

* feat: add proxy support for cli downloader

* feat: add SafeGoroutine for CLIDownloader initialization

* refactor: optimize code structure
2025-02-08 19:34:19 +08:00
7f9f7c6468 feat: add CLI tools auto-downloader and updater (#3559)
* feat: add CLI downloader feature

* feat: add CLI refresh endpoint and scheduler

* feat: improve binary names mapping for different platforms and architectures

* fix: format binary names in getBinaryNames function

* fix: change file permission notation to octal in cli_downloader.go

* feat: add isDemoMode check for CLI downloader features
2025-02-07 19:22:56 +08:00
b7a818e2d3 feat: support AirWallex payment provider (#3558)
* feat: support AirWallex payment provider

* chore: add some information due to AirWallex's risk control policy
2025-02-07 19:19:30 +08:00
1a8cfe4ee6 feat: can fetch SAML metadata from URL (#3560) 2025-02-06 23:50:39 +08:00
b3526de675 feat: add checkOrgMasterVerificationCode() 2025-02-06 23:46:22 +08:00
3b9e08b70d feat: Fix reset password flow for shared application (#3556) 2025-02-06 18:03:23 +08:00
cfc6015aca feat: rename Casdoor app URL to authenticator (#3553) 2025-02-05 23:08:06 +08:00
1600a6799a feat: return error for updateUsedByCode() 2025-02-05 13:40:41 +08:00
ca60cc3a33 feat: show SAML cert parse error better in frontend (#3551) 2025-02-05 10:06:02 +08:00
df295717f0 feat: can define what Casdoor pages an org admin can see via Organization.NavItems (#3539)
* feat: support define what Casdoor pages an org admin can see

* feat: remove useless code

* fix: fix NavItemNodes i18next invalid

* fix: only global admin can edit navItems

* fix: move navItem tree to extra file
2025-02-03 00:40:21 +08:00
e3001671a2 feat: fix bug that can not delete user if user doesn't belong to any group (#3544) 2025-02-02 17:54:05 +08:00
bbe2162e27 feat: fix bug in GetTokenByTokenValue() (#3541) 2025-01-30 00:48:20 +08:00
92b5ce3722 feat: add identifier validation for security in RunCasbinCommand (#3535)
* feat: add identifier validation for security in RunCasbinCommand

* refactor: update identifier validation to use SHA-256 hash and timestamp
2025-01-29 18:30:06 +08:00
bad21fb6bb feat: check empty password in CheckPassword() 2025-01-28 21:13:59 +08:00
5a78dcf06d feat: fix Casbin Permissions Not Working When Auto-login is Enabled (#3537)
* fix: fix Casbin Permissions Not Working When Auto-login is Enabled

* fix: fix oauth fastLogin not support permission
2025-01-28 19:15:53 +08:00
558b168477 feat: can verify OTP during OAuth login (#3531)
* feat: support verify OTP during OAuth login

* fix: fail to login if mfa not enable

* fix: fail to login if mfa not enable

* fix: fix mfaRequired not valid in saml/auth
2025-01-27 19:37:26 +08:00
802b6812a9 feat: fix strange "Email is invalid" error in forget password page (#3527) 2025-01-23 14:35:11 +08:00
a5a627f92e feat: optimize get-groups API and GroupListPage (#3518)
* fix: optimize get-groups api and GroupListPage

* fix: fix linter issue
2025-01-23 09:47:39 +08:00
9701818a6e feat: delete groups for user while deleting user (#3525) 2025-01-23 09:46:33 +08:00
06986fbd41 feat: fix theme filter for other URLs like SAML (#3523)
* fix: fix error cause by theme filter

* fix: add saml url to theme filter and use getGetOwnerAndNameFromIdWithError instead of using GetOwnerAndNameFromId

* fix: fix code error

* fix: add support for cas and pack judgement into a function

* fix: fix linter err
2025-01-22 19:12:12 +08:00
3d12ac8dc2 feat: improve HandleScim() 2025-01-22 16:15:19 +08:00
f01839123f feat: fix missing param recoveryCodes in /mfa/setup/enable API (#3520) 2025-01-21 22:56:02 +08:00
e1b3b0ac6a feat: allow user use other mfaType in mfa step and skip redundant MFA verification (#3499)
* feat: allow user use other mfaType in mfa step and skip redundant MFA verification

* feat: improve format
2025-01-21 20:16:18 +08:00
4b0a2fdbfc feat: append HTML document title and favicon to cookie (#3519)
* feat: append HTML document title and favicon to cookie

* feat: remove useless cookie
2025-01-21 19:42:21 +08:00
db551eb24a feat: LDAP user can reset password with old password and new password (#3516)
* feat: support user reset password with old password and new password

* feat: merge similar code
2025-01-20 21:42:05 +08:00
18b49bb731 feat: can reset LDAP password with different password encryption methods (#3513) 2025-01-20 20:00:23 +08:00
17653888a3 feat: refactor the TestSmtpServer code 2025-01-20 03:17:09 +08:00
ee16616df4 feat: support socks5Proxy for AWS Email provider 2025-01-20 02:39:23 +08:00
ea450005e0 feat: fix "logo" bug in footer 2025-01-20 00:01:46 +08:00
4c5ad14f6b fix: spin will squeeze login panel (#3509) 2025-01-19 23:35:04 +08:00
49dda2aea5 feat: append footerHtml to cookie (#3508) 2025-01-19 23:34:43 +08:00
a74a004540 feat: append logo url to cookie (#3507) 2025-01-19 08:02:44 +08:00
2b89f6b37b feat: fix issue that application theme is ignored in appendThemeCookie() (#3506) 2025-01-18 21:28:39 +08:00
c699e35e6b feat: load theme from first HTML render cookie (#3505) 2025-01-18 19:04:16 +08:00
e28d90d0aa feat: support CUCloud SMN notification provider (#3502) 2025-01-17 08:35:31 +08:00
4fc7600865 feat: skip update user ranking if ranking not in accountItem (#3500) 2025-01-14 22:43:49 +08:00
19f62a461b feat: fix SAML's redirectUrl and POST ProtocolBinding (#3498) 2025-01-13 20:55:37 +08:00
7ddc2778c0 feat: show error message when organization doesn't have default application in invitation edit page (#3495)
* fix: inform user when organization haven't default application in signup page

* fix: include org name in the error message
2025-01-12 22:48:21 +08:00
b96fa2a995 feat: skip GetUserCount() if there is no quota limit (#3491) 2025-01-10 22:28:25 +08:00
fcfb73af6e feat: increase org password field length to 200 2025-01-09 20:07:49 +08:00
43bebc03b9 feat: fix crash in roleChangeTrigger() 2025-01-09 16:41:56 +08:00
c5f25cbc7d feat: getPidByPort() supports alpine now (#3483)
Signed-off-by: WindSpiritSR <simon343riley@gmail.com>
2025-01-08 12:18:46 +08:00
3feb6ce84d feat: add Kwai OAuth provider (#3480)
* feat: add Kwai OAuth provider

* fix: incorrect parameter in getAuthUrl
2025-01-08 00:09:16 +08:00
08d6b45fc5 feat: keeps "build" folder during yarn build 2025-01-07 23:38:50 +08:00
56d0de64dc feat: support StopOldInstance() 2025-01-07 21:39:21 +08:00
1813e8e8c7 feat: return goroutine error in get-dashboard API (#3479) 2025-01-07 10:35:45 +08:00
e27c764a55 feat: fix bug that GitHub oauth provider shows error if failed to fetch user's email (#3474)
* fix: fix github idp will stop login if it cannot fetch user's email through al restful api

* Update github.go

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2025-01-05 20:25:42 +08:00
e5a2057382 feat: fix empty scope bug in RefreshToken API (#3467)
* fix: fix scope will be empty when user not passing scope in refresh api

* fix: promote code format
2025-01-02 12:53:17 +08:00
8457ff7433 feat: support radiusDefaultOrganization in app.conf 2025-01-02 00:10:58 +08:00
888a6f2feb feat: add regex to restrict Email addresses in OAuth provider (#3465)
* feat: support use regex expression to limit email receiver address

* feat: limit in correct pos

* feat: promote code format

* feat: promote code format

* fix: fix linter issue
2025-01-02 00:00:57 +08:00
b57b64fc36 feat: add origin field for mfaAccountTable (#3463) 2024-12-29 22:51:21 +08:00
0d239ba1cf feat: improve the error message of GitHub OAuth provider (#3462) 2024-12-29 21:54:54 +08:00
8927e08217 feat: speed up GetDashboard() by only fetching last 30 days data (#3458)
* feat: only check 30 days data

* refactor: refactor GetDashboard to reduce code line

* refactor: refactor GetDashboard to reduce code line

* refactor: remove unused where

* fix: fix error code
2024-12-29 16:15:52 +08:00
0636069584 feat: only fetch created_time field to reduce data size in get-dashboard API (#3457) 2024-12-28 23:52:19 +08:00
4d0f73c84e feat: fix Casdoor OAuth provider doesn't use domain field bug 2024-12-28 10:01:56 +08:00
74a2478e10 feat: Make MinIO storage provider region setting configurable (#3433)
* fix: Make MinIO provider region setting configurable

* Fix: Correct the issue where modifications to MinIO's default logic caused behavioral discrepancies
2024-12-23 16:07:14 +08:00
acc6f3e887 feat: escape the avatal URL in CAS response (#3434) 2024-12-20 17:11:58 +08:00
185ab9750a feat: fix VerificationRecord.IsUsed JSON Field Mapping 2024-12-18 13:56:54 +08:00
48adc050d6 feat: can pass empty user id on user update (#3443) 2024-12-18 07:56:44 +08:00
b0e318c9db feat: add localized tab titles for Basic and Advanced Editors (#3431)
* feat: add localized tab titles for Basic and Advanced Editors

* docs: update translations for model editor labels in multiple locales
2024-12-16 08:34:13 +08:00
f9a6efc00f feat: advanced model editor should support changing UI language (#3430) 2024-12-15 15:53:29 +08:00
bd4a6775dd feat: get github user email with user/emails api (#3428)
* feat: get user email use `user/emails` api

* feat: improve code format

* feat: improve code format
2024-12-15 10:28:18 +08:00
e3a43d0062 feat: improve the advanced editor of model edit page (#3427) 2024-12-15 02:07:02 +08:00
0cf281cac0 feat: fix record's password regex bug (#3421) 2024-12-11 08:43:03 +08:00
7322f67ae0 feat: add model, adapter and enforcer to the dashboard page chart (#3413)
* [feature] Add more data (Model, Adapter, Enforcer) to the dashboard page chart #3379

* feat: add model, adapter, enforcer to dashboard
2024-12-09 16:07:39 +08:00
b927c6d7b4 feat: support LDAP's SetPassword (#3395)
* fix: Resolve the issue mentioned in #3392

* fix: Change checkLdapUserPassword to CheckLdapUserPassword.

* fix: the issue mentioned by hsluoyz.

* fix: Check if the user parameter is nil

* fix: use existing i18n message
2024-12-09 16:06:24 +08:00
01212cd1f3 feat: add AiAssistantUrl to frontend config (#3385) 2024-12-08 20:44:28 +08:00
bf55f94d41 feat: support CUCloud OSS storage provider (#3400) 2024-12-08 20:24:38 +08:00
f14711d315 feat: fix frontend bug 2024-12-07 21:53:01 +08:00
58e1c28f7c feat: support LDAPS protocol (#3390)
* feat: support ldaps

* fix: unencrypted port 389 not work after enable SSL
fix: remove useless conf and set ldapsCertId to empty
fix: return and log getTLSconfig error

* fix: remove unused setting

* fix: check nil condition

* fix: not log fail when certId is empty
2024-12-07 21:26:07 +08:00
922b19c64b feat: reduce i18n items 2024-12-07 21:22:57 +08:00
1d21c3fa90 feat: fix issue that introspectionResponse uses Bearer instead of raw tokenType (#3399) 2024-12-05 20:59:30 +08:00
6175fd6764 feat: make token_type_hint optional (#3397) 2024-12-04 20:10:15 +08:00
2ceb54f058 feat: support most popular currencies (#3388) 2024-12-01 21:46:44 +08:00
aaeaa7fefa feat: update go sms sender (#3386) 2024-11-29 23:00:34 +08:00
d522247552 feat: fix countryCode param bug in MFA login (#3384) 2024-11-29 21:46:06 +08:00
79dbdab6c9 feat: fix "dest is missing" bug in MFA login (#3383)
* feat: support stateless mfa setup

* Revert "feat: support stateless mfa setup"

This reverts commit bd843b2ff3.

* feat: use new implement

* fix: missing set field on login
2024-11-29 19:59:30 +08:00
fe40910e3b feat: support stateless MFA setup (#3382) 2024-11-29 19:50:10 +08:00
2d1736f13a feat: Add more data to the dashboard page chart #3365 (#3375)
* test

* feat: #3365 add more dada to the dashboard page chart

* feat: #3365 Add more data to the dashboard page chart
2024-11-26 09:16:35 +08:00
12b4d1c7cd feat: change LDAP attribute from cn to title for correct username mapping (#3378) 2024-11-26 09:13:05 +08:00
a45d2b87c1 feat: Add translations for Persian (#3372) 2024-11-23 16:24:07 +08:00
8484465d09 feat: fix SAML failed to redirect issue when login api returns RequiredMfa (#3364) 2024-11-21 20:31:56 +08:00
dff65eee20 feat: Force users to change their passwords after 3/6/12 months (#3352)
* feat: Force users to change their passwords after 3/6/12 months

* feat: Check if the password has expired by using the last_change_password_time field added to the user table

* feat: Use the created_time field of the user table to aid password expiration checking

* feat: Rename variable
2024-11-19 21:06:52 +08:00
596016456c feat: update CI's upload-artifact and download-artifact actions to v4 (#3361)
v3 of `actions/upload-artifact` and `actions/download-artifact` will be
fully deprecated by 5 December 2024. Jobs that are scheduled to run
during the brownout periods will also fail. See [1][2].

[1]: https://github.blog/changelog/2024-04-16-deprecation-notice-v3-of-the-artifact-actions/
[2]: https://github.blog/changelog/2024-11-05-notice-of-breaking-changes-for-github-actions/

Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
2024-11-19 00:07:59 +08:00
673261c258 feat: fix placeholder bug in signin page (#3359) 2024-11-17 00:14:26 +08:00
3c5985a3c0 fix: fix several bugs in samlRequest (#3358) 2024-11-17 00:14:04 +08:00
4f3d62520a feat: fix the dashboard page shows zero data in mobile phone (#3356) 2024-11-16 22:02:49 +08:00
96f8b3d937 feat: fix SAML metadata URL and XML generation issue when enablePostBinding is enabled (#3354) 2024-11-16 15:35:30 +08:00
7ab5a5ade1 feat: add processArgsToTempFiles() to RunCasbinCommand() 2024-11-15 20:25:48 +08:00
5cbd0a96ca Use json format for argString in RunCasbinCommand() 2024-11-15 18:27:25 +08:00
7ccd8c4d4f feat: add RunCasbinCommand() API 2024-11-15 17:44:57 +08:00
b0fa3fc484 feat: add Casbin CLI API to Casdoor (#3351) 2024-11-15 16:10:22 +08:00
af01c4226a feat: add Organization.PasswordExpireDays field 2024-11-15 11:33:28 +08:00
7a3d85a29a feat: update github token to fix CI cannot release issue (#3348) 2024-11-14 18:05:56 +08:00
fd5ccd8d41 feat: support copying token to clipboard for casdoor-app (#3345)
* feat: support copy token to clipboard for casdoor-app auth

* feat: abstract casdoor-app related code
2024-11-13 17:06:09 +08:00
a439c5195d feat: get token only by hash now, remove get-by-value backward-compatible code 2024-11-13 17:04:27 +08:00
ba2e997d54 feat: fix CheckUpdateUser() logic to fix add-user error 2024-11-06 08:34:13 +08:00
0818de85d1 feat: fix username checks when organization.UseEmailAsUsername is enabled (#3329)
* feat: Username support email format

* feat: Only fulfill the first requirement

* fix: Improve code robustness
2024-11-05 20:38:47 +08:00
457c6098a4 feat: fix MFA empty CountryCode bug and show MFA error better in frontend 2024-11-04 16:17:24 +08:00
60f979fbb5 feat: fix MfaSetupPage empty bug when user's signup application is empty 2024-11-04 00:04:47 +08:00
ff53e44fa6 feat: use virtual select UI in role edit page (#3322) 2024-11-03 20:05:34 +08:00
1832de47db feat: fix bug in CheckEntryIp() 2024-11-03 20:00:52 +08:00
535eb0c465 fix: fix IP Whitelist field bug in application edit page 2024-11-03 19:55:59 +08:00
c190634cf3 feat: show Domain field for Qiniu storage provider (#3318)
allow Qiniu Provider to edit the Domain property in the edit page.
2024-10-27 14:10:58 +08:00
f7559aa040 feat: set created time if not presented in AddUser() API (#3315) 2024-10-24 23:06:05 +08:00
1e0b709c73 feat: pass signin method to CAS login to fix bug (#3313) 2024-10-24 14:56:12 +08:00
c0800b7fb3 feat: add util.IsValidOrigin() to improve CORS filter (#3301)
* fix: CORS check issue

* fix: promote format

* fix: promote format

* fix: promote format

* fix: promote format

* Update application.go

* Update cors_filter.go

* Update validation.go

---------

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2024-10-20 20:09:21 +08:00
6fcdad2100 feat: fix bug that fails to login when PasswordObfuscator is enabled (#3299) 2024-10-19 23:09:59 +08:00
69d26d5c21 feat: add-user/update-user API should check if username/id/email/phone has duplicated with existing user (#3295) 2024-10-18 22:18:37 +08:00
94e6b5ecb8 feat: fix bug in SetPassword() API (#3296) 2024-10-18 20:50:43 +08:00
95e8bdcd36 feat: add initDataNewOnly to app.conf to skip overriding existing data in initDataFromFile() (#3294)
* feat: support control whether overwrite existing data during initDataFromFile

* feat: change conf var name

* feat: change conf var name
2024-10-18 00:08:08 +08:00
6f1f93725e feat: fix GetAllActions()'s bug (#3289) 2024-10-16 21:55:06 +08:00
7ae067e369 feat: only admin can specify user in BuyProduct() (#3287)
* fix: balance can be used without login

* fix: balance can be used without login

* fix: fix bug

* fix: fix bug
2024-10-16 00:02:04 +08:00
dde936e935 feat: fix null application crash in CheckEntryIp() 2024-10-15 22:11:15 +08:00
fb561a98c8 feat: fix null user crash in RefreshToken() 2024-10-15 21:38:33 +08:00
7cd8f030ee feat: support IP limitation for user entry pages (#3267)
* feat: support IP limitation for user entry pages

* fix: error message, ip whiteList, check_entry_ip

* fix: perform checks on the backend

* fix: change the implementation of checking IpWhitelist

* fix: add entryIpCheck in SetPassword and remove it from VerifyCode

* fix: remove additional error message pop-ups

* fix: add isRestricted and show ip error in EntryPage.js

* fix: error message

* Update auth.go

* Update check_ip.go

* Update check_ip.go

* fix: update return value of the check function from string to error

* fix: remoteAddress position

* fix: IP whitelist

* fix: clientIp

* fix:add util.GetClientIpFromRequest

* fix: remove duplicate IP and port separation codes and remove extra special characters after clientIp

* fix: gofumpt

* fix: getIpInfo and localhost

---------

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2024-10-15 20:40:14 +08:00
a3f8ded10c feat: refactor util.GetClientIpFromRequest() 2024-10-15 12:22:38 +08:00
e3d135bc6e feat: improve MFA desc text (#3284)
* fix: fix i18n error for mfa

* fix: fix i18n error for mfa

* fix: promote translate
2024-10-14 18:31:48 +08:00
fc864b0de4 feat: support ".login-panel-dark" CSS for signup/login pages (#3269)
* feat: add custom dark mode CSS for login and registration forms.

* refactor: extract dark theme check to Setting.js
2024-10-13 22:31:54 +08:00
3211bcc777 feat: add getCaptchaRule() to fix bug (#3281)
* feat: update captcha rule when the login page component is mounted

* fix: remove enableCaptchaModel from the state of the login page to avoid inconsistency issues

* fix: use this.getApplicationObj() instead of this.props.application
2024-10-12 10:02:45 +08:00
9f4430ed04 feat: fix MFA's i18n error (#3273) 2024-10-08 21:58:06 +08:00
05830b9ff6 feat: update import lib: github.com/casdoor/ldapserver 2024-10-08 19:18:56 +08:00
347b25676f feat: dark mode now works for login/signup pages too (#3252)
* fix: trying to fix dark mode not applying on login/registration interface

* fix: trying to fix dark mode not applying on login/registration interface

* fix: trying to fix dark mode not applying on login/registration interface

* fix: Clean up unused code

* fix: loginBackgroundDark move to App.less

* fix: fix typo
2024-10-05 21:26:25 +08:00
2417ff84e6 feat: support initial group assignment for new invited users via invitation.SignupGroup field (#3266) 2024-10-04 20:15:51 +08:00
468631e654 feat: support "All" in organization's country codes (#3264) 2024-10-03 22:58:09 +08:00
e1dea9f697 feat: add organization's PasswordObfuscator to obfuscate login API's password (#3260)
* feat: add PasswordObfuscator to the login API

* fix: change key error message

* fix: remove unnecessary change

* fix: fix one

* fix: fix two

* fix: fix three

* fix: fix five

* fix: disable organization update when key is invalid

* fix: fix six

* fix: use Form.Item to control key

* fix: update obfuscator.js

* Update obfuscator.go

* Update obfuscator.go

* Update auth.go

* fix: remove real-time key monitoring

---------

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2024-10-03 10:38:37 +08:00
c0f22bae43 feat: better handling of organization.AccountItems on init_data import (#3263)
* Better handling of accountitems on init_data import.

* Removed commented code.

* Update init_data.go

* Update init_data.go

---------

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2024-10-03 08:49:09 +08:00
c9635d9e2b feat: improve i18n (#3259) 2024-10-01 00:10:49 +08:00
3bd52172ea feat: add Hide-Password option for signin method rule field (#3258) 2024-09-30 23:31:41 +08:00
bf730050d5 feat: increase Organization.Favicon to 200 chars 2024-09-29 11:45:56 +08:00
5b733b7f15 feat: improve filterRecordIn24Hours() logic 2024-09-29 11:45:15 +08:00
034f28def9 feat: logout if app.conf's inactiveTimeoutMinutes is reached (#3244)
* feat: logout if there's no activities for a long time

* fix: change the implementation of updating LastTime

* fix: add logoutMinites to app.conf

* fix: change the implementation of judgment statement

* fix: use sync.Map to ensure thread safety

* fix: syntax standards and Apache headers

* fix: change the implementation of obtaining logoutMinutes in app.conf

* fix: follow community code standards

* fix: <=0 or empty means no restriction

* Update logout_filter.go

* Update app.conf

* Update main.go

* Update and rename logout_filter.go to timeout_filter.go

* Update app.conf

* Update timeout_filter.go

* fix: update app.conf

---------

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2024-09-27 01:18:02 +08:00
c86ac8e6ad feat: fix UTF-8 charset for Alipay IdP (#3247) 2024-09-27 00:59:52 +08:00
d647eed22a feat: add OIDC WebFinger support (#3245)
* feat: add WebFinger support

* lint: used gofumpt

* oidc: ensure webfinger rel is checked
2024-09-26 13:06:36 +08:00
717c53f6e5 feat: support enableErrorMask2 config 2024-09-25 19:37:14 +08:00
097adac871 feat: support single-choice and multi-choices in signup page (#3234)
* feat: add custom signup field

* feat: support more field in signup page

* feat: support more field in signup page

* feat: support more field in signup page

* feat: Reduce code duplication in form item rendering

* feat: Simplify gender and info checks using includes

* feat: update translate

* Revert "feat: update translate"

This reverts commit 669334c716.

* feat: address feedback from hsluoyz
2024-09-25 12:48:37 +08:00
74543b9533 feat: improve QR code for casdoor-app (#3226)
* feat: simplify login url for casdoor-app

* feat: add token check

* fix: improve logic
2024-09-23 22:27:58 +08:00
110dc04179 feat: Revert "feat: fix permission problem in standard image" (#3231)
This reverts commit 6464bd10dc.
2024-09-23 22:19:27 +08:00
6464bd10dc feat: fix permission problem in standard image (#3228) 2024-09-23 18:40:39 +08:00
db878a890e feat: add type and options to signup items 2024-09-21 23:40:29 +08:00
12d6d8e6ce feat: fix cookie expire time too short bug 2024-09-21 22:45:13 +08:00
8ed6e4f934 feat: improve UI for "No account?" 2024-09-21 07:35:33 +08:00
ed9732caf9 feat: add condition for getWebBuildFolder function (#3219) 2024-09-20 23:59:13 +08:00
0de4e7da38 feat: fix organization pagination count error (#3215)
* fix(organization): ensure count includes shared organizations

Adjust the `GetOrganizationCount` function to account for shared organizations by adding
an additional parameter and modifying the count query accordingly. This change ensures that
the organization count correctly reflects shared organizations within the system.

* ```fix(organization): optimize GetOrganizationCount query

Refactor the GetOrganizationCount function to use a more efficient search
method by leveraging the 'is_shared' field directly in the query condition.
This change improves the performance for counting organizations by avoiding
unnecessary iteration over potentially large result sets.
```

---------

Co-authored-by: CuiJing <cuijing@tul.com.cn>
2024-09-20 23:58:46 +08:00
a330fbc11f docs: fix Docker link 2024-09-17 20:45:32 +08:00
ed158d4981 feat: support advanced editor in model edit page (#3176)
* feat: integrate external model editor and handle message events for model updates

* feat: add CasbinEditor and IframeEditor components for model editing

* feat: add tabbed editor interface for CasbinEditor

* fix: Synchronize content between basic and advanced editors

* refactor: simplify CasbinEditor and ModelEditPage components

* refactor: Refactor CasbinEditor for improved iframe initialization and model synchronization

* refactor: update default state of CasbinEditor active tab to "advanced

* chore: add Apache License header to CasbinEditor.js and IframeEditor.js files

* refactor: update CasbinEditor class names for consistency
2024-09-16 22:25:25 +08:00
8df965b98d feat: improve SAML XML's xmlns to fix SAML support for some clouds (#3207) 2024-09-16 08:01:28 +08:00
2c3749820e feat: add application.UseEmailAsSamlNameId field for SAML (#3203)
* feat: Add option to use email as SAML NameID based on application config

- Updated NewSamlResponse11 to accept an application parameter.
- Conditionally set SAML NameIdentifier to user's email or username based on application.UseEmailAsNameId.

* refactor: Update GetValidationBySaml to pass application to NewSamlResponse11

- Modified GetValidationBySaml function to include application parameter in NewSamlResponse11 call.

* feat: Rename field and update logic for using Email as SAML NameID

- Renamed the `UseEmailAsNameId` field to `UseEmailAsSamlNameId` in the `Application` struct.
- Updated `NewSamlResponse` and `NewSamlResponse11` functions to use `UseEmailAsSamlNameId` for setting the NameID value.
- Modified `ApplicationEditPage.js` to reflect the field name change and update the corresponding logic.
2024-09-15 23:00:50 +08:00
0b17cb9746 feat: make Organization.EnableSoftDeletion and User.IsDeleted work (#3205)
* feat: make Organization.EnableSoftDeletion and User.IsDeleted work

* fix: add handling of the situation where organization is nil
2024-09-15 14:35:44 +08:00
e2ce9ad625 feat: handle null account item issue in CheckPermissionForUpdateUser() (#3202)
* feat: improve the logic of the permission check code for users to modify account items

* fix: add skip operation for deleted account items in update-user API

* fix: add the function of removing deleted account item
2024-09-14 15:00:10 +08:00
64491abc64 feat: fix CORS issue of /api/acs for SAML IdP (#3200)
* fix: fix CORS problem of /api/acs when login with saml idp

* fix: fix origin get null when receive post with http protocol
2024-09-14 12:48:51 +08:00
934a8947c8 feat: fix CAS logout failure caused by Beego session update problem (#3194)
* feat: fix the cas logout failure caused by beego session update problem

* fix: simplify the implementation of logout timer

* fix: change the location of the login success code

* fix: add i18n to CasLogout.js
2024-09-10 21:31:37 +08:00
943edfb48b feat: support QR login for casdoor app (#3190)
* feat: add MFA devices QR code to UserEditPage

* chore: remove mfa devices
2024-09-08 22:38:13 +08:00
0d02b5e768 feat: remove disabled state in syncer.table 2024-09-07 21:08:21 +08:00
ba8d0b5f46 feat: Revert "feat: Users added through LDAP cannot log in using the set password" (#3186)
This reverts commit 973a1df6c2.
2024-09-07 20:55:14 +08:00
973a1df6c2 feat: Users added through LDAP cannot log in using the set password (#3175)
* fix: login will prioritize the use of password set in casdoor and use ldap when use LDAP option in login form or user never change their password in casdoor after sync

* fix: promote if statement
2024-09-06 10:31:34 +08:00
05bfd3a3a3 feat: fix bug that custom SAML providers are removed by GetMaskedApplication() (#3165) 2024-09-05 20:08:56 +08:00
69aa3c8a8b feat: Revert "feat: add Casbin editor's checking in model editor" (#3167)
This reverts commit a1b010a406.
2024-09-03 21:59:06 +08:00
a1b010a406 feat: add Casbin editor's checking in model editor (#3166)
* feat: add model syntax linting and update dependencies

* refactor: move model linter logic to separate module
2024-09-03 21:32:45 +08:00
89e92cbd47 feat: when using basic auth to fetch access_token will return restful response to oidc client (#3164) 2024-09-03 08:05:29 +08:00
d4c8193357 feat: support reCAPTCHA v3 captcha provider (#3160)
* feat: support reCAPTCHA v3 captcha provider

* fix: modify the implementation of row component style in CaptchaModal.js
2024-09-02 22:15:03 +08:00
9b33800b4c feat: add email_verified, phone_number and phone_number_verified field for standard jwt token (#3156)
* feat: add email_verified, phone_number and phone_number_verified field for standard jwt token

* fix: fix linter err
2024-08-31 12:49:39 +08:00
ec98785172 feat: certEditPage will be redirected to 404 when name is changed (#3154) 2024-08-30 23:04:50 +08:00
45dd4cc344 feat: fix nonce not parsed issue in fastAutoSignin() (#3153)
* fix: fix nonce none passed when auto sign enabled

* fix: fix query error
2024-08-30 22:29:23 +08:00
1adb172d6b feat: add more crypto algorithm for jwt signing (#3150)
* feat: add more algorithm support for JWT signing

* feat: add i18n support

* feat: add i18n support

* feat: optimize if statement

* fix: remove additional space line
2024-08-30 16:59:41 +08:00
c08f2b1f3f feat: support Casdoor storage provider (#3147)
* feat: support Casdoor storage provider

* fix: fix code format and nil pointer error

* feat: change cert if statement
2024-08-27 23:54:03 +08:00
62bb257c6d feat: make Resource.Url length to 500 2024-08-26 23:57:41 +08:00
230a77e3e3 feat: add captcha page (#3144) 2024-08-26 23:22:53 +08:00
dce0a96dea feat: improve uploaded file URL 2024-08-26 21:41:28 +08:00
65563fa0cd feat: Ensure MFA email and phone are validated before enabling (#3143)
Added validation checks to ensure that a user's email and phone number are provided before enabling MFA email and phone respectively. This fixes the issue where MFA could be enabled without these values, causing inconsistencies.
2024-08-26 08:40:22 +08:00
f2a94f671a feat: complete i18n translation (#3141)
* feat: complete i18n translation

* fix: fix problem in cs/data
2024-08-24 23:27:59 +08:00
1460a0498f feat: support assign a default group for synchronized from external openldap (#3140)
* feat: support default sync group for ldap (with without add i18n translate)

* feat: improve translation

* feat: update all i18n translation

* revert: remove new i18n translation
2024-08-24 00:12:52 +08:00
adc63ea726 feat: fix wrong error alert in ApiFilter's getObject() 2024-08-23 23:36:55 +08:00
0b8be016c5 feat: add enableErrorMask config 2024-08-23 22:19:17 +08:00
986dcbbda1 feat: handle error in ApiFilter 2024-08-23 21:50:48 +08:00
7d3920fb1f feat: add ManagedAccounts to JWT 2024-08-20 22:23:58 +08:00
b794ef87ee feat: Revert "feat: support reCAPTCHA v3 captcha provider" (#3135)
This reverts commit a0d6f2125e.
2024-08-20 17:56:53 +08:00
a0d6f2125e feat: support reCAPTCHA v3 captcha provider (#3130) 2024-08-20 17:29:37 +08:00
85cbb7d074 feat: add replaceAll polyfill to be compatible with Firefox 68 2024-08-17 18:37:21 +08:00
fdc1be9452 feat: add provider.Bucket to fileUrl response and TrimPrefix "/" before delete GCS object (#3129)
* feat: add provider.Bucket to fileUrl response

* feat: TrimPrefix "/" before Google Cloud Storage delete object
2024-08-17 11:46:58 +08:00
2bd7dabd33 feat: allow custom Domain of Google Cloud Storage Provider (#3128) 2024-08-15 23:28:36 +08:00
9b9a58e7ac feat: update casdoor/oss version to support Google Cloud's Application Default Credentials (#3125) 2024-08-15 13:45:27 +08:00
38e389e8c8 feat: Pagination not updating after last item deletion (#3120) 2024-08-13 16:09:16 +08:00
ab5fcf848e feat: support accessKey and accessSecret login in AutoSigninFilter (#3117) 2024-08-12 12:20:41 +08:00
b4e51b4631 feat: improve error message in GetFailedSigninConfigByUser() 2024-08-10 09:31:46 +08:00
45e25acc80 feat: fix JWT generate issue cause by shared application (#3113)
* fix: fix jwt generate cause by shared application

* fix: fix built-in org will not add -org-
2024-08-09 22:48:44 +08:00
97dcf24a91 feat: improve error message in GetAuthorizationCodeToken() 2024-08-09 21:06:23 +08:00
4c0fff66ff feat: support shared application across organizations (#3108)
* feat: support share application

* revert: revert i18n

* fix: improve code format

* fix: improve code format and move GetSharedOrgFromApp to string.go
2024-08-09 15:43:25 +08:00
e7230700e0 feat: Revert "feat: fix Beego session delete concurrent issue" (#3105)
This reverts commit f21aa9c0d2.
2024-08-07 16:51:54 +08:00
f21aa9c0d2 feat: fix Beego session delete concurrent issue (#3103) 2024-08-07 16:29:35 +08:00
4b2b875b2d feat: Czech, Slovak localization (#3095)
* feat: add l10n Czech, Slovak language support

* feat: i18n Czech, Slovak translation
2024-08-02 09:39:47 +08:00
df2a5681cc feat: add missing account items in CheckPermissionForUpdateUser() (#3094) 2024-08-01 23:34:12 +08:00
ac102480c7 feat: support Radius Challenge/Response for MFA (RFC2865) feature request (#3093)
* feat: support RFC2865 for radius server when user enable TOTP mfa

* fix: fix linter err
2024-08-01 22:02:49 +08:00
feff47d2dc feat: skip agreement check when the terms are not visible (#3088) 2024-07-30 14:04:03 +08:00
79b934d6c2 feat: enforce acceptance of terms and conditions for social logins (#3087)
* feat: Enforce acceptance of terms and conditions for social logins (#2975)

* feat: add error message for agreement acceptance
2024-07-29 17:22:48 +08:00
365449695b fix: fix application field in invitationEditPage will use translation of "All" as value (#3085) 2024-07-29 01:35:28 +08:00
55a52093e8 feat: fix bug that user can signup without invitation code via OAuth (#3084)
* fix:fix user can signup without invitation code when using 3rd oauth

* fix:use correct i18n translation
2024-07-29 00:59:02 +08:00
e65fdeb1e0 feat: ABAC support for /api/batch-enforce endpoint (#3082) 2024-07-27 09:43:58 +08:00
a46c1cc775 feat: update WeCom OAuth URLs (#3080) 2024-07-26 22:03:24 +08:00
5629343466 feat: fix missing extendApplicationWithSigninMethods() in getDefaultApplication() (#3076) 2024-07-24 22:30:15 +08:00
3718d2dc04 feat: improve name mapping in LarkIdProvider (#3075)
* fix: change user identifier to the `user_id` field in IdP Lark, and use Chinese name to be the display name

* Update lark.go

---------

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2024-07-23 21:12:53 +08:00
38b9ad1d9f feat: Add Support for memberOf Overlay in LDAP Server (#3068)
* feat: Allow All Users to Perform LDAP Search Lookups in their org

* feat: add ldap member of support
2024-07-21 01:25:42 +08:00
5a92411006 feat: add MFA accounts table (#3066)
* feat: add mfa accounts store

* fix: change MFA to Mfa

* fix: change MFA to Mfa

* fix: delete api
2024-07-20 22:51:15 +08:00
52eaf6c822 feat: Allow All Users to Perform LDAP Search Lookups in their org (#3064) 2024-07-20 20:44:29 +08:00
cc84709151 feat: add webhook support for invoice-payment and notify-payment (#3062) 2024-07-20 12:49:34 +08:00
22fca78be9 feat: fix bug in AdapterEditPage 2024-07-19 00:57:56 +08:00
DSP
effd257040 feat: fix isPasswordWithLdapEnabled logic in handleBind() for redirecting to other LDAP sources (#3059)
* Added parameters to function call in server.go

Added needed parameters for redirection to other LDAP sources to function correctly and not always run into the "wrong credentials" error

* Update server.go

---------

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2024-07-18 21:04:17 +08:00
a38747d90e feat: fix bug in GetPolicies() 2024-07-18 18:40:55 +08:00
da70682cd1 feat: fix bug in obtaining Casdoor version in Docker (#3056) 2024-07-16 18:13:44 +08:00
4a3bd84f84 feat: fix the problem of abnormal tour when refreshing (#3054)
* fix: fix the problem of abnormal tour when refreshing

* fix: change the way enableTour configuration is stored
2024-07-12 19:27:55 +08:00
7f2869cecb feat: link transaction with balance and payment (#3052)
* feat: add and update transaction when recharging

* feat: add pay with balance

* feat: improve code format

* feat: update icon url for balance
2024-07-12 15:48:37 +08:00
cef2ab213b feat: add JWT-Standard format to fix oidc address type problem (#3050)
* feat: add JWT-Standard option to return standard OIDC UserInfo

* fix: fix error occurs by different claim type

* feat: improve code format and add missing return
2024-07-12 09:36:50 +08:00
cc979c310e feat: OAuth provider lark supports getting phone number (#3047) 2024-07-11 08:56:28 +08:00
13d73732ce fix: improve initBuiltInOrganization() 2024-07-10 14:18:30 +08:00
5686fe5d22 feat: use orgnization logo as tour logo and allow to configure whether to enable tour in organization edit page (#3046) 2024-07-10 14:18:04 +08:00
d8cb82f67a feat: upgrade CI Node.js version to 20 2024-07-09 13:09:40 +08:00
cad2e1bcc3 feat: don't drop empty table for adapters (#3043)
* fix: solve the problem of update operation returning 'unaffected'

* feat: remove the action for Dropping empty adapter data table
2024-07-09 11:35:22 +08:00
52cc2e4fa7 feat: fix bug in permission's owner edit (#3041) 2024-07-06 11:24:08 +08:00
8077a2ccba feat: fix bug for access key and secret login (#3022)
* fix: get username for keys

* chore: move user nil check
2024-06-27 21:24:54 +08:00
4cb8e4a514 feat: Revert "feat: fix OIDC address field" (#3020)
This reverts commit 2f48d45773.
2024-06-25 16:14:26 +08:00
2f48d45773 feat: fix OIDC address field (#3013)
* feat:add fields of sync-database

* feat:add fields of sync-database

* feat: add several fields related to the OIDC specification address

* feat: add the field Address to Address structure in UserWithoutThirdIdp

* fix: delete redundant fields

* fix: add Address struct and delete redundant fields
2024-06-25 11:54:34 +08:00
cff0c7a273 feat: support "Use Email as username" in org (#3002)
Signed-off-by: Grégoire Bélorgey <gregoire@jianda.fr>
2024-06-22 16:52:11 +08:00
793a7d6cda feat: add free charge price mode for product buy page (#3015)
* feat: add free charge price mode for product buy page

* fix: improve code format
2024-06-22 14:05:53 +08:00
4cc2120fed feat: fix the top Navbar UI is broken issue (#3000) 2024-06-09 17:05:04 +08:00
93b0f52f26 feat: Revert "feat: fix cannot create "/files" folder issue in local file storage provider in Docker" (#2997)
This reverts commit e228045e37.
2024-06-06 11:09:02 +08:00
e228045e37 feat: fix cannot create "/files" folder issue in local file storage provider in Docker (#2994) 2024-06-06 10:49:56 +08:00
6b8c24e1f0 feat: fix password not encrypted issue in SetPassword() API (#2990)
* fix: fix password not encrypted in set password and password type not changed

* Update user.go

---------

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2024-06-04 13:32:13 +08:00
8a79bb64dd feat: test SMTP connection with browser parameters (#2986) 2024-06-04 01:34:36 +08:00
e5f9aab28f feat: support resetting password on first login (#2980)
* feat: support reset password in first login

* feat: disable needUpdatePassword when user haven't email and phone and mfa
2024-06-02 01:00:55 +08:00
7d05b69aac feat: remove useless code 2024-05-28 20:33:55 +08:00
868e66e866 feat: fix QQ login error when using mobile browser (#2971) 2024-05-27 01:07:15 +08:00
40ad3c9234 feat: support MFA fields in syncer (#2966)
* feat:add fields of sync-database

* feat:add fields of sync-database
2024-05-27 01:06:59 +08:00
e2cd0604c2 feat: add back arm64 support in Docker image (#2969) 2024-05-26 01:22:49 +08:00
78c3065fbb feat: fix address field bug in user edit page 2024-05-24 17:19:27 +08:00
af2a9f0374 feat: get phone number and country from Google OAuth provider (#2965)
* feat: get phone number and country from Google OAuth provider

* feat: fix i18n
2024-05-23 00:42:36 +08:00
bfcfb56336 feat: add address line 1 and 2 in web UI (#2961) 2024-05-19 23:55:38 +08:00
c48306d117 feat: check signup item email regex in signup page (#2960)
* feat: check email regex in frontend

* Update SignupPage.js

---------

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2024-05-19 22:07:34 +08:00
6efec6b4b5 feat: support "label" field for signin item table (#2956) 2024-05-19 03:07:36 +08:00
2daf26aa88 feat: use lowercase username when isUsernameLowered is enabled (#2952)
* feat: auto trim username during login and lowercase when isUsernameLowered enabled in conf

* fix: fix linter error

* fix: fix linter error

* fix: fix linter error
2024-05-17 11:43:19 +08:00
21c151bcf8 feat: fix password not updated bug when updating syncer (#2945) 2024-05-13 00:12:35 +08:00
b6b0b7d318 feat: support checking whether send-webhook API has error (#2944)
* feat: add webhook response for record

* refactor: refactor SendWebhook and use readall to read response body

* fix: improve code format

* fix: improve code format

* fix: improve code format
2024-05-12 20:30:15 +08:00
0ecc1d599f feat: fix bug in AddUsersInBatch() 2024-05-11 16:59:33 +08:00
3456fc6695 fix: update go-sms-sender to v0.23.0 2024-05-10 14:05:53 +08:00
c302dc7b8e fix: fix bug when init plan and pricing and record (#2934)
* fix: fix potential bugs in init data

* fix: improve code format

* fix: fix bug when init plan and pricing and record
2024-05-07 23:33:01 +08:00
d24ddd4f1c feat: fix potential bugs in init_data.go (#2932)
* fix: fix potential bugs in init data

* fix: improve code format
2024-05-07 23:11:08 +08:00
572616d390 fix: fix bug in ProviderItem.CountryCodes 2024-05-07 17:17:45 +08:00
2187310dbc feat: fix bug in initDefinedOrganization() 2024-05-06 13:57:08 +08:00
26345bb21b feat: add sms provider sendcloud (#2927) 2024-05-06 13:38:55 +08:00
e0455df504 feat: improve record content masking (#2923)
* feat: hide password in record

* feat: improve code format

* feat: improve code format
2024-05-05 12:42:09 +08:00
1dfbbf0e90 feat: fix bug that fails to import built-in org via init_data.json (#2922) 2024-05-05 01:06:15 +08:00
d43d58dee2 feat: fix getProviders() owner bug in product edit page 2024-05-01 18:04:50 +08:00
9eb4b12041 fix: rename to countryCodes for UI 2024-05-01 11:44:21 +08:00
3a45a4ee77 fix: rename to countryCodes 2024-05-01 09:47:44 +08:00
43393f034b feat: fix the Email provider fails to match bug in GetProviderByCategoryAndRule() 2024-05-01 09:44:19 +08:00
bafa80513b fix: improve ProviderTable column UI 2024-05-01 00:46:48 +08:00
8d08140421 fix: fix typo in initBuiltInPermission() 2024-05-01 00:41:16 +08:00
3d29e27d54 feat: support multiple SMS providers for different regions (#2914)
* feat: support using different sms provider for different region

* feat: add multiple support for select and remove log

* feat: revert change for countryCode in loginPage

* feat: revert change for countryCode in user_util.go

* feat: revert change for countryCode in auth.go

* Update application_item.go

* Update CountryCodeSelect.js

* Update ProviderTable.js

---------

Co-authored-by: Yang Luo <hsluoyz@qq.com>
2024-05-01 00:40:47 +08:00
199f1d4d10 feat: fix Auto-login causing AuthCodeWithPKCE Failures (#2911) 2024-04-30 12:14:50 +08:00
227e938db6 feat: fix error behavior of custom oauth/saml provider in login page in big icon mode (#2900) 2024-04-26 23:33:41 +08:00
739cfd84ed feat: cannot empty SigninMethodTable now 2024-04-26 21:23:23 +08:00
8dbb041a34 feat: fix empty custom CSS for new rows in signin items table (#2897) 2024-04-24 15:19:30 +08:00
af2d26daf2 Add object.IsAppUser() 2024-04-24 01:10:38 +08:00
90d502ab2b feat: add custom css style for signup page and enhance css edit (#2880)
* feat: add custom css style for signup page and enhance css edit in signintable

* feat: change cssStyle to customCss

* feat: auto hide <style> label, fix display problem on providers, remove auto add providers in signup page

* fix: fix indent in signin items customCss and fix providers display in signup items

* fix: fix login replace logical
2024-04-21 11:56:18 +08:00
d51af3378e fix: fix init data not saved to database (#2885) (#2886) 2024-04-21 11:55:06 +08:00
87e2b97813 feat: translate Ukrainian language i18n 2024-04-20 02:14:23 +08:00
d9e44c1f2d fix: add "Is used" to verification list page 2024-04-20 00:18:52 +08:00
dfa4503f24 feat: support "mfa_phone_enabled", "mfa_email_enabled" in update-user API 2024-04-20 00:16:45 +08:00
f7fb32893b fix: close file in LocalFileSystemProvider's Put() (#2882) 2024-04-20 00:11:52 +08:00
66d0758b13 feat: fix DisableVerificationCode bug about empty email and phone 2024-04-19 13:28:13 +08:00
46ad0fe0be Improve Email Send() logic 2024-04-11 19:09:48 +08:00
6b637e3b2e feat: fix SendgridEmailProvider error handling, fix send-email template 2024-04-11 00:18:39 +08:00
3354945119 feat: add SendGrid Email provider (#2865)
* feat: add support for email provider send grid

* feat: rename send grid to sendgrid

* feat: rename send grid to sendgrid

* feat: change logo url of send grid
2024-04-09 22:16:01 +08:00
19c4416f10 feat: degrade the ant-design/cssinjs version to fix the Chrome 87 broken UI issue (#2861) 2024-04-09 09:15:39 +08:00
2077db9091 fix: fix bug in VerificationListPage 2024-04-07 15:39:25 +08:00
800f0ed249 feat: add tzdata package in Dockerfile to fix timezone issue (#2857)
Add tzdata to resolve possible time zone errors
2024-04-07 14:27:45 +08:00
xyt
6161040c67 fix: Dismiss google one tap after logged in by setting disableCancelOnUnmount to false (#2854)
* fix: Google One Tap should be hidden after logged in

* Change the call location for google.accounts.id.cancel()

* fix: hide google one tap after login by set disableCancelOnUnmount to false
2024-04-05 23:39:33 +08:00
xyt
1d785e61c6 feat: Google One Tap should be hidden after logged in (#2853)
* fix: Google One Tap should be hidden after logged in

* Change the call location for google.accounts.id.cancel()
2024-04-05 20:10:13 +08:00
0329d24867 feat: add isUsernameLowered to config 2024-04-02 21:54:16 +08:00
fb6f3623ee feat: add requireProviderPermission() 2024-03-30 23:24:59 +08:00
eb448bd043 fix: fix permission problem in provider (#2848) 2024-03-30 23:18:03 +08:00
xyt
ea88839db9 feat: add back button in forget password page (#2847)
* feat: add back button in forget password page

* fix: can't step back when directly entering forgot password page

* feat: forget password page always return to login page

* feat: if has history then go back to history & change style

* Update ForgetPage.js

* fix: reset button position

* Update ForgetPage.js

* Update ForgetPage.js

---------

Co-authored-by: Eric Luo <hsluoyz@qq.com>
2024-03-30 23:17:47 +08:00
cb95f6977a fix: fix PasswordModal error when changing username 2024-03-30 12:28:55 +08:00
9067df92a7 feat: revert "feat: Support metamask mobile login" (#2845)
This reverts commit bfa2ab63ad.
2024-03-30 00:36:25 +08:00
bfa2ab63ad feat: Support metamask mobile login (#2844) 2024-03-30 00:08:52 +08:00
505054b0eb feat: use minWidth for a better display effect in org select (#2843) 2024-03-29 15:47:27 +08:00
f95ce13b82 fix: support "Email or Phone" in signup table 2024-03-29 09:07:37 +08:00
xyt
5315f16a48 feat: can specify UI theme via /?theme=default and /?theme=dark (#2842)
* feat: set themeType through URL parameter

* Update App.js

---------

Co-authored-by: Eric Luo <hsluoyz@qq.com>
2024-03-29 00:52:18 +08:00
d054f3e001 feat: The /login/oauth/access_token api supports the token and id_token grant types. (#2836)
* In the response of the /api/get-captcha endpoint, add the parameters "owner" and "name" because these two parameters will be used when calling the /api/verify-captcha endpoint.

* The /login/oauth/access_token api supports the token and id_token grant types.
2024-03-28 00:41:54 +08:00
b158b840bd Add "new-user" to webhook event list 2024-03-27 15:23:06 +08:00
b16f1807b3 fix: fix bug in "new-user" record 2024-03-27 15:15:40 +08:00
d0cce1bf7a Order by "id" in GetPaginationRecords() 2024-03-27 15:14:41 +08:00
9892cd20ab Improve erorr message in CheckVerificationCode() 2024-03-27 15:14:20 +08:00
d1f31dd327 feat: fix linter 2024-03-26 23:24:53 +08:00
94743246a1 Improve "%{user.friendlyName}" handling 2024-03-25 21:26:36 +08:00
39ad1bc593 Add signup's object in AfterRecordMessage() 2024-03-25 21:20:33 +08:00
d97f833d2a feat: Add 'owner' and 'name' Parameters to /api/get-captcha Response for /api/verify-captcha Usage (#2834) 2024-03-25 16:34:42 +08:00
948fa911e2 feat: add users to getGroups() and getGroup() APIs 2024-03-22 23:32:30 +08:00
6073a0f63d Rename GroupListPage and GroupEditPage 2024-03-22 23:14:05 +08:00
91268bca70 Improve enableAutoSignin option UI 2024-03-22 22:55:10 +08:00
23dbb0b926 feat: add response to Records page (#2830)
* feat: add response to Records page

* feat: improve AddRecord

* feat: remove log and return err

* feat: improve record in signup and record deny

* fix: filter will generate 403 record correctly
2024-03-22 14:53:38 +08:00
97cc1f9e2b fix: delete duplicate err check in utils/validation.go (#2831) 2024-03-21 18:17:38 +08:00
8c415be7c7 feat: upgrade goth to v1.79.0 2024-03-20 19:57:15 +08:00
e87165cfc8 Upgrade go.mod versions 2024-03-20 19:51:56 +08:00
fc4fa2e8b6 feat: add verification list page and related API (#2822)
* feat: add verification list page and relevant api

* feat: improve code format

* fix: fix timestamp display error
2024-03-19 19:10:52 +08:00
44ae76503e feat: add default user mapping in custom oauth2 provider (#2819) 2024-03-18 23:01:17 +08:00
ae1634a4d5 feat: fix user cannot logout issue about bug in GetSessionToken() 2024-03-18 02:11:39 +08:00
bdf9864f69 fix: add FaceIdSigninBegin() to verify user information before face login (#2815)
* feat: add FaceIdSigninBegin() to verify user information before face login

* Update face.go

---------

Co-authored-by: Eric Luo <hsluoyz@qq.com>
2024-03-18 00:04:12 +08:00
72839d6bf5 feat: fix TokenFormat error in get-account API 2024-03-17 23:03:50 +08:00
2c4b1093ed fix: Correct expiresIn calculation for WeChat Mini Program token. (#2814) 2024-03-17 22:20:21 +08:00
d1c55d5aa7 fix: improve error message in token_cas.go 2024-03-17 22:01:49 +08:00
c8aa35c9c6 feat: add token to the page for Chrome extension (#2804)
* feat: add token to the page for Chrome extension

* Update token_oauth.go

---------

Co-authored-by: Eric Luo <hsluoyz@qq.com>
2024-03-17 22:01:28 +08:00
6037f37b87 feat: add default token format for built-in app 2024-03-17 20:46:01 +08:00
1b478903d8 feat: fix login page error cannot show bug 2024-03-17 11:39:12 +08:00
4f5ac7a10b Fix Face IDs label 2024-03-17 09:56:24 +08:00
e81ba62234 Improve Face ID signin method UI 2024-03-17 09:56:23 +08:00
Ron
a19060c7cb fix: missing parameter type_token_hint in IntrospectToken() (#2812)
* fix: missing parameter type_token_hint in IntrospectToken(); fix key token type
2024-03-17 01:39:04 +08:00
96812f676b fix: "fs" module not found issue in face-api.js for browser usage (#2810) 2024-03-17 01:35:43 +08:00
04f0458b5c feat: improve handleCameraError() and camera call logic (#2809)
add i18n for face recognition
2024-03-16 22:52:57 +08:00
fd0bcd9a17 Improve getObject() for "/api/get-policies" 2024-03-16 21:42:00 +08:00
01a5958307 Improve error text in RequireAdmin() 2024-03-16 21:14:19 +08:00
be88b00278 feat: improve RequireAdmin() logic 2024-03-16 20:49:17 +08:00
1bd0245e7a Improve CheckVerificationCode() error message, add receiver to index 2024-03-16 18:16:29 +08:00
cc84bd37cf Add object field in RecordListPage 2024-03-16 16:57:04 +08:00
8302fcf805 Improve handleCameraError() 2024-03-16 09:55:55 +08:00
391a533ce1 feat: add "Face ID" login method (#2782)
Face Login via face-api.js
2024-03-16 09:04:00 +08:00
57431a59ad fix: Ensure /api/get-app-login Returns Captcha Provider for Applications Configured with Captcha (#2800)
In LoginPage.js, the line 92:const captchaProviderItems = this.getCaptchaProviderItems(this.props.application); 

captchaProviderItems have no Captcha Provider.
2024-03-15 19:56:12 +08:00
88a4736520 feat: fix GetDashboard() page 2024-03-15 19:52:19 +08:00
2cb6ff69ae fix: show selected organizations' statistics in dashboard page (#2805)
* fix: show selected organizations' statistics in dashboard page

* Update get-dashboard.go

* Update saml_idp.go

---------

Co-authored-by: Eric Luo <hsluoyz@qq.com>
2024-03-15 19:36:39 +08:00
e1e5943a3e fix: fix the issue of adding xmlns="" when generating XML (#2799)
* fix:solve the problem of adding xmlns="" when generating XML

* fix:remove fmt.Println

* Update saml_idp.go

---------

Co-authored-by: zhaoxianfei <zhaoxianfei@meiqia.cn>
Co-authored-by: Eric Luo <hsluoyz@qq.com>
2024-03-13 23:59:05 +08:00
3875896c1e feat: support custom header logo (#2801)
* feat: support custom header logo

* feat: add i18n

* feat: preview default logo when field is empty

* feat: improve logo setting and display logic

* feat: change logoLight to logo
2024-03-13 23:33:43 +08:00
7e2f265420 feat: improve organization select UI (#2798) 2024-03-12 19:39:53 +08:00
53ef179e9b Set Webhook.Url length to 200 2024-03-11 18:18:01 +08:00
376ef0ed14 feat: support custom Email content in /send-email API 2024-03-11 11:48:00 +08:00
ca183be336 Improve ManagedAccountTable UI 2024-03-11 00:13:34 +08:00
e5da57a005 feat: fix cert's ES options 2024-03-10 19:30:05 +08:00
e4e225db32 Use "ES512" value 2024-03-10 19:25:41 +08:00
a1add992ee Support legacy "RSA" value 2024-03-10 19:23:54 +08:00
2aac265ed4 Improve populateContent() 2024-03-10 18:58:53 +08:00
2dc755f529 fix: add more cert algorithms like ES256 and PS256 (#2793) 2024-03-10 18:39:41 +08:00
0dd474d5fc feat: fix public profile page shows blank page bug 2024-03-10 14:12:24 +08:00
6998451e97 fix: support roles and permissions in /userinfo API 2024-03-10 12:34:56 +08:00
9175e5b664 Fix bug in GetMaskedEmail() 2024-03-10 11:49:55 +08:00
dbc6b0dc45 feat: fix issue that forget password page fails to redirect back to signin page (#2792) 2024-03-10 09:55:44 +08:00
31b7000f6a fix: enable the only language for login page 2024-03-09 11:28:23 +08:00
d25eaa65cd feat: support custom page footer (#2790) 2024-03-08 23:11:03 +08:00
f5bcd00652 Add language to records page 2024-03-08 23:03:30 +08:00
0d5f49e40a fix: fix GetResources() bug for app users 2024-03-08 16:15:31 +08:00
3527e070a0 Fix my account page UI 2024-03-08 15:18:18 +08:00
0108b58db4 Return status 200 for unauthorized operation, revert commit: 2fd2d88d20 2024-03-08 15:11:25 +08:00
976b5766a5 feat: refactor out token_oauth.go 2024-03-08 15:03:28 +08:00
a92d20162a feat: show all resources for org admin 2024-03-08 15:03:03 +08:00
204b1c2b8c Fix resource page link error 2024-03-08 14:44:39 +08:00
49fb269170 Improve error handling for GetSamlResponse() 2024-03-08 02:17:50 +08:00
c532a5d54d Remove suspense fallback loading. 2024-03-07 23:21:25 +08:00
89df80baca feat: remove loading fallback in Suspense and use spin to display (#2780) 2024-03-06 20:30:54 +08:00
d988ac814c fix: fix account items display error (#2781) 2024-03-06 20:30:34 +08:00
e4b25055d5 Improve isAllowedInDemoMode() 2024-03-06 02:17:28 +08:00
4123d47174 feat: callback will jump to blank page when from param start with "http" (#2778) 2024-03-06 01:07:52 +08:00
fbdd5a926d Fix normal user my-account page blank bug 2024-03-06 01:07:28 +08:00
92b6fda0f6 feat: support more objects in init_data JSON (#2776) 2024-03-05 23:41:46 +08:00
6a7ac35e65 fix: fix wechat media account can not bind issue (#2774)
* fix: fix wechat media account can not bind

* fix: improve code format
2024-03-05 18:46:28 +08:00
fc137b9f76 feat: fix custom JS doesn't reload after refresh bug (#2773) 2024-03-05 15:03:25 +08:00
11dbd5ba9a fix: fix duplicated load bug of custom JS (#2771) 2024-03-05 00:09:37 +08:00
19942a8bd4 Add webhook.SingleOrgOnly 2024-03-04 21:14:52 +08:00
f9ee8a68cb Support Chrome extension redirecting 2024-03-04 18:31:56 +08:00
Ron
f241336ad7 feat: add OSON SMS provider (#2769)
* implemented SMS provider 'OSON SMS' for frontend

* feat: add 'OSON SMS' provider for frontend
2024-03-04 01:05:53 +08:00
8b64d113fb Upgrade go-sms-sender dependency to 0.20.0 2024-03-04 01:05:28 +08:00
a8800c4d5c fix: add missing / for style tag in signin items (#2768) 2024-03-03 23:46:57 +08:00
75fc9ab9f7 Improve GetMaskedApplication()'s logic 2024-03-03 22:01:49 +08:00
d06da76c3d feat: fix bug in /get-organization-applications API 2024-03-03 21:08:36 +08:00
bc399837cc Rename label to "Custom CSS" 2024-03-03 20:45:14 +08:00
265abfe102 fix: handle error in storage.GetStorageProvider() 2024-03-03 18:18:54 +08:00
12acb24dbc feat: add transaction pages (#2761) 2024-03-02 10:41:16 +08:00
ba1ddc7e50 fix: admin can modify user ID now 2024-02-28 18:07:53 +08:00
59e07a35aa Add balance to user 2024-02-28 16:54:30 +08:00
cabe830f55 feat: use dynamic import to load web3Auth (#2757)
* feat: use dynamic import to load web3Auth and success reduce the size of signin page to 720KB when web3 idp disabled

* feat: avoid frequent import in OAuthWidget.js which may cause e2e test EPIPE error

* feat: remove import may cause e2e error

* feat: remove import may cause e2e error

* feat: remove bug may cause e2e error

* feat: try use chrome in ci/cd instead of electron to solve e2e error
2024-02-28 15:58:04 +08:00
78af5daec3 feat: use resourcesToBackend to load i18n files (#2755) 2024-02-28 01:43:55 +08:00
6c76913f71 fix: Set default value for email and SMS rule to all instead of none (#2754) 2024-02-28 01:28:59 +08:00
5a0d1bcb6e Support login by user ID 2024-02-28 01:28:24 +08:00
37232faa07 feat: fix bug for missing SMS and Email provider in application 2024-02-27 22:54:35 +08:00
4d9c81ef96 Fix broken error messages 2024-02-27 22:48:33 +08:00
b0d87f60ae feat: use lazy load to load management pages (#2752) 2024-02-27 22:31:02 +08:00
a5499219d1 fix: refactor out ManagementPage.js from App.js (#2750)
* feat: basic separate

* feat: nearly fully separate

* feat: add License

* feat: full load application in /login url, lazy load in /login/oauth... etc

* fix: fix onChangeTheme error in organization edit page

* fix: revert lazy load
2024-02-27 18:49:23 +08:00
6a813a1f8c feat: fix headerHtml script not running bug (#2749)
* fix: fix custom head not exec <script> tag

* fix: fix create element bug
2024-02-26 20:21:07 +08:00
e4cf244cf8 fix: theme will fully restore after page reload (#2743)
* fix: theme will set to default after flush

* fix: use consume theme to ensure EntryPage will always use default themeAlgorithm

* fix: fix logo render, add try catch to handle
potential err cause by JSON.parse
2024-02-25 00:05:13 +08:00
f5a6415e57 feat: improve dark theme UI (#2742) 2024-02-24 20:11:42 +08:00
13e871043c fix: fix theme switch bug (#2741) 2024-02-24 16:56:12 +08:00
a8699d0b87 feat: use React routing to remove spin between signup and signin pages (#2740)
* fix: Regarding the color of loading

* fix: use goToLinkSoft and use same code format with result and forget psw

* fix: update signup url
2024-02-24 12:59:09 +08:00
6621d693de feat: revert "feat: use i18next-resources-to-backend to lazy load i18n" (#2739)
This reverts commit dc3131c683.
2024-02-23 23:38:49 +08:00
dc3131c683 feat: use i18next-resources-to-backend to lazy load i18n (#2738)
* feat: use i18next-resources-to-backend to lazy load i18n file

* feat: change source in yarn.lock
2024-02-23 22:35:59 +08:00
042a8d0ad6 feat: add rule for SMS and Email provider (#2733)
* add phonecoderule

* feat:add phone code rule

* feat: add email rule

* fix: merge
2024-02-23 00:09:37 +08:00
44abfb3430 feat: support custom header HTML in entry pages (#2731) 2024-02-22 17:56:47 +08:00
53b8424a1f feat: fix JSON typo in init_data.json template 2024-02-21 17:33:08 +08:00
23c2ba3a2b feat: support ssh key/pem file in DB syncer (#2727)
* feat: support connect database with ssh tunnel in syncer

* feat: improve i18n translate

* feat: improve code format and i18n
2024-02-21 17:27:37 +08:00
3a9ffedce4 feat: support phone and Email in /api/login/oauth/access_token API (#2725)
Phone Number supports for /api/login/oauth/access_token as username

 Closes: #2724
2024-02-21 17:27:24 +08:00
03f005389f feat: fix organizationChangeTrigger() and userChangeTrigger() bugs 2024-02-21 01:14:32 +08:00
69a8346d05 Remove "/auto-signup/oauth/authorize" path introduced in PR: #896 2024-02-20 17:40:39 +08:00
546512a0ea Fix getCasvisorApplication() 2024-02-20 13:45:03 +08:00
c4a307b9ec feat: add built-in "Records" pages back (#2720) 2024-02-20 13:28:29 +08:00
d731c3c934 feat: add regex support for account item (#2714)
* feat: add regex support for account item

* feat: use reflect to process user field

* fix: fix lint problem

* feat: improve code format and fix reflect error
2024-02-17 15:24:36 +08:00
4a68dd65cd Fix typo in renderFormItem() 2024-02-16 10:13:50 +08:00
d59148890e Improve error handling for CheckVerificationCode() 2024-02-16 08:53:56 +08:00
7f52755e32 feat: improve error messages 2024-02-16 01:13:34 +08:00
eaa6f50085 Add initial value for grantTypes 2024-02-15 23:18:23 +08:00
f35a5f9a47 feat: fix issue that admin cannot enable MFA for user (#2702) 2024-02-14 23:29:04 +08:00
7481b229a4 feat: show domain field for MinIO storage provider 2024-02-14 13:54:17 +08:00
39e485ae82 Fix SigninTable issue 2024-02-14 12:20:03 +08:00
764c64e67c Fix SigninTable CSS 2024-02-14 12:10:30 +08:00
e755a7331d Fix renderLink() 2024-02-14 09:45:21 +08:00
6d9d595f86 fix: Revert "fix: fix display bug in SigninTable" (#2700)
This reverts commit d52058d2ae.
2024-02-14 09:44:42 +08:00
d52058d2ae fix: fix display bug in SigninTable (#2698)
* fix: fix display bug in SigninTable

* fix: fix code bug

* feat: improve code format

* feat: improve code format
2024-02-14 09:26:51 +08:00
bcfbfc6947 Support "signinUrl" in forget page 2024-02-14 02:36:52 +08:00
75699c4a26 feat: improve code in getObject() 2024-02-13 23:50:21 +08:00
3e8bfb52a8 feat: add signin items table (#2695)
* feat: add signin items table

* fix:unable to login

* feat: improve code format

* fix: fix display err on signup link

* feat: improve display of sign up link
2024-02-13 23:12:40 +08:00
bbbd857a45 fix: fix bug that failed to run initApi adapter in docker (#2696) 2024-02-13 23:12:25 +08:00
498900df76 feat: allow dot in the username (like john.smith) (#2692) 2024-02-12 20:52:17 +08:00
7e3c1a6581 fix: improve goth code (#2693)
Signed-off-by: Dmitrii Aleksandrov <goodmobiledevices@gmail.com>
2024-02-12 20:51:58 +08:00
6e28043dba refactor: New Crowdin translations (#2648)
* refactor: New Crowdin translations by Github Action

* refactor: New Crowdin Backend translations by Github Action

---------

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2024-02-12 18:54:31 +08:00
cb200687dc feat: fix GetUserByUserId() API crash issue 2024-02-12 18:51:55 +08:00
23bb0ee450 feat: fix error handling in AdfsIdProvider (#2687) 2024-02-10 15:38:38 +08:00
117259dfc5 ci: fix repo name in CI 2024-02-10 15:38:17 +08:00
e71d0476f0 feat: support data initialization for groups, adapters, enforcers, plans and pricings (#2685) 2024-02-08 20:46:40 +08:00
b5d26767b2 docs: improve README 2024-02-08 00:02:31 +08:00
5c4e22288e feat: improve error handling and code format (#2682)
* feat: improve error process and code format

* feat: improve error process and code format
2024-02-07 20:55:33 +08:00
3ac4be64b8 fix: error msg for invalid org & app names in signup (#2679) 2024-02-07 08:53:50 +08:00
97db54b6b9 feat: full support for wechat official account login (#2677)
* feat: full support for wechat official account login

* feat: improve provider edit page

* fix: improve i18n format
2024-02-07 00:00:10 +08:00
3a19d4c7c8 fix: do not filter webhooks by org 2024-02-06 20:33:11 +08:00
a60be2b2ab feat: refactor MFA code and fix no-session bug (#2676)
* refactor: refactor mfa

* refactor: refactor mfa

* refactor: refactor mfa

* lint

* chore: reduce wait time
2024-02-06 20:17:59 +08:00
06ef97a080 feat: can delete the whole SigninMethodTable 2024-02-06 16:43:16 +08:00
167c1b0f1b feat: fix bug in WeChat OA login (#2674)
* fix: fix the problem of Wechat Official Account login

* fix: fix code format problem

* fix: add error display and fix the code format problem

* fix: i18n problem and code format
2024-02-05 21:38:12 +08:00
7d0eae230e fix: fix /signup organization parameter issue (#2669) 2024-02-03 11:47:36 +08:00
901867e8bb feat: fix /signup parameter issue 2024-02-03 10:00:47 +08:00
b7be1943fa feat: Add Invitation Code to Generate Invitation Link (#2666)
Add auto-population of invitation fields in the registration page based on the invitation code in the link
2024-02-02 21:12:56 +08:00
bbbda1982f feat: fix missing MFA session issue (#2667) 2024-02-02 10:23:17 +08:00
e593f5be5b fix: improve code format (#2665)
* feat: replace io/ioutils pacakage with io/os package

* fix: add missing error handling
2024-02-01 23:06:12 +08:00
0918757e85 feat: add template support for Custom HTTP SMS provider (#2662) 2024-02-01 17:50:22 +08:00
ce0d45a70b feat: support SAML POST binding (#2661)
* fix: support saml http post binding

* fix: support saml http post binding

* fix: support saml post binding sp
2024-02-01 17:28:56 +08:00
c4096788b2 feat: ABAC support for /api/enforce endpoint (#2660) 2024-01-31 23:14:55 +08:00
523186f895 feat: Support sha512 password encryption algorithm (#2657)
* add sha512 encryption support for password

* fead: add sha512 encryption support for password
2024-01-31 00:06:06 +08:00
ef373ca736 feat: add deletedTime to user (#2652) 2024-01-30 23:18:32 +08:00
721a681ff1 fix: improve error handling in GetUserApplication() 2024-01-30 21:40:39 +08:00
8b1c4b0c75 feat: make phone field longer to 100 2024-01-30 19:06:18 +08:00
540f22f8bd feat: refactor GetTokenByTokenValue() 2024-01-29 10:03:33 +08:00
79f81f1356 Improve error handling in IntrospectToken() 2024-01-29 09:58:40 +08:00
4e145f71b5 feat: improve MFA UI and jump URL (#2647)
* fix: mfa UI

* fix: mfa UI
2024-01-28 16:46:35 +08:00
104f975a2f fix: fix wrong org issue for user's "signupApplication" 2024-01-28 01:51:03 +08:00
71bb400559 feat: support using org's defaultAvatar when adding user in web UI 2024-01-28 01:07:20 +08:00
93c3c78d42 feat: support "id_card" in UpdateUser() 2024-01-26 08:23:55 +08:00
dd51bbbabf feat: fix autoComplete for MFA passcode and SMS code (#2642)
* update: mfa autoComplete="off"

* Update SendCodeInput.js

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2024-01-23 19:52:16 +08:00
5318519bf8 fix: fix bug in LDAP user login error count (#2636)
Fix the issue where the login error count is not reset to 0 after a successful LDAP user login.
2024-01-22 13:42:11 +08:00
d7c40459c0 feat: implement the enforcement for new invitation page (#2628)
Added new invitation code implementation
2024-01-22 02:25:13 +08:00
de2932b5fb feat: use standalone Twitter OAuth provider instead of goth (#2632) 2024-01-20 21:49:02 +08:00
f4c873ffe6 Fix user profile page UI 2024-01-20 19:28:43 +08:00
97c7f2631a feat: fix organization.IsProfilePublic issue 2024-01-20 16:00:04 +08:00
93f0425759 Remove old application's InvitationCodes 2024-01-20 10:58:08 +08:00
6a00657e42 feat: fix forbidden and soft-delete check in forget password page 2024-01-19 22:13:02 +08:00
88130bf020 feat: add forbidden check in SetPassword() 2024-01-19 16:30:22 +08:00
5e99007fc9 Update goth to v1.78.0 2024-01-19 16:09:32 +08:00
66aca3124c fix: improve error handling in LarkIdProvider 2024-01-19 15:37:15 +08:00
61deb75c84 refactor: New Crowdin translations (#2512)
* refactor: New Crowdin translations by Github Action

* refactor: New Crowdin Backend translations by Github Action

---------

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
2024-01-18 22:18:51 +08:00
b8db07db4d feat: enable GetMaskedSyncers() 2024-01-18 20:59:27 +08:00
a681c267b3 Refactor code format 2024-01-18 20:53:04 +08:00
5fb6ea0ab4 Fix "password" tab in SigninMethods 2024-01-18 20:17:05 +08:00
0f6b7984d4 feat: improve isAllowedInDemoMode() 2024-01-17 13:07:44 +08:00
ba9d6e5d78 Fix Swagger API version 2024-01-16 00:09:28 +08:00
a4524e9996 fix: fix Swagger @Tag 2024-01-15 23:35:40 +08:00
b469928780 Fix Swagger @router 2024-01-15 23:27:42 +08:00
dc6fe13f75 feat: use signupItem.Regex to check signup page 2024-01-15 18:12:38 +08:00
8227762988 Support more special chars in password validating 2024-01-15 18:12:38 +08:00
d92b072ed0 feat: revert PR: "feat: more RFC like LDAP server behaviour" (#2611) 2024-01-15 13:58:33 +08:00
1161310f81 feat: improve README.md 2024-01-15 10:14:01 +08:00
48ba5f91ed feat: add Synology NAS storage provider (#2605) 2024-01-14 22:38:31 +08:00
53df2c2704 fix: add semantic versioning for helm charts (#2603) 2024-01-14 09:44:16 +08:00
78066da208 Improve setCorsHeaders() for "include" mode 2024-01-13 23:46:05 +08:00
60096468fe fix: fix CI email 2024-01-13 18:12:52 +08:00
39d6bc10f7 Fix GetCaptchaStatus() crash if not logged in 2024-01-13 18:04:38 +08:00
177f2f2f11 Add userId param to GetAllObjects() API 2024-01-13 18:03:40 +08:00
79b393afee feat: add regex to SignupTable 2024-01-13 16:08:49 +08:00
5bb12a30d4 Don't show two errors in verificationCode login page 2024-01-13 16:01:22 +08:00
fdb68bf9c8 Rename to SigninMethodTable 2024-01-13 15:53:01 +08:00
37748850c8 Fix nameFormat in SamlItem 2024-01-13 15:32:49 +08:00
8968396ae5 Fix bug in getDefaultLoginMethod() 2024-01-13 12:13:09 +08:00
f5395f15f9 feat: fix isSigninMethodEnabled() bug in frontend 2024-01-13 11:35:06 +08:00
73e44df867 Improve GetAllRoles() error handling 2024-01-13 10:06:08 +08:00
0b575ccf84 Refactor getAllValues() 2024-01-13 09:58:55 +08:00
9b7f465a47 Fix failedSigninFrozenTime typo 2024-01-13 02:12:29 +08:00
b1fe28fb83 Refactor application.FailedSigninLimit code 2024-01-13 02:09:18 +08:00
530d054adb feat: ci should commit index.yaml and push to docker hub (#2600) 2024-01-11 16:10:08 +08:00
a2b9f9baaf feat: support "JWT-Custom" to customize user properties inside access token (#2594)
* feat: add custom attribute to access token

* Update token_jwt.go

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2024-01-10 00:59:02 +08:00
a2d20fcb63 Update i18n 2024-01-09 22:16:17 +08:00
b118a3bb76 Add TokenFields to application 2024-01-09 22:09:21 +08:00
280867d0cb Add checkSigninErrorTimes() for LDAP signin 2024-01-09 21:53:44 +08:00
30fa2f7d81 Disable LDAP login method by default 2024-01-09 21:36:09 +08:00
518288691d fix(ci): fix the helm publish step (#2593)
fixes https://github.com/casdoor/casdoor-helm/issues/3
2024-01-09 17:48:01 +08:00
ffa54247cd feat: add LDAP signin method (#2591)
Add support for LDAP login methods
Add option to control LDAP user in password login method.
2024-01-08 21:07:34 +08:00
0199ad9aaa fix: missing table prefix in get user group (#2590)
- Sort field and order field are missing table name prefix

Co-authored-by: xgenvn <brian7.ng@gmail.com>
2024-01-08 21:07:13 +08:00
b9d171718f chore(helm): move to dedicated helm-repo (#2587)
* chore(helm): move to dedicated helm-repo: https://github.com/casdoor/casdoor-helm

* feat(actions): explicit checkout helm repo

* chore: feedback from pr comment
2024-01-08 02:02:05 +08:00
e841d0ba8e feat: fix /api/send-email API for app user 2024-01-07 21:11:22 +08:00
e5a9594f90 Hide Google OneTap in iframe 2024-01-07 10:33:25 +08:00
c542929835 fix: add vscode local debugging support (#2585) 2024-01-07 09:26:33 +08:00
86dea71efd ci: update helm index.yaml 2024-01-06 19:31:07 +00:00
9e536850fd feat(helm): support for extra volume mounts (#2584)
* feat(helm): support for extraVolumes and extraVolumeMounts

* ci(helm): run helm unittests
2024-01-07 03:30:44 +08:00
fddd4a12b8 chore: update helm version to v1.492.0 (#2582) 2024-01-07 00:14:53 +08:00
2d6fae32be feat: support custom config path via "config" 2024-01-06 14:09:48 +08:00
741cff99df Remove isCreateDatabaseDefined 2024-01-06 14:08:34 +08:00
cad9c28e92 feat: helm hpa yaml must reference correct apiVersion (#2581) 2024-01-06 08:55:59 +08:00
524cf4dda5 feat: fix update application failed for permissions with the same name (#2579)
* fixed: update application failed where have two same permission in different organization

* Update application.go

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2024-01-05 20:45:55 +08:00
077a1cb8b7 fix: support owner parameter in enforce API (#2578) 2024-01-05 15:12:59 +08:00
00efdf1d03 Fix EmailVerified in UserInfo() 2024-01-05 09:37:42 +08:00
aa543f1abb feat: more RFC like LDAP server behaviour (#2574)
* feat: more RFC like LDAP server behaviour

* Extend FieldRelationMap to support case insensitive mapping, add more fields definition

* feat: Add group syncing for LDAP server
2024-01-05 09:24:12 +08:00
1d1d3049bd feat: fix dropped getAffiliationMap error in object (#2576) 2024-01-05 09:03:39 +08:00
4f497d44a5 Enable at least password login in extendApplicationWithSigninMethods() 2024-01-03 22:19:43 +08:00
369de36987 feat: add users with correct application (#2570) 2024-01-02 23:49:04 +08:00
e3f28e8b4c feat: Support more flexible login method control (#2566) 2024-01-02 21:11:52 +08:00
3373174c65 fix: add missing tableNamePrefix in some places 2023-12-31 22:40:41 +08:00
2fb79e4092 Add invitation pages 2023-12-31 21:38:36 +08:00
5846e337c7 feat: fix gofmt issue 2023-12-30 19:47:04 +08:00
44f4de1440 feat: support empty fileUrl in GetUploadFileUrl() 2023-12-30 19:06:35 +08:00
27adeb4620 Refactor initAPI() 2023-12-30 14:28:45 +08:00
5c107db43b fix: fix i18n typo 2023-12-30 00:49:39 +08:00
27187b3a54 feat: add "Reset to Default HTML" button 2023-12-30 00:47:10 +08:00
14fcedcc5d feat: support HTML in Email content 2023-12-29 23:31:50 +08:00
e7c015f288 feat: fix comment and configs for successfully generating OpenAPI typescript-axios sdk (#2560)
* fix: fix swagger.json, successfully generate java sdk

* fix:fix comment and change some content for successfully generating typescript-axios sdk
2023-12-29 15:12:40 +08:00
c4819602ec fix: add mfa API to isAllowedInDemoMode() 2023-12-26 20:06:27 +08:00
dea03cdd15 feat: replace deprecated github.com/RobotsAndPencils/go-saml (#2558)
The `github.com/RobotsAndPencils/go-saml` has been officially deprecated
and archived on 7 June 2023.

Signed-off-by: Eng Zer Jun <engzerjun@gmail.com>
2023-12-25 21:15:53 +08:00
21f394847e fix: fix Swagger docs by improving comments 2023-12-23 11:57:18 +08:00
9bef9691fb feat: fix volcengine SMS provider error handling 2023-12-22 20:49:45 +08:00
141f22a707 feat: upgrade to Node.js 18 and Go 1.20 in Dockerfile 2023-12-22 14:46:41 +08:00
02329d342a feat: fix bug in "*" users and roles in permission edit page. 2023-12-22 14:16:00 +08:00
b9d3e2184c fix: update CI node version from 16 to 18 2023-12-22 09:28:45 +08:00
28caf8550e Support token parsed result 2023-12-22 02:04:25 +08:00
79159dc809 Improve TokenEditPage 2023-12-22 00:44:34 +08:00
63081641d6 Improve i18n text 2023-12-22 00:25:46 +08:00
698f24f762 feat: fix template code bug in SMS provider of Amazon SNS 2023-12-21 23:32:55 +08:00
5499e62d7f feat: add the FailedSigninLimit and FailedSigninfrozenTime configuration options to the application (#2552)
Add configuration items to the application to limit the number of logins and the login wait time after the maximum number of errors is reached
feat: #2272

fix: fixed the issue where the token parameter could be set to a negative value
2023-12-20 22:29:53 +08:00
f8905ae64c Fix S3-compliant storage providers support 2023-12-20 14:38:32 +08:00
a42594859f feat: improve enforce() and batchEnforce() API response 2023-12-20 11:41:54 +08:00
46e0bc1a39 Improve i18n texts 2023-12-20 10:09:00 +08:00
ffe2330238 Fix tag field in user list page 2023-12-20 01:57:56 +08:00
ec53616dc8 Update README.md 2023-12-20 01:52:29 +08:00
067276d739 Add new B2C provider 2023-12-17 16:29:29 +08:00
468ceb6b71 Fix get-all-objects API 403 issue 2023-12-15 21:32:45 +08:00
b31a317585 feat: add helm release github action (#2546) 2023-12-15 19:30:10 +08:00
396b6fb65f feat: refactor custom HTTP related filenames 2023-12-15 00:06:05 +08:00
be637fca81 fix: fix wrong POST param logic in custom HTTP providers 2023-12-15 00:00:47 +08:00
374928e719 feat: add custom HTTP Email provider (#2542)
* feat: implement Custom HTTP Email provider

* Update Setting.js

* Update ProviderEditPage.js

* Update http.go

* Update provider.go

---------

Co-authored-by: hsluoyz <hsluoyz@qq.com>
2023-12-14 22:35:25 +08:00
5c103e8cd3 Improve error handling in GenerateIdForNewUser() 2023-12-14 10:12:00 +08:00
85b86e8831 fix: dropped object group errors (#2545) 2023-12-14 09:00:25 +08:00
08864686f3 feat: fix Google cloud storage provider bug 2023-12-14 00:25:50 +08:00
dc06eb9948 feat: fix secret information issue in the CAPTCHA provider code (#2531) 2023-12-11 18:01:56 +08:00
b068202e74 Improve Radius username handling 2023-12-11 18:01:28 +08:00
cb16567c7b feat: helm support extra containers (#2530) 2023-12-10 14:41:56 +08:00
4eb725d47a Improve image upload UI 2023-12-08 19:42:20 +08:00
ce72a172b0 feat: add back Custom HTTP SMS provider 2023-12-07 16:59:41 +08:00
5521962e0c feat: update go-sms-sender to v0.17.0 to improve error handling 2023-12-07 14:25:21 +08:00
37b8b09cc0 feat: update go-sms-sender to v0.16.0 to fix first number missing bug in AmazonSNSClient.SendMessage 2023-12-06 20:05:48 +08:00
482eb61168 feat: improve StaticFilter() 2023-12-05 18:33:06 +08:00
8819a8697b feat: fix dropped error in stripe.go (#2525) 2023-12-05 16:02:33 +08:00
85cb68eb66 feat: unbind LDAP clients if not used any more 2023-12-02 17:51:25 +08:00
b25b5f0249 Support original accessToken in token APIs 2023-12-02 16:56:18 +08:00
947dcf6e75 Fix "All" roles bug in permission edit page 2023-12-02 15:26:52 +08:00
113c27db73 Improve logout's id_token_hint logic 2023-12-02 02:13:34 +08:00
badfe34755 feat: add "nonce" into the OAuth and OIDC tokens, for some apps require "nonce" to integrate (#2522) 2023-12-01 18:29:39 +08:00
a5f9f61381 feat: add token hash to improve performance 2023-11-30 18:05:30 +08:00
419 changed files with 40986 additions and 12883 deletions

8
.gitattributes vendored
View File

@ -1,5 +1,5 @@
*.go linguist-detectable=true
*.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.
*.go linguist-detectable=true
*.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

@ -1,6 +1,6 @@
name: Build
on: [push, pull_request]
on: [ push, pull_request ]
jobs:
@ -35,7 +35,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
node-version: 20
cache: 'yarn'
cache-dependency-path: ./web/yarn.lock
- run: yarn install && CI=false yarn run build
@ -101,24 +101,25 @@ jobs:
working-directory: ./
- uses: actions/setup-node@v3
with:
node-version: 16
node-version: 20
cache: 'yarn'
cache-dependency-path: ./web/yarn.lock
- run: yarn install
working-directory: ./web
- uses: cypress-io/github-action@v5
with:
browser: chrome
start: yarn start
wait-on: 'http://localhost:7001'
wait-on-timeout: 210
working-directory: ./web
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
if: failure()
with:
name: cypress-screenshots
path: ./web/cypress/screenshots
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
if: always()
with:
name: cypress-videos
@ -127,7 +128,7 @@ jobs:
release-and-push:
name: Release And Push
runs-on: ubuntu-latest
if: github.repository == 'casbin/casdoor' && github.event_name == 'push'
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push'
needs: [ frontend, backend, linter, e2e ]
steps:
- name: Checkout
@ -137,7 +138,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v3
with:
node-version: 16
node-version: 20
- name: Fetch Previous version
id: get-previous-tag
@ -146,7 +147,7 @@ jobs:
- name: Release
run: yarn global add semantic-release@17.4.4 && semantic-release
env:
GH_TOKEN: ${{ secrets.GH_BOT_TOKEN }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Fetch Current version
id: get-current-tag
@ -167,10 +168,8 @@ jobs:
elif [ ${old_array[1]} != ${new_array[1]} ]
then
echo ::set-output name=push::'true'
else
echo ::set-output name=push::'false'
fi
- name: Set up QEMU
@ -184,27 +183,57 @@ jobs:
- name: Log in to Docker Hub
uses: docker/login-action@v1
if: github.repository == 'casbin/casdoor' && github.event_name == 'push' && steps.should_push.outputs.push=='true'
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push' && steps.should_push.outputs.push=='true'
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
- name: Push to Docker Hub
uses: docker/build-push-action@v3
if: github.repository == 'casbin/casdoor' && github.event_name == 'push' && steps.should_push.outputs.push=='true'
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push' && steps.should_push.outputs.push=='true'
with:
context: .
target: STANDARD
platforms: linux/amd64
platforms: linux/amd64,linux/arm64
push: true
tags: casbin/casdoor:${{steps.get-current-tag.outputs.tag }},casbin/casdoor:latest
- name: Push All In One Version to Docker Hub
uses: docker/build-push-action@v3
if: github.repository == 'casbin/casdoor' && github.event_name == 'push' && steps.should_push.outputs.push=='true'
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push' && steps.should_push.outputs.push=='true'
with:
context: .
target: ALLINONE
platforms: linux/amd64
platforms: linux/amd64,linux/arm64
push: true
tags: casbin/casdoor-all-in-one:${{steps.get-current-tag.outputs.tag }},casbin/casdoor-all-in-one:latest
- uses: actions/checkout@v3
if: steps.should_push.outputs.push=='true'
with:
repository: casdoor/casdoor-helm
ref: 'master'
token: ${{ secrets.GH_BOT_TOKEN }}
- name: Update Helm Chart
if: steps.should_push.outputs.push=='true'
run: |
# Set the appVersion and version of the chart to the current tag
sed -i "s/appVersion: .*/appVersion: ${{steps.get-current-tag.outputs.tag }}/g" ./charts/casdoor/Chart.yaml
sed -i "s/version: .*/version: ${{steps.get-current-tag.outputs.tag }}/g" ./charts/casdoor/Chart.yaml
REGISTRY=oci://registry-1.docker.io/casbin
cd charts/casdoor
helm package .
PKG_NAME=$(ls *.tgz)
helm repo index . --url $REGISTRY --merge index.yaml
helm push $PKG_NAME $REGISTRY
rm $PKG_NAME
# Commit and push the changes back to the repository
git config --global user.name "casbin-bot"
git config --global user.email "bot@casbin.org"
git add Chart.yaml index.yaml
git commit -m "chore(helm): bump helm charts appVersion to ${{steps.get-current-tag.outputs.tag }}"
git tag ${{steps.get-current-tag.outputs.tag }}
git push origin HEAD:master --follow-tags

View File

@ -7,7 +7,7 @@ on:
jobs:
synchronize-with-crowdin:
runs-on: ubuntu-latest
if: github.repository == 'casbin/casdoor' && github.event_name == 'push'
if: github.repository == 'casdoor/casdoor' && github.event_name == 'push'
steps:
- name: Checkout

5
.gitignore vendored
View File

@ -18,7 +18,7 @@ bin/
.idea/
*.iml
.vscode/
.vscode/settings.json
tmp/
tmpFiles/
@ -31,3 +31,6 @@ commentsRouter*.go
# ignore build result
casdoor
server
# include helm-chart
!manifests/casdoor

15
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,15 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug",
"type": "go",
"request": "launch",
"mode": "auto",
"program": "${workspaceFolder}",
"cwd": "${workspaceFolder}",
"debugAdapter": "dlv-dap",
"args": ["--createDatabase=true"]
}
]
}

View File

@ -1,10 +1,10 @@
FROM node:16.18.0 AS FRONT
FROM --platform=$BUILDPLATFORM node:18.19.0 AS FRONT
WORKDIR /web
COPY ./web .
RUN yarn install --frozen-lockfile --network-timeout 1000000 && yarn run build
RUN yarn install --frozen-lockfile --network-timeout 1000000 && NODE_OPTIONS="--max-old-space-size=4096" yarn run build
FROM golang:1.19.9 AS BACK
FROM --platform=$BUILDPLATFORM golang:1.21.13 AS BACK
WORKDIR /go/src/casdoor
COPY . .
RUN ./build.sh
@ -13,9 +13,13 @@ RUN go test -v -run TestGetVersionInfo ./util/system_test.go ./util/system.go >
FROM alpine:latest AS STANDARD
LABEL MAINTAINER="https://casdoor.org/"
ARG USER=casdoor
ARG TARGETOS
ARG TARGETARCH
ENV BUILDX_ARCH="${TARGETOS:-linux}_${TARGETARCH:-amd64}"
RUN sed -i 's/https/http/' /etc/apk/repositories
RUN apk add --update sudo
RUN apk add tzdata
RUN apk add curl
RUN apk add ca-certificates && update-ca-certificates
@ -27,7 +31,7 @@ RUN adduser -D $USER -u 1000 \
USER 1000
WORKDIR /
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/server ./server
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/server_${BUILDX_ARCH} ./server
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/swagger ./swagger
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/conf/app.conf ./conf/app.conf
COPY --from=BACK --chown=$USER:$USER /go/src/casdoor/version_info.txt ./go/src/casdoor/version_info.txt
@ -46,12 +50,15 @@ RUN apt update \
FROM db AS ALLINONE
LABEL MAINTAINER="https://casdoor.org/"
ARG TARGETOS
ARG TARGETARCH
ENV BUILDX_ARCH="${TARGETOS:-linux}_${TARGETARCH:-amd64}"
RUN apt update
RUN apt install -y ca-certificates && update-ca-certificates
WORKDIR /
COPY --from=BACK /go/src/casdoor/server ./server
COPY --from=BACK /go/src/casdoor/server_${BUILDX_ARCH} ./server
COPY --from=BACK /go/src/casdoor/swagger ./swagger
COPY --from=BACK /go/src/casdoor/docker-entrypoint.sh /docker-entrypoint.sh
COPY --from=BACK /go/src/casdoor/conf/app.conf ./conf/app.conf

View File

@ -86,6 +86,9 @@ docker-build: ## Build docker image with the manager.
docker-push: ## Push docker image with the manager.
docker push ${REGISTRY}/${IMG}:${IMG_TAG}
deps: ## Run dependencies for local development
docker compose up -d db
lint-install: ## Install golangci-lint
@# The following installs a specific version of golangci-lint, which is appropriate for a CI server to avoid different results from build to build
go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.40.1

190
README.md
View File

@ -1,88 +1,102 @@
<h1 align="center" style="border-bottom: none;">📦⚡️ Casdoor</h1>
<h3 align="center">An open-source UI-first Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML, CAS, LDAP, SCIM, WebAuthn, TOTP, MFA and RADIUS</h3>
<p align="center">
<a href="#badge">
<img alt="semantic-release" src="https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg">
</a>
<a href="https://hub.docker.com/r/casbin/casdoor">
<img alt="docker pull casbin/casdoor" src="https://img.shields.io/docker/pulls/casbin/casdoor.svg">
</a>
<a href="https://github.com/casdoor/casdoor/actions/workflows/build.yml">
<img alt="GitHub Workflow Status (branch)" src="https://github.com/casdoor/casdoor/workflows/Build/badge.svg?style=flat-square">
</a>
<a href="https://github.com/casdoor/casdoor/releases/latest">
<img alt="GitHub Release" src="https://img.shields.io/github/v/release/casdoor/casdoor.svg">
</a>
<a href="https://hub.docker.com/repository/docker/casbin/casdoor">
<img alt="Docker Image Version (latest semver)" src="https://img.shields.io/badge/Docker%20Hub-latest-brightgreen">
</a>
</p>
<p align="center">
<a href="https://goreportcard.com/report/github.com/casdoor/casdoor">
<img alt="Go Report Card" src="https://goreportcard.com/badge/github.com/casdoor/casdoor?style=flat-square">
</a>
<a href="https://github.com/casdoor/casdoor/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/casdoor/casdoor?style=flat-square" alt="license">
</a>
<a href="https://github.com/casdoor/casdoor/issues">
<img alt="GitHub issues" src="https://img.shields.io/github/issues/casdoor/casdoor?style=flat-square">
</a>
<a href="#">
<img alt="GitHub stars" src="https://img.shields.io/github/stars/casdoor/casdoor?style=flat-square">
</a>
<a href="https://github.com/casdoor/casdoor/network">
<img alt="GitHub forks" src="https://img.shields.io/github/forks/casdoor/casdoor?style=flat-square">
</a>
<a href="https://crowdin.com/project/casdoor-site">
<img alt="Crowdin" src="https://badges.crowdin.net/casdoor-site/localized.svg">
</a>
<a href="https://discord.gg/5rPsrAzK7S">
<img alt="Discord" src="https://img.shields.io/discord/1022748306096537660?style=flat-square&logo=discord&label=discord&color=5865F2">
</a>
</p>
## Online demo
- Read-only site: https://door.casdoor.com (any modification operation will fail)
- Writable site: https://demo.casdoor.com (original data will be restored for every 5 minutes)
## Documentation
https://casdoor.org
## Install
- By source code: https://casdoor.org/docs/basic/server-installation
- By Docker: https://casdoor.org/docs/basic/try-with-docker
## How to connect to Casdoor?
https://casdoor.org/docs/how-to-connect/overview
## Casdoor Public API
- Docs: https://casdoor.org/docs/basic/public-api
- Swagger: https://door.casdoor.com/swagger
## Integrations
https://casdoor.org/docs/category/integrations
## How to contact?
- Discord: https://discord.gg/5rPsrAzK7S
- Forum: https://forum.casbin.com
- Contact: https://tawk.to/chat/623352fea34c2456412b8c51/1fuc7od6e
## Contribute
For casdoor, if you have any questions, you can give Issues, or you can also directly start Pull Requests(but we recommend giving issues first to communicate with the community).
### I18n translation
If you are contributing to casdoor, please note that we use [Crowdin](https://crowdin.com/project/casdoor-site) as translating platform and i18next as translating tool. When you add some words using i18next in the `web/` directory, please remember to add what you have added to the `web/src/locales/en/data.json` file.
## License
[Apache-2.0](https://github.com/casdoor/casdoor/blob/master/LICENSE)
<h1 align="center" style="border-bottom: none;">📦⚡️ Casdoor</h1>
<h3 align="center">An open-source UI-first Identity and Access Management (IAM) / Single-Sign-On (SSO) platform with web UI supporting OAuth 2.0, OIDC, SAML, CAS, LDAP, SCIM, WebAuthn, TOTP, MFA and RADIUS</h3>
<p align="center">
<a href="#badge">
<img alt="semantic-release" src="https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg">
</a>
<a href="https://hub.docker.com/r/casbin/casdoor">
<img alt="docker pull casbin/casdoor" src="https://img.shields.io/docker/pulls/casbin/casdoor.svg">
</a>
<a href="https://github.com/casdoor/casdoor/actions/workflows/build.yml">
<img alt="GitHub Workflow Status (branch)" src="https://github.com/casdoor/casdoor/workflows/Build/badge.svg?style=flat-square">
</a>
<a href="https://github.com/casdoor/casdoor/releases/latest">
<img alt="GitHub Release" src="https://img.shields.io/github/v/release/casdoor/casdoor.svg">
</a>
<a href="https://hub.docker.com/r/casbin/casdoor">
<img alt="Docker Image Version (latest semver)" src="https://img.shields.io/badge/Docker%20Hub-latest-brightgreen">
</a>
</p>
<p align="center">
<a href="https://goreportcard.com/report/github.com/casdoor/casdoor">
<img alt="Go Report Card" src="https://goreportcard.com/badge/github.com/casdoor/casdoor?style=flat-square">
</a>
<a href="https://github.com/casdoor/casdoor/blob/master/LICENSE">
<img src="https://img.shields.io/github/license/casdoor/casdoor?style=flat-square" alt="license">
</a>
<a href="https://github.com/casdoor/casdoor/issues">
<img alt="GitHub issues" src="https://img.shields.io/github/issues/casdoor/casdoor?style=flat-square">
</a>
<a href="#">
<img alt="GitHub stars" src="https://img.shields.io/github/stars/casdoor/casdoor?style=flat-square">
</a>
<a href="https://github.com/casdoor/casdoor/network">
<img alt="GitHub forks" src="https://img.shields.io/github/forks/casdoor/casdoor?style=flat-square">
</a>
<a href="https://crowdin.com/project/casdoor-site">
<img alt="Crowdin" src="https://badges.crowdin.net/casdoor-site/localized.svg">
</a>
<a href="https://discord.gg/5rPsrAzK7S">
<img alt="Discord" src="https://img.shields.io/discord/1022748306096537660?style=flat-square&logo=discord&label=discord&color=5865F2">
</a>
</p>
<p align="center">
<sup>Sponsored by</sup>
<br>
<a href="https://stytch.com/docs?utm_source=oss-sponsorship&utm_medium=paid_sponsorship&utm_campaign=casbin">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://cdn.casbin.org/img/stytch-white.png">
<source media="(prefers-color-scheme: light)" srcset="https://cdn.casbin.org/img/stytch-charcoal.png">
<img src="https://cdn.casbin.org/img/stytch-charcoal.png" width="275">
</picture>
</a><br/>
<a href="https://stytch.com/docs?utm_source=oss-sponsorship&utm_medium=paid_sponsorship&utm_campaign=casbin"><b>Build auth with fraud prevention, faster.</b><br/> Try Stytch for API-first authentication, user & org management, multi-tenant SSO, MFA, device fingerprinting, and more.</a>
<br>
</p>
## Online demo
- Read-only site: https://door.casdoor.com (any modification operation will fail)
- Writable site: https://demo.casdoor.com (original data will be restored for every 5 minutes)
## Documentation
https://casdoor.org
## Install
- By source code: https://casdoor.org/docs/basic/server-installation
- By Docker: https://casdoor.org/docs/basic/try-with-docker
- By Kubernetes Helm: https://casdoor.org/docs/basic/try-with-helm
## How to connect to Casdoor?
https://casdoor.org/docs/how-to-connect/overview
## Casdoor Public API
- Docs: https://casdoor.org/docs/basic/public-api
- Swagger: https://door.casdoor.com/swagger
## Integrations
https://casdoor.org/docs/category/integrations
## How to contact?
- Discord: https://discord.gg/5rPsrAzK7S
- Contact: https://casdoor.org/help
## Contribute
For casdoor, if you have any questions, you can give Issues, or you can also directly start Pull Requests(but we recommend giving issues first to communicate with the community).
### I18n translation
If you are contributing to casdoor, please note that we use [Crowdin](https://crowdin.com/project/casdoor-site) as translating platform and i18next as translating tool. When you add some words using i18next in the `web/` directory, please remember to add what you have added to the `web/src/locales/en/data.json` file.
## License
[Apache-2.0](https://github.com/casdoor/casdoor/blob/master/LICENSE)

View File

@ -47,11 +47,13 @@ p, *, *, GET, /api/get-app-login, *, *
p, *, *, POST, /api/logout, *, *
p, *, *, GET, /api/logout, *, *
p, *, *, POST, /api/callback, *, *
p, *, *, POST, /api/device-auth, *, *
p, *, *, GET, /api/get-account, *, *
p, *, *, GET, /api/userinfo, *, *
p, *, *, GET, /api/user, *, *
p, *, *, GET, /api/health, *, *
p, *, *, POST, /api/webhook, *, *
p, *, *, *, /api/webhook, *, *
p, *, *, GET, /api/get-qrcode, *, *
p, *, *, GET, /api/get-webhook-event, *, *
p, *, *, GET, /api/get-captcha-status, *, *
p, *, *, *, /api/login/oauth, *, *
@ -76,10 +78,12 @@ p, *, *, POST, /api/verify-code, *, *
p, *, *, POST, /api/reset-email-or-phone, *, *
p, *, *, POST, /api/upload-resource, *, *
p, *, *, GET, /.well-known/openid-configuration, *, *
p, *, *, GET, /.well-known/webfinger, *, *
p, *, *, *, /.well-known/jwks, *, *
p, *, *, GET, /api/get-saml-login, *, *
p, *, *, POST, /api/acs, *, *
p, *, *, GET, /api/saml/metadata, *, *
p, *, *, *, /api/saml/redirect, *, *
p, *, *, *, /cas, *, *
p, *, *, *, /scim, *, *
p, *, *, *, /api/webauthn, *, *
@ -92,6 +96,13 @@ p, *, *, GET, /api/get-plan, *, *
p, *, *, GET, /api/get-subscription, *, *
p, *, *, GET, /api/get-provider, *, *
p, *, *, GET, /api/get-organization-names, *, *
p, *, *, GET, /api/get-all-objects, *, *
p, *, *, GET, /api/get-all-actions, *, *
p, *, *, GET, /api/get-all-roles, *, *
p, *, *, GET, /api/run-casbin-command, *, *
p, *, *, POST, /api/refresh-engines, *, *
p, *, *, GET, /api/get-invitation-info, *, *
p, *, *, GET, /api/faceid-signin-begin, *, *
`
sa := stringadapter.NewAdapter(ruleText)
@ -147,7 +158,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 {
if method == "POST" {
if strings.HasPrefix(urlPath, "/api/login") || urlPath == "/api/logout" || urlPath == "/api/signup" || urlPath == "/api/callback" || urlPath == "/api/send-verification-code" || urlPath == "/api/send-email" || urlPath == "/api/verify-captcha" {
if strings.HasPrefix(urlPath, "/api/login") || urlPath == "/api/logout" || urlPath == "/api/signup" || urlPath == "/api/callback" || urlPath == "/api/send-verification-code" || urlPath == "/api/send-email" || urlPath == "/api/verify-captcha" || urlPath == "/api/verify-code" || urlPath == "/api/check-user-password" || strings.HasPrefix(urlPath, "/api/mfa/") || urlPath == "/api/webhook" || urlPath == "/api/get-qrcode" || urlPath == "/api/refresh-engines" {
return true
} else if urlPath == "/api/update-user" {
// Allow ordinary users to update their own information
@ -155,6 +166,11 @@ func isAllowedInDemoMode(subOwner string, subName string, method string, urlPath
return true
}
return false
} else if urlPath == "/api/upload-resource" {
if subOwner == "app" && subName == "app-casibase" {
return true
}
return false
} else {
return false
}

View File

@ -8,4 +8,6 @@ else
echo "Google is blocked, Go proxy is enabled: GOPROXY=https://goproxy.cn,direct"
export GOPROXY="https://goproxy.cn,direct"
fi
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o server .
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags="-w -s" -o server_linux_amd64 .
CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -ldflags="-w -s" -o server_linux_arm64 .

View File

@ -15,32 +15,51 @@
package captcha
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"sort"
"strconv"
"strings"
"time"
"github.com/casdoor/casdoor/util"
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
openapiutil "github.com/alibabacloud-go/openapi-util/service"
teaUtil "github.com/alibabacloud-go/tea-utils/v2/service"
"github.com/alibabacloud-go/tea/tea"
)
const AliyunCaptchaVerifyUrl = "http://afs.aliyuncs.com"
const AliyunCaptchaVerifyUrl = "captcha.cn-shanghai.aliyuncs.com"
type captchaSuccessResponse struct {
Code int `json:"Code"`
Msg string `json:"Msg"`
type VerifyCaptchaRequest struct {
CaptchaVerifyParam *string `json:"CaptchaVerifyParam,omitempty" xml:"CaptchaVerifyParam,omitempty"`
SceneId *string `json:"SceneId,omitempty" xml:"SceneId,omitempty"`
}
type captchaFailResponse struct {
Code string `json:"Code"`
Message string `json:"Message"`
type VerifyCaptchaResponseBodyResult struct {
VerifyResult *bool `json:"VerifyResult,omitempty" xml:"VerifyResult,omitempty"`
}
type VerifyCaptchaResponseBody struct {
Code *string `json:"Code,omitempty" xml:"Code,omitempty"`
Message *string `json:"Message,omitempty" xml:"Message,omitempty"`
// Id of the request
RequestId *string `json:"RequestId,omitempty" xml:"RequestId,omitempty"`
Result *VerifyCaptchaResponseBodyResult `json:"Result,omitempty" xml:"Result,omitempty" type:"Struct"`
Success *bool `json:"Success,omitempty" xml:"Success,omitempty"`
}
type VerifyIntelligentCaptchaResponseBodyResult struct {
VerifyCode *string `json:"VerifyCode,omitempty" xml:"VerifyCode,omitempty"`
VerifyResult *bool `json:"VerifyResult,omitempty" xml:"VerifyResult,omitempty"`
}
type VerifyIntelligentCaptchaResponseBody struct {
Code *string `json:"Code,omitempty" xml:"Code,omitempty"`
Message *string `json:"Message,omitempty" xml:"Message,omitempty"`
// Id of the request
RequestId *string `json:"RequestId,omitempty" xml:"RequestId,omitempty"`
Result *VerifyIntelligentCaptchaResponseBodyResult `json:"Result,omitempty" xml:"Result,omitempty" type:"Struct"`
Success *bool `json:"Success,omitempty" xml:"Success,omitempty"`
}
type VerifyIntelligentCaptchaResponse struct {
Headers map[string]*string `json:"headers,omitempty" xml:"headers,omitempty" require:"true"`
StatusCode *int32 `json:"statusCode,omitempty" xml:"statusCode,omitempty" require:"true"`
Body *VerifyIntelligentCaptchaResponseBody `json:"body,omitempty" xml:"body,omitempty" require:"true"`
}
type AliyunCaptchaProvider struct{}
func NewAliyunCaptchaProvider() *AliyunCaptchaProvider {
@ -48,68 +67,69 @@ func NewAliyunCaptchaProvider() *AliyunCaptchaProvider {
return captcha
}
func contentEscape(str string) string {
str = strings.Replace(str, " ", "%20", -1)
str = url.QueryEscape(str)
return str
}
func (captcha *AliyunCaptchaProvider) VerifyCaptcha(token, clientId, clientSecret, clientId2 string) (bool, error) {
config := &openapi.Config{}
func (captcha *AliyunCaptchaProvider) VerifyCaptcha(token, clientSecret string) (bool, error) {
pathData, err := url.ParseQuery(token)
config.Endpoint = tea.String(AliyunCaptchaVerifyUrl)
config.ConnectTimeout = tea.Int(5000)
config.ReadTimeout = tea.Int(5000)
config.AccessKeyId = tea.String(clientId)
config.AccessKeySecret = tea.String(clientSecret)
client := new(openapi.Client)
err := client.Init(config)
if err != nil {
return false, err
}
pathData["Action"] = []string{"AuthenticateSig"}
pathData["Format"] = []string{"json"}
pathData["SignatureMethod"] = []string{"HMAC-SHA1"}
pathData["SignatureNonce"] = []string{strconv.FormatInt(time.Now().UnixNano(), 10)}
pathData["SignatureVersion"] = []string{"1.0"}
pathData["Timestamp"] = []string{time.Now().UTC().Format("2006-01-02T15:04:05Z")}
pathData["Version"] = []string{"2018-01-12"}
request := VerifyCaptchaRequest{CaptchaVerifyParam: tea.String(token), SceneId: tea.String(clientId2)}
var keys []string
for k := range pathData {
keys = append(keys, k)
}
sort.Strings(keys)
sortQuery := ""
for _, k := range keys {
sortQuery += k + "=" + contentEscape(pathData[k][0]) + "&"
}
sortQuery = strings.TrimSuffix(sortQuery, "&")
stringToSign := fmt.Sprintf("GET&%s&%s", url.QueryEscape("/"), url.QueryEscape(sortQuery))
signature := util.GetHmacSha1(clientSecret+"&", stringToSign)
resp, err := http.Get(fmt.Sprintf("%s?%s&Signature=%s", AliyunCaptchaVerifyUrl, sortQuery, url.QueryEscape(signature)))
err = teaUtil.ValidateModel(&request)
if err != nil {
return false, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
runtime := &teaUtil.RuntimeOptions{}
body := map[string]interface{}{}
if !tea.BoolValue(teaUtil.IsUnset(request.CaptchaVerifyParam)) {
body["CaptchaVerifyParam"] = request.CaptchaVerifyParam
}
if !tea.BoolValue(teaUtil.IsUnset(request.SceneId)) {
body["SceneId"] = request.SceneId
}
req := &openapi.OpenApiRequest{
Body: openapiutil.ParseToMap(body),
}
params := &openapi.Params{
Action: tea.String("VerifyIntelligentCaptcha"),
Version: tea.String("2023-03-05"),
Protocol: tea.String("HTTPS"),
Pathname: tea.String("/"),
Method: tea.String("POST"),
AuthType: tea.String("AK"),
Style: tea.String("RPC"),
ReqBodyType: tea.String("formData"),
BodyType: tea.String("json"),
}
res := &VerifyIntelligentCaptchaResponse{}
resBody, err := client.CallApi(params, req, runtime)
if err != nil {
return false, err
}
return handleCaptchaResponse(body)
}
func handleCaptchaResponse(body []byte) (bool, error) {
captchaResp := &captchaSuccessResponse{}
err := json.Unmarshal(body, captchaResp)
err = tea.Convert(resBody, &res)
if err != nil {
captchaFailResp := &captchaFailResponse{}
err = json.Unmarshal(body, captchaFailResp)
if err != nil {
return false, err
}
return false, errors.New(captchaFailResp.Message)
return false, err
}
return true, nil
if res.Body.Result.VerifyResult != nil && *res.Body.Result.VerifyResult {
return true, nil
}
return false, nil
}

View File

@ -23,6 +23,6 @@ func NewDefaultCaptchaProvider() *DefaultCaptchaProvider {
return captcha
}
func (captcha *DefaultCaptchaProvider) VerifyCaptcha(token, clientSecret string) (bool, error) {
func (captcha *DefaultCaptchaProvider) VerifyCaptcha(token, clientId, clientSecret, clientId2 string) (bool, error) {
return object.VerifyCaptcha(clientSecret, token), nil
}

View File

@ -35,7 +35,7 @@ func NewGEETESTCaptchaProvider() *GEETESTCaptchaProvider {
return captcha
}
func (captcha *GEETESTCaptchaProvider) VerifyCaptcha(token, clientSecret string) (bool, error) {
func (captcha *GEETESTCaptchaProvider) VerifyCaptcha(token, clientId, clientSecret, clientId2 string) (bool, error) {
pathData, err := url.ParseQuery(token)
if err != nil {
return false, err

View File

@ -32,7 +32,7 @@ func NewHCaptchaProvider() *HCaptchaProvider {
return captcha
}
func (captcha *HCaptchaProvider) VerifyCaptcha(token, clientSecret string) (bool, error) {
func (captcha *HCaptchaProvider) VerifyCaptcha(token, clientId, clientSecret, clientId2 string) (bool, error) {
reqData := url.Values{
"secret": {clientSecret},
"response": {token},

View File

@ -17,7 +17,7 @@ package captcha
import "fmt"
type CaptchaProvider interface {
VerifyCaptcha(token, clientSecret string) (bool, error)
VerifyCaptcha(token, clientId, clientSecret, clientId2 string) (bool, error)
}
func GetCaptchaProvider(captchaType string) CaptchaProvider {
@ -26,6 +26,10 @@ func GetCaptchaProvider(captchaType string) CaptchaProvider {
return NewDefaultCaptchaProvider()
case "reCAPTCHA":
return NewReCaptchaProvider()
case "reCAPTCHA v2":
return NewReCaptchaProvider()
case "reCAPTCHA v3":
return NewReCaptchaProvider()
case "Aliyun Captcha":
return NewAliyunCaptchaProvider()
case "hCaptcha":
@ -39,11 +43,11 @@ func GetCaptchaProvider(captchaType string) CaptchaProvider {
return nil
}
func VerifyCaptchaByCaptchaType(captchaType, token, clientSecret string) (bool, error) {
func VerifyCaptchaByCaptchaType(captchaType, token, clientId, clientSecret, clientId2 string) (bool, error) {
provider := GetCaptchaProvider(captchaType)
if provider == nil {
return false, fmt.Errorf("invalid captcha provider: %s", captchaType)
}
return provider.VerifyCaptcha(token, clientSecret)
return provider.VerifyCaptcha(token, clientId, clientSecret, clientId2)
}

View File

@ -32,7 +32,7 @@ func NewReCaptchaProvider() *ReCaptchaProvider {
return captcha
}
func (captcha *ReCaptchaProvider) VerifyCaptcha(token, clientSecret string) (bool, error) {
func (captcha *ReCaptchaProvider) VerifyCaptcha(token, clientId, clientSecret, clientId2 string) (bool, error) {
reqData := url.Values{
"secret": {clientSecret},
"response": {token},

View File

@ -32,7 +32,7 @@ func NewCloudflareTurnstileProvider() *CloudflareTurnstileProvider {
return captcha
}
func (captcha *CloudflareTurnstileProvider) VerifyCaptcha(token, clientSecret string) (bool, error) {
func (captcha *CloudflareTurnstileProvider) VerifyCaptcha(token, clientId, clientSecret, clientId2 string) (bool, error) {
reqData := url.Values{
"secret": {clientSecret},
"response": {token},

View File

@ -15,16 +15,23 @@ socks5Proxy = "127.0.0.1:10808"
verificationCodeTimeout = 10
initScore = 0
logPostOnly = true
isUsernameLowered = false
origin =
originFrontend =
staticBaseUrl = "https://cdn.casbin.org"
isDemoMode = false
batchSize = 100
enableErrorMask = false
enableGzip = true
inactiveTimeoutMinutes =
ldapServerPort = 389
ldapsCertId = ""
ldapsServerPort = 636
radiusServerPort = 1812
radiusDefaultOrganization = "built-in"
radiusSecret = "secret"
quota = {"organization": -1, "user": -1, "application": -1, "provider": -1}
logConfig = {"filename": "logs/casdoor.log", "maxdays":99999, "perm":"0770"}
logConfig = {"adapter":"file", "filename": "logs/casdoor.log", "maxdays":99999, "perm":"0770"}
initDataNewOnly = false
initDataFile = "./init_data.json"
frontendBaseDir = "../casdoor"
frontendBaseDir = "../cc_0"

View File

@ -71,7 +71,10 @@ func GetConfigInt64(key string) (int64, error) {
func GetConfigDataSourceName() string {
dataSourceName := GetConfigString("dataSourceName")
return ReplaceDataSourceNameByDocker(dataSourceName)
}
func ReplaceDataSourceNameByDocker(dataSourceName string) string {
runningInDocker := os.Getenv("RUNNING_IN_DOCKER")
if runningInDocker == "true" {
// https://stackoverflow.com/questions/48546124/what-is-linux-equivalent-of-host-docker-internal
@ -81,7 +84,6 @@ func GetConfigDataSourceName() string {
dataSourceName = strings.ReplaceAll(dataSourceName, "localhost", "host.docker.internal")
}
}
return dataSourceName
}
@ -108,13 +110,3 @@ func GetConfigBatchSize() int {
}
return res
}
func GetConfigRealDataSourceName(driverName string) string {
var dataSourceName string
if driverName != "mysql" {
dataSourceName = GetConfigDataSourceName()
} else {
dataSourceName = GetConfigDataSourceName() + GetConfigString("dbName")
}
return dataSourceName
}

View File

@ -115,7 +115,7 @@ func TestGetConfigLogs(t *testing.T) {
description string
expected string
}{
{"Default log config", `{"filename": "logs/casdoor.log", "maxdays":99999, "perm":"0770"}`},
{"Default log config", `{"adapter":"file", "filename": "logs/casdoor.log", "maxdays":99999, "perm":"0770"}`},
}
err := beego.LoadAppConfig("ini", "app.conf")

View File

@ -32,6 +32,7 @@ const (
ResponseTypeIdToken = "id_token"
ResponseTypeSaml = "saml"
ResponseTypeCas = "cas"
ResponseTypeDevice = "device"
)
type Response struct {
@ -41,9 +42,12 @@ type Response struct {
Name string `json:"name"`
Data interface{} `json:"data"`
Data2 interface{} `json:"data2"`
Data3 interface{} `json:"data3"`
}
type Captcha struct {
Owner string `json:"owner"`
Name string `json:"name"`
Type string `json:"type"`
AppKey string `json:"appKey"`
Scene string `json:"scene"`
@ -56,6 +60,17 @@ type Captcha struct {
SubType string `json:"subType"`
}
// this API is used by "Api URL" of Flarum's FoF Passport plugin
// https://github.com/FriendsOfFlarum/passport
type LaravelResponse struct {
Id string `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
EmailVerifiedAt string `json:"email_verified_at"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
// Signup
// @Tag Login API
// @Title Signup
@ -82,6 +97,10 @@ func (c *ApiController) Signup() {
c.ResponseError(err.Error())
return
}
if application == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), authForm.Application))
return
}
if !application.EnableSignUp {
c.ResponseError(c.T("account:The application does not allow to sign up new account"))
@ -94,24 +113,61 @@ func (c *ApiController) Signup() {
return
}
if organization == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:The organization: %s does not exist"), authForm.Organization))
return
}
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
err = object.CheckEntryIp(clientIp, nil, application, organization, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
}
msg := object.CheckUserSignup(application, organization, &authForm, c.GetAcceptLanguage())
if msg != "" {
c.ResponseError(msg)
return
}
invitation, msg := object.CheckInvitationCode(application, organization, &authForm, c.GetAcceptLanguage())
if msg != "" {
c.ResponseError(msg)
return
}
invitationName := ""
if invitation != nil {
invitationName = invitation.Name
}
userEmailVerified := false
if application.IsSignupItemVisible("Email") && application.GetSignupItemRule("Email") != "No verification" && authForm.Email != "" {
checkResult := object.CheckVerificationCode(authForm.Email, authForm.EmailCode, c.GetAcceptLanguage())
var checkResult *object.VerifyResult
checkResult, err = object.CheckVerificationCode(authForm.Email, authForm.EmailCode, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(c.T(err.Error()))
return
}
if checkResult.Code != object.VerificationSuccess {
c.ResponseError(checkResult.Msg)
return
}
userEmailVerified = true
}
var checkPhone string
if application.IsSignupItemVisible("Phone") && application.GetSignupItemRule("Phone") != "No verification" && authForm.Phone != "" {
checkPhone, _ = util.GetE164Number(authForm.Phone, authForm.CountryCode)
checkResult := object.CheckVerificationCode(checkPhone, authForm.PhoneCode, c.GetAcceptLanguage())
var checkResult *object.VerifyResult
checkResult, err = object.CheckVerificationCode(checkPhone, authForm.PhoneCode, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(c.T(err.Error()))
return
}
if checkResult.Code != object.VerificationSuccess {
c.ResponseError(checkResult.Msg)
return
@ -126,7 +182,11 @@ func (c *ApiController) Signup() {
username := authForm.Username
if !application.IsSignupItemVisible("Username") {
username = id
if organization.UseEmailAsUsername && application.IsSignupItemVisible("Email") {
username = authForm.Email
} else {
username = id
}
}
initScore, err := organization.GetInitScore()
@ -153,6 +213,10 @@ func (c *ApiController) Signup() {
Type: userType,
Password: authForm.Password,
DisplayName: authForm.Name,
Gender: authForm.Gender,
Bio: authForm.Bio,
Tag: authForm.Tag,
Education: authForm.Education,
Avatar: organization.DefaultAvatar,
Email: authForm.Email,
Phone: authForm.Phone,
@ -168,6 +232,9 @@ func (c *ApiController) Signup() {
SignupApplication: application.Name,
Properties: map[string]string{},
Karma: 0,
Invitation: invitationName,
InvitationCode: authForm.InvitationCode,
EmailVerified: userEmailVerified,
}
if len(organization.Tags) > 0 {
@ -185,7 +252,15 @@ func (c *ApiController) Signup() {
}
}
affected, err := object.AddUser(user)
if invitation != nil && invitation.SignupGroup != "" {
user.Groups = []string{invitation.SignupGroup}
}
if application.DefaultGroup != "" && user.Groups == nil {
user.Groups = []string{application.DefaultGroup}
}
affected, err := object.AddUser(user, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
@ -202,27 +277,38 @@ func (c *ApiController) Signup() {
return
}
if invitation != nil {
invitation.UsedCount += 1
_, err := object.UpdateInvitation(invitation.GetId(), invitation, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
}
}
if application.HasPromptPage() && user.Type == "normal-user" {
// The prompt page needs the user to be signed in
c.SetSessionUsername(user.GetId())
}
err = object.DisableVerificationCode(authForm.Email)
if err != nil {
c.ResponseError(err.Error())
return
if authForm.Email != "" {
err = object.DisableVerificationCode(authForm.Email)
if err != nil {
c.ResponseError(err.Error())
return
}
}
err = object.DisableVerificationCode(checkPhone)
if err != nil {
c.ResponseError(err.Error())
return
if checkPhone != "" {
err = object.DisableVerificationCode(checkPhone)
if err != nil {
c.ResponseError(err.Error())
return
}
}
record := object.NewRecord(c.Ctx)
record.Organization = application.Organization
record.User = user.Name
util.SafeGoroutine(func() { object.AddRecord(record) })
c.Ctx.Input.SetParam("recordUserId", user.GetId())
c.Ctx.Input.SetParam("recordSignup", "true")
userId := user.GetId()
util.LogInfo(c.Ctx, "API: [%s] is signed up as new user", userId)
@ -238,7 +324,7 @@ func (c *ApiController) Signup() {
// @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
// @router /logout [get,post]
// @router /logout [post]
func (c *ApiController) Logout() {
// https://openid.net/specs/openid-connect-rpinitiated-1_0-final.html
accessToken := c.Input().Get("id_token_hint")
@ -255,6 +341,7 @@ func (c *ApiController) Logout() {
}
c.ClearUserSession()
c.ClearTokenSession()
owner, username := util.GetOwnerAndNameFromId(user)
_, err := object.DeleteSessionId(util.GetSessionId(owner, username, object.CasdoorApplication), c.Ctx.Input.CruSession.SessionID())
if err != nil {
@ -282,17 +369,15 @@ func (c *ApiController) Logout() {
return
}
affected, application, token, err := object.ExpireTokenByAccessToken(accessToken)
_, application, token, err := object.ExpireTokenByAccessToken(accessToken)
if err != nil {
c.ResponseError(err.Error())
return
}
if !affected {
if token == nil {
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
@ -303,6 +388,7 @@ func (c *ApiController) Logout() {
}
c.ClearUserSession()
c.ClearTokenSession()
// TODO https://github.com/casdoor/casdoor/pull/1494#discussion_r1095675265
owner, username := util.GetOwnerAndNameFromId(user)
@ -319,7 +405,15 @@ func (c *ApiController) Logout() {
return
} else {
if application.IsRedirectUriValid(redirectUri) {
c.Ctx.Redirect(http.StatusFound, fmt.Sprintf("%s?state=%s", strings.TrimRight(redirectUri, "/"), state))
redirectUrl := redirectUri
if state != "" {
if strings.Contains(redirectUri, "?") {
redirectUrl = fmt.Sprintf("%s&state=%s", strings.TrimSuffix(redirectUri, "/"), state)
} else {
redirectUrl = fmt.Sprintf("%s?state=%s", strings.TrimSuffix(redirectUri, "/"), state)
}
}
c.Ctx.Redirect(http.StatusFound, redirectUrl)
} else {
c.ResponseError(fmt.Sprintf(c.T("token:Redirect URI: %s doesn't exist in the allowed Redirect URI list"), redirectUri))
return
@ -375,6 +469,21 @@ func (c *ApiController) GetAccount() {
return
}
if organization != nil && len(organization.CountryCodes) == 1 && u != nil && u.CountryCode == "" {
u.CountryCode = organization.CountryCodes[0]
}
accessToken := c.GetSessionToken()
if accessToken == "" {
accessToken, err = object.GetAccessTokenByUser(user, c.Ctx.Request.Host)
if err != nil {
c.ResponseError(err.Error())
return
}
c.SetSessionToken(accessToken)
}
u.AccessToken = accessToken
resp := Response{
Status: "ok",
Sub: user.Id,
@ -401,7 +510,12 @@ func (c *ApiController) GetUserinfo() {
scope, aud := c.GetSessionOidc()
host := c.Ctx.Request.Host
userInfo := object.GetUserInfo(user, scope, aud, host)
userInfo, err := object.GetUserInfo(user, scope, aud, host)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = userInfo
c.ServeJSON()
@ -412,7 +526,7 @@ func (c *ApiController) GetUserinfo() {
// @Title UserInfo2
// @Tag Account API
// @Description return Laravel compatible user information according to OAuth 2.0
// @Success 200 {object} LaravelResponse The Response object
// @Success 200 {object} controllers.LaravelResponse The Response object
// @router /user [get]
func (c *ApiController) GetUserinfo2() {
user, ok := c.RequireSignedInUser()
@ -420,17 +534,6 @@ func (c *ApiController) GetUserinfo2() {
return
}
// this API is used by "Api URL" of Flarum's FoF Passport plugin
// https://github.com/FriendsOfFlarum/passport
type LaravelResponse struct {
Id string `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
EmailVerifiedAt string `json:"email_verified_at"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
response := LaravelResponse{
Id: user.Id,
Name: user.Name,
@ -447,7 +550,8 @@ func (c *ApiController) GetUserinfo2() {
// GetCaptcha ...
// @Tag Login API
// @Title GetCaptcha
// @router /api/get-captcha [get]
// @router /get-captcha [get]
// @Success 200 {object} object.Userinfo The Response object
func (c *ApiController) GetCaptcha() {
applicationId := c.Input().Get("applicationId")
isCurrentProvider := c.Input().Get("isCurrentProvider")
@ -466,14 +570,16 @@ func (c *ApiController) GetCaptcha() {
return
}
c.ResponseOk(Captcha{Type: captchaProvider.Type, CaptchaId: id, CaptchaImage: img})
c.ResponseOk(Captcha{Owner: captchaProvider.Owner, Name: captchaProvider.Name, Type: captchaProvider.Type, CaptchaId: id, CaptchaImage: img})
return
} else if captchaProvider.Type != "" {
c.ResponseOk(Captcha{
Owner: captchaProvider.Owner,
Name: captchaProvider.Name,
Type: captchaProvider.Type,
SubType: captchaProvider.SubType,
ClientId: captchaProvider.ClientId,
ClientSecret: captchaProvider.ClientSecret,
ClientSecret: "***",
ClientId2: captchaProvider.ClientId2,
ClientSecret2: captchaProvider.ClientSecret2,
})

View File

@ -110,6 +110,9 @@ func (c *ApiController) GetApplication() {
}
}
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
object.CheckEntryIp(clientIp, nil, application, nil, c.GetAcceptLanguage())
c.ResponseOk(object.GetMaskedApplication(application, userId))
}
@ -139,6 +142,10 @@ func (c *ApiController) GetUserApplication() {
c.ResponseError(err.Error())
return
}
if application == nil {
c.ResponseError(fmt.Sprintf(c.T("general:The organization: %s should have one application at least"), user.Owner))
return
}
c.ResponseOk(object.GetMaskedApplication(application, userId))
}
@ -173,7 +180,7 @@ func (c *ApiController) GetOrganizationApplications() {
return
}
applications, err = object.GetAllowedApplications(applications, userId)
applications, err = object.GetAllowedApplications(applications, userId, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
@ -190,13 +197,19 @@ func (c *ApiController) GetOrganizationApplications() {
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
application, err := object.GetPaginationOrganizationApplications(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
applications, err := object.GetPaginationOrganizationApplications(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
return
}
applications := object.GetMaskedApplications(application, userId)
applications, err = object.GetAllowedApplications(applications, userId, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
}
applications = object.GetMaskedApplications(applications, userId)
c.ResponseOk(applications, paginator.Nums())
}
}
@ -219,6 +232,11 @@ func (c *ApiController) UpdateApplication() {
return
}
if err = object.CheckIpWhitelist(application.IpWhitelist, c.GetAcceptLanguage()); err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateApplication(id, &application))
c.ServeJSON()
}
@ -249,6 +267,11 @@ func (c *ApiController) AddApplication() {
return
}
if err = object.CheckIpWhitelist(application.IpWhitelist, c.GetAcceptLanguage()); err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddApplication(&application))
c.ServeJSON()
}

View File

@ -19,16 +19,18 @@ import (
"encoding/json"
"encoding/xml"
"fmt"
"io/ioutil"
"io"
"net/http"
"net/url"
"regexp"
"strconv"
"strings"
"sync"
"time"
"github.com/casdoor/casdoor/captcha"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/form"
"github.com/casdoor/casdoor/i18n"
"github.com/casdoor/casdoor/idp"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/proxy"
@ -37,11 +39,6 @@ import (
"golang.org/x/oauth2"
)
var (
wechatScanType string
lock sync.RWMutex
)
func codeToResponse(code *object.Code) *Response {
if code.Code == "" {
return &Response{Status: "error", Msg: code.Message, Data: code.Code}
@ -59,8 +56,20 @@ func tokenToResponse(token *object.Token) *Response {
// HandleLoggedIn ...
func (c *ApiController) HandleLoggedIn(application *object.Application, user *object.User, form *form.AuthForm) (resp *Response) {
if user.IsForbidden {
c.ResponseError(c.T("check:The user is forbidden to sign in, please contact the administrator"))
return
}
userId := user.GetId()
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
err := object.CheckEntryIp(clientIp, user, application, application.OrganizationObj, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
}
allowed, err := object.CheckLoginPermission(userId, application)
if err != nil {
c.ResponseError(err.Error(), nil)
@ -123,7 +132,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
if form.Type == ResponseTypeLogin {
c.SetSessionUsername(userId)
util.LogInfo(c.Ctx, "API: [%s] signed in", userId)
resp = &Response{Status: "ok", Msg: "", Data: userId}
resp = &Response{Status: "ok", Msg: "", Data: userId, Data3: user.NeedUpdatePassword}
} else if form.Type == ResponseTypeCode {
clientId := c.Input().Get("clientId")
responseType := c.Input().Get("responseType")
@ -138,14 +147,14 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
c.ResponseError(c.T("auth:Challenge method should be S256"))
return
}
code, err := object.GetOAuthCode(userId, clientId, responseType, redirectUri, scope, state, nonce, codeChallenge, c.Ctx.Request.Host, c.GetAcceptLanguage())
code, err := object.GetOAuthCode(userId, clientId, form.Provider, responseType, redirectUri, scope, state, nonce, codeChallenge, c.Ctx.Request.Host, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error(), nil)
return
}
resp = codeToResponse(code)
resp.Data3 = user.NeedUpdatePassword
if application.EnableSigninSession || application.HasPromptPage() {
// The prompt page needs the user to be signed in
c.SetSessionUsername(userId)
@ -155,16 +164,45 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
resp = &Response{Status: "error", Msg: fmt.Sprintf("error: grant_type: %s is not supported in this application", form.Type), Data: ""}
} else {
scope := c.Input().Get("scope")
token, _ := object.GetTokenByUser(application, user, scope, c.Ctx.Request.Host)
nonce := c.Input().Get("nonce")
token, _ := object.GetTokenByUser(application, user, scope, nonce, c.Ctx.Request.Host)
resp = tokenToResponse(token)
resp.Data3 = user.NeedUpdatePassword
}
} else if form.Type == ResponseTypeDevice {
authCache, ok := object.DeviceAuthMap.LoadAndDelete(form.UserCode)
if !ok {
c.ResponseError(c.T("auth:UserCode Expired"))
return
}
authCacheCast := authCache.(object.DeviceAuthCache)
if authCacheCast.RequestAt.Add(time.Second * 120).Before(time.Now()) {
c.ResponseError(c.T("auth:UserCode Expired"))
return
}
deviceAuthCacheDeviceCode, ok := object.DeviceAuthMap.Load(authCacheCast.UserName)
if !ok {
c.ResponseError(c.T("auth:DeviceCode Invalid"))
return
}
deviceAuthCacheDeviceCodeCast := deviceAuthCacheDeviceCode.(object.DeviceAuthCache)
deviceAuthCacheDeviceCodeCast.UserName = user.Name
deviceAuthCacheDeviceCodeCast.UserSignIn = true
object.DeviceAuthMap.Store(authCacheCast.UserName, deviceAuthCacheDeviceCodeCast)
resp = &Response{Status: "ok", Msg: "", Data: userId, Data3: user.NeedUpdatePassword}
} else if form.Type == ResponseTypeSaml { // saml flow
res, redirectUrl, method, err := object.GetSamlResponse(application, user, form.SamlRequest, c.Ctx.Request.Host)
if err != nil {
c.ResponseError(err.Error(), nil)
return
}
resp = &Response{Status: "ok", Msg: "", Data: res, Data2: map[string]string{"redirectUrl": redirectUrl, "method": method}}
resp = &Response{Status: "ok", Msg: "", Data: res, Data2: map[string]interface{}{"redirectUrl": redirectUrl, "method": method}, Data3: user.NeedUpdatePassword}
if application.EnableSigninSession || application.HasPromptPage() {
// The prompt page needs the user to be signed in
@ -221,7 +259,7 @@ func (c *ApiController) HandleLoggedIn(application *object.Application, user *ob
// @Param redirectUri query string true "redirect uri"
// @Param scope query string true "scope"
// @Param state query string true "state"
// @Success 200 {object} Response The Response object
// @Success 200 {object} controllers.Response The Response object
// @router /get-app-login [get]
func (c *ApiController) GetApplicationLogin() {
clientId := c.Input().Get("clientId")
@ -231,6 +269,7 @@ func (c *ApiController) GetApplicationLogin() {
state := c.Input().Get("state")
id := c.Input().Get("id")
loginType := c.Input().Get("type")
userCode := c.Input().Get("userCode")
var application *object.Application
var msg string
@ -257,8 +296,24 @@ func (c *ApiController) GetApplicationLogin() {
c.ResponseError(err.Error())
return
}
} else if loginType == "device" {
deviceAuthCache, ok := object.DeviceAuthMap.Load(userCode)
if !ok {
c.ResponseError(c.T("auth:UserCode Invalid"))
return
}
deviceAuthCacheCast := deviceAuthCache.(object.DeviceAuthCache)
application, err = object.GetApplication(deviceAuthCacheCast.ApplicationId)
if err != nil {
c.ResponseError(err.Error())
return
}
}
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
object.CheckEntryIp(clientIp, nil, application, nil, c.GetAcceptLanguage())
application = object.GetMaskedApplication(application, "")
if msg != "" {
c.ResponseError(msg, application)
@ -298,6 +353,35 @@ func isProxyProviderType(providerType string) bool {
return false
}
func checkMfaEnable(c *ApiController, user *object.User, organization *object.Organization, verificationType string) bool {
if object.IsNeedPromptMfa(organization, user) {
// The prompt page needs the user to be srigned in
c.SetSessionUsername(user.GetId())
c.ResponseOk(object.RequiredMfa)
return true
}
if user.IsMfaEnabled() {
c.setMfaUserSession(user.GetId())
mfaList := object.GetAllMfaProps(user, true)
mfaAllowList := []*object.MfaProps{}
for _, prop := range mfaList {
if prop.MfaType == verificationType || !prop.Enabled {
continue
}
mfaAllowList = append(mfaAllowList, prop)
}
if len(mfaAllowList) >= 1 {
c.SetSession("verificationCodeType", verificationType)
c.Ctx.Input.CruSession.SessionRelease(c.Ctx.ResponseWriter)
c.ResponseOk(object.NextMfa, mfaAllowList)
return true
}
}
return false
}
// Login ...
// @Title Login
// @Tag Login API
@ -323,6 +407,8 @@ func (c *ApiController) Login() {
return
}
verificationType := ""
if authForm.Username != "" {
if authForm.Type == ResponseTypeLogin {
if c.GetSessionUsername() != "" {
@ -332,7 +418,7 @@ func (c *ApiController) Login() {
}
var user *object.User
if authForm.Password == "" {
if authForm.SigninMethod == "Face ID" {
if user, err = object.GetUserByFields(authForm.Organization, authForm.Username); err != nil {
c.ResponseError(err.Error(), nil)
return
@ -341,7 +427,75 @@ func (c *ApiController) Login() {
return
}
var application *object.Application
application, err = object.GetApplication(fmt.Sprintf("admin/%s", authForm.Application))
if err != nil {
c.ResponseError(err.Error(), nil)
return
}
if application == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), authForm.Application))
return
}
if !application.IsFaceIdEnabled() {
c.ResponseError(c.T("auth:The login method: login with face is not enabled for the application"))
return
}
faceIdProvider, err := object.GetFaceIdProviderByApplication(util.GetId(application.Owner, application.Name), "false", c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
}
if faceIdProvider == nil {
if err := object.CheckFaceId(user, authForm.FaceId, c.GetAcceptLanguage()); err != nil {
c.ResponseError(err.Error(), nil)
return
}
} else {
ok, err := user.CheckUserFace(authForm.FaceIdImage, faceIdProvider)
if err != nil {
c.ResponseError(err.Error(), nil)
}
if !ok {
c.ResponseError(i18n.Translate(c.GetAcceptLanguage(), "check:Face data does not exist, cannot log in"))
return
}
}
} else if authForm.Password == "" {
if user, err = object.GetUserByFields(authForm.Organization, authForm.Username); err != nil {
c.ResponseError(err.Error(), nil)
return
} else if user == nil {
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(authForm.Organization, authForm.Username)))
return
}
var application *object.Application
application, err = object.GetApplication(fmt.Sprintf("admin/%s", authForm.Application))
if err != nil {
c.ResponseError(err.Error(), nil)
return
}
if application == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), authForm.Application))
return
}
verificationCodeType := object.GetVerifyType(authForm.Username)
if verificationCodeType == object.VerifyTypeEmail && !application.IsCodeSigninViaEmailEnabled() {
c.ResponseError(c.T("auth:The login method: login with email is not enabled for the application"))
return
}
if verificationCodeType == object.VerifyTypePhone && !application.IsCodeSigninViaSmsEnabled() {
c.ResponseError(c.T("auth:The login method: login with SMS is not enabled for the application"))
return
}
var checkDest string
if verificationCodeType == object.VerifyTypePhone {
authForm.CountryCode = user.GetCountryCode(authForm.CountryCode)
@ -350,6 +504,8 @@ func (c *ApiController) Login() {
c.ResponseError(fmt.Sprintf(c.T("verification:Phone number is invalid in your region %s"), authForm.CountryCode))
return
}
} else if verificationCodeType == object.VerifyTypeEmail {
checkDest = authForm.Username
}
// check result through Email or Phone
@ -365,6 +521,20 @@ func (c *ApiController) Login() {
c.ResponseError(err.Error(), nil)
return
}
if verificationCodeType == object.VerifyTypePhone {
verificationType = "sms"
} else {
verificationType = "email"
if !user.EmailVerified {
user.EmailVerified = true
_, err = object.UpdateUser(user.GetId(), user, []string{"email_verified"}, false)
if err != nil {
c.ResponseError(err.Error(), nil)
return
}
}
}
} else {
var application *object.Application
application, err = object.GetApplication(fmt.Sprintf("admin/%s", authForm.Application))
@ -377,17 +547,34 @@ func (c *ApiController) Login() {
c.ResponseError(fmt.Sprintf(c.T("auth:The application: %s does not exist"), authForm.Application))
return
}
if !application.EnablePassword {
if authForm.SigninMethod == "Password" && !application.IsPasswordEnabled() {
c.ResponseError(c.T("auth:The login method: login with password is not enabled for the application"))
return
}
if authForm.SigninMethod == "LDAP" && !application.IsLdapEnabled() {
c.ResponseError(c.T("auth:The login method: login with LDAP is not enabled for the application"))
return
}
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
var enableCaptcha bool
if enableCaptcha, err = object.CheckToEnableCaptcha(application, authForm.Organization, authForm.Username); err != nil {
if enableCaptcha, err = object.CheckToEnableCaptcha(application, authForm.Organization, authForm.Username, clientIp); err != nil {
c.ResponseError(err.Error())
return
} else if enableCaptcha {
captchaProvider, err := object.GetCaptchaProviderByApplication(util.GetId(application.Owner, application.Name), "false", c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
}
if captchaProvider.Type != "Default" {
authForm.ClientSecret = captchaProvider.ClientSecret
}
var isHuman bool
isHuman, err = captcha.VerifyCaptchaByCaptchaType(authForm.CaptchaType, authForm.CaptchaToken, authForm.ClientSecret)
isHuman, err = captcha.VerifyCaptchaByCaptchaType(authForm.CaptchaType, authForm.CaptchaToken, captchaProvider.ClientId, authForm.ClientSecret, captchaProvider.ClientId2)
if err != nil {
c.ResponseError(err.Error())
return
@ -400,7 +587,23 @@ func (c *ApiController) Login() {
}
password := authForm.Password
user, err = object.CheckUserPassword(authForm.Organization, authForm.Username, password, c.GetAcceptLanguage(), enableCaptcha)
if application.OrganizationObj != nil {
password, err = util.GetUnobfuscatedPassword(application.OrganizationObj.PasswordObfuscatorType, application.OrganizationObj.PasswordObfuscatorKey, authForm.Password)
if err != nil {
c.ResponseError(err.Error())
return
}
}
isSigninViaLdap := authForm.SigninMethod == "LDAP"
var isPasswordWithLdapEnabled bool
if authForm.SigninMethod == "Password" {
isPasswordWithLdapEnabled = application.IsPasswordWithLdapEnabled()
} else {
isPasswordWithLdapEnabled = false
}
user, err = object.CheckUserPassword(authForm.Organization, authForm.Username, password, c.GetAcceptLanguage(), enableCaptcha, isSigninViaLdap, isPasswordWithLdapEnabled)
}
if err != nil {
@ -425,25 +628,13 @@ func (c *ApiController) Login() {
c.ResponseError(err.Error())
}
if object.IsNeedPromptMfa(organization, user) {
// The prompt page needs the user to be signed in
c.SetSessionUsername(user.GetId())
c.ResponseOk(object.RequiredMfa)
return
}
if user.IsMfaEnabled() {
c.setMfaUserSession(user.GetId())
c.ResponseOk(object.NextMfa, user.GetPreferredMfaProps(true))
if checkMfaEnable(c, user, organization, verificationType) {
return
}
resp = c.HandleLoggedIn(application, user, &authForm)
record := object.NewRecord(c.Ctx)
record.Organization = application.Organization
record.User = user.Name
util.SafeGoroutine(func() { object.AddRecord(record) })
c.Ctx.Input.SetParam("recordUserId", user.GetId())
}
} else if authForm.Provider != "" {
var application *object.Application
@ -478,6 +669,9 @@ func (c *ApiController) Login() {
c.ResponseError(err.Error())
return
}
if provider == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:The provider: %s does not exist"), authForm.Provider))
}
providerItem := application.GetProviderItem(provider.Name)
if !providerItem.IsProviderVisible() {
@ -531,6 +725,17 @@ func (c *ApiController) Login() {
c.ResponseError(fmt.Sprintf(c.T("auth:Failed to login in: %s"), err.Error()))
return
}
if provider.EmailRegex != "" {
reg, err := regexp.Compile(provider.EmailRegex)
if err != nil {
c.ResponseError(fmt.Sprintf(c.T("auth:Failed to login in: %s"), err.Error()))
return
}
if !reg.MatchString(userInfo.Email) {
c.ResponseError(fmt.Sprintf(c.T("check:Email is invalid")))
}
}
}
if authForm.Method == "signup" {
@ -552,22 +757,20 @@ func (c *ApiController) Login() {
if user != nil && !user.IsDeleted {
// Sign in via OAuth (want to sign up but already have account)
if user.IsForbidden {
c.ResponseError(c.T("check:The user is forbidden to sign in, please contact the administrator"))
}
// sync info from 3rd-party if possible
_, err = object.SetUserOAuthProperties(organization, user, provider.Type, userInfo)
if err != nil {
c.ResponseError(err.Error())
return
}
if checkMfaEnable(c, user, organization, verificationType) {
return
}
resp = c.HandleLoggedIn(application, user, &authForm)
record := object.NewRecord(c.Ctx)
record.Organization = application.Organization
record.User = user.Name
util.SafeGoroutine(func() { object.AddRecord(record) })
c.Ctx.Input.SetParam("recordUserId", user.GetId())
} else if provider.Category == "OAuth" || provider.Category == "Web3" {
// Sign up via OAuth
if application.EnableLinkWithEmail {
@ -601,6 +804,11 @@ func (c *ApiController) Login() {
return
}
if application.IsSignupItemRequired("Invitation code") {
c.ResponseError(c.T("check:Invitation code cannot be blank"))
return
}
// Handle username conflicts
var tmpUser *object.User
tmpUser, err = object.GetUser(util.GetId(application.Organization, userInfo.Username))
@ -664,7 +872,7 @@ func (c *ApiController) Login() {
}
var affected bool
affected, err = object.AddUser(user)
affected, err = object.AddUser(user, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
@ -700,16 +908,8 @@ func (c *ApiController) Login() {
resp = c.HandleLoggedIn(application, user, &authForm)
record := object.NewRecord(c.Ctx)
record.Organization = application.Organization
record.User = user.Name
util.SafeGoroutine(func() { object.AddRecord(record) })
record2 := object.NewRecord(c.Ctx)
record2.Action = "signup"
record2.Organization = application.Organization
record2.User = user.Name
util.SafeGoroutine(func() { object.AddRecord(record2) })
c.Ctx.Input.SetParam("recordUserId", user.GetId())
c.Ctx.Input.SetParam("recordSignup", "true")
} else if provider.Category == "SAML" {
// TODO: since we get the user info from SAML response, we can try to create the user
resp = &Response{Status: "error", Msg: fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(application.Organization, userInfo.Id))}
@ -774,17 +974,32 @@ func (c *ApiController) Login() {
}
if authForm.Passcode != "" {
mfaUtil := object.GetMfaUtil(authForm.MfaType, user.GetPreferredMfaProps(false))
if authForm.MfaType == c.GetSession("verificationCodeType") {
c.ResponseError("Invalid multi-factor authentication type")
return
}
user.CountryCode = user.GetCountryCode(user.CountryCode)
mfaUtil := object.GetMfaUtil(authForm.MfaType, user.GetMfaProps(authForm.MfaType, false))
if mfaUtil == nil {
c.ResponseError("Invalid multi-factor authentication type")
return
}
err = mfaUtil.Verify(authForm.Passcode)
passed, err := c.checkOrgMasterVerificationCode(user, authForm.Passcode)
if err != nil {
c.ResponseError(err.Error())
return
}
if !passed {
err = mfaUtil.Verify(authForm.Passcode)
if err != nil {
c.ResponseError(err.Error())
return
}
}
c.SetSession("verificationCodeType", "")
} else if authForm.RecoveryCode != "" {
err = object.MfaRecover(user, authForm.RecoveryCode)
if err != nil {
@ -797,7 +1012,11 @@ func (c *ApiController) Login() {
}
var application *object.Application
application, err = object.GetApplication(fmt.Sprintf("admin/%s", authForm.Application))
if authForm.ClientId == "" {
application, err = object.GetApplication(fmt.Sprintf("admin/%s", authForm.Application))
} else {
application, err = object.GetApplicationByClientId(authForm.ClientId)
}
if err != nil {
c.ResponseError(err.Error())
return
@ -811,10 +1030,7 @@ func (c *ApiController) Login() {
resp = c.HandleLoggedIn(application, user, &authForm)
c.setMfaUserSession("")
record := object.NewRecord(c.Ctx)
record.Organization = application.Organization
record.User = user.Name
util.SafeGoroutine(func() { object.AddRecord(record) })
c.Ctx.Input.SetParam("recordUserId", user.GetId())
} else {
if c.GetSessionUsername() != "" {
// user already signed in to Casdoor, so let the user click the avatar button to do the quick sign-in
@ -830,19 +1046,32 @@ func (c *ApiController) Login() {
return
}
if authForm.Provider == "" {
authForm.Provider = authForm.ProviderBack
}
user := c.getCurrentUser()
resp = c.HandleLoggedIn(application, user, &authForm)
record := object.NewRecord(c.Ctx)
record.Organization = application.Organization
record.User = user.Name
util.SafeGoroutine(func() { object.AddRecord(record) })
c.Ctx.Input.SetParam("recordUserId", user.GetId())
} else {
c.ResponseError(fmt.Sprintf(c.T("auth:Unknown authentication type (not password or provider), form = %s"), util.StructToJson(authForm)))
return
}
}
if authForm.Language != "" {
user := c.getCurrentUser()
if user != nil {
user.Language = authForm.Language
_, err = object.UpdateUser(user.GetId(), user, []string{"language"}, user.IsAdmin)
if err != nil {
c.ResponseError(err.Error())
return
}
}
}
c.Data["json"] = resp
c.ServeJSON()
}
@ -853,6 +1082,7 @@ func (c *ApiController) GetSamlLogin() {
authURL, method, err := object.GenerateSamlRequest(providerId, relayState, c.Ctx.Request.Host, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(authURL, method)
}
@ -863,60 +1093,126 @@ func (c *ApiController) HandleSamlLogin() {
decode, err := base64.StdEncoding.DecodeString(relayState)
if err != nil {
c.ResponseError(err.Error())
return
}
slice := strings.Split(string(decode), "&")
relayState = url.QueryEscape(relayState)
samlResponse = url.QueryEscape(samlResponse)
targetUrl := fmt.Sprintf("%s?relayState=%s&samlResponse=%s",
slice[4], relayState, samlResponse)
c.Redirect(targetUrl, 303)
c.Redirect(targetUrl, http.StatusSeeOther)
}
// HandleOfficialAccountEvent ...
// @Tag HandleOfficialAccountEvent API
// @Tag System API
// @Title HandleOfficialAccountEvent
// @router /api/webhook [POST]
// @router /webhook [POST]
// @Success 200 {object} controllers.Response The Response object
func (c *ApiController) HandleOfficialAccountEvent() {
respBytes, err := ioutil.ReadAll(c.Ctx.Request.Body)
if c.Ctx.Request.Method == "GET" {
s := c.Ctx.Request.FormValue("echostr")
echostr, _ := strconv.Atoi(s)
c.SetData(echostr)
c.ServeJSON()
return
}
respBytes, err := io.ReadAll(c.Ctx.Request.Body)
if err != nil {
c.ResponseError(err.Error())
return
}
signature := c.Input().Get("signature")
timestamp := c.Input().Get("timestamp")
nonce := c.Input().Get("nonce")
var data struct {
MsgType string `xml:"MsgType"`
Event string `xml:"Event"`
EventKey string `xml:"EventKey"`
MsgType string `xml:"MsgType"`
Event string `xml:"Event"`
EventKey string `xml:"EventKey"`
FromUserName string `xml:"FromUserName"`
Ticket string `xml:"Ticket"`
}
err = xml.Unmarshal(respBytes, &data)
if err != nil {
c.ResponseError(err.Error())
return
}
lock.Lock()
defer lock.Unlock()
if data.EventKey != "" {
wechatScanType = data.Event
if strings.ToUpper(data.Event) != "SCAN" && strings.ToUpper(data.Event) != "SUBSCRIBE" {
c.Ctx.WriteString("")
return
}
if data.Ticket == "" {
c.ResponseError(err.Error())
return
}
providerId := data.EventKey
provider, err := object.GetProvider(providerId)
if err != nil {
c.ResponseError(err.Error())
return
}
if data.Ticket == "" {
c.ResponseError("empty ticket")
return
}
if !idp.VerifyWechatSignature(provider.Content, nonce, timestamp, signature) {
c.ResponseError("invalid signature")
return
}
idp.Lock.Lock()
if idp.WechatCacheMap == nil {
idp.WechatCacheMap = make(map[string]idp.WechatCacheMapValue)
}
idp.WechatCacheMap[data.Ticket] = idp.WechatCacheMapValue{
IsScanned: true,
WechatUnionId: data.FromUserName,
}
idp.Lock.Unlock()
c.Ctx.WriteString("")
}
// GetWebhookEventType ...
// @Tag GetWebhookEventType API
// @Tag System API
// @Title GetWebhookEventType
// @router /api/get-webhook-event [GET]
// @router /get-webhook-event [GET]
// @Param ticket query string true "The eventId of QRCode"
// @Success 200 {object} controllers.Response The Response object
func (c *ApiController) GetWebhookEventType() {
lock.Lock()
defer lock.Unlock()
resp := &Response{
Status: "ok",
Msg: "",
Data: wechatScanType,
ticket := c.Input().Get("ticket")
idp.Lock.RLock()
_, ok := idp.WechatCacheMap[ticket]
idp.Lock.RUnlock()
if !ok {
c.ResponseError("ticket not found")
return
}
c.Data["json"] = resp
wechatScanType = ""
c.ServeJSON()
c.ResponseOk("SCAN", ticket)
}
// GetQRCode
// @Tag System API
// @Title GetWechatQRCode
// @router /get-qrcode [GET]
// @Param id query string true "The id ( owner/name ) of provider"
// @Success 200 {object} controllers.Response The Response object
func (c *ApiController) GetQRCode() {
providerId := c.Input().Get("id")
provider, err := object.GetProvider(providerId)
if err != nil {
c.ResponseError(err.Error())
return
}
code, ticket, err := idp.GetWechatOfficialAccountQRCode(provider.ClientId2, provider.ClientSecret2, providerId)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(code, ticket)
}
// GetCaptchaStatus
@ -925,28 +1221,38 @@ func (c *ApiController) GetWebhookEventType() {
// @Description Get Login Error Counts
// @Param id query string true "The id ( owner/name ) of user"
// @Success 200 {object} controllers.Response The Response object
// @router /api/get-captcha-status [get]
// @router /get-captcha-status [get]
func (c *ApiController) GetCaptchaStatus() {
organization := c.Input().Get("organization")
userId := c.Input().Get("user_id")
user, err := object.GetUserByFields(organization, userId)
userId := c.Input().Get("userId")
applicationName := c.Input().Get("application")
application, err := object.GetApplication(fmt.Sprintf("admin/%s", applicationName))
if err != nil {
c.ResponseError(err.Error())
return
}
if application == nil {
c.ResponseError("application not found")
return
}
var captchaEnabled bool
if user != nil && user.SigninWrongTimes >= object.SigninWrongTimesLimit {
captchaEnabled = true
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
captchaEnabled, err := object.CheckToEnableCaptcha(application, organization, userId, clientIp)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(captchaEnabled)
return
}
// Callback
// @Title Callback
// @Tag Callback API
// @Description Get Login Error Counts
// @router /api/Callback [post]
// @router /Callback [post]
// @Success 200 {object} object.Userinfo The Response object
func (c *ApiController) Callback() {
code := c.GetString("code")
state := c.GetString("state")
@ -954,3 +1260,75 @@ func (c *ApiController) Callback() {
frontendCallbackUrl := fmt.Sprintf("/callback?code=%s&state=%s", code, state)
c.Ctx.Redirect(http.StatusFound, frontendCallbackUrl)
}
// DeviceAuth
// @Title DeviceAuth
// @Tag Device Authorization Endpoint
// @Description Endpoint for the device authorization flow
// @router /device-auth [post]
// @Success 200 {object} object.DeviceAuthResponse The Response object
func (c *ApiController) DeviceAuth() {
clientId := c.Input().Get("client_id")
scope := c.Input().Get("scope")
application, err := object.GetApplicationByClientId(clientId)
if err != nil {
c.Data["json"] = object.TokenError{
Error: err.Error(),
ErrorDescription: err.Error(),
}
c.ServeJSON()
return
}
if application == nil {
c.Data["json"] = object.TokenError{
Error: c.T("token:Invalid client_id"),
ErrorDescription: c.T("token:Invalid client_id"),
}
c.ServeJSON()
return
}
deviceCode := util.GenerateId()
userCode := util.GetRandomName()
generateTime := 0
for {
if generateTime > 5 {
c.Data["json"] = object.TokenError{
Error: "userCode gen",
ErrorDescription: c.T("token:Invalid client_id"),
}
c.ServeJSON()
return
}
_, ok := object.DeviceAuthMap.Load(userCode)
if !ok {
break
}
generateTime++
}
deviceAuthCache := object.DeviceAuthCache{
UserSignIn: false,
UserName: "",
Scope: scope,
ApplicationId: application.GetId(),
RequestAt: time.Now(),
}
userAuthCache := object.DeviceAuthCache{
UserSignIn: false,
UserName: deviceCode,
Scope: scope,
ApplicationId: application.GetId(),
RequestAt: time.Now(),
}
object.DeviceAuthMap.Store(deviceCode, deviceAuthCache)
object.DeviceAuthMap.Store(userCode, userAuthCache)
c.Data["json"] = object.GetDeviceAuthResponse(deviceCode, userCode, c.Ctx.Request.Host)
c.ServeJSON()
}

View File

@ -73,7 +73,7 @@ func (c *ApiController) IsAdminOrSelf(user2 *object.User) bool {
func (c *ApiController) isGlobalAdmin() (bool, *object.User) {
username := c.GetSessionUsername()
if strings.HasPrefix(username, "app/") {
if object.IsAppUser(username) {
// e.g., "app/app-casnode"
return true, nil
}
@ -122,6 +122,15 @@ func (c *ApiController) GetSessionUsername() string {
return user.(string)
}
func (c *ApiController) GetSessionToken() string {
accessToken := c.GetSession("accessToken")
if accessToken == nil {
return ""
}
return accessToken.(string)
}
func (c *ApiController) GetSessionApplication() *object.Application {
clientId := c.GetSession("aud")
if clientId == nil {
@ -141,6 +150,10 @@ func (c *ApiController) ClearUserSession() {
c.SetSessionData(nil)
}
func (c *ApiController) ClearTokenSession() {
c.SetSessionToken("")
}
func (c *ApiController) GetSessionOidc() (string, string) {
sessionData := c.GetSessionData()
if sessionData != nil &&
@ -167,6 +180,10 @@ func (c *ApiController) SetSessionUsername(user string) {
c.SetSession("username", user)
}
func (c *ApiController) SetSessionToken(accessToken string) {
c.SetSession("accessToken", accessToken)
}
// GetSessionData ...
func (c *ApiController) GetSessionData() *SessionData {
session := c.GetSession("SessionData")

View File

@ -16,6 +16,7 @@ package controllers
import (
"encoding/json"
"fmt"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
@ -23,12 +24,13 @@ import (
// Enforce
// @Title Enforce
// @Tag Enforce API
// @Tag Enforcer API
// @Description Call Casbin Enforce API
// @Param body body object.CasbinRequest true "Casbin request"
// @Param body body []string true "Casbin request"
// @Param permissionId query string false "permission id"
// @Param modelId query string false "model id"
// @Param resourceId query string false "resource id"
// @Param owner query string false "owner"
// @Success 200 {object} controllers.Response The Response object
// @router /enforce [post]
func (c *ApiController) Enforce() {
@ -36,13 +38,14 @@ func (c *ApiController) Enforce() {
modelId := c.Input().Get("modelId")
resourceId := c.Input().Get("resourceId")
enforcerId := c.Input().Get("enforcerId")
owner := c.Input().Get("owner")
if len(c.Ctx.Input.RequestBody) == 0 {
c.ResponseError("The request body should not be empty")
return
}
var request object.CasbinRequest
var request []string
err := json.Unmarshal(c.Ctx.Input.RequestBody, &request)
if err != nil {
c.ResponseError(err.Error())
@ -56,13 +59,22 @@ func (c *ApiController) Enforce() {
return
}
res, err := enforcer.Enforce(request...)
res := []bool{}
keyRes := []string{}
// type transformation
interfaceRequest := util.StringToInterfaceArray(request)
enforceResult, err := enforcer.Enforce(interfaceRequest...)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(res)
res = append(res, enforceResult)
keyRes = append(keyRes, enforcer.GetModelAndAdapter())
c.ResponseOk(res, keyRes)
return
}
@ -72,22 +84,24 @@ func (c *ApiController) Enforce() {
c.ResponseError(err.Error())
return
}
res := []bool{}
if permission == nil {
res = append(res, false)
} else {
enforceResult, err := object.Enforce(permission, &request)
if err != nil {
c.ResponseError(err.Error())
return
}
res = append(res, enforceResult)
c.ResponseError(fmt.Sprintf(c.T("permission:The permission: \"%s\" doesn't exist"), permissionId))
return
}
c.ResponseOk(res)
res := []bool{}
keyRes := []string{}
enforceResult, err := object.Enforce(permission, request)
if err != nil {
c.ResponseError(err.Error())
return
}
res = append(res, enforceResult)
keyRes = append(keyRes, permission.GetModelAndAdapter())
c.ResponseOk(res, keyRes)
return
}
@ -105,48 +119,57 @@ func (c *ApiController) Enforce() {
c.ResponseError(err.Error())
return
}
} else if owner != "" {
permissions, err = object.GetPermissions(owner)
if err != nil {
c.ResponseError(err.Error())
return
}
} else {
c.ResponseError(c.T("general:Missing parameter"))
return
}
res := []bool{}
keyRes := []string{}
listPermissionIdMap := object.GroupPermissionsByModelAdapter(permissions)
for _, permissionIds := range listPermissionIdMap {
for key, permissionIds := range listPermissionIdMap {
firstPermission, err := object.GetPermission(permissionIds[0])
if err != nil {
c.ResponseError(err.Error())
return
}
enforceResult, err := object.Enforce(firstPermission, &request, permissionIds...)
enforceResult, err := object.Enforce(firstPermission, request, permissionIds...)
if err != nil {
c.ResponseError(err.Error())
return
}
res = append(res, enforceResult)
keyRes = append(keyRes, key)
}
c.ResponseOk(res)
c.ResponseOk(res, keyRes)
}
// BatchEnforce
// @Title BatchEnforce
// @Tag Enforce API
// @Tag Enforcer API
// @Description Call Casbin BatchEnforce API
// @Param body body object.CasbinRequest true "array of casbin requests"
// @Param body body []string true "array of casbin requests"
// @Param permissionId query string false "permission id"
// @Param modelId query string false "model id"
// @Param owner query string false "owner"
// @Success 200 {object} controllers.Response The Response object
// @router /batch-enforce [post]
func (c *ApiController) BatchEnforce() {
permissionId := c.Input().Get("permissionId")
modelId := c.Input().Get("modelId")
enforcerId := c.Input().Get("enforcerId")
owner := c.Input().Get("owner")
var requests []object.CasbinRequest
var requests [][]string
err := json.Unmarshal(c.Ctx.Input.RequestBody, &requests)
if err != nil {
c.ResponseError(err.Error())
@ -160,13 +183,22 @@ func (c *ApiController) BatchEnforce() {
return
}
res, err := enforcer.BatchEnforce(requests)
res := [][]bool{}
keyRes := []string{}
// type transformation
interfaceRequests := util.StringToInterfaceArray2d(requests)
enforceResult, err := enforcer.BatchEnforce(interfaceRequests)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(res)
res = append(res, enforceResult)
keyRes = append(keyRes, enforcer.GetModelAndAdapter())
c.ResponseOk(res, keyRes)
return
}
@ -176,28 +208,24 @@ func (c *ApiController) BatchEnforce() {
c.ResponseError(err.Error())
return
}
res := [][]bool{}
if permission == nil {
l := len(requests)
resRequest := make([]bool, l)
for i := 0; i < l; i++ {
resRequest[i] = false
}
res = append(res, resRequest)
} else {
enforceResult, err := object.BatchEnforce(permission, &requests)
if err != nil {
c.ResponseError(err.Error())
return
}
res = append(res, enforceResult)
c.ResponseError(fmt.Sprintf(c.T("permission:The permission: \"%s\" doesn't exist"), permissionId))
return
}
c.ResponseOk(res)
res := [][]bool{}
keyRes := []string{}
enforceResult, err := object.BatchEnforce(permission, requests)
if err != nil {
c.ResponseError(err.Error())
return
}
res = append(res, enforceResult)
keyRes = append(keyRes, permission.GetModelAndAdapter())
c.ResponseOk(res, keyRes)
return
}
@ -209,13 +237,19 @@ func (c *ApiController) BatchEnforce() {
c.ResponseError(err.Error())
return
}
} else if owner != "" {
permissions, err = object.GetPermissions(owner)
if err != nil {
c.ResponseError(err.Error())
return
}
} else {
c.ResponseError(c.T("general:Missing parameter"))
return
}
res := [][]bool{}
keyRes := []string{}
listPermissionIdMap := object.GroupPermissionsByModelAdapter(permissions)
for _, permissionIds := range listPermissionIdMap {
firstPermission, err := object.GetPermission(permissionIds[0])
@ -224,44 +258,72 @@ func (c *ApiController) BatchEnforce() {
return
}
enforceResult, err := object.BatchEnforce(firstPermission, &requests, permissionIds...)
enforceResult, err := object.BatchEnforce(firstPermission, requests, permissionIds...)
if err != nil {
c.ResponseError(err.Error())
return
}
res = append(res, enforceResult)
keyRes = append(keyRes, firstPermission.GetModelAndAdapter())
}
c.ResponseOk(res)
c.ResponseOk(res, keyRes)
}
func (c *ApiController) GetAllObjects() {
userId := c.GetSessionUsername()
userId := c.Input().Get("userId")
if userId == "" {
c.ResponseError(c.T("general:Please login first"))
userId = c.GetSessionUsername()
if userId == "" {
c.ResponseError(c.T("general:Please login first"))
return
}
}
objects, err := object.GetAllObjects(userId)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(object.GetAllObjects(userId))
c.ResponseOk(objects)
}
func (c *ApiController) GetAllActions() {
userId := c.GetSessionUsername()
userId := c.Input().Get("userId")
if userId == "" {
c.ResponseError(c.T("general:Please login first"))
userId = c.GetSessionUsername()
if userId == "" {
c.ResponseError(c.T("general:Please login first"))
return
}
}
actions, err := object.GetAllActions(userId)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(object.GetAllActions(userId))
c.ResponseOk(actions)
}
func (c *ApiController) GetAllRoles() {
userId := c.GetSessionUsername()
userId := c.Input().Get("userId")
if userId == "" {
c.ResponseError(c.T("general:Please login first"))
userId = c.GetSessionUsername()
if userId == "" {
c.ResponseError(c.T("general:Please login first"))
return
}
}
roles, err := object.GetAllRoles(userId)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(object.GetAllRoles(userId))
c.ResponseOk(roles)
}

View File

@ -0,0 +1,247 @@
// Copyright 2024 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 (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"os"
"os/exec"
"sort"
"strings"
"sync"
"time"
)
type CLIVersionInfo struct {
Version string
BinaryPath string
BinaryTime time.Time
}
var (
cliVersionCache = make(map[string]*CLIVersionInfo)
cliVersionMutex sync.RWMutex
)
// getCLIVersion
// @Title getCLIVersion
// @Description Get CLI version with cache mechanism
// @Param language string The language of CLI (go/java/rust etc.)
// @Return string The version string of CLI
// @Return error Error if CLI execution fails
func getCLIVersion(language string) (string, error) {
binaryName := fmt.Sprintf("casbin-%s-cli", language)
binaryPath, err := exec.LookPath(binaryName)
if err != nil {
return "", fmt.Errorf("executable file not found: %v", err)
}
fileInfo, err := os.Stat(binaryPath)
if err != nil {
return "", fmt.Errorf("failed to get binary info: %v", err)
}
cliVersionMutex.RLock()
if info, exists := cliVersionCache[language]; exists {
if info.BinaryPath == binaryPath && info.BinaryTime == fileInfo.ModTime() {
cliVersionMutex.RUnlock()
return info.Version, nil
}
}
cliVersionMutex.RUnlock()
cmd := exec.Command(binaryName, "--version")
output, err := cmd.CombinedOutput()
if err != nil {
return "", fmt.Errorf("failed to get CLI version: %v", err)
}
version := strings.TrimSpace(string(output))
cliVersionMutex.Lock()
cliVersionCache[language] = &CLIVersionInfo{
Version: version,
BinaryPath: binaryPath,
BinaryTime: fileInfo.ModTime(),
}
cliVersionMutex.Unlock()
return version, nil
}
func processArgsToTempFiles(args []string) ([]string, []string, error) {
tempFiles := []string{}
newArgs := []string{}
for i := 0; i < len(args); i++ {
if (args[i] == "-m" || args[i] == "-p") && i+1 < len(args) {
pattern := fmt.Sprintf("casbin_temp_%s_*.conf", args[i])
tempFile, err := os.CreateTemp("", pattern)
if err != nil {
return nil, nil, fmt.Errorf("failed to create temp file: %v", err)
}
_, err = tempFile.WriteString(args[i+1])
if err != nil {
tempFile.Close()
return nil, nil, fmt.Errorf("failed to write to temp file: %v", err)
}
tempFile.Close()
tempFiles = append(tempFiles, tempFile.Name())
newArgs = append(newArgs, args[i], tempFile.Name())
i++
} else {
newArgs = append(newArgs, args[i])
}
}
return tempFiles, newArgs, nil
}
// RunCasbinCommand
// @Title RunCasbinCommand
// @Tag Enforcer API
// @Description Call Casbin CLI commands
// @Success 200 {object} controllers.Response The Response object
// @router /run-casbin-command [get]
func (c *ApiController) RunCasbinCommand() {
if err := validateIdentifier(c); err != nil {
c.ResponseError(err.Error())
return
}
language := c.Input().Get("language")
argString := c.Input().Get("args")
if language == "" {
language = "go"
}
// use "casbin-go-cli" by default, can be also "casbin-java-cli", "casbin-node-cli", etc.
// the pre-built binary of "casbin-go-cli" can be found at: https://github.com/casbin/casbin-go-cli/releases
binaryName := fmt.Sprintf("casbin-%s-cli", language)
_, err := exec.LookPath(binaryName)
if err != nil {
c.ResponseError(fmt.Sprintf("executable file: %s not found in PATH", binaryName))
return
}
// RBAC model & policy example:
// https://door.casdoor.com/api/run-casbin-command?language=go&args=["enforce", "-m", "[request_definition]\nr = sub, obj, act\n\n[policy_definition]\np = sub, obj, act\n\n[role_definition]\ng = _, _\n\n[policy_effect]\ne = some(where (p.eft == allow))\n\n[matchers]\nm = g(r.sub, p.sub) %26%26 r.obj == p.obj %26%26 r.act == p.act", "-p", "p, alice, data1, read\np, bob, data2, write\np, data2_admin, data2, read\np, data2_admin, data2, write\ng, alice, data2_admin", "alice", "data1", "read"]
// Casbin CLI usage:
// https://github.com/jcasbin/casbin-java-cli?tab=readme-ov-file#get-started
var args []string
err = json.Unmarshal([]byte(argString), &args)
if err != nil {
c.ResponseError(err.Error())
return
}
if len(args) > 0 && args[0] == "--version" {
version, err := getCLIVersion(language)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(version)
return
}
tempFiles, processedArgs, err := processArgsToTempFiles(args)
defer func() {
for _, file := range tempFiles {
os.Remove(file)
}
}()
if err != nil {
c.ResponseError(err.Error())
return
}
command := exec.Command(binaryName, processedArgs...)
outputBytes, err := command.CombinedOutput()
if err != nil {
errorString := err.Error()
if outputBytes != nil {
output := string(outputBytes)
errorString = fmt.Sprintf("%s, error: %s", output, err.Error())
}
c.ResponseError(errorString)
return
}
output := string(outputBytes)
output = strings.TrimSuffix(output, "\n")
c.ResponseOk(output)
}
// validateIdentifier
// @Title validateIdentifier
// @Description Validate the request hash and timestamp
// @Param hash string The SHA-256 hash string
// @Return error Returns error if validation fails, nil if successful
func validateIdentifier(c *ApiController) error {
language := c.Input().Get("language")
args := c.Input().Get("args")
hash := c.Input().Get("m")
timestamp := c.Input().Get("t")
if hash == "" || timestamp == "" || language == "" || args == "" {
return fmt.Errorf("invalid identifier")
}
requestTime, err := time.Parse(time.RFC3339, timestamp)
if err != nil {
return fmt.Errorf("invalid identifier")
}
timeDiff := time.Since(requestTime)
if timeDiff > 5*time.Minute || timeDiff < -5*time.Minute {
return fmt.Errorf("invalid identifier")
}
params := map[string]string{
"language": language,
"args": args,
}
keys := make([]string, 0, len(params))
for k := range params {
keys = append(keys, k)
}
sort.Strings(keys)
var paramParts []string
for _, k := range keys {
paramParts = append(paramParts, fmt.Sprintf("%s=%s", k, params[k]))
}
paramString := strings.Join(paramParts, "&")
version := "casbin-editor-v1"
rawString := fmt.Sprintf("%s|%s|%s", version, timestamp, paramString)
hasher := sha256.New()
hasher.Write([]byte(rawString))
calculatedHash := strings.ToLower(hex.EncodeToString(hasher.Sum(nil)))
if calculatedHash != strings.ToLower(hash) {
return fmt.Errorf("invalid identifier")
}
return nil
}

View File

@ -39,13 +39,13 @@ func (c *ApiController) GetCerts() {
sortOrder := c.Input().Get("sortOrder")
if limit == "" || page == "" {
maskedCerts, err := object.GetMaskedCerts(object.GetCerts(owner))
certs, err := object.GetMaskedCerts(object.GetCerts(owner))
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(maskedCerts)
c.ResponseOk(certs)
} else {
limit := util.ParseInt(limit)
count, err := object.GetCertCount(owner, field, value)
@ -68,7 +68,7 @@ func (c *ApiController) GetCerts() {
// GetGlobalCerts
// @Title GetGlobalCerts
// @Tag Cert API
// @Description get globle certs
// @Description get global certs
// @Success 200 {array} object.Cert The Response object
// @router /get-global-certs [get]
func (c *ApiController) GetGlobalCerts() {
@ -80,13 +80,13 @@ func (c *ApiController) GetGlobalCerts() {
sortOrder := c.Input().Get("sortOrder")
if limit == "" || page == "" {
maskedCerts, err := object.GetMaskedCerts(object.GetGlobalCerts())
certs, err := object.GetMaskedCerts(object.GetGlobalCerts())
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(maskedCerts)
c.ResponseOk(certs)
} else {
limit := util.ParseInt(limit)
count, err := object.GetGlobalCertsCount(field, value)

View File

@ -0,0 +1,519 @@
package controllers
import (
"archive/tar"
"archive/zip"
"compress/gzip"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"os"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/beego/beego"
"github.com/casdoor/casdoor/proxy"
"github.com/casdoor/casdoor/util"
)
const (
javaCliRepo = "https://api.github.com/repos/jcasbin/casbin-java-cli/releases/latest"
goCliRepo = "https://api.github.com/repos/casbin/casbin-go-cli/releases/latest"
rustCliRepo = "https://api.github.com/repos/casbin-rs/casbin-rust-cli/releases/latest"
downloadFolder = "bin"
)
type ReleaseInfo struct {
TagName string `json:"tag_name"`
Assets []struct {
Name string `json:"name"`
URL string `json:"browser_download_url"`
} `json:"assets"`
}
// @Title getBinaryNames
// @Description Get binary names for different platforms and architectures
// @Success 200 {map[string]string} map[string]string "Binary names map"
func getBinaryNames() map[string]string {
const (
golang = "go"
java = "java"
rust = "rust"
)
arch := runtime.GOARCH
archMap := map[string]struct{ goArch, rustArch string }{
"amd64": {"x86_64", "x86_64"},
"arm64": {"arm64", "aarch64"},
}
archNames, ok := archMap[arch]
if !ok {
archNames = struct{ goArch, rustArch string }{arch, arch}
}
switch runtime.GOOS {
case "windows":
return map[string]string{
golang: fmt.Sprintf("casbin-go-cli_Windows_%s.zip", archNames.goArch),
java: "casbin-java-cli.jar",
rust: fmt.Sprintf("casbin-rust-cli-%s-pc-windows-gnu", archNames.rustArch),
}
case "darwin":
return map[string]string{
golang: fmt.Sprintf("casbin-go-cli_Darwin_%s.tar.gz", archNames.goArch),
java: "casbin-java-cli.jar",
rust: fmt.Sprintf("casbin-rust-cli-%s-apple-darwin", archNames.rustArch),
}
case "linux":
return map[string]string{
golang: fmt.Sprintf("casbin-go-cli_Linux_%s.tar.gz", archNames.goArch),
java: "casbin-java-cli.jar",
rust: fmt.Sprintf("casbin-rust-cli-%s-unknown-linux-gnu", archNames.rustArch),
}
default:
return nil
}
}
// @Title getFinalBinaryName
// @Description Get final binary name for specific language
// @Param lang string true "Language type (go/java/rust)"
// @Success 200 {string} string "Final binary name"
func getFinalBinaryName(lang string) string {
switch lang {
case "go":
if runtime.GOOS == "windows" {
return "casbin-go-cli.exe"
}
return "casbin-go-cli"
case "java":
return "casbin-java-cli.jar"
case "rust":
if runtime.GOOS == "windows" {
return "casbin-rust-cli.exe"
}
return "casbin-rust-cli"
default:
return ""
}
}
// @Title getLatestCLIURL
// @Description Get latest CLI download URL from GitHub
// @Param repoURL string true "GitHub repository URL"
// @Param language string true "Language type"
// @Success 200 {string} string "Download URL and version"
func getLatestCLIURL(repoURL string, language string) (string, string, error) {
client := proxy.GetHttpClient(repoURL)
resp, err := client.Get(repoURL)
if err != nil {
return "", "", fmt.Errorf("failed to fetch release info: %v", err)
}
defer resp.Body.Close()
var release ReleaseInfo
if err := json.NewDecoder(resp.Body).Decode(&release); err != nil {
return "", "", err
}
binaryNames := getBinaryNames()
if binaryNames == nil {
return "", "", fmt.Errorf("unsupported OS: %s", runtime.GOOS)
}
binaryName := binaryNames[language]
for _, asset := range release.Assets {
if asset.Name == binaryName {
return asset.URL, release.TagName, nil
}
}
return "", "", fmt.Errorf("no suitable binary found for OS: %s, language: %s", runtime.GOOS, language)
}
// @Title extractGoCliFile
// @Description Extract the Go CLI file
// @Param filePath string true "The file path"
// @Success 200 {string} string "The extracted file path"
// @router /extractGoCliFile [post]
func extractGoCliFile(filePath string) error {
tempDir := filepath.Join(downloadFolder, "temp")
if err := os.MkdirAll(tempDir, 0o755); err != nil {
return err
}
defer os.RemoveAll(tempDir)
if runtime.GOOS == "windows" {
if err := unzipFile(filePath, tempDir); err != nil {
return err
}
} else {
if err := untarFile(filePath, tempDir); err != nil {
return err
}
}
execName := "casbin-go-cli"
if runtime.GOOS == "windows" {
execName += ".exe"
}
var execPath string
err := filepath.Walk(tempDir, func(path string, info os.FileInfo, err error) error {
if info.Name() == execName {
execPath = path
return nil
}
return nil
})
if err != nil {
return err
}
finalPath := filepath.Join(downloadFolder, execName)
if err := os.Rename(execPath, finalPath); err != nil {
return err
}
return os.Remove(filePath)
}
// @Title unzipFile
// @Description Unzip the file
// @Param zipPath string true "The zip file path"
// @Param destDir string true "The destination directory"
// @Success 200 {string} string "The extracted file path"
// @router /unzipFile [post]
func unzipFile(zipPath, destDir string) error {
r, err := zip.OpenReader(zipPath)
if err != nil {
return err
}
defer r.Close()
for _, f := range r.File {
fpath := filepath.Join(destDir, f.Name)
if f.FileInfo().IsDir() {
os.MkdirAll(fpath, os.ModePerm)
continue
}
if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
return err
}
outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
if err != nil {
return err
}
rc, err := f.Open()
if err != nil {
outFile.Close()
return err
}
_, err = io.Copy(outFile, rc)
outFile.Close()
rc.Close()
if err != nil {
return err
}
}
return nil
}
// @Title untarFile
// @Description Untar the file
// @Param tarPath string true "The tar file path"
// @Param destDir string true "The destination directory"
// @Success 200 {string} string "The extracted file path"
// @router /untarFile [post]
func untarFile(tarPath, destDir string) error {
file, err := os.Open(tarPath)
if err != nil {
return err
}
defer file.Close()
gzr, err := gzip.NewReader(file)
if err != nil {
return err
}
defer gzr.Close()
tr := tar.NewReader(gzr)
for {
header, err := tr.Next()
if err == io.EOF {
break
}
if err != nil {
return err
}
path := filepath.Join(destDir, header.Name)
switch header.Typeflag {
case tar.TypeDir:
if err := os.MkdirAll(path, 0o755); err != nil {
return err
}
case tar.TypeReg:
outFile, err := os.Create(path)
if err != nil {
return err
}
if _, err := io.Copy(outFile, tr); err != nil {
outFile.Close()
return err
}
outFile.Close()
}
}
return nil
}
// @Title createJavaCliWrapper
// @Description Create the Java CLI wrapper
// @Param binPath string true "The binary path"
// @Success 200 {string} string "The created file path"
// @router /createJavaCliWrapper [post]
func createJavaCliWrapper(binPath string) error {
if runtime.GOOS == "windows" {
// Create a Windows CMD file
cmdPath := filepath.Join(binPath, "casbin-java-cli.cmd")
cmdContent := fmt.Sprintf(`@echo off
java -jar "%s\casbin-java-cli.jar" %%*`, binPath)
err := os.WriteFile(cmdPath, []byte(cmdContent), 0o755)
if err != nil {
return fmt.Errorf("failed to create Java CLI wrapper: %v", err)
}
} else {
// Create Unix shell script
shPath := filepath.Join(binPath, "casbin-java-cli")
shContent := fmt.Sprintf(`#!/bin/sh
java -jar "%s/casbin-java-cli.jar" "$@"`, binPath)
err := os.WriteFile(shPath, []byte(shContent), 0o755)
if err != nil {
return fmt.Errorf("failed to create Java CLI wrapper: %v", err)
}
}
return nil
}
// @Title downloadCLI
// @Description Download and setup CLI tools
// @Success 200 {error} error "Error if any"
func downloadCLI() error {
pathEnv := os.Getenv("PATH")
binPath, err := filepath.Abs(downloadFolder)
if err != nil {
return fmt.Errorf("failed to get absolute path to download directory: %v", err)
}
if !strings.Contains(pathEnv, binPath) {
newPath := fmt.Sprintf("%s%s%s", binPath, string(os.PathListSeparator), pathEnv)
if err := os.Setenv("PATH", newPath); err != nil {
return fmt.Errorf("failed to update PATH environment variable: %v", err)
}
}
if err := os.MkdirAll(downloadFolder, 0o755); err != nil {
return fmt.Errorf("failed to create download directory: %v", err)
}
repos := map[string]string{
"java": javaCliRepo,
"go": goCliRepo,
"rust": rustCliRepo,
}
for lang, repo := range repos {
cliURL, version, err := getLatestCLIURL(repo, lang)
if err != nil {
fmt.Printf("failed to get %s CLI URL: %v\n", lang, err)
continue
}
originalPath := filepath.Join(downloadFolder, getBinaryNames()[lang])
fmt.Printf("downloading %s CLI: %s\n", lang, cliURL)
client := proxy.GetHttpClient(cliURL)
resp, err := client.Get(cliURL)
if err != nil {
fmt.Printf("failed to download %s CLI: %v\n", lang, err)
continue
}
func() {
defer resp.Body.Close()
if err := os.MkdirAll(filepath.Dir(originalPath), 0o755); err != nil {
fmt.Printf("failed to create directory for %s CLI: %v\n", lang, err)
return
}
tmpFile := originalPath + ".tmp"
out, err := os.Create(tmpFile)
if err != nil {
fmt.Printf("failed to create or write %s CLI: %v\n", lang, err)
return
}
defer func() {
out.Close()
os.Remove(tmpFile)
}()
if _, err = io.Copy(out, resp.Body); err != nil ||
out.Close() != nil ||
os.Rename(tmpFile, originalPath) != nil {
fmt.Printf("failed to download %s CLI: %v\n", lang, err)
return
}
}()
if lang == "go" {
if err := extractGoCliFile(originalPath); err != nil {
fmt.Printf("failed to extract Go CLI: %v\n", err)
continue
}
} else {
finalPath := filepath.Join(downloadFolder, getFinalBinaryName(lang))
if err := os.Rename(originalPath, finalPath); err != nil {
fmt.Printf("failed to rename %s CLI: %v\n", lang, err)
continue
}
}
if runtime.GOOS != "windows" {
execPath := filepath.Join(downloadFolder, getFinalBinaryName(lang))
if err := os.Chmod(execPath, 0o755); err != nil {
fmt.Printf("failed to set %s CLI execution permission: %v\n", lang, err)
continue
}
}
fmt.Printf("downloaded %s CLI version: %s\n", lang, version)
if lang == "java" {
if err := createJavaCliWrapper(binPath); err != nil {
fmt.Printf("failed to create Java CLI wrapper: %v\n", err)
continue
}
}
}
return nil
}
// @Title RefreshEngines
// @Tag CLI API
// @Description Refresh all CLI engines
// @Param m query string true "Hash for request validation"
// @Param t query string true "Timestamp for request validation"
// @Success 200 {object} controllers.Response The Response object
// @router /refresh-engines [post]
func (c *ApiController) RefreshEngines() {
if !beego.AppConfig.DefaultBool("isDemoMode", false) {
c.ResponseError("refresh engines is only available in demo mode")
return
}
hash := c.Input().Get("m")
timestamp := c.Input().Get("t")
if hash == "" || timestamp == "" {
c.ResponseError("invalid identifier")
return
}
requestTime, err := time.Parse(time.RFC3339, timestamp)
if err != nil {
c.ResponseError("invalid identifier")
return
}
timeDiff := time.Since(requestTime)
if timeDiff > 5*time.Minute || timeDiff < -5*time.Minute {
c.ResponseError("invalid identifier")
return
}
version := "casbin-editor-v1"
rawString := fmt.Sprintf("%s|%s", version, timestamp)
hasher := sha256.New()
hasher.Write([]byte(rawString))
calculatedHash := strings.ToLower(hex.EncodeToString(hasher.Sum(nil)))
if calculatedHash != strings.ToLower(hash) {
c.ResponseError("invalid identifier")
return
}
err = downloadCLI()
if err != nil {
c.ResponseError(fmt.Sprintf("failed to refresh engines: %v", err))
return
}
c.ResponseOk(map[string]string{
"status": "success",
"message": "CLI engines updated successfully",
})
}
// @Title ScheduleCLIUpdater
// @Description Start periodic CLI update scheduler
func ScheduleCLIUpdater() {
if !beego.AppConfig.DefaultBool("isDemoMode", false) {
return
}
ticker := time.NewTicker(1 * time.Hour)
defer ticker.Stop()
for range ticker.C {
err := downloadCLI()
if err != nil {
fmt.Printf("failed to update CLI: %v\n", err)
} else {
fmt.Println("CLI updated successfully")
}
}
}
// @Title DownloadCLI
// @Description Download the CLI
// @Success 200 {string} string "The downloaded file path"
// @router /downloadCLI [post]
func DownloadCLI() error {
return downloadCLI()
}
// @Title InitCLIDownloader
// @Description Initialize CLI downloader and start update scheduler
func InitCLIDownloader() {
if !beego.AppConfig.DefaultBool("isDemoMode", false) {
return
}
util.SafeGoroutine(func() {
err := DownloadCLI()
if err != nil {
fmt.Printf("failed to initialize CLI downloader: %v\n", err)
}
ScheduleCLIUpdater()
})
}

View File

@ -16,6 +16,7 @@ package controllers
import (
"encoding/json"
"fmt"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
@ -71,7 +72,7 @@ func (c *ApiController) GetEnforcers() {
// @Tag Enforcer API
// @Description get enforcer
// @Param id query string true "The id ( owner/name ) of enforcer"
// @Success 200 {object} object
// @Success 200 {object} object.Enforcer
// @router /get-enforcer [get]
func (c *ApiController) GetEnforcer() {
id := c.Input().Get("id")
@ -99,7 +100,7 @@ func (c *ApiController) GetEnforcer() {
// @Description update enforcer
// @Param id query string true "The id ( owner/name ) of enforcer"
// @Param enforcer body object true "The enforcer object"
// @Success 200 {object} object
// @Success 200 {object} object.Enforcer
// @router /update-enforcer [post]
func (c *ApiController) UpdateEnforcer() {
id := c.Input().Get("id")
@ -120,7 +121,7 @@ func (c *ApiController) UpdateEnforcer() {
// @Tag Enforcer API
// @Description add enforcer
// @Param enforcer body object true "The enforcer object"
// @Success 200 {object} object
// @Success 200 {object} object.Enforcer
// @router /add-enforcer [post]
func (c *ApiController) AddEnforcer() {
enforcer := object.Enforcer{}
@ -138,8 +139,8 @@ func (c *ApiController) AddEnforcer() {
// @Title DeleteEnforcer
// @Tag Enforcer API
// @Description delete enforcer
// @Param body body object.Enforce true "The enforcer object"
// @Success 200 {object} object
// @Param body body object.Enforcer true "The enforcer object"
// @Success 200 {object} object.Enforcer
// @router /delete-enforcer [post]
func (c *ApiController) DeleteEnforcer() {
var enforcer object.Enforcer
@ -163,11 +164,17 @@ func (c *ApiController) GetPolicies() {
c.ResponseError(err.Error())
return
}
if adapter == nil {
c.ResponseError(fmt.Sprintf(c.T("enforcer:the adapter: %s is not found"), adapterId))
return
}
err = adapter.InitAdapter()
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk()
return
}

55
controllers/face.go Normal file
View File

@ -0,0 +1,55 @@
// Copyright 2024 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.
// Casdoor will expose its providers as services to SDK
// We are going to implement those services as APIs here
package controllers
import (
"fmt"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
// FaceIDSigninBegin
// @Title FaceIDSigninBegin
// @Tag Login API
// @Description FaceId Login Flow 1st stage
// @Param owner query string true "owner"
// @Param name query string true "name"
// @Success 200 {object} controllers.Response The Response object
// @router /faceid-signin-begin [get]
func (c *ApiController) FaceIDSigninBegin() {
userOwner := c.Input().Get("owner")
userName := c.Input().Get("name")
user, err := object.GetUserByFields(userOwner, userName)
if err != nil {
c.ResponseError(err.Error())
return
}
if user == nil {
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(userOwner, userName)))
return
}
if len(user.FaceIds) == 0 {
c.ResponseError(c.T("check:Face data does not exist, cannot log in"))
return
}
c.ResponseOk()
}

View File

@ -18,7 +18,7 @@ import "github.com/casdoor/casdoor/object"
// GetDashboard
// @Title GetDashboard
// @Tag GetDashboard API
// @Tag System API
// @Description get information of dashboard
// @Success 200 {object} controllers.Response The Response object
// @router /get-dashboard [get]

View File

@ -15,6 +15,7 @@ package controllers
import (
"encoding/json"
"fmt"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
@ -43,13 +44,20 @@ func (c *ApiController) GetGroups() {
if err != nil {
c.ResponseError(err.Error())
return
} else {
if withTree == "true" {
c.ResponseOk(object.ConvertToTreeData(groups, owner))
return
}
c.ResponseOk(groups)
}
err = object.ExtendGroupsWithUsers(groups)
if err != nil {
c.ResponseError(err.Error())
return
}
if withTree == "true" {
c.ResponseOk(object.ConvertToTreeData(groups, owner))
return
}
c.ResponseOk(groups)
} else {
limit := util.ParseInt(limit)
count, err := object.GetGroupCount(owner, field, value)
@ -63,9 +71,33 @@ func (c *ApiController) GetGroups() {
if err != nil {
c.ResponseError(err.Error())
return
} else {
c.ResponseOk(groups, paginator.Nums())
}
groupsHaveChildrenMap, err := object.GetGroupsHaveChildrenMap(groups)
if err != nil {
c.ResponseError(err.Error())
return
}
for _, group := range groups {
_, ok := groupsHaveChildrenMap[group.GetId()]
if ok {
group.HaveChildren = true
}
parent, ok := groupsHaveChildrenMap[fmt.Sprintf("%s/%s", group.Owner, group.ParentId)]
if ok {
group.ParentName = parent.DisplayName
}
}
err = object.ExtendGroupsWithUsers(groups)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(groups, paginator.Nums())
}
}
@ -84,6 +116,13 @@ func (c *ApiController) GetGroup() {
c.ResponseError(err.Error())
return
}
err = object.ExtendGroupWithUsers(group)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(group)
}

View File

@ -0,0 +1,56 @@
// Copyright 2025 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 (
"fmt"
"os"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
func (c *ApiController) UploadGroups() {
userId := c.GetSessionUsername()
owner, user := util.GetOwnerAndNameFromId(userId)
file, header, err := c.Ctx.Request.FormFile("file")
if err != nil {
c.ResponseError(err.Error())
return
}
fileId := fmt.Sprintf("%s_%s_%s", owner, user, util.RemoveExt(header.Filename))
path := util.GetUploadXlsxPath(fileId)
defer os.Remove(path)
err = saveFile(path, &file)
if err != nil {
c.ResponseError(err.Error())
return
}
affected, err := object.UploadGroups(owner, path)
if err != nil {
c.ResponseError(err.Error())
return
}
if affected {
c.ResponseOk()
} else {
c.ResponseError(c.T("general:Failed to import groups"))
}
}

190
controllers/invitation.go Normal file
View File

@ -0,0 +1,190 @@
// 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/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
// GetInvitations
// @Title GetInvitations
// @Tag Invitation API
// @Description get invitations
// @Param owner query string true "The owner of invitations"
// @Success 200 {array} object.Invitation The Response object
// @router /get-invitations [get]
func (c *ApiController) GetInvitations() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
if limit == "" || page == "" {
invitations, err := object.GetInvitations(owner)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(invitations)
} else {
limit := util.ParseInt(limit)
count, err := object.GetInvitationCount(owner, field, value)
if err != nil {
c.ResponseError(err.Error())
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
invitations, err := object.GetPaginationInvitations(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(invitations, paginator.Nums())
}
}
// GetInvitation
// @Title GetInvitation
// @Tag Invitation API
// @Description get invitation
// @Param id query string true "The id ( owner/name ) of the invitation"
// @Success 200 {object} object.Invitation The Response object
// @router /get-invitation [get]
func (c *ApiController) GetInvitation() {
id := c.Input().Get("id")
invitation, err := object.GetInvitation(id)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(invitation)
}
// GetInvitationCodeInfo
// @Title GetInvitationCodeInfo
// @Tag Invitation API
// @Description get invitation code information
// @Param code query string true "Invitation code"
// @Success 200 {object} object.Invitation The Response object
// @router /get-invitation-info [get]
func (c *ApiController) GetInvitationCodeInfo() {
code := c.Input().Get("code")
applicationId := c.Input().Get("applicationId")
application, err := object.GetApplication(applicationId)
if err != nil {
c.ResponseError(err.Error())
return
}
invitation, msg := object.GetInvitationByCode(code, application.Organization, c.GetAcceptLanguage())
if msg != "" {
c.ResponseError(msg)
return
}
c.ResponseOk(object.GetMaskedInvitation(invitation))
}
// UpdateInvitation
// @Title UpdateInvitation
// @Tag Invitation API
// @Description update invitation
// @Param id query string true "The id ( owner/name ) of the invitation"
// @Param body body object.Invitation true "The details of the invitation"
// @Success 200 {object} controllers.Response The Response object
// @router /update-invitation [post]
func (c *ApiController) UpdateInvitation() {
id := c.Input().Get("id")
var invitation object.Invitation
err := json.Unmarshal(c.Ctx.Input.RequestBody, &invitation)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateInvitation(id, &invitation, c.GetAcceptLanguage()))
c.ServeJSON()
}
// AddInvitation
// @Title AddInvitation
// @Tag Invitation API
// @Description add invitation
// @Param body body object.Invitation true "The details of the invitation"
// @Success 200 {object} controllers.Response The Response object
// @router /add-invitation [post]
func (c *ApiController) AddInvitation() {
var invitation object.Invitation
err := json.Unmarshal(c.Ctx.Input.RequestBody, &invitation)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddInvitation(&invitation, c.GetAcceptLanguage()))
c.ServeJSON()
}
// DeleteInvitation
// @Title DeleteInvitation
// @Tag Invitation API
// @Description delete invitation
// @Param body body object.Invitation true "The details of the invitation"
// @Success 200 {object} controllers.Response The Response object
// @router /delete-invitation [post]
func (c *ApiController) DeleteInvitation() {
var invitation object.Invitation
err := json.Unmarshal(c.Ctx.Input.RequestBody, &invitation)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteInvitation(&invitation))
c.ServeJSON()
}
// VerifyInvitation
// @Title VerifyInvitation
// @Tag Invitation API
// @Description verify invitation
// @Param id query string true "The id ( owner/name ) of the invitation"
// @Success 200 {object} controllers.Response The Response object
// @router /verify-invitation [get]
func (c *ApiController) VerifyInvitation() {
id := c.Input().Get("id")
payment, attachInfo, err := object.VerifyInvitation(id)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(payment, attachInfo)
}

View File

@ -27,10 +27,10 @@ type LdapResp struct {
ExistUuids []string `json:"existUuids"`
}
//type LdapRespGroup struct {
// type LdapRespGroup struct {
// GroupId string
// GroupName string
//}
// }
type LdapSyncResp struct {
Exist []object.LdapUser `json:"exist"`
@ -42,7 +42,7 @@ type LdapSyncResp struct {
// @Tag Account API
// @Description get ldap users
// Param id string true "id"
// @Success 200 {object} LdapResp The Response object
// @Success 200 {object} controllers.LdapResp The Response object
// @router /get-ldap-users [get]
func (c *ApiController) GetLdapUsers() {
id := c.Input().Get("id")
@ -59,19 +59,20 @@ func (c *ApiController) GetLdapUsers() {
c.ResponseError(err.Error())
return
}
defer conn.Close()
//groupsMap, err := conn.GetLdapGroups(ldapServer.BaseDn)
//if err != nil {
// groupsMap, err := conn.GetLdapGroups(ldapServer.BaseDn)
// if err != nil {
// c.ResponseError(err.Error())
// return
//}
// }
//for _, group := range groupsMap {
// for _, group := range groupsMap {
// resp.Groups = append(resp.Groups, LdapRespGroup{
// GroupId: group.GidNumber,
// GroupName: group.Cn,
// })
//}
// }
users, err := conn.GetLdapUsers(ldapServer)
if err != nil {
@ -249,7 +250,7 @@ func (c *ApiController) DeleteLdap() {
// @Tag Account API
// @Description sync ldap users
// @Param id query string true "id"
// @Success 200 {object} LdapSyncResp The Response object
// @Success 200 {object} controllers.LdapSyncResp The Response object
// @router /sync-ldap-users [post]
func (c *ApiController) SyncLdapUsers() {
id := c.Input().Get("id")
@ -268,7 +269,11 @@ func (c *ApiController) SyncLdapUsers() {
return
}
exist, failed, _ := object.SyncLdapUsers(owner, users, ldapId)
exist, failed, err := object.SyncLdapUsers(owner, users, ldapId)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(&LdapSyncResp{
Exist: exist,

View File

@ -26,8 +26,10 @@ type LinkForm struct {
}
// Unlink ...
// @router /unlink [post]
// @Tag Login API
// @Title Unlink
// @router /unlink [post]
// @Success 200 {object} object.Userinfo The Response object
func (c *ApiController) Unlink() {
user, ok := c.RequireSignedInUser()
if !ok {
@ -58,7 +60,6 @@ func (c *ApiController) Unlink() {
c.ResponseError(err.Error())
return
}
if application == nil {
c.ResponseError(c.T("link:You can't unlink yourself, you are not a member of any application"))
return

View File

@ -19,6 +19,7 @@ import (
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
"github.com/google/uuid"
)
// MfaSetupInitiate
@ -57,12 +58,15 @@ func (c *ApiController) MfaSetupInitiate() {
return
}
mfaProps, err := MfaUtil.Initiate(c.Ctx, user.GetId())
mfaProps, err := MfaUtil.Initiate(user.GetId())
if err != nil {
c.ResponseError(err.Error())
return
}
recoveryCode := uuid.NewString()
mfaProps.RecoveryCodes = []string{recoveryCode}
resp := mfaProps
c.ResponseOk(resp)
}
@ -73,23 +77,55 @@ func (c *ApiController) MfaSetupInitiate() {
// @Description setup verify totp
// @param secret form string true "MFA secret"
// @param passcode form string true "MFA passcode"
// @Success 200 {object} Response object
// @Success 200 {object} controllers.Response The Response object
// @router /mfa/setup/verify [post]
func (c *ApiController) MfaSetupVerify() {
mfaType := c.Ctx.Request.Form.Get("mfaType")
passcode := c.Ctx.Request.Form.Get("passcode")
secret := c.Ctx.Request.Form.Get("secret")
dest := c.Ctx.Request.Form.Get("dest")
countryCode := c.Ctx.Request.Form.Get("countryCode")
if mfaType == "" || passcode == "" {
c.ResponseError("missing auth type or passcode")
return
}
mfaUtil := object.GetMfaUtil(mfaType, nil)
config := &object.MfaProps{
MfaType: mfaType,
}
if mfaType == object.TotpType {
if secret == "" {
c.ResponseError("totp secret is missing")
return
}
config.Secret = secret
} else if mfaType == object.SmsType {
if dest == "" {
c.ResponseError("destination is missing")
return
}
config.Secret = dest
if countryCode == "" {
c.ResponseError("country code is missing")
return
}
config.CountryCode = countryCode
} else if mfaType == object.EmailType {
if dest == "" {
c.ResponseError("destination is missing")
return
}
config.Secret = dest
}
mfaUtil := object.GetMfaUtil(mfaType, config)
if mfaUtil == nil {
c.ResponseError("Invalid multi-factor authentication type")
return
}
err := mfaUtil.SetupVerify(c.Ctx, passcode)
err := mfaUtil.SetupVerify(passcode)
if err != nil {
c.ResponseError(err.Error())
} else {
@ -104,12 +140,16 @@ func (c *ApiController) MfaSetupVerify() {
// @param owner form string true "owner of user"
// @param name form string true "name of user"
// @param type form string true "MFA auth type"
// @Success 200 {object} Response object
// @Success 200 {object} controllers.Response The Response object
// @router /mfa/setup/enable [post]
func (c *ApiController) MfaSetupEnable() {
owner := c.Ctx.Request.Form.Get("owner")
name := c.Ctx.Request.Form.Get("name")
mfaType := c.Ctx.Request.Form.Get("mfaType")
secret := c.Ctx.Request.Form.Get("secret")
dest := c.Ctx.Request.Form.Get("dest")
countryCode := c.Ctx.Request.Form.Get("secret")
recoveryCodes := c.Ctx.Request.Form.Get("recoveryCodes")
user, err := object.GetUser(util.GetId(owner, name))
if err != nil {
@ -122,13 +162,52 @@ func (c *ApiController) MfaSetupEnable() {
return
}
mfaUtil := object.GetMfaUtil(mfaType, nil)
config := &object.MfaProps{
MfaType: mfaType,
}
if mfaType == object.TotpType {
if secret == "" {
c.ResponseError("totp secret is missing")
return
}
config.Secret = secret
} else if mfaType == object.EmailType {
if user.Email == "" {
if dest == "" {
c.ResponseError("destination is missing")
return
}
user.Email = dest
}
} else if mfaType == object.SmsType {
if user.Phone == "" {
if dest == "" {
c.ResponseError("destination is missing")
return
}
user.Phone = dest
if countryCode == "" {
c.ResponseError("country code is missing")
return
}
user.CountryCode = countryCode
}
}
if recoveryCodes == "" {
c.ResponseError("recovery codes is missing")
return
}
config.RecoveryCodes = []string{recoveryCodes}
mfaUtil := object.GetMfaUtil(mfaType, config)
if mfaUtil == nil {
c.ResponseError("Invalid multi-factor authentication type")
return
}
err = mfaUtil.Enable(c.Ctx, user)
err = mfaUtil.Enable(user)
if err != nil {
c.ResponseError(err.Error())
return
@ -143,7 +222,7 @@ func (c *ApiController) MfaSetupEnable() {
// @Description: Delete MFA
// @param owner form string true "owner of user"
// @param name form string true "name of user"
// @Success 200 {object} Response object
// @Success 200 {object} controllers.Response The Response object
// @router /delete-mfa/ [post]
func (c *ApiController) DeleteMfa() {
owner := c.Ctx.Request.Form.Get("owner")
@ -176,7 +255,7 @@ func (c *ApiController) DeleteMfa() {
// @param owner form string true "owner of user"
// @param name form string true "name of user"
// @param id form string true "id of user's MFA props"
// @Success 200 {object} Response object
// @Success 200 {object} controllers.Response The Response object
// @router /set-preferred-mfa [post]
func (c *ApiController) SetPreferredMfa() {
mfaType := c.Ctx.Request.Form.Get("mfaType")

View File

@ -14,7 +14,11 @@
package controllers
import "github.com/casdoor/casdoor/object"
import (
"strings"
"github.com/casdoor/casdoor/object"
)
// GetOidcDiscovery
// @Title GetOidcDiscovery
@ -42,3 +46,31 @@ func (c *RootController) GetJwks() {
c.Data["json"] = jwks
c.ServeJSON()
}
// GetWebFinger
// @Title GetWebFinger
// @Tag OIDC API
// @Param resource query string true "resource"
// @Success 200 {object} object.WebFinger
// @router /.well-known/webfinger [get]
func (c *RootController) GetWebFinger() {
resource := c.Input().Get("resource")
rels := []string{}
host := c.Ctx.Request.Host
for key, value := range c.Input() {
if strings.HasPrefix(key, "rel") {
rels = append(rels, value...)
}
}
webfinger, err := object.GetWebFinger(resource, rels, host)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = webfinger
c.Ctx.Output.ContentType("application/jrd+json")
c.ServeJSON()
}

View File

@ -41,13 +41,12 @@ func (c *ApiController) GetOrganizations() {
isGlobalAdmin := c.IsGlobalAdmin()
if limit == "" || page == "" {
var maskedOrganizations []*object.Organization
var organizations []*object.Organization
var err error
if isGlobalAdmin {
maskedOrganizations, err = object.GetMaskedOrganizations(object.GetOrganizations(owner))
organizations, err = object.GetMaskedOrganizations(object.GetOrganizations(owner))
} else {
maskedOrganizations, err = object.GetMaskedOrganizations(object.GetOrganizations(owner, c.getCurrentUser().Owner))
organizations, err = object.GetMaskedOrganizations(object.GetOrganizations(owner, c.getCurrentUser().Owner))
}
if err != nil {
@ -55,18 +54,18 @@ func (c *ApiController) GetOrganizations() {
return
}
c.ResponseOk(maskedOrganizations)
c.ResponseOk(organizations)
} else {
if !isGlobalAdmin {
maskedOrganizations, err := object.GetMaskedOrganizations(object.GetOrganizations(owner, c.getCurrentUser().Owner))
organizations, err := object.GetMaskedOrganizations(object.GetOrganizations(owner, c.getCurrentUser().Owner))
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(maskedOrganizations)
c.ResponseOk(organizations)
} else {
limit := util.ParseInt(limit)
count, err := object.GetOrganizationCount(owner, field, value)
count, err := object.GetOrganizationCount(owner, organizationName, field, value)
if err != nil {
c.ResponseError(err.Error())
return
@ -93,13 +92,13 @@ func (c *ApiController) GetOrganizations() {
// @router /get-organization [get]
func (c *ApiController) GetOrganization() {
id := c.Input().Get("id")
maskedOrganization, err := object.GetMaskedOrganization(object.GetOrganization(id))
organization, err := object.GetMaskedOrganization(object.GetOrganization(id))
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(maskedOrganization)
c.ResponseOk(organization)
}
// UpdateOrganization ...
@ -120,7 +119,14 @@ func (c *ApiController) UpdateOrganization() {
return
}
c.Data["json"] = wrapActionResponse(object.UpdateOrganization(id, &organization))
if err = object.CheckIpWhitelist(organization.IpWhitelist, c.GetAcceptLanguage()); err != nil {
c.ResponseError(err.Error())
return
}
isGlobalAdmin, _ := c.isGlobalAdmin()
c.Data["json"] = wrapActionResponse(object.UpdateOrganization(id, &organization, isGlobalAdmin))
c.ServeJSON()
}
@ -139,7 +145,7 @@ func (c *ApiController) AddOrganization() {
return
}
count, err := object.GetOrganizationCount("", "", "")
count, err := object.GetOrganizationCount("", "", "", "")
if err != nil {
c.ResponseError(err.Error())
return
@ -150,6 +156,11 @@ func (c *ApiController) AddOrganization() {
return
}
if err = object.CheckIpWhitelist(organization.IpWhitelist, c.GetAcceptLanguage()); err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddOrganization(&organization))
c.ServeJSON()
}
@ -178,7 +189,7 @@ func (c *ApiController) DeleteOrganization() {
// @Tag Organization API
// @Description get default application
// @Param id query string true "organization id"
// @Success 200 {object} Response The Response object
// @Success 200 {object} controllers.Response The Response object
// @router /get-default-application [get]
func (c *ApiController) GetDefaultApplication() {
userId := c.GetSessionUsername()
@ -190,8 +201,8 @@ func (c *ApiController) GetDefaultApplication() {
return
}
maskedApplication := object.GetMaskedApplication(application, userId)
c.ResponseOk(maskedApplication)
application = object.GetMaskedApplication(application, userId)
c.ResponseOk(application)
}
// GetOrganizationNames ...

View File

@ -49,6 +49,6 @@ func (c *ApiController) UploadPermissions() {
if affected {
c.ResponseOk()
} else {
c.ResponseError(c.T("user_upload:Failed to import users"))
c.ResponseError(c.T("general:Failed to import users"))
}
}

View File

@ -17,6 +17,7 @@ package controllers
import (
"encoding/json"
"fmt"
"strconv"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
@ -164,6 +165,16 @@ func (c *ApiController) BuyProduct() {
host := c.Ctx.Request.Host
providerName := c.Input().Get("providerName")
paymentEnv := c.Input().Get("paymentEnv")
customPriceStr := c.Input().Get("customPrice")
if customPriceStr == "" {
customPriceStr = "0"
}
customPrice, err := strconv.ParseFloat(customPriceStr, 64)
if err != nil {
c.ResponseError(err.Error())
return
}
// buy `pricingName/planName` for `paidUserName`
pricingName := c.Input().Get("pricingName")
@ -171,6 +182,10 @@ func (c *ApiController) BuyProduct() {
paidUserName := c.Input().Get("userName")
owner, _ := util.GetOwnerAndNameFromId(id)
userId := util.GetId(owner, paidUserName)
if paidUserName != "" && paidUserName != c.GetSessionUsername() && !c.IsAdmin() {
c.ResponseError(c.T("general:Only admin user can specify user"))
return
}
if paidUserName == "" {
userId = c.GetSessionUsername()
}
@ -189,7 +204,7 @@ func (c *ApiController) BuyProduct() {
return
}
payment, attachInfo, err := object.BuyProduct(id, user, providerName, pricingName, planName, host, paymentEnv)
payment, attachInfo, err := object.BuyProduct(id, user, providerName, pricingName, planName, host, paymentEnv, customPrice)
if err != nil {
c.ResponseError(err.Error())
return

View File

@ -20,7 +20,7 @@ import (
// GetPrometheusInfo
// @Title GetPrometheusInfo
// @Tag Prometheus API
// @Tag System API
// @Description get Prometheus Info
// @Success 200 {object} object.PrometheusInfo The Response object
// @router /get-prometheus-info [get]

View File

@ -141,6 +141,20 @@ func (c *ApiController) GetProvider() {
c.ResponseOk(object.GetMaskedProvider(provider, isMaskEnabled))
}
func (c *ApiController) requireProviderPermission(provider *object.Provider) bool {
isGlobalAdmin, user := c.isGlobalAdmin()
if isGlobalAdmin {
return true
}
if provider.Owner == "admin" || user.Owner != provider.Owner {
c.ResponseError(c.T("auth:Unauthorized operation"))
return false
}
return true
}
// UpdateProvider
// @Title UpdateProvider
// @Tag Provider API
@ -159,6 +173,11 @@ func (c *ApiController) UpdateProvider() {
return
}
ok := c.requireProviderPermission(&provider)
if !ok {
return
}
c.Data["json"] = wrapActionResponse(object.UpdateProvider(id, &provider))
c.ServeJSON()
}
@ -184,11 +203,17 @@ func (c *ApiController) AddProvider() {
return
}
if err := checkQuotaForProvider(int(count)); err != nil {
err = checkQuotaForProvider(int(count))
if err != nil {
c.ResponseError(err.Error())
return
}
ok := c.requireProviderPermission(&provider)
if !ok {
return
}
c.Data["json"] = wrapActionResponse(object.AddProvider(&provider))
c.ServeJSON()
}
@ -208,6 +233,11 @@ func (c *ApiController) DeleteProvider() {
return
}
ok := c.requireProviderPermission(&provider)
if !ok {
return
}
c.Data["json"] = wrapActionResponse(object.DeleteProvider(&provider))
c.ServeJSON()
}

128
controllers/record.go Normal file
View File

@ -0,0 +1,128 @@
// Copyright 2021 The Casdoor Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
"encoding/json"
"github.com/casvisor/casvisor-go-sdk/casvisorsdk"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
// GetRecords
// @Title GetRecords
// @Tag Record API
// @Description get all records
// @Param pageSize query string true "The size of each page"
// @Param p query string true "The number of the page"
// @Success 200 {object} object.Record The Response object
// @router /get-records [get]
func (c *ApiController) GetRecords() {
organization, ok := c.RequireAdmin()
if !ok {
return
}
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")
organizationName := c.Input().Get("organizationName")
if limit == "" || page == "" {
records, err := object.GetRecords()
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(records)
} else {
limit := util.ParseInt(limit)
if c.IsGlobalAdmin() && organizationName != "" {
organization = organizationName
}
filterRecord := &casvisorsdk.Record{Organization: organization}
count, err := object.GetRecordCount(field, value, filterRecord)
if err != nil {
c.ResponseError(err.Error())
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
records, err := object.GetPaginationRecords(paginator.Offset(), limit, field, value, sortField, sortOrder, filterRecord)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(records, paginator.Nums())
}
}
// GetRecordsByFilter
// @Tag Record API
// @Title GetRecordsByFilter
// @Description get records by filter
// @Param filter body string true "filter Record message"
// @Success 200 {object} object.Record The Response object
// @router /get-records-filter [post]
func (c *ApiController) GetRecordsByFilter() {
_, ok := c.RequireAdmin()
if !ok {
return
}
body := string(c.Ctx.Input.RequestBody)
record := &casvisorsdk.Record{}
err := util.JsonToStruct(body, record)
if err != nil {
c.ResponseError(err.Error())
return
}
records, err := object.GetRecordsByField(record)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(records)
}
// AddRecord
// @Title AddRecord
// @Tag Record API
// @Description add a record
// @Param body body object.Record true "The details of the record"
// @Success 200 {object} controllers.Response The Response object
// @router /add-record [post]
func (c *ApiController) AddRecord() {
var record casvisorsdk.Record
err := json.Unmarshal(c.Ctx.Input.RequestBody, &record)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddRecord(&record))
c.ServeJSON()
}

View File

@ -52,6 +52,15 @@ func (c *ApiController) GetResources() {
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
isOrgAdmin, ok := c.IsOrgAdmin()
if !ok {
return
}
if isOrgAdmin {
user = ""
}
if sortField == "Direct" {
provider, err := c.GetProviderFromContext("Storage")
if err != nil {
@ -248,7 +257,7 @@ func (c *ApiController) UploadResource() {
fileType, _ = util.GetOwnerAndNameFromIdNoCheck(mimeType + "/")
}
fullFilePath = object.GetTruncatedPath(provider, fullFilePath, 175)
fullFilePath = object.GetTruncatedPath(provider, fullFilePath, 450)
if tag != "avatar" && tag != "termsOfUse" && !strings.HasPrefix(tag, "idCard") {
ext := filepath.Ext(filepath.Base(fullFilePath))
index := len(fullFilePath) - len(ext)

View File

@ -49,6 +49,6 @@ func (c *ApiController) UploadRoles() {
if affected {
c.ResponseOk()
} else {
c.ResponseError(c.T("user_upload:Failed to import users"))
c.ResponseError(c.T("general:Failed to import users"))
}
}

View File

@ -16,6 +16,7 @@ package controllers
import (
"fmt"
"net/http"
"github.com/casdoor/casdoor/object"
)
@ -34,7 +35,13 @@ func (c *ApiController) GetSamlMeta() {
return
}
metadata, err := object.GetSamlMeta(application, host)
enablePostBinding, err := c.GetBool("enablePostBinding", false)
if err != nil {
c.ResponseError(err.Error())
return
}
metadata, err := object.GetSamlMeta(application, host, enablePostBinding)
if err != nil {
c.ResponseError(err.Error())
return
@ -43,3 +50,17 @@ func (c *ApiController) GetSamlMeta() {
c.Data["xml"] = metadata
c.ServeXML()
}
func (c *ApiController) HandleSamlRedirect() {
host := c.Ctx.Request.Host
owner := c.Ctx.Input.Param(":owner")
application := c.Ctx.Input.Param(":application")
relayState := c.Input().Get("RelayState")
samlRequest := c.Input().Get("SAMLRequest")
targetURL := object.GetSamlRedirectAddress(owner, application, relayState, samlRequest, host)
c.Redirect(targetURL, http.StatusSeeOther)
}

View File

@ -21,6 +21,11 @@ import (
)
func (c *RootController) HandleScim() {
_, ok := c.RequireAdmin()
if !ok {
return
}
path := c.Ctx.Request.URL.Path
c.Ctx.Request.URL.Path = strings.TrimPrefix(path, "/scim")
scim.Server.ServeHTTP(c.Ctx.ResponseWriter, c.Ctx.Request)

View File

@ -27,11 +27,12 @@ import (
)
type EmailForm struct {
Title string `json:"title"`
Content string `json:"content"`
Sender string `json:"sender"`
Receivers []string `json:"receivers"`
Provider string `json:"provider"`
Title string `json:"title"`
Content string `json:"content"`
Sender string `json:"sender"`
Receivers []string `json:"receivers"`
Provider string `json:"provider"`
ProviderObject object.Provider `json:"providerObject"`
}
type SmsForm struct {
@ -51,11 +52,15 @@ type NotificationForm struct {
// @Param clientId query string true "The clientId of the application"
// @Param clientSecret query string true "The clientSecret of the application"
// @Param from body controllers.EmailForm true "Details of the email request"
// @Success 200 {object} Response object
// @router /api/send-email [post]
// @Success 200 {object} controllers.Response The Response object
// @router /send-email [post]
func (c *ApiController) SendEmail() {
var emailForm EmailForm
userId, ok := c.RequireSignedIn()
if !ok {
return
}
var emailForm EmailForm
err := json.Unmarshal(c.Ctx.Input.RequestBody, &emailForm)
if err != nil {
c.ResponseError(err.Error())
@ -70,7 +75,6 @@ func (c *ApiController) SendEmail() {
c.ResponseError(err.Error())
return
}
} else {
// called by Casdoor SDK via Client ID & Client Secret, so the used Email provider will be the application' Email provider or the default Email provider
provider, err = c.GetProviderFromContext("Email")
@ -80,9 +84,16 @@ func (c *ApiController) SendEmail() {
}
}
if emailForm.ProviderObject.Name != "" {
if emailForm.ProviderObject.ClientSecret == "***" {
emailForm.ProviderObject.ClientSecret = provider.ClientSecret
}
provider = &emailForm.ProviderObject
}
// when receiver is the reserved keyword: "TestSmtpServer", it means to test the SMTP server instead of sending a real Email
if len(emailForm.Receivers) == 1 && emailForm.Receivers[0] == "TestSmtpServer" {
err := object.DailSmtpServer(provider)
err = object.TestSmtpServer(provider)
if err != nil {
c.ResponseError(err.Error())
return
@ -107,9 +118,28 @@ func (c *ApiController) SendEmail() {
return
}
content := emailForm.Content
if content == "" {
content = provider.Content
}
code := "123456"
// "You have requested a verification code at Casdoor. Here is your code: %s, please enter in 5 minutes."
content := fmt.Sprintf(emailForm.Content, code)
content = strings.Replace(content, "%s", code, 1)
userString := "Hi"
if !object.IsAppUser(userId) {
var user *object.User
user, err = object.GetUser(userId)
if err != nil {
c.ResponseError(err.Error())
return
}
if user != nil {
userString = user.GetFriendlyName()
}
}
content = strings.Replace(content, "%{user.friendlyName}", userString, 1)
for _, receiver := range emailForm.Receivers {
err = object.SendEmail(provider, emailForm.Title, content, receiver, emailForm.Sender)
if err != nil {
@ -128,8 +158,8 @@ func (c *ApiController) SendEmail() {
// @Param clientId query string true "The clientId of the application"
// @Param clientSecret query string true "The clientSecret of the application"
// @Param from body controllers.SmsForm true "Details of the sms request"
// @Success 200 {object} Response object
// @router /api/send-sms [post]
// @Success 200 {object} controllers.Response The Response object
// @router /send-sms [post]
func (c *ApiController) SendSms() {
provider, err := c.GetProviderFromContext("SMS")
if err != nil {
@ -166,8 +196,8 @@ func (c *ApiController) SendSms() {
// @Tag Service API
// @Description This API is not for Casdoor frontend to call, it is for Casdoor SDKs.
// @Param from body controllers.NotificationForm true "Details of the notification request"
// @Success 200 {object} Response object
// @router /api/send-notification [post]
// @Success 200 {object} controllers.Response The Response object
// @router /send-notification [post]
func (c *ApiController) SendNotification() {
provider, err := c.GetProviderFromContext("Notification")
if err != nil {

View File

@ -40,13 +40,13 @@ func (c *ApiController) GetSyncers() {
organization := c.Input().Get("organization")
if limit == "" || page == "" {
organizationSyncers, err := object.GetOrganizationSyncers(owner, organization)
syncers, err := object.GetMaskedSyncers(object.GetOrganizationSyncers(owner, organization))
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(organizationSyncers)
c.ResponseOk(syncers)
} else {
limit := util.ParseInt(limit)
count, err := object.GetSyncerCount(owner, organization, field, value)
@ -56,7 +56,7 @@ func (c *ApiController) GetSyncers() {
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
syncers, err := object.GetPaginationSyncers(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder)
syncers, err := object.GetMaskedSyncers(object.GetPaginationSyncers(owner, organization, paginator.Offset(), limit, field, value, sortField, sortOrder))
if err != nil {
c.ResponseError(err.Error())
return
@ -76,7 +76,7 @@ func (c *ApiController) GetSyncers() {
func (c *ApiController) GetSyncer() {
id := c.Input().Get("id")
syncer, err := object.GetSyncer(id)
syncer, err := object.GetMaskedSyncer(object.GetSyncer(id))
if err != nil {
c.ResponseError(err.Error())
return
@ -168,3 +168,20 @@ func (c *ApiController) RunSyncer() {
c.ResponseOk()
}
func (c *ApiController) TestSyncerDb() {
var syncer object.Syncer
err := json.Unmarshal(c.Ctx.Input.RequestBody, &syncer)
if err != nil {
c.ResponseError(err.Error())
return
}
err = object.TestSyncerDb(syncer)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk()
}

View File

@ -46,7 +46,12 @@ func (c *ApiController) GetSystemInfo() {
// @Success 200 {object} util.VersionInfo The Response object
// @router /get-version-info [get]
func (c *ApiController) GetVersionInfo() {
errInfo := ""
versionInfo, err := util.GetVersionInfo()
if err != nil {
errInfo = "Git error: " + err.Error()
}
if versionInfo.Version != "" {
c.ResponseOk(versionInfo)
return
@ -54,9 +59,11 @@ func (c *ApiController) GetVersionInfo() {
versionInfo, err = util.GetVersionInfoFromFile()
if err != nil {
c.ResponseError(err.Error())
errInfo = errInfo + ", File error: " + err.Error()
c.ResponseError(errInfo)
return
}
c.ResponseOk(versionInfo)
}

View File

@ -16,6 +16,7 @@ package controllers
import (
"encoding/json"
"time"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/object"
@ -156,7 +157,7 @@ func (c *ApiController) DeleteToken() {
// @Success 200 {object} object.TokenWrapper The Response object
// @Success 400 {object} object.TokenError The Response object
// @Success 401 {object} object.TokenError The Response object
// @router api/login/oauth/access_token [post]
// @router /login/oauth/access_token [post]
func (c *ApiController) GetOAuthToken() {
clientId := c.Input().Get("client_id")
clientSecret := c.Input().Get("client_secret")
@ -164,17 +165,19 @@ func (c *ApiController) GetOAuthToken() {
code := c.Input().Get("code")
verifier := c.Input().Get("code_verifier")
scope := c.Input().Get("scope")
nonce := c.Input().Get("nonce")
username := c.Input().Get("username")
password := c.Input().Get("password")
tag := c.Input().Get("tag")
avatar := c.Input().Get("avatar")
refreshToken := c.Input().Get("refresh_token")
deviceCode := c.Input().Get("device_code")
if clientId == "" && clientSecret == "" {
clientId, clientSecret, _ = c.Ctx.Request.BasicAuth()
}
if len(c.Ctx.Input.RequestBody) != 0 {
if len(c.Ctx.Input.RequestBody) != 0 && grantType != "urn:ietf:params:oauth:grant-type:device_code" {
// If clientId is empty, try to read data from RequestBody
var tokenRequest TokenRequest
err := json.Unmarshal(c.Ctx.Input.RequestBody, &tokenRequest)
@ -197,6 +200,9 @@ func (c *ApiController) GetOAuthToken() {
if scope == "" {
scope = tokenRequest.Scope
}
if nonce == "" {
nonce = tokenRequest.Nonce
}
if username == "" {
username = tokenRequest.Username
}
@ -215,8 +221,48 @@ func (c *ApiController) GetOAuthToken() {
}
}
if deviceCode != "" {
deviceAuthCache, ok := object.DeviceAuthMap.Load(deviceCode)
if !ok {
c.Data["json"] = &object.TokenError{
Error: "expired_token",
ErrorDescription: "token is expired",
}
c.SetTokenErrorHttpStatus()
c.ServeJSON()
c.SetTokenErrorHttpStatus()
return
}
deviceAuthCacheCast := deviceAuthCache.(object.DeviceAuthCache)
if !deviceAuthCacheCast.UserSignIn {
c.Data["json"] = &object.TokenError{
Error: "authorization_pending",
ErrorDescription: "authorization pending",
}
c.SetTokenErrorHttpStatus()
c.ServeJSON()
c.SetTokenErrorHttpStatus()
return
}
if deviceAuthCacheCast.RequestAt.Add(time.Second * 120).Before(time.Now()) {
c.Data["json"] = &object.TokenError{
Error: "expired_token",
ErrorDescription: "token is expired",
}
c.SetTokenErrorHttpStatus()
c.ServeJSON()
c.SetTokenErrorHttpStatus()
return
}
object.DeviceAuthMap.Delete(deviceCode)
username = deviceAuthCacheCast.UserName
}
host := c.Ctx.Request.Host
token, err := object.GetOAuthToken(grantType, clientId, clientSecret, code, verifier, scope, username, password, host, refreshToken, tag, avatar, c.GetAcceptLanguage())
token, err := object.GetOAuthToken(grantType, clientId, clientSecret, code, verifier, scope, nonce, username, password, host, refreshToken, tag, avatar, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
@ -271,8 +317,17 @@ func (c *ApiController) RefreshToken() {
c.ServeJSON()
}
func (c *ApiController) ResponseTokenError(errorMsg string) {
c.Data["json"] = &object.TokenError{
Error: errorMsg,
}
c.SetTokenErrorHttpStatus()
c.ServeJSON()
}
// IntrospectToken
// @Title IntrospectToken
// @Tag Login API
// @Description The introspection endpoint is an OAuth 2.0 endpoint that takes a
// parameter representing an OAuth 2.0 token and returns a JSON document
// representing the meta information surrounding the
@ -292,63 +347,122 @@ func (c *ApiController) IntrospectToken() {
clientId = c.Input().Get("client_id")
clientSecret = c.Input().Get("client_secret")
if clientId == "" || clientSecret == "" {
c.ResponseError(c.T("token:Empty clientId or clientSecret"))
c.Data["json"] = &object.TokenError{
Error: object.InvalidRequest,
}
c.SetTokenErrorHttpStatus()
c.ServeJSON()
c.ResponseTokenError(object.InvalidRequest)
return
}
}
application, err := object.GetApplicationByClientId(clientId)
if err != nil {
c.ResponseError(err.Error())
c.ResponseTokenError(err.Error())
return
}
if application == nil || application.ClientSecret != clientSecret {
c.ResponseError(c.T("token:Invalid application or wrong clientSecret"))
c.Data["json"] = &object.TokenError{
Error: object.InvalidClient,
c.ResponseTokenError(c.T("token:Invalid application or wrong clientSecret"))
return
}
respondWithInactiveToken := func() {
c.Data["json"] = &object.IntrospectionResponse{Active: false}
c.ServeJSON()
}
tokenTypeHint := c.Input().Get("token_type_hint")
var token *object.Token
if tokenTypeHint != "" {
token, err = object.GetTokenByTokenValue(tokenValue, tokenTypeHint)
if err != nil {
c.ResponseTokenError(err.Error())
return
}
if token == nil || token.ExpiresIn <= 0 {
respondWithInactiveToken()
return
}
if token.ExpiresIn <= 0 {
c.Data["json"] = &object.IntrospectionResponse{Active: false}
c.ServeJSON()
return
}
c.SetTokenErrorHttpStatus()
return
}
token, err := object.GetTokenByTokenAndApplication(tokenValue, application.Name)
if err != nil {
c.ResponseError(err.Error())
return
}
if token == nil {
c.Data["json"] = &object.IntrospectionResponse{Active: false}
c.ServeJSON()
return
}
jwtToken, err := object.ParseJwtTokenByApplication(tokenValue, application)
if err != nil || jwtToken.Valid() != nil {
// and token revoked case. but we not implement
// TODO: 2022-03-03 add token revoked check, when we implemented the Token Revocation(rfc7009) Specs.
// refs: https://tools.ietf.org/html/rfc7009
c.Data["json"] = &object.IntrospectionResponse{Active: false}
c.ServeJSON()
return
var introspectionResponse object.IntrospectionResponse
if application.TokenFormat == "JWT-Standard" {
jwtToken, err := object.ParseStandardJwtTokenByApplication(tokenValue, application)
if err != nil {
// and token revoked case. but we not implement
// TODO: 2022-03-03 add token revoked check, when we implemented the Token Revocation(rfc7009) Specs.
// refs: https://tools.ietf.org/html/rfc7009
respondWithInactiveToken()
return
}
introspectionResponse = object.IntrospectionResponse{
Active: true,
Scope: jwtToken.Scope,
ClientId: clientId,
Username: jwtToken.Name,
TokenType: jwtToken.TokenType,
Exp: jwtToken.ExpiresAt.Unix(),
Iat: jwtToken.IssuedAt.Unix(),
Nbf: jwtToken.NotBefore.Unix(),
Sub: jwtToken.Subject,
Aud: jwtToken.Audience,
Iss: jwtToken.Issuer,
Jti: jwtToken.ID,
}
} else {
jwtToken, err := object.ParseJwtTokenByApplication(tokenValue, application)
if err != nil {
// and token revoked case. but we not implement
// TODO: 2022-03-03 add token revoked check, when we implemented the Token Revocation(rfc7009) Specs.
// refs: https://tools.ietf.org/html/rfc7009
respondWithInactiveToken()
return
}
introspectionResponse = object.IntrospectionResponse{
Active: true,
ClientId: clientId,
Exp: jwtToken.ExpiresAt.Unix(),
Iat: jwtToken.IssuedAt.Unix(),
Nbf: jwtToken.NotBefore.Unix(),
Sub: jwtToken.Subject,
Aud: jwtToken.Audience,
Iss: jwtToken.Issuer,
Jti: jwtToken.ID,
}
if jwtToken.Scope != "" {
introspectionResponse.Scope = jwtToken.Scope
}
if jwtToken.Name != "" {
introspectionResponse.Username = jwtToken.Name
}
if jwtToken.TokenType != "" {
introspectionResponse.TokenType = jwtToken.TokenType
}
}
c.Data["json"] = &object.IntrospectionResponse{
Active: true,
Scope: jwtToken.Scope,
ClientId: clientId,
Username: token.User,
TokenType: token.TokenType,
Exp: jwtToken.ExpiresAt.Unix(),
Iat: jwtToken.IssuedAt.Unix(),
Nbf: jwtToken.NotBefore.Unix(),
Sub: jwtToken.Subject,
Aud: jwtToken.Audience,
Iss: jwtToken.Issuer,
Jti: jwtToken.ID,
if tokenTypeHint == "" {
token, err = object.GetTokenByTokenValue(tokenValue, introspectionResponse.TokenType)
if err != nil {
c.ResponseTokenError(err.Error())
return
}
if token == nil || token.ExpiresIn <= 0 {
respondWithInactiveToken()
return
}
}
if token != nil {
introspectionResponse.TokenType = token.TokenType
}
c.Data["json"] = introspectionResponse
c.ServeJSON()
}

167
controllers/transaction.go Normal file
View File

@ -0,0 +1,167 @@
// Copyright 2024 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"
)
// GetTransactions
// @Title GetTransactions
// @Tag Transaction API
// @Description get transactions
// @Param owner query string true "The owner of transactions"
// @Success 200 {array} object.Transaction The Response object
// @router /get-transactions [get]
func (c *ApiController) GetTransactions() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
if limit == "" || page == "" {
transactions, err := object.GetTransactions(owner)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(transactions)
} else {
limit := util.ParseInt(limit)
count, err := object.GetTransactionCount(owner, field, value)
if err != nil {
c.ResponseError(err.Error())
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
transactions, err := object.GetPaginationTransactions(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(transactions, paginator.Nums())
}
}
// GetUserTransactions
// @Title GetUserTransaction
// @Tag Transaction API
// @Description get transactions for a user
// @Param owner query string true "The owner of transactions"
// @Param organization query string true "The organization of the user"
// @Param user query string true "The username of the user"
// @Success 200 {array} object.Transaction The Response object
// @router /get-user-transactions [get]
func (c *ApiController) GetUserTransactions() {
owner := c.Input().Get("owner")
user := c.Input().Get("user")
transactions, err := object.GetUserTransactions(owner, user)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(transactions)
}
// GetTransaction
// @Title GetTransaction
// @Tag Transaction API
// @Description get transaction
// @Param id query string true "The id ( owner/name ) of the transaction"
// @Success 200 {object} object.Transaction The Response object
// @router /get-transaction [get]
func (c *ApiController) GetTransaction() {
id := c.Input().Get("id")
transaction, err := object.GetTransaction(id)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(transaction)
}
// UpdateTransaction
// @Title UpdateTransaction
// @Tag Transaction API
// @Description update transaction
// @Param id query string true "The id ( owner/name ) of the transaction"
// @Param body body object.Transaction true "The details of the transaction"
// @Success 200 {object} controllers.Response The Response object
// @router /update-transaction [post]
func (c *ApiController) UpdateTransaction() {
id := c.Input().Get("id")
var transaction object.Transaction
err := json.Unmarshal(c.Ctx.Input.RequestBody, &transaction)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.UpdateTransaction(id, &transaction))
c.ServeJSON()
}
// AddTransaction
// @Title AddTransaction
// @Tag Transaction API
// @Description add transaction
// @Param body body object.Transaction true "The details of the transaction"
// @Success 200 {object} controllers.Response The Response object
// @router /add-transaction [post]
func (c *ApiController) AddTransaction() {
var transaction object.Transaction
err := json.Unmarshal(c.Ctx.Input.RequestBody, &transaction)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.AddTransaction(&transaction))
c.ServeJSON()
}
// DeleteTransaction
// @Title DeleteTransaction
// @Tag Transaction API
// @Description delete transaction
// @Param body body object.Transaction true "The details of the transaction"
// @Success 200 {object} controllers.Response The Response object
// @router /delete-transaction [post]
func (c *ApiController) DeleteTransaction() {
var transaction object.Transaction
err := json.Unmarshal(c.Ctx.Input.RequestBody, &transaction)
if err != nil {
c.ResponseError(err.Error())
return
}
c.Data["json"] = wrapActionResponse(object.DeleteTransaction(&transaction))
c.ServeJSON()
}

View File

@ -21,6 +21,7 @@ type TokenRequest struct {
Code string `json:"code"`
Verifier string `json:"code_verifier"`
Scope string `json:"scope"`
Nonce string `json:"nonce"`
Username string `json:"username"`
Password string `json:"password"`
Tag string `json:"tag"`

View File

@ -20,6 +20,7 @@ import (
"strings"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
)
@ -39,13 +40,13 @@ func (c *ApiController) GetGlobalUsers() {
sortOrder := c.Input().Get("sortOrder")
if limit == "" || page == "" {
maskedUsers, err := object.GetMaskedUsers(object.GetGlobalUsers())
users, err := object.GetMaskedUsers(object.GetGlobalUsers())
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(maskedUsers)
c.ResponseOk(users)
} else {
limit := util.ParseInt(limit)
count, err := object.GetGlobalUserCount(field, value)
@ -90,22 +91,22 @@ func (c *ApiController) GetUsers() {
if limit == "" || page == "" {
if groupName != "" {
maskedUsers, err := object.GetMaskedUsers(object.GetGroupUsers(util.GetId(owner, groupName)))
users, err := object.GetMaskedUsers(object.GetGroupUsers(util.GetId(owner, groupName)))
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(maskedUsers)
c.ResponseOk(users)
return
}
maskedUsers, err := object.GetMaskedUsers(object.GetUsers(owner))
users, err := object.GetMaskedUsers(object.GetUsers(owner))
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(maskedUsers)
c.ResponseOk(users)
} else {
limit := util.ParseInt(limit)
count, err := object.GetUserCount(owner, field, value, groupName)
@ -156,6 +157,10 @@ func (c *ApiController) GetUser() {
c.ResponseError(err.Error())
return
}
if userFromUserId == nil {
c.ResponseOk(nil)
return
}
id = util.GetId(userFromUserId.Owner, userFromUserId.Name)
}
@ -175,26 +180,6 @@ func (c *ApiController) GetUser() {
owner = util.GetOwnerFromId(id)
}
var organization *object.Organization
organization, err = object.GetOrganization(util.GetId("admin", owner))
if err != nil {
c.ResponseError(err.Error())
return
}
if organization == nil {
c.ResponseError(fmt.Sprintf("the organization: %s is not found", owner))
return
}
if !organization.IsProfilePublic {
requestUserId := c.GetSessionUsername()
hasPermission, err := object.CheckUserPermission(requestUserId, id, false, c.GetAcceptLanguage())
if !hasPermission {
c.ResponseError(err.Error())
return
}
}
switch {
case email != "":
user, err = object.GetUserByEmail(owner, email)
@ -212,6 +197,29 @@ func (c *ApiController) GetUser() {
return
}
var organization *object.Organization
if user != nil {
organization, err = object.GetOrganizationByUser(user)
if err != nil {
c.ResponseError(err.Error())
return
}
if organization == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:The organization: %s does not exist"), owner))
return
}
if !organization.IsProfilePublic {
requestUserId := c.GetSessionUsername()
var hasPermission bool
hasPermission, err = object.CheckUserPermission(requestUserId, user.GetId(), false, c.GetAcceptLanguage())
if !hasPermission {
c.ResponseError(err.Error())
return
}
}
}
if user != nil {
user.MultiFactorAuths = object.GetAllMfaProps(user, true)
}
@ -223,13 +231,21 @@ func (c *ApiController) GetUser() {
}
isAdminOrSelf := c.IsAdminOrSelf(user)
maskedUser, err := object.GetMaskedUser(user, isAdminOrSelf)
user, err = object.GetMaskedUser(user, isAdminOrSelf)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(maskedUser)
if organization != nil && user != nil {
user, err = object.GetFilteredUser(user, c.IsAdmin(), c.IsAdminOrSelf(user), organization.AccountItems)
if err != nil {
c.ResponseError(err.Error())
return
}
}
c.ResponseOk(user)
}
// UpdateUser
@ -274,11 +290,14 @@ func (c *ApiController) UpdateUser() {
return
}
if c.Input().Get("allowEmpty") == "" {
if user.DisplayName == "" {
c.ResponseError(c.T("user:Display name cannot be empty"))
return
}
if user.MfaEmailEnabled && user.Email == "" {
c.ResponseError(c.T("user:MFA email is enabled but email is empty"))
return
}
if user.MfaPhoneEnabled && user.Phone == "" {
c.ResponseError(c.T("user:MFA phone is enabled but phone number is empty"))
return
}
if msg := object.CheckUpdateUser(oldUser, &user, c.GetAcceptLanguage()); msg != "" {
@ -286,8 +305,14 @@ func (c *ApiController) UpdateUser() {
return
}
isUsernameLowered := conf.GetConfigBool("isUsernameLowered")
if isUsernameLowered {
user.Name = strings.ToLower(user.Name)
}
isAdmin := c.IsAdmin()
if pass, err := object.CheckPermissionForUpdateUser(oldUser, &user, isAdmin, c.GetAcceptLanguage()); !pass {
allowDisplayNameEmpty := c.Input().Get("allowEmpty") != ""
if pass, err := object.CheckPermissionForUpdateUser(oldUser, &user, isAdmin, allowDisplayNameEmpty, c.GetAcceptLanguage()); !pass {
c.ResponseError(err)
return
}
@ -330,24 +355,19 @@ func (c *ApiController) AddUser() {
return
}
count, err := object.GetUserCount("", "", "", "")
if err != nil {
if err := checkQuotaForUser(); err != nil {
c.ResponseError(err.Error())
return
}
if err := checkQuotaForUser(int(count)); err != nil {
c.ResponseError(err.Error())
return
}
msg := object.CheckUsername(user.Name, c.GetAcceptLanguage())
emptyUser := object.User{}
msg := object.CheckUpdateUser(&emptyUser, &user, c.GetAcceptLanguage())
if msg != "" {
c.ResponseError(msg)
return
}
c.Data["json"] = wrapActionResponse(object.AddUser(&user))
c.Data["json"] = wrapActionResponse(object.AddUser(&user, c.GetAcceptLanguage()))
c.ServeJSON()
}
@ -387,6 +407,12 @@ func (c *ApiController) GetEmailAndPhone() {
organization := c.Ctx.Request.Form.Get("organization")
username := c.Ctx.Request.Form.Get("username")
enableErrorMask2 := conf.GetConfigBool("enableErrorMask2")
if enableErrorMask2 {
c.ResponseError("Error")
return
}
user, err := object.GetUserByFields(organization, username)
if err != nil {
c.ResponseError(err.Error())
@ -433,10 +459,10 @@ func (c *ApiController) SetPassword() {
newPassword := c.Ctx.Request.Form.Get("newPassword")
code := c.Ctx.Request.Form.Get("code")
//if userOwner == "built-in" && userName == "admin" {
// if userOwner == "built-in" && userName == "admin" {
// c.ResponseError(c.T("auth:Unauthorized operation"))
// return
//}
// }
if strings.Contains(newPassword, " ") {
c.ResponseError(c.T("user:New password cannot contain blank space."))
@ -445,6 +471,16 @@ func (c *ApiController) SetPassword() {
userId := util.GetId(userOwner, userName)
user, err := object.GetUser(userId)
if err != nil {
c.ResponseError(err.Error())
return
}
if user == nil {
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), userId))
return
}
requestUserId := c.GetSessionUsername()
if requestUserId == "" && code == "" {
c.ResponseError(c.T("general:Please login first"), "Please login first")
@ -460,7 +496,12 @@ func (c *ApiController) SetPassword() {
c.ResponseError(c.T("general:Missing parameter"))
return
}
if userId != c.GetSession("verifiedUserId") {
c.ResponseError(c.T("general:Wrong userId"))
return
}
c.SetSession("verifiedCode", "")
c.SetSession("verifiedUserId", "")
}
targetUser, err := object.GetUser(userId)
@ -483,7 +524,11 @@ func (c *ApiController) SetPassword() {
}
}
} else if code == "" {
err = object.CheckPassword(targetUser, oldPassword, c.GetAcceptLanguage())
if user.Ldap == "" {
err = object.CheckPassword(targetUser, oldPassword, c.GetAcceptLanguage())
} else {
err = object.CheckLdapUserPassword(targetUser, oldPassword, c.GetAcceptLanguage())
}
if err != nil {
c.ResponseError(err.Error())
return
@ -496,8 +541,48 @@ func (c *ApiController) SetPassword() {
return
}
organization, err := object.GetOrganizationByUser(targetUser)
if err != nil {
c.ResponseError(err.Error())
return
}
if organization == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:the organization: %s is not found"), targetUser.Owner))
return
}
application, err := object.GetApplicationByUser(targetUser)
if err != nil {
c.ResponseError(err.Error())
return
}
if application == nil {
c.ResponseError(fmt.Sprintf(c.T("auth:the application for user %s is not found"), userId))
return
}
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
err = object.CheckEntryIp(clientIp, targetUser, application, organization, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
}
targetUser.Password = newPassword
_, err = object.SetUserField(targetUser, "password", targetUser.Password)
targetUser.UpdateUserPassword(organization)
targetUser.NeedUpdatePassword = false
targetUser.LastChangePasswordTime = util.GetCurrentTime()
if user.Ldap == "" {
_, err = object.UpdateUser(userId, targetUser, []string{"password", "password_salt", "need_update_password", "password_type", "last_change_password_time"}, false)
} else {
if isAdmin {
err = object.ResetLdapPassword(targetUser, "", newPassword, c.GetAcceptLanguage())
} else {
err = object.ResetLdapPassword(targetUser, oldPassword, newPassword, c.GetAcceptLanguage())
}
}
if err != nil {
c.ResponseError(err.Error())
return
@ -510,6 +595,7 @@ func (c *ApiController) SetPassword() {
// @Title CheckUserPassword
// @router /check-user-password [post]
// @Tag User API
// @Success 200 {object} object.Userinfo The Response object
func (c *ApiController) CheckUserPassword() {
var user object.User
err := json.Unmarshal(c.Ctx.Input.RequestBody, &user)
@ -518,7 +604,11 @@ func (c *ApiController) CheckUserPassword() {
return
}
_, err = object.CheckUserPassword(user.Owner, user.Name, user.Password, c.GetAcceptLanguage())
/*
* Verified password with user as subject, if field ldap not empty,
* then `isPasswordWithLdapEnabled` is true
*/
_, err = object.CheckUserPassword(user.Owner, user.Name, user.Password, c.GetAcceptLanguage(), false, false, user.Ldap != "")
if err != nil {
c.ResponseError(err.Error())
} else {
@ -540,13 +630,13 @@ func (c *ApiController) GetSortedUsers() {
sorter := c.Input().Get("sorter")
limit := util.ParseInt(c.Input().Get("limit"))
maskedUsers, err := object.GetMaskedUsers(object.GetSortedUsers(owner, sorter, limit))
users, err := object.GetMaskedUsers(object.GetSortedUsers(owner, sorter, limit))
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(maskedUsers)
c.ResponseOk(users)
}
// GetUserCount
@ -580,6 +670,7 @@ func (c *ApiController) GetUserCount() {
// @Title AddUserKeys
// @router /add-user-keys [post]
// @Tag User API
// @Success 200 {object} object.Userinfo The Response object
func (c *ApiController) AddUserKeys() {
var user object.User
err := json.Unmarshal(c.Ctx.Input.RequestBody, &user)
@ -614,7 +705,7 @@ func (c *ApiController) RemoveUserFromGroup() {
return
}
affected, err := object.DeleteGroupForUser(util.GetId(owner, name), groupName)
affected, err := object.DeleteGroupForUser(util.GetId(owner, name), util.GetId(owner, groupName))
if err != nil {
c.ResponseError(err.Error())
return

View File

@ -67,6 +67,6 @@ func (c *ApiController) UploadUsers() {
if affected {
c.ResponseOk()
} else {
c.ResponseError(c.T("user_upload:Failed to import users"))
c.ResponseError(c.T("general:Failed to import users"))
}
}

View File

@ -45,6 +45,22 @@ func (c *ApiController) ResponseOk(data ...interface{}) {
// ResponseError ...
func (c *ApiController) ResponseError(error string, data ...interface{}) {
enableErrorMask2 := conf.GetConfigBool("enableErrorMask2")
if enableErrorMask2 {
error = c.T("subscription:Error")
resp := &Response{Status: "error", Msg: error}
c.ResponseJsonData(resp, data...)
return
}
enableErrorMask := conf.GetConfigBool("enableErrorMask")
if enableErrorMask {
if strings.HasPrefix(error, "The user: ") && strings.HasSuffix(error, " doesn't exist") || strings.HasPrefix(error, "用户: ") && strings.HasSuffix(error, "不存在") {
error = c.T("check:password or code is incorrect")
}
}
resp := &Response{Status: "error", Msg: error}
c.ResponseJsonData(resp, data...)
}
@ -96,7 +112,7 @@ func (c *ApiController) RequireSignedInUser() (*object.User, bool) {
return nil, false
}
if strings.HasPrefix(userId, "app/") {
if object.IsAppUser(userId) {
tmpUserId := c.Input().Get("userId")
if tmpUserId != "" {
userId = tmpUserId
@ -108,12 +124,12 @@ func (c *ApiController) RequireSignedInUser() (*object.User, bool) {
c.ResponseError(err.Error())
return nil, false
}
if user == nil {
c.ClearUserSession()
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), userId))
return nil, false
}
return user, true
}
@ -127,9 +143,39 @@ func (c *ApiController) RequireAdmin() (string, bool) {
if user.Owner == "built-in" {
return "", true
}
if !user.IsAdmin {
c.ResponseError(c.T("general:this operation requires administrator to perform"))
return "", false
}
return user.Owner, true
}
func (c *ApiController) IsOrgAdmin() (bool, bool) {
userId, ok := c.RequireSignedIn()
if !ok {
return false, true
}
if object.IsAppUser(userId) {
return true, true
}
user, err := object.GetUser(userId)
if err != nil {
c.ResponseError(err.Error())
return false, false
}
if user == nil {
c.ClearUserSession()
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), userId))
return false, false
}
return user.IsAdmin, true
}
// IsMaskedEnabled ...
func (c *ApiController) IsMaskedEnabled() (bool, bool) {
isMaskEnabled := true
@ -248,12 +294,18 @@ func checkQuotaForProvider(count int) error {
return nil
}
func checkQuotaForUser(count int) error {
func checkQuotaForUser() error {
quota := conf.GetConfigQuota().User
if quota == -1 {
return nil
}
if count >= quota {
count, err := object.GetUserCount("", "", "", "")
if err != nil {
return err
}
if int(count) >= quota {
return fmt.Errorf("user quota is exceeded")
}
return nil

View File

@ -20,6 +20,7 @@ import (
"fmt"
"strings"
"github.com/beego/beego/utils/pagination"
"github.com/casdoor/casdoor/captcha"
"github.com/casdoor/casdoor/form"
"github.com/casdoor/casdoor/object"
@ -35,10 +36,95 @@ const (
MfaAuthVerification = "mfaAuth"
)
// GetVerifications
// @Title GetVerifications
// @Tag Verification API
// @Description get payments
// @Param owner query string true "The owner of payments"
// @Success 200 {array} object.Verification The Response object
// @router /get-payments [get]
func (c *ApiController) GetVerifications() {
owner := c.Input().Get("owner")
limit := c.Input().Get("pageSize")
page := c.Input().Get("p")
field := c.Input().Get("field")
value := c.Input().Get("value")
sortField := c.Input().Get("sortField")
sortOrder := c.Input().Get("sortOrder")
if limit == "" || page == "" {
payments, err := object.GetVerifications(owner)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(payments)
} else {
limit := util.ParseInt(limit)
count, err := object.GetVerificationCount(owner, field, value)
if err != nil {
c.ResponseError(err.Error())
return
}
paginator := pagination.SetPaginator(c.Ctx, limit, count)
payments, err := object.GetPaginationVerifications(owner, paginator.Offset(), limit, field, value, sortField, sortOrder)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(payments, paginator.Nums())
}
}
// GetUserVerifications
// @Title GetUserVerifications
// @Tag Verification API
// @Description get payments for a user
// @Param owner query string true "The owner of payments"
// @Param organization query string true "The organization of the user"
// @Param user query string true "The username of the user"
// @Success 200 {array} object.Verification The Response object
// @router /get-user-payments [get]
func (c *ApiController) GetUserVerifications() {
owner := c.Input().Get("owner")
user := c.Input().Get("user")
payments, err := object.GetUserVerifications(owner, user)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(payments)
}
// GetVerification
// @Title GetVerification
// @Tag Verification API
// @Description get payment
// @Param id query string true "The id ( owner/name ) of the payment"
// @Success 200 {object} object.Verification The Response object
// @router /get-payment [get]
func (c *ApiController) GetVerification() {
id := c.Input().Get("id")
payment, err := object.GetVerification(id)
if err != nil {
c.ResponseError(err.Error())
return
}
c.ResponseOk(payment)
}
// SendVerificationCode ...
// @Title SendVerificationCode
// @Tag Verification API
// @router /send-verification-code [post]
// @Success 200 {object} object.Userinfo The Response object
func (c *ApiController) SendVerificationCode() {
var vform form.VerificationForm
err := c.ParseForm(&vform)
@ -46,24 +132,42 @@ func (c *ApiController) SendVerificationCode() {
c.ResponseError(err.Error())
return
}
remoteAddr := util.GetIPFromRequest(c.Ctx.Request)
clientIp := util.GetClientIpFromRequest(c.Ctx.Request)
if msg := vform.CheckParameter(form.SendVerifyCode, c.GetAcceptLanguage()); msg != "" {
c.ResponseError(msg)
return
}
if vform.CaptchaType != "none" {
if captchaProvider := captcha.GetCaptchaProvider(vform.CaptchaType); captchaProvider == nil {
c.ResponseError(c.T("general:don't support captchaProvider: ") + vform.CaptchaType)
return
} else if isHuman, err := captchaProvider.VerifyCaptcha(vform.CaptchaToken, vform.ClientSecret); err != nil {
c.ResponseError(err.Error())
return
} else if !isHuman {
provider, err := object.GetCaptchaProviderByApplication(vform.ApplicationId, "false", c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
}
if provider != nil {
if vform.CaptchaType != provider.Type {
c.ResponseError(c.T("verification:Turing test failed."))
return
}
if provider.Type != "Default" {
vform.ClientSecret = provider.ClientSecret
}
if vform.CaptchaType != "none" {
if captchaProvider := captcha.GetCaptchaProvider(vform.CaptchaType); captchaProvider == nil {
c.ResponseError(c.T("general:don't support captchaProvider: ") + vform.CaptchaType)
return
} else if isHuman, err := captchaProvider.VerifyCaptcha(vform.CaptchaToken, provider.ClientId, vform.ClientSecret, provider.ClientId2); err != nil {
c.ResponseError(err.Error())
return
} else if !isHuman {
c.ResponseError(c.T("verification:Turing test failed."))
return
}
}
}
application, err := object.GetApplication(vform.ApplicationId)
@ -91,6 +195,15 @@ func (c *ApiController) SendVerificationCode() {
c.ResponseError(err.Error())
return
}
if user == nil || user.IsDeleted {
c.ResponseError(c.T("verification:the user does not exist, please sign up first"))
return
}
if user.IsForbidden {
c.ResponseError(c.T("check:The user is forbidden to sign in, please contact the administrator"))
return
}
}
// mfaUserSession != "", means method is MfaAuthVerification
@ -129,25 +242,23 @@ func (c *ApiController) SendVerificationCode() {
} else if vform.Method == ResetVerification {
user = c.getCurrentUser()
} else if vform.Method == MfaAuthVerification {
mfaProps := user.GetPreferredMfaProps(false)
mfaProps := user.GetMfaProps(object.EmailType, false)
if user != nil && util.GetMaskedEmail(mfaProps.Secret) == vform.Dest {
vform.Dest = mfaProps.Secret
}
} else if vform.Method == MfaSetupVerification {
c.SetSession(object.MfaDestSession, vform.Dest)
}
provider, err := application.GetEmailProvider()
provider, err = application.GetEmailProvider(vform.Method)
if err != nil {
c.ResponseError(err.Error())
return
}
if provider == nil {
c.ResponseError(fmt.Sprintf("please add an Email provider to the \"Providers\" list for the application: %s", application.Name))
c.ResponseError(fmt.Sprintf(c.T("verification:please add an Email provider to the \"Providers\" list for the application: %s"), application.Name))
return
}
sendResp = object.SendVerificationCodeToEmail(organization, user, provider, remoteAddr, vform.Dest)
sendResp = object.SendVerificationCodeToEmail(organization, user, provider, clientIp, vform.Dest)
case object.VerifyTypePhone:
if vform.Method == LoginVerification || vform.Method == ForgetVerification {
if user != nil && util.GetMaskedPhone(user.Phone) == vform.Dest {
@ -169,27 +280,23 @@ func (c *ApiController) SendVerificationCode() {
vform.CountryCode = user.GetCountryCode(vform.CountryCode)
}
}
if vform.Method == MfaSetupVerification {
c.SetSession(object.MfaCountryCodeSession, vform.CountryCode)
c.SetSession(object.MfaDestSession, vform.Dest)
}
} else if vform.Method == MfaAuthVerification {
mfaProps := user.GetPreferredMfaProps(false)
mfaProps := user.GetMfaProps(object.SmsType, false)
if user != nil && util.GetMaskedPhone(mfaProps.Secret) == vform.Dest {
vform.Dest = mfaProps.Secret
}
vform.CountryCode = mfaProps.CountryCode
vform.CountryCode = user.GetCountryCode(vform.CountryCode)
}
provider, err := application.GetSmsProvider()
provider, err = application.GetSmsProvider(vform.Method, vform.CountryCode)
if err != nil {
c.ResponseError(err.Error())
return
}
if provider == nil {
c.ResponseError(fmt.Sprintf("please add a SMS provider to the \"Providers\" list for the application: %s", application.Name))
c.ResponseError(fmt.Sprintf(c.T("verification:please add a SMS provider to the \"Providers\" list for the application: %s"), application.Name))
return
}
@ -197,7 +304,7 @@ func (c *ApiController) SendVerificationCode() {
c.ResponseError(fmt.Sprintf(c.T("verification:Phone number is invalid in your region %s"), vform.CountryCode))
return
} else {
sendResp = object.SendVerificationCodeToPhone(organization, user, provider, remoteAddr, phone)
sendResp = object.SendVerificationCodeToPhone(organization, user, provider, clientIp, phone)
}
}
@ -212,6 +319,7 @@ func (c *ApiController) SendVerificationCode() {
// @Title VerifyCaptcha
// @Tag Verification API
// @router /verify-captcha [post]
// @Success 200 {object} object.Userinfo The Response object
func (c *ApiController) VerifyCaptcha() {
var vform form.VerificationForm
err := c.ParseForm(&vform)
@ -225,13 +333,23 @@ func (c *ApiController) VerifyCaptcha() {
return
}
captchaProvider, err := object.GetCaptchaProviderByOwnerName(vform.ApplicationId, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
}
if captchaProvider.Type != "Default" {
vform.ClientSecret = captchaProvider.ClientSecret
}
provider := captcha.GetCaptchaProvider(vform.CaptchaType)
if provider == nil {
c.ResponseError(c.T("verification:Invalid captcha provider."))
return
}
isValid, err := provider.VerifyCaptcha(vform.CaptchaToken, vform.ClientSecret)
isValid, err := provider.VerifyCaptcha(vform.CaptchaToken, captchaProvider.ClientId, vform.ClientSecret, captchaProvider.ClientId2)
if err != nil {
c.ResponseError(err.Error())
return
@ -243,7 +361,8 @@ func (c *ApiController) VerifyCaptcha() {
// ResetEmailOrPhone ...
// @Tag Account API
// @Title ResetEmailOrPhone
// @router /api/reset-email-or-phone [post]
// @router /reset-email-or-phone [post]
// @Success 200 {object} object.Userinfo The Response object
func (c *ApiController) ResetEmailOrPhone() {
user, ok := c.RequireSignedInUser()
if !ok {
@ -304,7 +423,12 @@ func (c *ApiController) ResetEmailOrPhone() {
}
}
if result := object.CheckVerificationCode(checkDest, code, c.GetAcceptLanguage()); result.Code != object.VerificationSuccess {
result, err := object.CheckVerificationCode(checkDest, code, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(c.T(err.Error()))
return
}
if result.Code != object.VerificationSuccess {
c.ResponseError(result.Msg)
return
}
@ -312,7 +436,8 @@ func (c *ApiController) ResetEmailOrPhone() {
switch destType {
case object.VerifyTypeEmail:
user.Email = dest
_, err = object.SetUserField(user, "email", user.Email)
user.EmailVerified = true
_, err = object.UpdateUser(user.GetId(), user, []string{"email", "email_verified"}, false)
case object.VerifyTypePhone:
user.Phone = dest
_, err = object.SetUserField(user, "phone", user.Phone)
@ -337,7 +462,8 @@ func (c *ApiController) ResetEmailOrPhone() {
// VerifyCode
// @Tag Verification API
// @Title VerifyCode
// @router /api/verify-code [post]
// @router /verify-code [post]
// @Success 200 {object} object.Userinfo The Response object
func (c *ApiController) VerifyCode() {
var authForm form.AuthForm
err := json.Unmarshal(c.Ctx.Input.RequestBody, &authForm)
@ -385,16 +511,31 @@ func (c *ApiController) VerifyCode() {
}
}
if result := object.CheckVerificationCode(checkDest, authForm.Code, c.GetAcceptLanguage()); result.Code != object.VerificationSuccess {
c.ResponseError(result.Msg)
return
}
err = object.DisableVerificationCode(checkDest)
passed, err := c.checkOrgMasterVerificationCode(user, authForm.Code)
if err != nil {
c.ResponseError(err.Error())
c.ResponseError(c.T(err.Error()))
return
}
c.SetSession("verifiedCode", authForm.Code)
if !passed {
result, err := object.CheckVerificationCode(checkDest, authForm.Code, c.GetAcceptLanguage())
if err != nil {
c.ResponseError(err.Error())
return
}
if result.Code != object.VerificationSuccess {
c.ResponseError(result.Msg)
return
}
err = object.DisableVerificationCode(checkDest)
if err != nil {
c.ResponseError(err.Error())
return
}
}
c.SetSession("verifiedCode", authForm.Code)
c.SetSession("verifiedUserId", user.GetId())
c.ResponseOk()
}

View File

@ -0,0 +1,36 @@
// Copyright 2025 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 (
"fmt"
"github.com/casdoor/casdoor/object"
)
func (c *ApiController) checkOrgMasterVerificationCode(user *object.User, code string) (bool, error) {
organization, err := object.GetOrganizationByUser(user)
if err != nil {
return false, err
}
if organization == nil {
return false, fmt.Errorf("The organization: %s does not exist", user.Owner)
}
if organization.MasterVerificationCode != "" && organization.MasterVerificationCode == code {
return true, nil
}
return false, nil
}

View File

@ -16,7 +16,7 @@ package controllers
import (
"bytes"
"fmt"
"encoding/base64"
"io"
"github.com/casdoor/casdoor/form"
@ -118,24 +118,7 @@ func (c *ApiController) WebAuthnSigninBegin() {
return
}
userOwner := c.Input().Get("owner")
userName := c.Input().Get("name")
user, err := object.GetUserByFields(userOwner, userName)
if err != nil {
c.ResponseError(err.Error())
return
}
if user == nil {
c.ResponseError(fmt.Sprintf(c.T("general:The user: %s doesn't exist"), util.GetId(userOwner, userName)))
return
}
if len(user.WebauthnCredentials) == 0 {
c.ResponseError(c.T("webauthn:Found no credentials for this user"))
return
}
options, sessionData, err := webauthnObj.BeginLogin(user)
options, sessionData, err := webauthnObj.BeginDiscoverableLogin()
if err != nil {
c.ResponseError(err.Error())
return
@ -146,7 +129,7 @@ func (c *ApiController) WebAuthnSigninBegin() {
}
// WebAuthnSigninFinish
// @Title WebAuthnSigninBegin
// @Title WebAuthnSigninFinish
// @Tag Login API
// @Description WebAuthn Login Flow 2nd stage
// @Param body body protocol.CredentialAssertionResponse true "authenticator assertion Response"
@ -168,20 +151,23 @@ func (c *ApiController) WebAuthnSigninFinish() {
return
}
c.Ctx.Request.Body = io.NopCloser(bytes.NewBuffer(c.Ctx.Input.RequestBody))
userId := string(sessionData.UserID)
user, err := object.GetUser(userId)
if err != nil {
c.ResponseError(err.Error())
return
var user *object.User
handler := func(rawID, userHandle []byte) (webauthn.User, error) {
user, err = object.GetUserByWebauthID(base64.StdEncoding.EncodeToString(rawID))
if err != nil {
return nil, err
}
return user, nil
}
_, err = webauthnObj.FinishLogin(user, sessionData, c.Ctx.Request)
_, err = webauthnObj.FinishDiscoverableLogin(handler, sessionData, c.Ctx.Request)
if err != nil {
c.ResponseError(err.Error())
return
}
c.SetSessionUsername(userId)
util.LogInfo(c.Ctx, "API: [%s] signed in", userId)
c.SetSessionUsername(user.GetId())
util.LogInfo(c.Ctx, "API: [%s] signed in", user.GetId())
var application *object.Application

View File

@ -23,7 +23,7 @@ func NewArgon2idCredManager() *Argon2idCredManager {
return cm
}
func (cm *Argon2idCredManager) GetHashedPassword(password string, userSalt string, organizationSalt string) string {
func (cm *Argon2idCredManager) GetHashedPassword(password string, salt string) string {
hash, err := argon2id.CreateHash(password, argon2id.DefaultParams)
if err != nil {
return ""
@ -31,7 +31,7 @@ func (cm *Argon2idCredManager) GetHashedPassword(password string, userSalt strin
return hash
}
func (cm *Argon2idCredManager) IsPasswordCorrect(plainPwd string, hashedPwd string, userSalt string, organizationSalt string) bool {
func (cm *Argon2idCredManager) IsPasswordCorrect(plainPwd string, hashedPwd string, salt string) bool {
match, _ := argon2id.ComparePasswordAndHash(plainPwd, hashedPwd)
return match
}

View File

@ -9,7 +9,7 @@ func NewBcryptCredManager() *BcryptCredManager {
return cm
}
func (cm *BcryptCredManager) GetHashedPassword(password string, userSalt string, organizationSalt string) string {
func (cm *BcryptCredManager) GetHashedPassword(password string, salt string) string {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return ""
@ -17,7 +17,7 @@ func (cm *BcryptCredManager) GetHashedPassword(password string, userSalt string,
return string(bytes)
}
func (cm *BcryptCredManager) IsPasswordCorrect(plainPwd string, hashedPwd string, userSalt string, organizationSalt string) bool {
func (cm *BcryptCredManager) IsPasswordCorrect(plainPwd string, hashedPwd string, salt string) bool {
err := bcrypt.CompareHashAndPassword([]byte(hashedPwd), []byte(plainPwd))
return err == nil
}

View File

@ -15,8 +15,8 @@
package cred
type CredManager interface {
GetHashedPassword(password string, userSalt string, organizationSalt string) string
IsPasswordCorrect(password string, passwordHash string, userSalt string, organizationSalt string) bool
GetHashedPassword(password string, salt string) string
IsPasswordCorrect(password string, passwordHash string, salt string) bool
}
func GetCredManager(passwordType string) CredManager {
@ -24,6 +24,8 @@ func GetCredManager(passwordType string) CredManager {
return NewPlainCredManager()
} else if passwordType == "salt" {
return NewSha256SaltCredManager()
} else if passwordType == "sha512-salt" {
return NewSha512SaltCredManager()
} else if passwordType == "md5-salt" {
return NewMd5UserSaltCredManager()
} else if passwordType == "bcrypt" {
@ -32,6 +34,8 @@ func GetCredManager(passwordType string) CredManager {
return NewPbkdf2SaltCredManager()
} else if passwordType == "argon2id" {
return NewArgon2idCredManager()
} else if passwordType == "pbkdf2-django" {
return NewPbkdf2DjangoCredManager()
}
return nil
}

View File

@ -37,14 +37,10 @@ func NewMd5UserSaltCredManager() *Md5UserSaltCredManager {
return cm
}
func (cm *Md5UserSaltCredManager) GetHashedPassword(password string, userSalt string, organizationSalt string) string {
res := getMd5HexDigest(password)
if userSalt != "" {
res = getMd5HexDigest(res + userSalt)
}
return res
func (cm *Md5UserSaltCredManager) GetHashedPassword(password string, salt string) string {
return getMd5HexDigest(getMd5HexDigest(password) + salt)
}
func (cm *Md5UserSaltCredManager) IsPasswordCorrect(plainPwd string, hashedPwd string, userSalt string, organizationSalt string) bool {
return hashedPwd == cm.GetHashedPassword(plainPwd, userSalt, organizationSalt)
func (cm *Md5UserSaltCredManager) IsPasswordCorrect(plainPwd string, hashedPwd string, salt string) bool {
return hashedPwd == cm.GetHashedPassword(plainPwd, salt)
}

View File

@ -28,13 +28,13 @@ func NewPbkdf2SaltCredManager() *Pbkdf2SaltCredManager {
return cm
}
func (cm *Pbkdf2SaltCredManager) GetHashedPassword(password string, userSalt string, organizationSalt string) string {
func (cm *Pbkdf2SaltCredManager) GetHashedPassword(password string, salt string) string {
// https://www.keycloak.org/docs/latest/server_admin/index.html#password-database-compromised
decodedSalt, _ := base64.StdEncoding.DecodeString(userSalt)
decodedSalt, _ := base64.StdEncoding.DecodeString(salt)
res := pbkdf2.Key([]byte(password), decodedSalt, 27500, 64, sha256.New)
return base64.StdEncoding.EncodeToString(res)
}
func (cm *Pbkdf2SaltCredManager) IsPasswordCorrect(plainPwd string, hashedPwd string, userSalt string, organizationSalt string) bool {
return hashedPwd == cm.GetHashedPassword(plainPwd, userSalt, organizationSalt)
func (cm *Pbkdf2SaltCredManager) IsPasswordCorrect(plainPwd string, hashedPwd string, salt string) bool {
return hashedPwd == cm.GetHashedPassword(plainPwd, salt)
}

67
cred/pbkdf2_django.go Normal file
View File

@ -0,0 +1,67 @@
// Copyright 2025 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 cred
import (
"crypto/sha256"
"encoding/base64"
"strconv"
"strings"
"golang.org/x/crypto/pbkdf2"
)
// password type: pbkdf2-django
type Pbkdf2DjangoCredManager struct{}
func NewPbkdf2DjangoCredManager() *Pbkdf2DjangoCredManager {
cm := &Pbkdf2DjangoCredManager{}
return cm
}
func (m *Pbkdf2DjangoCredManager) GetHashedPassword(password string, salt string) string {
iterations := 260000
saltBytes := []byte(salt)
passwordBytes := []byte(password)
computedHash := pbkdf2.Key(passwordBytes, saltBytes, iterations, sha256.Size, sha256.New)
hashBase64 := base64.StdEncoding.EncodeToString(computedHash)
return "pbkdf2_sha256$" + strconv.Itoa(iterations) + "$" + salt + "$" + hashBase64
}
func (m *Pbkdf2DjangoCredManager) IsPasswordCorrect(password string, passwordHash string, _salt string) bool {
parts := strings.Split(passwordHash, "$")
if len(parts) != 4 {
return false
}
algorithm, iterations, salt, hash := parts[0], parts[1], parts[2], parts[3]
if algorithm != "pbkdf2_sha256" {
return false
}
iter, err := strconv.Atoi(iterations)
if err != nil {
return false
}
saltBytes := []byte(salt)
passwordBytes := []byte(password)
computedHash := pbkdf2.Key(passwordBytes, saltBytes, iter, sha256.Size, sha256.New)
computedHashBase64 := base64.StdEncoding.EncodeToString(computedHash)
return computedHashBase64 == hash
}

View File

@ -21,10 +21,10 @@ func NewPlainCredManager() *PlainCredManager {
return cm
}
func (cm *PlainCredManager) GetHashedPassword(password string, userSalt string, organizationSalt string) string {
func (cm *PlainCredManager) GetHashedPassword(password string, salt string) string {
return password
}
func (cm *PlainCredManager) IsPasswordCorrect(plainPwd string, hashedPwd string, userSalt string, organizationSalt string) bool {
func (cm *PlainCredManager) IsPasswordCorrect(plainPwd string, hashedPwd string, salt string) bool {
return hashedPwd == plainPwd
}

View File

@ -37,14 +37,10 @@ func NewSha256SaltCredManager() *Sha256SaltCredManager {
return cm
}
func (cm *Sha256SaltCredManager) GetHashedPassword(password string, userSalt string, organizationSalt string) string {
res := getSha256HexDigest(password)
if organizationSalt != "" {
res = getSha256HexDigest(res + organizationSalt)
}
return res
func (cm *Sha256SaltCredManager) GetHashedPassword(password string, salt string) string {
return getSha256HexDigest(getSha256HexDigest(password) + salt)
}
func (cm *Sha256SaltCredManager) IsPasswordCorrect(plainPwd string, hashedPwd string, userSalt string, organizationSalt string) bool {
return hashedPwd == cm.GetHashedPassword(plainPwd, userSalt, organizationSalt)
func (cm *Sha256SaltCredManager) IsPasswordCorrect(plainPwd string, hashedPwd string, salt string) bool {
return hashedPwd == cm.GetHashedPassword(plainPwd, salt)
}

View File

@ -23,12 +23,12 @@ func TestGetSaltedPassword(t *testing.T) {
password := "123456"
salt := "123"
cm := NewSha256SaltCredManager()
fmt.Printf("%s -> %s\n", password, cm.GetHashedPassword(password, "", salt))
fmt.Printf("%s -> %s\n", password, cm.GetHashedPassword(password, salt))
}
func TestGetPassword(t *testing.T) {
password := "123456"
cm := NewSha256SaltCredManager()
// https://passwordsgenerator.net/sha256-hash-generator/
fmt.Printf("%s -> %s\n", "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92", cm.GetHashedPassword(password, "", ""))
fmt.Printf("%s -> %s\n", "8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92", cm.GetHashedPassword(password, ""))
}

46
cred/sha512-salt.go Normal file
View File

@ -0,0 +1,46 @@
// Copyright 2024 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 cred
import (
"crypto/sha512"
"encoding/hex"
)
type Sha512SaltCredManager struct{}
func getSha512(data []byte) []byte {
hash := sha512.Sum512(data)
return hash[:]
}
func getSha512HexDigest(s string) string {
b := getSha512([]byte(s))
res := hex.EncodeToString(b)
return res
}
func NewSha512SaltCredManager() *Sha512SaltCredManager {
cm := &Sha512SaltCredManager{}
return cm
}
func (cm *Sha512SaltCredManager) GetHashedPassword(password string, salt string) string {
return getSha512HexDigest(getSha512HexDigest(password) + salt)
}
func (cm *Sha512SaltCredManager) IsPasswordCorrect(plainPwd string, hashedPwd string, salt string) bool {
return hashedPwd == cm.GetHashedPassword(plainPwd, salt)
}

View File

@ -27,7 +27,21 @@ import (
)
func deployStaticFiles(provider *object.Provider) {
storageProvider := storage.GetStorageProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.RegionId, provider.Bucket, provider.Endpoint)
certificate := ""
if provider.Category == "Storage" && provider.Type == "Casdoor" {
cert, err := object.GetCert(util.GetId(provider.Owner, provider.Cert))
if err != nil {
panic(err)
}
if cert == nil {
panic(err)
}
certificate = cert.Certificate
}
storageProvider, err := storage.GetStorageProvider(provider.Type, provider.ClientId, provider.ClientSecret, provider.RegionId, provider.Bucket, provider.Endpoint, certificate, provider.Content)
if err != nil {
panic(err)
}
if storageProvider == nil {
panic(fmt.Sprintf("the provider type: %s is not supported", provider.Type))
}

View File

@ -111,46 +111,44 @@ func newEmail(fromAddress string, toAddress string, subject string, content stri
Subject: subject,
HTML: content,
},
Importance: importanceNormal,
Importance: importanceNormal,
Attachments: []Attachment{},
}
}
func (a *AzureACSEmailProvider) sendEmail(e *Email) error {
postBody, err := json.Marshal(e)
if err != nil {
return fmt.Errorf("email JSON marshall failed: %s", err)
}
func (a *AzureACSEmailProvider) Send(fromAddress string, fromName string, toAddress string, subject string, content string) error {
email := newEmail(fromAddress, toAddress, subject, content)
bodyBuffer := bytes.NewBuffer(postBody)
postBody, err := json.Marshal(email)
if err != nil {
return err
}
endpoint := strings.TrimSuffix(a.Endpoint, "/")
url := fmt.Sprintf("%s/emails:send?api-version=2023-03-31", endpoint)
bodyBuffer := bytes.NewBuffer(postBody)
req, err := http.NewRequest("POST", url, bodyBuffer)
if err != nil {
return fmt.Errorf("error creating AzureACS API request: %s", err)
return err
}
// Sign the request using the AzureACS access key and HMAC-SHA256
err = signRequestHMAC(a.AccessKey, req)
if err != nil {
return fmt.Errorf("error signing AzureACS API request: %s", err)
return err
}
req.Header.Set("Content-Type", "application/json")
// Some important header
req.Header.Set("repeatability-request-id", uuid.New().String())
req.Header.Set("repeatability-first-sent", time.Now().UTC().Format(http.TimeFormat))
// Send request
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("error sending AzureACS API request: %s", err)
return err
}
defer resp.Body.Close()
// Response error Handling
if resp.StatusCode == http.StatusBadRequest || resp.StatusCode == http.StatusUnauthorized {
commError := ErrorResponse{}
@ -159,11 +157,11 @@ func (a *AzureACSEmailProvider) sendEmail(e *Email) error {
return err
}
return fmt.Errorf("error sending email: %s", commError.Error.Message)
return fmt.Errorf("status code: %d, error message: %s", resp.StatusCode, commError.Error.Message)
}
if resp.StatusCode != http.StatusAccepted {
return fmt.Errorf("error sending email: status: %d", resp.StatusCode)
return fmt.Errorf("status code: %d", resp.StatusCode)
}
return nil
@ -221,9 +219,3 @@ func GetHmac(content string, key []byte) string {
return base64.StdEncoding.EncodeToString(hmac.Sum(nil))
}
func (a *AzureACSEmailProvider) Send(fromAddress string, fromName string, toAddress string, subject string, content string) error {
e := newEmail(fromAddress, toAddress, subject, content)
return a.sendEmail(e)
}

132
email/custom_http.go Normal file
View File

@ -0,0 +1,132 @@
// 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 email
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"net/url"
"strings"
"github.com/casdoor/casdoor/proxy"
)
type HttpEmailProvider struct {
endpoint string
method string
httpHeaders map[string]string
bodyMapping map[string]string
contentType string
}
func NewHttpEmailProvider(endpoint string, method string, httpHeaders map[string]string, bodyMapping map[string]string, contentType string) *HttpEmailProvider {
if contentType == "" {
contentType = "application/x-www-form-urlencoded"
}
client := &HttpEmailProvider{
endpoint: endpoint,
method: method,
httpHeaders: httpHeaders,
bodyMapping: bodyMapping,
contentType: contentType,
}
return client
}
func (c *HttpEmailProvider) Send(fromAddress string, fromName string, toAddress string, subject string, content string) error {
var req *http.Request
var err error
fromNameField := "fromName"
toAddressField := "toAddress"
subjectField := "subject"
contentField := "content"
for k, v := range c.bodyMapping {
switch k {
case "fromName":
fromNameField = v
case "toAddress":
toAddressField = v
case "subject":
subjectField = v
case "content":
contentField = v
}
}
if c.method == "POST" || c.method == "PUT" || c.method == "DELETE" {
bodyMap := make(map[string]string)
bodyMap[fromNameField] = fromName
bodyMap[toAddressField] = toAddress
bodyMap[subjectField] = subject
bodyMap[contentField] = content
var fromValueBytes []byte
if c.contentType == "application/json" {
fromValueBytes, err = json.Marshal(bodyMap)
if err != nil {
return err
}
req, err = http.NewRequest(c.method, c.endpoint, bytes.NewBuffer(fromValueBytes))
} else {
formValues := url.Values{}
for k, v := range bodyMap {
formValues.Add(k, v)
}
req, err = http.NewRequest(c.method, c.endpoint, strings.NewReader(formValues.Encode()))
}
if err != nil {
return err
}
req.Header.Set("Content-Type", c.contentType)
} else if c.method == "GET" {
req, err = http.NewRequest(c.method, c.endpoint, nil)
if err != nil {
return err
}
q := req.URL.Query()
q.Add(fromNameField, fromName)
q.Add(toAddressField, toAddress)
q.Add(subjectField, subject)
q.Add(contentField, content)
req.URL.RawQuery = q.Encode()
} else {
return fmt.Errorf("HttpEmailProvider's Send() error, unsupported method: %s", c.method)
}
for k, v := range c.httpHeaders {
req.Header.Set(k, v)
}
httpClient := proxy.DefaultHttpClient
resp, err := httpClient.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("HttpEmailProvider's Send() error, custom HTTP Email request failed with status: %s", resp.Status)
}
return err
}

View File

@ -18,9 +18,13 @@ type EmailProvider interface {
Send(fromAddress string, fromName, toAddress string, subject string, content string) error
}
func GetEmailProvider(typ string, clientId string, clientSecret string, host string, port int, disableSsl bool) EmailProvider {
func GetEmailProvider(typ string, clientId string, clientSecret string, host string, port int, disableSsl bool, endpoint string, method string, httpHeaders map[string]string, bodyMapping map[string]string, contentType string) EmailProvider {
if typ == "Azure ACS" {
return NewAzureACSEmailProvider(clientSecret, host)
} else if typ == "Custom HTTP Email" {
return NewHttpEmailProvider(endpoint, method, httpHeaders, bodyMapping, contentType)
} else if typ == "SendGrid" {
return NewSendgridEmailProvider(clientSecret, host, endpoint)
} else {
return NewSmtpEmailProvider(clientId, clientSecret, host, port, typ, disableSsl)
}

87
email/sendgrid.go Normal file
View File

@ -0,0 +1,87 @@
// Copyright 2024 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 email
import (
"encoding/json"
"fmt"
"net/http"
"github.com/sendgrid/sendgrid-go"
"github.com/sendgrid/sendgrid-go/helpers/mail"
)
type SendgridEmailProvider struct {
ApiKey string
Host string
Endpoint string
}
type SendgridResponseBody struct {
Errors []struct {
Message string `json:"message"`
Field interface{} `json:"field"`
Help interface{} `json:"help"`
} `json:"errors"`
}
func NewSendgridEmailProvider(apiKey string, host string, endpoint string) *SendgridEmailProvider {
return &SendgridEmailProvider{ApiKey: apiKey, Host: host, Endpoint: endpoint}
}
func (s *SendgridEmailProvider) Send(fromAddress string, fromName string, toAddress string, subject string, content string) error {
client := s.initSendgridClient()
from := mail.NewEmail(fromName, fromAddress)
to := mail.NewEmail("", toAddress)
message := mail.NewSingleEmail(from, subject, to, "", content)
resp, err := client.Send(message)
if err != nil {
return err
}
if resp.StatusCode >= 300 {
var responseBody SendgridResponseBody
err = json.Unmarshal([]byte(resp.Body), &responseBody)
if err != nil {
return err
}
messages := []string{}
for _, sendgridError := range responseBody.Errors {
messages = append(messages, sendgridError.Message)
}
return fmt.Errorf("status code: %d, error message: %s", resp.StatusCode, messages)
}
if resp.StatusCode != http.StatusAccepted {
return fmt.Errorf("status code: %d", resp.StatusCode)
}
return nil
}
func (s *SendgridEmailProvider) initSendgridClient() *sendgrid.Client {
if s.Host == "" || s.Endpoint == "" {
return sendgrid.NewSendClient(s.ApiKey)
}
request := sendgrid.GetRequest(s.ApiKey, s.Endpoint, s.Host)
request.Method = "POST"
return &sendgrid.Client{Request: request}
}

View File

@ -16,7 +16,9 @@ package email
import (
"crypto/tls"
"strings"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/gomail/v2"
)
@ -25,14 +27,20 @@ type SmtpEmailProvider struct {
}
func NewSmtpEmailProvider(userName string, password string, host string, port int, typ string, disableSsl bool) *SmtpEmailProvider {
dialer := &gomail.Dialer{}
dialer = gomail.NewDialer(host, port, userName, password)
dialer := gomail.NewDialer(host, port, userName, password)
if typ == "SUBMAIL" {
dialer.TLSConfig = &tls.Config{InsecureSkipVerify: true}
}
dialer.SSL = !disableSsl
if strings.HasSuffix(host, ".amazonaws.com") {
socks5Proxy := conf.GetConfigString("socks5Proxy")
if socks5Proxy != "" {
dialer.SetSocks5Proxy(socks5Proxy)
}
}
return &SmtpEmailProvider{Dialer: dialer}
}

81
faceId/aliyun.go Normal file
View File

@ -0,0 +1,81 @@
// Copyright 2025 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 faceId
import (
"strings"
openapi "github.com/alibabacloud-go/darabonba-openapi/v2/client"
facebody20191230 "github.com/alibabacloud-go/facebody-20191230/v5/client"
util "github.com/alibabacloud-go/tea-utils/v2/service"
"github.com/alibabacloud-go/tea/tea"
)
type AliyunFaceIdProvider struct {
AccessKey string
AccessSecret string
Endpoint string
QualityScoreThreshold float32
}
func NewAliyunFaceIdProvider(accessKey string, accessSecret string, endPoint string) *AliyunFaceIdProvider {
return &AliyunFaceIdProvider{
AccessKey: accessKey,
AccessSecret: accessSecret,
Endpoint: endPoint,
QualityScoreThreshold: 0.65,
}
}
func (provider *AliyunFaceIdProvider) Check(base64ImageA string, base64ImageB string) (bool, error) {
config := openapi.Config{
AccessKeyId: tea.String(provider.AccessKey),
AccessKeySecret: tea.String(provider.AccessSecret),
}
config.Endpoint = tea.String(provider.Endpoint)
client, err := facebody20191230.NewClient(&config)
if err != nil {
return false, err
}
compareFaceRequest := &facebody20191230.CompareFaceRequest{
QualityScoreThreshold: tea.Float32(provider.QualityScoreThreshold),
ImageDataA: tea.String(strings.Replace(base64ImageA, "data:image/png;base64,", "", -1)),
ImageDataB: tea.String(strings.Replace(base64ImageB, "data:image/png;base64,", "", -1)),
}
runtime := &util.RuntimeOptions{}
defer func() {
if r := tea.Recover(recover()); r != nil {
err = r
}
}()
result, err := client.CompareFaceWithOptions(compareFaceRequest, runtime)
if err != nil {
return false, err
}
if result == nil {
return false, nil
}
if *result.Body.Data.Thresholds[0] < *result.Body.Data.Confidence {
return true, nil
}
return false, nil
}

23
faceId/provider.go Normal file
View File

@ -0,0 +1,23 @@
// Copyright 2025 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 faceId
type FaceIdProvider interface {
Check(base64ImageA string, base64ImageB string) (bool, error)
}
func GetFaceIdProvider(typ string, clientId string, clientSecret string, endPoint string) FaceIdProvider {
return NewAliyunFaceIdProvider(clientId, clientSecret, endPoint)
}

View File

@ -14,8 +14,11 @@
package form
import "reflect"
type AuthForm struct {
Type string `json:"type"`
Type string `json:"type"`
SigninMethod string `json:"signinMethod"`
Organization string `json:"organization"`
Username string `json:"username"`
@ -23,20 +26,26 @@ type AuthForm struct {
Name string `json:"name"`
FirstName string `json:"firstName"`
LastName string `json:"lastName"`
Gender string `json:"gender"`
Bio string `json:"bio"`
Tag string `json:"tag"`
Education string `json:"education"`
Email string `json:"email"`
Phone string `json:"phone"`
Affiliation string `json:"affiliation"`
IdCard string `json:"idCard"`
Language string `json:"language"`
Region string `json:"region"`
InvitationCode string `json:"invitationCode"`
Application string `json:"application"`
ClientId string `json:"clientId"`
Provider string `json:"provider"`
Code string `json:"code"`
State string `json:"state"`
RedirectUri string `json:"redirectUri"`
Method string `json:"method"`
Application string `json:"application"`
ClientId string `json:"clientId"`
Provider string `json:"provider"`
ProviderBack string `json:"providerBack"`
Code string `json:"code"`
State string `json:"state"`
RedirectUri string `json:"redirectUri"`
Method string `json:"method"`
EmailCode string `json:"emailCode"`
PhoneCode string `json:"phoneCode"`
@ -58,4 +67,18 @@ type AuthForm struct {
Plan string `json:"plan"`
Pricing string `json:"pricing"`
FaceId []float64 `json:"faceId"`
FaceIdImage []string `json:"faceIdImage"`
UserCode string `json:"userCode"`
}
func GetAuthFormFieldValue(form *AuthForm, fieldName string) (bool, string) {
val := reflect.ValueOf(*form)
fieldValue := val.FieldByName(fieldName)
if fieldValue.IsValid() && fieldValue.Kind() == reflect.String {
return true, fieldValue.String()
}
return false, ""
}

236
go.mod
View File

@ -1,75 +1,249 @@
module github.com/casdoor/casdoor
go 1.16
go 1.21
require (
github.com/Masterminds/squirrel v1.5.3
github.com/RobotsAndPencils/go-saml v0.0.0-20170520135329-fb13cb52a46b
github.com/alexedwards/argon2id v0.0.0-20211130144151-3585854a6387
github.com/alibabacloud-go/darabonba-openapi/v2 v2.1.4
github.com/alibabacloud-go/facebody-20191230/v5 v5.1.2
github.com/alibabacloud-go/openapi-util v0.1.0
github.com/alibabacloud-go/tea v1.3.2
github.com/alibabacloud-go/tea-utils/v2 v2.0.7
github.com/aws/aws-sdk-go v1.45.5
github.com/beego/beego v1.12.12
github.com/beevik/etree v1.1.0
github.com/casbin/casbin v1.9.1 // indirect
github.com/casbin/casbin/v2 v2.77.2
github.com/casdoor/go-sms-sender v0.15.0
github.com/casdoor/gomail/v2 v2.0.1
github.com/casdoor/notify v0.45.0
github.com/casdoor/oss v1.3.0
github.com/casdoor/go-sms-sender v0.25.0
github.com/casdoor/gomail/v2 v2.1.0
github.com/casdoor/ldapserver v1.2.0
github.com/casdoor/notify v1.0.1
github.com/casdoor/oss v1.8.0
github.com/casdoor/xorm-adapter/v3 v3.1.0
github.com/casvisor/casvisor-go-sdk v1.0.3
github.com/casvisor/casvisor-go-sdk v1.4.0
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f
github.com/denisenkom/go-mssqldb v0.9.0
github.com/elazarl/go-bindata-assetfs v1.0.1 // indirect
github.com/elimity-com/scim v0.0.0-20230426070224-941a5eac92f3
github.com/fogleman/gg v1.3.0
github.com/forestmgy/ldapserver v1.1.0
github.com/go-git/go-git/v5 v5.6.0
github.com/go-asn1-ber/asn1-ber v1.5.5
github.com/go-git/go-git/v5 v5.13.0
github.com/go-ldap/ldap/v3 v3.4.6
github.com/go-mysql-org/go-mysql v1.7.0
github.com/go-pay/gopay v1.5.72
github.com/go-sql-driver/mysql v1.6.0
github.com/go-telegram-bot-api/telegram-bot-api v4.6.4+incompatible
github.com/go-webauthn/webauthn v0.6.0
github.com/golang-jwt/jwt/v4 v4.5.0
github.com/google/uuid v1.3.1
github.com/json-iterator/go v1.1.12 // indirect
github.com/kardianos/osext v0.0.0-20190222173326-2bc1f35cddc0 // indirect
github.com/lestrrat-go/jwx v1.2.21
github.com/go-webauthn/webauthn v0.10.2
github.com/golang-jwt/jwt/v5 v5.2.2
github.com/google/uuid v1.6.0
github.com/json-iterator/go v1.1.12
github.com/lestrrat-go/jwx v1.2.29
github.com/lib/pq v1.10.9
github.com/lor00x/goldap v0.0.0-20180618054307-a546dffdd1a3
github.com/markbates/goth v1.75.2
github.com/markbates/goth v1.79.0
github.com/mitchellh/mapstructure v1.5.0
github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d // indirect
github.com/nyaruka/phonenumbers v1.1.5
github.com/pquerna/otp v1.4.0
github.com/prometheus/client_golang v1.11.1
github.com/prometheus/client_model v0.3.0
github.com/prometheus/client_model v0.4.0
github.com/qiangmzsx/string-adapter/v2 v2.1.0
github.com/robfig/cron/v3 v3.0.1
github.com/russellhaering/gosaml2 v0.9.0
github.com/russellhaering/goxmldsig v1.2.0
github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
github.com/sendgrid/sendgrid-go v3.14.0+incompatible
github.com/shirou/gopsutil v3.21.11+incompatible
github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/stretchr/testify v1.8.4
github.com/stretchr/testify v1.10.0
github.com/stripe/stripe-go/v74 v74.29.0
github.com/tealeg/xlsx v1.0.5
github.com/thanhpk/randstr v1.0.4
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/xorm-io/builder v0.3.13
github.com/xorm-io/core v0.7.4
github.com/xorm-io/xorm v1.1.6
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/crypto v0.13.0
golang.org/x/net v0.14.0
golang.org/x/oauth2 v0.11.0
golang.org/x/text v0.13.0 // indirect
google.golang.org/api v0.138.0
gopkg.in/ini.v1 v1.67.0 // indirect
golang.org/x/crypto v0.32.0
golang.org/x/net v0.34.0
golang.org/x/oauth2 v0.17.0
golang.org/x/text v0.21.0
google.golang.org/api v0.150.0
gopkg.in/square/go-jose.v2 v2.6.0
layeh.com/radius v0.0.0-20221205141417-e7fbddd11d68
maunium.net/go/mautrix v0.16.0
modernc.org/sqlite v1.18.2
)
require (
cloud.google.com/go v0.110.8 // indirect
cloud.google.com/go/compute v1.23.1 // indirect
cloud.google.com/go/compute/metadata v0.2.3 // indirect
cloud.google.com/go/iam v1.1.3 // indirect
cloud.google.com/go/storage v1.35.1 // indirect
dario.cat/mergo v1.0.0 // indirect
github.com/Azure/azure-pipeline-go v0.2.3 // indirect
github.com/Azure/azure-storage-blob-go v0.15.0 // indirect
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
github.com/BurntSushi/toml v0.3.1 // indirect
github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/ProtonMail/go-crypto v1.1.3 // indirect
github.com/RocketChat/Rocket.Chat.Go.SDK v0.0.0-20221121042443-a3fd332d56d9 // indirect
github.com/SherClockHolmes/webpush-go v1.2.0 // indirect
github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.5 // indirect
github.com/alibabacloud-go/darabonba-number v1.0.4 // indirect
github.com/alibabacloud-go/debug v1.0.1 // indirect
github.com/alibabacloud-go/endpoint-util v1.1.0 // indirect
github.com/alibabacloud-go/openplatform-20191219/v2 v2.0.1 // indirect
github.com/alibabacloud-go/tea-fileform v1.1.1 // indirect
github.com/alibabacloud-go/tea-oss-sdk v1.1.3 // indirect
github.com/alibabacloud-go/tea-oss-utils v1.1.0 // indirect
github.com/alibabacloud-go/tea-utils v1.3.6 // indirect
github.com/alibabacloud-go/tea-xml v1.1.3 // indirect
github.com/aliyun/alibaba-cloud-sdk-go v1.62.545 // indirect
github.com/aliyun/aliyun-oss-go-sdk v2.2.2+incompatible // indirect
github.com/aliyun/credentials-go v1.3.10 // indirect
github.com/apistd/uni-go-sdk v0.0.2 // indirect
github.com/atc0005/go-teams-notify/v2 v2.13.0 // indirect
github.com/baidubce/bce-sdk-go v0.9.156 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blinkbean/dingtalk v0.0.0-20210905093040-7d935c0f7e19 // indirect
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
github.com/bwmarrin/discordgo v0.27.1 // indirect
github.com/casdoor/casdoor-go-sdk v0.50.0 // indirect
github.com/casdoor/go-reddit/v2 v2.1.0 // indirect
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/clbanning/mxj/v2 v2.7.0 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/cschomburg/go-pushbullet v0.0.0-20171206132031-67759df45fbb // indirect
github.com/cyphar/filepath-securejoin v0.2.5 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/dghubble/oauth1 v0.7.2 // indirect
github.com/dghubble/sling v1.4.0 // indirect
github.com/di-wu/parser v0.2.2 // indirect
github.com/di-wu/xsd-datetime v1.0.0 // indirect
github.com/drswork/go-twitter v0.0.0-20221107160839-dea1b6ed53d7 // indirect
github.com/elazarl/go-bindata-assetfs v1.0.1 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/fxamacker/cbor/v2 v2.6.0 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.6.0 // indirect
github.com/go-lark/lark v1.9.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/go-webauthn/x v0.1.9 // indirect
github.com/goccy/go-json v0.10.2 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/golang/snappy v0.0.4 // indirect
github.com/gomodule/redigo v2.0.0+incompatible // indirect
github.com/google/go-querystring v1.1.0 // indirect
github.com/google/go-tpm v0.9.0 // indirect
github.com/google/s2a-go v0.1.7 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/gregdel/pushover v1.2.1 // indirect
github.com/hashicorp/golang-lru v0.5.4 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jmespath/go-jmespath v0.4.0 // indirect
github.com/jonboulle/clockwork v0.2.2 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect
github.com/lestrrat-go/blackmagic v1.0.2 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
github.com/lestrrat-go/iter v1.0.2 // indirect
github.com/lestrrat-go/option v1.0.1 // indirect
github.com/line/line-bot-sdk-go v7.8.0+incompatible // indirect
github.com/markbates/going v1.0.0 // indirect
github.com/mattermost/xml-roundtrip-validator v0.1.0 // indirect
github.com/mattn/go-colorable v0.1.12 // indirect
github.com/mattn/go-ieproxy v0.0.1 // indirect
github.com/mattn/go-isatty v0.0.16 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
github.com/mileusna/viber v1.0.1 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/mrjones/oauth v0.0.0-20180629183705-f4e24b6d100c // indirect
github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
github.com/pingcap/errors v0.11.5-0.20210425183316-da1aaba5fb63 // indirect
github.com/pingcap/log v0.0.0-20210625125904-98ed8e2eb1c7 // indirect
github.com/pingcap/tidb/parser v0.0.0-20221126021158-6b02a5d8ba7d // indirect
github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/common v0.30.0 // indirect
github.com/prometheus/procfs v0.7.3 // indirect
github.com/qiniu/go-sdk/v7 v7.12.1 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/rs/zerolog v1.30.0 // indirect
github.com/scim2/filter-parser/v2 v2.2.0 // indirect
github.com/sendgrid/rest v2.6.9+incompatible // indirect
github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect
github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 // indirect
github.com/siddontang/go v0.0.0-20180604090527-bdc77568d726 // indirect
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/skeema/knownhosts v1.3.0 // indirect
github.com/slack-go/slack v0.12.3 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/technoweenie/multipartstreamer v1.0.1 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.744 // indirect
github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/sms v1.0.744 // indirect
github.com/tidwall/gjson v1.16.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
github.com/tjfoc/gmsm v1.4.1 // indirect
github.com/tklauser/go-sysconf v0.3.10 // indirect
github.com/tklauser/numcpus v0.4.0 // indirect
github.com/twilio/twilio-go v1.13.0 // indirect
github.com/ucloud/ucloud-sdk-go v0.22.5 // indirect
github.com/utahta/go-linenotify v0.5.0 // indirect
github.com/volcengine/volc-sdk-golang v1.0.117 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
go.mau.fi/util v0.0.0-20230805171708-199bf3eec776 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.7.0 // indirect
go.uber.org/zap v1.19.1 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
golang.org/x/image v0.0.0-20190802002840-cff245a6509b // indirect
golang.org/x/mod v0.19.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/time v0.3.0 // indirect
golang.org/x/tools v0.23.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto v0.0.0-20231016165738-49dd2c1f3d0b // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20231016165738-49dd2c1f3d0b // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20231030173426-d783a09b4405 // indirect
google.golang.org/grpc v1.59.0 // indirect
google.golang.org/protobuf v1.32.0 // indirect
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
gopkg.in/warnings.v0 v0.1.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/uint128 v1.1.1 // indirect
maunium.net/go/maulogger/v2 v2.4.1 // indirect
modernc.org/cc/v3 v3.37.0 // indirect
modernc.org/ccgo/v3 v3.16.9 // indirect
modernc.org/libc v1.18.0 // indirect
modernc.org/mathutil v1.5.0 // indirect
modernc.org/memory v1.3.0 // indirect
modernc.org/opt v0.1.1 // indirect
modernc.org/strutil v1.1.3 // indirect
modernc.org/token v1.0.1 // indirect
)

1831
go.sum

File diff suppressed because it is too large Load Diff

View File

@ -84,6 +84,10 @@ func getAllFilePathsInFolder(folder string, fileSuffix string) []string {
return err
}
if strings.HasSuffix(path, "node_modules") {
return filepath.SkipDir
}
if !strings.HasSuffix(info.Name(), fileSuffix) {
return nil
}

View File

@ -45,6 +45,8 @@ func TestGenerateI18nFrontend(t *testing.T) {
applyToOtherLanguage("frontend", "uk", data)
applyToOtherLanguage("frontend", "kk", data)
applyToOtherLanguage("frontend", "fa", data)
applyToOtherLanguage("frontend", "cs", data)
applyToOtherLanguage("frontend", "sk", data)
}
func TestGenerateI18nBackend(t *testing.T) {
@ -73,4 +75,6 @@ func TestGenerateI18nBackend(t *testing.T) {
applyToOtherLanguage("backend", "uk", data)
applyToOtherLanguage("backend", "kk", data)
applyToOtherLanguage("backend", "fa", data)
applyToOtherLanguage("backend", "cs", data)
applyToOtherLanguage("backend", "sk", data)
}

View File

@ -7,6 +7,7 @@
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
@ -15,54 +16,93 @@
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face 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 organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Affiliation cannot be blank",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"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.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "Session outdated, please login again",
"The invitation code has already been used": "The invitation code has already been used",
"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 in LDAP server": "The user: %s doesn't exist in LDAP server",
"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 value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"Username supports email format. Also 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. Also pay attention to the email format.": "Username supports email format. Also 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. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"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"
},
"enforcer": {
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Failed to import users",
"Missing parameter": "Missing parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Please login first",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
@ -78,7 +118,11 @@
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s."
"Unknown modify rule %s.": "Unknown modify rule %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "Invalid application id",
@ -103,8 +147,10 @@
"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"
},
"subscription": {
"Error": "Error"
},
"token": {
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
@ -113,10 +159,10 @@
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space."
},
"user_upload": {
"Failed to import users": "Failed to import users"
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"New password cannot contain blank space.": "New password cannot contain blank space.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
@ -124,19 +170,21 @@
"The provider: %s is not found": "The provider: %s is not found"
},
"verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"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 verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

190
i18n/locales/cs/data.json Normal file
View File

@ -0,0 +1,190 @@
{
"account": {
"Failed to add user": "Nepodařilo se přidat uživatele",
"Get init score failed, error: %w": "Nepodařilo se získat počáteční skóre, chyba: %w",
"Please sign out first": "Nejprve se prosím odhlaste",
"The application does not allow to sign up new account": "Aplikace neumožňuje registraci nového účtu"
},
"auth": {
"Challenge method should be S256": "Metoda výzvy by měla být S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "Nepodařilo se vytvořit uživatele, informace o uživateli jsou neplatné: %s",
"Failed to login in: %s": "Nepodařilo se přihlásit: %s",
"Invalid token": "Neplatný token",
"State expected: %s, but got: %s": "Očekávaný stav: %s, ale získán: %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": "Účet pro poskytovatele: %s a uživatelské jméno: %s (%s) neexistuje a není povoleno se registrovat jako nový účet přes %%s, prosím použijte jiný způsob registrace",
"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": "Účet pro poskytovatele: %s a uživatelské jméno: %s (%s) neexistuje a není povoleno se registrovat jako nový účet, prosím kontaktujte svou IT podporu",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Účet pro poskytovatele: %s a uživatelské jméno: %s (%s) je již propojen s jiným účtem: %s (%s)",
"The application: %s does not exist": "Aplikace: %s neexistuje",
"The login method: login with LDAP is not enabled for the application": "Metoda přihlášení: přihlášení pomocí LDAP není pro aplikaci povolena",
"The login method: login with SMS is not enabled for the application": "Metoda přihlášení: přihlášení pomocí SMS není pro aplikaci povolena",
"The login method: login with email is not enabled for the application": "Metoda přihlášení: přihlášení pomocí emailu není pro aplikaci povolena",
"The login method: login with face is not enabled for the application": "Metoda přihlášení: přihlášení pomocí obličeje není pro aplikaci povolena",
"The login method: login with password is not enabled for the application": "Metoda přihlášení: přihlášení pomocí hesla není pro aplikaci povolena",
"The organization: %s does not exist": "Organizace: %s neexistuje",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "Poskytovatel: %s není pro aplikaci povolen",
"Unauthorized operation": "Neoprávněná operace",
"Unknown authentication type (not password or provider), form = %s": "Neznámý typ autentizace (není heslo nebo poskytovatel), formulář = %s",
"User's tag: %s is not listed in the application's tags": "Štítek uživatele: %s není uveden v štítcích aplikace",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "Placený uživatel %s nemá aktivní nebo čekající předplatné a aplikace: %s nemá výchozí ceny",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Služba %s a %s se neshodují"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Příslušnost nemůže být prázdná",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Výchozí kód neodpovídá pravidlům pro shodu kódů",
"DisplayName cannot be blank": "Zobrazované jméno nemůže být prázdné",
"DisplayName is not valid real name": "Zobrazované jméno není platné skutečné jméno",
"Email already exists": "Email již existuje",
"Email cannot be empty": "Email nemůže být prázdný",
"Email is invalid": "Email je neplatný",
"Empty username.": "Prázdné uživatelské jméno.",
"Face data does not exist, cannot log in": "Data obličeje neexistují, nelze se přihlásit",
"Face data mismatch": "Neshoda dat obličeje",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "Křestní jméno nemůže být prázdné",
"Invitation code cannot be blank": "Pozvánkový kód nemůže být prázdný",
"Invitation code exhausted": "Pozvánkový kód vyčerpán",
"Invitation code is invalid": "Pozvánkový kód je neplatný",
"Invitation code suspended": "Pozvánkový kód pozastaven",
"LDAP user name or password incorrect": "Uživatelské jméno nebo heslo LDAP je nesprávné",
"LastName cannot be blank": "Příjmení nemůže být prázdné",
"Multiple accounts with same uid, please check your ldap server": "Více účtů se stejným uid, prosím zkontrolujte svůj ldap server",
"Organization does not exist": "Organizace neexistuje",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "Telefon již existuje",
"Phone cannot be empty": "Telefon nemůže být prázdný",
"Phone number is invalid": "Telefonní číslo je neplatné",
"Please register using the email corresponding to the invitation code": "Prosím zaregistrujte se pomocí emailu odpovídajícího pozvánkovému kódu",
"Please register using the phone corresponding to the invitation code": "Prosím zaregistrujte se pomocí telefonu odpovídajícího pozvánkovému kódu",
"Please register using the username corresponding to the invitation code": "Prosím zaregistrujte se pomocí uživatelského jména odpovídajícího pozvánkovému kódu",
"Session outdated, please login again": "Relace je zastaralá, prosím přihlaste se znovu",
"The invitation code has already been used": "Pozvánkový kód již byl použit",
"The user is forbidden to sign in, please contact the administrator": "Uživatel má zakázáno se přihlásit, prosím kontaktujte administrátora",
"The user: %s doesn't exist in LDAP server": "Uživatel: %s neexistuje na LDAP serveru",
"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.": "Uživatelské jméno může obsahovat pouze alfanumerické znaky, podtržítka nebo pomlčky, nemůže mít po sobě jdoucí pomlčky nebo podtržítka a nemůže začínat nebo končit pomlčkou nebo podtržítkem.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "Hodnota \\\"%s\\\" pro pole účtu \\\"%s\\\" neodpovídá regulárnímu výrazu položky účtu",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "Hodnota \\\"%s\\\" pro pole registrace \\\"%s\\\" neodpovídá regulárnímu výrazu položky registrace aplikace \\\"%s\\\"",
"Username already exists": "Uživatelské jméno již existuje",
"Username cannot be an email address": "Uživatelské jméno nemůže být emailová adresa",
"Username cannot contain white spaces": "Uživatelské jméno nemůže obsahovat mezery",
"Username cannot start with a digit": "Uživatelské jméno nemůže začínat číslicí",
"Username is too long (maximum is 255 characters).": "Uživatelské jméno je příliš dlouhé (maximálně 255 znaků).",
"Username must have at least 2 characters": "Uživatelské jméno musí mít alespoň 2 znaky",
"Username supports email format. Also 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. Also pay attention to the email format.": "Username supports email format. Also 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. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Zadali jste špatné heslo nebo kód příliš mnohokrát, prosím počkejte %d minut a zkuste to znovu",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Vaše oblast neumožňuje registraci pomocí telefonu",
"password or code is incorrect": "heslo nebo kód je nesprávné",
"password or code is incorrect, you have %d remaining chances": "heslo nebo kód je nesprávné, máte %d zbývajících pokusů",
"unsupported password type: %s": "nepodporovaný typ hesla: %s"
},
"enforcer": {
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Nepodařilo se importovat uživatele",
"Missing parameter": "Chybějící parametr",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Prosím, přihlaste se nejprve",
"The organization: %s should have one application at least": "Organizace: %s by měla mít alespoň jednu aplikaci",
"The user: %s doesn't exist": "Uživatel: %s neexistuje",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "nepodporuje captchaProvider: ",
"this operation is not allowed in demo mode": "tato operace není povolena v demo režimu",
"this operation requires administrator to perform": "tato operace vyžaduje administrátora"
},
"ldap": {
"Ldap server exist": "Ldap server existuje"
},
"link": {
"Please link first": "Prosím, nejprve propojte",
"This application has no providers": "Tato aplikace nemá žádné poskytovatele",
"This application has no providers of type": "Tato aplikace nemá žádné poskytovatele typu",
"This provider can't be unlinked": "Tento poskytovatel nemůže být odpojen",
"You are not the global admin, you can't unlink other users": "Nejste globální administrátor, nemůžete odpojovat jiné uživatele",
"You can't unlink yourself, you are not a member of any application": "Nemůžete odpojit sami sebe, nejste členem žádné aplikace"
},
"organization": {
"Only admin can modify the %s.": "Pouze administrátor může upravit %s.",
"The %s is immutable.": "%s je neměnný.",
"Unknown modify rule %s.": "Neznámé pravidlo úpravy %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "Oprávnění: \\\"%s\\\" neexistuje"
},
"provider": {
"Invalid application id": "Neplatné ID aplikace",
"the provider: %s does not exist": "poskytovatel: %s neexistuje"
},
"resource": {
"User is nil for tag: avatar": "Uživatel je nil pro tag: avatar",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Uživatelské jméno nebo úplná cesta k souboru je prázdná: uživatelské jméno = %s, úplná cesta k souboru = %s"
},
"saml": {
"Application %s not found": "Aplikace %s nebyla nalezena"
},
"saml_sp": {
"provider %s's category is not SAML": "poskytovatel %s není kategorie SAML"
},
"service": {
"Empty parameters for emailForm: %v": "Prázdné parametry pro emailForm: %v",
"Invalid Email receivers: %s": "Neplatní příjemci emailu: %s",
"Invalid phone receivers: %s": "Neplatní příjemci telefonu: %s"
},
"storage": {
"The objectKey: %s is not allowed": "objectKey: %s není povolen",
"The provider type: %s is not supported": "typ poskytovatele: %s není podporován"
},
"subscription": {
"Error": "Error"
},
"token": {
"Grant_type: %s is not supported in this application": "Grant_type: %s není v této aplikaci podporován",
"Invalid application or wrong clientSecret": "Neplatná aplikace nebo špatný clientSecret",
"Invalid client_id": "Neplatné client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Přesměrovací URI: %s neexistuje v seznamu povolených přesměrovacích URI",
"Token not found, invalid accessToken": "Token nenalezen, neplatný accessToken"
},
"user": {
"Display name cannot be empty": "Zobrazované jméno nemůže být prázdné",
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"New password cannot contain blank space.": "Nové heslo nemůže obsahovat prázdné místo.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"util": {
"No application is found for userId: %s": "Pro userId: %s nebyla nalezena žádná aplikace",
"No provider for category: %s is found for application: %s": "Pro kategorii: %s nebyl nalezen žádný poskytovatel pro aplikaci: %s",
"The provider: %s is not found": "Poskytovatel: %s nebyl nalezen"
},
"verification": {
"Invalid captcha provider.": "Neplatný poskytovatel captcha.",
"Phone number is invalid in your region %s": "Telefonní číslo je ve vaší oblasti %s neplatné",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "Ověřovací kód ještě nebyl odeslán!",
"Turing test failed.": "Turingův test selhal.",
"Unable to get the email modify rule.": "Nelze získat pravidlo pro úpravu emailu.",
"Unable to get the phone modify rule.": "Nelze získat pravidlo pro úpravu telefonu.",
"Unknown type": "Neznámý typ",
"Wrong verification code!": "Špatný ověřovací kód!",
"You should verify your code in %d min!": "Měli byste ověřit svůj kód do %d minut!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "prosím přidejte poskytovatele SMS do seznamu \\\"Providers\\\" pro aplikaci: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "prosím přidejte poskytovatele emailu do seznamu \\\"Providers\\\" pro aplikaci: %s",
"the user does not exist, please sign up first": "uživatel neexistuje, prosím nejprve se zaregistrujte"
},
"webauthn": {
"Please call WebAuthnSigninBegin first": "Prosím, nejprve zavolejte WebAuthnSigninBegin"
}
}

View File

@ -7,6 +7,7 @@
},
"auth": {
"Challenge method should be S256": "Die Challenge-Methode sollte S256 sein",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "Es konnte kein Benutzer erstellt werden, da die Benutzerinformationen ungültig sind: %s",
"Failed to login in: %s": "Konnte nicht anmelden: %s",
"Invalid token": "Ungültiges Token",
@ -15,54 +16,93 @@
"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": "Das Konto für den Anbieter %s und Benutzernamen %s (%s) existiert nicht und es ist nicht erlaubt, ein neues Konto anzumelden. Bitte wenden Sie sich an Ihren IT-Support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Das Konto für den Anbieter %s und Benutzernamen %s (%s) ist bereits mit einem anderen Konto verknüpft: %s (%s)",
"The application: %s does not exist": "Die Anwendung: %s existiert nicht",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "Die Anmeldeart \"Anmeldung mit Passwort\" ist für die Anwendung nicht aktiviert",
"The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "Der Anbieter: %s ist nicht für die Anwendung aktiviert",
"Unauthorized operation": "Nicht autorisierte Operation",
"Unknown authentication type (not password or provider), form = %s": "Unbekannter Authentifizierungstyp (nicht Passwort oder Anbieter), Formular = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Service %s und %s stimmen nicht überein"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Zugehörigkeit darf nicht leer sein",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"DisplayName cannot be blank": "Anzeigename kann nicht leer sein",
"DisplayName is not valid real name": "DisplayName ist kein gültiger Vorname",
"Email already exists": "E-Mail existiert bereits",
"Email cannot be empty": "E-Mail darf nicht leer sein",
"Email is invalid": "E-Mail ist ungültig",
"Empty username.": "Leerer Benutzername.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "Vorname darf nicht leer sein",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "Ldap Benutzername oder Passwort falsch",
"LastName cannot be blank": "Nachname darf nicht leer sein",
"Multiple accounts with same uid, please check your ldap server": "Mehrere Konten mit derselben uid, bitte überprüfen Sie Ihren LDAP-Server",
"Organization does not exist": "Organisation existiert nicht",
"Password must have at least 6 characters": "Das Passwort muss mindestens 6 Zeichen enthalten",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "Telefon existiert bereits",
"Phone cannot be empty": "Das Telefon darf nicht leer sein",
"Phone number is invalid": "Die Telefonnummer ist ungültig",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "Sitzung abgelaufen, bitte erneut anmelden",
"The invitation code has already been used": "The invitation code has already been used",
"The user is forbidden to sign in, please contact the administrator": "Dem Benutzer ist der Zugang verboten, bitte kontaktieren Sie den Administrator",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"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.": "Der Benutzername darf nur alphanumerische Zeichen, Unterstriche oder Bindestriche enthalten, keine aufeinanderfolgenden Bindestriche oder Unterstriche haben und darf nicht mit einem Bindestrich oder Unterstrich beginnen oder enden.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "Benutzername existiert bereits",
"Username cannot be an email address": "Benutzername kann keine E-Mail-Adresse sein",
"Username cannot contain white spaces": "Benutzername darf keine Leerzeichen enthalten",
"Username cannot start with a digit": "Benutzername darf nicht mit einer Ziffer beginnen",
"Username is too long (maximum is 39 characters).": "Benutzername ist zu lang (das Maximum beträgt 39 Zeichen).",
"Username is too long (maximum is 255 characters).": "Benutzername ist zu lang (das Maximum beträgt 255 Zeichen).",
"Username must have at least 2 characters": "Benutzername muss mindestens 2 Zeichen lang sein",
"Username supports email format. Also 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. Also pay attention to the email format.": "Username supports email format. Also 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. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Sie haben zu oft das falsche Passwort oder den falschen Code eingegeben. Bitte warten Sie %d Minuten und versuchen Sie es erneut",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Ihre Region ist nicht berechtigt, sich telefonisch anzumelden",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "Das Passwort oder der Code ist falsch. Du hast noch %d Versuche übrig",
"unsupported password type: %s": "Nicht unterstützter Passworttyp: %s"
},
"enforcer": {
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Fehler beim Importieren von Benutzern",
"Missing parameter": "Fehlender Parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Bitte zuerst einloggen",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "Der Benutzer %s existiert nicht",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "Unterstütze captchaProvider nicht:",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
},
"ldap": {
"Ldap server exist": "Es gibt einen LDAP-Server"
@ -78,7 +118,11 @@
"organization": {
"Only admin can modify the %s.": "Nur der Administrator kann das %s ändern.",
"The %s is immutable.": "Das %s ist unveränderlich.",
"Unknown modify rule %s.": "Unbekannte Änderungsregel %s."
"Unknown modify rule %s.": "Unbekannte Änderungsregel %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "Ungültige Anwendungs-ID",
@ -103,8 +147,10 @@
"The objectKey: %s is not allowed": "Der Objektschlüssel %s ist nicht erlaubt",
"The provider type: %s is not supported": "Der Anbieter-Typ %s wird nicht unterstützt"
},
"subscription": {
"Error": "Error"
},
"token": {
"Empty clientId or clientSecret": "Leerer clientId oder clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s wird von dieser Anwendung nicht unterstützt",
"Invalid application or wrong clientSecret": "Ungültige Anwendung oder falsches clientSecret",
"Invalid client_id": "Ungültige client_id",
@ -113,10 +159,10 @@
},
"user": {
"Display name cannot be empty": "Anzeigename darf nicht leer sein",
"New password cannot contain blank space.": "Das neue Passwort darf keine Leerzeichen enthalten."
},
"user_upload": {
"Failed to import users": "Fehler beim Importieren von Benutzern"
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"New password cannot contain blank space.": "Das neue Passwort darf keine Leerzeichen enthalten.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"util": {
"No application is found for userId: %s": "Es wurde keine Anwendung für die Benutzer-ID gefunden: %s",
@ -124,19 +170,21 @@
"The provider: %s is not found": "Der Anbieter: %s wurde nicht gefunden"
},
"verification": {
"Code has not been sent yet!": "Der Code wurde noch nicht versendet!",
"Invalid captcha provider.": "Ungültiger Captcha-Anbieter.",
"Phone number is invalid in your region %s": "Die Telefonnummer ist in Ihrer Region %s ungültig",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"Turing test failed.": "Turing-Test fehlgeschlagen.",
"Unable to get the email modify rule.": "Nicht in der Lage, die E-Mail-Änderungsregel zu erhalten.",
"Unable to get the phone modify rule.": "Nicht in der Lage, die Telefon-Änderungsregel zu erhalten.",
"Unknown type": "Unbekannter Typ",
"Wrong verification code!": "Falscher Bestätigungscode!",
"You should verify your code in %d min!": "Du solltest deinen Code in %d Minuten verifizieren!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "Der Benutzer existiert nicht, bitte zuerst anmelden"
},
"webauthn": {
"Found no credentials for this user": "Es wurden keine Anmeldeinformationen für diesen Benutzer gefunden",
"Please call WebAuthnSigninBegin first": "Bitte rufen Sie zuerst WebAuthnSigninBegin auf"
}
}

View File

@ -7,6 +7,7 @@
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
@ -15,54 +16,93 @@
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face 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 organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Affiliation cannot be blank",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"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.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "Session outdated, please login again",
"The invitation code has already been used": "The invitation code has already been used",
"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 in LDAP server": "The user: %s doesn't exist in LDAP server",
"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 value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"Username supports email format. Also 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. Also pay attention to the email format.": "Username supports email format. Also 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. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"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"
},
"enforcer": {
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Failed to import users",
"Missing parameter": "Missing parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Please login first",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
@ -78,7 +118,11 @@
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s."
"Unknown modify rule %s.": "Unknown modify rule %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "Invalid application id",
@ -103,8 +147,10 @@
"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"
},
"subscription": {
"Error": "Error"
},
"token": {
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
@ -113,10 +159,10 @@
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space."
},
"user_upload": {
"Failed to import users": "Failed to import users"
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"New password cannot contain blank space.": "New password cannot contain blank space.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
@ -124,19 +170,21 @@
"The provider: %s is not found": "The provider: %s is not found"
},
"verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"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 verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

View File

@ -7,6 +7,7 @@
},
"auth": {
"Challenge method should be S256": "El método de desafío debe ser S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "No se pudo crear el usuario, la información del usuario es inválida: %s",
"Failed to login in: %s": "No se ha podido iniciar sesión en: %s",
"Invalid token": "Token inválido",
@ -15,54 +16,93 @@
"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": "La cuenta para el proveedor: %s y el nombre de usuario: %s (%s) no existe y no se permite registrarse como una nueva cuenta, por favor contacte a su soporte de TI",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "La cuenta para proveedor: %s y nombre de usuario: %s (%s) ya está vinculada a otra cuenta: %s (%s)",
"The application: %s does not exist": "La aplicación: %s no existe",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "El método de inicio de sesión: inicio de sesión con contraseña no está habilitado para la aplicación",
"The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "El proveedor: %s no está habilitado para la aplicación",
"Unauthorized operation": "Operación no autorizada",
"Unknown authentication type (not password or provider), form = %s": "Tipo de autenticación desconocido (no es contraseña o proveedor), formulario = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Los servicios %s y %s no coinciden"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Afiliación no puede estar en blanco",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"DisplayName cannot be blank": "El nombre de visualización no puede estar en blanco",
"DisplayName is not valid real name": "El nombre de pantalla no es un nombre real válido",
"Email already exists": "El correo electrónico ya existe",
"Email cannot be empty": "El correo electrónico no puede estar vacío",
"Email is invalid": "El correo electrónico no es válido",
"Empty username.": "Nombre de usuario vacío.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "El nombre no puede estar en blanco",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "Nombre de usuario o contraseña de Ldap incorrectos",
"LastName cannot be blank": "El apellido no puede estar en blanco",
"Multiple accounts with same uid, please check your ldap server": "Cuentas múltiples con el mismo uid, por favor revise su servidor ldap",
"Organization does not exist": "La organización no existe",
"Password must have at least 6 characters": "La contraseña debe tener al menos 6 caracteres",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "El teléfono ya existe",
"Phone cannot be empty": "Teléfono no puede estar vacío",
"Phone number is invalid": "El número de teléfono no es válido",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "Sesión expirada, por favor vuelva a iniciar sesión",
"The invitation code has already been used": "The invitation code has already been used",
"The user is forbidden to sign in, please contact the administrator": "El usuario no está autorizado a iniciar sesión, por favor contacte al administrador",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"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.": "El nombre de usuario solo puede contener caracteres alfanuméricos, guiones bajos o guiones, no puede tener guiones o subrayados consecutivos, y no puede comenzar ni terminar con un guión o subrayado.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "El nombre de usuario ya existe",
"Username cannot be an email address": "Nombre de usuario no puede ser una dirección de correo electrónico",
"Username cannot contain white spaces": "Nombre de usuario no puede contener espacios en blanco",
"Username cannot start with a digit": "El nombre de usuario no puede empezar con un dígito",
"Username is too long (maximum is 39 characters).": "El nombre de usuario es demasiado largo (el máximo es de 39 caracteres).",
"Username is too long (maximum is 255 characters).": "El nombre de usuario es demasiado largo (el máximo es de 255 caracteres).",
"Username must have at least 2 characters": "Nombre de usuario debe tener al menos 2 caracteres",
"Username supports email format. Also 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. Also pay attention to the email format.": "Username supports email format. Also 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. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Has ingresado la contraseña o código incorrecto demasiadas veces, por favor espera %d minutos e intenta de nuevo",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Tu región no está permitida para registrarse por teléfono",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "Contraseña o código incorrecto, tienes %d intentos restantes",
"unsupported password type: %s": "Tipo de contraseña no compatible: %s"
},
"enforcer": {
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Error al importar usuarios",
"Missing parameter": "Parámetro faltante",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Por favor, inicia sesión primero",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "El usuario: %s no existe",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "No apoyo a captchaProvider",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
},
"ldap": {
"Ldap server exist": "El servidor LDAP existe"
@ -78,7 +118,11 @@
"organization": {
"Only admin can modify the %s.": "Solo el administrador puede modificar los %s.",
"The %s is immutable.": "El %s es inmutable.",
"Unknown modify rule %s.": "Regla de modificación desconocida %s."
"Unknown modify rule %s.": "Regla de modificación desconocida %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "Identificación de aplicación no válida",
@ -103,8 +147,10 @@
"The objectKey: %s is not allowed": "El objectKey: %s no está permitido",
"The provider type: %s is not supported": "El tipo de proveedor: %s no es compatible"
},
"subscription": {
"Error": "Error"
},
"token": {
"Empty clientId or clientSecret": "ClienteId o clienteSecret vacío",
"Grant_type: %s is not supported in this application": "El tipo de subvención: %s no es compatible con esta aplicación",
"Invalid application or wrong clientSecret": "Solicitud inválida o clientSecret incorrecto",
"Invalid client_id": "Identificador de cliente no válido",
@ -113,10 +159,10 @@
},
"user": {
"Display name cannot be empty": "El nombre de pantalla no puede estar vacío",
"New password cannot contain blank space.": "La nueva contraseña no puede contener espacios en blanco."
},
"user_upload": {
"Failed to import users": "Error al importar usuarios"
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"New password cannot contain blank space.": "La nueva contraseña no puede contener espacios en blanco.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"util": {
"No application is found for userId: %s": "No se encuentra ninguna aplicación para el Id de usuario: %s",
@ -124,19 +170,21 @@
"The provider: %s is not found": "El proveedor: %s no se encuentra"
},
"verification": {
"Code has not been sent yet!": "¡El código aún no ha sido enviado!",
"Invalid captcha provider.": "Proveedor de captcha no válido.",
"Phone number is invalid in your region %s": "El número de teléfono es inválido en tu región %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"Turing test failed.": "El test de Turing falló.",
"Unable to get the email modify rule.": "No se puede obtener la regla de modificación de correo electrónico.",
"Unable to get the phone modify rule.": "No se pudo obtener la regla de modificación del teléfono.",
"Unknown type": "Tipo desconocido",
"Wrong verification code!": "¡Código de verificación incorrecto!",
"You should verify your code in %d min!": "¡Deberías verificar tu código en %d minutos!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "El usuario no existe, por favor regístrese primero"
},
"webauthn": {
"Found no credentials for this user": "No se encontraron credenciales para este usuario",
"Please call WebAuthnSigninBegin first": "Por favor, llama primero a WebAuthnSigninBegin"
}
}

View File

@ -1,142 +1,190 @@
{
"account": {
"Failed to add user": "Failed to add user",
"Get init score failed, error: %w": "Get init score failed, error: %w",
"Please sign out first": "Please sign out first",
"The application does not allow to sign up new account": "The application does not allow to sign up new account"
"Failed to add user": "عدم موفقیت در افزودن کاربر",
"Get init score failed, error: %w": "عدم موفقیت در دریافت امتیاز اولیه، خطا: %w",
"Please sign out first": "لطفاً ابتدا خارج شوید",
"The application does not allow to sign up new account": "برنامه اجازه ثبت‌نام حساب جدید را نمی‌دهد"
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
"State expected: %s, but got: %s": "State expected: %s, but got: %s",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account via %%s, please use another way to sign up",
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with password is not enabled for the application": "The login method: login with password is not enabled for the application",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
"Challenge method should be S256": "روش چالش باید S256 باشد",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "عدم موفقیت در ایجاد کاربر، اطلاعات کاربر نامعتبر است: %s",
"Failed to login in: %s": "عدم موفقیت در ورود: %s",
"Invalid token": "توکن نامعتبر",
"State expected: %s, but got: %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) is already linked to another account: %s (%s)": "حساب برای ارائه‌دهنده: %s و نام کاربری: %s (%s) در حال حاضر به حساب دیگری مرتبط است: %s (%s)",
"The application: %s does not exist": "برنامه: %s وجود ندارد",
"The login method: login with LDAP is not enabled for the application": "روش ورود: ورود با LDAP برای برنامه فعال نیست",
"The login method: login with SMS is not enabled for the application": "روش ورود: ورود با پیامک برای برنامه فعال نیست",
"The login method: login with email is not enabled for the application": "روش ورود: ورود با ایمیل برای برنامه فعال نیست",
"The login method: login with face is not enabled for the application": "روش ورود: ورود با چهره برای برنامه فعال نیست",
"The login method: login with password is not enabled for the application": "روش ورود: ورود با رمز عبور برای برنامه فعال نیست",
"The organization: %s does not exist": "سازمان: %s وجود ندارد",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "ارائه‌دهنده: %s برای برنامه فعال نیست",
"Unauthorized operation": "عملیات غیرمجاز",
"Unknown authentication type (not password or provider), form = %s": "نوع احراز هویت ناشناخته (نه رمز عبور و نه ارائه‌دهنده)، فرم = %s",
"User's tag: %s is not listed in the application's tags": "برچسب کاربر: %s در برچسب‌های برنامه فهرست نشده است",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "کاربر پرداختی %s اشتراک فعال یا در انتظار ندارد و برنامه: %s قیمت‌گذاری پیش‌فرض ندارد",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
"Service %s and %s do not match": "سرویس %s و %s مطابقت ندارند"
},
"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",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Session outdated, please login again": "Session outdated, please login again",
"The user is forbidden to sign in, please contact the administrator": "The user is forbidden to sign in, please contact the administrator",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.": "The username may only contain alphanumeric characters, underlines or hyphens, cannot have consecutive hyphens or underlines, and cannot begin or end with a hyphen or underline.",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"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"
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "وابستگی نمی‌تواند خالی باشد",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "کد پیش‌فرض با قوانین تطبیق کد مطابقت ندارد",
"DisplayName cannot be blank": "نام نمایشی نمی‌تواند خالی باشد",
"DisplayName is not valid real name": "نام نمایشی یک نام واقعی معتبر نیست",
"Email already exists": "ایمیل قبلاً وجود دارد",
"Email cannot be empty": "ایمیل نمی‌تواند خالی باشد",
"Email is invalid": "ایمیل نامعتبر است",
"Empty username.": "نام کاربری خالی است.",
"Face data does not exist, cannot log in": "داده‌های چهره وجود ندارد، نمی‌توان وارد شد",
"Face data mismatch": "عدم تطابق داده‌های چهره",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "نام نمی‌تواند خالی باشد",
"Invitation code cannot be blank": "کد دعوت نمی‌تواند خالی باشد",
"Invitation code exhausted": "کد دعوت استفاده شده است",
"Invitation code is invalid": "کد دعوت نامعتبر است",
"Invitation code suspended": "کد دعوت معلق است",
"LDAP user name or password incorrect": "نام کاربری یا رمز عبور LDAP نادرست است",
"LastName cannot be blank": "نام خانوادگی نمی‌تواند خالی باشد",
"Multiple accounts with same uid, please check your ldap server": "چندین حساب با uid یکسان، لطفاً سرور LDAP خود را بررسی کنید",
"Organization does not exist": "سازمان وجود ندارد",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "تلفن قبلاً وجود دارد",
"Phone cannot be empty": "تلفن نمی‌تواند خالی باشد",
"Phone number is invalid": "شماره تلفن نامعتبر است",
"Please register using the email corresponding to the invitation code": "لطفاً با استفاده از ایمیل مربوط به کد دعوت ثبت‌نام کنید",
"Please register using the phone corresponding to the invitation code": "لطفاً با استفاده از تلفن مربوط به کد دعوت ثبت‌نام کنید",
"Please register using the username corresponding to the invitation code": "لطفاً با استفاده از نام کاربری مربوط به کد دعوت ثبت‌نام کنید",
"Session outdated, please login again": "جلسه منقضی شده است، لطفاً دوباره وارد شوید",
"The invitation code has already been used": "کد دعوت قبلاً استفاده شده است",
"The user is forbidden to sign in, please contact the administrator": "ورود کاربر ممنوع است، لطفاً با مدیر تماس بگیرید",
"The user: %s doesn't exist in LDAP server": "کاربر: %s در سرور LDAP وجود ندارد",
"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 value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "نام کاربری قبلاً وجود دارد",
"Username cannot be an email address": "نام کاربری نمی‌تواند یک آدرس ایمیل باشد",
"Username cannot contain white spaces": "نام کاربری نمی‌تواند حاوی فاصله باشد",
"Username cannot start with a digit": "نام کاربری نمی‌تواند با یک رقم شروع شود",
"Username is too long (maximum is 255 characters).": "نام کاربری بیش از حد طولانی است (حداکثر ۳۹ کاراکتر).",
"Username must have at least 2 characters": "نام کاربری باید حداقل ۲ کاراکتر داشته باشد",
"Username supports email format. Also 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. Also pay attention to the email format.": "Username supports email format. Also 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. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "شما رمز عبور یا کد اشتباه را بیش از حد وارد کرده‌اید، لطفاً %d دقیقه صبر کنید و دوباره تلاش کنید",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "منطقه شما اجازه ثبت‌نام با تلفن را ندارد",
"password or code is incorrect": "رمز عبور یا کد نادرست است",
"password or code is incorrect, you have %d remaining chances": "رمز عبور یا کد نادرست است، شما %d فرصت باقی‌مانده دارید",
"unsupported password type: %s": "نوع رمز عبور پشتیبانی نشده: %s"
},
"enforcer": {
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Missing parameter": "Missing parameter",
"Please login first": "Please login first",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
"Failed to import groups": "Failed to import groups",
"Failed to import users": "عدم موفقیت در وارد کردن کاربران",
"Missing parameter": "پارامتر گمشده",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "لطفاً ابتدا وارد شوید",
"The organization: %s should have one application at least": "سازمان: %s باید حداقل یک برنامه داشته باشد",
"The user: %s doesn't exist": "کاربر: %s وجود ندارد",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "از captchaProvider پشتیبانی نمی‌شود: ",
"this operation is not allowed in demo mode": "این عملیات در حالت دمو مجاز نیست",
"this operation requires administrator to perform": "این عملیات نیاز به مدیر برای انجام دارد"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
"Ldap server exist": "سرور LDAP وجود دارد"
},
"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"
"Please link first": "لطفاً ابتدا پیوند دهید",
"This application has no providers": "این برنامه ارائه‌دهنده‌ای ندارد",
"This application has no providers of type": "این برنامه ارائه‌دهنده‌ای از نوع ندارد",
"This provider can't be unlinked": "این ارائه‌دهنده نمی‌تواند لغو پیوند شود",
"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": "شما نمی‌توانید خودتان را لغو پیوند کنید، شما عضو هیچ برنامه‌ای نیستید"
},
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s."
"Only admin can modify the %s.": "فقط مدیر می‌تواند %s را تغییر دهد.",
"The %s is immutable.": "%s غیرقابل تغییر است.",
"Unknown modify rule %s.": "قانون تغییر ناشناخته %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "Invalid application id",
"the provider: %s does not exist": "the provider: %s does not exist"
"Invalid application id": "شناسه برنامه نامعتبر",
"the provider: %s does not exist": "ارائه‌دهنده: %s وجود ندارد"
},
"resource": {
"User is nil for tag: avatar": "User is nil for tag: avatar",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "Username or fullFilePath is empty: username = %s, fullFilePath = %s"
"User is nil for tag: avatar": "کاربر برای برچسب: آواتار تهی است",
"Username or fullFilePath is empty: username = %s, fullFilePath = %s": "نام کاربری یا مسیر کامل فایل خالی است: نام کاربری = %s، مسیر کامل فایل = %s"
},
"saml": {
"Application %s not found": "Application %s not found"
"Application %s not found": "برنامه %s یافت نشد"
},
"saml_sp": {
"provider %s's category is not SAML": "provider %s's category is not SAML"
"provider %s's category is not SAML": "دسته‌بندی ارائه‌دهنده %s SAML نیست"
},
"service": {
"Empty parameters for emailForm: %v": "Empty parameters for emailForm: %v",
"Invalid Email receivers: %s": "Invalid Email receivers: %s",
"Invalid phone receivers: %s": "Invalid phone receivers: %s"
"Empty parameters for emailForm: %v": "پارامترهای خالی برای emailForm: %v",
"Invalid Email receivers: %s": "گیرندگان ایمیل نامعتبر: %s",
"Invalid phone receivers: %s": "گیرندگان تلفن نامعتبر: %s"
},
"storage": {
"The objectKey: %s is not allowed": "The objectKey: %s is not allowed",
"The provider type: %s is not supported": "The provider type: %s is not supported"
"The objectKey: %s is not allowed": "objectKey: %s مجاز نیست",
"The provider type: %s is not supported": "نوع ارائه‌دهنده: %s پشتیبانی نمی‌شود"
},
"subscription": {
"Error": "Error"
},
"token": {
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "Redirect URI: %s doesn't exist in the allowed Redirect URI list",
"Token not found, invalid accessToken": "Token not found, invalid accessToken"
"Grant_type: %s is not supported in this application": "grant_type: %s در این برنامه پشتیبانی نمی‌شود",
"Invalid application or wrong clientSecret": "برنامه نامعتبر یا clientSecret نادرست",
"Invalid client_id": "client_id نامعتبر",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "آدرس بازگشت: %s در لیست آدرس‌های بازگشت مجاز وجود ندارد",
"Token not found, invalid accessToken": "توکن یافت نشد، accessToken نامعتبر"
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space."
},
"user_upload": {
"Failed to import users": "Failed to import users"
"Display name cannot be empty": "نام نمایشی نمی‌تواند خالی باشد",
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"New password cannot contain blank space.": "رمز عبور جدید نمی‌تواند حاوی فاصله خالی باشد.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
"No provider for category: %s is found for application: %s": "No provider for category: %s is found for application: %s",
"The provider: %s is not found": "The provider: %s is not found"
"No application is found for userId: %s": "هیچ برنامه‌ای برای userId: %s یافت نشد",
"No provider for category: %s is found for application: %s": "هیچ ارائه‌دهنده‌ای برای دسته‌بندی: %s برای برنامه: %s یافت نشد",
"The provider: %s is not found": "ارائه‌دهنده: %s یافت نشد"
},
"verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"Turing test failed.": "Turing test failed.",
"Unable to get the email modify rule.": "Unable to get the email modify rule.",
"Unable to get the phone modify rule.": "Unable to get the phone modify rule.",
"Unknown type": "Unknown type",
"Wrong verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
"Invalid captcha provider.": "ارائه‌دهنده کپچا نامعتبر.",
"Phone number is invalid in your region %s": "شماره تلفن در منطقه شما نامعتبر است %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "کد تأیید هنوز ارسال نشده است!",
"Turing test failed.": "تست تورینگ ناموفق بود.",
"Unable to get the email modify rule.": "عدم توانایی در دریافت قانون تغییر ایمیل.",
"Unable to get the phone modify rule.": "عدم توانایی در دریافت قانون تغییر تلفن.",
"Unknown type": "نوع ناشناخته",
"Wrong verification code!": "کد تأیید اشتباه!",
"You should verify your code in %d min!": "شما باید کد خود را در %d دقیقه تأیید کنید!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "کاربر وجود ندارد، لطفاً ابتدا ثبت‌نام کنید"
},
"webauthn": {
"Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
"Please call WebAuthnSigninBegin first": "لطفاً ابتدا WebAuthnSigninBegin را فراخوانی کنید"
}
}

View File

@ -7,6 +7,7 @@
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
@ -15,54 +16,93 @@
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face 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 organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Affiliation cannot be blank",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"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.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "Session outdated, please login again",
"The invitation code has already been used": "The invitation code has already been used",
"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 in LDAP server": "The user: %s doesn't exist in LDAP server",
"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 value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"Username supports email format. Also 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. Also pay attention to the email format.": "Username supports email format. Also 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. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"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"
},
"enforcer": {
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Failed to import users",
"Missing parameter": "Missing parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Please login first",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
@ -78,7 +118,11 @@
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s."
"Unknown modify rule %s.": "Unknown modify rule %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "Invalid application id",
@ -103,8 +147,10 @@
"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"
},
"subscription": {
"Error": "Error"
},
"token": {
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
@ -113,10 +159,10 @@
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space."
},
"user_upload": {
"Failed to import users": "Failed to import users"
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"New password cannot contain blank space.": "New password cannot contain blank space.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
@ -124,19 +170,21 @@
"The provider: %s is not found": "The provider: %s is not found"
},
"verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"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 verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

View File

@ -7,6 +7,7 @@
},
"auth": {
"Challenge method should be S256": "La méthode de défi doit être S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "Échec de la création de l'utilisateur, les informations utilisateur sont invalides : %s",
"Failed to login in: %s": "Échec de la connexion : %s",
"Invalid token": "Jeton invalide",
@ -15,54 +16,93 @@
"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": "Le compte pour le fournisseur : %s et le nom d'utilisateur : %s (%s) n'existe pas et n'est pas autorisé à s'inscrire comme nouveau compte, veuillez contacter votre support informatique",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Le compte du fournisseur : %s et le nom d'utilisateur : %s (%s) sont déjà liés à un autre compte : %s (%s)",
"The application: %s does not exist": "L'application : %s n'existe pas",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "La méthode de connexion : connexion avec mot de passe n'est pas activée pour l'application",
"The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "Le fournisseur :%s n'est pas activé pour l'application",
"Unauthorized operation": "Opération non autorisée",
"Unknown authentication type (not password or provider), form = %s": "Type d'authentification inconnu (pas de mot de passe ou de fournisseur), formulaire = %s",
"User's tag: %s is not listed in the application's tags": "Le tag de lutilisateur %s nest pas répertorié dans les tags de lapplication"
"User's tag: %s is not listed in the application's tags": "Le tag de lutilisateur %s nest pas répertorié dans les tags de lapplication",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Les services %s et %s ne correspondent pas"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Affiliation ne peut pas être vide",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"DisplayName cannot be blank": "Le nom d'affichage ne peut pas être vide",
"DisplayName is not valid real name": "DisplayName n'est pas un nom réel valide",
"Email already exists": "E-mail déjà existant",
"Email cannot be empty": "L'e-mail ne peut pas être vide",
"Email is invalid": "L'adresse e-mail est invalide",
"Empty username.": "Nom d'utilisateur vide.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "Le prénom ne peut pas être laissé vide",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "Nom d'utilisateur ou mot de passe LDAP incorrect",
"LastName cannot be blank": "Le nom de famille ne peut pas être vide",
"Multiple accounts with same uid, please check your ldap server": "Plusieurs comptes avec le même identifiant d'utilisateur, veuillez vérifier votre serveur LDAP",
"Organization does not exist": "L'organisation n'existe pas",
"Password must have at least 6 characters": "Le mot de passe doit comporter au moins 6 caractères",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "Le téléphone existe déjà",
"Phone cannot be empty": "Le téléphone ne peut pas être vide",
"Phone number is invalid": "Le numéro de téléphone est invalide",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "Session expirée, veuillez vous connecter à nouveau",
"The invitation code has already been used": "The invitation code has already been used",
"The user is forbidden to sign in, please contact the administrator": "L'utilisateur est interdit de se connecter, veuillez contacter l'administrateur",
"The user: %s doesn't exist in LDAP server": "L'utilisateur %s n'existe pas sur le serveur LDAP",
"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.": "Le nom d'utilisateur ne peut contenir que des caractères alphanumériques, des traits soulignés ou des tirets, ne peut pas avoir de tirets ou de traits soulignés consécutifs et ne peut pas commencer ou se terminer par un tiret ou un trait souligné.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "Nom d'utilisateur existe déjà",
"Username cannot be an email address": "Nom d'utilisateur ne peut pas être une adresse e-mail",
"Username cannot contain white spaces": "Nom d'utilisateur ne peut pas contenir d'espaces blancs",
"Username cannot start with a digit": "Nom d'utilisateur ne peut pas commencer par un chiffre",
"Username is too long (maximum is 39 characters).": "Nom d'utilisateur est trop long (maximum de 39 caractères).",
"Username is too long (maximum is 255 characters).": "Nom d'utilisateur est trop long (maximum de 255 caractères).",
"Username must have at least 2 characters": "Le nom d'utilisateur doit comporter au moins 2 caractères",
"Username supports email format. Also 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. Also pay attention to the email format.": "Username supports email format. Also 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. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Vous avez entré le mauvais mot de passe ou code plusieurs fois, veuillez attendre %d minutes et réessayer",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Votre région n'est pas autorisée à s'inscrire par téléphone",
"password or code is incorrect": "mot de passe ou code invalide",
"password or code is incorrect, you have %d remaining chances": "Le mot de passe ou le code est incorrect, il vous reste %d chances",
"unsupported password type: %s": "Type de mot de passe non pris en charge : %s"
},
"enforcer": {
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Échec de l'importation des utilisateurs",
"Missing parameter": "Paramètre manquant",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Veuillez d'abord vous connecter",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "L'utilisateur : %s n'existe pas",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "ne prend pas en charge captchaProvider: ",
"this operation is not allowed in demo mode": "cette opération nest pas autorisée en mode démo"
"this operation is not allowed in demo mode": "cette opération nest pas autorisée en mode démo",
"this operation requires administrator to perform": "this operation requires administrator to perform"
},
"ldap": {
"Ldap server exist": "Le serveur LDAP existe"
@ -78,7 +118,11 @@
"organization": {
"Only admin can modify the %s.": "Seul l'administrateur peut modifier le %s.",
"The %s is immutable.": "Le %s est immuable.",
"Unknown modify rule %s.": "Règle de modification inconnue %s."
"Unknown modify rule %s.": "Règle de modification inconnue %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "Identifiant d'application invalide",
@ -103,8 +147,10 @@
"The objectKey: %s is not allowed": "La clé d'objet : %s n'est pas autorisée",
"The provider type: %s is not supported": "Le type de fournisseur : %s n'est pas pris en charge"
},
"subscription": {
"Error": "Error"
},
"token": {
"Empty clientId or clientSecret": "clientId ou clientSecret vide",
"Grant_type: %s is not supported in this application": "Type_de_subvention : %s n'est pas pris en charge dans cette application",
"Invalid application or wrong clientSecret": "Application invalide ou clientSecret incorrect",
"Invalid client_id": "Identifiant de client invalide",
@ -113,10 +159,10 @@
},
"user": {
"Display name cannot be empty": "Le nom d'affichage ne peut pas être vide",
"New password cannot contain blank space.": "Le nouveau mot de passe ne peut pas contenir d'espace."
},
"user_upload": {
"Failed to import users": "Échec de l'importation des utilisateurs"
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"New password cannot contain blank space.": "Le nouveau mot de passe ne peut pas contenir d'espace.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"util": {
"No application is found for userId: %s": "Aucune application n'a été trouvée pour l'identifiant d'utilisateur : %s",
@ -124,19 +170,21 @@
"The provider: %s is not found": "Le fournisseur : %s n'a pas été trouvé"
},
"verification": {
"Code has not been sent yet!": "Le code n'a pas encore été envoyé !",
"Invalid captcha provider.": "Fournisseur de captcha invalide.",
"Phone number is invalid in your region %s": "Le numéro de téléphone n'est pas valide dans votre région %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"Turing test failed.": "Le test de Turing a échoué.",
"Unable to get the email modify rule.": "Incapable d'obtenir la règle de modification de courriel.",
"Unable to get the phone modify rule.": "Impossible d'obtenir la règle de modification de téléphone.",
"Unknown type": "Type inconnu",
"Wrong verification code!": "Mauvais code de vérification !",
"You should verify your code in %d min!": "Vous devriez vérifier votre code en %d min !",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "L'utilisateur n'existe pas, veuillez vous inscrire d'abord"
},
"webauthn": {
"Found no credentials for this user": "Aucune référence trouvée pour cet utilisateur",
"Please call WebAuthnSigninBegin first": "Veuillez d'abord appeler WebAuthnSigninBegin"
}
}

View File

@ -7,6 +7,7 @@
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
@ -15,54 +16,93 @@
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face 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 organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Affiliation cannot be blank",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"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.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "Session outdated, please login again",
"The invitation code has already been used": "The invitation code has already been used",
"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 in LDAP server": "The user: %s doesn't exist in LDAP server",
"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 value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"Username supports email format. Also 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. Also pay attention to the email format.": "Username supports email format. Also 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. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"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"
},
"enforcer": {
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Failed to import users",
"Missing parameter": "Missing parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Please login first",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
@ -78,7 +118,11 @@
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s."
"Unknown modify rule %s.": "Unknown modify rule %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "Invalid application id",
@ -103,8 +147,10 @@
"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"
},
"subscription": {
"Error": "Error"
},
"token": {
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
@ -113,10 +159,10 @@
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space."
},
"user_upload": {
"Failed to import users": "Failed to import users"
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"New password cannot contain blank space.": "New password cannot contain blank space.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
@ -124,19 +170,21 @@
"The provider: %s is not found": "The provider: %s is not found"
},
"verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"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 verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

View File

@ -1,88 +1,132 @@
{
"account": {
"Failed to add user": "Gagal menambahkan pengguna",
"Get init score failed, error: %w": "Gagal mendapatkan nilai init, kesalahan: %w",
"Get init score failed, error: %w": "Gagal mendapatkan nilai inisiasi, kesalahan: %w",
"Please sign out first": "Silakan keluar terlebih dahulu",
"The application does not allow to sign up new account": "Aplikasi tidak memperbolehkan untuk mendaftar akun baru"
"The application does not allow to sign up new account": "Aplikasi tidak memperbolehkan pendaftaran akun baru"
},
"auth": {
"Challenge method should be S256": "Metode tantangan harus S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "Gagal membuat pengguna, informasi pengguna tidak valid: %s",
"Failed to login in: %s": "Gagal masuk: %s",
"Invalid token": "Token tidak valid",
"State expected: %s, but got: %s": "Diharapkan: %s, tapi diperoleh: %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": "Akun untuk penyedia: %s dan nama pengguna: %s (%s) tidak ada dan tidak diizinkan untuk mendaftar sebagai akun baru melalui %%s, silakan gunakan cara lain untuk mendaftar",
"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": "Akun untuk penyedia: %s dan nama pengguna: %s (%s) tidak ada dan tidak diizinkan untuk mendaftar sebagai akun baru, silakan hubungi dukungan IT Anda",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Akun untuk provider: %s dan username: %s (%s) sudah terhubung dengan akun lain: %s (%s)",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "Akun untuk penyedia: %s dan username: %s (%s) sudah terhubung dengan akun lain: %s (%s)",
"The application: %s does not exist": "Aplikasi: %s tidak ada",
"The login method: login with password is not enabled for the application": "Metode login: login dengan kata sandi tidak diaktifkan untuk aplikasi tersebut",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "Metode login: login dengan sandi tidak diaktifkan untuk aplikasi tersebut",
"The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "Penyedia: %s tidak diaktifkan untuk aplikasi ini",
"Unauthorized operation": "Operasi tidak sah",
"Unknown authentication type (not password or provider), form = %s": "Jenis otentikasi tidak diketahui (bukan kata sandi atau pemberi), formulir = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
"Unknown authentication type (not password or provider), form = %s": "Jenis otentikasi tidak diketahui (bukan sandi atau penyedia), formulir = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Layanan %s dan %s tidak cocok"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Keterkaitan tidak boleh kosong",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"DisplayName cannot be blank": "Nama Pengguna tidak boleh kosong",
"DisplayName is not valid real name": "DisplayName bukanlah nama asli yang valid",
"Email already exists": "Email sudah ada",
"Email cannot be empty": "Email tidak boleh kosong",
"Email is invalid": "Email tidak valid",
"Empty username.": "Nama pengguna kosong.",
"Face data does not exist, cannot log in": "Data wajah tidak ada, tidak bisa login",
"Face data mismatch": "Ketidakcocokan data wajah",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "Nama depan tidak boleh kosong",
"LDAP user name or password incorrect": "Nama pengguna atau kata sandi Ldap salah",
"Invitation code cannot be blank": "Kode undangan tidak boleh kosong",
"Invitation code exhausted": "Kode undangan habis",
"Invitation code is invalid": "Kode undangan tidak valid",
"Invitation code suspended": "Kode undangan ditangguhkan",
"LDAP user name or password incorrect": "Nama pengguna atau sandi LDAP salah",
"LastName cannot be blank": "Nama belakang tidak boleh kosong",
"Multiple accounts with same uid, please check your ldap server": "Beberapa akun dengan uid yang sama, harap periksa server ldap Anda",
"Multiple accounts with same uid, please check your ldap server": "Beberapa akun dengan uid yang sama, harap periksa server LDAP Anda",
"Organization does not exist": "Organisasi tidak ada",
"Password must have at least 6 characters": "Kata sandi harus memiliki minimal 6 karakter",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "Telepon sudah ada",
"Phone cannot be empty": "Telepon tidak boleh kosong",
"Phone number is invalid": "Nomor telepon tidak valid",
"Session outdated, please login again": "Sesi kedaluwarsa, silakan masuk lagi",
"Please register using the email corresponding to the invitation code": "Silakan mendaftar menggunakan email yang sesuai dengan kode undangan",
"Please register using the phone corresponding to the invitation code": "Silakan mendaftar menggunakan email yang sesuai dengan kode undangan",
"Please register using the username corresponding to the invitation code": "Silakan mendaftar menggunakan username yang sesuai dengan kode undangan",
"Session outdated, please login again": "Sesi kadaluwarsa, silakan masuk lagi",
"The invitation code has already been used": "Kode undangan sudah digunakan",
"The user is forbidden to sign in, please contact the administrator": "Pengguna dilarang masuk, silakan hubungi administrator",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"The user: %s doesn't exist in LDAP server": "Pengguna: %s tidak ada di server LDAP",
"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.": "Nama pengguna hanya bisa menggunakan karakter alfanumerik, garis bawah atau tanda hubung, tidak boleh memiliki dua tanda hubung atau garis bawah berurutan, dan tidak boleh diawali atau diakhiri dengan tanda hubung atau garis bawah.",
"The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "Nilai \\\"%s\\\" pada bidang akun \\\"%s\\\" tidak cocok dengan ketentuan",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "Nilai \\\"%s\\\" pada bidang pendaftaran \\\"%s\\\" tidak cocok dengan ketentuan aplikasi \\\"%s\\\"",
"Username already exists": "Nama pengguna sudah ada",
"Username cannot be an email address": "Username tidak bisa menjadi alamat email",
"Username cannot contain white spaces": "Username tidak boleh mengandung spasi",
"Username cannot start with a digit": "Username tidak dapat dimulai dengan angka",
"Username is too long (maximum is 39 characters).": "Nama pengguna terlalu panjang (maksimum 39 karakter).",
"Username is too long (maximum is 255 characters).": "Nama pengguna terlalu panjang (maksimum 255 karakter).",
"Username must have at least 2 characters": "Nama pengguna harus memiliki setidaknya 2 karakter",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Anda telah memasukkan kata sandi atau kode yang salah terlalu banyak kali, mohon tunggu selama %d menit dan coba lagi",
"Username supports email format. Also 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. Also pay attention to the email format.": "Username supports email format. Also 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. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "Anda telah memasukkan sandi atau kode yang salah terlalu sering, mohon tunggu selama %d menit lalu coba kembali",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Wilayah Anda tidak diizinkan untuk mendaftar melalui telepon",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "Kata sandi atau kode salah, Anda memiliki %d kesempatan tersisa",
"password or code is incorrect": "kata sandi atau kode salah",
"password or code is incorrect, you have %d remaining chances": "Sandi atau kode salah, Anda memiliki %d kesempatan tersisa",
"unsupported password type: %s": "jenis sandi tidak didukung: %s"
},
"enforcer": {
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Gagal mengimpor pengguna",
"Missing parameter": "Parameter hilang",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Silahkan login terlebih dahulu",
"The organization: %s should have one application at least": "Organisasi: %s setidaknya harus memiliki satu aplikasi",
"The user: %s doesn't exist": "Pengguna: %s tidak ada",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "Jangan mendukung captchaProvider:",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
"this operation is not allowed in demo mode": "tindakan ini tidak diizinkan pada mode demo",
"this operation requires administrator to perform": "tindakan ini membutuhkan peran administrator"
},
"ldap": {
"Ldap server exist": "Server ldap ada"
},
"link": {
"Please link first": "Tolong tautkan terlebih dahulu",
"Please link first": "Silahkan tautkan terlebih dahulu",
"This application has no providers": "Aplikasi ini tidak memiliki penyedia",
"This application has no providers of type": " Aplikasi ini tidak memiliki penyedia tipe ",
"This provider can't be unlinked": "Pemberi layanan ini tidak dapat dipisahkan",
"This provider can't be unlinked": "Penyedia layanan ini tidak dapat dipisahkan",
"You are not the global admin, you can't unlink other users": "Anda bukan admin global, Anda tidak dapat memutuskan tautan pengguna lain",
"You can't unlink yourself, you are not a member of any application": "Anda tidak dapat memutuskan tautan diri sendiri, karena Anda bukan anggota dari aplikasi apa pun"
},
"organization": {
"Only admin can modify the %s.": "Hanya admin yang dapat memodifikasi %s.",
"The %s is immutable.": "%s tidak dapat diubah.",
"Unknown modify rule %s.": "Aturan modifikasi tidak diketahui %s."
"Unknown modify rule %s.": "Aturan modifikasi tidak diketahui %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "Izin: \\\"%s\\\" tidak ada"
},
"provider": {
"Invalid application id": "ID aplikasi tidak valid",
"the provider: %s does not exist": "provider: %s tidak ada"
"the provider: %s does not exist": "penyedia: %s tidak ada"
},
"resource": {
"User is nil for tag: avatar": "Pengguna kosong untuk tag: avatar",
@ -103,20 +147,22 @@
"The objectKey: %s is not allowed": "Kunci objek: %s tidak diizinkan",
"The provider type: %s is not supported": "Jenis penyedia: %s tidak didukung"
},
"subscription": {
"Error": "Error"
},
"token": {
"Empty clientId or clientSecret": "Kosong clientId atau clientSecret",
"Grant_type: %s is not supported in this application": "Jenis grant (grant_type) %s tidak didukung dalam aplikasi ini",
"Invalid application or wrong clientSecret": "Aplikasi tidak valid atau clientSecret salah",
"Invalid client_id": "Invalid client_id = ID klien tidak valid",
"Invalid client_id": "ID klien tidak valid",
"Redirect URI: %s doesn't exist in the allowed Redirect URI list": "URI pengalihan: %s tidak ada dalam daftar URI Pengalihan yang diizinkan",
"Token not found, invalid accessToken": "Token tidak ditemukan, accessToken tidak valid"
},
"user": {
"Display name cannot be empty": "Nama tampilan tidak boleh kosong",
"New password cannot contain blank space.": "Kata sandi baru tidak boleh mengandung spasi kosong."
},
"user_upload": {
"Failed to import users": "Gagal mengimpor pengguna"
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"New password cannot contain blank space.": "Sandi baru tidak boleh mengandung spasi kosong.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"util": {
"No application is found for userId: %s": "Tidak ditemukan aplikasi untuk userId: %s",
@ -124,19 +170,21 @@
"The provider: %s is not found": "Penyedia: %s tidak ditemukan"
},
"verification": {
"Code has not been sent yet!": "Kode belum dikirimkan!",
"Invalid captcha provider.": "Penyedia captcha tidak valid.",
"Phone number is invalid in your region %s": "Nomor telepon tidak valid di wilayah anda %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "Kode verifikasi belum terkirim!",
"Turing test failed.": "Tes Turing gagal.",
"Unable to get the email modify rule.": "Tidak dapat memperoleh aturan modifikasi email.",
"Unable to get the phone modify rule.": "Tidak dapat memodifikasi aturan telepon.",
"Unknown type": "Tipe tidak diketahui",
"Wrong verification code!": "Kode verifikasi salah!",
"You should verify your code in %d min!": "Anda harus memverifikasi kode Anda dalam %d menit!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "silahkan tambahkan penyedia SMS ke daftar \\\"Penyedia\\\" untuk aplikasi: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "silahkan tambahkan penyedia Email ke daftar \\\"Penyedia\\\" untuk aplikasi: %s",
"the user does not exist, please sign up first": "Pengguna tidak ada, silakan daftar terlebih dahulu"
},
"webauthn": {
"Found no credentials for this user": "Tidak ditemukan kredensial untuk pengguna ini",
"Please call WebAuthnSigninBegin first": "Harap panggil WebAuthnSigninBegin terlebih dahulu"
}
}

View File

@ -7,6 +7,7 @@
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
@ -15,54 +16,93 @@
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face 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 organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Affiliation cannot be blank",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"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.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "Session outdated, please login again",
"The invitation code has already been used": "The invitation code has already been used",
"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 in LDAP server": "The user: %s doesn't exist in LDAP server",
"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 value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"Username supports email format. Also 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. Also pay attention to the email format.": "Username supports email format. Also 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. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"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"
},
"enforcer": {
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Failed to import users",
"Missing parameter": "Missing parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Please login first",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
@ -78,7 +118,11 @@
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s."
"Unknown modify rule %s.": "Unknown modify rule %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "Invalid application id",
@ -103,8 +147,10 @@
"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"
},
"subscription": {
"Error": "Error"
},
"token": {
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
@ -113,10 +159,10 @@
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space."
},
"user_upload": {
"Failed to import users": "Failed to import users"
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"New password cannot contain blank space.": "New password cannot contain blank space.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
@ -124,19 +170,21 @@
"The provider: %s is not found": "The provider: %s is not found"
},
"verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"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 verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

View File

@ -7,6 +7,7 @@
},
"auth": {
"Challenge method should be S256": "チャレンジメソッドはS256である必要があります",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "ユーザーの作成に失敗しました。ユーザー情報が無効です:%s",
"Failed to login in: %s": "ログインできませんでした:%s",
"Invalid token": "無効なトークン",
@ -15,54 +16,93 @@
"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 application: %s does not exist": "アプリケーション: %sは存在しません",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "ログイン方法:パスワードでのログインはアプリケーションで有効になっていません",
"The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "プロバイダー:%sはアプリケーションでは有効化されていません",
"Unauthorized operation": "不正操作",
"Unknown authentication type (not password or provider), form = %s": "不明な認証タイプ(パスワードまたはプロバイダーではない)フォーム=%s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "サービス%sと%sは一致しません"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "所属は空白にできません",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"DisplayName cannot be blank": "表示名は空白にできません",
"DisplayName is not valid real name": "表示名は有効な実名ではありません",
"Email already exists": "メールは既に存在します",
"Email cannot be empty": "メールが空白にできません",
"Email is invalid": "電子メールは無効です",
"Empty username.": "空のユーザー名。",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "ファーストネームは空白にできません",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "Ldapのユーザー名またはパスワードが間違っています",
"LastName cannot be blank": "姓は空白にできません",
"Multiple accounts with same uid, please check your ldap server": "同じuidを持つ複数のアカウントがあります。あなたのLDAPサーバーを確認してください",
"Organization does not exist": "組織は存在しません",
"Password must have at least 6 characters": "パスワードは少なくとも6つの文字が必要です",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "電話はすでに存在しています",
"Phone cannot be empty": "電話は空っぽにできません",
"Phone number is invalid": "電話番号が無効です",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "セッションが期限切れになりました。再度ログインしてください",
"The invitation code has already been used": "The invitation code has already been used",
"The user is forbidden to sign in, please contact the administrator": "ユーザーはサインインできません。管理者に連絡してください",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"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 value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "ユーザー名はすでに存在しています",
"Username cannot be an email address": "ユーザー名には電子メールアドレスを使用できません",
"Username cannot contain white spaces": "ユーザ名にはスペースを含めることはできません",
"Username cannot start with a digit": "ユーザー名は数字で始めることはできません",
"Username is too long (maximum is 39 characters).": "ユーザー名が長すぎます(最大39文字)。",
"Username is too long (maximum is 255 characters).": "ユーザー名が長すぎます(最大255文字)。",
"Username must have at least 2 characters": "ユーザー名は少なくとも2文字必要です",
"Username supports email format. Also 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. Also pay attention to the email format.": "Username supports email format. Also 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. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "あなたは間違ったパスワードまたはコードを何度も入力しました。%d 分間待ってから再度お試しください",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "あなたの地域は電話でサインアップすることができません",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "パスワードまたはコードが間違っています。あと%d回の試行機会があります",
"unsupported password type: %s": "サポートされていないパスワードタイプ:%s"
},
"enforcer": {
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "ユーザーのインポートに失敗しました",
"Missing parameter": "不足しているパラメーター",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "最初にログインしてください",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "そのユーザー:%sは存在しません",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "captchaProviderをサポートしないでください",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
},
"ldap": {
"Ldap server exist": "LDAPサーバーは存在します"
@ -78,7 +118,11 @@
"organization": {
"Only admin can modify the %s.": "管理者のみが%sを変更できます。",
"The %s is immutable.": "%sは不変です。",
"Unknown modify rule %s.": "未知の変更ルール%s。"
"Unknown modify rule %s.": "未知の変更ルール%s。",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "アプリケーションIDが無効です",
@ -103,8 +147,10 @@
"The objectKey: %s is not allowed": "オブジェクトキー %s は許可されていません",
"The provider type: %s is not supported": "プロバイダータイプ:%sはサポートされていません"
},
"subscription": {
"Error": "Error"
},
"token": {
"Empty clientId or clientSecret": "クライアントIDまたはクライアントシークレットが空です",
"Grant_type: %s is not supported in this application": "grant_type%sはこのアプリケーションでサポートされていません",
"Invalid application or wrong clientSecret": "無効なアプリケーションまたは誤ったクライアントシークレットです",
"Invalid client_id": "client_idが無効です",
@ -113,10 +159,10 @@
},
"user": {
"Display name cannot be empty": "表示名は空にできません",
"New password cannot contain blank space.": "新しいパスワードにはスペースを含めることはできません。"
},
"user_upload": {
"Failed to import users": "ユーザーのインポートに失敗しました"
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"New password cannot contain blank space.": "新しいパスワードにはスペースを含めることはできません。",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"util": {
"No application is found for userId: %s": "ユーザーIDに対するアプリケーションが見つかりません %s",
@ -124,19 +170,21 @@
"The provider: %s is not found": "プロバイダー:%sが見つかりません"
},
"verification": {
"Code has not been sent yet!": "まだコードが送信されていません!",
"Invalid captcha provider.": "無効なCAPTCHAプロバイダー。",
"Phone number is invalid in your region %s": "電話番号はあなたの地域で無効です %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"Turing test failed.": "チューリングテストは失敗しました。",
"Unable to get the email modify rule.": "電子メール変更規則を取得できません。",
"Unable to get the phone modify rule.": "電話の変更ルールを取得できません。",
"Unknown type": "不明なタイプ",
"Wrong verification code!": "誤った検証コードです!",
"You should verify your code in %d min!": "あなたは%d分であなたのコードを確認する必要があります",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "ユーザーは存在しません。まず登録してください"
},
"webauthn": {
"Found no credentials for this user": "このユーザーの資格情報が見つかりませんでした",
"Please call WebAuthnSigninBegin first": "最初にWebAuthnSigninBeginを呼び出してください"
}
}

View File

@ -7,6 +7,7 @@
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
@ -15,54 +16,93 @@
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face 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 organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Affiliation cannot be blank",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"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.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "Session outdated, please login again",
"The invitation code has already been used": "The invitation code has already been used",
"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 in LDAP server": "The user: %s doesn't exist in LDAP server",
"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 value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"Username supports email format. Also 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. Also pay attention to the email format.": "Username supports email format. Also 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. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"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"
},
"enforcer": {
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Failed to import users",
"Missing parameter": "Missing parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Please login first",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
@ -78,7 +118,11 @@
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s."
"Unknown modify rule %s.": "Unknown modify rule %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "Invalid application id",
@ -103,8 +147,10 @@
"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"
},
"subscription": {
"Error": "Error"
},
"token": {
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
@ -113,10 +159,10 @@
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space."
},
"user_upload": {
"Failed to import users": "Failed to import users"
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"New password cannot contain blank space.": "New password cannot contain blank space.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
@ -124,19 +170,21 @@
"The provider: %s is not found": "The provider: %s is not found"
},
"verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"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 verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

View File

@ -7,6 +7,7 @@
},
"auth": {
"Challenge method should be S256": "도전 방식은 S256이어야 합니다",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "사용자를 만들지 못했습니다. 사용자 정보가 잘못되었습니다: %s",
"Failed to login in: %s": "로그인에 실패했습니다.: %s",
"Invalid token": "유효하지 않은 토큰",
@ -15,54 +16,93 @@
"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 application: %s does not exist": "해당 애플리케이션(%s)이 존재하지 않습니다",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face is not enabled for the application",
"The login method: login with password is not enabled for the application": "어플리케이션에서는 암호를 사용한 로그인 방법이 활성화되어 있지 않습니다",
"The organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "제공자 %s은(는) 응용 프로그램에서 활성화되어 있지 않습니다",
"Unauthorized operation": "무단 조작",
"Unknown authentication type (not password or provider), form = %s": "알 수 없는 인증 유형(암호 또는 공급자가 아님), 폼 = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "서비스 %s와 %s는 일치하지 않습니다"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "소속은 비워 둘 수 없습니다",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"DisplayName cannot be blank": "DisplayName는 비어 있을 수 없습니다",
"DisplayName is not valid real name": "DisplayName는 유효한 실제 이름이 아닙니다",
"Email already exists": "이메일이 이미 존재합니다",
"Email cannot be empty": "이메일은 비어 있을 수 없습니다",
"Email is invalid": "이메일이 유효하지 않습니다",
"Empty username.": "빈 사용자 이름.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "이름은 공백일 수 없습니다",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "LDAP 사용자 이름 또는 암호가 잘못되었습니다",
"LastName cannot be blank": "성은 비어 있을 수 없습니다",
"Multiple accounts with same uid, please check your ldap server": "동일한 UID를 가진 여러 계정이 있습니다. LDAP 서버를 확인해주세요",
"Organization does not exist": "조직은 존재하지 않습니다",
"Password must have at least 6 characters": "암호는 적어도 6자 이상이어야 합니다",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "전화기는 이미 존재합니다",
"Phone cannot be empty": "전화는 비워 둘 수 없습니다",
"Phone number is invalid": "전화번호가 유효하지 않습니다",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "세션이 만료되었습니다. 다시 로그인해주세요",
"The invitation code has already been used": "The invitation code has already been used",
"The user is forbidden to sign in, please contact the administrator": "사용자는 로그인이 금지되어 있습니다. 관리자에게 문의하십시오",
"The user: %s doesn't exist in LDAP server": "The user: %s doesn't exist in LDAP server",
"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 value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "사용자 이름이 이미 존재합니다",
"Username cannot be an email address": "사용자 이름은 이메일 주소가 될 수 없습니다",
"Username cannot contain white spaces": "사용자 이름에는 공백이 포함될 수 없습니다",
"Username cannot start with a digit": "사용자 이름은 숫자로 시작할 수 없습니다",
"Username is too long (maximum is 39 characters).": "사용자 이름이 너무 깁니다 (최대 39자).",
"Username is too long (maximum is 255 characters).": "사용자 이름이 너무 깁니다 (최대 255자).",
"Username must have at least 2 characters": "사용자 이름은 적어도 2개의 문자가 있어야 합니다",
"Username supports email format. Also 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. Also pay attention to the email format.": "Username supports email format. Also 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. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "올바르지 않은 비밀번호나 코드를 여러 번 입력했습니다. %d분 동안 기다리신 후 다시 시도해주세요",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "당신의 지역은 전화로 가입할 수 없습니다",
"password or code is incorrect": "password or code is incorrect",
"password or code is incorrect, you have %d remaining chances": "암호 또는 코드가 올바르지 않습니다. %d번의 기회가 남아 있습니다",
"unsupported password type: %s": "지원되지 않는 암호 유형: %s"
},
"enforcer": {
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "사용자 가져오기를 실패했습니다",
"Missing parameter": "누락된 매개변수",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "먼저 로그인 하십시오",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "사용자 %s는 존재하지 않습니다",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "CaptchaProvider를 지원하지 마세요",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
},
"ldap": {
"Ldap server exist": "LDAP 서버가 존재합니다"
@ -78,7 +118,11 @@
"organization": {
"Only admin can modify the %s.": "관리자만 %s을(를) 수정할 수 있습니다.",
"The %s is immutable.": "%s 는 변경할 수 없습니다.",
"Unknown modify rule %s.": "미확인 수정 규칙 %s."
"Unknown modify rule %s.": "미확인 수정 규칙 %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "잘못된 애플리케이션 ID입니다",
@ -103,8 +147,10 @@
"The objectKey: %s is not allowed": "객체 키 : %s 는 허용되지 않습니다",
"The provider type: %s is not supported": "제공자 유형: %s은/는 지원되지 않습니다"
},
"subscription": {
"Error": "Error"
},
"token": {
"Empty clientId or clientSecret": "클라이언트 ID 또는 클라이언트 비밀번호가 비어 있습니다",
"Grant_type: %s is not supported in this application": "그랜트 유형: %s은(는) 이 어플리케이션에서 지원되지 않습니다",
"Invalid application or wrong clientSecret": "잘못된 어플리케이션 또는 올바르지 않은 클라이언트 시크릿입니다",
"Invalid client_id": "잘못된 클라이언트 ID입니다",
@ -113,10 +159,10 @@
},
"user": {
"Display name cannot be empty": "디스플레이 이름은 비어 있을 수 없습니다",
"New password cannot contain blank space.": "새 비밀번호에는 공백이 포함될 수 없습니다."
},
"user_upload": {
"Failed to import users": "사용자 가져오기를 실패했습니다"
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"New password cannot contain blank space.": "새 비밀번호에는 공백이 포함될 수 없습니다.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"util": {
"No application is found for userId: %s": "어플리케이션을 찾을 수 없습니다. userId: %s",
@ -124,19 +170,21 @@
"The provider: %s is not found": "제공자: %s를 찾을 수 없습니다"
},
"verification": {
"Code has not been sent yet!": "코드는 아직 전송되지 않았습니다!",
"Invalid captcha provider.": "잘못된 captcha 제공자입니다.",
"Phone number is invalid in your region %s": "전화 번호가 당신의 지역 %s에서 유효하지 않습니다",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"Turing test failed.": "튜링 테스트 실패.",
"Unable to get the email modify rule.": "이메일 수정 규칙을 가져올 수 없습니다.",
"Unable to get the phone modify rule.": "전화 수정 규칙을 가져올 수 없습니다.",
"Unknown type": "알 수 없는 유형",
"Wrong verification code!": "잘못된 인증 코드입니다!",
"You should verify your code in %d min!": "당신은 %d분 안에 코드를 검증해야 합니다!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "사용자가 존재하지 않습니다. 먼저 회원 가입 해주세요"
},
"webauthn": {
"Found no credentials for this user": "이 사용자의 자격 증명을 찾을 수 없습니다",
"Please call WebAuthnSigninBegin first": "WebAuthnSigninBegin을 먼저 호출해주세요"
}
}

View File

@ -7,6 +7,7 @@
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
@ -15,54 +16,93 @@
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face 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 organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Affiliation cannot be blank",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"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.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "Session outdated, please login again",
"The invitation code has already been used": "The invitation code has already been used",
"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 in LDAP server": "The user: %s doesn't exist in LDAP server",
"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 value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"Username supports email format. Also 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. Also pay attention to the email format.": "Username supports email format. Also 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. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"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"
},
"enforcer": {
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Failed to import users",
"Missing parameter": "Missing parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Please login first",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
@ -78,7 +118,11 @@
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s."
"Unknown modify rule %s.": "Unknown modify rule %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "Invalid application id",
@ -103,8 +147,10 @@
"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"
},
"subscription": {
"Error": "Error"
},
"token": {
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
@ -113,10 +159,10 @@
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space."
},
"user_upload": {
"Failed to import users": "Failed to import users"
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"New password cannot contain blank space.": "New password cannot contain blank space.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
@ -124,19 +170,21 @@
"The provider: %s is not found": "The provider: %s is not found"
},
"verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"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 verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

View File

@ -7,6 +7,7 @@
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
@ -15,54 +16,93 @@
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face 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 organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Affiliation cannot be blank",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"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.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "Session outdated, please login again",
"The invitation code has already been used": "The invitation code has already been used",
"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 in LDAP server": "The user: %s doesn't exist in LDAP server",
"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 value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"Username supports email format. Also 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. Also pay attention to the email format.": "Username supports email format. Also 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. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"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"
},
"enforcer": {
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Failed to import users",
"Missing parameter": "Missing parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Please login first",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
@ -78,7 +118,11 @@
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s."
"Unknown modify rule %s.": "Unknown modify rule %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "Invalid application id",
@ -103,8 +147,10 @@
"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"
},
"subscription": {
"Error": "Error"
},
"token": {
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
@ -113,10 +159,10 @@
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space."
},
"user_upload": {
"Failed to import users": "Failed to import users"
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"New password cannot contain blank space.": "New password cannot contain blank space.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
@ -124,19 +170,21 @@
"The provider: %s is not found": "The provider: %s is not found"
},
"verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"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 verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

View File

@ -7,6 +7,7 @@
},
"auth": {
"Challenge method should be S256": "Challenge method should be S256",
"DeviceCode Invalid": "DeviceCode Invalid",
"Failed to create user, user information is invalid: %s": "Failed to create user, user information is invalid: %s",
"Failed to login in: %s": "Failed to login in: %s",
"Invalid token": "Invalid token",
@ -15,54 +16,93 @@
"The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support": "The account for provider: %s and username: %s (%s) does not exist and is not allowed to sign up as new account, please contact your IT support",
"The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)": "The account for provider: %s and username: %s (%s) is already linked to another account: %s (%s)",
"The application: %s does not exist": "The application: %s does not exist",
"The login method: login with LDAP is not enabled for the application": "The login method: login with LDAP is not enabled for the application",
"The login method: login with SMS is not enabled for the application": "The login method: login with SMS is not enabled for the application",
"The login method: login with email is not enabled for the application": "The login method: login with email is not enabled for the application",
"The login method: login with face is not enabled for the application": "The login method: login with face 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 organization: %s does not exist": "The organization: %s does not exist",
"The provider: %s does not exist": "The provider: %s does not exist",
"The provider: %s is not enabled for the application": "The provider: %s is not enabled for the application",
"Unauthorized operation": "Unauthorized operation",
"Unknown authentication type (not password or provider), form = %s": "Unknown authentication type (not password or provider), form = %s",
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags"
"User's tag: %s is not listed in the application's tags": "User's tag: %s is not listed in the application's tags",
"UserCode Expired": "UserCode Expired",
"UserCode Invalid": "UserCode Invalid",
"paid-user %s does not have active or pending subscription and the application: %s does not have default pricing": "paid-user %s does not have active or pending subscription and the application: %s does not have default pricing",
"the application for user %s is not found": "the application for user %s is not found",
"the organization: %s is not found": "the organization: %s is not found"
},
"cas": {
"Service %s and %s do not match": "Service %s and %s do not match"
},
"check": {
"%s does not meet the CIDR format requirements: %s": "%s does not meet the CIDR format requirements: %s",
"Affiliation cannot be blank": "Affiliation cannot be blank",
"CIDR for IP: %s should not be empty": "CIDR for IP: %s should not be empty",
"Default code does not match the code's matching rules": "Default code does not match the code's matching rules",
"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.",
"Face data does not exist, cannot log in": "Face data does not exist, cannot log in",
"Face data mismatch": "Face data mismatch",
"Failed to parse client IP: %s": "Failed to parse client IP: %s",
"FirstName cannot be blank": "FirstName cannot be blank",
"Invitation code cannot be blank": "Invitation code cannot be blank",
"Invitation code exhausted": "Invitation code exhausted",
"Invitation code is invalid": "Invitation code is invalid",
"Invitation code suspended": "Invitation code suspended",
"LDAP user name or password incorrect": "LDAP user name or password incorrect",
"LastName cannot be blank": "LastName cannot be blank",
"Multiple accounts with same uid, please check your ldap server": "Multiple accounts with same uid, please check your ldap server",
"Organization does not exist": "Organization does not exist",
"Password must have at least 6 characters": "Password must have at least 6 characters",
"Password cannot be empty": "Password cannot be empty",
"Phone already exists": "Phone already exists",
"Phone cannot be empty": "Phone cannot be empty",
"Phone number is invalid": "Phone number is invalid",
"Please register using the email corresponding to the invitation code": "Please register using the email corresponding to the invitation code",
"Please register using the phone corresponding to the invitation code": "Please register using the phone corresponding to the invitation code",
"Please register using the username corresponding to the invitation code": "Please register using the username corresponding to the invitation code",
"Session outdated, please login again": "Session outdated, please login again",
"The invitation code has already been used": "The invitation code has already been used",
"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 in LDAP server": "The user: %s doesn't exist in LDAP server",
"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 value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex": "The value \\\"%s\\\" for account field \\\"%s\\\" doesn't match the account item regex",
"The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"": "The value \\\"%s\\\" for signup field \\\"%s\\\" doesn't match the signup item regex of the application \\\"%s\\\"",
"Username already exists": "Username already exists",
"Username cannot be an email address": "Username cannot be an email address",
"Username cannot contain white spaces": "Username cannot contain white spaces",
"Username cannot start with a digit": "Username cannot start with a digit",
"Username is too long (maximum is 39 characters).": "Username is too long (maximum is 39 characters).",
"Username is too long (maximum is 255 characters).": "Username is too long (maximum is 255 characters).",
"Username must have at least 2 characters": "Username must have at least 2 characters",
"Username supports email format. Also 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. Also pay attention to the email format.": "Username supports email format. Also 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. Also pay attention to the email format.",
"You have entered the wrong password or code too many times, please wait for %d minutes and try again": "You have entered the wrong password or code too many times, please wait for %d minutes and try again",
"Your IP address: %s has been banned according to the configuration of: ": "Your IP address: %s has been banned according to the configuration of: ",
"Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"": "Your password has expired. Please reset your password by clicking \\\"Forgot password\\\"",
"Your region is not allow to signup by phone": "Your region is not allow to signup by phone",
"password or code is incorrect": "password or code is incorrect",
"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"
},
"enforcer": {
"the adapter: %s is not found": "the adapter: %s is not found"
},
"general": {
"Failed to import groups": "Failed to import groups",
"Failed to import users": "Failed to import users",
"Missing parameter": "Missing parameter",
"Only admin user can specify user": "Only admin user can specify user",
"Please login first": "Please login first",
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
"The user: %s doesn't exist": "The user: %s doesn't exist",
"Wrong userId": "Wrong userId",
"don't support captchaProvider: ": "don't support captchaProvider: ",
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode"
"this operation is not allowed in demo mode": "this operation is not allowed in demo mode",
"this operation requires administrator to perform": "this operation requires administrator to perform"
},
"ldap": {
"Ldap server exist": "Ldap server exist"
@ -78,7 +118,11 @@
"organization": {
"Only admin can modify the %s.": "Only admin can modify the %s.",
"The %s is immutable.": "The %s is immutable.",
"Unknown modify rule %s.": "Unknown modify rule %s."
"Unknown modify rule %s.": "Unknown modify rule %s.",
"adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option.": "adding a new user to the 'built-in' organization is currently disabled. Please note: all users in the 'built-in' organization are global administrators in Casdoor. Refer to the docs: https://casdoor.org/docs/basic/core-concepts#how-does-casdoor-manage-itself. If you still wish to create a user for the 'built-in' organization, go to the organization's settings page and enable the 'Has privilege consent' option."
},
"permission": {
"The permission: \\\"%s\\\" doesn't exist": "The permission: \\\"%s\\\" doesn't exist"
},
"provider": {
"Invalid application id": "Invalid application id",
@ -103,8 +147,10 @@
"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"
},
"subscription": {
"Error": "Error"
},
"token": {
"Empty clientId or clientSecret": "Empty clientId or clientSecret",
"Grant_type: %s is not supported in this application": "Grant_type: %s is not supported in this application",
"Invalid application or wrong clientSecret": "Invalid application or wrong clientSecret",
"Invalid client_id": "Invalid client_id",
@ -113,10 +159,10 @@
},
"user": {
"Display name cannot be empty": "Display name cannot be empty",
"New password cannot contain blank space.": "New password cannot contain blank space."
},
"user_upload": {
"Failed to import users": "Failed to import users"
"MFA email is enabled but email is empty": "MFA email is enabled but email is empty",
"MFA phone is enabled but phone number is empty": "MFA phone is enabled but phone number is empty",
"New password cannot contain blank space.": "New password cannot contain blank space.",
"the user's owner and name should not be empty": "the user's owner and name should not be empty"
},
"util": {
"No application is found for userId: %s": "No application is found for userId: %s",
@ -124,19 +170,21 @@
"The provider: %s is not found": "The provider: %s is not found"
},
"verification": {
"Code has not been sent yet!": "Code has not been sent yet!",
"Invalid captcha provider.": "Invalid captcha provider.",
"Phone number is invalid in your region %s": "Phone number is invalid in your region %s",
"The verification code has already been used!": "The verification code has already been used!",
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
"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 verification code!": "Wrong verification code!",
"You should verify your code in %d min!": "You should verify your code in %d min!",
"please add a SMS provider to the \\\"Providers\\\" list for the application: %s": "please add a SMS provider to the \\\"Providers\\\" list for the application: %s",
"please add an Email provider to the \\\"Providers\\\" list for the application: %s": "please add an Email provider to the \\\"Providers\\\" list for the application: %s",
"the user does not exist, please sign up first": "the user does not exist, please sign up first"
},
"webauthn": {
"Found no credentials for this user": "Found no credentials for this user",
"Please call WebAuthnSigninBegin first": "Please call WebAuthnSigninBegin first"
}
}

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