[Fix] Replace Osquery query parser lib (#113425)

This commit is contained in:
Patryk Kopyciński 2021-09-29 20:07:13 +02:00 committed by GitHub
parent f79a96fe7f
commit a7874ff8a5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 75 additions and 52 deletions

View file

@ -266,6 +266,7 @@
"js-levenshtein": "^1.1.6",
"js-search": "^1.4.3",
"js-sha256": "^0.9.0",
"js-sql-parser": "^1.4.1",
"js-yaml": "^3.14.0",
"json-stable-stringify": "^1.0.1",
"json-stringify-pretty-compact": "1.2.0",
@ -298,7 +299,6 @@
"nock": "12.0.3",
"node-fetch": "^2.6.1",
"node-forge": "^0.10.0",
"node-sql-parser": "^3.6.1",
"nodemailer": "^6.6.2",
"normalize-path": "^3.0.0",
"object-hash": "^1.3.1",

View file

@ -73,7 +73,6 @@ export const DEV_ONLY_LICENSE_ALLOWED = ['MPL-2.0'];
export const LICENSE_OVERRIDES = {
'jsts@1.6.2': ['Eclipse Distribution License - v 1.0'], // cf. https://github.com/bjornharrtell/jsts
'@mapbox/jsonlint-lines-primitives@2.0.2': ['MIT'], // license in readme https://github.com/tmcw/jsonlint
'node-sql-parser@3.6.1': ['(GPL-2.0 OR MIT)'], // GPL-2.0* https://github.com/taozhi8833998/node-sql-parser
'@elastic/ems-client@7.15.0': ['Elastic License 2.0'],
'@elastic/eui@38.0.1': ['SSPL-1.0 OR Elastic License 2.0'],

9
typings/js_sql_parser.d.ts vendored Normal file
View file

@ -0,0 +1,9 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/
declare module 'js-sql-parser';

View file

@ -6,7 +6,7 @@
*/
import { produce } from 'immer';
import { find, orderBy, sortedUniqBy, isArray, map } from 'lodash';
import { isEmpty, find, orderBy, sortedUniqBy, isArray, map } from 'lodash';
import React, {
forwardRef,
useCallback,
@ -30,7 +30,7 @@ import {
EuiText,
EuiIcon,
} from '@elastic/eui';
import { Parser, Select } from 'node-sql-parser';
import sqlParser from 'js-sql-parser';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import styled from 'styled-components';
@ -615,47 +615,65 @@ export const ECSMappingEditorField = ({ field, query, fieldRef }: ECSMappingEdit
return currentValue;
}
const parser = new Parser();
let ast: Select;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let ast: Record<string, any> | undefined;
try {
const parsedQuery = parser.astify(query);
ast = (isArray(parsedQuery) ? parsedQuery[0] : parsedQuery) as Select;
ast = sqlParser.parse(query)?.value;
} catch (e) {
return currentValue;
}
const tablesOrderMap = ast?.from?.reduce((acc, table, index) => {
acc[table.as ?? table.table] = index;
return acc;
}, {});
const tablesOrderMap =
ast?.from?.value?.reduce(
(
acc: { [x: string]: number },
table: { value: { alias?: { value: string }; value: { value: string } } },
index: number
) => {
acc[table.value.alias?.value ?? table.value.value.value] = index;
return acc;
},
{}
) ?? {};
const astOsqueryTables: Record<string, OsqueryColumn[]> = ast?.from?.reduce((acc, table) => {
const osqueryTable = find(osquerySchema, ['name', table.table]);
const astOsqueryTables: Record<string, OsqueryColumn[]> =
ast?.from?.value?.reduce(
(
acc: { [x: string]: OsqueryColumn[] },
table: { value: { alias?: { value: string }; value: { value: string } } }
) => {
const osqueryTable = find(osquerySchema, ['name', table.value.value.value]);
if (osqueryTable) {
acc[table.as ?? table.table] = osqueryTable.columns;
}
if (osqueryTable) {
acc[table.value.alias?.value ?? table.value.value.value] = osqueryTable.columns;
}
return acc;
}, {});
return acc;
},
{}
) ?? {};
// Table doesn't exist in osquery schema
if (
!isArray(ast?.columns) &&
ast?.columns !== '*' &&
!astOsqueryTables[ast?.from && ast?.from[0].table]
) {
if (isEmpty(astOsqueryTables)) {
return currentValue;
}
/*
Simple query
select * from users;
*/
if (ast?.columns === '*' && ast.from?.length && astOsqueryTables[ast.from[0].table]) {
const tableName = ast.from[0].as ?? ast.from[0].table;
if (
ast?.selectItems?.value?.length &&
ast?.selectItems?.value[0].value === '*' &&
ast.from?.value?.length &&
ast?.from.value[0].value?.value?.value &&
astOsqueryTables[ast.from.value[0].value.value.value]
) {
const tableName =
ast.from.value[0].value.alias?.value ?? ast.from.value[0].value.value.value;
return astOsqueryTables[ast.from[0].table].map((osqueryColumn) => ({
return astOsqueryTables[ast.from.value[0].value.value.value].map((osqueryColumn) => ({
label: osqueryColumn.name,
value: {
name: osqueryColumn.name,
@ -672,39 +690,39 @@ export const ECSMappingEditorField = ({ field, query, fieldRef }: ECSMappingEdit
select i.*, p.resident_size, p.user_time, p.system_time, time.minutes as counter from osquery_info i, processes p, time where p.pid = i.pid;
*/
const suggestions =
isArray(ast?.columns) &&
ast?.columns
?.map((column) => {
if (column.expr.column === '*' && astOsqueryTables[column.expr.table]) {
return astOsqueryTables[column.expr.table].map((osqueryColumn) => ({
isArray(ast?.selectItems?.value) &&
ast?.selectItems?.value
// @ts-expect-error update types
?.map((selectItem) => {
const [table, column] = selectItem.value?.split('.');
if (column === '*' && astOsqueryTables[table]) {
return astOsqueryTables[table].map((osqueryColumn) => ({
label: osqueryColumn.name,
value: {
name: osqueryColumn.name,
description: osqueryColumn.description,
table: column.expr.table,
tableOrder: tablesOrderMap[column.expr.table],
table,
tableOrder: tablesOrderMap[table],
suggestion_label: `${osqueryColumn.name}`,
},
}));
}
if (astOsqueryTables && astOsqueryTables[column.expr.table]) {
const osqueryColumn = find(astOsqueryTables[column.expr.table], [
'name',
column.expr.column,
]);
if (astOsqueryTables && astOsqueryTables[table]) {
const osqueryColumn = find(astOsqueryTables[table], ['name', column]);
if (osqueryColumn) {
const label = column.as ?? column.expr.column;
const label = selectItem.hasAs ? selectItem.alias : column;
return [
{
label: column.as ?? column.expr.column,
label,
value: {
name: osqueryColumn.name,
description: osqueryColumn.description,
table: column.expr.table,
tableOrder: tablesOrderMap[column.expr.table],
table,
tableOrder: tablesOrderMap[table],
suggestion_label: `${label}`,
},
},
@ -718,7 +736,6 @@ export const ECSMappingEditorField = ({ field, query, fieldRef }: ECSMappingEdit
// Remove column duplicates by keeping the column from the table that appears last in the query
return sortedUniqBy(
// @ts-expect-error update types
orderBy(suggestions, ['value.suggestion_label', 'value.tableOrder'], ['asc', 'desc']),
'label'
);

View file

@ -8362,7 +8362,7 @@ better-opn@^2.0.0:
dependencies:
open "^7.0.3"
big-integer@^1.6.16, big-integer@^1.6.48:
big-integer@^1.6.16:
version "1.6.48"
resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.48.tgz#8fd88bd1632cba4a1c8c3e3d7159f08bb95b4b9e"
integrity sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==
@ -17523,6 +17523,11 @@ js-sha3@0.8.0:
resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==
js-sql-parser@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/js-sql-parser/-/js-sql-parser-1.4.1.tgz#775516b3187dd5872ecec04bef8ed4a430242fda"
integrity sha512-J8zi3+/yK4FWSnVvLOjS2HIGfJhR6v7ApwIF8gZ/SpaO/tFIDlsgugD6ZMn6flXiuMsCjJxvhE0+xBgbdzvDDw==
js-string-escape@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/js-string-escape/-/js-string-escape-1.0.1.tgz#e2625badbc0d67c7533e9edc1068c587ae4137ef"
@ -20096,13 +20101,6 @@ node-sass@^6.0.1:
stdout-stream "^1.4.0"
"true-case-path" "^1.0.2"
node-sql-parser@^3.6.1:
version "3.6.1"
resolved "https://registry.yarnpkg.com/node-sql-parser/-/node-sql-parser-3.6.1.tgz#6f096e9df1f19d1e2daa658d864bd68b0e2cd2c6"
integrity sha512-AseDvELmUvL22L6C63DsTuzF+0i/HBIHjJq/uxC7jV3PGpAUib5Oe6oz4sgAniSUMPSZQbZmRore6Na68Sg4Tg==
dependencies:
big-integer "^1.6.48"
nodemailer@^6.6.2:
version "6.6.2"
resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.6.2.tgz#e184c9ed5bee245a3e0bcabc7255866385757114"