mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-18 05:52:51 +00:00
fix: prevent possible nil pointer panics (#11728)
# Which Problems Are Solved We found multiple cases where potentially a panic occurred or could occur: - when de/encrypting certain information - returning apps without any configuration type (?) - apple IdPs without a proper private key # How the Problems Are Solved - Added nil checks - Check private key format for apple IdPs - Added necessary helper function # Additional Changes Fixed i18n yaml where the IDP errors were indented under `org` instead of directly under `errors`. # Additional Context - requires backport to v4.x --------- Co-authored-by: Marco A. <[email protected]>
This commit is contained in:
@@ -3,6 +3,9 @@
|
||||
package events_test
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
@@ -14,6 +17,7 @@ import (
|
||||
"github.com/zitadel/zitadel/backend/v3/domain"
|
||||
"github.com/zitadel/zitadel/backend/v3/storage/database"
|
||||
"github.com/zitadel/zitadel/backend/v3/storage/database/repository"
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
zitadel_internal_domain "github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/integration"
|
||||
"github.com/zitadel/zitadel/pkg/grpc/admin"
|
||||
@@ -2012,7 +2016,7 @@ func TestServer_TestIDProviderInstanceReduces(t *testing.T) {
|
||||
ClientId: "clientID",
|
||||
TeamId: "teamIDteam",
|
||||
KeyId: "keyIDKeyId",
|
||||
PrivateKey: []byte("privateKey"),
|
||||
PrivateKey: generatePrivateKeyPKCS8(t),
|
||||
Scopes: []string{"scope"},
|
||||
ProviderOptions: &idp_grpc.Options{
|
||||
IsLinkingAllowed: false,
|
||||
@@ -2064,7 +2068,7 @@ func TestServer_TestIDProviderInstanceReduces(t *testing.T) {
|
||||
ClientId: "clientID",
|
||||
TeamId: "teamIDteam",
|
||||
KeyId: "keyIDKeyId",
|
||||
PrivateKey: []byte("privateKey"),
|
||||
PrivateKey: generatePrivateKeyPKCS8(t),
|
||||
Scopes: []string{"scope"},
|
||||
ProviderOptions: &idp_grpc.Options{
|
||||
IsLinkingAllowed: false,
|
||||
@@ -2095,7 +2099,7 @@ func TestServer_TestIDProviderInstanceReduces(t *testing.T) {
|
||||
ClientId: "new_clientID",
|
||||
TeamId: "new_teamID",
|
||||
KeyId: "new_kKeyId",
|
||||
PrivateKey: []byte("new_privateKey"),
|
||||
PrivateKey: generatePrivateKeyPKCS8(t),
|
||||
Scopes: []string{"new_scope"},
|
||||
ProviderOptions: &idp_grpc.Options{
|
||||
IsLinkingAllowed: true,
|
||||
@@ -2361,3 +2365,11 @@ func defaultInstanceLDAPRequest(name string) *admin.AddLDAPProviderRequest {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func generatePrivateKeyPKCS8(t *testing.T) []byte {
|
||||
privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
require.NoError(t, err)
|
||||
data, err := crypto.PrivateKeyToBytesPKCS8(privateKey)
|
||||
require.NoError(t, err)
|
||||
return data
|
||||
}
|
||||
|
||||
@@ -1978,7 +1978,7 @@ func TestServer_TestIDProviderOrgReduces(t *testing.T) {
|
||||
ClientId: "clientID",
|
||||
TeamId: "teamIDteam",
|
||||
KeyId: "keyIDKeyId",
|
||||
PrivateKey: []byte("privateKey"),
|
||||
PrivateKey: generatePrivateKeyPKCS8(t),
|
||||
Scopes: []string{"scope"},
|
||||
ProviderOptions: &idp_grpc.Options{
|
||||
IsLinkingAllowed: false,
|
||||
@@ -2030,7 +2030,7 @@ func TestServer_TestIDProviderOrgReduces(t *testing.T) {
|
||||
ClientId: "clientID",
|
||||
TeamId: "teamIDteam",
|
||||
KeyId: "keyIDKeyId",
|
||||
PrivateKey: []byte("privateKey"),
|
||||
PrivateKey: generatePrivateKeyPKCS8(t),
|
||||
Scopes: []string{"scope"},
|
||||
ProviderOptions: &idp_grpc.Options{
|
||||
IsLinkingAllowed: false,
|
||||
@@ -2061,7 +2061,7 @@ func TestServer_TestIDProviderOrgReduces(t *testing.T) {
|
||||
ClientId: "new_clientID",
|
||||
TeamId: "new_teamID",
|
||||
KeyId: "new_kKeyId",
|
||||
PrivateKey: []byte("new_privateKey"),
|
||||
PrivateKey: generatePrivateKeyPKCS8(t),
|
||||
Scopes: []string{"new_scope"},
|
||||
ProviderOptions: &idp_grpc.Options{
|
||||
IsLinkingAllowed: true,
|
||||
|
||||
@@ -38,7 +38,10 @@ func AppConfigToPb(app *query.App) app_pb.AppConfig {
|
||||
if app.SAMLConfig != nil {
|
||||
return AppSAMLConfigToPb(app.SAMLConfig)
|
||||
}
|
||||
return AppAPIConfigToPb(app.APIConfig)
|
||||
if app.APIConfig != nil {
|
||||
return AppAPIConfigToPb(app.APIConfig)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func AppOIDCConfigToPb(app *query.OIDCApp) *app_pb.App_OidcConfig {
|
||||
|
||||
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/idp/providers/apple"
|
||||
"github.com/zitadel/zitadel/internal/idp/providers/saml"
|
||||
"github.com/zitadel/zitadel/internal/repository/instance"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
@@ -1668,6 +1669,9 @@ func (c *Commands) prepareAddInstanceAppleProvider(a *instance.Aggregate, writeM
|
||||
if len(provider.PrivateKey) == 0 {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "INST-GVD4n", "Errors.IDP.PrivateKeyMissing")
|
||||
}
|
||||
if _, err := apple.BytesToPrivateKey(provider.PrivateKey); err != nil {
|
||||
return nil, zerrors.ThrowInvalidArgument(err, "INST-Fk38d", "Errors.IDP.InvalidPrivateKey")
|
||||
}
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
if err != nil {
|
||||
@@ -1713,6 +1717,11 @@ func (c *Commands) prepareUpdateInstanceAppleProvider(a *instance.Aggregate, wri
|
||||
if provider.KeyID = strings.TrimSpace(provider.KeyID); provider.KeyID == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "INST-Gh4z2", "Errors.IDP.KeyIDMissing")
|
||||
}
|
||||
if len(provider.PrivateKey) > 0 {
|
||||
if _, err := apple.BytesToPrivateKey(provider.PrivateKey); err != nil {
|
||||
return nil, zerrors.ThrowInvalidArgument(err, "INST-eWSDf", "Errors.IDP.InvalidPrivateKey")
|
||||
}
|
||||
}
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
if err != nil {
|
||||
|
||||
@@ -2,6 +2,9 @@ package command
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -4893,6 +4896,14 @@ func TestCommandSide_UpdateInstanceLDAPIDP(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
privateKeyPKCS8 = func() []byte {
|
||||
privateKey, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
|
||||
data, _ := crypto.PrivateKeyToBytesPKCS8(privateKey)
|
||||
return data
|
||||
}()
|
||||
)
|
||||
|
||||
func TestCommandSide_AddInstanceAppleIDP(t *testing.T) {
|
||||
type fields struct {
|
||||
eventstore func(*testing.T) *eventstore.Eventstore
|
||||
@@ -4906,7 +4917,7 @@ func TestCommandSide_AddInstanceAppleIDP(t *testing.T) {
|
||||
type res struct {
|
||||
id string
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
err error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -4925,9 +4936,7 @@ func TestCommandSide_AddInstanceAppleIDP(t *testing.T) {
|
||||
provider: AppleProvider{},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, zerrors.ThrowInvalidArgument(nil, "INST-jkn3w", "Errors.IDP.ClientIDMissing"))
|
||||
},
|
||||
err: zerrors.ThrowInvalidArgument(nil, "INST-jkn3w", "Errors.IDP.ClientIDMissing"),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -4943,9 +4952,7 @@ func TestCommandSide_AddInstanceAppleIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, zerrors.ThrowInvalidArgument(nil, "INST-Ffg32", "Errors.IDP.TeamIDMissing"))
|
||||
},
|
||||
err: zerrors.ThrowInvalidArgument(nil, "INST-Ffg32", "Errors.IDP.TeamIDMissing"),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -4962,13 +4969,11 @@ func TestCommandSide_AddInstanceAppleIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, zerrors.ThrowInvalidArgument(nil, "INST-GDjm5", "Errors.IDP.KeyIDMissing"))
|
||||
},
|
||||
err: zerrors.ThrowInvalidArgument(nil, "INST-GDjm5", "Errors.IDP.KeyIDMissing"),
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid privateKey",
|
||||
"no privateKey",
|
||||
fields{
|
||||
eventstore: expectEventstore(),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
@@ -4982,10 +4987,27 @@ func TestCommandSide_AddInstanceAppleIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, zerrors.ThrowInvalidArgument(nil, "INST-GVD4n", "Errors.IDP.PrivateKeyMissing"))
|
||||
err: zerrors.ThrowInvalidArgument(nil, "INST-GVD4n", "Errors.IDP.PrivateKeyMissing"),
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid privateKey",
|
||||
fields{
|
||||
eventstore: expectEventstore(),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
provider: AppleProvider{
|
||||
ClientID: "clientID",
|
||||
TeamID: "teamID",
|
||||
KeyID: "keyID",
|
||||
PrivateKey: []byte("invalid"),
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: zerrors.ThrowInvalidArgument(crypto.ErrEmpty, "INST-Fk38d", "Errors.IDP.InvalidPrivateKey"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ok",
|
||||
@@ -5003,7 +5025,7 @@ func TestCommandSide_AddInstanceAppleIDP(t *testing.T) {
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("privateKey"),
|
||||
Crypted: privateKeyPKCS8,
|
||||
},
|
||||
nil,
|
||||
idp.Options{},
|
||||
@@ -5019,7 +5041,7 @@ func TestCommandSide_AddInstanceAppleIDP(t *testing.T) {
|
||||
ClientID: "clientID",
|
||||
TeamID: "teamID",
|
||||
KeyID: "keyID",
|
||||
PrivateKey: []byte("privateKey"),
|
||||
PrivateKey: privateKeyPKCS8,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@@ -5043,7 +5065,7 @@ func TestCommandSide_AddInstanceAppleIDP(t *testing.T) {
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("privateKey"),
|
||||
Crypted: privateKeyPKCS8,
|
||||
},
|
||||
[]string{"name", "email"},
|
||||
idp.Options{
|
||||
@@ -5064,7 +5086,7 @@ func TestCommandSide_AddInstanceAppleIDP(t *testing.T) {
|
||||
ClientID: "clientID",
|
||||
TeamID: "teamID",
|
||||
KeyID: "keyID",
|
||||
PrivateKey: []byte("privateKey"),
|
||||
PrivateKey: privateKeyPKCS8,
|
||||
Scopes: []string{"name", "email"},
|
||||
IDPOptions: idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
@@ -5088,12 +5110,7 @@ func TestCommandSide_AddInstanceAppleIDP(t *testing.T) {
|
||||
idpConfigEncryption: tt.fields.secretCrypto,
|
||||
}
|
||||
id, got, err := c.AddInstanceAppleProvider(tt.args.ctx, tt.args.provider)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.res.err != nil && !tt.res.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
assert.ErrorIs(t, err, tt.res.err)
|
||||
if tt.res.err == nil {
|
||||
assert.Equal(t, tt.res.id, id)
|
||||
assertObjectDetails(t, tt.res.want, got)
|
||||
@@ -5114,7 +5131,7 @@ func TestCommandSide_UpdateInstanceAppleIDP(t *testing.T) {
|
||||
}
|
||||
type res struct {
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
err error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -5132,9 +5149,7 @@ func TestCommandSide_UpdateInstanceAppleIDP(t *testing.T) {
|
||||
provider: AppleProvider{},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, zerrors.ThrowInvalidArgument(nil, "INST-FRHBH", "Errors.IDMissing"))
|
||||
},
|
||||
err: zerrors.ThrowInvalidArgument(nil, "INST-FRHBH", "Errors.IDMissing"),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -5148,9 +5163,7 @@ func TestCommandSide_UpdateInstanceAppleIDP(t *testing.T) {
|
||||
provider: AppleProvider{},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, zerrors.ThrowInvalidArgument(nil, "INST-SFm4l", "Errors.IDP.ClientIDMissing"))
|
||||
},
|
||||
err: zerrors.ThrowInvalidArgument(nil, "INST-SFm4l", "Errors.IDP.ClientIDMissing"),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -5166,9 +5179,7 @@ func TestCommandSide_UpdateInstanceAppleIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, zerrors.ThrowInvalidArgument(nil, "INST-SG34t", "Errors.IDP.TeamIDMissing"))
|
||||
},
|
||||
err: zerrors.ThrowInvalidArgument(nil, "INST-SG34t", "Errors.IDP.TeamIDMissing"),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -5185,10 +5196,27 @@ func TestCommandSide_UpdateInstanceAppleIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, zerrors.ThrowInvalidArgument(nil, "INST-Gh4z2", "Errors.IDP.KeyIDMissing"))
|
||||
err: zerrors.ThrowInvalidArgument(nil, "INST-Gh4z2", "Errors.IDP.KeyIDMissing"),
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid key",
|
||||
fields{
|
||||
eventstore: expectEventstore(),
|
||||
},
|
||||
args{
|
||||
ctx: authz.WithInstanceID(context.Background(), "instance1"),
|
||||
id: "id1",
|
||||
provider: AppleProvider{
|
||||
ClientID: "clientID",
|
||||
TeamID: "teamID",
|
||||
KeyID: "keyID",
|
||||
PrivateKey: []byte("invalid"),
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: zerrors.ThrowInvalidArgument(nil, "INST-eWSDf", "Errors.IDP.InvalidPrivateKey"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "not found",
|
||||
@@ -5207,7 +5235,7 @@ func TestCommandSide_UpdateInstanceAppleIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: zerrors.IsNotFound,
|
||||
err: zerrors.ThrowNotFound(nil, "INST-SG3bh", "Errors.IDPConfig.NotExisting"),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -5282,7 +5310,7 @@ func TestCommandSide_UpdateInstanceAppleIDP(t *testing.T) {
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("newPrivateKey"),
|
||||
Crypted: privateKeyPKCS8,
|
||||
}),
|
||||
idp.ChangeAppleScopes([]string{"name", "email"}),
|
||||
idp.ChangeAppleOptions(idp.OptionChanges{
|
||||
@@ -5306,7 +5334,7 @@ func TestCommandSide_UpdateInstanceAppleIDP(t *testing.T) {
|
||||
ClientID: "clientID2",
|
||||
TeamID: "teamID2",
|
||||
KeyID: "keyID2",
|
||||
PrivateKey: []byte("newPrivateKey"),
|
||||
PrivateKey: privateKeyPKCS8,
|
||||
Scopes: []string{"name", "email"},
|
||||
IDPOptions: idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
@@ -5328,12 +5356,7 @@ func TestCommandSide_UpdateInstanceAppleIDP(t *testing.T) {
|
||||
idpConfigEncryption: tt.fields.secretCrypto,
|
||||
}
|
||||
got, err := c.UpdateInstanceAppleProvider(tt.args.ctx, tt.args.id, tt.args.provider)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.res.err != nil && !tt.res.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
assert.ErrorIs(t, err, tt.res.err)
|
||||
if tt.res.err == nil {
|
||||
assertObjectDetails(t, tt.res.want, got)
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/domain"
|
||||
"github.com/zitadel/zitadel/internal/eventstore"
|
||||
"github.com/zitadel/zitadel/internal/idp/providers/apple"
|
||||
"github.com/zitadel/zitadel/internal/idp/providers/saml"
|
||||
"github.com/zitadel/zitadel/internal/repository/org"
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
@@ -1642,6 +1643,9 @@ func (c *Commands) prepareAddOrgAppleProvider(a *org.Aggregate, writeModel *OrgA
|
||||
if len(provider.PrivateKey) == 0 {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "ORG-GVD4n", "Errors.IDP.PrivateKeyMissing")
|
||||
}
|
||||
if _, err := apple.BytesToPrivateKey(provider.PrivateKey); err != nil {
|
||||
return nil, zerrors.ThrowInvalidArgument(err, "ORG-Fk38d", "Errors.IDP.InvalidPrivateKey")
|
||||
}
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
if err != nil {
|
||||
@@ -1687,6 +1691,11 @@ func (c *Commands) prepareUpdateOrgAppleProvider(a *org.Aggregate, writeModel *O
|
||||
if provider.KeyID = strings.TrimSpace(provider.KeyID); provider.KeyID == "" {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "ORG-Gh4z2", "Errors.IDP.KeyIDMissing")
|
||||
}
|
||||
if len(provider.PrivateKey) > 0 {
|
||||
if _, err := apple.BytesToPrivateKey(provider.PrivateKey); err != nil {
|
||||
return nil, zerrors.ThrowInvalidArgument(err, "ORG-eWSDf", "Errors.IDP.InvalidPrivateKey")
|
||||
}
|
||||
}
|
||||
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||
events, err := filter(ctx, writeModel.Query())
|
||||
if err != nil {
|
||||
|
||||
@@ -4966,7 +4966,7 @@ func TestCommandSide_AddOrgAppleIDP(t *testing.T) {
|
||||
type res struct {
|
||||
id string
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
err error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -4986,9 +4986,7 @@ func TestCommandSide_AddOrgAppleIDP(t *testing.T) {
|
||||
provider: AppleProvider{},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, zerrors.ThrowInvalidArgument(nil, "ORG-jkn3w", "Errors.IDP.ClientIDMissing"))
|
||||
},
|
||||
err: zerrors.ThrowInvalidArgument(nil, "ORG-jkn3w", "Errors.IDP.ClientIDMissing"),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -5005,9 +5003,7 @@ func TestCommandSide_AddOrgAppleIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, zerrors.ThrowInvalidArgument(nil, "ORG-Ffg32", "Errors.IDP.TeamIDMissing"))
|
||||
},
|
||||
err: zerrors.ThrowInvalidArgument(nil, "ORG-Ffg32", "Errors.IDP.TeamIDMissing"),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -5025,13 +5021,11 @@ func TestCommandSide_AddOrgAppleIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, zerrors.ThrowInvalidArgument(nil, "ORG-GDjm5", "Errors.IDP.KeyIDMissing"))
|
||||
},
|
||||
err: zerrors.ThrowInvalidArgument(nil, "ORG-GDjm5", "Errors.IDP.KeyIDMissing"),
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid privateKey",
|
||||
"no privateKey",
|
||||
fields{
|
||||
eventstore: expectEventstore(),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
@@ -5046,10 +5040,28 @@ func TestCommandSide_AddOrgAppleIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, zerrors.ThrowInvalidArgument(nil, "ORG-GVD4n", "Errors.IDP.PrivateKeyMissing"))
|
||||
err: zerrors.ThrowInvalidArgument(nil, "ORG-GVD4n", "Errors.IDP.PrivateKeyMissing"),
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid privateKey",
|
||||
fields{
|
||||
eventstore: expectEventstore(),
|
||||
idGenerator: id_mock.NewIDGeneratorExpectIDs(t, "id1"),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
resourceOwner: "org1",
|
||||
provider: AppleProvider{
|
||||
ClientID: "clientID",
|
||||
TeamID: "teamID",
|
||||
KeyID: "keyID",
|
||||
PrivateKey: []byte("invalid"),
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: zerrors.ThrowInvalidArgument(crypto.ErrEmpty, "ORG-Fk38d", "Errors.IDP.InvalidPrivateKey"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ok",
|
||||
@@ -5067,7 +5079,7 @@ func TestCommandSide_AddOrgAppleIDP(t *testing.T) {
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("privateKey"),
|
||||
Crypted: privateKeyPKCS8,
|
||||
},
|
||||
nil,
|
||||
idp.Options{},
|
||||
@@ -5084,7 +5096,7 @@ func TestCommandSide_AddOrgAppleIDP(t *testing.T) {
|
||||
ClientID: "clientID",
|
||||
TeamID: "teamID",
|
||||
KeyID: "keyID",
|
||||
PrivateKey: []byte("privateKey"),
|
||||
PrivateKey: privateKeyPKCS8,
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
@@ -5108,7 +5120,7 @@ func TestCommandSide_AddOrgAppleIDP(t *testing.T) {
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("privateKey"),
|
||||
Crypted: privateKeyPKCS8,
|
||||
},
|
||||
[]string{"name", "email"},
|
||||
idp.Options{
|
||||
@@ -5130,7 +5142,7 @@ func TestCommandSide_AddOrgAppleIDP(t *testing.T) {
|
||||
ClientID: "clientID",
|
||||
TeamID: "teamID",
|
||||
KeyID: "keyID",
|
||||
PrivateKey: []byte("privateKey"),
|
||||
PrivateKey: privateKeyPKCS8,
|
||||
Scopes: []string{"name", "email"},
|
||||
IDPOptions: idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
@@ -5154,12 +5166,7 @@ func TestCommandSide_AddOrgAppleIDP(t *testing.T) {
|
||||
idpConfigEncryption: tt.fields.secretCrypto,
|
||||
}
|
||||
id, got, err := c.AddOrgAppleProvider(tt.args.ctx, tt.args.resourceOwner, tt.args.provider)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.res.err != nil && !tt.res.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
assert.ErrorIs(t, err, tt.res.err)
|
||||
if tt.res.err == nil {
|
||||
assert.Equal(t, tt.res.id, id)
|
||||
assertObjectDetails(t, tt.res.want, got)
|
||||
@@ -5181,7 +5188,7 @@ func TestCommandSide_UpdateOrgAppleIDP(t *testing.T) {
|
||||
}
|
||||
type res struct {
|
||||
want *domain.ObjectDetails
|
||||
err func(error) bool
|
||||
err error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@@ -5200,9 +5207,7 @@ func TestCommandSide_UpdateOrgAppleIDP(t *testing.T) {
|
||||
provider: AppleProvider{},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, zerrors.ThrowInvalidArgument(nil, "ORG-FRHBH", "Errors.IDMissing"))
|
||||
},
|
||||
err: zerrors.ThrowInvalidArgument(nil, "ORG-FRHBH", "Errors.IDMissing"),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -5217,9 +5222,7 @@ func TestCommandSide_UpdateOrgAppleIDP(t *testing.T) {
|
||||
provider: AppleProvider{},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, zerrors.ThrowInvalidArgument(nil, "ORG-SFm4l", "Errors.IDP.ClientIDMissing"))
|
||||
},
|
||||
err: zerrors.ThrowInvalidArgument(nil, "ORG-SFm4l", "Errors.IDP.ClientIDMissing"),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -5236,9 +5239,7 @@ func TestCommandSide_UpdateOrgAppleIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, zerrors.ThrowInvalidArgument(nil, "ORG-SG34t", "Errors.IDP.TeamIDMissing"))
|
||||
},
|
||||
err: zerrors.ThrowInvalidArgument(nil, "ORG-SG34t", "Errors.IDP.TeamIDMissing"),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -5256,10 +5257,27 @@ func TestCommandSide_UpdateOrgAppleIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: func(err error) bool {
|
||||
return errors.Is(err, zerrors.ThrowInvalidArgument(nil, "ORG-Gh4z2", "Errors.IDP.KeyIDMissing"))
|
||||
err: zerrors.ThrowInvalidArgument(nil, "ORG-Gh4z2", "Errors.IDP.KeyIDMissing"),
|
||||
},
|
||||
},
|
||||
{
|
||||
"invalid key",
|
||||
fields{
|
||||
eventstore: expectEventstore(),
|
||||
},
|
||||
args{
|
||||
ctx: context.Background(),
|
||||
id: "id1",
|
||||
provider: AppleProvider{
|
||||
ClientID: "clientID",
|
||||
TeamID: "teamID",
|
||||
KeyID: "keyID",
|
||||
PrivateKey: []byte("invalid"),
|
||||
},
|
||||
},
|
||||
res{
|
||||
err: zerrors.ThrowInvalidArgument(nil, "ORG-eWSDf", "Errors.IDP.InvalidPrivateKey"),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "not found",
|
||||
@@ -5279,7 +5297,7 @@ func TestCommandSide_UpdateOrgAppleIDP(t *testing.T) {
|
||||
},
|
||||
},
|
||||
res: res{
|
||||
err: zerrors.IsNotFound,
|
||||
err: zerrors.ThrowNotFound(nil, "ORG-SG3bh", "Errors.IDPConfig.NotExisting"),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -5298,7 +5316,7 @@ func TestCommandSide_UpdateOrgAppleIDP(t *testing.T) {
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("privateKey"),
|
||||
Crypted: privateKeyPKCS8,
|
||||
},
|
||||
nil,
|
||||
idp.Options{},
|
||||
@@ -5355,7 +5373,7 @@ func TestCommandSide_UpdateOrgAppleIDP(t *testing.T) {
|
||||
CryptoType: crypto.TypeEncryption,
|
||||
Algorithm: "enc",
|
||||
KeyID: "id",
|
||||
Crypted: []byte("newPrivateKey"),
|
||||
Crypted: privateKeyPKCS8,
|
||||
}),
|
||||
idp.ChangeAppleScopes([]string{"name", "email"}),
|
||||
idp.ChangeAppleOptions(idp.OptionChanges{
|
||||
@@ -5380,7 +5398,7 @@ func TestCommandSide_UpdateOrgAppleIDP(t *testing.T) {
|
||||
ClientID: "clientID2",
|
||||
TeamID: "teamID2",
|
||||
KeyID: "keyID2",
|
||||
PrivateKey: []byte("newPrivateKey"),
|
||||
PrivateKey: privateKeyPKCS8,
|
||||
Scopes: []string{"name", "email"},
|
||||
IDPOptions: idp.Options{
|
||||
IsCreationAllowed: true,
|
||||
@@ -5402,12 +5420,7 @@ func TestCommandSide_UpdateOrgAppleIDP(t *testing.T) {
|
||||
idpConfigEncryption: tt.fields.secretCrypto,
|
||||
}
|
||||
got, err := c.UpdateOrgAppleProvider(tt.args.ctx, tt.args.resourceOwner, tt.args.id, tt.args.provider)
|
||||
if tt.res.err == nil {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
if tt.res.err != nil && !tt.res.err(err) {
|
||||
t.Errorf("got wrong err: %v ", err)
|
||||
}
|
||||
assert.ErrorIs(t, err, tt.res.err)
|
||||
if tt.res.err == nil {
|
||||
assertObjectDetails(t, tt.res.want, got)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"database/sql/driver"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"slices"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
@@ -41,7 +42,7 @@ func (c *CryptoValue) Value() (driver.Value, error) {
|
||||
return json.Marshal(c)
|
||||
}
|
||||
|
||||
func (c *CryptoValue) Scan(src interface{}) error {
|
||||
func (c *CryptoValue) Scan(src any) error {
|
||||
if b, ok := src.([]byte); ok {
|
||||
return json.Unmarshal(b, c)
|
||||
}
|
||||
@@ -58,6 +59,9 @@ func Crypt(value []byte, alg EncryptionAlgorithm) (*CryptoValue, error) {
|
||||
}
|
||||
|
||||
func Encrypt(value []byte, alg EncryptionAlgorithm) (*CryptoValue, error) {
|
||||
if alg == nil {
|
||||
return nil, zerrors.ThrowInvalidArgument(nil, "CRYPT-03ltQd", "input encryption algorithm cannot be nil")
|
||||
}
|
||||
encrypted, err := alg.Encrypt(value)
|
||||
if err != nil {
|
||||
return nil, zerrors.ThrowInternal(err, "CRYPT-qCD0JB", "error encrypting value")
|
||||
@@ -106,13 +110,17 @@ func DecryptString(value *CryptoValue, alg EncryptionAlgorithm) (string, error)
|
||||
}
|
||||
|
||||
func checkEncryptionAlgorithm(value *CryptoValue, alg EncryptionAlgorithm) error {
|
||||
if value == nil {
|
||||
return zerrors.ThrowInvalidArgument(nil, "CRYPT-mNsQwe", "input value cannot be nil")
|
||||
}
|
||||
if alg == nil {
|
||||
return zerrors.ThrowInvalidArgument(nil, "CRYPT-paiRey", "input encryption algorithm cannot be nil")
|
||||
}
|
||||
if value.Algorithm != alg.Algorithm() {
|
||||
return zerrors.ThrowInvalidArgument(nil, "CRYPT-Nx7XlT", "value was encrypted with a different key")
|
||||
}
|
||||
for _, id := range alg.DecryptionKeyIDs() {
|
||||
if id == value.KeyID {
|
||||
return nil
|
||||
}
|
||||
if slices.Contains(alg.DecryptionKeyIDs(), value.KeyID) {
|
||||
return nil
|
||||
}
|
||||
return zerrors.ThrowInvalidArgument(nil, "CRYPT-Kq12vn", "value was encrypted with a different key")
|
||||
}
|
||||
@@ -121,6 +129,9 @@ func CheckToken(alg EncryptionAlgorithm, token string, content string) error {
|
||||
if token == "" {
|
||||
return zerrors.ThrowPermissionDenied(nil, "CRYPTO-Sfefs", "Errors.Intent.InvalidToken")
|
||||
}
|
||||
if alg == nil {
|
||||
return zerrors.ThrowInvalidArgument(nil, "CRYPT-edCJsp", "input encryption algorithm cannot be nil")
|
||||
}
|
||||
data, err := base64.RawURLEncoding.DecodeString(token)
|
||||
if err != nil {
|
||||
return zerrors.ThrowPermissionDenied(err, "CRYPTO-Swg31", "Errors.Intent.InvalidToken")
|
||||
|
||||
@@ -69,10 +69,15 @@ func TestCrypt(t *testing.T) {
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
"encrypt",
|
||||
args{[]byte("test"), &mockEncCrypto{}},
|
||||
&CryptoValue{CryptoType: TypeEncryption, Algorithm: "enc", KeyID: "keyID", Crypted: []byte("test")},
|
||||
false,
|
||||
name: "encrypt ok",
|
||||
args: args{[]byte("test"), &mockEncCrypto{}},
|
||||
want: &CryptoValue{CryptoType: TypeEncryption, Algorithm: "enc", KeyID: "keyID", Crypted: []byte("test")},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "encryption algorithm nil should return error",
|
||||
args: args{[]byte("test"), nil},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -101,10 +106,15 @@ func TestEncrypt(t *testing.T) {
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
"ok",
|
||||
args{[]byte("test"), &mockEncCrypto{}},
|
||||
&CryptoValue{CryptoType: TypeEncryption, Algorithm: "enc", KeyID: "keyID", Crypted: []byte("test")},
|
||||
false,
|
||||
name: "ok",
|
||||
args: args{[]byte("test"), &mockEncCrypto{}},
|
||||
want: &CryptoValue{CryptoType: TypeEncryption, Algorithm: "enc", KeyID: "keyID", Crypted: []byte("test")},
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "encryption algorithm nil should return error",
|
||||
args: args{[]byte("test"), nil},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -133,16 +143,25 @@ func TestDecrypt(t *testing.T) {
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
"ok",
|
||||
args{&CryptoValue{CryptoType: TypeEncryption, Algorithm: "enc", KeyID: "keyID", Crypted: []byte("test")}, &mockEncCrypto{}},
|
||||
[]byte("test"),
|
||||
false,
|
||||
name: "ok",
|
||||
args: args{&CryptoValue{CryptoType: TypeEncryption, Algorithm: "enc", KeyID: "keyID", Crypted: []byte("test")}, &mockEncCrypto{}},
|
||||
want: []byte("test"),
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
"wrong id",
|
||||
args{&CryptoValue{CryptoType: TypeEncryption, Algorithm: "enc", KeyID: "keyID2", Crypted: []byte("test")}, &mockEncCrypto{}},
|
||||
nil,
|
||||
true,
|
||||
name: "wrong id",
|
||||
args: args{&CryptoValue{CryptoType: TypeEncryption, Algorithm: "enc", KeyID: "keyID2", Crypted: []byte("test")}, &mockEncCrypto{}},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "when encryption algorithm is nil should return error",
|
||||
args: args{&CryptoValue{CryptoType: TypeEncryption, Algorithm: "enc", KeyID: "keyID2", Crypted: []byte("test")}, nil},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "when crypto value is nil should return error",
|
||||
args: args{nil, &mockEncCrypto{}},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
@@ -171,16 +190,25 @@ func TestDecryptString(t *testing.T) {
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
"ok",
|
||||
args{&CryptoValue{CryptoType: TypeEncryption, Algorithm: "enc", KeyID: "keyID", Crypted: []byte("test")}, &mockEncCrypto{}},
|
||||
"test",
|
||||
false,
|
||||
name: "ok",
|
||||
args: args{&CryptoValue{CryptoType: TypeEncryption, Algorithm: "enc", KeyID: "keyID", Crypted: []byte("test")}, &mockEncCrypto{}},
|
||||
want: "test",
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
"wrong id",
|
||||
args{&CryptoValue{CryptoType: TypeEncryption, Algorithm: "enc", KeyID: "keyID2", Crypted: []byte("test")}, &mockEncCrypto{}},
|
||||
"",
|
||||
true,
|
||||
name: "wrong id",
|
||||
args: args{&CryptoValue{CryptoType: TypeEncryption, Algorithm: "enc", KeyID: "keyID2", Crypted: []byte("test")}, &mockEncCrypto{}},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "when encryption algorithm is nil should return error",
|
||||
args: args{&CryptoValue{CryptoType: TypeEncryption, Algorithm: "enc", KeyID: "keyID2", Crypted: []byte("test")}, nil},
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "when crypto value is nil should return error",
|
||||
args: args{nil, &mockEncCrypto{}},
|
||||
wantErr: true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
|
||||
+46
-2
@@ -2,6 +2,7 @@ package crypto
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
"crypto/x509"
|
||||
@@ -11,6 +12,8 @@ import (
|
||||
"fmt"
|
||||
"math/big"
|
||||
"time"
|
||||
|
||||
"github.com/zitadel/zitadel/internal/zerrors"
|
||||
)
|
||||
|
||||
func GenerateKeyPair(bits int) (*rsa.PrivateKey, *rsa.PublicKey, error) {
|
||||
@@ -128,18 +131,40 @@ func PrivateKeyToBytes(priv *rsa.PrivateKey) []byte {
|
||||
)
|
||||
}
|
||||
|
||||
func PrivateKeyToBytesPKCS8(priv crypto.PrivateKey) ([]byte, error) {
|
||||
der, err := x509.MarshalPKCS8PrivateKey(priv)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
err = pem.Encode(buffer,
|
||||
&pem.Block{
|
||||
Type: "PRIVATE KEY",
|
||||
Bytes: der,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
||||
func PublicKeyToBytes(pub *rsa.PublicKey) ([]byte, error) {
|
||||
pubASN1, err := x509.MarshalPKIXPublicKey(pub)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pubBytes := pem.EncodeToMemory(&pem.Block{
|
||||
buffer := bytes.NewBuffer(nil)
|
||||
err = pem.Encode(buffer, &pem.Block{
|
||||
Type: "RSA PUBLIC KEY",
|
||||
Bytes: pubASN1,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pubBytes, nil
|
||||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
||||
func BytesToPrivateKey(priv []byte) (*rsa.PrivateKey, error) {
|
||||
@@ -160,6 +185,25 @@ func BytesToPrivateKey(priv []byte) (*rsa.PrivateKey, error) {
|
||||
return key, nil
|
||||
}
|
||||
|
||||
func BytesToPrivateKeyPKCS8[T crypto.PrivateKey](priv []byte) (T, error) {
|
||||
var zero T
|
||||
if len(priv) == 0 {
|
||||
return zero, ErrEmpty
|
||||
}
|
||||
block, _ := pem.Decode(priv)
|
||||
if block == nil {
|
||||
return zero, ErrEmpty
|
||||
}
|
||||
key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
|
||||
if err != nil {
|
||||
return zero, err
|
||||
}
|
||||
if k, ok := key.(T); ok {
|
||||
return k, nil
|
||||
}
|
||||
return zero, zerrors.ThrowInvalidArgumentf(nil, "CRYP-9n2s3", "wrong type: expected %T, got %T", zero, key)
|
||||
}
|
||||
|
||||
var ErrEmpty = errors.New("cannot decode, empty data")
|
||||
|
||||
func BytesToPublicKey(pub []byte) (*rsa.PublicKey, error) {
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
package apple
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"crypto/ecdsa"
|
||||
"time"
|
||||
|
||||
"github.com/go-jose/go-jose/v4"
|
||||
"github.com/zitadel/oidc/v3/pkg/crypto"
|
||||
openid "github.com/zitadel/oidc/v3/pkg/oidc"
|
||||
|
||||
zcrypto "github.com/zitadel/zitadel/internal/crypto"
|
||||
"github.com/zitadel/zitadel/internal/idp"
|
||||
"github.com/zitadel/zitadel/internal/idp/providers/oidc"
|
||||
)
|
||||
@@ -42,9 +42,7 @@ func New(clientID, teamID, keyID, callbackURL string, key []byte, scopes []strin
|
||||
|
||||
// clientSecretFromPrivateKey uses the private key to create and sign a JWT, which has to be used as client_secret at Apple.
|
||||
func clientSecretFromPrivateKey(key []byte, teamID, clientID, keyID string) (string, error) {
|
||||
block, _ := pem.Decode(key)
|
||||
b := block.Bytes
|
||||
pk, err := x509.ParsePKCS8PrivateKey(b)
|
||||
pk, err := BytesToPrivateKey(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -66,3 +64,7 @@ func clientSecretFromPrivateKey(key []byte, teamID, clientID, keyID string) (str
|
||||
IssuedAt: openid.FromTime(iat),
|
||||
}, signer)
|
||||
}
|
||||
|
||||
func BytesToPrivateKey(key []byte) (*ecdsa.PrivateKey, error) {
|
||||
return zcrypto.BytesToPrivateKeyPKCS8[*ecdsa.PrivateKey](key)
|
||||
}
|
||||
|
||||
@@ -237,12 +237,6 @@ Errors:
|
||||
AlreadyExists: "النطاق موجود بالفعل"
|
||||
InvalidCharacter: "يسمح فقط بالأحرف الأبجدية الرقمية و . و - للنطاق"
|
||||
EmptyString: "تم استبدال الأحرف غير الرقمية والأبجدية غير الصالحة بمساحات فارغة والنطاق الناتج هو سلسلة فارغة"
|
||||
IDP:
|
||||
InvalidSearchQuery: "استعلام بحث غير صالح"
|
||||
ClientIDMissing: "معرف العميل مفقود"
|
||||
TeamIDMissing: "معرف الفريق مفقود"
|
||||
KeyIDMissing: "معرف المفتاح مفقود"
|
||||
PrivateKeyMissing: "المفتاح الخاص مفقود"
|
||||
LoginPolicy:
|
||||
NotFound: "سياسة تسجيل الدخول غير موجودة"
|
||||
Invalid: "سياسة تسجيل الدخول غير صالحة"
|
||||
@@ -609,6 +603,13 @@ Errors:
|
||||
Duplicate: "معرف مفتاح الويب ليس فريداً"
|
||||
NoActive: "لم يتم العثور على مفتاح ويب نشط"
|
||||
NotFound: "مفتاح الويب غير موجود"
|
||||
IDP:
|
||||
InvalidSearchQuery: "استعلام بحث غير صالح"
|
||||
ClientIDMissing: "معرف العميل مفقود"
|
||||
TeamIDMissing: "معرف الفريق مفقود"
|
||||
KeyIDMissing: "معرف المفتاح مفقود"
|
||||
PrivateKeyMissing: "المفتاح الخاص مفقود"
|
||||
InvalidPrivateKey: "تنسيق مفتاح خاص غير صالح"
|
||||
|
||||
AggregateTypes:
|
||||
action: "إجراء"
|
||||
|
||||
@@ -236,12 +236,6 @@ Errors:
|
||||
AlreadyExists: "Домейнът вече съществува"
|
||||
InvalidCharacter: "Само буквено-цифрови знаци, . "
|
||||
EmptyString: "Невалидни нецифрови и азбучни знаци бяха заменени с празни интервали и полученият домейн е празен низ"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Невалидна заявка за търсене"
|
||||
ClientIDMissing: "Липсва ClientID"
|
||||
TeamIDMissing: "TeamID липсва"
|
||||
KeyIDMissing: "Липсва KeyID"
|
||||
PrivateKeyMissing: "Липсва частен ключ"
|
||||
LoginPolicy:
|
||||
NotFound: "Правилата за влизане не са намерени"
|
||||
Invalid: "Правилата за влизане са невалидни"
|
||||
@@ -613,6 +607,13 @@ Errors:
|
||||
Duplicate: "ID на уеб ключ не е уникален"
|
||||
NoActive: "Не е намерен активен уеб ключ"
|
||||
NotFound: "Уеб ключът не е намерен"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Невалидна заявка за търсене"
|
||||
ClientIDMissing: "Липсва ClientID"
|
||||
TeamIDMissing: "TeamID липсва"
|
||||
KeyIDMissing: "Липсва KeyID"
|
||||
PrivateKeyMissing: "Липсва частен ключ"
|
||||
InvalidPrivateKey: "Невалиден формат на частния ключ"
|
||||
|
||||
AggregateTypes:
|
||||
action: "Действие"
|
||||
|
||||
@@ -236,12 +236,6 @@ Errors:
|
||||
AlreadyExists: "Doména již existuje"
|
||||
InvalidCharacter: "Pro doménu jsou povoleny pouze alfanumerické znaky, . a -"
|
||||
EmptyString: "Neplatné nečíselné a nealfabetické znaky byly nahrazeny prázdnými místy a výsledná doména je prázdný řetězec"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Neplatný vyhledávací dotaz"
|
||||
ClientIDMissing: "Chybí ClientID"
|
||||
TeamIDMissing: "Chybí TeamID"
|
||||
KeyIDMissing: "Chybí KeyID"
|
||||
PrivateKeyMissing: "Chybí privátní klíč"
|
||||
LoginPolicy:
|
||||
NotFound: "Přihlašovací politika nenalezena"
|
||||
Invalid: "Přihlašovací politika je neplatná"
|
||||
@@ -611,6 +605,13 @@ Errors:
|
||||
Duplicate: "ID webového klíče není jedinečné"
|
||||
NoActive: "Nebyl nalezen žádný aktivní webový klíč"
|
||||
NotFound: "Webový klíč nebyl nalezen"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Neplatný vyhledávací dotaz"
|
||||
ClientIDMissing: "Chybí ClientID"
|
||||
TeamIDMissing: "Chybí TeamID"
|
||||
KeyIDMissing: "Chybí KeyID"
|
||||
PrivateKeyMissing: "Chybí privátní klíč"
|
||||
InvalidPrivateKey: "Neplatný formát privátního klíče"
|
||||
|
||||
AggregateTypes:
|
||||
action: "Akce"
|
||||
|
||||
@@ -236,12 +236,6 @@ Errors:
|
||||
AlreadyExists: "Domäne existiert bereits"
|
||||
InvalidCharacter: "Nur alphanumerische Zeichen, . und - sind für eine Domäne erlaubt"
|
||||
EmptyString: "Ungültige nicht numerische und alphabetische Zeichen wurden durch Leerzeichen ersetzt und die resultierende Domäne ist eine leere Zeichenfolge"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Ungültiger Suchparameter"
|
||||
ClientIDMissing: "ClientID fehlt"
|
||||
TeamIDMissing: "TeamID fehlt"
|
||||
KeyIDMissing: "KeyID fehlt"
|
||||
PrivateKeyMissing: "Private Key fehlt"
|
||||
LoginPolicy:
|
||||
NotFound: "Login Policy konnte nicht gefunden werden"
|
||||
Invalid: "Login Policy ist ungültig"
|
||||
@@ -613,6 +607,13 @@ Errors:
|
||||
Duplicate: "Webschlüssel-ID nicht eindeutig"
|
||||
NoActive: "Kein aktiver Webschlüssel gefunden"
|
||||
NotFound: "Webschlüssel nicht gefunden"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Ungültiger Suchparameter"
|
||||
ClientIDMissing: "ClientID fehlt"
|
||||
TeamIDMissing: "TeamID fehlt"
|
||||
KeyIDMissing: "KeyID fehlt"
|
||||
PrivateKeyMissing: "Private Key fehlt"
|
||||
InvalidPrivateKey: "Ungültiges Format des privaten Schlüssels"
|
||||
|
||||
AggregateTypes:
|
||||
action: "Action"
|
||||
|
||||
@@ -238,12 +238,6 @@ Errors:
|
||||
AlreadyExists: "Domain already exists"
|
||||
InvalidCharacter: "Only alphanumeric characters, . and - are allowed for a domain"
|
||||
EmptyString: "Invalid non numeric and alphabetical characters were replaced with empty spaces and resulting domain is an empty string"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Invalid search query"
|
||||
ClientIDMissing: "ClientID missing"
|
||||
TeamIDMissing: "TeamID missing"
|
||||
KeyIDMissing: "KeyID missing"
|
||||
PrivateKeyMissing: "Private Key missing"
|
||||
LoginPolicy:
|
||||
NotFound: "Login Policy not found"
|
||||
Invalid: "Login Policy is invalid"
|
||||
@@ -615,6 +609,13 @@ Errors:
|
||||
Duplicate: "Web key ID not unique"
|
||||
NoActive: "No active web key found"
|
||||
NotFound: "Web key not found"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Invalid search query"
|
||||
ClientIDMissing: "ClientID missing"
|
||||
TeamIDMissing: "TeamID missing"
|
||||
KeyIDMissing: "KeyID missing"
|
||||
PrivateKeyMissing: "Private Key missing"
|
||||
InvalidPrivateKey: "Invalid Private Key format"
|
||||
|
||||
AggregateTypes:
|
||||
action: "Action"
|
||||
|
||||
@@ -236,12 +236,6 @@ Errors:
|
||||
AlreadyExists: "El dominio ya existe"
|
||||
InvalidCharacter: "Solo caracteres alfanuméricos, . y - se permiten para un dominio"
|
||||
EmptyString: "Los caracteres alfabéticos y no numéricos no válidos se reemplazaron con espacios vacíos y el dominio resultante es una cadena vacía"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Consulta de búsqueda no válida"
|
||||
ClientIDMissing: "Falta ClientID"
|
||||
TeamIDMissing: "Falta TeamID"
|
||||
KeyIDMissing: "Falta KeyID"
|
||||
PrivateKeyMissing: "Falta la clave privada"
|
||||
LoginPolicy:
|
||||
NotFound: "Política de inicio de sesión no encontrada"
|
||||
Invalid: "Política de inicio de sesión no es válida"
|
||||
@@ -613,6 +607,13 @@ Errors:
|
||||
Duplicate: "ID de clave web no único"
|
||||
NoActive: "No se encontró ninguna clave web activa"
|
||||
NotFound: "Clave web no encontrada"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Consulta de búsqueda no válida"
|
||||
ClientIDMissing: "Falta ClientID"
|
||||
TeamIDMissing: "Falta TeamID"
|
||||
KeyIDMissing: "Falta KeyID"
|
||||
PrivateKeyMissing: "Falta la clave privada"
|
||||
InvalidPrivateKey: "Formato de clave privada inválido"
|
||||
|
||||
AggregateTypes:
|
||||
action: "Acción"
|
||||
|
||||
@@ -236,12 +236,6 @@ Errors:
|
||||
AlreadyExists: "Le domaine existe déjà"
|
||||
InvalidCharacter: "Seuls les caractères alphanumériques, . et - sont autorisés pour un domaine"
|
||||
EmptyString: "Les caractères non numériques et alphabétiques non valides ont été remplacés par des espaces vides et le domaine résultant est une chaîne vide"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Paramètre de recherche non valide"
|
||||
ClientIDMissing: "ID client manquant"
|
||||
TeamIDMissing: "TeamID manquant"
|
||||
KeyIDMissing: "ID de clé manquant"
|
||||
PrivateKeyMissing: "clé privée manquante"
|
||||
LoginPolicy:
|
||||
NotFound: "Politique de connexion non trouvée"
|
||||
Invalid: "La politique de connexion n'est pas valide"
|
||||
@@ -613,6 +607,13 @@ Errors:
|
||||
Duplicate: "L'ID de clé Web n'est pas unique"
|
||||
NoActive: "Aucune clé Web active trouvée"
|
||||
NotFound: "Clé Web introuvable"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Paramètre de recherche non valide"
|
||||
ClientIDMissing: "ID client manquant"
|
||||
TeamIDMissing: "TeamID manquant"
|
||||
KeyIDMissing: "ID de clé manquant"
|
||||
PrivateKeyMissing: "clé privée manquante"
|
||||
InvalidPrivateKey: "Format de clé privée invalide"
|
||||
|
||||
AggregateTypes:
|
||||
action: "Action"
|
||||
|
||||
@@ -236,12 +236,6 @@ Errors:
|
||||
AlreadyExists: "A domain már létezik"
|
||||
InvalidCharacter: "Csak alfanumerikus karakterek, . és - engedélyezettek a domain számára"
|
||||
EmptyString: "Érvénytelen nem numerikus és alfabetikus karaktereket üres helyekre cseréltük és az eredményül kapott domain egy üres string"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Érvénytelen keresési lekérdezés"
|
||||
ClientIDMissing: "ClientID hiányzik"
|
||||
TeamIDMissing: "TeamID hiányzik"
|
||||
KeyIDMissing: "KeyID hiányzik"
|
||||
PrivateKeyMissing: "Privát kulcs hiányzik"
|
||||
LoginPolicy:
|
||||
NotFound: "Bejelentkezési politika nem található"
|
||||
Invalid: "Bejelentkezési politika érvénytelen"
|
||||
@@ -613,6 +607,13 @@ Errors:
|
||||
Duplicate: "A webkulcs azonosító nem egyedi"
|
||||
NoActive: "Aktív web kulcs nem található"
|
||||
NotFound: "Web kulcs nem található"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Érvénytelen keresési lekérdezés"
|
||||
ClientIDMissing: "ClientID hiányzik"
|
||||
TeamIDMissing: "TeamID hiányzik"
|
||||
KeyIDMissing: "KeyID hiányzik"
|
||||
PrivateKeyMissing: "Privát kulcs hiányzik"
|
||||
InvalidPrivateKey: "Érvénytelen titkos kulcs formátum"
|
||||
|
||||
AggregateTypes:
|
||||
action: "Művelet"
|
||||
|
||||
@@ -236,12 +236,6 @@ Errors:
|
||||
AlreadyExists: "Domain sudah ada"
|
||||
InvalidCharacter: "Hanya karakter alfanumerik, . "
|
||||
EmptyString: "Karakter non numerik dan alfabet yang tidak valid diganti dengan spasi kosong dan domain yang dihasilkan berupa string kosong"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Kueri penelusuran tidak valid"
|
||||
ClientIDMissing: "ID Klien tidak ada"
|
||||
TeamIDMissing: "ID Tim hilang"
|
||||
KeyIDMissing: "ID Kunci hilang"
|
||||
PrivateKeyMissing: "Kunci Pribadi hilang"
|
||||
LoginPolicy:
|
||||
NotFound: "Kebijakan Login tidak ditemukan"
|
||||
Invalid: "Kebijakan Masuk tidak valid"
|
||||
@@ -608,6 +602,13 @@ Errors:
|
||||
Duplicate: "ID kunci web tidak unik"
|
||||
NoActive: "Tidak ditemukan kunci web aktif"
|
||||
NotFound: "Kunci web tidak ditemukan"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Kueri penelusuran tidak valid"
|
||||
ClientIDMissing: "ID Klien tidak ada"
|
||||
TeamIDMissing: "ID Tim hilang"
|
||||
KeyIDMissing: "ID Kunci hilang"
|
||||
PrivateKeyMissing: "Kunci Pribadi hilang"
|
||||
InvalidPrivateKey: "Format kunci pribadi tidak valid"
|
||||
|
||||
AggregateTypes:
|
||||
action: "Tindakan"
|
||||
|
||||
@@ -236,12 +236,6 @@ Errors:
|
||||
AlreadyExists: "Il dominio già esistente"
|
||||
InvalidCharacter: "Solo caratteri alfanumerici, . e - sono consentiti per un dominio"
|
||||
EmptyString: "I caratteri non numerici e alfabetici non validi sono stati sostituiti con spazi vuoti e il dominio risultante è una stringa vuota"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Parametro di ricerca non valido"
|
||||
ClientIDMissing: "ClientID mancante"
|
||||
TeamIDMissing: "TeamID mancante"
|
||||
KeyIDMissing: "ID chiave mancante"
|
||||
PrivateKeyMissing: "Chiave privata mancante"
|
||||
LoginPolicy:
|
||||
NotFound: "Impostazioni di accesso non trovati"
|
||||
Invalid: "Impostazioni di accesso non sono validi"
|
||||
@@ -613,6 +607,13 @@ Errors:
|
||||
Duplicate: "ID chiave Web non univoco"
|
||||
NoActive: "Nessuna chiave Web attiva trovata"
|
||||
NotFound: "Chiave Web non trovata"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Parametro di ricerca non valido"
|
||||
ClientIDMissing: "ClientID mancante"
|
||||
TeamIDMissing: "TeamID mancante"
|
||||
KeyIDMissing: "ID chiave mancante"
|
||||
PrivateKeyMissing: "Chiave privata mancante"
|
||||
InvalidPrivateKey: "Formato chiave privata non valido"
|
||||
|
||||
AggregateTypes:
|
||||
action: "Azione"
|
||||
|
||||
@@ -237,12 +237,6 @@ Errors:
|
||||
AlreadyExists: "ドメインはすでに存在します"
|
||||
InvalidCharacter: "ドメインは英数字、'.'、'-'のみ使用可能です。"
|
||||
EmptyString: "無効な数字およびアルファベット以外の文字は空のスペースに置き換えられ、結果のドメインは空の文字列になります"
|
||||
IDP:
|
||||
InvalidSearchQuery: "無効な検索クエリです"
|
||||
ClientIDMissing: "クライアントIDがありません"
|
||||
TeamIDMissing: "チームIDがありません"
|
||||
KeyIDMissing: "キーIDがありません"
|
||||
PrivateKeyMissing: "秘密キーがありません"
|
||||
LoginPolicy:
|
||||
NotFound: "ログインポリシーが見つかりません"
|
||||
Invalid: "無効なログインポリシーです"
|
||||
@@ -614,6 +608,13 @@ Errors:
|
||||
Duplicate: "Web キー ID が一意ではありません"
|
||||
NoActive: "アクティブな Web キーが見つかりません"
|
||||
NotFound: "Web キーが見つかりません"
|
||||
IDP:
|
||||
InvalidSearchQuery: "無効な検索クエリです"
|
||||
ClientIDMissing: "クライアントIDがありません"
|
||||
TeamIDMissing: "チームIDがありません"
|
||||
KeyIDMissing: "キーIDがありません"
|
||||
PrivateKeyMissing: "秘密キーがありません"
|
||||
InvalidPrivateKey: "無効な秘密鍵形式"
|
||||
|
||||
AggregateTypes:
|
||||
action: "アクション"
|
||||
|
||||
@@ -237,12 +237,6 @@ Errors:
|
||||
AlreadyExists: "도메인이 이미 존재합니다"
|
||||
InvalidCharacter: "도메인에는 영숫자, ., -만 허용됩니다"
|
||||
EmptyString: "유효하지 않은 문자들이 비어 있는 문자열로 대체되었고 결과 도메인이 비어 있습니다"
|
||||
IDP:
|
||||
InvalidSearchQuery: "잘못된 검색 쿼리입니다"
|
||||
ClientIDMissing: "ClientID가 누락되었습니다"
|
||||
TeamIDMissing: "TeamID가 누락되었습니다"
|
||||
KeyIDMissing: "KeyID가 누락되었습니다"
|
||||
PrivateKeyMissing: "개인 키가 누락되었습니다"
|
||||
LoginPolicy:
|
||||
NotFound: "로그인 정책을 찾을 수 없습니다"
|
||||
Invalid: "로그인 정책이 유효하지 않습니다"
|
||||
@@ -614,6 +608,13 @@ Errors:
|
||||
Duplicate: "웹 키 ID가 고유하지 않습니다"
|
||||
NoActive: "활성 웹 키가 없습니다"
|
||||
NotFound: "웹 키를 찾을 수 없습니다"
|
||||
IDP:
|
||||
InvalidSearchQuery: "잘못된 검색 쿼리입니다"
|
||||
ClientIDMissing: "ClientID가 누락되었습니다"
|
||||
TeamIDMissing: "TeamID가 누락되었습니다"
|
||||
KeyIDMissing: "KeyID가 누락되었습니다"
|
||||
PrivateKeyMissing: "개인 키가 누락되었습니다"
|
||||
InvalidPrivateKey: "유효하지 않은 개인 키 형식"
|
||||
|
||||
AggregateTypes:
|
||||
action: "작업"
|
||||
|
||||
@@ -235,12 +235,6 @@ Errors:
|
||||
AlreadyExists: "Доменот веќе постои"
|
||||
InvalidCharacter: "Дозволени се само алфанумерички знаци, . и - се дозволени за домен"
|
||||
EmptyString: "Неважечките ненумерички и азбучни знаци се заменети со празни места и добиениот домен е празна низа"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Невалидно пребарување"
|
||||
ClientID Missing: "ClientID недостасува"
|
||||
TeamIDMissing: "TeamID недостасува"
|
||||
Клучен ID Недостасува: "Недостасува ID на клуч"
|
||||
PrivateKeyMissing: "Недостасува приватен клуч"
|
||||
LoginPolicy:
|
||||
NotFound: "Политиката за најавување не е пронајдена"
|
||||
Invalid: "Политиката за најавување е невалидна"
|
||||
@@ -612,6 +606,13 @@ Errors:
|
||||
Duplicate: "ID на веб-клучот не е единствен"
|
||||
NoActive: "Не е пронајден активен веб-клуч"
|
||||
NotFound: "Веб-клучот не е пронајден"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Невалидно пребарување"
|
||||
ClientIDMissing: "ClientID недостасува"
|
||||
TeamIDMissing: "TeamID недостасува"
|
||||
KeyIDMissing: "Недостасува ID на клуч"
|
||||
PrivateKeyMissing: "Недостасува приватен клуч"
|
||||
InvalidPrivateKey: "Невалиден формат на приватен клуч"
|
||||
|
||||
AggregateTypes:
|
||||
action: "Акција"
|
||||
|
||||
@@ -236,12 +236,6 @@ Errors:
|
||||
AlreadyExists: "Domein bestaat al"
|
||||
InvalidCharacter: "Alleen alfanumerieke tekens, . en - zijn toegestaan voor een domein"
|
||||
EmptyString: "Ongeldige niet-numerieke en alfabetische tekens zijn vervangen door lege spaties en het resulterende domein is een lege string"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Ongeldige zoekopdracht"
|
||||
ClientIDMissing: "ClientID ontbreekt"
|
||||
TeamIDMissing: "TeamID ontbreekt"
|
||||
KeyIDMissing: "KeyID ontbreekt"
|
||||
PrivateKeyMissing: "Privésleutel ontbreekt"
|
||||
LoginPolicy:
|
||||
NotFound: "Login Beleid niet gevonden"
|
||||
Invalid: "Login Beleid is ongeldig"
|
||||
@@ -613,6 +607,13 @@ Errors:
|
||||
Duplicate: "Websleutel-ID niet uniek"
|
||||
NoActive: "Geen actieve websleutel gevonden"
|
||||
NotFound: "Websleutel niet gevonden"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Ongeldige zoekopdracht"
|
||||
ClientIDMissing: "ClientID ontbreekt"
|
||||
TeamIDMissing: "TeamID ontbreekt"
|
||||
KeyIDMissing: "KeyID ontbreekt"
|
||||
PrivateKeyMissing: "Privésleutel ontbreekt"
|
||||
InvalidPrivateKey: "Ongeldig formaat van privésleutel"
|
||||
|
||||
AggregateTypes:
|
||||
action: "Actie"
|
||||
|
||||
@@ -236,12 +236,6 @@ Errors:
|
||||
AlreadyExists: "Domena już istnieje"
|
||||
InvalidCharacter: "Tylko znaki alfanumeryczne, . i - są dozwolone dla domeny"
|
||||
EmptyString: "Nieprawidłowe znaki inne niż numeryczne i alfabetyczne zostały zastąpione pustymi spacjami, a wynikowa domena jest pustym ciągiem znaków"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Nieprawidłowe zapytanie wyszukiwania"
|
||||
ClientIDMissing: "Brak ClientID"
|
||||
TeamIDMissing: "Brak TeamID"
|
||||
KeyIDMissing: "Brak KeyID"
|
||||
PrivateKeyMissing: "Brak klucza prywatnego"
|
||||
LoginPolicy:
|
||||
NotFound: "Polityka logowania nie znaleziona"
|
||||
Invalid: "Polityka logowania jest nieprawidłowa"
|
||||
@@ -613,6 +607,13 @@ Errors:
|
||||
Duplicate: "Identyfikator klucza internetowego nie jest unikalny"
|
||||
NoActive: "Nie znaleziono aktywnego klucza internetowego"
|
||||
NotFound: "Nie znaleziono klucza internetowego"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Nieprawidłowe zapytanie wyszukiwania"
|
||||
ClientIDMissing: "Brak ClientID"
|
||||
TeamIDMissing: "Brak TeamID"
|
||||
KeyIDMissing: "Brak KeyID"
|
||||
PrivateKeyMissing: "Brak klucza prywatnego"
|
||||
InvalidPrivateKey: "Nieprawidłowy format klucza prywatnego"
|
||||
|
||||
AggregateTypes:
|
||||
action: "Działanie"
|
||||
|
||||
@@ -235,12 +235,6 @@ Errors:
|
||||
AlreadyExists: "Domínio já existe"
|
||||
InvalidCharacter: "Apenas caracteres alfanuméricos, . e - são permitidos para um domínio"
|
||||
EmptyString: "Caracteres não numéricos e alfabéticos inválidos foram substituídos por espaços vazios e o domínio resultante é uma string vazia"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Consulta de pesquisa inválida"
|
||||
ClientIDMissing: "ClientID ausente"
|
||||
TeamIDMissing: "TeamID ausente"
|
||||
KeyIDMissing: "KeyID ausente"
|
||||
PrivateKeyMissing: "Chave privada ausente"
|
||||
LoginPolicy:
|
||||
NotFound: "Política de login não encontrada"
|
||||
Invalid: "Política de login é inválida"
|
||||
@@ -612,6 +606,13 @@ Errors:
|
||||
Duplicate: "ID da chave Web não exclusivo"
|
||||
NoActive: "Nenhuma chave web ativa encontrada"
|
||||
NotFound: "Chave Web não encontrada"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Consulta de pesquisa inválida"
|
||||
ClientIDMissing: "ClientID ausente"
|
||||
TeamIDMissing: "TeamID ausente"
|
||||
KeyIDMissing: "KeyID ausente"
|
||||
PrivateKeyMissing: "Chave privada ausente"
|
||||
InvalidPrivateKey: "Formato de chave privada inválido"
|
||||
|
||||
AggregateTypes:
|
||||
action: "Ação"
|
||||
|
||||
@@ -237,12 +237,6 @@ Errors:
|
||||
AlreadyExists: "Domeniul există deja"
|
||||
InvalidCharacter: "Numai caractere alfanumerice, . și - sunt permise pentru un domeniu"
|
||||
EmptyString: "Caracterele non-numerice și alfabetice invalide au fost înlocuite cu spații goale și domeniul rezultat este un șir gol"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Interogare de căutare invalidă"
|
||||
ClientIDMissing: "ClientID lipsă"
|
||||
TeamIDMissing: "TeamID lipsă"
|
||||
KeyIDMissing: "KeyID lipsă"
|
||||
PrivateKeyMissing: "Cheie Privată lipsă"
|
||||
LoginPolicy:
|
||||
NotFound: "Politica de conectare nu a fost găsită"
|
||||
Invalid: "Politica de conectare este invalidă"
|
||||
@@ -609,6 +603,13 @@ Errors:
|
||||
Duplicate: "ID-ul cheii web nu este unic"
|
||||
NoActive: "Nu a fost găsită nicio cheie web activă"
|
||||
NotFound: "Cheia web nu a fost găsită"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Interogare de căutare invalidă"
|
||||
ClientIDMissing: "ClientID lipsă"
|
||||
TeamIDMissing: "TeamID lipsă"
|
||||
KeyIDMissing: "KeyID lipsă"
|
||||
PrivateKeyMissing: "Cheie Privată lipsă"
|
||||
InvalidPrivateKey: "Format de cheie privată nevalid"
|
||||
|
||||
AggregateTypes:
|
||||
action: "Acțiune"
|
||||
|
||||
@@ -230,12 +230,6 @@ Errors:
|
||||
Domain:
|
||||
AlreadyExists: "Домен уже существует"
|
||||
InvalidCharacter: "Только буквенно-цифровые символы, . и - разрешены для домена"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Неверный поисковый запрос"
|
||||
ClientIDMissing: "ClientID отсутствует"
|
||||
TeamIDMissing: "TeamID отсутствует"
|
||||
KeyIDMissing: "KeyID отсутствует"
|
||||
PrivateKeyMissing: "Закрытый ключ отсутствует"
|
||||
LoginPolicy:
|
||||
NotFound: "Политика входа в систему не найдена"
|
||||
Invalid: "Политика входа в систему недействительна"
|
||||
@@ -602,6 +596,13 @@ Errors:
|
||||
Duplicate: "Идентификатор веб-ключа не уникален"
|
||||
NoActive: "Активный веб-ключ не найден"
|
||||
NotFound: "Веб-ключ не найден"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Неверный поисковый запрос"
|
||||
ClientIDMissing: "ClientID отсутствует"
|
||||
TeamIDMissing: "TeamID отсутствует"
|
||||
KeyIDMissing: "KeyID отсутствует"
|
||||
PrivateKeyMissing: "Закрытый ключ отсутствует"
|
||||
InvalidPrivateKey: "Неверный формат приватного ключа"
|
||||
|
||||
AggregateTypes:
|
||||
action: "Действие"
|
||||
|
||||
@@ -236,12 +236,6 @@ Errors:
|
||||
AlreadyExists: "Domänen finns redan"
|
||||
InvalidCharacter: "Endast alfanumeriska tecken, . och - är tillåtna för en domän"
|
||||
EmptyString: "Ogiltiga icke-numeriska och alfabetiska tecken ersattes med tomma utrymmen och den resulterande domänen är en tom sträng"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Ogiltig sökfråga"
|
||||
ClientIDMissing: "ClientID saknas"
|
||||
TeamIDMissing: "TeamID saknas"
|
||||
KeyIDMissing: "KeyID saknas"
|
||||
PrivateKeyMissing: "Privat nyckel saknas"
|
||||
LoginPolicy:
|
||||
NotFound: "Inloggningspolicyn hittades inte"
|
||||
Invalid: "Inloggningspolicyn är ogiltig"
|
||||
@@ -613,6 +607,13 @@ Errors:
|
||||
Duplicate: "Webnyckel-ID är inte unikt"
|
||||
NoActive: "Ingen aktiv webbnyckel hittades"
|
||||
NotFound: "Webnyckel hittades inte"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Ogiltig sökfråga"
|
||||
ClientIDMissing: "ClientID saknas"
|
||||
TeamIDMissing: "TeamID saknas"
|
||||
KeyIDMissing: "KeyID saknas"
|
||||
PrivateKeyMissing: "Privat nyckel saknas"
|
||||
InvalidPrivateKey: "Ogiltigt format för privat nyckel"
|
||||
|
||||
AggregateTypes:
|
||||
action: "Åtgärd"
|
||||
|
||||
@@ -237,12 +237,6 @@ Errors:
|
||||
AlreadyExists: "Domain zaten mevcut"
|
||||
InvalidCharacter: "Domain için sadece alfanümerik karakterler, . ve - kullanılabilir"
|
||||
EmptyString: "Geçersiz sayısal olmayan ve alfabetik olmayan karakterler boş alanlarla değiştirildi ve sonuçta domain boş bir dize oldu"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Geçersiz arama sorgusu"
|
||||
ClientIDMissing: "ClientID eksik"
|
||||
TeamIDMissing: "TeamID eksik"
|
||||
KeyIDMissing: "KeyID eksik"
|
||||
PrivateKeyMissing: "Özel Anahtar eksik"
|
||||
LoginPolicy:
|
||||
NotFound: "Giriş Politikası bulunamadı"
|
||||
Invalid: "Giriş Politikası geçersiz"
|
||||
@@ -614,6 +608,13 @@ Errors:
|
||||
Duplicate: "Web anahtarı ID benzersiz değil"
|
||||
NoActive: "Aktif web anahtarı bulunamadı"
|
||||
NotFound: "Web anahtarı bulunamadı"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Geçersiz arama sorgusu"
|
||||
ClientIDMissing: "ClientID eksik"
|
||||
TeamIDMissing: "TeamID eksik"
|
||||
KeyIDMissing: "KeyID eksik"
|
||||
PrivateKeyMissing: "Özel Anahtar eksik"
|
||||
InvalidPrivateKey: "Geçersiz özel anahtar biçimi"
|
||||
|
||||
AggregateTypes:
|
||||
action: "Eylem"
|
||||
|
||||
@@ -231,12 +231,6 @@ Errors:
|
||||
AlreadyExists: "Домен вже існує"
|
||||
InvalidCharacter: "Для домену дозволені лише буквено-цифрові символи, . та -"
|
||||
EmptyString: "Недійсні не цифрові та не алфавітні символи були замінені порожніми пробілами і результуючий домен є порожнім рядком"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Недійсний пошуковий запит"
|
||||
ClientIDMissing: "Відсутній ClientID"
|
||||
TeamIDMissing: "Відсутній TeamID"
|
||||
KeyIDMissing: "Відсутній KeyID"
|
||||
PrivateKeyMissing: "Відсутній приватний ключ"
|
||||
LoginPolicy:
|
||||
NotFound: "Політика входу не знайдена"
|
||||
Invalid: "Політика входу недійсна"
|
||||
@@ -608,6 +602,13 @@ Errors:
|
||||
Duplicate: "Ідентифікатор веб-ключа не унікальний"
|
||||
NoActive: "Активний веб-ключ не знайдено"
|
||||
NotFound: "Веб-ключ не знайдено"
|
||||
IDP:
|
||||
InvalidSearchQuery: "Недійсний пошуковий запит"
|
||||
ClientIDMissing: "Відсутній ClientID"
|
||||
TeamIDMissing: "Відсутній TeamID"
|
||||
KeyIDMissing: "Відсутній KeyID"
|
||||
PrivateKeyMissing: "Відсутній приватний ключ"
|
||||
InvalidPrivateKey: "Невірний формат приватного ключа"
|
||||
|
||||
AggregateTypes:
|
||||
action: "Дія"
|
||||
|
||||
@@ -237,12 +237,6 @@ Errors:
|
||||
AlreadyExists: "域名已存在"
|
||||
InvalidCharacter: "只有字母数字字符,.和 - 允许用于域名中"
|
||||
EmptyString: "无效的非数字和字母字符被替换为空格,结果域是空字符串"
|
||||
IDP:
|
||||
InvalidSearchQuery: "无效的搜索查询"
|
||||
ClientIDMissing: "客户端 ID 丢失"
|
||||
TeamIDMissing: "团队 ID 丢失"
|
||||
KeyIDMissing: "密钥 ID 丢失"
|
||||
PrivateKeyMissing: "私钥丢失"
|
||||
LoginPolicy:
|
||||
NotFound: "未找到登录策略"
|
||||
Invalid: "登录策略无效"
|
||||
@@ -614,6 +608,13 @@ Errors:
|
||||
Duplicate: "Web 密钥 ID 不唯一"
|
||||
NoActive: "未找到活动 Web 密钥"
|
||||
NotFound: "未找到 Web 密钥"
|
||||
IDP:
|
||||
InvalidSearchQuery: "无效的搜索查询"
|
||||
ClientIDMissing: "客户端 ID 丢失"
|
||||
TeamIDMissing: "团队 ID 丢失"
|
||||
KeyIDMissing: "密钥 ID 丢失"
|
||||
PrivateKeyMissing: "私钥丢失"
|
||||
InvalidPrivateKey: "无效的私钥格式"
|
||||
|
||||
AggregateTypes:
|
||||
action: "动作"
|
||||
|
||||
Reference in New Issue
Block a user