Upgraded the web client to work with the TeaClient again

canary
WolverinDEV 2019-03-31 20:07:03 +02:00
parent 13b260e369
commit 41c45a0c8a
19 changed files with 373 additions and 175 deletions

View File

@ -4,10 +4,14 @@ html, body {
}
.app-container {
right: 0;
left: 0;
top: 0;
bottom: 0;
width: 100%;
height: 100%;
position: absolute;
width: 100%;
display: flex;
justify-content: center;

View File

@ -1,25 +1,6 @@
declare namespace native {
function client_version(): Promise<string>;
}
/* File: client/js/teaforo.ts */
declare namespace forum {
interface UserData {
session_id: string;
username: string;
application_data: string;
application_data_sign: string;
}
}
declare namespace audio.player {
interface Device {
device_id: string;
name: string;
}
function initialized(): boolean;
function context(): AudioContext;
function destination(): AudioNode;
function on_ready(cb: () => any): void;
function initialize(): boolean;
function available_devices(): Promise<Device[]>;
function set_device(device_id?: string): Promise<void>;
function current_device(device_id?: string): Device;
export function register_callback(callback: () => any);
export function open();
}

23
client/generate_packed.sh Executable file
View File

@ -0,0 +1,23 @@
#!/usr/bin/env bash
BASEDIR=$(dirname "$0")
cd "$BASEDIR"
source ../scripts/resolve_commands.sh
if [[ ! -e declarations/imports_shared.d.ts ]]; then
echo "generate the declarations first!"
echo "Execute: /scripts/build_declarations.sh"
exit 1
fi
if [[ ! -e ../shared/generated/shared.js ]]; then
echo "generate the shared packed file first!"
echo "Execute: /shared/generate_packed.sh"
exit 1
fi
execute_tsc -p tsconfig/tsconfig_packed.json
if [[ $? -ne 0 ]]; then
echo "Failed to build file"
exit 1
fi

View File

@ -1,25 +1,25 @@
import TeaForumIdentity = profiles.identities.TeaForumIdentity;
namespace forum {
const ipc = require("electron").ipcRenderer;
let callback_listener: (() => any)[] = [];
const ipc = require("electron").ipcRenderer;
let callback_listener: (() => any)[] = [];
ipc.on('teaforo-update', (event, data) => {
console.log("Got data update: %o", data);
profiles.identities.set_static_identity(data ? new profiles.identities.TeaForumIdentity(data.application_data, data.application_data_sign) : undefined);
try {
for(let listener of callback_listener)
setImmediate(listener);
} catch(e) {
console.log(e);
}
ipc.on('teaforo-update', (event, data: forum.UserData) => {
console.log("Got data update: %o", data);
profiles.identities.set_static_identity(data ? new TeaForumIdentity(data.application_data, data.application_data_sign) : undefined);
try {
for(let listener of callback_listener)
setImmediate(listener);
} catch(e) {
console.log(e);
callback_listener = [];
});
export function register_callback(callback: () => any) {
callback_listener.push(callback);
}
callback_listener = [];
});
export function register_callback(callback: () => any) {
callback_listener.push(callback);
}
export function open() {
ipc.send("teaforo-login");
export function open() {
ipc.send("teaforo-login");
}
}

View File

@ -0,0 +1,6 @@
{
"source_files": [
"../js/**/*.ts"
],
"target_file": "../declarations/exports.d.ts"
}

View File

@ -0,0 +1,12 @@
/* general web project config */
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"sourceMap": true
},
"include": [
"../declarations/imports_*.d.ts",
"../js/**/*.ts"
]
}

View File

@ -0,0 +1,14 @@
/* packed web project config */
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "none",
"outFile": "../generated/client.js",
"allowJs": true
},
"include": [
"../declarations/imports_*.d.ts",
"../js/**/*.ts",
"../../shared/generated/shared.js"
]
}

View File

@ -1,7 +1,6 @@
<?php
/* this file generates the final environment. All files have to be compiled before! */
$APP_FILE_LIST = [
/* shared part */
$APP_FILE_LIST_SHARED_SOURCE = [
[ /* shared html and php files */
"type" => "html",
"search-pattern" => "/^([a-zA-Z]+)\.(html|php|json)$/",
@ -124,9 +123,10 @@
"path" => "i18n/",
"local-path" => "./shared/i18n/"
],
]
];
/* vendors */
$APP_FILE_LIST_SHARED_VENDORS = [
[
"type" => "js",
"search-pattern" => "/.*\.js$/",
@ -142,10 +142,11 @@
"path" => "vendor/",
"local-path" => "./vendor/"
],
]
];
/* client specific */
[
$APP_FILE_LIST_CLIENT_SOURCE = [
[ /* client css files */
"client-only" => true,
"type" => "css",
"search-pattern" => "/.*\.css$/",
@ -154,17 +155,39 @@
"path" => "css/",
"local-path" => "./client/css/"
],
[
[ /* client js files */
"client-only" => true,
"type" => "js",
"search-pattern" => "/.*\.js/",
"build-target" => "dev|rel",
"build-target" => "dev",
"path" => "js/",
"local-path" => "./client/js/"
],
/* web specific */
/* release specific */
[ /* web merged javascript files (shared inclusive) */
"client-only" => true,
"type" => "js",
"search-pattern" => "/.*\.js$/",
"build-target" => "rel",
"path" => "js/",
"local-path" => "./client/generated/"
],
[ /* Add the shared generated files. Exclude the shared file because we're including it already */
"client-only" => true,
"type" => "js",
"search-pattern" => "/.*\.js$/",
"search-exclude" => "/shared\.js(.map)?$/",
"build-target" => "rel",
"path" => "js/",
"local-path" => "./shared/generated/"
],
];
$APP_FILE_LIST_WEB_SOURCE = [
[ /* web javascript files (development mode only) */
"web-only" => true,
"type" => "js",
@ -210,10 +233,10 @@
"path" => "./",
"local-path" => "./web/html/"
],
]
];
$APP_FILE_LIST_WEB_TEASPEAK = [
/* special web.teaspeak.de only auth files */
[ /* login page and api */
"web-only" => true,
@ -255,9 +278,17 @@
"path" => "certs/",
"local-path" => "./auth/certs/",
"req-parm" => ["-xf"]
],
]
];
$APP_FILE_LIST = array_merge(
$APP_FILE_LIST_SHARED_SOURCE,
$APP_FILE_LIST_SHARED_VENDORS,
$APP_FILE_LIST_CLIENT_SOURCE,
$APP_FILE_LIST_WEB_SOURCE,
$APP_FILE_LIST_WEB_TEASPEAK
);
function systemify_path($path) {
return str_replace("/", DIRECTORY_SEPARATOR, $path);
}

View File

@ -35,6 +35,11 @@ npm run dtsgen -- --config web/tsconfig/dtsconfig.json -v
replace_tribble web/declarations/exports.d.ts
echo "Generated web declarations"
#Client
npm run dtsgen -- --config client/tsconfig/dtsconfig.json -v
replace_tribble client/declarations/exports.d.ts
echo "Generated client declarations"
#Shared
npm run dtsgen -- --config shared/tsconfig/dtsconfig.json -v
replace_tribble shared/declarations/exports.d.ts
@ -54,4 +59,5 @@ generate_link web/declarations/exports.d.ts shared/declarations/imports_web.d.ts
#Last but not least the client imports
generate_link shared/declarations/exports.d.ts web/declarations/imports_shared.d.ts
generate_link shared/declarations/exports.d.ts web/declarations/imports_shared.d.ts
generate_link shared/declarations/exports.d.ts client/declarations/imports_shared.d.ts

96
scripts/client_build.sh Executable file
View File

@ -0,0 +1,96 @@
#!/usr/bin/env bash
source `dirname $0`/resolve_commands.sh
BASEDIR=$(dirname "$0")
cd "$BASEDIR/../"
source_path="client-api/environment/ui-files/raw"
if [[ "$1" == "development" ]] || [[ "$1" == "dev" ]] || [[ "$1" == "debug" ]]; then
type="development"
elif [[ "$1" == "release" ]] || [[ "$1" == "rel" ]]; then
type="release"
else
if [[ $# -lt 1 ]]; then
echo "Invalid argument count!"
else
echo "Invalid option $1"
fi
echo 'Available options are: "development" or "dev", "release" or "rel"'
exit 1
fi
echo "Generating style files"
npm run compile-sass
if [[ $? -ne 0 ]]; then
echo "Failed to generate style files"
exit 1
fi
echo "Generating web workers"
npm run build-worker-codec
if [[ $? -ne 0 ]]; then
echo "Failed to build web worker codec"
exit 1
fi
npm run build-worker-pow
if [[ $? -ne 0 ]]; then
echo "Failed to build web worker pow"
exit 1
fi
#Lets build some tools
#dtsgen should be already build by build_declarations.sh
./tools/build_trgen.sh
if [[ $? -ne 0 ]]; then
echo "Failed to build typescript translation generator"
exit 1
fi
#Now lets build the declarations
echo "Building declarations"
./scripts/build_declarations.sh
if [[ $? -ne 0 ]]; then
echo "Failed to generate declarations"
exit 1
fi
if [[ "$type" == "release" ]]; then #Compile everything for release mode
#Compile the shared source first
echo "Building shared source"
./shared/generate_packed.sh
if [[ $? -ne 0 ]]; then
echo "Failed to build shared source"
exit 1
fi
#Now compile the web client itself
echo "Building web client"
./client/generate_packed.sh
if [[ $? -ne 0 ]]; then
echo "Failed to build web client"
exit 1
fi
elif [[ "$type" == "development" ]]; then
echo "Building shared source"
execute_ttsc -p ./shared/tsconfig/tsconfig.json
if [[ $? -ne 0 ]]; then
echo "Failed to compile shared sources"
exit 1
fi
echo "Building client client source"
execute_ttsc -p ./client/tsconfig/tsconfig.json
if [[ $? -ne 0 ]]; then
echo "Failed to compile web sources"
exit 1
fi
fi
echo "Generating environment"
php files.php generate client ${type}
if [[ $? -ne 0 ]]; then
echo "Failed to generate environment"
exit 1
fi
echo "Successfully build!"

View File

@ -13,7 +13,7 @@ if [[ "$#" -ne 3 ]]; then
exit 1
fi
if [[ ! -d client/environment/ui-files/ ]]; then
if [[ ! -d client-api/environment/ui-files/ ]]; then
echo "Missing UI Files"
exit 1
fi

View File

@ -331,7 +331,6 @@ $animation_length: .5s;
.app-container {
right: 0;
left: 0;
bottom: 25px;
top: 0;
transition: all $animation_length linear;

View File

@ -1,3 +1,4 @@
declare const native: any; //FIXME: Read client declarations!
namespace connection {
export interface HandshakeIdentityHandler {
connection: AbstractServerConnection;

View File

@ -407,26 +407,41 @@ function displayCriticalError(message: string) {
/* all javascript loaders */
const loader_javascript = {
detect_type: async () => {
/* test if js/proto.js is available. If so we're in debug mode */
const request = new XMLHttpRequest();
request.open('GET', 'js/proto.js', true);
if(window.require) {
const request = new Request("js/proto.js");
let file_path = request.url;
if(!file_path.startsWith("file://"))
throw "Invalid file path (" + file_path + ")";
file_path = file_path.substring(7);
await new Promise((resolve, reject) => {
request.onreadystatechange = () => {
if (request.readyState === 4){
if (request.status === 404) {
app.type = app.Type.WEB_RELEASE;
} else {
app.type = app.Type.WEB_DEBUG;
const fs = require('fs');
if(fs.existsSync(file_path)) {
app.type = app.Type.CLIENT_DEBUG;
} else {
app.type = app.Type.CLIENT_RELEASE;
}
} else {
/* test if js/proto.js is available. If so we're in debug mode */
const request = new XMLHttpRequest();
request.open('GET', 'js/proto.js', true);
await new Promise((resolve, reject) => {
request.onreadystatechange = () => {
if (request.readyState === 4){
if (request.status === 404) {
app.type = app.Type.WEB_RELEASE;
} else {
app.type = app.Type.WEB_DEBUG;
}
resolve();
}
resolve();
}
};
request.onerror = () => {
reject("Failed to detect app type");
};
request.send();
});
};
request.onerror = () => {
reject("Failed to detect app type");
};
request.send();
});
}
},
load_scripts: async () => {
/*
@ -468,7 +483,7 @@ const loader_javascript = {
loader.register_task(loader.Stage.JAVASCRIPT, {
name: "scripts release",
priority: 20,
function: loader_javascript.loadRelease
function: loader_javascript.load_release
});
} else {
loader.register_task(loader.Stage.JAVASCRIPT, {
@ -596,7 +611,7 @@ const loader_javascript = {
]);
},
loadRelease: async () => {
load_release: async () => {
console.log("Load for release!");
await loader.load_scripts([
@ -809,24 +824,6 @@ loader.register_task(loader.Stage.INITIALIZING, {
priority: 50
});
window["Module"] = window["Module"] || {};
/* TeaClient */
if(window.require) {
const path = require("path");
const remote = require('electron').remote;
module.paths.push(path.join(remote.app.getAppPath(), "/modules"));
module.paths.push(path.join(path.dirname(remote.getGlobal("browser-root")), "js"));
const connector = require("renderer");
console.log(connector);
loader.register_task(loader.Stage.INITIALIZING, {
name: "teaclient initialize",
function: connector.initialize,
priority: 40
});
}
loader.register_task(loader.Stage.INITIALIZING, {
name: "Browser detection",
function: async () => {
@ -855,9 +852,12 @@ loader.register_task(loader.Stage.INITIALIZING, {
name: "secure tester",
function: async () => {
/* we need https or localhost to use some things like the storage API */
if(location.protocol !== 'https:' && location.hostname !== 'localhost') {
if(typeof isSecureContext === "undefined")
(<any>window)["isSecureContext"] = location.protocol !== 'https:' && location.hostname !== 'localhost';
if(!isSecureContext) {
display_critical_load("TeaWeb cant run on unsecured sides.", "App requires to be loaded via HTTPS!");
throw "App requires to be loaded via HTTPS!"
throw "App requires a secure context!"
}
},
priority: 20
@ -918,80 +918,99 @@ loader.register_task(loader.Stage.LOADED, {
priority: 20
});
const hello_world = () => {
const print_security = () => {
window["Module"] = window["Module"] || {};
/* TeaClient */
if(window.require) {
const path = require("path");
const remote = require('electron').remote;
module.paths.push(path.join(remote.app.getAppPath(), "/modules"));
module.paths.push(path.join(path.dirname(remote.getGlobal("browser-root")), "js"));
const connector = require("renderer");
console.log(connector);
loader.register_task(loader.Stage.INITIALIZING, {
name: "teaclient initialize",
function: connector.initialize,
priority: 40
});
} else {
const hello_world = () => {
const print_security = () => {
{
const css = [
"display: block",
"text-align: center",
"font-size: 42px",
"font-weight: bold",
"-webkit-text-stroke: 2px black",
"color: red"
].join(";");
console.log("%c ", "font-size: 100px;");
console.log("%cSecurity warning:", css);
}
{
const css = [
"display: block",
"text-align: center",
"font-size: 18px",
"font-weight: bold"
].join(";");
console.log("%cPasting anything in here could give attackers access to your data.", css);
console.log("%cUnless you understand exactly what you are doing, close this window and stay safe.", css);
console.log("%c ", "font-size: 100px;");
}
};
/* print the hello world */
{
const css = [
"display: block",
"text-align: center",
"font-size: 42px",
"font-size: 72px",
"font-weight: bold",
"-webkit-text-stroke: 2px black",
"color: red"
"color: #18BC9C"
].join(";");
console.log("%c ", "font-size: 100px;");
console.log("%cSecurity warning:", css);
console.log("%cHey, hold on!", css);
}
{
const css = [
"display: block",
"text-align: center",
"font-size: 18px",
"font-size: 26px",
"font-weight: bold"
].join(";");
console.log("%cPasting anything in here could give attackers access to your data.", css);
console.log("%cUnless you understand exactly what you are doing, close this window and stay safe.", css);
console.log("%c ", "font-size: 100px;");
const css_2 = [
"display: block",
"text-align: center",
"font-size: 26px",
"font-weight: bold",
"color: blue"
].join(";");
const display_detect = /./;
display_detect.toString = function() { print_security(); return ""; }
console.log("%cLovely to see you using and debugging the TeaSpeak Web client.", css);
console.log("%cIf you have some good ideas or already done some incredible changes,", css);
console.log("%cyou'll be may interested to share them here: %chttps://github.com/TeaSpeak/TeaWeb", css, css_2);
console.log("%c ", display_detect);
}
};
/* print the hello world */
{
const css = [
"display: block",
"text-align: center",
"font-size: 72px",
"font-weight: bold",
"-webkit-text-stroke: 2px black",
"color: #18BC9C"
].join(";");
console.log("%cHey, hold on!", css);
try { /* lets try to print it as VM code :)*/
let hello_world_code = hello_world.toString();
hello_world_code = hello_world_code.substr(hello_world_code.indexOf('() => {') + 8);
hello_world_code = hello_world_code.substring(0, hello_world_code.lastIndexOf("}"));
hello_world_code = hello_world_code.replace(/(?!"\S*) {2,}(?!\S*")/g, " ").replace(/[\n\r]/g, "");
eval(hello_world_code);
} catch(e) {
hello_world();
}
{
const css = [
"display: block",
"text-align: center",
"font-size: 26px",
"font-weight: bold"
].join(";");
const css_2 = [
"display: block",
"text-align: center",
"font-size: 26px",
"font-weight: bold",
"color: blue"
].join(";");
const display_detect = /./;
display_detect.toString = function() { print_security(); return ""; }
console.log("%cLovely to see you using and debugging the TeaSpeak Web client.", css);
console.log("%cIf you have some good ideas or already done some incredible changes,", css);
console.log("%cyou'll be may interested to share them here: %chttps://github.com/TeaSpeak/TeaWeb", css, css_2);
console.log("%c ", display_detect);
}
};
try { /* lets try to print it as VM code :)*/
let hello_world_code = hello_world.toString();
hello_world_code = hello_world_code.substr(hello_world_code.indexOf('() => {') + 8);
hello_world_code = hello_world_code.substring(0, hello_world_code.lastIndexOf("}"));
hello_world_code = hello_world_code.replace(/(?!"\S*) {2,}(?!\S*")/g, " ").replace(/[\n\r]/g, "");
eval(hello_world_code);
} catch(e) {
hello_world();
}
loader.execute().then(() => {

View File

@ -23,6 +23,11 @@ function getUserMediaFunction() {
return (navigator as any).getUserMedia || (navigator as any).webkitGetUserMedia || (navigator as any).mozGetUserMedia;
}
interface Window {
open_connected_question: () => Promise<boolean>;
}
function setup_close() {
window.onbeforeunload = event => {
if(profiles.requires_save())
@ -34,23 +39,18 @@ function setup_close() {
if(!native_client) {
event.returnValue = "Are you really sure?<br>You're still connected!";
} else {
event.preventDefault();
event.returnValue = "question";
if(window.open_connected_question) {
event.preventDefault();
event.returnValue = "question";
window.open_connected_question().then(result => {
if(result) {
window.onbeforeunload = undefined;
const {remote} = require('electron');
const dialog = remote.dialog;
dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'question',
buttons: ['Yes', 'No'],
title: 'Confirm',
message: 'Are you really sure?\nYou\'re still connected!'
}, choice => {
if(choice === 0) {
window.onbeforeunload = undefined;
remote.getCurrentWindow().close();
}
});
const {remote} = require('electron');
remote.getCurrentWindow().close();
}
});
} else { /* we're in debugging mode */ }
}
}
};

View File

@ -1,3 +1,4 @@
/// <reference path="../../../declarations/imports_client.d.ts" />
/// <reference path="../../utils/modal.ts" />
/// <reference path="../../utils/tab.ts" />
/// <reference path="../../proto.ts" />
@ -936,7 +937,6 @@ namespace Modals {
if (native_client) {
teaforo_tag.find(".native-teaforo-login").on('click', event => {
setTimeout(() => {
const forum = require("teaforo.js");
const call = () => {
if (modal.shown) {
display_settings(selected_profile);

View File

@ -511,7 +511,7 @@ const loader_javascript = {
["js/WebPPTListener.js"]
]);
}),
loadRelease: () => __awaiter(this, void 0, void 0, function* () {
load_release: () => __awaiter(this, void 0, void 0, function* () {
console.log("Load for release!");
yield loader.load_scripts([
//Load general API's

View File

@ -1 +0,0 @@
C:/Users/WolverinDEV/TeaSpeak/TeaWeb/vendor/jquery/jquery.min.js

View File

@ -29,3 +29,10 @@ html, body {
display: flex; flex-direction: column; resize: both;
}
}
$small_device: 650px;
@media only screen and (max-width: $small_device) {
.app-container {
bottom: 25px;
}
}