mirror of
https://github.com/zitadel/zitadel.git
synced 2025-03-01 00:07:22 +00:00
parent
5c0f527a49
commit
3a63fb765a
@ -157,7 +157,7 @@ func startAPIs(ctx context.Context, router *mux.Router, commands *command.Comman
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error starting auth repo: %w", err)
|
return fmt.Errorf("error starting auth repo: %w", err)
|
||||||
}
|
}
|
||||||
adminRepo, err := admin_es.Start(config.Admin, store, dbClient, login.HandlerPrefix)
|
adminRepo, err := admin_es.Start(config.Admin, store, dbClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error starting admin repo: %w", err)
|
return fmt.Errorf("error starting admin repo: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -3405,7 +3405,7 @@ This is an empty request
|
|||||||
|
|
||||||
| Field | Type | Description | Validation |
|
| Field | Type | Description | Validation |
|
||||||
| ----- | ---- | ----------- | ----------- |
|
| ----- | ---- | ----------- | ----------- |
|
||||||
| email | string | TODO: check if no value is allowed | string.email: true<br /> |
|
| email | string | - | string.email: true<br /> |
|
||||||
| is_email_verified | bool | - | |
|
| is_email_verified | bool | - | |
|
||||||
|
|
||||||
|
|
||||||
|
@ -16,7 +16,6 @@ title: zitadel/app.proto
|
|||||||
| Field | Type | Description | Validation |
|
| Field | Type | Description | Validation |
|
||||||
| ----- | ---- | ----------- | ----------- |
|
| ----- | ---- | ----------- | ----------- |
|
||||||
| client_id | string | - | |
|
| client_id | string | - | |
|
||||||
| client_secret | string | - | |
|
|
||||||
| auth_method_type | APIAuthMethodType | - | |
|
| auth_method_type | APIAuthMethodType | - | |
|
||||||
|
|
||||||
|
|
||||||
@ -72,7 +71,6 @@ title: zitadel/app.proto
|
|||||||
| grant_types | repeated OIDCGrantType | - | |
|
| grant_types | repeated OIDCGrantType | - | |
|
||||||
| app_type | OIDCAppType | - | |
|
| app_type | OIDCAppType | - | |
|
||||||
| client_id | string | - | |
|
| client_id | string | - | |
|
||||||
| client_secret | string | - | |
|
|
||||||
| auth_method_type | OIDCAuthMethodType | - | |
|
| auth_method_type | OIDCAuthMethodType | - | |
|
||||||
| post_logout_redirect_uris | repeated string | - | |
|
| post_logout_redirect_uris | repeated string | - | |
|
||||||
| version | OIDCVersion | - | |
|
| version | OIDCVersion | - | |
|
||||||
|
@ -1341,7 +1341,7 @@ This is an empty request
|
|||||||
|
|
||||||
| Field | Type | Description | Validation |
|
| Field | Type | Description | Validation |
|
||||||
| ----- | ---- | ----------- | ----------- |
|
| ----- | ---- | ----------- | ----------- |
|
||||||
| email | string | TODO: check if no value is allowed | string.email: true<br /> |
|
| email | string | - | string.email: true<br /> |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -3155,7 +3155,7 @@ This is an empty request
|
|||||||
|
|
||||||
| Field | Type | Description | Validation |
|
| Field | Type | Description | Validation |
|
||||||
| ----- | ---- | ----------- | ----------- |
|
| ----- | ---- | ----------- | ----------- |
|
||||||
| email | string | TODO: check if no value is allowed | string.email: true<br /> |
|
| email | string | - | string.email: true<br /> |
|
||||||
| is_email_verified | bool | - | |
|
| is_email_verified | bool | - | |
|
||||||
|
|
||||||
|
|
||||||
@ -5159,7 +5159,7 @@ This is an empty response
|
|||||||
|
|
||||||
| Field | Type | Description | Validation |
|
| Field | Type | Description | Validation |
|
||||||
| ----- | ---- | ----------- | ----------- |
|
| ----- | ---- | ----------- | ----------- |
|
||||||
| email | string | TODO: check if no value is allowed | string.email: true<br /> |
|
| email | string | - | string.email: true<br /> |
|
||||||
| is_email_verified | bool | - | |
|
| is_email_verified | bool | - | |
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,13 +28,12 @@ func (h *handler) Eventstore() v1.Eventstore {
|
|||||||
return h.es
|
return h.es
|
||||||
}
|
}
|
||||||
|
|
||||||
func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es v1.Eventstore, static static.Storage, loginPrefix string) []query.Handler {
|
func Register(configs Configs, bulkLimit, errorCount uint64, view *view.View, es v1.Eventstore, static static.Storage) []query.Handler {
|
||||||
handlers := []query.Handler{}
|
handlers := []query.Handler{}
|
||||||
if static != nil {
|
if static != nil {
|
||||||
handlers = append(handlers, newStyling(
|
handlers = append(handlers, newStyling(
|
||||||
handler{view, bulkLimit, configs.cycleDuration("Styling"), errorCount, es},
|
handler{view, bulkLimit, configs.cycleDuration("Styling"), errorCount, es},
|
||||||
static,
|
static))
|
||||||
loginPrefix))
|
|
||||||
}
|
}
|
||||||
return handlers
|
return handlers
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
"github.com/muesli/gamut"
|
"github.com/muesli/gamut"
|
||||||
"github.com/zitadel/logging"
|
"github.com/zitadel/logging"
|
||||||
|
|
||||||
|
"github.com/zitadel/zitadel/internal/api/ui/login"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/eventstore"
|
"github.com/zitadel/zitadel/internal/eventstore"
|
||||||
v1 "github.com/zitadel/zitadel/internal/eventstore/v1"
|
v1 "github.com/zitadel/zitadel/internal/eventstore/v1"
|
||||||
@ -31,16 +32,13 @@ type Styling struct {
|
|||||||
handler
|
handler
|
||||||
static static.Storage
|
static static.Storage
|
||||||
subscription *v1.Subscription
|
subscription *v1.Subscription
|
||||||
resourceUrl string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newStyling(handler handler, static static.Storage, loginPrefix string) *Styling {
|
func newStyling(handler handler, static static.Storage) *Styling {
|
||||||
h := &Styling{
|
h := &Styling{
|
||||||
handler: handler,
|
handler: handler,
|
||||||
static: static,
|
static: static,
|
||||||
}
|
}
|
||||||
h.resourceUrl = loginPrefix + "/resources/dynamic" //TODO: ?
|
|
||||||
|
|
||||||
h.subscribe()
|
h.subscribe()
|
||||||
|
|
||||||
return h
|
return h
|
||||||
@ -218,7 +216,7 @@ func (m *Styling) writeFile(policy *iam_model.LabelPolicyView) (io.Reader, int64
|
|||||||
}
|
}
|
||||||
cssContent += "}"
|
cssContent += "}"
|
||||||
if policy.FontURL != "" {
|
if policy.FontURL != "" {
|
||||||
cssContent += fmt.Sprintf(fontFaceTemplate, fontname, m.resourceUrl, policy.AggregateID, policy.FontURL)
|
cssContent += fmt.Sprintf(fontFaceTemplate, fontname, login.HandlerPrefix+login.EndpointDynamicResources, policy.AggregateID, policy.FontURL)
|
||||||
}
|
}
|
||||||
cssContent += ".lgn-dark-theme {"
|
cssContent += ".lgn-dark-theme {"
|
||||||
if policy.PrimaryColorDark != "" {
|
if policy.PrimaryColorDark != "" {
|
||||||
|
@ -22,7 +22,7 @@ type EsRepository struct {
|
|||||||
eventstore.AdministratorRepo
|
eventstore.AdministratorRepo
|
||||||
}
|
}
|
||||||
|
|
||||||
func Start(conf Config, static static.Storage, dbClient *sql.DB, loginPrefix string) (*EsRepository, error) {
|
func Start(conf Config, static static.Storage, dbClient *sql.DB) (*EsRepository, error) {
|
||||||
es, err := v1.Start(dbClient)
|
es, err := v1.Start(dbClient)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -32,7 +32,7 @@ func Start(conf Config, static static.Storage, dbClient *sql.DB, loginPrefix str
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
spool := spooler.StartSpooler(conf.Spooler, es, view, dbClient, static, loginPrefix)
|
spool := spooler.StartSpooler(conf.Spooler, es, view, dbClient, static)
|
||||||
|
|
||||||
return &EsRepository{
|
return &EsRepository{
|
||||||
spooler: spool,
|
spooler: spool,
|
||||||
|
@ -18,12 +18,12 @@ type SpoolerConfig struct {
|
|||||||
Handlers handler.Configs
|
Handlers handler.Configs
|
||||||
}
|
}
|
||||||
|
|
||||||
func StartSpooler(c SpoolerConfig, es v1.Eventstore, view *view.View, sql *sql.DB, static static.Storage, loginPrefix string) *spooler.Spooler {
|
func StartSpooler(c SpoolerConfig, es v1.Eventstore, view *view.View, sql *sql.DB, static static.Storage) *spooler.Spooler {
|
||||||
spoolerConfig := spooler.Config{
|
spoolerConfig := spooler.Config{
|
||||||
Eventstore: es,
|
Eventstore: es,
|
||||||
Locker: &locker{dbClient: sql},
|
Locker: &locker{dbClient: sql},
|
||||||
ConcurrentWorkers: c.ConcurrentWorkers,
|
ConcurrentWorkers: c.ConcurrentWorkers,
|
||||||
ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, static, loginPrefix),
|
ViewHandlers: handler.Register(c.Handlers, c.BulkLimit, c.FailureCountUntilSkip, view, es, static),
|
||||||
}
|
}
|
||||||
spool := spoolerConfig.New()
|
spool := spoolerConfig.New()
|
||||||
spool.Start()
|
spool.Start()
|
||||||
|
@ -81,7 +81,7 @@ func NewHandler(commands *command.Commands, verifier *authz.TokenVerifier, authC
|
|||||||
query: queries,
|
query: queries,
|
||||||
}
|
}
|
||||||
|
|
||||||
verifier.RegisterServer("Management-API", "assets", AssetsService_AuthMethods) //TODO: separate api?
|
verifier.RegisterServer("Assets-API", "assets", AssetsService_AuthMethods)
|
||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
router.Use(sentryhttp.New(sentryhttp.Options{}).Handle, instanceInterceptor)
|
router.Use(sentryhttp.New(sentryhttp.Options{}).Handle, instanceInterceptor)
|
||||||
RegisterRoutes(router, h)
|
RegisterRoutes(router, h)
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
package action
|
package action
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"google.golang.org/protobuf/types/known/durationpb"
|
||||||
|
|
||||||
object_grpc "github.com/zitadel/zitadel/internal/api/grpc/object"
|
object_grpc "github.com/zitadel/zitadel/internal/api/grpc/object"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
"github.com/zitadel/zitadel/internal/domain"
|
||||||
"github.com/zitadel/zitadel/internal/query"
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
action_pb "github.com/zitadel/zitadel/pkg/grpc/action"
|
action_pb "github.com/zitadel/zitadel/pkg/grpc/action"
|
||||||
"google.golang.org/protobuf/types/known/durationpb"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func FlowTypeToDomain(flowType action_pb.FlowType) domain.FlowType {
|
func FlowTypeToDomain(flowType action_pb.FlowType) domain.FlowType {
|
||||||
|
@ -86,9 +86,6 @@ func domainPolicyToDomain(userLoginMustBeDomain, validateOrgDomains, smtpSenderA
|
|||||||
|
|
||||||
func updateDomainPolicyToDomain(req *admin_pb.UpdateDomainPolicyRequest) *domain.DomainPolicy {
|
func updateDomainPolicyToDomain(req *admin_pb.UpdateDomainPolicyRequest) *domain.DomainPolicy {
|
||||||
return &domain.DomainPolicy{
|
return &domain.DomainPolicy{
|
||||||
// ObjectRoot: models.ObjectRoot{
|
|
||||||
// // AggreagateID: //TODO: there should only be ONE default
|
|
||||||
// },
|
|
||||||
UserLoginMustBeDomain: req.UserLoginMustBeDomain,
|
UserLoginMustBeDomain: req.UserLoginMustBeDomain,
|
||||||
ValidateOrgDomains: req.ValidateOrgDomains,
|
ValidateOrgDomains: req.ValidateOrgDomains,
|
||||||
SMTPSenderAddressMatchesInstanceDomain: req.SmtpSenderAddressMatchesInstanceDomain,
|
SMTPSenderAddressMatchesInstanceDomain: req.SmtpSenderAddressMatchesInstanceDomain,
|
||||||
|
@ -45,7 +45,7 @@ func Test_addOIDCIDPRequestToDomain(t *testing.T) {
|
|||||||
"State",
|
"State",
|
||||||
"OIDCConfig.AuthorizationEndpoint",
|
"OIDCConfig.AuthorizationEndpoint",
|
||||||
"OIDCConfig.TokenEndpoint",
|
"OIDCConfig.TokenEndpoint",
|
||||||
"Type", //TODO: default (0) is oidc
|
"Type",
|
||||||
"JWTConfig",
|
"JWTConfig",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -79,7 +79,7 @@ func Test_addOIDCIDPRequestToDomainOIDCIDPConfig(t *testing.T) {
|
|||||||
got := addOIDCIDPRequestToDomainOIDCIDPConfig(tt.args.req)
|
got := addOIDCIDPRequestToDomainOIDCIDPConfig(tt.args.req)
|
||||||
test.AssertFieldsMapped(t, got,
|
test.AssertFieldsMapped(t, got,
|
||||||
"ObjectRoot",
|
"ObjectRoot",
|
||||||
"ClientSecret", //TODO: is client secret string enough for backend?
|
"ClientSecret",
|
||||||
"IDPConfigID",
|
"IDPConfigID",
|
||||||
"AuthorizationEndpoint",
|
"AuthorizationEndpoint",
|
||||||
"TokenEndpoint",
|
"TokenEndpoint",
|
||||||
@ -116,7 +116,7 @@ func Test_updateIDPToDomain(t *testing.T) {
|
|||||||
"OIDCConfig",
|
"OIDCConfig",
|
||||||
"JWTConfig",
|
"JWTConfig",
|
||||||
"State",
|
"State",
|
||||||
"Type", //TODO: type should not be changeable
|
"Type",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ import (
|
|||||||
"github.com/zitadel/zitadel/internal/api/grpc/object"
|
"github.com/zitadel/zitadel/internal/api/grpc/object"
|
||||||
"github.com/zitadel/zitadel/internal/query"
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
admin_pb "github.com/zitadel/zitadel/pkg/grpc/admin"
|
admin_pb "github.com/zitadel/zitadel/pkg/grpc/admin"
|
||||||
|
"github.com/zitadel/zitadel/pkg/grpc/instance"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ListInstanceDomainsRequestToModel(req *admin_pb.ListInstanceDomainsRequest) (*query.InstanceDomainSearchQueries, error) {
|
func ListInstanceDomainsRequestToModel(req *admin_pb.ListInstanceDomainsRequest) (*query.InstanceDomainSearchQueries, error) {
|
||||||
@ -15,11 +16,26 @@ func ListInstanceDomainsRequestToModel(req *admin_pb.ListInstanceDomainsRequest)
|
|||||||
}
|
}
|
||||||
return &query.InstanceDomainSearchQueries{
|
return &query.InstanceDomainSearchQueries{
|
||||||
SearchRequest: query.SearchRequest{
|
SearchRequest: query.SearchRequest{
|
||||||
Offset: offset,
|
Offset: offset,
|
||||||
Limit: limit,
|
Limit: limit,
|
||||||
Asc: asc,
|
Asc: asc,
|
||||||
|
SortingColumn: fieldNameToInstanceDomainColumn(req.SortingColumn),
|
||||||
},
|
},
|
||||||
//SortingColumn: //TODO: sorting
|
|
||||||
Queries: queries,
|
Queries: queries,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fieldNameToInstanceDomainColumn(fieldName instance.DomainFieldName) query.Column {
|
||||||
|
switch fieldName {
|
||||||
|
case instance.DomainFieldName_DOMAIN_FIELD_NAME_DOMAIN:
|
||||||
|
return query.InstanceDomainDomainCol
|
||||||
|
case instance.DomainFieldName_DOMAIN_FIELD_NAME_PRIMARY:
|
||||||
|
return query.InstanceDomainIsPrimaryCol
|
||||||
|
case instance.DomainFieldName_DOMAIN_FIELD_NAME_GENERATED:
|
||||||
|
return query.InstanceDomainIsGeneratedCol
|
||||||
|
case instance.DomainFieldName_DOMAIN_FIELD_NAME_CREATION_DATE:
|
||||||
|
return query.InstanceDomainCreationDateCol
|
||||||
|
default:
|
||||||
|
return query.Column{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -52,15 +52,13 @@ func (s *Server) SetUpOrg(ctx context.Context, req *admin_pb.SetUpOrgRequest) (*
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_ = userIDs //TODO: handle userIDs
|
|
||||||
human := setUpOrgHumanToCommand(req.User.(*admin_pb.SetUpOrgRequest_Human_).Human) //TODO: handle machine
|
human := setUpOrgHumanToCommand(req.User.(*admin_pb.SetUpOrgRequest_Human_).Human) //TODO: handle machine
|
||||||
org := setUpOrgOrgToDomain(req.Org) //TODO: handle domain
|
|
||||||
_ = org
|
|
||||||
|
|
||||||
userID, objectDetails, err := s.command.SetUpOrg(ctx, &command.OrgSetup{
|
userID, objectDetails, err := s.command.SetUpOrg(ctx, &command.OrgSetup{
|
||||||
Name: req.Org.Name,
|
Name: req.Org.Name,
|
||||||
Human: human,
|
CustomDomain: req.Org.Domain,
|
||||||
})
|
Human: human,
|
||||||
|
}, userIDs...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package admin
|
|||||||
import (
|
import (
|
||||||
"github.com/zitadel/zitadel/internal/api/grpc/object"
|
"github.com/zitadel/zitadel/internal/api/grpc/object"
|
||||||
org_grpc "github.com/zitadel/zitadel/internal/api/grpc/org"
|
org_grpc "github.com/zitadel/zitadel/internal/api/grpc/org"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
"github.com/zitadel/zitadel/internal/query"
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
"github.com/zitadel/zitadel/pkg/grpc/admin"
|
"github.com/zitadel/zitadel/pkg/grpc/admin"
|
||||||
"github.com/zitadel/zitadel/pkg/grpc/org"
|
"github.com/zitadel/zitadel/pkg/grpc/org"
|
||||||
@ -34,14 +33,3 @@ func fieldNameToOrgColumn(fieldName org.OrgFieldName) query.Column {
|
|||||||
return query.Column{}
|
return query.Column{}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func setUpOrgOrgToDomain(req *admin.SetUpOrgRequest_Org) *domain.Org {
|
|
||||||
org := &domain.Org{
|
|
||||||
Name: req.Name,
|
|
||||||
Domains: []*domain.OrgDomain{},
|
|
||||||
}
|
|
||||||
if req.Domain != "" {
|
|
||||||
org.Domains = append(org.Domains, &domain.OrgDomain{Domain: req.Domain})
|
|
||||||
}
|
|
||||||
return org
|
|
||||||
}
|
|
||||||
|
@ -190,8 +190,6 @@ func IDPViewToConfigPb(config *query.IDP) idp_pb.IDPConfig {
|
|||||||
|
|
||||||
func FieldNameToModel(fieldName idp_pb.IDPFieldName) query.Column {
|
func FieldNameToModel(fieldName idp_pb.IDPFieldName) query.Column {
|
||||||
switch fieldName {
|
switch fieldName {
|
||||||
// case admin.IdpSearchKey_IDPSEARCHKEY_IDP_CONFIG_ID: //TODO: not implemented in proto
|
|
||||||
// return iam_model.IDPConfigSearchKeyIdpConfigID
|
|
||||||
case idp_pb.IDPFieldName_IDP_FIELD_NAME_NAME:
|
case idp_pb.IDPFieldName_IDP_FIELD_NAME_NAME:
|
||||||
return query.IDPNameCol
|
return query.IDPNameCol
|
||||||
default:
|
default:
|
||||||
|
@ -45,7 +45,7 @@ func Test_addOIDCIDPRequestToDomain(t *testing.T) {
|
|||||||
"State",
|
"State",
|
||||||
"OIDCConfig.AuthorizationEndpoint",
|
"OIDCConfig.AuthorizationEndpoint",
|
||||||
"OIDCConfig.TokenEndpoint",
|
"OIDCConfig.TokenEndpoint",
|
||||||
"Type", //TODO: default (0) is oidc
|
"Type",
|
||||||
"JWTConfig",
|
"JWTConfig",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -79,7 +79,7 @@ func Test_addOIDCIDPRequestToDomainOIDCIDPConfig(t *testing.T) {
|
|||||||
got := addOIDCIDPRequestToDomainOIDCIDPConfig(tt.args.req)
|
got := addOIDCIDPRequestToDomainOIDCIDPConfig(tt.args.req)
|
||||||
test.AssertFieldsMapped(t, got,
|
test.AssertFieldsMapped(t, got,
|
||||||
"ObjectRoot",
|
"ObjectRoot",
|
||||||
"ClientSecret", //TODO: is client secret string enough for backend?
|
"ClientSecret",
|
||||||
"IDPConfigID",
|
"IDPConfigID",
|
||||||
"AuthorizationEndpoint",
|
"AuthorizationEndpoint",
|
||||||
"TokenEndpoint",
|
"TokenEndpoint",
|
||||||
@ -116,7 +116,7 @@ func Test_updateIDPToDomain(t *testing.T) {
|
|||||||
"OIDCConfig",
|
"OIDCConfig",
|
||||||
"JWTConfig",
|
"JWTConfig",
|
||||||
"State",
|
"State",
|
||||||
"Type", //TODO: type should not be changeable
|
"Type",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -65,7 +65,6 @@ func AppAPIConfigToPb(app *query.APIApp) app_pb.AppConfig {
|
|||||||
return &app_pb.App_ApiConfig{
|
return &app_pb.App_ApiConfig{
|
||||||
ApiConfig: &app_pb.APIConfig{
|
ApiConfig: &app_pb.APIConfig{
|
||||||
ClientId: app.ClientID,
|
ClientId: app.ClientID,
|
||||||
ClientSecret: "", //TODO: remove from proto
|
|
||||||
AuthMethodType: APIAuthMethodeTypeToPb(app.AuthMethodType),
|
AuthMethodType: APIAuthMethodeTypeToPb(app.AuthMethodType),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,8 @@ package user
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/zitadel/zitadel/internal/api/grpc/object"
|
"github.com/zitadel/zitadel/internal/api/grpc/object"
|
||||||
"github.com/zitadel/zitadel/internal/domain"
|
|
||||||
"github.com/zitadel/zitadel/internal/errors"
|
"github.com/zitadel/zitadel/internal/errors"
|
||||||
"github.com/zitadel/zitadel/internal/query"
|
"github.com/zitadel/zitadel/internal/query"
|
||||||
user_model "github.com/zitadel/zitadel/internal/user/model"
|
|
||||||
user_pb "github.com/zitadel/zitadel/pkg/grpc/user"
|
user_pb "github.com/zitadel/zitadel/pkg/grpc/user"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -36,62 +34,6 @@ func MembershipQueryToQuery(req *user_pb.MembershipQuery) (query.SearchQuery, er
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func MembershipIAMQueryToModel(q *user_pb.MembershipIAMQuery) []*user_model.UserMembershipSearchQuery {
|
|
||||||
return []*user_model.UserMembershipSearchQuery{
|
|
||||||
{
|
|
||||||
Key: user_model.UserMembershipSearchKeyMemberType,
|
|
||||||
Method: domain.SearchMethodEquals,
|
|
||||||
Value: user_model.MemberTypeIam,
|
|
||||||
},
|
|
||||||
//TODO: q.IAM?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func MembershipOrgQueryToModel(q *user_pb.MembershipOrgQuery) []*user_model.UserMembershipSearchQuery {
|
|
||||||
return []*user_model.UserMembershipSearchQuery{
|
|
||||||
{
|
|
||||||
Key: user_model.UserMembershipSearchKeyMemberType,
|
|
||||||
Method: domain.SearchMethodEquals,
|
|
||||||
Value: user_model.MemberTypeOrganisation,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: user_model.UserMembershipSearchKeyObjectID,
|
|
||||||
Method: domain.SearchMethodEquals,
|
|
||||||
Value: q.OrgId,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func MembershipProjectQueryToModel(q *user_pb.MembershipProjectQuery) []*user_model.UserMembershipSearchQuery {
|
|
||||||
return []*user_model.UserMembershipSearchQuery{
|
|
||||||
{
|
|
||||||
Key: user_model.UserMembershipSearchKeyMemberType,
|
|
||||||
Method: domain.SearchMethodEquals,
|
|
||||||
Value: user_model.MemberTypeProject,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: user_model.UserMembershipSearchKeyObjectID,
|
|
||||||
Method: domain.SearchMethodEquals,
|
|
||||||
Value: q.ProjectId,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func MembershipProjectGrantQueryToModel(q *user_pb.MembershipProjectGrantQuery) []*user_model.UserMembershipSearchQuery {
|
|
||||||
return []*user_model.UserMembershipSearchQuery{
|
|
||||||
{
|
|
||||||
Key: user_model.UserMembershipSearchKeyMemberType,
|
|
||||||
Method: domain.SearchMethodEquals,
|
|
||||||
Value: user_model.MemberTypeProjectGrant,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
Key: user_model.UserMembershipSearchKeyObjectID,
|
|
||||||
Method: domain.SearchMethodEquals,
|
|
||||||
Value: q.ProjectGrantId,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func MembershipsToMembershipsPb(memberships []*query.Membership) []*user_pb.Membership {
|
func MembershipsToMembershipsPb(memberships []*query.Membership) []*user_pb.Membership {
|
||||||
converted := make([]*user_pb.Membership, len(memberships))
|
converted := make([]*user_pb.Membership, len(memberships))
|
||||||
for i, membership := range memberships {
|
for i, membership := range memberships {
|
||||||
|
@ -62,7 +62,7 @@ func authorize(r *http.Request, verifier *authz.TokenVerifier, authConfig authz.
|
|||||||
return nil, errors.New("auth header missing")
|
return nil, errors.New("auth header missing")
|
||||||
}
|
}
|
||||||
|
|
||||||
ctxSetter, err := authz.CheckUserAuthorization(authCtx, &httpReq{}, authToken, http_util.GetOrgID(r), verifier, authConfig, authOpt, r.RequestURI) //TODO: permission
|
ctxSetter, err := authz.CheckUserAuthorization(authCtx, &httpReq{}, authToken, http_util.GetOrgID(r), verifier, authConfig, authOpt, r.RequestURI)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,6 @@ func (o *OPStorage) CreateAuthRequest(ctx context.Context, req *oidc.AuthRequest
|
|||||||
return nil, errors.ThrowPreconditionFailed(err, "OIDC-Gqrfg", "Errors.Internal")
|
return nil, errors.ThrowPreconditionFailed(err, "OIDC-Gqrfg", "Errors.Internal")
|
||||||
}
|
}
|
||||||
authRequest := CreateAuthRequestToBusiness(ctx, req, userAgentID, userID)
|
authRequest := CreateAuthRequestToBusiness(ctx, req, userAgentID, userID)
|
||||||
//TODO: ensure splitting of command and query side durring auth request and login refactoring
|
|
||||||
resp, err := o.repo.CreateAuthRequest(ctx, authRequest)
|
resp, err := o.repo.CreateAuthRequest(ctx, authRequest)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -66,8 +66,7 @@ func (l *Login) handleRegisterOrgCheck(w http.ResponseWriter, r *http.Request) {
|
|||||||
l.renderRegisterOrg(w, r, authRequest, data, err)
|
l.renderRegisterOrg(w, r, authRequest, data, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_ = userIDs //TODO: handle userIDs
|
_, _, err = l.command.SetUpOrg(ctx, data.toCommandOrg(), userIDs...)
|
||||||
_, _, err = l.command.SetUpOrg(ctx, data.toCommandOrg())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.renderRegisterOrg(w, r, authRequest, data, err)
|
l.renderRegisterOrg(w, r, authRequest, data, err)
|
||||||
return
|
return
|
||||||
|
@ -432,7 +432,7 @@ func (l *Login) getErrorMessage(r *http.Request, err error) (errID, errMsg strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *Login) getTheme(r *http.Request) string {
|
func (l *Login) getTheme(r *http.Request) string {
|
||||||
return "zitadel" //TODO: impl
|
return "zitadel"
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *Login) getThemeMode(r *http.Request) string {
|
func (l *Login) getThemeMode(r *http.Request) string {
|
||||||
|
@ -17,11 +17,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type OrgSetup struct {
|
type OrgSetup struct {
|
||||||
Name string
|
Name string
|
||||||
Human AddHuman
|
CustomDomain string
|
||||||
|
Human AddHuman
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Commands) SetUpOrg(ctx context.Context, o *OrgSetup) (string, *domain.ObjectDetails, error) {
|
func (c *Commands) SetUpOrg(ctx context.Context, o *OrgSetup, userIDs ...string) (string, *domain.ObjectDetails, error) {
|
||||||
orgID, err := id.SonyFlakeGenerator.Next()
|
orgID, err := id.SonyFlakeGenerator.Next()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
@ -35,11 +36,19 @@ func (c *Commands) SetUpOrg(ctx context.Context, o *OrgSetup) (string, *domain.O
|
|||||||
orgAgg := org.NewAggregate(orgID)
|
orgAgg := org.NewAggregate(orgID)
|
||||||
userAgg := user_repo.NewAggregate(userID, orgID)
|
userAgg := user_repo.NewAggregate(userID, orgID)
|
||||||
|
|
||||||
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter,
|
validations := []preparation.Validation{
|
||||||
AddOrgCommand(ctx, orgAgg, o.Name),
|
AddOrgCommand(ctx, orgAgg, o.Name, userIDs...),
|
||||||
AddHumanCommand(userAgg, &o.Human, c.userPasswordAlg, c.userEncryption),
|
AddHumanCommand(userAgg, &o.Human, c.userPasswordAlg, c.userEncryption),
|
||||||
c.AddOrgMemberCommand(orgAgg, userID, domain.RoleOrgOwner),
|
c.AddOrgMemberCommand(orgAgg, userID, domain.RoleOrgOwner),
|
||||||
)
|
}
|
||||||
|
if o.CustomDomain != "" {
|
||||||
|
validations = append(validations, AddOrgDomain(orgAgg, o.CustomDomain))
|
||||||
|
for _, userID := range userIDs {
|
||||||
|
validations = append(validations, c.prepareUserDomainClaimed(userID))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, validations...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
@ -57,7 +66,7 @@ func (c *Commands) SetUpOrg(ctx context.Context, o *OrgSetup) (string, *domain.O
|
|||||||
|
|
||||||
//AddOrgCommand defines the commands to create a new org,
|
//AddOrgCommand defines the commands to create a new org,
|
||||||
// this includes the verified default domain
|
// this includes the verified default domain
|
||||||
func AddOrgCommand(ctx context.Context, a *org.Aggregate, name string) preparation.Validation {
|
func AddOrgCommand(ctx context.Context, a *org.Aggregate, name string, userIDs ...string) preparation.Validation {
|
||||||
return func() (preparation.CreateCommands, error) {
|
return func() (preparation.CreateCommands, error) {
|
||||||
if name = strings.TrimSpace(name); name == "" {
|
if name = strings.TrimSpace(name); name == "" {
|
||||||
return nil, errors.ThrowInvalidArgument(nil, "ORG-mruNY", "Errors.Invalid.Argument")
|
return nil, errors.ThrowInvalidArgument(nil, "ORG-mruNY", "Errors.Invalid.Argument")
|
||||||
|
@ -44,8 +44,6 @@ func AddAPIAppCommand(app *addAPIApp, clientSecretAlg crypto.HashAlgorithm) prep
|
|||||||
return nil, errors.ThrowInternal(err, "V2-f0pgP", "Errors.Internal")
|
return nil, errors.ThrowInternal(err, "V2-f0pgP", "Errors.Internal")
|
||||||
}
|
}
|
||||||
|
|
||||||
//requires client secret
|
|
||||||
// TODO(release blocking):we have to return the secret
|
|
||||||
if app.AuthMethodType == domain.APIAuthMethodTypeBasic {
|
if app.AuthMethodType == domain.APIAuthMethodTypeBasic {
|
||||||
app.ClientSecret, app.ClientSecretPlain, err = newAppClientSecret(ctx, filter, clientSecretAlg)
|
app.ClientSecret, app.ClientSecretPlain, err = newAppClientSecret(ctx, filter, clientSecretAlg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -340,6 +340,38 @@ func (c *Commands) userDomainClaimed(ctx context.Context, userID string) (events
|
|||||||
}, changedUserGrant, nil
|
}, changedUserGrant, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Commands) prepareUserDomainClaimed(userID string) preparation.Validation {
|
||||||
|
return func() (_ preparation.CreateCommands, err error) {
|
||||||
|
return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) {
|
||||||
|
userWriteModel, err := userWriteModelByID(ctx, filter, userID, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if !userWriteModel.UserState.Exists() {
|
||||||
|
return nil, caos_errs.ThrowNotFound(nil, "COMMAND-ii9K0", "Errors.User.NotFound")
|
||||||
|
}
|
||||||
|
domainPolicy, err := domainPolicyWriteModel(ctx, filter)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
userAgg := UserAggregateFromWriteModel(&userWriteModel.WriteModel)
|
||||||
|
|
||||||
|
id, err := c.idGenerator.Next()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return []eventstore.Command{user.NewDomainClaimedEvent(
|
||||||
|
ctx,
|
||||||
|
userAgg,
|
||||||
|
fmt.Sprintf("%s@temporary.%s", id, authz.GetInstance(ctx).RequestedDomain()),
|
||||||
|
userWriteModel.UserName,
|
||||||
|
domainPolicy.UserLoginMustBeDomain),
|
||||||
|
}, nil
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Commands) UserDomainClaimedSent(ctx context.Context, orgID, userID string) (err error) {
|
func (c *Commands) UserDomainClaimedSent(ctx context.Context, orgID, userID string) (err error) {
|
||||||
if userID == "" {
|
if userID == "" {
|
||||||
return caos_errs.ThrowInvalidArgument(nil, "COMMAND-5m0fs", "Errors.IDMissing")
|
return caos_errs.ThrowInvalidArgument(nil, "COMMAND-5m0fs", "Errors.IDMissing")
|
||||||
@ -414,3 +446,17 @@ func ExistsUser(ctx context.Context, filter preparation.FilterToQueryReducer, id
|
|||||||
func newUserInitCode(ctx context.Context, filter preparation.FilterToQueryReducer, alg crypto.EncryptionAlgorithm) (value *crypto.CryptoValue, expiry time.Duration, err error) {
|
func newUserInitCode(ctx context.Context, filter preparation.FilterToQueryReducer, alg crypto.EncryptionAlgorithm) (value *crypto.CryptoValue, expiry time.Duration, err error) {
|
||||||
return newCryptoCodeWithExpiry(ctx, filter, domain.SecretGeneratorTypeInitCode, alg)
|
return newCryptoCodeWithExpiry(ctx, filter, domain.SecretGeneratorTypeInitCode, alg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func userWriteModelByID(ctx context.Context, filter preparation.FilterToQueryReducer, userID, resourceOwner string) (*UserWriteModel, error) {
|
||||||
|
user := NewUserWriteModel(userID, resourceOwner)
|
||||||
|
events, err := filter(ctx, user.Query())
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(events) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
user.AppendEvents(events...)
|
||||||
|
err = user.Reduce()
|
||||||
|
return user, err
|
||||||
|
}
|
||||||
|
@ -344,7 +344,7 @@ func columnType(columnType ColumnType) string {
|
|||||||
case ColumnTypeBytes:
|
case ColumnTypeBytes:
|
||||||
return "BYTES"
|
return "BYTES"
|
||||||
default:
|
default:
|
||||||
panic("") //TODO: remove?
|
panic("unknown column type")
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -248,7 +248,6 @@ func prepareInstancesQuery() (sq.SelectBuilder, func(*sql.Rows) (*Instances, err
|
|||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
instance := new(Instance)
|
instance := new(Instance)
|
||||||
lang := ""
|
lang := ""
|
||||||
//TODO: Get Host
|
|
||||||
err := rows.Scan(
|
err := rows.Scan(
|
||||||
&instance.ID,
|
&instance.ID,
|
||||||
&instance.CreationDate,
|
&instance.CreationDate,
|
||||||
|
@ -59,10 +59,6 @@ var (
|
|||||||
name: projection.ProjectColumnInstanceID,
|
name: projection.ProjectColumnInstanceID,
|
||||||
table: projectsTable,
|
table: projectsTable,
|
||||||
}
|
}
|
||||||
ProjectColumnCreator = Column{
|
|
||||||
name: projection.ProjectColumnCreator,
|
|
||||||
table: projectsTable,
|
|
||||||
}
|
|
||||||
ProjectColumnSequence = Column{
|
ProjectColumnSequence = Column{
|
||||||
name: projection.ProjectColumnSequence,
|
name: projection.ProjectColumnSequence,
|
||||||
table: projectsTable,
|
table: projectsTable,
|
||||||
|
@ -65,10 +65,6 @@ var (
|
|||||||
name: projection.ProjectGrantColumnRoleKeys,
|
name: projection.ProjectGrantColumnRoleKeys,
|
||||||
table: projectGrantsTable,
|
table: projectGrantsTable,
|
||||||
}
|
}
|
||||||
ProjectGrantColumnCreator = Column{
|
|
||||||
name: projection.ProjectGrantColumnCreator,
|
|
||||||
table: projectGrantsTable,
|
|
||||||
}
|
|
||||||
ProjectGrantColumnGrantedOrgName = Column{
|
ProjectGrantColumnGrantedOrgName = Column{
|
||||||
name: projection.OrgColumnName,
|
name: projection.OrgColumnName,
|
||||||
table: orgsTable.setAlias(ProjectGrantGrantedOrgTableAlias),
|
table: orgsTable.setAlias(ProjectGrantGrantedOrgTableAlias),
|
||||||
|
@ -53,10 +53,6 @@ var (
|
|||||||
name: projection.ProjectRoleColumnGroupName,
|
name: projection.ProjectRoleColumnGroupName,
|
||||||
table: projectRolesTable,
|
table: projectRolesTable,
|
||||||
}
|
}
|
||||||
ProjectRoleColumnCreator = Column{
|
|
||||||
name: projection.ProjectRoleColumnCreator,
|
|
||||||
table: projectRolesTable,
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ProjectRoles struct {
|
type ProjectRoles struct {
|
||||||
|
@ -94,17 +94,17 @@ func NewAppProjection(ctx context.Context, config crdb.StatementHandlerConfig) *
|
|||||||
crdb.NewColumn(AppOIDCConfigColumnClientID, crdb.ColumnTypeText),
|
crdb.NewColumn(AppOIDCConfigColumnClientID, crdb.ColumnTypeText),
|
||||||
crdb.NewColumn(AppOIDCConfigColumnClientSecret, crdb.ColumnTypeJSONB, crdb.Nullable()),
|
crdb.NewColumn(AppOIDCConfigColumnClientSecret, crdb.ColumnTypeJSONB, crdb.Nullable()),
|
||||||
crdb.NewColumn(AppOIDCConfigColumnRedirectUris, crdb.ColumnTypeTextArray, crdb.Nullable()),
|
crdb.NewColumn(AppOIDCConfigColumnRedirectUris, crdb.ColumnTypeTextArray, crdb.Nullable()),
|
||||||
crdb.NewColumn(AppOIDCConfigColumnResponseTypes, crdb.ColumnTypeEnumArray, crdb.Nullable()), //TODO: null?
|
crdb.NewColumn(AppOIDCConfigColumnResponseTypes, crdb.ColumnTypeEnumArray, crdb.Nullable()),
|
||||||
crdb.NewColumn(AppOIDCConfigColumnGrantTypes, crdb.ColumnTypeEnumArray, crdb.Nullable()), //TODO: null?
|
crdb.NewColumn(AppOIDCConfigColumnGrantTypes, crdb.ColumnTypeEnumArray, crdb.Nullable()),
|
||||||
crdb.NewColumn(AppOIDCConfigColumnApplicationType, crdb.ColumnTypeEnum),
|
crdb.NewColumn(AppOIDCConfigColumnApplicationType, crdb.ColumnTypeEnum),
|
||||||
crdb.NewColumn(AppOIDCConfigColumnAuthMethodType, crdb.ColumnTypeEnum),
|
crdb.NewColumn(AppOIDCConfigColumnAuthMethodType, crdb.ColumnTypeEnum),
|
||||||
crdb.NewColumn(AppOIDCConfigColumnPostLogoutRedirectUris, crdb.ColumnTypeTextArray, crdb.Nullable()),
|
crdb.NewColumn(AppOIDCConfigColumnPostLogoutRedirectUris, crdb.ColumnTypeTextArray, crdb.Nullable()),
|
||||||
crdb.NewColumn(AppOIDCConfigColumnDevMode, crdb.ColumnTypeBool),
|
crdb.NewColumn(AppOIDCConfigColumnDevMode, crdb.ColumnTypeBool),
|
||||||
crdb.NewColumn(AppOIDCConfigColumnAccessTokenType, crdb.ColumnTypeEnum),
|
crdb.NewColumn(AppOIDCConfigColumnAccessTokenType, crdb.ColumnTypeEnum),
|
||||||
crdb.NewColumn(AppOIDCConfigColumnAccessTokenRoleAssertion, crdb.ColumnTypeBool, crdb.Nullable()), //TODO: null?
|
crdb.NewColumn(AppOIDCConfigColumnAccessTokenRoleAssertion, crdb.ColumnTypeBool, crdb.Default(false)),
|
||||||
crdb.NewColumn(AppOIDCConfigColumnIDTokenRoleAssertion, crdb.ColumnTypeBool, crdb.Nullable()), //TODO: null?
|
crdb.NewColumn(AppOIDCConfigColumnIDTokenRoleAssertion, crdb.ColumnTypeBool, crdb.Default(false)),
|
||||||
crdb.NewColumn(AppOIDCConfigColumnIDTokenUserinfoAssertion, crdb.ColumnTypeBool, crdb.Nullable()), //TODO: null?
|
crdb.NewColumn(AppOIDCConfigColumnIDTokenUserinfoAssertion, crdb.ColumnTypeBool, crdb.Default(false)),
|
||||||
crdb.NewColumn(AppOIDCConfigColumnClockSkew, crdb.ColumnTypeInt64, crdb.Nullable()), //TODO: null?
|
crdb.NewColumn(AppOIDCConfigColumnClockSkew, crdb.ColumnTypeInt64, crdb.Default(0)),
|
||||||
crdb.NewColumn(AppOIDCConfigColumnAdditionalOrigins, crdb.ColumnTypeTextArray, crdb.Nullable()),
|
crdb.NewColumn(AppOIDCConfigColumnAdditionalOrigins, crdb.ColumnTypeTextArray, crdb.Nullable()),
|
||||||
},
|
},
|
||||||
crdb.NewPrimaryKey(AppOIDCConfigColumnAppID),
|
crdb.NewPrimaryKey(AppOIDCConfigColumnAppID),
|
||||||
|
@ -26,7 +26,6 @@ const (
|
|||||||
ProjectColumnProjectRoleCheck = "project_role_check"
|
ProjectColumnProjectRoleCheck = "project_role_check"
|
||||||
ProjectColumnHasProjectCheck = "has_project_check"
|
ProjectColumnHasProjectCheck = "has_project_check"
|
||||||
ProjectColumnPrivateLabelingSetting = "private_labeling_setting"
|
ProjectColumnPrivateLabelingSetting = "private_labeling_setting"
|
||||||
ProjectColumnCreator = "creator_id" //TODO: necessary?
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ProjectProjection struct {
|
type ProjectProjection struct {
|
||||||
@ -51,7 +50,6 @@ func NewProjectProjection(ctx context.Context, config crdb.StatementHandlerConfi
|
|||||||
crdb.NewColumn(ProjectColumnProjectRoleCheck, crdb.ColumnTypeBool),
|
crdb.NewColumn(ProjectColumnProjectRoleCheck, crdb.ColumnTypeBool),
|
||||||
crdb.NewColumn(ProjectColumnHasProjectCheck, crdb.ColumnTypeBool),
|
crdb.NewColumn(ProjectColumnHasProjectCheck, crdb.ColumnTypeBool),
|
||||||
crdb.NewColumn(ProjectColumnPrivateLabelingSetting, crdb.ColumnTypeEnum),
|
crdb.NewColumn(ProjectColumnPrivateLabelingSetting, crdb.ColumnTypeEnum),
|
||||||
crdb.NewColumn(ProjectColumnCreator, crdb.ColumnTypeText),
|
|
||||||
},
|
},
|
||||||
crdb.NewPrimaryKey(ProjectColumnInstanceID, ProjectColumnID),
|
crdb.NewPrimaryKey(ProjectColumnInstanceID, ProjectColumnID),
|
||||||
crdb.WithIndex(crdb.NewIndex("ro_idx", []string{ProjectColumnResourceOwner})),
|
crdb.WithIndex(crdb.NewIndex("ro_idx", []string{ProjectColumnResourceOwner})),
|
||||||
@ -111,7 +109,6 @@ func (p *ProjectProjection) reduceProjectAdded(event eventstore.Event) (*handler
|
|||||||
handler.NewCol(ProjectColumnHasProjectCheck, e.HasProjectCheck),
|
handler.NewCol(ProjectColumnHasProjectCheck, e.HasProjectCheck),
|
||||||
handler.NewCol(ProjectColumnPrivateLabelingSetting, e.PrivateLabelingSetting),
|
handler.NewCol(ProjectColumnPrivateLabelingSetting, e.PrivateLabelingSetting),
|
||||||
handler.NewCol(ProjectColumnState, domain.ProjectStateActive),
|
handler.NewCol(ProjectColumnState, domain.ProjectStateActive),
|
||||||
handler.NewCol(ProjectColumnCreator, e.EditorUser()),
|
|
||||||
},
|
},
|
||||||
), nil
|
), nil
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,6 @@ const (
|
|||||||
ProjectGrantColumnProjectID = "project_id"
|
ProjectGrantColumnProjectID = "project_id"
|
||||||
ProjectGrantColumnGrantedOrgID = "granted_org_id"
|
ProjectGrantColumnGrantedOrgID = "granted_org_id"
|
||||||
ProjectGrantColumnRoleKeys = "granted_role_keys"
|
ProjectGrantColumnRoleKeys = "granted_role_keys"
|
||||||
ProjectGrantColumnCreator = "creator_id" //TODO: necessary?
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ProjectGrantProjection struct {
|
type ProjectGrantProjection struct {
|
||||||
@ -49,7 +48,6 @@ func NewProjectGrantProjection(ctx context.Context, config crdb.StatementHandler
|
|||||||
crdb.NewColumn(ProjectGrantColumnProjectID, crdb.ColumnTypeText),
|
crdb.NewColumn(ProjectGrantColumnProjectID, crdb.ColumnTypeText),
|
||||||
crdb.NewColumn(ProjectGrantColumnGrantedOrgID, crdb.ColumnTypeText),
|
crdb.NewColumn(ProjectGrantColumnGrantedOrgID, crdb.ColumnTypeText),
|
||||||
crdb.NewColumn(ProjectGrantColumnRoleKeys, crdb.ColumnTypeTextArray),
|
crdb.NewColumn(ProjectGrantColumnRoleKeys, crdb.ColumnTypeTextArray),
|
||||||
crdb.NewColumn(ProjectGrantColumnCreator, crdb.ColumnTypeText),
|
|
||||||
},
|
},
|
||||||
crdb.NewPrimaryKey(ProjectGrantColumnInstanceID, ProjectGrantColumnGrantID),
|
crdb.NewPrimaryKey(ProjectGrantColumnInstanceID, ProjectGrantColumnGrantID),
|
||||||
crdb.WithIndex(crdb.NewIndex("ro_idx", []string{ProjectGrantColumnResourceOwner})),
|
crdb.WithIndex(crdb.NewIndex("ro_idx", []string{ProjectGrantColumnResourceOwner})),
|
||||||
@ -116,7 +114,6 @@ func (p *ProjectGrantProjection) reduceProjectGrantAdded(event eventstore.Event)
|
|||||||
handler.NewCol(ProjectGrantColumnSequence, e.Sequence()),
|
handler.NewCol(ProjectGrantColumnSequence, e.Sequence()),
|
||||||
handler.NewCol(ProjectGrantColumnGrantedOrgID, e.GrantedOrgID),
|
handler.NewCol(ProjectGrantColumnGrantedOrgID, e.GrantedOrgID),
|
||||||
handler.NewCol(ProjectGrantColumnRoleKeys, pq.StringArray(e.RoleKeys)),
|
handler.NewCol(ProjectGrantColumnRoleKeys, pq.StringArray(e.RoleKeys)),
|
||||||
handler.NewCol(ProjectGrantColumnCreator, e.EditorUser()),
|
|
||||||
},
|
},
|
||||||
), nil
|
), nil
|
||||||
}
|
}
|
||||||
|
@ -220,7 +220,7 @@ func TestProjectGrantProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "INSERT INTO projections.project_grants (grant_id, project_id, creation_date, change_date, resource_owner, instance_id, state, sequence, granted_org_id, granted_role_keys, creator_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)",
|
expectedStmt: "INSERT INTO projections.project_grants (grant_id, project_id, creation_date, change_date, resource_owner, instance_id, state, sequence, granted_org_id, granted_role_keys) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
"grant-id",
|
"grant-id",
|
||||||
"agg-id",
|
"agg-id",
|
||||||
@ -232,7 +232,6 @@ func TestProjectGrantProjection_reduces(t *testing.T) {
|
|||||||
uint64(15),
|
uint64(15),
|
||||||
"granted-org-id",
|
"granted-org-id",
|
||||||
pq.StringArray{"admin", "user"},
|
pq.StringArray{"admin", "user"},
|
||||||
"editor-user",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -22,7 +22,6 @@ const (
|
|||||||
ProjectRoleColumnInstanceID = "instance_id"
|
ProjectRoleColumnInstanceID = "instance_id"
|
||||||
ProjectRoleColumnDisplayName = "display_name"
|
ProjectRoleColumnDisplayName = "display_name"
|
||||||
ProjectRoleColumnGroupName = "group_name"
|
ProjectRoleColumnGroupName = "group_name"
|
||||||
ProjectRoleColumnCreator = "creator_id" //TODO: necessary?
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type ProjectRoleProjection struct {
|
type ProjectRoleProjection struct {
|
||||||
@ -44,7 +43,6 @@ func NewProjectRoleProjection(ctx context.Context, config crdb.StatementHandlerC
|
|||||||
crdb.NewColumn(ProjectRoleColumnInstanceID, crdb.ColumnTypeText),
|
crdb.NewColumn(ProjectRoleColumnInstanceID, crdb.ColumnTypeText),
|
||||||
crdb.NewColumn(ProjectRoleColumnDisplayName, crdb.ColumnTypeText),
|
crdb.NewColumn(ProjectRoleColumnDisplayName, crdb.ColumnTypeText),
|
||||||
crdb.NewColumn(ProjectRoleColumnGroupName, crdb.ColumnTypeText),
|
crdb.NewColumn(ProjectRoleColumnGroupName, crdb.ColumnTypeText),
|
||||||
crdb.NewColumn(ProjectRoleColumnCreator, crdb.ColumnTypeText),
|
|
||||||
},
|
},
|
||||||
crdb.NewPrimaryKey(ProjectRoleColumnInstanceID, ProjectRoleColumnProjectID, ProjectRoleColumnKey),
|
crdb.NewPrimaryKey(ProjectRoleColumnInstanceID, ProjectRoleColumnProjectID, ProjectRoleColumnKey),
|
||||||
),
|
),
|
||||||
@ -96,7 +94,6 @@ func (p *ProjectRoleProjection) reduceProjectRoleAdded(event eventstore.Event) (
|
|||||||
handler.NewCol(ProjectRoleColumnSequence, e.Sequence()),
|
handler.NewCol(ProjectRoleColumnSequence, e.Sequence()),
|
||||||
handler.NewCol(ProjectRoleColumnDisplayName, e.DisplayName),
|
handler.NewCol(ProjectRoleColumnDisplayName, e.DisplayName),
|
||||||
handler.NewCol(ProjectRoleColumnGroupName, e.Group),
|
handler.NewCol(ProjectRoleColumnGroupName, e.Group),
|
||||||
handler.NewCol(ProjectRoleColumnCreator, e.EditorUser()),
|
|
||||||
},
|
},
|
||||||
), nil
|
), nil
|
||||||
}
|
}
|
||||||
|
@ -143,7 +143,7 @@ func TestProjectRoleProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "INSERT INTO projections.project_roles (role_key, project_id, creation_date, change_date, resource_owner, instance_id, sequence, display_name, group_name, creator_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)",
|
expectedStmt: "INSERT INTO projections.project_roles (role_key, project_id, creation_date, change_date, resource_owner, instance_id, sequence, display_name, group_name) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
"key",
|
"key",
|
||||||
"agg-id",
|
"agg-id",
|
||||||
@ -154,7 +154,6 @@ func TestProjectRoleProjection_reduces(t *testing.T) {
|
|||||||
uint64(15),
|
uint64(15),
|
||||||
"Key",
|
"Key",
|
||||||
"Group",
|
"Group",
|
||||||
"editor-user",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -178,7 +178,7 @@ func TestProjectProjection_reduces(t *testing.T) {
|
|||||||
executer: &testExecuter{
|
executer: &testExecuter{
|
||||||
executions: []execution{
|
executions: []execution{
|
||||||
{
|
{
|
||||||
expectedStmt: "INSERT INTO projections.projects (id, creation_date, change_date, resource_owner, instance_id, sequence, name, project_role_assertion, project_role_check, has_project_check, private_labeling_setting, state, creator_id) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)",
|
expectedStmt: "INSERT INTO projections.projects (id, creation_date, change_date, resource_owner, instance_id, sequence, name, project_role_assertion, project_role_check, has_project_check, private_labeling_setting, state) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)",
|
||||||
expectedArgs: []interface{}{
|
expectedArgs: []interface{}{
|
||||||
"agg-id",
|
"agg-id",
|
||||||
anyArg{},
|
anyArg{},
|
||||||
@ -192,7 +192,6 @@ func TestProjectProjection_reduces(t *testing.T) {
|
|||||||
true,
|
true,
|
||||||
domain.PrivateLabelingSettingEnforceProjectResourceOwnerPolicy,
|
domain.PrivateLabelingSettingEnforceProjectResourceOwnerPolicy,
|
||||||
domain.ProjectStateActive,
|
domain.ProjectStateActive,
|
||||||
"editor-user",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -88,7 +88,6 @@ var (
|
|||||||
` projections.users.change_date,` +
|
` projections.users.change_date,` +
|
||||||
` projections.users.resource_owner,` +
|
` projections.users.resource_owner,` +
|
||||||
` projections.users.sequence,` +
|
` projections.users.sequence,` +
|
||||||
//` projections.users.state,` + //TODO:
|
|
||||||
` projections.users_humans.user_id,` +
|
` projections.users_humans.user_id,` +
|
||||||
` projections.users_humans.first_name,` +
|
` projections.users_humans.first_name,` +
|
||||||
` projections.users_humans.last_name,` +
|
` projections.users_humans.last_name,` +
|
||||||
@ -105,7 +104,6 @@ var (
|
|||||||
"change_date",
|
"change_date",
|
||||||
"resource_owner",
|
"resource_owner",
|
||||||
"sequence",
|
"sequence",
|
||||||
//"state", //TODO:
|
|
||||||
"user_id",
|
"user_id",
|
||||||
"first_name",
|
"first_name",
|
||||||
"last_name",
|
"last_name",
|
||||||
@ -120,7 +118,6 @@ var (
|
|||||||
` projections.users.change_date,` +
|
` projections.users.change_date,` +
|
||||||
` projections.users.resource_owner,` +
|
` projections.users.resource_owner,` +
|
||||||
` projections.users.sequence,` +
|
` projections.users.sequence,` +
|
||||||
//` projections.users.state,` + //TODO:
|
|
||||||
` projections.users_humans.user_id,` +
|
` projections.users_humans.user_id,` +
|
||||||
` projections.users_humans.email,` +
|
` projections.users_humans.email,` +
|
||||||
` projections.users_humans.is_email_verified` +
|
` projections.users_humans.is_email_verified` +
|
||||||
@ -132,7 +129,6 @@ var (
|
|||||||
"change_date",
|
"change_date",
|
||||||
"resource_owner",
|
"resource_owner",
|
||||||
"sequence",
|
"sequence",
|
||||||
//"state", //TODO:
|
|
||||||
"user_id",
|
"user_id",
|
||||||
"email",
|
"email",
|
||||||
"is_email_verified",
|
"is_email_verified",
|
||||||
@ -142,7 +138,6 @@ var (
|
|||||||
` projections.users.change_date,` +
|
` projections.users.change_date,` +
|
||||||
` projections.users.resource_owner,` +
|
` projections.users.resource_owner,` +
|
||||||
` projections.users.sequence,` +
|
` projections.users.sequence,` +
|
||||||
//` projections.users.state,` + //TODO:
|
|
||||||
` projections.users_humans.user_id,` +
|
` projections.users_humans.user_id,` +
|
||||||
` projections.users_humans.phone,` +
|
` projections.users_humans.phone,` +
|
||||||
` projections.users_humans.is_phone_verified` +
|
` projections.users_humans.is_phone_verified` +
|
||||||
@ -154,7 +149,6 @@ var (
|
|||||||
"change_date",
|
"change_date",
|
||||||
"resource_owner",
|
"resource_owner",
|
||||||
"sequence",
|
"sequence",
|
||||||
//"state", //TODO:
|
|
||||||
"user_id",
|
"user_id",
|
||||||
"phone",
|
"phone",
|
||||||
"is_phone_verified",
|
"is_phone_verified",
|
||||||
@ -163,28 +157,15 @@ var (
|
|||||||
userUniqueQuery = `SELECT projections.users.id,` +
|
userUniqueQuery = `SELECT projections.users.id,` +
|
||||||
` projections.users.state,` +
|
` projections.users.state,` +
|
||||||
` projections.users.username,` +
|
` projections.users.username,` +
|
||||||
//` login_names.login_names,` +
|
|
||||||
//` preferred_login_name.login_name,` +
|
|
||||||
` projections.users_humans.user_id,` +
|
` projections.users_humans.user_id,` +
|
||||||
` projections.users_humans.email,` +
|
` projections.users_humans.email,` +
|
||||||
` projections.users_humans.is_email_verified` +
|
` projections.users_humans.is_email_verified` +
|
||||||
` FROM projections.users` +
|
` FROM projections.users` +
|
||||||
` LEFT JOIN projections.users_humans ON projections.users.id = projections.users_humans.user_id`
|
` LEFT JOIN projections.users_humans ON projections.users.id = projections.users_humans.user_id`
|
||||||
//` LEFT JOIN` +
|
|
||||||
//` (SELECT login_names.user_id, ARRAY_AGG(login_names.login_name) as login_names` +
|
|
||||||
//` FROM projections.login_names as login_names` +
|
|
||||||
//` GROUP BY login_names.user_id) as login_names` +
|
|
||||||
//` on login_names.user_id = projections.users.id` +
|
|
||||||
//` LEFT JOIN` +
|
|
||||||
//` (SELECT preferred_login_name.user_id, preferred_login_name.login_name FROM projections.login_names as preferred_login_name WHERE preferred_login_name.is_primary = $1) as preferred_login_name` +
|
|
||||||
//` on preferred_login_name.user_id = projections.users.id`
|
|
||||||
userUniqueCols = []string{
|
userUniqueCols = []string{
|
||||||
"id",
|
"id",
|
||||||
"state",
|
"state",
|
||||||
"username",
|
"username",
|
||||||
//"login_names",
|
|
||||||
//"login_name",
|
|
||||||
//human
|
|
||||||
"user_id",
|
"user_id",
|
||||||
"email",
|
"email",
|
||||||
"is_email_verified",
|
"is_email_verified",
|
||||||
|
@ -10,7 +10,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
//TODO: use for org events as suffix (when possible)
|
|
||||||
DomainPolicyAddedEventType = "policy.domain.added"
|
DomainPolicyAddedEventType = "policy.domain.added"
|
||||||
DomainPolicyChangedEventType = "policy.domain.changed"
|
DomainPolicyChangedEventType = "policy.domain.changed"
|
||||||
DomainPolicyRemovedEventType = "policy.domain.removed"
|
DomainPolicyRemovedEventType = "policy.domain.removed"
|
||||||
|
@ -2892,7 +2892,7 @@ message SetUpOrgRequest {
|
|||||||
min_length: 1;
|
min_length: 1;
|
||||||
example: "\"gigi@caos.ch\"";
|
example: "\"gigi@caos.ch\"";
|
||||||
}
|
}
|
||||||
]; //TODO: check if no value is allowed
|
];
|
||||||
bool is_email_verified = 2;
|
bool is_email_verified = 2;
|
||||||
}
|
}
|
||||||
message Phone {
|
message Phone {
|
||||||
|
@ -63,6 +63,8 @@ message AppNameQuery {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message OIDCConfig {
|
message OIDCConfig {
|
||||||
|
reserved "client_secret";
|
||||||
|
reserved 6;
|
||||||
repeated string redirect_uris = 1 [
|
repeated string redirect_uris = 1 [
|
||||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
example: "[\"https://console.zitadel.ch/auth/callback\"]";
|
example: "[\"https://console.zitadel.ch/auth/callback\"]";
|
||||||
@ -90,12 +92,6 @@ message OIDCConfig {
|
|||||||
description: "generated oauth2/oidc client id";
|
description: "generated oauth2/oidc client id";
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
string client_secret = 6 [
|
|
||||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
|
||||||
example: "\"gjöq34589uasgh\"";
|
|
||||||
description: "generated secret for this config";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
OIDCAuthMethodType auth_method_type = 7 [
|
OIDCAuthMethodType auth_method_type = 7 [
|
||||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
description: "defines how the application passes login credentials";
|
description: "defines how the application passes login credentials";
|
||||||
@ -208,18 +204,14 @@ enum APIAuthMethodType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message APIConfig {
|
message APIConfig {
|
||||||
|
reserved "client_secret";
|
||||||
|
reserved 2;
|
||||||
string client_id = 1 [
|
string client_id = 1 [
|
||||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
example: "\"69629023906488334@ZITADEL\"";
|
example: "\"69629023906488334@ZITADEL\"";
|
||||||
description: "generated oauth2/oidc client_id";
|
description: "generated oauth2/oidc client_id";
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
string client_secret = 2 [
|
|
||||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
|
||||||
example: "\"gjöq34589uasgh\"";
|
|
||||||
description: "generated secret for this config";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
APIAuthMethodType auth_method_type = 3 [
|
APIAuthMethodType auth_method_type = 3 [
|
||||||
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
(grpc.gateway.protoc_gen_openapiv2.options.openapiv2_field) = {
|
||||||
description: "defines how the api passes the login credentials";
|
description: "defines how the api passes the login credentials";
|
||||||
|
@ -771,7 +771,7 @@ message GetMyEmailResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message SetMyEmailRequest {
|
message SetMyEmailRequest {
|
||||||
string email = 1 [(validate.rules).string.email = true]; //TODO: check if no value is allowed
|
string email = 1 [(validate.rules).string.email = true];
|
||||||
}
|
}
|
||||||
|
|
||||||
message SetMyEmailResponse {
|
message SetMyEmailResponse {
|
||||||
|
@ -138,7 +138,6 @@ service ManagementService {
|
|||||||
value: {
|
value: {
|
||||||
description: "OK";
|
description: "OK";
|
||||||
}
|
}
|
||||||
//TODO: errors
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -2952,7 +2951,7 @@ message AddHumanUserRequest {
|
|||||||
zitadel.user.v1.Gender gender = 6;
|
zitadel.user.v1.Gender gender = 6;
|
||||||
}
|
}
|
||||||
message Email {
|
message Email {
|
||||||
string email = 1 [(validate.rules).string.email = true]; //TODO: check if no value is allowed
|
string email = 1 [(validate.rules).string.email = true];
|
||||||
bool is_email_verified = 2;
|
bool is_email_verified = 2;
|
||||||
}
|
}
|
||||||
message Phone {
|
message Phone {
|
||||||
@ -2984,7 +2983,7 @@ message ImportHumanUserRequest {
|
|||||||
zitadel.user.v1.Gender gender = 6;
|
zitadel.user.v1.Gender gender = 6;
|
||||||
}
|
}
|
||||||
message Email {
|
message Email {
|
||||||
string email = 1 [(validate.rules).string.email = true]; //TODO: check if no value is allowed
|
string email = 1 [(validate.rules).string.email = true];
|
||||||
bool is_email_verified = 2;
|
bool is_email_verified = 2;
|
||||||
}
|
}
|
||||||
message Phone {
|
message Phone {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user