diff --git a/src/app/core/_components/tables/files-attack-table/files-attack-table.component.html b/src/app/core/_components/tables/files-attack-table/files-attack-table.component.html
index 0b3f866e0..41a40eb2f 100644
--- a/src/app/core/_components/tables/files-attack-table/files-attack-table.component.html
+++ b/src/app/core/_components/tables/files-attack-table/files-attack-table.component.html
@@ -1,5 +1,6 @@
\ No newline at end of file
diff --git a/src/app/core/_components/tables/ht-table/ht-table.component.html b/src/app/core/_components/tables/ht-table/ht-table.component.html
index 034aba72f..e5c5ec238 100644
--- a/src/app/core/_components/tables/ht-table/ht-table.component.html
+++ b/src/app/core/_components/tables/ht-table/ht-table.component.html
@@ -198,7 +198,11 @@
@if (isCmdPreproAttack) {
-
+
}
diff --git a/src/app/core/_components/tables/ht-table/ht-table.component.ts b/src/app/core/_components/tables/ht-table/ht-table.component.ts
index 2f8e9af00..a2db04ec4 100644
--- a/src/app/core/_components/tables/ht-table/ht-table.component.ts
+++ b/src/app/core/_components/tables/ht-table/ht-table.component.ts
@@ -160,6 +160,8 @@ export class HTTableComponent implements OnInit, AfterViewI
/** Flag to enable or disable cmd preprocessor attack checkbox. */
@Input() isCmdPreproAttack = false;
+ @Input() isCmdPreproFiles: number[] = [];
+
/** Flag to add dual label text. */
@Input() isCmdLabel: string;
@@ -680,6 +682,10 @@ export class HTTableComponent implements OnInit, AfterViewI
}
}
+ isPreproSelected(row: T): boolean {
+ return this.isCmdPreproFiles.includes(row.id);
+ }
+
/**
* Checks if all rows are selected.
*/
diff --git a/src/app/tasks/new-tasks/new-tasks.component.html b/src/app/tasks/new-tasks/new-tasks.component.html
index c20626d7f..3b9412764 100644
--- a/src/app/tasks/new-tasks/new-tasks.component.html
+++ b/src/app/tasks/new-tasks/new-tasks.component.html
@@ -188,7 +188,7 @@ Ta
[fileType]="FileType.OTHER"
[formData]="getFormData()"
(updateFormEvent)="onUpdateForm($event)"
- [cmdPrepro]="false"
+ [cmdPrepro]="isPreprocessor()"
>
diff --git a/src/app/tasks/new-tasks/new-tasks.component.spec.ts b/src/app/tasks/new-tasks/new-tasks.component.spec.ts
index f001fd8e7..d2e655589 100644
--- a/src/app/tasks/new-tasks/new-tasks.component.spec.ts
+++ b/src/app/tasks/new-tasks/new-tasks.component.spec.ts
@@ -6,6 +6,7 @@ import { MatDialog } from '@angular/material/dialog';
import { ActivatedRoute, Params, Router } from '@angular/router';
import { UiSettings } from '@models/config-ui.schema';
+import { FileType } from '@models/file.model';
import { JPretask } from '@models/pretask.model';
import { ResponseWrapper } from '@models/response.model';
import { JTask } from '@models/task.model';
@@ -426,6 +427,60 @@ describe('NewTasksComponent', () => {
expect(routerSpy.navigate).toHaveBeenCalledWith(['tasks/show-tasks']);
});
+ it('should merge the preprocessor files into the task files', async () => {
+ await initComponent(fixture);
+
+ component.form.patchValue({
+ taskName: 'My Task',
+ hashlistId: 1,
+ attackCmd: '-a 0 #HL# dict.txt',
+ priority: 0,
+ crackerBinaryId: 10,
+ files: [10]
+ });
+ component['onUpdateForm']({
+ type: 'CMD_PREPRO',
+ attackCmd: '--prince keyspace.txt',
+ files: [],
+ otherFiles: [10, 30]
+ });
+ component.form.updateValueAndValidity();
+
+ await component['onSubmit']();
+
+ const payload = globalServiceSpy.create.calls.mostRecent().args[1] as { files: number[] };
+ expect(payload.files).toEqual([10, 30]);
+ });
+
+ it('should drop the preprocessor files when the preprocessor is set to none', async () => {
+ await initComponent(fixture);
+
+ component.form.patchValue({
+ taskName: 'My Task',
+ hashlistId: 1,
+ attackCmd: '-a 0 #HL# dict.txt',
+ priority: 0,
+ crackerBinaryId: 10,
+ preprocessorId: 1,
+ files: [10]
+ });
+ component['onUpdateForm']({
+ type: 'CMD_PREPRO',
+ attackCmd: '--prince keyspace.txt',
+ files: [],
+ otherFiles: [30]
+ });
+
+ component.form.controls.preprocessorId.setValue(0);
+ component.form.updateValueAndValidity();
+
+ await component['onSubmit']();
+
+ const payload = globalServiceSpy.create.calls.mostRecent().args[1] as { files: number[] };
+ expect(payload.files).toEqual([10]);
+ expect(component.form.controls.preprocessorCommand.value).toBe('');
+ });
+
it('should mark form as touched when invalid and not submit', async () => {
await initComponent(fixture);
@@ -900,6 +955,41 @@ describe('NewTasksComponent', () => {
});
});
+ describe('Preprocessor file selection', () => {
+ function cmdPreproByFileType(): Record {
+ const tables = Array.from(fixture.nativeElement.querySelectorAll('app-files-attack-table')) as Record<
+ string,
+ unknown
+ >[];
+
+ return Object.fromEntries(tables.map((table) => [table['fileType'] as number, table['cmdPrepro']]));
+ }
+
+ it('should offer the preprocessor checkbox for wordlists and other files when a preprocessor is set', async () => {
+ await initComponent(fixture);
+
+ component.form.controls.preprocessorId.setValue(5, { emitEvent: false });
+ fixture.detectChanges();
+
+ const cmdPrepro = cmdPreproByFileType();
+ expect(cmdPrepro[FileType.WORDLIST]).toBe(true);
+ expect(cmdPrepro[FileType.OTHER]).toBe(true);
+ expect(cmdPrepro[FileType.RULES]).toBe(false);
+ });
+
+ it('should hide the preprocessor checkbox on every file table when no preprocessor is set', async () => {
+ await initComponent(fixture);
+
+ component.form.controls.preprocessorId.setValue(0, { emitEvent: false });
+ fixture.detectChanges();
+
+ const cmdPrepro = cmdPreproByFileType();
+ expect(cmdPrepro[FileType.WORDLIST]).toBe(false);
+ expect(cmdPrepro[FileType.OTHER]).toBe(false);
+ expect(cmdPrepro[FileType.RULES]).toBe(false);
+ });
+ });
+
describe('onUpdateForm', () => {
it('should update attackCmd and files when event type is CMD', async () => {
await initComponent(fixture);
@@ -927,6 +1017,22 @@ describe('NewTasksComponent', () => {
expect(component.form.controls.preprocessorCommand.value).toBe('--prince-elem-cnt-min=1');
});
+
+ it('should keep the preprocessor files out of the task files when event type is not CMD', async () => {
+ await initComponent(fixture);
+
+ component.form.controls.files.setValue([10]);
+
+ component['onUpdateForm']({
+ type: 'CMD_PREPRO',
+ attackCmd: '--prince keyspace.txt',
+ files: [],
+ otherFiles: [30]
+ });
+
+ expect(component.form.controls.preprocessorCommand.value).toBe('--prince keyspace.txt');
+ expect(component.form.controls.files.value).toEqual([10]);
+ });
});
describe('openHelpDialog', () => {
diff --git a/src/app/tasks/new-tasks/new-tasks.component.ts b/src/app/tasks/new-tasks/new-tasks.component.ts
index eafb799b4..989286bac 100644
--- a/src/app/tasks/new-tasks/new-tasks.component.ts
+++ b/src/app/tasks/new-tasks/new-tasks.component.ts
@@ -94,6 +94,8 @@ export class NewTasksComponent implements OnInit {
copyFiles: FileId[];
editedIndex: number;
+ private preprocessorFiles: FileId[] = [];
+
// Tooltips
tasktip: TaskTooltipsLevel;
@@ -174,6 +176,10 @@ export class NewTasksComponent implements OnInit {
});
this.form.controls.preprocessorId.valueChanges.pipe(takeUntilDestroyed(this.destroyRef)).subscribe((newValue) => {
+ if (newValue === 0) {
+ this.preprocessorFiles = [];
+ this.form.controls.preprocessorCommand.setValue('', { emitEvent: false });
+ }
this.handleChangePreprocessor(newValue);
});
}
@@ -279,6 +285,7 @@ export class NewTasksComponent implements OnInit {
return {
attackCmd: this.form.controls.attackCmd.value,
files: this.form.controls.files.value,
+ otherFiles: this.preprocessorFiles,
preprocessorCommand: this.form.controls.preprocessorCommand.value
};
}
@@ -303,6 +310,7 @@ export class NewTasksComponent implements OnInit {
files: event.files
});
} else {
+ this.preprocessorFiles = event.otherFiles;
this.form.patchValue({
preprocessorCommand: event.attackCmd
});
@@ -408,6 +416,7 @@ export class NewTasksComponent implements OnInit {
const payload = { ...this.form.value };
delete payload.crackerBinaryTypeId;
+ payload.files = [...new Set([...(payload.files ?? []), ...this.preprocessorFiles])];
this.gs.create(SERV.TASKS, payload).subscribe({
next: () => {