summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRaindropsSys <contact@minteck.org>2023-09-09 19:22:06 +0200
committerRaindropsSys <contact@minteck.org>2023-09-09 19:22:06 +0200
commitf581fff0254dba02181465153bb6a16aaff63311 (patch)
tree6c636ad458c6bfb5300c492549c627a201861f25
parent7f779ed7c1f1f50fe3dd11690b871b0d2d8a0113 (diff)
downloadchatroom-f581fff0254dba02181465153bb6a16aaff63311.tar.gz
chatroom-f581fff0254dba02181465153bb6a16aaff63311.tar.bz2
chatroom-f581fff0254dba02181465153bb6a16aaff63311.zip
Updated 6 files, added shared/verity.js and deleted 2 files (automated)
-rw-r--r--client/commands.js15
-rwxr-xr-xclient/index.html123
-rwxr-xr-xclient/main.js8
-rwxr-xr-xserver/server.js87
-rw-r--r--shared/lang/de.json158
-rw-r--r--shared/lang/en.json9
-rw-r--r--shared/lang/es.json158
-rw-r--r--shared/lang/fr.json9
-rw-r--r--shared/verity.js7
9 files changed, 183 insertions, 391 deletions
diff --git a/client/commands.js b/client/commands.js
index 84b37d2..3740fab 100644
--- a/client/commands.js
+++ b/client/commands.js
@@ -1,6 +1,14 @@
commands = {
- "verify": (_1, _2) => {
- localSystemMessage(l("commands/verify") + "<br><pre style='margin: 0 !important;'>" + require('crypto').createHash("sha256").update(window.serverVerifyKey).digest("base64").match(/.{1,35}/g).join("\n") + "</pre>", true);
+ "verify": (argument, _2) => {
+ if (argument.trim() === "") {
+ localSystemMessage(l("commands/verify/server") + "<br><pre style='margin: 0 !important;'>" + require('crypto').createHash("sha256").update(window.serverVerifyKey).digest("base64").match(/.{1,35}/g).join("\n") + "</pre><br>" + l("commands/verify/user") + "<br><pre style='margin: 0 !important;'>" + require('crypto').createHash("sha256").update(window.verifyKey.publicKey).digest("base64").match(/.{1,35}/g).join("\n"), true);
+ } else {
+ send({
+ server: true,
+ type: "verify",
+ user: argument
+ });
+ }
},
"nick": (argument, _) => {
if (argument.trim() === "") argument = require('os').userInfo().username;
@@ -19,6 +27,9 @@ commands = {
location.reload();
},
+ "whoami": (argument, _) => {
+ localSystemMessage(l("commands/whoami").replace("%1", localStorage.getItem("userLogin")));
+ },
"switch": async (argument, _) => {
await updateServer();
location.reload();
diff --git a/client/index.html b/client/index.html
index d64159f..e17cdcd 100755
--- a/client/index.html
+++ b/client/index.html
@@ -3,27 +3,31 @@
<head>
<script>
//window.version = "2.4";
- window.version = "2.5-beta.2023-05-08";
+ window.version = "3.0-beta.2023-09-07";
window.betaVersion = true;
window.changeLog = `
Thanks for using Localchat. You are currently running Localchat version %1, below are all the changes in that version compared to the previous version.
-Localchat Client 2.5 Beta:
- - Localization coverage is now complete
- - Added Spanish and German translations
- - Added a "New" badge next to the language selector
- - Fixed translations not loading in some cases
- - Fixed being able to drag title bar icons on Linux
- - Fixed odd titlebar behavior on KDE Plasma
- - Both server and client data are in the same place:
- - ~/.localchat on Linux
- - ~/Library/Application Support/Localchat on macOS
- - %appdata%/.localchat on Windows
- * Requires Launcher 1.4.0 or newer
- - Added /lang to change the language after OOBE
- - Added /switch to import another .ltcsc file
+Localchat Client 3.0 Beta:
+ - Removed Spanish and German translations
+ - Instead of an IP address, users are now identified by a unique username
Here is what changed in the previous versions:
+ * Localchat Client 2.5:
+ - Localization coverage is now complete
+ - Added Spanish and German translations
+ - Added a "New" badge next to the language selector
+ - Fixed translations not loading in some cases
+ - Fixed being able to drag title bar icons on Linux
+ - Fixed odd titlebar behavior on KDE Plasma
+ - Both server and client data are in the same place:
+ - ~/.localchat on Linux
+ - ~/Library/Application Support/Localchat on macOS
+ - %appdata%/.localchat on Windows
+ * Requires Launcher 1.4.0 or newer
+ - Added /lang to change the language after OOBE
+ - Added /switch to import another .ltcsc file
+
* Localchat Client 2.4:
- Added experimental localization support (only on beta)
- Added Linux support, without content protection
@@ -78,6 +82,7 @@ Here is what changed in the previous versions:
<meta charset="UTF-8">
<title>Localchat</title>
<script src="../shared/crypt.js"></script>
+ <script src="../shared/verity.js"></script>
<script src="commands.js"></script>
<script type="text/javascript" src="lib/purify.min.js"></script>
<script src="lib/marked.min.js"></script>
@@ -105,6 +110,10 @@ Here is what changed in the previous versions:
color: #e0e3e2;
}
+ pre {
+ margin: inherit !important;
+ }
+
.message-file .message-text {
background-color: #3f4949;
color: #bec8c8;
@@ -583,6 +592,10 @@ Here is what changed in the previous versions:
}
</style>
<script>
+ if (!localStorage.getItem("userLogin")) {
+ localStorage.setItem("userLogin", generateUsername());
+ }
+
function oobePage(page) {
document.getElementById("oobe-" + page).classList.add("oobe-page-shown");
}
@@ -624,8 +637,8 @@ Here is what changed in the previous versions:
window.addEventListener('load', () => {
document.getElementById("emoji-picker").addEventListener('emoji-click', (event) => {
- if (document.getElementById("input-text").contentEditable && !document.getElementById("input-text").disabled) {
- document.getElementById("input-text").insertAdjacentText("beforeend", event.detail.unicode);
+ if (!document.getElementById("input-text").disabled) {
+ document.getElementById("input-text").value += event.detail.unicode;
unpickEmoji();
document.getElementById("input-text").focus();
}
@@ -909,12 +922,17 @@ Here is what changed in the previous versions:
<a data-i18n-title="input/upload" class="input-icon" onclick="if (window.connected) uploadFile();"><img src="icons/upload.svg"></a>
<a data-i18n-title="input/emoji" class="input-icon" onclick="pickEmoji();"><img src="icons/emojis.svg"></a>
</div>
- <div contenteditable="true" style="font-family: inherit; font-size: 14px;" id="input-text"></div>
+ <input type="text" placeholder="Message" style="font-family: inherit; font-size: 14px;" id="input-text"></input>
</div>
<div id="typing"><b id="typing-single">X</b><span id="typing-two-outer"> <span data-i18n-text="input/typing/and"></span> <b id="typing-two">X</b></span><span id="typing-many" data-i18n-text="input/typing/many"></span> <span id="typing-singular" data-i18n-text="input/typing/singular"></span> <span id="typing-plural" data-i18n-text="input/typing/plural"></span> <span data-i18n-text="input/typing/end"></span></div>
</div>
<script>
+ if (!localStorage.getItem("verifyKey")) {
+ localStorage.setItem("verifyKey", JSON.stringify(generateKeys()));
+ }
+
+ window.verifyKey = JSON.parse(localStorage.getItem("verifyKey"));
const { ipcRenderer } = require('electron');
const os = require("os");
@@ -992,7 +1010,7 @@ Here is what changed in the previous versions:
window.directOverview = false;
window.typing = {};
window.lastTyping = 0;
- window.token = generateToken();
+ window.token = null;
window.files = {};
window.ping = -1;
window.displayedMessages = [];
@@ -1006,7 +1024,7 @@ Here is what changed in the previous versions:
}, 100);
function stripHTML(text) {
- return text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;");
+ return text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\n", "<br>");
}
function displayMessages() {
@@ -1036,7 +1054,7 @@ Here is what changed in the previous versions:
` : (message['type'] === "system" ? `
<div class="message system-message" id="message-${message['_id']}">
<span class="message-date" title="${new Date(message['date']).toString()}">${new Date(message['date']).toTimeString().split(":").splice(0, 2).join(":")}</span>
- <span class="message-text">${stripHTML(message['text'])}</span>
+ <span class="message-text">${stripHTML(message['text']).replaceAll("[[", "<pre>").replaceAll("]]", "</pre>")}</span>
</div>
` : (message['type'] === "system-raw" ? `
<div class="message system-message" id="message-${message['_id']}">
@@ -1104,9 +1122,9 @@ Here is what changed in the previous versions:
ws.onopen = () => {
ws.send(JSON.stringify({
- type: "keyExchange",
- key: keys.publicKey,
- token: encrypt(token, serverInfo.key)
+ type: "authenticate",
+ userName: localStorage.getItem("userLogin"),
+ publicKey: verifyKey.publicKey
}));
}
@@ -1127,20 +1145,9 @@ Here is what changed in the previous versions:
rej(new Error("Received invalid data"));
}
- if (data.type === "keyExchange") {
- if (data.token === token) {
- success = true;
- ws.close();
- res(true);
- } else {
- success = true;
- ws.close();
- rej(new Error("Invalid server key"));
- }
- } else if (data.type === "banned") {
+ if (data.type === "authenticated") {
success = true;
ws.close();
- rej(new Error("Banned from server"));
}
}
} catch (e) {
@@ -1186,9 +1193,9 @@ Here is what changed in the previous versions:
console.log(e);
ws.send(JSON.stringify({
- type: "keyExchange",
- key: keys.publicKey,
- token: encrypt(token, serverVerifyKey)
+ type: "authenticate",
+ userName: localStorage.getItem("userLogin"),
+ publicKey: verifyKey.publicKey
}));
wsPingInterval = setInterval(() => {
@@ -1248,6 +1255,16 @@ Here is what changed in the previous versions:
return;
}
+ if (data.type === "authenticated") {
+ window.token = decrypt(data.token, verifyKey.privateKey);
+
+ ws.send(JSON.stringify({
+ type: "keyExchange",
+ key: keys.publicKey,
+ token: encrypt(token, serverVerifyKey)
+ }));
+ }
+
if (data.type === "keyExchange") {
if (data.token === window.token) {
window.serverKey = data.key;
@@ -1276,8 +1293,10 @@ Here is what changed in the previous versions:
deciphered += decipher.final("utf8");
decrypted.file.content = deciphered;
- if (crypto.createHash("md5").update(Buffer.from(deciphered, "base64")).digest("hex") !== decrypted.file.md5) {
- localSystemMessage(l("upload/corrupt"));
+ let compare = crypto.createHash("md5").update(Buffer.from(deciphered, "base64")).digest("hex");
+
+ if (compare !== decrypted.file.md5) {
+ console.warn("Potentially corrupted file. Expected " + decrypted.file.md5 + " but got " + compare + ".");
}
}
@@ -1421,7 +1440,7 @@ Here is what changed in the previous versions:
cryptObj[token] = encrypted;
ws.send(JSON.stringify(cryptObj));
- fileObj['_source'] = "localhost";
+ fileObj['_source'] = localStorage.getItem("userLogin");
fileObj['_id'] = uuid();
fileObj['file']['content'] = content;
fileObj['admin'] = window.isAdmin;
@@ -1448,23 +1467,23 @@ Here is what changed in the previous versions:
}
document.getElementById("input-text").onkeyup = () => {
- if (document.getElementById("input-text").innerText.length > 501) document.getElementById("input-text").innerText = document.getElementById("input-text").innerText.substring(0, 501);
+ if (document.getElementById("input-text").value.length > 501) document.getElementById("input-text").value = document.getElementById("input-text").value.substring(0, 501);
}
document.getElementById("input-text").onkeydown = (e) => {
- if (document.getElementById("input-text").innerText.length > 501) document.getElementById("input-text").innerText = document.getElementById("input-text").innerText.substring(0, 501);
+ if (document.getElementById("input-text").value.length > 501) document.getElementById("input-text").value = document.getElementById("input-text").value.substring(0, 501);
if (e.code === "Enter" && !e.shiftKey) {
e.preventDefault();
- if (document.getElementById("input-text").innerText.trim() === "" || !window.connected || window.banned) return;
+ if (document.getElementById("input-text").value.trim() === "" || !window.connected || window.banned) return;
- if (document.getElementById("input-text").innerText.trim().startsWith("/") && document.getElementById("input-text").innerText.trim().length > 1) {
- let text = document.getElementById("input-text").innerText.trim();
- document.getElementById("input-text").innerText = "";
+ if (document.getElementById("input-text").value.trim().startsWith("/") && document.getElementById("input-text").value.trim().length > 1) {
+ let text = document.getElementById("input-text").value.trim();
+ document.getElementById("input-text").value = "";
runCommand(text);
} else {
- let text = document.getElementById("input-text").innerText.trim();
- if (document.getElementById("input-text").innerText.startsWith("\\/")) text = document.getElementById("input-text").innerText.substring(1);
+ let text = document.getElementById("input-text").value.trim();
+ if (document.getElementById("input-text").value.startsWith("\\/")) text = document.getElementById("input-text").value.substring(1);
let obj = {
type: "text",
@@ -1475,7 +1494,7 @@ Here is what changed in the previous versions:
}
send(obj);
- obj['_source'] = "localhost";
+ obj['_source'] = localStorage.getItem("userLogin");
obj['_id'] = uuid();
obj['admin'] = window.isAdmin;
@@ -1488,7 +1507,7 @@ Here is what changed in the previous versions:
}
displayMessages();
- document.getElementById("input-text").innerText = "";
+ document.getElementById("input-text").value = "";
}
} else {
if (window.connected && !window.banned && new Date().getTime() - window.lastTyping > 1000) {
diff --git a/client/main.js b/client/main.js
index c2590c6..257d3a2 100755
--- a/client/main.js
+++ b/client/main.js
@@ -144,10 +144,12 @@ app.whenReady().then(() => {
globalShortcut.register('Alt+CommandOrControl+C', () => {
if (mainWindow) {
try {
- if (mainWindow.isMinimized()) {
- mainWindow.restore();
+ if (!mainWindow.isVisible()) {
+ mainWindow.show();
+ if (process.platform === "darwin") app.dock.show();
} else {
- mainWindow.minimize();
+ mainWindow.hide();
+ if (process.platform === "darwin") app.dock.hide();
}
} catch (e) {}
}
diff --git a/server/server.js b/server/server.js
index 1ead0c6..e2a399a 100755
--- a/server/server.js
+++ b/server/server.js
@@ -1,6 +1,7 @@
const { WebSocketServer } = require('ws');
const crypt = require('../shared/crypt');
-const {decrypt, encrypt} = require("../shared/crypt");
+const verity = require('../shared/verity');
+const {decrypt, encrypt, generateToken} = require("../shared/crypt");
const uuid = require('uuid-v4');
const fs = require('fs');
const crypto = require('crypto');
@@ -17,7 +18,7 @@ if (!fs.existsSync(localchatDataRoot + "/server/logs")) fs.mkdirSync(localchatDa
if (!fs.existsSync(localchatDataRoot + "/server/data")) fs.mkdirSync(localchatDataRoot + "/server/data");
process.chdir(localchatDataRoot + "/server");
-const version = "1.11";
+const version = "2.0b";
const port = 27342;
function mergeRecursive(obj1, obj2) {
@@ -80,7 +81,7 @@ function log(message, address) {
console.log("Localchat Server v" + version + "; (c) Equestria.dev Developers");
console.log("powered by love and friendship");
-console.log(" - Want to contribute? https://git.equestria.dev/equestria.dev/localchat");
+console.log(" - Want to contribute? https://source.equestria.dev/equestria.dev/localchat");
console.log(" - Found a bug? https://bugs.equestria.dev/issues/LCHT\n");
const readline = require('readline').createInterface({
@@ -128,6 +129,11 @@ readline.question("Enter the IP address users would use to connect to the server
let clients = [];
log("Loaded ban list");
+ log("Loading user identities list...");
+ if (!fs.existsSync("./config/identities.json")) fs.writeFileSync("./config/identities.json", "{}");
+ let identities = JSON.parse(fs.readFileSync("./config/identities.json").toString());
+ log("Loaded user identities list");
+
log("Loading operators list...");
if (!fs.existsSync("./config/ops.json")) fs.writeFileSync("./config/ops.json", "[]");
let operators = JSON.parse(fs.readFileSync("./config/ops.json").toString());
@@ -144,21 +150,15 @@ readline.question("Enter the IP address users would use to connect to the server
wss.on('connection', function connection(ws, req) {
log("Connection from " + req.socket.remoteAddress);
ws.publicKey = null;
+ ws.verityKey = null;
+ ws.token = null;
ws.lang = "en";
ws.id = uuid();
- ws.address = parseAddress(req.socket.remoteAddress);
+ ws.ipAddress = parseAddress(req.socket.remoteAddress);
+ ws.userName = ws.address = null;
ws.lastPacket = 0;
ws.rateLimitAttempts = [];
- if (bans.includes(ws.address)) {
- log("Kicking user because they are banned", ws.address);
-
- ws.send(JSON.stringify({
- type: "banned"
- }));
- ws.close();
- }
-
clients.push(ws);
ws.on('error', (error) => {
@@ -168,9 +168,43 @@ readline.question("Enter the IP address users would use to connect to the server
ws.on('message', function message(_data) {
try {
+ if (ws.userName && bans.includes(ws.userName)) {
+ log("Kicking user because they are banned", ws.userName);
+
+ ws.send(JSON.stringify({
+ type: "banned"
+ }));
+ ws.close();
+ }
+
let data = JSON.parse(_data);
let diff = new Date().getTime() - ws.lastPacket;
+ if (data.type === "authenticate") {
+ log("User authenticated as " + data.userName, ws.ipAddress);
+ ws.userName = ws.address = data.userName;
+
+ ws.token = generateToken();
+ let publicKey = data.publicKey;
+
+ if (identities[data.userName]) {
+ ws.verityKey = publicKey = identities[data.userName];
+ } else {
+ ws.verityKey = identities[data.userName] = publicKey;
+ fs.writeFileSync("./config/identities.json", JSON.stringify(identities));
+ }
+
+ ws.send(JSON.stringify({
+ type: "authenticated",
+ token: encrypt(ws.token, publicKey)
+ }));
+
+ return
+ } else if (!ws.userName) {
+ log("User did not attempt authentication and instead sent a " + data.type + " request", ws.ipAddress);
+ ws.close();
+ }
+
if (diff <= 75 && ws.publicKey && data.type !== "keyExchange" && data.type !== "ping") {
ws.send(JSON.stringify({
type: "encrypted",
@@ -232,6 +266,10 @@ readline.question("Enter the IP address users would use to connect to the server
let token = decrypt(data.token, verify.privateKey);
+ if (token !== ws.token) {
+ ws.close();
+ }
+
ws.send(JSON.stringify({
type: "keyExchange",
key: keys.publicKey,
@@ -388,11 +426,32 @@ readline.question("Enter the IP address users would use to connect to the server
message: encrypt(JSON.stringify({
type: "system",
date: new Date().getTime(),
- text: l('server/ops', ws.lang) + " " + [...operators, "127.0.0.1"].join(", ")
+ text: l('server/ops', ws.lang) + " " + operators.join(", ")
}), ws.publicKey)
}));
log("Requested operators list", ws.address);
+ } else if (message.type === "verify") {
+ let key = "-";
+
+ for (let client of clients) {
+ if (client.userName === message.user) {
+ key = require('crypto').createHash("sha256").update(client.verityKey).digest("base64").match(/.{1,35}/g).join("\n");
+ break;
+ }
+ }
+
+ ws.send(JSON.stringify({
+ type: "encrypted",
+ source: ws.address,
+ message: encrypt(JSON.stringify({
+ type: "system",
+ date: new Date().getTime(),
+ text: l('commands/verify/other', ws.lang).replace("%1", message.user) + "\n[[" + key + "]]"
+ }), ws.publicKey)
+ }));
+
+ log("Requested verity key of " + message.user, ws.address);
} else if (message.type === "ban") {
if (ws.address !== "::1" && !ws.address.startsWith("127.") && !operators.includes(ws.address)) {
ws.send(JSON.stringify({
diff --git a/shared/lang/de.json b/shared/lang/de.json
deleted file mode 100644
index eb84bdc..0000000
--- a/shared/lang/de.json
+++ /dev/null
@@ -1,158 +0,0 @@
-{
- "_locale": "de_DE",
- "oobe": {
- "title": "Willkommen in Ihrer örtlichen Messaging -App",
- "developer": "Entwickleroptionen aktivieren",
- "beta": "Gehen Sie zum Beta -Kanal",
- "stable": "Gehen Sie zum stabilen Kanal",
- "navigation": {
- "start": "Start",
- "restart": "Neustarten",
- "next": "Folgen"
- },
- "connect": {
- "title": "Lassen Sie uns eine Verbindung herstellen",
- "description": "Ihr Administrator hätte Ihnen eine Localchat (.lctsc) -Konfigurationsdatei zur Verfügung gestellt haben. Stellen Sie sicher, dass Sie diese Datei haben, bevor Sie auf Weiter klicken.",
- "check": "Dateiüberprüfung ..."
- },
- "error": {
- "title": "Irgendwas stimmt nicht",
- "description": "Wir können Ihre Konfiguration nicht überprüfen. Stellen Sie sicher, dass Sie die richtige Datei zur Verfügung gestellt haben und der Server eingeschaltet ist und ordnungsgemäß funktioniert."
- },
- "disclaimers": {
- "title": "Benutzerwarnungen"
- },
- "diagnostics": {
- "title": "Diagnosedaten autorisieren?",
- "description": "Equestria.dev kann diagnostische Daten sammeln, während Sie Localchat verwenden, um die Probleme zu lösen, die Sie begegnen, und Ihre Erfahrung zu verbessern.",
- "no": "Ignorieren",
- "yes": "Ich nehme an"
- },
- "changelog": {
- "title": "Kürzliche Änderungen"
- },
- "done": {
- "title": "Es ist alles gut !",
- "description": "Bitte verwenden Sie Localchat. Sie haben jetzt den Konfigurationsprozess abgeschlossen und können Localchat verwenden. Klicken Sie auf Fertig stellen, um zu starten",
- "complete": "Beenden"
- }
- },
- "beta": "Beta",
- "input": {
- "upload": "Sende eine Datei",
- "emoji": "Fügen Sie Emojis hinzu",
- "typing": {
- "and": "Und",
- "many": "einige Leute",
- "singular": "Ost",
- "plural": "Sind",
- "end": "Schreiben…"
- }
- },
- "error": "Es trat ein Fehler auf: %1: %2; Bitte melden Sie es unter https://bugs.equestria.dev/issues/LCHT",
- "background_error": "Es ist unmöglich, das Hintergrundbild zu laden: %1; Ausführen /background, um es zu ändern oder zu entfernen",
- "byte": "B",
- "invalid_config": "Die von Ihnen ausgewählte Serverkonfiguration ist nicht gültig. Bitte wählen Sie eine andere aus.",
- "status": {
- "leave": "Sie haben die Diskussion verlassen",
- "leave2": "%1 verließ die Diskussion",
- "error": "Es ist nicht möglich",
- "import": "Wenn Sie eine Verbindung zu einem anderen Server herstellen möchten, erhalten Sie %1hier, um eine andere .lctsc%2 -Datei zu importieren",
- "join": "Sie haben sich der Diskussion angeschlossen",
- "join2": "%1 (%2) schloss sich der Diskussion an",
- "unverify": "Es ist unmöglich, die Identität des Servers zu überprüfen",
- "banned": "Sie wurden von diesem Server blockiert"
- },
- "upload": {
- "folder": "Ordner oder andere spezielle Dateien können nicht gesendet werden",
- "corrupt": "WARNUNG: Diese Datei ist möglicherweise korrupt. Überprüfen Sie sie unbedingt, bevor Sie sie öffnen",
- "size": "Diese Datei kann nicht gesendet werden, da sie die maximal autorisierte Größe überschreitet (%1)",
- "error": "Bei der Senden Ihrer Datei trat ein Fehler auf. Versuchen Sie es später erneut"
- },
- "dm_notice": "Dies ist eine private Nachricht vom Serverbesitzer. Verwenden Sie /r, um privat zu antworten.",
- "send": {
- "offline": "Es ist unmöglich, diese Nachricht zu senden, da Sie nicht mit dem Server verbunden sind",
- "banned": "Es ist unmöglich, diese Nachricht zu senden, da Sie vom Server blockiert sind"
- },
- "commands": {
- "_server": "Bitte stellen Sie eine Verbindung zu einem Server her, bevor Sie Befehle verwenden",
- "_server2": "Sie sind derzeit nicht mit einem Server verbunden",
- "_": "Entschuldigung, /%1 ist kein gültiger Befehl, verwenden /help, um eine Liste zu haben",
- "help": "Verfügbare Befehle:",
- "channel": {
- "beta": "Localchat verwendet nun den Beta -Kanal und starten Sie die Anwendung neu, um die Änderung abzuschließen.",
- "stable": "Localchat verwendet nun den stabilen Kanal und starten Sie die Anwendung neu, um die Änderung abzuschließen."
- },
- "version": {
- "localchat": "Localchat Version:",
- "launcher": "Launcher-Version:",
- "node": "Node.js Version:",
- "chrome": "Chrome Version:",
- "electron": "Electron Version:",
- "server": "Serverversion:"
- },
- "url": "Der Server, den Sie angeschlossen sind, lautet:",
- "ping": "Ihre Antwortzeit ist: %1 ms",
- "r": "Bitte geben Sie die Senden der Nachricht an",
- "msg": "Bitte geben Sie die IP -Adresse des Kunden an, an wen die Nachricht",
- "deop": "Bitte geben Sie die IP -Adresse eines Kunden an, den Sie Operator machen möchten",
- "op": "Bitte geben Sie die IP -Adresse eines Kunden an, den Sie Operator machen möchten",
- "unban": "Bitte geben Sie die IP -Adresse eines Kunden an, den Sie freischalten möchten",
- "ban": "Bitte geben Sie die IP -Adresse eines Kunden an, den Sie blockieren möchten",
- "verify": "Verwenden Sie diese Ausleihe, um die Identität des Servers zu überprüfen:",
- "nick": {
- "self": "Ihr Name ist jetzt \"%1\"",
- "other": "%1 hat seinen Namen für \"%2\" geändert."
- },
- "background": {
- "error": "Es ist unmöglich, den Hintergrund zu ändern: %1",
- "removed": "Erfolgreich das Hintergrundbild entfernt",
- "changed": "Veränderte das Hintergrundbild für %1 erfolgreich"
- },
- "color": {
- "reset": {
- "self": "Ihre Profilfarben sind jetzt standardmäßig diejenigen",
- "other": "%1 hat seine Profilfarben für diejenigen standardmäßig geändert"
- },
- "invalid": {
- "first": "Die erste Farbe ist kein gültiger hexadezimaler Farbcode",
- "second": "Die zweite Farbe ist kein gültiger hexadezimaler Farbcode"
- },
- "changed": {
- "self": "Ihre Profilfarben sind jetzt #%1 und #%2",
- "other": "%1 hat seine Profilfarben geändert"
- }
- }
- },
- "server": {
- "ratelimit": "Sie sind in der Zeit begrenzt, versuchen Sie es in wenigen Augenblicken erneut",
- "autoban": "%1 wurde automatisch blockiert, um Zeitgrenzen zu oft zu überschreiten",
- "list": {
- "users": "Verbundene Benutzer:",
- "alone": "Sie sind der einzige Benutzer auf diesem Server"
- },
- "permission": "Auf dem Serverbesitzer kann die Bestellung %1 verwenden",
- "mod": "Nur Serveroperatoren können den Befehl %1 verwenden",
- "invalid": "%1 ist keine gültige Kunden -IP -Adresse",
- "no_owner": "Der Eigentümer des Servers ist derzeit nicht online",
- "ops": "Serverbetreiber:",
- "block": {
- "already": "%1 ist auf diesem Server bereits blockiert",
- "banned": "%1 erfolgreich blockiert",
- "unbanned": "Schloss %1 erfolgreich entsperrt",
- "broadcast": "%1 blockiert %2",
- "broadcast2": "%1 a freigeschaltet %2",
- "nothing": "%1 ist auf diesem Server nicht blockiert"
- },
- "op": {
- "already": "%1 ist bereits ein Serverbetreiber",
- "oped": "%1 als Erfolgsbetreiber erfolgreich hinzugefügt",
- "unoped": "Rückzug %1 der Serverbetreiber erfolgreich",
- "broadcast": "%1 hat %2 als Serverbetreiber hinzugefügt",
- "broadcast2": "%1 zog %2 von Serverbetreibern zurück",
- "nothing": "%1 ist kein Serverbetreiber",
- "you": "Sie sind jetzt Serverbetreiber",
- "you2": "Sie sind kein Betreiber des Servers mehr"
- }
- }
-} \ No newline at end of file
diff --git a/shared/lang/en.json b/shared/lang/en.json
index 141f0cc..3e30058 100644
--- a/shared/lang/en.json
+++ b/shared/lang/en.json
@@ -99,7 +99,11 @@
"op": "Please specify the IP address of a client you want to make an operator",
"unban": "Please specify the IP address of a client you want to unblock",
"ban": "Please specify the IP address of a client you want to block",
- "verify": "Use this fingerprint to verify the server's identity:",
+ "verify": {
+ "server": "Use this fingerprint to verify the server's identity:",
+ "user": "Others can use this fingerprint to verify your identity:",
+ "other": "Use this fingerprint to verify %1's identity:"
+ },
"nick": {
"self": "Your name is now \"%1\"",
"other": "%1 changed their name to \"%2\""
@@ -122,7 +126,8 @@
"self": "Your profile colors are now #%1 and #%2",
"other": "%1 changed their profile colors"
}
- }
+ },
+ "whoami": "Your login name is: %1. This name is used to prove your identity to the server and to other users."
},
"server": {
"ratelimit": "You are being rate limited, try again in a few moments",
diff --git a/shared/lang/es.json b/shared/lang/es.json
deleted file mode 100644
index 624e306..0000000
--- a/shared/lang/es.json
+++ /dev/null
@@ -1,158 +0,0 @@
-{
- "_locale": "es_ES",
- "oobe": {
- "title": "Bienvenido a su aplicación de mensajería local",
- "developer": "Activar opciones de desarrollador",
- "beta": "Ir al canal beta",
- "stable": "Ir al canal estable",
- "navigation": {
- "start": "Comenzar",
- "restart": "Para reiniciar",
- "next": "Próximo"
- },
- "connect": {
- "title": "Conectemos",
- "description": "Su administrador debería haberle proporcionado un archivo de configuración Localchat (.lctsc). Asegúrese de tener este archivo antes de hacer clic en Siguiente.",
- "check": "Verificación de archivos..."
- },
- "error": {
- "title": "Algo no va bien",
- "description": "No podemos verificar su configuración. Asegúrese de haber proporcionado el archivo correcto y el servidor está encendido y funciona correctamente."
- },
- "disclaimers": {
- "title": "Advertencias de usuario"
- },
- "diagnostics": {
- "title": "Autorizar datos de diagnóstico?",
- "description": "Equestria.dev puede recopilar datos de diagnóstico mientras usa Localchat para resolver los problemas que encuentra y mejorar su experiencia.",
- "no": "Ignorar",
- "yes": "Acepto"
- },
- "changelog": {
- "title": "Cambios recientes"
- },
- "done": {
- "title": "Todo es bueno !",
- "description": "Por favor, use Localchat. Ahora ha completado el proceso de configuración y puede usar Localchat. Haga clic en Finalizar para comenzar",
- "complete": "Para terminar"
- }
- },
- "beta": "Beta",
- "input": {
- "upload": "Enviar un archivo",
- "emoji": "Agregar emojis",
- "typing": {
- "and": "y",
- "many": "Varias personas",
- "singular": "Este",
- "plural": "están",
- "end": "escribiendo…"
- }
- },
- "error": "Se produjo un error: %1: %2; Informe en https://bugs.equestria.dev/issues/LCHT",
- "background_error": "Imposible cargar la imagen de fondo: %1; Ejecutar /background para cambiarlo o eliminarlo",
- "byte": "B",
- "invalid_config": "La configuración del servidor que ha seleccionado no es válida, seleccione otra.",
- "status": {
- "leave": "Dejaste la discusión",
- "leave2": "%1 dejó la discusión",
- "error": "Imposible conectarse al servidor Localchat en %1, asegúrese de que el servidor esté en servicio",
- "import": "Si desea conectarse a otro servidor, %1llegar aquí para importar otro archivo .lctsc%2",
- "join": "Te has unido a la discusión",
- "join2": "%1 (%2) se unió a la discusión",
- "unverify": "Imposible verificar la identidad del servidor",
- "banned": "Fuiste bloqueado desde este servidor"
- },
- "upload": {
- "folder": "No se puede enviar carpetas u otros archivos especiales",
- "corrupt": "Advertencia: este archivo es posiblemente corrupto, asegúrese de verificarlo antes de abrirlo",
- "size": "No se puede enviar este archivo porque excede el tamaño máximo autorizado (%1)",
- "error": "Se produjo un error al enviar su archivo, intente nuevamente más tarde"
- },
- "dm_notice": "Este es un mensaje privado del propietario del servidor. Usar /r para responder en privado.",
- "send": {
- "offline": "Imposible enviar este mensaje porque no está conectado al servidor",
- "banned": "Imposible enviar este mensaje porque está bloqueado desde el servidor"
- },
- "commands": {
- "_server": "Conéctese a un servidor antes de usar comandos",
- "_server2": "Actualmente no está conectado a un servidor",
- "_": "Lo siento, /%1 no es un comando válido, use /help a tener una lista",
- "help": "Comandos disponibles:",
- "channel": {
- "beta": "Localchat ahora usará el canal beta, reiniciará la aplicación para completar el cambio.",
- "stable": "Localchat ahora usará el canal estable, reiniciará la aplicación para completar el cambio."
- },
- "version": {
- "localchat": "Versión de Localchat:",
- "launcher": "Versión del lanzador:",
- "node": "Versión de Node.js:",
- "chrome": "Versión de Chrome:",
- "electron": "Versión de Electron:",
- "server": "Versión del servidor:"
- },
- "url": "El servidor que está conectado es:",
- "ping": "Su tiempo de respuesta es: %1 ms",
- "r": "Especifique el mensaje para enviar",
- "msg": "Especifique la dirección IP del cliente a quien el mensaje",
- "deop": "Especifique la dirección IP de un cliente que desea hacer operador",
- "op": "Especifique la dirección IP de un cliente que desea hacer operador",
- "unban": "Especifique la dirección IP de un cliente que desea desbloquear",
- "ban": "Especifique la dirección IP de un cliente que desea bloquear",
- "verify": "Use este préstamo para verificar la identidad del servidor:",
- "nick": {
- "self": "Tu nombre ahora es \"%1\"",
- "other": "%1 ha cambiado su nombre para \"%2\""
- },
- "background": {
- "error": "Imposible cambiar el fondo: %1",
- "removed": "Eliminó con éxito la imagen de fondo",
- "changed": "Cambió la imagen de fondo para %1 correctamente"
- },
- "color": {
- "reset": {
- "self": "Los colores de su perfil son ahora aquellos de forma predeterminada",
- "other": "%1 ha cambiado sus colores de perfil para aquellos por defecto"
- },
- "invalid": {
- "first": "El primer color no es un código de color hexadecimal válido",
- "second": "El segundo color no es un código de color hexadecimal válido"
- },
- "changed": {
- "self": "Los colores de su perfil ahora son #%1 y #%2",
- "other": "%1 ha cambiado sus colores de perfil"
- }
- }
- },
- "server": {
- "ratelimit": "Estás limitado en el tiempo, intente de nuevo en unos momentos",
- "autoban": "%1 se bloqueó automáticamente para los límites de tiempo superiores demasiadas veces",
- "list": {
- "users": "Usuarios conectados:",
- "alone": "Eres el único usuario en este servidor"
- },
- "permission": "En el propietario del servidor puede usar el pedido %1",
- "mod": "Solo los operadores del servidor pueden usar el comando %1",
- "invalid": "%1 no es una dirección IP de cliente válida",
- "no_owner": "El propietario del servidor no está actualmente en línea",
- "ops": "Operadores de servidor:",
- "block": {
- "already": "%1 ya está bloqueado en este servidor",
- "banned": "Bloqueado %1 con éxito",
- "unbanned": "Desbloqueado %1 con éxito",
- "broadcast": "%1 bloqueado %2",
- "broadcast2": "%1 A desbloqueado %2",
- "nothing": "%1 no está bloqueado en este servidor"
- },
- "op": {
- "already": "%1 ya es un operador de servidor",
- "oped": "Se agregó %1 como operador de éxito con éxito",
- "unoped": "Retirado %1 de los operadores del servidor con éxito",
- "broadcast": "%1 agregado %2 como operador de servidor",
- "broadcast2": "%1 Retirar %2 de los operadores del servidor",
- "nothing": "%1 no es un operador de servidor",
- "you": "Ahora eres un operador del servidor",
- "you2": "Ya no eres un operador del servidor"
- }
- }
-} \ No newline at end of file
diff --git a/shared/lang/fr.json b/shared/lang/fr.json
index 0bb0e88..663685a 100644
--- a/shared/lang/fr.json
+++ b/shared/lang/fr.json
@@ -99,7 +99,11 @@
"op": "Veuillez spécifier l'adresse IP d'un client que vous voulez rendre opérateur",
"unban": "Veuillez spécifier l'adresse IP d'un client que vous voulez débloquer",
"ban": "Veuillez spécifier l'adresse IP d'un client que vous voulez bloquer",
- "verify": "Utilisez cette emprunte pour vérifier l'identité du serveur :",
+ "verify": {
+ "server": "Utilisez cette emprunte pour vérifier l'identité du serveur :",
+ "user": "Les autres peuvent utiliser cette emprunte pour vérifier votre identité :",
+ "other": "Utilisez cette emprunte pour vérifier l'identité de %1 :"
+ },
"nick": {
"self": "Votre nom est désormais \"%1\"",
"other": "%1 a changé son nom pour \"%2\""
@@ -122,7 +126,8 @@
"self": "Vos couleurs de profil sont désormais #%1 et #%2",
"other": "%1 a changé ses couleurs de profil"
}
- }
+ },
+ "whoami": "Votre nom de connexion est : %1. Ce nom est utilisé pour prouver votre identité au serveur et aux autres utilisateurs."
},
"server": {
"ratelimit": "Vous êtes limité dans le temps, essayez de nouveau dans quelques instants",
diff --git a/shared/verity.js b/shared/verity.js
new file mode 100644
index 0000000..3bfc5a5
--- /dev/null
+++ b/shared/verity.js
@@ -0,0 +1,7 @@
+function generateUsername() {
+ const crypto = require('crypto');
+
+ return (parseInt(crypto.randomBytes(8).toString("hex"), 16).toString(36).replace(/\d/g, "") + parseInt(crypto.randomBytes(8).toString("hex"), 16).toString(36).replace(/\d/g, "")).substring(0, 7) + "_" + (parseInt(crypto.randomBytes(8).toString("hex"), 16).toString(36).replace(/\d/g, "") + parseInt(crypto.randomBytes(8).toString("hex"), 16).toString(36).replace(/\d/g, "")).substring(0, 7) + "_" + parseInt(crypto.randomBytes(5).toString("hex"), 16).toString().substring(0, 3);
+}
+
+if (module) module.exports = {generateUsername} \ No newline at end of file