mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
* replace querystring (querystring-browser) -> query-string * QueryString remove encode/decode methods * remove query_string file * remove querystring-browser from package.json * add kibana_utils\url module * cleanup * update notice.txt * fix merge conflict * fix CI * fix wrong import * fix CI * fix X-Pack firefox smoke test * remove urlUtils.parseUrlQuery * remove url.stringifyUrlQuery * use url.encodeQuery * Record<string, any> -> ParsedQuery * Update src/plugins/console/public/application/containers/editor/legacy/console_editor/editor.tsx Co-Authored-By: Luke Elmers <lukeelmers@gmail.com> * add more tests for APM Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com> Co-authored-by: Luke Elmers <lukeelmers@gmail.com> # Conflicts: # x-pack/plugins/endpoint/public/applications/endpoint/store/alerts/middleware.ts
This commit is contained in:
parent
13de160e00
commit
f3104aa77e
69 changed files with 398 additions and 524 deletions
|
@ -359,13 +359,7 @@ module.exports = {
|
|||
settings: {
|
||||
// instructs import/no-extraneous-dependencies to treat certain modules
|
||||
// as core modules, even if they aren't listed in package.json
|
||||
'import/core-modules': [
|
||||
'plugins',
|
||||
'legacy/ui',
|
||||
'uiExports',
|
||||
// TODO: Remove once https://github.com/benmosher/eslint-plugin-import/issues/1374 is fixed
|
||||
'querystring',
|
||||
],
|
||||
'import/core-modules': ['plugins', 'legacy/ui', 'uiExports'],
|
||||
|
||||
'import/resolver': {
|
||||
'@kbn/eslint-import-resolver-kibana': {
|
||||
|
|
25
NOTICE.txt
25
NOTICE.txt
|
@ -218,28 +218,3 @@ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
---
|
||||
This product includes code that was extracted from angular@1.3.
|
||||
Original license:
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2010-2014 Google, Inc. http://angularjs.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
|
|
@ -227,7 +227,7 @@
|
|||
"prop-types": "15.6.0",
|
||||
"proxy-from-env": "1.0.0",
|
||||
"pug": "^2.0.4",
|
||||
"querystring-browser": "1.0.4",
|
||||
"query-string": "6.10.1",
|
||||
"raw-loader": "3.1.0",
|
||||
"react": "^16.12.0",
|
||||
"react-color": "^2.13.8",
|
||||
|
|
|
@ -29,7 +29,6 @@ exports.getWebpackConfig = function(kibanaPath, projectRoot, config) {
|
|||
// Kibana defaults https://github.com/elastic/kibana/blob/6998f074542e8c7b32955db159d15661aca253d7/src/legacy/ui/ui_bundler_env.js#L30-L36
|
||||
ui: fromKibana('src/legacy/ui/public'),
|
||||
test_harness: fromKibana('src/test_harness/public'),
|
||||
querystring: 'querystring-browser',
|
||||
|
||||
// Dev defaults for test bundle https://github.com/elastic/kibana/blob/6998f074542e8c7b32955db159d15661aca253d7/src/core_plugins/tests_bundle/index.js#L73-L78
|
||||
ng_mock$: fromKibana('src/test_utils/public/ng_mock'),
|
||||
|
|
|
@ -19,8 +19,7 @@
|
|||
import { Request } from 'hapi';
|
||||
import { merge } from 'lodash';
|
||||
import { Socket } from 'net';
|
||||
|
||||
import querystring from 'querystring';
|
||||
import { stringify } from 'query-string';
|
||||
|
||||
import { schema } from '@kbn/config-schema';
|
||||
|
||||
|
@ -55,7 +54,8 @@ function createKibanaRequestMock({
|
|||
socket = new Socket(),
|
||||
routeTags,
|
||||
}: RequestFixtureOptions = {}) {
|
||||
const queryString = querystring.stringify(query);
|
||||
const queryString = stringify(query, { sort: false });
|
||||
|
||||
return KibanaRequest.from(
|
||||
createRawRequestMock({
|
||||
headers,
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { ParsedUrlQuery } from 'querystring';
|
||||
import { ParsedQuery } from 'query-string';
|
||||
import { format as formatUrl, parse as parseUrl, UrlObject } from 'url';
|
||||
|
||||
/**
|
||||
|
@ -33,7 +32,7 @@ export interface URLMeaningfulParts {
|
|||
protocol?: string | null;
|
||||
slashes?: boolean | null;
|
||||
port?: string | null;
|
||||
query: ParsedUrlQuery;
|
||||
query: ParsedQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,10 +20,10 @@
|
|||
import Stream from 'stream';
|
||||
import moment from 'moment-timezone';
|
||||
import { get, _ } from 'lodash';
|
||||
import queryString from 'query-string';
|
||||
import numeral from '@elastic/numeral';
|
||||
import chalk from 'chalk';
|
||||
import stringify from 'json-stringify-safe';
|
||||
import querystring from 'querystring';
|
||||
import applyFiltersToKeys from './apply_filters_to_keys';
|
||||
import { inspect } from 'util';
|
||||
import { logWithMetadata } from './log_with_metadata';
|
||||
|
@ -108,7 +108,7 @@ export default class TransformObjStream extends Stream.Transform {
|
|||
contentLength: contentLength,
|
||||
};
|
||||
|
||||
const query = querystring.stringify(event.query);
|
||||
const query = queryString.stringify(event.query, { sort: false });
|
||||
if (query) data.req.url += '?' + query;
|
||||
|
||||
data.message = data.req.method.toUpperCase() + ' ';
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { QueryString } from '../utils/query_string';
|
||||
import { StateProvider } from './state';
|
||||
import { uiModules } from '../modules';
|
||||
import { createLegacyClass } from '../utils/legacy_class';
|
||||
|
@ -35,10 +34,6 @@ export function GlobalStateProvider(Private) {
|
|||
// if the url param is missing, write it back
|
||||
GlobalState.prototype._persistAcrossApps = true;
|
||||
|
||||
GlobalState.prototype.removeFromUrl = function(url) {
|
||||
return QueryString.replaceParamInUrl(url, this._urlParam, null);
|
||||
};
|
||||
|
||||
return new GlobalState();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,129 +0,0 @@
|
|||
/*
|
||||
* 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 { encodeQueryComponent } from '../../../utils';
|
||||
|
||||
export const QueryString = {};
|
||||
|
||||
/*****
|
||||
/*** originally copied from angular, modified our purposes
|
||||
/*****/
|
||||
|
||||
function tryDecodeURIComponent(value) {
|
||||
try {
|
||||
return decodeURIComponent(value);
|
||||
} catch (e) {
|
||||
// Ignore any invalid uri component
|
||||
} // eslint-disable-line no-empty
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an escaped url query string into key-value pairs.
|
||||
* @returns {Object.<string,boolean|Array>}
|
||||
*/
|
||||
QueryString.decode = function(keyValue) {
|
||||
const obj = {};
|
||||
let keyValueParts;
|
||||
let key;
|
||||
|
||||
(keyValue || '').split('&').forEach(function(keyValue) {
|
||||
if (keyValue) {
|
||||
keyValueParts = keyValue.split('=');
|
||||
key = tryDecodeURIComponent(keyValueParts[0]);
|
||||
if (key !== void 0) {
|
||||
const val = keyValueParts[1] !== void 0 ? tryDecodeURIComponent(keyValueParts[1]) : true;
|
||||
if (!obj[key]) {
|
||||
obj[key] = val;
|
||||
} else if (Array.isArray(obj[key])) {
|
||||
obj[key].push(val);
|
||||
} else {
|
||||
obj[key] = [obj[key], val];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
return obj;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a queryString out of an object
|
||||
* @param {Object} obj
|
||||
* @return {String}
|
||||
*/
|
||||
QueryString.encode = function(obj) {
|
||||
const parts = [];
|
||||
const keys = Object.keys(obj).sort();
|
||||
keys.forEach(function(key) {
|
||||
const value = obj[key];
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach(function(arrayValue) {
|
||||
parts.push(QueryString.param(key, arrayValue));
|
||||
});
|
||||
} else {
|
||||
parts.push(QueryString.param(key, value));
|
||||
}
|
||||
});
|
||||
return parts.length ? parts.join('&') : '';
|
||||
};
|
||||
|
||||
QueryString.param = function(key, val) {
|
||||
return (
|
||||
encodeQueryComponent(key, true) + (val === true ? '' : '=' + encodeQueryComponent(val, true))
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Extracts the query string from a url
|
||||
* @param {String} url
|
||||
* @return {Object} - returns an object describing the start/end index of the url in the string. The indices will be
|
||||
* the same if the url does not have a query string
|
||||
*/
|
||||
QueryString.findInUrl = function(url) {
|
||||
let qsStart = url.indexOf('?');
|
||||
let hashStart = url.lastIndexOf('#');
|
||||
|
||||
if (hashStart === -1) {
|
||||
// out of bounds
|
||||
hashStart = url.length;
|
||||
}
|
||||
|
||||
if (qsStart === -1) {
|
||||
qsStart = hashStart;
|
||||
}
|
||||
|
||||
return {
|
||||
start: qsStart,
|
||||
end: hashStart,
|
||||
};
|
||||
};
|
||||
|
||||
QueryString.replaceParamInUrl = function(url, param, newVal) {
|
||||
const loc = QueryString.findInUrl(url);
|
||||
const parsed = QueryString.decode(url.substring(loc.start + 1, loc.end));
|
||||
|
||||
if (newVal != null) {
|
||||
parsed[param] = newVal;
|
||||
} else {
|
||||
delete parsed[param];
|
||||
}
|
||||
|
||||
const chars = url.split('');
|
||||
chars.splice(loc.start, loc.end - loc.start, '?' + QueryString.encode(parsed));
|
||||
return chars.join('');
|
||||
};
|
|
@ -30,7 +30,6 @@ export const UI_EXPORT_DEFAULTS = {
|
|||
ui: resolve(ROOT, 'src/legacy/ui/public'),
|
||||
__kibanaCore__$: resolve(ROOT, 'src/core/public'),
|
||||
test_harness: resolve(ROOT, 'src/test_harness/public'),
|
||||
querystring: 'querystring-browser',
|
||||
moment$: resolve(ROOT, 'webpackShims/moment'),
|
||||
'moment-timezone$': resolve(ROOT, 'webpackShims/moment-timezone'),
|
||||
},
|
||||
|
|
|
@ -21,7 +21,6 @@ export { BinderBase } from './binder';
|
|||
export { BinderFor } from './binder_for';
|
||||
export { deepCloneWithBuffers } from './deep_clone_with_buffers';
|
||||
export { unset } from './unset';
|
||||
export { encodeQueryComponent } from './encode_query_component';
|
||||
export { watchStdioForLine } from './watch_stdio_for_line';
|
||||
export { IS_KIBANA_DISTRIBUTABLE } from './artifact_type';
|
||||
export { IS_KIBANA_RELEASE } from './artifact_type';
|
||||
|
|
|
@ -21,11 +21,7 @@ import React, { CSSProperties, useCallback, useEffect, useRef, useState } from '
|
|||
import { EuiToolTip } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
// Node v5 querystring for browser.
|
||||
// @ts-ignore
|
||||
import * as qs from 'querystring-browser';
|
||||
|
||||
import { parse } from 'query-string';
|
||||
import { EuiIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import { useServicesContext, useEditorReadContext } from '../../../../contexts';
|
||||
import { useUIAceKeyboardMode } from '../use_ui_ace_keyboard_mode';
|
||||
|
@ -51,6 +47,10 @@ export interface EditorProps {
|
|||
initialTextValue: string;
|
||||
}
|
||||
|
||||
interface QueryParams {
|
||||
load_from: string;
|
||||
}
|
||||
|
||||
const abs: CSSProperties = {
|
||||
position: 'absolute',
|
||||
top: '0',
|
||||
|
@ -98,7 +98,8 @@ function EditorUI({ initialTextValue }: EditorProps) {
|
|||
|
||||
const readQueryParams = () => {
|
||||
const [, queryString] = (window.location.hash || '').split('?');
|
||||
return qs.parse(queryString || '');
|
||||
|
||||
return parse(queryString || '', { sort: false }) as Required<QueryParams>;
|
||||
};
|
||||
|
||||
const loadBufferFromRemote = (url: string) => {
|
||||
|
@ -138,6 +139,7 @@ function EditorUI({ initialTextValue }: EditorProps) {
|
|||
window.addEventListener('hashchange', onHashChange);
|
||||
|
||||
const initialQueryParams = readQueryParams();
|
||||
|
||||
if (initialQueryParams.load_from) {
|
||||
loadBufferFromRemote(initialQueryParams.load_from);
|
||||
} else {
|
||||
|
|
|
@ -17,8 +17,8 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { stringify as formatQueryString } from 'querystring';
|
||||
import $ from 'jquery';
|
||||
import { stringify } from 'query-string';
|
||||
|
||||
const esVersion: string[] = [];
|
||||
|
||||
|
@ -35,7 +35,7 @@ export function send(method: string, path: string, data: any) {
|
|||
const wrappedDfd = $.Deferred(); // eslint-disable-line new-cap
|
||||
|
||||
const options: JQuery.AjaxSettings = {
|
||||
url: '../api/console/proxy?' + formatQueryString({ path, method }),
|
||||
url: '../api/console/proxy?' + stringify({ path, method }, { sort: false }),
|
||||
data,
|
||||
contentType: getContentType(data),
|
||||
cache: false,
|
||||
|
|
|
@ -16,8 +16,7 @@
|
|||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import qs from 'querystring';
|
||||
import { parse } from 'query-string';
|
||||
|
||||
export function parseQueryString() {
|
||||
// window.location.search is an empty string
|
||||
|
@ -27,5 +26,5 @@ export function parseQueryString() {
|
|||
return {};
|
||||
}
|
||||
|
||||
return qs.parse(hrefSplit[1]);
|
||||
return parse(hrefSplit[1], { sort: false });
|
||||
}
|
||||
|
|
|
@ -24,3 +24,4 @@ export * from './state_containers';
|
|||
export * from './typed_json';
|
||||
export { createGetterSetter, Get, Set } from './create_getter_setter';
|
||||
export { distinctUntilChangedWithInitialValue } from './distinct_until_changed_with_initial_value';
|
||||
export { url } from './url';
|
||||
|
|
|
@ -17,27 +17,10 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { encodeUriQuery, stringifyQueryString } from './stringify_query_string';
|
||||
import { encodeUriQuery, encodeQuery } from './encode_uri_query';
|
||||
|
||||
describe('stringifyQueryString', () => {
|
||||
it('stringifyQueryString', () => {
|
||||
expect(
|
||||
stringifyQueryString({
|
||||
a: 'asdf1234asdf',
|
||||
b: "-_.!~*'() -_.!~*'()",
|
||||
c: ':@$, :@$,',
|
||||
d: "&;=+# &;=+#'",
|
||||
f: ' ',
|
||||
g: 'null',
|
||||
})
|
||||
).toMatchInlineSnapshot(
|
||||
`"a=asdf1234asdf&b=-_.!~*'()%20-_.!~*'()&c=:@$,%20:@$,&d=%26;%3D%2B%23%20%26;%3D%2B%23'&f=%20&g=null"`
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('encodeUriQuery', function() {
|
||||
it('should correctly encode uri query and not encode chars defined as pchar set in rfc3986', () => {
|
||||
describe('encodeUriQuery', () => {
|
||||
test('should correctly encode uri query and not encode chars defined as pchar set in rfc3986', () => {
|
||||
// don't encode alphanum
|
||||
expect(encodeUriQuery('asdf1234asdf')).toBe('asdf1234asdf');
|
||||
|
||||
|
@ -63,3 +46,25 @@ describe('encodeUriQuery', function() {
|
|||
expect(encodeUriQuery('null')).toBe('null');
|
||||
});
|
||||
});
|
||||
|
||||
describe('encodeQuery', () => {
|
||||
test('encodeQuery', () => {
|
||||
expect(
|
||||
encodeQuery({
|
||||
a: 'asdf1234asdf',
|
||||
b: "-_.!~*'() -_.!~*'()",
|
||||
c: ':@$, :@$,',
|
||||
d: "&;=+# &;=+#'",
|
||||
f: ' ',
|
||||
g: 'null',
|
||||
})
|
||||
).toEqual({
|
||||
a: 'asdf1234asdf',
|
||||
b: "-_.!~*'()%20-_.!~*'()",
|
||||
c: ':@$,%20:@$,',
|
||||
d: "%26;%3D%2B%23%20%26;%3D%2B%23'",
|
||||
f: '%20',
|
||||
g: 'null',
|
||||
});
|
||||
});
|
||||
});
|
|
@ -17,6 +17,9 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { ParsedQuery } from 'query-string';
|
||||
import { transform } from 'lodash';
|
||||
|
||||
/**
|
||||
* This method is intended for encoding *key* or *value* parts of query component. We need a custom
|
||||
* method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
|
||||
|
@ -28,11 +31,27 @@
|
|||
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
||||
* / "*" / "+" / "," / ";" / "="
|
||||
*/
|
||||
export function encodeQueryComponent(val: string, pctEncodeSpaces = false) {
|
||||
export function encodeUriQuery(val: string, pctEncodeSpaces = false) {
|
||||
return encodeURIComponent(val)
|
||||
.replace(/%40/gi, '@')
|
||||
.replace(/%3A/gi, ':')
|
||||
.replace(/%24/g, '$')
|
||||
.replace(/%2C/gi, ',')
|
||||
.replace(/%3B/gi, ';')
|
||||
.replace(/%20/g, pctEncodeSpaces ? '%20' : '+');
|
||||
}
|
||||
|
||||
export const encodeQuery = (
|
||||
query: ParsedQuery,
|
||||
encodeFunction: (val: string, pctEncodeSpaces?: boolean) => string = encodeUriQuery
|
||||
) =>
|
||||
transform(query, (result, value, key) => {
|
||||
if (key) {
|
||||
const singleValue = Array.isArray(value) ? value.join(',') : value;
|
||||
|
||||
result[key] = encodeFunction(
|
||||
singleValue === undefined || singleValue === null ? '' : singleValue,
|
||||
true
|
||||
);
|
||||
}
|
||||
});
|
|
@ -17,12 +17,9 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
declare class QueryStringClass {
|
||||
public decode(queryString: string): any;
|
||||
public encode(obj: any): string;
|
||||
public param(key: string, value: string): string;
|
||||
}
|
||||
import { encodeUriQuery, encodeQuery } from './encode_uri_query';
|
||||
|
||||
declare const QueryString: QueryStringClass;
|
||||
|
||||
export { QueryString };
|
||||
export const url = {
|
||||
encodeQuery,
|
||||
encodeUriQuery,
|
||||
};
|
|
@ -17,16 +17,18 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { parse, stringify } from 'query-string';
|
||||
import { History, Location } from 'history';
|
||||
import { parse } from 'querystring';
|
||||
import { stringifyQueryString } from '../state_management/url/stringify_query_string'; // TODO: extract it to ../url
|
||||
import { url } from '../../common';
|
||||
|
||||
export function removeQueryParam(history: History, param: string, replace: boolean = true) {
|
||||
const oldLocation = history.location;
|
||||
const search = (oldLocation.search || '').replace(/^\?/, '');
|
||||
const query = parse(search);
|
||||
const query = parse(search, { sort: false });
|
||||
|
||||
delete query[param];
|
||||
const newSearch = stringifyQueryString(query);
|
||||
|
||||
const newSearch = stringify(url.encodeQuery(query), { sort: false, encode: false });
|
||||
const newLocation: Location<any> = {
|
||||
...oldLocation,
|
||||
search: newSearch,
|
||||
|
|
|
@ -26,6 +26,7 @@ export {
|
|||
Set,
|
||||
UiComponent,
|
||||
UiComponentInstance,
|
||||
url,
|
||||
JsonValue,
|
||||
JsonObject,
|
||||
JsonArray,
|
||||
|
|
|
@ -18,18 +18,22 @@
|
|||
*/
|
||||
|
||||
import { format as formatUrl } from 'url';
|
||||
import { ParsedUrlQuery } from 'querystring';
|
||||
import { stringify, ParsedQuery } from 'query-string';
|
||||
import { parseUrl, parseUrlHash } from './parse';
|
||||
import { stringifyQueryString } from './stringify_query_string';
|
||||
import { url as urlUtils } from '../../../common';
|
||||
|
||||
export function replaceUrlHashQuery(
|
||||
rawUrl: string,
|
||||
queryReplacer: (query: ParsedUrlQuery) => ParsedUrlQuery
|
||||
queryReplacer: (query: ParsedQuery) => ParsedQuery
|
||||
) {
|
||||
const url = parseUrl(rawUrl);
|
||||
const hash = parseUrlHash(rawUrl);
|
||||
const newQuery = queryReplacer(hash?.query || {});
|
||||
const searchQueryString = stringifyQueryString(newQuery);
|
||||
const searchQueryString = stringify(urlUtils.encodeQuery(newQuery), {
|
||||
sort: false,
|
||||
encode: false,
|
||||
});
|
||||
|
||||
if ((!hash || !hash.search) && !searchQueryString) return rawUrl; // nothing to change. return original url
|
||||
return formatUrl({
|
||||
...url,
|
||||
|
|
|
@ -18,11 +18,12 @@
|
|||
*/
|
||||
|
||||
import { format as formatUrl } from 'url';
|
||||
import { stringify } from 'query-string';
|
||||
import { createBrowserHistory, History } from 'history';
|
||||
import { decodeState, encodeState } from '../state_encoder';
|
||||
import { getCurrentUrl, parseUrl, parseUrlHash } from './parse';
|
||||
import { stringifyQueryString } from './stringify_query_string';
|
||||
import { replaceUrlHashQuery } from './format';
|
||||
import { url as urlUtils } from '../../../common';
|
||||
|
||||
/**
|
||||
* Parses a kibana url and retrieves all the states encoded into url,
|
||||
|
@ -243,11 +244,11 @@ export function getRelativeToHistoryPath(absoluteUrl: string, history: History):
|
|||
|
||||
return formatUrl({
|
||||
pathname: stripBasename(parsedUrl.pathname),
|
||||
search: stringifyQueryString(parsedUrl.query),
|
||||
search: stringify(urlUtils.encodeQuery(parsedUrl.query), { sort: false, encode: false }),
|
||||
hash: parsedHash
|
||||
? formatUrl({
|
||||
pathname: parsedHash.pathname,
|
||||
search: stringifyQueryString(parsedHash.query),
|
||||
search: stringify(urlUtils.encodeQuery(parsedHash.query), { sort: false, encode: false }),
|
||||
})
|
||||
: parsedUrl.hash,
|
||||
});
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
* 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 { stringify, ParsedUrlQuery } from 'querystring';
|
||||
|
||||
// encodeUriQuery implements the less-aggressive encoding done naturally by
|
||||
// the browser. We use it to generate the same urls the browser would
|
||||
export const stringifyQueryString = (query: ParsedUrlQuery) =>
|
||||
stringify(query, undefined, undefined, {
|
||||
// encode spaces with %20 is needed to produce the same queries as angular does
|
||||
// https://github.com/angular/angular.js/blob/51c516e7d4f2d10b0aaa4487bd0b52772022207a/src/Angular.js#L1377
|
||||
encodeURIComponent: (val: string) => encodeUriQuery(val, true),
|
||||
});
|
||||
|
||||
/**
|
||||
* Extracted from angular.js
|
||||
* repo: https://github.com/angular/angular.js
|
||||
* license: MIT - https://github.com/angular/angular.js/blob/51c516e7d4f2d10b0aaa4487bd0b52772022207a/LICENSE
|
||||
* source: https://github.com/angular/angular.js/blob/51c516e7d4f2d10b0aaa4487bd0b52772022207a/src/Angular.js#L1413-L1432
|
||||
*/
|
||||
|
||||
/**
|
||||
* This method is intended for encoding *key* or *value* parts of query component. We need a custom
|
||||
* method because encodeURIComponent is too aggressive and encodes stuff that doesn't have to be
|
||||
* encoded per http://tools.ietf.org/html/rfc3986:
|
||||
* query = *( pchar / "/" / "?" )
|
||||
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
||||
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
||||
* pct-encoded = "%" HEXDIG HEXDIG
|
||||
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
||||
* / "*" / "+" / "," / ";" / "="
|
||||
*/
|
||||
export function encodeUriQuery(val: string, pctEncodeSpaces: boolean = false) {
|
||||
return encodeURIComponent(val)
|
||||
.replace(/%40/gi, '@')
|
||||
.replace(/%3A/gi, ':')
|
||||
.replace(/%24/g, '$')
|
||||
.replace(/%2C/gi, ',')
|
||||
.replace(/%3B/gi, ';')
|
||||
.replace(/%20/g, pctEncodeSpaces ? '%20' : '+');
|
||||
}
|
|
@ -17,4 +17,4 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export { Get, Set, createGetterSetter } from '../common';
|
||||
export { Get, Set, createGetterSetter, url } from '../common';
|
||||
|
|
|
@ -17,16 +17,16 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { parse } from 'query-string';
|
||||
import fn from './quandl';
|
||||
|
||||
const parseURL = require('url').parse;
|
||||
const parseQueryString = require('querystring').parse;
|
||||
const tlConfig = require('./fixtures/tl_config')();
|
||||
import moment from 'moment';
|
||||
import fetchMock from 'node-fetch';
|
||||
|
||||
const parseURL = require('url').parse;
|
||||
const tlConfig = require('./fixtures/tl_config')();
|
||||
|
||||
function parseUrlParams(url) {
|
||||
return parseQueryString(parseURL(url).query);
|
||||
return parse(parseURL(url).query, { sort: false });
|
||||
}
|
||||
|
||||
jest.mock('node-fetch', () =>
|
||||
|
|
|
@ -16,6 +16,44 @@ describe('toQuery', () => {
|
|||
});
|
||||
|
||||
describe('fromQuery', () => {
|
||||
it('should not encode the following characters', () => {
|
||||
expect(
|
||||
fromQuery({
|
||||
a: true,
|
||||
b: 5000,
|
||||
c: ':'
|
||||
})
|
||||
).toEqual('a=true&b=5000&c=:');
|
||||
});
|
||||
|
||||
it('should encode the following characters', () => {
|
||||
expect(
|
||||
fromQuery({
|
||||
a: '@',
|
||||
b: '.',
|
||||
c: ';',
|
||||
d: ' '
|
||||
})
|
||||
).toEqual('a=%40&b=.&c=%3B&d=%20');
|
||||
});
|
||||
|
||||
it('should handle null and undefined', () => {
|
||||
expect(
|
||||
fromQuery({
|
||||
a: undefined,
|
||||
b: null
|
||||
})
|
||||
).toEqual('a=&b=');
|
||||
});
|
||||
|
||||
it('should handle arrays', () => {
|
||||
expect(
|
||||
fromQuery({
|
||||
arr: ['a', 'b']
|
||||
})
|
||||
).toEqual('arr=a%2Cb');
|
||||
});
|
||||
|
||||
it('should parse object to string', () => {
|
||||
expect(
|
||||
fromQuery({
|
||||
|
|
|
@ -4,19 +4,20 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import qs from 'querystring';
|
||||
import { parse, stringify } from 'query-string';
|
||||
import { LocalUIFilterName } from '../../../../server/lib/ui_filters/local_ui_filters/config';
|
||||
import { url } from '../../../../../../../../src/plugins/kibana_utils/public';
|
||||
|
||||
export function toQuery(search?: string): APMQueryParamsRaw {
|
||||
return search ? qs.parse(search.slice(1)) : {};
|
||||
return search ? parse(search.slice(1), { sort: false }) : {};
|
||||
}
|
||||
|
||||
export function fromQuery(query: Record<string, any>) {
|
||||
return qs.stringify(query, undefined, undefined, {
|
||||
encodeURIComponent: (value: string) => {
|
||||
return encodeURIComponent(value).replace(/%3A/g, ':');
|
||||
}
|
||||
});
|
||||
const encodedQuery = url.encodeQuery(query, value =>
|
||||
encodeURIComponent(value).replace(/%3A/g, ':')
|
||||
);
|
||||
|
||||
return stringify(encodedQuery, { sort: false, encode: false });
|
||||
}
|
||||
|
||||
export type APMQueryParams = {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { parse, stringify } from 'querystring';
|
||||
import { parse, stringify } from 'query-string';
|
||||
import React from 'react';
|
||||
import { withRouter, RouteComponentProps } from 'react-router-dom';
|
||||
import { FlatObject } from '../frontend_types';
|
||||
|
@ -31,7 +31,9 @@ export class WithURLStateComponent<URLState extends object> extends React.Compon
|
|||
> {
|
||||
private get URLState(): URLState {
|
||||
// slice because parse does not account for the initial ? in the search string
|
||||
return parse(decodeURIComponent(this.props.history.location.search).substring(1)) as URLState;
|
||||
return parse(decodeURIComponent(this.props.history.location.search).substring(1), {
|
||||
sort: false,
|
||||
}) as URLState;
|
||||
}
|
||||
|
||||
private historyListener: (() => void) | null = null;
|
||||
|
@ -63,10 +65,13 @@ export class WithURLStateComponent<URLState extends object> extends React.Compon
|
|||
newState = state;
|
||||
}
|
||||
|
||||
const search: string = stringify({
|
||||
...pastState,
|
||||
...newState,
|
||||
});
|
||||
const search: string = stringify(
|
||||
{
|
||||
...pastState,
|
||||
...newState,
|
||||
},
|
||||
{ sort: false }
|
||||
);
|
||||
|
||||
const newLocation = {
|
||||
...this.props.history.location,
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
import rison from 'rison-node';
|
||||
// @ts-ignore Untyped local.
|
||||
import { fetch } from '../../../../common/lib/fetch';
|
||||
import { getStartPlugins } from '../../../legacy';
|
||||
import { CanvasWorkpad } from '../../../../types';
|
||||
import { url } from '../../../../../../../../src/plugins/kibana_utils/public';
|
||||
|
||||
// type of the desired pdf output (print or preserve_layout)
|
||||
const PDF_LAYOUT_TYPE = 'preserve_layout';
|
||||
|
@ -71,11 +71,10 @@ function getPdfUrlParts(
|
|||
|
||||
export function getPdfUrl(...args: Arguments): string {
|
||||
const urlParts = getPdfUrlParts(...args);
|
||||
const param = (key: string, val: any) =>
|
||||
url.encodeUriQuery(key, true) + (val === true ? '' : '=' + url.encodeUriQuery(val, true));
|
||||
|
||||
return `${urlParts.createPdfUri}?${getStartPlugins().__LEGACY.QueryString.param(
|
||||
'jobParams',
|
||||
urlParts.createPdfPayload.jobParams
|
||||
)}`;
|
||||
return `${urlParts.createPdfUri}?${param('jobParams', urlParts.createPdfPayload.jobParams)}`;
|
||||
}
|
||||
|
||||
export function createPdf(...args: Arguments) {
|
||||
|
|
|
@ -13,8 +13,6 @@ import { absoluteToParsedUrl } from 'ui/url/absolute_to_parsed_url'; // eslint-d
|
|||
import { Storage } from '../../../../../src/plugins/kibana_utils/public'; // eslint-disable-line import/order
|
||||
// @ts-ignore Untyped Kibana Lib
|
||||
import { formatMsg } from '../../../../../src/plugins/kibana_legacy/public'; // eslint-disable-line import/order
|
||||
// @ts-ignore Untyped Kibana Lib
|
||||
import { QueryString } from 'ui/utils/query_string'; // eslint-disable-line import/order
|
||||
|
||||
const shimCoreSetup = {
|
||||
...npSetup.core,
|
||||
|
@ -33,7 +31,6 @@ const shimStartPlugins: CanvasStartDeps = {
|
|||
absoluteToParsedUrl,
|
||||
// ToDo: Copy directly into canvas
|
||||
formatMsg,
|
||||
QueryString,
|
||||
storage: Storage,
|
||||
// ToDo: Won't be a part of New Platform. Will need to handle internally
|
||||
trackSubUrlForApp: chrome.trackSubUrlForApp,
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import querystring from 'querystring';
|
||||
import { parse } from 'query-string';
|
||||
import { get } from 'lodash';
|
||||
// @ts-ignore untyped local
|
||||
import { getInitialState } from '../state/initial_state';
|
||||
|
@ -38,7 +38,7 @@ export function getDefaultAppState(): AppState {
|
|||
export function getCurrentAppState(): AppState {
|
||||
const history = historyProvider(getWindow());
|
||||
const { search } = history.getLocation();
|
||||
const qs = !!search ? querystring.parse(search.replace(/^\?/, '')) : {};
|
||||
const qs = !!search ? parse(search.replace(/^\?/, ''), { sort: false }) : {};
|
||||
const appState = assignAppState({}, qs);
|
||||
|
||||
return appState;
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { ParsedUrlQuery } from 'querystring';
|
||||
import { ParsedQuery } from 'query-string';
|
||||
import { format as formatUrl, parse as parseUrl, UrlObject } from 'url';
|
||||
|
||||
/**
|
||||
|
@ -20,7 +20,7 @@ export interface URLMeaningfulParts {
|
|||
protocol?: string | null;
|
||||
slashes?: boolean | null;
|
||||
port?: string | null;
|
||||
query: ParsedUrlQuery;
|
||||
query: ParsedQuery;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -43,7 +43,6 @@ export interface CanvasStartDeps {
|
|||
__LEGACY: {
|
||||
absoluteToParsedUrl: (url: string, basePath: string) => any;
|
||||
formatMsg: any;
|
||||
QueryString: any;
|
||||
storage: typeof Storage;
|
||||
trackSubUrlForApp: Chrome['trackSubUrlForApp'];
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { parse } from 'querystring';
|
||||
import { parse } from 'query-string';
|
||||
|
||||
export function extractQueryParams(queryString) {
|
||||
const hrefSplit = queryString.split('?');
|
||||
|
@ -12,5 +12,5 @@ export function extractQueryParams(queryString) {
|
|||
return {};
|
||||
}
|
||||
|
||||
return parse(hrefSplit[1]);
|
||||
return parse(hrefSplit[1], { sort: false });
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
*/
|
||||
|
||||
import { createLocation } from 'history';
|
||||
import { stringify } from 'querystring';
|
||||
import { stringify } from 'query-string';
|
||||
import { APPS, BASE_PATH, BASE_PATH_REMOTE_CLUSTERS } from '../../../common/constants';
|
||||
|
||||
const isModifiedEvent = event =>
|
||||
|
@ -22,16 +22,7 @@ const queryParamsFromObject = (params, encodeParams = false) => {
|
|||
return;
|
||||
}
|
||||
|
||||
const paramsStr = stringify(
|
||||
params,
|
||||
'&',
|
||||
'=',
|
||||
encodeParams
|
||||
? {}
|
||||
: {
|
||||
encodeURIComponent: val => val, // Don't encode special chars
|
||||
}
|
||||
);
|
||||
const paramsStr = stringify(params, { sort: false, encode: encodeParams });
|
||||
return `?${paramsStr}`;
|
||||
};
|
||||
|
||||
|
|
|
@ -8,10 +8,11 @@ import { EuiButton } from '@elastic/eui';
|
|||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import React from 'react';
|
||||
import { encode } from 'rison-node';
|
||||
import { QueryString } from 'ui/utils/query_string';
|
||||
import url from 'url';
|
||||
import { stringify } from 'query-string';
|
||||
import { useKibana } from '../../../../../../../../src/plugins/kibana_react/public';
|
||||
import { TimeRange } from '../../../../common/http_api/shared/time_range';
|
||||
import { url as urlUtils } from '../../../../../../../../src/plugins/kibana_utils/public';
|
||||
|
||||
export const AnalyzeInMlButton: React.FunctionComponent<{
|
||||
jobId: string;
|
||||
|
@ -61,7 +62,7 @@ const getOverallAnomalyExplorerLink = (pathname: string, jobId: string, timeRang
|
|||
},
|
||||
});
|
||||
|
||||
const hash = `/explorer?${QueryString.encode({ _g })}`;
|
||||
const hash = `/explorer?${stringify(urlUtils.encodeQuery({ _g }), { encode: false })}`;
|
||||
|
||||
return url.format({
|
||||
pathname,
|
||||
|
@ -94,7 +95,10 @@ const getPartitionSpecificSingleMetricViewerLink = (
|
|||
},
|
||||
});
|
||||
|
||||
const hash = `/timeseriesexplorer?${QueryString.encode({ _g, _a })}`;
|
||||
const hash = `/timeseriesexplorer?${stringify(urlUtils.encodeQuery({ _g, _a }), {
|
||||
sort: false,
|
||||
encode: false,
|
||||
})}`;
|
||||
|
||||
return url.format({
|
||||
pathname,
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { parse, stringify } from 'query-string';
|
||||
import { Location } from 'history';
|
||||
import omit from 'lodash/fp/omit';
|
||||
import { parse as parseQueryString, stringify as stringifyQueryString } from 'querystring';
|
||||
import React from 'react';
|
||||
import { RouteComponentProps, withRouter } from 'react-router-dom';
|
||||
// eslint-disable-next-line @typescript-eslint/camelcase
|
||||
|
@ -102,7 +102,7 @@ const encodeRisonAppState = (state: AnyObject) => ({
|
|||
export const mapRisonAppLocationToState = <State extends {}>(
|
||||
mapState: (risonAppState: AnyObject) => State = (state: AnyObject) => state as State
|
||||
) => (location: Location): State => {
|
||||
const queryValues = parseQueryString(location.search.substring(1));
|
||||
const queryValues = parse(location.search.substring(1), { sort: false });
|
||||
const decodedState = decodeRisonAppState(queryValues);
|
||||
return mapState(decodedState);
|
||||
};
|
||||
|
@ -110,17 +110,20 @@ export const mapRisonAppLocationToState = <State extends {}>(
|
|||
export const mapStateToRisonAppLocation = <State extends {}>(
|
||||
mapState: (state: State) => AnyObject = (state: State) => state
|
||||
) => (state: State, location: Location): Location => {
|
||||
const previousQueryValues = parseQueryString(location.search.substring(1));
|
||||
const previousQueryValues = parse(location.search.substring(1), { sort: false });
|
||||
const previousState = decodeRisonAppState(previousQueryValues);
|
||||
|
||||
const encodedState = encodeRisonAppState({
|
||||
...previousState,
|
||||
...mapState(state),
|
||||
});
|
||||
const newQueryValues = stringifyQueryString({
|
||||
...previousQueryValues,
|
||||
...encodedState,
|
||||
});
|
||||
const newQueryValues = stringify(
|
||||
{
|
||||
...previousQueryValues,
|
||||
...encodedState,
|
||||
},
|
||||
{ sort: false }
|
||||
);
|
||||
return {
|
||||
...location,
|
||||
search: `?${newQueryValues}`,
|
||||
|
|
|
@ -19,7 +19,7 @@ describe('RedirectToLogs component', () => {
|
|||
|
||||
expect(component).toMatchInlineSnapshot(`
|
||||
<Redirect
|
||||
to="/logs/stream?logFilter=(expression:'',kind:kuery)&logPosition=(position:(tiebreaker:0,time:1550671089404),streamLive:!f)&sourceId=default"
|
||||
to="/logs/stream?sourceId=default&logPosition=(position:(tiebreaker:0,time:1550671089404),streamLive:!f)&logFilter=(expression:'',kind:kuery)"
|
||||
/>
|
||||
`);
|
||||
});
|
||||
|
@ -33,7 +33,7 @@ describe('RedirectToLogs component', () => {
|
|||
|
||||
expect(component).toMatchInlineSnapshot(`
|
||||
<Redirect
|
||||
to="/logs/stream?logFilter=(expression:'FILTER_FIELD:FILTER_VALUE',kind:kuery)&logPosition=(position:(tiebreaker:0,time:1550671089404),streamLive:!f)&sourceId=default"
|
||||
to="/logs/stream?sourceId=default&logPosition=(position:(tiebreaker:0,time:1550671089404),streamLive:!f)&logFilter=(expression:'FILTER_FIELD:FILTER_VALUE',kind:kuery)"
|
||||
/>
|
||||
`);
|
||||
});
|
||||
|
@ -45,7 +45,7 @@ describe('RedirectToLogs component', () => {
|
|||
|
||||
expect(component).toMatchInlineSnapshot(`
|
||||
<Redirect
|
||||
to="/logs/stream?logFilter=(expression:'',kind:kuery)&sourceId=SOME-OTHER-SOURCE"
|
||||
to="/logs/stream?sourceId=SOME-OTHER-SOURCE&logFilter=(expression:'',kind:kuery)"
|
||||
/>
|
||||
`);
|
||||
});
|
||||
|
|
|
@ -35,7 +35,7 @@ describe('RedirectToNodeLogs component', () => {
|
|||
|
||||
expect(component).toMatchInlineSnapshot(`
|
||||
<Redirect
|
||||
to="/logs?logFilter=(expression:'HOST_FIELD:%20HOST_NAME',kind:kuery)&sourceId=default"
|
||||
to="/logs?sourceId=default&logFilter=(expression:'HOST_FIELD:%20HOST_NAME',kind:kuery)"
|
||||
/>
|
||||
`);
|
||||
});
|
||||
|
@ -47,7 +47,7 @@ describe('RedirectToNodeLogs component', () => {
|
|||
|
||||
expect(component).toMatchInlineSnapshot(`
|
||||
<Redirect
|
||||
to="/logs?logFilter=(expression:'CONTAINER_FIELD:%20CONTAINER_ID',kind:kuery)&sourceId=default"
|
||||
to="/logs?sourceId=default&logFilter=(expression:'CONTAINER_FIELD:%20CONTAINER_ID',kind:kuery)"
|
||||
/>
|
||||
`);
|
||||
});
|
||||
|
@ -59,7 +59,7 @@ describe('RedirectToNodeLogs component', () => {
|
|||
|
||||
expect(component).toMatchInlineSnapshot(`
|
||||
<Redirect
|
||||
to="/logs?logFilter=(expression:'POD_FIELD:%20POD_ID',kind:kuery)&sourceId=default"
|
||||
to="/logs?sourceId=default&logFilter=(expression:'POD_FIELD:%20POD_ID',kind:kuery)"
|
||||
/>
|
||||
`);
|
||||
});
|
||||
|
@ -73,7 +73,7 @@ describe('RedirectToNodeLogs component', () => {
|
|||
|
||||
expect(component).toMatchInlineSnapshot(`
|
||||
<Redirect
|
||||
to="/logs?logFilter=(expression:'HOST_FIELD:%20HOST_NAME',kind:kuery)&logPosition=(position:(tiebreaker:0,time:1550671089404),streamLive:!f)&sourceId=default"
|
||||
to="/logs?sourceId=default&logPosition=(position:(tiebreaker:0,time:1550671089404),streamLive:!f)&logFilter=(expression:'HOST_FIELD:%20HOST_NAME',kind:kuery)"
|
||||
/>
|
||||
`);
|
||||
});
|
||||
|
@ -89,7 +89,7 @@ describe('RedirectToNodeLogs component', () => {
|
|||
|
||||
expect(component).toMatchInlineSnapshot(`
|
||||
<Redirect
|
||||
to="/logs?logFilter=(expression:'(HOST_FIELD:%20HOST_NAME)%20and%20(FILTER_FIELD:FILTER_VALUE)',kind:kuery)&logPosition=(position:(tiebreaker:0,time:1550671089404),streamLive:!f)&sourceId=default"
|
||||
to="/logs?sourceId=default&logPosition=(position:(tiebreaker:0,time:1550671089404),streamLive:!f)&logFilter=(expression:'(HOST_FIELD:%20HOST_NAME)%20and%20(FILTER_FIELD:FILTER_VALUE)',kind:kuery)"
|
||||
/>
|
||||
`);
|
||||
});
|
||||
|
@ -103,7 +103,7 @@ describe('RedirectToNodeLogs component', () => {
|
|||
|
||||
expect(component).toMatchInlineSnapshot(`
|
||||
<Redirect
|
||||
to="/logs?logFilter=(expression:'HOST_FIELD:%20HOST_NAME',kind:kuery)&sourceId=SOME-OTHER-SOURCE"
|
||||
to="/logs?sourceId=SOME-OTHER-SOURCE&logFilter=(expression:'HOST_FIELD:%20HOST_NAME',kind:kuery)"
|
||||
/>
|
||||
`);
|
||||
});
|
||||
|
|
|
@ -4,13 +4,13 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { parse, stringify } from 'query-string';
|
||||
import { History, Location } from 'history';
|
||||
import throttle from 'lodash/fp/throttle';
|
||||
import React from 'react';
|
||||
import { Route, RouteProps } from 'react-router-dom';
|
||||
import { decode, encode, RisonValue } from 'rison-node';
|
||||
|
||||
import { QueryString } from 'ui/utils/query_string';
|
||||
import { url } from '../../../../../../src/plugins/kibana_utils/public';
|
||||
|
||||
interface UrlStateContainerProps<UrlState> {
|
||||
urlState: UrlState | undefined;
|
||||
|
@ -145,7 +145,9 @@ const encodeRisonUrlState = (state: any) => encode(state);
|
|||
export const getQueryStringFromLocation = (location: Location) => location.search.substring(1);
|
||||
|
||||
export const getParamFromQueryString = (queryString: string, key: string): string | undefined => {
|
||||
const queryParam = QueryString.decode(queryString)[key];
|
||||
const parsedQueryString: Record<string, any> = parse(queryString, { sort: false });
|
||||
const queryParam = parsedQueryString[key];
|
||||
|
||||
return Array.isArray(queryParam) ? queryParam[0] : queryParam;
|
||||
};
|
||||
|
||||
|
@ -153,13 +155,17 @@ export const replaceStateKeyInQueryString = <UrlState extends any>(
|
|||
stateKey: string,
|
||||
urlState: UrlState | undefined
|
||||
) => (queryString: string) => {
|
||||
const previousQueryValues = QueryString.decode(queryString);
|
||||
const previousQueryValues = parse(queryString, { sort: false });
|
||||
const encodedUrlState =
|
||||
typeof urlState !== 'undefined' ? encodeRisonUrlState(urlState) : undefined;
|
||||
return QueryString.encode({
|
||||
...previousQueryValues,
|
||||
[stateKey]: encodedUrlState,
|
||||
});
|
||||
|
||||
return stringify(
|
||||
url.encodeQuery({
|
||||
...previousQueryValues,
|
||||
[stateKey]: encodedUrlState,
|
||||
}),
|
||||
{ sort: false, encode: false }
|
||||
);
|
||||
};
|
||||
|
||||
const replaceQueryStringInLocation = (location: Location, queryString: string): Location => {
|
||||
|
|
|
@ -4,10 +4,11 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { parse, stringify } from 'query-string';
|
||||
import { Location } from 'history';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { decode, encode, RisonValue } from 'rison-node';
|
||||
import { QueryString } from 'ui/utils/query_string';
|
||||
import { url } from '../../../../../../src/plugins/kibana_utils/public';
|
||||
|
||||
import { useHistory } from './history_context';
|
||||
|
||||
|
@ -84,7 +85,7 @@ export const useUrlState = <State>({
|
|||
return [state, setState] as [typeof state, typeof setState];
|
||||
};
|
||||
|
||||
const decodeRisonUrlState = (value: string | undefined): RisonValue | undefined => {
|
||||
const decodeRisonUrlState = (value: string | undefined | null): RisonValue | undefined => {
|
||||
try {
|
||||
return value ? decode(value) : undefined;
|
||||
} catch (error) {
|
||||
|
@ -99,8 +100,10 @@ const encodeRisonUrlState = (state: any) => encode(state);
|
|||
|
||||
const getQueryStringFromLocation = (location: Location) => location.search.substring(1);
|
||||
|
||||
const getParamFromQueryString = (queryString: string, key: string): string | undefined => {
|
||||
const queryParam = QueryString.decode(queryString)[key];
|
||||
const getParamFromQueryString = (queryString: string, key: string) => {
|
||||
const parsedQueryString = parse(queryString, { sort: false });
|
||||
const queryParam = parsedQueryString[key];
|
||||
|
||||
return Array.isArray(queryParam) ? queryParam[0] : queryParam;
|
||||
};
|
||||
|
||||
|
@ -108,13 +111,17 @@ export const replaceStateKeyInQueryString = <UrlState extends any>(
|
|||
stateKey: string,
|
||||
urlState: UrlState | undefined
|
||||
) => (queryString: string) => {
|
||||
const previousQueryValues = QueryString.decode(queryString);
|
||||
const previousQueryValues = parse(queryString, { sort: false });
|
||||
const encodedUrlState =
|
||||
typeof urlState !== 'undefined' ? encodeRisonUrlState(urlState) : undefined;
|
||||
return QueryString.encode({
|
||||
...previousQueryValues,
|
||||
[stateKey]: encodedUrlState,
|
||||
});
|
||||
|
||||
return stringify(
|
||||
url.encodeQuery({
|
||||
...previousQueryValues,
|
||||
[stateKey]: encodedUrlState,
|
||||
}),
|
||||
{ sort: false, encode: false }
|
||||
);
|
||||
};
|
||||
|
||||
const replaceQueryStringInLocation = (location: Location, queryString: string): Location => {
|
||||
|
|
|
@ -4,12 +4,10 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { parse } from 'query-string';
|
||||
import React, { FC } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { decode } from 'rison-node';
|
||||
|
||||
// @ts-ignore
|
||||
import queryString from 'query-string';
|
||||
import { MlRoute, PageLoader, PageProps } from '../../router';
|
||||
import { useResolver } from '../../use_resolver';
|
||||
import { basicResolvers } from '../../resolvers';
|
||||
|
@ -36,7 +34,8 @@ export const analyticsJobExplorationRoute: MlRoute = {
|
|||
|
||||
const PageWrapper: FC<PageProps> = ({ location, deps }) => {
|
||||
const { context } = useResolver('', undefined, deps.config, basicResolvers(deps));
|
||||
const { _g } = queryString.parse(location.search);
|
||||
const { _g }: Record<string, any> = parse(location.search, { sort: false });
|
||||
|
||||
let globalState: any = null;
|
||||
try {
|
||||
globalState = decode(_g);
|
||||
|
|
|
@ -4,11 +4,9 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { parse } from 'query-string';
|
||||
import React, { FC } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
// @ts-ignore
|
||||
import queryString from 'query-string';
|
||||
import { MlRoute, PageLoader, PageProps } from '../../router';
|
||||
import { useResolver } from '../../use_resolver';
|
||||
import { Page } from '../../../datavisualizer/index_based';
|
||||
|
@ -37,7 +35,7 @@ export const indexBasedRoute: MlRoute = {
|
|||
};
|
||||
|
||||
const PageWrapper: FC<PageProps> = ({ location, deps }) => {
|
||||
const { index, savedSearchId } = queryString.parse(location.search);
|
||||
const { index, savedSearchId }: Record<string, any> = parse(location.search, { sort: false });
|
||||
const { context } = useResolver(index, savedSearchId, deps.config, {
|
||||
checkBasicLicense,
|
||||
loadIndexPatterns: () => loadIndexPatterns(deps.indexPatterns),
|
||||
|
|
|
@ -4,11 +4,9 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { parse } from 'query-string';
|
||||
import React, { FC } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
// @ts-ignore
|
||||
import queryString from 'query-string';
|
||||
import { MlRoute, PageLoader, PageProps } from '../../router';
|
||||
import { useResolver } from '../../use_resolver';
|
||||
import { basicResolvers } from '../../resolvers';
|
||||
|
@ -33,7 +31,7 @@ export const jobTypeRoute: MlRoute = {
|
|||
};
|
||||
|
||||
const PageWrapper: FC<PageProps> = ({ location, deps }) => {
|
||||
const { index, savedSearchId } = queryString.parse(location.search);
|
||||
const { index, savedSearchId }: Record<string, any> = parse(location.search, { sort: false });
|
||||
const { context } = useResolver(index, savedSearchId, deps.config, basicResolvers(deps));
|
||||
return (
|
||||
<PageLoader context={context}>
|
||||
|
|
|
@ -4,11 +4,9 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { parse } from 'query-string';
|
||||
import React, { FC } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
// @ts-ignore
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { MlRoute, PageLoader, PageProps } from '../../router';
|
||||
import { useResolver } from '../../use_resolver';
|
||||
import { basicResolvers } from '../../resolvers';
|
||||
|
@ -41,7 +39,7 @@ export const checkViewOrCreateRoute: MlRoute = {
|
|||
};
|
||||
|
||||
const PageWrapper: FC<PageProps> = ({ location, deps }) => {
|
||||
const { id, index, savedSearchId } = queryString.parse(location.search);
|
||||
const { id, index, savedSearchId }: Record<string, any> = parse(location.search, { sort: false });
|
||||
const { context, results } = useResolver(index, savedSearchId, deps.config, {
|
||||
...basicResolvers(deps),
|
||||
existingJobsAndGroups: mlJobService.getJobAndGroupIds,
|
||||
|
@ -55,7 +53,10 @@ const PageWrapper: FC<PageProps> = ({ location, deps }) => {
|
|||
};
|
||||
|
||||
const CheckViewOrCreateWrapper: FC<PageProps> = ({ location, deps }) => {
|
||||
const { id: moduleId, index: indexPatternId } = queryString.parse(location.search);
|
||||
const { id: moduleId, index: indexPatternId }: Record<string, any> = parse(location.search, {
|
||||
sort: false,
|
||||
});
|
||||
|
||||
// the single resolver checkViewOrCreateJobs redirects only. so will always reject
|
||||
useResolver(undefined, undefined, deps.config, {
|
||||
checkViewOrCreateJobs: () => checkViewOrCreateJobs(moduleId, indexPatternId),
|
||||
|
|
|
@ -4,10 +4,9 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { parse } from 'query-string';
|
||||
import React, { FC } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
// @ts-ignore
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { basicResolvers } from '../../resolvers';
|
||||
import { MlRoute, PageLoader, PageProps } from '../../router';
|
||||
|
@ -113,7 +112,7 @@ export const categorizationRoute: MlRoute = {
|
|||
};
|
||||
|
||||
const PageWrapper: FC<WizardPageProps> = ({ location, jobType, deps }) => {
|
||||
const { index, savedSearchId } = queryString.parse(location.search);
|
||||
const { index, savedSearchId }: Record<string, any> = parse(location.search, { sort: false });
|
||||
const { context, results } = useResolver(index, savedSearchId, deps.config, {
|
||||
...basicResolvers(deps),
|
||||
privileges: checkCreateJobsPrivilege,
|
||||
|
|
|
@ -8,8 +8,6 @@ import { isEqual } from 'lodash';
|
|||
import React, { FC, useCallback, useEffect, useState } from 'react';
|
||||
import { usePrevious } from 'react-use';
|
||||
import moment from 'moment';
|
||||
// @ts-ignore
|
||||
import queryString from 'query-string';
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
|
|
|
@ -4,10 +4,9 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { parse, stringify } from 'query-string';
|
||||
import { useCallback } from 'react';
|
||||
import { isEqual } from 'lodash';
|
||||
// @ts-ignore
|
||||
import queryString from 'query-string';
|
||||
import { decode, encode } from 'rison-node';
|
||||
import { useHistory, useLocation } from 'react-router-dom';
|
||||
|
||||
|
@ -33,12 +32,12 @@ function isRisonSerializationRequired(queryParam: string): boolean {
|
|||
|
||||
export function getUrlState(search: string): Dictionary<any> {
|
||||
const urlState: Dictionary<any> = {};
|
||||
const parsedQueryString = queryString.parse(search);
|
||||
const parsedQueryString = parse(search, { sort: false });
|
||||
|
||||
try {
|
||||
Object.keys(parsedQueryString).forEach(a => {
|
||||
if (isRisonSerializationRequired(a)) {
|
||||
urlState[a] = decode(parsedQueryString[a]) as Dictionary<any>;
|
||||
urlState[a] = decode(parsedQueryString[a] as string);
|
||||
} else {
|
||||
urlState[a] = parsedQueryString[a];
|
||||
}
|
||||
|
@ -64,7 +63,7 @@ export const useUrlState = (accessor: string): UrlState => {
|
|||
const setUrlState = useCallback(
|
||||
(attribute: string | Dictionary<any>, value?: any) => {
|
||||
const urlState = getUrlState(search);
|
||||
const parsedQueryString = queryString.parse(search);
|
||||
const parsedQueryString = parse(search, { sort: false });
|
||||
|
||||
if (!Object.prototype.hasOwnProperty.call(urlState, accessor)) {
|
||||
urlState[accessor] = {};
|
||||
|
@ -84,7 +83,7 @@ export const useUrlState = (accessor: string): UrlState => {
|
|||
}
|
||||
|
||||
try {
|
||||
const oldLocationSearch = queryString.stringify(parsedQueryString, { encode: false });
|
||||
const oldLocationSearch = stringify(parsedQueryString, { sort: false, encode: false });
|
||||
|
||||
Object.keys(urlState).forEach(a => {
|
||||
if (isRisonSerializationRequired(a)) {
|
||||
|
@ -93,11 +92,11 @@ export const useUrlState = (accessor: string): UrlState => {
|
|||
parsedQueryString[a] = urlState[a];
|
||||
}
|
||||
});
|
||||
const newLocationSearch = queryString.stringify(parsedQueryString, { encode: false });
|
||||
const newLocationSearch = stringify(parsedQueryString, { sort: false, encode: false });
|
||||
|
||||
if (oldLocationSearch !== newLocationSearch) {
|
||||
history.push({
|
||||
search: queryString.stringify(parsedQueryString),
|
||||
search: stringify(parsedQueryString, { sort: false }),
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { parse } from 'querystring';
|
||||
import { parse } from 'query-string';
|
||||
|
||||
export function extractQueryParams(queryString) {
|
||||
const hrefSplit = queryString.split('?');
|
||||
|
@ -12,5 +12,5 @@ export function extractQueryParams(queryString) {
|
|||
return {};
|
||||
}
|
||||
|
||||
return parse(hrefSplit[1]);
|
||||
return parse(hrefSplit[1], { sort: false });
|
||||
}
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
/* eslint-disable @kbn/eslint/require-license-header */
|
||||
|
||||
// This function was extracted from angular v1.3
|
||||
|
||||
/* @notice
|
||||
* This product includes code that was extracted from angular@1.3.
|
||||
* Original license:
|
||||
* The MIT License
|
||||
*
|
||||
* Copyright (c) 2010-2014 Google, Inc. http://angularjs.org
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
export function encodeUriQuery(val, pctEncodeSpaces) {
|
||||
return encodeURIComponent(val)
|
||||
.replace(/%40/gi, '@')
|
||||
.replace(/%3A/gi, ':')
|
||||
.replace(/%24/g, '$')
|
||||
.replace(/%2C/gi, ',')
|
||||
.replace(/%3B/gi, ';')
|
||||
.replace(/%20/g, pctEncodeSpaces ? '%20' : '+');
|
||||
}
|
|
@ -5,20 +5,20 @@
|
|||
*/
|
||||
|
||||
import { forEach, isArray } from 'lodash';
|
||||
import { encodeUriQuery } from './encode_uri_query';
|
||||
import { url } from '../../../../../../../../src/plugins/kibana_utils/server';
|
||||
|
||||
function toKeyValue(obj) {
|
||||
const parts = [];
|
||||
forEach(obj, function(value, key) {
|
||||
if (isArray(value)) {
|
||||
forEach(value, function(arrayValue) {
|
||||
const keyStr = encodeUriQuery(key, true);
|
||||
const valStr = arrayValue === true ? '' : '=' + encodeUriQuery(arrayValue, true);
|
||||
const keyStr = url.encodeUriQuery(key, true);
|
||||
const valStr = arrayValue === true ? '' : '=' + url.encodeUriQuery(arrayValue, true);
|
||||
parts.push(keyStr + valStr);
|
||||
});
|
||||
} else {
|
||||
const keyStr = encodeUriQuery(key, true);
|
||||
const valStr = value === true ? '' : '=' + encodeUriQuery(value, true);
|
||||
const keyStr = url.encodeUriQuery(key, true);
|
||||
const valStr = value === true ? '' : '=' + url.encodeUriQuery(value, true);
|
||||
parts.push(keyStr + valStr);
|
||||
}
|
||||
});
|
||||
|
@ -27,5 +27,5 @@ function toKeyValue(obj) {
|
|||
|
||||
export const uriEncode = {
|
||||
stringify: toKeyValue,
|
||||
string: encodeUriQuery,
|
||||
string: url.encodeUriQuery,
|
||||
};
|
||||
|
|
|
@ -3,16 +3,13 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { stringify } from 'query-string';
|
||||
import { npStart } from 'ui/new_platform';
|
||||
import querystring from 'querystring';
|
||||
|
||||
const { core } = npStart;
|
||||
|
||||
// @ts-ignore
|
||||
import rison from 'rison-node';
|
||||
import { add } from './job_completion_notifications';
|
||||
|
||||
const { core } = npStart;
|
||||
const API_BASE_URL = '/api/reporting/generate';
|
||||
|
||||
interface JobParams {
|
||||
|
@ -20,7 +17,7 @@ interface JobParams {
|
|||
}
|
||||
|
||||
export const getReportingJobPath = (exportType: string, jobParams: JobParams) => {
|
||||
const params = querystring.stringify({ jobParams: rison.encode(jobParams) });
|
||||
const params = stringify({ jobParams: rison.encode(jobParams) });
|
||||
|
||||
return `${core.http.basePath.prepend(API_BASE_URL)}/${exportType}?${params}`;
|
||||
};
|
||||
|
|
|
@ -4,16 +4,18 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { parse, stringify } from 'query-string';
|
||||
import React from 'react';
|
||||
|
||||
import { Redirect, Route, Switch, RouteComponentProps } from 'react-router-dom';
|
||||
import { QueryString } from 'ui/utils/query_string';
|
||||
import { addEntitiesToKql } from './add_entities_to_kql';
|
||||
import { replaceKQLParts } from './replace_kql_parts';
|
||||
import { emptyEntity, multipleEntities, getMultipleEntities } from './entity_helpers';
|
||||
import { SiemPageName } from '../../../pages/home/types';
|
||||
import { HostsTableType } from '../../../store/hosts/model';
|
||||
|
||||
import { url as urlUtils } from '../../../../../../../../src/plugins/kibana_utils/public';
|
||||
|
||||
interface QueryStringType {
|
||||
'?_g': string;
|
||||
query: string | null;
|
||||
|
@ -29,13 +31,17 @@ export const MlHostConditionalContainer = React.memo<MlHostConditionalProps>(({
|
|||
exact
|
||||
path={url}
|
||||
render={({ location }) => {
|
||||
const queryStringDecoded: QueryStringType = QueryString.decode(
|
||||
location.search.substring(1)
|
||||
);
|
||||
const queryStringDecoded = parse(location.search.substring(1), {
|
||||
sort: false,
|
||||
}) as Required<QueryStringType>;
|
||||
|
||||
if (queryStringDecoded.query != null) {
|
||||
queryStringDecoded.query = replaceKQLParts(queryStringDecoded.query);
|
||||
}
|
||||
const reEncoded = QueryString.encode(queryStringDecoded);
|
||||
const reEncoded = stringify(urlUtils.encodeQuery(queryStringDecoded), {
|
||||
sort: false,
|
||||
encode: false,
|
||||
});
|
||||
return <Redirect to={`/${SiemPageName.hosts}?${reEncoded}`} />;
|
||||
}}
|
||||
/>
|
||||
|
@ -47,14 +53,19 @@ export const MlHostConditionalContainer = React.memo<MlHostConditionalProps>(({
|
|||
params: { hostName },
|
||||
},
|
||||
}) => {
|
||||
const queryStringDecoded: QueryStringType = QueryString.decode(
|
||||
location.search.substring(1)
|
||||
);
|
||||
const queryStringDecoded = parse(location.search.substring(1), {
|
||||
sort: false,
|
||||
}) as Required<QueryStringType>;
|
||||
|
||||
if (queryStringDecoded.query != null) {
|
||||
queryStringDecoded.query = replaceKQLParts(queryStringDecoded.query);
|
||||
}
|
||||
if (emptyEntity(hostName)) {
|
||||
const reEncoded = QueryString.encode(queryStringDecoded);
|
||||
const reEncoded = stringify(urlUtils.encodeQuery(queryStringDecoded), {
|
||||
sort: false,
|
||||
encode: false,
|
||||
});
|
||||
|
||||
return (
|
||||
<Redirect to={`/${SiemPageName.hosts}/${HostsTableType.anomalies}?${reEncoded}`} />
|
||||
);
|
||||
|
@ -65,12 +76,20 @@ export const MlHostConditionalContainer = React.memo<MlHostConditionalProps>(({
|
|||
hosts,
|
||||
queryStringDecoded.query || ''
|
||||
);
|
||||
const reEncoded = QueryString.encode(queryStringDecoded);
|
||||
const reEncoded = stringify(urlUtils.encodeQuery(queryStringDecoded), {
|
||||
sort: false,
|
||||
encode: false,
|
||||
});
|
||||
|
||||
return (
|
||||
<Redirect to={`/${SiemPageName.hosts}/${HostsTableType.anomalies}?${reEncoded}`} />
|
||||
);
|
||||
} else {
|
||||
const reEncoded = QueryString.encode(queryStringDecoded);
|
||||
const reEncoded = stringify(urlUtils.encodeQuery(queryStringDecoded), {
|
||||
sort: false,
|
||||
encode: false,
|
||||
});
|
||||
|
||||
return (
|
||||
<Redirect
|
||||
to={`/${SiemPageName.hosts}/${hostName}/${HostsTableType.anomalies}?${reEncoded}`}
|
||||
|
|
|
@ -4,15 +4,17 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { parse, stringify } from 'query-string';
|
||||
import React from 'react';
|
||||
|
||||
import { Redirect, Route, Switch, RouteComponentProps } from 'react-router-dom';
|
||||
import { QueryString } from 'ui/utils/query_string';
|
||||
import { addEntitiesToKql } from './add_entities_to_kql';
|
||||
import { replaceKQLParts } from './replace_kql_parts';
|
||||
import { emptyEntity, getMultipleEntities, multipleEntities } from './entity_helpers';
|
||||
import { SiemPageName } from '../../../pages/home/types';
|
||||
|
||||
import { url as urlUtils } from '../../../../../../../../src/plugins/kibana_utils/public';
|
||||
|
||||
interface QueryStringType {
|
||||
'?_g': string;
|
||||
query: string | null;
|
||||
|
@ -28,13 +30,19 @@ export const MlNetworkConditionalContainer = React.memo<MlNetworkConditionalProp
|
|||
exact
|
||||
path={url}
|
||||
render={({ location }) => {
|
||||
const queryStringDecoded: QueryStringType = QueryString.decode(
|
||||
location.search.substring(1)
|
||||
);
|
||||
const queryStringDecoded = parse(location.search.substring(1), {
|
||||
sort: false,
|
||||
}) as Required<QueryStringType>;
|
||||
|
||||
if (queryStringDecoded.query != null) {
|
||||
queryStringDecoded.query = replaceKQLParts(queryStringDecoded.query);
|
||||
}
|
||||
const reEncoded = QueryString.encode(queryStringDecoded);
|
||||
|
||||
const reEncoded = stringify(urlUtils.encodeQuery(queryStringDecoded), {
|
||||
sort: false,
|
||||
encode: false,
|
||||
});
|
||||
|
||||
return <Redirect to={`/${SiemPageName.network}?${reEncoded}`} />;
|
||||
}}
|
||||
/>
|
||||
|
@ -46,14 +54,20 @@ export const MlNetworkConditionalContainer = React.memo<MlNetworkConditionalProp
|
|||
params: { ip },
|
||||
},
|
||||
}) => {
|
||||
const queryStringDecoded: QueryStringType = QueryString.decode(
|
||||
location.search.substring(1)
|
||||
);
|
||||
const queryStringDecoded = parse(location.search.substring(1), {
|
||||
sort: false,
|
||||
}) as Required<QueryStringType>;
|
||||
|
||||
if (queryStringDecoded.query != null) {
|
||||
queryStringDecoded.query = replaceKQLParts(queryStringDecoded.query);
|
||||
}
|
||||
|
||||
if (emptyEntity(ip)) {
|
||||
const reEncoded = QueryString.encode(queryStringDecoded);
|
||||
const reEncoded = stringify(urlUtils.encodeQuery(queryStringDecoded), {
|
||||
sort: false,
|
||||
encode: false,
|
||||
});
|
||||
|
||||
return <Redirect to={`/${SiemPageName.network}?${reEncoded}`} />;
|
||||
} else if (multipleEntities(ip)) {
|
||||
const ips: string[] = getMultipleEntities(ip);
|
||||
|
@ -62,10 +76,16 @@ export const MlNetworkConditionalContainer = React.memo<MlNetworkConditionalProp
|
|||
ips,
|
||||
queryStringDecoded.query || ''
|
||||
);
|
||||
const reEncoded = QueryString.encode(queryStringDecoded);
|
||||
const reEncoded = stringify(urlUtils.encodeQuery(queryStringDecoded), {
|
||||
sort: false,
|
||||
encode: false,
|
||||
});
|
||||
return <Redirect to={`/${SiemPageName.network}?${reEncoded}`} />;
|
||||
} else {
|
||||
const reEncoded = QueryString.encode(queryStringDecoded);
|
||||
const reEncoded = stringify(urlUtils.encodeQuery(queryStringDecoded), {
|
||||
sort: false,
|
||||
encode: false,
|
||||
});
|
||||
return <Redirect to={`/${SiemPageName.network}/ip/${ip}?${reEncoded}`} />;
|
||||
}
|
||||
}}
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { parse, stringify } from 'query-string';
|
||||
import { decode, encode } from 'rison-node';
|
||||
import * as H from 'history';
|
||||
import { QueryString } from 'ui/utils/query_string';
|
||||
import { Query, Filter } from 'src/plugins/data/public';
|
||||
|
||||
import { isEmpty } from 'lodash/fp';
|
||||
|
@ -24,6 +24,8 @@ import {
|
|||
UpdateUrlStateString,
|
||||
} from './types';
|
||||
|
||||
import { url } from '../../../../../../../src/plugins/kibana_utils/public';
|
||||
|
||||
export const decodeRisonUrlState = <T>(value: string | undefined): T | null => {
|
||||
try {
|
||||
return value ? ((decode(value) as unknown) as T) : null;
|
||||
|
@ -40,30 +42,35 @@ export const encodeRisonUrlState = (state: any) => encode(state);
|
|||
|
||||
export const getQueryStringFromLocation = (search: string) => search.substring(1);
|
||||
|
||||
export const getParamFromQueryString = (queryString: string, key: string): string | undefined => {
|
||||
const queryParam = QueryString.decode(queryString)[key];
|
||||
export const getParamFromQueryString = (queryString: string, key: string) => {
|
||||
const parsedQueryString = parse(queryString, { sort: false });
|
||||
const queryParam = parsedQueryString[key];
|
||||
|
||||
return Array.isArray(queryParam) ? queryParam[0] : queryParam;
|
||||
};
|
||||
|
||||
export const replaceStateKeyInQueryString = <T>(stateKey: string, urlState: T) => (
|
||||
queryString: string
|
||||
): string => {
|
||||
const previousQueryValues = QueryString.decode(queryString);
|
||||
const previousQueryValues = parse(queryString, { sort: false });
|
||||
if (urlState == null || (typeof urlState === 'string' && urlState === '')) {
|
||||
delete previousQueryValues[stateKey];
|
||||
return QueryString.encode({
|
||||
...previousQueryValues,
|
||||
});
|
||||
|
||||
return stringify(url.encodeQuery(previousQueryValues), { sort: false, encode: false });
|
||||
}
|
||||
|
||||
// ಠ_ಠ Code was copied from x-pack/legacy/plugins/infra/public/utils/url_state.tsx ಠ_ಠ
|
||||
// Remove this if these utilities are promoted to kibana core
|
||||
const encodedUrlState =
|
||||
typeof urlState !== 'undefined' ? encodeRisonUrlState(urlState) : undefined;
|
||||
return QueryString.encode({
|
||||
...previousQueryValues,
|
||||
[stateKey]: encodedUrlState,
|
||||
});
|
||||
|
||||
return stringify(
|
||||
url.encodeQuery({
|
||||
...previousQueryValues,
|
||||
[stateKey]: encodedUrlState,
|
||||
}),
|
||||
{ sort: false, encode: false }
|
||||
);
|
||||
};
|
||||
|
||||
export const replaceQueryStringInLocation = (
|
||||
|
|
|
@ -147,7 +147,7 @@ describe('UrlStateContainer - lodash.throttle mocked to test update url', () =>
|
|||
hash: '',
|
||||
pathname: '/network',
|
||||
search:
|
||||
'?timeline=(id:hello_timeline_id,isOpen:!t)&timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))',
|
||||
'?timerange=(global:(linkTo:!(timeline),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1558048243696,fromStr:now-24h,kind:relative,to:1558134643697,toStr:now)))&timeline=(id:hello_timeline_id,isOpen:!t)',
|
||||
state: '',
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,9 +4,9 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { parse } from 'query-string';
|
||||
import React, { Fragment, useState, useEffect } from 'react';
|
||||
import { RouteComponentProps } from 'react-router-dom';
|
||||
import { parse } from 'querystring';
|
||||
import { EuiButton, EuiCallOut, EuiLink, EuiEmptyPrompt, EuiSpacer, EuiIcon } from '@elastic/eui';
|
||||
|
||||
import { APP_SLM_CLUSTER_PRIVILEGES } from '../../../../../common/constants';
|
||||
|
@ -86,7 +86,7 @@ export const SnapshotList: React.FunctionComponent<RouteComponentProps<MatchPara
|
|||
const [filteredPolicy, setFilteredPolicy] = useState<string | undefined>(undefined);
|
||||
useEffect(() => {
|
||||
if (search) {
|
||||
const parsedParams = parse(search.replace(/^\?/, ''));
|
||||
const parsedParams = parse(search.replace(/^\?/, ''), { sort: false });
|
||||
const { repository, policy } = parsedParams;
|
||||
|
||||
if (policy && policy !== filteredPolicy) {
|
||||
|
|
|
@ -3,9 +3,10 @@
|
|||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { parse } from 'query-string';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { RouteComponentProps } from 'react-router-dom';
|
||||
import { parse } from 'querystring';
|
||||
|
||||
import { EuiPageBody, EuiPageContent, EuiSpacer, EuiTitle } from '@elastic/eui';
|
||||
import { Repository, EmptyRepository } from '../../../../common/types';
|
||||
|
@ -44,7 +45,8 @@ export const RepositoryAdd: React.FunctionComponent<RouteComponentProps> = ({
|
|||
if (error) {
|
||||
setSaveError(error);
|
||||
} else {
|
||||
const { redirect } = parse(search.replace(/^\?/, ''));
|
||||
const { redirect } = parse(search.replace(/^\?/, ''), { sort: false });
|
||||
|
||||
history.push(redirect ? (redirect as string) : `${BASE_PATH}/${section}/${name}`);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import qs from 'querystring';
|
||||
import { parse, stringify } from 'query-string';
|
||||
import { useLocation, useHistory } from 'react-router-dom';
|
||||
import { UptimeUrlParams, getSupportedUrlParams } from '../lib/helper';
|
||||
|
||||
|
@ -23,14 +23,17 @@ export const useUrlParams: UptimeUrlParamsHook = () => {
|
|||
search = location.search;
|
||||
}
|
||||
|
||||
const params = search ? { ...qs.parse(search[0] === '?' ? search.slice(1) : search) } : {};
|
||||
const params = search
|
||||
? parse(search[0] === '?' ? search.slice(1) : search, { sort: false })
|
||||
: {};
|
||||
|
||||
return getSupportedUrlParams(params);
|
||||
};
|
||||
|
||||
const updateUrlParams: UpdateUrlParams = updatedParams => {
|
||||
if (!history || !location) return;
|
||||
const { pathname, search } = location;
|
||||
const currentParams: any = qs.parse(search[0] === '?' ? search.slice(1) : search);
|
||||
const currentParams = parse(search[0] === '?' ? search.slice(1) : search, { sort: false });
|
||||
const mergedParams = {
|
||||
...currentParams,
|
||||
...updatedParams,
|
||||
|
@ -38,7 +41,7 @@ export const useUrlParams: UptimeUrlParamsHook = () => {
|
|||
|
||||
history.push({
|
||||
pathname,
|
||||
search: qs.stringify(
|
||||
search: stringify(
|
||||
// drop any parameters that have no value
|
||||
Object.keys(mergedParams).reduce((params, key) => {
|
||||
const value = mergedParams[key];
|
||||
|
@ -49,7 +52,8 @@ export const useUrlParams: UptimeUrlParamsHook = () => {
|
|||
...params,
|
||||
[key]: value,
|
||||
};
|
||||
}, {})
|
||||
}, {}),
|
||||
{ sort: false }
|
||||
),
|
||||
});
|
||||
};
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import qs from 'querystring';
|
||||
import { stringify } from 'query-string';
|
||||
import { UptimeUrlParams } from './url_params';
|
||||
import { CLIENT_DEFAULTS } from '../../../common/constants';
|
||||
|
||||
|
@ -38,5 +38,5 @@ export const stringifyUrlParams = (params: Partial<UptimeUrlParams>, ignoreEmpty
|
|||
}
|
||||
});
|
||||
}
|
||||
return `?${qs.stringify(params)}`;
|
||||
return `?${stringify(params, { sort: false })}`;
|
||||
};
|
||||
|
|
|
@ -46,7 +46,7 @@ const {
|
|||
* require further development.
|
||||
*/
|
||||
export const getSupportedUrlParams = (params: {
|
||||
[key: string]: string | string[] | undefined;
|
||||
[key: string]: string | string[] | undefined | null;
|
||||
}): UptimeUrlParams => {
|
||||
const filteredParams: { [key: string]: string | undefined } = {};
|
||||
Object.keys(params).forEach(key => {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import qs from 'querystring';
|
||||
import { stringify } from 'query-string';
|
||||
import { getApiPath } from '../../lib/helper';
|
||||
import { APIFn } from './types';
|
||||
import { GetPingHistogramParams, HistogramResult } from '../../../common/types';
|
||||
|
@ -25,7 +25,7 @@ export const fetchPingHistogram: APIFn<GetPingHistogramParams, HistogramResult>
|
|||
...(statusFilter && { statusFilter }),
|
||||
...(filters && { filters }),
|
||||
};
|
||||
const urlParams = qs.stringify(params).toString();
|
||||
const urlParams = stringify(params, { sort: false });
|
||||
const response = await fetch(`${url}?${urlParams}`);
|
||||
if (!response.ok) {
|
||||
throw new Error(response.statusText);
|
||||
|
|
|
@ -291,7 +291,9 @@
|
|||
"proper-lockfile": "^3.2.0",
|
||||
"puid": "1.0.7",
|
||||
"puppeteer-core": "^1.19.0",
|
||||
"query-string": "6.10.1",
|
||||
"raw-loader": "3.1.0",
|
||||
"re-resizable": "^6.1.1",
|
||||
"react": "^16.12.0",
|
||||
"react-apollo": "^2.1.4",
|
||||
"react-beautiful-dnd": "^8.0.7",
|
||||
|
@ -323,7 +325,6 @@
|
|||
"request": "^2.88.0",
|
||||
"reselect": "3.0.1",
|
||||
"resize-observer-polyfill": "^1.5.0",
|
||||
"re-resizable": "^6.1.1",
|
||||
"rison-node": "0.3.1",
|
||||
"rxjs": "^6.5.3",
|
||||
"semver": "5.7.0",
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// DIRECT COPY FROM `src/core/utils/url`, since it's not possible to import from there,
|
||||
// nor can I re-export from `src/core/server`...
|
||||
|
||||
import { ParsedUrlQuery } from 'querystring';
|
||||
import { ParsedQuery } from 'query-string';
|
||||
import { format as formatUrl, parse as parseUrl, UrlObject } from 'url';
|
||||
|
||||
export interface URLMeaningfulParts {
|
||||
|
@ -19,7 +19,7 @@ export interface URLMeaningfulParts {
|
|||
protocol: string | null;
|
||||
slashes: boolean | null;
|
||||
port: string | null;
|
||||
query: ParsedUrlQuery | {};
|
||||
query: ParsedQuery | {};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
*/
|
||||
|
||||
import expect from '@kbn/expect';
|
||||
import querystring from 'querystring';
|
||||
|
||||
import { stringify } from 'query-string';
|
||||
import { registerHelpers } from './rollup.test_helpers';
|
||||
import { INDEX_TO_ROLLUP_MAPPINGS, INDEX_PATTERNS_EXTENSION_BASE_PATH } from './constants';
|
||||
import { getRandomString } from './lib';
|
||||
|
@ -39,7 +38,7 @@ export default function({ getService }) {
|
|||
|
||||
it('"params" is required', async () => {
|
||||
params = { pattern: 'foo' };
|
||||
uri = `${BASE_URI}?${querystring.stringify(params)}`;
|
||||
uri = `${BASE_URI}?${stringify(params, { sort: false })}`;
|
||||
({ body } = await supertest.get(uri).expect(400));
|
||||
expect(body.message).to.contain(
|
||||
'[request query.params]: expected value of type [string]'
|
||||
|
@ -48,14 +47,14 @@ export default function({ getService }) {
|
|||
|
||||
it('"params" must be a valid JSON string', async () => {
|
||||
params = { pattern: 'foo', params: 'foobarbaz' };
|
||||
uri = `${BASE_URI}?${querystring.stringify(params)}`;
|
||||
uri = `${BASE_URI}?${stringify(params, { sort: false })}`;
|
||||
({ body } = await supertest.get(uri).expect(400));
|
||||
expect(body.message).to.contain('[request query.params]: expected JSON string');
|
||||
});
|
||||
|
||||
it('"params" requires a "rollup_index" property', async () => {
|
||||
params = { pattern: 'foo', params: JSON.stringify({}) };
|
||||
uri = `${BASE_URI}?${querystring.stringify(params)}`;
|
||||
uri = `${BASE_URI}?${stringify(params, { sort: false })}`;
|
||||
({ body } = await supertest.get(uri).expect(400));
|
||||
expect(body.message).to.contain('[request query.params]: "rollup_index" is required');
|
||||
});
|
||||
|
@ -65,7 +64,7 @@ export default function({ getService }) {
|
|||
pattern: 'foo',
|
||||
params: JSON.stringify({ rollup_index: 'my_index', someProp: 'bar' }),
|
||||
};
|
||||
uri = `${BASE_URI}?${querystring.stringify(params)}`;
|
||||
uri = `${BASE_URI}?${stringify(params, { sort: false })}`;
|
||||
({ body } = await supertest.get(uri).expect(400));
|
||||
expect(body.message).to.contain('[request query.params]: someProp is not allowed');
|
||||
});
|
||||
|
@ -76,7 +75,7 @@ export default function({ getService }) {
|
|||
params: JSON.stringify({ rollup_index: 'bar' }),
|
||||
meta_fields: 'stringValue',
|
||||
};
|
||||
uri = `${BASE_URI}?${querystring.stringify(params)}`;
|
||||
uri = `${BASE_URI}?${stringify(params, { sort: false })}`;
|
||||
({ body } = await supertest.get(uri).expect(400));
|
||||
expect(body.message).to.contain(
|
||||
'[request query.meta_fields]: could not parse array value from [stringValue]'
|
||||
|
@ -84,10 +83,13 @@ export default function({ getService }) {
|
|||
});
|
||||
|
||||
it('should return 404 the rollup index to query does not exist', async () => {
|
||||
uri = `${BASE_URI}?${querystring.stringify({
|
||||
pattern: 'foo',
|
||||
params: JSON.stringify({ rollup_index: 'bar' }),
|
||||
})}`;
|
||||
uri = `${BASE_URI}?${stringify(
|
||||
{
|
||||
pattern: 'foo',
|
||||
params: JSON.stringify({ rollup_index: 'bar' }),
|
||||
},
|
||||
{ sort: false }
|
||||
)}`;
|
||||
({ body } = await supertest.get(uri).expect(404));
|
||||
expect(body.message).to.contain('[index_not_found_exception] no such index [bar]');
|
||||
});
|
||||
|
@ -105,7 +107,7 @@ export default function({ getService }) {
|
|||
pattern: indexName,
|
||||
params: JSON.stringify({ rollup_index: rollupIndex }),
|
||||
};
|
||||
const uri = `${BASE_URI}?${querystring.stringify(params)}`;
|
||||
const uri = `${BASE_URI}?${stringify(params, { sort: false })}`;
|
||||
const { body } = await supertest.get(uri).expect(200);
|
||||
|
||||
// Verify that the fields for wildcard correspond to our declared mappings
|
||||
|
|
|
@ -22,7 +22,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
state: undefined,
|
||||
};
|
||||
const expectedSearchString =
|
||||
"logFilter=(expression:'trace.id:433b4651687e18be2c6c8e3b11f53d09',kind:kuery)&logPosition=(position:(tiebreaker:0,time:1565707203194),streamLive:!f)&sourceId=default";
|
||||
"sourceId=default&logPosition=(position:(tiebreaker:0,time:1565707203194),streamLive:!f)&logFilter=(expression:'trace.id:433b4651687e18be2c6c8e3b11f53d09',kind:kuery)";
|
||||
const expectedRedirectPath = '/logs/stream?';
|
||||
|
||||
await pageObjects.common.navigateToActualUrl(
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import querystring from 'querystring';
|
||||
import { stringify } from 'query-string';
|
||||
import url from 'url';
|
||||
import { delay } from 'bluebird';
|
||||
import expect from '@kbn/expect';
|
||||
|
@ -443,7 +443,7 @@ export default function({ getService }: FtrProviderContext) {
|
|||
it('should invalidate access token on IdP initiated logout', async () => {
|
||||
const logoutRequest = await createLogoutRequest({ sessionIndex: idpSessionIndex });
|
||||
const logoutResponse = await supertest
|
||||
.get(`/api/security/logout?${querystring.stringify(logoutRequest)}`)
|
||||
.get(`/api/security/logout?${stringify(logoutRequest, { sort: false })}`)
|
||||
.set('Cookie', sessionCookie.cookieString())
|
||||
.expect(302);
|
||||
|
||||
|
@ -479,7 +479,7 @@ export default function({ getService }: FtrProviderContext) {
|
|||
it('should invalidate access token on IdP initiated logout even if there is no Kibana session', async () => {
|
||||
const logoutRequest = await createLogoutRequest({ sessionIndex: idpSessionIndex });
|
||||
const logoutResponse = await supertest
|
||||
.get(`/api/security/logout?${querystring.stringify(logoutRequest)}`)
|
||||
.get(`/api/security/logout?${stringify(logoutRequest, { sort: false })}`)
|
||||
.expect(302);
|
||||
|
||||
expect(logoutResponse.headers['set-cookie']).to.be(undefined);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
import crypto from 'crypto';
|
||||
import fs from 'fs';
|
||||
import querystring from 'querystring';
|
||||
import { stringify } from 'query-string';
|
||||
import url from 'url';
|
||||
import zlib from 'zlib';
|
||||
import { promisify } from 'util';
|
||||
|
@ -140,7 +140,7 @@ export async function getLogoutRequest({
|
|||
};
|
||||
|
||||
const signer = crypto.createSign('RSA-SHA256');
|
||||
signer.update(querystring.stringify(queryStringParameters));
|
||||
signer.update(stringify(queryStringParameters, { sort: false }));
|
||||
queryStringParameters.Signature = signer.sign(signingKey.toString(), 'base64');
|
||||
|
||||
return queryStringParameters;
|
||||
|
|
24
yarn.lock
24
yarn.lock
|
@ -24470,6 +24470,15 @@ qs@~6.4.0:
|
|||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233"
|
||||
integrity sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=
|
||||
|
||||
query-string@6.10.1:
|
||||
version "6.10.1"
|
||||
resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.10.1.tgz#30b3505f6fca741d5ae541964d1b3ae9dc2a0de8"
|
||||
integrity sha512-SHTUV6gDlgMXg/AQUuLpTiBtW/etZ9JT6k6RCtCyqADquApLX0Aq5oK/s5UeTUAWBG50IExjIr587GqfXRfM4A==
|
||||
dependencies:
|
||||
decode-uri-component "^0.2.0"
|
||||
split-on-first "^1.0.0"
|
||||
strict-uri-encode "^2.0.0"
|
||||
|
||||
query-string@^4.1.0, query-string@^4.2.2:
|
||||
version "4.3.4"
|
||||
resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb"
|
||||
|
@ -24487,11 +24496,6 @@ query-string@^5.0.1:
|
|||
object-assign "^4.1.0"
|
||||
strict-uri-encode "^1.0.0"
|
||||
|
||||
querystring-browser@1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/querystring-browser/-/querystring-browser-1.0.4.tgz#f2e35881840a819bc7b1bf597faf0979e6622dc6"
|
||||
integrity sha1-8uNYgYQKgZvHsb9Zf68JeeZiLcY=
|
||||
|
||||
querystring-es3@^0.2.0:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
|
||||
|
@ -28083,6 +28087,11 @@ spdy@^4.0.1:
|
|||
select-hose "^2.0.0"
|
||||
spdy-transport "^3.0.0"
|
||||
|
||||
split-on-first@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f"
|
||||
integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==
|
||||
|
||||
split-string@^3.0.1, split-string@^3.0.2:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
|
||||
|
@ -28391,6 +28400,11 @@ strict-uri-encode@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713"
|
||||
integrity sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=
|
||||
|
||||
strict-uri-encode@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
|
||||
integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY=
|
||||
|
||||
string-length@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/string-length/-/string-length-1.0.1.tgz#56970fb1c38558e9e70b728bf3de269ac45adfac"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue