diff --git a/github b/github index 099ed8e..ca5350f 160000 --- a/github +++ b/github @@ -1 +1 @@ -Subproject commit 099ed8e240637a59be6f656ed299bbcac148b389 +Subproject commit ca5350f32137268f13811961d84f4fd96639ae67 diff --git a/modules/core/main.ts b/modules/core/main.ts index 3c1c4fc..25bc0bd 100644 --- a/modules/core/main.ts +++ b/modules/core/main.ts @@ -1,6 +1,6 @@ import * as electron from "electron"; -import {app, Menu} from "electron"; +import {app, Menu, protocol} from "electron"; import MessageBoxOptions = electron.MessageBoxOptions; import {processArguments, parseProcessArguments, Arguments} from "../shared/process-arguments"; @@ -11,6 +11,7 @@ import {initializeSingleInstance} from "./MultiInstanceHandler"; import "./AppInstance"; import {dereferenceApp, referenceApp} from "./AppInstance"; import {showUpdateWindow} from "./windows/client-updater/controller/ClientUpdate"; +import {initializeCustomUiPackProtocol} from "./ui-loader/Loader"; async function handleAppReady() { Menu.setApplicationMenu(null); @@ -173,6 +174,7 @@ function main() { } } + initializeCustomUiPackProtocol(); app.on('ready', handleAppReady); } export const execute = main; \ No newline at end of file diff --git a/modules/core/ui-loader/Loader.ts b/modules/core/ui-loader/Loader.ts index 4308fe1..708564e 100644 --- a/modules/core/ui-loader/Loader.ts +++ b/modules/core/ui-loader/Loader.ts @@ -9,21 +9,35 @@ import * as tar from "tar-stream"; import {Arguments, processArguments} from "../../shared/process-arguments"; import {parseVersion} from "../../shared/version"; -import * as electron from "electron"; -import MessageBoxOptions = Electron.MessageBoxOptions; import {clientAppInfo, currentClientVersion} from "../app-updater"; import {CachedUIPack, UIPackInfo} from "./CacheFile"; import {localUiCache, saveLocalUiCache} from "./Cache"; import {shippedClientUi} from "./Shipped"; import {downloadUiPack, queryRemoteUiPacks} from "./Remote"; import * as url from "url"; -import {showUpdateWindow} from "../windows/client-updater/controller/ClientUpdate"; +import {protocol, session} from "electron"; +import {kWindowPartitionMainApp} from "../windows/main-window/controller/MainWindow"; + +const kUiPackProtocol = "shared-ui"; export const remoteUiUrl = () => { - const default_path = is_debug ? "http://localhost/home/TeaSpeak/Web-Client/client-api/environment/" : "https://clientapi.teaspeak.de/"; - return processArguments.has_value(...Arguments.SERVER_URL) ? processArguments.value(...Arguments.SERVER_URL) : default_path; + return processArguments.has_value(...Arguments.SERVER_URL) ? processArguments.value(...Arguments.SERVER_URL) : "https://clientapi.teaspeak.de/"; }; +export function initializeCustomUiPackProtocol() { + protocol.registerSchemesAsPrivileged([{ + scheme: kUiPackProtocol, + privileges: { + allowServiceWorkers: true, + supportFetchAPI: true, + bypassCSP: false, + corsEnabled: false, + secure: true, + standard: true + } + }]); +} + let temporaryDirectoryPromise: Promise; function generateTemporaryDirectory() : Promise { if(temporaryDirectoryPromise) { @@ -53,7 +67,7 @@ async function unpackLocalUiPack(version: CachedUIPack) : Promise { throw "failed to create temporary directory"; } - const gunzip = zlib.createGunzip(); + const unzip = zlib.createUnzip(); const extract = tar.extract(); let fpipe: fs.ReadStream; @@ -90,7 +104,7 @@ async function unpackLocalUiPack(version: CachedUIPack) : Promise { }); const finishPromise = new Promise((resolve, reject) => { - gunzip.on('error', event => { + unzip.on('error', event => { reject(event); }); @@ -100,7 +114,7 @@ async function unpackLocalUiPack(version: CachedUIPack) : Promise { reject(event); }); - fpipe.pipe(gunzip).pipe(extract); + fpipe.pipe(unzip).pipe(extract); }); try { @@ -133,6 +147,32 @@ async function loadBundledUiPack(channel: string, callbackStatus: (message: stri return url.pathToFileURL(path.join(result, "index.html")).toString(); } +function initializeFileSystemProtocol(directory: string) { + directory = path.normalize(directory); + + const sessionProtocol = session.fromPartition(kWindowPartitionMainApp).protocol; + sessionProtocol.registerFileProtocol(kUiPackProtocol, (request, callback) => { + let targetPath; + const pathStartIndex = request.url.indexOf('/', kUiPackProtocol.length + 3); + if(pathStartIndex === -1) { + targetPath = path.join(directory, "index.html"); + } else { + const endIndex = request.url.indexOf("?"); + + let requestedPath = endIndex === -1 ? request.url.substring(pathStartIndex) : request.url.substring(pathStartIndex, endIndex); + targetPath = path.normalize(path.join(directory, requestedPath)); + } + + if(!targetPath.startsWith(directory)) { + console.warn("Having UI-Pack path request which exceeds the target directory: %s", targetPath); + callback({ path: "__non__exiting" }); + } else { + console.debug("Resolved %s to %s", request.url, targetPath); + callback({ path: targetPath }); + } + }); +} + async function loadCachedOrRemoteUiPack(channel: string, callbackStatus: (message: string, index: number) => any, ignoreNewVersionTimestamp: boolean) : Promise { callbackStatus("Fetching info", 0); @@ -237,7 +277,8 @@ async function loadCachedOrRemoteUiPack(channel: string, callbackStatus: (messag callbackStatus("UI pack loaded", 1); await doVersionInvalidate(); - return url.pathToFileURL(path.join(target, "index.html")).toString(); + initializeFileSystemProtocol(target); + return kUiPackProtocol + "://shared-ui/index.html"; } catch (error) { invalidatedVersions.push(pack); console.log("Failed to unpack UI pack: %o", error); diff --git a/modules/core/windows/main-window/controller/MainWindow.ts b/modules/core/windows/main-window/controller/MainWindow.ts index aeb758a..8f71d84 100644 --- a/modules/core/windows/main-window/controller/MainWindow.ts +++ b/modules/core/windows/main-window/controller/MainWindow.ts @@ -8,6 +8,7 @@ import * as path from "path"; let windowInstance: BrowserWindow; +export const kWindowPartitionMainApp = "persist:main-app"; export async function showMainWindow(entryPointUrl: string) { if(windowInstance) { throw "main window already initialized"; @@ -29,7 +30,8 @@ export async function showMainWindow(entryPointUrl: string) { webSecurity: false, nodeIntegrationInWorker: true, nodeIntegration: true, - preload: path.join(__dirname, "..", "renderer", "PreloadScript.js") + preload: path.join(__dirname, "..", "renderer", "PreloadScript.js"), + partition: kWindowPartitionMainApp }, icon: path.join(__dirname, "..", "..", "..", "..", "resources", "logo.ico"), }); diff --git a/package.json b/package.json index ed4cede..224c280 100644 --- a/package.json +++ b/package.json @@ -1,16 +1,12 @@ { "name": "TeaClient", - "version": "1.5.1-2", + "version": "1.5.2", "description": "", "main": "main.js", "scripts": { "crash_handler": "electron . crash-handler", "test": "echo \"Error: no test specified\" && exit 1", - "start-d1": "electron . --disable-hardware-acceleration --debug -t --gdb -s -u=http://clientapi.teaspeak.dev/ --updater-ui-loader_type=0", - "start-n": "electron . -t --disable-hardware-acceleration --no-single-instance -u=https://clientapi.teaspeak.de/ -d", - "start-nd": "electron . -t --gdb --disable-hardware-acceleration --no-single-instance -u=http://clientapi.teaspeak.dev/ -d --updater-ui-loader_type=0", - "start-01": "electron . --updater-channel=test -u=http://dev.clientapi.teaspeak.de/ -d --updater-ui-loader_type=0 --updater-local-version=1.0.1", - "start-devel-download": "electron . --disable-hardware-acceleration --gdb --debug --updater-ui-loader_type=2 --updater-ui-ignore-version -t -u http://localhost:8081/", + "start-download-dev": "electron . --disable-hardware-acceleration --gdb --debug --updater-ui-loader_type=0 -t -u https://clientapi.teaspeak.dev/", "start-s": "electron . --disable-hardware-acceleration --gdb --debug --updater-ui-loader_type=3 --updater-ui-ignore-version -t -u http://localhost:8080/", "dtest": "electron . dtest", "sass": "sass",