You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@metron.apache.org by rm...@apache.org on 2018/08/17 15:34:50 UTC
[35/51] [abbrv] metron git commit: METRON-1712 PCAP UI - Input
validation (tiborm via merrimanr) closes apache/metron#1142
METRON-1712 PCAP UI - Input validation (tiborm via merrimanr) closes apache/metron#1142
Project: http://git-wip-us.apache.org/repos/asf/metron/repo
Commit: http://git-wip-us.apache.org/repos/asf/metron/commit/52de126f
Tree: http://git-wip-us.apache.org/repos/asf/metron/tree/52de126f
Diff: http://git-wip-us.apache.org/repos/asf/metron/diff/52de126f
Branch: refs/heads/master
Commit: 52de126fc746181d6aac8ce002d6b814fd1e6cb5
Parents: afb9607
Author: tiborm <ti...@gmail.com>
Authored: Wed Aug 8 16:36:35 2018 -0500
Committer: rmerriman <me...@gmail.com>
Committed: Wed Aug 8 16:36:35 2018 -0500
----------------------------------------------------------------------
.../src/app/pcap/model/pcap.mock.ts | 4 +-
.../src/app/pcap/model/pcap.request.ts | 4 +-
.../pcap-filters/pcap-filters.component.html | 12 +-
.../pcap-filters/pcap-filters.component.spec.ts | 228 ++++++++++++++++++-
.../pcap/pcap-filters/pcap-filters.component.ts | 5 +
5 files changed, 232 insertions(+), 21 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/metron/blob/52de126f/metron-interface/metron-alerts/src/app/pcap/model/pcap.mock.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/app/pcap/model/pcap.mock.ts b/metron-interface/metron-alerts/src/app/pcap/model/pcap.mock.ts
index c867fe9..bf02da8 100644
--- a/metron-interface/metron-alerts/src/app/pcap/model/pcap.mock.ts
+++ b/metron-interface/metron-alerts/src/app/pcap/model/pcap.mock.ts
@@ -22,9 +22,9 @@ export const fakePcapRequest = {
startTimeMs: 0,
endTimeMs: 0,
ipSrcAddr: '0.0.0.0',
- ipSrcPort: '80',
+ ipSrcPort: 80,
ipDstAddr: '0.0.0.0',
- ipDstPort: '80',
+ ipDstPort: 80,
protocol: '*',
packetFilter: '*',
includeReverse: false
http://git-wip-us.apache.org/repos/asf/metron/blob/52de126f/metron-interface/metron-alerts/src/app/pcap/model/pcap.request.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/app/pcap/model/pcap.request.ts b/metron-interface/metron-alerts/src/app/pcap/model/pcap.request.ts
index 91c2287..d00a6ac 100644
--- a/metron-interface/metron-alerts/src/app/pcap/model/pcap.request.ts
+++ b/metron-interface/metron-alerts/src/app/pcap/model/pcap.request.ts
@@ -20,9 +20,9 @@ export class PcapRequest {
startTimeMs: number = 0;
endTimeMs: number = 150000000000000000;
ipSrcAddr: string = '';
- ipSrcPort: string = '';
+ ipSrcPort: number = 0;
ipDstAddr: string = '';
- ipDstPort: string = '';
+ ipDstPort: number = 0;
protocol: string = '';
packetFilter: string = '';
includeReverse: boolean = false;
http://git-wip-us.apache.org/repos/asf/metron/blob/52de126f/metron-interface/metron-alerts/src/app/pcap/pcap-filters/pcap-filters.component.html
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/app/pcap/pcap-filters/pcap-filters.component.html b/metron-interface/metron-alerts/src/app/pcap/pcap-filters/pcap-filters.component.html
index f4133df..039307a 100644
--- a/metron-interface/metron-alerts/src/app/pcap/pcap-filters/pcap-filters.component.html
+++ b/metron-interface/metron-alerts/src/app/pcap/pcap-filters/pcap-filters.component.html
@@ -24,21 +24,21 @@
<div class="form-group">
<label for="ipSrcAddr">IP Source Address</label>
- <input name="ipSrcAddr" #ipSrcAddr="ngModel" class="form-control" pattern="^(?:\d{1,3}\.){3}\d{1,3}(.\d{1,2})?$" [(ngModel)]="model.ipSrcAddr">
+ <input name="ipSrcAddr" #ipSrcAddr="ngModel" class="form-control" pattern="^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}$" [(ngModel)]="model.ipSrcAddr" data-qe-id="ip-src-addr">
</div>
-
+
<div class="form-group">
<label for="ipSrcPort">IP Source Port</label>
- <input name="ipSrcPort" #ipSrcPort="ngModel" class="form-control" type="number" [(ngModel)]="model.ipSrcPort">
+ <input name="ipSrcPort" class="form-control" pattern="^([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$" [(ngModel)]="ipSrcPort" data-qe-id="ip-src-port">
</div>
<div class="form-group"><label for="ipDstAddr">IP Dest Address</label>
- <input name="ipDstAddr" #ipDstAddr="ngModel" class="form-control" pattern="^(?:\d{1,3}\.){3}\d{1,3}(.\d{1,2})?$" [(ngModel)]="model.ipDstAddr">
+ <input name="ipDstAddr" #ipDstAddr="ngModel" class="form-control" pattern="^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}$" [(ngModel)]="model.ipDstAddr" data-qe-id="ip-dst-addr">
</div>
<div class="form-group">
<label for="ipDstPort">IP Dest Port</label>
- <input id="ipDstPort" name="ipDstPort" #ipDstPort="ngModel" class="form-control" type="number" [(ngModel)]="model.ipDstPort">
+ <input id="ipDstPort" name="ipDstPort" class="form-control" pattern="^([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$" [(ngModel)]="ipDstPort" data-qe-id="ip-dest-port">
</div>
<div class="form-group">
@@ -57,6 +57,6 @@
</div>
<div class="form-group">
- <button type="submit" [ngClass]="{'disabled':!f.form.valid || queryRunning}" class="btn btn-primary btn-search" [disabled]="!f.form.valid || queryRunning"></button>
+ <button type="submit" [ngClass]="{'disabled':!f.form.valid || queryRunning}" class="btn btn-primary btn-search" [disabled]="!f.form.valid || queryRunning" data-qe-id="submit-button"></button>
</div>
</form>
http://git-wip-us.apache.org/repos/asf/metron/blob/52de126f/metron-interface/metron-alerts/src/app/pcap/pcap-filters/pcap-filters.component.spec.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/app/pcap/pcap-filters/pcap-filters.component.spec.ts b/metron-interface/metron-alerts/src/app/pcap/pcap-filters/pcap-filters.component.spec.ts
index c0f9c3b..4336b22 100644
--- a/metron-interface/metron-alerts/src/app/pcap/pcap-filters/pcap-filters.component.spec.ts
+++ b/metron-interface/metron-alerts/src/app/pcap/pcap-filters/pcap-filters.component.spec.ts
@@ -16,20 +16,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { async, ComponentFixture, TestBed, fakeAsync, tick } from '@angular/core/testing';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { PcapFiltersComponent } from './pcap-filters.component';
import { FormsModule } from '../../../../node_modules/@angular/forms';
-import { Component, Input, Output, EventEmitter } from '@angular/core';
+import { Component, Input, Output, EventEmitter, DebugElement } from '@angular/core';
import { PcapRequest } from '../model/pcap.request';
-import { emit } from 'cluster';
@Component({
selector: 'app-date-picker',
template: '<input type="text" [(value)]="date">',
})
-class FakeDatePicker {
+class FakeDatePickerComponent {
@Input() date: string;
@Output() dateChange = new EventEmitter<string>();
}
@@ -44,7 +43,7 @@ describe('PcapFiltersComponent', () => {
FormsModule
],
declarations: [
- FakeDatePicker,
+ FakeDatePickerComponent,
PcapFiltersComponent,
]
})
@@ -86,13 +85,21 @@ describe('PcapFiltersComponent', () => {
expect(component.model.ipSrcAddr).toBe('192.168.0.1');
});
- it('IP Source Port should be bound to the model', () => {
+ it('IP Source Port should be bound to the property', () => {
let input: HTMLInputElement = fixture.nativeElement.querySelector('[name="ipSrcPort"]');
input.value = '9345';
input.dispatchEvent(new Event('input'));
fixture.detectChanges();
- expect(component.model.ipSrcPort).toBe(9345);
+ expect(component.ipSrcPort).toBe('9345');
+ });
+
+ it('IP Source Port should be converted to number on submit', () => {
+ component.ipSrcPort = '42';
+ component.search.emit = (model: PcapRequest) => {
+ expect(model.ipSrcPort).toBe(42);
+ };
+ component.onSubmit();
});
it('IP Dest Address should be bound to the model', () => {
@@ -104,13 +111,21 @@ describe('PcapFiltersComponent', () => {
expect(component.model.ipDstAddr).toBe('256.0.0.7');
});
- it('IP Dest Port should be bound to the model', () => {
+ it('IP Dest Port should be bound to the property', () => {
let input: HTMLInputElement = fixture.nativeElement.querySelector('[name="ipDstPort"]');
input.value = '8989';
input.dispatchEvent(new Event('input'));
fixture.detectChanges();
- expect(component.model.ipDstPort).toBe(8989);
+ expect(component.ipDstPort).toBe('8989');
+ });
+
+ it('IP Dest Port should be converted to number on submit', () => {
+ component.ipDstPort = '42';
+ component.search.emit = (model: PcapRequest) => {
+ expect(model.ipDstPort).toBe(42);
+ };
+ component.onSubmit();
});
it('Protocol should be bound to the model', () => {
@@ -144,7 +159,7 @@ describe('PcapFiltersComponent', () => {
component.startTimeStr = '2220-12-12 12:12:12';
component.search.emit = (model: PcapRequest) => {
expect(model.startTimeMs).toBe(new Date(component.startTimeStr).getTime());
- }
+ };
component.onSubmit();
});
@@ -152,7 +167,7 @@ describe('PcapFiltersComponent', () => {
component.endTimeStr = '2320-03-13 13:13:13';
component.search.emit = (model: PcapRequest) => {
expect(model.endTimeMs).toBe(new Date(component.endTimeStr).getTime());
- }
+ };
component.onSubmit();
});
@@ -187,4 +202,195 @@ describe('PcapFiltersComponent', () => {
expect(fixture.componentInstance.model.hasOwnProperty('includeReverse')).toBeTruthy();
});
+ describe('Filter validation', () => {
+
+ function setup() {
+ component.queryRunning = false;
+ fixture.detectChanges();
+ }
+
+ function getFieldWithSubmit(fieldId: string): { field: DebugElement, submit: DebugElement } {
+ const field = fixture.debugElement.query(By.css('[data-qe-id="' + fieldId + '"]'));
+ const submit = fixture.debugElement.query(By.css('[data-qe-id="submit-button"]'));
+ return {
+ field,
+ submit
+ };
+ }
+
+ function setFieldValue(field: DebugElement, value: any) {
+ field.nativeElement.value = value;
+ field.nativeElement.dispatchEvent(new Event('input'));
+ fixture.detectChanges();
+ }
+
+ function isSubmitDisabled(submit: DebugElement): boolean {
+ return submit.classes['disabled'] && submit.nativeElement.disabled;
+ }
+
+ function isFieldInvalid(field: DebugElement): boolean {
+ return field.classes['ng-invalid'];
+ }
+
+ function tearDown(field: DebugElement) {
+ setFieldValue(field, '');
+ };
+
+ beforeEach(setup);
+
+ it('should disable the form if the ip source port is invalid', () => {
+ const invalidValues = [
+ '-42',
+ '-1',
+ 'foobar',
+ '.',
+ '-',
+ '+',
+ 'e',
+ 'E',
+ '3.14',
+ '123456',
+ '65536',
+ '99999',
+ '2352363474576',
+ '1e3',
+ ];
+
+ invalidValues.forEach((value) => {
+ const els = getFieldWithSubmit('ip-src-port');
+ expect(isFieldInvalid(els.field)).toBe(false, 'the field should be valid without ' + value);
+ expect(isSubmitDisabled(els.submit)).toBe(false, 'the submit button should be enabled without ' + value);
+
+ setFieldValue(els.field, value);
+
+ expect(isFieldInvalid(els.field)).toBe(true, 'the field should be invalid with ' + value);
+ expect(isSubmitDisabled(els.submit)).toBe(true, 'the submit button should be disabled with ' + value);
+ tearDown(els.field);
+ });
+ });
+
+ it('should keep the form enabled if the ip source port is valid', () => {
+ const validValues = [
+ '8080',
+ '1024',
+ '3000',
+ '1',
+ '0',
+ '12345',
+ '65535',
+ ];
+
+ validValues.forEach((value) => {
+ const els = getFieldWithSubmit('ip-src-port');
+ expect(isFieldInvalid(els.field)).toBe(false, 'the field should be valid without ' + value);
+ expect(isSubmitDisabled(els.submit)).toBe(false, 'the submit button should be enabled without ' + value);
+
+ setFieldValue(els.field, value);
+
+ expect(isFieldInvalid(els.field)).toBe(false, 'the field should be valid with ' + value);
+ expect(isSubmitDisabled(els.submit)).toBe(false, 'the submit button should be enabled with ' + value);
+ tearDown(els.field);
+ });
+ });
+
+ it('should disable the form if the ip destination port is invalid', () => {
+ const invalidValues = [
+ '-42',
+ '-1',
+ 'foobar',
+ '.',
+ '-',
+ '+',
+ 'e',
+ 'E',
+ '3.14',
+ '123456',
+ '65536',
+ '99999',
+ '2352363474576',
+ '1e3',
+ ];
+
+ invalidValues.forEach((value) => {
+ const els = getFieldWithSubmit('ip-dest-port');
+ expect(isFieldInvalid(els.field)).toBe(false, 'the field should be valid without ' + value);
+ expect(isSubmitDisabled(els.submit)).toBe(false, 'the submit button should be enabled without ' + value);
+
+ setFieldValue(els.field, value);
+
+ expect(isFieldInvalid(els.field)).toBe(true, 'the field should be invalid with ' + value);
+ expect(isSubmitDisabled(els.submit)).toBe(true, 'the submit button should be disabled with ' + value);
+ tearDown(els.field);
+ });
+ });
+
+ it('should keep the form enabled if the ip destination port is valid', () => {
+ const validValues = [
+ '8080',
+ '1024',
+ '3000',
+ '1',
+ '0',
+ '12345',
+ '65535',
+ ];
+
+ validValues.forEach((value) => {
+ const els = getFieldWithSubmit('ip-dest-port');
+ expect(isFieldInvalid(els.field)).toBe(false, 'the field should be valid without ' + value);
+ expect(isSubmitDisabled(els.submit)).toBe(false, 'the submit button should be enabled without ' + value);
+
+ setFieldValue(els.field, value);
+
+ expect(isFieldInvalid(els.field)).toBe(false, 'the field should be valid with ' + value);
+ expect(isSubmitDisabled(els.submit)).toBe(false, 'the submit button should be enabled with ' + value);
+ tearDown(els.field);
+ });
+ });
+
+
+ it('should disable the form if the ip source field is invalid', () => {
+ const invalidValues = [
+ 'tst',
+ 0o0,
+ 0,
+ '111.111.111',
+ '222.222.222.222.222',
+ '333.333.333.333',
+ ];
+
+ invalidValues.forEach((value) => {
+ const els = getFieldWithSubmit('ip-src-addr');
+ expect(isFieldInvalid(els.field)).toBe(false, 'the field should be valid without ' + value);
+ expect(isSubmitDisabled(els.submit)).toBe(false, 'the submit button should be enabled without ' + value);
+
+ setFieldValue(els.field, value);
+
+ expect(isFieldInvalid(els.field)).toBe(true, 'the field should be invalid with ' + value);
+ expect(isSubmitDisabled(els.submit)).toBe(true, 'the submit button should be disabled with ' + value);
+ tearDown(els.field);
+ });
+ });
+
+ it('should keep the form enabled if the ip source field is valid', () => {
+ const validValues = [
+ '0.0.0.0',
+ '222.222.222.222',
+ '255.255.255.255',
+ ];
+
+ validValues.forEach((value) => {
+ const els = getFieldWithSubmit('ip-src-addr');
+ expect(isFieldInvalid(els.field)).toBe(false, 'the field should be valid without ' + value);
+ expect(isSubmitDisabled(els.submit)).toBe(false, 'the submit button should be enabled without ' + value);
+
+ setFieldValue(els.field, value);
+
+ expect(isFieldInvalid(els.field)).toBe(false, 'tthe field should be valid with ' + value);
+ expect(isSubmitDisabled(els.submit)).toBe(false, 'the submit button should be enabled with ' + value);
+ tearDown(els.field);
+ });
+ });
+
+ });
});
http://git-wip-us.apache.org/repos/asf/metron/blob/52de126f/metron-interface/metron-alerts/src/app/pcap/pcap-filters/pcap-filters.component.ts
----------------------------------------------------------------------
diff --git a/metron-interface/metron-alerts/src/app/pcap/pcap-filters/pcap-filters.component.ts b/metron-interface/metron-alerts/src/app/pcap/pcap-filters/pcap-filters.component.ts
index 4f6a3dd..5bbdb67 100644
--- a/metron-interface/metron-alerts/src/app/pcap/pcap-filters/pcap-filters.component.ts
+++ b/metron-interface/metron-alerts/src/app/pcap/pcap-filters/pcap-filters.component.ts
@@ -33,6 +33,8 @@ export class PcapFiltersComponent implements OnInit {
startTimeStr: string;
endTimeStr: string;
+ ipSrcPort: string = '';
+ ipDstPort: string = '';
model = new PcapRequest();
@@ -49,6 +51,9 @@ export class PcapFiltersComponent implements OnInit {
onSubmit() {
this.model.startTimeMs = new Date(this.startTimeStr).getTime();
this.model.endTimeMs = new Date(this.endTimeStr).getTime();
+ this.model.ipSrcPort = +this.ipSrcPort;
+ this.model.ipDstPort = +this.ipDstPort;
+
this.search.emit(this.model);
}
}