Skip to content

Commit

Permalink
Adds PCAP/Attachment download capability (#120)
Browse files Browse the repository at this point in the history
* adding file/pcap download capability

* updating packages

* updating dev version of shared package

* updating shared package dev version

* update typescript, fix import

* fixing broken ts build

* sorting file names

* update nm-web-shared version
  • Loading branch information
sperry94 authored Oct 3, 2019
1 parent c5797de commit fcf39e2
Show file tree
Hide file tree
Showing 26 changed files with 1,228 additions and 114 deletions.
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@
"@kbn/test-subj-selector": "0.2.1",
"@kbn/ui-framework": "1.0.0",
"@logrhythm/icons": "^1.19.0",
"@logrhythm/nm-web-shared": "1.10.1",
"@logrhythm/nm-web-shared": "1.11.0",
"@logrhythm/webui": "^5.9.15",
"@types/json-stable-stringify": "^1.0.32",
"@types/lodash.clonedeep": "^4.5.4",
Expand All @@ -130,6 +130,7 @@
"abortcontroller-polyfill": "^1.1.9",
"angular": "1.6.9",
"angular-aria": "1.6.6",
"angular-bind-html-compile": "^1.4.1",
"angular-elastic": "2.5.0",
"angular-recursion": "^1.0.5",
"angular-route": "1.4.7",
Expand Down Expand Up @@ -216,7 +217,7 @@
"react-dom": "^16.8.0",
"react-grid-layout": "^0.16.2",
"react-input-range": "^1.3.0",
"react-jss": "^8.6.1",
"react-jss": "^10.0.0",
"react-markdown": "^3.4.1",
"react-redux": "^5.0.7",
"react-router-dom": "^4.3.1",
Expand Down Expand Up @@ -326,7 +327,6 @@
"@types/puppeteer-core": "^1.9.0",
"@types/react": "^16.8.0",
"@types/react-dom": "^16.8.0",
"@types/react-jss": "8.6.1",
"@types/react-redux": "^6.0.6",
"@types/react-router-dom": "^4.3.1",
"@types/react-virtualized": "^9.18.7",
Expand Down Expand Up @@ -433,7 +433,7 @@
"supertest": "^3.1.0",
"supertest-as-promised": "^4.0.2",
"tree-kill": "^1.1.0",
"typescript": "^3.3.3333",
"typescript": "3.6.3",
"typings-tester": "^0.3.2",
"vinyl-fs": "^3.0.2",
"xml2js": "^0.4.19",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import { QueryBarInput } from './query_bar_input';

import { getQueryLog } from '../lib/get_query_log';

import { SaveRule } from '../../../../../../netmon/components/save_rule';
import { SaveRule } from '../../../../../../netmon/components/save_rule/save_rule';

const config = chrome.getUiSettingsClient();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@
tooltip-placement="top"
tooltip="{{ ::'kbnDocViews.table.objectsInArraysAreNotWellSupportedTooltip' | i18n: { defaultMessage: 'Objects in arrays are not well supported.' } }}"
class="fa fa-warning text-color-warning kbnDocViewer__objectArray"></i>
<div class="kbnDocViewer__value" ng-bind-html="typeof(formatted[field]) === 'undefined' ? hit[field] : formatted[field] | trustAsHtml"></div>
<div class="kbnDocViewer__value" bind-html-compile="typeof(formatted[field]) === 'undefined' ? hit[field] : formatted[field]"></div>
</td>
</tr>
</tbody>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,33 +17,75 @@
* under the License.
*/

import _ from 'lodash';
import { asPrettyString } from '../../utils/as_pretty_string';
import { getHighlightHtml } from '../../../../../core_plugins/kibana/common/highlight/highlight_html';
import { formatNetmonBoolean } from '../../../../../../netmon/field_formats/boolean_formats';

export function createBoolFormat(FieldFormat) {
return class BoolFormat extends FieldFormat {
_convert(value) {
if (typeof value === 'string') {
value = value.trim().toLowerCase();
}

switch (value) {
case false:
case 0:
case 'false':
case 'no':
return 'false';
case true:
case 1:
case 'true':
case 'yes':
return 'true';
default:
return asPrettyString(value);
}
}

class BoolFormat extends FieldFormat {
static id = 'boolean';
static title = 'Boolean';
static fieldType = ['boolean', 'number', 'string'];
}

const getTruthy = (value) => {
switch (value) {
case false:
case 0:
case 'false':
case 'no':
return false;
case true:
case 1:
case 'true':
case 'yes':
return true;
default:
return null;
}
};

const formatText = (value) => {
if (typeof value === 'string') {
value = value.trim().toLowerCase();
}

const truthy = getTruthy(value);

if(truthy) {
return 'true';
} else if (truthy === false) {
return 'false';
}

return asPrettyString(value);
};

const defaultHtml = (value, field, hit) => {
const formatted = _.escape(formatText(value));

if(!hit || !hit.highlight || !hit.highlight[field.name]) {
return formatted;
} else {
return getHighlightHtml(formatted, hit.highlight[field.name]);
}
};

BoolFormat.prototype._convert = {
text: function (value) {
return formatText(value);
},
html: function (value, field, hit) {
const truthy = getTruthy(value);

if(!field || truthy === null) {
return defaultHtml(value, field, hit);
}

return formatNetmonBoolean(value, field, hit) || defaultHtml(value, field, hit);
}
};

return BoolFormat;
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@
data-test-subj="docTableHeader-{{name}}"
>
{{getShortDotsName(name)}}
<capture-header
ng-if="name === 'Captured'"
on-select-all="onSelectAll"
on-select-current-page="onSelectCurrentPage"
></capture-header>
<button
data-test-subj="docTableHeaderFieldSort_{{name}}"
id="docTableHeaderFieldSort{{name}}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ module.directive('kbnTableHeader', function () {
onChangeSortOrder: '=?',
onRemoveColumn: '=?',
onMoveColumn: '=?',
onSelectAll: '=?',
onSelectCurrentPage: '=?'
},
template: headerHtml,
controller: function ($scope, config) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
on-change-sort-order="onChangeSortOrder"
on-move-column="onMoveColumn"
on-remove-column="onRemoveColumn"
on-select-all="onSelectAll"
on-select-current-page="onSelectCurrentPage"
></thead>
<tbody>
<tr ng-repeat="row in pageOfItems|limitTo:limit track by row._index+row._type+row._id+row._score+row._version"
Expand Down Expand Up @@ -85,6 +87,7 @@
on-change-sort-order="onChangeSortOrder"
on-move-column="onMoveColumn"
on-remove-column="onRemoveColumn"
on-select-all="onSelectAll"
></thead>
<tbody>
<tr ng-repeat="row in hits|limitTo:limit track by row._index+row._type+row._id+row._score+row._version"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import 'ui/pager';
import { getRequestInspectorStats, getResponseInspectorStats } from 'ui/courier/utils/courier_inspector_utils';

import { getLimitedSearchResultsMessage } from './doc_table_strings';
import SelectedCaptureSessions from '@logrhythm/nm-web-shared/services/selected_capture_sessions';

uiModules.get('app/discover')
.directive('docTable', function (config, Notifier, getAppState, pagerFactory, $filter, courier) {
Expand Down Expand Up @@ -183,6 +184,20 @@ uiModules.get('app/discover')
$scope.shouldShowLimitedResultsWarning = () => (
!$scope.pager.hasNextPage && $scope.pager.totalItems < $scope.totalHitCount
);

$scope.onSelectAll = () => {
const allSessions = $scope.hits
.map(h => !!h && !!h._source && h._source.Session)
.filter(h => !!h);
SelectedCaptureSessions.set(allSessions);
};

$scope.onSelectCurrentPage = () => {
const allSessions = $scope.pageOfItems
.map(h => !!h && !!h._source && h._source.Session)
.filter(h => !!h);
SelectedCaptureSessions.set(allSessions);
};
}
};
});
1 change: 1 addition & 0 deletions src/legacy/core_plugins/kibana/public/kibana.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import './management';
import './doc';
import './dev_tools';
import './context';
import '../../../../netmon/directives';
import 'ui/vislib';
import 'ui/agg_response';
import 'ui/agg_types';
Expand Down
4 changes: 4 additions & 0 deletions src/legacy/ui/field_formats/content_types.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import _ from 'lodash';
import { asPrettyString } from '../../core_plugins/kibana/common/utils/as_pretty_string';
import { getHighlightHtml } from '../../core_plugins/kibana/common/highlight/highlight_html';
import { shouldBindFormat } from '../../../netmon/field_formats/should_bind_format';

const types = {
html: function (format, convert) {
Expand All @@ -43,6 +44,9 @@ const types = {
}

return function (...args) {
if(!!args[1] && shouldBindFormat(args[1].name)) {
return `<span>${recurse(...args)}</span>`;
}
return `<span ng-non-bindable>${recurse(...args)}</span>`;
};
},
Expand Down
104 changes: 104 additions & 0 deletions src/netmon/components/attach_download.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import React, { useState, useEffect } from 'react';
import { createUseStyles } from 'react-jss';
import { EuiButtonIcon } from '@elastic/eui';
import { toastNotifications } from 'ui/notify';
import { startAttachmentDownload } from '@logrhythm/nm-web-shared/services/session_files';
import FileDownloadModal from './file_download/file_download_modal';

const useStyles = createUseStyles({
buttonWrapper: {
cursor: 'pointer',
},
});

export interface AttachDownloadProps {
session: string;
fileName: string;
}

const AttachDownload = (props: AttachDownloadProps) => {
const { session, fileName } = props;

const classes = useStyles();

const [downloadId, setDownloadId] = useState('');
const [fileNames, setFileNames] = useState<string[]>([]);

useEffect(
() => {
const newFileNames = new Set<string>();

fileName
.split(',')
.map(f => f.trim())
.forEach(file => {
let fileNameToAdd: string = file;

const prefix: number = 1;
while (newFileNames.has(fileNameToAdd)) {
fileNameToAdd = `${prefix}_${file}`;
}

newFileNames.add(fileNameToAdd);
});

setFileNames(Array.from(newFileNames));
},
[fileName]
);

const handleStartDownload = async () => {
try {
const startDownloadRes = await startAttachmentDownload(session, fileNames);

setDownloadId(startDownloadRes.data.downloadID);
} catch (err) {
console.error( // eslint-disable-line
`An error occurred creating an attachment download for session ${session}`,
err
);
toastNotifications.addDanger('An error initiating a download for the attachment(s).');
return;
}
};

return (
<>
<div className={classes.buttonWrapper}>
<EuiButtonIcon
disabled={fileNames.length === 0}
iconType="importAction"
color="primary"
onClick={handleStartDownload}
aria-label="Download Attachment"
/>
</div>
<FileDownloadModal
downloadId={downloadId}
fileType="reconstruction"
onClose={() => setDownloadId('')}
/>
</>
);
};

export default AttachDownload; // eslint-disable-line
Loading

0 comments on commit fcf39e2

Please sign in to comment.