@openziti/ziti-browzer-sw
Version:
Service Worker used as part of the OpenZiti browZer stack
653 lines (643 loc) • 21.6 kB
JavaScript
/**
* Copyright 2018 Google Inc. All Rights Reserved.
* Licensed 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.
*/
// If the loader is already loaded, just stop.
if (!self.define) {
let registry = {};
// Used for `eval` and `importScripts` where we can't get script URL by other means.
// In both cases, it's safe to use a global var because those functions are synchronous.
let nextDefineUri;
const singleRequire = (uri, parentUri) => {
uri = new URL(uri + ".js", parentUri).href;
return registry[uri] || (
new Promise(resolve => {
if ("document" in self) {
const script = document.createElement("script");
script.src = uri;
script.onload = resolve;
document.head.appendChild(script);
} else {
nextDefineUri = uri;
importScripts(uri);
resolve();
}
})
.then(() => {
let promise = registry[uri];
if (!promise) {
throw new Error(`Module ${uri} didn’t register its module`);
}
return promise;
})
);
};
self.define = (depsNames, factory) => {
const uri = nextDefineUri || ("document" in self ? document.currentScript.src : "") || location.href;
if (registry[uri]) {
// Module is already loading or loaded.
return;
}
let exports = {};
const require = depUri => singleRequire(depUri, uri);
const specialDeps = {
module: { uri },
exports,
require
};
registry[uri] = Promise.all(depsNames.map(
depName => specialDeps[depName] || require(depName)
)).then(deps => {
factory(...deps);
return exports;
});
};
}
define(['./ziti-browzer-sw-workbox-core-56411b90', './ziti-browzer-sw-misc-7bbd97fe', './ziti-browzer-sw-workbox-expiration-42b24cd3', './ziti-browzer-sw--workbox-routing--96725e09', './ziti-browzer-sw--ziti-browzer-sw-workbox-strategies--e89a4927', './ziti-browzer-sw--ziti-browzer-core--427625e5', './ziti-browzer-sw-uuid-48496ec7', './ziti-browzer-sw-workbox-strategies-80d7d1b3', './ziti-browzer-sw--lodash-es--5f72a803'], (function (zitiBrowzerSwWorkboxCore, zitiBrowzerSwMisc, zitiBrowzerSwWorkboxExpiration, zitiBrowzerSw_WorkboxRouting_, zitiBrowzerSw_ZitiBrowzerSwWorkboxStrategies_, zitiBrowzerSw_ZitiBrowzerCore_, zitiBrowzerSwUuid, zitiBrowzerSwWorkboxStrategies, zitiBrowzerSw_LodashEs_) { 'use strict';
var name = "@openziti/ziti-browzer-sw";
var version = "0.84.0";
var files = [
"dist"
];
var main = "dist/ziti-browzer-sw.js";
var description = "Service Worker used as part of the OpenZiti browZer stack";
var engines = {
node: ">= 10.0.0"
};
var devDependencies = {
"@rollup/plugin-commonjs": "^22.0.0",
"@rollup/plugin-json": "^4.1.0",
"@rollup/plugin-node-resolve": "^13.2.1",
"@rollup/plugin-replace": "^2.3.4",
"@rollup/plugin-typescript": "^8.3.1",
"@surma/rollup-plugin-off-main-thread": "^2.2.3",
"@types/uuid": "^8.3.4",
fsbin: "^1.0.11",
"npm-run-all": "^4.1.5",
rimraf: "^3.0.2",
rollup: "^2.71.1",
"rollup-plugin-terser": "^7.0.2",
tslib: "^2.3.1",
typescript: "^5.2.2",
"urlpattern-polyfill": "^0.1.6"
};
var scripts = {
prebuild: "node scripts/prebuild.mjs",
build: "run-s clean bundle-sw",
"bundle-sw": "rollup -c",
clean: "rimraf dist",
preinstall: "node -e \"if(process.env.npm_execpath.indexOf('yarn') === -1) throw new Error('You must use Yarn to install, not NPM')\""
};
var dependencies = {
"@openziti/ziti-browzer-sw-workbox-strategies": "^0.89.0",
"@types/lodash-es": "^4.17.6",
"workbox-core": "^6.6.0",
"workbox-expiration": "^6.6.0",
"workbox-precaching": "^6.6.0",
"workbox-routing": "^6.6.0",
"workbox-strategies": "^6.6.0"
};
var keywords = [
"ziti",
"zero trust",
"zero-trust",
"browZer",
"browser",
"js",
"javascript",
"workbox"
];
var repository = {
type: "git",
url: "https://github.com/openziti/ziti-browzer-sw.git"
};
var author = {
name: "NetFoundry",
url: "http://netfoundry.io",
email: "openziti@netfoundry.io"
};
var license = "Apache-2.0";
var bugs = {
url: "https://github.com/openziti/ziti-browzer-sw/issues"
};
var homepage = "https://github.com/openziti/ziti-browzer-sw";
var packageManager = "yarn@4.0.2+sha512.4e502bea682e7d8004561f916f1da2dfbe6f718024f6aa50bf8cd86f38ea3a94a7f1bf854a9ca666dd8eafcfb8d44baaa91bf5c7876e79a7aeac952c332f0e88";
var pjson = {
name: name,
version: version,
files: files,
main: main,
description: description,
engines: engines,
devDependencies: devDependencies,
scripts: scripts,
dependencies: dependencies,
keywords: keywords,
repository: repository,
author: author,
license: license,
bugs: bugs,
homepage: homepage,
packageManager: packageManager
};
/**
*
*/
self._uuid = zitiBrowzerSwUuid.v4();
self._core = new zitiBrowzerSw_ZitiBrowzerCore_.ZitiBrowzerCore({});
let erudaSpecification = new URLSearchParams(location.search).get("eruda");
self._eruda = false;
if (erudaSpecification && (erudaSpecification === 'true')) {
self._eruda = true;
}
self._logger = self._core.createZitiLogger({
logLevel: new URLSearchParams(location.search).get("logLevel") || 'Silent',
suffix: 'ZBSW',
useSWPostMessage: self._eruda,
zitiBrowzerServiceWorkerGlobalScope: self,
});
self._cookieObject = {};
self._logger.trace(`main sw starting for UUID: `, self._uuid);
let zfs = new zitiBrowzerSw_ZitiBrowzerSwWorkboxStrategies_.ZitiFirstStrategy({
uuid: self._uuid,
zitiBrowzerServiceWorkerGlobalScope: self,
logLevel: new URLSearchParams(location.search).get("logLevel") || 'Silent',
controllerApi: new URLSearchParams(location.search).get("controllerApi") || undefined,
eruda: self._eruda,
cacheName: 'ziti-browzer-cache',
plugins: [
new zitiBrowzerSwWorkboxExpiration.ExpirationPlugin({
// Cap the number of items we cache
maxEntries: 1000,
// Don't keep any items for more than 7 days
maxAgeSeconds: 7 * 24 * 60 * 60,
// Automatically cleanup if cache quota is exceeded
purgeOnQuotaError: false
}),
{
fetchDidFail: async ({ originalRequest, request, error, event, state }) => {
// No return expected.
// Note: `originalRequest` is the browser's request, `request` is the
// request after being passed through plugins with
// `requestWillFetch` callbacks, and `error` is the exception that caused
// the underlying `fetch()` to fail.
},
},
],
});
const matchGETCb = (url, request) => {
let getURL = new URL(url);
if (getURL.pathname.includes(".well-known/openid-configuration")) {
return false;
}
if (getURL.pathname.includes("ziti-browzer-latest-release-version")) {
return false;
}
if (getURL.pathname.includes("browzer_error")) {
return false;
}
if (typeof self._zitiConfig === 'undefined') {
return true;
}
if (getURL.searchParams.get("code") && getURL.searchParams.get("state")) { // possible IdP-related URL
if (getURL.hostname === self._zitiConfig.browzer.bootstrapper.self.host) { // ..but if hitting the protected web app itself
return true; // ..then let it go over Ziti
}
else {
return false; // ..otherwise, route over raw internet since it's IdP-related
}
}
let controllerURL = new URL(self._zitiConfig.controller.api);
if ((url.hostname === controllerURL.hostname) && (url.port === controllerURL.port)) {
return false;
}
else {
return true;
}
};
zitiBrowzerSw_WorkboxRouting_.registerRoute(({ url, request }) => matchGETCb(url), zfs, 'GET');
zitiBrowzerSw_WorkboxRouting_.registerRoute(({ url, request }) => matchGETCb(url), zfs, 'HEAD');
const filter = (url) => {
if (typeof self._zitiConfig === 'undefined') {
return false;
}
let filterURL = new URL(url);
let controllerURL = new URL(self._zitiConfig.controller.api);
if ((filterURL.hostname === controllerURL.hostname) && (filterURL.port === controllerURL.port)) {
return false;
}
let idpURL = new URL(self._zitiConfig.idp.host);
if ((filterURL.hostname === idpURL.hostname)) {
return false;
}
if (filterURL.pathname.includes("controller-oidc-proxy")) {
return false;
}
return true;
};
const matchPOSTCb = (url, request) => {
return filter(url);
};
zitiBrowzerSw_WorkboxRouting_.registerRoute(({ url, request }) => matchPOSTCb(url), zfs, 'POST');
const matchPUTCb = (url, request) => {
return filter(url);
};
zitiBrowzerSw_WorkboxRouting_.registerRoute(({ url, request }) => matchPUTCb(url), zfs, 'PUT');
const matchPATCHCb = (url, request) => {
return filter(url);
};
zitiBrowzerSw_WorkboxRouting_.registerRoute(({ url, request }) => matchPATCHCb(url), zfs, 'PATCH');
const matchDELETECb = (url, request) => {
return filter(url);
};
zitiBrowzerSw_WorkboxRouting_.registerRoute(({ url, request }) => matchDELETECb(url), zfs, 'DELETE');
zitiBrowzerSwWorkboxCore.clientsClaim();
self.addEventListener('install', (event) => {
self._logger.trace(`'install' received`);
self.skipWaiting();
});
/**
*
*/
self.addEventListener('message', async (event) => {
/**
*
*/
if (event.data.type === 'GET_VERSION') {
self.skipWaiting();
self._logger.trace(`message.GET_VERSION received`);
event.ports[0].postMessage({
version: pjson.version,
zitiConfig: self._zitiConfig
});
}
/**
*
*/
else if (event.data.type === 'GET_CURRENT_API_SESSION') {
self.skipWaiting();
self._logger.trace(`message.GET_CURRENT_API_SESSION received`);
event.ports[0].postMessage(self._currentAPISession);
}
/**
*
*/
else if (event.data.type === 'SET_CONFIG') {
self.skipWaiting();
self._logger.trace(`message.SET_CONFIG received, payload is: `, event.data.payload);
self._zitiConfig = event.data.payload.zitiConfig;
self._logger.trace(`message.SET_CONFIG set for UUID: `, self._uuid);
event.ports[0].postMessage({
version: pjson.version,
zitiConfig: self._zitiConfig
});
}
/**
*
*/
else if (event.data.type === 'SET_COOKIE') {
// self._logger.trace(`message.SET_COOKIE received, payload is: `, event.data.payload);
let name = event.data.payload.name;
let value = event.data.payload.value;
if (typeof self._cookieObject !== 'undefined') {
self._cookieObject[name] = value;
// self._logger.trace(`_cookieObject: `, self._cookieObject);
}
}
/**
*
*/
else if (event.data.type === 'ZBR_INIT_COMPLETE') {
self._logger.trace(`message.ZBR_INIT_COMPLETE received, payload is: `, event.data.payload);
self._zbrReloadPending = false;
self._zitiConfig = event.data.payload.zitiConfig;
self._zbrPingTimestamp = Date.now();
}
/**
*
*/
else if (event.data.type === 'ZBR_PING') {
self._zbrPingTimestamp = event.data.payload.timestamp;
}
/**
*
*/
else if (event.data.type === 'UNREGISTER') {
self._logger.trace(`message.UNREGISTER received `);
self.registration.unregister();
const windows = await self.clients.matchAll({ type: 'window' });
for (const window of windows) {
window.postMessage({
type: 'RELOAD'
});
}
}
/**
*
*/
else {
self._logger.info(`message.<UNKNOWN> received [${event.data.type}]`);
}
});
/**
*
*/
self._unregister = async function () {
self._logger.trace(`_unregister starting `);
self.registration.unregister();
const windows = await self.clients.matchAll({ type: 'window' });
for (const window of windows) {
window.postMessage({
type: 'RELOAD'
});
}
self._logger.trace(`_unregister completed `);
};
/**
*
*/
self._unregisterNoReload = function () {
self._logger.trace(`_unregisterNoReload starting `);
self.registration.unregister();
self._logger.trace(`_unregisterNoReload completed `);
};
/**
*
*/
self._accessTokenExpired = async function () {
self._logger.trace(`_accessTokenExpired starting `);
const windows = await self.clients.matchAll({ type: 'window' });
for (const window of windows) {
window.postMessage({
type: 'ACCESS_TOKEN_EXPIRED'
});
}
self._logger.trace(`_accessTokenExpired completed `);
};
/**
*
*/
self._accessTokenRefreshed = async function () {
self._logger.trace(`_accessTokenRefreshed starting `);
const windows = await self.clients.matchAll({ type: 'window' });
for (const window of windows) {
window.postMessage({
type: 'ACCESS_TOKEN_REFRESHED'
});
}
self._logger.trace(`_accessTokenRefreshed completed `);
};
/**
*
*/
self._pingPage = async function () {
self._logger.trace(`_pingPage starting `);
self.registration.unregister();
const windows = await self.clients.matchAll({ type: 'window' });
return new Promise(async function (resolve, reject) {
for (const window of windows) {
var messageChannel = new MessageChannel();
messageChannel.port1.onmessage = function (event) {
self._logger.trace('_pingPage() <-- reply received');
resolve('ok');
};
window.postMessage({
type: 'PING',
}, [messageChannel.port2]);
}
self._logger.trace(`_pingPage() --> sent `);
});
};
/**
*
*/
self._noConfigForService = async function (event) {
self._logger.trace(`_noConfigForService starting `);
const windows = await self.clients.matchAll({ type: 'window' });
for (const window of windows) {
window.postMessage({
type: 'NO_CONFIG_FOR_SERVICE',
payload: {
event
}
});
}
self._logger.trace(`_noConfigForService completed `);
};
/**
*
*/
self._noConfigProtocolForService = async function (event) {
self._logger.trace(`_noConfigProtocolForService starting `);
const windows = await self.clients.matchAll({ type: 'window' });
for (const window of windows) {
window.postMessage({
type: 'NO_CONFIG_PROTOCOL_FOR_SERVICE',
payload: {
event
}
});
}
self._logger.trace(`_noConfigProtocolForService completed `);
};
/**
*
*/
self._wssERConnectionError = async function (event) {
self._logger.trace(`_wssERConnectionError starting `);
const windows = await self.clients.matchAll({ type: 'window' });
for (const window of windows) {
window.postMessage({
type: 'WSS_ROUTER_CONNECTION_ERROR',
payload: {
event
}
});
}
self._logger.trace(`_wssERConnectionError completed `);
};
/**
*
*/
self._controllerConnectionError = async function (event) {
self._logger.trace(`_controllerConnectionError starting `);
const windows = await self.clients.matchAll({ type: 'window' });
for (const window of windows) {
window.postMessage({
type: 'CONTROLLER_CONNECTION_ERROR',
payload: {
event
}
});
}
self._logger.trace(`_controllerConnectionError completed `);
};
/**
*
*/
self._sessionCreationError = async function (event) {
self._logger.trace(`_sessionCreationError starting `);
const windows = await self.clients.matchAll({ type: 'window' });
for (const window of windows) {
window.postMessage({
type: 'SESSION_CREATION_ERROR',
payload: {
event
}
});
}
self._logger.trace(`_sessionCreationError completed `);
};
/**
*
*/
self._noService = async function (event) {
self._logger.trace(`_noService starting `);
const windows = await self.clients.matchAll({ type: 'window' });
for (const window of windows) {
window.postMessage({
type: 'NO_SERVICE',
payload: {
event
}
});
}
self._logger.trace(`_noService completed `);
};
/**
*
*/
self._invalidAuth = async function (event) {
self._logger.trace(`_invalidAuth starting `);
const windows = await self.clients.matchAll({ type: 'window' });
for (const window of windows) {
window.postMessage({
type: 'INVALID_AUTH',
payload: {
event
}
});
}
self._logger.trace(`_invalidAuth completed `);
};
/**
*
*/
self._channelConnectFail = async function (event) {
self._logger.trace(`_channelConnectFail starting `);
const windows = await self.clients.matchAll({ type: 'window' });
for (const window of windows) {
window.postMessage({
type: 'CHANNEL_CONNECT_FAIL',
payload: {
event
}
});
}
self._logger.trace(`_channelConnectFail completed `);
};
/**
*
*/
self._noWSSRouters = async function (event) {
self._logger.trace(`_noWSSRouters starting `);
const windows = await self.clients.matchAll({ type: 'window' });
for (const window of windows) {
window.postMessage({
type: 'NO_WSS_ROUTERS',
payload: {
event
}
});
}
self._logger.trace(`_noWSSRouters completed `);
};
/**
*
*/
self._requestFailedWithNoResponse = async function (event) {
self._logger.trace(`_requestFailedWithNoResponse starting `);
const windows = await self.clients.matchAll({ type: 'window' });
for (const window of windows) {
window.postMessage({
type: 'REQUEST_FAILED_WITH_NO_RESPONSE',
payload: {
event
}
});
}
self._logger.trace(`_invalidAuth completed `);
};
/**
*
*/
self._xgressEvent = async function (event) {
const windows = await self.clients.matchAll({ type: 'window' });
for (const window of windows) {
window.postMessage({
type: 'XGRESS_EVENT',
payload: {
event
}
});
}
};
/**
*
*/
self._nestedTLSHandshakeTimeout = async function (event) {
const windows = await self.clients.matchAll({ type: 'window' });
for (const window of windows) {
window.postMessage({
type: 'NESTED_TLS_HANDSHAKE_TIMEOUT_EVENT',
payload: {
event
}
});
}
};
/**
*
*/
self._sendLogMessage = async function (event) {
const windows = await self.clients.matchAll({ type: 'window' });
for (const window of windows) {
window.postMessage({
type: 'LOG_MESSAGE_EVENT',
payload: {
event
}
});
}
};
/**
*
*/
self._sendMessageToClients = async function (message) {
const allClients = await self.clients.matchAll({ type: 'window' });
return new Promise(async function (resolve, reject) {
for (const client of allClients) {
self._logger.trace('sendMessageToClients() processing cmd: ', message.type);
var messageChannel = new MessageChannel();
messageChannel.port1.onmessage = function (event) {
self._logger.trace('ziti-sw: sendMessageToClient() reply event is: ', message.type, ' - ', event.data.response);
if (event.data.error) {
reject(event.data.error);
}
else {
resolve(event.data.response);
}
};
client.postMessage(message, [messageChannel.port2]);
}
});
};
}));