mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
Remove broadcast-channel dependency from security plugin (#132427)
* Remove broadcast-channel dependency from security plugin * cleanup * Update x-pack/plugins/security/public/session/session_timeout.ts Co-authored-by: Joe Portner <5295965+jportner@users.noreply.github.com> Co-authored-by: Joe Portner <5295965+jportner@users.noreply.github.com>
This commit is contained in:
parent
ccb25d048c
commit
0dfa6374ba
8 changed files with 118 additions and 75 deletions
|
@ -229,7 +229,6 @@
|
|||
"base64-js": "^1.3.1",
|
||||
"bitmap-sdf": "^1.0.3",
|
||||
"brace": "0.11.1",
|
||||
"broadcast-channel": "4.10.0",
|
||||
"canvg": "^3.0.9",
|
||||
"chalk": "^4.1.0",
|
||||
"cheerio": "^1.0.0-rc.10",
|
||||
|
|
|
@ -18,6 +18,8 @@ export * from './redux_helpers';
|
|||
|
||||
export * from './router_helpers';
|
||||
|
||||
export * from './stub_broadcast_channel';
|
||||
|
||||
export * from './stub_browser_storage';
|
||||
|
||||
export * from './stub_web_worker';
|
||||
|
|
83
packages/kbn-test-jest-helpers/src/stub_broadcast_channel.ts
Normal file
83
packages/kbn-test-jest-helpers/src/stub_broadcast_channel.ts
Normal file
|
@ -0,0 +1,83 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
const channelCache: BroadcastChannel[] = [];
|
||||
|
||||
class StubBroadcastChannel implements BroadcastChannel {
|
||||
constructor(public readonly name: string) {
|
||||
channelCache.push(this);
|
||||
}
|
||||
|
||||
onmessage = jest.fn();
|
||||
onmessageerror = jest.fn();
|
||||
close = jest.fn();
|
||||
postMessage = jest.fn().mockImplementation((data: any) => {
|
||||
channelCache.forEach((channel) => {
|
||||
if (channel === this) return; // don't postMessage to ourselves
|
||||
if (channel.onmessage) {
|
||||
channel.onmessage(new MessageEvent(this.name, { data }));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
addEventListener<K extends keyof BroadcastChannelEventMap>(
|
||||
type: K,
|
||||
listener: (this: BroadcastChannel, ev: BroadcastChannelEventMap[K]) => any,
|
||||
options?: boolean | AddEventListenerOptions
|
||||
): void;
|
||||
addEventListener(
|
||||
type: string,
|
||||
listener: EventListenerOrEventListenerObject,
|
||||
options?: boolean | AddEventListenerOptions
|
||||
): void;
|
||||
addEventListener(type: any, listener: any, options?: any): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
removeEventListener<K extends keyof BroadcastChannelEventMap>(
|
||||
type: K,
|
||||
listener: (this: BroadcastChannel, ev: BroadcastChannelEventMap[K]) => any,
|
||||
options?: boolean | EventListenerOptions
|
||||
): void;
|
||||
removeEventListener(
|
||||
type: string,
|
||||
listener: EventListenerOrEventListenerObject,
|
||||
options?: boolean | EventListenerOptions
|
||||
): void;
|
||||
removeEventListener(type: any, listener: any, options?: any): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
dispatchEvent(event: Event): boolean {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all BroadcastChannel instances.
|
||||
* @returns BroadcastChannel[]
|
||||
*/
|
||||
function getBroadcastChannelInstances() {
|
||||
return [...channelCache];
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all BroadcastChannel instances.
|
||||
*/
|
||||
function clearBroadcastChannelInstances() {
|
||||
channelCache.splice(0, channelCache.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stubs the global window.BroadcastChannel for use in jest tests.
|
||||
*/
|
||||
function stubBroadcastChannel() {
|
||||
if (!window.BroadcastChannel) {
|
||||
window.BroadcastChannel = StubBroadcastChannel;
|
||||
}
|
||||
}
|
||||
|
||||
export { stubBroadcastChannel, getBroadcastChannelInstances, clearBroadcastChannelInstances };
|
|
@ -114,7 +114,6 @@
|
|||
{
|
||||
"groupName": "platform security modules",
|
||||
"matchPackageNames": [
|
||||
"broadcast-channel",
|
||||
"node-forge",
|
||||
"@types/node-forge",
|
||||
"require-in-the-middle",
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { enforceOptions } from 'broadcast-channel';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import type { CoreSetup } from '@kbn/core/public';
|
||||
|
@ -14,19 +13,15 @@ import type { DataViewsPublicPluginStart } from '@kbn/data-views-plugin/public';
|
|||
import type { FeaturesPluginStart } from '@kbn/features-plugin/public';
|
||||
import { licensingMock } from '@kbn/licensing-plugin/public/mocks';
|
||||
import { managementPluginMock } from '@kbn/management-plugin/public/mocks';
|
||||
import { stubBroadcastChannel } from '@kbn/test-jest-helpers';
|
||||
|
||||
import { ManagementService } from './management';
|
||||
import type { PluginStartDependencies } from './plugin';
|
||||
import { SecurityPlugin } from './plugin';
|
||||
|
||||
describe('Security Plugin', () => {
|
||||
beforeAll(() => {
|
||||
enforceOptions({ type: 'simulate' });
|
||||
});
|
||||
afterAll(() => {
|
||||
enforceOptions(null);
|
||||
});
|
||||
stubBroadcastChannel();
|
||||
|
||||
describe('Security Plugin', () => {
|
||||
describe('#setup', () => {
|
||||
it('should be able to setup if optional plugins are not available', () => {
|
||||
const plugin = new SecurityPlugin(coreMock.createPluginInitializerContext());
|
||||
|
|
|
@ -5,10 +5,14 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { BroadcastChannel } from 'broadcast-channel';
|
||||
|
||||
import type { ToastInputFields } from '@kbn/core/public';
|
||||
import { coreMock } from '@kbn/core/public/mocks';
|
||||
import {
|
||||
clearBroadcastChannelInstances,
|
||||
getBroadcastChannelInstances,
|
||||
stubBroadcastChannel,
|
||||
} from '@kbn/test-jest-helpers';
|
||||
stubBroadcastChannel();
|
||||
|
||||
import {
|
||||
SESSION_CHECK_MS,
|
||||
|
@ -19,11 +23,8 @@ import {
|
|||
} from '../../common/constants';
|
||||
import type { SessionInfo } from '../../common/types';
|
||||
import { createSessionExpiredMock } from './session_expired.mock';
|
||||
import type { SessionState } from './session_timeout';
|
||||
import { SessionTimeout, startTimer } from './session_timeout';
|
||||
|
||||
jest.mock('broadcast-channel');
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
jest.spyOn(window, 'addEventListener');
|
||||
|
@ -56,6 +57,7 @@ describe('SessionTimeout', () => {
|
|||
afterEach(async () => {
|
||||
jest.clearAllMocks();
|
||||
jest.clearAllTimers();
|
||||
clearBroadcastChannelInstances();
|
||||
});
|
||||
|
||||
test(`does not initialize when starting an anonymous path`, async () => {
|
||||
|
@ -242,14 +244,17 @@ describe('SessionTimeout', () => {
|
|||
|
||||
jest.advanceTimersByTime(30 * 1000);
|
||||
|
||||
const [broadcastChannelMock] = jest.requireMock('broadcast-channel').BroadcastChannel.mock
|
||||
.instances as [BroadcastChannel<SessionState>];
|
||||
const [broadcastChannelMock] = getBroadcastChannelInstances();
|
||||
|
||||
broadcastChannelMock.onmessage!({
|
||||
lastExtensionTime: Date.now(),
|
||||
expiresInMs: 60 * 1000,
|
||||
canBeExtended: true,
|
||||
});
|
||||
broadcastChannelMock.onmessage!(
|
||||
new MessageEvent('name', {
|
||||
data: {
|
||||
lastExtensionTime: Date.now(),
|
||||
expiresInMs: 60 * 1000,
|
||||
canBeExtended: true,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
jest.advanceTimersByTime(30 * 1000);
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { BroadcastChannel as BroadcastChannelType } from 'broadcast-channel';
|
||||
import type { Subscription } from 'rxjs';
|
||||
import { BehaviorSubject } from 'rxjs';
|
||||
import { skip, tap, throttleTime } from 'rxjs/operators';
|
||||
|
@ -34,7 +33,7 @@ export interface SessionState extends Pick<SessionInfo, 'expiresInMs' | 'canBeEx
|
|||
}
|
||||
|
||||
export class SessionTimeout {
|
||||
private channel?: BroadcastChannelType<SessionState>;
|
||||
private channel?: BroadcastChannel;
|
||||
|
||||
private isVisible = document.visibilityState !== 'hidden';
|
||||
private isFetchingSessionInfo = false;
|
||||
|
@ -77,11 +76,8 @@ export class SessionTimeout {
|
|||
// Subscribe to a broadcast channel for session timeout messages.
|
||||
// This allows us to synchronize the UX across tabs and avoid repetitive API calls.
|
||||
try {
|
||||
const { BroadcastChannel } = await import('broadcast-channel');
|
||||
this.channel = new BroadcastChannel(`${this.tenant}/session_timeout`, {
|
||||
webWorkerSupport: false,
|
||||
});
|
||||
this.channel.onmessage = this.handleChannelMessage;
|
||||
this.channel = new BroadcastChannel(`${this.tenant}/session_timeout`);
|
||||
this.channel.onmessage = (event) => this.handleChannelMessage(event);
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.warn(
|
||||
|
@ -108,8 +104,14 @@ export class SessionTimeout {
|
|||
/**
|
||||
* Event handler that receives session information from other browser tabs.
|
||||
*/
|
||||
private handleChannelMessage = (message: SessionState) => {
|
||||
this.sessionState$.next(message);
|
||||
private handleChannelMessage = (messageEvent: MessageEvent<any>) => {
|
||||
if (this.isSessionState(messageEvent.data)) {
|
||||
this.sessionState$.next(messageEvent.data);
|
||||
}
|
||||
};
|
||||
|
||||
private isSessionState = (data: unknown): data is SessionState => {
|
||||
return typeof data === 'object' && Object.hasOwn(data ?? {}, 'canBeExtended');
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
46
yarn.lock
46
yarn.lock
|
@ -9428,20 +9428,6 @@ brfs@^2.0.0, brfs@^2.0.2:
|
|||
static-module "^3.0.2"
|
||||
through2 "^2.0.0"
|
||||
|
||||
broadcast-channel@4.10.0:
|
||||
version "4.10.0"
|
||||
resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-4.10.0.tgz#d19fb902df227df40b1b580351713d30c302d198"
|
||||
integrity sha512-hOUh312XyHk6JTVyX9cyXaH1UYs+2gHVtnW16oQAu9FL7ALcXGXc/YoJWqlkV8vUn14URQPMmRi4A9q4UrwVEQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.16.0"
|
||||
detect-node "^2.1.0"
|
||||
microseconds "0.2.0"
|
||||
nano-time "1.0.0"
|
||||
oblivious-set "1.0.0"
|
||||
p-queue "6.6.2"
|
||||
rimraf "3.0.2"
|
||||
unload "2.3.1"
|
||||
|
||||
broadcast-channel@^3.4.1:
|
||||
version "3.4.1"
|
||||
resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-3.4.1.tgz#65b63068d0a5216026a19905c9b2d5e9adf0928a"
|
||||
|
@ -12520,7 +12506,7 @@ detect-node-es@^1.1.0:
|
|||
resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493"
|
||||
integrity sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==
|
||||
|
||||
detect-node@2.1.0, detect-node@^2.0.4, detect-node@^2.1.0:
|
||||
detect-node@^2.0.4:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1"
|
||||
integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==
|
||||
|
@ -13921,7 +13907,7 @@ eventemitter2@^6.4.3:
|
|||
resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-6.4.3.tgz#35c563619b13f3681e7eb05cbdaf50f56ba58820"
|
||||
integrity sha512-t0A2msp6BzOf+QAcI6z9XMktLj52OjGQg+8SJH6v5+3uxNpWYRR3wQmfA+6xtMU9kOC59qk9licus5dYcrYkMQ==
|
||||
|
||||
eventemitter3@^4.0.0, eventemitter3@^4.0.4:
|
||||
eventemitter3@^4.0.0:
|
||||
version "4.0.7"
|
||||
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
|
||||
integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
|
||||
|
@ -21304,11 +21290,6 @@ objectorarray@^1.0.4:
|
|||
resolved "https://registry.yarnpkg.com/objectorarray/-/objectorarray-1.0.4.tgz#d69b2f0ff7dc2701903d308bb85882f4ddb49483"
|
||||
integrity sha512-91k8bjcldstRz1bG6zJo8lWD7c6QXcB4nTDUqiEvIL1xAsLoZlOOZZG+nd6YPz+V7zY1580J4Xxh1vZtyv4i/w==
|
||||
|
||||
oblivious-set@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/oblivious-set/-/oblivious-set-1.0.0.tgz#c8316f2c2fb6ff7b11b6158db3234c49f733c566"
|
||||
integrity sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==
|
||||
|
||||
oboe@^2.1.4:
|
||||
version "2.1.4"
|
||||
resolved "https://registry.yarnpkg.com/oboe/-/oboe-2.1.4.tgz#20c88cdb0c15371bb04119257d4fdd34b0aa49f6"
|
||||
|
@ -21654,14 +21635,6 @@ p-map@^4.0.0:
|
|||
dependencies:
|
||||
aggregate-error "^3.0.0"
|
||||
|
||||
p-queue@6.6.2:
|
||||
version "6.6.2"
|
||||
resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-6.6.2.tgz#2068a9dcf8e67dd0ec3e7a2bcb76810faa85e426"
|
||||
integrity sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==
|
||||
dependencies:
|
||||
eventemitter3 "^4.0.4"
|
||||
p-timeout "^3.2.0"
|
||||
|
||||
p-retry@^3.0.1:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-3.0.1.tgz#316b4c8893e2c8dc1cfa891f406c4b422bebf328"
|
||||
|
@ -21684,13 +21657,6 @@ p-timeout@^2.0.1:
|
|||
dependencies:
|
||||
p-finally "^1.0.0"
|
||||
|
||||
p-timeout@^3.2.0:
|
||||
version "3.2.0"
|
||||
resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe"
|
||||
integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==
|
||||
dependencies:
|
||||
p-finally "^1.0.0"
|
||||
|
||||
p-try@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
|
||||
|
@ -28557,14 +28523,6 @@ unload@2.2.0:
|
|||
"@babel/runtime" "^7.6.2"
|
||||
detect-node "^2.0.4"
|
||||
|
||||
unload@2.3.1:
|
||||
version "2.3.1"
|
||||
resolved "https://registry.yarnpkg.com/unload/-/unload-2.3.1.tgz#9d16862d372a5ce5cb630ad1309c2fd6e35dacfe"
|
||||
integrity sha512-MUZEiDqvAN9AIDRbbBnVYVvfcR6DrjCqeU2YQMmliFZl9uaBUjTkhuDQkBiyAy8ad5bx1TXVbqZ3gg7namsWjA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.6.2"
|
||||
detect-node "2.1.0"
|
||||
|
||||
unpipe@1.0.0, unpipe@~1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue