UI: Add JWT security settings form and restyle security page
This commit is contained in:
		
							parent
							
								
									b776cf13b6
								
							
						
					
					
						commit
						fc1da12999
					
				@ -20,16 +20,18 @@ import { Observable } from 'rxjs';
 | 
				
			|||||||
import { HttpClient } from '@angular/common/http';
 | 
					import { HttpClient } from '@angular/common/http';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
  AdminSettings,
 | 
					  AdminSettings,
 | 
				
			||||||
  RepositorySettings,
 | 
					  AutoCommitSettings,
 | 
				
			||||||
 | 
					  JwtSettings,
 | 
				
			||||||
  MailServerSettings,
 | 
					  MailServerSettings,
 | 
				
			||||||
 | 
					  RepositorySettings,
 | 
				
			||||||
 | 
					  RepositorySettingsInfo,
 | 
				
			||||||
  SecuritySettings,
 | 
					  SecuritySettings,
 | 
				
			||||||
  TestSmsRequest,
 | 
					  TestSmsRequest,
 | 
				
			||||||
  UpdateMessage,
 | 
					  UpdateMessage
 | 
				
			||||||
  AutoCommitSettings,
 | 
					 | 
				
			||||||
  RepositorySettingsInfo
 | 
					 | 
				
			||||||
} from '@shared/models/settings.models';
 | 
					} from '@shared/models/settings.models';
 | 
				
			||||||
import { EntitiesVersionControlService } from '@core/http/entities-version-control.service';
 | 
					import { EntitiesVersionControlService } from '@core/http/entities-version-control.service';
 | 
				
			||||||
import { tap } from 'rxjs/operators';
 | 
					import { tap } from 'rxjs/operators';
 | 
				
			||||||
 | 
					import { LoginResponse } from '@shared/models/login.models';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Injectable({
 | 
					@Injectable({
 | 
				
			||||||
  providedIn: 'root'
 | 
					  providedIn: 'root'
 | 
				
			||||||
@ -70,6 +72,14 @@ export class AdminService {
 | 
				
			|||||||
      defaultHttpOptionsFromConfig(config));
 | 
					      defaultHttpOptionsFromConfig(config));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public getJwtSettings(config?: RequestConfig): Observable<JwtSettings> {
 | 
				
			||||||
 | 
					    return this.http.get<JwtSettings>(`/api/admin/jwtSettings`, defaultHttpOptionsFromConfig(config));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public saveJwtSettings(jwtSettings: JwtSettings, config?: RequestConfig): Observable<LoginResponse> {
 | 
				
			||||||
 | 
					    return this.http.post<LoginResponse>('/api/admin/jwtSettings', jwtSettings, defaultHttpOptionsFromConfig(config));
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public getRepositorySettings(config?: RequestConfig): Observable<RepositorySettings> {
 | 
					  public getRepositorySettings(config?: RequestConfig): Observable<RepositorySettings> {
 | 
				
			||||||
    return this.http.get<RepositorySettings>(`/api/admin/repositorySettings`, defaultHttpOptionsFromConfig(config));
 | 
					    return this.http.get<RepositorySettings>(`/api/admin/repositorySettings`, defaultHttpOptionsFromConfig(config));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
				
			|||||||
@ -15,144 +15,237 @@
 | 
				
			|||||||
    limitations under the License.
 | 
					    limitations under the License.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
-->
 | 
					-->
 | 
				
			||||||
<div>
 | 
					<mat-card class="settings-card">
 | 
				
			||||||
  <mat-card class="settings-card">
 | 
					  <mat-card-title>
 | 
				
			||||||
    <mat-card-title>
 | 
					    <div fxLayout="row">
 | 
				
			||||||
      <div fxLayout="row">
 | 
					      <span class="mat-headline" translate>admin.security-settings</span>
 | 
				
			||||||
        <span class="mat-headline" translate>admin.security-settings</span>
 | 
					      <span fxFlex></span>
 | 
				
			||||||
        <span fxFlex></span>
 | 
					      <div tb-help="securitySettings"></div>
 | 
				
			||||||
        <div tb-help="securitySettings"></div>
 | 
					    </div>
 | 
				
			||||||
      </div>
 | 
					  </mat-card-title>
 | 
				
			||||||
    </mat-card-title>
 | 
					  <mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
 | 
				
			||||||
    <mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
 | 
					  </mat-progress-bar>
 | 
				
			||||||
    </mat-progress-bar>
 | 
					  <div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
 | 
				
			||||||
    <div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
 | 
					  <mat-card-content style="padding-top: 16px;">
 | 
				
			||||||
    <mat-card-content style="padding-top: 16px;">
 | 
					    <form [formGroup]="securitySettingsFormGroup" (ngSubmit)="save()" autocomplete="off">
 | 
				
			||||||
      <form [formGroup]="securitySettingsFormGroup" (ngSubmit)="save()" autocomplete="off">
 | 
					      <fieldset [disabled]="isLoading$ | async">
 | 
				
			||||||
        <fieldset [disabled]="isLoading$ | async">
 | 
					        <fieldset class="fields-group">
 | 
				
			||||||
          <div class="mat-accordion-container">
 | 
					          <legend class="group-title" translate>admin.general-policy</legend>
 | 
				
			||||||
            <mat-accordion multi="true">
 | 
					          <mat-form-field class="mat-block">
 | 
				
			||||||
              <mat-expansion-panel [expanded]="true">
 | 
					            <mat-label translate>admin.max-failed-login-attempts</mat-label>
 | 
				
			||||||
                <mat-expansion-panel-header>
 | 
					            <input matInput type="number"
 | 
				
			||||||
                  <mat-panel-title>
 | 
					                   formControlName="maxFailedLoginAttempts"
 | 
				
			||||||
                    <div class="tb-panel-title" translate>admin.general-policy</div>
 | 
					                   step="1"
 | 
				
			||||||
                  </mat-panel-title>
 | 
					                   min="0"/>
 | 
				
			||||||
                </mat-expansion-panel-header>
 | 
					            <mat-error *ngIf="securitySettingsFormGroup.get('maxFailedLoginAttempts').hasError('min')">
 | 
				
			||||||
                <mat-form-field class="mat-block">
 | 
					              {{ 'admin.minimum-max-failed-login-attempts-range' | translate }}
 | 
				
			||||||
                  <mat-label translate>admin.max-failed-login-attempts</mat-label>
 | 
					            </mat-error>
 | 
				
			||||||
                  <input matInput type="number"
 | 
					          </mat-form-field>
 | 
				
			||||||
                         formControlName="maxFailedLoginAttempts"
 | 
					          <mat-form-field class="mat-block">
 | 
				
			||||||
                         step="1"
 | 
					            <mat-label translate>admin.user-lockout-notification-email</mat-label>
 | 
				
			||||||
                         min="0"/>
 | 
					            <input matInput type="email"
 | 
				
			||||||
                  <mat-error *ngIf="securitySettingsFormGroup.get('maxFailedLoginAttempts').hasError('min')">
 | 
					                   formControlName="userLockoutNotificationEmail"/>
 | 
				
			||||||
                    {{ 'admin.minimum-max-failed-login-attempts-range' | translate }}
 | 
					          </mat-form-field>
 | 
				
			||||||
                  </mat-error>
 | 
					 | 
				
			||||||
                </mat-form-field>
 | 
					 | 
				
			||||||
                <mat-form-field class="mat-block">
 | 
					 | 
				
			||||||
                  <mat-label translate>admin.user-lockout-notification-email</mat-label>
 | 
					 | 
				
			||||||
                  <input matInput type="email"
 | 
					 | 
				
			||||||
                         formControlName="userLockoutNotificationEmail"/>
 | 
					 | 
				
			||||||
                </mat-form-field>
 | 
					 | 
				
			||||||
              </mat-expansion-panel>
 | 
					 | 
				
			||||||
              <mat-expansion-panel [expanded]="true">
 | 
					 | 
				
			||||||
                <mat-expansion-panel-header>
 | 
					 | 
				
			||||||
                  <mat-panel-title>
 | 
					 | 
				
			||||||
                    <div class="tb-panel-title" translate>admin.password-policy</div>
 | 
					 | 
				
			||||||
                  </mat-panel-title>
 | 
					 | 
				
			||||||
                </mat-expansion-panel-header>
 | 
					 | 
				
			||||||
                <section formGroupName="passwordPolicy">
 | 
					 | 
				
			||||||
                  <mat-form-field class="mat-block">
 | 
					 | 
				
			||||||
                    <mat-label translate>admin.minimum-password-length</mat-label>
 | 
					 | 
				
			||||||
                    <input matInput type="number"
 | 
					 | 
				
			||||||
                           formControlName="minimumLength"
 | 
					 | 
				
			||||||
                           step="1"
 | 
					 | 
				
			||||||
                           min="5"
 | 
					 | 
				
			||||||
                           max="50"
 | 
					 | 
				
			||||||
                           required/>
 | 
					 | 
				
			||||||
                    <mat-error *ngIf="securitySettingsFormGroup.get('passwordPolicy.minimumLength').hasError('required')">
 | 
					 | 
				
			||||||
                      {{ 'admin.minimum-password-length-required' | translate }}
 | 
					 | 
				
			||||||
                    </mat-error>
 | 
					 | 
				
			||||||
                    <mat-error *ngIf="securitySettingsFormGroup.get('passwordPolicy.minimumLength').hasError('min')">
 | 
					 | 
				
			||||||
                      {{ 'admin.minimum-password-length-range' | translate }}
 | 
					 | 
				
			||||||
                    </mat-error>
 | 
					 | 
				
			||||||
                    <mat-error *ngIf="securitySettingsFormGroup.get('passwordPolicy.minimumLength').hasError('max')">
 | 
					 | 
				
			||||||
                      {{ 'admin.minimum-password-length-range' | translate }}
 | 
					 | 
				
			||||||
                    </mat-error>
 | 
					 | 
				
			||||||
                  </mat-form-field>
 | 
					 | 
				
			||||||
                  <mat-form-field class="mat-block">
 | 
					 | 
				
			||||||
                    <mat-label translate>admin.minimum-uppercase-letters</mat-label>
 | 
					 | 
				
			||||||
                    <input matInput type="number"
 | 
					 | 
				
			||||||
                           formControlName="minimumUppercaseLetters"
 | 
					 | 
				
			||||||
                           step="1"
 | 
					 | 
				
			||||||
                           min="0"/>
 | 
					 | 
				
			||||||
                    <mat-error *ngIf="securitySettingsFormGroup.get('passwordPolicy.minimumUppercaseLetters').hasError('min')">
 | 
					 | 
				
			||||||
                      {{ 'admin.minimum-uppercase-letters-range' | translate }}
 | 
					 | 
				
			||||||
                    </mat-error>
 | 
					 | 
				
			||||||
                  </mat-form-field>
 | 
					 | 
				
			||||||
                  <mat-form-field class="mat-block">
 | 
					 | 
				
			||||||
                    <mat-label translate>admin.minimum-lowercase-letters</mat-label>
 | 
					 | 
				
			||||||
                    <input matInput type="number"
 | 
					 | 
				
			||||||
                           formControlName="minimumLowercaseLetters"
 | 
					 | 
				
			||||||
                           step="1"
 | 
					 | 
				
			||||||
                           min="0"/>
 | 
					 | 
				
			||||||
                    <mat-error *ngIf="securitySettingsFormGroup.get('passwordPolicy.minimumLowercaseLetters').hasError('min')">
 | 
					 | 
				
			||||||
                      {{ 'admin.minimum-lowercase-letters-range' | translate }}
 | 
					 | 
				
			||||||
                    </mat-error>
 | 
					 | 
				
			||||||
                  </mat-form-field>
 | 
					 | 
				
			||||||
                  <mat-form-field class="mat-block">
 | 
					 | 
				
			||||||
                    <mat-label translate>admin.minimum-digits</mat-label>
 | 
					 | 
				
			||||||
                    <input matInput type="number"
 | 
					 | 
				
			||||||
                           formControlName="minimumDigits"
 | 
					 | 
				
			||||||
                           step="1"
 | 
					 | 
				
			||||||
                           min="0"/>
 | 
					 | 
				
			||||||
                    <mat-error *ngIf="securitySettingsFormGroup.get('passwordPolicy.minimumDigits').hasError('min')">
 | 
					 | 
				
			||||||
                      {{ 'admin.minimum-digits-range' | translate }}
 | 
					 | 
				
			||||||
                    </mat-error>
 | 
					 | 
				
			||||||
                  </mat-form-field>
 | 
					 | 
				
			||||||
                  <mat-form-field class="mat-block">
 | 
					 | 
				
			||||||
                    <mat-label translate>admin.minimum-special-characters</mat-label>
 | 
					 | 
				
			||||||
                    <input matInput type="number"
 | 
					 | 
				
			||||||
                           formControlName="minimumSpecialCharacters"
 | 
					 | 
				
			||||||
                           step="1"
 | 
					 | 
				
			||||||
                           min="0"/>
 | 
					 | 
				
			||||||
                    <mat-error *ngIf="securitySettingsFormGroup.get('passwordPolicy.minimumSpecialCharacters').hasError('min')">
 | 
					 | 
				
			||||||
                      {{ 'admin.minimum-special-characters-range' | translate }}
 | 
					 | 
				
			||||||
                    </mat-error>
 | 
					 | 
				
			||||||
                  </mat-form-field>
 | 
					 | 
				
			||||||
                  <mat-form-field class="mat-block">
 | 
					 | 
				
			||||||
                    <mat-label translate>admin.password-expiration-period-days</mat-label>
 | 
					 | 
				
			||||||
                    <input matInput type="number"
 | 
					 | 
				
			||||||
                           formControlName="passwordExpirationPeriodDays"
 | 
					 | 
				
			||||||
                           step="1"
 | 
					 | 
				
			||||||
                           min="0"/>
 | 
					 | 
				
			||||||
                    <mat-error *ngIf="securitySettingsFormGroup.get('passwordPolicy.passwordExpirationPeriodDays').hasError('min')">
 | 
					 | 
				
			||||||
                      {{ 'admin.password-expiration-period-days-range' | translate }}
 | 
					 | 
				
			||||||
                    </mat-error>
 | 
					 | 
				
			||||||
                  </mat-form-field>
 | 
					 | 
				
			||||||
                  <mat-form-field class="mat-block">
 | 
					 | 
				
			||||||
                    <mat-label translate>admin.password-reuse-frequency-days</mat-label>
 | 
					 | 
				
			||||||
                    <input matInput type="number"
 | 
					 | 
				
			||||||
                           formControlName="passwordReuseFrequencyDays"
 | 
					 | 
				
			||||||
                           step="1"
 | 
					 | 
				
			||||||
                           min="0"/>
 | 
					 | 
				
			||||||
                    <mat-error *ngIf="securitySettingsFormGroup.get('passwordPolicy.passwordReuseFrequencyDays').hasError('min')">
 | 
					 | 
				
			||||||
                      {{ 'admin.password-reuse-frequency-days-range' | translate }}
 | 
					 | 
				
			||||||
                    </mat-error>
 | 
					 | 
				
			||||||
                  </mat-form-field>
 | 
					 | 
				
			||||||
                  <mat-checkbox formControlName = "allowWhitespaces" >
 | 
					 | 
				
			||||||
                    <mat-label translate>admin.allow-whitespace</mat-label>
 | 
					 | 
				
			||||||
                  </mat-checkbox>
 | 
					 | 
				
			||||||
                </section>
 | 
					 | 
				
			||||||
              </mat-expansion-panel>
 | 
					 | 
				
			||||||
            </mat-accordion>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
          <div fxLayout="row" fxLayoutAlign="end center" style="width: 100%;" class="layout-wrap">
 | 
					 | 
				
			||||||
            <button mat-button mat-raised-button color="primary" [disabled]="(isLoading$ | async) || securitySettingsFormGroup.invalid || !securitySettingsFormGroup.dirty"
 | 
					 | 
				
			||||||
                    type="submit">{{'action.save' | translate}}
 | 
					 | 
				
			||||||
            </button>
 | 
					 | 
				
			||||||
          </div>
 | 
					 | 
				
			||||||
        </fieldset>
 | 
					        </fieldset>
 | 
				
			||||||
      </form>
 | 
					
 | 
				
			||||||
    </mat-card-content>
 | 
					        <fieldset class="fields-group">
 | 
				
			||||||
  </mat-card>
 | 
					          <legend class="group-title" translate>admin.password-policy</legend>
 | 
				
			||||||
</div>
 | 
					          <section formGroupName="passwordPolicy">
 | 
				
			||||||
 | 
					            <mat-form-field class="mat-block">
 | 
				
			||||||
 | 
					              <mat-label translate>admin.minimum-password-length</mat-label>
 | 
				
			||||||
 | 
					              <input matInput type="number"
 | 
				
			||||||
 | 
					                     formControlName="minimumLength"
 | 
				
			||||||
 | 
					                     step="1"
 | 
				
			||||||
 | 
					                     min="5"
 | 
				
			||||||
 | 
					                     max="50"
 | 
				
			||||||
 | 
					                     required/>
 | 
				
			||||||
 | 
					              <mat-error *ngIf="securitySettingsFormGroup.get('passwordPolicy.minimumLength').hasError('required')">
 | 
				
			||||||
 | 
					                {{ 'admin.minimum-password-length-required' | translate }}
 | 
				
			||||||
 | 
					              </mat-error>
 | 
				
			||||||
 | 
					              <mat-error *ngIf="securitySettingsFormGroup.get('passwordPolicy.minimumLength').hasError('min')">
 | 
				
			||||||
 | 
					                {{ 'admin.minimum-password-length-range' | translate }}
 | 
				
			||||||
 | 
					              </mat-error>
 | 
				
			||||||
 | 
					              <mat-error *ngIf="securitySettingsFormGroup.get('passwordPolicy.minimumLength').hasError('max')">
 | 
				
			||||||
 | 
					                {{ 'admin.minimum-password-length-range' | translate }}
 | 
				
			||||||
 | 
					              </mat-error>
 | 
				
			||||||
 | 
					            </mat-form-field>
 | 
				
			||||||
 | 
					            <div fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
 | 
				
			||||||
 | 
					              <mat-form-field fxFlex class="mat-block">
 | 
				
			||||||
 | 
					                <mat-label translate>admin.minimum-uppercase-letters</mat-label>
 | 
				
			||||||
 | 
					                <input matInput type="number"
 | 
				
			||||||
 | 
					                       formControlName="minimumUppercaseLetters"
 | 
				
			||||||
 | 
					                       step="1"
 | 
				
			||||||
 | 
					                       min="0"/>
 | 
				
			||||||
 | 
					                <mat-error
 | 
				
			||||||
 | 
					                  *ngIf="securitySettingsFormGroup.get('passwordPolicy.minimumUppercaseLetters').hasError('min')">
 | 
				
			||||||
 | 
					                  {{ 'admin.minimum-uppercase-letters-range' | translate }}
 | 
				
			||||||
 | 
					                </mat-error>
 | 
				
			||||||
 | 
					              </mat-form-field>
 | 
				
			||||||
 | 
					              <mat-form-field fxFlex class="mat-block">
 | 
				
			||||||
 | 
					                <mat-label translate>admin.minimum-lowercase-letters</mat-label>
 | 
				
			||||||
 | 
					                <input matInput type="number"
 | 
				
			||||||
 | 
					                       formControlName="minimumLowercaseLetters"
 | 
				
			||||||
 | 
					                       step="1"
 | 
				
			||||||
 | 
					                       min="0"/>
 | 
				
			||||||
 | 
					                <mat-error
 | 
				
			||||||
 | 
					                  *ngIf="securitySettingsFormGroup.get('passwordPolicy.minimumLowercaseLetters').hasError('min')">
 | 
				
			||||||
 | 
					                  {{ 'admin.minimum-lowercase-letters-range' | translate }}
 | 
				
			||||||
 | 
					                </mat-error>
 | 
				
			||||||
 | 
					              </mat-form-field>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
 | 
				
			||||||
 | 
					              <mat-form-field fxFlex class="mat-block">
 | 
				
			||||||
 | 
					                <mat-label translate>admin.minimum-digits</mat-label>
 | 
				
			||||||
 | 
					                <input matInput type="number"
 | 
				
			||||||
 | 
					                       formControlName="minimumDigits"
 | 
				
			||||||
 | 
					                       step="1"
 | 
				
			||||||
 | 
					                       min="0"/>
 | 
				
			||||||
 | 
					                <mat-error *ngIf="securitySettingsFormGroup.get('passwordPolicy.minimumDigits').hasError('min')">
 | 
				
			||||||
 | 
					                  {{ 'admin.minimum-digits-range' | translate }}
 | 
				
			||||||
 | 
					                </mat-error>
 | 
				
			||||||
 | 
					              </mat-form-field>
 | 
				
			||||||
 | 
					              <mat-form-field fxFlex class="mat-block">
 | 
				
			||||||
 | 
					                <mat-label translate>admin.minimum-special-characters</mat-label>
 | 
				
			||||||
 | 
					                <input matInput type="number"
 | 
				
			||||||
 | 
					                       formControlName="minimumSpecialCharacters"
 | 
				
			||||||
 | 
					                       step="1"
 | 
				
			||||||
 | 
					                       min="0"/>
 | 
				
			||||||
 | 
					                <mat-error
 | 
				
			||||||
 | 
					                  *ngIf="securitySettingsFormGroup.get('passwordPolicy.minimumSpecialCharacters').hasError('min')">
 | 
				
			||||||
 | 
					                  {{ 'admin.minimum-special-characters-range' | translate }}
 | 
				
			||||||
 | 
					                </mat-error>
 | 
				
			||||||
 | 
					              </mat-form-field>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <div fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
 | 
				
			||||||
 | 
					              <mat-form-field fxFlex class="mat-block">
 | 
				
			||||||
 | 
					                <mat-label translate>admin.password-expiration-period-days</mat-label>
 | 
				
			||||||
 | 
					                <input matInput type="number"
 | 
				
			||||||
 | 
					                       formControlName="passwordExpirationPeriodDays"
 | 
				
			||||||
 | 
					                       step="1"
 | 
				
			||||||
 | 
					                       min="0"/>
 | 
				
			||||||
 | 
					                <mat-error
 | 
				
			||||||
 | 
					                  *ngIf="securitySettingsFormGroup.get('passwordPolicy.passwordExpirationPeriodDays').hasError('min')">
 | 
				
			||||||
 | 
					                  {{ 'admin.password-expiration-period-days-range' | translate }}
 | 
				
			||||||
 | 
					                </mat-error>
 | 
				
			||||||
 | 
					              </mat-form-field>
 | 
				
			||||||
 | 
					              <mat-form-field fxFlex class="mat-block">
 | 
				
			||||||
 | 
					                <mat-label translate>admin.password-reuse-frequency-days</mat-label>
 | 
				
			||||||
 | 
					                <input matInput type="number"
 | 
				
			||||||
 | 
					                       formControlName="passwordReuseFrequencyDays"
 | 
				
			||||||
 | 
					                       step="1"
 | 
				
			||||||
 | 
					                       min="0"/>
 | 
				
			||||||
 | 
					                <mat-error
 | 
				
			||||||
 | 
					                  *ngIf="securitySettingsFormGroup.get('passwordPolicy.passwordReuseFrequencyDays').hasError('min')">
 | 
				
			||||||
 | 
					                  {{ 'admin.password-reuse-frequency-days-range' | translate }}
 | 
				
			||||||
 | 
					                </mat-error>
 | 
				
			||||||
 | 
					              </mat-form-field>
 | 
				
			||||||
 | 
					            </div>
 | 
				
			||||||
 | 
					            <mat-checkbox formControlName="allowWhitespaces" style="margin-bottom: 16px">
 | 
				
			||||||
 | 
					              <mat-label translate>admin.allow-whitespace</mat-label>
 | 
				
			||||||
 | 
					            </mat-checkbox>
 | 
				
			||||||
 | 
					          </section>
 | 
				
			||||||
 | 
					        </fieldset>
 | 
				
			||||||
 | 
					        <div fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="8px" class="layout-wrap" style="margin-top: 16px">
 | 
				
			||||||
 | 
					          <button mat-button color="primary"
 | 
				
			||||||
 | 
					                  [disabled]="securitySettingsFormGroup.pristine"
 | 
				
			||||||
 | 
					                  (click)="discardSetting()"
 | 
				
			||||||
 | 
					                  type="button">{{'action.undo' | translate}}
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <button mat-button mat-raised-button color="primary" [disabled]="(isLoading$ | async) || securitySettingsFormGroup.invalid || !securitySettingsFormGroup.dirty"
 | 
				
			||||||
 | 
					                  type="submit">{{'action.save' | translate}}
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </fieldset>
 | 
				
			||||||
 | 
					    </form>
 | 
				
			||||||
 | 
					  </mat-card-content>
 | 
				
			||||||
 | 
					</mat-card>
 | 
				
			||||||
 | 
					<mat-card class="settings-card">
 | 
				
			||||||
 | 
					  <mat-card-title>
 | 
				
			||||||
 | 
					    <div fxLayout="row">
 | 
				
			||||||
 | 
					      <span class="mat-headline" translate>admin.jwt.security-settings</span>
 | 
				
			||||||
 | 
					    </div>
 | 
				
			||||||
 | 
					  </mat-card-title>
 | 
				
			||||||
 | 
					  <mat-progress-bar color="warn" mode="indeterminate" *ngIf="isLoading$ | async">
 | 
				
			||||||
 | 
					  </mat-progress-bar>
 | 
				
			||||||
 | 
					  <div style="height: 4px;" *ngIf="!(isLoading$ | async)"></div>
 | 
				
			||||||
 | 
					  <mat-card-content style="padding-top: 16px;">
 | 
				
			||||||
 | 
					    <form [formGroup]="jwtSecuritySettingsFormGroup" (ngSubmit)="saveJwtSettings()" autocomplete="off">
 | 
				
			||||||
 | 
					      <fieldset [disabled]="isLoading$ | async">
 | 
				
			||||||
 | 
					        <div fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
 | 
				
			||||||
 | 
					          <mat-form-field fxFlex class="mat-block">
 | 
				
			||||||
 | 
					            <mat-label translate>admin.jwt.issuer-name</mat-label>
 | 
				
			||||||
 | 
					            <input matInput required formControlName="tokenIssuer"/>
 | 
				
			||||||
 | 
					            <mat-error *ngIf="jwtSecuritySettingsFormGroup.get('tokenIssuer').hasError('required')">
 | 
				
			||||||
 | 
					              {{ 'admin.jwt.issuer-name-required' | translate }}
 | 
				
			||||||
 | 
					            </mat-error>
 | 
				
			||||||
 | 
					          </mat-form-field>
 | 
				
			||||||
 | 
					          <mat-form-field fxFlex class="mat-block">
 | 
				
			||||||
 | 
					            <mat-label translate>admin.jwt.signings-key</mat-label>
 | 
				
			||||||
 | 
					            <input matInput required formControlName="tokenSigningKey"/>
 | 
				
			||||||
 | 
					            <button type="button"
 | 
				
			||||||
 | 
					                    matSuffix
 | 
				
			||||||
 | 
					                    mat-button
 | 
				
			||||||
 | 
					                    (click)="generateSigningKey()"
 | 
				
			||||||
 | 
					                    color="primary">
 | 
				
			||||||
 | 
					              {{ 'admin.jwt.generate-key' | translate }}
 | 
				
			||||||
 | 
					            </button>
 | 
				
			||||||
 | 
					            <mat-error *ngIf="jwtSecuritySettingsFormGroup.get('tokenSigningKey').hasError('required')">
 | 
				
			||||||
 | 
					              {{ 'admin.jwt.signings-key-required' | translate }}
 | 
				
			||||||
 | 
					            </mat-error>
 | 
				
			||||||
 | 
					            <mat-error *ngIf="jwtSecuritySettingsFormGroup.get('tokenSigningKey').hasError('base64')">
 | 
				
			||||||
 | 
					              {{ 'admin.jwt.signings-key-base64' | translate }}
 | 
				
			||||||
 | 
					            </mat-error>
 | 
				
			||||||
 | 
					          </mat-form-field>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div fxLayout="row" fxLayout.xs="column" fxLayoutGap.gt-xs="8px">
 | 
				
			||||||
 | 
					          <mat-form-field fxFlex class="mat-block">
 | 
				
			||||||
 | 
					            <mat-label translate>admin.jwt.expiration-time</mat-label>
 | 
				
			||||||
 | 
					            <input matInput type="number" required
 | 
				
			||||||
 | 
					                   formControlName="tokenExpirationTime"
 | 
				
			||||||
 | 
					                   step="1"
 | 
				
			||||||
 | 
					                   min="0"/>
 | 
				
			||||||
 | 
					            <mat-error *ngIf="jwtSecuritySettingsFormGroup.get('tokenExpirationTime').hasError('required')">
 | 
				
			||||||
 | 
					              {{ 'admin.jwt.expiration-time-required' | translate }}
 | 
				
			||||||
 | 
					            </mat-error>
 | 
				
			||||||
 | 
					            <mat-error *ngIf="jwtSecuritySettingsFormGroup.get('tokenExpirationTime').hasError('pattern')">
 | 
				
			||||||
 | 
					              {{ 'admin.jwt.expiration-time-pattern' | translate }}
 | 
				
			||||||
 | 
					            </mat-error>
 | 
				
			||||||
 | 
					            <mat-error *ngIf="jwtSecuritySettingsFormGroup.get('tokenExpirationTime').hasError('min')">
 | 
				
			||||||
 | 
					              {{ 'admin.jwt.expiration-time-min' | translate }}
 | 
				
			||||||
 | 
					            </mat-error>
 | 
				
			||||||
 | 
					          </mat-form-field>
 | 
				
			||||||
 | 
					          <mat-form-field fxFlex class="mat-block">
 | 
				
			||||||
 | 
					            <mat-label translate>admin.jwt.refresh-expiration-time</mat-label>
 | 
				
			||||||
 | 
					            <input matInput type="number" required
 | 
				
			||||||
 | 
					                   formControlName="refreshTokenExpTime"
 | 
				
			||||||
 | 
					                   step="1"
 | 
				
			||||||
 | 
					                   min="0"/>
 | 
				
			||||||
 | 
					            <mat-error *ngIf="jwtSecuritySettingsFormGroup.get('refreshTokenExpTime').hasError('required')">
 | 
				
			||||||
 | 
					              {{ 'admin.jwt.refresh-expiration-time-required' | translate }}
 | 
				
			||||||
 | 
					            </mat-error>
 | 
				
			||||||
 | 
					            <mat-error *ngIf="jwtSecuritySettingsFormGroup.get('refreshTokenExpTime').hasError('pattern')">
 | 
				
			||||||
 | 
					              {{ 'admin.jwt.refresh-expiration-time-pattern' | translate }}
 | 
				
			||||||
 | 
					            </mat-error>
 | 
				
			||||||
 | 
					            <mat-error *ngIf="jwtSecuritySettingsFormGroup.get('refreshTokenExpTime').hasError('min')">
 | 
				
			||||||
 | 
					              {{ 'admin.jwt.refresh-expiration-time-min' | translate }}
 | 
				
			||||||
 | 
					            </mat-error>
 | 
				
			||||||
 | 
					            <mat-error *ngIf="jwtSecuritySettingsFormGroup.get('refreshTokenExpTime').hasError('lessToken')">
 | 
				
			||||||
 | 
					              {{ 'admin.jwt.refresh-expiration-time-less-token' | translate }}
 | 
				
			||||||
 | 
					            </mat-error>
 | 
				
			||||||
 | 
					          </mat-form-field>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					        <div fxLayout="row" fxLayoutAlign="end center" fxLayoutGap="8px" class="layout-wrap">
 | 
				
			||||||
 | 
					          <button mat-button color="primary"
 | 
				
			||||||
 | 
					                  [disabled]="jwtSecuritySettingsFormGroup.pristine"
 | 
				
			||||||
 | 
					                  (click)="discardJwtSetting()"
 | 
				
			||||||
 | 
					                  type="button">{{'action.undo' | translate}}
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					          <button mat-raised-button color="primary"
 | 
				
			||||||
 | 
					                  [disabled]="(isLoading$ | async) || jwtSecuritySettingsFormGroup.invalid || !jwtSecuritySettingsFormGroup.dirty"
 | 
				
			||||||
 | 
					                  type="submit">{{'action.save' | translate}}
 | 
				
			||||||
 | 
					          </button>
 | 
				
			||||||
 | 
					        </div>
 | 
				
			||||||
 | 
					      </fieldset>
 | 
				
			||||||
 | 
					    </form>
 | 
				
			||||||
 | 
					  </mat-card-content>
 | 
				
			||||||
 | 
					</mat-card>
 | 
				
			||||||
 | 
				
			|||||||
@ -14,7 +14,26 @@
 | 
				
			|||||||
 * limitations under the License.
 | 
					 * limitations under the License.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
:host {
 | 
					:host {
 | 
				
			||||||
  .mat-accordion-container {
 | 
					  .mat-headline {
 | 
				
			||||||
    margin-bottom: 16px;
 | 
					    margin-bottom: 8px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .mat-card-title {
 | 
				
			||||||
 | 
					    margin: 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .mat-card-content {
 | 
				
			||||||
 | 
					    padding: 0 !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .fields-group {
 | 
				
			||||||
 | 
					    padding: 8px 16px 0;
 | 
				
			||||||
 | 
					    margin: 10px 0;
 | 
				
			||||||
 | 
					    border: 1px groove rgba(0, 0, 0, .25);
 | 
				
			||||||
 | 
					    border-radius: 4px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    legend {
 | 
				
			||||||
 | 
					      color: rgba(0, 0, 0, .7);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -14,40 +14,50 @@
 | 
				
			|||||||
/// limitations under the License.
 | 
					/// limitations under the License.
 | 
				
			||||||
///
 | 
					///
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Component, OnInit } from '@angular/core';
 | 
					import { Component } from '@angular/core';
 | 
				
			||||||
import { Store } from '@ngrx/store';
 | 
					import { Store } from '@ngrx/store';
 | 
				
			||||||
import { AppState } from '@core/core.state';
 | 
					import { AppState } from '@core/core.state';
 | 
				
			||||||
import { PageComponent } from '@shared/components/page.component';
 | 
					import { PageComponent } from '@shared/components/page.component';
 | 
				
			||||||
import { Router } from '@angular/router';
 | 
					import { Router } from '@angular/router';
 | 
				
			||||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
 | 
					import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
 | 
				
			||||||
import { SecuritySettings } from '@shared/models/settings.models';
 | 
					import { JwtSettings, SecuritySettings } from '@shared/models/settings.models';
 | 
				
			||||||
import { AdminService } from '@core/http/admin.service';
 | 
					import { AdminService } from '@core/http/admin.service';
 | 
				
			||||||
import { HasConfirmForm } from '@core/guards/confirm-on-exit.guard';
 | 
					import { HasConfirmForm } from '@core/guards/confirm-on-exit.guard';
 | 
				
			||||||
 | 
					import { mergeMap, tap } from 'rxjs/operators';
 | 
				
			||||||
 | 
					import { randomAlphanumeric } from '@core/utils';
 | 
				
			||||||
 | 
					import { AuthService } from '@core/auth/auth.service';
 | 
				
			||||||
 | 
					import { DialogService } from '@core/services/dialog.service';
 | 
				
			||||||
 | 
					import { TranslateService } from '@ngx-translate/core';
 | 
				
			||||||
 | 
					import { Observable, of } from 'rxjs';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  selector: 'tb-security-settings',
 | 
					  selector: 'tb-security-settings',
 | 
				
			||||||
  templateUrl: './security-settings.component.html',
 | 
					  templateUrl: './security-settings.component.html',
 | 
				
			||||||
  styleUrls: ['./security-settings.component.scss', './settings-card.scss']
 | 
					  styleUrls: ['./security-settings.component.scss', './settings-card.scss']
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
export class SecuritySettingsComponent extends PageComponent implements OnInit, HasConfirmForm {
 | 
					export class SecuritySettingsComponent extends PageComponent implements HasConfirmForm {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  securitySettingsFormGroup: FormGroup;
 | 
					  securitySettingsFormGroup: FormGroup;
 | 
				
			||||||
  securitySettings: SecuritySettings;
 | 
					  jwtSecuritySettingsFormGroup: FormGroup;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private securitySettings: SecuritySettings;
 | 
				
			||||||
 | 
					  private jwtSettings: JwtSettings;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constructor(protected store: Store<AppState>,
 | 
					  constructor(protected store: Store<AppState>,
 | 
				
			||||||
              private router: Router,
 | 
					              private router: Router,
 | 
				
			||||||
              private adminService: AdminService,
 | 
					              private adminService: AdminService,
 | 
				
			||||||
              public fb: FormBuilder) {
 | 
					              private authService: AuthService,
 | 
				
			||||||
 | 
					              private dialogService: DialogService,
 | 
				
			||||||
 | 
					              private translate: TranslateService,
 | 
				
			||||||
 | 
					              private fb: FormBuilder) {
 | 
				
			||||||
    super(store);
 | 
					    super(store);
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  ngOnInit() {
 | 
					 | 
				
			||||||
    this.buildSecuritySettingsForm();
 | 
					    this.buildSecuritySettingsForm();
 | 
				
			||||||
 | 
					    this.buildJwtSecuritySettingsForm();
 | 
				
			||||||
    this.adminService.getSecuritySettings().subscribe(
 | 
					    this.adminService.getSecuritySettings().subscribe(
 | 
				
			||||||
      (securitySettings) => {
 | 
					      securitySettings => this.processSecuritySettings(securitySettings)
 | 
				
			||||||
        this.securitySettings = securitySettings;
 | 
					    );
 | 
				
			||||||
        this.securitySettingsFormGroup.reset(this.securitySettings);
 | 
					    this.adminService.getJwtSettings().subscribe(
 | 
				
			||||||
      }
 | 
					      jwtSettings => this.processJwtSettings(jwtSettings)
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -70,18 +80,104 @@ export class SecuritySettingsComponent extends PageComponent implements OnInit,
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  save(): void {
 | 
					  buildJwtSecuritySettingsForm() {
 | 
				
			||||||
    this.securitySettings = {...this.securitySettings, ...this.securitySettingsFormGroup.value};
 | 
					    this.jwtSecuritySettingsFormGroup = this.fb.group({
 | 
				
			||||||
    this.adminService.saveSecuritySettings(this.securitySettings).subscribe(
 | 
					      tokenIssuer: ['', Validators.required],
 | 
				
			||||||
      (securitySettings) => {
 | 
					      tokenSigningKey: ['', [Validators.required, this.base64Format]],
 | 
				
			||||||
        this.securitySettings = securitySettings;
 | 
					      tokenExpirationTime: [0, [Validators.required, Validators.pattern('[0-9]*'), Validators.min(60)]],
 | 
				
			||||||
        this.securitySettingsFormGroup.reset(this.securitySettings);
 | 
					      refreshTokenExpTime: [0, [Validators.required, Validators.pattern('[0-9]*'), Validators.min(900)]]
 | 
				
			||||||
      }
 | 
					    }, {validators: this.refreshTokenTimeGreatTokenTime.bind(this)});
 | 
				
			||||||
 | 
					    this.jwtSecuritySettingsFormGroup.get('tokenExpirationTime').valueChanges.subscribe(
 | 
				
			||||||
 | 
					      () => this.jwtSecuritySettingsFormGroup.get('refreshTokenExpTime').updateValueAndValidity({onlySelf: true})
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  save(): void {
 | 
				
			||||||
 | 
					    this.securitySettings = {...this.securitySettings, ...this.securitySettingsFormGroup.value};
 | 
				
			||||||
 | 
					    this.adminService.saveSecuritySettings(this.securitySettings).subscribe(
 | 
				
			||||||
 | 
					      securitySettings => this.processSecuritySettings(securitySettings)
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  saveJwtSettings() {
 | 
				
			||||||
 | 
					    const jwtFormSettings = this.jwtSecuritySettingsFormGroup.value;
 | 
				
			||||||
 | 
					    this.confirmChangeJWTSettings().pipe(mergeMap(value => {
 | 
				
			||||||
 | 
					      if (value) {
 | 
				
			||||||
 | 
					        return this.adminService.saveJwtSettings(jwtFormSettings).pipe(
 | 
				
			||||||
 | 
					          tap((data) => this.authService.setUserFromJwtToken(data.token, data.refreshToken, false)),
 | 
				
			||||||
 | 
					          mergeMap(() => this.adminService.getJwtSettings()),
 | 
				
			||||||
 | 
					          tap(jwtSettings => this.processJwtSettings(jwtSettings))
 | 
				
			||||||
 | 
					        );
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      return of(null);
 | 
				
			||||||
 | 
					    })).subscribe(() => {});
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  discardSetting() {
 | 
				
			||||||
 | 
					    this.securitySettingsFormGroup.reset(this.securitySettings);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  discardJwtSetting() {
 | 
				
			||||||
 | 
					    this.jwtSecuritySettingsFormGroup.reset(this.jwtSettings);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private confirmChangeJWTSettings(): Observable<boolean> {
 | 
				
			||||||
 | 
					    if (this.jwtSecuritySettingsFormGroup.get('tokenIssuer').value !== (this.jwtSettings?.tokenIssuer || '') ||
 | 
				
			||||||
 | 
					      this.jwtSecuritySettingsFormGroup.get('tokenSigningKey').value !== (this.jwtSettings?.tokenSigningKey || '')) {
 | 
				
			||||||
 | 
					      return this.dialogService.confirm(
 | 
				
			||||||
 | 
					        this.translate.instant('admin.jwt.info-header'),
 | 
				
			||||||
 | 
					        `<div style="max-width: 400px">${this.translate.instant('admin.jwt.info-message')}</div>`,
 | 
				
			||||||
 | 
					        this.translate.instant('action.discard-changes'),
 | 
				
			||||||
 | 
					        this.translate.instant('action.confirm')
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return of(true);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  generateSigningKey() {
 | 
				
			||||||
 | 
					    this.jwtSecuritySettingsFormGroup.get('tokenSigningKey').setValue(randomAlphanumeric(44));
 | 
				
			||||||
 | 
					    if (this.jwtSecuritySettingsFormGroup.get('tokenSigningKey').pristine) {
 | 
				
			||||||
 | 
					      this.jwtSecuritySettingsFormGroup.get('tokenSigningKey').markAsDirty();
 | 
				
			||||||
 | 
					      this.jwtSecuritySettingsFormGroup.get('tokenSigningKey').markAsTouched();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private processSecuritySettings(securitySettings: SecuritySettings) {
 | 
				
			||||||
 | 
					    this.securitySettings = securitySettings;
 | 
				
			||||||
 | 
					    this.securitySettingsFormGroup.reset(this.securitySettings);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private processJwtSettings(jwtSettings: JwtSettings) {
 | 
				
			||||||
 | 
					    this.jwtSettings = jwtSettings;
 | 
				
			||||||
 | 
					    this.jwtSecuritySettingsFormGroup.reset(jwtSettings);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private refreshTokenTimeGreatTokenTime(formGroup: FormGroup): { [key: string]: boolean } | null {
 | 
				
			||||||
 | 
					    if (formGroup) {
 | 
				
			||||||
 | 
					      const tokenTime = formGroup.value.tokenExpirationTime;
 | 
				
			||||||
 | 
					      const refreshTokenTime = formGroup.value.refreshTokenExpTime;
 | 
				
			||||||
 | 
					      if (tokenTime >= refreshTokenTime ) {
 | 
				
			||||||
 | 
					        if (formGroup.get('refreshTokenExpTime').untouched) {
 | 
				
			||||||
 | 
					          formGroup.get('refreshTokenExpTime').markAsTouched();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        formGroup.get('refreshTokenExpTime').setErrors({lessToken: true});
 | 
				
			||||||
 | 
					        return {lessToken: true};
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return null;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private base64Format(control: FormControl): { [key: string]: boolean } | null {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const value = btoa(control.value);
 | 
				
			||||||
 | 
					      return null;
 | 
				
			||||||
 | 
					    } catch (e) {
 | 
				
			||||||
 | 
					      return {base64: true};
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  confirmForm(): FormGroup {
 | 
					  confirmForm(): FormGroup {
 | 
				
			||||||
    return this.securitySettingsFormGroup;
 | 
					    return this.securitySettingsFormGroup.dirty ? this.securitySettingsFormGroup : this.jwtSecuritySettingsFormGroup;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -16,7 +16,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
-->
 | 
					-->
 | 
				
			||||||
<h2 mat-dialog-title>{{data.title}}</h2>
 | 
					<h2 mat-dialog-title>{{data.title}}</h2>
 | 
				
			||||||
<div mat-dialog-content [innerHTML]="data.message"></div>
 | 
					<div mat-dialog-content [innerHTML]="data.message | safe: 'html'"></div>
 | 
				
			||||||
<div mat-dialog-actions fxLayoutAlign="end center">
 | 
					<div mat-dialog-actions fxLayoutAlign="end center">
 | 
				
			||||||
  <button mat-button color="primary" [mat-dialog-close]="false">{{data.cancel}}</button>
 | 
					  <button mat-button color="primary" [mat-dialog-close]="false">{{data.cancel}}</button>
 | 
				
			||||||
  <button mat-button color="primary" [mat-dialog-close]="true" cdkFocusInitial>{{data.ok}}</button>
 | 
					  <button mat-button color="primary" [mat-dialog-close]="true" cdkFocusInitial>{{data.ok}}</button>
 | 
				
			||||||
 | 
				
			|||||||
@ -63,6 +63,13 @@ export interface SecuritySettings {
 | 
				
			|||||||
  passwordPolicy: UserPasswordPolicy;
 | 
					  passwordPolicy: UserPasswordPolicy;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface JwtSettings {
 | 
				
			||||||
 | 
					  tokenIssuer: string;
 | 
				
			||||||
 | 
					  tokenSigningKey: string;
 | 
				
			||||||
 | 
					  tokenExpirationTime: number;
 | 
				
			||||||
 | 
					  refreshTokenExpTime: number;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface UpdateMessage {
 | 
					export interface UpdateMessage {
 | 
				
			||||||
  message: string;
 | 
					  message: string;
 | 
				
			||||||
  updateAvailable: boolean;
 | 
					  updateAvailable: boolean;
 | 
				
			||||||
 | 
				
			|||||||
@ -381,6 +381,26 @@
 | 
				
			|||||||
            "within-time": "Within time (sec)",
 | 
					            "within-time": "Within time (sec)",
 | 
				
			||||||
            "within-time-pattern": "Time must be a positive integer.",
 | 
					            "within-time-pattern": "Time must be a positive integer.",
 | 
				
			||||||
            "within-time-required": "Time is required."
 | 
					            "within-time-required": "Time is required."
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        "jwt": {
 | 
				
			||||||
 | 
					            "security-settings": "JWT security settings",
 | 
				
			||||||
 | 
					            "issuer-name": "Issuer name",
 | 
				
			||||||
 | 
					            "issuer-name-required": "Issuer name is required.",
 | 
				
			||||||
 | 
					            "signings-key": "Signing key",
 | 
				
			||||||
 | 
					            "signings-key-required": "Signing key is required.",
 | 
				
			||||||
 | 
					            "signings-key-base64": "Signing key must be base64 format.",
 | 
				
			||||||
 | 
					            "expiration-time": "Token expiration time (sec)",
 | 
				
			||||||
 | 
					            "expiration-time-required": "Token expiration time is required.",
 | 
				
			||||||
 | 
					            "expiration-time-pattern": "Token expiration time be a positive integer.",
 | 
				
			||||||
 | 
					            "expiration-time-min": "Minimum time is 60 seconds (1 minute).",
 | 
				
			||||||
 | 
					            "refresh-expiration-time": "Refresh token expiration time",
 | 
				
			||||||
 | 
					            "refresh-expiration-time-required": "Refresh token expiration time is required.",
 | 
				
			||||||
 | 
					            "refresh-expiration-time-pattern": "Refresh token expiration time be a positive integer.",
 | 
				
			||||||
 | 
					            "refresh-expiration-time-min": "Minimum time is 900 seconds (15 minute).",
 | 
				
			||||||
 | 
					            "refresh-expiration-time-less-token": "Refresh token time must be greater token time.",
 | 
				
			||||||
 | 
					            "generate-key": "Generate key",
 | 
				
			||||||
 | 
					            "info-header": "All users will be to re-logined",
 | 
				
			||||||
 | 
					            "info-message": "Change of the JWT Signing Key will cause all issued tokens to be invalid. All users will need to re-login. This will also affect scripts that use Rest API/Websockets."
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      },
 | 
					      },
 | 
				
			||||||
    "alarm": {
 | 
					    "alarm": {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user