Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NAS-124260 / 13.0 / Improved Cautions on Debugs and Personal Information (by AlexKarpov98) #8933

Merged
merged 2 commits into from
Sep 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/app/helptext/system/advanced.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ export const helptext_system_advanced = {
fieldset_replication: T('Replication'),

dialog_generate_debug_title: T('Generate Debug File'),
dialog_generate_debug_message: T('This operation might take a long time. Proceed?'),
dialog_generate_debug_message: T('Warning: Debugs may contain log files with personal information such\
as usernames or other identifying information about your system. Please review debugs and redact any\
sensitive information before sharing with external entities.'),
dialog_button_ok: T('Proceed'),

debug_dialog: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
<div id="{{config.name}}" class="dynamic-field form-checkbox" [formGroup]="group" [ngClass]="fieldShow" [class.has-tooltip]="config.tooltip" *ngIf="!config['isHidden']">
<mat-checkbox *ngIf="!config.updater" [formControlName]="config.name" [required]="config.required" ix-auto ix-auto-type="checkbox" ix-auto-identifier="{{config.placeholder}}">
<mat-checkbox
*ngIf="!config.updater"
ix-auto
ix-auto-type="checkbox"
ix-auto-identifier="{{config.placeholder}}"
[formControlName]="config.name"
[required]="config.required"
>
{{ config.placeholder | translate }}
</mat-checkbox>
<mat-checkbox *ngIf="config.updater" class="updater" [formControlName]="config.name" [required]="config.required" (click)="checkboxUpdate()">
<mat-checkbox
*ngIf="config.updater"
class="updater"
[formControlName]="config.name"
[required]="config.required"
(click)="checkboxUpdate()"
>
{{ config.placeholder | translate }}
</mat-checkbox>

<tooltip *ngIf="config.tooltip" [header]="config.placeholder" [message]="config.tooltip" [position]="config.tooltipPosition ? config.tooltipPosition : null"></tooltip>
<mat-error *ngIf="config['hasErrors']"><div [innerHTML]="config['errors']"></div></mat-error>
<mat-error *ngIf="config.warnings"><div [innerHTML]="config.warnings | translate"></div></mat-error>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { Component, ViewContainerRef } from '@angular/core';
import { Component } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';

import { FieldConfig } from '../../models/field-config.interface';
import { Field } from '../../models/field.interface';
import { TooltipComponent } from '../tooltip/tooltip.component';

@Component({
selector: 'form-checkbox',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,77 @@ export interface InputUnitConfig {
}

export interface FieldConfig {
disabled?: boolean; label?: string; inlineLabel?: string; name: string; options?: any[];
errors?: string; hasErrors?: boolean; placeholder?: string; type: string;
inputType?: string; inputUnit?: InputUnitConfig; validation?: any[] | ValidatorFn | ValidatorFn[];
disabled?: boolean;
label?: string;
inlineLabel?: string;
name: string;
options?: any[];
errors?: string;
hasErrors?: boolean;
placeholder?: string;
type: string;
inputType?: string;
inputUnit?: InputUnitConfig;
validation?: any[] | ValidatorFn | ValidatorFn[];
asyncValidation?: AsyncValidatorFn | AsyncValidatorFn[];
value?: any; multiple?: boolean; tristate?: boolean; tooltip?: string; tooltipPosition?: string;
relation?: RelationGroup[]; isHidden?: boolean; formarray?: any;
initialCount?: number; readonly?: boolean; initial?: string; rootSelectable?: boolean;
min?: number; max?: number; tabs?: any[]; tabName?: string; class?: string;
customEventActionLabel?: string; explorerType?: string; explorerParam?: any; customTemplateStringOptions?: any;
required?: boolean; deleteButtonOnFirst?: boolean; addBtnMessage?: string;
acceptedFiles?: string; fileLocation?: string; fileType?: string;width?: string;
message?: any; updater?: any; parent?: any;togglePw?: boolean; paraText?: any;
noexec?: boolean; blurStatus?: boolean;blurEvent?: any;noMinutes?: boolean;
warnings?: string; hideButton?: boolean; searchOptions?: any[]; hideDirs?: any;
listFields?: FieldConfig[][]; templateListField?: FieldConfig[];
updateLocal?: boolean; isLoading?: boolean; textAreaRows?: number; netmaskPreset?: number;
isLargeText?: boolean; paragraphIcon?: string; paragraphIconSize?: string; zeroStateMessage?: string; isDoubleConfirm?: boolean;
maskValue?: any; hideErrMsg?: boolean; id?: string; autocomplete?: boolean; filereader?: boolean;
customEventMethod?(data: any); onChangeOption?(data: any); hint?: string;
value?: any;
multiple?: boolean;
tristate?: boolean;
tooltip?: string;
tooltipPosition?: string;
relation?: RelationGroup[];
isHidden?: boolean;
formarray?: any;
initialCount?: number;
readonly?: boolean;
initial?: string;
rootSelectable?: boolean;
min?: number;
max?: number;
tabs?: any[];
tabName?: string;
class?: string;
customEventActionLabel?: string;
explorerType?: string;
explorerParam?: any;
customTemplateStringOptions?: any;
required?: boolean;
deleteButtonOnFirst?: boolean;
addBtnMessage?: string;
acceptedFiles?: string;
fileLocation?: string;
fileType?: string;
width?: string;
message?: any;
updater?: any;
parent?: any;
togglePw?: boolean;
paraText?: any;
noexec?: boolean;
blurStatus?: boolean;
blurEvent?: any;
noMinutes?: boolean;
warnings?: string;
hideButton?: boolean;
searchOptions?: any[];
hideDirs?: any;
listFields?: FieldConfig[][];
templateListField?: FieldConfig[];
updateLocal?: boolean;
isLoading?: boolean;
textAreaRows?: number;
netmaskPreset?: number;
isLargeText?: boolean;
paragraphIcon?: string;
paragraphIconSize?: string;
zeroStateMessage?: string;
isDoubleConfirm?: boolean;
maskValue?: any;
hideErrMsg?: boolean;
id?: string;
autocomplete?: boolean;
filereader?: boolean;
customEventMethod?(data: any);
onChangeOption?(data: any);
hint?: string;
}
152 changes: 90 additions & 62 deletions src/app/pages/system/support/fn-support/fn-support.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@ import { FieldSet } from 'app/pages/common/entity/entity-form/models/fieldset.in
import { WebSocketService } from 'app/services/';
import { helptext_system_support as helptext } from 'app/helptext/system/support';
import { Subscription } from 'rxjs';
import { AttachDebugWarningService } from 'app/pages/system/support/services/attach-debug-warning.service';
import { FormControl } from '@angular/forms';

@Component({
selector: 'app-fn-support',
template: '<entity-form [conf]="this"></entity-form>',
})
export class FnSupportComponent implements OnDestroy {
private subscriptions = new Subscription();
entityEdit: EntityFormComponent;
category: any;
screenshot: any;
Expand Down Expand Up @@ -118,27 +121,31 @@ export class FnSupportComponent implements OnDestroy {
},
];

private categoriesSubscription: Subscription;

constructor(protected ws: WebSocketService, protected dialog: MatDialog,
protected translate: TranslateService) { }
constructor(
protected ws: WebSocketService,
protected dialog: MatDialog,
protected translate: TranslateService,
private attachDebugWarningService: AttachDebugWarningService
) { }

afterInit(entityEdit: any) {
this.entityEdit = entityEdit;
setTimeout(() => {
this.translate.get(helptext.contactUs).subscribe((res) => {
_.find(this.fieldConfig, { name: 'FN_col2' }).paraText = '<i class="material-icons">mail</i>' + res;
});
this.subscriptions.add(
this.translate.get(helptext.contactUs).subscribe((res) => {
_.find(this.fieldConfig, { name: 'FN_col2' }).paraText = '<i class="material-icons">mail</i>' + res;
})
);
}, 2000);

this.category = _.find(this.fieldConfig, { name: 'category' });
this.loadCategoriesOnAuth();

this.listenForAttachDebugChanges();
}

ngOnDestroy(): void {
if (this.categoriesSubscription) {
this.categoriesSubscription.unsubscribe();
}
this.subscriptions.unsubscribe();
}

customSubmit(values): void {
Expand All @@ -160,39 +167,49 @@ export class FnSupportComponent implements OnDestroy {
let url;
dialogRef.componentInstance.setCall('support.new_ticket', [payload]);
dialogRef.componentInstance.submit();
dialogRef.componentInstance.success.subscribe((res) => {
if (res.result) {
url = `<a href="${res.result.url}" target="_blank" style="text-decoration:underline;">${res.result.url}</a>`;
}
if (res.method === 'support.new_ticket' && this.subs && this.subs.length > 0) {
this.subs.forEach((item) => {
const formData: FormData = new FormData();
formData.append('data', JSON.stringify({
method: 'support.attach_ticket',
params: [{
ticket: (res.result.ticket),
filename: item.file.name,
token: payload.token,
}],
}));
formData.append('file', item.file, item.apiEndPoint);
dialogRef.componentInstance.wspost(item.apiEndPoint, formData);
dialogRef.componentInstance.success.subscribe(() => {
this.resetForm();
});
dialogRef.componentInstance.failure.subscribe((res) => {
dialogRef.componentInstance.setDescription(res.error);
this.subscriptions.add(
dialogRef.componentInstance.success.subscribe((res) => {
if (res.result) {
url = `<a href="${res.result.url}" target="_blank" style="text-decoration:underline;">${res.result.url}</a>`;
}
if (res.method === 'support.new_ticket' && this.subs && this.subs.length > 0) {
this.subs.forEach((item) => {
const formData: FormData = new FormData();
formData.append('data', JSON.stringify({
method: 'support.attach_ticket',
params: [{
ticket: (res.result.ticket),
filename: item.file.name,
token: payload.token,
}],
}));
formData.append('file', item.file, item.apiEndPoint);
dialogRef.componentInstance.wspost(item.apiEndPoint, formData);
this.subscriptions.add(
dialogRef.componentInstance.success.subscribe(() => {
this.resetForm();
})
);

this.subscriptions.add(
dialogRef.componentInstance.failure.subscribe((res) => {
dialogRef.componentInstance.setDescription(res.error);
})
);
});
});
dialogRef.componentInstance.setDescription(url);
} else {
dialogRef.componentInstance.setDescription(url);
this.resetForm();
}
});
dialogRef.componentInstance.failure.subscribe((res) => {
dialogRef.componentInstance.setDescription(res.error);
});
dialogRef.componentInstance.setDescription(url);
} else {
dialogRef.componentInstance.setDescription(url);
this.resetForm();
}
})
);

this.subscriptions.add(
dialogRef.componentInstance.failure.subscribe((res) => {
dialogRef.componentInstance.setDescription(res.error);
})
);
}

resetForm() {
Expand All @@ -219,27 +236,38 @@ export class FnSupportComponent implements OnDestroy {
}

private loadCategoriesOnAuth(): void {
this.entityEdit.formGroup.controls['token'].valueChanges.subscribe((token) => {
if (!token) {
return;
}
this.subscriptions.add(
this.entityEdit.formGroup.controls['token'].valueChanges.subscribe((token) => {
if (!token) {
return;
}

this.category.isLoading = true;
this.ws.call('support.fetch_categories', [token]).subscribe((res) => {
this.category.isLoading = false;
this.entityEdit.setDisabled('category', false);
const options = [];
for (const property in res) {
if (res.hasOwnProperty(property)) {
options.push({ label: property, value: res[property] });
this.category.isLoading = true;
this.ws.call('support.fetch_categories', [token]).subscribe((res) => {
this.category.isLoading = false;
this.entityEdit.setDisabled('category', false);
const options = [];
for (const property in res) {
if (res.hasOwnProperty(property)) {
options.push({ label: property, value: res[property] });
}
this.category.options = _.sortBy(options, ['label']);
}
this.category.options = _.sortBy(options, ['label']);
}
}, (error) => {
this.entityEdit.setDisabled('category', true);
this.category.isLoading = false;
new EntityUtils().handleWSError(this, error, this.dialog);
});
});
}, (error) => {
this.entityEdit.setDisabled('category', true);
this.category.isLoading = false;
new EntityUtils().handleWSError(this, error, this.dialog);
});
})
);
}

private listenForAttachDebugChanges(): void {
const control = this.entityEdit.formGroup.controls['attach_debug'] as FormControl;

this.subscriptions.add(
this.attachDebugWarningService.handleAttachDebugChanges(control)
.subscribe((checked) => control.patchValue(checked))
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Injectable } from '@angular/core';
import { FormControl } from '@angular/forms';
import { TranslateService } from '@ngx-translate/core';
import { Observable } from 'rxjs';
import { filter, pairwise, startWith, switchMap } from 'rxjs/operators';
import { DialogService } from 'app/services/dialog.service';

@Injectable()
export class AttachDebugWarningService {

constructor(private dialogService: DialogService, private translate: TranslateService) { }

handleAttachDebugChanges(control: FormControl): Observable<boolean> {
return control.valueChanges.pipe(
startWith(null),
pairwise(),
filter(([previousValue, currentValue]) => !previousValue && currentValue),
switchMap(() => this.showConfirmationDialog()),
);
}

showConfirmationDialog(): Observable<boolean> {
return this.dialogService
.confirm({
title: this.translate.instant('Warning'),
message: 'Debugs may contain log files with personal information such as usernames or other identifying information about your system. Debugs by default are attached privately to Jira tickets and only visible by iXsystem’s Engineering Staff. Please review debugs and redact any sensitive information before sharing with external entities. Debugs can be manually generated from System → Advanced → Save Debug',
hideCheckBox: true,
buttonMsg: this.translate.instant('Agree'),
});
}
}
Loading
Loading