mirror of
https://github.com/casdoor/casdoor.git
synced 2025-09-07 11:00:28 +08:00
Make cert work.
This commit is contained in:
@@ -28,7 +28,7 @@ func (c *RootController) GetOidcDiscovery() {
|
|||||||
// @Tag OIDC API
|
// @Tag OIDC API
|
||||||
// @router /api/certs [get]
|
// @router /api/certs [get]
|
||||||
func (c *RootController) GetOidcCert() {
|
func (c *RootController) GetOidcCert() {
|
||||||
jwks, err := object.GetJSONWebKeySet()
|
jwks, err := object.GetJsonWebKeySet()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.ResponseError(err.Error())
|
c.ResponseError(err.Error())
|
||||||
return
|
return
|
||||||
|
@@ -31,6 +31,7 @@ type Application struct {
|
|||||||
HomepageUrl string `xorm:"varchar(100)" json:"homepageUrl"`
|
HomepageUrl string `xorm:"varchar(100)" json:"homepageUrl"`
|
||||||
Description string `xorm:"varchar(100)" json:"description"`
|
Description string `xorm:"varchar(100)" json:"description"`
|
||||||
Organization string `xorm:"varchar(100)" json:"organization"`
|
Organization string `xorm:"varchar(100)" json:"organization"`
|
||||||
|
Cert string `xorm:"varchar(100)" json:"cert"`
|
||||||
EnablePassword bool `json:"enablePassword"`
|
EnablePassword bool `json:"enablePassword"`
|
||||||
EnableSignUp bool `json:"enableSignUp"`
|
EnableSignUp bool `json:"enableSignUp"`
|
||||||
EnableSigninSession bool `json:"enableSigninSession"`
|
EnableSigninSession bool `json:"enableSigninSession"`
|
||||||
|
@@ -124,6 +124,12 @@ func UpdateCert(id string, cert *Cert) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func AddCert(cert *Cert) bool {
|
func AddCert(cert *Cert) bool {
|
||||||
|
if cert.PublicKey == "" || cert.PrivateKey == "" {
|
||||||
|
publicKey, privateKey := generateRsaKeys(cert.BitSize, cert.ExpireInYears, cert.Name, cert.Owner)
|
||||||
|
cert.PublicKey = publicKey
|
||||||
|
cert.PrivateKey = privateKey
|
||||||
|
}
|
||||||
|
|
||||||
affected, err := adapter.Engine.Insert(cert)
|
affected, err := adapter.Engine.Insert(cert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -144,3 +150,15 @@ func DeleteCert(cert *Cert) bool {
|
|||||||
func (p *Cert) GetId() string {
|
func (p *Cert) GetId() string {
|
||||||
return fmt.Sprintf("%s/%s", p.Owner, p.Name)
|
return fmt.Sprintf("%s/%s", p.Owner, p.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getCertByApplication(application *Application) *Cert {
|
||||||
|
if application.Cert != "" {
|
||||||
|
return getCert("admin", application.Cert)
|
||||||
|
} else {
|
||||||
|
return GetDefaultCert()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDefaultCert() *Cert {
|
||||||
|
return getCert("admin", "cert-built-in")
|
||||||
|
}
|
||||||
|
@@ -14,12 +14,23 @@
|
|||||||
|
|
||||||
package object
|
package object
|
||||||
|
|
||||||
import "github.com/casbin/casdoor/util"
|
import (
|
||||||
|
_ "embed"
|
||||||
|
|
||||||
|
"github.com/casbin/casdoor/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed token_jwt_key.pem
|
||||||
|
var tokenJwtPublicKey string
|
||||||
|
|
||||||
|
//go:embed token_jwt_key.key
|
||||||
|
var tokenJwtPrivateKey string
|
||||||
|
|
||||||
func InitDb() {
|
func InitDb() {
|
||||||
initBuiltInOrganization()
|
initBuiltInOrganization()
|
||||||
initBuiltInUser()
|
initBuiltInUser()
|
||||||
initBuiltInApplication()
|
initBuiltInApplication()
|
||||||
|
initBuiltInCert()
|
||||||
initBuiltInLdap()
|
initBuiltInLdap()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,6 +101,7 @@ func initBuiltInApplication() {
|
|||||||
Logo: "https://cdn.casbin.com/logo/logo_1024x256.png",
|
Logo: "https://cdn.casbin.com/logo/logo_1024x256.png",
|
||||||
HomepageUrl: "https://casdoor.org",
|
HomepageUrl: "https://casdoor.org",
|
||||||
Organization: "built-in",
|
Organization: "built-in",
|
||||||
|
Cert: "cert-built-in",
|
||||||
EnablePassword: true,
|
EnablePassword: true,
|
||||||
EnableSignUp: true,
|
EnableSignUp: true,
|
||||||
Providers: []*ProviderItem{},
|
Providers: []*ProviderItem{},
|
||||||
@@ -109,6 +121,28 @@ func initBuiltInApplication() {
|
|||||||
AddApplication(application)
|
AddApplication(application)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func initBuiltInCert() {
|
||||||
|
cert := getCert("admin", "cert-built-in")
|
||||||
|
if cert != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cert = &Cert{
|
||||||
|
Owner: "admin",
|
||||||
|
Name: "cert-built-in",
|
||||||
|
CreatedTime: util.GetCurrentTime(),
|
||||||
|
DisplayName: "Built-in Cert",
|
||||||
|
Scope: "JWT",
|
||||||
|
Type: "x509",
|
||||||
|
CryptoAlgorithm: "RSA",
|
||||||
|
BitSize: 4096,
|
||||||
|
ExpireInYears: 20,
|
||||||
|
PublicKey: tokenJwtPublicKey,
|
||||||
|
PrivateKey: tokenJwtPrivateKey,
|
||||||
|
}
|
||||||
|
AddCert(cert)
|
||||||
|
}
|
||||||
|
|
||||||
func initBuiltInLdap() {
|
func initBuiltInLdap() {
|
||||||
ldap := GetLdap("ldap-built-in")
|
ldap := GetLdap("ldap-built-in")
|
||||||
if ldap != nil {
|
if ldap != nil {
|
||||||
|
@@ -72,13 +72,15 @@ func GetOidcDiscovery() OidcDiscovery {
|
|||||||
return oidcDiscovery
|
return oidcDiscovery
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetJSONWebKeySet() (jose.JSONWebKeySet, error) {
|
func GetJsonWebKeySet() (jose.JSONWebKeySet, error) {
|
||||||
|
cert := GetDefaultCert()
|
||||||
|
|
||||||
//follows the protocol rfc 7517(draft)
|
//follows the protocol rfc 7517(draft)
|
||||||
//link here: https://self-issued.info/docs/draft-ietf-jose-json-web-key.html
|
//link here: https://self-issued.info/docs/draft-ietf-jose-json-web-key.html
|
||||||
//or https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key
|
//or https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key
|
||||||
certPEMBlock := []byte(tokenJwtPublicKey)
|
certPemBlock := []byte(cert.PublicKey)
|
||||||
certDERBlock, _ := pem.Decode(certPEMBlock)
|
certDerBlock, _ := pem.Decode(certPemBlock)
|
||||||
x509Cert, _ := x509.ParseCertificate(certDERBlock.Bytes)
|
x509Cert, _ := x509.ParseCertificate(certDerBlock.Bytes)
|
||||||
|
|
||||||
var jwk jose.JSONWebKey
|
var jwk jose.JSONWebKey
|
||||||
jwk.Key = x509Cert.PublicKey
|
jwk.Key = x509Cert.PublicKey
|
||||||
|
@@ -332,7 +332,9 @@ func RefreshToken(grantType string, refreshToken string, scope string, clientId
|
|||||||
Code: "",
|
Code: "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
claims, err := ParseJwtToken(refreshToken)
|
|
||||||
|
cert := getCertByApplication(application)
|
||||||
|
claims, err := ParseJwtToken(refreshToken, cert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &Code{
|
return &Code{
|
||||||
Message: "error: invalid refresh_token",
|
Message: "error: invalid refresh_token",
|
||||||
|
@@ -23,12 +23,6 @@ import (
|
|||||||
"github.com/golang-jwt/jwt/v4"
|
"github.com/golang-jwt/jwt/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed token_jwt_key.pem
|
|
||||||
var tokenJwtPublicKey string
|
|
||||||
|
|
||||||
//go:embed token_jwt_key.key
|
|
||||||
var tokenJwtPrivateKey string
|
|
||||||
|
|
||||||
type Claims struct {
|
type Claims struct {
|
||||||
*User
|
*User
|
||||||
Name string `json:"name,omitempty"`
|
Name string `json:"name,omitempty"`
|
||||||
@@ -68,9 +62,10 @@ func generateJwtToken(application *Application, user *User, nonce string) (strin
|
|||||||
claims.ExpiresAt = jwt.NewNumericDate(refreshExpireTime)
|
claims.ExpiresAt = jwt.NewNumericDate(refreshExpireTime)
|
||||||
refreshToken := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
|
refreshToken := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
|
||||||
|
|
||||||
// Use "token_jwt_key.key" as RSA private key
|
cert := getCertByApplication(application)
|
||||||
privateKey := tokenJwtPrivateKey
|
|
||||||
key, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(privateKey))
|
// RSA private key
|
||||||
|
key, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(cert.PrivateKey))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", "", err
|
return "", "", err
|
||||||
}
|
}
|
||||||
@@ -84,14 +79,14 @@ func generateJwtToken(application *Application, user *User, nonce string) (strin
|
|||||||
return tokenString, refreshTokenString, err
|
return tokenString, refreshTokenString, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseJwtToken(token string) (*Claims, error) {
|
func ParseJwtToken(token string, cert *Cert) (*Claims, error) {
|
||||||
t, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
|
t, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
|
||||||
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
|
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
|
||||||
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use "token_jwt_key.pem" as RSA public key
|
// RSA public key
|
||||||
publicKey, err := jwt.ParseRSAPublicKeyFromPEM([]byte(tokenJwtPublicKey))
|
publicKey, err := jwt.ParseRSAPublicKeyFromPEM([]byte(cert.PublicKey))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@@ -20,19 +20,14 @@ import (
|
|||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"crypto/x509/pkix"
|
"crypto/x509/pkix"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/casbin/casdoor/util"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func generateRsaKeys(fileId string) {
|
func generateRsaKeys(bitSize int, expireInYears int, commonName string, organization string) (string, string) {
|
||||||
// https://stackoverflow.com/questions/64104586/use-golang-to-get-rsa-key-the-same-way-openssl-genrsa
|
// https://stackoverflow.com/questions/64104586/use-golang-to-get-rsa-key-the-same-way-openssl-genrsa
|
||||||
// https://stackoverflow.com/questions/43822945/golang-can-i-create-x509keypair-using-rsa-key
|
// https://stackoverflow.com/questions/43822945/golang-can-i-create-x509keypair-using-rsa-key
|
||||||
|
|
||||||
bitSize := 4096
|
|
||||||
|
|
||||||
// Generate RSA key.
|
// Generate RSA key.
|
||||||
key, err := rsa.GenerateKey(rand.Reader, bitSize)
|
key, err := rsa.GenerateKey(rand.Reader, bitSize)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -50,12 +45,12 @@ func generateRsaKeys(fileId string) {
|
|||||||
tml := x509.Certificate{
|
tml := x509.Certificate{
|
||||||
// you can add any attr that you need
|
// you can add any attr that you need
|
||||||
NotBefore: time.Now(),
|
NotBefore: time.Now(),
|
||||||
NotAfter: time.Now().AddDate(20, 0, 0),
|
NotAfter: time.Now().AddDate(expireInYears, 0, 0),
|
||||||
// you have to generate a different serial number each execution
|
// you have to generate a different serial number each execution
|
||||||
SerialNumber: big.NewInt(123456),
|
SerialNumber: big.NewInt(123456),
|
||||||
Subject: pkix.Name{
|
Subject: pkix.Name{
|
||||||
CommonName: "Casdoor Cert",
|
CommonName: commonName,
|
||||||
Organization: []string{"Casdoor Organization"},
|
Organization: []string{organization},
|
||||||
},
|
},
|
||||||
BasicConstraintsValid: true,
|
BasicConstraintsValid: true,
|
||||||
}
|
}
|
||||||
@@ -70,9 +65,5 @@ func generateRsaKeys(fileId string) {
|
|||||||
Bytes: cert,
|
Bytes: cert,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Write private key to file.
|
return string(certPem), string(privateKeyPem)
|
||||||
util.WriteBytesToPath(privateKeyPem, fmt.Sprintf("%s.key", fileId))
|
|
||||||
|
|
||||||
// Write certificate (aka public key) to file.
|
|
||||||
util.WriteBytesToPath(certPem, fmt.Sprintf("%s.pem", fileId))
|
|
||||||
}
|
}
|
||||||
|
@@ -14,9 +14,20 @@
|
|||||||
|
|
||||||
package object
|
package object
|
||||||
|
|
||||||
import "testing"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/casbin/casdoor/util"
|
||||||
|
)
|
||||||
|
|
||||||
func TestGenerateRsaKeys(t *testing.T) {
|
func TestGenerateRsaKeys(t *testing.T) {
|
||||||
fileId := "token_jwt_key"
|
fileId := "token_jwt_key"
|
||||||
generateRsaKeys(fileId)
|
publicKey, privateKey := generateRsaKeys(4096, 20, "Casdoor Cert", "Casdoor Organization")
|
||||||
|
|
||||||
|
// Write certificate (aka public key) to file.
|
||||||
|
util.WriteStringToPath(publicKey, fmt.Sprintf("%s.pem", fileId))
|
||||||
|
|
||||||
|
// Write private key to file.
|
||||||
|
util.WriteStringToPath(privateKey, fmt.Sprintf("%s.key", fileId))
|
||||||
}
|
}
|
||||||
|
@@ -31,7 +31,8 @@ func AutoSigninFilter(ctx *context.Context) {
|
|||||||
// "/page?access_token=123"
|
// "/page?access_token=123"
|
||||||
accessToken := ctx.Input.Query("accessToken")
|
accessToken := ctx.Input.Query("accessToken")
|
||||||
if accessToken != "" {
|
if accessToken != "" {
|
||||||
claims, err := object.ParseJwtToken(accessToken)
|
cert := object.GetDefaultCert()
|
||||||
|
claims, err := object.ParseJwtToken(accessToken, cert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
responseError(ctx, "invalid JWT token")
|
responseError(ctx, "invalid JWT token")
|
||||||
return
|
return
|
||||||
@@ -71,7 +72,8 @@ func AutoSigninFilter(ctx *context.Context) {
|
|||||||
// Authorization: Bearer bearerToken
|
// Authorization: Bearer bearerToken
|
||||||
bearerToken := parseBearerToken(ctx)
|
bearerToken := parseBearerToken(ctx)
|
||||||
if bearerToken != "" {
|
if bearerToken != "" {
|
||||||
claims, err := object.ParseJwtToken(bearerToken)
|
cert := object.GetDefaultCert()
|
||||||
|
claims, err := object.ParseJwtToken(bearerToken, cert)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
responseError(ctx, err.Error())
|
responseError(ctx, err.Error())
|
||||||
return
|
return
|
||||||
|
@@ -137,7 +137,7 @@ class UserListPage extends BaseListPage {
|
|||||||
title: i18next.t("general:Name"),
|
title: i18next.t("general:Name"),
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
key: 'name',
|
key: 'name',
|
||||||
width: (Setting.isMobile()) ? "80px" : "100px",
|
width: (Setting.isMobile()) ? "80px" : "110px",
|
||||||
fixed: 'left',
|
fixed: 'left',
|
||||||
sorter: true,
|
sorter: true,
|
||||||
...this.getColumnSearchProps('name'),
|
...this.getColumnSearchProps('name'),
|
||||||
|
@@ -33,6 +33,29 @@
|
|||||||
"Token format": "Token format",
|
"Token format": "Token format",
|
||||||
"Token format - Tooltip": "Token format - Tooltip"
|
"Token format - Tooltip": "Token format - Tooltip"
|
||||||
},
|
},
|
||||||
|
"cert": {
|
||||||
|
"Bit size": "Bit size",
|
||||||
|
"Bit size - Tooltip": "Bit size - Tooltip",
|
||||||
|
"Copy private key": "Copy private key",
|
||||||
|
"Copy public key": "Copy public key",
|
||||||
|
"Crypto algorithm": "Crypto algorithm",
|
||||||
|
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
|
||||||
|
"Download private key": "Download private key",
|
||||||
|
"Download public key": "Download public key",
|
||||||
|
"Edit Cert": "Edit Cert",
|
||||||
|
"Expire in years": "Expire in years",
|
||||||
|
"Expire in years - Tooltip": "Expire in years - Tooltip",
|
||||||
|
"Private key": "Private key",
|
||||||
|
"Private key - Tooltip": "Private key - Tooltip",
|
||||||
|
"Private key copied to clipboard successfully": "Private key copied to clipboard successfully",
|
||||||
|
"Public key": "Public key",
|
||||||
|
"Public key - Tooltip": "Public key - Tooltip",
|
||||||
|
"Public key copied to clipboard successfully": "Public key copied to clipboard successfully",
|
||||||
|
"Scope": "Scope",
|
||||||
|
"Scope - Tooltip": "Scope - Tooltip",
|
||||||
|
"Type": "Type",
|
||||||
|
"Type - Tooltip": "Type - Tooltip"
|
||||||
|
},
|
||||||
"code": {
|
"code": {
|
||||||
"Code You Received": "Code You Received",
|
"Code You Received": "Code You Received",
|
||||||
"Email code": "Email code",
|
"Email code": "Email code",
|
||||||
@@ -69,6 +92,7 @@
|
|||||||
"Avatar - Tooltip": "Avatar to show to others",
|
"Avatar - Tooltip": "Avatar to show to others",
|
||||||
"Back Home": "Back Home",
|
"Back Home": "Back Home",
|
||||||
"Captcha": "Captcha",
|
"Captcha": "Captcha",
|
||||||
|
"Certs": "Certs",
|
||||||
"Client IP": "Client IP",
|
"Client IP": "Client IP",
|
||||||
"Created time": "Created time",
|
"Created time": "Created time",
|
||||||
"Default avatar": "Default avatar",
|
"Default avatar": "Default avatar",
|
||||||
|
@@ -33,6 +33,29 @@
|
|||||||
"Token format": "Token format",
|
"Token format": "Token format",
|
||||||
"Token format - Tooltip": "Token format - Tooltip"
|
"Token format - Tooltip": "Token format - Tooltip"
|
||||||
},
|
},
|
||||||
|
"cert": {
|
||||||
|
"Bit size": "Bit size",
|
||||||
|
"Bit size - Tooltip": "Bit size - Tooltip",
|
||||||
|
"Copy private key": "Copy private key",
|
||||||
|
"Copy public key": "Copy public key",
|
||||||
|
"Crypto algorithm": "Crypto algorithm",
|
||||||
|
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
|
||||||
|
"Download private key": "Download private key",
|
||||||
|
"Download public key": "Download public key",
|
||||||
|
"Edit Cert": "Edit Cert",
|
||||||
|
"Expire in years": "Expire in years",
|
||||||
|
"Expire in years - Tooltip": "Expire in years - Tooltip",
|
||||||
|
"Private key": "Private key",
|
||||||
|
"Private key - Tooltip": "Private key - Tooltip",
|
||||||
|
"Private key copied to clipboard successfully": "Private key copied to clipboard successfully",
|
||||||
|
"Public key": "Public key",
|
||||||
|
"Public key - Tooltip": "Public key - Tooltip",
|
||||||
|
"Public key copied to clipboard successfully": "Public key copied to clipboard successfully",
|
||||||
|
"Scope": "Scope",
|
||||||
|
"Scope - Tooltip": "Scope - Tooltip",
|
||||||
|
"Type": "Type",
|
||||||
|
"Type - Tooltip": "Type - Tooltip"
|
||||||
|
},
|
||||||
"code": {
|
"code": {
|
||||||
"Code You Received": "Code You Received",
|
"Code You Received": "Code You Received",
|
||||||
"Email code": "Email code",
|
"Email code": "Email code",
|
||||||
@@ -69,6 +92,7 @@
|
|||||||
"Avatar - Tooltip": "Avatar - Tooltip",
|
"Avatar - Tooltip": "Avatar - Tooltip",
|
||||||
"Back Home": "Back Home",
|
"Back Home": "Back Home",
|
||||||
"Captcha": "Captcha",
|
"Captcha": "Captcha",
|
||||||
|
"Certs": "Certs",
|
||||||
"Client IP": "Client IP",
|
"Client IP": "Client IP",
|
||||||
"Created time": "Created time",
|
"Created time": "Created time",
|
||||||
"Default avatar": "Default avatar",
|
"Default avatar": "Default avatar",
|
||||||
|
@@ -33,6 +33,29 @@
|
|||||||
"Token format": "Token format",
|
"Token format": "Token format",
|
||||||
"Token format - Tooltip": "Token format - Tooltip"
|
"Token format - Tooltip": "Token format - Tooltip"
|
||||||
},
|
},
|
||||||
|
"cert": {
|
||||||
|
"Bit size": "Bit size",
|
||||||
|
"Bit size - Tooltip": "Bit size - Tooltip",
|
||||||
|
"Copy private key": "Copy private key",
|
||||||
|
"Copy public key": "Copy public key",
|
||||||
|
"Crypto algorithm": "Crypto algorithm",
|
||||||
|
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
|
||||||
|
"Download private key": "Download private key",
|
||||||
|
"Download public key": "Download public key",
|
||||||
|
"Edit Cert": "Edit Cert",
|
||||||
|
"Expire in years": "Expire in years",
|
||||||
|
"Expire in years - Tooltip": "Expire in years - Tooltip",
|
||||||
|
"Private key": "Private key",
|
||||||
|
"Private key - Tooltip": "Private key - Tooltip",
|
||||||
|
"Private key copied to clipboard successfully": "Private key copied to clipboard successfully",
|
||||||
|
"Public key": "Public key",
|
||||||
|
"Public key - Tooltip": "Public key - Tooltip",
|
||||||
|
"Public key copied to clipboard successfully": "Public key copied to clipboard successfully",
|
||||||
|
"Scope": "Scope",
|
||||||
|
"Scope - Tooltip": "Scope - Tooltip",
|
||||||
|
"Type": "Type",
|
||||||
|
"Type - Tooltip": "Type - Tooltip"
|
||||||
|
},
|
||||||
"code": {
|
"code": {
|
||||||
"Code You Received": "Code You Received",
|
"Code You Received": "Code You Received",
|
||||||
"Email code": "Email code",
|
"Email code": "Email code",
|
||||||
@@ -69,6 +92,7 @@
|
|||||||
"Avatar - Tooltip": "Avatar to show to others",
|
"Avatar - Tooltip": "Avatar to show to others",
|
||||||
"Back Home": "Back Home",
|
"Back Home": "Back Home",
|
||||||
"Captcha": "Captcha",
|
"Captcha": "Captcha",
|
||||||
|
"Certs": "Certs",
|
||||||
"Client IP": "Client IP",
|
"Client IP": "Client IP",
|
||||||
"Created time": "Created time",
|
"Created time": "Created time",
|
||||||
"Default avatar": "Default avatar",
|
"Default avatar": "Default avatar",
|
||||||
|
@@ -33,6 +33,29 @@
|
|||||||
"Token format": "Token format",
|
"Token format": "Token format",
|
||||||
"Token format - Tooltip": "Token format - Tooltip"
|
"Token format - Tooltip": "Token format - Tooltip"
|
||||||
},
|
},
|
||||||
|
"cert": {
|
||||||
|
"Bit size": "Bit size",
|
||||||
|
"Bit size - Tooltip": "Bit size - Tooltip",
|
||||||
|
"Copy private key": "Copy private key",
|
||||||
|
"Copy public key": "Copy public key",
|
||||||
|
"Crypto algorithm": "Crypto algorithm",
|
||||||
|
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
|
||||||
|
"Download private key": "Download private key",
|
||||||
|
"Download public key": "Download public key",
|
||||||
|
"Edit Cert": "Edit Cert",
|
||||||
|
"Expire in years": "Expire in years",
|
||||||
|
"Expire in years - Tooltip": "Expire in years - Tooltip",
|
||||||
|
"Private key": "Private key",
|
||||||
|
"Private key - Tooltip": "Private key - Tooltip",
|
||||||
|
"Private key copied to clipboard successfully": "Private key copied to clipboard successfully",
|
||||||
|
"Public key": "Public key",
|
||||||
|
"Public key - Tooltip": "Public key - Tooltip",
|
||||||
|
"Public key copied to clipboard successfully": "Public key copied to clipboard successfully",
|
||||||
|
"Scope": "Scope",
|
||||||
|
"Scope - Tooltip": "Scope - Tooltip",
|
||||||
|
"Type": "Type",
|
||||||
|
"Type - Tooltip": "Type - Tooltip"
|
||||||
|
},
|
||||||
"code": {
|
"code": {
|
||||||
"Code You Received": "Code You Received",
|
"Code You Received": "Code You Received",
|
||||||
"Email code": "Email code",
|
"Email code": "Email code",
|
||||||
@@ -69,6 +92,7 @@
|
|||||||
"Avatar - Tooltip": "Avatar to show to others",
|
"Avatar - Tooltip": "Avatar to show to others",
|
||||||
"Back Home": "Back Home",
|
"Back Home": "Back Home",
|
||||||
"Captcha": "Captcha",
|
"Captcha": "Captcha",
|
||||||
|
"Certs": "Certs",
|
||||||
"Client IP": "Client IP",
|
"Client IP": "Client IP",
|
||||||
"Created time": "Created time",
|
"Created time": "Created time",
|
||||||
"Default avatar": "Default avatar",
|
"Default avatar": "Default avatar",
|
||||||
|
@@ -33,6 +33,29 @@
|
|||||||
"Token format": "Token format",
|
"Token format": "Token format",
|
||||||
"Token format - Tooltip": "Token format - Tooltip"
|
"Token format - Tooltip": "Token format - Tooltip"
|
||||||
},
|
},
|
||||||
|
"cert": {
|
||||||
|
"Bit size": "Bit size",
|
||||||
|
"Bit size - Tooltip": "Bit size - Tooltip",
|
||||||
|
"Copy private key": "Copy private key",
|
||||||
|
"Copy public key": "Copy public key",
|
||||||
|
"Crypto algorithm": "Crypto algorithm",
|
||||||
|
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
|
||||||
|
"Download private key": "Download private key",
|
||||||
|
"Download public key": "Download public key",
|
||||||
|
"Edit Cert": "Edit Cert",
|
||||||
|
"Expire in years": "Expire in years",
|
||||||
|
"Expire in years - Tooltip": "Expire in years - Tooltip",
|
||||||
|
"Private key": "Private key",
|
||||||
|
"Private key - Tooltip": "Private key - Tooltip",
|
||||||
|
"Private key copied to clipboard successfully": "Private key copied to clipboard successfully",
|
||||||
|
"Public key": "Public key",
|
||||||
|
"Public key - Tooltip": "Public key - Tooltip",
|
||||||
|
"Public key copied to clipboard successfully": "Public key copied to clipboard successfully",
|
||||||
|
"Scope": "Scope",
|
||||||
|
"Scope - Tooltip": "Scope - Tooltip",
|
||||||
|
"Type": "Type",
|
||||||
|
"Type - Tooltip": "Type - Tooltip"
|
||||||
|
},
|
||||||
"code": {
|
"code": {
|
||||||
"Code You Received": "Code You Received",
|
"Code You Received": "Code You Received",
|
||||||
"Email code": "Email code",
|
"Email code": "Email code",
|
||||||
@@ -69,6 +92,7 @@
|
|||||||
"Avatar - Tooltip": "Avatar to show to others",
|
"Avatar - Tooltip": "Avatar to show to others",
|
||||||
"Back Home": "Back Home",
|
"Back Home": "Back Home",
|
||||||
"Captcha": "Captcha",
|
"Captcha": "Captcha",
|
||||||
|
"Certs": "Certs",
|
||||||
"Client IP": "Client IP",
|
"Client IP": "Client IP",
|
||||||
"Created time": "Created time",
|
"Created time": "Created time",
|
||||||
"Default avatar": "Default avatar",
|
"Default avatar": "Default avatar",
|
||||||
|
@@ -33,6 +33,29 @@
|
|||||||
"Token format": "Token format",
|
"Token format": "Token format",
|
||||||
"Token format - Tooltip": "Token format - Tooltip"
|
"Token format - Tooltip": "Token format - Tooltip"
|
||||||
},
|
},
|
||||||
|
"cert": {
|
||||||
|
"Bit size": "Bit size",
|
||||||
|
"Bit size - Tooltip": "Bit size - Tooltip",
|
||||||
|
"Copy private key": "Copy private key",
|
||||||
|
"Copy public key": "Copy public key",
|
||||||
|
"Crypto algorithm": "Crypto algorithm",
|
||||||
|
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
|
||||||
|
"Download private key": "Download private key",
|
||||||
|
"Download public key": "Download public key",
|
||||||
|
"Edit Cert": "Edit Cert",
|
||||||
|
"Expire in years": "Expire in years",
|
||||||
|
"Expire in years - Tooltip": "Expire in years - Tooltip",
|
||||||
|
"Private key": "Private key",
|
||||||
|
"Private key - Tooltip": "Private key - Tooltip",
|
||||||
|
"Private key copied to clipboard successfully": "Private key copied to clipboard successfully",
|
||||||
|
"Public key": "Public key",
|
||||||
|
"Public key - Tooltip": "Public key - Tooltip",
|
||||||
|
"Public key copied to clipboard successfully": "Public key copied to clipboard successfully",
|
||||||
|
"Scope": "Scope",
|
||||||
|
"Scope - Tooltip": "Scope - Tooltip",
|
||||||
|
"Type": "Type",
|
||||||
|
"Type - Tooltip": "Type - Tooltip"
|
||||||
|
},
|
||||||
"code": {
|
"code": {
|
||||||
"Code You Received": "Code You Received",
|
"Code You Received": "Code You Received",
|
||||||
"Email code": "Email code",
|
"Email code": "Email code",
|
||||||
@@ -69,6 +92,7 @@
|
|||||||
"Avatar - Tooltip": "Avatar to show to others",
|
"Avatar - Tooltip": "Avatar to show to others",
|
||||||
"Back Home": "Back Home",
|
"Back Home": "Back Home",
|
||||||
"Captcha": "Captcha",
|
"Captcha": "Captcha",
|
||||||
|
"Certs": "Certs",
|
||||||
"Client IP": "Client IP",
|
"Client IP": "Client IP",
|
||||||
"Created time": "Created time",
|
"Created time": "Created time",
|
||||||
"Default avatar": "Default avatar",
|
"Default avatar": "Default avatar",
|
||||||
|
@@ -33,6 +33,29 @@
|
|||||||
"Token format": "Access Token格式",
|
"Token format": "Access Token格式",
|
||||||
"Token format - Tooltip": "Access Token格式"
|
"Token format - Tooltip": "Access Token格式"
|
||||||
},
|
},
|
||||||
|
"cert": {
|
||||||
|
"Bit size": "位大小",
|
||||||
|
"Bit size - Tooltip": "Bit size - Tooltip",
|
||||||
|
"Copy private key": "复制私钥",
|
||||||
|
"Copy public key": "复制公钥",
|
||||||
|
"Crypto algorithm": "加密算法",
|
||||||
|
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
|
||||||
|
"Download private key": "下载私钥",
|
||||||
|
"Download public key": "下载公钥",
|
||||||
|
"Edit Cert": "修改证书",
|
||||||
|
"Expire in years": "有效期(年)",
|
||||||
|
"Expire in years - Tooltip": "Expire in years - Tooltip",
|
||||||
|
"Private key": "私钥",
|
||||||
|
"Private key - Tooltip": "Private key - Tooltip",
|
||||||
|
"Private key copied to clipboard successfully": "私钥已成功复制到剪贴板",
|
||||||
|
"Public key": "公钥",
|
||||||
|
"Public key - Tooltip": "Public key - Tooltip",
|
||||||
|
"Public key copied to clipboard successfully": "公钥已成功复制到剪贴板",
|
||||||
|
"Scope": "用途",
|
||||||
|
"Scope - Tooltip": "Scope - Tooltip",
|
||||||
|
"Type": "类型",
|
||||||
|
"Type - Tooltip": "Type - Tooltip"
|
||||||
|
},
|
||||||
"code": {
|
"code": {
|
||||||
"Code You Received": "验证码",
|
"Code You Received": "验证码",
|
||||||
"Email code": "邮箱验证码",
|
"Email code": "邮箱验证码",
|
||||||
@@ -69,6 +92,7 @@
|
|||||||
"Avatar - Tooltip": "向其他人展示的头像",
|
"Avatar - Tooltip": "向其他人展示的头像",
|
||||||
"Back Home": "返回到首页",
|
"Back Home": "返回到首页",
|
||||||
"Captcha": "人机验证码",
|
"Captcha": "人机验证码",
|
||||||
|
"Certs": "证书",
|
||||||
"Client IP": "客户端IP",
|
"Client IP": "客户端IP",
|
||||||
"Created time": "创建时间",
|
"Created time": "创建时间",
|
||||||
"Default avatar": "默认头像",
|
"Default avatar": "默认头像",
|
||||||
|
Reference in New Issue
Block a user