diff --git a/changelog/17769.txt b/changelog/17769.txt new file mode 100644 index 0000000000000..12fe2d4d114f3 --- /dev/null +++ b/changelog/17769.txt @@ -0,0 +1,3 @@ +```release-note:bug +ui: Fixes issue with not being able to download raft snapshot via service worker +``` \ No newline at end of file diff --git a/ui/app/components/raft-storage-overview.js b/ui/app/components/raft-storage-overview.js index 794f99b1a259e..b77028e679dfc 100644 --- a/ui/app/components/raft-storage-overview.js +++ b/ui/app/components/raft-storage-overview.js @@ -5,6 +5,8 @@ import { inject as service } from '@ember/service'; export default Component.extend({ flashMessages: service(), + auth: service(), + useServiceWorker: null, async init() { @@ -16,12 +18,32 @@ export default Component.extend({ if ('serviceWorker' in navigator) { // this checks to see if there's an active service worker - if it failed to register // for any reason, then this would be null - let worker = await navigator.serviceWorker.getRegistration(config.serviceWorkerScope); + const worker = await navigator.serviceWorker.getRegistration(config.serviceWorkerScope); if (worker) { + navigator.serviceWorker.addEventListener('message', this.serviceWorkerGetToken.bind(this)); + this.set('useServiceWorker', true); } } }, + willDestroy() { + if (this.useServiceWorker) { + navigator.serviceWorker.removeEventListener('message', this.serviceWorkerGetToken); + } + this._super(...arguments); + }, + + serviceWorkerGetToken(event) { + const { action } = event.data; + const [port] = event.ports; + + if (action === 'getToken') { + port.postMessage({ token: this.auth.currentToken }); + } else { + console.error('Unknown event', event); // eslint-disable-line + port.postMessage({ error: 'Unknown request' }); + } + }, actions: { async removePeer(model) { diff --git a/ui/lib/service-worker-authenticated-download/service-worker-registration/index.js b/ui/lib/service-worker-authenticated-download/service-worker-registration/index.js index 525317e8122a9..6236505e09a73 100644 --- a/ui/lib/service-worker-authenticated-download/service-worker-registration/index.js +++ b/ui/lib/service-worker-authenticated-download/service-worker-registration/index.js @@ -1,32 +1,6 @@ import { addSuccessHandler } from 'ember-service-worker/service-worker-registration'; -import Namespace from '@ember/application/namespace'; - -function getToken() { - // fix this later by allowing registration somewhere in the app lifecycle were we can have access to - // services, etc. - return Namespace.NAMESPACES_BY_ID['vault'].__container__.lookup('service:auth').currentToken; -} addSuccessHandler(function (registration) { - // attach the handler for the message event so we can send over the auth token - navigator.serviceWorker.addEventListener('message', (event) => { - let { action } = event.data; - let port = event.ports[0]; - - if (action === 'getToken') { - let token = getToken(); - if (!token) { - console.error('Unable to retrieve Vault tokent'); // eslint-disable-line - } - port.postMessage({ token: token }); - } else { - console.error('Unknown event', event); // eslint-disable-line - port.postMessage({ - error: 'Unknown request', - }); - } - }); - // attempt to unregister the service worker on unload because we're not doing any sort of caching window.addEventListener('unload', function () { registration.unregister(); diff --git a/ui/tests/integration/components/raft-storage-overview-test.js b/ui/tests/integration/components/raft-storage-overview-test.js index dde28f67eb6eb..54b289439aaec 100644 --- a/ui/tests/integration/components/raft-storage-overview-test.js +++ b/ui/tests/integration/components/raft-storage-overview-test.js @@ -2,17 +2,56 @@ import { module, test } from 'qunit'; import { setupRenderingTest } from 'ember-qunit'; import { render } from '@ember/test-helpers'; import hbs from 'htmlbars-inline-precompile'; +import sinon from 'sinon'; module('Integration | Component | raft-storage-overview', function (hooks) { setupRenderingTest(hooks); - test('it renders', async function (assert) { - let model = [ + hooks.beforeEach(function () { + this.model = [ { address: '127.0.0.1:8200', voter: true }, { address: '127.0.0.1:8200', voter: true, leader: true }, ]; - this.set('model', model); + }); + + test('it renders', async function (assert) { await render(hbs``); assert.dom('[data-raft-row]').exists({ count: 2 }); }); + + test('it should download snapshot via service worker', async function (assert) { + assert.expect(3); + + const token = this.owner.lookup('service:auth').currentToken; + const generateMockEvent = (action) => ({ + data: { action }, + ports: [ + { + postMessage(message) { + const getToken = action === 'getToken'; + const expected = getToken ? { token } : { error: 'Unknown request' }; + assert.deepEqual( + message, + expected, + `${ + getToken ? 'Token' : 'Error' + } is returned to service worker in message event listener callback` + ); + }, + }, + ], + }); + + sinon.stub(navigator.serviceWorker, 'getRegistration').resolves(true); + sinon.stub(navigator.serviceWorker, 'addEventListener').callsFake((name, cb) => { + assert.strictEqual(name, 'message', 'Event listener added for service worker message'); + cb(generateMockEvent('getToken')); + cb(generateMockEvent('unknown')); + }); + + await render(hbs``); + // avoid clicking the download button or the url will change + // the service worker invokes the event listener callback when it intercepts the request to /v1/sys/storage/raft/snapshot + // for the test we manually fire the callback as soon as it is passed to the addEventListener stub + }); });