Updated the project structure, for the upcoming client (Still needs some work)

canary
WolverinDEV 2018-10-03 22:04:29 +02:00
parent 48081603ba
commit 8d1a6628fb
157 changed files with 846 additions and 22061 deletions

3
.gitignore vendored
View File

@ -1,4 +1,5 @@
js/**/*.js*
**.js*
*.css.map
asm/build/
generated/
node_modules/

View File

@ -1,458 +0,0 @@
// Read an INI file into easy-to-access name/value pairs.
// inih and INIReader are released under the New BSD license (see LICENSE.txt).
// Go to the project home page for more info:
//
// https://github.com/benhoyt/inih
/* inih -- simple .INI file parser
inih is released under the New BSD license (see LICENSE.txt). Go to the project
home page for more info:
https://github.com/benhoyt/inih
*/
#ifndef __INI_H__
#define __INI_H__
/* Make this header file easier to include in C++ code */
#ifdef __cplusplus
extern "C" {
#endif
#include <stdio.h>
/* Typedef for prototype of handler function. */
typedef int (*ini_handler)(void* user, const char* section,
const char* name, const char* value);
/* Typedef for prototype of fgets-style reader function. */
typedef char* (*ini_reader)(char* str, int num, void* stream);
/* Parse given INI-style file. May have [section]s, name=value pairs
(whitespace stripped), and comments starting with ';' (semicolon). Section
is "" if name=value pair parsed before any section heading. name:value
pairs are also supported as a concession to Python's configparser.
For each name=value pair parsed, call handler function with given user
pointer as well as section, name, and value (data only valid for duration
of handler call). Handler should return nonzero on success, zero on error.
Returns 0 on success, line number of first error on parse error (doesn't
stop on first error), -1 on file open error, or -2 on memory allocation
error (only when INI_USE_STACK is zero).
*/
int ini_parse(const char* filename, ini_handler handler, void* user);
/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
close the file when it's finished -- the caller must do that. */
int ini_parse_file(FILE* file, ini_handler handler, void* user);
inline int ini_parse_message(const std::string& message, ini_handler handler, void* user);
/* Same as ini_parse(), but takes an ini_reader function pointer instead of
filename. Used for implementing custom or string-based I/O. */
int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
void* user);
/* Nonzero to allow multi-line value parsing, in the style of Python's
configparser. If allowed, ini_parse() will call the handler with the same
name for each subsequent line parsed. */
#ifndef INI_ALLOW_MULTILINE
#define INI_ALLOW_MULTILINE 1
#endif
/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
the file. See http://code.google.com/p/inih/issues/detail?id=21 */
#ifndef INI_ALLOW_BOM
#define INI_ALLOW_BOM 1
#endif
/* Nonzero to allow inline comments (with valid inline comment characters
specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match
Python 3.2+ configparser behaviour. */
#ifndef INI_ALLOW_INLINE_COMMENTS
#define INI_ALLOW_INLINE_COMMENTS 1
#endif
#ifndef INI_INLINE_COMMENT_PREFIXES
#define INI_INLINE_COMMENT_PREFIXES ";"
#endif
/* Nonzero to use stack, zero to use heap (malloc/free). */
#ifndef INI_USE_STACK
#define INI_USE_STACK 1
#endif
/* Stop parsing on first error (default is to keep parsing). */
#ifndef INI_STOP_ON_FIRST_ERROR
#define INI_STOP_ON_FIRST_ERROR 0
#endif
/* Maximum line length for any line in INI file. */
#ifndef INI_MAX_LINE
#define INI_MAX_LINE 200
#endif
#ifdef __cplusplus
}
#endif
/* inih -- simple .INI file parser
inih is released under the New BSD license (see LICENSE.txt). Go to the project
home page for more info:
https://github.com/benhoyt/inih
*/
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <sstream>
#if !INI_USE_STACK
#include <stdlib.h>
#endif
#define MAX_SECTION 50
#define MAX_NAME 50
/* Strip whitespace chars off end of given string, in place. Return s. */
inline static char* rstrip(char* s)
{
char* p = s + strlen(s);
while (p > s && isspace((unsigned char)(*--p)))
*p = '\0';
return s;
}
/* Return pointer to first non-whitespace char in given string. */
inline static char* lskip(const char* s)
{
while (*s && isspace((unsigned char)(*s)))
s++;
return (char*)s;
}
/* Return pointer to first char (of chars) or inline comment in given string,
or pointer to null at end of string if neither found. Inline comment must
be prefixed by a whitespace character to register as a comment. */
inline static char* find_chars_or_comment(const char* s, const char* chars)
{
#if INI_ALLOW_INLINE_COMMENTS
int was_space = 0;
while (*s && (!chars || !strchr(chars, *s)) &&
!(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) {
was_space = isspace((unsigned char)(*s));
s++;
}
#else
while (*s && (!chars || !strchr(chars, *s))) {
s++;
}
#endif
return (char*)s;
}
/* Version of strncpy that ensures dest (size bytes) is null-terminated. */
inline static char* strncpy0(char* dest, const char* src, size_t size)
{
strncpy(dest, src, size);
dest[size - 1] = '\0';
return dest;
}
/* See documentation in header file. */
inline int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
void* user)
{
/* Uses a fair bit of stack (use heap instead if you need to) */
#if INI_USE_STACK
char line[INI_MAX_LINE];
#else
char* line;
#endif
char section[MAX_SECTION] = "";
char prev_name[MAX_NAME] = "";
char* start;
char* end;
char* name;
char* value;
int lineno = 0;
int error = 0;
#if !INI_USE_STACK
line = (char*)malloc(INI_MAX_LINE);
if (!line) {
return -2;
}
#endif
/* Scan through stream line by line */
while (reader(line, INI_MAX_LINE, stream) != NULL) {
lineno++;
start = line;
#if INI_ALLOW_BOM
if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
(unsigned char)start[1] == 0xBB &&
(unsigned char)start[2] == 0xBF) {
start += 3;
}
#endif
start = lskip(rstrip(start));
if (*start == ';' || *start == '#') {
/* Per Python configparser, allow both ; and # comments at the
start of a line */
}
#if INI_ALLOW_MULTILINE
else if (*prev_name && *start && start > line) {
#if INI_ALLOW_INLINE_COMMENTS
end = find_chars_or_comment(start, NULL);
if (*end)
*end = '\0';
rstrip(start);
#endif
/* Non-blank line with leading whitespace, treat as continuation
of previous name's value (as per Python configparser). */
if (!handler(user, section, prev_name, start) && !error)
error = lineno;
}
#endif
else if (*start == '[') {
/* A "[section]" line */
end = find_chars_or_comment(start + 1, "]");
if (*end == ']') {
*end = '\0';
strncpy0(section, start + 1, sizeof(section));
*prev_name = '\0';
}
else if (!error) {
/* No ']' found on section line */
error = lineno;
}
}
else if (*start) {
/* Not a comment, must be a name[=:]value pair */
end = find_chars_or_comment(start, "=:");
if (*end == '=' || *end == ':') {
*end = '\0';
name = rstrip(start);
value = lskip(end + 1);
#if INI_ALLOW_INLINE_COMMENTS
end = find_chars_or_comment(value, NULL);
if (*end)
*end = '\0';
#endif
rstrip(value);
/* Valid name[=:]value pair found, call handler */
strncpy0(prev_name, name, sizeof(prev_name));
if (!handler(user, section, name, value) && !error)
error = lineno;
}
else if (!error) {
/* No '=' or ':' found on name[=:]value line */
error = lineno;
}
}
#if INI_STOP_ON_FIRST_ERROR
if (error)
break;
#endif
}
#if !INI_USE_STACK
free(line);
#endif
return error;
}
/* See documentation in header file. */
inline int ini_parse_file(FILE* file, ini_handler handler, void* user)
{
return ini_parse_stream((ini_reader)fgets, file, handler, user);
}
/* See documentation in header file. */
inline int ini_parse_message(const std::string& message, ini_handler handler, void* user)
{
std::istringstream stream(message);
return ini_parse_stream((ini_reader) [](char* str, int num, void* ptrStream) {
auto stream = (std::istringstream*) ptrStream;
stream->getline(str, num);
return !!*stream ? str : nullptr;
}, &stream, handler, user);
}
/* See documentation in header file. */
inline int ini_parse(const char* filename, ini_handler handler, void* user)
{
FILE* file;
int error;
file = fopen(filename, "r");
if (!file)
return -1;
error = ini_parse_file(file, handler, user);
fclose(file);
return error;
}
#endif /* __INI_H__ */
#ifndef __INIREADER_H__
#define __INIREADER_H__
#include <map>
#include <set>
#include <string>
// Read an INI file into easy-to-access name/value pairs. (Note that I've gone
// for simplicity here rather than speed, but it should be pretty decent.)
class INIReader
{
public:
// Empty Constructor
INIReader() {};
// Construct INIReader and parse given filename. See ini.h for more info
// about the parsing.
INIReader(std::string filename, bool raw = false);
// Return the result of ini_parse(), i.e., 0 on success, line number of
// first error on parse error, or -1 on file open error.
int ParseError() const;
// Return the list of sections found in ini file
std::set<std::string> Sections();
// Get a string value from INI file, returning default_value if not found.
std::string Get(std::string section, std::string name,
std::string default_value);
// Get an integer (long) value from INI file, returning default_value if
// not found or not a valid integer (decimal "1234", "-1234", or hex "0x4d2").
long GetInteger(std::string section, std::string name, long default_value);
// Get a real (floating point double) value from INI file, returning
// default_value if not found or not a valid floating point value
// according to strtod().
double GetReal(std::string section, std::string name, double default_value);
// Get a boolean value from INI file, returning default_value if not found or if
// not a valid true/false value. Valid true values are "true", "yes", "on", "1",
// and valid false values are "false", "no", "off", "0" (not case sensitive).
bool GetBoolean(std::string section, std::string name, bool default_value);
private:
int _error;
std::map<std::string, std::string> _values;
std::set<std::string> _sections;
static std::string MakeKey(std::string section, std::string name);
static int ValueHandler(void* user, const char* section, const char* name,
const char* value);
};
#endif // __INIREADER_H__
#ifndef __INIREADER__
#define __INIREADER__
#include <algorithm>
#include <cctype>
#include <cstdlib>
using std::string;
inline INIReader::INIReader(string data, bool raw)
{
if(raw)
_error = ini_parse_message(data, ValueHandler, this);
else
_error = ini_parse(data.c_str(), ValueHandler, this);
}
inline int INIReader::ParseError() const
{
return _error;
}
inline std::set<string> INIReader::Sections()
{
return _sections;
}
inline string INIReader::Get(string section, string name, string default_value)
{
string key = MakeKey(section, name);
return _values.count(key) ? _values[key] : default_value;
}
inline long INIReader::GetInteger(string section, string name, long default_value)
{
string valstr = Get(section, name, "");
const char* value = valstr.c_str();
char* end;
// This parses "1234" (decimal) and also "0x4D2" (hex)
long n = strtol(value, &end, 0);
return end > value ? n : default_value;
}
inline double INIReader::GetReal(string section, string name, double default_value)
{
string valstr = Get(section, name, "");
const char* value = valstr.c_str();
char* end;
double n = strtod(value, &end);
return end > value ? n : default_value;
}
inline bool INIReader::GetBoolean(string section, string name, bool default_value)
{
string valstr = Get(section, name, "");
// Convert to lower case to make string comparisons case-insensitive
std::transform(valstr.begin(), valstr.end(), valstr.begin(), ::tolower);
if (valstr == "true" || valstr == "yes" || valstr == "on" || valstr == "1")
return true;
else if (valstr == "false" || valstr == "no" || valstr == "off" || valstr == "0")
return false;
else
return default_value;
}
inline string INIReader::MakeKey(string section, string name)
{
string key = section + "=" + name;
// Convert to lower case to make section/name lookups case-insensitive
std::transform(key.begin(), key.end(), key.begin(), ::tolower);
return key;
}
inline int INIReader::ValueHandler(void* user, const char* section, const char* name,
const char* value)
{
INIReader* reader = (INIReader*)user;
string key = MakeKey(section, name);
if (reader->_values[key].size() > 0)
reader->_values[key] += "\n";
reader->_values[key] += value;
reader->_sections.insert(section);
return 1;
}
#endif // __INIREADER__

View File

@ -1,283 +0,0 @@
#include "Identity.h"
#include <iostream>
#include "base64.h"
#define SHA_DIGEST_LENGTH 20
#define ECC_TYPE_INDEX 5
static const char *TSKEY =
"b9dfaa7bee6ac57ac7b65f1094a1c155"
"e747327bc2fe5d51c512023fe54a2802"
"01004e90ad1daaae1075d53b7d571c30"
"e063b5a62a4a017bb394833aa0983e6e";
using namespace std;
inline int SHA1(const char* input, size_t length, char* result) {
hash_state ctx = {};
if (sha1_init(&ctx) != CRYPT_OK)
{ return -1; }
if (sha1_process(&ctx, (uint8_t*) input, length) != CRYPT_OK)
{ return -1; }
if (sha1_done(&ctx, (uint8_t*) result) != CRYPT_OK)
{ return -1; }
return 0;
}
static int decriptIdentity(char *data, uint32_t length) {
int dataSize = std::min((uint32_t) 100, length);
for (int i = 0; i < dataSize; i++) {
data[i] ^= TSKEY[i];
}
char hash[SHA_DIGEST_LENGTH];
//if(SHA1(data + 20, strlen(data + 20), hash) < 0) return -1;
hash_state ctx = {};
if (sha1_init(&ctx) != CRYPT_OK)
{ return -1; }
if (sha1_process(&ctx, (uint8_t*)data + 20, strlen(data + 20)) != CRYPT_OK)
{ return -1; }
if (sha1_done(&ctx, (uint8_t*)hash) != CRYPT_OK)
{ return -1; }
for (int i = 0; i < 20; i++) {
data[i] ^= hash[i];
}
return 0;
}
static int encriptIdentity(char *data, uint32_t length) {
char hash[SHA_DIGEST_LENGTH];
//if(SHA1(data, length, hash) < 0) return -1;
hash_state ctx;
if (sha1_init(&ctx) != CRYPT_OK)
{ return -1; }
if (sha1_process(&ctx, (uint8_t*)data + 20, strlen(data + 20)) != CRYPT_OK)
{ return -1; }
if (sha1_done(&ctx, (uint8_t*)hash) != CRYPT_OK)
{ return -1; }
for (int i = 0; i < 20; i++) {
data[i] ^= hash[i];
}
int dataSize = std::min((uint32_t) 100, length);
for (int i = 0; i < dataSize; i++) {
data[i] ^= TSKEY[i];
}
return 0;
}
namespace ts {
Identity* Identity::createNew() {
auto result = new Identity();
prng_state rndState = {};
memset(&rndState, 0, sizeof(prng_state));
int err;
result->keyPair = new ecc_key;
//cout << " -> " << find_prng("sprng") << endl;
if((err = ecc_make_key_ex(&rndState, find_prng("sprng"), result->keyPair, &ltc_ecc_sets[ECC_TYPE_INDEX])) != CRYPT_OK){
printf("Cant create a new identity (Keygen)\n");
printf("Message: %s\n", error_to_string(err));
delete result;
return nullptr;
}
return result;
}
Identity* Identity::parse(const std::string& data, std::string& error) {
int vindex = data.find('V');
if(vindex <= 0) {
error = "Invalid structure";
return nullptr;
}
auto slevel = data.substr(0, vindex);
if(slevel.find_first_not_of("0123456789") != std::string::npos) {
error = "Invalid offset (" + slevel + ")";
return nullptr;
}
mp_int keyOffset{};
mp_init(&keyOffset);
mp_read_radix(&keyOffset, slevel.data(), 10);
auto keyData = data.substr(vindex + 1);
keyData = base64::decode(keyData);
if(encriptIdentity(&keyData[0], keyData.length()) < 0) {
error = "Could not decrypt key";
return nullptr;
}
auto identity = new Identity(base64::decode(keyData), keyOffset, keyOffset);
if(!identity->keyPair) {
error = "Could not load key";
delete identity;
return nullptr;
}
printf("X: %s | %s\n", slevel.c_str(), identity->lastValidKeyOffsetString().c_str());
return identity;
}
Identity::Identity(const std::string& asnStruct, mp_int keyOffset, mp_int lastCheckedOffset) {
this->keyOffset = keyOffset;
this->lastCheckedOffset = lastCheckedOffset;
importKey(asnStruct);
mp_init_copy(&this->keyOffset, &keyOffset);
mp_init_copy(&this->lastCheckedOffset, &lastCheckedOffset);
}
Identity::Identity() {
mp_init_multi(&this->keyOffset, &this->lastCheckedOffset, nullptr);
this->keyPair = nullptr;
}
Identity::~Identity() {
delete this->keyPair;
this->keyPair = nullptr;
mp_clear_multi(&this->keyOffset, &this->lastCheckedOffset, nullptr);
}
void Identity::importKey(std::string asnStruct) {
this->keyPair = new ecc_key;
int err;
if((err = ecc_import_ex((const unsigned char *) asnStruct.data(), asnStruct.length(), this->keyPair, &ltc_ecc_sets[ECC_TYPE_INDEX])) != CRYPT_OK){
delete this->keyPair;
this->keyPair = nullptr;
printf("Cant import identity from asn structure\n");
printf("Message: %s\n", error_to_string(err));
return;
}
}
std::string Identity::exportIdentity() {
std::string data = privateKey();
decriptIdentity((char *) data.data(), data.length());
return this->lastValidKeyOffsetString() + "V" + base64_encode(data);
}
std::string Identity::uid() {
char buffer[SHA_DIGEST_LENGTH];
auto key = this->publicKey();
SHA1(key.data(), key.length(), buffer);
return base64::encode(buffer, SHA_DIGEST_LENGTH);
}
inline string hex(string input, char beg, char end){
assert(end - beg == 16);
int len = input.length() * 2;
char output[len];
int idx = 0;
for(int index = 0; index < input.length(); index++){
char elm = input[index];
output[idx++] = static_cast<char>(beg + ((elm >> 4) & 0x0F));
output[idx++] = static_cast<char>(beg + ((elm & 0x0F) >> 0));
}
return string(output, len);
}
std::string Identity::avatarId() {
return hex(base64::decode(this->uid()), 'a', 'q');
}
std::string Identity::publicKey() {
assert(this->keyPair);
ulong32 bufferLength = 1028;
char buffer[bufferLength];
ecc_export((unsigned char *) buffer, &bufferLength, PK_PUBLIC, this->keyPair);
return base64_encode(std::string(buffer, bufferLength));
}
std::string Identity::privateKey() {
assert(this->keyPair);
ulong32 bufferLength = 1028;
char buffer[bufferLength];
ecc_export((unsigned char *) buffer, &bufferLength, PK_PRIVATE, this->keyPair);
return base64_encode(std::string(buffer, bufferLength));
}
ecc_key& Identity::getPrivateKey() {
return *keyPair;
}
#define MaxUlongString 20
bool Identity::improveSecurityLevel(int target) {
auto publicKey = this->publicKey();
char hashBuffer[publicKey.length() + MaxUlongString];
memcpy(hashBuffer, publicKey.data(), publicKey.length());
if(mp_cmp(&this->lastCheckedOffset, &this->keyOffset) < 0)
mp_copy(&this->keyOffset, &this->lastCheckedOffset);
int best = getSecurityLevel(hashBuffer, publicKey.length(), this->lastCheckedOffset);
while(true){
if(best >= target) return true;
int currentLevel = getSecurityLevel(hashBuffer, publicKey.length(), this->lastCheckedOffset);
if(currentLevel >= best){
this->keyOffset = this->lastCheckedOffset;
best = currentLevel;
}
mp_add_d(&this->lastCheckedOffset, 1, &this->lastCheckedOffset);
}
}
int Identity::getSecurityLevel() {
auto length = publicKey().length();
char hashBuffer[length + MaxUlongString];
auto publicKey = this->publicKey();
memcpy(hashBuffer, publicKey.data(), publicKey.length());
return getSecurityLevel(hashBuffer, publicKey.length(), this->keyOffset);
}
int Identity::getSecurityLevel(char *hashBuffer, size_t keyLength, mp_int offset) {
char numBuffer[MaxUlongString];
mp_todecimal(&offset, numBuffer);
/*
int numLen = 0;
do {
numBuffer[numLen] = '0' + (offset % 10);
offset /= 10;
numLen++;
} while(offset > 0);
for(int i = 0; i < numLen; i++)
hashBuffer[keyLength + i] = numBuffer[numLen - (i + 1)];
*/
auto numLen = strlen(numBuffer);
memcpy(&hashBuffer[keyLength], numBuffer, numLen);
char shaBuffer[SHA_DIGEST_LENGTH];
SHA1(hashBuffer, keyLength + numLen, shaBuffer);
//Leading zero bits
int zeroBits = 0;
int i;
for(i = 0; i < SHA_DIGEST_LENGTH; i++)
if(shaBuffer[i] == 0) zeroBits += 8;
else break;
if(i < SHA_DIGEST_LENGTH)
for(int bit = 0; bit < 8; bit++)
if((shaBuffer[i] & (1 << bit)) == 0) zeroBits++;
else break;
return zeroBits;
}
}

View File

@ -1,59 +0,0 @@
#pragma once
#include <tomcrypt.h>
#include <string>
#include <tommath.h>
namespace ts {
class Identity {
inline std::string toString(const mp_int& num) {
char buffer[1024];
mp_todecimal(&num, buffer);
return std::string(buffer);
}
public:
static Identity* createNew();
static Identity* parse(const std::string&, std::string&);
Identity(const std::string& asnStruct,mp_int keyOffset,mp_int lastCheckedOffset);
~Identity();
bool valid(){ return keyPair != nullptr; }
std::string uid();
std::string avatarId();
std::string publicKey();
std::string privateKey();
std::string exportIdentity();
ecc_key* getKeyPair(){
return keyPair;
}
ecc_key& getPrivateKey();
bool improveSecurityLevel(int target);
int getSecurityLevel();
mp_int lastValidKeyOffset(){ return keyOffset; }
mp_int lastTestedKeyOffset(){ return lastCheckedOffset; }
std::string lastValidKeyOffsetString(){
return toString(this->lastValidKeyOffset());
}
std::string lastTestedKeyOffsetString(){
return toString(this->lastTestedKeyOffset());
}
private:
Identity();
int getSecurityLevel(char* hasBuffer, size_t keyLength, mp_int offset);
void importKey(std::string asn1);
ecc_key* keyPair = nullptr;
mp_int keyOffset;
mp_int lastCheckedOffset;
};
}

View File

@ -1,136 +0,0 @@
#include <cstdio>
#include <emscripten.h>
#include <emscripten/bind.h>
#include <tomcrypt.h>
#include <cmath>
#include <iostream>
#include "Identity.h"
#include "base64.h"
#define INI_MAX_LINE 1024
#include "INIReader.h"
using namespace emscripten;
using namespace std;
extern "C" {
std::string errorMessage = "";
inline const char* cstr(const std::string& message) {
auto buffer = (char*) malloc(message.length() + 1);
cout << "Allocating at " << (void*) buffer << endl;
buffer[message.length()] = '\0';
memcpy(buffer, message.data(), message.length());
return buffer;
}
EMSCRIPTEN_KEEPALIVE
const char* last_error_message() {
return cstr(errorMessage);
};
EMSCRIPTEN_KEEPALIVE
void destroy_string(const char* str) {
cout << "Deallocating at " << (void*) str << endl;
if(str) free((void *) str);
};
inline void clear_error() { errorMessage = ""; }
EMSCRIPTEN_KEEPALIVE
int tomcrypt_initialize() {
init_LTM();
if(register_prng(&sprng_desc) == -1) {
printf("could not setup prng\n");
return EXIT_FAILURE;
}
if (register_cipher(&rijndael_desc) == -1) {
printf("could not setup rijndael\n");
return EXIT_FAILURE;
}
cout << "Initialized!" << endl;
return 0;
}
EMSCRIPTEN_KEEPALIVE
void* parse_identity(const char* input) {
cout << "Got messsage: " << input << endl;
clear_error();
return ts::Identity::parse(input, errorMessage);
}
EMSCRIPTEN_KEEPALIVE
void* parse_identity_file(const char* input) {
clear_error();
INIReader reader(input, true);
if(reader.ParseError() != 0) {
errorMessage = "Could not parse file " + to_string(reader.ParseError());
return nullptr;
}
auto identity = reader.Get("Identity", "identity", "");
if(!identity.empty() && identity[0] == '"')
identity = identity.substr(1);
if(!identity.empty() && identity.back() == '"')
identity = identity.substr(0, identity.length() - 1);
if(identity.empty()) {
errorMessage = "Mussing identity value at Identity::identity";
return nullptr;
}
return ts::Identity::parse(identity, errorMessage);
}
#define IDENTITIEFY(_ret) \
auto identity = dynamic_cast<ts::Identity*>((ts::Identity*) ptrIdentity); \
if(!identity) { \
errorMessage = "Invalid identity pointer!"; \
return _ret; \
}
EMSCRIPTEN_KEEPALIVE
void delete_identity(void* ptrIdentity) {
IDENTITIEFY(;);
delete identity;
}
EMSCRIPTEN_KEEPALIVE
const char* identity_security_level(void* ptrIdentity) {
IDENTITIEFY("");
return cstr(std::to_string(identity->getSecurityLevel()));
}
EMSCRIPTEN_KEEPALIVE
const char* identity_export(void* ptrIdentity) {
IDENTITIEFY("");
return cstr(identity->exportIdentity());
}
EMSCRIPTEN_KEEPALIVE
const char* identity_key_public(void* ptrIdentity) {
IDENTITIEFY("");
return cstr(identity->publicKey());
}
EMSCRIPTEN_KEEPALIVE
const char* identity_uid(void* ptrIdentity) {
IDENTITIEFY("");
return cstr(identity->uid());
}
EMSCRIPTEN_KEEPALIVE
const char* identity_sign(void* ptrIdentity, const char* message, int length) {
IDENTITIEFY("");
ulong32 bufferLength = 128;
char signBuffer[bufferLength];
prng_state rndState = {};
memset(&rndState, 0, sizeof(prng_state));
auto state = ecc_sign_hash((const unsigned char*) message, length, reinterpret_cast<unsigned char *>(signBuffer), &bufferLength, &rndState, find_prng("sprng"), identity->getKeyPair());
if(state != CRYPT_OK) {
errorMessage = "Could not sign message (" + std::string(error_to_string(state)) + "|" + std::to_string(state) + ")";
return "";
}
return cstr(base64::encode(signBuffer, bufferLength));
}
}

View File

@ -1,59 +0,0 @@
#pragma once
#include <string>
#include <tomcrypt.h>
#include <iostream>
namespace base64 {
/**
* Encodes a given string in Base64
* @param input The input string to Base64-encode
* @param inputSize The size of the input to decode
* @return A Base64-encoded version of the encoded string
*/
inline std::string encode(const char* input, const unsigned long inputSize) {
auto outlen = static_cast<unsigned long>(inputSize + (inputSize / 3.0) + 16);
auto outbuf = new unsigned char[outlen]; //Reserve output memory
if(base64_encode((unsigned char*) input, inputSize, outbuf, &outlen) != CRYPT_OK){
std::cerr << "Invalid input '" << input << "'" << std::endl;
return "";
}
std::string ret((char*) outbuf, outlen);
delete[] outbuf;
return ret;
}
/**
* Encodes a given string in Base64
* @param input The input string to Base64-encode
* @return A Base64-encoded version of the encoded string
*/
inline std::string encode(const std::string& input) { return encode(input.c_str(), input.size()); }
/**
* Decodes a Base64-encoded string.
* @param input The input string to decode
* @return A string (binary) that represents the Base64-decoded data of the input
*/
inline std::string decode(const char* input, ulong32 size) {
auto out = new unsigned char[size];
if(base64_strict_decode((unsigned char*) input, size, out, &size) != CRYPT_OK){
std::cerr << "Invalid base 64 string '" << input << "'" << std::endl;
return "";
}
std::string ret((char*) out, size);
delete[] out;
return ret;
}
/**
* Decodes a Base64-encoded string.
* @param input The input string to decode
* @return A string (binary) that represents the Base64-decoded data of the input
*/
inline std::string decode(const std::string& input) { return decode(input.c_str(), input.size()); }
}
inline std::string base64_encode(const char* input, const unsigned long inputSize) { return base64::encode(input, inputSize); }
inline std::string base64_encode(const std::string& input) { return base64::encode(input.c_str(), input.size()); }

@ -1 +0,0 @@
Subproject commit b97dd67fdc75a39d0fc99ceee573921ba3e73b1f

@ -1 +0,0 @@
Subproject commit bc6d70bd1f4a6778cf51379090d8391dcf53590d

@ -1 +0,0 @@
Subproject commit fe6cc64884b2b408b607389f46266d44fd942a79

View File

@ -1,132 +0,0 @@
#include <opus.h>
#include <emscripten.h>
#include <string>
using namespace std;
extern "C" {
struct OpusHandle {
OpusEncoder* encoder = nullptr;
OpusDecoder* decoder = nullptr;
size_t channelCount = 1;
size_t sampleRate = 48000;
int opusType = OPUS_APPLICATION_AUDIO;
};
const char* opus_errors[7] = {
"One or more invalid/out of range arguments", //-1 (OPUS_BAD_ARG)
"Not enough bytes allocated in the buffer", //-2 (OPUS_BUFFER_TOO_SMALL)
"An internal error was detected", //-3 (OPUS_INTERNAL_ERROR)
"The compressed data passed is corrupted", //-4 (OPUS_INVALID_PACKET)
"Invalid/unsupported request number", //-5 (OPUS_UNIMPLEMENTED)
"An encoder or decoder structure is invalid or already freed", //-6 (OPUS_INVALID_STATE)
"Memory allocation has failed" //-7 (OPUS_ALLOC_FAIL)
};
inline const char* opus_error_message(int error) {
error = abs(error);
if(error > 0 && error <= 7) return opus_errors[error - 1];
return "undefined error";
}
inline int currentMillies() {
return EM_ASM_INT({ return Date.now(); });
}
#define _S(x) #x
#define INVOKE_OPUS(result, method, ...) \
result = method( __VA_ARGS__ ); \
if(error != 0){ \
printf("Got opus error while invoking %s. Code: %d Message: %s\n", _S(method), error, opus_error_message(error)); \
return false; \
}
inline bool reinitialize_decoder(OpusHandle *handle) {
if (handle->decoder)
opus_decoder_destroy(handle->decoder);
int error = 0;
INVOKE_OPUS(handle->decoder, opus_decoder_create, 48000, handle->channelCount, &error);
return true;
}
inline bool reinitialize_encoder(OpusHandle *handle) {
if (handle->encoder)
opus_encoder_destroy(handle->encoder);
int error = 0;
INVOKE_OPUS(handle->encoder, opus_encoder_create, 48000, handle->channelCount, handle->opusType, &error);
INVOKE_OPUS(error, opus_encoder_ctl, handle->encoder, OPUS_SET_COMPLEXITY(1));
//INVOKE_OPUS(error, opus_encoder_ctl, handle->encoder, OPUS_SET_BITRATE(4740));
EM_ASM(
printMessageToServerTab('Encoder initialized!');
printMessageToServerTab(' Comprexity: 1');
printMessageToServerTab(' Bitrate: 4740');
);
return true;
}
EMSCRIPTEN_KEEPALIVE
OpusHandle* codec_opus_createNativeHandle(size_t channelCount, int type) {
printf("Initialize opus. (Channel count: %d Sample rate: %d Type: %d)!\n", channelCount, 48000, type);
auto codec = new OpusHandle{};
codec->opusType = type;
if(!reinitialize_decoder(codec)) return nullptr;
if(!reinitialize_encoder(codec)) return nullptr;
return codec;
}
EMSCRIPTEN_KEEPALIVE
void codec_opus_deleteNativeHandle(OpusHandle* codec) {
if(!codec) return;
if(codec->decoder) opus_decoder_destroy(codec->decoder);
codec->decoder = nullptr;
if(codec->encoder) opus_encoder_destroy(codec->encoder);
codec->encoder = nullptr;
delete codec;
}
EMSCRIPTEN_KEEPALIVE
int codec_opus_encode(OpusHandle* handle, uint8_t* buffer, size_t length, size_t maxLength) {
auto begin = currentMillies();
auto result = opus_encode_float(handle->encoder, (float*) buffer, length / handle->channelCount, buffer, maxLength);
if(result < 0) return result;
auto end = currentMillies();
EM_ASM({
printMessageToServerTab("codec_opus_encode(...) tooks " + $0 + "ms to execute!");
}, end - begin);
return result;
}
EMSCRIPTEN_KEEPALIVE
int codec_opus_decode(OpusHandle* handle, uint8_t* buffer, size_t length, size_t maxLength) {
auto result = opus_decode_float(handle->decoder, buffer, length, (float*) buffer, maxLength / sizeof(float) / handle->channelCount, false);
if(result < 0) return result; //Failed
return result;
}
EMSCRIPTEN_KEEPALIVE
int codec_opus_changeApplication(OpusHandle* handle, int type) {
handle->opusType = type;
if(type != OPUS_APPLICATION_VOIP && type != OPUS_APPLICATION_AUDIO && type != OPUS_APPLICATION_RESTRICTED_LOWDELAY)
return 1;
return opus_encoder_ctl(handle->encoder, OPUS_SET_APPLICATION(type));
}
EMSCRIPTEN_KEEPALIVE
int codec_opus_reset(OpusHandle* handle) {
if(!reinitialize_decoder(handle)) return 0;
if(!reinitialize_encoder(handle)) return 0;
return 1;
}
/*
opus_encoder_ctl(enc, OPUS_SET_BITRATE(bitrate));
opus_encoder_ctl(enc, OPUS_SET_COMPLEXITY(complexity));
opus_encoder_ctl(enc, OPUS_SET_SIGNAL(signal_type));
*/
}

View File

@ -239,15 +239,17 @@
}
}
if (isset($_GET["type"])) {
error_log("Got authX request!");
var_dump($_GET);
var_dump($_POST);
if ($_GET["type"] == "login") {
checkLogin($_POST["user"], $_POST["pass"]);
} else if ($_GET["type"] == "logout") {
logout();
} else die("unknown type!");
} else if(isset($_POST)) {
error_log("Got auth request!");
if(!$_INCLIDE_ONLY) {
if (isset($_GET["type"])) {
error_log("Got authX request!");
var_dump($_GET);
var_dump($_POST);
if ($_GET["type"] == "login") {
checkLogin($_POST["user"], $_POST["pass"]);
} else if ($_GET["type"] == "logout") {
logout();
} else die("unknown type!");
} else if(isset($_POST)) {
error_log("Got auth request!");
}
}

View File

@ -1,73 +0,0 @@
const btn_login = $("#btn_login");
btn_login.on('click', () => {
btn_login
.prop("disabled", true)
.empty()
.append($(document.createElement("i")).addClass("fa fa-circle-o-notch fa-spin"));
submitLogin($("#user").val(), $("#pass").val());
});
function submitLogin(user, pass) {
$.ajax({
url: "auth.php?type=login",
type: "POST",
cache: false,
data: {
user: user,
pass: pass
},
success: (result) => {
setTimeout(() => {
let data;
try {
data = JSON.parse(result);
}
catch (e) {
loginFailed("Invalid response: " + result);
return;
}
if (data["success"] == false) {
loginFailed(data["msg"]);
return;
}
if (data["allowed"] == false) {
loginFailed("You're not allowed for the closed alpha!");
return;
}
$("#login").hide(500);
$("#success").show(500);
document.cookie = data["sessionName"] + "=" + data["sessionId"] + ";path=/";
document.cookie = data["cookie_name_data"] + "=" + data["user_data"] + ";path=/";
document.cookie = data["cookie_name_sign"] + "=" + data["user_sign"] + ";path=/";
console.log(result);
setTimeout(() => {
window.location.href = btn_login.attr("target");
}, 1000 + Math.random() % 1500);
}, 500 + Math.random() % 500);
},
error: function (xhr, status, error) {
loginFailed("Invalid request (" + status + ") => " + error);
}
});
}
function loginFailed(err = "") {
btn_login
.prop("disabled", false)
.empty()
.append($(document.createElement("a")).text("Login"));
let errTag = $(".box .error");
if (err !== "") {
errTag.text(err).show(500);
}
else
errTag.hide(500);
}
//<i class="fa fa-circle-o-notch fa-spin" id="login-loader"></i>
$("#user").on('keydown', event => {
if (event.key == "Enter")
$("#pass").focus();
});
$("#pass").on('keydown', event => {
if (event.key == "Enter")
$("#btn_login").trigger("click");
});
//# sourceMappingURL=auth.js.map

20
client/css/main.css Normal file
View File

@ -0,0 +1,20 @@
html, body {
border: 0;
margin: 0; }
.app-container {
width: 100%;
height: 100%;
position: absolute;
width: 100%;
display: flex;
justify-content: center; }
.app-container .app {
width: 100%;
height: 100%;
margin: 0;
display: flex;
flex-direction: column;
resize: both; }
/*# sourceMappingURL=main.css.map */

21
client/css/main.scss Normal file
View File

@ -0,0 +1,21 @@
html, body {
border: 0;
margin: 0;
}
.app-container {
width: 100%;
height: 100%;
position: absolute;
width: 100%;
display: flex;
justify-content: center;
.app {
width: 100%;
height: 100%;
margin: 0;
display: flex; flex-direction: column; resize: both;
}
}

3
client/js/index.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
/* native functions declaration */
declare function displayCriticalError(message: string);

View File

@ -1,7 +0,0 @@
{
"version": 3,
"mappings": "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",
"sources": ["loader.scss"],
"names": [],
"file": "loader.css"
}

File diff suppressed because one or more lines are too long

View File

@ -1,7 +0,0 @@
{
"version": 3,
"mappings": "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",
"sources": ["info_plate.scss"],
"names": [],
"file": "info_plate.css"
}

View File

@ -1 +0,0 @@
../../auth/js/auth.js

View File

@ -1 +0,0 @@
../../generated/js/client.min.js

View File

@ -1 +0,0 @@
../../../js/codec/CompiledCodecWorker.js

View File

@ -1 +0,0 @@
../../js/load.js

View File

@ -1 +0,0 @@
../../../js/workers/WorkerCodec.js

304
files.php Normal file
View File

@ -0,0 +1,304 @@
<?php
$APP_FILE_LIST = [
[
"type" => "html",
"search-pattern" => "/^([a-zA-Z]+)\.html$/",
"path" => "./",
"local-path" => "./"
],
[
"type" => "js",
"search-pattern" => "/.*\.js$/",
"search-exclude" => "/(.*\/)?workers\/.*/",
"path" => "js/",
"local-path" => "./shared/js/"
],
[
"type" => "js",
"search-pattern" => "/WorkerCodec.js$/",
"path" => "js/workers/",
"local-path" => "./shared/js/workers/"
],
[
"type" => "css",
"search-pattern" => "/.*\.css$/",
"path" => "css/",
"local-path" => "./shared/css/"
],
[
"type" => "img",
"search-pattern" => "/.*\.(svg|png)/",
"path" => "img/",
"local-path" => "./shared/img/"
],
[
"type" => "wasm",
"search-pattern" => "/.*\.(wasm)/",
"path" => "wasm/",
"local-path" => "./asm/generated/"
],
[
"type" => "js",
"search-pattern" => "/.*\.(js)/",
"path" => "asm/generated/",
"local-path" => "./asm/generated/"
],
/* vendors */
[
"type" => "js",
"search-pattern" => "/.*\.js$/",
"path" => "vendor/",
"local-path" => "./vendor/"
],
[
"type" => "css",
"search-pattern" => "/.*\.css$/",
"path" => "vendor/",
"local-path" => "./vendor/"
],
/* client specs */
[
"client-only" => true,
"type" => "css",
"search-pattern" => "/.*\.css$/",
"path" => "css/",
"local-path" => "./client/css/"
],
/* web specs */
[
"web-only" => true,
"type" => "css",
"search-pattern" => "/.*\.css$/",
"path" => "css/",
"local-path" => "./web/css/"
],
[
"web-only" => true,
"type" => "html",
"search-pattern" => "/.*\.(php|html)/",
"path" => "./",
"local-path" => "./web/html/"
],
[
"web-only" => true,
"type" => "html",
"search-pattern" => "/.*\.(php|html)/",
"search-exclude" => "/(files.php)/",
"search-depth" => 1,
"path" => "./",
"local-path" => "./"
],
];
function list_dir($base_dir, $match = null, $depth = -1, &$results = array(), $dir = "") {
if($depth == 0) return $results;
$files = scandir($base_dir . $dir);
foreach($files as $key => $value){
$path = $base_dir.$dir.DIRECTORY_SEPARATOR.$value;
if(!is_dir($path)) {
if(!$match || preg_match($match, ($dir ? $dir.DIRECTORY_SEPARATOR : "").$value))
$results[] = ($dir ? $dir.DIRECTORY_SEPARATOR : "").$value;
} else if($value != "." && $value != "..") {
list_dir($base_dir, $match, $depth - 1, $results, ($dir ? $dir.DIRECTORY_SEPARATOR : "").$value);
}
}
return $results;
}
class AppFile {
public $type;
public $name;
public $path;
public $local_path;
public $hash;
}
function find_files($flag = 0b11) { //TODO Use cache here!
global $APP_FILE_LIST;
$result = [];
foreach ($APP_FILE_LIST as $entry) {
if(isset($entry["web-only"]) && $entry["web-only"] && ($flag & 0b01) == 0) continue;
if(isset($entry["client-only"]) && $entry["client-only"] && ($flag & 0b10) == 0) continue;
$entries = list_dir($entry["local-path"], $entry["search-pattern"], isset($entry["search-depth"]) ? $entry["search-depth"] : -1);
foreach ($entries as $f_entry) {
if(isset($entry["search-exclude"]) && preg_match($entry["search-exclude"], $f_entry)) continue;
$file = new AppFile;
$idx_sep = strrpos($f_entry, DIRECTORY_SEPARATOR);
$file->path = "./" . $entry["path"] . "/";
if($idx_sep > 0) {
$file->name = substr($f_entry, strrpos($f_entry, DIRECTORY_SEPARATOR) + 1);
$file->path = $file->path . substr($f_entry, 0, strrpos($f_entry, DIRECTORY_SEPARATOR));
} else {
$file->name = $f_entry;
}
$file->local_path = $entry["local-path"] . DIRECTORY_SEPARATOR . $f_entry;
$file->type = $entry["type"];
$file->hash = sha1_file($file->local_path);
if(strlen($file->hash) > 0) {
foreach ($result as $e)
if($e->hash == $file->hash) goto ignore;
}
array_push($result, $file);
ignore:
}
}
return $result;
}
function fdump($name) {
$file = fopen($name, "r") or die(json_encode([
"success" => false,
"error" => "missing file (" . $name . ")"
]));
echo (fread($file, filesize($name)));
fclose($file);
}
function handle_web_request() {
if($_GET["type"] === "files") {
header("Content-Type: text/plain");
header("info-version: 1");
echo ("type\thash\tpath\tname\n");
foreach (find_files(0b10) as $file) {
echo $file->type . "\t" . $file->hash . "\t" . $file->path . "\t" . $file->name . "\n";
}
echo "html\t".sha1("main")."\t.\tindex.html\n";
die;
} else if($_GET["type"] === "file") {
header("Content-Type: text/plain");
$available_files = find_files(0b10);
foreach ($available_files as $entry) {
if(($entry->path == $_GET["path"]) && ($entry->name == $_GET["name"])) {
fdump($entry->local_path);
die();
}
}
if($_GET["name"] == "index.html") {
$CLIENT = true;
include "./index.php";
die();
}
die(json_encode([
"success" => false,
"error" => "missing file!"
]));
} else die(json_encode([
"success" => false,
"error" => "invalid action!"
]));
}
if(isset($_SERVER['REQUEST_METHOD'])) {
handle_web_request();
die(); //Should never happen!
}
if(isset($_SERVER["argv"])) { //Executed by command line
if(strpos(PHP_OS, "Linux") == -1) {
error_log("Invalid operating system! Help tool only available under linux!");
exit(1);
}
if(count($_SERVER["argv"]) < 2) {
error_log("Invalid parameters!");
goto help;
}
if($_SERVER["argv"][1] == "help") {
help:
echo "php " . $_SERVER["argv"][0] . " <type> <args...>" . PHP_EOL;
echo " generate <web/client>" . PHP_EOL;
echo " list <web/client>" . PHP_EOL;
exit(1);
} else if($_SERVER["argv"][1] == "list") {
if(count($_SERVER["argv"]) < 3) {
error_log("Invalid parameter count!");
goto help;
}
echo ("type\thash\tpath\tname\n");
foreach (find_files(0b10) as $file) {
echo $file->type . "\t" . $file->hash . "\t" . $file->path . "\t" . $file->name . "\n";
}
echo "html\t".sha1("main")."\t.\tindex.html\n";
return;
} else if($_SERVER["argv"][1] == "generate") {
$state = 0;
$flagset = 0b00;
$environment = "";
if($_SERVER["argv"][2] == "web") {
$flagset = 0b01;
$environment = "web/environment";
} else if($_SERVER["argv"][2] == "client") {
$flagset = 0b10;
$environment = "client/environment";
} else {
error_log("Invalid type!");
goto help;
}
{
exec($command = "rm -r " . $environment, $output, $state);
exec($command = "mkdir " . $environment, $output, $state); if($state) goto handle_error;
$files = find_files(0b01);
if(!chdir($environment)) {
error_log("Failed to enter directory " . $environment . "!");
exit(1);
}
foreach($files as $file) {
if(!is_dir($file->path)) {
exec($command = "mkdir -p " . $file->path, $output, $state);
if($state) goto handle_error;
}
$parent = substr_count(realpath($file->path), DIRECTORY_SEPARATOR) - substr_count(realpath('.'), DIRECTORY_SEPARATOR);
$path = "../../";
for($index = 0; $index < $parent; $index++)
$path = $path . "../";
exec($command = "ln -s " . $path . $file->local_path . " " . $file->path, $output, $state);
if($state) goto handle_error;
echo $command . PHP_EOL;
}
echo "Generated!" . PHP_EOL;
}
exit(0);
handle_error:
error_log("Failed to execute command '" . $command . "'!");
error_log("Command returned code " . $state . ". Output: " . PHP_EOL);
foreach ($output as $line)
error_log($line);
exit(1);
}
}

172
index.php
View File

@ -1,7 +1,7 @@
<?php
$testXF = false;
$_INCLIDE_ONLY = true;
if (file_exists('auth.php'))
include_once('auth.php');
else if (file_exists('auth/auth.php'))
@ -29,11 +29,15 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<title>TeaSpeak-Web</title>
<?php
if(!isset($CLIENT) || !$CLIENT) {
if($CLIENT) {
echo "<title>TeaClient</title>";
} else {
echo "<title>TeaSpeak-Web</title>";
}
?>
<link rel="stylesheet" href="css/main.css" type="text/css">
<link rel="stylesheet" href="css/scroll.css" type="text/css">
<link rel="stylesheet" href="css/ts/tab.css" type="text/css">
<link rel="stylesheet" href="css/ts/chat.css" type="text/css">
@ -47,7 +51,6 @@
<link rel="stylesheet" href="css/control_bar.css" type="text/css">
<link rel="stylesheet" href="css/context_menu.css" type="text/css">
<link rel="stylesheet" href="vendor/bbcode/xbbcode.css" type="text/css">
<?php } ?>
<!-- https://localhost:9987/?forward_url=http%3A%2F%2Flocalhost%3A63344%2FWeb-Client%2Findex.php%3F_ijt%3D82b1uhmnh0a5l1n35nnjps5eid%26loader_ignore_age%3D1%26connect_default_host%3Dlocalhost%26default_connect_type%3Dforum%26default_connect_url%3Dtrue%26default_connect_type%3Dteamspeak%26default_connect_url%3Dlocalhost%253A9987 -->
<!-- PHP generated properies -->
<!-- localhost:63342/TeaSpeak-Web/index.php?_ijt=o48hmliefjoa8cer8v7mpl98pj&connect_default_host=192.168.43.141 -->
@ -86,8 +89,7 @@
</head>
<body>
<!-- No javascript error -->
<div style="display: block; position: fixed; top: 0px; bottom: 0px; left: 0px; right: 0px; background-color: gray; z-index: 1000; text-align: center;"
class="no-js">
<div style="display: block; position: fixed; top: 0px; bottom: 0px; left: 0px; right: 0px; background-color: gray; z-index: 1000; text-align: center;" class="no-js">
<div style="position: relative; display: inline-block; top: 30%">
<img src="img/script.svg" height="128px">
<h1>Please enable JavaScript</h1>
@ -96,7 +98,7 @@
</div>
</div>
<script type="text/javascript" class="no-js">
var elements = document.getElementsByClassName("no-js");
let elements = document.getElementsByClassName("no-js");
while (elements.length > 0) //Removing these elements (even self)
elements.item(0).remove();
</script>
@ -119,7 +121,7 @@
</div>
<!-- Critical load error -->
<div style="display: none; position: fixed; top: 0px; bottom: 0px; left: 0px; right: 0px; background-color: gray; z-index: 1000; text-align: center;"
<div style="display: none; position: fixed; top: 0; bottom: 0; left: 0; right: 0; background-color: gray; z-index: 1000; text-align: center;"
id="critical-load">
<div style="position: relative; display: inline-block; top: 30%">
<img src="img/script.svg" height="128px">
@ -128,157 +130,10 @@
</div>
</div>
<!-- -->
TeaSpeak-Web<br>
<div style="width: 100%; display: flex; justify-content: center">
<div style="width: 1200px; height: 900px; display: flex; flex-direction: column; resize: both; margin: 20px">
<!-- Container -->
<div style="height: 45px; width: 100%; border-radius: 2px 0px 0px 0px; border-bottom-width: 0px; background-color: lightgrey"
class="main_container">
<div id="control_bar" class="control_bar">
<div class="button btn_connect" title="Connect to a server">
<div class="icon_x32 client-connect"></div>
</div>
<div class="button btn_disconnect" title="Disconnect from server" style="display: none">
<div class="icon_x32 client-disconnect"></div>
</div>
<!--<div class="button btn_disconnect"><div class="icon_x32 client-disconnect"></div></div>-->
<div class="divider"></div>
<div class="button-dropdown btn_away" title="Toggle away status">
<div class="buttons">
<div class="button icon_x32 client-away btn_away_toggle"></div>
<div class="button-dropdown">
<div class="arrow"></div>
</div>
</div>
<div class="dropdown">
<div class="btn_away_toggle"><div class="icon client-away"></div><a>Toggle away status</a></div>vendor/jquery/jquery.min.js
<div class="btn_away_message"><div class="icon client-away"></div><a>Set away message</a></div>
</div>
</div>
<div class="button btn_mute_input">
<div class="icon_x32 client-input_muted" title="Mute/unmute microphone"></div>
</div>
<div class="button btn_mute_output">
<div class="icon_x32 client-output_muted" title="Mute/unmute headphones"></div>
</div>
<div class="divider"></div>
<div class="button-dropdown btn_token" title="Use token">
<div class="buttons">
<div class="button icon_x32 client-token btn_token_use"></div>
<div class="button-dropdown">
<div class="arrow"></div>
</div>
</div>
<div class="dropdown">
<div class="btn_token_list"><div class="icon client-token"></div><a>List tokens</a></div>
<div class="btn_token_use"><div class="icon client-token_use"></div><a>Use token</a></div>
</div>
</div>
<div style="width: 100%"></div>
<div class="button btn_permissions" title="View/edit permissions">
<div class="icon_x32 client-permission_overview"></div>
</div>
<div class="divider"></div>
<div class="button btn_open_settings" title="Edit global client settings">
<div class="icon_x32 client-settings"></div>
</div>
</div>
</div>
<div style="flex-direction: row; height: 100%; width: 100%; display: flex">
<div style="width: 60%; flex-direction: column;">
<div style="height: 60%; border-radius: 0px 0px 0px 0px; border-right-width: 0px; overflow: auto; overflow-x: visible"
class="main_container">
<div class="channelTree" id="channelTree"></div>
</div> <!-- Channel tree -->
<div style="height: 40%; border-radius: 0px 0px 0px 2px; border-top-width: 0px; border-right-width: 0px;"
class="main_container">
<div id="chat">
<div class="messages">
<div class="message_box"></div>
</div>
<div class="chats"></div>
<div class="input">
<!--<div contentEditable="true" class="input_box"></div>-->
<textarea class="input_box" title=""></textarea>
<button>Send</button>
</div>
</div>
</div> <!-- Chat window -->
</div>
<div style="width: 40%; border-radius: 0px 0px 2px 0px;" class="main_container">
<div id="select_info" class="select_info" style="width: 100%; max-width: 100%">
</div>
</div> <!-- Selection info -->
</div>
</div>
</div>
<div id="contextMenu" class="context-menu"></div>
<!--
<div style="background-color:white;">
<div style=" color: white; mix-blend-mode: difference;">And stay alive... XXXXXXX</div>
</div>
-->
<div id="templates"></div>
<div id="music-test"></div>
<div style="height: 100px"></div>
<script type="application/javascript">
/**
* @param path {string}
* @returns {Promise}
*/
function load_script0(path) {
if(window.require !== undefined) {
return new Promise((resolve, reject) => {
console.log("load via node %o %o", resolve, reject);
const ipcRenderer = require('electron').ipcRenderer;
ipcRenderer.send("load-file", "loaded-file-" + path, path);
ipcRenderer.once("loaded-file-" + path, (event, data) => {
if(data === '404') {
reject('script missing');
return;
}
const tag = document.createElement("script");
tag.type = "text\/javascript";
document.getElementById("scripts").appendChild(tag);
tag.src = URL.createObjectURL(new Blob([decodeURIComponent(data)], {type: "text/javascript"}));
resolve();
});
});
} else { //Normal web browser load
return new Promise((resolve, reject) => {
console.log("load via web %o %o", resolve, reject);
const tag = document.createElement("script");
tag.type = "text\/javascript";
tag.onerror = error => {
console.log(error);
tag.remove();
reject(error);
};
tag.onload = () => resolve();
document.getElementById("scripts").appendChild(tag);
tag.src = path;
});
}
}
if(window.require !== undefined) {
module.paths.push("/home/wolverindev/Development-WebApp/")
window.$ = require("jquery");
} else {
load_script0("vendor/jquery/jquery.min.js");
}
load_script0("load.js");
</script>
<div id="templates"></div>
</body>
<?php if(!$CLIENT) { ?>
<footer>
<div class="container" style="display: flex; flex-direction: row; align-content: space-between;">
<div style="align-self: center; position: fixed; left: 5px;">Open source on <a href="https://github.com/TeaSpeak/TeaSpeak-Web" style="display: inline-block; position: relative">github.com</a></div>
@ -296,4 +151,5 @@
</div>
</div>
</footer>
<?php } ?>
</html>

View File

@ -1,91 +0,0 @@
<?php
$APP_FILE_LIST = [ ];
$APP_FILE_ROOT = [
"js" => "../js/",
"css" => "../css/",
"vendor" => "../"
];
function list_dir($base_dir, $match = null, &$results = array(), $dir = "") {
$files = scandir($base_dir . $dir);
foreach($files as $key => $value){
$path = $base_dir.$dir.DIRECTORY_SEPARATOR.$value;
if(!is_dir($path)) {
if(!$match || preg_match($match, $path))
$results[] = ($dir ? $dir.DIRECTORY_SEPARATOR : "").$value;
} else if($value != "." && $value != "..") {
list_dir($base_dir, $match, $results, ($dir ? $dir.DIRECTORY_SEPARATOR : "").$value);
}
}
return $results;
}
function files_css() {
global $APP_FILE_ROOT;
return list_dir($APP_FILE_ROOT["css"], "/.*\.css$/");
}
function files_js() {
global $APP_FILE_ROOT;
return list_dir($APP_FILE_ROOT["js"], "/.*\.js$/");
}
function vendor() {
return ["vendor/jquery/jquery.min.js", "vendor/bbcode/xbbcode.js", "vendor/jsrender/jsrender.min.js", "asm/generated/TeaWeb-Identity.js"];
}
function fdump($name) {
$file = fopen($name, "r") or die(json_encode([
"success" => false,
"error" => "missing file (" . $name . ")"
]));
echo (fread($file, filesize($name)));
fclose($file);
}
error_log("XXX: ");
if($_GET["type"] === "files") {
header("Content-Type: text/plain");
header("info-version: 1");
foreach(files_js() as $file) {
echo $file . "\t" . sha1_file($APP_FILE_ROOT["js"] . DIRECTORY_SEPARATOR . $file) . "\n";
}
foreach(files_css() as $file) {
echo $file . "\t" . sha1_file($APP_FILE_ROOT["css"] . DIRECTORY_SEPARATOR . $file) . "\n";
}
foreach(vendor() as $file) {
echo $file . "\t" . sha1_file($APP_FILE_ROOT["vendor"] . DIRECTORY_SEPARATOR . $file) . "\n";
}
echo "main\t".sha1("main");
die;
} else if($_GET["type"] === "file") {
error_log("XXX: " . $_GET["name"]);
if($_GET["name"] == "main") {
global $CLIENT;
$CLIENT = true;
include("../index.php");
} else {
foreach(files_css() as $file) {
if($file == $_GET["name"]) {
fdump($APP_FILE_ROOT["css"] . $_GET["name"]); //FIXME test path!
die();
}
}
foreach(files_js() as $file) {
if($file == $_GET["name"]) {
fdump($APP_FILE_ROOT["js"] . $_GET["name"]); //FIXME test path!
die();
}
}
fdump('../' . $_GET["name"]); //FIXME remove this!
}
die();
} else die(json_encode([
"success" => false,
"error" => "invalid action!"
]));

View File

@ -1,30 +0,0 @@
{
"name": "client",
"version": "1.0.0",
"description": "Welcome here! This repository is created with two reasons:\n 1. People can bring their own ideas and follow their implementation\n 2. People can see TeaSpeak Web client progress and avoid creating repetitive issues all the time.",
"main": "main.js",
"directories": {
"test": "test"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"@types/node": "^9.4.6"
},
"dependencies": {
"@types/emscripten": "0.0.31",
"@types/jquery": "^3.3.0",
"@types/websocket": "0.0.38"
},
"repository": {
"type": "git",
"url": "git+https://github.com/TeaSpeak/TeaWeb/TeaWeb.git"
},
"bugs": {
"url": "https://github.com/TeaSpeak/TeaWeb/issues"
},
"homepage": "https://github.com/TeaSpeak/TeaWeb/TeaWeb#readme"
}

101
shared/css/context_menu.css Normal file
View File

@ -0,0 +1,101 @@
.context-menu {
overflow: visible;
display: none;
z-index: 1000;
position: absolute;
border: 1px solid #CCC;
white-space: nowrap;
font-family: sans-serif;
background: #FFF;
color: #333;
padding: 3px; }
.context-menu * {
font-family: Arial, serif;
font-size: 12px;
white-space: pre;
line-height: 1;
vertical-align: middle; }
.context-menu .entry {
/*padding: 8px 12px;*/
padding-right: 12px;
cursor: pointer;
list-style-type: none;
transition: all .3s ease;
user-select: none;
align-items: center;
display: flex; }
.context-menu .entry.disabled {
background-color: lightgray;
cursor: not-allowed; }
.context-menu .entry:hover:not(.disabled) {
background-color: #DEF; }
.context-menu .icon_empty, .context-menu .icon {
margin-right: 4px; }
.context-menu .arrow {
cursor: pointer;
pointer-events: all;
width: 7px;
height: 7px;
padding: 0;
margin-right: 5px;
margin-left: 5px;
position: absolute;
right: 3px; }
.context-menu .sub-container {
padding-right: 3px;
position: relative; }
.context-menu .sub-container:hover .sub-menu {
display: block; }
.context-menu .sub-menu {
display: none;
left: 100%;
top: -4px;
position: absolute;
margin-left: 3px; }
.context-menu .checkbox {
margin-top: 1px;
margin-left: 1px;
display: block;
position: relative;
padding-left: 14px;
margin-bottom: 12px;
cursor: pointer;
font-size: 22px;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
/* Hide the browser's default checkbox */ }
.context-menu .checkbox input {
position: absolute;
opacity: 0;
cursor: pointer;
display: none; }
.context-menu .checkbox .checkmark {
position: absolute;
top: 0;
left: 0;
height: 11px;
width: 11px;
background-color: #eee; }
.context-menu .checkbox .checkmark:after {
content: "";
position: absolute;
display: none;
left: 4px;
top: 1px;
width: 3px;
height: 7px;
border: solid white;
border-width: 0 2px 2px 0;
-webkit-transform: rotate(45deg);
-ms-transform: rotate(45deg);
transform: rotate(45deg); }
.context-menu .checkbox:hover input ~ .checkmark {
background-color: #ccc; }
.context-menu .checkbox input:checked ~ .checkmark {
background-color: #2196F3; }
.context-menu .checkbox input:checked ~ .checkmark:after {
display: block; }
/*# sourceMappingURL=context_menu.css.map */

View File

@ -0,0 +1,93 @@
.control_bar {
display: flex;
flex-direction: row; }
.control_bar .divider {
border-left: 2px solid gray;
height: auto;
margin-left: 5px;
margin-right: 5px; }
.control_bar .button {
cursor: pointer;
background-color: lightgray;
border-radius: 5px;
align-items: center;
border: 2px solid transparent;
height: 36px;
width: 36px;
margin-right: 5px;
margin-left: 5px; }
.control_bar .button:hover {
background-color: rgba(0, 0, 0, 0.4);
border-color: rgba(255, 255, 255, 0.75);
/*box-shadow: 0 12px 16px 0 rgba(0,0,0,0.24), 0 17px 50px 0 rgba(0,0,0,0.19);*/ }
.control_bar .button.activated {
background-color: rgba(0, 0, 0, 0.25);
border-color: rgba(255, 255, 255, 0.75); }
.control_bar .button.activated:hover {
background-color: rgba(0, 0, 0, 0.4);
border-color: rgba(255, 255, 255, 0.75); }
.control_bar .button-dropdown .buttons {
display: grid;
grid-template-columns: auto auto;
grid-template-rows: 100%;
grid-gap: 2px; }
.control_bar .button-dropdown .buttons .button {
margin-right: 0px; }
.control_bar .button-dropdown .buttons .button-dropdown {
display: inline-flex;
justify-content: space-around;
width: 18px;
cursor: pointer;
border-radius: 0 5px 5px 0;
align-items: center;
border: 2px solid transparent;
border-left: 0; }
.control_bar .button-dropdown .buttons .button-dropdown .arrow {
border: solid black;
border-width: 0 3px 3px 0;
display: inline-block;
padding: 3px;
transform: rotate(45deg);
-webkit-transform: rotate(45deg);
vertical-align: text-bottom; }
.control_bar .button-dropdown .buttons:hover .button {
border-right: 1px;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
background-color: rgba(0, 0, 0, 0.4);
border-color: rgba(255, 255, 255, 0.75);
/*box-shadow: 0 12px 16px 0 rgba(0,0,0,0.24), 0 17px 50px 0 rgba(0,0,0,0.19);*/ }
.control_bar .button-dropdown .buttons:hover .button-dropdown {
background-color: rgba(0, 0, 0, 0.4);
border-color: rgba(255, 255, 255, 0.75);
/*box-shadow: 0 12px 16px 0 rgba(0,0,0,0.24), 0 17px 50px 0 rgba(0,0,0,0.19);*/ }
.control_bar .button-dropdown .dropdown {
display: none;
position: absolute;
margin-left: 5px;
background-color: lightgray;
border-radius: 5px;
align-items: center;
border: 2px solid transparent;
border-color: rgba(255, 255, 255, 0.75);
width: 230px;
user-select: none;
z-index: 1000;
/*box-shadow: 0 12px 16px 0 rgba(0,0,0,0.24), 0 17px 50px 0 rgba(0,0,0,0.19);*/ }
.control_bar .button-dropdown .dropdown .icon {
vertical-align: middle;
margin-right: 5px; }
.control_bar .button-dropdown .dropdown > div {
display: block;
cursor: pointer;
padding: 1px 2px 1px 4px; }
.control_bar .button-dropdown .dropdown > div:hover {
background-color: rgba(0, 0, 0, 0.25); }
.control_bar .button-dropdown .dropdown > div:first-of-type {
border-radius: 2px 2px 0 0; }
.control_bar .button-dropdown .dropdown > div:last-of-type {
border-radius: 0 0 2px 2px; }
.control_bar .button-dropdown:hover .dropdown.displayed {
display: block; }
/*# sourceMappingURL=control_bar.css.map */

View File

Before

Width:  |  Height:  |  Size: 334 KiB

After

Width:  |  Height:  |  Size: 334 KiB

View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

Before

Width:  |  Height:  |  Size: 669 B

After

Width:  |  Height:  |  Size: 669 B

View File

Before

Width:  |  Height:  |  Size: 574 B

After

Width:  |  Height:  |  Size: 574 B

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

Before

Width:  |  Height:  |  Size: 653 B

After

Width:  |  Height:  |  Size: 653 B

View File

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

Before

Width:  |  Height:  |  Size: 19 KiB

After

Width:  |  Height:  |  Size: 19 KiB

View File

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 48 KiB

View File

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 75 KiB

View File

Before

Width:  |  Height:  |  Size: 87 KiB

After

Width:  |  Height:  |  Size: 87 KiB

View File

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 75 KiB

View File

@ -36,13 +36,13 @@ namespace app {
};
Module['onAbort'] = message => {
//Module['onAbort'] = undefined;
//displayCriticalError("Could not load webassembly files!<br>Message: <code>" + message + "</code>", false);
Module['onRuntimeInitialized'](); //FIXME! Just a bridge
Module['onAbort'] = undefined;
displayCriticalError("Could not load webassembly files!<br>Message: <code>" + message + "</code>", false);
};
Module['locateFile'] = file => {
console.log(file + "|" + type);
console.log("File path for " + file);
return "wasm/" + file;
switch (type) {
case Type.RELEASE:
return "js/assembly/" + file;
@ -59,22 +59,6 @@ namespace app {
}
}
/* safari remove "fix" */
Object.defineProperty(Element.prototype, "remove", {
enumerable: false,
configurable: false,
writable: false,
value: function(){
this.parentElement.removeChild(this);
}
});
if(typeof Module === "undefined")
this["Module"] = {};
app.initialize();
app.loadedListener.push(fadeoutLoader);
function loadScripts(paths: (string | string[])[]) : {path: string, promise: Promise<Boolean>}[] {
let result = [];
for(let path of paths)
@ -94,7 +78,18 @@ function loadScript(path: string | string[]) : Promise<Boolean> {
});
});
} else {
return load_script0(path);
return new Promise((resolve, reject) => {
const tag = document.createElement("script");
tag.type = "application/javascript";
tag.onerror = error => {
console.log(error);
tag.remove();
reject(error);
};
tag.onload = () => resolve();
document.getElementById("scripts").appendChild(tag);
tag.src = path;
});
}
}
@ -205,33 +200,21 @@ function awaitLoad(promises: {path: string, promise: Promise<Boolean>}[]) : Prom
if(error instanceof TypeError) {
console.error(error);
let name = (error as any).fileName + "@" + (error as any).lineNumber + ":" + (error as any).columnNumber;
displayCriticalError("Failed to execute script <code>" + name + "</code>.<hr>If you believe that it isn't you're mistake<br>then please contact an administrator!", false);
displayCriticalError("Failed to execute script <code>" + name + "</code>.<hr>If you believe that it isn't your mistake<br>then please contact an administrator!");
return;
} else {
console.error("Failed to load script " + entry.path);
}
displayCriticalError("Failed to load script " + formatPath(entry.path) + ".<hr>If you believe that it isn't you're mistake<br>then please contact an administrator!", false);
displayCriticalError("Failed to load script " + formatPath(entry.path) + ".<hr>If you believe that it isn't your mistake<br>then please contact an administrator!");
})
}
});
}
function displayCriticalError(message: string, closeable: boolean = true) {
if(typeof(createErrorModal) !== 'undefined') {
createErrorModal("A critical error occurred while loading the page!", message, {closeable: closeable}).open();
} else {
let tag = document.getElementById("critical-load");
let detail = tag.getElementsByClassName("detail")[0];
detail.innerHTML = message;
tag.style.display = "block";
}
fadeoutLoader();
}
function loadTemplates() {
//Load the templates
$.ajax("http://localhost/home/TeaSpeak/TeaSpeak/Web-Client/templates.html", {
$.ajax("templates.html", {
cache: false, //Change this when in release mode
}).then((element, status) => {
let node = document.createElement("html");
@ -243,35 +226,26 @@ function loadTemplates() {
tags = node.children;
let root = document.getElementById("templates");
while(tags.length > 0)
root.appendChild(tags.item(0));
while(tags.length > 0){
let tag = tags.item(0);
if(tag.id == "tmpl_main")
document.getElementsByTagName("body").item(0).appendChild(tag);
else
root.appendChild(tag);
}
/*
root = document.getElementById("script");
while(tags.length > 0)
root.appendChild(tags.item(0));
*/
}).catch(error => {
console.error("Could not load templates!");
console.log(error);
displayCriticalError("Could not load HTML templates!", false);
displayCriticalError("Could not load HTML templates!");
});
}
navigator.browserSpecs = (function(){
let ua = navigator.userAgent, tem, M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
if(/trident/i.test(M[1])){
tem = /\brv[ :]+(\d+)/g.exec(ua) || [];
return {name:'IE',version:(tem[1] || '')};
}
if(M[1]=== 'Chrome'){
tem = ua.match(/\b(OPR|Edge)\/(\d+)/);
if(tem != null) return {name:tem[1].replace('OPR', 'Opera'),version:tem[2]};
}
M = M[2]? [M[1], M[2]]: [navigator.appName, navigator.appVersion, '-?'];
if((tem = ua.match(/version\/(\d+)/i))!= null)
M.splice(1, 1, tem[1]);
return {name:M[0], version:M[1]};
})();
console.log(navigator.browserSpecs); //Object { name: "Firefox", version: "42" }
//TODO release config!
function loadSide() {
if(typeof (WebAssembly) === "undefined" || typeof (WebAssembly.compile) === "undefined") {
@ -288,12 +262,18 @@ function loadSide() {
displayCriticalError("You require WebAssembly for TeaSpeak-Web!");
return;
}
if(window.require !== undefined) {
const app = require('electron').remote.app;
module.paths.push(app.getAppPath());
window.$ = require("jquery");
}
//Load the general scripts and required scripts
awaitLoad(loadScripts([
//["vendor/jquery/jquery.min.js", /*"https://code.jquery.com/jquery-latest.min.js"*/],
["vendor/jquery/jquery.min.js", /*"https://code.jquery.com/jquery-latest.min.js"*/],
["vendor/bbcode/xbbcode.js"],
["https://webrtc.github.io/adapter/adapter-latest.js"]
])).then(() => awaitLoad(loadScripts([
])).then(() => {
}).then(() => awaitLoad(loadScripts([
//["https://ajax.microsoft.com/ajax/jquery.templates/beta1/jquery.tmpl.min.js"]
["vendor/jsrender/jsrender.min.js"]
]))).then(() => {
@ -304,8 +284,6 @@ function loadSide() {
});
}
loadSide();
//FUN: loader_ignore_age=0&loader_default_duration=1500&loader_default_age=5000
function fadeoutLoader(duration = undefined, minAge = undefined, ignoreAge = undefined) {
let settingsDefined = typeof(StaticSettings) !== "undefined";
@ -334,4 +312,54 @@ function fadeoutLoader(duration = undefined, minAge = undefined, ignoreAge = und
$(".loader .half").animate({width: 0}, duration, () => {
$(".loader").detach();
});
}
}
/* safari remove "fix" */
if(Element.prototype.remove === undefined)
Object.defineProperty(Element.prototype, "remove", {
enumerable: false,
configurable: false,
writable: false,
value: function(){
this.parentElement.removeChild(this);
}
});
if(typeof Module === "undefined")
this["Module"] = {};
app.initialize();
app.loadedListener.push(fadeoutLoader);
if(!window.displayCriticalError) {
window.displayCriticalError = function(message: string) {
if(typeof(createErrorModal) !== 'undefined') {
createErrorModal("A critical error occurred while loading the page!", message, {closeable: false}).open();
} else {
let tag = document.getElementById("critical-load");
let detail = tag.getElementsByClassName("detail")[0];
detail.innerHTML = message;
tag.style.display = "block";
}
fadeoutLoader();
}
}
navigator.browserSpecs = (function(){
let ua = navigator.userAgent, tem, M = ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
if(/trident/i.test(M[1])){
tem = /\brv[ :]+(\d+)/g.exec(ua) || [];
return {name:'IE',version:(tem[1] || '')};
}
if(M[1]=== 'Chrome'){
tem = ua.match(/\b(OPR|Edge)\/(\d+)/);
if(tem != null) return {name:tem[1].replace('OPR', 'Opera'),version:tem[2]};
}
M = M[2]? [M[1], M[2]]: [navigator.appName, navigator.appVersion, '-?'];
if((tem = ua.match(/version\/(\d+)/i))!= null)
M.splice(1, 1, tem[1]);
return {name:M[0], version:M[1]};
})();
console.log(navigator.browserSpecs); //Object { name: "Firefox", version: "42" }
loadSide();

View File

@ -16,9 +16,15 @@ let chat: ChatBox;
let forumIdentity: TeaForumIdentity;
const js_render = window.jsrender || $;
function main() {
$.views.settings.allowCode(true);
$.views.tags("rnd", (argument) => {
if(!js_render) {
displayCriticalError("Missing jsrender extension!");
return;
}
js_render.views.settings.allowCode(true);
js_render.views.tags("rnd", (argument) => {
let min = parseInt(argument.substr(0, argument.indexOf('~')));
let max = parseInt(argument.substr(argument.indexOf('~') + 1));

View File

@ -108,7 +108,14 @@ if(typeof ($) !== "undefined") {
}
if(!$.prototype.renderTag) {
$.prototype.renderTag = function (values?: any) : JQuery {
let result = $(this.render(values));
let result;
if(this.render) {
result = $(this.render(values));
} else {
result = window.jsrender.templates("xxx", this.html())
result = window.jsrender.render["xxx"](values);
result = $(result);
}
result.find("node").each((index, element) => {
$(element).replaceWith(values[$(element).attr("key")] || values[0][$(element).attr("key")]);
});

Some files were not shown because too many files have changed in this diff Show More