forked from olcxjas-softworks/LarpixClient
Compatibility tweaks
- Fix (i hope all) electron issues - Add complete blah support - Add userscript
This commit is contained in:
parent
588d55abf8
commit
7ff648ba3a
19 changed files with 478 additions and 576 deletions
40
android/app/src/main/assets/public/blah/en-us.json
Normal file
40
android/app/src/main/assets/public/blah/en-us.json
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
{
|
||||||
|
"user.not.found": "User not found",
|
||||||
|
"cant.invite.urself": "You can't invite yourself",
|
||||||
|
"user.already.invited": "You have already invited this user",
|
||||||
|
"user.invited": "User invited successfully",
|
||||||
|
"cant.create.dm.without.invitation": "You can't create a dm without invitation",
|
||||||
|
"dm.begin.notice": "At the beginning of a DM, you should always verify that the person you're talking to is the intended recipient",
|
||||||
|
"failed.accept.dm": "Failed to accept DM",
|
||||||
|
"dm.accepted": "DM accepted",
|
||||||
|
"no.invite.found": "You can't create a dm without invitation",
|
||||||
|
"unknown.error": "Unknown error",
|
||||||
|
"account.creation.request.expired": "Account creation request expired. Try again",
|
||||||
|
"invalid.username": "Invalid username: {0}",
|
||||||
|
"invalid.password": "Invalid password: {0}",
|
||||||
|
"incorrect.captcha": "Incorrect captcha. Try again",
|
||||||
|
"username.taken": "This username is already taken",
|
||||||
|
"accounts.slots.full": "You can't create a new account because all ids are used. Try again later",
|
||||||
|
"registration.disabled": "Registration disabled",
|
||||||
|
"account.created": "Account created successfully",
|
||||||
|
"password.changed": "Password changed successfully",
|
||||||
|
"keys.updated": "Keys updated successfully",
|
||||||
|
"unknown.request": "Unknown request: {0}",
|
||||||
|
"login.successful": "Login successful",
|
||||||
|
"username.length": "Username must be {0} characters long",
|
||||||
|
"username.conditions.allowed": "Username can only include {all}",
|
||||||
|
"password.not.hashed.properly": "Password is not hashed properly",
|
||||||
|
"invalid.username.or.password": "Invalid username or password",
|
||||||
|
"account.not.exist": "Account with this name doesn't exist",
|
||||||
|
"invalid.nonce": "Invalid nonce. Try again",
|
||||||
|
"username.changed": "Username changed successfully",
|
||||||
|
"auth.failed.redirect.to.login": "Failed to auth. Redirecting to login...",
|
||||||
|
"dm.refresh.failed": "Failed to refresh dms",
|
||||||
|
"chat.add.failed": "Failed to add chat",
|
||||||
|
"something.wrong.mayb.pass": "Something went wrong... (probably wrong password)",
|
||||||
|
"something.wrong": "Something went wrong...",
|
||||||
|
"passwords.not.match": "Passwords do not match",
|
||||||
|
"password.cant.empty": "Password cannot be empty",
|
||||||
|
"username.cant.empty": "Username cannot be empty",
|
||||||
|
"bad.request": "Bad request"
|
||||||
|
}
|
||||||
|
|
@ -84,14 +84,14 @@
|
||||||
Splash
|
Splash
|
||||||
</roomtopbar>
|
</roomtopbar>
|
||||||
<roomcontent2>
|
<roomcontent2>
|
||||||
<div style="display: flex;justify-content: center;align-items: center;height:100%;flex-direction: column;">
|
<div style="display: flex;justify-content: center;align-items: center;height:100%;flex-direction: column;text-align: center;">
|
||||||
<img src="favicon.svg" style="width: 6rem">
|
<img src="favicon.svg" style="width: 6rem">
|
||||||
<herotitle>Welcome to Miarven</herotitle>
|
<herotitle>Welcome to Miarven</herotitle>
|
||||||
<p>First Larpix client. <span class="aqua">v<span class="clientver aqua">1.0</span></span></p>
|
<p>First Larpix client. <span class="aqua">v<span class="clientver aqua">1.0</span></span></p>
|
||||||
</div>
|
</div>
|
||||||
</roomcontent2>
|
</roomcontent2>
|
||||||
</roomcontent>
|
</roomcontent>
|
||||||
<sidebar class="second hidden" id="roomdetailsbar" style="display: none;">
|
<sidebar class="second" id="roomdetailsbar" style="display: none;">
|
||||||
</sidebar>
|
</sidebar>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
@ -100,21 +100,28 @@
|
||||||
<script>
|
<script>
|
||||||
async function start() {
|
async function start() {
|
||||||
try {
|
try {
|
||||||
|
if (host != null)
|
||||||
|
{
|
||||||
|
await updateProtocolAndUrl(host);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await updateProtocolAndUrl(window.location.hostname);
|
||||||
|
}
|
||||||
|
|
||||||
showAction("Authenticating...", "startauth");
|
showAction("Authenticating...", "startauth");
|
||||||
let res = await Auth(username, password);
|
let res = await Auth(username, password);
|
||||||
clearAction("startauth");
|
clearAction("startauth");
|
||||||
if (res == "Login successful") {
|
if (res.startsWith("success:")) {
|
||||||
await refreshDms();
|
await refreshDms();
|
||||||
} else {
|
} else {
|
||||||
showNotification("Failed to auth. Redirecting to login...", "error", 3500);
|
showBlahNotification("error:auth.failed.redirect.to.login");
|
||||||
await delay(2000);
|
await delay(2000);
|
||||||
window.location.href = "login/index.html";
|
window.location.href = "login/index.html";
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
clearAction("startauth");
|
clearAction("startauth");
|
||||||
showNotification("Failed to auth. Redirecting to login...", "error", 3500);
|
showBlahNotification("error:auth.failed.redirect.to.login");
|
||||||
await delay(2000);
|
await delay(2000);
|
||||||
window.location.href = "login/index.html";
|
window.location.href = "login/index.html";
|
||||||
}
|
}
|
||||||
|
|
@ -131,9 +138,27 @@
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
clearAction("dmrefresh");
|
clearAction("dmrefresh");
|
||||||
showNotification("Failed to refresh dms", "error", 3500);
|
showBlahNotification("error:dm.refresh.failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function addDm() {
|
||||||
|
try {
|
||||||
|
showAction("Adding...", "dmadd");
|
||||||
|
let res = await fetchEncrypted("user/dm/invite", document.getElementById("addchat-username").value);
|
||||||
|
console.log(res);
|
||||||
|
let ressplit = res.split(":");
|
||||||
|
clearAction("dmadd");
|
||||||
|
showBlahNotification(res);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
console.log(e);
|
||||||
|
clearAction("dmadd");
|
||||||
|
showBlahNotification("error:chat.add.failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
start();
|
start();
|
||||||
</script>
|
</script>
|
||||||
|
<script src="userscript.js"></script>
|
||||||
|
|
@ -264,11 +264,10 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
<script src="../main.js"></script>
|
<script src="../main.js"></script>
|
||||||
<script>
|
<script>
|
||||||
document.getElementById("reg-host").value = window.location.hostname;
|
|
||||||
document.getElementById("login-host").value = window.location.hostname;
|
|
||||||
|
|
||||||
const container = document.getElementById('auth-container');
|
const container = document.getElementById('auth-container');
|
||||||
|
|
||||||
|
|
@ -311,13 +310,12 @@
|
||||||
formLogin.addEventListener('submit', async (e) => {
|
formLogin.addEventListener('submit', async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
try {
|
try {
|
||||||
url = `${window.location.protocol}//${loginHost.value}/_larpix`;
|
|
||||||
|
|
||||||
let res = await Auth(loginUsername.value, loginPassword.value);
|
let res = await Auth(loginUsername.value, loginPassword.value);
|
||||||
|
|
||||||
if (res == "Login successful")
|
if (res.startsWith("success:"))
|
||||||
{
|
{
|
||||||
showNotification(res, "success", 3500);
|
showBlahNotification(res);
|
||||||
await delay(1000);
|
await delay(1000);
|
||||||
localStorage.setItem("username", loginUsername.value);
|
localStorage.setItem("username", loginUsername.value);
|
||||||
localStorage.setItem("password", loginPassword.value);
|
localStorage.setItem("password", loginPassword.value);
|
||||||
|
|
@ -327,12 +325,12 @@
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
showNotification(res, "error", 3500);
|
showBlahNotification(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
showNotification("Something went wrong... (probably wrong password)", "error", 3500);
|
showBlahNotification("error:something.wrong.mayb.pass");
|
||||||
container.className = 'auth-container';
|
container.className = 'auth-container';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -343,20 +341,20 @@
|
||||||
captchaCode.value = "";
|
captchaCode.value = "";
|
||||||
regKeyInput.value = "";
|
regKeyInput.value = "";
|
||||||
|
|
||||||
url = `${window.location.protocol}//${registerHost.value}/_larpix`;
|
|
||||||
|
|
||||||
if (!registerUsername.value || registerUsername.value.trim() === '') {
|
if (!registerUsername.value || registerUsername.value.trim() === '') {
|
||||||
showNotification("Username cannot be empty", "error");
|
showBlahNotification("error:username.cant.empty");
|
||||||
container.className = 'auth-container show-register';
|
container.className = 'auth-container show-register';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!registerPassword.value || registerPassword.value.trim() === '') {
|
if (!registerPassword.value || registerPassword.value.trim() === '') {
|
||||||
showNotification("Password cannot be empty", "error");
|
showBlahNotification("error:password.cant.empty");
|
||||||
container.className = 'auth-container show-register';
|
container.className = 'auth-container show-register';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (registerPassword.value != registerPasswordConfirm.value) {
|
if (registerPassword.value != registerPasswordConfirm.value) {
|
||||||
showNotification("Passwords do not match", "error");
|
showBlahNotification("error:passwords.not.match");
|
||||||
container.className = 'auth-container show-register';
|
container.className = 'auth-container show-register';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -388,13 +386,13 @@
|
||||||
if (res.length > 64 || res.length <= 1) {
|
if (res.length > 64 || res.length <= 1) {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
showNotification(res, "error", 3500);
|
showBlahNotification(res);
|
||||||
container.className = 'auth-container show-register';
|
container.className = 'auth-container show-register';
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
showNotification("Something went wrong...", "error", 3500);
|
showBlahNotification("error:something.wrong");
|
||||||
container.className = 'auth-container show-register';
|
container.className = 'auth-container show-register';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -414,11 +412,8 @@
|
||||||
if (res.length > 64 || res.length <= 1) {
|
if (res.length > 64 || res.length <= 1) {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
if (res.toLowerCase().includes("incorrect")) {
|
if (res.startsWith("success")) {
|
||||||
showNotification(res, "error", 3500);
|
showBlahNotification(res);
|
||||||
container.className = 'auth-container show-register';
|
|
||||||
} else if (res.toLowerCase().includes("created")) {
|
|
||||||
showNotification(res, "success", 3500);
|
|
||||||
await delay(1000);
|
await delay(1000);
|
||||||
localStorage.setItem("username", registerUsername.value);
|
localStorage.setItem("username", registerUsername.value);
|
||||||
localStorage.setItem("password", registerPassword.value);
|
localStorage.setItem("password", registerPassword.value);
|
||||||
|
|
@ -427,12 +422,12 @@
|
||||||
window.location.href = "../";
|
window.location.href = "../";
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
showNotification(res, "info", 3500);
|
showBlahNotification(res);
|
||||||
container.className = 'auth-container show-register';
|
container.className = 'auth-container show-register';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showNotification("Something went wrong...", "error", 3500);
|
showBlahNotification("error:something.wrong");
|
||||||
container.className = 'auth-container show-register';
|
container.className = 'auth-container show-register';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -450,6 +445,7 @@
|
||||||
async function updateLoginForm(host)
|
async function updateLoginForm(host)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
await updateProtocolAndUrl(host);
|
||||||
let serverInfo = await getServerInfo(host);
|
let serverInfo = await getServerInfo(host);
|
||||||
if (serverInfo["registration"] == "disabled")
|
if (serverInfo["registration"] == "disabled")
|
||||||
{
|
{
|
||||||
|
|
@ -484,5 +480,4 @@
|
||||||
|
|
||||||
loginHostChanged();
|
loginHostChanged();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
<script src="../userscript.js"></script>
|
||||||
</html>
|
|
||||||
|
|
@ -1,36 +1,62 @@
|
||||||
console.log(window.location.protocol);
|
var prot = window.location.protocol;
|
||||||
|
|
||||||
var url = `${window.location.protocol}//${window.location.hostname}/_larpix`;
|
async function updateProtocolAndUrl(host)
|
||||||
|
{
|
||||||
|
prot = window.location.protocol == "miarven:" ? "http:" : window.location.protocol;
|
||||||
|
if (prot == "http:") {
|
||||||
|
try {
|
||||||
|
JSON.parse(await fetchAsync(`${prot}//${host}/_larpix/serverinfo`));
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
try {
|
||||||
|
JSON.parse(await fetchAsync(`https://${host}/_larpix/serverinfo`));
|
||||||
|
prot = "https:";
|
||||||
|
}
|
||||||
|
catch (error) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
url = `${prot}//${host}/_larpix`;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(prot);
|
||||||
|
|
||||||
|
var url = `${prot}//${window.location.hostname}/_larpix`;
|
||||||
var params = new URLSearchParams(window.location.search);
|
var params = new URLSearchParams(window.location.search);
|
||||||
|
|
||||||
const collapseDmsBtn = document.getElementById("collapse-dms");
|
try {
|
||||||
const collapseGroupsBtn = document.getElementById("collapse-groups");
|
|
||||||
|
|
||||||
const addDmBtn = document.getElementById("add-dm-btn");
|
|
||||||
const addGroupBtn = document.getElementById("add-group-btn");
|
|
||||||
|
|
||||||
const sidebarHome = document.getElementById("sidebar-home");
|
var collapseDmsBtn = document.getElementById("collapse-dms");
|
||||||
const sidebarHomeButton = sidebarHome.children.item(1);
|
var collapseGroupsBtn = document.getElementById("collapse-groups");
|
||||||
const sidebarHomeIndicator = sidebarHome.children.item(0);
|
|
||||||
|
|
||||||
const sidebarAdd = document.getElementById("sidebar-add");
|
var addDmBtn = document.getElementById("add-dm-btn");
|
||||||
const sidebarAddButton = sidebarAdd.children.item(1);
|
var addGroupBtn = document.getElementById("add-group-btn");
|
||||||
const sidebarAddIndicator = sidebarAdd.children.item(0);
|
|
||||||
|
|
||||||
const roomDetailsBar = document.getElementById("roomdetailsbar");
|
var sidebarHome = document.getElementById("sidebar-home");
|
||||||
const roomContent = document.getElementsByTagName("roomcontent")[0];
|
var sidebarHomeButton = sidebarHome.children.item(1);
|
||||||
const roomsBar = document.getElementById("roomsbar");
|
var sidebarHomeIndicator = sidebarHome.children.item(0);
|
||||||
const sideBar = document.getElementsByTagName("sidebar")[0];
|
|
||||||
|
|
||||||
const roomContentMain = document.getElementsByTagName("roomcontent2")[0];
|
var sidebarAdd = document.getElementById("sidebar-add");
|
||||||
|
var sidebarAddButton = sidebarAdd.children.item(1);
|
||||||
|
var sidebarAddIndicator = sidebarAdd.children.item(0);
|
||||||
|
|
||||||
const roomContentBar = roomContent.children[0];
|
var roomDetailsBar = document.getElementById("roomdetailsbar");
|
||||||
|
var roomContent = document.getElementsByTagName("roomcontent")[0];
|
||||||
|
var roomsBar = document.getElementById("roomsbar");
|
||||||
|
var sideBar = document.getElementsByTagName("sidebar")[0];
|
||||||
|
|
||||||
|
var roomContentMain = document.getElementsByTagName("roomcontent2")[0];
|
||||||
|
|
||||||
|
var roomContentBar = roomContent.children[0];
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function delay(time) {
|
function delay(time) {
|
||||||
return new Promise(resolve => setTimeout(resolve, time));
|
return new Promise(resolve => setTimeout(resolve, time));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function packetEncPass(pass, key, username) {
|
async function packetEncPass(pass, key, username) {
|
||||||
return await encryptWithNonce(pass, key, getNonce(username, key));
|
return await encryptWithNonce(pass, key, getNonce(username, key));
|
||||||
}
|
}
|
||||||
|
|
@ -42,8 +68,7 @@ async function getNonce(username, key) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
nonce = await decryptString(fetchRes, key);
|
nonce = await decryptString(fetchRes, key);
|
||||||
}
|
} catch (err) {
|
||||||
catch(err) {
|
|
||||||
nonce = await decryptString(fetchRes, "");
|
nonce = await decryptString(fetchRes, "");
|
||||||
}
|
}
|
||||||
return nonce;
|
return nonce;
|
||||||
|
|
@ -86,6 +111,7 @@ function keyDataFromServerJson(jsonFromServer) {
|
||||||
function base64ToUint8(base64) {
|
function base64ToUint8(base64) {
|
||||||
return Uint8Array.from(atob(base64), c => c.charCodeAt(0));
|
return Uint8Array.from(atob(base64), c => c.charCodeAt(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
function uint8ToBase64(uint8) {
|
function uint8ToBase64(uint8) {
|
||||||
return fixBase64Padding(btoa(String.fromCharCode(...uint8)));
|
return fixBase64Padding(btoa(String.fromCharCode(...uint8)));
|
||||||
}
|
}
|
||||||
|
|
@ -263,13 +289,11 @@ async function fetchAsyncWAuth(url) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getServerInfo(host) {
|
async function getServerInfo(host) {
|
||||||
console.log(`${window.location.protocol}//${host}/_larpix/serverinfo`)
|
console.log(`${prot}//${host}/_larpix/serverinfo`)
|
||||||
return JSON.parse(await fetchAsync(`${window.location.protocol}//${host}/_larpix/serverinfo`));
|
return JSON.parse(await fetchAsync(`${prot}//${host}/_larpix/serverinfo`));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function Auth(username, password) {
|
async function Auth(username, password) {
|
||||||
|
|
||||||
|
|
||||||
let passwordHash = await hashSHA3_512(password);
|
let passwordHash = await hashSHA3_512(password);
|
||||||
let response = await fetch(`${url}/auth?u=${username}`, {
|
let response = await fetch(`${url}/auth?u=${username}`, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
|
|
@ -285,8 +309,7 @@ async function Auth(username, password) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function fetchEncrypted(request, body)
|
async function fetchEncrypted(request, body) {
|
||||||
{
|
|
||||||
|
|
||||||
let nonce = await getNonce(username, passwordHash);
|
let nonce = await getNonce(username, passwordHash);
|
||||||
|
|
||||||
|
|
@ -294,7 +317,6 @@ async function fetchEncrypted(request, body)
|
||||||
method: "POST",
|
method: "POST",
|
||||||
credentials: "omit",
|
credentials: "omit",
|
||||||
body: await encryptWithNonce(
|
body: await encryptWithNonce(
|
||||||
|
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
string1: request,
|
string1: request,
|
||||||
string2: body
|
string2: body
|
||||||
|
|
@ -334,6 +356,15 @@ function fixBase64Padding(base64String) {
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showBlahNotification(blahmessage, duration = 3500) {
|
||||||
|
try {
|
||||||
|
let split = blahmessage.split(":");
|
||||||
|
showNotification(processBlah(blahmessage), split[0], duration);
|
||||||
|
} catch (e) {
|
||||||
|
showNotification(blahmessage, "info", duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function showNotification(message, type = 'info', duration = 3500) {
|
function showNotification(message, type = 'info', duration = 3500) {
|
||||||
let container = document.getElementById('notification-container');
|
let container = document.getElementById('notification-container');
|
||||||
if (!container) {
|
if (!container) {
|
||||||
|
|
@ -385,13 +416,16 @@ function showAction(message, actionid) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function clearAction(actionid) {
|
|
||||||
|
|
||||||
let notif = document.getElementById(`notification-${actionid}`);
|
function clearAction(actionid) {
|
||||||
|
const notifications = document.querySelectorAll(`[id="notification-${actionid}"]`);
|
||||||
|
|
||||||
|
notifications.forEach(notif => {
|
||||||
notif.classList.remove('show');
|
notif.classList.remove('show');
|
||||||
|
|
||||||
notif.addEventListener('transitionend', () => {
|
notif.addEventListener('transitionend', () => {
|
||||||
notif.remove();
|
notif.remove();
|
||||||
|
}, { once: true });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -405,20 +439,76 @@ async function hashSHA3_512(input) {
|
||||||
return hashHex;
|
return hashHex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var blah;
|
||||||
|
|
||||||
|
async function initBlahs() {
|
||||||
|
lang = lang.toLowerCase();
|
||||||
|
let res;
|
||||||
|
|
||||||
|
let path = window.location.pathname.replace("/login/index.html", "/");
|
||||||
|
|
||||||
|
try { //try user lang first
|
||||||
|
res = await fetchAsync(`${path}blah/${lang}.json`);
|
||||||
|
} catch (e) { //fallback to en-us
|
||||||
|
res = await fetchAsync(`${path}blah/en-us.json`);
|
||||||
|
}
|
||||||
|
blah = JSON.parse(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
function processBlah(blahmessage) {
|
||||||
|
try {
|
||||||
|
let split = blahmessage.split(":");
|
||||||
|
let values = [];
|
||||||
|
try {
|
||||||
|
values = split[2].split(";");
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
let message = blah[split[1]];
|
||||||
|
|
||||||
|
let valueslist = "";
|
||||||
|
for (let i = 0; i < values.length; i++) {
|
||||||
|
let value = values[i];
|
||||||
|
valueslist+=`${values[i]}, `;
|
||||||
|
processBlah(value);
|
||||||
|
|
||||||
|
message = message.replaceAll(`{${i}}`, value);
|
||||||
|
}
|
||||||
|
valueslist = valueslist.slice(0, -2);
|
||||||
|
if (message.includes('{all}')) {
|
||||||
|
|
||||||
|
message = message.replaceAll('{all}', valueslist);
|
||||||
|
}
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
catch (e)
|
||||||
|
{
|
||||||
|
return blahmessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLang() {
|
||||||
|
return (navigator.language || navigator.languages[0]);
|
||||||
|
}
|
||||||
|
|
||||||
var password = "";
|
var password = "";
|
||||||
var username = "";
|
var username = "";
|
||||||
var passwordHash = "";
|
var passwordHash = "";
|
||||||
var host = "";
|
var host = "";
|
||||||
async function mainJS()
|
var lang = getLang();
|
||||||
{
|
|
||||||
|
async function mainJS() {
|
||||||
|
await initBlahs();
|
||||||
|
|
||||||
|
passwordHash = await hashSHA3_512(password);
|
||||||
|
if (localStorage.getItem('lang') != null) {
|
||||||
|
lang = localStorage.getItem('lang');
|
||||||
|
}
|
||||||
|
}
|
||||||
username = localStorage.getItem('username');
|
username = localStorage.getItem('username');
|
||||||
password = localStorage.getItem('password');
|
password = localStorage.getItem('password');
|
||||||
host = localStorage.getItem('host');
|
host = localStorage.getItem('host');
|
||||||
passwordHash = await hashSHA3_512(password);
|
|
||||||
url = `${window.location.protocol}//${host}/_larpix`;
|
|
||||||
}
|
|
||||||
mainJS();
|
mainJS();
|
||||||
|
|
||||||
collapseDmsBtn.addEventListener("click", () => {
|
collapseDmsBtn.addEventListener("click", () => {
|
||||||
|
|
@ -431,7 +521,7 @@ collapseGroupsBtn.addEventListener("click", () => {
|
||||||
addDmBtn.addEventListener("click", () => {
|
addDmBtn.addEventListener("click", () => {
|
||||||
roomContentMain.innerHTML =
|
roomContentMain.innerHTML =
|
||||||
`
|
`
|
||||||
<div style="display: flex;justify-content: center;align-items: center;height:100%;flex-direction: column;">
|
<div style="display: flex;justify-content: center;align-items: center;height:100%;flex-direction: column;text-align: center;">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="3rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M120-160v-600q0-33 23.5-56.5T200-840h480q33 0 56.5 23.5T760-760v203q-10-2-20-2.5t-20-.5q-10 0-20 .5t-20 2.5v-203H200v400h283q-2 10-2.5 20t-.5 20q0 10 .5 20t2.5 20H240L120-160Zm160-440h320v-80H280v80Zm0 160h200v-80H280v80Zm400 280v-120H560v-80h120v-120h80v120h120v80H760v120h-80ZM200-360v-400 400Z"/></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" width="3rem" viewBox="0 -960 960 960" fill="var(--text-color)"><path d="M120-160v-600q0-33 23.5-56.5T200-840h480q33 0 56.5 23.5T760-760v203q-10-2-20-2.5t-20-.5q-10 0-20 .5t-20 2.5v-203H200v400h283q-2 10-2.5 20t-.5 20q0 10 .5 20t2.5 20H240L120-160Zm160-440h320v-80H280v80Zm0 160h200v-80H280v80Zm400 280v-120H560v-80h120v-120h80v120h120v80H760v120h-80ZM200-360v-400 400Z"/></svg>
|
||||||
<herotitle>Add Chat</herotitle>
|
<herotitle>Add Chat</herotitle>
|
||||||
<p>Add a private, encrypted chat by entering a username</p>
|
<p>Add a private, encrypted chat by entering a username</p>
|
||||||
|
|
@ -441,7 +531,7 @@ addDmBtn.addEventListener("click", () => {
|
||||||
<input type="text" id="addchat-username" placeholder="@username:serverhost" class="forminput">
|
<input type="text" id="addchat-username" placeholder="@username:serverhost" class="forminput">
|
||||||
</div>
|
</div>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<button class="submit-button">
|
<button class="submit-button" onclick="addDm()">
|
||||||
Add chat
|
Add chat
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -453,7 +543,6 @@ addGroupBtn.addEventListener("click", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sidebarHomeButton.addEventListener("mouseenter", () => {
|
sidebarHomeButton.addEventListener("mouseenter", () => {
|
||||||
sidebarHomeIndicator.classList.add("hover");
|
sidebarHomeIndicator.classList.add("hover");
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,10 @@
|
||||||
--big-red: rgb(202 0 0);
|
--big-red: rgb(202 0 0);
|
||||||
--big-green: rgb(25 189 0);
|
--big-green: rgb(25 189 0);
|
||||||
}
|
}
|
||||||
|
*:focus {
|
||||||
|
outline: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
.red {
|
.red {
|
||||||
color: var(--big-red);
|
color: var(--big-red);
|
||||||
}
|
}
|
||||||
|
|
@ -303,11 +307,12 @@ herotitle {
|
||||||
|
|
||||||
|
|
||||||
.input-group {
|
.input-group {
|
||||||
|
text-align: left;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
gap: 0.2rem;
|
gap: 0.2rem;
|
||||||
|
|
||||||
width: 80%;
|
width: 90%;
|
||||||
max-width: 30rem;
|
max-width: 30rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
4
android/app/src/main/assets/public/userscript.js
Normal file
4
android/app/src/main/assets/public/userscript.js
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
//write your custom deployment scripts here
|
||||||
|
|
||||||
|
loginHost.value = "olcxja.ovh";
|
||||||
|
loginHostChanged();
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
require('./rt/electron-rt');
|
require('./rt/electron-rt');
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
// User Defined Preload scripts below
|
// User Defined Preload scripts below
|
||||||
console.log('User Preload!');
|
//console.log('User Preload!');
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ class ElectronCapacitorApp {
|
||||||
{ role: 'viewMenu' },
|
{ role: 'viewMenu' },
|
||||||
];
|
];
|
||||||
this.CapacitorFileConfig = capacitorFileConfig;
|
this.CapacitorFileConfig = capacitorFileConfig;
|
||||||
this.customScheme = (_b = (_a = this.CapacitorFileConfig.electron) === null || _a === void 0 ? void 0 : _a.customUrlScheme) !== null && _b !== void 0 ? _b : 'capacitor-electron';
|
this.customScheme = (_b = (_a = this.CapacitorFileConfig.electron) === null || _a === void 0 ? void 0 : _a.customUrlScheme) !== null && _b !== void 0 ? _b : 'miarven';
|
||||||
if (trayMenuTemplate) {
|
if (trayMenuTemplate) {
|
||||||
this.TrayMenuTemplate = trayMenuTemplate;
|
this.TrayMenuTemplate = trayMenuTemplate;
|
||||||
}
|
}
|
||||||
|
|
@ -101,8 +101,10 @@ class ElectronCapacitorApp {
|
||||||
height: this.mainWindowState.height,
|
height: this.mainWindowState.height,
|
||||||
autoHideMenuBar: true,
|
autoHideMenuBar: true,
|
||||||
webPreferences: {
|
webPreferences: {
|
||||||
nodeIntegration: true,
|
nodeIntegration: false,
|
||||||
contextIsolation: true,
|
contextIsolation: true,
|
||||||
|
webSecurity: true,
|
||||||
|
allowRunningInsecureContent: true,
|
||||||
// Use preload to inject the electron varriant overrides for capacitor plugins.
|
// Use preload to inject the electron varriant overrides for capacitor plugins.
|
||||||
// preload: join(app.getAppPath(), "node_modules", "@capacitor-community", "electron", "dist", "runtime", "electron-rt.js"),
|
// preload: join(app.getAppPath(), "node_modules", "@capacitor-community", "electron", "dist", "runtime", "electron-rt.js"),
|
||||||
preload: preloadPath,
|
preload: preloadPath,
|
||||||
|
|
@ -175,6 +177,11 @@ class ElectronCapacitorApp {
|
||||||
electron_1.CapElectronEventEmitter.emit('CAPELECTRON_DeeplinkListenerInitialized', '');
|
electron_1.CapElectronEventEmitter.emit('CAPELECTRON_DeeplinkListenerInitialized', '');
|
||||||
}, 400);
|
}, 400);
|
||||||
});
|
});
|
||||||
|
this.MainWindow.webContents.on('before-input-event', (event, input) => {
|
||||||
|
if (input.control && input.shift && input.key.toLowerCase() === 'i') {
|
||||||
|
this.MainWindow.webContents.openDevTools();
|
||||||
|
}
|
||||||
|
});
|
||||||
this.MainWindow.setMenu(null);
|
this.MainWindow.setMenu(null);
|
||||||
this.MainWindow.setAutoHideMenuBar(true);
|
this.MainWindow.setAutoHideMenuBar(true);
|
||||||
this.MainWindow.removeMenu();
|
this.MainWindow.removeMenu();
|
||||||
|
|
@ -186,8 +193,8 @@ function setupContentSecurityPolicy(customScheme) {
|
||||||
electron_2.session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
|
electron_2.session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
|
||||||
callback({
|
callback({
|
||||||
responseHeaders: Object.assign(Object.assign({}, details.responseHeaders), { 'Content-Security-Policy': [
|
responseHeaders: Object.assign(Object.assign({}, details.responseHeaders), { 'Content-Security-Policy': [
|
||||||
electronIsDev
|
true
|
||||||
? `default-src ${customScheme}://* 'unsafe-inline' devtools://* 'unsafe-eval' data:`
|
? `default-src ${customScheme}://* 'unsafe-inline' 'unsafe-eval' devtools://* http://* https://* ws://* wss://* * data: blob:; frame-src *; style-src * 'unsafe-inline';`
|
||||||
: `default-src ${customScheme}://* 'unsafe-inline' data:`,
|
: `default-src ${customScheme}://* 'unsafe-inline' data:`,
|
||||||
] }),
|
] }),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
import type { CapacitorElectronConfig } from '@capacitor-community/electron';
|
|
||||||
import { getCapacitorElectronConfig, setupElectronDeepLinking } from '@capacitor-community/electron';
|
|
||||||
import type { MenuItemConstructorOptions } from 'electron';
|
|
||||||
import { app, MenuItem } from 'electron';
|
|
||||||
var electronIsDev = false;
|
|
||||||
import unhandled from 'electron-unhandled';
|
|
||||||
//import { autoUpdater } from 'electron-updater';
|
|
||||||
|
|
||||||
import { ElectronCapacitorApp, setupContentSecurityPolicy, setupReloadWatcher } from './setup';
|
|
||||||
|
|
||||||
// Graceful handling of unhandled errors.
|
|
||||||
unhandled();
|
|
||||||
|
|
||||||
// Define our menu templates (these are optional)
|
|
||||||
const trayMenuTemplate: (MenuItemConstructorOptions | MenuItem)[] = [new MenuItem({ label: 'Quit App', role: 'quit' })];
|
|
||||||
const appMenuBarMenuTemplate: (MenuItemConstructorOptions | MenuItem)[] = [
|
|
||||||
{ role: process.platform === 'darwin' ? 'appMenu' : 'fileMenu' },
|
|
||||||
{ role: 'viewMenu' },
|
|
||||||
];
|
|
||||||
|
|
||||||
// Get Config options from capacitor.config
|
|
||||||
const capacitorFileConfig: CapacitorElectronConfig = getCapacitorElectronConfig();
|
|
||||||
|
|
||||||
// Initialize our app. You can pass menu templates into the app here.
|
|
||||||
// const myCapacitorApp = new ElectronCapacitorApp(capacitorFileConfig);
|
|
||||||
const myCapacitorApp = new ElectronCapacitorApp(capacitorFileConfig, trayMenuTemplate, appMenuBarMenuTemplate);
|
|
||||||
|
|
||||||
// If deeplinking is enabled then we will set it up here.
|
|
||||||
if (capacitorFileConfig.electron?.deepLinkingEnabled) {
|
|
||||||
setupElectronDeepLinking(myCapacitorApp, {
|
|
||||||
customProtocol: capacitorFileConfig.electron.deepLinkingCustomProtocol ?? 'mycapacitorapp',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we are in Dev mode, use the file watcher components.
|
|
||||||
if (electronIsDev) {
|
|
||||||
setupReloadWatcher(myCapacitorApp);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run Application
|
|
||||||
(async () => {
|
|
||||||
// Wait for electron app to be ready.
|
|
||||||
await app.whenReady();
|
|
||||||
// Security - Set Content-Security-Policy based on whether or not we are in dev mode.
|
|
||||||
setupContentSecurityPolicy(myCapacitorApp.getCustomURLScheme());
|
|
||||||
// Initialize our app, build windows, and load content.
|
|
||||||
await myCapacitorApp.init();
|
|
||||||
// Check for updates if we are in a packaged app.
|
|
||||||
//autoUpdater.checkForUpdatesAndNotify();
|
|
||||||
})();
|
|
||||||
|
|
||||||
// Handle when all of our windows are close (platforms have their own expectations).
|
|
||||||
app.on('window-all-closed', function () {
|
|
||||||
// On OS X it is common for applications and their menu bar
|
|
||||||
// to stay active until the user quits explicitly with Cmd + Q
|
|
||||||
if (process.platform !== 'darwin') {
|
|
||||||
app.quit();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// When the dock icon is clicked.
|
|
||||||
app.on('activate', async function () {
|
|
||||||
// On OS X it's common to re-create a window in the app when the
|
|
||||||
// dock icon is clicked and there are no other windows open.
|
|
||||||
if (myCapacitorApp.getMainWindow().isDestroyed()) {
|
|
||||||
await myCapacitorApp.init();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Place all ipc or other electron api calls and custom functionality under this line
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
require('./rt/electron-rt');
|
|
||||||
//////////////////////////////
|
|
||||||
// User Defined Preload scripts below
|
|
||||||
console.log('User Preload!');
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
}
|
|
||||||
|
|
@ -1,88 +0,0 @@
|
||||||
import { randomBytes } from 'crypto';
|
|
||||||
import { ipcRenderer, contextBridge } from 'electron';
|
|
||||||
import { EventEmitter } from 'events';
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
||||||
const plugins = require('./electron-plugins');
|
|
||||||
|
|
||||||
const randomId = (length = 5) => randomBytes(length).toString('hex');
|
|
||||||
|
|
||||||
const contextApi: {
|
|
||||||
[plugin: string]: { [functionName: string]: () => Promise<any> };
|
|
||||||
} = {};
|
|
||||||
|
|
||||||
Object.keys(plugins).forEach((pluginKey) => {
|
|
||||||
Object.keys(plugins[pluginKey])
|
|
||||||
.filter((className) => className !== 'default')
|
|
||||||
.forEach((classKey) => {
|
|
||||||
const functionList = Object.getOwnPropertyNames(plugins[pluginKey][classKey].prototype).filter(
|
|
||||||
(v) => v !== 'constructor'
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!contextApi[classKey]) {
|
|
||||||
contextApi[classKey] = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
functionList.forEach((functionName) => {
|
|
||||||
if (!contextApi[classKey][functionName]) {
|
|
||||||
contextApi[classKey][functionName] = (...args) => ipcRenderer.invoke(`${classKey}-${functionName}`, ...args);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Events
|
|
||||||
if (plugins[pluginKey][classKey].prototype instanceof EventEmitter) {
|
|
||||||
const listeners: { [key: string]: { type: string; listener: (...args: any[]) => void } } = {};
|
|
||||||
const listenersOfTypeExist = (type) =>
|
|
||||||
!!Object.values(listeners).find((listenerObj) => listenerObj.type === type);
|
|
||||||
|
|
||||||
Object.assign(contextApi[classKey], {
|
|
||||||
addListener(type: string, callback: (...args) => void) {
|
|
||||||
const id = randomId();
|
|
||||||
|
|
||||||
// Deduplicate events
|
|
||||||
if (!listenersOfTypeExist(type)) {
|
|
||||||
ipcRenderer.send(`event-add-${classKey}`, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
const eventHandler = (_, ...args) => callback(...args);
|
|
||||||
|
|
||||||
ipcRenderer.addListener(`event-${classKey}-${type}`, eventHandler);
|
|
||||||
listeners[id] = { type, listener: eventHandler };
|
|
||||||
|
|
||||||
return id;
|
|
||||||
},
|
|
||||||
removeListener(id: string) {
|
|
||||||
if (!listeners[id]) {
|
|
||||||
throw new Error('Invalid id');
|
|
||||||
}
|
|
||||||
|
|
||||||
const { type, listener } = listeners[id];
|
|
||||||
|
|
||||||
ipcRenderer.removeListener(`event-${classKey}-${type}`, listener);
|
|
||||||
|
|
||||||
delete listeners[id];
|
|
||||||
|
|
||||||
if (!listenersOfTypeExist(type)) {
|
|
||||||
ipcRenderer.send(`event-remove-${classKey}-${type}`);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
removeAllListeners(type: string) {
|
|
||||||
Object.entries(listeners).forEach(([id, listenerObj]) => {
|
|
||||||
if (!type || listenerObj.type === type) {
|
|
||||||
ipcRenderer.removeListener(`event-${classKey}-${listenerObj.type}`, listenerObj.listener);
|
|
||||||
ipcRenderer.send(`event-remove-${classKey}-${listenerObj.type}`);
|
|
||||||
delete listeners[id];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
contextBridge.exposeInMainWorld('CapacitorCustomPlatform', {
|
|
||||||
name: 'electron',
|
|
||||||
plugins: contextApi,
|
|
||||||
});
|
|
||||||
////////////////////////////////////////////////////////
|
|
||||||
|
|
@ -1,231 +0,0 @@
|
||||||
import type { CapacitorElectronConfig } from '@capacitor-community/electron';
|
|
||||||
import {
|
|
||||||
CapElectronEventEmitter,
|
|
||||||
CapacitorSplashScreen,
|
|
||||||
setupCapacitorElectronPlugins,
|
|
||||||
} from '@capacitor-community/electron';
|
|
||||||
import chokidar from 'chokidar';
|
|
||||||
import type { MenuItemConstructorOptions } from 'electron';
|
|
||||||
import { app, BrowserWindow, Menu, MenuItem, nativeImage, Tray, session } from 'electron';
|
|
||||||
//import electronIsDev from 'electron-is-dev';
|
|
||||||
var electronIsDev = false;
|
|
||||||
import electronServe from 'electron-serve';
|
|
||||||
import windowStateKeeper from 'electron-window-state';
|
|
||||||
import { join } from 'path';
|
|
||||||
|
|
||||||
// Define components for a watcher to detect when the webapp is changed so we can reload in Dev mode.
|
|
||||||
const reloadWatcher = {
|
|
||||||
debouncer: null,
|
|
||||||
ready: false,
|
|
||||||
watcher: null,
|
|
||||||
};
|
|
||||||
export function setupReloadWatcher(electronCapacitorApp: ElectronCapacitorApp): void {
|
|
||||||
reloadWatcher.watcher = chokidar
|
|
||||||
.watch(join(app.getAppPath(), 'app'), {
|
|
||||||
ignored: /[/\\]\./,
|
|
||||||
persistent: true,
|
|
||||||
})
|
|
||||||
.on('ready', () => {
|
|
||||||
reloadWatcher.ready = true;
|
|
||||||
})
|
|
||||||
.on('all', (_event, _path) => {
|
|
||||||
if (reloadWatcher.ready) {
|
|
||||||
clearTimeout(reloadWatcher.debouncer);
|
|
||||||
reloadWatcher.debouncer = setTimeout(async () => {
|
|
||||||
electronCapacitorApp.getMainWindow().webContents.reload();
|
|
||||||
reloadWatcher.ready = false;
|
|
||||||
clearTimeout(reloadWatcher.debouncer);
|
|
||||||
reloadWatcher.debouncer = null;
|
|
||||||
reloadWatcher.watcher = null;
|
|
||||||
setupReloadWatcher(electronCapacitorApp);
|
|
||||||
}, 1500);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define our class to manage our app.
|
|
||||||
export class ElectronCapacitorApp {
|
|
||||||
private MainWindow: BrowserWindow | null = null;
|
|
||||||
private SplashScreen: CapacitorSplashScreen | null = null;
|
|
||||||
private TrayIcon: Tray | null = null;
|
|
||||||
private CapacitorFileConfig: CapacitorElectronConfig;
|
|
||||||
private TrayMenuTemplate: (MenuItem | MenuItemConstructorOptions)[] = [
|
|
||||||
new MenuItem({ label: 'Quit App', role: 'quit' }),
|
|
||||||
];
|
|
||||||
private AppMenuBarMenuTemplate: (MenuItem | MenuItemConstructorOptions)[] = [
|
|
||||||
{ role: process.platform === 'darwin' ? 'appMenu' : 'fileMenu' },
|
|
||||||
{ role: 'viewMenu' },
|
|
||||||
];
|
|
||||||
private mainWindowState;
|
|
||||||
private loadWebApp;
|
|
||||||
private customScheme: string;
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
capacitorFileConfig: CapacitorElectronConfig,
|
|
||||||
trayMenuTemplate?: (MenuItemConstructorOptions | MenuItem)[],
|
|
||||||
appMenuBarMenuTemplate?: (MenuItemConstructorOptions | MenuItem)[]
|
|
||||||
) {
|
|
||||||
this.CapacitorFileConfig = capacitorFileConfig;
|
|
||||||
|
|
||||||
this.customScheme = this.CapacitorFileConfig.electron?.customUrlScheme ?? 'capacitor-electron';
|
|
||||||
|
|
||||||
if (trayMenuTemplate) {
|
|
||||||
this.TrayMenuTemplate = trayMenuTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (appMenuBarMenuTemplate) {
|
|
||||||
this.AppMenuBarMenuTemplate = appMenuBarMenuTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup our web app loader, this lets us load apps like react, vue, and angular without changing their build chains.
|
|
||||||
this.loadWebApp = electronServe({
|
|
||||||
directory: join(app.getAppPath(), 'app'),
|
|
||||||
scheme: this.customScheme,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper function to load in the app.
|
|
||||||
private async loadMainWindow(thisRef: any) {
|
|
||||||
await thisRef.loadWebApp(thisRef.MainWindow);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Expose the mainWindow ref for use outside of the class.
|
|
||||||
getMainWindow(): BrowserWindow {
|
|
||||||
return this.MainWindow;
|
|
||||||
}
|
|
||||||
|
|
||||||
getCustomURLScheme(): string {
|
|
||||||
return this.customScheme;
|
|
||||||
}
|
|
||||||
|
|
||||||
async init(): Promise<void> {
|
|
||||||
const icon = nativeImage.createFromPath(
|
|
||||||
join(app.getAppPath(), 'assets', process.platform === 'win32' ? 'icon.ico' : 'icon.png')
|
|
||||||
);
|
|
||||||
|
|
||||||
const appName = "olcxja.miarven"
|
|
||||||
app.setName(appName);
|
|
||||||
|
|
||||||
app.setAppUserModelId(appName);
|
|
||||||
|
|
||||||
this.mainWindowState = windowStateKeeper({
|
|
||||||
defaultWidth: 1000,
|
|
||||||
defaultHeight: 800,
|
|
||||||
});
|
|
||||||
// Setup preload script path and construct our main window.
|
|
||||||
const preloadPath = join(app.getAppPath(), 'build', 'src', 'preload.js');
|
|
||||||
this.MainWindow = new BrowserWindow({
|
|
||||||
icon,
|
|
||||||
show: false,
|
|
||||||
x: this.mainWindowState.x,
|
|
||||||
y: this.mainWindowState.y,
|
|
||||||
width: this.mainWindowState.width,
|
|
||||||
height: this.mainWindowState.height,
|
|
||||||
autoHideMenuBar: true,
|
|
||||||
webPreferences: {
|
|
||||||
nodeIntegration: true,
|
|
||||||
contextIsolation: true,
|
|
||||||
// Use preload to inject the electron varriant overrides for capacitor plugins.
|
|
||||||
// preload: join(app.getAppPath(), "node_modules", "@capacitor-community", "electron", "dist", "runtime", "electron-rt.js"),
|
|
||||||
preload: preloadPath,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
this.mainWindowState.manage(this.MainWindow);
|
|
||||||
|
|
||||||
if (this.CapacitorFileConfig.backgroundColor) {
|
|
||||||
this.MainWindow.setBackgroundColor(this.CapacitorFileConfig.electron.backgroundColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we close the main window with the splashscreen enabled we need to destory the ref.
|
|
||||||
this.MainWindow.on('closed', () => {
|
|
||||||
if (this.SplashScreen?.getSplashWindow() && !this.SplashScreen.getSplashWindow().isDestroyed()) {
|
|
||||||
this.SplashScreen.getSplashWindow().close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// When the tray icon is enabled, setup the options.
|
|
||||||
if (this.CapacitorFileConfig.electron?.trayIconAndMenuEnabled) {
|
|
||||||
this.TrayIcon = new Tray(icon);
|
|
||||||
this.TrayIcon.on('double-click', () => {
|
|
||||||
if (this.MainWindow) {
|
|
||||||
if (this.MainWindow.isVisible()) {
|
|
||||||
this.MainWindow.hide();
|
|
||||||
} else {
|
|
||||||
this.MainWindow.show();
|
|
||||||
this.MainWindow.focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.TrayIcon.on('click', () => {
|
|
||||||
if (this.MainWindow) {
|
|
||||||
if (this.MainWindow.isVisible()) {
|
|
||||||
this.MainWindow.hide();
|
|
||||||
} else {
|
|
||||||
this.MainWindow.show();
|
|
||||||
this.MainWindow.focus();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this.TrayIcon.setToolTip(app.getName());
|
|
||||||
this.TrayIcon.setContextMenu(Menu.buildFromTemplate(this.TrayMenuTemplate));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup the main manu bar at the top of our window.
|
|
||||||
//Menu.setApplicationMenu(Menu.buildFromTemplate(this.AppMenuBarMenuTemplate));
|
|
||||||
Menu.setApplicationMenu(null);
|
|
||||||
|
|
||||||
|
|
||||||
this.loadMainWindow(this);
|
|
||||||
|
|
||||||
|
|
||||||
// Security
|
|
||||||
this.MainWindow.webContents.setWindowOpenHandler((details) => {
|
|
||||||
|
|
||||||
return { action: 'allow' };
|
|
||||||
|
|
||||||
});
|
|
||||||
this.MainWindow.webContents.on('will-navigate', (event, _newURL) => {
|
|
||||||
if (!this.MainWindow.webContents.getURL().includes(this.customScheme)) {
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Link electron plugins into the system.
|
|
||||||
setupCapacitorElectronPlugins();
|
|
||||||
|
|
||||||
// When the web app is loaded we hide the splashscreen if needed and show the mainwindow.
|
|
||||||
this.MainWindow.webContents.on('dom-ready', () => {
|
|
||||||
if (this.CapacitorFileConfig.electron?.splashScreenEnabled) {
|
|
||||||
this.SplashScreen.getSplashWindow().hide();
|
|
||||||
}
|
|
||||||
if (!this.CapacitorFileConfig.electron?.hideMainWindowOnLaunch) {
|
|
||||||
this.MainWindow.show();
|
|
||||||
}
|
|
||||||
setTimeout(() => {
|
|
||||||
|
|
||||||
CapElectronEventEmitter.emit('CAPELECTRON_DeeplinkListenerInitialized', '');
|
|
||||||
}, 400);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.MainWindow.setMenu(null);
|
|
||||||
this.MainWindow.setAutoHideMenuBar(true);
|
|
||||||
this.MainWindow.removeMenu();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set a CSP up for our application based on the custom scheme
|
|
||||||
export function setupContentSecurityPolicy(customScheme: string): void {
|
|
||||||
session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
|
|
||||||
callback({
|
|
||||||
responseHeaders: {
|
|
||||||
...details.responseHeaders,
|
|
||||||
'Content-Security-Policy': [
|
|
||||||
electronIsDev
|
|
||||||
? `default-src ${customScheme}://* 'unsafe-inline' devtools://* 'unsafe-eval' data:`
|
|
||||||
: `default-src ${customScheme}://* 'unsafe-inline' data:`,
|
|
||||||
],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
40
webroot/blah/en-us.json
Normal file
40
webroot/blah/en-us.json
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
{
|
||||||
|
"user.not.found": "User not found",
|
||||||
|
"cant.invite.urself": "You can't invite yourself",
|
||||||
|
"user.already.invited": "You have already invited this user",
|
||||||
|
"user.invited": "User invited successfully",
|
||||||
|
"cant.create.dm.without.invitation": "You can't create a dm without invitation",
|
||||||
|
"dm.begin.notice": "At the beginning of a DM, you should always verify that the person you're talking to is the intended recipient",
|
||||||
|
"failed.accept.dm": "Failed to accept DM",
|
||||||
|
"dm.accepted": "DM accepted",
|
||||||
|
"no.invite.found": "You can't create a dm without invitation",
|
||||||
|
"unknown.error": "Unknown error",
|
||||||
|
"account.creation.request.expired": "Account creation request expired. Try again",
|
||||||
|
"invalid.username": "Invalid username: {0}",
|
||||||
|
"invalid.password": "Invalid password: {0}",
|
||||||
|
"incorrect.captcha": "Incorrect captcha. Try again",
|
||||||
|
"username.taken": "This username is already taken",
|
||||||
|
"accounts.slots.full": "You can't create a new account because all ids are used. Try again later",
|
||||||
|
"registration.disabled": "Registration disabled",
|
||||||
|
"account.created": "Account created successfully",
|
||||||
|
"password.changed": "Password changed successfully",
|
||||||
|
"keys.updated": "Keys updated successfully",
|
||||||
|
"unknown.request": "Unknown request: {0}",
|
||||||
|
"login.successful": "Login successful",
|
||||||
|
"username.length": "Username must be {0} characters long",
|
||||||
|
"username.conditions.allowed": "Username can only include {all}",
|
||||||
|
"password.not.hashed.properly": "Password is not hashed properly",
|
||||||
|
"invalid.username.or.password": "Invalid username or password",
|
||||||
|
"account.not.exist": "Account with this name doesn't exist",
|
||||||
|
"invalid.nonce": "Invalid nonce. Try again",
|
||||||
|
"username.changed": "Username changed successfully",
|
||||||
|
"auth.failed.redirect.to.login": "Failed to auth. Redirecting to login...",
|
||||||
|
"dm.refresh.failed": "Failed to refresh dms",
|
||||||
|
"chat.add.failed": "Failed to add chat",
|
||||||
|
"something.wrong.mayb.pass": "Something went wrong... (probably wrong password)",
|
||||||
|
"something.wrong": "Something went wrong...",
|
||||||
|
"passwords.not.match": "Passwords do not match",
|
||||||
|
"password.cant.empty": "Password cannot be empty",
|
||||||
|
"username.cant.empty": "Username cannot be empty",
|
||||||
|
"bad.request": "Bad request"
|
||||||
|
}
|
||||||
|
|
@ -100,7 +100,14 @@
|
||||||
<script>
|
<script>
|
||||||
async function start() {
|
async function start() {
|
||||||
try {
|
try {
|
||||||
|
if (host != null)
|
||||||
|
{
|
||||||
|
await updateProtocolAndUrl(host);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
await updateProtocolAndUrl(window.location.hostname);
|
||||||
|
}
|
||||||
|
|
||||||
showAction("Authenticating...", "startauth");
|
showAction("Authenticating...", "startauth");
|
||||||
let res = await Auth(username, password);
|
let res = await Auth(username, password);
|
||||||
|
|
@ -108,13 +115,13 @@
|
||||||
if (res.startsWith("success:")) {
|
if (res.startsWith("success:")) {
|
||||||
await refreshDms();
|
await refreshDms();
|
||||||
} else {
|
} else {
|
||||||
showNotification("Failed to auth. Redirecting to login...", "error", 3500);
|
showBlahNotification("error:auth.failed.redirect.to.login");
|
||||||
await delay(2000);
|
await delay(2000);
|
||||||
window.location.href = "login/index.html";
|
window.location.href = "login/index.html";
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
clearAction("startauth");
|
clearAction("startauth");
|
||||||
showNotification("Failed to auth. Redirecting to login...", "error", 3500);
|
showBlahNotification("error:auth.failed.redirect.to.login");
|
||||||
await delay(2000);
|
await delay(2000);
|
||||||
window.location.href = "login/index.html";
|
window.location.href = "login/index.html";
|
||||||
}
|
}
|
||||||
|
|
@ -131,28 +138,27 @@
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
clearAction("dmrefresh");
|
clearAction("dmrefresh");
|
||||||
showNotification("Failed to refresh dms", "error", 3500);
|
showBlahNotification("error:dm.refresh.failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function addDm() {
|
async function addDm() {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
|
||||||
showAction("Adding...", "dmadd");
|
showAction("Adding...", "dmadd");
|
||||||
let res = await fetchEncrypted("user/dm/invite", document.getElementById("addchat-username").value);
|
let res = await fetchEncrypted("user/dm/invite", document.getElementById("addchat-username").value);
|
||||||
console.log(res);
|
console.log(res);
|
||||||
let ressplit = res.split(":");
|
let ressplit = res.split(":");
|
||||||
clearAction("dmadd");
|
clearAction("dmadd");
|
||||||
showNotification(ressplit[1], ressplit[0], 3500);
|
showBlahNotification(res);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
clearAction("dmadd");
|
clearAction("dmadd");
|
||||||
showNotification("Failed to add chat", "error", 3500);
|
showBlahNotification("error:chat.add.failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
start();
|
start();
|
||||||
</script>
|
</script>
|
||||||
|
<script src="userscript.js"></script>
|
||||||
|
|
@ -264,11 +264,10 @@
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
<script src="../main.js"></script>
|
<script src="../main.js"></script>
|
||||||
<script>
|
<script>
|
||||||
document.getElementById("reg-host").value = window.location.hostname;
|
|
||||||
document.getElementById("login-host").value = window.location.hostname;
|
|
||||||
|
|
||||||
const container = document.getElementById('auth-container');
|
const container = document.getElementById('auth-container');
|
||||||
|
|
||||||
|
|
@ -311,13 +310,12 @@
|
||||||
formLogin.addEventListener('submit', async (e) => {
|
formLogin.addEventListener('submit', async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
try {
|
try {
|
||||||
url = `${window.location.protocol}//${loginHost.value}/_larpix`;
|
|
||||||
|
|
||||||
let res = await Auth(loginUsername.value, loginPassword.value);
|
let res = await Auth(loginUsername.value, loginPassword.value);
|
||||||
|
|
||||||
if (res.startsWith("success:"))
|
if (res.startsWith("success:"))
|
||||||
{
|
{
|
||||||
showNotification(res, "success", 3500);
|
showBlahNotification(res);
|
||||||
await delay(1000);
|
await delay(1000);
|
||||||
localStorage.setItem("username", loginUsername.value);
|
localStorage.setItem("username", loginUsername.value);
|
||||||
localStorage.setItem("password", loginPassword.value);
|
localStorage.setItem("password", loginPassword.value);
|
||||||
|
|
@ -327,12 +325,12 @@
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
showNotification(res, "error", 3500);
|
showBlahNotification(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
showNotification("Something went wrong... (probably wrong password)", "error", 3500);
|
showBlahNotification("error:something.wrong.mayb.pass");
|
||||||
container.className = 'auth-container';
|
container.className = 'auth-container';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -343,20 +341,20 @@
|
||||||
captchaCode.value = "";
|
captchaCode.value = "";
|
||||||
regKeyInput.value = "";
|
regKeyInput.value = "";
|
||||||
|
|
||||||
url = `${window.location.protocol}//${registerHost.value}/_larpix`;
|
|
||||||
|
|
||||||
if (!registerUsername.value || registerUsername.value.trim() === '') {
|
if (!registerUsername.value || registerUsername.value.trim() === '') {
|
||||||
showNotification("Username cannot be empty", "error");
|
showBlahNotification("error:username.cant.empty");
|
||||||
container.className = 'auth-container show-register';
|
container.className = 'auth-container show-register';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!registerPassword.value || registerPassword.value.trim() === '') {
|
if (!registerPassword.value || registerPassword.value.trim() === '') {
|
||||||
showNotification("Password cannot be empty", "error");
|
showBlahNotification("error:password.cant.empty");
|
||||||
container.className = 'auth-container show-register';
|
container.className = 'auth-container show-register';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (registerPassword.value != registerPasswordConfirm.value) {
|
if (registerPassword.value != registerPasswordConfirm.value) {
|
||||||
showNotification("Passwords do not match", "error");
|
showBlahNotification("error:passwords.not.match");
|
||||||
container.className = 'auth-container show-register';
|
container.className = 'auth-container show-register';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -388,13 +386,13 @@
|
||||||
if (res.length > 64 || res.length <= 1) {
|
if (res.length > 64 || res.length <= 1) {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
showNotification(res, "error", 3500);
|
showBlahNotification(res);
|
||||||
container.className = 'auth-container show-register';
|
container.className = 'auth-container show-register';
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
showNotification("Something went wrong...", "error", 3500);
|
showBlahNotification("error:something.wrong");
|
||||||
container.className = 'auth-container show-register';
|
container.className = 'auth-container show-register';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -414,11 +412,8 @@
|
||||||
if (res.length > 64 || res.length <= 1) {
|
if (res.length > 64 || res.length <= 1) {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
}
|
}
|
||||||
if (res.startsWith("error")) {
|
if (res.startsWith("success")) {
|
||||||
showNotification(res, "error", 3500);
|
showBlahNotification(res);
|
||||||
container.className = 'auth-container show-register';
|
|
||||||
} else if (res.startsWith("success")) {
|
|
||||||
showNotification(res, "success", 3500);
|
|
||||||
await delay(1000);
|
await delay(1000);
|
||||||
localStorage.setItem("username", registerUsername.value);
|
localStorage.setItem("username", registerUsername.value);
|
||||||
localStorage.setItem("password", registerPassword.value);
|
localStorage.setItem("password", registerPassword.value);
|
||||||
|
|
@ -426,16 +421,13 @@
|
||||||
|
|
||||||
window.location.href = "../";
|
window.location.href = "../";
|
||||||
|
|
||||||
} else if (res.startsWith("info")) {
|
|
||||||
showNotification(res, "info", 3500);
|
|
||||||
container.className = 'auth-container show-register';
|
|
||||||
} else {
|
} else {
|
||||||
showNotification(res, "info", 3500);
|
showBlahNotification(res);
|
||||||
container.className = 'auth-container show-register';
|
container.className = 'auth-container show-register';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showNotification("Something went wrong...", "error", 3500);
|
showBlahNotification("error:something.wrong");
|
||||||
container.className = 'auth-container show-register';
|
container.className = 'auth-container show-register';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -453,6 +445,7 @@
|
||||||
async function updateLoginForm(host)
|
async function updateLoginForm(host)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
await updateProtocolAndUrl(host);
|
||||||
let serverInfo = await getServerInfo(host);
|
let serverInfo = await getServerInfo(host);
|
||||||
if (serverInfo["registration"] == "disabled")
|
if (serverInfo["registration"] == "disabled")
|
||||||
{
|
{
|
||||||
|
|
@ -487,5 +480,4 @@
|
||||||
|
|
||||||
loginHostChanged();
|
loginHostChanged();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
<script src="../userscript.js"></script>
|
||||||
</html>
|
|
||||||
170
webroot/main.js
170
webroot/main.js
|
|
@ -1,37 +1,62 @@
|
||||||
console.log(window.location.protocol);
|
var prot = window.location.protocol;
|
||||||
|
|
||||||
var url = `${window.location.protocol}//${window.location.hostname}/_larpix`;
|
async function updateProtocolAndUrl(host)
|
||||||
|
{
|
||||||
|
prot = window.location.protocol == "miarven:" ? "http:" : window.location.protocol;
|
||||||
|
if (prot == "http:") {
|
||||||
|
try {
|
||||||
|
JSON.parse(await fetchAsync(`${prot}//${host}/_larpix/serverinfo`));
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
try {
|
||||||
|
JSON.parse(await fetchAsync(`https://${host}/_larpix/serverinfo`));
|
||||||
|
prot = "https:";
|
||||||
|
}
|
||||||
|
catch (error) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
url = `${prot}//${host}/_larpix`;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(prot);
|
||||||
|
|
||||||
|
var url = `${prot}//${window.location.hostname}/_larpix`;
|
||||||
var params = new URLSearchParams(window.location.search);
|
var params = new URLSearchParams(window.location.search);
|
||||||
|
|
||||||
const collapseDmsBtn = document.getElementById("collapse-dms");
|
try {
|
||||||
const collapseGroupsBtn = document.getElementById("collapse-groups");
|
|
||||||
|
|
||||||
const addDmBtn = document.getElementById("add-dm-btn");
|
|
||||||
const addGroupBtn = document.getElementById("add-group-btn");
|
|
||||||
|
|
||||||
const sidebarHome = document.getElementById("sidebar-home");
|
|
||||||
const sidebarHomeButton = sidebarHome.children.item(1);
|
|
||||||
const sidebarHomeIndicator = sidebarHome.children.item(0);
|
|
||||||
|
|
||||||
const sidebarAdd = document.getElementById("sidebar-add");
|
|
||||||
const sidebarAddButton = sidebarAdd.children.item(1);
|
|
||||||
const sidebarAddIndicator = sidebarAdd.children.item(0);
|
|
||||||
|
|
||||||
const roomDetailsBar = document.getElementById("roomdetailsbar");
|
|
||||||
const roomContent = document.getElementsByTagName("roomcontent")[0];
|
|
||||||
const roomsBar = document.getElementById("roomsbar");
|
|
||||||
const sideBar = document.getElementsByTagName("sidebar")[0];
|
|
||||||
|
|
||||||
const roomContentMain = document.getElementsByTagName("roomcontent2")[0];
|
|
||||||
|
|
||||||
const roomContentBar = roomContent.children[0];
|
|
||||||
|
|
||||||
|
|
||||||
|
var collapseDmsBtn = document.getElementById("collapse-dms");
|
||||||
|
var collapseGroupsBtn = document.getElementById("collapse-groups");
|
||||||
|
|
||||||
|
var addDmBtn = document.getElementById("add-dm-btn");
|
||||||
|
var addGroupBtn = document.getElementById("add-group-btn");
|
||||||
|
|
||||||
|
var sidebarHome = document.getElementById("sidebar-home");
|
||||||
|
var sidebarHomeButton = sidebarHome.children.item(1);
|
||||||
|
var sidebarHomeIndicator = sidebarHome.children.item(0);
|
||||||
|
|
||||||
|
var sidebarAdd = document.getElementById("sidebar-add");
|
||||||
|
var sidebarAddButton = sidebarAdd.children.item(1);
|
||||||
|
var sidebarAddIndicator = sidebarAdd.children.item(0);
|
||||||
|
|
||||||
|
var roomDetailsBar = document.getElementById("roomdetailsbar");
|
||||||
|
var roomContent = document.getElementsByTagName("roomcontent")[0];
|
||||||
|
var roomsBar = document.getElementById("roomsbar");
|
||||||
|
var sideBar = document.getElementsByTagName("sidebar")[0];
|
||||||
|
|
||||||
|
var roomContentMain = document.getElementsByTagName("roomcontent2")[0];
|
||||||
|
|
||||||
|
var roomContentBar = roomContent.children[0];
|
||||||
|
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function delay(time) {
|
function delay(time) {
|
||||||
return new Promise(resolve => setTimeout(resolve, time));
|
return new Promise(resolve => setTimeout(resolve, time));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function packetEncPass(pass, key, username) {
|
async function packetEncPass(pass, key, username) {
|
||||||
return await encryptWithNonce(pass, key, getNonce(username, key));
|
return await encryptWithNonce(pass, key, getNonce(username, key));
|
||||||
}
|
}
|
||||||
|
|
@ -43,8 +68,7 @@ async function getNonce(username, key) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
nonce = await decryptString(fetchRes, key);
|
nonce = await decryptString(fetchRes, key);
|
||||||
}
|
} catch (err) {
|
||||||
catch(err) {
|
|
||||||
nonce = await decryptString(fetchRes, "");
|
nonce = await decryptString(fetchRes, "");
|
||||||
}
|
}
|
||||||
return nonce;
|
return nonce;
|
||||||
|
|
@ -87,6 +111,7 @@ function keyDataFromServerJson(jsonFromServer) {
|
||||||
function base64ToUint8(base64) {
|
function base64ToUint8(base64) {
|
||||||
return Uint8Array.from(atob(base64), c => c.charCodeAt(0));
|
return Uint8Array.from(atob(base64), c => c.charCodeAt(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
function uint8ToBase64(uint8) {
|
function uint8ToBase64(uint8) {
|
||||||
return fixBase64Padding(btoa(String.fromCharCode(...uint8)));
|
return fixBase64Padding(btoa(String.fromCharCode(...uint8)));
|
||||||
}
|
}
|
||||||
|
|
@ -264,13 +289,11 @@ async function fetchAsyncWAuth(url) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getServerInfo(host) {
|
async function getServerInfo(host) {
|
||||||
console.log(`${window.location.protocol}//${host}/_larpix/serverinfo`)
|
console.log(`${prot}//${host}/_larpix/serverinfo`)
|
||||||
return JSON.parse(await fetchAsync(`${window.location.protocol}//${host}/_larpix/serverinfo`));
|
return JSON.parse(await fetchAsync(`${prot}//${host}/_larpix/serverinfo`));
|
||||||
}
|
}
|
||||||
|
|
||||||
async function Auth(username, password) {
|
async function Auth(username, password) {
|
||||||
|
|
||||||
|
|
||||||
let passwordHash = await hashSHA3_512(password);
|
let passwordHash = await hashSHA3_512(password);
|
||||||
let response = await fetch(`${url}/auth?u=${username}`, {
|
let response = await fetch(`${url}/auth?u=${username}`, {
|
||||||
method: "GET",
|
method: "GET",
|
||||||
|
|
@ -286,8 +309,7 @@ async function Auth(username, password) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function fetchEncrypted(request, body)
|
async function fetchEncrypted(request, body) {
|
||||||
{
|
|
||||||
|
|
||||||
let nonce = await getNonce(username, passwordHash);
|
let nonce = await getNonce(username, passwordHash);
|
||||||
|
|
||||||
|
|
@ -295,7 +317,6 @@ async function fetchEncrypted(request, body)
|
||||||
method: "POST",
|
method: "POST",
|
||||||
credentials: "omit",
|
credentials: "omit",
|
||||||
body: await encryptWithNonce(
|
body: await encryptWithNonce(
|
||||||
|
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
string1: request,
|
string1: request,
|
||||||
string2: body
|
string2: body
|
||||||
|
|
@ -335,6 +356,15 @@ function fixBase64Padding(base64String) {
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function showBlahNotification(blahmessage, duration = 3500) {
|
||||||
|
try {
|
||||||
|
let split = blahmessage.split(":");
|
||||||
|
showNotification(processBlah(blahmessage), split[0], duration);
|
||||||
|
} catch (e) {
|
||||||
|
showNotification(blahmessage, "info", duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function showNotification(message, type = 'info', duration = 3500) {
|
function showNotification(message, type = 'info', duration = 3500) {
|
||||||
let container = document.getElementById('notification-container');
|
let container = document.getElementById('notification-container');
|
||||||
if (!container) {
|
if (!container) {
|
||||||
|
|
@ -386,13 +416,16 @@ function showAction(message, actionid) {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function clearAction(actionid) {
|
|
||||||
|
|
||||||
let notif = document.getElementById(`notification-${actionid}`);
|
function clearAction(actionid) {
|
||||||
|
const notifications = document.querySelectorAll(`[id="notification-${actionid}"]`);
|
||||||
|
|
||||||
|
notifications.forEach(notif => {
|
||||||
notif.classList.remove('show');
|
notif.classList.remove('show');
|
||||||
|
|
||||||
notif.addEventListener('transitionend', () => {
|
notif.addEventListener('transitionend', () => {
|
||||||
notif.remove();
|
notif.remove();
|
||||||
|
}, { once: true });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -406,20 +439,76 @@ async function hashSHA3_512(input) {
|
||||||
return hashHex;
|
return hashHex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var blah;
|
||||||
|
|
||||||
|
async function initBlahs() {
|
||||||
|
lang = lang.toLowerCase();
|
||||||
|
let res;
|
||||||
|
|
||||||
|
let path = window.location.pathname.replace("/login/index.html", "/");
|
||||||
|
|
||||||
|
try { //try user lang first
|
||||||
|
res = await fetchAsync(`${path}blah/${lang}.json`);
|
||||||
|
} catch (e) { //fallback to en-us
|
||||||
|
res = await fetchAsync(`${path}blah/en-us.json`);
|
||||||
|
}
|
||||||
|
blah = JSON.parse(res);
|
||||||
|
}
|
||||||
|
|
||||||
|
function processBlah(blahmessage) {
|
||||||
|
try {
|
||||||
|
let split = blahmessage.split(":");
|
||||||
|
let values = [];
|
||||||
|
try {
|
||||||
|
values = split[2].split(";");
|
||||||
|
} catch (e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
let message = blah[split[1]];
|
||||||
|
|
||||||
|
let valueslist = "";
|
||||||
|
for (let i = 0; i < values.length; i++) {
|
||||||
|
let value = values[i];
|
||||||
|
valueslist+=`${values[i]}, `;
|
||||||
|
processBlah(value);
|
||||||
|
|
||||||
|
message = message.replaceAll(`{${i}}`, value);
|
||||||
|
}
|
||||||
|
valueslist = valueslist.slice(0, -2);
|
||||||
|
if (message.includes('{all}')) {
|
||||||
|
|
||||||
|
message = message.replaceAll('{all}', valueslist);
|
||||||
|
}
|
||||||
|
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
catch (e)
|
||||||
|
{
|
||||||
|
return blahmessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLang() {
|
||||||
|
return (navigator.language || navigator.languages[0]);
|
||||||
|
}
|
||||||
|
|
||||||
var password = "";
|
var password = "";
|
||||||
var username = "";
|
var username = "";
|
||||||
var passwordHash = "";
|
var passwordHash = "";
|
||||||
var host = "";
|
var host = "";
|
||||||
async function mainJS()
|
var lang = getLang();
|
||||||
{
|
|
||||||
|
async function mainJS() {
|
||||||
|
await initBlahs();
|
||||||
|
|
||||||
|
passwordHash = await hashSHA3_512(password);
|
||||||
|
if (localStorage.getItem('lang') != null) {
|
||||||
|
lang = localStorage.getItem('lang');
|
||||||
|
}
|
||||||
|
}
|
||||||
username = localStorage.getItem('username');
|
username = localStorage.getItem('username');
|
||||||
password = localStorage.getItem('password');
|
password = localStorage.getItem('password');
|
||||||
host = localStorage.getItem('host');
|
host = localStorage.getItem('host');
|
||||||
passwordHash = await hashSHA3_512(password);
|
|
||||||
url = `${window.location.protocol}//${host}/_larpix`;
|
|
||||||
}
|
|
||||||
mainJS();
|
mainJS();
|
||||||
|
|
||||||
collapseDmsBtn.addEventListener("click", () => {
|
collapseDmsBtn.addEventListener("click", () => {
|
||||||
|
|
@ -454,7 +543,6 @@ addGroupBtn.addEventListener("click", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
sidebarHomeButton.addEventListener("mouseenter", () => {
|
sidebarHomeButton.addEventListener("mouseenter", () => {
|
||||||
sidebarHomeIndicator.classList.add("hover");
|
sidebarHomeIndicator.classList.add("hover");
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,10 @@
|
||||||
--big-red: rgb(202 0 0);
|
--big-red: rgb(202 0 0);
|
||||||
--big-green: rgb(25 189 0);
|
--big-green: rgb(25 189 0);
|
||||||
}
|
}
|
||||||
|
*:focus {
|
||||||
|
outline: none;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
.red {
|
.red {
|
||||||
color: var(--big-red);
|
color: var(--big-red);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
4
webroot/userscript.js
Normal file
4
webroot/userscript.js
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
//write your custom deployment scripts here
|
||||||
|
|
||||||
|
loginHost.value = "olcxja.ovh";
|
||||||
|
loginHostChanged();
|
||||||
Loading…
Add table
Add a link
Reference in a new issue