METRON-1724 Date/time validation missing in PCAP query (tiborm via nickwallen) closes apache/metron#1172
Project: http://git-wip-us.apache.org/repos/asf/metron/repo Commit: http://git-wip-us.apache.org/repos/asf/metron/commit/e66cfc80 Tree: http://git-wip-us.apache.org/repos/asf/metron/tree/e66cfc80 Diff: http://git-wip-us.apache.org/repos/asf/metron/diff/e66cfc80 Branch: refs/remotes/apache/feature/METRON-1699-create-batch-profiler Commit: e66cfc80e6a6fa53110c3f2fa8ee0d31ea997bf6 Parents: 9fdccba Author: tiborm <[email protected]> Authored: Mon Aug 27 09:04:21 2018 -0400 Committer: nickallen <[email protected]> Committed: Mon Aug 27 09:04:21 2018 -0400 ---------------------------------------------------------------------- .../src/app/pcap/model/pcap.mock.ts | 4 +- .../src/app/pcap/model/pcap.request.ts | 18 +- .../pcap-filters/pcap-filters.component.html | 55 +++-- .../pcap-filters/pcap-filters.component.scss | 13 +- .../pcap-filters/pcap-filters.component.spec.ts | 207 ++++++++++--------- .../pcap/pcap-filters/pcap-filters.component.ts | 156 +++++++++++--- .../app/pcap/pcap-list/pcap-list.component.html | 4 +- .../pcap-packet-line.component.spec.ts | 3 +- .../pcap-packet-line.component.ts | 22 +- .../pcap-panel/pcap-panel.component.spec.ts | 16 +- .../app/pcap/pcap-panel/pcap-panel.component.ts | 6 +- .../metron-alerts/src/app/pcap/pcap.module.ts | 5 +- .../date-picker/date-picker.component.scss | 14 +- .../shared/date-picker/date-picker.component.ts | 34 ++- .../shared/date-picker/date-picker.module.ts | 3 +- .../metron-alerts/src/app/utils/constants.ts | 3 + .../metron-alerts/src/app/utils/utils.ts | 12 +- 17 files changed, 360 insertions(+), 215 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/metron/blob/e66cfc80/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 bf02da8..c867fe9 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/e66cfc80/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 8afc963..3e00a4b 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 @@ -17,13 +17,13 @@ */ export class PcapRequest { - startTimeMs: number = 0; - endTimeMs: number = 150000000000000000; - ipSrcAddr: string = ''; - ipSrcPort: number; - ipDstAddr: string = ''; - ipDstPort: number; - protocol: string = ''; - packetFilter: string = ''; - includeReverse: boolean = false; + startTimeMs: number; + endTimeMs: number; + ipSrcAddr = ''; + ipSrcPort = ''; + ipDstAddr = ''; + ipDstPort = ''; + protocol = ''; + packetFilter = ''; + includeReverse = false; } http://git-wip-us.apache.org/repos/asf/metron/blob/e66cfc80/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 039307a..c7a4db5 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 @@ -11,52 +11,63 @@ OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> -<form (ngSubmit)="onSubmit()" #f="ngForm" class="form-inline pcap-search"> +<form (ngSubmit)="onSubmit()" #f="ngForm" [formGroup]="filterForm" class="form-inline pcap-search"> <div class="form-group"> <label>From</label> - <app-date-picker id="startTime" [(date)]="startTimeStr"> </app-date-picker> + <app-date-picker formControlName="startTime" data-qe-id="start-time"> </app-date-picker> </div> <div class="form-group"> <label>To</label> - <app-date-picker id="endTime" [(date)]="endTimeStr"> </app-date-picker> + <app-date-picker formControlName="endTime" data-qe-id="end-time"> </app-date-picker> </div> <div class="form-group"> - <label for="ipSrcAddr">IP Source Address</label> - <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"> + <label>IP Source Address</label> + <input class="form-control" formControlName="ipSrcAddr" data-qe-id="ip-src-addr"> </div> <div class="form-group"> - <label for="ipSrcPort">IP Source Port</label> - <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"> + <label>IP Source Port</label> + <input class="form-control" formControlName="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="^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}$" [(ngModel)]="model.ipDstAddr" data-qe-id="ip-dst-addr"> + <div class="form-group"> + <label>IP Dest Address</label> + <input class="form-control" formControlName="ipDstAddr" data-qe-id="ip-dst-addr"> </div> <div class="form-group"> - <label for="ipDstPort">IP Dest Port</label> - <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"> + <label>IP Dest Port</label> + <input class="form-control" formControlName="ipDstPort" data-qe-id="ip-dst-port"> </div> - <div class="form-group"> - <label for="protocol">Protocol</label> - <input id="protocol" name="protocol" #protocol="ngModel" class="form-control" [(ngModel)]="model.protocol"> - </div> + <div class="form-group"> + <label>Protocol</label> + <input class="form-control" formControlName="protocol" data-qe-id="protocol"> + </div> - <div class="form-group"> - <label for="includeReverse">Include Reverse Traffic</label> - <input id="includeReverse" name="includeReverse" #includeReverse="ngModel" class="form-control" type="checkbox" [(ngModel)]="model.includeReverse"> - </div> + <div class="form-group"> + <label>Include Reverse Traffic</label> + <input class="form-control" type="checkbox" formControlName="includeReverse" data-qe-id="include-reverse"> + </div> <div class="form-group"> - <label for="filter">Filter</label> - <input id="filter" name="filter" #filter="ngModel" class="form-control" [(ngModel)]="model.packetFilter"> + <label>Filter</label> + <input class="form-control" formControlName="packetFilter" data-qe-id="packet-filter"> </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" data-qe-id="submit-button"></button> + <button type="submit" [ngClass]="{'disabled': filterForm.status === 'INVALID' || queryRunning}" class="btn btn-primary btn-search" [disabled]="filterForm.status === 'INVALID' || queryRunning" data-qe-id="submit-button"></button> </div> </form> +<div class="pcap-search-validation-errors alert alert-danger" *ngIf="filterForm.invalid"> + <h5 class="alert-heading">Validation errors</h5> + <ul> + <li *ngIf="filterForm.controls.startTime.invalid || filterForm.controls.endTime.invalid">Selected date range is invalid. The "To" date must be later than the "From" date and the "To" date cannot be in the future.</li> + <li *ngIf="filterForm.controls.ipSrcAddr.invalid">Source IP address format is invalid. Use valid v4IP format, for example, 192.168.0.1</li> + <li *ngIf="filterForm.controls.ipSrcPort.invalid">Source port is invalid. Port number must be within the range of 0-65535.</li> + <li *ngIf="filterForm.controls.ipDstAddr.invalid">Destination IP address format is invalid. Use valid v4IP format, for example, 192.168.0.1</li> + <li *ngIf="filterForm.controls.ipDstPort.invalid">Destination port is invalid. Port number must be within the range of 0-65535.</li> + </ul> +</div> http://git-wip-us.apache.org/repos/asf/metron/blob/e66cfc80/metron-interface/metron-alerts/src/app/pcap/pcap-filters/pcap-filters.component.scss ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/pcap/pcap-filters/pcap-filters.component.scss b/metron-interface/metron-alerts/src/app/pcap/pcap-filters/pcap-filters.component.scss index b33e804..909ce02 100644 --- a/metron-interface/metron-alerts/src/app/pcap/pcap-filters/pcap-filters.component.scss +++ b/metron-interface/metron-alerts/src/app/pcap/pcap-filters/pcap-filters.component.scss @@ -19,11 +19,7 @@ @import "../../../styles.scss"; @import "../../../variables.scss"; -.ng-valid[required], .ng-valid.required { - -} - -.ng-invalid:not(form) { +.ng-invalid:not(form) { border-left: 5px solid #a94442; /* red */ } @@ -35,7 +31,6 @@ } .btn-search { - min-width: 42px; padding-left: 0; padding-right: 0; @@ -67,3 +62,9 @@ background: $icon-button-background; } } + +.pcap-search-validation-errors { + & ul { + margin: 0 + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/e66cfc80/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 3f1ab07..c707451 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 @@ -19,19 +19,14 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { By } from '@angular/platform-browser'; +import { DebugElement, SimpleChange } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; + import { PcapFiltersComponent } from './pcap-filters.component'; -import { FormsModule } from '../../../../node_modules/@angular/forms'; -import { Component, Input, Output, EventEmitter, DebugElement, SimpleChange } from '@angular/core'; +import { DatePickerModule } from '../../shared/date-picker/date-picker.module'; import { PcapRequest } from '../model/pcap.request'; - -@Component({ - selector: 'app-date-picker', - template: '<input type="text" [(value)]="date">', -}) -class FakeDatePickerComponent { - @Input() date: string; - @Output() dateChange = new EventEmitter<string>(); -} +import { DEFAULT_TIMESTAMP_FORMAT } from '../../utils/constants'; +import * as moment from 'moment/moment'; describe('PcapFiltersComponent', () => { let component: PcapFiltersComponent; @@ -40,10 +35,11 @@ describe('PcapFiltersComponent', () => { beforeEach(async(() => { TestBed.configureTestingModule({ imports: [ - FormsModule + FormsModule, + ReactiveFormsModule, + DatePickerModule, ], declarations: [ - FakeDatePickerComponent, PcapFiltersComponent, ] }) @@ -59,114 +55,113 @@ describe('PcapFiltersComponent', () => { }); it('From date should be bound to the component', () => { - let input = fixture.debugElement.query(By.css('#startTime')); + let input = fixture.debugElement.query(By.css('[data-qe-id="start-time"]')); const dateString = '2020-11-11 11:11:11'; - input.componentInstance.dateChange.emit(dateString); + input.componentInstance.onChange(dateString); fixture.detectChanges(); - - expect(component.startTimeStr).toBe(dateString); + expect(component.filterForm.controls.startTime.value).toBe(dateString); }); it('To date should be bound to the component', () => { - let input = fixture.debugElement.query(By.css('#endTime')); + let input = fixture.debugElement.query(By.css('[data-qe-id="end-time"]')); const dateString = '2030-11-11 11:11:11'; - input.componentInstance.dateChange.emit(dateString); + input.componentInstance.onChange(dateString); fixture.detectChanges(); - expect(component.endTimeStr).toBe(dateString); + expect(component.filterForm.controls.endTime.value).toBe(dateString); }); it('IP Source Address should be bound to the model', () => { - let input: HTMLInputElement = fixture.nativeElement.querySelector('[name="ipSrcAddr"]'); + let input: HTMLInputElement = fixture.nativeElement.querySelector('[data-qe-id="ip-src-addr"]'); input.value = '192.168.0.1'; input.dispatchEvent(new Event('input')); fixture.detectChanges(); - expect(component.model.ipSrcAddr).toBe('192.168.0.1'); + expect(component.filterForm.controls.ipSrcAddr.value).toBe('192.168.0.1'); }); it('IP Source Port should be bound to the property', () => { - let input: HTMLInputElement = fixture.nativeElement.querySelector('[name="ipSrcPort"]'); + let input: HTMLInputElement = fixture.nativeElement.querySelector('[data-qe-id="ip-src-port"]'); input.value = '9345'; input.dispatchEvent(new Event('input')); fixture.detectChanges(); - expect(component.ipSrcPort).toBe('9345'); + expect(component.filterForm.controls.ipSrcPort.value).toBe('9345'); }); it('IP Source Port should be converted to number on submit', () => { - component.ipSrcPort = '42'; + component.filterForm.patchValue({ ipSrcPort: '42' }); component.search.emit = (model: PcapRequest) => { - expect(model.ipSrcPort).toBe(42); + expect(model.ipSrcPort).toBe('42'); }; component.onSubmit(); }); it('IP Dest Address should be bound to the model', () => { - let input: HTMLInputElement = fixture.nativeElement.querySelector('[name="ipDstAddr"]'); + let input: HTMLInputElement = fixture.nativeElement.querySelector('[data-qe-id="ip-dst-addr"]'); input.value = '256.0.0.7'; input.dispatchEvent(new Event('input')); fixture.detectChanges(); - expect(component.model.ipDstAddr).toBe('256.0.0.7'); + expect(component.filterForm.controls.ipDstAddr.value).toBe('256.0.0.7'); }); it('IP Dest Port should be bound to the property', () => { - let input: HTMLInputElement = fixture.nativeElement.querySelector('[name="ipDstPort"]'); + let input: HTMLInputElement = fixture.nativeElement.querySelector('[data-qe-id="ip-dst-port"]'); input.value = '8989'; input.dispatchEvent(new Event('input')); fixture.detectChanges(); - expect(component.ipDstPort).toBe('8989'); + expect(component.filterForm.controls.ipDstPort.value).toBe('8989'); }); it('IP Dest Port should be converted to number on submit', () => { - component.ipDstPort = '42'; + component.filterForm.patchValue({ ipDstPort: '42' }); component.search.emit = (model: PcapRequest) => { - expect(model.ipDstPort).toBe(42); + expect(model.ipDstPort).toBe('42'); }; component.onSubmit(); }); it('Protocol should be bound to the model', () => { - let input: HTMLInputElement = fixture.nativeElement.querySelector('[name="protocol"]'); + let input: HTMLInputElement = fixture.nativeElement.querySelector('[data-qe-id="protocol"]'); input.value = 'TCP'; input.dispatchEvent(new Event('input')); fixture.detectChanges(); - expect(component.model.protocol).toBe('TCP'); + expect(component.filterForm.controls.protocol.value).toBe('TCP'); }); it('Include Reverse Traffic should be bound to the model', () => { - let input: HTMLInputElement = fixture.nativeElement.querySelector('[name="includeReverse"]'); + let input: HTMLInputElement = fixture.nativeElement.querySelector('[data-qe-id="include-reverse"]'); input.click(); input.dispatchEvent(new Event('input')); fixture.detectChanges(); - expect(component.model.includeReverse).toBe(true); + expect(component.filterForm.controls.includeReverse.value).toBe(true); }); it('Text filter should be bound to the model', () => { - let input: HTMLInputElement = fixture.nativeElement.querySelector('[name="protocol"]'); + let input: HTMLInputElement = fixture.nativeElement.querySelector('[data-qe-id="packet-filter"]'); input.value = 'TestStringFilter'; input.dispatchEvent(new Event('input')); fixture.detectChanges(); - expect(component.model.protocol).toBe('TestStringFilter'); + expect(component.filterForm.controls.packetFilter.value).toBe('TestStringFilter'); }); it('From date should be converted to timestamp on submit', () => { - component.startTimeStr = '2220-12-12 12:12:12'; + component.filterForm.patchValue({ startTime: '2220-12-12 12:12:12' }); component.search.emit = (model: PcapRequest) => { - expect(model.startTimeMs).toBe(new Date(component.startTimeStr).getTime()); + expect(model.startTimeMs).toBe(new Date(component.filterForm.controls.startTime.value).getTime()); }; component.onSubmit(); }); it('To date should be converted to timestamp on submit', () => { - component.endTimeStr = '2320-03-13 13:13:13'; + component.filterForm.patchValue({ endTimeStr: '2320-03-13 13:13:13' }); component.search.emit = (model: PcapRequest) => { - expect(model.endTimeMs).toBe(new Date(component.endTimeStr).getTime()); + expect(model.endTimeMs).toBe(new Date(component.filterForm.controls.endTime.value).getTime()); }; component.onSubmit(); }); @@ -179,19 +174,6 @@ describe('PcapFiltersComponent', () => { component.onSubmit(); }); - it('Port fields should be removed from request when set to empty', () => { - component.model.ipSrcPort = 44; - component.model.ipDstPort = 44; - component.ipSrcPort = ''; - component.ipDstPort = ''; - - component.search.emit = (model: PcapRequest) => { - expect(model.ipSrcPort).toBeFalsy(); - expect(model.ipDstPort).toBeFalsy(); - }; - component.onSubmit(); - }); - it('Filter should have an output called search', () => { component.search.subscribe((filterModel) => { expect(filterModel).toBeDefined(); @@ -205,68 +187,43 @@ describe('PcapFiltersComponent', () => { expect(component.search.emit).toHaveBeenCalled(); }); - it('Search event should contains the filter model', () => { - spyOn(component.search, 'emit'); - component.onSubmit(); - expect(component.search.emit).toHaveBeenCalledWith(component.model); - }); - - it('Filter model structure aka PcapRequest', () => { - expect(fixture.componentInstance.model.hasOwnProperty('startTimeMs')).toBeTruthy(); - expect(fixture.componentInstance.model.hasOwnProperty('endTimeMs')).toBeTruthy(); - expect(fixture.componentInstance.model.hasOwnProperty('ipSrcAddr')).toBeTruthy(); - expect(fixture.componentInstance.model.hasOwnProperty('ipSrcPort')).toBeFalsy(); - expect(fixture.componentInstance.model.hasOwnProperty('ipDstAddr')).toBeTruthy(); - expect(fixture.componentInstance.model.hasOwnProperty('ipDstPort')).toBeFalsy(); - expect(fixture.componentInstance.model.hasOwnProperty('protocol')).toBeTruthy(); - expect(fixture.componentInstance.model.hasOwnProperty('packetFilter')).toBeTruthy(); - expect(fixture.componentInstance.model.hasOwnProperty('includeReverse')).toBeTruthy(); - }); - it('should update request on changes', () => { + const startTimeStr = '2220-12-12 12:12:12'; + const endTimeStr = '2320-03-13 13:13:13'; - let startTimeStr = '2220-12-12 12:12:12'; - let endTimeStr = '2320-03-13 13:13:13'; - - let newModel = { - startTimeMs: new Date(startTimeStr).getTime(), - endTimeMs: new Date(endTimeStr).getTime(), - ipSrcPort: 9345, - ipDstPort: 8989 - }; - component.model.startTimeMs = new Date(startTimeStr).getTime(); - component.model.endTimeMs = new Date(endTimeStr).getTime(); + const newModel = new PcapRequest(); + newModel.startTimeMs = new Date(startTimeStr).getTime(); + newModel.endTimeMs = new Date(endTimeStr).getTime(); + newModel.ipSrcPort = '9345'; + newModel.ipDstPort = '8989'; component.ngOnChanges({ model: new SimpleChange(null, newModel, false) }); - expect(component.startTimeStr).toBe(startTimeStr); - expect(component.endTimeStr).toBe(endTimeStr); - expect(component.ipSrcPort).toBe('9345'); - expect(component.ipDstPort).toBe('8989'); + expect(component.filterForm.controls.startTime.value).toBe(startTimeStr); + expect(component.filterForm.controls.endTime.value).toBe(endTimeStr); + expect(component.filterForm.controls.ipSrcPort.value).toBe('9345'); + expect(component.filterForm.controls.ipDstPort.value).toBe('8989'); }); it('should update request on changes with missing port filters', () => { - let startTimeStr = '2220-12-12 12:12:12'; - let endTimeStr = '2320-03-13 13:13:13'; + const startTimeStr = '2220-12-12 12:12:12'; + const endTimeStr = '2320-03-13 13:13:13'; - let newModel = { - startTimeMs: new Date(startTimeStr).getTime(), - endTimeMs: new Date(endTimeStr).getTime() - }; - component.model.startTimeMs = new Date(startTimeStr).getTime(); - component.model.endTimeMs = new Date(endTimeStr).getTime(); + let newModel = new PcapRequest(); + newModel.startTimeMs = new Date(startTimeStr).getTime(); + newModel.endTimeMs = new Date(endTimeStr).getTime(); component.ngOnChanges({ model: new SimpleChange(null, newModel, false) }); - expect(component.startTimeStr).toBe(startTimeStr); - expect(component.endTimeStr).toBe(endTimeStr); - expect(component.ipSrcPort).toBe(''); - expect(component.ipDstPort).toBe(''); + expect(component.filterForm.controls.startTime.value).toBe(startTimeStr); + expect(component.filterForm.controls.endTime.value).toBe(endTimeStr); + expect(component.filterForm.controls.ipSrcPort.value).toBe(''); + expect(component.filterForm.controls.ipDstPort.value).toBe(''); }); describe('Filter validation', () => { @@ -379,7 +336,7 @@ describe('PcapFiltersComponent', () => { ]; invalidValues.forEach((value) => { - const els = getFieldWithSubmit('ip-dest-port'); + const els = getFieldWithSubmit('ip-dst-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); @@ -403,7 +360,7 @@ describe('PcapFiltersComponent', () => { ]; validValues.forEach((value) => { - const els = getFieldWithSubmit('ip-dest-port'); + const els = getFieldWithSubmit('ip-dst-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); @@ -453,11 +410,55 @@ describe('PcapFiltersComponent', () => { setFieldValue(els.field, value); - expect(isFieldInvalid(els.field)).toBe(false, 'tthe field should be valid with ' + 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('start date should be valid by default', () => { + expect(component.filterForm.get('startTime').valid).toBe(true); + }); + + it('start date is invalid if it is bigger than end date', () => { + // start time is bigger than end time + component.filterForm.patchValue({ + startTime: '2018-08-24 16:30:00', + endTime: '2018-08-23 16:30:00' + }); + + expect(component.filterForm.get('startTime').valid).toBe(false); + }); + + it('start date should be valid again based on the end date', () => { + // start time is bigger than end time + component.filterForm.patchValue({ + startTime: '2018-08-24 16:30:00', + endTime: '2018-08-23 16:30:00' + }); + + expect(component.filterForm.get('startTime').valid).toBe(false); + + component.filterForm.patchValue({ + endTime: '2018-08-25 16:30:00' + }); + + expect(component.filterForm.get('startTime').valid).toBe(true); + }); + + it('end date should be valid by default', () => { + expect(component.filterForm.get('endTime').valid).toBe(true); + }); + + it('end date is invalid if it is in the future', () => { + + expect(component.filterForm.get('endTime').valid).toBe(true); + + component.filterForm.patchValue({ + endTime: moment(new Date()).add(2, 'days').format(DEFAULT_TIMESTAMP_FORMAT) + }); + + expect(component.filterForm.get('endTime').valid).toBe(false); + }); }); }); http://git-wip-us.apache.org/repos/asf/metron/blob/e66cfc80/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 b23a2e2..7cc8980 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 @@ -15,63 +15,153 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {Component, Input, Output, EventEmitter, OnInit, OnChanges, SimpleChanges} from '@angular/core'; +import {Component, Input, Output, EventEmitter, OnChanges, OnInit, OnDestroy, SimpleChanges} from '@angular/core'; +import { FormGroup, FormControl, Validators, ValidationErrors } from '@angular/forms'; + import * as moment from 'moment/moment'; -import { DEFAULT_TIMESTAMP_FORMAT } from '../../utils/constants'; +import { DEFAULT_START_TIME, DEFAULT_END_TIME, DEFAULT_TIMESTAMP_FORMAT } from '../../utils/constants'; import { PcapRequest } from '../model/pcap.request'; +import { Observable, Subscription } from 'rxjs'; + +function validateStartDate(formControl: FormControl): ValidationErrors | null { + if (!formControl.parent) { + return null; + } + const filterForm = formControl.parent; + const startTimeMs = new Date(filterForm.controls['startTime'].value).getTime(); + const endTimeMs = new Date(filterForm.controls['endTime'].value).getTime(); + if (startTimeMs > endTimeMs) { + return { error: 'Start time cannot be bigger than end date.' }; + } + return null; +} + +function validateEndDate(formControl: FormControl): ValidationErrors | null { + if (!formControl.parent) { + return null; + } + const filterForm = formControl.parent; + const endTimeMs = new Date(filterForm.controls['endTime'].value).getTime(); + if (endTimeMs > new Date().getTime()) { + return { error: 'End time cannot be in the future.' }; + } + return null; +} + +function transformPcapRequestToFormGroupValue(model: PcapRequest): PcapFilterFormValue { + const startTimeStr = moment(model.startTimeMs > 0 ? model.startTimeMs : DEFAULT_START_TIME).format(DEFAULT_TIMESTAMP_FORMAT); + let endTimeStr = moment(model.endTimeMs).format(DEFAULT_TIMESTAMP_FORMAT); + if (isNaN((new Date(model.endTimeMs).getTime()))) { + endTimeStr = moment(DEFAULT_END_TIME).format(DEFAULT_TIMESTAMP_FORMAT); + } else { + endTimeStr = moment(model.endTimeMs).format(DEFAULT_TIMESTAMP_FORMAT); + } + + return { + startTime: startTimeStr, + endTime: endTimeStr, + ipSrcAddr: model.ipSrcAddr, + ipDstAddr: model.ipDstAddr, + ipSrcPort: model.ipSrcPort ? String(model.ipSrcPort) : '', + ipDstPort: model.ipDstPort ? String(model.ipDstPort) : '', + protocol: model.protocol, + includeReverse: model.includeReverse, + packetFilter: model.packetFilter + }; +} + +function transformFormGroupValueToPcapRequest(control: FormGroup): PcapRequest { + const pcapRequest = new PcapRequest(); + pcapRequest.startTimeMs = new Date(control.value.startTime).getTime(); + pcapRequest.endTimeMs = new Date(control.value.endTime).getTime(); + pcapRequest.ipSrcAddr = control.value.ipSrcAddr; + pcapRequest.ipDstAddr = control.value.ipDstAddr; + pcapRequest.ipSrcPort = control.value.ipSrcPort; + pcapRequest.ipDstPort = control.value.ipDstPort; + pcapRequest.protocol = control.value.protocol; + pcapRequest.includeReverse = control.value.includeReverse; + pcapRequest.packetFilter = control.value.packetFilter; + return pcapRequest; +} + +export type PcapFilterFormValue = { + startTime: string, + endTime: string, + ipSrcAddr: string, + ipDstAddr: string, + ipSrcPort: string, + ipDstPort: string, + protocol: string, + includeReverse: boolean, + packetFilter: string +}; @Component({ selector: 'app-pcap-filters', templateUrl: './pcap-filters.component.html', styleUrls: ['./pcap-filters.component.scss'] }) -export class PcapFiltersComponent implements OnInit, OnChanges { +export class PcapFiltersComponent implements OnInit, OnChanges, OnDestroy { - @Input() queryRunning: boolean = true; + @Input() queryRunning = true; @Input() model: PcapRequest = new PcapRequest(); @Output() search: EventEmitter<PcapRequest> = new EventEmitter<PcapRequest>(); - startTimeStr: string; - endTimeStr: string; - ipSrcPort: string = ''; - ipDstPort: string = ''; + private validIp: RegExp = /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}$/; + private validPort: RegExp = /^([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])$/; - constructor() { } + private dateRangeChangeSubscription: Subscription; - ngOnInit() { - const endTime = new Date(); - const startTime = new Date().setDate(endTime.getDate() - 5); + filterForm = new FormGroup({ + startTime: new FormControl(moment(DEFAULT_START_TIME).format(DEFAULT_TIMESTAMP_FORMAT), validateStartDate), + endTime: new FormControl(moment(DEFAULT_END_TIME).format(DEFAULT_TIMESTAMP_FORMAT), validateEndDate), + ipSrcAddr: new FormControl('', Validators.pattern(this.validIp)), + ipSrcPort: new FormControl('', Validators.pattern(this.validPort)), + ipDstAddr: new FormControl('', Validators.pattern(this.validIp)), + ipDstPort: new FormControl('', Validators.pattern(this.validPort)), + protocol: new FormControl(''), + includeReverse: new FormControl(), + packetFilter: new FormControl(''), + }); + + subscribeToDateRangeChanges(callback: () => void): Subscription { + const startTimeChanges: Observable<string> = this.filterForm.get('startTime').valueChanges; + const endTimeChanges: Observable<string> = this.filterForm.get('endTime').valueChanges; + return startTimeChanges.merge(endTimeChanges).subscribe(callback); + } - this.startTimeStr = moment(startTime).format(DEFAULT_TIMESTAMP_FORMAT); - this.endTimeStr = moment(endTime).format(DEFAULT_TIMESTAMP_FORMAT); + forceValidateDateRangeFields() { + [ + this.filterForm.get('startTime'), + this.filterForm.get('endTime'), + ].forEach((control: FormControl) => { + control.updateValueAndValidity({ + emitEvent: false + }); + }); + } + + ngOnInit() { + this.dateRangeChangeSubscription = this.subscribeToDateRangeChanges(() => { + this.forceValidateDateRangeFields(); + }); } ngOnChanges(changes: SimpleChanges): void { if (changes['model']) { - this.startTimeStr = moment(changes['model'].currentValue.startTimeMs).format(DEFAULT_TIMESTAMP_FORMAT); - this.endTimeStr = moment(changes['model'].currentValue.endTimeMs).format(DEFAULT_TIMESTAMP_FORMAT); - let newIpSrcPort = changes['model'].currentValue.ipSrcPort; - this.ipSrcPort = newIpSrcPort ? newIpSrcPort.toString() : ''; - let newIpDstPort = changes['model'].currentValue.ipDstPort; - this.ipDstPort = newIpDstPort ? newIpDstPort.toString() : ''; + const newModel: PcapRequest = changes['model'].currentValue; + const controlValue = transformPcapRequestToFormGroupValue(newModel); + this.filterForm.setValue(controlValue); } } onSubmit() { - this.model.startTimeMs = moment(this.startTimeStr, DEFAULT_TIMESTAMP_FORMAT).valueOf(); - this.model.endTimeMs = moment(this.endTimeStr, DEFAULT_TIMESTAMP_FORMAT).valueOf(); - if (this.ipSrcPort !== '') { - this.model.ipSrcPort = +this.ipSrcPort; - } else { - delete this.model.ipSrcPort; - } - if (this.ipDstPort !== '') { - this.model.ipDstPort = +this.ipDstPort; - } else { - delete this.model.ipDstPort; - } + const pcapRequest = transformFormGroupValueToPcapRequest(this.filterForm); + this.search.emit(pcapRequest); + } - this.search.emit(this.model); + ngOnDestroy() { + this.dateRangeChangeSubscription.unsubscribe(); } } http://git-wip-us.apache.org/repos/asf/metron/blob/e66cfc80/metron-interface/metron-alerts/src/app/pcap/pcap-list/pcap-list.component.html ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/pcap/pcap-list/pcap-list.component.html b/metron-interface/metron-alerts/src/app/pcap/pcap-list/pcap-list.component.html index 5337935..10b7be2 100644 --- a/metron-interface/metron-alerts/src/app/pcap/pcap-list/pcap-list.component.html +++ b/metron-interface/metron-alerts/src/app/pcap/pcap-list/pcap-list.component.html @@ -16,9 +16,9 @@ <thead> <tr> <th scope="col">Timestamp</th> - <th scope="col">Source Addr</th> + <th scope="col">Source Address</th> <th scope="col">Source Port</th> - <th scope="col">Dest Addr</th> + <th scope="col">Dest Address</th> <th scope="col">Dest Port</th> <th scope="col">Protocol</th> </tr> http://git-wip-us.apache.org/repos/asf/metron/blob/e66cfc80/metron-interface/metron-alerts/src/app/pcap/pcap-packet-line/pcap-packet-line.component.spec.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/pcap/pcap-packet-line/pcap-packet-line.component.spec.ts b/metron-interface/metron-alerts/src/app/pcap/pcap-packet-line/pcap-packet-line.component.spec.ts index 00f081f..dccfaa2 100644 --- a/metron-interface/metron-alerts/src/app/pcap/pcap-packet-line/pcap-packet-line.component.spec.ts +++ b/metron-interface/metron-alerts/src/app/pcap/pcap-packet-line/pcap-packet-line.component.spec.ts @@ -16,8 +16,7 @@ * limitations under the License. */ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { fakePacket } from '../model/pdml.mock'; -import { fakeUdpPacket } from '../model/pdml.mock'; +import { fakePacket, fakeUdpPacket } from '../model/pdml.mock'; import { PcapPacketLineComponent } from './pcap-packet-line.component'; http://git-wip-us.apache.org/repos/asf/metron/blob/e66cfc80/metron-interface/metron-alerts/src/app/pcap/pcap-packet-line/pcap-packet-line.component.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/pcap/pcap-packet-line/pcap-packet-line.component.ts b/metron-interface/metron-alerts/src/app/pcap/pcap-packet-line/pcap-packet-line.component.ts index b1546af..913aff9 100644 --- a/metron-interface/metron-alerts/src/app/pcap/pcap-packet-line/pcap-packet-line.component.ts +++ b/metron-interface/metron-alerts/src/app/pcap/pcap-packet-line/pcap-packet-line.component.ts @@ -16,7 +16,7 @@ * limitations under the License. */ import { Component, OnInit, Input } from '@angular/core'; -import { PdmlPacket, PdmlProto, PdmlField } from '../model/pdml' +import { PdmlPacket, PdmlProto, PdmlField } from '../model/pdml'; @Component({ selector: '[app-pcap-packet-line]', @@ -37,18 +37,18 @@ export class PcapPacketLineComponent implements OnInit { constructor() { } ngOnInit() { - const genProto: PdmlProto = this.packet.protos.filter(p => p.name == "geninfo")[0]; - const ipProto: PdmlProto = this.packet.protos.filter(p => p.name == "ip")[0]; - const tcpProto: PdmlProto = this.packet.protos.filter(p => p.name == "tcp")[0]; - const udpProto: PdmlProto = this.packet.protos.filter(p => p.name == "udp")[0]; + const genProto: PdmlProto = this.packet.protos.filter(p => p.name === 'geninfo')[0]; + const ipProto: PdmlProto = this.packet.protos.filter(p => p.name === 'ip')[0]; + const tcpProto: PdmlProto = this.packet.protos.filter(p => p.name === 'tcp')[0]; + const udpProto: PdmlProto = this.packet.protos.filter(p => p.name === 'udp')[0]; this.ip = { - timestamp: PdmlProto.findField(genProto,'timestamp'), - ipSrcAddr: PdmlProto.findField(ipProto,'ip.src'), - ipSrcPort: tcpProto ? PdmlProto.findField(tcpProto,'tcp.srcport') : PdmlProto.findField(udpProto,'udp.srcport'), - ipDestAddr: PdmlProto.findField(ipProto,'ip.dst'), - ipDestPort: tcpProto ? PdmlProto.findField(tcpProto,'tcp.dstport') : PdmlProto.findField(udpProto,'udp.dstport'), - protocol: PdmlProto.findField(ipProto,'ip.proto') + timestamp: PdmlProto.findField(genProto, 'timestamp'), + ipSrcAddr: PdmlProto.findField(ipProto, 'ip.src'), + ipSrcPort: tcpProto ? PdmlProto.findField(tcpProto, 'tcp.srcport') : PdmlProto.findField(udpProto, 'udp.srcport'), + ipDestAddr: PdmlProto.findField(ipProto, 'ip.dst'), + ipDestPort: tcpProto ? PdmlProto.findField(tcpProto, 'tcp.dstport') : PdmlProto.findField(udpProto, 'udp.dstport'), + protocol: PdmlProto.findField(ipProto, 'ip.proto') }; } http://git-wip-us.apache.org/repos/asf/metron/blob/e66cfc80/metron-interface/metron-alerts/src/app/pcap/pcap-panel/pcap-panel.component.spec.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/pcap/pcap-panel/pcap-panel.component.spec.ts b/metron-interface/metron-alerts/src/app/pcap/pcap-panel/pcap-panel.component.spec.ts index fe4df1e..2ebf884 100644 --- a/metron-interface/metron-alerts/src/app/pcap/pcap-panel/pcap-panel.component.spec.ts +++ b/metron-interface/metron-alerts/src/app/pcap/pcap-panel/pcap-panel.component.spec.ts @@ -26,8 +26,8 @@ import { PcapPagination } from '../model/pcap-pagination'; import { By } from '../../../../node_modules/@angular/platform-browser'; import { PcapRequest } from '../model/pcap.request'; import { defer } from 'rxjs/observable/defer'; -import {Observable} from "rxjs/Observable"; -import {RestError} from "../../model/rest-error"; +import { Observable } from 'rxjs/Observable'; +import { RestError } from '../../model/rest-error'; @Component({ selector: 'app-pcap-filters', @@ -349,7 +349,7 @@ describe('PcapPanelComponent', () => { it('should hide the progress bar if the user clicks on the cancel button', fakeAsync(() => { component.queryRunning = true; - component.queryId = 'testid'; + component.queryId = '42'; fixture.detectChanges(); expect(fixture.debugElement.query(By.css('.pcap-progress'))).toBeDefined(); @@ -360,7 +360,7 @@ describe('PcapPanelComponent', () => { tick(); fixture.detectChanges(); - expect(fixture.debugElement.query(By.css('.pcap-progress'))).toBeFalsy(); + expect(fixture.debugElement.query(By.css('.pcap-progress')) == null).toBe(true); })); it('should hide the progress bar if the cancellation request fails', fakeAsync(() => { @@ -370,7 +370,7 @@ describe('PcapPanelComponent', () => { ); component.queryRunning = true; - component.queryId = 'testid'; + component.queryId = '42'; fixture.detectChanges(); expect(fixture.debugElement.query(By.css('.pcap-progress'))).toBeDefined(); @@ -381,7 +381,7 @@ describe('PcapPanelComponent', () => { tick(); fixture.detectChanges(); - expect(fixture.debugElement.query(By.css('.pcap-progress'))).toBeFalsy(); + expect(fixture.debugElement.query(By.css('.pcap-progress')) == null).toBe(true); })); it('should show an error message if the cancellation request fails', fakeAsync(() => { @@ -392,9 +392,9 @@ describe('PcapPanelComponent', () => { ); component.queryRunning = true; - component.queryId = 'testid'; + component.queryId = '42'; fixture.detectChanges(); - expect(fixture.debugElement.query(By.css('[data-qe-id="error"]'))).toBeFalsy(); + expect(fixture.debugElement.query(By.css('[data-qe-id="error"]')) == null).toBe(true); const cancelBtn = fixture.debugElement.query(By.css('[data-qe-id="pcap-cancel-query-button"]')); const cancelBtnEl = cancelBtn.nativeElement; http://git-wip-us.apache.org/repos/asf/metron/blob/e66cfc80/metron-interface/metron-alerts/src/app/pcap/pcap-panel/pcap-panel.component.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/pcap/pcap-panel/pcap-panel.component.ts b/metron-interface/metron-alerts/src/app/pcap/pcap-panel/pcap-panel.component.ts index 7c88007..4a017db 100644 --- a/metron-interface/metron-alerts/src/app/pcap/pcap-panel/pcap-panel.component.ts +++ b/metron-interface/metron-alerts/src/app/pcap/pcap-panel/pcap-panel.component.ts @@ -23,7 +23,7 @@ import { PcapRequest } from '../model/pcap.request'; import { Pdml } from '../model/pdml'; import { Subscription } from 'rxjs/Rx'; import { PcapPagination } from '../model/pcap-pagination'; -import { RestError } from "../../model/rest-error"; +import { RestError } from '../../model/rest-error'; @Component({ selector: 'app-pcap-panel', @@ -40,9 +40,9 @@ export class PcapPanelComponent implements OnInit, OnDestroy { cancelSubscription: Subscription; submitSubscription: Subscription; getSubscription: Subscription; - queryRunning: boolean = false; + queryRunning = false; queryId: string; - progressWidth: number = 0; + progressWidth = 0; pagination: PcapPagination = new PcapPagination(); savedPcapRequest: {}; errorMsg: string; http://git-wip-us.apache.org/repos/asf/metron/blob/e66cfc80/metron-interface/metron-alerts/src/app/pcap/pcap.module.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/pcap/pcap.module.ts b/metron-interface/metron-alerts/src/app/pcap/pcap.module.ts index 8c0db02..784bc93 100644 --- a/metron-interface/metron-alerts/src/app/pcap/pcap.module.ts +++ b/metron-interface/metron-alerts/src/app/pcap/pcap.module.ts @@ -17,7 +17,7 @@ */ import {NgModule} from '@angular/core'; import { CommonModule } from '@angular/common'; -import { FormsModule } from '@angular/forms'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { HttpModule } from '@angular/http'; import { routing } from './pcap.routing'; @@ -29,7 +29,7 @@ import { PcapPacketComponent } from './pcap-packet/pcap-packet.component'; import { PcapFiltersComponent } from './pcap-filters/pcap-filters.component'; import { PcapPanelComponent } from './pcap-panel/pcap-panel.component'; import { PcapPacketLineComponent } from './pcap-packet-line/pcap-packet-line.component'; -import { PcapPaginationComponent } from './pcap-pagination/pcap-pagination.component' +import { PcapPaginationComponent } from './pcap-pagination/pcap-pagination.component'; import { PcapService } from './service/pcap.service'; @NgModule({ @@ -37,6 +37,7 @@ import { PcapService } from './service/pcap.service'; routing, CommonModule, FormsModule, + ReactiveFormsModule, HttpModule, DatePickerModule, ], http://git-wip-us.apache.org/repos/asf/metron/blob/e66cfc80/metron-interface/metron-alerts/src/app/shared/date-picker/date-picker.component.scss ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/shared/date-picker/date-picker.component.scss b/metron-interface/metron-alerts/src/app/shared/date-picker/date-picker.component.scss index 813b6a5..f46599a 100644 --- a/metron-interface/metron-alerts/src/app/shared/date-picker/date-picker.component.scss +++ b/metron-interface/metron-alerts/src/app/shared/date-picker/date-picker.component.scss @@ -28,4 +28,16 @@ font-family: "FontAwesome"; content: '\f073'; } -} \ No newline at end of file +} + +:host(.ng-invalid):not(form) { + border-left: none !important; +} + +:host(.ng-invalid) input { + border-left: 5px solid #a94442; /* red */ + + &:focus { + border-color: #4D4D4D; + } +} http://git-wip-us.apache.org/repos/asf/metron/blob/e66cfc80/metron-interface/metron-alerts/src/app/shared/date-picker/date-picker.component.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/shared/date-picker/date-picker.component.ts b/metron-interface/metron-alerts/src/app/shared/date-picker/date-picker.component.ts index d58bb5f..9014058 100644 --- a/metron-interface/metron-alerts/src/app/shared/date-picker/date-picker.component.ts +++ b/metron-interface/metron-alerts/src/app/shared/date-picker/date-picker.component.ts @@ -15,21 +15,29 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - import { Component, OnInit, ViewChild, ElementRef, OnChanges, SimpleChanges, Input, Output, EventEmitter } from '@angular/core'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; import * as moment from 'moment/moment'; -import * as Pikaday from "pikaday-time"; +import * as Pikaday from 'pikaday-time'; @Component({ selector: 'app-date-picker', templateUrl: './date-picker.component.html', + providers : [{ + provide : NG_VALUE_ACCESSOR, + useExisting: DatePickerComponent, + multi: true, + }], styleUrls: ['./date-picker.component.scss'] }) -export class DatePickerComponent implements OnInit, OnChanges { +export class DatePickerComponent implements OnInit, OnChanges, ControlValueAccessor { defaultDateStr = 'now'; picker: Pikaday; dateStr = this.defaultDateStr; + private onChange: Function; + private onTouched: Function; + @Input() date = ''; @Input() minDate = ''; @Output() dateChange = new EventEmitter<string>(); @@ -45,7 +53,12 @@ export class DatePickerComponent implements OnInit, OnChanges { use24hour: true, onSelect: function() { _datePickerComponent.dateStr = this.getMoment().format('YYYY-MM-DD HH:mm:ss'); - setTimeout(() => _datePickerComponent.dateChange.emit(_datePickerComponent.dateStr), 0); + setTimeout(() => { + _datePickerComponent.dateChange.emit(_datePickerComponent.dateStr); + if (_datePickerComponent.onChange) { + _datePickerComponent.onChange(_datePickerComponent.dateStr); + } + }, 0); } }; this.picker = new Pikaday(pikadayConfig); @@ -62,6 +75,19 @@ export class DatePickerComponent implements OnInit, OnChanges { } } + writeValue(value) { + this.date = value; + this.setDate(); + } + + registerOnChange(fn) { + this.onChange = fn; + } + + registerOnTouched(fn) { + this.onTouched = fn; + } + setDate() { if (this.date === '') { this.dateStr = this.defaultDateStr; http://git-wip-us.apache.org/repos/asf/metron/blob/e66cfc80/metron-interface/metron-alerts/src/app/shared/date-picker/date-picker.module.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/shared/date-picker/date-picker.module.ts b/metron-interface/metron-alerts/src/app/shared/date-picker/date-picker.module.ts index d59d566..e5dfd6c 100644 --- a/metron-interface/metron-alerts/src/app/shared/date-picker/date-picker.module.ts +++ b/metron-interface/metron-alerts/src/app/shared/date-picker/date-picker.module.ts @@ -19,8 +19,7 @@ import { NgModule } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule } from '@angular/forms'; -import {DatePickerComponent} from './date-picker.component'; -import {SharedModule} from '../shared.module'; +import { DatePickerComponent } from './date-picker.component'; @NgModule({ imports: [ http://git-wip-us.apache.org/repos/asf/metron/blob/e66cfc80/metron-interface/metron-alerts/src/app/utils/constants.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/utils/constants.ts b/metron-interface/metron-alerts/src/app/utils/constants.ts index 74e887a..703e0f7 100644 --- a/metron-interface/metron-alerts/src/app/utils/constants.ts +++ b/metron-interface/metron-alerts/src/app/utils/constants.ts @@ -37,3 +37,6 @@ export let INDEXES = environment.indices ? environment.indices.split(',') : []; export let POLLING_DEFAULT_STATE = environment.defaultPollingState; export let MAX_ALERTS_IN_META_ALERTS = 350; + +export const DEFAULT_END_TIME = new Date(); +export const DEFAULT_START_TIME = new Date().setDate(DEFAULT_END_TIME.getDate() - 5); http://git-wip-us.apache.org/repos/asf/metron/blob/e66cfc80/metron-interface/metron-alerts/src/app/utils/utils.ts ---------------------------------------------------------------------- diff --git a/metron-interface/metron-alerts/src/app/utils/utils.ts b/metron-interface/metron-alerts/src/app/utils/utils.ts index 61cc45b..4eb098a 100644 --- a/metron-interface/metron-alerts/src/app/utils/utils.ts +++ b/metron-interface/metron-alerts/src/app/utils/utils.ts @@ -17,12 +17,15 @@ */ import * as moment from 'moment/moment'; -import {DEFAULT_TIMESTAMP_FORMAT, META_ALERTS_SENSOR_TYPE} from './constants'; -import {Alert} from '../model/alert'; -import {DateFilterValue} from '../model/date-filter-value'; -import { environment } from 'environments/environment'; +import { DEFAULT_START_TIME, DEFAULT_END_TIME, DEFAULT_TIMESTAMP_FORMAT, META_ALERTS_SENSOR_TYPE } from './constants'; +import { Alert } from '../model/alert'; +import { DateFilterValue } from '../model/date-filter-value'; +import { PcapRequest } from '../pcap/model/pcap.request'; +import { PcapFilterFormValue } from '../pcap/pcap-filters/pcap-filters.component'; +import { FormGroup } from '@angular/forms'; export class Utils { + public static escapeESField(field: string): string { return field.replace(/:/g, '\\:'); } @@ -201,5 +204,4 @@ export class Utils { return {toDate: toDate, fromDate: fromDate}; } - }
