Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/server/saved_objects/client/saved_objects_client.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export class SavedObjectsClient {
index,
mappings,
callCluster,
onBeforeWrite = () => {},
onBeforeWrite = () => { },
} = options;

this._index = index;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`addSpaceUrlContext it throws an error when the requested path does not start with a slash 1`] = `"path must start with a /"`;
7 changes: 7 additions & 0 deletions x-pack/plugins/spaces/common/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,10 @@
*/

export const DEFAULT_SPACE_ID = `default`;

export const SELECTED_SPACE_COOKIE = 'selectedSpace';

/**
* Cookie expiration for the user's selected Space. (90 days)
*/
export const SELECTED_SPACE_COOKIE_TTL_MILLIS = 1000 * 60 * 60 * 24 * 90;
17 changes: 17 additions & 0 deletions x-pack/plugins/spaces/common/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

export {
addSpaceUrlContext,
stripSpaceUrlContext,
getSpaceUrlContext,
} from './spaces_url_parser';

export {
DEFAULT_SPACE_ID,
SELECTED_SPACE_COOKIE,
SELECTED_SPACE_COOKIE_TTL_MILLIS,
} from './constants';
13 changes: 12 additions & 1 deletion x-pack/plugins/spaces/common/spaces_url_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/

export function getSpaceUrlContext(basePath = '/', defaultContext = null) {
export function getSpaceUrlContext(basePath = '/', defaultContext = '') {
// Look for `/s/space-url-context` in the base path
const matchResult = basePath.match(/\/s\/([a-z0-9\-]+)/);

Expand Down Expand Up @@ -42,3 +42,14 @@ export function stripSpaceUrlContext(basePath = '/') {

return basePathWithoutSpace;
}

export function addSpaceUrlContext(basePath = '/', urlContext = '', requestedPath = '') {
if (requestedPath && !requestedPath.startsWith('/')) {
throw new Error(`path must start with a /`);
}

if (urlContext) {
return `${basePath}/s/${urlContext}${requestedPath}`;
}
return `${basePath}${requestedPath}`;
}
72 changes: 48 additions & 24 deletions x-pack/plugins/spaces/common/spaces_url_parser.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,61 @@
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/
import { stripSpaceUrlContext, getSpaceUrlContext } from './spaces_url_parser';
import { stripSpaceUrlContext, getSpaceUrlContext, addSpaceUrlContext } from './spaces_url_parser';

test('it removes the space url context from the base path when the space is not at the root', () => {
const basePath = `/foo/s/my-space`;
expect(stripSpaceUrlContext(basePath)).toEqual('/foo');
});
describe('stripSpaceUrlContext', () => {
test('it removes the space url context from the base path when the space is not at the root', () => {
const basePath = `/foo/s/my-space`;
expect(stripSpaceUrlContext(basePath)).toEqual('/foo');
});

test('it removes the space url context from the base path when the space is the root', () => {
const basePath = `/s/my-space`;
expect(stripSpaceUrlContext(basePath)).toEqual('');
});
test('it removes the space url context from the base path when the space is the root', () => {
const basePath = `/s/my-space`;
expect(stripSpaceUrlContext(basePath)).toEqual('');
});

test(`it doesn't change base paths without a space url context`, () => {
const basePath = `/this/is/a-base-path/ok`;
expect(stripSpaceUrlContext(basePath)).toEqual(basePath);
});
test(`it doesn't change base paths without a space url context`, () => {
const basePath = `/this/is/a-base-path/ok`;
expect(stripSpaceUrlContext(basePath)).toEqual(basePath);
});

test('it accepts no parameters', () => {
expect(stripSpaceUrlContext()).toEqual('');
});
test('it accepts no parameters', () => {
expect(stripSpaceUrlContext()).toEqual('');
});

test('it remove the trailing slash', () => {
expect(stripSpaceUrlContext('/')).toEqual('');
test('it remove the trailing slash', () => {
expect(stripSpaceUrlContext('/')).toEqual('');
});
});

test('it identifies the space url context', () => {
const basePath = `/this/is/a/crazy/path/s/my-awesome-space-lives-here`;
expect(getSpaceUrlContext(basePath)).toEqual('my-awesome-space-lives-here');
describe('getSpaceUrlContext', () => {
test('it identifies the space url context', () => {
const basePath = `/this/is/a/crazy/path/s/my-awesome-space-lives-here`;
expect(getSpaceUrlContext(basePath)).toEqual('my-awesome-space-lives-here');
});

test('it handles base url without a space url context', () => {
const basePath = `/this/is/a/crazy/path/s`;
expect(getSpaceUrlContext(basePath)).toEqual('');
});
});

test('it handles base url without a space url context', () => {
const basePath = `/this/is/a/crazy/path/s`;
expect(getSpaceUrlContext(basePath)).toEqual(null);
describe('addSpaceUrlContext', () => {
test('handles no parameters', () => {
expect(addSpaceUrlContext()).toEqual(`/`);
});

test('it adds to the basePath correctly', () => {
expect(addSpaceUrlContext('/my/base/path', 'url-context')).toEqual('/my/base/path/s/url-context');
});

test('it appends the requested path to the end of the url context', () => {
expect(addSpaceUrlContext('/base', 'context', '/final/destination')).toEqual('/base/s/context/final/destination');
});

test('it throws an error when the requested path does not start with a slash', () => {
expect(() => {
addSpaceUrlContext('', '', 'foo');
}).toThrowErrorMatchingSnapshot();
});
});
13 changes: 12 additions & 1 deletion x-pack/plugins/spaces/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { mirrorPluginStatus } from '../../server/lib/mirror_plugin_status';
import { getActiveSpace } from './server/lib/get_active_space';
import { wrapError } from './server/lib/errors';
import mappings from './mappings.json';
import { initSelectedSpaceState } from './server/lib/selected_space_state';

export const spaces = (kibana) => new kibana.Plugin({
id: 'spaces',
Expand All @@ -24,6 +25,7 @@ export const spaces = (kibana) => new kibana.Plugin({
config(Joi) {
return Joi.object({
enabled: Joi.boolean().default(true),
rememberSelectedSpace: Joi.boolean().default(true),
}).default();
},

Expand All @@ -47,12 +49,19 @@ export const spaces = (kibana) => new kibana.Plugin({
};
},
replaceInjectedVars: async function (vars, request) {
// A rather obtuse way of preventing the Kibana login/logout resources from trying to make these requests.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm open to suggestions here -- replaceInjectedVars is called when loading the login/logout pages, which throws visible security exceptions, because the user is not yet (or no longer) authenticated to ES.

We should only need to do the variable replacement when doing a full page load within Kibana, which I believe is constrained to loading entire apps, via the /app/* pattern

// This seems safer than excluding a couple of hard-coded paths.
const canReplace = request.path.startsWith('/app/');
if (!canReplace) {
return vars;
}

try {
vars.activeSpace = {
valid: true,
space: await getActiveSpace(request.getSavedObjectsClient(), request.getBasePath())
};
} catch(e) {
} catch (e) {
vars.activeSpace = {
valid: false,
error: wrapError(e).output.payload
Expand All @@ -76,6 +85,8 @@ export const spaces = (kibana) => new kibana.Plugin({

initSpacesApi(server);

initSelectedSpaceState(server, config);

initSpacesRequestInterceptors(server);

await createDefaultSpace(server);
Expand Down
10 changes: 10 additions & 0 deletions x-pack/plugins/spaces/public/lib/spaces_manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,14 @@ export class SpacesManager {
return await this._httpAgent
.delete(`${this._baseUrl}/space/${space.id}`);
}

async changeSelectedSpace(space) {
return await this._httpAgent
.put(`${this._baseUrl}/space/${space.id}/select`)
.then(response => {
if (response.data && response.data.location) {
window.location = response.data.location;
}
});
}
}
4 changes: 2 additions & 2 deletions x-pack/plugins/spaces/public/views/components/space_cards.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import React, { Component, Fragment } from 'react';
import PropTypes from 'prop-types';
import chrome from 'ui/chrome';
import { SpaceCard } from './space_card';
import { stripSpaceUrlContext } from '../../../common/spaces_url_parser';
import { stripSpaceUrlContext, addSpaceUrlContext } from '../../../common/spaces_url_parser';
import {
EuiFlexGroup,
EuiFlexItem,
Expand Down Expand Up @@ -48,7 +48,7 @@ export class SpaceCards extends Component {
return () => {
const baseUrlWithoutSpace = stripSpaceUrlContext(chrome.getBasePath());

window.location = `${baseUrlWithoutSpace}/s/${space.urlContext}`;
window.location = addSpaceUrlContext(baseUrlWithoutSpace, space.urlContext);
};
};
}
Expand Down
Loading