From 3500961fbb21f496d2382abf5a31f92fa5b411d1 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 10 Jun 2022 12:39:38 +0200 Subject: [PATCH] fix: add smtp config, remove smtp and sms provider, console adaptations (#3792) * fix: add AddSMTPConfig to admin api * addsmtpconfig * fix: add RemoveSMTPConfig and RemoveSMSProvider to admin api * update twilio, token fcn * fix account switcher, twilio token set, cleanup dialog * cleanup * buttons Co-authored-by: Livio Amstutz --- .../accounts-card.component.html | 2 - .../accounts-card.component.scss | 8 +- .../dialog-add-sms-provider.component.html | 17 +- .../dialog-add-sms-provider.component.ts | 77 +++- .../notification-settings.component.html | 5 +- .../notification-settings.component.ts | 102 +++-- .../notification-settings.module.ts | 4 +- .../password-dialog.component.html} | 4 +- .../password-dialog.component.scss} | 0 .../password-dialog.component.spec.ts} | 12 +- .../password-dialog.component.ts | 16 + .../smtp-password-dialog.component.ts | 16 - console/src/app/services/admin.service.ts | 386 +++++++++--------- console/src/assets/i18n/de.json | 5 +- console/src/assets/i18n/en.json | 5 +- console/src/assets/i18n/it.json | 5 +- docs/docs/apis/proto/admin.md | 102 +++++ internal/api/grpc/admin/iam_settings.go | 26 ++ .../api/grpc/admin/iam_settings_converter.go | 15 +- internal/api/grpc/admin/sms.go | 11 + .../command/instance_smtp_config_model.go | 8 + internal/command/sms_config.go | 4 +- internal/command/sms_config_test.go | 6 +- internal/command/smtp.go | 35 ++ internal/command/smtp_test.go | 95 +++++ internal/domain/smtp.go | 1 + internal/repository/instance/eventstore.go | 1 + internal/repository/instance/smtp_config.go | 38 ++ proto/zitadel/admin.proto | 62 +++ 29 files changed, 793 insertions(+), 275 deletions(-) rename console/src/app/modules/policies/notification-settings/{smtp-password-dialog/smtp-password-dialog.component.html => password-dialog/password-dialog.component.html} (78%) rename console/src/app/modules/policies/notification-settings/{smtp-password-dialog/smtp-password-dialog.component.scss => password-dialog/password-dialog.component.scss} (100%) rename console/src/app/modules/policies/notification-settings/{smtp-password-dialog/smtp-password-dialog.component.spec.ts => password-dialog/password-dialog.component.spec.ts} (51%) create mode 100644 console/src/app/modules/policies/notification-settings/password-dialog/password-dialog.component.ts delete mode 100644 console/src/app/modules/policies/notification-settings/smtp-password-dialog/smtp-password-dialog.component.ts diff --git a/console/src/app/modules/accounts-card/accounts-card.component.html b/console/src/app/modules/accounts-card/accounts-card.component.html index cb7fc37eed..74db5d2994 100644 --- a/console/src/app/modules/accounts-card/accounts-card.component.html +++ b/console/src/app/modules/accounts-card/accounts-card.component.html @@ -44,7 +44,6 @@ >{{ 'USER.STATE.' + session.authState | translate }} - keyboard_arrow_right @@ -54,7 +53,6 @@ {{ 'USER.ADDACCOUNT' | translate }} - keyboard_arrow_right diff --git a/console/src/app/modules/accounts-card/accounts-card.component.scss b/console/src/app/modules/accounts-card/accounts-card.component.scss index 895bfe11bc..f0a1e30f74 100644 --- a/console/src/app/modules/accounts-card/accounts-card.component.scss +++ b/console/src/app/modules/accounts-card/accounts-card.component.scss @@ -109,6 +109,7 @@ flex: 1; display: flex; flex-direction: column; + overflow-x: hidden; .user-title { font-weight: 500; @@ -123,11 +124,14 @@ .loginname { font-size: 0.8rem; line-height: 1rem; + white-space: nowrap; width: fit-content; } .loginname { color: $secondary-text; + text-overflow: ellipsis; + overflow: hidden; } .state { @@ -136,10 +140,6 @@ padding: 1px 0.5rem; } } - - .fill-space { - flex: 1; - } } } } diff --git a/console/src/app/modules/policies/notification-settings/dialog-add-sms-provider/dialog-add-sms-provider.component.html b/console/src/app/modules/policies/notification-settings/dialog-add-sms-provider/dialog-add-sms-provider.component.html index 3de3c17bac..49690d88b3 100644 --- a/console/src/app/modules/policies/notification-settings/dialog-add-sms-provider/dialog-add-sms-provider.component.html +++ b/console/src/app/modules/policies/notification-settings/dialog-add-sms-provider/dialog-add-sms-provider.component.html @@ -2,20 +2,7 @@ {{ provider === SMSProviderType.Twilio ? 'Twilio' : ('SETTING.SMS.ADDPROVIDER' | translate) }}
- - - -
- - {{ 'SETTING.SMS.TWILIO.SID' | translate }} @@ -30,6 +17,10 @@ {{ 'SETTING.SMS.TWILIO.SENDERNUMBER' | translate }} + +
diff --git a/console/src/app/modules/policies/notification-settings/dialog-add-sms-provider/dialog-add-sms-provider.component.ts b/console/src/app/modules/policies/notification-settings/dialog-add-sms-provider/dialog-add-sms-provider.component.ts index dec6df7a57..37f1c31fee 100644 --- a/console/src/app/modules/policies/notification-settings/dialog-add-sms-provider/dialog-add-sms-provider.component.ts +++ b/console/src/app/modules/policies/notification-settings/dialog-add-sms-provider/dialog-add-sms-provider.component.ts @@ -1,7 +1,16 @@ import { Component, Inject } from '@angular/core'; import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { AddSMSProviderTwilioRequest } from 'src/app/proto/generated/zitadel/admin_pb'; +import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; +import { + AddSMSProviderTwilioRequest, + UpdateSMSProviderTwilioRequest, + UpdateSMSProviderTwilioTokenRequest, +} from 'src/app/proto/generated/zitadel/admin_pb'; +import { SMSProvider, TwilioConfig } from 'src/app/proto/generated/zitadel/settings_pb'; +import { AdminService } from 'src/app/services/admin.service'; +import { ToastService } from 'src/app/services/toast.service'; + +import { PasswordDialogComponent } from '../password-dialog/password-dialog.component'; enum SMSProviderType { Twilio = 1, @@ -16,13 +25,18 @@ export class DialogAddSMSProviderComponent { public SMSProviderType: any = SMSProviderType; public availableSMSProviders: SMSProviderType[] = [SMSProviderType.Twilio]; public provider: SMSProviderType = SMSProviderType.Twilio; - public req: AddSMSProviderTwilioRequest = new AddSMSProviderTwilioRequest(); + public req!: AddSMSProviderTwilioRequest | UpdateSMSProviderTwilioRequest; public twilioForm!: FormGroup; + private smsProviders: SMSProvider.AsObject[] = []; + constructor( private fb: FormBuilder, + private service: AdminService, public dialogRef: MatDialogRef, + private toast: ToastService, + private dialog: MatDialog, @Inject(MAT_DIALOG_DATA) public data: any, ) { this.twilioForm = this.fb.group({ @@ -30,6 +44,11 @@ export class DialogAddSMSProviderComponent { token: ['', [Validators.required]], senderNumber: ['', [Validators.required]], }); + + this.smsProviders = data.smsProviders; + if (!!this.twilio) { + this.twilioForm.patchValue(this.twilio); + } } public closeDialog(): void { @@ -37,11 +56,46 @@ export class DialogAddSMSProviderComponent { } public closeDialogWithRequest(): void { - this.req.setSid(this.sid?.value); - this.req.setToken(this.token?.value); - this.req.setSenderNumber(this.senderNumber?.value); + if (!!this.twilio) { + this.req = new UpdateSMSProviderTwilioRequest(); - this.dialogRef.close(this.req); + this.req.setSid(this.sid?.value); + this.req.setSenderNumber(this.senderNumber?.value); + this.dialogRef.close(this.req); + } else { + this.req = new AddSMSProviderTwilioRequest(); + + this.req.setSid(this.sid?.value); + this.req.setToken(this.token?.value); + this.req.setSenderNumber(this.senderNumber?.value); + this.dialogRef.close(this.req); + } + } + + public changeToken(): void { + const dialogRef = this.dialog.open(PasswordDialogComponent, { + width: '400px', + data: { + i18nTitle: 'SETTING.SMS.TWILIO.SETTOKEN', + i18nLabel: 'SETTING.SMS.TWILIO.TOKEN', + }, + }); + + dialogRef.afterClosed().subscribe((token: string) => { + if (token) { + const tokenReq = new UpdateSMSProviderTwilioTokenRequest(); + tokenReq.setToken(token); + + this.service + .updateSMSProviderTwilioToken(tokenReq) + .then(() => { + this.toast.showInfo('SETTING.SMS.TWILIO.TOKENSET', true); + }) + .catch((error) => { + this.toast.showError(error); + }); + } + }); } public get senderNumber(): AbstractControl | null { @@ -55,4 +109,13 @@ export class DialogAddSMSProviderComponent { public get sid(): AbstractControl | null { return this.twilioForm.get('sid'); } + + public get twilio(): TwilioConfig.AsObject | undefined { + const twilioProvider: SMSProvider.AsObject | undefined = this.smsProviders.find((p) => p.twilio); + if (twilioProvider && !!twilioProvider.twilio) { + return twilioProvider.twilio; + } else { + return undefined; + } + } } diff --git a/console/src/app/modules/policies/notification-settings/notification-settings.component.html b/console/src/app/modules/policies/notification-settings/notification-settings.component.html index 81ac4d9e09..1124997324 100644 --- a/console/src/app/modules/policies/notification-settings/notification-settings.component.html +++ b/console/src/app/modules/policies/notification-settings/notification-settings.component.html @@ -39,8 +39,9 @@
diff --git a/console/src/app/modules/policies/notification-settings/notification-settings.component.ts b/console/src/app/modules/policies/notification-settings/notification-settings.component.ts index 35548498d4..9599cb7794 100644 --- a/console/src/app/modules/policies/notification-settings/notification-settings.component.ts +++ b/console/src/app/modules/policies/notification-settings/notification-settings.component.ts @@ -3,10 +3,12 @@ import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/fo import { MatDialog } from '@angular/material/dialog'; import { take } from 'rxjs'; import { - AddSMSProviderTwilioRequest, - UpdateSMTPConfigPasswordRequest, - UpdateSMTPConfigPasswordResponse, - UpdateSMTPConfigRequest, + AddSMSProviderTwilioRequest, + AddSMTPConfigRequest, + UpdateSMSProviderTwilioRequest, + UpdateSMTPConfigPasswordRequest, + UpdateSMTPConfigPasswordResponse, + UpdateSMTPConfigRequest, } from 'src/app/proto/generated/zitadel/admin_pb'; import { DebugNotificationProvider, SMSProvider, SMSProviderConfigState } from 'src/app/proto/generated/zitadel/settings_pb'; import { AdminService } from 'src/app/services/admin.service'; @@ -16,7 +18,7 @@ import { ToastService } from 'src/app/services/toast.service'; import { InfoSectionType } from '../../info-section/info-section.component'; import { PolicyComponentServiceType } from '../policy-component-types.enum'; import { DialogAddSMSProviderComponent } from './dialog-add-sms-provider/dialog-add-sms-provider.component'; -import { SMTPPasswordDialogComponent } from './smtp-password-dialog/smtp-password-dialog.component'; +import { PasswordDialogComponent } from './password-dialog/password-dialog.component'; @Component({ selector: 'cnsl-notification-settings', @@ -39,6 +41,8 @@ export class NotificationSettingsComponent implements OnInit { public SMSProviderConfigState: any = SMSProviderConfigState; public InfoSectionType: any = InfoSectionType; + public hasSMTPConfig: boolean = false; + // show available providers constructor( @@ -76,6 +80,7 @@ export class NotificationSettingsComponent implements OnInit { .then((smtpConfig) => { this.smtpLoading = false; if (smtpConfig.smtpConfig) { + this.hasSMTPConfig = true; this.form.patchValue(smtpConfig.smtpConfig); } }) @@ -83,6 +88,7 @@ export class NotificationSettingsComponent implements OnInit { this.smtpLoading = false; if (error && error.code === 5) { console.log(error); + this.hasSMTPConfig = false; } }); @@ -109,9 +115,8 @@ export class NotificationSettingsComponent implements OnInit { this.logNotificationProvider = logNotificationProvider.provider; } }) - .catch((error) => { + .catch(() => { this.logProviderLoading = false; - this.toast.showError(error); }); this.fileProviderLoading = true; @@ -123,23 +128,35 @@ export class NotificationSettingsComponent implements OnInit { this.fileNotificationProvider = fileNotificationProvider.provider; } }) - .catch((error) => { + .catch(() => { this.fileProviderLoading = false; - this.toast.showError(error); }); } private updateData(): Promise | any { - const req = new UpdateSMTPConfigRequest(); - req.setHost(this.host?.value ?? ''); - req.setSenderAddress(this.senderAddress?.value ?? ''); - req.setSenderName(this.senderName?.value ?? ''); - req.setTls(this.tls?.value ?? false); - req.setUser(this.user?.value ?? ''); + if (this.hasSMTPConfig) { + const req = new UpdateSMTPConfigRequest(); + req.setHost(this.host?.value ?? ''); + req.setSenderAddress(this.senderAddress?.value ?? ''); + req.setSenderName(this.senderName?.value ?? ''); + req.setTls(this.tls?.value ?? false); + req.setUser(this.user?.value ?? ''); - return this.service.updateSMTPConfig(req).catch((error) => { - this.toast.showError(error); - }); + return this.service.updateSMTPConfig(req).catch((error) => { + this.toast.showError(error); + }); + } else { + const req = new AddSMTPConfigRequest(); + req.setHost(this.host?.value ?? ''); + req.setSenderAddress(this.senderAddress?.value ?? ''); + req.setSenderName(this.senderName?.value ?? ''); + req.setTls(this.tls?.value ?? false); + req.setUser(this.user?.value ?? ''); + + return this.service.addSMTPConfig(req).catch((error) => { + this.toast.showError(error); + }); + } } public savePolicy(): void { @@ -158,28 +175,46 @@ export class NotificationSettingsComponent implements OnInit { } } - public addSMSProvider(): void { + public editSMSProvider(): void { const dialogRef = this.dialog.open(DialogAddSMSProviderComponent, { width: '400px', + data: { + smsProviders: this.smsProviders, + }, }); - dialogRef.afterClosed().subscribe((req: AddSMSProviderTwilioRequest) => { + dialogRef.afterClosed().subscribe((req: AddSMSProviderTwilioRequest | UpdateSMSProviderTwilioRequest) => { if (req) { - this.service - .addSMSProviderTwilio(req) - .then(() => { - this.toast.showInfo('SETTING.SMS.TWILIO.ADDED', true); - }) - .catch((error) => { - this.toast.showError(error); - }); + if (this.hasTwilio) { + this.service + .updateSMSProviderTwilio(req as UpdateSMSProviderTwilioRequest) + .then(() => { + this.toast.showInfo('SETTING.SMS.TWILIO.ADDED', true); + }) + .catch((error) => { + this.toast.showError(error); + }); + } else { + this.service + .addSMSProviderTwilio(req as AddSMSProviderTwilioRequest) + .then(() => { + this.toast.showInfo('SETTING.SMS.TWILIO.ADDED', true); + }) + .catch((error) => { + this.toast.showError(error); + }); + } } }); } public setSMTPPassword(): void { - const dialogRef = this.dialog.open(SMTPPasswordDialogComponent, { + const dialogRef = this.dialog.open(PasswordDialogComponent, { width: '400px', + data: { + i18nTitle: 'SETTING.SMTP.SETPASSWORD', + i18nLabel: 'SETTING.SMTP.PASSWORD', + }, }); dialogRef.afterClosed().subscribe((password: string) => { @@ -222,4 +257,13 @@ export class NotificationSettingsComponent implements OnInit { public get host(): AbstractControl | null { return this.form.get('host'); } + + public get hasTwilio(): boolean { + const twilioProvider: SMSProvider.AsObject | undefined = this.smsProviders.find((p) => p.twilio); + if (twilioProvider && !!twilioProvider.twilio) { + return true; + } else { + return false; + } + } } diff --git a/console/src/app/modules/policies/notification-settings/notification-settings.module.ts b/console/src/app/modules/policies/notification-settings/notification-settings.module.ts index f5664dc97c..ceb10ce32d 100644 --- a/console/src/app/modules/policies/notification-settings/notification-settings.module.ts +++ b/console/src/app/modules/policies/notification-settings/notification-settings.module.ts @@ -15,10 +15,10 @@ import { InfoSectionModule } from '../../info-section/info-section.module'; import { InputModule } from '../../input/input.module'; import { DialogAddSMSProviderComponent } from './dialog-add-sms-provider/dialog-add-sms-provider.component'; import { NotificationSettingsComponent } from './notification-settings.component'; -import { SMTPPasswordDialogComponent } from './smtp-password-dialog/smtp-password-dialog.component'; +import { PasswordDialogComponent } from './password-dialog/password-dialog.component'; @NgModule({ - declarations: [NotificationSettingsComponent, DialogAddSMSProviderComponent, SMTPPasswordDialogComponent], + declarations: [NotificationSettingsComponent, DialogAddSMSProviderComponent, PasswordDialogComponent], imports: [ CommonModule, CardModule, diff --git a/console/src/app/modules/policies/notification-settings/smtp-password-dialog/smtp-password-dialog.component.html b/console/src/app/modules/policies/notification-settings/password-dialog/password-dialog.component.html similarity index 78% rename from console/src/app/modules/policies/notification-settings/smtp-password-dialog/smtp-password-dialog.component.html rename to console/src/app/modules/policies/notification-settings/password-dialog/password-dialog.component.html index 2ea9d6ee52..fdc31555a0 100644 --- a/console/src/app/modules/policies/notification-settings/smtp-password-dialog/smtp-password-dialog.component.html +++ b/console/src/app/modules/policies/notification-settings/password-dialog/password-dialog.component.html @@ -1,9 +1,9 @@

- {{ 'SETTING.SMTP.SETPASSWORD' | translate }} {{ data?.number }} + {{ data.i18nTitle | translate }} {{ data?.number }}

- {{ 'SETTING.SMTP.PASSWORD' | translate }} + {{ data.i18nLabel | translate }}
diff --git a/console/src/app/modules/policies/notification-settings/smtp-password-dialog/smtp-password-dialog.component.scss b/console/src/app/modules/policies/notification-settings/password-dialog/password-dialog.component.scss similarity index 100% rename from console/src/app/modules/policies/notification-settings/smtp-password-dialog/smtp-password-dialog.component.scss rename to console/src/app/modules/policies/notification-settings/password-dialog/password-dialog.component.scss diff --git a/console/src/app/modules/policies/notification-settings/smtp-password-dialog/smtp-password-dialog.component.spec.ts b/console/src/app/modules/policies/notification-settings/password-dialog/password-dialog.component.spec.ts similarity index 51% rename from console/src/app/modules/policies/notification-settings/smtp-password-dialog/smtp-password-dialog.component.spec.ts rename to console/src/app/modules/policies/notification-settings/password-dialog/password-dialog.component.spec.ts index 176f75cf97..45f7f38a66 100644 --- a/console/src/app/modules/policies/notification-settings/smtp-password-dialog/smtp-password-dialog.component.spec.ts +++ b/console/src/app/modules/policies/notification-settings/password-dialog/password-dialog.component.spec.ts @@ -1,19 +1,19 @@ import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { SMTPPasswordDialogComponent } from './smtp-password-dialog.component'; +import { PasswordDialogComponent } from './password-dialog.component'; -describe('CodeDialogComponent', () => { - let component: SMTPPasswordDialogComponent; - let fixture: ComponentFixture; +describe('PasswordDialogComponent', () => { + let component: PasswordDialogComponent; + let fixture: ComponentFixture; beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ - declarations: [SMTPPasswordDialogComponent], + declarations: [PasswordDialogComponent], }).compileComponents(); })); beforeEach(() => { - fixture = TestBed.createComponent(SMTPPasswordDialogComponent); + fixture = TestBed.createComponent(PasswordDialogComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/console/src/app/modules/policies/notification-settings/password-dialog/password-dialog.component.ts b/console/src/app/modules/policies/notification-settings/password-dialog/password-dialog.component.ts new file mode 100644 index 0000000000..1e1263e1a1 --- /dev/null +++ b/console/src/app/modules/policies/notification-settings/password-dialog/password-dialog.component.ts @@ -0,0 +1,16 @@ +import { Component, Inject } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; + +@Component({ + selector: 'cnsl-password-dialog', + templateUrl: './password-dialog.component.html', + styleUrls: ['./password-dialog.component.scss'], +}) +export class PasswordDialogComponent { + public password: string = ''; + constructor(public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: any) {} + + closeDialog(password: string = ''): void { + this.dialogRef.close(password); + } +} diff --git a/console/src/app/modules/policies/notification-settings/smtp-password-dialog/smtp-password-dialog.component.ts b/console/src/app/modules/policies/notification-settings/smtp-password-dialog/smtp-password-dialog.component.ts deleted file mode 100644 index d8ddc4f3ce..0000000000 --- a/console/src/app/modules/policies/notification-settings/smtp-password-dialog/smtp-password-dialog.component.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Component, Inject } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; - -@Component({ - selector: 'cnsl-smtp-password-dialog', - templateUrl: './smtp-password-dialog.component.html', - styleUrls: ['./smtp-password-dialog.component.scss'], -}) -export class SMTPPasswordDialogComponent { - public password: string = ''; - constructor(public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: any) {} - - closeDialog(password: string = ''): void { - this.dialogRef.close(password); - } -} diff --git a/console/src/app/services/admin.service.ts b/console/src/app/services/admin.service.ts index 84f0eb922d..183ef92ceb 100644 --- a/console/src/app/services/admin.service.ts +++ b/console/src/app/services/admin.service.ts @@ -1,189 +1,195 @@ import { Injectable } from '@angular/core'; import { - ActivateLabelPolicyRequest, - ActivateLabelPolicyResponse, - AddCustomDomainPolicyRequest, - AddCustomOrgIAMPolicyResponse, - AddIAMMemberRequest, - AddIAMMemberResponse, - AddIDPToLoginPolicyRequest, - AddIDPToLoginPolicyResponse, - AddJWTIDPRequest, - AddJWTIDPResponse, - AddMultiFactorToLoginPolicyRequest, - AddMultiFactorToLoginPolicyResponse, - AddOIDCIDPRequest, - AddOIDCIDPResponse, - AddSecondFactorToLoginPolicyRequest, - AddSecondFactorToLoginPolicyResponse, - AddSMSProviderTwilioRequest, - AddSMSProviderTwilioResponse, - DeactivateIDPRequest, - DeactivateIDPResponse, - GetCustomDomainClaimedMessageTextRequest, - GetCustomDomainClaimedMessageTextResponse, - GetCustomDomainPolicyRequest, - GetCustomDomainPolicyResponse, - GetCustomInitMessageTextRequest, - GetCustomInitMessageTextResponse, - GetCustomLoginTextsRequest, - GetCustomLoginTextsResponse, - GetCustomPasswordlessRegistrationMessageTextRequest, - GetCustomPasswordlessRegistrationMessageTextResponse, - GetCustomPasswordResetMessageTextRequest, - GetCustomPasswordResetMessageTextResponse, - GetCustomVerifyEmailMessageTextRequest, - GetCustomVerifyEmailMessageTextResponse, - GetCustomVerifyPhoneMessageTextRequest, - GetCustomVerifyPhoneMessageTextResponse, - GetDefaultDomainClaimedMessageTextRequest, - GetDefaultDomainClaimedMessageTextResponse, - GetDefaultInitMessageTextRequest, - GetDefaultInitMessageTextResponse, - GetDefaultLanguageRequest, - GetDefaultLanguageResponse, - GetDefaultLoginTextsRequest, - GetDefaultLoginTextsResponse, - GetDefaultPasswordlessRegistrationMessageTextRequest, - GetDefaultPasswordlessRegistrationMessageTextResponse, - GetDefaultPasswordResetMessageTextRequest, - GetDefaultPasswordResetMessageTextResponse, - GetDefaultVerifyEmailMessageTextRequest, - GetDefaultVerifyEmailMessageTextResponse, - GetDefaultVerifyPhoneMessageTextRequest, - GetDefaultVerifyPhoneMessageTextResponse, - GetDomainPolicyRequest, - GetDomainPolicyResponse, - GetFileSystemNotificationProviderRequest, - GetFileSystemNotificationProviderResponse, - GetIDPByIDRequest, - GetIDPByIDResponse, - GetLabelPolicyRequest, - GetLabelPolicyResponse, - GetLockoutPolicyRequest, - GetLockoutPolicyResponse, - GetLoginPolicyRequest, - GetLoginPolicyResponse, - GetLogNotificationProviderRequest, - GetLogNotificationProviderResponse, - GetOIDCSettingsRequest, - GetOIDCSettingsResponse, - GetPasswordAgePolicyRequest, - GetPasswordAgePolicyResponse, - GetPasswordComplexityPolicyRequest, - GetPasswordComplexityPolicyResponse, - GetPreviewLabelPolicyRequest, - GetPreviewLabelPolicyResponse, - GetPrivacyPolicyRequest, - GetPrivacyPolicyResponse, - GetSecretGeneratorRequest, - GetSecretGeneratorResponse, - GetSMSProviderRequest, - GetSMSProviderResponse, - GetSMTPConfigRequest, - GetSMTPConfigResponse, - GetSupportedLanguagesRequest, - GetSupportedLanguagesResponse, - IDPQuery, - ListFailedEventsRequest, - ListFailedEventsResponse, - ListIAMMemberRolesRequest, - ListIAMMemberRolesResponse, - ListIAMMembersRequest, - ListIAMMembersResponse, - ListIDPsRequest, - ListIDPsResponse, - ListLoginPolicyIDPsRequest, - ListLoginPolicyIDPsResponse, - ListLoginPolicyMultiFactorsRequest, - ListLoginPolicyMultiFactorsResponse, - ListLoginPolicySecondFactorsRequest, - ListLoginPolicySecondFactorsResponse, - ListSecretGeneratorsRequest, - ListSecretGeneratorsResponse, - ListSMSProvidersRequest, - ListSMSProvidersResponse, - ListViewsRequest, - ListViewsResponse, - ReactivateIDPRequest, - ReactivateIDPResponse, - RemoveFailedEventRequest, - RemoveFailedEventResponse, - RemoveIAMMemberRequest, - RemoveIAMMemberResponse, - RemoveIDPFromLoginPolicyRequest, - RemoveIDPFromLoginPolicyResponse, - RemoveIDPRequest, - RemoveIDPResponse, - RemoveLabelPolicyFontRequest, - RemoveLabelPolicyFontResponse, - RemoveLabelPolicyIconDarkRequest, - RemoveLabelPolicyIconDarkResponse, - RemoveLabelPolicyIconRequest, - RemoveLabelPolicyIconResponse, - RemoveLabelPolicyLogoDarkRequest, - RemoveLabelPolicyLogoDarkResponse, - RemoveLabelPolicyLogoRequest, - RemoveLabelPolicyLogoResponse, - RemoveMultiFactorFromLoginPolicyRequest, - RemoveMultiFactorFromLoginPolicyResponse, - RemoveSecondFactorFromLoginPolicyRequest, - RemoveSecondFactorFromLoginPolicyResponse, - ResetCustomDomainPolicyToDefaultRequest, - ResetCustomDomainPolicyToDefaultResponse, - ResetCustomLoginTextsToDefaultRequest, - ResetCustomLoginTextsToDefaultResponse, - SetCustomLoginTextsRequest, - SetCustomLoginTextsResponse, - SetDefaultDomainClaimedMessageTextRequest, - SetDefaultDomainClaimedMessageTextResponse, - SetDefaultInitMessageTextRequest, - SetDefaultInitMessageTextResponse, - SetDefaultLanguageRequest, - SetDefaultLanguageResponse, - SetDefaultPasswordlessRegistrationMessageTextRequest, - SetDefaultPasswordlessRegistrationMessageTextResponse, - SetDefaultPasswordResetMessageTextRequest, - SetDefaultPasswordResetMessageTextResponse, - SetDefaultVerifyEmailMessageTextRequest, - SetDefaultVerifyEmailMessageTextResponse, - SetDefaultVerifyPhoneMessageTextRequest, - SetDefaultVerifyPhoneMessageTextResponse, - SetUpOrgRequest, - SetUpOrgResponse, - UpdateCustomDomainPolicyRequest, - UpdateCustomDomainPolicyResponse, - UpdateDomainPolicyRequest, - UpdateDomainPolicyResponse, - UpdateIAMMemberRequest, - UpdateIAMMemberResponse, - UpdateIDPJWTConfigRequest, - UpdateIDPJWTConfigResponse, - UpdateIDPOIDCConfigRequest, - UpdateIDPOIDCConfigResponse, - UpdateIDPRequest, - UpdateIDPResponse, - UpdateLabelPolicyRequest, - UpdateLabelPolicyResponse, - UpdateLockoutPolicyRequest, - UpdateLockoutPolicyResponse, - UpdateLoginPolicyRequest, - UpdateLoginPolicyResponse, - UpdateOIDCSettingsRequest, - UpdateOIDCSettingsResponse, - UpdatePasswordAgePolicyRequest, - UpdatePasswordAgePolicyResponse, - UpdatePasswordComplexityPolicyRequest, - UpdatePasswordComplexityPolicyResponse, - UpdatePrivacyPolicyRequest, - UpdatePrivacyPolicyResponse, - UpdateSecretGeneratorRequest, - UpdateSecretGeneratorResponse, - UpdateSMTPConfigPasswordRequest, - UpdateSMTPConfigPasswordResponse, - UpdateSMTPConfigRequest, - UpdateSMTPConfigResponse, + ActivateLabelPolicyRequest, + ActivateLabelPolicyResponse, + AddCustomDomainPolicyRequest, + AddCustomOrgIAMPolicyResponse, + AddIAMMemberRequest, + AddIAMMemberResponse, + AddIDPToLoginPolicyRequest, + AddIDPToLoginPolicyResponse, + AddJWTIDPRequest, + AddJWTIDPResponse, + AddMultiFactorToLoginPolicyRequest, + AddMultiFactorToLoginPolicyResponse, + AddOIDCIDPRequest, + AddOIDCIDPResponse, + AddSecondFactorToLoginPolicyRequest, + AddSecondFactorToLoginPolicyResponse, + AddSMSProviderTwilioRequest, + AddSMSProviderTwilioResponse, + AddSMTPConfigRequest, + AddSMTPConfigResponse, + DeactivateIDPRequest, + DeactivateIDPResponse, + GetCustomDomainClaimedMessageTextRequest, + GetCustomDomainClaimedMessageTextResponse, + GetCustomDomainPolicyRequest, + GetCustomDomainPolicyResponse, + GetCustomInitMessageTextRequest, + GetCustomInitMessageTextResponse, + GetCustomLoginTextsRequest, + GetCustomLoginTextsResponse, + GetCustomPasswordlessRegistrationMessageTextRequest, + GetCustomPasswordlessRegistrationMessageTextResponse, + GetCustomPasswordResetMessageTextRequest, + GetCustomPasswordResetMessageTextResponse, + GetCustomVerifyEmailMessageTextRequest, + GetCustomVerifyEmailMessageTextResponse, + GetCustomVerifyPhoneMessageTextRequest, + GetCustomVerifyPhoneMessageTextResponse, + GetDefaultDomainClaimedMessageTextRequest, + GetDefaultDomainClaimedMessageTextResponse, + GetDefaultInitMessageTextRequest, + GetDefaultInitMessageTextResponse, + GetDefaultLanguageRequest, + GetDefaultLanguageResponse, + GetDefaultLoginTextsRequest, + GetDefaultLoginTextsResponse, + GetDefaultPasswordlessRegistrationMessageTextRequest, + GetDefaultPasswordlessRegistrationMessageTextResponse, + GetDefaultPasswordResetMessageTextRequest, + GetDefaultPasswordResetMessageTextResponse, + GetDefaultVerifyEmailMessageTextRequest, + GetDefaultVerifyEmailMessageTextResponse, + GetDefaultVerifyPhoneMessageTextRequest, + GetDefaultVerifyPhoneMessageTextResponse, + GetDomainPolicyRequest, + GetDomainPolicyResponse, + GetFileSystemNotificationProviderRequest, + GetFileSystemNotificationProviderResponse, + GetIDPByIDRequest, + GetIDPByIDResponse, + GetLabelPolicyRequest, + GetLabelPolicyResponse, + GetLockoutPolicyRequest, + GetLockoutPolicyResponse, + GetLoginPolicyRequest, + GetLoginPolicyResponse, + GetLogNotificationProviderRequest, + GetLogNotificationProviderResponse, + GetOIDCSettingsRequest, + GetOIDCSettingsResponse, + GetPasswordAgePolicyRequest, + GetPasswordAgePolicyResponse, + GetPasswordComplexityPolicyRequest, + GetPasswordComplexityPolicyResponse, + GetPreviewLabelPolicyRequest, + GetPreviewLabelPolicyResponse, + GetPrivacyPolicyRequest, + GetPrivacyPolicyResponse, + GetSecretGeneratorRequest, + GetSecretGeneratorResponse, + GetSMSProviderRequest, + GetSMSProviderResponse, + GetSMTPConfigRequest, + GetSMTPConfigResponse, + GetSupportedLanguagesRequest, + GetSupportedLanguagesResponse, + IDPQuery, + ListFailedEventsRequest, + ListFailedEventsResponse, + ListIAMMemberRolesRequest, + ListIAMMemberRolesResponse, + ListIAMMembersRequest, + ListIAMMembersResponse, + ListIDPsRequest, + ListIDPsResponse, + ListLoginPolicyIDPsRequest, + ListLoginPolicyIDPsResponse, + ListLoginPolicyMultiFactorsRequest, + ListLoginPolicyMultiFactorsResponse, + ListLoginPolicySecondFactorsRequest, + ListLoginPolicySecondFactorsResponse, + ListSecretGeneratorsRequest, + ListSecretGeneratorsResponse, + ListSMSProvidersRequest, + ListSMSProvidersResponse, + ListViewsRequest, + ListViewsResponse, + ReactivateIDPRequest, + ReactivateIDPResponse, + RemoveFailedEventRequest, + RemoveFailedEventResponse, + RemoveIAMMemberRequest, + RemoveIAMMemberResponse, + RemoveIDPFromLoginPolicyRequest, + RemoveIDPFromLoginPolicyResponse, + RemoveIDPRequest, + RemoveIDPResponse, + RemoveLabelPolicyFontRequest, + RemoveLabelPolicyFontResponse, + RemoveLabelPolicyIconDarkRequest, + RemoveLabelPolicyIconDarkResponse, + RemoveLabelPolicyIconRequest, + RemoveLabelPolicyIconResponse, + RemoveLabelPolicyLogoDarkRequest, + RemoveLabelPolicyLogoDarkResponse, + RemoveLabelPolicyLogoRequest, + RemoveLabelPolicyLogoResponse, + RemoveMultiFactorFromLoginPolicyRequest, + RemoveMultiFactorFromLoginPolicyResponse, + RemoveSecondFactorFromLoginPolicyRequest, + RemoveSecondFactorFromLoginPolicyResponse, + ResetCustomDomainPolicyToDefaultRequest, + ResetCustomDomainPolicyToDefaultResponse, + ResetCustomLoginTextsToDefaultRequest, + ResetCustomLoginTextsToDefaultResponse, + SetCustomLoginTextsRequest, + SetCustomLoginTextsResponse, + SetDefaultDomainClaimedMessageTextRequest, + SetDefaultDomainClaimedMessageTextResponse, + SetDefaultInitMessageTextRequest, + SetDefaultInitMessageTextResponse, + SetDefaultLanguageRequest, + SetDefaultLanguageResponse, + SetDefaultPasswordlessRegistrationMessageTextRequest, + SetDefaultPasswordlessRegistrationMessageTextResponse, + SetDefaultPasswordResetMessageTextRequest, + SetDefaultPasswordResetMessageTextResponse, + SetDefaultVerifyEmailMessageTextRequest, + SetDefaultVerifyEmailMessageTextResponse, + SetDefaultVerifyPhoneMessageTextRequest, + SetDefaultVerifyPhoneMessageTextResponse, + SetUpOrgRequest, + SetUpOrgResponse, + UpdateCustomDomainPolicyRequest, + UpdateCustomDomainPolicyResponse, + UpdateDomainPolicyRequest, + UpdateDomainPolicyResponse, + UpdateIAMMemberRequest, + UpdateIAMMemberResponse, + UpdateIDPJWTConfigRequest, + UpdateIDPJWTConfigResponse, + UpdateIDPOIDCConfigRequest, + UpdateIDPOIDCConfigResponse, + UpdateIDPRequest, + UpdateIDPResponse, + UpdateLabelPolicyRequest, + UpdateLabelPolicyResponse, + UpdateLockoutPolicyRequest, + UpdateLockoutPolicyResponse, + UpdateLoginPolicyRequest, + UpdateLoginPolicyResponse, + UpdateOIDCSettingsRequest, + UpdateOIDCSettingsResponse, + UpdatePasswordAgePolicyRequest, + UpdatePasswordAgePolicyResponse, + UpdatePasswordComplexityPolicyRequest, + UpdatePasswordComplexityPolicyResponse, + UpdatePrivacyPolicyRequest, + UpdatePrivacyPolicyResponse, + UpdateSecretGeneratorRequest, + UpdateSecretGeneratorResponse, + UpdateSMSProviderTwilioRequest, + UpdateSMSProviderTwilioResponse, + UpdateSMSProviderTwilioTokenRequest, + UpdateSMSProviderTwilioTokenResponse, + UpdateSMTPConfigPasswordRequest, + UpdateSMTPConfigPasswordResponse, + UpdateSMTPConfigRequest, + UpdateSMTPConfigResponse, } from '../proto/generated/zitadel/admin_pb'; import { SearchQuery } from '../proto/generated/zitadel/member_pb'; import { ListQuery } from '../proto/generated/zitadel/object_pb'; @@ -466,6 +472,10 @@ export class AdminService { return this.grpcService.admin.getSMTPConfig(req, null).then((resp) => resp.toObject()); } + public addSMTPConfig(req: AddSMTPConfigRequest): Promise { + return this.grpcService.admin.addSMTPConfig(req, null).then((resp) => resp.toObject()); + } + public updateSMTPConfig(req: UpdateSMTPConfigRequest): Promise { return this.grpcService.admin.updateSMTPConfig(req, null).then((resp) => resp.toObject()); } @@ -490,6 +500,16 @@ export class AdminService { return this.grpcService.admin.addSMSProviderTwilio(req, null).then((resp) => resp.toObject()); } + public updateSMSProviderTwilio(req: UpdateSMSProviderTwilioRequest): Promise { + return this.grpcService.admin.updateSMSProviderTwilio(req, null).then((resp) => resp.toObject()); + } + + public updateSMSProviderTwilioToken( + req: UpdateSMSProviderTwilioTokenRequest, + ): Promise { + return this.grpcService.admin.updateSMSProviderTwilioToken(req, null).then((resp) => resp.toObject()); + } + /* lockout */ public getLockoutPolicy(): Promise { diff --git a/console/src/assets/i18n/de.json b/console/src/assets/i18n/de.json index 07b607c249..512bca21a5 100644 --- a/console/src/assets/i18n/de.json +++ b/console/src/assets/i18n/de.json @@ -886,7 +886,10 @@ "SID": "Sid", "TOKEN": "Token", "SENDERNUMBER": "Sender Number", - "ADDED": "Twilio erfolgreich hinzugefügt." + "ADDED": "Twilio erfolgreich hinzugefügt.", + "CHANGETOKEN": "Token ändern", + "SETTOKEN": "Token setzen", + "TOKENSET": "Token erfolgreich gesetzt." } }, "OIDC": { diff --git a/console/src/assets/i18n/en.json b/console/src/assets/i18n/en.json index 961c867c41..adf0ede3f2 100644 --- a/console/src/assets/i18n/en.json +++ b/console/src/assets/i18n/en.json @@ -886,7 +886,10 @@ "SID": "Sid", "TOKEN": "Token", "SENDERNUMBER": "Sender Number", - "ADDED": "Twilio added successfully." + "ADDED": "Twilio added successfully.", + "CHANGETOKEN": "Change Token", + "SETTOKEN": "Set Token", + "TOKENSET": "Token successfully set." } }, "OIDC": { diff --git a/console/src/assets/i18n/it.json b/console/src/assets/i18n/it.json index bf8efbb039..bd784e064b 100644 --- a/console/src/assets/i18n/it.json +++ b/console/src/assets/i18n/it.json @@ -886,7 +886,10 @@ "SID": "Sid", "TOKEN": "Token", "SENDERNUMBER": "Sender Number", - "ADDED": "Twilio aggiunto con successo." + "ADDED": "Twilio aggiunto con successo.", + "CHANGETOKEN": "Cambia Token", + "SETTOKEN": "Cambia Token", + "TOKENSET": "Token cambiato con successo." } }, "OIDC": { diff --git a/docs/docs/apis/proto/admin.md b/docs/docs/apis/proto/admin.md index 7c0e4bc145..5e5000f423 100644 --- a/docs/docs/apis/proto/admin.md +++ b/docs/docs/apis/proto/admin.md @@ -116,6 +116,18 @@ Get system smtp configuration GET: /smtp +### AddSMTPConfig + +> **rpc** AddSMTPConfig([AddSMTPConfigRequest](#addsmtpconfigrequest)) +[AddSMTPConfigResponse](#addsmtpconfigresponse) + +Add system smtp configuration + + + + POST: /smtp + + ### UpdateSMTPConfig > **rpc** UpdateSMTPConfig([UpdateSMTPConfigRequest](#updatesmtpconfigrequest)) @@ -140,6 +152,18 @@ Update system smtp configuration password for host PUT: /smtp/password +### RemoveSMTPConfig + +> **rpc** RemoveSMTPConfig([RemoveSMTPConfigRequest](#removesmtpconfigrequest)) +[RemoveSMTPConfigResponse](#removesmtpconfigresponse) + +Remove system smtp configuration + + + + DELETE: /smtp + + ### ListSMSProviders > **rpc** ListSMSProviders([ListSMSProvidersRequest](#listsmsprovidersrequest)) @@ -200,6 +224,18 @@ Update twilio sms provider token PUT: /sms/twilio/{id}/token +### RemoveSMSProvider + +> **rpc** RemoveSMSProvider([RemoveSMSProviderRequest](#removesmsproviderrequest)) +[RemoveSMSProviderResponse](#removesmsproviderresponse) + +Remove sms provider token + + + + DELETE: /sms/{id} + + ### GetOIDCSettings > **rpc** GetOIDCSettings([GetOIDCSettingsRequest](#getoidcsettingsrequest)) @@ -1646,6 +1682,33 @@ This is an empty request +### AddSMTPConfigRequest + + + +| Field | Type | Description | Validation | +| ----- | ---- | ----------- | ----------- | +| sender_address | string | - | string.min_len: 1
string.max_len: 200
| +| sender_name | string | - | string.min_len: 1
string.max_len: 200
| +| tls | bool | - | | +| host | string | - | string.min_len: 1
string.max_len: 500
| +| user | string | - | | +| password | string | - | | + + + + +### AddSMTPConfigResponse + + + +| Field | Type | Description | Validation | +| ----- | ---- | ----------- | ----------- | +| details | zitadel.v1.ObjectDetails | - | | + + + + ### AddSecondFactorToLoginPolicyRequest @@ -2941,6 +3004,45 @@ This is an empty request +### RemoveSMSProviderRequest + + + +| Field | Type | Description | Validation | +| ----- | ---- | ----------- | ----------- | +| id | string | - | string.min_len: 1
string.max_len: 200
| + + + + +### RemoveSMSProviderResponse + + + +| Field | Type | Description | Validation | +| ----- | ---- | ----------- | ----------- | +| details | zitadel.v1.ObjectDetails | - | | + + + + +### RemoveSMTPConfigRequest +this is en empty request + + + + +### RemoveSMTPConfigResponse + + + +| Field | Type | Description | Validation | +| ----- | ---- | ----------- | ----------- | +| details | zitadel.v1.ObjectDetails | - | | + + + + ### RemoveSecondFactorFromLoginPolicyRequest diff --git a/internal/api/grpc/admin/iam_settings.go b/internal/api/grpc/admin/iam_settings.go index c5ea8602bd..2e10e65a8e 100644 --- a/internal/api/grpc/admin/iam_settings.go +++ b/internal/api/grpc/admin/iam_settings.go @@ -55,6 +55,19 @@ func (s *Server) GetSMTPConfig(ctx context.Context, req *admin_pb.GetSMTPConfigR }, nil } +func (s *Server) AddSMTPConfig(ctx context.Context, req *admin_pb.AddSMTPConfigRequest) (*admin_pb.AddSMTPConfigResponse, error) { + details, err := s.command.AddSMTPConfig(ctx, AddSMTPToConfig(req)) + if err != nil { + return nil, err + } + return &admin_pb.AddSMTPConfigResponse{ + Details: object.ChangeToDetailsPb( + details.Sequence, + details.EventDate, + details.ResourceOwner), + }, nil +} + func (s *Server) UpdateSMTPConfig(ctx context.Context, req *admin_pb.UpdateSMTPConfigRequest) (*admin_pb.UpdateSMTPConfigResponse, error) { details, err := s.command.ChangeSMTPConfig(ctx, UpdateSMTPToConfig(req)) if err != nil { @@ -68,6 +81,19 @@ func (s *Server) UpdateSMTPConfig(ctx context.Context, req *admin_pb.UpdateSMTPC }, nil } +func (s *Server) RemoveSMTPConfig(ctx context.Context, _ *admin_pb.RemoveSMTPConfigRequest) (*admin_pb.RemoveSMTPConfigResponse, error) { + details, err := s.command.RemoveSMTPConfig(ctx) + if err != nil { + return nil, err + } + return &admin_pb.RemoveSMTPConfigResponse{ + Details: object.ChangeToDetailsPb( + details.Sequence, + details.EventDate, + details.ResourceOwner), + }, nil +} + func (s *Server) UpdateSMTPConfigPassword(ctx context.Context, req *admin_pb.UpdateSMTPConfigPasswordRequest) (*admin_pb.UpdateSMTPConfigPasswordResponse, error) { details, err := s.command.ChangeSMTPConfigPassword(ctx, req.Password) if err != nil { diff --git a/internal/api/grpc/admin/iam_settings_converter.go b/internal/api/grpc/admin/iam_settings_converter.go index b5d6c681a3..1265a8a500 100644 --- a/internal/api/grpc/admin/iam_settings_converter.go +++ b/internal/api/grpc/admin/iam_settings_converter.go @@ -1,12 +1,12 @@ package admin import ( - "github.com/zitadel/zitadel/internal/domain" "google.golang.org/protobuf/types/known/durationpb" "github.com/zitadel/zitadel/internal/api/grpc/object" obj_grpc "github.com/zitadel/zitadel/internal/api/grpc/object" "github.com/zitadel/zitadel/internal/crypto" + "github.com/zitadel/zitadel/internal/domain" "github.com/zitadel/zitadel/internal/errors" "github.com/zitadel/zitadel/internal/notification/channels/smtp" "github.com/zitadel/zitadel/internal/query" @@ -113,6 +113,19 @@ func SecretGeneratorTypeToDomain(generatorType settings_pb.SecretGeneratorType) } } +func AddSMTPToConfig(req *admin_pb.AddSMTPConfigRequest) *smtp.EmailConfig { + return &smtp.EmailConfig{ + Tls: req.Tls, + From: req.SenderAddress, + FromName: req.SenderName, + SMTP: smtp.SMTP{ + Host: req.Host, + User: req.User, + Password: req.Password, + }, + } +} + func UpdateSMTPToConfig(req *admin_pb.UpdateSMTPConfigRequest) *smtp.EmailConfig { return &smtp.EmailConfig{ Tls: req.Tls, diff --git a/internal/api/grpc/admin/sms.go b/internal/api/grpc/admin/sms.go index db08aeb60f..2332ab11d5 100644 --- a/internal/api/grpc/admin/sms.go +++ b/internal/api/grpc/admin/sms.go @@ -73,3 +73,14 @@ func (s *Server) UpdateSMSProviderTwilioToken(ctx context.Context, req *admin_pb Details: object.DomainToChangeDetailsPb(result), }, nil } + +func (s *Server) RemoveSMSProvider(ctx context.Context, req *admin_pb.RemoveSMSProviderRequest) (*admin_pb.RemoveSMSProviderResponse, error) { + result, err := s.command.RemoveSMSConfig(ctx, authz.GetInstance(ctx).InstanceID(), req.Id) + if err != nil { + return nil, err + + } + return &admin_pb.RemoveSMSProviderResponse{ + Details: object.DomainToAddDetailsPb(result), + }, nil +} diff --git a/internal/command/instance_smtp_config_model.go b/internal/command/instance_smtp_config_model.go index cb4377539d..07e0539f3a 100644 --- a/internal/command/instance_smtp_config_model.go +++ b/internal/command/instance_smtp_config_model.go @@ -82,6 +82,14 @@ func (wm *InstanceSMTPConfigWriteModel) Reduce() error { if e.User != nil { wm.User = *e.User } + case *instance.SMTPConfigRemovedEvent: + wm.State = domain.SMTPConfigStateRemoved + wm.TLS = false + wm.SenderName = "" + wm.SenderAddress = "" + wm.Host = "" + wm.User = "" + wm.Password = nil case *instance.DomainAddedEvent: wm.domainState = domain.InstanceDomainStateActive case *instance.DomainRemovedEvent: diff --git a/internal/command/sms_config.go b/internal/command/sms_config.go index efdbbf6088..3eb82b3610 100644 --- a/internal/command/sms_config.go +++ b/internal/command/sms_config.go @@ -170,7 +170,7 @@ func (c *Commands) DeactivateSMSConfigTwilio(ctx context.Context, instanceID, id return writeModelToObjectDetails(&smsConfigWriteModel.WriteModel), nil } -func (c *Commands) RemoveSMSConfigTwilio(ctx context.Context, instanceID, id string) (*domain.ObjectDetails, error) { +func (c *Commands) RemoveSMSConfig(ctx context.Context, instanceID, id string) (*domain.ObjectDetails, error) { if id == "" { return nil, caos_errs.ThrowInvalidArgument(nil, "SMS-3j9fs", "Errors.IDMissing") } @@ -178,7 +178,7 @@ func (c *Commands) RemoveSMSConfigTwilio(ctx context.Context, instanceID, id str if err != nil { return nil, err } - if !smsConfigWriteModel.State.Exists() || smsConfigWriteModel.Twilio == nil { + if !smsConfigWriteModel.State.Exists() { return nil, caos_errs.ThrowNotFound(nil, "COMMAND-sn9we", "Errors.SMSConfig.NotFound") } diff --git a/internal/command/sms_config_test.go b/internal/command/sms_config_test.go index 8ed7159738..987554669f 100644 --- a/internal/command/sms_config_test.go +++ b/internal/command/sms_config_test.go @@ -496,7 +496,7 @@ func TestCommandSide_DeactivateSMSConfigTwilio(t *testing.T) { } } -func TestCommandSide_RemoveSMSConfigTwilio(t *testing.T) { +func TestCommandSide_RemoveSMSConfig(t *testing.T) { type fields struct { eventstore *eventstore.Eventstore } @@ -547,7 +547,7 @@ func TestCommandSide_RemoveSMSConfigTwilio(t *testing.T) { }, }, { - name: "sms config twilio remove, ok", + name: "sms config remove, ok", fields: fields{ eventstore: eventstoreExpect( t, @@ -593,7 +593,7 @@ func TestCommandSide_RemoveSMSConfigTwilio(t *testing.T) { r := &Commands{ eventstore: tt.fields.eventstore, } - got, err := r.RemoveSMSConfigTwilio(tt.args.ctx, tt.args.instanceID, tt.args.id) + got, err := r.RemoveSMSConfig(tt.args.ctx, tt.args.instanceID, tt.args.id) if tt.res.err == nil { assert.NoError(t, err) } diff --git a/internal/command/smtp.go b/internal/command/smtp.go index f94b7014f5..a3f99f6dc0 100644 --- a/internal/command/smtp.go +++ b/internal/command/smtp.go @@ -81,6 +81,24 @@ func (c *Commands) ChangeSMTPConfigPassword(ctx context.Context, password string }, nil } +func (c *Commands) RemoveSMTPConfig(ctx context.Context) (*domain.ObjectDetails, error) { + instanceAgg := instance.NewAggregate(authz.GetInstance(ctx).InstanceID()) + validation := c.prepareRemoveSMTPConfig(instanceAgg) + cmds, err := preparation.PrepareCommands(ctx, c.eventstore.Filter, validation) + if err != nil { + return nil, err + } + events, err := c.eventstore.Push(ctx, cmds...) + if err != nil { + return nil, err + } + return &domain.ObjectDetails{ + Sequence: events[len(events)-1].Sequence(), + EventDate: events[len(events)-1].CreationDate(), + ResourceOwner: events[len(events)-1].Aggregate().InstanceID, + }, nil +} + func (c *Commands) prepareAddSMTPConfig(a *instance.Aggregate, from, name, host, user string, password []byte, tls bool) preparation.Validation { return func() (preparation.CreateCommands, error) { if from = strings.TrimSpace(from); from == "" { @@ -171,6 +189,23 @@ func (c *Commands) prepareChangeSMTPConfig(a *instance.Aggregate, from, name, ho } } +func (c *Commands) prepareRemoveSMTPConfig(a *instance.Aggregate) preparation.Validation { + return func() (preparation.CreateCommands, error) { + return func(ctx context.Context, filter preparation.FilterToQueryReducer) ([]eventstore.Command, error) { + writeModel, err := getSMTPConfigWriteModel(ctx, filter, "") + if err != nil { + return nil, err + } + if writeModel.State != domain.SMTPConfigStateActive { + return nil, errors.ThrowNotFound(nil, "INST-Sfefg", "Errors.SMTPConfig.NotFound") + } + return []eventstore.Command{ + instance.NewSMTPConfigRemovedEvent(ctx, &a.Aggregate), + }, nil + }, nil + } +} + func checkSenderAddress(writeModel *InstanceSMTPConfigWriteModel) error { if !writeModel.smtpSenderAddressMatchesInstanceDomain { return nil diff --git a/internal/command/smtp_test.go b/internal/command/smtp_test.go index 6158ea90ec..9806c8c9c7 100644 --- a/internal/command/smtp_test.go +++ b/internal/command/smtp_test.go @@ -554,6 +554,101 @@ func TestCommandSide_ChangeSMTPConfigPassword(t *testing.T) { } } +func TestCommandSide_RemoveSMTPConfig(t *testing.T) { + type fields struct { + eventstore *eventstore.Eventstore + alg crypto.EncryptionAlgorithm + } + type args struct { + ctx context.Context + } + type res struct { + want *domain.ObjectDetails + err func(error) bool + } + tests := []struct { + name string + fields fields + args args + res res + }{ + { + name: "smtp config, error not found", + fields: fields{ + eventstore: eventstoreExpect( + t, + expectFilter(), + ), + }, + args: args{ + ctx: context.Background(), + }, + res: res{ + err: caos_errs.IsNotFound, + }, + }, + { + name: "remove smtp config, ok", + fields: fields{ + eventstore: eventstoreExpect( + t, + expectFilter( + eventFromEventPusher( + instance.NewSMTPConfigAddedEvent( + context.Background(), + &instance.NewAggregate("INSTANCE").Aggregate, + true, + "from", + "name", + "host", + "user", + &crypto.CryptoValue{}, + ), + ), + ), + expectPush( + []*repository.Event{ + eventFromEventPusherWithInstanceID( + "INSTANCE", + instance.NewSMTPConfigRemovedEvent( + context.Background(), + &instance.NewAggregate("INSTANCE").Aggregate, + ), + ), + }, + ), + ), + }, + args: args{ + ctx: authz.WithInstanceID(context.Background(), "INSTANCE"), + }, + res: res{ + want: &domain.ObjectDetails{ + ResourceOwner: "INSTANCE", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + r := &Commands{ + eventstore: tt.fields.eventstore, + smtpEncryption: tt.fields.alg, + } + got, err := r.RemoveSMTPConfig(tt.args.ctx) + 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) + } + if tt.res.err == nil { + assert.Equal(t, tt.res.want, got) + } + }) + } +} + func newSMTPConfigChangedEvent(ctx context.Context, tls bool, fromAddress, fromName, host, user string) *instance.SMTPConfigChangedEvent { changes := []instance.SMTPConfigChanges{ instance.ChangeSMTPConfigTLS(tls), diff --git a/internal/domain/smtp.go b/internal/domain/smtp.go index aa190ab076..02460ca8b2 100644 --- a/internal/domain/smtp.go +++ b/internal/domain/smtp.go @@ -5,4 +5,5 @@ type SMTPConfigState int32 const ( SMTPConfigStateUnspecified SMTPConfigState = iota SMTPConfigStateActive + SMTPConfigStateRemoved ) diff --git a/internal/repository/instance/eventstore.go b/internal/repository/instance/eventstore.go index 6778e0c503..1365a67ebb 100644 --- a/internal/repository/instance/eventstore.go +++ b/internal/repository/instance/eventstore.go @@ -15,6 +15,7 @@ func RegisterEventMappers(es *eventstore.Eventstore) { RegisterFilterEventMapper(SMTPConfigAddedEventType, SMTPConfigAddedEventMapper). RegisterFilterEventMapper(SMTPConfigChangedEventType, SMTPConfigChangedEventMapper). RegisterFilterEventMapper(SMTPConfigPasswordChangedEventType, SMTPConfigPasswordChangedEventMapper). + RegisterFilterEventMapper(SMTPConfigRemovedEventType, SMTPConfigRemovedEventMapper). RegisterFilterEventMapper(SMSConfigTwilioAddedEventType, SMSConfigTwilioAddedEventMapper). RegisterFilterEventMapper(SMSConfigTwilioChangedEventType, SMSConfigTwilioChangedEventMapper). RegisterFilterEventMapper(SMSConfigTwilioTokenChangedEventType, SMSConfigTwilioTokenChangedEventMapper). diff --git a/internal/repository/instance/smtp_config.go b/internal/repository/instance/smtp_config.go index 7feeb441b7..dc93f80820 100644 --- a/internal/repository/instance/smtp_config.go +++ b/internal/repository/instance/smtp_config.go @@ -15,6 +15,7 @@ const ( SMTPConfigAddedEventType = instanceEventTypePrefix + smtpConfigPrefix + "added" SMTPConfigChangedEventType = instanceEventTypePrefix + smtpConfigPrefix + "changed" SMTPConfigPasswordChangedEventType = instanceEventTypePrefix + smtpConfigPrefix + "password.changed" + SMTPConfigRemovedEventType = instanceEventTypePrefix + smtpConfigPrefix + "removed" ) type SMTPConfigAddedEvent struct { @@ -197,3 +198,40 @@ func SMTPConfigPasswordChangedEventMapper(event *repository.Event) (eventstore.E return smtpConfigPasswordChagned, nil } + +type SMTPConfigRemovedEvent struct { + eventstore.BaseEvent `json:"-"` +} + +func NewSMTPConfigRemovedEvent( + ctx context.Context, + aggregate *eventstore.Aggregate, +) *SMTPConfigRemovedEvent { + return &SMTPConfigRemovedEvent{ + BaseEvent: *eventstore.NewBaseEventForPush( + ctx, + aggregate, + SMTPConfigRemovedEventType, + ), + } +} + +func (e *SMTPConfigRemovedEvent) Data() interface{} { + return e +} + +func (e *SMTPConfigRemovedEvent) UniqueConstraints() []*eventstore.EventUniqueConstraint { + return nil +} + +func SMTPConfigRemovedEventMapper(event *repository.Event) (eventstore.Event, error) { + smtpConfigRemoved := &SMTPConfigRemovedEvent{ + BaseEvent: *eventstore.BaseEventFromRepo(event), + } + err := json.Unmarshal(event.Data, smtpConfigRemoved) + if err != nil { + return nil, errors.ThrowInternal(err, "IAM-DVw1s", "unable to unmarshal smtp config removed") + } + + return smtpConfigRemoved, nil +} diff --git a/proto/zitadel/admin.proto b/proto/zitadel/admin.proto index 4254784041..8f2f925fd1 100644 --- a/proto/zitadel/admin.proto +++ b/proto/zitadel/admin.proto @@ -237,6 +237,18 @@ service AdminService { }; } + // Add system smtp configuration + rpc AddSMTPConfig(AddSMTPConfigRequest) returns (AddSMTPConfigResponse) { + option (google.api.http) = { + post: "/smtp"; + body: "*" + }; + + option (zitadel.v1.auth_option) = { + permission: "iam.write"; + }; + } + // Update system smtp configuration rpc UpdateSMTPConfig(UpdateSMTPConfigRequest) returns (UpdateSMTPConfigResponse) { option (google.api.http) = { @@ -261,6 +273,17 @@ service AdminService { }; } + // Remove system smtp configuration + rpc RemoveSMTPConfig(RemoveSMTPConfigRequest) returns (RemoveSMTPConfigResponse) { + option (google.api.http) = { + delete: "/smtp"; + }; + + option (zitadel.v1.auth_option) = { + permission: "iam.write"; + }; + } + // list sms provider configurations rpc ListSMSProviders(ListSMSProvidersRequest) returns (ListSMSProvidersResponse) { option (google.api.http) = { @@ -320,6 +343,17 @@ service AdminService { }; } + // Remove sms provider token + rpc RemoveSMSProvider(RemoveSMSProviderRequest) returns (RemoveSMSProviderResponse) { + option (google.api.http) = { + delete: "/sms/{id}"; + }; + + option (zitadel.v1.auth_option) = { + permission: "iam.write"; + }; + } + // Get OIDC settings (e.g token lifetimes, etc.) rpc GetOIDCSettings(GetOIDCSettingsRequest) returns (GetOIDCSettingsResponse) { option (google.api.http) = { @@ -2661,6 +2695,19 @@ message GetSMTPConfigResponse { zitadel.settings.v1.SMTPConfig smtp_config = 1; } +message AddSMTPConfigRequest { + string sender_address = 1 [(validate.rules).string = {min_len: 1, max_len: 200}]; + string sender_name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}]; + bool tls = 3; + string host = 4 [(validate.rules).string = {min_len: 1, max_len: 500}]; + string user = 5; + string password = 6; +} + +message AddSMTPConfigResponse { + zitadel.v1.ObjectDetails details = 1; +} + message UpdateSMTPConfigRequest { string sender_address = 1 [(validate.rules).string = {min_len: 1, max_len: 200}]; string sender_name = 2 [(validate.rules).string = {min_len: 1, max_len: 200}]; @@ -2681,6 +2728,13 @@ message UpdateSMTPConfigPasswordResponse { zitadel.v1.ObjectDetails details = 1; } +//this is en empty request +message RemoveSMTPConfigRequest {} + +message RemoveSMTPConfigResponse { + zitadel.v1.ObjectDetails details = 1; +} + message ListSMSProvidersRequest { //list limitations and ordering zitadel.v1.ListQuery query = 1; @@ -2729,6 +2783,14 @@ message UpdateSMSProviderTwilioTokenResponse { zitadel.v1.ObjectDetails details = 1; } +message RemoveSMSProviderRequest { + string id = 1 [(validate.rules).string = {min_len: 1, max_len: 200}]; +} + +message RemoveSMSProviderResponse { + zitadel.v1.ObjectDetails details = 1; +} + //This is an empty request message GetFileSystemNotificationProviderRequest {}