Compare commits

...

13 Commits

Author SHA1 Message Date
hsluoyz
d92b072ed0 feat: revert PR: "feat: more RFC like LDAP server behaviour" (#2611) 2024-01-15 13:58:33 +08:00
hsluoyz
1161310f81 feat: improve README.md 2024-01-15 10:14:01 +08:00
xiao-kong-long
48ba5f91ed feat: add Synology NAS storage provider (#2605) 2024-01-14 22:38:31 +08:00
Satinder Singh
53df2c2704 fix: add semantic versioning for helm charts (#2603) 2024-01-14 09:44:16 +08:00
Yang Luo
78066da208 Improve setCorsHeaders() for "include" mode 2024-01-13 23:46:05 +08:00
Yang Luo
60096468fe fix: fix CI email 2024-01-13 18:12:52 +08:00
Yang Luo
39d6bc10f7 Fix GetCaptchaStatus() crash if not logged in 2024-01-13 18:04:38 +08:00
Yang Luo
177f2f2f11 Add userId param to GetAllObjects() API 2024-01-13 18:03:40 +08:00
Yang Luo
79b393afee feat: add regex to SignupTable 2024-01-13 16:08:49 +08:00
Yang Luo
5bb12a30d4 Don't show two errors in verificationCode login page 2024-01-13 16:01:22 +08:00
Yang Luo
fdb68bf9c8 Rename to SigninMethodTable 2024-01-13 15:53:01 +08:00
Yang Luo
37748850c8 Fix nameFormat in SamlItem 2024-01-13 15:32:49 +08:00
Yang Luo
8968396ae5 Fix bug in getDefaultLoginMethod() 2024-01-13 12:13:09 +08:00
47 changed files with 255 additions and 554 deletions

View File

@@ -217,13 +217,9 @@ jobs:
- name: Update Helm Chart
if: steps.should_push.outputs.push=='true'
run: |
# Set the appVersion of the chart to the current tag
# 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
# increase the patch version of the chart
currentChartVersion=$(cat ./charts/casdoor/Chart.yaml | grep ^version | awk '{print $2}')
newChartVersion=$(echo $currentChartVersion | awk -F. -v OFS=. '{$NF++;print}')
sed -i "s/version: .*/version: $newChartVersion/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
@@ -235,7 +231,8 @@ jobs:
# Commit and push the changes back to the repository
git config --global user.name "casbin-bot"
git config --global user.email "casbin-bot@github.com"
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 push origin HEAD:master
git tag ${{steps.get-current-tag.outputs.tag }}
git push origin HEAD:master --follow-tags

View File

@@ -69,6 +69,7 @@ https://casdoor.org
- 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?

View File

@@ -973,23 +973,27 @@ func (c *ApiController) GetWebhookEventType() {
// @router /api/get-captcha-status [get]
func (c *ApiController) GetCaptchaStatus() {
organization := c.Input().Get("organization")
userId := c.Input().Get("user_id")
userId := c.Input().Get("userId")
user, err := object.GetUserByFields(organization, userId)
if err != nil {
c.ResponseError(err.Error())
return
}
failedSigninLimit, _, err := object.GetFailedSigninConfigByUser(user)
if err != nil {
c.ResponseError(err.Error())
return
captchaEnabled := false
if user != nil {
var failedSigninLimit int
failedSigninLimit, _, err = object.GetFailedSigninConfigByUser(user)
if err != nil {
c.ResponseError(err.Error())
return
}
if user.SigninWrongTimes >= failedSigninLimit {
captchaEnabled = true
}
}
var captchaEnabled bool
if user != nil && user.SigninWrongTimes >= failedSigninLimit {
captchaEnabled = true
}
c.ResponseOk(captchaEnabled)
}

View File

@@ -264,10 +264,13 @@ func (c *ApiController) BatchEnforce() {
}
func (c *ApiController) GetAllObjects() {
userId := c.GetSessionUsername()
userId := c.Input().Get("userId")
if userId == "" {
c.ResponseError(c.T("general:Please login first"))
return
userId = c.GetSessionUsername()
if userId == "" {
c.ResponseError(c.T("general:Please login first"))
return
}
}
objects, err := object.GetAllObjects(userId)
@@ -280,10 +283,13 @@ func (c *ApiController) GetAllObjects() {
}
func (c *ApiController) GetAllActions() {
userId := c.GetSessionUsername()
userId := c.Input().Get("userId")
if userId == "" {
c.ResponseError(c.T("general:Please login first"))
return
userId = c.GetSessionUsername()
if userId == "" {
c.ResponseError(c.T("general:Please login first"))
return
}
}
actions, err := object.GetAllActions(userId)
@@ -296,10 +302,13 @@ func (c *ApiController) GetAllActions() {
}
func (c *ApiController) GetAllRoles() {
userId := c.GetSessionUsername()
userId := c.Input().Get("userId")
if userId == "" {
c.ResponseError(c.T("general:Please login first"))
return
userId = c.GetSessionUsername()
if userId == "" {
c.ResponseError(c.T("general:Please login first"))
return
}
}
roles, err := object.GetAllRoles(userId)

2
go.mod
View File

@@ -12,7 +12,7 @@ require (
github.com/casdoor/go-sms-sender v0.19.0
github.com/casdoor/gomail/v2 v2.0.1
github.com/casdoor/notify v0.45.0
github.com/casdoor/oss v1.4.1
github.com/casdoor/oss v1.5.0
github.com/casdoor/xorm-adapter/v3 v3.1.0
github.com/casvisor/casvisor-go-sdk v1.0.3
github.com/dchest/captcha v0.0.0-20200903113550-03f5f0333e1f

2
go.sum
View File

@@ -1091,6 +1091,8 @@ github.com/casdoor/notify v0.45.0 h1:OlaFvcQFjGOgA4mRx07M8AH1gvb5xNo21mcqrVGlLgk
github.com/casdoor/notify v0.45.0/go.mod h1:wNHQu0tiDROMBIvz0j3Om3Lhd5yZ+AIfnFb8MYb8OLQ=
github.com/casdoor/oss v1.4.1 h1:/P2JCyGzB2TtpJ3LocKocI1VAme2YdvVau2wpMQGt7I=
github.com/casdoor/oss v1.4.1/go.mod h1:rJAWA0hLhtu94t6IRpotLUkXO1NWMASirywQYaGizJE=
github.com/casdoor/oss v1.5.0 h1:mi1htaXR5fynskDry1S3wk+Dd2nRY1z1pVcnGsqMqP4=
github.com/casdoor/oss v1.5.0/go.mod h1:rJAWA0hLhtu94t6IRpotLUkXO1NWMASirywQYaGizJE=
github.com/casdoor/xorm-adapter/v3 v3.1.0 h1:NodWayRtSLVSeCvL9H3Hc61k0G17KhV9IymTCNfh3kk=
github.com/casdoor/xorm-adapter/v3 v3.1.0/go.mod h1:4WTcUw+bTgBylGHeGHzTtBvuTXRS23dtwzFLl9tsgFM=
github.com/casvisor/casvisor-go-sdk v1.0.3 h1:TKJQWKnhtznEBhzLPEdNsp7nJK2GgdD8JsB0lFPMW7U=

View File

@@ -18,7 +18,6 @@ import (
"fmt"
"hash/fnv"
"log"
"strings"
"github.com/casdoor/casdoor/conf"
"github.com/casdoor/casdoor/object"
@@ -50,17 +49,7 @@ func handleBind(w ldap.ResponseWriter, m *ldap.Message) {
res := ldap.NewBindResponse(ldap.LDAPResultSuccess)
if r.AuthenticationChoice() == "simple" {
bindDN := string(r.Name())
bindPassword := string(r.AuthenticationSimple())
if bindDN == "" && bindPassword == "" {
res.SetResultCode(ldap.LDAPResultInappropriateAuthentication)
res.SetDiagnosticMessage("Anonymous bind disallowed")
w.Write(res)
return
}
bindUsername, bindOrg, err := getNameAndOrgFromDN(bindDN)
bindUsername, bindOrg, err := getNameAndOrgFromDN(string(r.Name()))
if err != nil {
log.Printf("getNameAndOrgFromDN() error: %s", err.Error())
res.SetResultCode(ldap.LDAPResultInvalidDNSyntax)
@@ -69,6 +58,7 @@ func handleBind(w ldap.ResponseWriter, m *ldap.Message) {
return
}
bindPassword := string(r.AuthenticationSimple())
bindUser, err := object.CheckUserPassword(bindOrg, bindUsername, bindPassword, "en")
if err != nil {
log.Printf("Bind failed User=%s, Pass=%#v, ErrMsg=%s", string(r.Name()), r.Authentication(), err)
@@ -103,46 +93,7 @@ func handleSearch(w ldap.ResponseWriter, m *ldap.Message) {
}
r := m.GetSearchRequest()
// case insensitive match
if strings.EqualFold(r.FilterString(), "(objectClass=*)") {
if len(r.Attributes()) == 0 {
w.Write(res)
return
}
first_attr := string(r.Attributes()[0])
if string(r.BaseObject()) == "" {
// handle special search requests
if first_attr == "namingContexts" {
orgs, code := GetFilteredOrganizations(m)
if code != ldap.LDAPResultSuccess {
res.SetResultCode(code)
w.Write(res)
return
}
e := ldap.NewSearchResultEntry(string(r.BaseObject()))
dnlist := make([]message.AttributeValue, len(orgs))
for i, org := range orgs {
dnlist[i] = message.AttributeValue(fmt.Sprintf("ou=%s", org.Name))
}
e.AddAttribute("namingContexts", dnlist...)
w.Write(e)
} else if first_attr == "subschemaSubentry" {
e := ldap.NewSearchResultEntry(string(r.BaseObject()))
e.AddAttribute("subschemaSubentry", message.AttributeValue("cn=Subschema"))
w.Write(e)
}
} else if strings.EqualFold(first_attr, "objectclasses") && string(r.BaseObject()) == "cn=Subschema" {
e := ldap.NewSearchResultEntry(string(r.BaseObject()))
e.AddAttribute("objectClasses", []message.AttributeValue{
"( 1.3.6.1.1.1.2.0 NAME 'posixAccount' DESC 'Abstraction of an account with POSIX attributes' SUP top AUXILIARY MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory ) MAY ( userPassword $ loginShell $ gecos $ description ) )",
"( 1.3.6.1.1.1.2.2 NAME 'posixGroup' DESC 'Abstraction of a group of accounts' SUP top STRUCTURAL MUST ( cn $ gidNumber ) MAY ( userPassword $ memberUid $ description ) )",
}...)
w.Write(e)
}
if r.FilterString() == "(objectClass=*)" {
w.Write(res)
return
}
@@ -155,72 +106,38 @@ func handleSearch(w ldap.ResponseWriter, m *ldap.Message) {
default:
}
objectClass := searchFilterForEquality(r.Filter(), "objectClass", "posixAccount", "posixGroup")
switch objectClass {
case "posixAccount":
users, code := GetFilteredUsers(m)
if code != ldap.LDAPResultSuccess {
res.SetResultCode(code)
w.Write(res)
return
}
// log.Printf("Handling posixAccount filter=%s", r.FilterString())
for _, user := range users {
dn := fmt.Sprintf("uid=%s,cn=users,%s", user.Name, string(r.BaseObject()))
e := ldap.NewSearchResultEntry(dn)
attrs := r.Attributes()
for _, attr := range attrs {
if string(attr) == "*" {
attrs = AdditionalLdapUserAttributes
break
}
}
for _, attr := range attrs {
if strings.HasSuffix(string(attr), ";binary") {
// unsupported: userCertificate;binary
continue
}
field, ok := ldapUserAttributesMapping.CaseInsensitiveGet(string(attr))
if ok {
e.AddAttribute(message.AttributeDescription(attr), field.GetAttributeValues(user)...)
}
}
w.Write(e)
}
case "posixGroup":
// log.Printf("Handling posixGroup filter=%s", r.FilterString())
groups, code := GetFilteredGroups(m)
if code != ldap.LDAPResultSuccess {
res.SetResultCode(code)
w.Write(res)
return
}
for _, group := range groups {
dn := fmt.Sprintf("cn=%s,cn=groups,%s", group.Name, string(r.BaseObject()))
e := ldap.NewSearchResultEntry(dn)
attrs := r.Attributes()
for _, attr := range attrs {
if string(attr) == "*" {
attrs = AdditionalLdapGroupAttributes
break
}
}
for _, attr := range attrs {
field, ok := ldapGroupAttributesMapping.CaseInsensitiveGet(string(attr))
if ok {
e.AddAttribute(message.AttributeDescription(attr), field.GetAttributeValues(group)...)
}
}
w.Write(e)
}
case "":
log.Printf("Unmatched search request. filter=%s", r.FilterString())
users, code := GetFilteredUsers(m)
if code != ldap.LDAPResultSuccess {
res.SetResultCode(code)
w.Write(res)
return
}
for _, user := range users {
dn := fmt.Sprintf("uid=%s,cn=%s,%s", user.Id, user.Name, string(r.BaseObject()))
e := ldap.NewSearchResultEntry(dn)
uidNumberStr := fmt.Sprintf("%v", hash(user.Name))
e.AddAttribute("uidNumber", message.AttributeValue(uidNumberStr))
e.AddAttribute("gidNumber", message.AttributeValue(uidNumberStr))
e.AddAttribute("homeDirectory", message.AttributeValue("/home/"+user.Name))
e.AddAttribute("cn", message.AttributeValue(user.Name))
e.AddAttribute("uid", message.AttributeValue(user.Id))
attrs := r.Attributes()
for _, attr := range attrs {
if string(attr) == "*" {
attrs = AdditionalLdapAttributes
break
}
}
for _, attr := range attrs {
e.AddAttribute(message.AttributeDescription(attr), getAttribute(string(attr), user))
if string(attr) == "cn" {
e.AddAttribute(message.AttributeDescription(attr), getAttribute("title", user))
}
}
w.Write(e)
}
w.Write(res)
}

View File

@@ -18,7 +18,6 @@ import (
"fmt"
"log"
"strings"
"time"
"github.com/casdoor/casdoor/object"
"github.com/casdoor/casdoor/util"
@@ -29,259 +28,65 @@ import (
"github.com/xorm-io/builder"
)
type V = message.AttributeValue
type AttributeMapper func(user *object.User) message.AttributeValue
type UserAttributeMapper func(user *object.User) []V
type UserFieldRelation struct {
type FieldRelation struct {
userField string
ldapField string
notSearchable bool
hideOnStarOp bool
fieldMapper UserAttributeMapper
constantValue []V
fieldMapper AttributeMapper
}
func (rel UserFieldRelation) GetField() (string, error) {
func (rel FieldRelation) GetField() (string, error) {
if rel.notSearchable {
return "", fmt.Errorf("attribute %s not supported", rel.userField)
}
return rel.userField, nil
}
func (rel UserFieldRelation) GetAttributeValues(user *object.User) []V {
if rel.constantValue != nil && rel.fieldMapper == nil {
return rel.constantValue
}
func (rel FieldRelation) GetAttributeValue(user *object.User) message.AttributeValue {
return rel.fieldMapper(user)
}
type UserFieldRelationMap map[string]UserFieldRelation
func (m UserFieldRelationMap) CaseInsensitiveGet(key string) (UserFieldRelation, bool) {
lowerKey := strings.ToLower(key)
ret, ok := m[lowerKey]
return ret, ok
}
type GroupAttributeMapper func(group *object.Group) []V
type GroupFieldRelation struct {
groupField string
ldapField string
notSearchable bool
hideOnStarOp bool
fieldMapper GroupAttributeMapper
constantValue []V
}
func (rel GroupFieldRelation) GetField() (string, error) {
if rel.notSearchable {
return "", fmt.Errorf("attribute %s not supported", rel.groupField)
}
return rel.groupField, nil
}
func (rel GroupFieldRelation) GetAttributeValues(group *object.Group) []V {
if rel.constantValue != nil && rel.fieldMapper == nil {
return rel.constantValue
}
return rel.fieldMapper(group)
}
type GroupFieldRelationMap map[string]GroupFieldRelation
func (m GroupFieldRelationMap) CaseInsensitiveGet(key string) (GroupFieldRelation, bool) {
lowerKey := strings.ToLower(key)
ret, ok := m[lowerKey]
return ret, ok
}
var ldapUserAttributesMapping = UserFieldRelationMap{
"cn": {ldapField: "cn", userField: "name", hideOnStarOp: true, fieldMapper: func(user *object.User) []V {
return []V{V(user.Name)}
var ldapAttributesMapping = map[string]FieldRelation{
"cn": {userField: "name", hideOnStarOp: true, fieldMapper: func(user *object.User) message.AttributeValue {
return message.AttributeValue(user.Name)
}},
"uid": {ldapField: "uid", userField: "name", hideOnStarOp: true, fieldMapper: func(user *object.User) []V {
return []V{V(user.Name)}
"uid": {userField: "name", hideOnStarOp: true, fieldMapper: func(user *object.User) message.AttributeValue {
return message.AttributeValue(user.Name)
}},
"displayname": {ldapField: "displayName", userField: "displayName", fieldMapper: func(user *object.User) []V {
return []V{V(user.DisplayName)}
"displayname": {userField: "displayName", fieldMapper: func(user *object.User) message.AttributeValue {
return message.AttributeValue(user.DisplayName)
}},
"email": {ldapField: "email", userField: "email", fieldMapper: func(user *object.User) []V {
return []V{V(user.Email)}
"email": {userField: "email", fieldMapper: func(user *object.User) message.AttributeValue {
return message.AttributeValue(user.Email)
}},
"mail": {ldapField: "mail", userField: "email", fieldMapper: func(user *object.User) []V {
return []V{V(user.Email)}
"mail": {userField: "email", fieldMapper: func(user *object.User) message.AttributeValue {
return message.AttributeValue(user.Email)
}},
"mobile": {ldapField: "mobile", userField: "phone", fieldMapper: func(user *object.User) []V {
return []V{V(user.Phone)}
"mobile": {userField: "phone", fieldMapper: func(user *object.User) message.AttributeValue {
return message.AttributeValue(user.Phone)
}},
"telephonenumber": {ldapField: "telephoneNumber", userField: "phone", fieldMapper: func(user *object.User) []V {
return []V{V(user.Phone)}
"title": {userField: "tag", fieldMapper: func(user *object.User) message.AttributeValue {
return message.AttributeValue(user.Tag)
}},
"postaladdress": {ldapField: "postalAddress", userField: "address", fieldMapper: func(user *object.User) []V {
return []V{V(strings.Join(user.Address, " "))}
}},
"title": {ldapField: "title", userField: "title", fieldMapper: func(user *object.User) []V {
return []V{V(user.Title)}
}},
"gecos": {ldapField: "gecos", userField: "displayName", fieldMapper: func(user *object.User) []V {
return []V{V(user.DisplayName)}
}},
"description": {ldapField: "description", userField: "displayName", fieldMapper: func(user *object.User) []V {
return []V{V(user.DisplayName)}
}},
"logindisabled": {ldapField: "loginDisabled", userField: "isForbidden", fieldMapper: func(user *object.User) []V {
if user.IsForbidden {
return []V{V("1")}
} else {
return []V{V("0")}
}
}},
"userpassword": {
ldapField: "userPassword",
"userPassword": {
userField: "userPassword",
notSearchable: true,
fieldMapper: func(user *object.User) []V {
return []V{V(getUserPasswordWithType(user))}
fieldMapper: func(user *object.User) message.AttributeValue {
return message.AttributeValue(getUserPasswordWithType(user))
},
},
"uidnumber": {ldapField: "uidNumber", notSearchable: true, fieldMapper: func(user *object.User) []V {
return []V{V(fmt.Sprintf("%v", hash(user.Name)))}
}},
"gidnumber": {ldapField: "gidNumber", notSearchable: true, fieldMapper: func(user *object.User) []V {
if len(user.Groups) == 0 {
return []V{V("")}
}
group, err := object.GetGroup(user.Groups[0])
if err != nil {
log.Printf("gidnumber object.GetGroup error: %s", err)
return []V{V("")}
}
return []V{V(fmt.Sprintf("%v", hash(group.Name)))}
}},
"homedirectory": {ldapField: "homeDirectory", notSearchable: true, fieldMapper: func(user *object.User) []V {
return []V{V("/home/" + user.Name)}
}},
"loginshell": {ldapField: "loginShell", notSearchable: true, fieldMapper: func(user *object.User) []V {
if user.IsForbidden || user.IsDeleted {
return []V{V("/sbin/nologin")}
} else {
return []V{V("/bin/bash")}
}
}},
"shadowlastchange": {ldapField: "shadowLastChange", notSearchable: true, fieldMapper: func(user *object.User) []V {
// "this attribute specifies number of days between January 1, 1970, and the date that the password was last modified"
updatedTime, err := time.Parse(time.RFC3339, user.UpdatedTime)
if err != nil {
log.Printf("shadowlastchange time.Parse error: %s", err)
updatedTime = time.Now()
}
return []V{V(fmt.Sprint(updatedTime.Unix() / 86400))}
}},
"pwdchangedtime": {ldapField: "pwdChangedTime", notSearchable: true, fieldMapper: func(user *object.User) []V {
updatedTime, err := time.Parse(time.RFC3339, user.UpdatedTime)
if err != nil {
log.Printf("pwdchangedtime time.Parse error: %s", err)
updatedTime = time.Now()
}
return []V{V(updatedTime.UTC().Format("20060102030405Z"))}
}},
"shadowmin": {ldapField: "shadowMin", notSearchable: true, constantValue: []V{V("0")}},
"shadowmax": {ldapField: "shadowMax", notSearchable: true, constantValue: []V{V("99999")}},
"shadowwarning": {ldapField: "shadowWarning", notSearchable: true, constantValue: []V{V("7")}},
"shadowexpire": {ldapField: "shadowExpire", notSearchable: true, fieldMapper: func(user *object.User) []V {
if user.IsForbidden {
return []V{V("1")}
} else {
return []V{V("-1")}
}
}},
"shadowinactive": {ldapField: "shadowInactive", notSearchable: true, constantValue: []V{V("0")}},
"shadowflag": {ldapField: "shadowFlag", notSearchable: true, constantValue: []V{V("0")}},
"memberof": {ldapField: "memberOf", notSearchable: true, fieldMapper: func(user *object.User) []V {
var groupdn []V
for _, groupId := range user.Groups {
group, err := object.GetGroup(groupId)
if err != nil {
log.Printf("memberOf object.GetGroup error: %s", err)
continue
}
groupdn = append(groupdn, V(fmt.Sprintf("cn=%s,cn=groups,ou=%s", group.Name, group.Owner)))
}
return groupdn
}},
"objectclass": {ldapField: "objectClass", notSearchable: true, constantValue: []V{
V("top"),
V("posixAccount"),
V("shadowAccount"),
V("person"),
V("organizationalPerson"),
V("inetOrgPerson"),
V("apple-user"),
V("sambaSamAccount"),
V("sambaIdmapEntry"),
V("extensibleObject"),
}},
}
var ldapGroupAttributesMapping = GroupFieldRelationMap{
"cn": {ldapField: "cn", hideOnStarOp: true, fieldMapper: func(group *object.Group) []V {
return []V{V(group.Name)}
}},
"gidnumber": {ldapField: "gidNumber", hideOnStarOp: true, fieldMapper: func(group *object.Group) []V {
return []V{V(fmt.Sprintf("%v", hash(group.Name)))}
}},
"member": {ldapField: "member", fieldMapper: func(group *object.Group) []V {
users, err := object.GetGroupUsers(group.GetId())
if err != nil {
log.Printf("member object.GetGroupUsers error: %s", err)
return []V{V("")}
}
var members []V
for _, user := range users {
members = append(members, V(fmt.Sprintf("uid=%s,cn=users,ou=%s", user.Name, user.Owner)))
}
return members
}},
"memberuid": {ldapField: "memberUid", fieldMapper: func(group *object.Group) []V {
users, err := object.GetGroupUsers(group.GetId())
if err != nil {
log.Printf("member object.GetGroupUsers error: %s", err)
return []V{V("")}
}
var members []message.AttributeValue
for _, user := range users {
members = append(members, message.AttributeValue(user.Name))
}
return members
}},
"description": {ldapField: "description", hideOnStarOp: true, fieldMapper: func(group *object.Group) []V {
return []V{V(group.DisplayName)}
}},
"objectclass": {ldapField: "objectClass", hideOnStarOp: true, constantValue: []V{
V("top"),
V("posixGroup"),
}},
}
var (
AdditionalLdapUserAttributes []message.LDAPString
AdditionalLdapGroupAttributes []message.LDAPString
)
var AdditionalLdapAttributes []message.LDAPString
func init() {
for _, v := range ldapUserAttributesMapping {
for k, v := range ldapAttributesMapping {
if v.hideOnStarOp {
continue
}
AdditionalLdapUserAttributes = append(AdditionalLdapUserAttributes, message.LDAPString(v.ldapField))
}
for _, v := range ldapGroupAttributesMapping {
if v.hideOnStarOp {
continue
}
AdditionalLdapGroupAttributes = append(AdditionalLdapGroupAttributes, message.LDAPString(v.ldapField))
AdditionalLdapAttributes = append(AdditionalLdapAttributes, message.LDAPString(k))
}
}
@@ -502,52 +307,6 @@ func GetFilteredUsers(m *ldap.Message) (filteredUsers []*object.User, code int)
}
}
func GetFilteredOrganizations(m *ldap.Message) ([]*object.Organization, int) {
if m.Client.IsGlobalAdmin {
organizations, err := object.GetOrganizations("")
if err != nil {
panic(err)
}
return organizations, ldap.LDAPResultSuccess
} else if m.Client.IsOrgAdmin {
requestUserId := util.GetId(m.Client.OrgName, m.Client.UserName)
user, err := object.GetUser(requestUserId)
if err != nil {
panic(err)
}
organization, err := object.GetOrganizationByUser(user)
if err != nil {
panic(err)
}
return []*object.Organization{organization}, ldap.LDAPResultSuccess
} else {
return nil, ldap.LDAPResultInsufficientAccessRights
}
}
func GetFilteredGroups(m *ldap.Message) ([]*object.Group, int) {
if m.Client.IsGlobalAdmin {
groups, err := object.GetGroups("")
if err != nil {
panic(err)
}
return groups, ldap.LDAPResultSuccess
} else if m.Client.IsOrgAdmin {
requestUserId := util.GetId(m.Client.OrgName, m.Client.UserName)
user, err := object.GetUser(requestUserId)
if err != nil {
panic(err)
}
groups, err := object.GetGroups(user.Owner)
if err != nil {
panic(err)
}
return groups, ldap.LDAPResultSuccess
} else {
return nil, ldap.LDAPResultInsufficientAccessRights
}
}
// get user password with hash type prefix
// TODO not handle salt yet
// @return {md5}5f4dcc3b5aa765d61d8327deb882cf99
@@ -571,49 +330,18 @@ func getUserPasswordWithType(user *object.User) string {
return fmt.Sprintf("{%s}%s", prefix, user.Password)
}
func getAttribute(attributeName string, user *object.User) message.AttributeValue {
v, ok := ldapAttributesMapping[attributeName]
if !ok {
return ""
}
return v.GetAttributeValue(user)
}
func getUserFieldFromAttribute(attributeName string) (string, error) {
v, ok := ldapUserAttributesMapping.CaseInsensitiveGet(attributeName)
v, ok := ldapAttributesMapping[attributeName]
if !ok {
return "", fmt.Errorf("attribute %s not supported", attributeName)
}
return v.GetField()
}
func searchFilterForEquality(filter message.Filter, desc string, values ...string) string {
switch f := filter.(type) {
case message.FilterAnd:
for _, child := range f {
if val := searchFilterForEquality(child, desc, values...); val != "" {
return val
}
}
case message.FilterOr:
for _, child := range f {
if val := searchFilterForEquality(child, desc, values...); val != "" {
return val
}
}
case message.FilterNot:
return searchFilterForEquality(f.Filter, desc, values...)
case message.FilterSubstrings:
// Handle FilterSubstrings case if needed
case message.FilterEqualityMatch:
if strings.EqualFold(string(f.AttributeDesc()), desc) {
for _, value := range values {
if val := string(f.AssertionValue()); val == value {
return val
}
}
}
case message.FilterGreaterOrEqual:
// Handle FilterGreaterOrEqual case if needed
case message.FilterLessOrEqual:
// Handle FilterLessOrEqual case if needed
case message.FilterPresent:
// Handle FilterPresent case if needed
case message.FilterApproxMatch:
// Handle FilterApproxMatch case if needed
}
return ""
}

View File

@@ -37,12 +37,13 @@ type SignupItem struct {
Prompted bool `json:"prompted"`
Label string `json:"label"`
Placeholder string `json:"placeholder"`
Regex string `json:"regex"`
Rule string `json:"rule"`
}
type SamlItem struct {
Name string `json:"name"`
NameFormat string `json:"nameformat"`
NameFormat string `json:"nameFormat"`
Value string `json:"value"`
}
@@ -347,6 +348,17 @@ func GetMaskedApplication(application *Application, userId string) *Application
return nil
}
if application.TokenFields == nil {
application.TokenFields = []string{}
}
if application.FailedSigninLimit == 0 {
application.FailedSigninLimit = DefaultFailedSigninLimit
}
if application.FailedSigninFrozenTime == 0 {
application.FailedSigninFrozenTime = DefaultFailedSigninFrozenTime
}
if userId != "" {
if isUserIdGlobalAdmin(userId) {
return application
@@ -384,13 +396,6 @@ func GetMaskedApplication(application *Application, userId string) *Application
application.InvitationCodes = []string{"***"}
}
if application.FailedSigninLimit == 0 {
application.FailedSigninLimit = DefaultFailedSigninLimit
}
if application.FailedSigninFrozenTime == 0 {
application.FailedSigninFrozenTime = DefaultFailedSigninFrozenTime
}
return application
}

View File

@@ -24,16 +24,18 @@ import (
)
const (
headerOrigin = "Origin"
headerAllowOrigin = "Access-Control-Allow-Origin"
headerAllowMethods = "Access-Control-Allow-Methods"
headerAllowHeaders = "Access-Control-Allow-Headers"
headerOrigin = "Origin"
headerAllowOrigin = "Access-Control-Allow-Origin"
headerAllowMethods = "Access-Control-Allow-Methods"
headerAllowHeaders = "Access-Control-Allow-Headers"
headerAllowCredentials = "Access-Control-Allow-Credentials"
)
func setCorsHeaders(ctx *context.Context, origin string) {
ctx.Output.Header(headerAllowOrigin, origin)
ctx.Output.Header(headerAllowMethods, "POST, GET, OPTIONS, DELETE")
ctx.Output.Header(headerAllowHeaders, "Content-Type, Authorization")
ctx.Output.Header(headerAllowCredentials, "true")
if ctx.Input.Method() == "OPTIONS" {
ctx.ResponseWriter.WriteHeader(http.StatusOK)

View File

@@ -34,6 +34,8 @@ func GetStorageProvider(providerType string, clientId string, clientSecret strin
return NewQiniuCloudKodoStorageProvider(clientId, clientSecret, region, bucket, endpoint)
case "Google Cloud Storage":
return NewGoogleCloudStorageProvider(clientSecret, bucket, endpoint)
case "Synology":
return NewSynologyNasStorageProvider(clientId, clientSecret, endpoint)
}
return nil

31
storage/synology_nas.go Normal file
View File

@@ -0,0 +1,31 @@
// 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 storage
import (
"github.com/casdoor/oss"
"github.com/casdoor/oss/synology"
)
func NewSynologyNasStorageProvider(clientId string, clientSecret string, endpoint string) oss.StorageInterface {
sp := synology.New(&synology.Config{
AccessID: clientId,
AccessKey: clientSecret,
Endpoint: endpoint,
SharedFolder: "/home",
})
return sp
}

View File

@@ -6761,7 +6761,7 @@
"name": {
"type": "string"
},
"nameformat": {
"nameFormat": {
"type": "string"
},
"value": {

View File

@@ -4451,7 +4451,7 @@ definitions:
properties:
name:
type: string
nameformat:
nameFormat:
type: string
value:
type: string

View File

@@ -27,7 +27,7 @@ import LoginPage from "./auth/LoginPage";
import i18next from "i18next";
import UrlTable from "./table/UrlTable";
import ProviderTable from "./table/ProviderTable";
import SigninTable from "./table/SigninTable";
import SigninMethodTable from "./table/SigninMethodTable";
import SignupTable from "./table/SignupTable";
import SamlAttributeTable from "./table/SamlAttributeTable";
import PromptPage from "./auth/PromptPage";
@@ -487,7 +487,7 @@ class ApplicationEditPage extends React.Component {
{Setting.getLabel(i18next.t("application:Signin methods"), i18next.t("application:Signin methods - Tooltip"))} :
</Col>
<Col span={22} >
<SigninTable
<SigninMethodTable
title={i18next.t("application:Signin methods")}
table={this.state.application.signinMethods}
onUpdateTable={(value) => {
@@ -797,7 +797,7 @@ class ApplicationEditPage extends React.Component {
</Col>
<Col span={22} >
<Row style={{marginTop: "20px"}} >
<Radio.Group onChange={e => {this.updateApplicationField("formOffset", e.target.value);}} value={this.state.application.formOffset}>
<Radio.Group buttonStyle="solid" onChange={e => {this.updateApplicationField("formOffset", e.target.value);}} value={this.state.application.formOffset}>
<Radio.Button value={1}>{i18next.t("application:Left")}</Radio.Button>
<Radio.Button value={2}>{i18next.t("application:Center")}</Radio.Button>
<Radio.Button value={3}>{i18next.t("application:Right")}</Radio.Button>
@@ -837,7 +837,7 @@ class ApplicationEditPage extends React.Component {
</Col>
<Col span={22} style={{marginTop: "5px"}}>
<Row>
<Radio.Group value={this.state.application.themeData?.isEnabled ?? false} onChange={e => {
<Radio.Group buttonStyle="solid" value={this.state.application.themeData?.isEnabled ?? false} onChange={e => {
const {_, ...theme} = this.state.application.themeData ?? {...Conf.ThemeDefault, isEnabled: false};
this.updateApplicationField("themeData", {...theme, isEnabled: e.target.value});
}} >

View File

@@ -393,7 +393,7 @@ class OrganizationEditPage extends React.Component {
</Col>
<Col span={22} style={{marginTop: "5px"}}>
<Row>
<Radio.Group value={this.state.organization.themeData?.isEnabled ?? false} onChange={e => {
<Radio.Group buttonStyle="solid" value={this.state.organization.themeData?.isEnabled ?? false} onChange={e => {
const {_, ...theme} = this.state.organization.themeData ?? {...Conf.ThemeDefault, isEnabled: false};
this.updateOrganizationField("themeData", {...theme, isEnabled: e.target.value});
}} >

View File

@@ -796,7 +796,7 @@ class ProviderEditPage extends React.Component {
</Col>
</Row>
)}
{["Custom HTTP SMS", "Local File System", "MinIO", "Tencent Cloud COS", "Google Cloud Storage", "Qiniu Cloud Kodo"].includes(this.state.provider.type) ? null : (
{["Custom HTTP SMS", "Local File System", "MinIO", "Tencent Cloud COS", "Google Cloud Storage", "Qiniu Cloud Kodo", "Synology"].includes(this.state.provider.type) ? null : (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={2}>
{Setting.getLabel(i18next.t("provider:Endpoint (Intranet)"), i18next.t("provider:Region endpoint for Intranet"))} :
@@ -832,7 +832,7 @@ class ProviderEditPage extends React.Component {
</Col>
</Row>
)}
{["Custom HTTP SMS", "MinIO", "Google Cloud Storage", "Qiniu Cloud Kodo"].includes(this.state.provider.type) ? null : (
{["Custom HTTP SMS", "MinIO", "Google Cloud Storage", "Qiniu Cloud Kodo", "Synology"].includes(this.state.provider.type) ? null : (
<Row style={{marginTop: "20px"}} >
<Col style={{marginTop: "5px"}} span={2}>
{Setting.getLabel(i18next.t("provider:Domain"), i18next.t("provider:Domain - Tooltip"))} :

View File

@@ -207,6 +207,10 @@ export const OtherProviderInfo = {
logo: `${StaticBaseUrl}/img/social_google_cloud.png`,
url: "https://cloud.google.com/storage",
},
"Synology": {
logo: `${StaticBaseUrl}/img/social_synology.png`,
url: "https://www.synology.com/en-global/dsm/feature/file_sharing",
},
},
SAML: {
"Aliyun IDaaS": {
@@ -1024,6 +1028,7 @@ export function getProviderTypeOptions(category) {
{id: "Azure Blob", name: "Azure Blob"},
{id: "Qiniu Cloud Kodo", name: "Qiniu Cloud Kodo"},
{id: "Google Cloud Storage", name: "Google Cloud Storage"},
{id: "Synology", name: "Synology"},
]
);
} else if (category === "SAML") {

View File

@@ -146,7 +146,7 @@ export function getWechatMessageEvent() {
}
export function getCaptchaStatus(values) {
return fetch(`${Setting.ServerUrl}/api/get-captcha-status?organization=${values["organization"]}&user_id=${values["username"]}`, {
return fetch(`${Setting.ServerUrl}/api/get-captcha-status?organization=${values["organization"]}&userId=${values["username"]}`, {
method: "GET",
credentials: "include",
headers: {

View File

@@ -201,7 +201,7 @@ class LoginPage extends React.Component {
}
getDefaultLoginMethod(application) {
if (application?.signinMethods.length > 0) {
if (application?.signinMethods?.length > 0) {
switch (application?.signinMethods[0].name) {
case "Password": return "password";
case "Verification code": {
@@ -588,6 +588,10 @@ class LoginPage extends React.Component {
},
{
validator: (_, value) => {
if (value === "") {
return Promise.resolve();
}
if (this.state.loginMethod === "verificationCode") {
if (!Setting.isValidEmail(value) && !Setting.isValidPhone(value)) {
this.setState({validEmailOrPhone: false});
@@ -937,7 +941,7 @@ class LoginPage extends React.Component {
[generateItemKey("LDAP", "None"), {label: i18next.t("login:LDAP"), key: "ldap"}],
]);
application?.signinMethods.forEach((signinMethod) => {
application?.signinMethods?.forEach((signinMethod) => {
const item = itemsMap.get(generateItemKey(signinMethod.name, signinMethod.rule));
if (item) {
const label = signinMethod.name === signinMethod.displayName ? item.label : signinMethod.displayName;

View File

@@ -267,6 +267,7 @@
"Models": "Models",
"Name": "Name",
"Name - Tooltip": "Unique, string-based ID",
"Name format": "Name format",
"Non-LDAP": "Non-LDAP",
"None": "None",
"OAuth providers": "OAuth providers",
@@ -887,6 +888,7 @@
"Please input your real name!": "Please input your real name!",
"Please select your country code!": "Please select your country code!",
"Please select your country/region!": "Please select your country/region!",
"Regex": "Regex",
"Terms of Use": "Terms of Use",
"Terms of Use - Tooltip": "Terms of use that users need to read and agree to during registration",
"Text 1": "Text 1",
@@ -1053,8 +1055,6 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",
@@ -1092,7 +1092,6 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Upload a photo",
"Value": "Value",
"Values": "Values",
"Verification code sent": "Verification code sent",
"WebAuthn credentials": "WebAuthn credentials",

View File

@@ -267,6 +267,7 @@
"Models": "Modelle",
"Name": "Name",
"Name - Tooltip": "Eindeutige, auf Strings basierende ID",
"Name format": "Name format",
"Non-LDAP": "Non-LDAP",
"None": "None",
"OAuth providers": "OAuth-Provider",
@@ -887,6 +888,7 @@
"Please input your real name!": "Bitte geben Sie Ihren richtigen Namen ein!",
"Please select your country code!": "Bitte wählen Sie Ihren Ländercode aus!",
"Please select your country/region!": "Bitte wählen Sie Ihr Land/Ihre Region aus!",
"Regex": "Regex",
"Terms of Use": "Nutzungsbedingungen",
"Terms of Use - Tooltip": "Nutzungsbedingungen, die Benutzer während der Registrierung lesen und akzeptieren müssen",
"Text 1": "Text 1",
@@ -1053,8 +1055,6 @@
"Managed accounts": "Verwaltete Konten",
"Modify password...": "Passwort ändern...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "Neue E-Mail",
"New Password": "Neues Passwort",
"New User": "Neuer Benutzer",
@@ -1092,7 +1092,6 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Lade ein Foto hoch",
"Value": "Value",
"Values": "Werte",
"Verification code sent": "Bestätigungscode gesendet",
"WebAuthn credentials": "WebAuthn-Anmeldeinformationen",

View File

@@ -267,6 +267,7 @@
"Models": "Models",
"Name": "Name",
"Name - Tooltip": "Unique, string-based ID",
"Name format": "Name format",
"Non-LDAP": "Non-LDAP",
"None": "None",
"OAuth providers": "OAuth providers",
@@ -887,6 +888,7 @@
"Please input your real name!": "Please input your real name!",
"Please select your country code!": "Please select your country code!",
"Please select your country/region!": "Please select your country/region!",
"Regex": "Regex",
"Terms of Use": "Terms of Use",
"Terms of Use - Tooltip": "Terms of use that users need to read and agree to during registration",
"Text 1": "Text 1",
@@ -1053,8 +1055,6 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",
@@ -1092,7 +1092,6 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Upload a photo",
"Value": "Value",
"Values": "Values",
"Verification code sent": "Verification code sent",
"WebAuthn credentials": "WebAuthn credentials",

View File

@@ -267,6 +267,7 @@
"Models": "Modelos",
"Name": "Nombre",
"Name - Tooltip": "ID único basado en cadenas",
"Name format": "Name format",
"Non-LDAP": "Non-LDAP",
"None": "None",
"OAuth providers": "Proveedores de OAuth",
@@ -887,6 +888,7 @@
"Please input your real name!": "¡Por favor, ingresa tu nombre real!",
"Please select your country code!": "¡Por favor seleccione su código de país!",
"Please select your country/region!": "¡Por favor seleccione su país/región!",
"Regex": "Regex",
"Terms of Use": "Términos de uso",
"Terms of Use - Tooltip": "Términos de uso que los usuarios necesitan leer y aceptar durante el registro",
"Text 1": "Text 1",
@@ -1053,8 +1055,6 @@
"Managed accounts": "Cuentas gestionadas",
"Modify password...": "Modificar contraseña...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "Nuevo correo electrónico",
"New Password": "Nueva contraseña",
"New User": "Nuevo Usuario",
@@ -1092,7 +1092,6 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Subir una foto",
"Value": "Value",
"Values": "Valores",
"Verification code sent": "Código de verificación enviado",
"WebAuthn credentials": "Credenciales de WebAuthn",

View File

@@ -267,6 +267,7 @@
"Models": "Models",
"Name": "Name",
"Name - Tooltip": "Unique, string-based ID",
"Name format": "Name format",
"Non-LDAP": "Non-LDAP",
"None": "None",
"OAuth providers": "OAuth providers",
@@ -887,6 +888,7 @@
"Please input your real name!": "Please input your real name!",
"Please select your country code!": "Please select your country code!",
"Please select your country/region!": "Please select your country/region!",
"Regex": "Regex",
"Terms of Use": "Terms of Use",
"Terms of Use - Tooltip": "Terms of use that users need to read and agree to during registration",
"Text 1": "Text 1",
@@ -1053,8 +1055,6 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",
@@ -1092,7 +1092,6 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Upload a photo",
"Value": "Value",
"Values": "Values",
"Verification code sent": "Verification code sent",
"WebAuthn credentials": "WebAuthn credentials",

View File

@@ -267,6 +267,7 @@
"Models": "Models",
"Name": "Name",
"Name - Tooltip": "Unique, string-based ID",
"Name format": "Name format",
"Non-LDAP": "Non-LDAP",
"None": "None",
"OAuth providers": "OAuth providers",
@@ -887,6 +888,7 @@
"Please input your real name!": "Please input your real name!",
"Please select your country code!": "Please select your country code!",
"Please select your country/region!": "Please select your country/region!",
"Regex": "Regex",
"Terms of Use": "Terms of Use",
"Terms of Use - Tooltip": "Terms of use that users need to read and agree to during registration",
"Text 1": "Text 1",
@@ -1053,8 +1055,6 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",
@@ -1092,7 +1092,6 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Upload a photo",
"Value": "Value",
"Values": "Values",
"Verification code sent": "Verification code sent",
"WebAuthn credentials": "WebAuthn credentials",

View File

@@ -267,6 +267,7 @@
"Models": "Modèles",
"Name": "Nom",
"Name - Tooltip": "Identifiant unique à base de chaîne",
"Name format": "Name format",
"Non-LDAP": "Non-LDAP",
"None": "Aucun",
"OAuth providers": "Fournisseurs OAuth",
@@ -887,6 +888,7 @@
"Please input your real name!": "Veuillez saisir votre nom complet !",
"Please select your country code!": "Sélectionnez votre code de pays, s'il vous plaît !",
"Please select your country/region!": "Veuillez sélectionner votre pays/région !",
"Regex": "Regex",
"Terms of Use": "Conditions d'utilisation",
"Terms of Use - Tooltip": "Conditions d'utilisation qui doivent être lus acceptés lors de l'enregistrement du compte",
"Text 1": "Text 1",
@@ -1053,8 +1055,6 @@
"Managed accounts": "Comptes gérés",
"Modify password...": "Modifier le mot de passe...",
"Multi-factor authentication": "Authentification multifacteur",
"Name": "Name",
"Name format": "Name format",
"New Email": "Nouvelle adresse e-mail",
"New Password": "Nouveau mot de passe",
"New User": "Nouveau compte",
@@ -1092,7 +1092,6 @@
"Upload ID card front picture": "Télécharger une photo de l'endroit de la pièce d'identité",
"Upload ID card with person picture": "Télécharger une photo la pièce d'identité avec une personne",
"Upload a photo": "Télécharger une photo",
"Value": "Value",
"Values": "Valeurs",
"Verification code sent": "Code de vérification envoyé",
"WebAuthn credentials": "Identifiants WebAuthn",

View File

@@ -267,6 +267,7 @@
"Models": "Models",
"Name": "Name",
"Name - Tooltip": "Unique, string-based ID",
"Name format": "Name format",
"Non-LDAP": "Non-LDAP",
"None": "None",
"OAuth providers": "OAuth providers",
@@ -887,6 +888,7 @@
"Please input your real name!": "Please input your real name!",
"Please select your country code!": "Please select your country code!",
"Please select your country/region!": "Please select your country/region!",
"Regex": "Regex",
"Terms of Use": "Terms of Use",
"Terms of Use - Tooltip": "Terms of use that users need to read and agree to during registration",
"Text 1": "Text 1",
@@ -1053,8 +1055,6 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",
@@ -1092,7 +1092,6 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Upload a photo",
"Value": "Value",
"Values": "Values",
"Verification code sent": "Verification code sent",
"WebAuthn credentials": "WebAuthn credentials",

View File

@@ -267,6 +267,7 @@
"Models": "Model-model",
"Name": "Nama",
"Name - Tooltip": "ID unik berbasis string",
"Name format": "Name format",
"Non-LDAP": "Non-LDAP",
"None": "None",
"OAuth providers": "Penyedia OAuth",
@@ -887,6 +888,7 @@
"Please input your real name!": "Silakan masukkan nama asli Anda!",
"Please select your country code!": "Tolong pilih kode negara Anda!",
"Please select your country/region!": "Silakan pilih negara/region Anda!",
"Regex": "Regex",
"Terms of Use": "Syarat Penggunaan",
"Terms of Use - Tooltip": "Syarat penggunaan yang harus dibaca dan disetujui oleh pengguna selama proses registrasi",
"Text 1": "Text 1",
@@ -1053,8 +1055,6 @@
"Managed accounts": "Akun yang dikelola",
"Modify password...": "Mengubah kata sandi...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "Email baru",
"New Password": "Kata Sandi Baru",
"New User": "Pengguna Baru",
@@ -1092,7 +1092,6 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Unggah foto",
"Value": "Value",
"Values": "Nilai-nilai",
"Verification code sent": "Kode verifikasi telah dikirim",
"WebAuthn credentials": "Kredensial WebAuthn",

View File

@@ -267,6 +267,7 @@
"Models": "Models",
"Name": "Name",
"Name - Tooltip": "Unique, string-based ID",
"Name format": "Name format",
"Non-LDAP": "Non-LDAP",
"None": "None",
"OAuth providers": "OAuth providers",
@@ -887,6 +888,7 @@
"Please input your real name!": "Please input your real name!",
"Please select your country code!": "Please select your country code!",
"Please select your country/region!": "Please select your country/region!",
"Regex": "Regex",
"Terms of Use": "Terms of Use",
"Terms of Use - Tooltip": "Terms of use that users need to read and agree to during registration",
"Text 1": "Text 1",
@@ -1053,8 +1055,6 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",
@@ -1092,7 +1092,6 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Upload a photo",
"Value": "Value",
"Values": "Values",
"Verification code sent": "Verification code sent",
"WebAuthn credentials": "WebAuthn credentials",

View File

@@ -267,6 +267,7 @@
"Models": "モデル",
"Name": "名前",
"Name - Tooltip": "ユニークで文字列ベースのID",
"Name format": "Name format",
"Non-LDAP": "Non-LDAP",
"None": "None",
"OAuth providers": "OAuthプロバイダー",
@@ -887,6 +888,7 @@
"Please input your real name!": "正しい名前を入力してください!",
"Please select your country code!": "あなたの国コードを選択してください!",
"Please select your country/region!": "あなたの国/地域を選択してください!",
"Regex": "Regex",
"Terms of Use": "利用規約",
"Terms of Use - Tooltip": "ユーザーが登録する際に読んで同意する必要がある利用規約",
"Text 1": "Text 1",
@@ -1053,8 +1055,6 @@
"Managed accounts": "管理アカウント",
"Modify password...": "パスワードを変更する...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "新しいメール",
"New Password": "新しいパスワード",
"New User": "新しいユーザー",
@@ -1092,7 +1092,6 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "写真をアップロードしてください",
"Value": "Value",
"Values": "価値観",
"Verification code sent": "確認コードを送信しました",
"WebAuthn credentials": "WebAuthnの資格情報",

View File

@@ -267,6 +267,7 @@
"Models": "Models",
"Name": "Name",
"Name - Tooltip": "Unique, string-based ID",
"Name format": "Name format",
"Non-LDAP": "Non-LDAP",
"None": "None",
"OAuth providers": "OAuth providers",
@@ -887,6 +888,7 @@
"Please input your real name!": "Please input your real name!",
"Please select your country code!": "Please select your country code!",
"Please select your country/region!": "Please select your country/region!",
"Regex": "Regex",
"Terms of Use": "Terms of Use",
"Terms of Use - Tooltip": "Terms of use that users need to read and agree to during registration",
"Text 1": "Text 1",
@@ -1053,8 +1055,6 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",
@@ -1092,7 +1092,6 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Upload a photo",
"Value": "Value",
"Values": "Values",
"Verification code sent": "Verification code sent",
"WebAuthn credentials": "WebAuthn credentials",

View File

@@ -267,6 +267,7 @@
"Models": "모델들",
"Name": "이름",
"Name - Tooltip": "고유한 문자열 기반 ID",
"Name format": "Name format",
"Non-LDAP": "Non-LDAP",
"None": "None",
"OAuth providers": "OAuth 공급자",
@@ -887,6 +888,7 @@
"Please input your real name!": "진짜 이름을 입력해주세요!",
"Please select your country code!": "국가 코드를 선택해 주세요!",
"Please select your country/region!": "국가 / 지역을 선택해주세요!",
"Regex": "Regex",
"Terms of Use": "사용 약관",
"Terms of Use - Tooltip": "등록 중 사용자가 읽어야 하고 동의해야하는 이용 약관",
"Text 1": "Text 1",
@@ -1053,8 +1055,6 @@
"Managed accounts": "관리 계정",
"Modify password...": "비밀번호 수정하기...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "새 이메일",
"New Password": "새로운 비밀번호",
"New User": "새로운 사용자",
@@ -1092,7 +1092,6 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "사진을 업로드하세요",
"Value": "Value",
"Values": "가치들",
"Verification code sent": "인증 코드가 전송되었습니다",
"WebAuthn credentials": "웹 인증 자격증명",

View File

@@ -267,6 +267,7 @@
"Models": "Models",
"Name": "Name",
"Name - Tooltip": "Unique, string-based ID",
"Name format": "Name format",
"Non-LDAP": "Non-LDAP",
"None": "None",
"OAuth providers": "OAuth providers",
@@ -887,6 +888,7 @@
"Please input your real name!": "Please input your real name!",
"Please select your country code!": "Please select your country code!",
"Please select your country/region!": "Please select your country/region!",
"Regex": "Regex",
"Terms of Use": "Terms of Use",
"Terms of Use - Tooltip": "Terms of use that users need to read and agree to during registration",
"Text 1": "Text 1",
@@ -1053,8 +1055,6 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",
@@ -1092,7 +1092,6 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Upload a photo",
"Value": "Value",
"Values": "Values",
"Verification code sent": "Verification code sent",
"WebAuthn credentials": "WebAuthn credentials",

View File

@@ -267,6 +267,7 @@
"Models": "Models",
"Name": "Name",
"Name - Tooltip": "Unique, string-based ID",
"Name format": "Name format",
"Non-LDAP": "Non-LDAP",
"None": "None",
"OAuth providers": "OAuth providers",
@@ -887,6 +888,7 @@
"Please input your real name!": "Please input your real name!",
"Please select your country code!": "Please select your country code!",
"Please select your country/region!": "Please select your country/region!",
"Regex": "Regex",
"Terms of Use": "Terms of Use",
"Terms of Use - Tooltip": "Terms of use that users need to read and agree to during registration",
"Text 1": "Text 1",
@@ -1053,8 +1055,6 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",
@@ -1092,7 +1092,6 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Upload a photo",
"Value": "Value",
"Values": "Values",
"Verification code sent": "Verification code sent",
"WebAuthn credentials": "WebAuthn credentials",

View File

@@ -267,6 +267,7 @@
"Models": "Models",
"Name": "Name",
"Name - Tooltip": "Unique, string-based ID",
"Name format": "Name format",
"Non-LDAP": "Non-LDAP",
"None": "None",
"OAuth providers": "OAuth providers",
@@ -887,6 +888,7 @@
"Please input your real name!": "Please input your real name!",
"Please select your country code!": "Please select your country code!",
"Please select your country/region!": "Please select your country/region!",
"Regex": "Regex",
"Terms of Use": "Terms of Use",
"Terms of Use - Tooltip": "Terms of use that users need to read and agree to during registration",
"Text 1": "Text 1",
@@ -1053,8 +1055,6 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",
@@ -1092,7 +1092,6 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Upload a photo",
"Value": "Value",
"Values": "Values",
"Verification code sent": "Verification code sent",
"WebAuthn credentials": "WebAuthn credentials",

View File

@@ -267,6 +267,7 @@
"Models": "Modelos",
"Name": "Nome",
"Name - Tooltip": "ID único em formato de string",
"Name format": "Name format",
"Non-LDAP": "Non-LDAP",
"None": "None",
"OAuth providers": "Provedores OAuth",
@@ -887,6 +888,7 @@
"Please input your real name!": "Por favor, insira seu nome real!",
"Please select your country code!": "Por favor, selecione o código do seu país!",
"Please select your country/region!": "Por favor, selecione seu país/região!",
"Regex": "Regex",
"Terms of Use": "Termos de Uso",
"Terms of Use - Tooltip": "Termos de uso que os usuários precisam ler e concordar durante o registro",
"Text 1": "Text 1",
@@ -1053,8 +1055,6 @@
"Managed accounts": "Contas gerenciadas",
"Modify password...": "Modificar senha...",
"Multi-factor authentication": "Autenticação de vários fatores",
"Name": "Name",
"Name format": "Name format",
"New Email": "Novo E-mail",
"New Password": "Nova Senha",
"New User": "Novo Usuário",
@@ -1092,7 +1092,6 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Enviar uma foto",
"Value": "Value",
"Values": "Valores",
"Verification code sent": "Código de verificação enviado",
"WebAuthn credentials": "Credenciais WebAuthn",

View File

@@ -267,6 +267,7 @@
"Models": "Модели",
"Name": "Имя",
"Name - Tooltip": "Уникальный идентификатор на основе строки",
"Name format": "Name format",
"Non-LDAP": "Non-LDAP",
"None": "None",
"OAuth providers": "Провайдеры OAuth",
@@ -887,6 +888,7 @@
"Please input your real name!": "Пожалуйста, введите своё настоящее имя!",
"Please select your country code!": "Пожалуйста, выберите код своей страны!",
"Please select your country/region!": "Пожалуйста, выберите свою страну / регион!",
"Regex": "Regex",
"Terms of Use": "Условия использования",
"Terms of Use - Tooltip": "Условия использования, которые пользователи должны прочитать и согласиться с ними при регистрации",
"Text 1": "Text 1",
@@ -1053,8 +1055,6 @@
"Managed accounts": "Управляемые счета",
"Modify password...": "Изменить пароль...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "Новое электронное письмо",
"New Password": "Новый пароль",
"New User": "Новый пользователь",
@@ -1092,7 +1092,6 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Загрузить фото",
"Value": "Value",
"Values": "Значения",
"Verification code sent": "Код подтверждения отправлен",
"WebAuthn credentials": "WebAuthn удостоверения",

View File

@@ -267,6 +267,7 @@
"Models": "Models",
"Name": "Name",
"Name - Tooltip": "Unique, string-based ID",
"Name format": "Name format",
"Non-LDAP": "Non-LDAP",
"None": "None",
"OAuth providers": "OAuth providers",
@@ -887,6 +888,7 @@
"Please input your real name!": "Please input your real name!",
"Please select your country code!": "Please select your country code!",
"Please select your country/region!": "Please select your country/region!",
"Regex": "Regex",
"Terms of Use": "Terms of Use",
"Terms of Use - Tooltip": "Terms of use that users need to read and agree to during registration",
"Text 1": "Text 1",
@@ -1053,8 +1055,6 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",
@@ -1092,7 +1092,6 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Upload a photo",
"Value": "Value",
"Values": "Values",
"Verification code sent": "Verification code sent",
"WebAuthn credentials": "WebAuthn credentials",

View File

@@ -267,6 +267,7 @@
"Models": "Models",
"Name": "Name",
"Name - Tooltip": "Unique, string-based ID",
"Name format": "Name format",
"Non-LDAP": "Non-LDAP",
"None": "None",
"OAuth providers": "OAuth providers",
@@ -887,6 +888,7 @@
"Please input your real name!": "Please input your real name!",
"Please select your country code!": "Please select your country code!",
"Please select your country/region!": "Please select your country/region!",
"Regex": "Regex",
"Terms of Use": "Terms of Use",
"Terms of Use - Tooltip": "Terms of use that users need to read and agree to during registration",
"Text 1": "Text 1",
@@ -1053,8 +1055,6 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",
@@ -1092,7 +1092,6 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Upload a photo",
"Value": "Value",
"Values": "Values",
"Verification code sent": "Verification code sent",
"WebAuthn credentials": "WebAuthn credentials",

View File

@@ -267,6 +267,7 @@
"Models": "Models",
"Name": "Name",
"Name - Tooltip": "Unique, string-based ID",
"Name format": "Name format",
"Non-LDAP": "Non-LDAP",
"None": "None",
"OAuth providers": "OAuth providers",
@@ -887,6 +888,7 @@
"Please input your real name!": "Please input your real name!",
"Please select your country code!": "Please select your country code!",
"Please select your country/region!": "Please select your country/region!",
"Regex": "Regex",
"Terms of Use": "Terms of Use",
"Terms of Use - Tooltip": "Terms of use that users need to read and agree to during registration",
"Text 1": "Text 1",
@@ -1053,8 +1055,6 @@
"Managed accounts": "Managed accounts",
"Modify password...": "Modify password...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "New Email",
"New Password": "New Password",
"New User": "New User",
@@ -1092,7 +1092,6 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Upload a photo",
"Value": "Value",
"Values": "Values",
"Verification code sent": "Verification code sent",
"WebAuthn credentials": "WebAuthn credentials",

View File

@@ -267,6 +267,7 @@
"Models": "Mô hình",
"Name": "Tên",
"Name - Tooltip": "ID duy nhất dựa trên chuỗi",
"Name format": "Name format",
"Non-LDAP": "Non-LDAP",
"None": "None",
"OAuth providers": "Nhà cung cấp OAuth",
@@ -887,6 +888,7 @@
"Please input your real name!": "Vui lòng nhập tên thật của bạn!",
"Please select your country code!": "Vui lòng chọn mã quốc gia của bạn!",
"Please select your country/region!": "Vui lòng chọn quốc gia/vùng của bạn!",
"Regex": "Regex",
"Terms of Use": "Điều khoản sử dụng",
"Terms of Use - Tooltip": "Điều khoản sử dụng mà người dùng cần đọc và đồng ý trong quá trình đăng ký",
"Text 1": "Text 1",
@@ -1053,8 +1055,6 @@
"Managed accounts": "Quản lý tài khoản",
"Modify password...": "Sửa đổi mật khẩu...",
"Multi-factor authentication": "Multi-factor authentication",
"Name": "Name",
"Name format": "Name format",
"New Email": "Email mới",
"New Password": "Mật khẩu mới",
"New User": "Người dùng mới",
@@ -1092,7 +1092,6 @@
"Upload ID card front picture": "Upload ID card front picture",
"Upload ID card with person picture": "Upload ID card with person picture",
"Upload a photo": "Tải lên một bức ảnh",
"Value": "Value",
"Values": "Giá trị",
"Verification code sent": "Mã xác minh đã được gửi",
"WebAuthn credentials": "Chứng chỉ WebAuthn",

View File

@@ -267,6 +267,7 @@
"Models": "Casbin模型",
"Name": "名称",
"Name - Tooltip": "唯一的、字符串式的ID",
"Name format": "名称格式",
"Non-LDAP": "禁用LDAP",
"None": "无",
"OAuth providers": "OAuth提供方",
@@ -887,6 +888,7 @@
"Please input your real name!": "请输入您的姓名!",
"Please select your country code!": "请选择国家代码!",
"Please select your country/region!": "请选择您的国家或地区",
"Regex": "正则表达式",
"Terms of Use": "《用户协议》",
"Terms of Use - Tooltip": "用户注册时需要阅读并同意的使用条款",
"Text 1": "文本1",
@@ -1053,8 +1055,6 @@
"Managed accounts": "托管账户",
"Modify password...": "编辑密码...",
"Multi-factor authentication": "多因素认证",
"Name": "Name",
"Name format": "Name format",
"New Email": "新邮箱",
"New Password": "新密码",
"New User": "添加用户",
@@ -1092,7 +1092,6 @@
"Upload ID card front picture": "上传身份证正面照片",
"Upload ID card with person picture": "上传手持身份证照片",
"Upload a photo": "上传头像",
"Value": "值",
"Values": "值",
"Verification code sent": "验证码已发送",
"WebAuthn credentials": "WebAuthn凭据",

View File

@@ -193,7 +193,7 @@ class ProviderTable extends React.Component {
title: i18next.t("application:Rule"),
dataIndex: "rule",
key: "rule",
width: "100px",
width: "120px",
render: (text, record, index) => {
if (record.provider?.type === "Google") {
if (text === "None") {

View File

@@ -38,7 +38,7 @@ class SamlAttributeTable extends React.Component {
}
addRow(table) {
const row = {Name: "", nameformat: "", value: ""};
const row = {Name: "", nameFormat: "", value: ""};
if (table === undefined || table === null) {
table = [];
}
@@ -64,7 +64,7 @@ class SamlAttributeTable extends React.Component {
renderTable(table) {
const columns = [
{
title: i18next.t("user:Name"),
title: i18next.t("general:Name"),
dataIndex: "name",
key: "name",
width: "200px",
@@ -77,9 +77,9 @@ class SamlAttributeTable extends React.Component {
},
},
{
title: i18next.t("user:Name format"),
dataIndex: "nameformat",
key: "nameformat",
title: i18next.t("general:Name format"),
dataIndex: "nameFormat",
key: "nameFormat",
width: "200px",
render: (text, record, index) => {
return (
@@ -87,7 +87,7 @@ class SamlAttributeTable extends React.Component {
value={text}
defaultValue="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified"
onChange={value => {
this.updateField(table, index, "nameformat", value);
this.updateField(table, index, "nameFormat", value);
}} >
<Option key="Unspecified" value="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">Unspecified</Option>
<Option key="Basic" value="urn:oasis:names:tc:SAML:2.0:attrname-format:basic">Basic</Option>
@@ -98,7 +98,7 @@ class SamlAttributeTable extends React.Component {
},
},
{
title: i18next.t("user:Value"),
title: i18next.t("webhook:Value"),
dataIndex: "value",
key: "value",
width: "200px",

View File

@@ -20,7 +20,7 @@ import i18next from "i18next";
const {Option} = Select;
class SigninTable extends React.Component {
class SigninMethodTable extends React.Component {
constructor(props) {
super(props);
this.state = {
@@ -163,7 +163,7 @@ class SigninTable extends React.Component {
<Button style={{marginRight: "5px"}} disabled={index === table.length - 1} icon={<DownOutlined />} size="small" onClick={() => this.downRow(table, index)} />
</Tooltip>
<Tooltip placement="topLeft" title={i18next.t("general:Delete")}>
<Button icon={<DeleteOutlined />} size="small" disabled={Setting.getDeduplicatedArray(items, table, "name").length >= items.length - 1} onClick={() => this.deleteRow(items, table, index)} />
<Button icon={<DeleteOutlined />} size="small" disabled={table.length <= 1} onClick={() => this.deleteRow(items, table, index)} />
</Tooltip>
</div>
);
@@ -198,4 +198,4 @@ class SigninTable extends React.Component {
}
}
export default SigninTable;
export default SigninMethodTable;

View File

@@ -224,6 +224,23 @@ class SignupTable extends React.Component {
);
},
},
{
title: i18next.t("signup:Regex"),
dataIndex: "regex",
key: "regex",
width: "200px",
render: (text, record, index) => {
if (record.name.startsWith("Text ") || record.name === "Password" || record.name === "Confirm password") {
return null;
}
return (
<Input value={text} onChange={e => {
this.updateField(table, index, "regex", e.target.value);
}} />
);
},
},
{
title: i18next.t("application:Rule"),
dataIndex: "rule",