| 
									
										
										
										
											2021-12-06 16:57:35 +01:00
										 |  |  | package projection | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-04-27 01:01:45 +02:00
										 |  |  | 	"github.com/zitadel/zitadel/internal/crypto" | 
					
						
							|  |  |  | 	"github.com/zitadel/zitadel/internal/errors" | 
					
						
							|  |  |  | 	"github.com/zitadel/zitadel/internal/eventstore" | 
					
						
							|  |  |  | 	"github.com/zitadel/zitadel/internal/eventstore/handler" | 
					
						
							|  |  |  | 	"github.com/zitadel/zitadel/internal/eventstore/handler/crdb" | 
					
						
							|  |  |  | 	"github.com/zitadel/zitadel/internal/repository/keypair" | 
					
						
							| 
									
										
										
										
											2021-12-06 16:57:35 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-23 09:02:39 +01:00
										 |  |  | const ( | 
					
						
							|  |  |  | 	KeyProjectionTable = "projections.keys" | 
					
						
							|  |  |  | 	KeyPrivateTable    = KeyProjectionTable + "_" + privateKeyTableSuffix | 
					
						
							|  |  |  | 	KeyPublicTable     = KeyProjectionTable + "_" + publicKeyTableSuffix | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	KeyColumnID            = "id" | 
					
						
							|  |  |  | 	KeyColumnCreationDate  = "creation_date" | 
					
						
							|  |  |  | 	KeyColumnChangeDate    = "change_date" | 
					
						
							|  |  |  | 	KeyColumnResourceOwner = "resource_owner" | 
					
						
							|  |  |  | 	KeyColumnInstanceID    = "instance_id" | 
					
						
							|  |  |  | 	KeyColumnSequence      = "sequence" | 
					
						
							|  |  |  | 	KeyColumnAlgorithm     = "algorithm" | 
					
						
							|  |  |  | 	KeyColumnUse           = "use" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-25 14:15:13 +02:00
										 |  |  | 	privateKeyTableSuffix      = "private" | 
					
						
							|  |  |  | 	KeyPrivateColumnID         = "id" | 
					
						
							|  |  |  | 	KeyPrivateColumnInstanceID = "instance_id" | 
					
						
							|  |  |  | 	KeyPrivateColumnExpiry     = "expiry" | 
					
						
							|  |  |  | 	KeyPrivateColumnKey        = "key" | 
					
						
							| 
									
										
										
										
											2022-03-23 09:02:39 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-05-25 14:15:13 +02:00
										 |  |  | 	publicKeyTableSuffix      = "public" | 
					
						
							|  |  |  | 	KeyPublicColumnID         = "id" | 
					
						
							|  |  |  | 	KeyPublicColumnInstanceID = "instance_id" | 
					
						
							|  |  |  | 	KeyPublicColumnExpiry     = "expiry" | 
					
						
							|  |  |  | 	KeyPublicColumnKey        = "key" | 
					
						
							| 
									
										
										
										
											2022-03-23 09:02:39 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-14 07:51:00 +02:00
										 |  |  | type keyProjection struct { | 
					
						
							| 
									
										
										
										
											2021-12-06 16:57:35 +01:00
										 |  |  | 	crdb.StatementHandler | 
					
						
							|  |  |  | 	encryptionAlgorithm crypto.EncryptionAlgorithm | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-14 07:51:00 +02:00
										 |  |  | func newKeyProjection(ctx context.Context, config crdb.StatementHandlerConfig, keyEncryptionAlgorithm crypto.EncryptionAlgorithm) *keyProjection { | 
					
						
							|  |  |  | 	p := new(keyProjection) | 
					
						
							| 
									
										
										
										
											2021-12-06 16:57:35 +01:00
										 |  |  | 	config.ProjectionName = KeyProjectionTable | 
					
						
							|  |  |  | 	config.Reducers = p.reducers() | 
					
						
							| 
									
										
										
										
											2022-03-23 09:02:39 +01:00
										 |  |  | 	config.InitCheck = crdb.NewMultiTableCheck( | 
					
						
							|  |  |  | 		crdb.NewTable([]*crdb.Column{ | 
					
						
							|  |  |  | 			crdb.NewColumn(KeyColumnID, crdb.ColumnTypeText), | 
					
						
							|  |  |  | 			crdb.NewColumn(KeyColumnCreationDate, crdb.ColumnTypeTimestamp), | 
					
						
							|  |  |  | 			crdb.NewColumn(KeyColumnChangeDate, crdb.ColumnTypeTimestamp), | 
					
						
							|  |  |  | 			crdb.NewColumn(KeyColumnResourceOwner, crdb.ColumnTypeText), | 
					
						
							|  |  |  | 			crdb.NewColumn(KeyColumnInstanceID, crdb.ColumnTypeText), | 
					
						
							|  |  |  | 			crdb.NewColumn(KeyColumnSequence, crdb.ColumnTypeInt64), | 
					
						
							|  |  |  | 			crdb.NewColumn(KeyColumnAlgorithm, crdb.ColumnTypeText, crdb.Default("")), | 
					
						
							| 
									
										
										
										
											2022-04-25 10:01:17 +02:00
										 |  |  | 			crdb.NewColumn(KeyColumnUse, crdb.ColumnTypeEnum, crdb.Default(0)), | 
					
						
							| 
									
										
										
										
											2022-03-23 09:02:39 +01:00
										 |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2022-05-25 14:15:13 +02:00
										 |  |  | 			crdb.NewPrimaryKey(KeyColumnID, KeyColumnInstanceID), | 
					
						
							| 
									
										
										
										
											2022-03-28 10:05:09 +02:00
										 |  |  | 			crdb.WithConstraint(crdb.NewConstraint("id_unique", []string{KeyColumnID})), | 
					
						
							| 
									
										
										
										
											2022-03-23 09:02:39 +01:00
										 |  |  | 		), | 
					
						
							|  |  |  | 		crdb.NewSuffixedTable([]*crdb.Column{ | 
					
						
							| 
									
										
										
										
											2022-05-25 14:15:13 +02:00
										 |  |  | 			crdb.NewColumn(KeyPrivateColumnID, crdb.ColumnTypeText), | 
					
						
							|  |  |  | 			crdb.NewColumn(KeyPrivateColumnInstanceID, crdb.ColumnTypeText), | 
					
						
							| 
									
										
										
										
											2022-03-23 09:02:39 +01:00
										 |  |  | 			crdb.NewColumn(KeyPrivateColumnExpiry, crdb.ColumnTypeTimestamp), | 
					
						
							|  |  |  | 			crdb.NewColumn(KeyPrivateColumnKey, crdb.ColumnTypeJSONB), | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2022-05-25 14:15:13 +02:00
										 |  |  | 			crdb.NewPrimaryKey(KeyPrivateColumnID, KeyPrivateColumnInstanceID), | 
					
						
							| 
									
										
										
										
											2022-03-23 09:02:39 +01:00
										 |  |  | 			privateKeyTableSuffix, | 
					
						
							| 
									
										
										
										
											2022-05-25 14:15:13 +02:00
										 |  |  | 			crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_private_ref_keys")), | 
					
						
							| 
									
										
										
										
											2022-03-23 09:02:39 +01:00
										 |  |  | 		), | 
					
						
							|  |  |  | 		crdb.NewSuffixedTable([]*crdb.Column{ | 
					
						
							| 
									
										
										
										
											2022-05-25 14:15:13 +02:00
										 |  |  | 			crdb.NewColumn(KeyPublicColumnID, crdb.ColumnTypeText), | 
					
						
							|  |  |  | 			crdb.NewColumn(KeyPublicColumnInstanceID, crdb.ColumnTypeText), | 
					
						
							| 
									
										
										
										
											2022-03-23 09:02:39 +01:00
										 |  |  | 			crdb.NewColumn(KeyPublicColumnExpiry, crdb.ColumnTypeTimestamp), | 
					
						
							|  |  |  | 			crdb.NewColumn(KeyPublicColumnKey, crdb.ColumnTypeBytes), | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2022-05-25 14:15:13 +02:00
										 |  |  | 			crdb.NewPrimaryKey(KeyPublicColumnID, KeyPublicColumnInstanceID), | 
					
						
							| 
									
										
										
										
											2022-03-23 09:02:39 +01:00
										 |  |  | 			publicKeyTableSuffix, | 
					
						
							| 
									
										
										
										
											2022-05-25 14:15:13 +02:00
										 |  |  | 			crdb.WithForeignKey(crdb.NewForeignKeyOfPublicKeys("fk_public_ref_keys")), | 
					
						
							| 
									
										
										
										
											2022-03-23 09:02:39 +01:00
										 |  |  | 		), | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2022-03-14 07:55:09 +01:00
										 |  |  | 	p.encryptionAlgorithm = keyEncryptionAlgorithm | 
					
						
							| 
									
										
										
										
											2022-07-22 12:08:39 +02:00
										 |  |  | 	p.StatementHandler = crdb.NewStatementHandler(ctx, config) | 
					
						
							| 
									
										
										
										
											2022-03-14 07:55:09 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return p | 
					
						
							| 
									
										
										
										
											2021-12-06 16:57:35 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-14 07:51:00 +02:00
										 |  |  | func (p *keyProjection) reducers() []handler.AggregateReducer { | 
					
						
							| 
									
										
										
										
											2021-12-06 16:57:35 +01:00
										 |  |  | 	return []handler.AggregateReducer{ | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			Aggregate: keypair.AggregateType, | 
					
						
							|  |  |  | 			EventRedusers: []handler.EventReducer{ | 
					
						
							|  |  |  | 				{ | 
					
						
							|  |  |  | 					Event:  keypair.AddedEventType, | 
					
						
							|  |  |  | 					Reduce: p.reduceKeyPairAdded, | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-14 07:51:00 +02:00
										 |  |  | func (p *keyProjection) reduceKeyPairAdded(event eventstore.Event) (*handler.Statement, error) { | 
					
						
							| 
									
										
										
										
											2021-12-06 16:57:35 +01:00
										 |  |  | 	e, ok := event.(*keypair.AddedEvent) | 
					
						
							|  |  |  | 	if !ok { | 
					
						
							| 
									
										
										
										
											2022-03-23 09:02:39 +01:00
										 |  |  | 		return nil, errors.ThrowInvalidArgumentf(nil, "HANDL-SAbr2", "reduce.wrong.event.type %s", keypair.AddedEventType) | 
					
						
							| 
									
										
										
										
											2021-12-06 16:57:35 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if e.PrivateKey.Expiry.Before(time.Now()) && e.PublicKey.Expiry.Before(time.Now()) { | 
					
						
							|  |  |  | 		return crdb.NewNoOpStatement(e), nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-01-03 09:19:07 +01:00
										 |  |  | 	creates := []func(eventstore.Event) crdb.Exec{ | 
					
						
							| 
									
										
										
										
											2021-12-06 16:57:35 +01:00
										 |  |  | 		crdb.AddCreateStatement( | 
					
						
							|  |  |  | 			[]handler.Column{ | 
					
						
							|  |  |  | 				handler.NewCol(KeyColumnID, e.Aggregate().ID), | 
					
						
							|  |  |  | 				handler.NewCol(KeyColumnCreationDate, e.CreationDate()), | 
					
						
							|  |  |  | 				handler.NewCol(KeyColumnChangeDate, e.CreationDate()), | 
					
						
							|  |  |  | 				handler.NewCol(KeyColumnResourceOwner, e.Aggregate().ResourceOwner), | 
					
						
							| 
									
										
										
										
											2022-03-23 09:02:39 +01:00
										 |  |  | 				handler.NewCol(KeyColumnInstanceID, e.Aggregate().InstanceID), | 
					
						
							| 
									
										
										
										
											2021-12-06 16:57:35 +01:00
										 |  |  | 				handler.NewCol(KeyColumnSequence, e.Sequence()), | 
					
						
							|  |  |  | 				handler.NewCol(KeyColumnAlgorithm, e.Algorithm), | 
					
						
							|  |  |  | 				handler.NewCol(KeyColumnUse, e.Usage), | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if e.PrivateKey.Expiry.After(time.Now()) { | 
					
						
							|  |  |  | 		creates = append(creates, crdb.AddCreateStatement( | 
					
						
							|  |  |  | 			[]handler.Column{ | 
					
						
							|  |  |  | 				handler.NewCol(KeyPrivateColumnID, e.Aggregate().ID), | 
					
						
							| 
									
										
										
										
											2022-05-25 14:15:13 +02:00
										 |  |  | 				handler.NewCol(KeyPrivateColumnInstanceID, e.Aggregate().InstanceID), | 
					
						
							| 
									
										
										
										
											2021-12-06 16:57:35 +01:00
										 |  |  | 				handler.NewCol(KeyPrivateColumnExpiry, e.PrivateKey.Expiry), | 
					
						
							|  |  |  | 				handler.NewCol(KeyPrivateColumnKey, e.PrivateKey.Key), | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			crdb.WithTableSuffix(privateKeyTableSuffix), | 
					
						
							|  |  |  | 		)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if e.PublicKey.Expiry.After(time.Now()) { | 
					
						
							|  |  |  | 		publicKey, err := crypto.Decrypt(e.PublicKey.Key, p.encryptionAlgorithm) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return nil, errors.ThrowInternal(err, "HANDL-DAg2f", "cannot decrypt public key") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		creates = append(creates, crdb.AddCreateStatement( | 
					
						
							|  |  |  | 			[]handler.Column{ | 
					
						
							|  |  |  | 				handler.NewCol(KeyPublicColumnID, e.Aggregate().ID), | 
					
						
							| 
									
										
										
										
											2022-05-25 14:15:13 +02:00
										 |  |  | 				handler.NewCol(KeyPublicColumnInstanceID, e.Aggregate().InstanceID), | 
					
						
							| 
									
										
										
										
											2021-12-06 16:57:35 +01:00
										 |  |  | 				handler.NewCol(KeyPublicColumnExpiry, e.PublicKey.Expiry), | 
					
						
							|  |  |  | 				handler.NewCol(KeyPublicColumnKey, publicKey), | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			crdb.WithTableSuffix(publicKeyTableSuffix), | 
					
						
							|  |  |  | 		)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return crdb.NewMultiStatement(e, creates...), nil | 
					
						
							|  |  |  | } |