mirror of
https://github.com/casdoor/casdoor.git
synced 2025-07-17 12:43:50 +08:00
Compare commits
37 Commits
Author | SHA1 | Date | |
---|---|---|---|
2187310dbc | |||
26345bb21b | |||
e0455df504 | |||
1dfbbf0e90 | |||
d43d58dee2 | |||
9eb4b12041 | |||
3a45a4ee77 | |||
43393f034b | |||
bafa80513b | |||
8d08140421 | |||
3d29e27d54 | |||
199f1d4d10 | |||
227e938db6 | |||
739cfd84ed | |||
8dbb041a34 | |||
af2d26daf2 | |||
90d502ab2b | |||
d51af3378e | |||
87e2b97813 | |||
d9e44c1f2d | |||
dfa4503f24 | |||
f7fb32893b | |||
66d0758b13 | |||
46ad0fe0be | |||
6b637e3b2e | |||
3354945119 | |||
19c4416f10 | |||
2077db9091 | |||
800f0ed249 | |||
6161040c67 | |||
1d785e61c6 | |||
0329d24867 | |||
fb6f3623ee | |||
eb448bd043 | |||
ea88839db9 | |||
cb95f6977a | |||
9067df92a7 |
@ -16,6 +16,7 @@ ARG USER=casdoor
|
||||
|
||||
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
|
||||
|
||||
|
@ -15,6 +15,7 @@ socks5Proxy = "127.0.0.1:10808"
|
||||
verificationCodeTimeout = 10
|
||||
initScore = 0
|
||||
logPostOnly = true
|
||||
isUsernameLowered = false
|
||||
origin =
|
||||
originFrontend =
|
||||
staticBaseUrl = "https://cdn.casbin.org"
|
||||
|
@ -261,16 +261,20 @@ func (c *ApiController) Signup() {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
c.Ctx.Input.SetParam("recordUserId", user.GetId())
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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()
|
||||
}
|
||||
|
@ -113,25 +113,25 @@ func (c *ApiController) SendEmail() {
|
||||
|
||||
content := emailForm.Content
|
||||
if content == "" {
|
||||
code := "123456"
|
||||
content = provider.Content
|
||||
}
|
||||
|
||||
// "You have requested a verification code at Casdoor. Here is your code: %s, please enter in 5 minutes."
|
||||
content = strings.Replace(provider.Content, "%s", code, 1)
|
||||
if !strings.HasPrefix(userId, "app/") {
|
||||
var user *object.User
|
||||
user, err = object.GetUser(userId)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
userString := "Hi"
|
||||
if user != nil {
|
||||
userString = user.GetFriendlyName()
|
||||
}
|
||||
content = strings.Replace(content, "%{user.friendlyName}", userString, 1)
|
||||
code := "123456"
|
||||
// "You have requested a verification code at Casdoor. Here is your code: %s, please enter in 5 minutes."
|
||||
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)
|
||||
|
@ -96,7 +96,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
|
||||
@ -142,7 +142,7 @@ func (c *ApiController) IsOrgAdmin() (bool, bool) {
|
||||
return false, true
|
||||
}
|
||||
|
||||
if strings.HasPrefix(userId, "app/") {
|
||||
if object.IsAppUser(userId) {
|
||||
return true, true
|
||||
}
|
||||
|
||||
|
@ -295,7 +295,7 @@ func (c *ApiController) SendVerificationCode() {
|
||||
vform.CountryCode = mfaProps.CountryCode
|
||||
}
|
||||
|
||||
provider, err = application.GetSmsProvider(vform.Method)
|
||||
provider, err = application.GetSmsProvider(vform.Method, vform.CountryCode)
|
||||
if err != nil {
|
||||
c.ResponseError(err.Error())
|
||||
return
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -23,6 +23,8 @@ func GetEmailProvider(typ string, clientId string, clientSecret string, host str
|
||||
return NewAzureACSEmailProvider(clientSecret, host)
|
||||
} else if typ == "Custom HTTP Email" {
|
||||
return NewHttpEmailProvider(endpoint, method)
|
||||
} else if typ == "SendGrid" {
|
||||
return NewSendgridEmailProvider(clientSecret)
|
||||
} else {
|
||||
return NewSmtpEmailProvider(clientId, clientSecret, host, port, typ, disableSsl)
|
||||
}
|
||||
|
68
email/sendgrid.go
Normal file
68
email/sendgrid.go
Normal file
@ -0,0 +1,68 @@
|
||||
// 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"
|
||||
"strings"
|
||||
|
||||
"github.com/sendgrid/sendgrid-go"
|
||||
"github.com/sendgrid/sendgrid-go/helpers/mail"
|
||||
)
|
||||
|
||||
type SendgridEmailProvider struct {
|
||||
ApiKey string
|
||||
}
|
||||
|
||||
type SendgridResponseBody struct {
|
||||
Errors []struct {
|
||||
Message string `json:"message"`
|
||||
Field interface{} `json:"field"`
|
||||
Help interface{} `json:"help"`
|
||||
} `json:"errors"`
|
||||
}
|
||||
|
||||
func NewSendgridEmailProvider(apiKey string) *SendgridEmailProvider {
|
||||
return &SendgridEmailProvider{ApiKey: apiKey}
|
||||
}
|
||||
|
||||
func (s *SendgridEmailProvider) Send(fromAddress string, fromName, toAddress string, subject string, content string) error {
|
||||
from := mail.NewEmail(fromName, fromAddress)
|
||||
to := mail.NewEmail("", toAddress)
|
||||
message := mail.NewSingleEmail(from, subject, to, "", content)
|
||||
client := sendgrid.NewSendClient(s.ApiKey)
|
||||
response, err := client.Send(message)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if response.StatusCode >= 300 {
|
||||
var responseBody SendgridResponseBody
|
||||
err = json.Unmarshal([]byte(response.Body), &responseBody)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
messages := []string{}
|
||||
for _, sendgridError := range responseBody.Errors {
|
||||
messages = append(messages, sendgridError.Message)
|
||||
}
|
||||
|
||||
return fmt.Errorf("SendGrid status code: %d, error message: %s", response.StatusCode, strings.Join(messages, " | "))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
7
go.mod
7
go.mod
@ -9,7 +9,7 @@ require (
|
||||
github.com/beego/beego v1.12.12
|
||||
github.com/beevik/etree v1.1.0
|
||||
github.com/casbin/casbin/v2 v2.77.2
|
||||
github.com/casdoor/go-sms-sender v0.20.0
|
||||
github.com/casdoor/go-sms-sender v0.22.0
|
||||
github.com/casdoor/gomail/v2 v2.0.1
|
||||
github.com/casdoor/notify v0.45.0
|
||||
github.com/casdoor/oss v1.6.0
|
||||
@ -19,7 +19,6 @@ require (
|
||||
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/ethereum/go-ethereum v1.13.14
|
||||
github.com/fogleman/gg v1.3.0
|
||||
github.com/forestmgy/ldapserver v1.1.0
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.5
|
||||
@ -40,12 +39,13 @@ require (
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
github.com/nyaruka/phonenumbers v1.1.5
|
||||
github.com/pquerna/otp v1.4.0
|
||||
github.com/prometheus/client_golang v1.12.0
|
||||
github.com/prometheus/client_golang v1.11.1
|
||||
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/sendgrid/sendgrid-go v3.14.0+incompatible
|
||||
github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
|
||||
github.com/shirou/gopsutil v3.21.11+incompatible
|
||||
github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed
|
||||
@ -55,6 +55,7 @@ require (
|
||||
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
|
||||
|
@ -81,7 +81,8 @@
|
||||
"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",
|
||||
"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"
|
||||
@ -145,9 +146,10 @@
|
||||
"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 not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"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.",
|
||||
|
@ -81,7 +81,8 @@
|
||||
"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",
|
||||
"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"
|
||||
@ -145,9 +146,10 @@
|
||||
"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 not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"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.",
|
||||
|
@ -81,7 +81,8 @@
|
||||
"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",
|
||||
"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"
|
||||
@ -145,9 +146,10 @@
|
||||
"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 not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"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.",
|
||||
|
@ -81,7 +81,8 @@
|
||||
"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",
|
||||
"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"
|
||||
@ -145,9 +146,10 @@
|
||||
"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 not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"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.",
|
||||
|
@ -81,7 +81,8 @@
|
||||
"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",
|
||||
"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"
|
||||
@ -145,9 +146,10 @@
|
||||
"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 not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"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.",
|
||||
|
@ -81,7 +81,8 @@
|
||||
"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",
|
||||
"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"
|
||||
@ -145,9 +146,10 @@
|
||||
"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 not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"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.",
|
||||
|
@ -81,7 +81,8 @@
|
||||
"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",
|
||||
"don't support captchaProvider: ": "ne prend pas en charge captchaProvider: ",
|
||||
"this operation is not allowed in demo mode": "cette opération n’est pas autorisée en mode démo"
|
||||
"this operation is not allowed in demo mode": "cette opération n’est 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"
|
||||
@ -145,9 +146,10 @@
|
||||
"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 not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"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.",
|
||||
|
@ -81,7 +81,8 @@
|
||||
"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",
|
||||
"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"
|
||||
@ -145,9 +146,10 @@
|
||||
"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 not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"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.",
|
||||
|
@ -81,7 +81,8 @@
|
||||
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
|
||||
"The user: %s doesn't exist": "Pengguna: %s tidak ada",
|
||||
"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": "this operation is not allowed in demo mode",
|
||||
"this operation requires administrator to perform": "this operation requires administrator to perform"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "Server ldap ada"
|
||||
@ -145,9 +146,10 @@
|
||||
"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 not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"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.",
|
||||
|
@ -81,7 +81,8 @@
|
||||
"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",
|
||||
"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"
|
||||
@ -145,9 +146,10 @@
|
||||
"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 not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"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.",
|
||||
|
@ -81,7 +81,8 @@
|
||||
"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は存在しません",
|
||||
"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サーバーは存在します"
|
||||
@ -145,9 +146,10 @@
|
||||
"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 not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"Turing test failed.": "チューリングテストは失敗しました。",
|
||||
"Unable to get the email modify rule.": "電子メール変更規則を取得できません。",
|
||||
"Unable to get the phone modify rule.": "電話の変更ルールを取得できません。",
|
||||
|
@ -81,7 +81,8 @@
|
||||
"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",
|
||||
"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"
|
||||
@ -145,9 +146,10 @@
|
||||
"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 not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"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.",
|
||||
|
@ -81,7 +81,8 @@
|
||||
"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는 존재하지 않습니다",
|
||||
"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 서버가 존재합니다"
|
||||
@ -145,9 +146,10 @@
|
||||
"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 not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"Turing test failed.": "튜링 테스트 실패.",
|
||||
"Unable to get the email modify rule.": "이메일 수정 규칙을 가져올 수 없습니다.",
|
||||
"Unable to get the phone modify rule.": "전화 수정 규칙을 가져올 수 없습니다.",
|
||||
|
@ -81,7 +81,8 @@
|
||||
"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",
|
||||
"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"
|
||||
@ -145,9 +146,10 @@
|
||||
"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 not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"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.",
|
||||
|
@ -81,7 +81,8 @@
|
||||
"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",
|
||||
"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"
|
||||
@ -145,9 +146,10 @@
|
||||
"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 not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"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.",
|
||||
|
@ -81,7 +81,8 @@
|
||||
"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",
|
||||
"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"
|
||||
@ -145,9 +146,10 @@
|
||||
"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 not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"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.",
|
||||
|
@ -81,7 +81,8 @@
|
||||
"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",
|
||||
"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"
|
||||
@ -145,9 +146,10 @@
|
||||
"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 not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"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.",
|
||||
|
@ -81,7 +81,8 @@
|
||||
"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 не существует",
|
||||
"don't support captchaProvider: ": "неподдерживаемый captchaProvider: ",
|
||||
"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-сервер существует"
|
||||
@ -145,9 +146,10 @@
|
||||
"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 not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"Turing test failed.": "Тест Тьюринга не удался.",
|
||||
"Unable to get the email modify rule.": "Невозможно получить правило изменения электронной почты.",
|
||||
"Unable to get the phone modify rule.": "Невозможно получить правило изменения телефона.",
|
||||
|
@ -81,7 +81,8 @@
|
||||
"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",
|
||||
"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"
|
||||
@ -145,9 +146,10 @@
|
||||
"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 not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"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.",
|
||||
|
@ -81,7 +81,8 @@
|
||||
"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",
|
||||
"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"
|
||||
@ -145,9 +146,10 @@
|
||||
"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": "Telefon numaranızın bulunduğu bölgeye hizmet veremiyoruz",
|
||||
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"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.",
|
||||
|
@ -81,7 +81,8 @@
|
||||
"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",
|
||||
"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"
|
||||
@ -145,9 +146,10 @@
|
||||
"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 not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"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.",
|
||||
|
@ -81,7 +81,8 @@
|
||||
"The organization: %s should have one application at least": "The organization: %s should have one application at least",
|
||||
"The user: %s doesn't exist": "Người dùng: %s không tồn tại",
|
||||
"don't support captchaProvider: ": "không hỗ trợ 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": "Máy chủ LDAP tồn tại"
|
||||
@ -145,9 +146,10 @@
|
||||
"The provider: %s is not found": "Nhà cung cấp: %s không được tìm thấy"
|
||||
},
|
||||
"verification": {
|
||||
"Code has not been sent yet!": "Mã chưa được gửi đến!",
|
||||
"Invalid captcha provider.": "Nhà cung cấp captcha không hợp lệ.",
|
||||
"Phone number is invalid in your region %s": "Số điện thoại không hợp lệ trong vùng của bạn %s",
|
||||
"The verification code has not been sent yet!": "The verification code has not been sent yet!",
|
||||
"The verification code has not been sent yet, or has already been used!": "The verification code has not been sent yet, or has already been used!",
|
||||
"Turing test failed.": "Kiểm định Turing thất bại.",
|
||||
"Unable to get the email modify rule.": "Không thể lấy quy tắc sửa đổi email.",
|
||||
"Unable to get the phone modify rule.": "Không thể thay đổi quy tắc trên điện thoại.",
|
||||
|
@ -81,7 +81,8 @@
|
||||
"The organization: %s should have one application at least": "组织: %s 应该拥有至少一个应用",
|
||||
"The user: %s doesn't exist": "用户: %s不存在",
|
||||
"don't support captchaProvider: ": "不支持验证码提供商: ",
|
||||
"this operation is not allowed in demo mode": "demo模式下不允许该操作"
|
||||
"this operation is not allowed in demo mode": "demo模式下不允许该操作",
|
||||
"this operation requires administrator to perform": "只有管理员才能进行此操作"
|
||||
},
|
||||
"ldap": {
|
||||
"Ldap server exist": "LDAP服务器已存在"
|
||||
@ -145,9 +146,10 @@
|
||||
"The provider: %s is not found": "未找到提供商: %s"
|
||||
},
|
||||
"verification": {
|
||||
"Code has not been sent yet!": "验证码还未发送",
|
||||
"Invalid captcha provider.": "非法的验证码提供商",
|
||||
"Phone number is invalid in your region %s": "您所在地区的电话号码无效 %s",
|
||||
"The verification code has not been sent yet!": "验证码未发送!",
|
||||
"The verification code has not been sent yet, or has already been used!": "验证码未发送或已被使用!",
|
||||
"Turing test failed.": "验证码还未发送",
|
||||
"Unable to get the email modify rule.": "无法获取邮箱修改规则",
|
||||
"Unable to get the phone modify rule.": "无法获取手机号修改规则",
|
||||
|
@ -15,43 +15,15 @@
|
||||
package idp
|
||||
|
||||
import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/ethereum/go-ethereum/crypto"
|
||||
|
||||
"golang.org/x/oauth2"
|
||||
)
|
||||
|
||||
type EIP712Message struct {
|
||||
Domain struct {
|
||||
ChainId string `json:"chainId"`
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
} `json:"domain"`
|
||||
Message struct {
|
||||
Prompt string `json:"prompt"`
|
||||
Nonce string `json:"nonce"`
|
||||
CreateAt string `json:"createAt"`
|
||||
} `json:"message"`
|
||||
PrimaryType string `json:"primaryType"`
|
||||
Types struct {
|
||||
EIP712Domain []struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
} `json:"EIP712Domain"`
|
||||
AuthRequest []struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
} `json:"AuthRequest"`
|
||||
} `json:"types"`
|
||||
}
|
||||
|
||||
type MetaMaskIdProvider struct {
|
||||
Client *http.Client
|
||||
}
|
||||
@ -70,15 +42,6 @@ func (idp *MetaMaskIdProvider) GetToken(code string) (*oauth2.Token, error) {
|
||||
if err := json.Unmarshal([]byte(code), &web3AuthToken); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
valid, err := VerifySignature(web3AuthToken.Address, web3AuthToken.TypedData, web3AuthToken.Signature)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !valid {
|
||||
return nil, fmt.Errorf("invalid signature")
|
||||
}
|
||||
|
||||
token := &oauth2.Token{
|
||||
AccessToken: web3AuthToken.Signature,
|
||||
TokenType: "Bearer",
|
||||
@ -105,43 +68,3 @@ func (idp *MetaMaskIdProvider) GetUserInfo(token *oauth2.Token) (*UserInfo, erro
|
||||
}
|
||||
return userInfo, nil
|
||||
}
|
||||
|
||||
func VerifySignature(userAddress string, originalMessage string, signatureHex string) (bool, error) {
|
||||
var eip712Mes EIP712Message
|
||||
err := json.Unmarshal([]byte(originalMessage), &eip712Mes)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("invalid signature (Error parsing JSON)")
|
||||
}
|
||||
|
||||
createAtTime, err := time.Parse("2006/1/2 15:04:05", eip712Mes.Message.CreateAt)
|
||||
currentTime := time.Now()
|
||||
if createAtTime.Before(currentTime.Add(-1*time.Minute)) && createAtTime.After(currentTime) {
|
||||
return false, fmt.Errorf("invalid signature (signature does not meet time requirements)")
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(signatureHex, "0x") {
|
||||
signatureHex = "0x" + signatureHex
|
||||
}
|
||||
|
||||
signatureBytes, err := hex.DecodeString(signatureHex[2:])
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
if signatureBytes[64] != 27 && signatureBytes[64] != 28 {
|
||||
return false, fmt.Errorf("invalid signature (incorrect recovery id)")
|
||||
}
|
||||
signatureBytes[64] -= 27
|
||||
|
||||
msg := fmt.Sprintf("\x19Ethereum Signed Message:\n%d%s", len([]byte(originalMessage)), []byte(originalMessage))
|
||||
hash := crypto.Keccak256Hash([]byte(msg))
|
||||
|
||||
pubKey, err := crypto.SigToPub(hash.Bytes(), signatureBytes)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
recoveredAddr := crypto.PubkeyToAddress(*pubKey)
|
||||
|
||||
return strings.EqualFold(recoveredAddr.Hex(), userAddress), nil
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ type SignupItem struct {
|
||||
Visible bool `json:"visible"`
|
||||
Required bool `json:"required"`
|
||||
Prompted bool `json:"prompted"`
|
||||
CustomCss string `json:"customCss"`
|
||||
Label string `json:"label"`
|
||||
Placeholder string `json:"placeholder"`
|
||||
Regex string `json:"regex"`
|
||||
@ -208,7 +209,7 @@ func extendApplicationWithSigninItems(application *Application) (err error) {
|
||||
signinItem := &SigninItem{
|
||||
Name: "Back button",
|
||||
Visible: true,
|
||||
Label: "\n<style>\n .back-button {\n top: 65px;\n left: 15px;\n position: absolute;\n }\n</style>\n",
|
||||
Label: ".back-button {\n top: 65px;\n left: 15px;\n position: absolute;\n}\n.back-inner-button{}",
|
||||
Placeholder: "",
|
||||
Rule: "None",
|
||||
}
|
||||
@ -216,7 +217,7 @@ func extendApplicationWithSigninItems(application *Application) (err error) {
|
||||
signinItem = &SigninItem{
|
||||
Name: "Languages",
|
||||
Visible: true,
|
||||
Label: "\n<style>\n .login-languages {\n top: 55px;\n right: 5px;\n position: absolute;\n }\n</style>\n",
|
||||
Label: ".login-languages {\n top: 55px;\n right: 5px;\n position: absolute;\n}",
|
||||
Placeholder: "",
|
||||
Rule: "None",
|
||||
}
|
||||
@ -224,7 +225,7 @@ func extendApplicationWithSigninItems(application *Application) (err error) {
|
||||
signinItem = &SigninItem{
|
||||
Name: "Logo",
|
||||
Visible: true,
|
||||
Label: "\n<style>\n .login-logo-box {\n }\n</style>\n",
|
||||
Label: ".login-logo-box {}",
|
||||
Placeholder: "",
|
||||
Rule: "None",
|
||||
}
|
||||
@ -232,7 +233,7 @@ func extendApplicationWithSigninItems(application *Application) (err error) {
|
||||
signinItem = &SigninItem{
|
||||
Name: "Signin methods",
|
||||
Visible: true,
|
||||
Label: "\n<style>\n .signin-methods {\n }\n</style>\n",
|
||||
Label: ".signin-methods {}",
|
||||
Placeholder: "",
|
||||
Rule: "None",
|
||||
}
|
||||
@ -240,7 +241,7 @@ func extendApplicationWithSigninItems(application *Application) (err error) {
|
||||
signinItem = &SigninItem{
|
||||
Name: "Username",
|
||||
Visible: true,
|
||||
Label: "\n<style>\n .login-username {\n }\n</style>\n",
|
||||
Label: ".login-username {}\n.login-username-input{}",
|
||||
Placeholder: "",
|
||||
Rule: "None",
|
||||
}
|
||||
@ -248,7 +249,7 @@ func extendApplicationWithSigninItems(application *Application) (err error) {
|
||||
signinItem = &SigninItem{
|
||||
Name: "Password",
|
||||
Visible: true,
|
||||
Label: "\n<style>\n .login-password {\n }\n</style>\n",
|
||||
Label: ".login-password {}\n.login-password-input{}",
|
||||
Placeholder: "",
|
||||
Rule: "None",
|
||||
}
|
||||
@ -256,7 +257,7 @@ func extendApplicationWithSigninItems(application *Application) (err error) {
|
||||
signinItem = &SigninItem{
|
||||
Name: "Agreement",
|
||||
Visible: true,
|
||||
Label: "\n<style>\n .login-agreement {\n }\n</style>\n",
|
||||
Label: ".login-agreement {}",
|
||||
Placeholder: "",
|
||||
Rule: "None",
|
||||
}
|
||||
@ -264,7 +265,7 @@ func extendApplicationWithSigninItems(application *Application) (err error) {
|
||||
signinItem = &SigninItem{
|
||||
Name: "Forgot password?",
|
||||
Visible: true,
|
||||
Label: "\n<style>\n .login-forget-password {\n display: inline-flex;\n justify-content: space-between;\n width: 320px;\n margin-bottom: 25px;\n }\n</style>\n",
|
||||
Label: ".login-forget-password {\n display: inline-flex;\n justify-content: space-between;\n width: 320px;\n margin-bottom: 25px;\n}",
|
||||
Placeholder: "",
|
||||
Rule: "None",
|
||||
}
|
||||
@ -272,7 +273,7 @@ func extendApplicationWithSigninItems(application *Application) (err error) {
|
||||
signinItem = &SigninItem{
|
||||
Name: "Login button",
|
||||
Visible: true,
|
||||
Label: "\n<style>\n .login-button-box {\n margin-bottom: 5px;\n }\n .login-button {\n width: 100%;\n }\n</style>\n",
|
||||
Label: ".login-button-box {\n margin-bottom: 5px;\n}\n.login-button {\n width: 100%;\n}",
|
||||
Placeholder: "",
|
||||
Rule: "None",
|
||||
}
|
||||
@ -280,7 +281,7 @@ func extendApplicationWithSigninItems(application *Application) (err error) {
|
||||
signinItem = &SigninItem{
|
||||
Name: "Signup link",
|
||||
Visible: true,
|
||||
Label: "\n<style>\n .login-signup-link {\n margin-bottom: 24px;\n display: flex;\n justify-content: end;\n}\n</style>\n",
|
||||
Label: ".login-signup-link {\n margin-bottom: 24px;\n display: flex;\n justify-content: end;\n}",
|
||||
Placeholder: "",
|
||||
Rule: "None",
|
||||
}
|
||||
@ -288,7 +289,7 @@ func extendApplicationWithSigninItems(application *Application) (err error) {
|
||||
signinItem = &SigninItem{
|
||||
Name: "Providers",
|
||||
Visible: true,
|
||||
Label: "\n<style>\n .provider-img {\n width: 30px;\n margin: 5px;\n }\n .provider-big-img {\n margin-bottom: 10px;\n }\n</style>\n",
|
||||
Label: ".provider-img {\n width: 30px;\n margin: 5px;\n}\n.provider-big-img {\n margin-bottom: 10px;\n}",
|
||||
Placeholder: "",
|
||||
Rule: "None",
|
||||
}
|
||||
@ -404,8 +405,8 @@ func GetApplicationByUser(user *User) (*Application, error) {
|
||||
}
|
||||
|
||||
func GetApplicationByUserId(userId string) (application *Application, err error) {
|
||||
owner, name := util.GetOwnerAndNameFromId(userId)
|
||||
if owner == "app" {
|
||||
_, name := util.GetOwnerAndNameFromId(userId)
|
||||
if IsAppUser(userId) {
|
||||
application, err = getApplication("admin", name)
|
||||
return
|
||||
}
|
||||
@ -669,11 +670,7 @@ func AddApplication(application *Application) (bool, error) {
|
||||
return affected != 0, nil
|
||||
}
|
||||
|
||||
func DeleteApplication(application *Application) (bool, error) {
|
||||
if application.Name == "app-built-in" {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func deleteApplication(application *Application) (bool, error) {
|
||||
affected, err := ormer.Engine.ID(core.PK{application.Owner, application.Name}).Delete(&Application{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
@ -682,6 +679,14 @@ func DeleteApplication(application *Application) (bool, error) {
|
||||
return affected != 0, nil
|
||||
}
|
||||
|
||||
func DeleteApplication(application *Application) (bool, error) {
|
||||
if application.Name == "app-built-in" {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return deleteApplication(application)
|
||||
}
|
||||
|
||||
func (application *Application) GetId() string {
|
||||
return fmt.Sprintf("%s/%s", application.Owner, application.Name)
|
||||
}
|
||||
|
@ -38,7 +38,20 @@ func (application *Application) GetProviderByCategory(category string) (*Provide
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (application *Application) GetProviderByCategoryAndRule(category string, method string) (*Provider, error) {
|
||||
func isProviderItemCountryCodeMatched(providerItem *ProviderItem, countryCode string) bool {
|
||||
if len(providerItem.CountryCodes) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
for _, countryCode2 := range providerItem.CountryCodes {
|
||||
if countryCode2 == "" || countryCode2 == "All" || countryCode2 == "all" || countryCode2 == countryCode {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (application *Application) GetProviderByCategoryAndRule(category string, method string, countryCode string) (*Provider, error) {
|
||||
providers, err := GetProviders(application.Organization)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@ -54,7 +67,13 @@ func (application *Application) GetProviderByCategoryAndRule(category string, me
|
||||
}
|
||||
|
||||
for _, providerItem := range application.Providers {
|
||||
if providerItem.Rule == method || (providerItem.Rule == "all" || providerItem.Rule == "" || providerItem.Rule == "None") {
|
||||
if providerItem.Provider != nil && providerItem.Provider.Category == "SMS" {
|
||||
if !isProviderItemCountryCodeMatched(providerItem, countryCode) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
if providerItem.Rule == method || providerItem.Rule == "" || providerItem.Rule == "All" || providerItem.Rule == "all" || providerItem.Rule == "None" {
|
||||
if provider, ok := m[providerItem.Name]; ok {
|
||||
return provider, nil
|
||||
}
|
||||
@ -65,11 +84,11 @@ func (application *Application) GetProviderByCategoryAndRule(category string, me
|
||||
}
|
||||
|
||||
func (application *Application) GetEmailProvider(method string) (*Provider, error) {
|
||||
return application.GetProviderByCategoryAndRule("Email", method)
|
||||
return application.GetProviderByCategoryAndRule("Email", method, "All")
|
||||
}
|
||||
|
||||
func (application *Application) GetSmsProvider(method string) (*Provider, error) {
|
||||
return application.GetProviderByCategoryAndRule("SMS", method)
|
||||
func (application *Application) GetSmsProvider(method string, countryCode string) (*Provider, error) {
|
||||
return application.GetProviderByCategoryAndRule("SMS", method, countryCode)
|
||||
}
|
||||
|
||||
func (application *Application) GetStorageProvider() (*Provider, error) {
|
||||
|
@ -410,7 +410,7 @@ func CheckUserPermission(requestUserId, userId string, strict bool, lang string)
|
||||
}
|
||||
|
||||
hasPermission := false
|
||||
if strings.HasPrefix(requestUserId, "app/") {
|
||||
if IsAppUser(requestUserId) {
|
||||
hasPermission = true
|
||||
} else {
|
||||
requestUser, err := GetUser(requestUserId)
|
||||
|
@ -71,7 +71,7 @@ func getBuiltInAccountItems() []*AccountItem {
|
||||
{Name: "Permissions", Visible: true, ViewRule: "Public", ModifyRule: "Immutable"},
|
||||
{Name: "Groups", Visible: true, ViewRule: "Public", ModifyRule: "Admin"},
|
||||
{Name: "3rd-party logins", Visible: true, ViewRule: "Self", ModifyRule: "Self"},
|
||||
{Name: "Properties", Visible: false, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||
{Name: "Properties", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||
{Name: "Is admin", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||
{Name: "Is forbidden", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||
{Name: "Is deleted", Visible: true, ViewRule: "Admin", ModifyRule: "Admin"},
|
||||
@ -409,7 +409,7 @@ func initBuiltInPermission() {
|
||||
Groups: []string{},
|
||||
Roles: []string{},
|
||||
Domains: []string{},
|
||||
Model: "model-built-in",
|
||||
Model: "user-model-built-in",
|
||||
Adapter: "",
|
||||
ResourceType: "Application",
|
||||
Resources: []string{"app-built-in"},
|
||||
|
@ -266,7 +266,13 @@ func initDefinedOrganization(organization *Organization) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
return
|
||||
affected, err := deleteOrganization(organization)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !affected {
|
||||
panic("Fail to delete organization")
|
||||
}
|
||||
}
|
||||
organization.CreatedTime = util.GetCurrentTime()
|
||||
organization.AccountItems = getBuiltInAccountItems()
|
||||
@ -284,7 +290,13 @@ func initDefinedApplication(application *Application) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
return
|
||||
affected, err := deleteApplication(application)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !affected {
|
||||
panic("Fail to delete application")
|
||||
}
|
||||
}
|
||||
application.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddApplication(application)
|
||||
@ -299,11 +311,19 @@ func initDefinedUser(user *User) {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
return
|
||||
affected, err := DeleteUser(user)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !affected {
|
||||
panic("Fail to delete user")
|
||||
}
|
||||
}
|
||||
user.CreatedTime = util.GetCurrentTime()
|
||||
user.Id = util.GenerateId()
|
||||
user.Properties = make(map[string]string)
|
||||
if user.Properties == nil {
|
||||
user.Properties = make(map[string]string)
|
||||
}
|
||||
_, err = AddUser(user)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -317,7 +337,13 @@ func initDefinedCert(cert *Cert) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
return
|
||||
affected, err := DeleteCert(cert)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !affected {
|
||||
panic("Fail to delete cert")
|
||||
}
|
||||
}
|
||||
cert.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddCert(cert)
|
||||
@ -333,7 +359,13 @@ func initDefinedLdap(ldap *Ldap) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
return
|
||||
affected, err := DeleteLdap(ldap)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !affected {
|
||||
panic("Fail to delete ldap")
|
||||
}
|
||||
}
|
||||
_, err = AddLdap(ldap)
|
||||
if err != nil {
|
||||
@ -348,7 +380,13 @@ func initDefinedProvider(provider *Provider) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
return
|
||||
affected, err := DeleteProvider(provider)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !affected {
|
||||
panic("Fail to delete provider")
|
||||
}
|
||||
}
|
||||
_, err = AddProvider(provider)
|
||||
if err != nil {
|
||||
@ -363,7 +401,13 @@ func initDefinedModel(model *Model) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
return
|
||||
affected, err := DeleteModel(model)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !affected {
|
||||
panic("Fail to delete provider")
|
||||
}
|
||||
}
|
||||
model.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddModel(model)
|
||||
@ -379,7 +423,13 @@ func initDefinedPermission(permission *Permission) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
return
|
||||
affected, err := DeletePermission(permission)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !affected {
|
||||
panic("Fail to delete permission")
|
||||
}
|
||||
}
|
||||
permission.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddPermission(permission)
|
||||
@ -395,7 +445,13 @@ func initDefinedPayment(payment *Payment) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
return
|
||||
affected, err := DeletePayment(payment)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !affected {
|
||||
panic("Fail to delete payment")
|
||||
}
|
||||
}
|
||||
payment.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddPayment(payment)
|
||||
@ -411,7 +467,13 @@ func initDefinedProduct(product *Product) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
return
|
||||
affected, err := DeleteProduct(product)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !affected {
|
||||
panic("Fail to delete product")
|
||||
}
|
||||
}
|
||||
product.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddProduct(product)
|
||||
@ -427,7 +489,13 @@ func initDefinedResource(resource *Resource) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
return
|
||||
affected, err := DeleteResource(resource)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !affected {
|
||||
panic("Fail to delete resource")
|
||||
}
|
||||
}
|
||||
resource.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddResource(resource)
|
||||
@ -443,7 +511,13 @@ func initDefinedRole(role *Role) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
return
|
||||
affected, err := DeleteRole(role)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !affected {
|
||||
panic("Fail to delete role")
|
||||
}
|
||||
}
|
||||
role.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddRole(role)
|
||||
@ -459,7 +533,13 @@ func initDefinedSyncer(syncer *Syncer) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
return
|
||||
affected, err := DeleteSyncer(syncer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !affected {
|
||||
panic("Fail to delete role")
|
||||
}
|
||||
}
|
||||
syncer.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddSyncer(syncer)
|
||||
@ -475,7 +555,13 @@ func initDefinedToken(token *Token) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
return
|
||||
affected, err := DeleteToken(token)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !affected {
|
||||
panic("Fail to delete token")
|
||||
}
|
||||
}
|
||||
token.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddToken(token)
|
||||
@ -491,7 +577,13 @@ func initDefinedWebhook(webhook *Webhook) {
|
||||
}
|
||||
|
||||
if existed != nil {
|
||||
return
|
||||
affected, err := DeleteWebhook(webhook)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !affected {
|
||||
panic("Fail to delete webhook")
|
||||
}
|
||||
}
|
||||
webhook.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddWebhook(webhook)
|
||||
@ -506,7 +598,13 @@ func initDefinedGroup(group *Group) {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
return
|
||||
affected, err := DeleteGroup(group)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !affected {
|
||||
panic("Fail to delete group")
|
||||
}
|
||||
}
|
||||
group.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddGroup(group)
|
||||
@ -521,7 +619,13 @@ func initDefinedAdapter(adapter *Adapter) {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
return
|
||||
affected, err := DeleteAdapter(adapter)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !affected {
|
||||
panic("Fail to delete adapter")
|
||||
}
|
||||
}
|
||||
adapter.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddAdapter(adapter)
|
||||
@ -536,7 +640,13 @@ func initDefinedEnforcer(enforcer *Enforcer) {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
return
|
||||
affected, err := DeleteEnforcer(enforcer)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !affected {
|
||||
panic("Fail to delete enforcer")
|
||||
}
|
||||
}
|
||||
enforcer.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddEnforcer(enforcer)
|
||||
@ -551,7 +661,13 @@ func initDefinedPlan(plan *Plan) {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
return
|
||||
affected, err := DeletePlan(plan)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !affected {
|
||||
panic("Fail to delete enforcer")
|
||||
}
|
||||
}
|
||||
plan.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddPlan(plan)
|
||||
@ -566,7 +682,13 @@ func initDefinedPricing(pricing *Pricing) {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
return
|
||||
affected, err := DeletePricing(pricing)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !affected {
|
||||
panic("Fail to delete pricing")
|
||||
}
|
||||
}
|
||||
pricing.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddPricing(pricing)
|
||||
@ -581,7 +703,13 @@ func initDefinedInvitation(invitation *Invitation) {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
return
|
||||
affected, err := DeleteInvitation(invitation)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !affected {
|
||||
panic("Fail to delete invitation")
|
||||
}
|
||||
}
|
||||
invitation.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddInvitation(invitation, "en")
|
||||
@ -609,7 +737,13 @@ func initDefinedSubscription(subscription *Subscription) {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
return
|
||||
affected, err := DeleteSubscription(subscription)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !affected {
|
||||
panic("Fail to delete subscription")
|
||||
}
|
||||
}
|
||||
subscription.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddSubscription(subscription)
|
||||
@ -624,7 +758,13 @@ func initDefinedTransaction(transaction *Transaction) {
|
||||
panic(err)
|
||||
}
|
||||
if existed != nil {
|
||||
return
|
||||
affected, err := DeleteTransaction(transaction)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if !affected {
|
||||
panic("Fail to delete transaction")
|
||||
}
|
||||
}
|
||||
transaction.CreatedTime = util.GetCurrentTime()
|
||||
_, err = AddTransaction(transaction)
|
||||
|
@ -241,11 +241,7 @@ func AddOrganization(organization *Organization) (bool, error) {
|
||||
return affected != 0, nil
|
||||
}
|
||||
|
||||
func DeleteOrganization(organization *Organization) (bool, error) {
|
||||
if organization.Name == "built-in" {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func deleteOrganization(organization *Organization) (bool, error) {
|
||||
affected, err := ormer.Engine.ID(core.PK{organization.Owner, organization.Name}).Delete(&Organization{})
|
||||
if err != nil {
|
||||
return false, err
|
||||
@ -254,6 +250,14 @@ func DeleteOrganization(organization *Organization) (bool, error) {
|
||||
return affected != 0, nil
|
||||
}
|
||||
|
||||
func DeleteOrganization(organization *Organization) (bool, error) {
|
||||
if organization.Name == "built-in" {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return deleteOrganization(organization)
|
||||
}
|
||||
|
||||
func GetOrganizationByUser(user *User) (*Organization, error) {
|
||||
if user == nil {
|
||||
return nil, nil
|
||||
|
@ -18,13 +18,14 @@ type ProviderItem struct {
|
||||
Owner string `json:"owner"`
|
||||
Name string `json:"name"`
|
||||
|
||||
CanSignUp bool `json:"canSignUp"`
|
||||
CanSignIn bool `json:"canSignIn"`
|
||||
CanUnlink bool `json:"canUnlink"`
|
||||
Prompted bool `json:"prompted"`
|
||||
SignupGroup string `json:"signupGroup"`
|
||||
Rule string `json:"rule"`
|
||||
Provider *Provider `json:"provider"`
|
||||
CanSignUp bool `json:"canSignUp"`
|
||||
CanSignIn bool `json:"canSignIn"`
|
||||
CanUnlink bool `json:"canUnlink"`
|
||||
CountryCodes []string `json:"countryCode"`
|
||||
Prompted bool `json:"prompted"`
|
||||
SignupGroup string `json:"signupGroup"`
|
||||
Rule string `json:"rule"`
|
||||
Provider *Provider `json:"provider"`
|
||||
}
|
||||
|
||||
func (application *Application) GetProviderItem(providerName string) *ProviderItem {
|
||||
|
@ -17,6 +17,7 @@ package object
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/beego/beego/context"
|
||||
@ -25,10 +26,14 @@ import (
|
||||
"github.com/casvisor/casvisor-go-sdk/casvisorsdk"
|
||||
)
|
||||
|
||||
var logPostOnly bool
|
||||
var (
|
||||
logPostOnly bool
|
||||
passwordRegex *regexp.Regexp
|
||||
)
|
||||
|
||||
func init() {
|
||||
logPostOnly = conf.GetConfigBool("logPostOnly")
|
||||
passwordRegex = regexp.MustCompile("\"password\":\".+\"")
|
||||
}
|
||||
|
||||
type Record struct {
|
||||
@ -40,6 +45,10 @@ type Response struct {
|
||||
Msg string `json:"msg"`
|
||||
}
|
||||
|
||||
func maskPassword(recordString string) string {
|
||||
return passwordRegex.ReplaceAllString(recordString, "\"password\":\"***\"")
|
||||
}
|
||||
|
||||
func NewRecord(ctx *context.Context) (*casvisorsdk.Record, error) {
|
||||
ip := strings.Replace(util.GetIPFromRequest(ctx.Request), ": ", "", -1)
|
||||
action := strings.Replace(ctx.Request.URL.Path, "/api/", "", -1)
|
||||
@ -51,6 +60,7 @@ func NewRecord(ctx *context.Context) (*casvisorsdk.Record, error) {
|
||||
object := ""
|
||||
if ctx.Input.RequestBody != nil && len(ctx.Input.RequestBody) != 0 {
|
||||
object = string(ctx.Input.RequestBody)
|
||||
object = maskPassword(object)
|
||||
}
|
||||
|
||||
respBytes, err := json.Marshal(ctx.Input.Data()["json"])
|
||||
@ -99,6 +109,8 @@ func AddRecord(record *casvisorsdk.Record) bool {
|
||||
|
||||
record.Owner = record.Organization
|
||||
|
||||
record.Object = maskPassword(record.Object)
|
||||
|
||||
errWebhook := SendWebhooks(record)
|
||||
if errWebhook == nil {
|
||||
record.IsTriggered = true
|
||||
|
@ -48,7 +48,7 @@ func SendSms(provider *Provider, content string, phoneNumbers ...string) error {
|
||||
if provider.AppId != "" {
|
||||
phoneNumbers = append([]string{provider.AppId}, phoneNumbers...)
|
||||
}
|
||||
} else if provider.Type == sender.Aliyun {
|
||||
} else if provider.Type == sender.Aliyun || provider.Type == sender.SendCloud {
|
||||
for i, number := range phoneNumbers {
|
||||
phoneNumbers[i] = strings.TrimPrefix(number, "+86")
|
||||
}
|
||||
|
@ -675,7 +675,7 @@ func UpdateUser(id string, user *User, columns []string, isAdmin bool) (bool, er
|
||||
"owner", "display_name", "avatar", "first_name", "last_name",
|
||||
"location", "address", "country_code", "region", "language", "affiliation", "title", "id_card_type", "id_card", "homepage", "bio", "tag", "language", "gender", "birthday", "education", "score", "karma", "ranking", "signup_application",
|
||||
"is_admin", "is_forbidden", "is_deleted", "hash", "is_default_avatar", "properties", "webauthnCredentials", "managedAccounts", "face_ids",
|
||||
"signin_wrong_times", "last_signin_wrong_time", "groups", "access_key", "access_secret",
|
||||
"signin_wrong_times", "last_signin_wrong_time", "groups", "access_key", "access_secret", "mfa_phone_enabled", "mfa_email_enabled",
|
||||
"github", "google", "qq", "wechat", "facebook", "dingtalk", "weibo", "gitee", "linkedin", "wecom", "lark", "gitlab", "adfs",
|
||||
"baidu", "alipay", "casdoor", "infoflow", "apple", "azuread", "azureadb2c", "slack", "steam", "bilibili", "okta", "douyin", "line", "amazon",
|
||||
"auth0", "battlenet", "bitbucket", "box", "cloudfoundry", "dailymotion", "deezer", "digitalocean", "discord", "dropbox",
|
||||
@ -833,6 +833,11 @@ func AddUser(user *User) (bool, error) {
|
||||
}
|
||||
}
|
||||
|
||||
isUsernameLowered := conf.GetConfigBool("isUsernameLowered")
|
||||
if isUsernameLowered {
|
||||
user.Name = strings.ToLower(user.Name)
|
||||
}
|
||||
|
||||
affected, err := ormer.Engine.Insert(user)
|
||||
if err != nil {
|
||||
return false, err
|
||||
@ -846,6 +851,8 @@ func AddUsers(users []*User) (bool, error) {
|
||||
return false, fmt.Errorf("no users are provided")
|
||||
}
|
||||
|
||||
isUsernameLowered := conf.GetConfigBool("isUsernameLowered")
|
||||
|
||||
// organization := GetOrganizationByUser(users[0])
|
||||
for _, user := range users {
|
||||
// this function is only used for syncer or batch upload, so no need to encrypt the password
|
||||
@ -869,6 +876,10 @@ func AddUsers(users []*User) (bool, error) {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
|
||||
if isUsernameLowered {
|
||||
user.Name = strings.ToLower(user.Name)
|
||||
}
|
||||
}
|
||||
|
||||
affected, err := ormer.Engine.Insert(users)
|
||||
@ -992,7 +1003,7 @@ func (user *User) GetFriendlyName() string {
|
||||
}
|
||||
|
||||
func isUserIdGlobalAdmin(userId string) bool {
|
||||
return strings.HasPrefix(userId, "built-in/") || strings.HasPrefix(userId, "app/")
|
||||
return strings.HasPrefix(userId, "built-in/") || IsAppUser(userId)
|
||||
}
|
||||
|
||||
func ExtendUserWithRolesAndPermissions(user *User) (err error) {
|
||||
|
@ -464,3 +464,10 @@ func (user *User) IsAdminUser() bool {
|
||||
|
||||
return user.IsAdmin || user.IsGlobalAdmin()
|
||||
}
|
||||
|
||||
func IsAppUser(userId string) bool {
|
||||
if strings.HasPrefix(userId, "app/") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -59,7 +59,7 @@ func fastAutoSignin(ctx *context.Context) (string, error) {
|
||||
scope := ctx.Input.Query("scope")
|
||||
state := ctx.Input.Query("state")
|
||||
nonce := ""
|
||||
codeChallenge := ""
|
||||
codeChallenge := ctx.Input.Query("code_challenge")
|
||||
if clientId == "" || responseType != "code" || redirectUri == "" {
|
||||
return "", nil
|
||||
}
|
||||
|
@ -70,6 +70,7 @@ func (sp LocalFileSystemProvider) Put(path string, reader io.Reader) (*oss.Objec
|
||||
|
||||
dst, err := os.Create(filepath.Clean(fullPath))
|
||||
if err == nil {
|
||||
defer dst.Close()
|
||||
if seeker, ok := reader.(io.ReadSeeker); ok {
|
||||
seeker.Seek(0, 0)
|
||||
}
|
||||
|
@ -3,14 +3,13 @@
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"@ant-design/cssinjs": "1.16.1",
|
||||
"@ant-design/cssinjs": "^1.10.1",
|
||||
"@ant-design/icons": "^4.7.0",
|
||||
"@craco/craco": "^6.4.5",
|
||||
"@crowdin/cli": "^3.7.10",
|
||||
"@ctrl/tinycolor": "^3.5.0",
|
||||
"@emotion/react": "^11.10.5",
|
||||
"@metamask/eth-sig-util": "^6.0.0",
|
||||
"@metamask/sdk-react": "^0.18.0",
|
||||
"@web3-onboard/coinbase": "^2.2.5",
|
||||
"@web3-onboard/core": "^2.20.5",
|
||||
"@web3-onboard/frontier": "^2.0.4",
|
||||
|
@ -374,6 +374,7 @@ class App extends Component {
|
||||
});
|
||||
}}
|
||||
onLoginSuccess={(redirectUrl) => {
|
||||
window.google?.accounts?.id?.cancel();
|
||||
if (redirectUrl) {
|
||||
localStorage.setItem("mfaRedirectUrl", redirectUrl);
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ import * as ApplicationBackend from "./backend/ApplicationBackend";
|
||||
import i18next from "i18next";
|
||||
import BaseListPage from "./BaseListPage";
|
||||
import PopconfirmModal from "./common/modal/PopconfirmModal";
|
||||
import {SignupTableDefaultCssMap} from "./table/SignupTable";
|
||||
|
||||
class ApplicationListPage extends BaseListPage {
|
||||
constructor(props) {
|
||||
@ -61,6 +62,8 @@ class ApplicationListPage extends BaseListPage {
|
||||
{name: "Email", visible: true, required: true, rule: "Normal"},
|
||||
{name: "Phone", visible: true, required: true, rule: "None"},
|
||||
{name: "Agreement", visible: true, required: true, rule: "None"},
|
||||
{name: "Signup button", visible: true, required: true, rule: "None"},
|
||||
{name: "Providers", visible: true, required: true, rule: "None", customCss: SignupTableDefaultCssMap["Providers"]},
|
||||
],
|
||||
grantTypes: ["authorization_code", "password", "client_credentials", "token", "id_token", "refresh_token"],
|
||||
cert: "cert-built-in",
|
||||
|
@ -41,7 +41,7 @@ class ProductEditPage extends React.Component {
|
||||
UNSAFE_componentWillMount() {
|
||||
this.getProduct();
|
||||
this.getOrganizations();
|
||||
this.getPaymentProviders();
|
||||
this.getPaymentProviders(this.state.organizationName);
|
||||
}
|
||||
|
||||
getProduct() {
|
||||
@ -67,8 +67,8 @@ class ProductEditPage extends React.Component {
|
||||
});
|
||||
}
|
||||
|
||||
getPaymentProviders() {
|
||||
ProviderBackend.getProviders(this.props.account.owner)
|
||||
getPaymentProviders(organizationName) {
|
||||
ProviderBackend.getProviders(organizationName)
|
||||
.then((res) => {
|
||||
if (res.status === "ok") {
|
||||
this.setState({
|
||||
|
@ -209,6 +209,8 @@ class ProviderEditPage extends React.Component {
|
||||
return Setting.getLabel(i18next.t("provider:Public key"), i18next.t("provider:Public key - Tooltip"));
|
||||
} else if (provider.type === "Msg91 SMS" || provider.type === "Infobip SMS" || provider.type === "OSON SMS") {
|
||||
return Setting.getLabel(i18next.t("provider:Sender Id"), i18next.t("provider:Sender Id - Tooltip"));
|
||||
} else if (provider.type === "SendCloud SMS") {
|
||||
return "SMS_USER";
|
||||
} else {
|
||||
return Setting.getLabel(i18next.t("provider:Client ID"), i18next.t("provider:Client ID - Tooltip"));
|
||||
}
|
||||
@ -244,7 +246,7 @@ class ProviderEditPage extends React.Component {
|
||||
return Setting.getLabel(i18next.t("provider:Client secret"), i18next.t("provider:Client secret - Tooltip"));
|
||||
}
|
||||
case "Email":
|
||||
if (provider.type === "Azure ACS") {
|
||||
if (provider.type === "Azure ACS" || provider.type === "SendGrid") {
|
||||
return Setting.getLabel(i18next.t("provider:Secret key"), i18next.t("provider:Secret key - Tooltip"));
|
||||
} else {
|
||||
return Setting.getLabel(i18next.t("general:Password"), i18next.t("general:Password - Tooltip"));
|
||||
@ -260,6 +262,8 @@ class ProviderEditPage extends React.Component {
|
||||
return Setting.getLabel(i18next.t("provider:Auth Key"), i18next.t("provider:Auth Key - Tooltip"));
|
||||
} else if (provider.type === "Infobip SMS") {
|
||||
return Setting.getLabel(i18next.t("provider:Api Key"), i18next.t("provider:Api Key - Tooltip"));
|
||||
} else if (provider.type === "SendCloud SMS") {
|
||||
return "SMS_KEY";
|
||||
} else {
|
||||
return Setting.getLabel(i18next.t("provider:Client secret"), i18next.t("provider:Client secret - Tooltip"));
|
||||
}
|
||||
@ -729,7 +733,7 @@ class ProviderEditPage extends React.Component {
|
||||
<React.Fragment>
|
||||
{
|
||||
(this.state.provider.category === "Storage" && this.state.provider.type === "Google Cloud Storage") ||
|
||||
(this.state.provider.category === "Email" && this.state.provider.type === "Azure ACS") ||
|
||||
(this.state.provider.category === "Email" && (this.state.provider.type === "Azure ACS" || this.state.provider.type === "SendGrid")) ||
|
||||
(this.state.provider.category === "Notification" && (this.state.provider.type === "Line" || this.state.provider.type === "Telegram" || this.state.provider.type === "Bark" || this.state.provider.type === "Discord" || this.state.provider.type === "Slack" || this.state.provider.type === "Pushbullet" || this.state.provider.type === "Pushover" || this.state.provider.type === "Lark" || this.state.provider.type === "Microsoft Teams")) ? null : (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
@ -770,7 +774,7 @@ class ProviderEditPage extends React.Component {
|
||||
</Col>
|
||||
</Row>
|
||||
{
|
||||
(this.state.provider.type === "WeChat Pay") || (this.state.provider.category === "Email" && this.state.provider.type === "Azure ACS") ? null : (
|
||||
(this.state.provider.type === "WeChat Pay") || (this.state.provider.category === "Email" && (this.state.provider.type === "Azure ACS" || this.state.provider.type === "SendGrid")) ? null : (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{this.getClientSecret2Label(this.state.provider)} :
|
||||
@ -985,17 +989,19 @@ class ProviderEditPage extends React.Component {
|
||||
</React.Fragment>
|
||||
) : this.state.provider.category === "Email" ? (
|
||||
<React.Fragment>
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Host"), i18next.t("provider:Host - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input prefix={<LinkOutlined />} value={this.state.provider.host} onChange={e => {
|
||||
this.updateProviderField("host", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
{["Azure ACS"].includes(this.state.provider.type) ? null : (
|
||||
{["SendGrid"].includes(this.state.provider.type) ? null : (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Host"), i18next.t("provider:Host - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<Input prefix={<LinkOutlined />} value={this.state.provider.host} onChange={e => {
|
||||
this.updateProviderField("host", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
{["Azure ACS", "SendGrid"].includes(this.state.provider.type) ? null : (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Port"), i18next.t("provider:Port - Tooltip"))} :
|
||||
@ -1007,7 +1013,7 @@ class ProviderEditPage extends React.Component {
|
||||
</Col>
|
||||
</Row>
|
||||
)}
|
||||
{["Azure ACS"].includes(this.state.provider.type) ? null : (
|
||||
{["Azure ACS", "SendGrid"].includes(this.state.provider.type) ? null : (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Disable SSL"), i18next.t("provider:Disable SSL - Tooltip"))} :
|
||||
@ -1073,7 +1079,7 @@ class ProviderEditPage extends React.Component {
|
||||
this.updateProviderField("receiver", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
{["Azure ACS"].includes(this.state.provider.type) ? null : (
|
||||
{["Azure ACS", "SendGrid"].includes(this.state.provider.type) ? null : (
|
||||
<Button style={{marginLeft: "10px", marginBottom: "5px"}} onClick={() => ProviderEditTestEmail.connectSmtpServer(this.state.provider)} >
|
||||
{i18next.t("provider:Test SMTP Connection")}
|
||||
</Button>
|
||||
@ -1087,7 +1093,7 @@ class ProviderEditPage extends React.Component {
|
||||
</React.Fragment>
|
||||
) : this.state.provider.category === "SMS" ? (
|
||||
<React.Fragment>
|
||||
{["Custom HTTP SMS", "Twilio SMS", "Amazon SNS", "Azure ACS", "Msg91 SMS", "Infobip SMS"].includes(this.state.provider.type) ?
|
||||
{["Custom HTTP SMS", "Twilio SMS", "Amazon SNS", "Azure ACS", "Msg91 SMS", "Infobip SMS", "SendCloud SMS"].includes(this.state.provider.type) ?
|
||||
null :
|
||||
(<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
@ -1337,20 +1343,6 @@ class ProviderEditPage extends React.Component {
|
||||
</Row>
|
||||
) : null
|
||||
}
|
||||
{
|
||||
this.state.provider.type === "MetaMask" ? (
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Signature messages"), i18next.t("provider:Signature messages - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22}>
|
||||
<Input value={this.state.provider.metadata} onChange={e => {
|
||||
this.updateProviderField("metadata", e.target.value);
|
||||
}} />
|
||||
</Col>
|
||||
</Row>
|
||||
) : null
|
||||
}
|
||||
<Row style={{marginTop: "20px"}} >
|
||||
<Col style={{marginTop: "5px"}} span={(Setting.isMobile()) ? 22 : 2}>
|
||||
{Setting.getLabel(i18next.t("provider:Provider URL"), i18next.t("provider:Provider URL - Tooltip"))} :
|
||||
|
@ -139,6 +139,10 @@ export const OtherProviderInfo = {
|
||||
logo: `${StaticBaseUrl}/img/social_twilio.svg`,
|
||||
url: "https://www.twilio.com/messaging",
|
||||
},
|
||||
"SendCloud SMS": {
|
||||
logo: `${StaticBaseUrl}/img/sms_sendcloud.png`,
|
||||
url: "https://www.sendcloud.net/",
|
||||
},
|
||||
"SmsBao SMS": {
|
||||
logo: `${StaticBaseUrl}/img/social_smsbao.png`,
|
||||
url: "https://www.smsbao.com/",
|
||||
@ -181,6 +185,10 @@ export const OtherProviderInfo = {
|
||||
logo: `${StaticBaseUrl}/img/social_azure.png`,
|
||||
url: "https://learn.microsoft.com/zh-cn/azure/communication-services",
|
||||
},
|
||||
"SendGrid": {
|
||||
logo: `${StaticBaseUrl}/img/email_sendgrid.png`,
|
||||
url: "https://sendgrid.com/",
|
||||
},
|
||||
"Custom HTTP Email": {
|
||||
logo: `${StaticBaseUrl}/img/social_default.png`,
|
||||
url: "https://casdoor.org/docs/provider/email/overview",
|
||||
@ -1015,6 +1023,7 @@ export function getProviderTypeOptions(category) {
|
||||
{id: "SUBMAIL", name: "SUBMAIL"},
|
||||
{id: "Mailtrap", name: "Mailtrap"},
|
||||
{id: "Azure ACS", name: "Azure ACS"},
|
||||
{id: "SendGrid", name: "SendGrid"},
|
||||
{id: "Custom HTTP Email", name: "Custom HTTP Email"},
|
||||
]
|
||||
);
|
||||
@ -1034,6 +1043,7 @@ export function getProviderTypeOptions(category) {
|
||||
{id: "Huawei Cloud SMS", name: "Huawei Cloud SMS"},
|
||||
{id: "UCloud SMS", name: "UCloud SMS"},
|
||||
{id: "Twilio SMS", name: "Twilio SMS"},
|
||||
{id: "SendCloud SMS", name: "SendCloud SMS"},
|
||||
{id: "SmsBao SMS", name: "SmsBao SMS"},
|
||||
{id: "SUBMAIL SMS", name: "SUBMAIL SMS"},
|
||||
{id: "Msg91 SMS", name: "Msg91 SMS"},
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
import React from "react";
|
||||
import {Button, Card, Col, Form, Input, InputNumber, List, Result, Row, Select, Space, Spin, Switch, Tag} from "antd";
|
||||
import {Button, Card, Col, Form, Input, InputNumber, List, Result, Row, Select, Space, Spin, Switch, Tag, Tooltip} from "antd";
|
||||
import {withRouter} from "react-router-dom";
|
||||
import {TotpMfaType} from "./auth/MfaSetupPage";
|
||||
import * as GroupBackend from "./backend/GroupBackend";
|
||||
@ -407,7 +407,17 @@ class UserEditPage extends React.Component {
|
||||
{Setting.getLabel(i18next.t("general:Password"), i18next.t("general:Password - Tooltip"))} :
|
||||
</Col>
|
||||
<Col span={22} >
|
||||
<PasswordModal user={this.state.user} userName={this.state.userName} organization={this.getUserOrganization()} account={this.props.account} disabled={disabled} />
|
||||
{
|
||||
(this.state.user.name === this.state.userName) ? (
|
||||
<PasswordModal user={this.state.user} userName={this.state.userName} organization={this.getUserOrganization()} account={this.props.account} disabled={disabled} />
|
||||
) : (
|
||||
<Tooltip placement={"topLeft"} title={i18next.t("user:You have changed the username, please save your change first before modifying the password")}>
|
||||
<span>
|
||||
<PasswordModal user={this.state.user} userName={this.state.userName} organization={this.getUserOrganization()} account={this.props.account} disabled={true} />
|
||||
</span>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
|
@ -19,7 +19,7 @@ import * as VerificationBackend from "./backend/VerificationBackend";
|
||||
import i18next from "i18next";
|
||||
import {Link} from "react-router-dom";
|
||||
import React from "react";
|
||||
import {Table} from "antd";
|
||||
import {Switch, Table} from "antd";
|
||||
|
||||
class VerificationListPage extends BaseListPage {
|
||||
newVerification() {
|
||||
@ -35,26 +35,48 @@ class VerificationListPage extends BaseListPage {
|
||||
renderTable(verifications) {
|
||||
const columns = [
|
||||
{
|
||||
title: i18next.t("general:Name"),
|
||||
dataIndex: "name",
|
||||
key: "name",
|
||||
width: "150px",
|
||||
fixed: "left",
|
||||
title: i18next.t("general:Organization"),
|
||||
dataIndex: "owner",
|
||||
key: "owner",
|
||||
width: "120px",
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps("name"),
|
||||
...this.getColumnSearchProps("owner"),
|
||||
render: (text, record, index) => {
|
||||
if (text === "admin") {
|
||||
return `(${i18next.t("general:empty")})`;
|
||||
}
|
||||
|
||||
return (
|
||||
<Link to={`/syncers/${text}`}>
|
||||
<Link to={`/organizations/${text}`}>
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Name"),
|
||||
dataIndex: "name",
|
||||
key: "name",
|
||||
width: "260px",
|
||||
fixed: "left",
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps("name"),
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Created time"),
|
||||
dataIndex: "createdTime",
|
||||
key: "createdTime",
|
||||
width: "160px",
|
||||
sorter: true,
|
||||
render: (text, record, index) => {
|
||||
return Setting.getFormattedDate(text);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("provider:Type"),
|
||||
dataIndex: "type",
|
||||
key: "type",
|
||||
width: "120px",
|
||||
width: "90px",
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps("type"),
|
||||
},
|
||||
@ -67,7 +89,7 @@ class VerificationListPage extends BaseListPage {
|
||||
...this.getColumnSearchProps("user"),
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Link to={`/users/${record.owner}/${text}`}>
|
||||
<Link to={`/users/${text}`}>
|
||||
{text}
|
||||
</Link>
|
||||
);
|
||||
@ -88,6 +110,26 @@ class VerificationListPage extends BaseListPage {
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Client IP"),
|
||||
dataIndex: "remoteAddr",
|
||||
key: "remoteAddr",
|
||||
width: "100px",
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps("remoteAddr"),
|
||||
render: (text, record, index) => {
|
||||
let clientIp = text;
|
||||
if (clientIp.endsWith(": ")) {
|
||||
clientIp = clientIp.slice(0, -2);
|
||||
}
|
||||
|
||||
return (
|
||||
<a target="_blank" rel="noreferrer" href={`https://db-ip.com/${clientIp}`}>
|
||||
{clientIp}
|
||||
</a>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("verification:Receiver"),
|
||||
dataIndex: "receiver",
|
||||
@ -100,28 +142,20 @@ class VerificationListPage extends BaseListPage {
|
||||
title: i18next.t("login:Verification code"),
|
||||
dataIndex: "code",
|
||||
key: "code",
|
||||
width: "120px",
|
||||
width: "150px",
|
||||
sorter: true,
|
||||
...this.getColumnSearchProps("code"),
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Timestamp"),
|
||||
dataIndex: "time",
|
||||
key: "time",
|
||||
width: "160px",
|
||||
title: i18next.t("verification:Is used"),
|
||||
dataIndex: "isUsed",
|
||||
key: "isUsed",
|
||||
width: "90px",
|
||||
sorter: true,
|
||||
render: (text, record, index) => {
|
||||
return Setting.getFormattedDate(text * 1000);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("general:Created time"),
|
||||
dataIndex: "createdTime",
|
||||
key: "createdTime",
|
||||
width: "160px",
|
||||
sorter: true,
|
||||
render: (text, record, index) => {
|
||||
return Setting.getFormattedDate(text);
|
||||
return (
|
||||
<Switch disabled checkedChildren="ON" unCheckedChildren="OFF" checked={text} />
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
@ -156,7 +190,7 @@ class VerificationListPage extends BaseListPage {
|
||||
value = params.type;
|
||||
}
|
||||
this.setState({loading: true});
|
||||
VerificationBackend.getVerifications("admin", Setting.isDefaultOrganizationSelected(this.props.account) ? "" : Setting.getRequestOrganization(this.props.account), params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
|
||||
VerificationBackend.getVerifications("", Setting.isDefaultOrganizationSelected(this.props.account) ? "" : Setting.getRequestOrganization(this.props.account), params.pagination.current, params.pagination.pageSize, field, value, sortField, sortOrder)
|
||||
.then((res) => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
|
@ -21,7 +21,7 @@ import * as Setting from "../Setting";
|
||||
import i18next from "i18next";
|
||||
import {SendCodeInput} from "../common/SendCodeInput";
|
||||
import * as UserBackend from "../backend/UserBackend";
|
||||
import {CheckCircleOutlined, KeyOutlined, LockOutlined, SolutionOutlined, UserOutlined} from "@ant-design/icons";
|
||||
import {ArrowLeftOutlined, CheckCircleOutlined, KeyOutlined, LockOutlined, SolutionOutlined, UserOutlined} from "@ant-design/icons";
|
||||
import CustomGithubCorner from "../common/CustomGithubCorner";
|
||||
import {withRouter} from "react-router-dom";
|
||||
import * as PasswordChecker from "../common/PasswordChecker";
|
||||
@ -443,6 +443,18 @@ class ForgetPage extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
stepBack() {
|
||||
if (this.state.current > 0) {
|
||||
this.setState({
|
||||
current: this.state.current - 1,
|
||||
});
|
||||
} else if (this.props.history.length > 1) {
|
||||
this.props.history.goBack();
|
||||
} else {
|
||||
Setting.redirectToLoginPage(this.getApplicationObj(), this.props.history);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const application = this.getApplicationObj();
|
||||
if (application === undefined) {
|
||||
@ -456,6 +468,9 @@ class ForgetPage extends React.Component {
|
||||
<React.Fragment>
|
||||
<CustomGithubCorner />
|
||||
<div className="forget-content" style={{padding: Setting.isMobile() ? "0" : null, boxShadow: Setting.isMobile() ? "none" : null}}>
|
||||
<Button type="text" style={{position: "relative", left: Setting.isMobile() ? "10px" : "-90px", top: 0}} size={"large"} onClick={() => {this.stepBack();}}>
|
||||
<ArrowLeftOutlined style={{fontSize: "24px"}} />
|
||||
</Button>
|
||||
<Row>
|
||||
<Col span={24} style={{justifyContent: "center"}}>
|
||||
<Row>
|
||||
|
@ -52,7 +52,7 @@ export function GoogleOneTapLoginVirtualButton(prop) {
|
||||
redirectUri = `${redirectUri}?state=${state}&code=${encodeURIComponent(code)}`;
|
||||
Setting.goToLink(redirectUri);
|
||||
},
|
||||
disableCancelOnUnmount: true,
|
||||
disableCancelOnUnmount: false,
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -532,7 +532,7 @@ class LoginPage extends React.Component {
|
||||
if (signinItem.name === "Logo") {
|
||||
return (
|
||||
<div className="login-logo-box">
|
||||
<div dangerouslySetInnerHTML={{__html: signinItem.label}} />
|
||||
<div dangerouslySetInnerHTML={{__html: ("<style>" + signinItem.label?.replaceAll("<style>", "").replaceAll("</style>", "") + "</style>")}} />
|
||||
{
|
||||
Setting.renderHelmet(application)
|
||||
}
|
||||
@ -543,8 +543,8 @@ class LoginPage extends React.Component {
|
||||
);
|
||||
} else if (signinItem.name === "Back button") {
|
||||
return (
|
||||
<div>
|
||||
<div dangerouslySetInnerHTML={{__html: signinItem.label}} />
|
||||
<div className="back-button">
|
||||
<div dangerouslySetInnerHTML={{__html: ("<style>" + signinItem.label?.replaceAll("<style>", "").replaceAll("</style>", "") + "</style>")}} />
|
||||
{
|
||||
this.renderBackButton()
|
||||
}
|
||||
@ -562,24 +562,25 @@ class LoginPage extends React.Component {
|
||||
|
||||
return (
|
||||
<div className="login-languages">
|
||||
<div dangerouslySetInnerHTML={{__html: signinItem.label}} />
|
||||
<div dangerouslySetInnerHTML={{__html: ("<style>" + signinItem.label?.replaceAll("<style>", "").replaceAll("</style>", "") + "</style>")}} />
|
||||
<LanguageSelect languages={application.organizationObj.languages} />
|
||||
</div>
|
||||
);
|
||||
} else if (signinItem.name === "Signin methods") {
|
||||
return (
|
||||
<div>
|
||||
<div dangerouslySetInnerHTML={{__html: signinItem.label}} />
|
||||
<div dangerouslySetInnerHTML={{__html: ("<style>" + signinItem.label?.replaceAll("<style>", "").replaceAll("</style>", "") + "</style>")}} />
|
||||
{this.renderMethodChoiceBox()}
|
||||
</div>
|
||||
)
|
||||
;
|
||||
} else if (signinItem.name === "Username") {
|
||||
return (
|
||||
<div className="login-username">
|
||||
<div dangerouslySetInnerHTML={{__html: signinItem.label}} />
|
||||
<div>
|
||||
<div dangerouslySetInnerHTML={{__html: ("<style>" + signinItem.label?.replaceAll("<style>", "").replaceAll("</style>", "") + "</style>")}} />
|
||||
<Form.Item
|
||||
name="username"
|
||||
className="login-username"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
@ -637,6 +638,7 @@ class LoginPage extends React.Component {
|
||||
|
||||
<Input
|
||||
id="input"
|
||||
className="login-username-input"
|
||||
prefix={<UserOutlined className="site-form-item-icon" />}
|
||||
placeholder={this.getPlaceholder()}
|
||||
onChange={e => {
|
||||
@ -651,14 +653,14 @@ class LoginPage extends React.Component {
|
||||
} else if (signinItem.name === "Password") {
|
||||
return (
|
||||
<div>
|
||||
<div dangerouslySetInnerHTML={{__html: signinItem.label}} />
|
||||
<div dangerouslySetInnerHTML={{__html: ("<style>" + signinItem.label?.replaceAll("<style>", "").replaceAll("</style>", "") + "</style>")}} />
|
||||
{this.renderPasswordOrCodeInput()}
|
||||
</div>
|
||||
);
|
||||
} else if (signinItem.name === "Forgot password?") {
|
||||
return (
|
||||
<div>
|
||||
<div dangerouslySetInnerHTML={{__html: signinItem.label}} />
|
||||
<div dangerouslySetInnerHTML={{__html: ("<style>" + signinItem.label?.replaceAll("<style>", "").replaceAll("</style>", "") + "</style>")}} />
|
||||
<div className="login-forget-password">
|
||||
<Form.Item name="autoSignin" valuePropName="checked" noStyle>
|
||||
<Checkbox style={{float: "left"}}>
|
||||
@ -676,7 +678,7 @@ class LoginPage extends React.Component {
|
||||
} else if (signinItem.name === "Login button") {
|
||||
return (
|
||||
<Form.Item className="login-button-box">
|
||||
<div dangerouslySetInnerHTML={{__html: signinItem.label}} />
|
||||
<div dangerouslySetInnerHTML={{__html: ("<style>" + signinItem.label?.replaceAll("<style>", "").replaceAll("</style>", "") + "</style>")}} />
|
||||
<Button
|
||||
type="primary"
|
||||
htmlType="submit"
|
||||
@ -720,7 +722,7 @@ class LoginPage extends React.Component {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div dangerouslySetInnerHTML={{__html: signinItem.label}} />
|
||||
<div dangerouslySetInnerHTML={{__html: ("<style>" + signinItem.label?.replaceAll("<style>", "").replaceAll("</style>", "") + "</style>")}} />
|
||||
<Form.Item>
|
||||
{
|
||||
application.providers.filter(providerItem => this.isProviderVisible(providerItem)).map(providerItem => {
|
||||
@ -740,7 +742,7 @@ class LoginPage extends React.Component {
|
||||
} else if (signinItem.name === "Signup link") {
|
||||
return (
|
||||
<div style={{width: "100%"}} className="login-signup-link">
|
||||
<div dangerouslySetInnerHTML={{__html: signinItem.label}} />
|
||||
<div dangerouslySetInnerHTML={{__html: ("<style>" + signinItem.label?.replaceAll("<style>", "").replaceAll("</style>", "") + "</style>")}} />
|
||||
{this.renderFooter(application)}
|
||||
</div>
|
||||
);
|
||||
@ -838,7 +840,7 @@ class LoginPage extends React.Component {
|
||||
{application.displayName}
|
||||
</span>
|
||||
</a>
|
||||
:
|
||||
:
|
||||
</div>
|
||||
<br />
|
||||
{
|
||||
@ -1025,12 +1027,14 @@ class LoginPage extends React.Component {
|
||||
if (this.state.loginMethod === "password" || this.state.loginMethod === "ldap") {
|
||||
return (
|
||||
<Col span={24}>
|
||||
<div className="login-password">
|
||||
<div>
|
||||
<Form.Item
|
||||
name="password"
|
||||
className="login-password"
|
||||
rules={[{required: true, message: i18next.t("login:Please input your password!")}]}
|
||||
>
|
||||
<Input.Password
|
||||
className="login-password-input"
|
||||
prefix={<LockOutlined className="site-form-item-icon" />}
|
||||
type="password"
|
||||
placeholder={i18next.t("general:Password")}
|
||||
@ -1195,8 +1199,7 @@ class LoginPage extends React.Component {
|
||||
renderBackButton() {
|
||||
if (this.state.orgChoiceMode === "None" || this.props.preview === "auto") {
|
||||
return (
|
||||
<Button type="text" size="large" icon={<ArrowLeftOutlined />}
|
||||
className="back-button"
|
||||
<Button className="back-inner-button" type="text" size="large" icon={<ArrowLeftOutlined />}
|
||||
onClick={() => history.back()}>
|
||||
</Button>
|
||||
);
|
||||
|
@ -1,107 +0,0 @@
|
||||
// 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.
|
||||
|
||||
import {getAuthUrl} from "./Provider";
|
||||
import {getProviderLogoURL, goToLink, showMessage} from "../Setting";
|
||||
import i18next from "i18next";
|
||||
import {
|
||||
generateNonce,
|
||||
getWeb3AuthTokenKey,
|
||||
setWeb3AuthToken
|
||||
} from "./Web3Auth";
|
||||
import {useSDK} from "@metamask/sdk-react";
|
||||
import React, {useEffect} from "react";
|
||||
|
||||
export function MetaMaskLoginButton(props) {
|
||||
const {application, web3Provider, method, width, margin} = props;
|
||||
const {sdk, chainId, account} = useSDK();
|
||||
const [typedData, setTypedData] = React.useState("");
|
||||
const [nonce, setNonce] = React.useState("");
|
||||
const [signature, setSignature] = React.useState();
|
||||
|
||||
useEffect(() => {
|
||||
if (account && signature) {
|
||||
const date = new Date();
|
||||
|
||||
const token = {
|
||||
address: account,
|
||||
nonce: nonce,
|
||||
createAt: Math.floor(date.getTime() / 1000),
|
||||
typedData: typedData,
|
||||
signature: signature,
|
||||
};
|
||||
setWeb3AuthToken(token);
|
||||
|
||||
const redirectUri = `${getAuthUrl(application, web3Provider, method)}&web3AuthTokenKey=${getWeb3AuthTokenKey(account)}`;
|
||||
goToLink(redirectUri);
|
||||
}
|
||||
}, [account, signature]);
|
||||
|
||||
const handleConnectAndSign = async() => {
|
||||
try {
|
||||
terminate();
|
||||
|
||||
const date = new Date();
|
||||
|
||||
const nonce = generateNonce();
|
||||
setNonce(nonce);
|
||||
|
||||
const prompt = web3Provider?.metadata === "" ? "Casdoor: In order to authenticate to this website, sign this request and your public address will be sent to the server in a verifiable way." : web3Provider.metadata;
|
||||
const typedData = JSON.stringify({
|
||||
domain: {
|
||||
chainId: chainId,
|
||||
name: "Casdoor",
|
||||
version: "1",
|
||||
},
|
||||
message: {
|
||||
prompt: `${prompt}`,
|
||||
nonce: nonce,
|
||||
createAt: `${date.toLocaleString()}`,
|
||||
},
|
||||
primaryType: "AuthRequest",
|
||||
types: {
|
||||
EIP712Domain: [
|
||||
{name: "name", type: "string"},
|
||||
{name: "version", type: "string"},
|
||||
{name: "chainId", type: "uint256"},
|
||||
],
|
||||
AuthRequest: [
|
||||
{name: "prompt", type: "string"},
|
||||
{name: "nonce", type: "string"},
|
||||
{name: "createAt", type: "string"},
|
||||
],
|
||||
},
|
||||
});
|
||||
setTypedData(typedData);
|
||||
|
||||
const sig = await sdk.connectAndSign({msg: typedData});
|
||||
setSignature(sig);
|
||||
} catch (err) {
|
||||
showMessage("error", `${i18next.t("login:Failed to obtain MetaMask authorization")}: ${err.message}`);
|
||||
}
|
||||
};
|
||||
|
||||
const terminate = () => {
|
||||
sdk?.terminate();
|
||||
};
|
||||
|
||||
return (
|
||||
<a key={web3Provider.displayName} onClick={handleConnectAndSign}>
|
||||
<img width={width} height={width} src={getProviderLogoURL(web3Provider)} alt={web3Provider.displayName}
|
||||
className="provider-img" style={{margin: margin}} />
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
||||
export default MetaMaskLoginButton;
|
@ -43,8 +43,6 @@ import DouyinLoginButton from "./DouyinLoginButton";
|
||||
import LoginButton from "./LoginButton";
|
||||
import * as AuthBackend from "./AuthBackend";
|
||||
import {WechatOfficialAccountModal} from "./Util";
|
||||
import {MetaMaskProvider} from "@metamask/sdk-react";
|
||||
import MetaMaskLoginButton from "./MetaMaskLoginButton";
|
||||
|
||||
function getSigninButton(provider) {
|
||||
const text = i18next.t("login:Sign in with {type}").replace("{type}", provider.displayName !== "" ? provider.displayName : provider.type);
|
||||
@ -162,36 +160,11 @@ export function renderProviderLogo(provider, application, width, margin, size, l
|
||||
</a>
|
||||
);
|
||||
} else if (provider.category === "Web3") {
|
||||
if (provider.type === "MetaMask") {
|
||||
return (
|
||||
<MetaMaskProvider
|
||||
debug={false}
|
||||
sdkOptions={{
|
||||
communicationServerUrl: process.env.REACT_APP_COMM_SERVER_URL,
|
||||
checkInstallationImmediately: false, // This will automatically connect to MetaMask on page load
|
||||
dappMetadata: {
|
||||
name: "Casdoor",
|
||||
url: window.location.protocol + "//" + window.location.host,
|
||||
},
|
||||
}}
|
||||
>
|
||||
<MetaMaskLoginButton
|
||||
application={application}
|
||||
web3Provider={provider}
|
||||
method={"signup"}
|
||||
width={width}
|
||||
margin={margin}
|
||||
/>
|
||||
</MetaMaskProvider>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<a key={provider.displayName} onClick={() => goToWeb3Url(application, provider, "signup")}>
|
||||
<img width={width} height={width} src={getProviderLogoURL(provider)} alt={provider.displayName}
|
||||
className="provider-img" style={{margin: margin}} />
|
||||
</a>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<a key={provider.displayName} onClick={() => goToWeb3Url(application, provider, "signup")}>
|
||||
<img width={width} height={width} src={getProviderLogoURL(provider)} alt={provider.displayName} className="provider-img" style={{margin: margin}} />
|
||||
</a>
|
||||
);
|
||||
}
|
||||
} else if (provider.type === "Custom") {
|
||||
// style definition
|
||||
@ -199,23 +172,23 @@ export function renderProviderLogo(provider, application, width, margin, size, l
|
||||
const customAStyle = {display: "block", height: "55px", color: "#000"};
|
||||
const customButtonStyle = {display: "flex", alignItems: "center", width: "calc(100% - 10px)", height: "50px", margin: "5px", padding: "0 10px", backgroundColor: "transparent", boxShadow: "0px 1px 3px rgba(0,0,0,0.5)", border: "0px", borderRadius: "3px", cursor: "pointer"};
|
||||
const customImgStyle = {justfyContent: "space-between"};
|
||||
const customSpanStyle = {textAlign: "center", lineHeight: "50px", width: "100%", fontSize: "19px"};
|
||||
const customSpanStyle = {textAlign: "center", width: "100%", fontSize: "19px"};
|
||||
if (provider.category === "OAuth") {
|
||||
return (
|
||||
<a key={provider.displayName} href={Provider.getAuthUrl(application, provider, "signup")} style={customAStyle}>
|
||||
<button style={customButtonStyle}>
|
||||
<div style={customButtonStyle}>
|
||||
<img width={26} src={getProviderLogoURL(provider)} alt={provider.displayName} className="provider-img" style={customImgStyle} />
|
||||
<span style={customSpanStyle}>{text}</span>
|
||||
</button>
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
} else if (provider.category === "SAML") {
|
||||
return (
|
||||
<a key={provider.displayName} onClick={() => goToSamlUrl(provider, location)} style={customAStyle}>
|
||||
<button style={customButtonStyle}>
|
||||
<div style={customButtonStyle}>
|
||||
<img width={26} src={getProviderLogoURL(provider)} alt={provider.displayName} className="provider-img" style={customImgStyle} />
|
||||
<span style={customSpanStyle}>{text}</span>
|
||||
</button>
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
|
@ -248,6 +248,7 @@ class SignupPage extends React.Component {
|
||||
return (
|
||||
<Form.Item
|
||||
name="username"
|
||||
className="signup-username"
|
||||
label={signupItem.label ? signupItem.label : i18next.t("signup:Username")}
|
||||
rules={[
|
||||
{
|
||||
@ -257,7 +258,8 @@ class SignupPage extends React.Component {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input placeholder={signupItem.placeholder} disabled={this.state.invitation !== undefined && this.state.invitation.username !== ""} />
|
||||
<Input className="signup-username-input" placeholder={signupItem.placeholder}
|
||||
disabled={this.state.invitation !== undefined && this.state.invitation.username !== ""} />
|
||||
</Form.Item>
|
||||
);
|
||||
} else if (signupItem.name === "Display name") {
|
||||
@ -266,6 +268,7 @@ class SignupPage extends React.Component {
|
||||
<React.Fragment>
|
||||
<Form.Item
|
||||
name="firstName"
|
||||
className="signup-first-name"
|
||||
label={signupItem.label ? signupItem.label : i18next.t("general:First name")}
|
||||
rules={[
|
||||
{
|
||||
@ -275,10 +278,11 @@ class SignupPage extends React.Component {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input placeholder={signupItem.placeholder} />
|
||||
<Input className="signup-first-name-input" placeholder={signupItem.placeholder} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
name="lastName"
|
||||
className="signup-last-name"
|
||||
label={signupItem.label ? signupItem.label : i18next.t("general:Last name")}
|
||||
rules={[
|
||||
{
|
||||
@ -288,7 +292,7 @@ class SignupPage extends React.Component {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input placeholder={signupItem.placeholder} />
|
||||
<Input className="signup-last-name-input" placeholder={signupItem.placeholder} />
|
||||
</Form.Item>
|
||||
</React.Fragment>
|
||||
);
|
||||
@ -297,6 +301,7 @@ class SignupPage extends React.Component {
|
||||
return (
|
||||
<Form.Item
|
||||
name="name"
|
||||
className="signup-name"
|
||||
label={(signupItem.label ? signupItem.label : (signupItem.rule === "Real name" || signupItem.rule === "First, last") ? i18next.t("general:Real name") : i18next.t("general:Display name"))}
|
||||
rules={[
|
||||
{
|
||||
@ -306,13 +311,14 @@ class SignupPage extends React.Component {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input placeholder={signupItem.placeholder} />
|
||||
<Input className="signup-name-input" placeholder={signupItem.placeholder} />
|
||||
</Form.Item>
|
||||
);
|
||||
} else if (signupItem.name === "Affiliation") {
|
||||
return (
|
||||
<Form.Item
|
||||
name="affiliation"
|
||||
className="signup-affiliation"
|
||||
label={signupItem.label ? signupItem.label : i18next.t("user:Affiliation")}
|
||||
rules={[
|
||||
{
|
||||
@ -322,13 +328,14 @@ class SignupPage extends React.Component {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input placeholder={signupItem.placeholder} />
|
||||
<Input className="signup-affiliation-input" placeholder={signupItem.placeholder} />
|
||||
</Form.Item>
|
||||
);
|
||||
} else if (signupItem.name === "ID card") {
|
||||
return (
|
||||
<Form.Item
|
||||
name="idCard"
|
||||
className="signup-idcard"
|
||||
label={signupItem.label ? signupItem.label : i18next.t("user:ID card")}
|
||||
rules={[
|
||||
{
|
||||
@ -343,13 +350,14 @@ class SignupPage extends React.Component {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input placeholder={signupItem.placeholder} />
|
||||
<Input className="signup-idcard-input" placeholder={signupItem.placeholder} />
|
||||
</Form.Item>
|
||||
);
|
||||
} else if (signupItem.name === "Country/Region") {
|
||||
return (
|
||||
<Form.Item
|
||||
name="country_region"
|
||||
className="signup-country-region"
|
||||
label={signupItem.label ? signupItem.label : i18next.t("user:Country/Region")}
|
||||
rules={[
|
||||
{
|
||||
@ -358,7 +366,7 @@ class SignupPage extends React.Component {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<RegionSelect onChange={(value) => {this.setState({region: value});}} />
|
||||
<RegionSelect className="signup-region-select" onChange={(value) => {this.setState({region: value});}} />
|
||||
</Form.Item>
|
||||
);
|
||||
} else if (signupItem.name === "Email" || signupItem.name === "Phone" || signupItem.name === "Email or Phone" || signupItem.name === "Phone or Email") {
|
||||
@ -367,6 +375,7 @@ class SignupPage extends React.Component {
|
||||
<React.Fragment>
|
||||
<Form.Item
|
||||
name="email"
|
||||
className="signup-email"
|
||||
label={signupItem.label ? signupItem.label : i18next.t("general:Email")}
|
||||
rules={[
|
||||
{
|
||||
@ -386,12 +395,13 @@ class SignupPage extends React.Component {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input placeholder={signupItem.placeholder} disabled={this.state.invitation !== undefined && this.state.invitation.email !== ""} onChange={e => this.setState({email: e.target.value})} />
|
||||
<Input className="signup-email-input" placeholder={signupItem.placeholder} disabled={this.state.invitation !== undefined && this.state.invitation.email !== ""} onChange={e => this.setState({email: e.target.value})} />
|
||||
</Form.Item>
|
||||
{
|
||||
signupItem.rule !== "No verification" &&
|
||||
<Form.Item
|
||||
name="emailCode"
|
||||
className="signup-email-code"
|
||||
label={signupItem.label ? signupItem.label : i18next.t("code:Email code")}
|
||||
rules={[{
|
||||
required: required,
|
||||
@ -399,6 +409,7 @@ class SignupPage extends React.Component {
|
||||
}]}
|
||||
>
|
||||
<SendCodeInput
|
||||
className="signup-email-code-input"
|
||||
disabled={!this.state.validEmail}
|
||||
method={"signup"}
|
||||
onButtonClickArgs={[this.state.email, "email", Setting.getApplicationName(application)]}
|
||||
@ -413,7 +424,7 @@ class SignupPage extends React.Component {
|
||||
const renderPhoneItem = () => {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Form.Item label={signupItem.label ? signupItem.label : i18next.t("general:Phone")} required={required}>
|
||||
<Form.Item className="signup-phone" label={signupItem.label ? signupItem.label : i18next.t("general:Phone")} required={required}>
|
||||
<Input.Group compact>
|
||||
<Form.Item
|
||||
name="countryCode"
|
||||
@ -457,6 +468,7 @@ class SignupPage extends React.Component {
|
||||
]}
|
||||
>
|
||||
<Input
|
||||
className="signup-phone-input"
|
||||
placeholder={signupItem.placeholder}
|
||||
style={{width: "65%"}}
|
||||
disabled={this.state.invitation !== undefined && this.state.invitation.phone !== ""}
|
||||
@ -469,6 +481,7 @@ class SignupPage extends React.Component {
|
||||
signupItem.rule !== "No verification" &&
|
||||
<Form.Item
|
||||
name="phoneCode"
|
||||
className="phone-code"
|
||||
label={signupItem.label ? signupItem.label : i18next.t("code:Phone code")}
|
||||
rules={[
|
||||
{
|
||||
@ -478,6 +491,7 @@ class SignupPage extends React.Component {
|
||||
]}
|
||||
>
|
||||
<SendCodeInput
|
||||
className="signup-phone-code-input"
|
||||
disabled={!this.state.validPhone}
|
||||
method={"signup"}
|
||||
onButtonClickArgs={[this.state.phone, "phone", Setting.getApplicationName(application)]}
|
||||
@ -535,6 +549,7 @@ class SignupPage extends React.Component {
|
||||
return (
|
||||
<Form.Item
|
||||
name="password"
|
||||
className="signup-password"
|
||||
label={signupItem.label ? signupItem.label : i18next.t("general:Password")}
|
||||
rules={[
|
||||
{
|
||||
@ -552,13 +567,14 @@ class SignupPage extends React.Component {
|
||||
]}
|
||||
hasFeedback
|
||||
>
|
||||
<Input.Password placeholder={signupItem.placeholder} />
|
||||
<Input.Password className="signup-password-input" placeholder={signupItem.placeholder} />
|
||||
</Form.Item>
|
||||
);
|
||||
} else if (signupItem.name === "Confirm password") {
|
||||
return (
|
||||
<Form.Item
|
||||
name="confirm"
|
||||
className="signup-confirm"
|
||||
label={signupItem.label ? signupItem.label : i18next.t("signup:Confirm")}
|
||||
dependencies={["password"]}
|
||||
hasFeedback
|
||||
@ -585,6 +601,7 @@ class SignupPage extends React.Component {
|
||||
return (
|
||||
<Form.Item
|
||||
name="invitationCode"
|
||||
className="signup-invitation-code"
|
||||
label={signupItem.label ? signupItem.label : i18next.t("application:Invitation code")}
|
||||
rules={[
|
||||
{
|
||||
@ -593,7 +610,7 @@ class SignupPage extends React.Component {
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input placeholder={signupItem.placeholder} disabled={this.state.invitation !== undefined && this.state.invitation !== ""} />
|
||||
<Input className="signup-invitation-code-input" placeholder={signupItem.placeholder} disabled={this.state.invitation !== undefined && this.state.invitation !== ""} />
|
||||
</Form.Item>
|
||||
);
|
||||
} else if (signupItem.name === "Agreement") {
|
||||
@ -602,6 +619,37 @@ class SignupPage extends React.Component {
|
||||
return (
|
||||
<div dangerouslySetInnerHTML={{__html: signupItem.label}} />
|
||||
);
|
||||
} else if (signupItem.name === "Signup button") {
|
||||
return (
|
||||
<Form.Item {...tailFormItemLayout}>
|
||||
<Button type="primary" htmlType="submit" className="signup-button">
|
||||
{i18next.t("account:Sign Up")}
|
||||
</Button>
|
||||
{i18next.t("signup:Have account?")}
|
||||
<a className="signup-link" onClick={() => {
|
||||
const linkInStorage = sessionStorage.getItem("signinUrl");
|
||||
if (linkInStorage !== null && linkInStorage !== "") {
|
||||
Setting.goToLinkSoft(this, linkInStorage);
|
||||
} else {
|
||||
Setting.redirectToLoginPage(application, this.props.history);
|
||||
}
|
||||
}}>
|
||||
{i18next.t("signup:sign in now")}
|
||||
</a>
|
||||
</Form.Item>
|
||||
);
|
||||
} else if (signupItem.name === "Providers") {
|
||||
const showForm = Setting.isPasswordEnabled(application) || Setting.isCodeSigninEnabled(application) || Setting.isWebAuthnEnabled(application) || Setting.isLdapEnabled(application);
|
||||
if (signupItem.rule === "None" || signupItem.rule === "") {
|
||||
signupItem.rule = showForm ? "small" : "big";
|
||||
}
|
||||
return (
|
||||
|
||||
application.providers.filter(providerItem => this.isProviderVisible(providerItem)).map(providerItem => {
|
||||
return ProviderButton.renderProviderLogo(providerItem.provider, application, null, null, signupItem.rule, this.props.location);
|
||||
})
|
||||
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -676,27 +724,13 @@ class SignupPage extends React.Component {
|
||||
>
|
||||
</Form.Item>
|
||||
{
|
||||
application.signupItems?.map(signupItem => this.renderFormItem(application, signupItem))
|
||||
}
|
||||
<Form.Item {...tailFormItemLayout}>
|
||||
<Button type="primary" htmlType="submit">
|
||||
{i18next.t("account:Sign Up")}
|
||||
</Button>
|
||||
{i18next.t("signup:Have account?")}
|
||||
<a onClick={() => {
|
||||
const linkInStorage = sessionStorage.getItem("signinUrl");
|
||||
if (linkInStorage !== null && linkInStorage !== "") {
|
||||
Setting.goToLinkSoft(this, linkInStorage);
|
||||
} else {
|
||||
Setting.redirectToLoginPage(application, this.props.history);
|
||||
}
|
||||
}}>
|
||||
{i18next.t("signup:sign in now")}
|
||||
</a>
|
||||
</Form.Item>
|
||||
{
|
||||
application.providers.filter(providerItem => this.isProviderVisible(providerItem)).map(providerItem => {
|
||||
return ProviderButton.renderProviderLogo(providerItem.provider, application, 30, 5, "small", this.props.location);
|
||||
application.signupItems?.map((signupItem, idx) => {
|
||||
return (
|
||||
<div key={idx}>
|
||||
<div dangerouslySetInnerHTML={{__html: ("<style>" + signupItem.customCss + "</style>")}} />
|
||||
{this.renderFormItem(application, signupItem)}
|
||||
</div>
|
||||
);
|
||||
})
|
||||
}
|
||||
</Form>
|
||||
@ -709,6 +743,20 @@ class SignupPage extends React.Component {
|
||||
return null;
|
||||
}
|
||||
|
||||
let existSignupButton = false;
|
||||
application.signupItems?.map(item => {
|
||||
item.name === "Signup button" ? existSignupButton = true : null;
|
||||
});
|
||||
if (!existSignupButton) {
|
||||
application.signupItems?.push({
|
||||
customCss: "",
|
||||
label: "",
|
||||
name: "Signup button",
|
||||
placeholder: "",
|
||||
visible: true,
|
||||
});
|
||||
}
|
||||
|
||||
if (application.signupHtml !== "") {
|
||||
return (
|
||||
<div dangerouslySetInnerHTML={{__html: application.signupHtml}} />
|
||||
|
@ -13,11 +13,14 @@
|
||||
// limitations under the License.
|
||||
|
||||
import {Select} from "antd";
|
||||
import i18next from "i18next";
|
||||
import * as Setting from "../../Setting";
|
||||
import React from "react";
|
||||
|
||||
const {Option} = Select;
|
||||
|
||||
export const CountryCodeSelect = (props) => {
|
||||
const {onChange, style, disabled, initValue} = props;
|
||||
const {onChange, style, disabled, initValue, mode} = props;
|
||||
const countryCodes = props.countryCodes ?? [];
|
||||
const [value, setValue] = React.useState("");
|
||||
|
||||
@ -42,11 +45,19 @@ export const CountryCodeSelect = (props) => {
|
||||
style={style}
|
||||
disabled={disabled}
|
||||
value={value}
|
||||
mode={mode}
|
||||
dropdownMatchSelectWidth={false}
|
||||
optionLabelProp={"label"}
|
||||
onChange={handleOnChange}
|
||||
filterOption={(input, option) => (option?.text ?? "").toLowerCase().includes(input.toLowerCase())}
|
||||
>
|
||||
{
|
||||
props.hasDefault ? (<Option key={"All"} value={"All"} label={i18next.t("organization:All")} text={"organization:All"} >
|
||||
<div style={{display: "flex", justifyContent: "space-between", marginRight: "10px"}}>
|
||||
{i18next.t("organization:All")}
|
||||
</div>
|
||||
</Option>) : null
|
||||
}
|
||||
{
|
||||
Setting.getCountryCodeData(countryCodes).map((country) => Setting.getCountryCodeOption(country))
|
||||
}
|
||||
|
@ -80,6 +80,7 @@
|
||||
"Only signup": "Only signup",
|
||||
"Org choice mode": "Org choice mode",
|
||||
"Org choice mode - Tooltip": "Org choice mode - Tooltip",
|
||||
"Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"": "Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"",
|
||||
"Please input your application!": "Please input your application!",
|
||||
"Please input your organization!": "Please input your organization!",
|
||||
"Please select a HTML file": "Please select a HTML file",
|
||||
@ -229,6 +230,7 @@
|
||||
"Email": "Email",
|
||||
"Email - Tooltip": "Valid email address",
|
||||
"Email only": "Email only",
|
||||
"Email or Phone": "Email or Phone",
|
||||
"Enable": "Enable",
|
||||
"Enable dark logo": "Enable dark logo",
|
||||
"Enable dark logo - Tooltip": "Enable dark logo",
|
||||
@ -311,6 +313,7 @@
|
||||
"Phone": "Phone",
|
||||
"Phone - Tooltip": "Phone number",
|
||||
"Phone only": "Phone only",
|
||||
"Phone or Email": "Phone or Email",
|
||||
"Plan": "Plan",
|
||||
"Plan - Tooltip": "Plan - Tooltip",
|
||||
"Plans": "Plans",
|
||||
@ -391,6 +394,7 @@
|
||||
"User type": "User type",
|
||||
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
|
||||
"Users": "Users",
|
||||
"Users - Tooltip": "Users - Tooltip",
|
||||
"Users under all organizations": "Users under all organizations",
|
||||
"Verifications": "Verifications",
|
||||
"Webhooks": "Webhooks",
|
||||
@ -473,7 +477,6 @@
|
||||
"LDAP username, Email or phone": "LDAP username, Email or phone",
|
||||
"Loading": "Loading",
|
||||
"Logging out...": "Logging out...",
|
||||
"Login button": "Login button",
|
||||
"MetaMask plugin not detected": "MetaMask plugin not detected",
|
||||
"Model loading failure": "Model loading failure",
|
||||
"No account?": "No account?",
|
||||
@ -498,6 +501,7 @@
|
||||
"Sign in with Face ID": "Sign in with Face ID",
|
||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||
"Sign in with {type}": "Sign in with {type}",
|
||||
"Signin button": "Signin button",
|
||||
"Signing in...": "Signing in...",
|
||||
"Successfully logged in with WebAuthn credentials": "Successfully logged in with WebAuthn credentials",
|
||||
"The camera is currently in use by another webpage": "The camera is currently in use by another webpage",
|
||||
@ -941,6 +945,7 @@
|
||||
"Please select your country code!": "Please select your country code!",
|
||||
"Please select your country/region!": "Please select your country/region!",
|
||||
"Regex": "Regex",
|
||||
"Signup button": "Signup button",
|
||||
"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",
|
||||
@ -1162,6 +1167,7 @@
|
||||
"Values": "Values",
|
||||
"Verification code sent": "Verification code sent",
|
||||
"WebAuthn credentials": "WebAuthn credentials",
|
||||
"You have changed the username, please save your change first before modifying the password": "You have changed the username, please save your change first before modifying the password",
|
||||
"input password": "input password"
|
||||
},
|
||||
"verification": {
|
||||
|
@ -80,6 +80,7 @@
|
||||
"Only signup": "Only signup",
|
||||
"Org choice mode": "Org choice mode",
|
||||
"Org choice mode - Tooltip": "Org choice mode - Tooltip",
|
||||
"Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"": "Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"",
|
||||
"Please input your application!": "Bitte geben Sie Ihre Anwendung ein!",
|
||||
"Please input your organization!": "Bitte geben Sie Ihre Organisation ein!",
|
||||
"Please select a HTML file": "Bitte wählen Sie eine HTML-Datei aus",
|
||||
@ -229,6 +230,7 @@
|
||||
"Email": "E-Mail",
|
||||
"Email - Tooltip": "Gültige E-Mail-Adresse",
|
||||
"Email only": "Email only",
|
||||
"Email or Phone": "Email or Phone",
|
||||
"Enable": "Enable",
|
||||
"Enable dark logo": "Enable dark logo",
|
||||
"Enable dark logo - Tooltip": "Enable dark logo",
|
||||
@ -311,6 +313,7 @@
|
||||
"Phone": "Telefon",
|
||||
"Phone - Tooltip": "Telefonnummer",
|
||||
"Phone only": "Phone only",
|
||||
"Phone or Email": "Phone or Email",
|
||||
"Plan": "Plan",
|
||||
"Plan - Tooltip": "Plan - Tooltip",
|
||||
"Plans": "Pläne",
|
||||
@ -391,6 +394,7 @@
|
||||
"User type": "Benutzertyp",
|
||||
"User type - Tooltip": "Tags, denen der Benutzer angehört, standardmäßig auf \"normaler Benutzer\" festgelegt",
|
||||
"Users": "Benutzer",
|
||||
"Users - Tooltip": "Users - Tooltip",
|
||||
"Users under all organizations": "Benutzer unter allen Organisationen",
|
||||
"Verifications": "Verifications",
|
||||
"Webhooks": "Webhooks",
|
||||
@ -473,7 +477,6 @@
|
||||
"LDAP username, Email or phone": "LDAP username, Email or phone",
|
||||
"Loading": "Laden",
|
||||
"Logging out...": "Ausloggen...",
|
||||
"Login button": "Login button",
|
||||
"MetaMask plugin not detected": "MetaMask plugin not detected",
|
||||
"Model loading failure": "Model loading failure",
|
||||
"No account?": "Kein Konto?",
|
||||
@ -498,6 +501,7 @@
|
||||
"Sign in with Face ID": "Sign in with Face ID",
|
||||
"Sign in with WebAuthn": "Melden Sie sich mit WebAuthn an",
|
||||
"Sign in with {type}": "Melden Sie sich mit {type} an",
|
||||
"Signin button": "Signin button",
|
||||
"Signing in...": "Anmelden...",
|
||||
"Successfully logged in with WebAuthn credentials": "Erfolgreich mit WebAuthn-Anmeldeinformationen angemeldet",
|
||||
"The camera is currently in use by another webpage": "The camera is currently in use by another webpage",
|
||||
@ -941,6 +945,7 @@
|
||||
"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",
|
||||
"Signup button": "Signup button",
|
||||
"Terms of Use": "Nutzungsbedingungen",
|
||||
"Terms of Use - Tooltip": "Nutzungsbedingungen, die Benutzer während der Registrierung lesen und akzeptieren müssen",
|
||||
"Text 1": "Text 1",
|
||||
@ -1162,6 +1167,7 @@
|
||||
"Values": "Werte",
|
||||
"Verification code sent": "Bestätigungscode gesendet",
|
||||
"WebAuthn credentials": "WebAuthn-Anmeldeinformationen",
|
||||
"You have changed the username, please save your change first before modifying the password": "You have changed the username, please save your change first before modifying the password",
|
||||
"input password": "Eingabe des Passworts"
|
||||
},
|
||||
"verification": {
|
||||
|
@ -80,6 +80,7 @@
|
||||
"Only signup": "Only signup",
|
||||
"Org choice mode": "Org choice mode",
|
||||
"Org choice mode - Tooltip": "Org choice mode - Tooltip",
|
||||
"Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"": "Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"",
|
||||
"Please input your application!": "Please input your application!",
|
||||
"Please input your organization!": "Please input your organization!",
|
||||
"Please select a HTML file": "Please select a HTML file",
|
||||
@ -229,6 +230,7 @@
|
||||
"Email": "Email",
|
||||
"Email - Tooltip": "Valid email address",
|
||||
"Email only": "Email only",
|
||||
"Email or Phone": "Email or Phone",
|
||||
"Enable": "Enable",
|
||||
"Enable dark logo": "Enable dark logo",
|
||||
"Enable dark logo - Tooltip": "Enable dark logo",
|
||||
@ -311,6 +313,7 @@
|
||||
"Phone": "Phone",
|
||||
"Phone - Tooltip": "Phone number",
|
||||
"Phone only": "Phone only",
|
||||
"Phone or Email": "Phone or Email",
|
||||
"Plan": "Plan",
|
||||
"Plan - Tooltip": "Plan - Tooltip",
|
||||
"Plans": "Plans",
|
||||
@ -391,6 +394,7 @@
|
||||
"User type": "User type",
|
||||
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
|
||||
"Users": "Users",
|
||||
"Users - Tooltip": "Users - Tooltip",
|
||||
"Users under all organizations": "Users under all organizations",
|
||||
"Verifications": "Verifications",
|
||||
"Webhooks": "Webhooks",
|
||||
@ -473,7 +477,6 @@
|
||||
"LDAP username, Email or phone": "LDAP username, Email or phone",
|
||||
"Loading": "Loading",
|
||||
"Logging out...": "Logging out...",
|
||||
"Login button": "Login button",
|
||||
"MetaMask plugin not detected": "MetaMask plugin not detected",
|
||||
"Model loading failure": "Model loading failure",
|
||||
"No account?": "No account?",
|
||||
@ -498,6 +501,7 @@
|
||||
"Sign in with Face ID": "Sign in with Face ID",
|
||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||
"Sign in with {type}": "Sign in with {type}",
|
||||
"Signin button": "Signin button",
|
||||
"Signing in...": "Signing in...",
|
||||
"Successfully logged in with WebAuthn credentials": "Successfully logged in with WebAuthn credentials",
|
||||
"The camera is currently in use by another webpage": "The camera is currently in use by another webpage",
|
||||
@ -941,6 +945,7 @@
|
||||
"Please select your country code!": "Please select your country code!",
|
||||
"Please select your country/region!": "Please select your country/region!",
|
||||
"Regex": "Regex",
|
||||
"Signup button": "Signup button",
|
||||
"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",
|
||||
@ -1162,6 +1167,7 @@
|
||||
"Values": "Values",
|
||||
"Verification code sent": "Verification code sent",
|
||||
"WebAuthn credentials": "WebAuthn credentials",
|
||||
"You have changed the username, please save your change first before modifying the password": "You have changed the username, please save your change first before modifying the password",
|
||||
"input password": "input password"
|
||||
},
|
||||
"verification": {
|
||||
|
@ -80,6 +80,7 @@
|
||||
"Only signup": "Only signup",
|
||||
"Org choice mode": "Org choice mode",
|
||||
"Org choice mode - Tooltip": "Org choice mode - Tooltip",
|
||||
"Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"": "Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"",
|
||||
"Please input your application!": "¡Por favor, ingrese su solicitud!",
|
||||
"Please input your organization!": "¡Por favor, ingrese su organización!",
|
||||
"Please select a HTML file": "Por favor, seleccione un archivo HTML",
|
||||
@ -229,6 +230,7 @@
|
||||
"Email": "Correo electrónico",
|
||||
"Email - Tooltip": "Dirección de correo electrónico válida",
|
||||
"Email only": "Email only",
|
||||
"Email or Phone": "Email or Phone",
|
||||
"Enable": "Enable",
|
||||
"Enable dark logo": "Enable dark logo",
|
||||
"Enable dark logo - Tooltip": "Enable dark logo",
|
||||
@ -311,6 +313,7 @@
|
||||
"Phone": "Teléfono",
|
||||
"Phone - Tooltip": "Número de teléfono",
|
||||
"Phone only": "Phone only",
|
||||
"Phone or Email": "Phone or Email",
|
||||
"Plan": "Plan",
|
||||
"Plan - Tooltip": "Plan - Tooltip",
|
||||
"Plans": "Planes",
|
||||
@ -391,6 +394,7 @@
|
||||
"User type": "Tipo de usuario",
|
||||
"User type - Tooltip": "Etiquetas a las que el usuario pertenece, con una configuración predeterminada en \"usuario-normal\"",
|
||||
"Users": "Usuarios",
|
||||
"Users - Tooltip": "Users - Tooltip",
|
||||
"Users under all organizations": "Usuarios bajo todas las organizaciones",
|
||||
"Verifications": "Verifications",
|
||||
"Webhooks": "Webhooks",
|
||||
@ -473,7 +477,6 @@
|
||||
"LDAP username, Email or phone": "LDAP username, Email or phone",
|
||||
"Loading": "Cargando",
|
||||
"Logging out...": "Cerrando sesión...",
|
||||
"Login button": "Login button",
|
||||
"MetaMask plugin not detected": "MetaMask plugin not detected",
|
||||
"Model loading failure": "Model loading failure",
|
||||
"No account?": "¿No tienes cuenta?",
|
||||
@ -498,6 +501,7 @@
|
||||
"Sign in with Face ID": "Sign in with Face ID",
|
||||
"Sign in with WebAuthn": "Iniciar sesión con WebAuthn",
|
||||
"Sign in with {type}": "Inicia sesión con {tipo}",
|
||||
"Signin button": "Signin button",
|
||||
"Signing in...": "Iniciando sesión...",
|
||||
"Successfully logged in with WebAuthn credentials": "Inició sesión correctamente con las credenciales de WebAuthn",
|
||||
"The camera is currently in use by another webpage": "The camera is currently in use by another webpage",
|
||||
@ -941,6 +945,7 @@
|
||||
"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",
|
||||
"Signup button": "Signup button",
|
||||
"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",
|
||||
@ -1162,6 +1167,7 @@
|
||||
"Values": "Valores",
|
||||
"Verification code sent": "Código de verificación enviado",
|
||||
"WebAuthn credentials": "Credenciales de WebAuthn",
|
||||
"You have changed the username, please save your change first before modifying the password": "You have changed the username, please save your change first before modifying the password",
|
||||
"input password": "Ingresar contraseña"
|
||||
},
|
||||
"verification": {
|
||||
|
@ -80,6 +80,7 @@
|
||||
"Only signup": "Only signup",
|
||||
"Org choice mode": "Org choice mode",
|
||||
"Org choice mode - Tooltip": "Org choice mode - Tooltip",
|
||||
"Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"": "Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"",
|
||||
"Please input your application!": "Please input your application!",
|
||||
"Please input your organization!": "Please input your organization!",
|
||||
"Please select a HTML file": "Please select a HTML file",
|
||||
@ -229,6 +230,7 @@
|
||||
"Email": "Email",
|
||||
"Email - Tooltip": "Valid email address",
|
||||
"Email only": "Email only",
|
||||
"Email or Phone": "Email or Phone",
|
||||
"Enable": "Enable",
|
||||
"Enable dark logo": "Enable dark logo",
|
||||
"Enable dark logo - Tooltip": "Enable dark logo",
|
||||
@ -311,6 +313,7 @@
|
||||
"Phone": "Phone",
|
||||
"Phone - Tooltip": "Phone number",
|
||||
"Phone only": "Phone only",
|
||||
"Phone or Email": "Phone or Email",
|
||||
"Plan": "Plan",
|
||||
"Plan - Tooltip": "Plan - Tooltip",
|
||||
"Plans": "Plans",
|
||||
@ -391,6 +394,7 @@
|
||||
"User type": "User type",
|
||||
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
|
||||
"Users": "Users",
|
||||
"Users - Tooltip": "Users - Tooltip",
|
||||
"Users under all organizations": "Users under all organizations",
|
||||
"Verifications": "Verifications",
|
||||
"Webhooks": "Webhooks",
|
||||
@ -473,7 +477,6 @@
|
||||
"LDAP username, Email or phone": "LDAP username, Email or phone",
|
||||
"Loading": "Loading",
|
||||
"Logging out...": "Logging out...",
|
||||
"Login button": "Login button",
|
||||
"MetaMask plugin not detected": "MetaMask plugin not detected",
|
||||
"Model loading failure": "Model loading failure",
|
||||
"No account?": "No account?",
|
||||
@ -498,6 +501,7 @@
|
||||
"Sign in with Face ID": "Sign in with Face ID",
|
||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||
"Sign in with {type}": "Sign in with {type}",
|
||||
"Signin button": "Signin button",
|
||||
"Signing in...": "Signing in...",
|
||||
"Successfully logged in with WebAuthn credentials": "Successfully logged in with WebAuthn credentials",
|
||||
"The camera is currently in use by another webpage": "The camera is currently in use by another webpage",
|
||||
@ -941,6 +945,7 @@
|
||||
"Please select your country code!": "Please select your country code!",
|
||||
"Please select your country/region!": "Please select your country/region!",
|
||||
"Regex": "Regex",
|
||||
"Signup button": "Signup button",
|
||||
"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",
|
||||
@ -1162,6 +1167,7 @@
|
||||
"Values": "Values",
|
||||
"Verification code sent": "Verification code sent",
|
||||
"WebAuthn credentials": "WebAuthn credentials",
|
||||
"You have changed the username, please save your change first before modifying the password": "You have changed the username, please save your change first before modifying the password",
|
||||
"input password": "input password"
|
||||
},
|
||||
"verification": {
|
||||
|
@ -80,6 +80,7 @@
|
||||
"Only signup": "Only signup",
|
||||
"Org choice mode": "Org choice mode",
|
||||
"Org choice mode - Tooltip": "Org choice mode - Tooltip",
|
||||
"Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"": "Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"",
|
||||
"Please input your application!": "Please input your application!",
|
||||
"Please input your organization!": "Please input your organization!",
|
||||
"Please select a HTML file": "Please select a HTML file",
|
||||
@ -229,6 +230,7 @@
|
||||
"Email": "Email",
|
||||
"Email - Tooltip": "Valid email address",
|
||||
"Email only": "Email only",
|
||||
"Email or Phone": "Email or Phone",
|
||||
"Enable": "Enable",
|
||||
"Enable dark logo": "Enable dark logo",
|
||||
"Enable dark logo - Tooltip": "Enable dark logo",
|
||||
@ -311,6 +313,7 @@
|
||||
"Phone": "Phone",
|
||||
"Phone - Tooltip": "Phone number",
|
||||
"Phone only": "Phone only",
|
||||
"Phone or Email": "Phone or Email",
|
||||
"Plan": "Plan",
|
||||
"Plan - Tooltip": "Plan - Tooltip",
|
||||
"Plans": "Plans",
|
||||
@ -391,6 +394,7 @@
|
||||
"User type": "User type",
|
||||
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
|
||||
"Users": "Users",
|
||||
"Users - Tooltip": "Users - Tooltip",
|
||||
"Users under all organizations": "Users under all organizations",
|
||||
"Verifications": "Verifications",
|
||||
"Webhooks": "Webhooks",
|
||||
@ -473,7 +477,6 @@
|
||||
"LDAP username, Email or phone": "LDAP username, Email or phone",
|
||||
"Loading": "Loading",
|
||||
"Logging out...": "Logging out...",
|
||||
"Login button": "Login button",
|
||||
"MetaMask plugin not detected": "MetaMask plugin not detected",
|
||||
"Model loading failure": "Model loading failure",
|
||||
"No account?": "No account?",
|
||||
@ -498,6 +501,7 @@
|
||||
"Sign in with Face ID": "Sign in with Face ID",
|
||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||
"Sign in with {type}": "Sign in with {type}",
|
||||
"Signin button": "Signin button",
|
||||
"Signing in...": "Signing in...",
|
||||
"Successfully logged in with WebAuthn credentials": "Successfully logged in with WebAuthn credentials",
|
||||
"The camera is currently in use by another webpage": "The camera is currently in use by another webpage",
|
||||
@ -941,6 +945,7 @@
|
||||
"Please select your country code!": "Please select your country code!",
|
||||
"Please select your country/region!": "Please select your country/region!",
|
||||
"Regex": "Regex",
|
||||
"Signup button": "Signup button",
|
||||
"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",
|
||||
@ -1162,6 +1167,7 @@
|
||||
"Values": "Values",
|
||||
"Verification code sent": "Verification code sent",
|
||||
"WebAuthn credentials": "WebAuthn credentials",
|
||||
"You have changed the username, please save your change first before modifying the password": "You have changed the username, please save your change first before modifying the password",
|
||||
"input password": "input password"
|
||||
},
|
||||
"verification": {
|
||||
|
@ -80,6 +80,7 @@
|
||||
"Only signup": "Inscription uniquement",
|
||||
"Org choice mode": "Choix du mode de l'organisation",
|
||||
"Org choice mode - Tooltip": "Choix du mode de l'organisation - Info-bulle",
|
||||
"Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"": "Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"",
|
||||
"Please input your application!": "Veuillez saisir votre application !",
|
||||
"Please input your organization!": "Veuillez saisir votre organisation !",
|
||||
"Please select a HTML file": "Veuillez sélectionner un fichier HTML",
|
||||
@ -229,6 +230,7 @@
|
||||
"Email": "E-mail",
|
||||
"Email - Tooltip": "Adresse e-mail valide",
|
||||
"Email only": "Email only",
|
||||
"Email or Phone": "Email or Phone",
|
||||
"Enable": "Activer",
|
||||
"Enable dark logo": "Enable dark logo",
|
||||
"Enable dark logo - Tooltip": "Enable dark logo",
|
||||
@ -311,6 +313,7 @@
|
||||
"Phone": "Téléphone",
|
||||
"Phone - Tooltip": "Numéro de téléphone",
|
||||
"Phone only": "Phone only",
|
||||
"Phone or Email": "Phone or Email",
|
||||
"Plan": "Offre",
|
||||
"Plan - Tooltip": "Offre - Infobulle",
|
||||
"Plans": "Offres",
|
||||
@ -391,6 +394,7 @@
|
||||
"User type": "Type de compte",
|
||||
"User type - Tooltip": "Étiquettes associées au compte, avec une valeur par défaut \"normal-user\"",
|
||||
"Users": "Comptes",
|
||||
"Users - Tooltip": "Users - Tooltip",
|
||||
"Users under all organizations": "Comptes sous toutes les organisations",
|
||||
"Verifications": "Verifications",
|
||||
"Webhooks": "Crochets web",
|
||||
@ -473,7 +477,6 @@
|
||||
"LDAP username, Email or phone": "LDAP username, Email or phone",
|
||||
"Loading": "Chargement",
|
||||
"Logging out...": "Déconnexion...",
|
||||
"Login button": "Login button",
|
||||
"MetaMask plugin not detected": "Le plugin MetaMask n'a pas été détecté",
|
||||
"Model loading failure": "Model loading failure",
|
||||
"No account?": "Pas de compte ?",
|
||||
@ -498,6 +501,7 @@
|
||||
"Sign in with Face ID": "Sign in with Face ID",
|
||||
"Sign in with WebAuthn": "Connectez-vous avec WebAuthn",
|
||||
"Sign in with {type}": "Connectez-vous avec {type}",
|
||||
"Signin button": "Signin button",
|
||||
"Signing in...": "Connexion en cours...",
|
||||
"Successfully logged in with WebAuthn credentials": "Connexion avec les identifiants WebAuthn réussie",
|
||||
"The camera is currently in use by another webpage": "The camera is currently in use by another webpage",
|
||||
@ -941,6 +945,7 @@
|
||||
"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",
|
||||
"Signup button": "Signup button",
|
||||
"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",
|
||||
@ -1162,6 +1167,7 @@
|
||||
"Values": "Valeurs",
|
||||
"Verification code sent": "Code de vérification envoyé",
|
||||
"WebAuthn credentials": "Identifiants WebAuthn",
|
||||
"You have changed the username, please save your change first before modifying the password": "You have changed the username, please save your change first before modifying the password",
|
||||
"input password": "saisir le mot de passe"
|
||||
},
|
||||
"verification": {
|
||||
|
@ -80,6 +80,7 @@
|
||||
"Only signup": "Only signup",
|
||||
"Org choice mode": "Org choice mode",
|
||||
"Org choice mode - Tooltip": "Org choice mode - Tooltip",
|
||||
"Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"": "Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"",
|
||||
"Please input your application!": "Please input your application!",
|
||||
"Please input your organization!": "Please input your organization!",
|
||||
"Please select a HTML file": "Please select a HTML file",
|
||||
@ -229,6 +230,7 @@
|
||||
"Email": "Email",
|
||||
"Email - Tooltip": "Valid email address",
|
||||
"Email only": "Email only",
|
||||
"Email or Phone": "Email or Phone",
|
||||
"Enable": "Enable",
|
||||
"Enable dark logo": "Enable dark logo",
|
||||
"Enable dark logo - Tooltip": "Enable dark logo",
|
||||
@ -311,6 +313,7 @@
|
||||
"Phone": "Phone",
|
||||
"Phone - Tooltip": "Phone number",
|
||||
"Phone only": "Phone only",
|
||||
"Phone or Email": "Phone or Email",
|
||||
"Plan": "Plan",
|
||||
"Plan - Tooltip": "Plan - Tooltip",
|
||||
"Plans": "Plans",
|
||||
@ -391,6 +394,7 @@
|
||||
"User type": "User type",
|
||||
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
|
||||
"Users": "Users",
|
||||
"Users - Tooltip": "Users - Tooltip",
|
||||
"Users under all organizations": "Users under all organizations",
|
||||
"Verifications": "Verifications",
|
||||
"Webhooks": "Webhooks",
|
||||
@ -473,7 +477,6 @@
|
||||
"LDAP username, Email or phone": "LDAP username, Email or phone",
|
||||
"Loading": "Loading",
|
||||
"Logging out...": "Logging out...",
|
||||
"Login button": "Login button",
|
||||
"MetaMask plugin not detected": "MetaMask plugin not detected",
|
||||
"Model loading failure": "Model loading failure",
|
||||
"No account?": "No account?",
|
||||
@ -498,6 +501,7 @@
|
||||
"Sign in with Face ID": "Sign in with Face ID",
|
||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||
"Sign in with {type}": "Sign in with {type}",
|
||||
"Signin button": "Signin button",
|
||||
"Signing in...": "Signing in...",
|
||||
"Successfully logged in with WebAuthn credentials": "Successfully logged in with WebAuthn credentials",
|
||||
"The camera is currently in use by another webpage": "The camera is currently in use by another webpage",
|
||||
@ -941,6 +945,7 @@
|
||||
"Please select your country code!": "Please select your country code!",
|
||||
"Please select your country/region!": "Please select your country/region!",
|
||||
"Regex": "Regex",
|
||||
"Signup button": "Signup button",
|
||||
"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",
|
||||
@ -1162,6 +1167,7 @@
|
||||
"Values": "Values",
|
||||
"Verification code sent": "Verification code sent",
|
||||
"WebAuthn credentials": "WebAuthn credentials",
|
||||
"You have changed the username, please save your change first before modifying the password": "You have changed the username, please save your change first before modifying the password",
|
||||
"input password": "input password"
|
||||
},
|
||||
"verification": {
|
||||
|
@ -80,6 +80,7 @@
|
||||
"Only signup": "Only signup",
|
||||
"Org choice mode": "Org choice mode",
|
||||
"Org choice mode - Tooltip": "Org choice mode - Tooltip",
|
||||
"Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"": "Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"",
|
||||
"Please input your application!": "Silakan masukkan aplikasi Anda!",
|
||||
"Please input your organization!": "Silakan masukkan organisasi Anda!",
|
||||
"Please select a HTML file": "Silahkan pilih file HTML",
|
||||
@ -229,6 +230,7 @@
|
||||
"Email": "Email",
|
||||
"Email - Tooltip": "Alamat email yang valid",
|
||||
"Email only": "Email only",
|
||||
"Email or Phone": "Email or Phone",
|
||||
"Enable": "Enable",
|
||||
"Enable dark logo": "Enable dark logo",
|
||||
"Enable dark logo - Tooltip": "Enable dark logo",
|
||||
@ -311,6 +313,7 @@
|
||||
"Phone": "Telepon",
|
||||
"Phone - Tooltip": "Nomor telepon",
|
||||
"Phone only": "Phone only",
|
||||
"Phone or Email": "Phone or Email",
|
||||
"Plan": "Plan",
|
||||
"Plan - Tooltip": "Plan - Tooltip",
|
||||
"Plans": "Rencana",
|
||||
@ -391,6 +394,7 @@
|
||||
"User type": "Jenis pengguna",
|
||||
"User type - Tooltip": "Tag yang dimiliki oleh pengguna, defaultnya adalah \"normal-user\"",
|
||||
"Users": "Pengguna-pengguna",
|
||||
"Users - Tooltip": "Users - Tooltip",
|
||||
"Users under all organizations": "Pengguna di bawah semua organisasi",
|
||||
"Verifications": "Verifications",
|
||||
"Webhooks": "Webhooks",
|
||||
@ -473,7 +477,6 @@
|
||||
"LDAP username, Email or phone": "LDAP username, Email or phone",
|
||||
"Loading": "Memuat",
|
||||
"Logging out...": "Keluar...",
|
||||
"Login button": "Login button",
|
||||
"MetaMask plugin not detected": "MetaMask plugin not detected",
|
||||
"Model loading failure": "Model loading failure",
|
||||
"No account?": "Tidak memiliki akun?",
|
||||
@ -498,6 +501,7 @@
|
||||
"Sign in with Face ID": "Sign in with Face ID",
|
||||
"Sign in with WebAuthn": "Masuk dengan WebAuthn",
|
||||
"Sign in with {type}": "Masuk dengan {type}",
|
||||
"Signin button": "Signin button",
|
||||
"Signing in...": "Masuk...",
|
||||
"Successfully logged in with WebAuthn credentials": "Berhasil masuk dengan kredensial WebAuthn",
|
||||
"The camera is currently in use by another webpage": "The camera is currently in use by another webpage",
|
||||
@ -941,6 +945,7 @@
|
||||
"Please select your country code!": "Tolong pilih kode negara Anda!",
|
||||
"Please select your country/region!": "Silakan pilih negara/region Anda!",
|
||||
"Regex": "Regex",
|
||||
"Signup button": "Signup button",
|
||||
"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",
|
||||
@ -1162,6 +1167,7 @@
|
||||
"Values": "Nilai-nilai",
|
||||
"Verification code sent": "Kode verifikasi telah dikirim",
|
||||
"WebAuthn credentials": "Kredensial WebAuthn",
|
||||
"You have changed the username, please save your change first before modifying the password": "You have changed the username, please save your change first before modifying the password",
|
||||
"input password": "masukkan kata sandi"
|
||||
},
|
||||
"verification": {
|
||||
|
@ -80,6 +80,7 @@
|
||||
"Only signup": "Only signup",
|
||||
"Org choice mode": "Org choice mode",
|
||||
"Org choice mode - Tooltip": "Org choice mode - Tooltip",
|
||||
"Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"": "Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"",
|
||||
"Please input your application!": "Please input your application!",
|
||||
"Please input your organization!": "Please input your organization!",
|
||||
"Please select a HTML file": "Please select a HTML file",
|
||||
@ -229,6 +230,7 @@
|
||||
"Email": "Email",
|
||||
"Email - Tooltip": "Valid email address",
|
||||
"Email only": "Email only",
|
||||
"Email or Phone": "Email or Phone",
|
||||
"Enable": "Enable",
|
||||
"Enable dark logo": "Enable dark logo",
|
||||
"Enable dark logo - Tooltip": "Enable dark logo",
|
||||
@ -311,6 +313,7 @@
|
||||
"Phone": "Phone",
|
||||
"Phone - Tooltip": "Phone number",
|
||||
"Phone only": "Phone only",
|
||||
"Phone or Email": "Phone or Email",
|
||||
"Plan": "Plan",
|
||||
"Plan - Tooltip": "Plan - Tooltip",
|
||||
"Plans": "Plans",
|
||||
@ -391,6 +394,7 @@
|
||||
"User type": "User type",
|
||||
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
|
||||
"Users": "Users",
|
||||
"Users - Tooltip": "Users - Tooltip",
|
||||
"Users under all organizations": "Users under all organizations",
|
||||
"Verifications": "Verifications",
|
||||
"Webhooks": "Webhooks",
|
||||
@ -473,7 +477,6 @@
|
||||
"LDAP username, Email or phone": "LDAP username, Email or phone",
|
||||
"Loading": "Loading",
|
||||
"Logging out...": "Logging out...",
|
||||
"Login button": "Login button",
|
||||
"MetaMask plugin not detected": "MetaMask plugin not detected",
|
||||
"Model loading failure": "Model loading failure",
|
||||
"No account?": "No account?",
|
||||
@ -498,6 +501,7 @@
|
||||
"Sign in with Face ID": "Sign in with Face ID",
|
||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||
"Sign in with {type}": "Sign in with {type}",
|
||||
"Signin button": "Signin button",
|
||||
"Signing in...": "Signing in...",
|
||||
"Successfully logged in with WebAuthn credentials": "Successfully logged in with WebAuthn credentials",
|
||||
"The camera is currently in use by another webpage": "The camera is currently in use by another webpage",
|
||||
@ -941,6 +945,7 @@
|
||||
"Please select your country code!": "Please select your country code!",
|
||||
"Please select your country/region!": "Please select your country/region!",
|
||||
"Regex": "Regex",
|
||||
"Signup button": "Signup button",
|
||||
"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",
|
||||
@ -1162,6 +1167,7 @@
|
||||
"Values": "Values",
|
||||
"Verification code sent": "Verification code sent",
|
||||
"WebAuthn credentials": "WebAuthn credentials",
|
||||
"You have changed the username, please save your change first before modifying the password": "You have changed the username, please save your change first before modifying the password",
|
||||
"input password": "input password"
|
||||
},
|
||||
"verification": {
|
||||
|
@ -80,6 +80,7 @@
|
||||
"Only signup": "Only signup",
|
||||
"Org choice mode": "Org choice mode",
|
||||
"Org choice mode - Tooltip": "Org choice mode - Tooltip",
|
||||
"Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"": "Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"",
|
||||
"Please input your application!": "あなたの申請を入力してください!",
|
||||
"Please input your organization!": "あなたの組織を入力してください!",
|
||||
"Please select a HTML file": "HTMLファイルを選択してください",
|
||||
@ -229,6 +230,7 @@
|
||||
"Email": "電子メール",
|
||||
"Email - Tooltip": "有効な電子メールアドレス",
|
||||
"Email only": "Email only",
|
||||
"Email or Phone": "Email or Phone",
|
||||
"Enable": "Enable",
|
||||
"Enable dark logo": "Enable dark logo",
|
||||
"Enable dark logo - Tooltip": "Enable dark logo",
|
||||
@ -311,6 +313,7 @@
|
||||
"Phone": "電話",
|
||||
"Phone - Tooltip": "電話番号",
|
||||
"Phone only": "Phone only",
|
||||
"Phone or Email": "Phone or Email",
|
||||
"Plan": "Plan",
|
||||
"Plan - Tooltip": "Plan - Tooltip",
|
||||
"Plans": "プラン",
|
||||
@ -391,6 +394,7 @@
|
||||
"User type": "ユーザータイプ",
|
||||
"User type - Tooltip": "ユーザーが属するタグは、デフォルトでは「通常ユーザー」となります",
|
||||
"Users": "ユーザー",
|
||||
"Users - Tooltip": "Users - Tooltip",
|
||||
"Users under all organizations": "すべての組織のユーザー",
|
||||
"Verifications": "Verifications",
|
||||
"Webhooks": "Webhooks",
|
||||
@ -473,7 +477,6 @@
|
||||
"LDAP username, Email or phone": "LDAP username, Email or phone",
|
||||
"Loading": "ローディング",
|
||||
"Logging out...": "ログアウト中...",
|
||||
"Login button": "Login button",
|
||||
"MetaMask plugin not detected": "MetaMask plugin not detected",
|
||||
"Model loading failure": "Model loading failure",
|
||||
"No account?": "アカウントがありませんか?",
|
||||
@ -498,6 +501,7 @@
|
||||
"Sign in with Face ID": "Sign in with Face ID",
|
||||
"Sign in with WebAuthn": "WebAuthnでサインインしてください",
|
||||
"Sign in with {type}": "{type}でサインインしてください",
|
||||
"Signin button": "Signin button",
|
||||
"Signing in...": "サインイン中...",
|
||||
"Successfully logged in with WebAuthn credentials": "WebAuthnの認証情報で正常にログインしました",
|
||||
"The camera is currently in use by another webpage": "The camera is currently in use by another webpage",
|
||||
@ -941,6 +945,7 @@
|
||||
"Please select your country code!": "あなたの国コードを選択してください!",
|
||||
"Please select your country/region!": "あなたの国/地域を選択してください!",
|
||||
"Regex": "Regex",
|
||||
"Signup button": "Signup button",
|
||||
"Terms of Use": "利用規約",
|
||||
"Terms of Use - Tooltip": "ユーザーが登録する際に読んで同意する必要がある利用規約",
|
||||
"Text 1": "Text 1",
|
||||
@ -1162,6 +1167,7 @@
|
||||
"Values": "価値観",
|
||||
"Verification code sent": "確認コードを送信しました",
|
||||
"WebAuthn credentials": "WebAuthnの資格情報",
|
||||
"You have changed the username, please save your change first before modifying the password": "You have changed the username, please save your change first before modifying the password",
|
||||
"input password": "パスワードを入力してください"
|
||||
},
|
||||
"verification": {
|
||||
|
@ -80,6 +80,7 @@
|
||||
"Only signup": "Only signup",
|
||||
"Org choice mode": "Org choice mode",
|
||||
"Org choice mode - Tooltip": "Org choice mode - Tooltip",
|
||||
"Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"": "Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"",
|
||||
"Please input your application!": "Please input your application!",
|
||||
"Please input your organization!": "Please input your organization!",
|
||||
"Please select a HTML file": "Please select a HTML file",
|
||||
@ -229,6 +230,7 @@
|
||||
"Email": "Email",
|
||||
"Email - Tooltip": "Valid email address",
|
||||
"Email only": "Email only",
|
||||
"Email or Phone": "Email or Phone",
|
||||
"Enable": "Enable",
|
||||
"Enable dark logo": "Enable dark logo",
|
||||
"Enable dark logo - Tooltip": "Enable dark logo",
|
||||
@ -311,6 +313,7 @@
|
||||
"Phone": "Phone",
|
||||
"Phone - Tooltip": "Phone number",
|
||||
"Phone only": "Phone only",
|
||||
"Phone or Email": "Phone or Email",
|
||||
"Plan": "Plan",
|
||||
"Plan - Tooltip": "Plan - Tooltip",
|
||||
"Plans": "Plans",
|
||||
@ -391,6 +394,7 @@
|
||||
"User type": "User type",
|
||||
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
|
||||
"Users": "Users",
|
||||
"Users - Tooltip": "Users - Tooltip",
|
||||
"Users under all organizations": "Users under all organizations",
|
||||
"Verifications": "Verifications",
|
||||
"Webhooks": "Webhooks",
|
||||
@ -473,7 +477,6 @@
|
||||
"LDAP username, Email or phone": "LDAP username, Email or phone",
|
||||
"Loading": "Loading",
|
||||
"Logging out...": "Logging out...",
|
||||
"Login button": "Login button",
|
||||
"MetaMask plugin not detected": "MetaMask plugin not detected",
|
||||
"Model loading failure": "Model loading failure",
|
||||
"No account?": "No account?",
|
||||
@ -498,6 +501,7 @@
|
||||
"Sign in with Face ID": "Sign in with Face ID",
|
||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||
"Sign in with {type}": "Sign in with {type}",
|
||||
"Signin button": "Signin button",
|
||||
"Signing in...": "Signing in...",
|
||||
"Successfully logged in with WebAuthn credentials": "Successfully logged in with WebAuthn credentials",
|
||||
"The camera is currently in use by another webpage": "The camera is currently in use by another webpage",
|
||||
@ -941,6 +945,7 @@
|
||||
"Please select your country code!": "Please select your country code!",
|
||||
"Please select your country/region!": "Please select your country/region!",
|
||||
"Regex": "Regex",
|
||||
"Signup button": "Signup button",
|
||||
"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",
|
||||
@ -1162,6 +1167,7 @@
|
||||
"Values": "Values",
|
||||
"Verification code sent": "Verification code sent",
|
||||
"WebAuthn credentials": "WebAuthn credentials",
|
||||
"You have changed the username, please save your change first before modifying the password": "You have changed the username, please save your change first before modifying the password",
|
||||
"input password": "input password"
|
||||
},
|
||||
"verification": {
|
||||
|
@ -80,6 +80,7 @@
|
||||
"Only signup": "Only signup",
|
||||
"Org choice mode": "Org choice mode",
|
||||
"Org choice mode - Tooltip": "Org choice mode - Tooltip",
|
||||
"Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"": "Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"",
|
||||
"Please input your application!": "당신의 신청서를 입력해주세요!",
|
||||
"Please input your organization!": "귀하의 조직을 입력해 주세요!",
|
||||
"Please select a HTML file": "HTML 파일을 선택해 주세요",
|
||||
@ -229,6 +230,7 @@
|
||||
"Email": "이메일",
|
||||
"Email - Tooltip": "유효한 이메일 주소",
|
||||
"Email only": "Email only",
|
||||
"Email or Phone": "Email or Phone",
|
||||
"Enable": "Enable",
|
||||
"Enable dark logo": "Enable dark logo",
|
||||
"Enable dark logo - Tooltip": "Enable dark logo",
|
||||
@ -311,6 +313,7 @@
|
||||
"Phone": "전화기",
|
||||
"Phone - Tooltip": "전화 번호",
|
||||
"Phone only": "Phone only",
|
||||
"Phone or Email": "Phone or Email",
|
||||
"Plan": "Plan",
|
||||
"Plan - Tooltip": "Plan - Tooltip",
|
||||
"Plans": "플랜",
|
||||
@ -391,6 +394,7 @@
|
||||
"User type": "사용자 유형",
|
||||
"User type - Tooltip": "사용자가 속한 태그는 기본적으로 \"보통 사용자\"로 설정됩니다",
|
||||
"Users": "사용자",
|
||||
"Users - Tooltip": "Users - Tooltip",
|
||||
"Users under all organizations": "모든 조직의 사용자",
|
||||
"Verifications": "Verifications",
|
||||
"Webhooks": "Webhooks",
|
||||
@ -473,7 +477,6 @@
|
||||
"LDAP username, Email or phone": "LDAP username, Email or phone",
|
||||
"Loading": "로딩 중입니다",
|
||||
"Logging out...": "로그아웃 중...",
|
||||
"Login button": "Login button",
|
||||
"MetaMask plugin not detected": "MetaMask plugin not detected",
|
||||
"Model loading failure": "Model loading failure",
|
||||
"No account?": "계정이 없나요?",
|
||||
@ -498,6 +501,7 @@
|
||||
"Sign in with Face ID": "Sign in with Face ID",
|
||||
"Sign in with WebAuthn": "WebAuthn으로 로그인하세요",
|
||||
"Sign in with {type}": "{type}로 로그인하세요",
|
||||
"Signin button": "Signin button",
|
||||
"Signing in...": "로그인 중...",
|
||||
"Successfully logged in with WebAuthn credentials": "WebAuthn 자격 증명으로 로그인 성공적으로 수행했습니다",
|
||||
"The camera is currently in use by another webpage": "The camera is currently in use by another webpage",
|
||||
@ -941,6 +945,7 @@
|
||||
"Please select your country code!": "국가 코드를 선택해 주세요!",
|
||||
"Please select your country/region!": "국가 / 지역을 선택해주세요!",
|
||||
"Regex": "Regex",
|
||||
"Signup button": "Signup button",
|
||||
"Terms of Use": "사용 약관",
|
||||
"Terms of Use - Tooltip": "등록 중 사용자가 읽어야 하고 동의해야하는 이용 약관",
|
||||
"Text 1": "Text 1",
|
||||
@ -1162,6 +1167,7 @@
|
||||
"Values": "가치들",
|
||||
"Verification code sent": "인증 코드가 전송되었습니다",
|
||||
"WebAuthn credentials": "웹 인증 자격증명",
|
||||
"You have changed the username, please save your change first before modifying the password": "You have changed the username, please save your change first before modifying the password",
|
||||
"input password": "비밀번호를 입력해주세요"
|
||||
},
|
||||
"verification": {
|
||||
|
@ -80,6 +80,7 @@
|
||||
"Only signup": "Only signup",
|
||||
"Org choice mode": "Org choice mode",
|
||||
"Org choice mode - Tooltip": "Org choice mode - Tooltip",
|
||||
"Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"": "Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"",
|
||||
"Please input your application!": "Please input your application!",
|
||||
"Please input your organization!": "Please input your organization!",
|
||||
"Please select a HTML file": "Please select a HTML file",
|
||||
@ -229,6 +230,7 @@
|
||||
"Email": "Email",
|
||||
"Email - Tooltip": "Valid email address",
|
||||
"Email only": "Email only",
|
||||
"Email or Phone": "Email or Phone",
|
||||
"Enable": "Enable",
|
||||
"Enable dark logo": "Enable dark logo",
|
||||
"Enable dark logo - Tooltip": "Enable dark logo",
|
||||
@ -311,6 +313,7 @@
|
||||
"Phone": "Phone",
|
||||
"Phone - Tooltip": "Phone number",
|
||||
"Phone only": "Phone only",
|
||||
"Phone or Email": "Phone or Email",
|
||||
"Plan": "Plan",
|
||||
"Plan - Tooltip": "Plan - Tooltip",
|
||||
"Plans": "Plans",
|
||||
@ -391,6 +394,7 @@
|
||||
"User type": "User type",
|
||||
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
|
||||
"Users": "Users",
|
||||
"Users - Tooltip": "Users - Tooltip",
|
||||
"Users under all organizations": "Users under all organizations",
|
||||
"Verifications": "Verifications",
|
||||
"Webhooks": "Webhooks",
|
||||
@ -473,7 +477,6 @@
|
||||
"LDAP username, Email or phone": "LDAP username, Email or phone",
|
||||
"Loading": "Loading",
|
||||
"Logging out...": "Logging out...",
|
||||
"Login button": "Login button",
|
||||
"MetaMask plugin not detected": "MetaMask plugin not detected",
|
||||
"Model loading failure": "Model loading failure",
|
||||
"No account?": "No account?",
|
||||
@ -498,6 +501,7 @@
|
||||
"Sign in with Face ID": "Sign in with Face ID",
|
||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||
"Sign in with {type}": "Sign in with {type}",
|
||||
"Signin button": "Signin button",
|
||||
"Signing in...": "Signing in...",
|
||||
"Successfully logged in with WebAuthn credentials": "Successfully logged in with WebAuthn credentials",
|
||||
"The camera is currently in use by another webpage": "The camera is currently in use by another webpage",
|
||||
@ -941,6 +945,7 @@
|
||||
"Please select your country code!": "Please select your country code!",
|
||||
"Please select your country/region!": "Please select your country/region!",
|
||||
"Regex": "Regex",
|
||||
"Signup button": "Signup button",
|
||||
"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",
|
||||
@ -1162,6 +1167,7 @@
|
||||
"Values": "Values",
|
||||
"Verification code sent": "Verification code sent",
|
||||
"WebAuthn credentials": "WebAuthn credentials",
|
||||
"You have changed the username, please save your change first before modifying the password": "You have changed the username, please save your change first before modifying the password",
|
||||
"input password": "input password"
|
||||
},
|
||||
"verification": {
|
||||
|
@ -80,6 +80,7 @@
|
||||
"Only signup": "Only signup",
|
||||
"Org choice mode": "Org choice mode",
|
||||
"Org choice mode - Tooltip": "Org choice mode - Tooltip",
|
||||
"Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"": "Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"",
|
||||
"Please input your application!": "Please input your application!",
|
||||
"Please input your organization!": "Please input your organization!",
|
||||
"Please select a HTML file": "Please select a HTML file",
|
||||
@ -229,6 +230,7 @@
|
||||
"Email": "Email",
|
||||
"Email - Tooltip": "Valid email address",
|
||||
"Email only": "Email only",
|
||||
"Email or Phone": "Email or Phone",
|
||||
"Enable": "Enable",
|
||||
"Enable dark logo": "Enable dark logo",
|
||||
"Enable dark logo - Tooltip": "Enable dark logo",
|
||||
@ -311,6 +313,7 @@
|
||||
"Phone": "Phone",
|
||||
"Phone - Tooltip": "Phone number",
|
||||
"Phone only": "Phone only",
|
||||
"Phone or Email": "Phone or Email",
|
||||
"Plan": "Plan",
|
||||
"Plan - Tooltip": "Plan - Tooltip",
|
||||
"Plans": "Plans",
|
||||
@ -391,6 +394,7 @@
|
||||
"User type": "User type",
|
||||
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
|
||||
"Users": "Users",
|
||||
"Users - Tooltip": "Users - Tooltip",
|
||||
"Users under all organizations": "Users under all organizations",
|
||||
"Verifications": "Verifications",
|
||||
"Webhooks": "Webhooks",
|
||||
@ -473,7 +477,6 @@
|
||||
"LDAP username, Email or phone": "LDAP username, Email or phone",
|
||||
"Loading": "Loading",
|
||||
"Logging out...": "Logging out...",
|
||||
"Login button": "Login button",
|
||||
"MetaMask plugin not detected": "MetaMask plugin not detected",
|
||||
"Model loading failure": "Model loading failure",
|
||||
"No account?": "No account?",
|
||||
@ -498,6 +501,7 @@
|
||||
"Sign in with Face ID": "Sign in with Face ID",
|
||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||
"Sign in with {type}": "Sign in with {type}",
|
||||
"Signin button": "Signin button",
|
||||
"Signing in...": "Signing in...",
|
||||
"Successfully logged in with WebAuthn credentials": "Successfully logged in with WebAuthn credentials",
|
||||
"The camera is currently in use by another webpage": "The camera is currently in use by another webpage",
|
||||
@ -941,6 +945,7 @@
|
||||
"Please select your country code!": "Please select your country code!",
|
||||
"Please select your country/region!": "Please select your country/region!",
|
||||
"Regex": "Regex",
|
||||
"Signup button": "Signup button",
|
||||
"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",
|
||||
@ -1162,6 +1167,7 @@
|
||||
"Values": "Values",
|
||||
"Verification code sent": "Verification code sent",
|
||||
"WebAuthn credentials": "WebAuthn credentials",
|
||||
"You have changed the username, please save your change first before modifying the password": "You have changed the username, please save your change first before modifying the password",
|
||||
"input password": "input password"
|
||||
},
|
||||
"verification": {
|
||||
|
@ -80,6 +80,7 @@
|
||||
"Only signup": "Only signup",
|
||||
"Org choice mode": "Org choice mode",
|
||||
"Org choice mode - Tooltip": "Org choice mode - Tooltip",
|
||||
"Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"": "Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"",
|
||||
"Please input your application!": "Please input your application!",
|
||||
"Please input your organization!": "Please input your organization!",
|
||||
"Please select a HTML file": "Please select a HTML file",
|
||||
@ -229,6 +230,7 @@
|
||||
"Email": "Email",
|
||||
"Email - Tooltip": "Valid email address",
|
||||
"Email only": "Email only",
|
||||
"Email or Phone": "Email or Phone",
|
||||
"Enable": "Enable",
|
||||
"Enable dark logo": "Enable dark logo",
|
||||
"Enable dark logo - Tooltip": "Enable dark logo",
|
||||
@ -311,6 +313,7 @@
|
||||
"Phone": "Phone",
|
||||
"Phone - Tooltip": "Phone number",
|
||||
"Phone only": "Phone only",
|
||||
"Phone or Email": "Phone or Email",
|
||||
"Plan": "Plan",
|
||||
"Plan - Tooltip": "Plan - Tooltip",
|
||||
"Plans": "Plans",
|
||||
@ -391,6 +394,7 @@
|
||||
"User type": "User type",
|
||||
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
|
||||
"Users": "Users",
|
||||
"Users - Tooltip": "Users - Tooltip",
|
||||
"Users under all organizations": "Users under all organizations",
|
||||
"Verifications": "Verifications",
|
||||
"Webhooks": "Webhooks",
|
||||
@ -473,7 +477,6 @@
|
||||
"LDAP username, Email or phone": "LDAP username, Email or phone",
|
||||
"Loading": "Loading",
|
||||
"Logging out...": "Logging out...",
|
||||
"Login button": "Login button",
|
||||
"MetaMask plugin not detected": "MetaMask plugin not detected",
|
||||
"Model loading failure": "Model loading failure",
|
||||
"No account?": "No account?",
|
||||
@ -498,6 +501,7 @@
|
||||
"Sign in with Face ID": "Sign in with Face ID",
|
||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||
"Sign in with {type}": "Sign in with {type}",
|
||||
"Signin button": "Signin button",
|
||||
"Signing in...": "Signing in...",
|
||||
"Successfully logged in with WebAuthn credentials": "Successfully logged in with WebAuthn credentials",
|
||||
"The camera is currently in use by another webpage": "The camera is currently in use by another webpage",
|
||||
@ -941,6 +945,7 @@
|
||||
"Please select your country code!": "Please select your country code!",
|
||||
"Please select your country/region!": "Please select your country/region!",
|
||||
"Regex": "Regex",
|
||||
"Signup button": "Signup button",
|
||||
"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",
|
||||
@ -1162,6 +1167,7 @@
|
||||
"Values": "Values",
|
||||
"Verification code sent": "Verification code sent",
|
||||
"WebAuthn credentials": "WebAuthn credentials",
|
||||
"You have changed the username, please save your change first before modifying the password": "You have changed the username, please save your change first before modifying the password",
|
||||
"input password": "input password"
|
||||
},
|
||||
"verification": {
|
||||
|
@ -80,6 +80,7 @@
|
||||
"Only signup": "Apenas registro",
|
||||
"Org choice mode": "Modo de escolha Org",
|
||||
"Org choice mode - Tooltip": "Modo de escolha Org - Dica",
|
||||
"Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"": "Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"",
|
||||
"Please input your application!": "Por favor, insira o nome da sua aplicação!",
|
||||
"Please input your organization!": "Por favor, insira o nome da sua organização!",
|
||||
"Please select a HTML file": "Por favor, selecione um arquivo HTML",
|
||||
@ -229,6 +230,7 @@
|
||||
"Email": "E-mail",
|
||||
"Email - Tooltip": "Endereço de e-mail válido",
|
||||
"Email only": "Email only",
|
||||
"Email or Phone": "Email or Phone",
|
||||
"Enable": "Habilitar",
|
||||
"Enable dark logo": "Enable dark logo",
|
||||
"Enable dark logo - Tooltip": "Enable dark logo",
|
||||
@ -311,6 +313,7 @@
|
||||
"Phone": "Telefone",
|
||||
"Phone - Tooltip": "Número de telefone",
|
||||
"Phone only": "Phone only",
|
||||
"Phone or Email": "Phone or Email",
|
||||
"Plan": "Plan",
|
||||
"Plan - Tooltip": "Plan - Tooltip",
|
||||
"Plans": "Kế hoạch",
|
||||
@ -391,6 +394,7 @@
|
||||
"User type": "Tipo de Usuário",
|
||||
"User type - Tooltip": "Tags às quais o usuário pertence, com valor padrão de \"usuário-normal\"",
|
||||
"Users": "Usuários",
|
||||
"Users - Tooltip": "Users - Tooltip",
|
||||
"Users under all organizations": "Usuários em todas as organizações",
|
||||
"Verifications": "Verifications",
|
||||
"Webhooks": "Webhooks",
|
||||
@ -473,7 +477,6 @@
|
||||
"LDAP username, Email or phone": "LDAP username, Email or phone",
|
||||
"Loading": "Carregando",
|
||||
"Logging out...": "Saindo...",
|
||||
"Login button": "Login button",
|
||||
"MetaMask plugin not detected": "MetaMask plugin not detected",
|
||||
"Model loading failure": "Model loading failure",
|
||||
"No account?": "Não possui uma conta?",
|
||||
@ -498,6 +501,7 @@
|
||||
"Sign in with Face ID": "Sign in with Face ID",
|
||||
"Sign in with WebAuthn": "Entrar com WebAuthn",
|
||||
"Sign in with {type}": "Entrar com {type}",
|
||||
"Signin button": "Signin button",
|
||||
"Signing in...": "Entrando...",
|
||||
"Successfully logged in with WebAuthn credentials": "Logado com sucesso usando credenciais WebAuthn",
|
||||
"The camera is currently in use by another webpage": "The camera is currently in use by another webpage",
|
||||
@ -941,6 +945,7 @@
|
||||
"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",
|
||||
"Signup button": "Signup button",
|
||||
"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",
|
||||
@ -1162,6 +1167,7 @@
|
||||
"Values": "Valores",
|
||||
"Verification code sent": "Código de verificação enviado",
|
||||
"WebAuthn credentials": "Credenciais WebAuthn",
|
||||
"You have changed the username, please save your change first before modifying the password": "You have changed the username, please save your change first before modifying the password",
|
||||
"input password": "Digite a senha"
|
||||
},
|
||||
"verification": {
|
||||
|
@ -80,6 +80,7 @@
|
||||
"Only signup": "Только при регистрации",
|
||||
"Org choice mode": "Режим выбора организации",
|
||||
"Org choice mode - Tooltip": "Выбор режима выбора организации пользователем",
|
||||
"Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"": "Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"",
|
||||
"Please input your application!": "Пожалуйста, введите свою заявку!",
|
||||
"Please input your organization!": "Пожалуйста, введите название вашей организации!",
|
||||
"Please select a HTML file": "Пожалуйста, выберите файл HTML",
|
||||
@ -229,6 +230,7 @@
|
||||
"Email": "Электронная почта",
|
||||
"Email - Tooltip": "Действительный адрес электронной почты",
|
||||
"Email only": "Email only",
|
||||
"Email or Phone": "Email or Phone",
|
||||
"Enable": "Включить",
|
||||
"Enable dark logo": "Enable dark logo",
|
||||
"Enable dark logo - Tooltip": "Enable dark logo",
|
||||
@ -311,6 +313,7 @@
|
||||
"Phone": "Телефон",
|
||||
"Phone - Tooltip": "Номер телефона",
|
||||
"Phone only": "Phone only",
|
||||
"Phone or Email": "Phone or Email",
|
||||
"Plan": "План",
|
||||
"Plan - Tooltip": "Plan - Tooltip",
|
||||
"Plans": "Планы",
|
||||
@ -391,6 +394,7 @@
|
||||
"User type": "Тип пользователя",
|
||||
"User type - Tooltip": "Теги, к которым принадлежит пользователь, по умолчанию \"обычный пользователь\"",
|
||||
"Users": "Пользователи",
|
||||
"Users - Tooltip": "Users - Tooltip",
|
||||
"Users under all organizations": "Пользователи всех организаций",
|
||||
"Verifications": "Verifications",
|
||||
"Webhooks": "Вебхуки",
|
||||
@ -473,7 +477,6 @@
|
||||
"LDAP username, Email or phone": "LDAP username, Email or phone",
|
||||
"Loading": "Загрузка",
|
||||
"Logging out...": "Выход...",
|
||||
"Login button": "Login button",
|
||||
"MetaMask plugin not detected": "MetaMask plugin not detected",
|
||||
"Model loading failure": "Model loading failure",
|
||||
"No account?": "Нет аккаунта?",
|
||||
@ -498,6 +501,7 @@
|
||||
"Sign in with Face ID": "Sign in with Face ID",
|
||||
"Sign in with WebAuthn": "Войти с помощью WebAuthn",
|
||||
"Sign in with {type}": "Войти с помощью {type}",
|
||||
"Signin button": "Signin button",
|
||||
"Signing in...": "Вход в систему...",
|
||||
"Successfully logged in with WebAuthn credentials": "Успешный вход с учетными данными WebAuthn",
|
||||
"The camera is currently in use by another webpage": "The camera is currently in use by another webpage",
|
||||
@ -941,6 +945,7 @@
|
||||
"Please select your country code!": "Пожалуйста, выберите код своей страны!",
|
||||
"Please select your country/region!": "Пожалуйста, выберите свою страну / регион!",
|
||||
"Regex": "Regex",
|
||||
"Signup button": "Signup button",
|
||||
"Terms of Use": "Условия использования",
|
||||
"Terms of Use - Tooltip": "Условия использования, которые пользователи должны прочитать и согласиться с ними при регистрации",
|
||||
"Text 1": "Text 1",
|
||||
@ -1162,6 +1167,7 @@
|
||||
"Values": "Значения",
|
||||
"Verification code sent": "Код подтверждения отправлен",
|
||||
"WebAuthn credentials": "WebAuthn удостоверения",
|
||||
"You have changed the username, please save your change first before modifying the password": "You have changed the username, please save your change first before modifying the password",
|
||||
"input password": "введите пароль"
|
||||
},
|
||||
"verification": {
|
||||
|
@ -80,6 +80,7 @@
|
||||
"Only signup": "Only signup",
|
||||
"Org choice mode": "Org choice mode",
|
||||
"Org choice mode - Tooltip": "Org choice mode - Tooltip",
|
||||
"Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"": "Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"",
|
||||
"Please input your application!": "Please input your application!",
|
||||
"Please input your organization!": "Please input your organization!",
|
||||
"Please select a HTML file": "Please select a HTML file",
|
||||
@ -229,6 +230,7 @@
|
||||
"Email": "Email",
|
||||
"Email - Tooltip": "Valid email address",
|
||||
"Email only": "Email only",
|
||||
"Email or Phone": "Email or Phone",
|
||||
"Enable": "Enable",
|
||||
"Enable dark logo": "Enable dark logo",
|
||||
"Enable dark logo - Tooltip": "Enable dark logo",
|
||||
@ -311,6 +313,7 @@
|
||||
"Phone": "Phone",
|
||||
"Phone - Tooltip": "Phone number",
|
||||
"Phone only": "Phone only",
|
||||
"Phone or Email": "Phone or Email",
|
||||
"Plan": "Plan",
|
||||
"Plan - Tooltip": "Plan - Tooltip",
|
||||
"Plans": "Plans",
|
||||
@ -391,6 +394,7 @@
|
||||
"User type": "User type",
|
||||
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
|
||||
"Users": "Users",
|
||||
"Users - Tooltip": "Users - Tooltip",
|
||||
"Users under all organizations": "Users under all organizations",
|
||||
"Verifications": "Verifications",
|
||||
"Webhooks": "Webhooks",
|
||||
@ -473,7 +477,6 @@
|
||||
"LDAP username, Email or phone": "LDAP username, Email or phone",
|
||||
"Loading": "Loading",
|
||||
"Logging out...": "Logging out...",
|
||||
"Login button": "Login button",
|
||||
"MetaMask plugin not detected": "MetaMask plugin not detected",
|
||||
"Model loading failure": "Model loading failure",
|
||||
"No account?": "No account?",
|
||||
@ -498,6 +501,7 @@
|
||||
"Sign in with Face ID": "Sign in with Face ID",
|
||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||
"Sign in with {type}": "Sign in with {type}",
|
||||
"Signin button": "Signin button",
|
||||
"Signing in...": "Signing in...",
|
||||
"Successfully logged in with WebAuthn credentials": "Successfully logged in with WebAuthn credentials",
|
||||
"The camera is currently in use by another webpage": "The camera is currently in use by another webpage",
|
||||
@ -941,6 +945,7 @@
|
||||
"Please select your country code!": "Please select your country code!",
|
||||
"Please select your country/region!": "Please select your country/region!",
|
||||
"Regex": "Regex",
|
||||
"Signup button": "Signup button",
|
||||
"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",
|
||||
@ -1162,6 +1167,7 @@
|
||||
"Values": "Values",
|
||||
"Verification code sent": "Verification code sent",
|
||||
"WebAuthn credentials": "WebAuthn credentials",
|
||||
"You have changed the username, please save your change first before modifying the password": "You have changed the username, please save your change first before modifying the password",
|
||||
"input password": "input password"
|
||||
},
|
||||
"verification": {
|
||||
|
@ -80,6 +80,7 @@
|
||||
"Only signup": "Only signup",
|
||||
"Org choice mode": "Org choice mode",
|
||||
"Org choice mode - Tooltip": "Org choice mode - Tooltip",
|
||||
"Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"": "Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"",
|
||||
"Please input your application!": "Please input your application!",
|
||||
"Please input your organization!": "Please input your organization!",
|
||||
"Please select a HTML file": "Please select a HTML file",
|
||||
@ -229,6 +230,7 @@
|
||||
"Email": "E-Posta",
|
||||
"Email - Tooltip": "Geçerli e-posta adresi",
|
||||
"Email only": "Sadece eposta",
|
||||
"Email or Phone": "Email or Phone",
|
||||
"Enable": "Etkinleştir",
|
||||
"Enable dark logo": "Enable dark logo",
|
||||
"Enable dark logo - Tooltip": "Enable dark logo",
|
||||
@ -311,6 +313,7 @@
|
||||
"Phone": "Telefon",
|
||||
"Phone - Tooltip": "Telefon numarası",
|
||||
"Phone only": "Sadece telefon",
|
||||
"Phone or Email": "Phone or Email",
|
||||
"Plan": "Plan",
|
||||
"Plan - Tooltip": "Plan - Tooltip",
|
||||
"Plans": "Plans",
|
||||
@ -391,6 +394,7 @@
|
||||
"User type": "User type",
|
||||
"User type - Tooltip": "Tags that the user belongs to, defaulting to \"normal-user\"",
|
||||
"Users": "Kullanıcılar",
|
||||
"Users - Tooltip": "Users - Tooltip",
|
||||
"Users under all organizations": "Users under all organizations",
|
||||
"Verifications": "Verifications",
|
||||
"Webhooks": "Webhooks",
|
||||
@ -473,7 +477,6 @@
|
||||
"LDAP username, Email or phone": "LDAP username, Email or phone",
|
||||
"Loading": "Yükleniyor",
|
||||
"Logging out...": "Çıkış yapılıyor...",
|
||||
"Login button": "Login button",
|
||||
"MetaMask plugin not detected": "Metamask plugin-in bulunamadı",
|
||||
"Model loading failure": "Model loading failure",
|
||||
"No account?": "Hesabınız yok mu?",
|
||||
@ -498,6 +501,7 @@
|
||||
"Sign in with Face ID": "Sign in with Face ID",
|
||||
"Sign in with WebAuthn": "Sign in with WebAuthn",
|
||||
"Sign in with {type}": "{type} ile giriş yap",
|
||||
"Signin button": "Signin button",
|
||||
"Signing in...": "Signing in...",
|
||||
"Successfully logged in with WebAuthn credentials": "Successfully logged in with WebAuthn credentials",
|
||||
"The camera is currently in use by another webpage": "The camera is currently in use by another webpage",
|
||||
@ -941,6 +945,7 @@
|
||||
"Please select your country code!": "Please select your country code!",
|
||||
"Please select your country/region!": "Please select your country/region!",
|
||||
"Regex": "Regex",
|
||||
"Signup button": "Signup button",
|
||||
"Terms of Use": "Kullanım Koşulları",
|
||||
"Terms of Use - Tooltip": "Kayıt olabilmek için kullanım koşullarını okuyup, kabul etmelisiniz",
|
||||
"Text 1": "Text 1",
|
||||
@ -1162,6 +1167,7 @@
|
||||
"Values": "Values",
|
||||
"Verification code sent": "Verification code sent",
|
||||
"WebAuthn credentials": "WebAuthn credentials",
|
||||
"You have changed the username, please save your change first before modifying the password": "You have changed the username, please save your change first before modifying the password",
|
||||
"input password": "şifreyi girin"
|
||||
},
|
||||
"verification": {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -80,6 +80,7 @@
|
||||
"Only signup": "Chỉ đăng ký",
|
||||
"Org choice mode": "Org choice mode",
|
||||
"Org choice mode - Tooltip": "Org choice mode - Tooltip",
|
||||
"Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"": "Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"",
|
||||
"Please input your application!": "Vui lòng nhập ứng dụng của bạn!",
|
||||
"Please input your organization!": "Vui lòng nhập tổ chức của bạn!",
|
||||
"Please select a HTML file": "Vui lòng chọn tệp HTML",
|
||||
@ -229,6 +230,7 @@
|
||||
"Email": "Email: Thư điện tử",
|
||||
"Email - Tooltip": "Địa chỉ email hợp lệ",
|
||||
"Email only": "Email only",
|
||||
"Email or Phone": "Email or Phone",
|
||||
"Enable": "Enable",
|
||||
"Enable dark logo": "Enable dark logo",
|
||||
"Enable dark logo - Tooltip": "Enable dark logo",
|
||||
@ -311,6 +313,7 @@
|
||||
"Phone": "Điện thoại",
|
||||
"Phone - Tooltip": "Số điện thoại",
|
||||
"Phone only": "Phone only",
|
||||
"Phone or Email": "Phone or Email",
|
||||
"Plan": "Plan",
|
||||
"Plan - Tooltip": "Plan - Tooltip",
|
||||
"Plans": "Kế hoạch",
|
||||
@ -391,6 +394,7 @@
|
||||
"User type": "Loại người dùng",
|
||||
"User type - Tooltip": "Các thẻ mà người dùng thuộc vào, mặc định là \"người dùng bình thường\"",
|
||||
"Users": "Người dùng",
|
||||
"Users - Tooltip": "Users - Tooltip",
|
||||
"Users under all organizations": "Người dùng trong tất cả các tổ chức",
|
||||
"Verifications": "Verifications",
|
||||
"Webhooks": "Webhooks",
|
||||
@ -473,7 +477,6 @@
|
||||
"LDAP username, Email or phone": "LDAP username, Email or phone",
|
||||
"Loading": "Đang tải",
|
||||
"Logging out...": "Đăng xuất ...",
|
||||
"Login button": "Login button",
|
||||
"MetaMask plugin not detected": "MetaMask plugin not detected",
|
||||
"Model loading failure": "Model loading failure",
|
||||
"No account?": "Không có tài khoản?",
|
||||
@ -498,6 +501,7 @@
|
||||
"Sign in with Face ID": "Sign in with Face ID",
|
||||
"Sign in with WebAuthn": "Đăng nhập với WebAuthn",
|
||||
"Sign in with {type}": "Đăng nhập bằng {type}",
|
||||
"Signin button": "Signin button",
|
||||
"Signing in...": "Đăng nhập...",
|
||||
"Successfully logged in with WebAuthn credentials": "Đã đăng nhập thành công với thông tin WebAuthn",
|
||||
"The camera is currently in use by another webpage": "The camera is currently in use by another webpage",
|
||||
@ -941,6 +945,7 @@
|
||||
"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",
|
||||
"Signup button": "Signup button",
|
||||
"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",
|
||||
@ -1162,6 +1167,7 @@
|
||||
"Values": "Giá trị",
|
||||
"Verification code sent": "Mã xác minh đã được gửi",
|
||||
"WebAuthn credentials": "Chứng chỉ WebAuthn",
|
||||
"You have changed the username, please save your change first before modifying the password": "You have changed the username, please save your change first before modifying the password",
|
||||
"input password": "Nhập mật khẩu"
|
||||
},
|
||||
"verification": {
|
||||
|
@ -80,6 +80,7 @@
|
||||
"Only signup": "仅注册",
|
||||
"Org choice mode": "组织选择模式",
|
||||
"Org choice mode - Tooltip": "采用什么方式选择要登录的组织",
|
||||
"Please enable \\\"Signin session\\\" first before enabling \\\"Auto signin\\\"": "开启 \\\"保持登录会话\\\" 后才能开启 \\\"自动登录\\\"",
|
||||
"Please input your application!": "请输入你的应用",
|
||||
"Please input your organization!": "请输入你的组织",
|
||||
"Please select a HTML file": "请选择一个HTML文件",
|
||||
@ -229,6 +230,7 @@
|
||||
"Email": "电子邮箱",
|
||||
"Email - Tooltip": "合法的电子邮件地址",
|
||||
"Email only": "仅支持邮件",
|
||||
"Email or Phone": "电子邮件或手机",
|
||||
"Enable": "启用",
|
||||
"Enable dark logo": "开启暗黑Logo",
|
||||
"Enable dark logo - Tooltip": "开启暗黑Logo",
|
||||
@ -311,6 +313,7 @@
|
||||
"Phone": "手机号",
|
||||
"Phone - Tooltip": "手机号",
|
||||
"Phone only": "仅支持手机号",
|
||||
"Phone or Email": "手机或电子邮件",
|
||||
"Plan": "计划",
|
||||
"Plan - Tooltip": "订阅里的计划",
|
||||
"Plans": "计划",
|
||||
@ -391,6 +394,7 @@
|
||||
"User type": "用户类型",
|
||||
"User type - Tooltip": "用户所属的标签,默认为\"normal-user\"",
|
||||
"Users": "用户",
|
||||
"Users - Tooltip": "用户 - Tooltip",
|
||||
"Users under all organizations": "所有组织里的用户",
|
||||
"Verifications": "验证",
|
||||
"Webhooks": "Webhooks",
|
||||
@ -473,7 +477,6 @@
|
||||
"LDAP username, Email or phone": "LDAP用户名, Email或手机号",
|
||||
"Loading": "加载中",
|
||||
"Logging out...": "正在退出登录...",
|
||||
"Login button": "登录按钮",
|
||||
"MetaMask plugin not detected": "未检测到MetaMask插件",
|
||||
"Model loading failure": "人脸识别模型加载失败",
|
||||
"No account?": "没有账号?",
|
||||
@ -498,6 +501,7 @@
|
||||
"Sign in with Face ID": "人脸登录",
|
||||
"Sign in with WebAuthn": "WebAuthn登录",
|
||||
"Sign in with {type}": "{type}登录",
|
||||
"Signin button": "登录按钮",
|
||||
"Signing in...": "正在登录...",
|
||||
"Successfully logged in with WebAuthn credentials": "成功使用WebAuthn证书登录",
|
||||
"The camera is currently in use by another webpage": "摄像头被占用,无法使用",
|
||||
@ -941,6 +945,7 @@
|
||||
"Please select your country code!": "请选择国家代码!",
|
||||
"Please select your country/region!": "请选择您的国家或地区",
|
||||
"Regex": "正则表达式",
|
||||
"Signup button": "注册按钮",
|
||||
"Terms of Use": "《用户协议》",
|
||||
"Terms of Use - Tooltip": "用户注册时需要阅读并同意的使用条款",
|
||||
"Text 1": "文本1",
|
||||
@ -1162,6 +1167,7 @@
|
||||
"Values": "值",
|
||||
"Verification code sent": "验证码已发送",
|
||||
"WebAuthn credentials": "WebAuthn凭据",
|
||||
"You have changed the username, please save your change first before modifying the password": "你已经更改了你的用户名,请你再更改密码前保存更改",
|
||||
"input password": "输入密码"
|
||||
},
|
||||
"verification": {
|
||||
|
@ -15,6 +15,7 @@
|
||||
import React from "react";
|
||||
import {DeleteOutlined, DownOutlined, UpOutlined} from "@ant-design/icons";
|
||||
import {Button, Col, Input, Row, Select, Switch, Table, Tooltip} from "antd";
|
||||
import {CountryCodeSelect} from "../common/select/CountryCodeSelect";
|
||||
import * as Setting from "../Setting";
|
||||
import i18next from "i18next";
|
||||
import * as Provider from "../auth/Provider";
|
||||
@ -29,6 +30,10 @@ class ProviderTable extends React.Component {
|
||||
};
|
||||
}
|
||||
|
||||
getUserOrganization() {
|
||||
return this.props.application?.organizationObj;
|
||||
}
|
||||
|
||||
updateTable(table) {
|
||||
this.props.onUpdateTable(table);
|
||||
}
|
||||
@ -79,7 +84,7 @@ class ProviderTable extends React.Component {
|
||||
|
||||
// If the provider is email or SMS, set the rule to "all" instead of the default "None"
|
||||
if (provider.category === "Email" || provider.category === "SMS") {
|
||||
this.updateField(table, index, "rule", "all");
|
||||
this.updateField(table, index, "rule", "All");
|
||||
}
|
||||
}} >
|
||||
{
|
||||
@ -109,6 +114,30 @@ class ProviderTable extends React.Component {
|
||||
return Provider.getProviderLogoWidget(provider);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("user:Country/Region"),
|
||||
dataIndex: "countryCodes",
|
||||
key: "countryCodes",
|
||||
width: "140px",
|
||||
render: (text, record, index) => {
|
||||
if (record.provider?.category !== "SMS") {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<CountryCodeSelect
|
||||
style={{width: "100%"}}
|
||||
hasDefault={true}
|
||||
mode={"multiple"}
|
||||
initValue={text ? text : ["All"]}
|
||||
onChange={(value) => {
|
||||
this.updateField(table, index, "countryCodes", value);
|
||||
}}
|
||||
countryCodes={this.getUserOrganization()?.countryCodes}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("provider:Can signup"),
|
||||
dataIndex: "canSignUp",
|
||||
@ -198,7 +227,7 @@ class ProviderTable extends React.Component {
|
||||
title: i18next.t("application:Rule"),
|
||||
dataIndex: "rule",
|
||||
key: "rule",
|
||||
width: "120px",
|
||||
width: "160px",
|
||||
render: (text, record, index) => {
|
||||
if (record.provider?.type === "Google") {
|
||||
if (text === "None") {
|
||||
@ -230,12 +259,12 @@ class ProviderTable extends React.Component {
|
||||
);
|
||||
} else if (record.provider?.category === "SMS" || record.provider?.category === "Email") {
|
||||
if (text === "None") {
|
||||
text = "all";
|
||||
text = "All";
|
||||
}
|
||||
return (
|
||||
<Select virtual={false} style={{width: "100%"}}
|
||||
value={text}
|
||||
defaultValue="all"
|
||||
defaultValue="All"
|
||||
onChange={value => {
|
||||
this.updateField(table, index, "rule", value);
|
||||
}}>
|
||||
|
@ -164,7 +164,7 @@ class SigninMethodTable 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" onClick={() => this.deleteRow(items, table, index)} />
|
||||
<Button disabled={table.length <= 1} icon={<DeleteOutlined />} size="small" onClick={() => this.deleteRow(items, table, index)} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
|
@ -26,6 +26,20 @@ require("codemirror/mode/htmlmixed/htmlmixed");
|
||||
|
||||
const {Option} = Select;
|
||||
|
||||
export const SigninTableDefaultCssMap = {
|
||||
"Back button": ".back-button {\n top: 65px;\n left: 15px;\n position: absolute;\n}\n.back-inner-button{}",
|
||||
"Languages": ".login-languages {\n top: 55px;\n right: 5px;\n position: absolute;\n}",
|
||||
"Logo": ".login-logo-box {}",
|
||||
"Signin methods": ".signin-methods {}",
|
||||
"Username": ".login-username {}\n.login-username-input{}",
|
||||
"Password": ".login-password {}\n.login-password-input{}",
|
||||
"Agreement": ".login-agreement {}",
|
||||
"Forgot password?": ".login-forget-password {\n display: inline-flex;\n justify-content: space-between;\n width: 320px;\n margin-bottom: 25px;\n}",
|
||||
"Login button": ".login-button-box {\n margin-bottom: 5px;\n}\n.login-button {\n width: 100%;\n}",
|
||||
"Signup link": ".login-signup-link {\n margin-bottom: 24px;\n display: flex;\n justify-content: end;\n}",
|
||||
"Providers": ".provider-img {\n width: 30px;\n margin: 5px;\n}\n.provider-big-img {\n margin-bottom: 10px;\n}",
|
||||
};
|
||||
|
||||
class SigninTable extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
@ -103,7 +117,7 @@ class SigninTable extends React.Component {
|
||||
{name: "Providers", displayName: i18next.t("general:Providers")},
|
||||
{name: "Agreement", displayName: i18next.t("signup:Agreement")},
|
||||
{name: "Forgot password?", displayName: i18next.t("login:Forgot password?")},
|
||||
{name: "Login button", displayName: i18next.t("login:Login button")},
|
||||
{name: "Login button", displayName: i18next.t("login:Signin button")},
|
||||
{name: "Signup link", displayName: i18next.t("general:Signup link")},
|
||||
];
|
||||
|
||||
@ -120,6 +134,7 @@ class SigninTable extends React.Component {
|
||||
value={getItemDisplayName(text)}
|
||||
onChange={value => {
|
||||
this.updateField(table, index, "name", value);
|
||||
this.updateField(table, index, "label", SigninTableDefaultCssMap[value]);
|
||||
}} >
|
||||
{
|
||||
Setting.getDeduplicatedArray(items, table, "name").map((item, index) => <Option key={index} value={item.name}>{item.displayName}</Option>)
|
||||
@ -187,15 +202,15 @@ class SigninTable extends React.Component {
|
||||
return (
|
||||
<Popover placement="right" content={
|
||||
<div style={{width: "900px", height: "300px"}} >
|
||||
<CodeMirror value={text}
|
||||
options={{mode: "htmlmixed", theme: "material-darker"}}
|
||||
<CodeMirror value={text?.replaceAll("<style>", "").replaceAll("</style>", "")}
|
||||
options={{mode: "css", theme: "material-darker"}}
|
||||
onBeforeChange={(editor, data, value) => {
|
||||
this.updateField(table, index, "label", value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
} title={i18next.t("application:CSS style")} trigger="click">
|
||||
<Input value={text} onChange={e => {
|
||||
<Input value={text?.replaceAll("<style>", "").replaceAll("</style>", "")} onChange={e => {
|
||||
this.updateField(table, index, "label", e.target.value);
|
||||
}} />
|
||||
</Popover>
|
||||
|
@ -24,6 +24,27 @@ import "codemirror/lib/codemirror.css";
|
||||
require("codemirror/theme/material-darker.css");
|
||||
require("codemirror/mode/htmlmixed/htmlmixed");
|
||||
|
||||
const EmailCss = ".signup-email{}\n.signup-email-input{}\n.signup-email-code{}\n.signup-email-code-input{}\n";
|
||||
const PhoneCss = ".signup-phone{}\n.signup-phone-input{}\n.phone-code{}\n.signup-phone-code-input{}";
|
||||
|
||||
export const SignupTableDefaultCssMap = {
|
||||
"Username": ".signup-username {}\n.signup-username-input {}",
|
||||
"Display name": ".signup-first-name {}\n.signup-first-name-input{}\n.signup-last-name{}\n.signup-last-name-input{}\n.signup-name{}\n.signup-name-input{}",
|
||||
"Affiliation": ".signup-affiliation{}\n.signup-affiliation-input{}",
|
||||
"Country/Region": ".signup-country-region{}\n.signup-region-select{}",
|
||||
"ID card": ".signup-idcard{}\n.signup-idcard-input{}",
|
||||
"Password": ".signup-password{}\n.signup-password-input{}",
|
||||
"Confirm password": ".signup-confirm{}",
|
||||
"Email": EmailCss,
|
||||
"Phone": PhoneCss,
|
||||
"Email or Phone": EmailCss + PhoneCss,
|
||||
"Phone or Email": EmailCss + PhoneCss,
|
||||
"Invitation code": ".signup-invitation-code{}\n.signup-invitation-code-input{}",
|
||||
"Agreement": ".login-agreement{}",
|
||||
"Signup button": ".signup-button{}\n.signup-link{}",
|
||||
"Providers": ".provider-img {\n width: 30px;\n margin: 5px;\n }\n .provider-big-img {\n margin-bottom: 10px;\n }\n ",
|
||||
};
|
||||
|
||||
const {Option} = Select;
|
||||
|
||||
class SignupTable extends React.Component {
|
||||
@ -44,7 +65,7 @@ class SignupTable extends React.Component {
|
||||
}
|
||||
|
||||
addRow(table) {
|
||||
const row = {name: Setting.getNewRowNameForTable(table, "Please select a signup item"), visible: true, required: true, rule: "None"};
|
||||
const row = {name: Setting.getNewRowNameForTable(table, "Please select a signup item"), visible: true, required: true, rule: "None", customCss: ""};
|
||||
if (table === undefined) {
|
||||
table = [];
|
||||
}
|
||||
@ -89,6 +110,8 @@ class SignupTable extends React.Component {
|
||||
{name: "Phone or Email", displayName: i18next.t("general:Phone or Email")},
|
||||
{name: "Invitation code", displayName: i18next.t("application:Invitation code")},
|
||||
{name: "Agreement", displayName: i18next.t("signup:Agreement")},
|
||||
{name: "Signup button", displayName: i18next.t("signup:Signup button")},
|
||||
{name: "Providers", displayName: i18next.t("general:Providers")},
|
||||
{name: "Text 1", displayName: i18next.t("signup:Text 1")},
|
||||
{name: "Text 2", displayName: i18next.t("signup:Text 2")},
|
||||
{name: "Text 3", displayName: i18next.t("signup:Text 3")},
|
||||
@ -109,6 +132,7 @@ class SignupTable extends React.Component {
|
||||
value={getItemDisplayName(text)}
|
||||
onChange={value => {
|
||||
this.updateField(table, index, "name", value);
|
||||
this.updateField(table, index, "customCss", SignupTableDefaultCssMap[value]);
|
||||
}} >
|
||||
{
|
||||
Setting.getDeduplicatedArray(items, table, "name").map((item, index) => <Option key={index} value={item.name}>{item.displayName}</Option>)
|
||||
@ -121,7 +145,7 @@ class SignupTable extends React.Component {
|
||||
title: i18next.t("organization:Visible"),
|
||||
dataIndex: "visible",
|
||||
key: "visible",
|
||||
width: "120px",
|
||||
width: "80px",
|
||||
render: (text, record, index) => {
|
||||
if (record.name === "ID") {
|
||||
return null;
|
||||
@ -143,9 +167,9 @@ class SignupTable extends React.Component {
|
||||
title: i18next.t("provider:Required"),
|
||||
dataIndex: "required",
|
||||
key: "required",
|
||||
width: "120px",
|
||||
width: "80px",
|
||||
render: (text, record, index) => {
|
||||
if (!record.visible) {
|
||||
if (!record.visible || ["Signup button", "Providers"].includes(record.name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -160,9 +184,9 @@ class SignupTable extends React.Component {
|
||||
title: i18next.t("provider:Prompted"),
|
||||
dataIndex: "prompted",
|
||||
key: "prompted",
|
||||
width: "120px",
|
||||
width: "80px",
|
||||
render: (text, record, index) => {
|
||||
if (record.name === "ID") {
|
||||
if (["ID", "Signup button", "Providers"].includes(record.name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -181,7 +205,7 @@ class SignupTable extends React.Component {
|
||||
title: i18next.t("signup:Label"),
|
||||
dataIndex: "label",
|
||||
key: "label",
|
||||
width: "200px",
|
||||
width: "150px",
|
||||
render: (text, record, index) => {
|
||||
if (record.name.startsWith("Text ")) {
|
||||
return (
|
||||
@ -209,6 +233,30 @@ class SignupTable extends React.Component {
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("application:Custom CSS"),
|
||||
dataIndex: "customCss",
|
||||
key: "customCss",
|
||||
width: "180px",
|
||||
render: (text, record, index) => {
|
||||
return (
|
||||
<Popover placement="right" content={
|
||||
<div style={{width: "900px", height: "300px"}}>
|
||||
<CodeMirror value={text ? text : SignupTableDefaultCssMap[record.name]}
|
||||
options={{mode: "css", theme: "material-darker"}}
|
||||
onBeforeChange={(editor, data, value) => {
|
||||
this.updateField(table, index, "customCss", value ? value : SignupTableDefaultCssMap[record.name]);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
} title={i18next.t("application:CSS style")} trigger="click">
|
||||
<Input value={text ? text : SignupTableDefaultCssMap[record.name]} onChange={e => {
|
||||
this.updateField(table, index, "customCss", e.target.value ? e.target.value : SignupTableDefaultCssMap[record.name]);
|
||||
}} />
|
||||
</Popover>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: i18next.t("signup:Placeholder"),
|
||||
dataIndex: "placeholder",
|
||||
@ -230,9 +278,9 @@ class SignupTable extends React.Component {
|
||||
title: i18next.t("signup:Regex"),
|
||||
dataIndex: "regex",
|
||||
key: "regex",
|
||||
width: "200px",
|
||||
width: "180px",
|
||||
render: (text, record, index) => {
|
||||
if (record.name.startsWith("Text ") || record.name === "Password" || record.name === "Confirm password") {
|
||||
if (record.name.startsWith("Text ") || ["Password", "Confirm password", "Signup button", "Provider"].includes(record.name)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -277,6 +325,11 @@ class SignupTable extends React.Component {
|
||||
{id: "Signin", name: i18next.t("application:Signin")},
|
||||
{id: "Signin (Default True)", name: i18next.t("application:Signin (Default True)")},
|
||||
];
|
||||
} else if (record.name === "Providers") {
|
||||
options = [
|
||||
{id: "big", name: i18next.t("application:Big icon")},
|
||||
{id: "small", name: i18next.t("application:Small icon")},
|
||||
];
|
||||
}
|
||||
|
||||
if (options.length === 0) {
|
||||
@ -304,7 +357,7 @@ class SignupTable 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" onClick={() => this.deleteRow(table, index)} />
|
||||
<Button disabled={record.name === "Signup button"} icon={<DeleteOutlined />} size="small" onClick={() => this.deleteRow(table, index)} />
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
|
1098
web/yarn.lock
1098
web/yarn.lock
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user