rena_client/client.js

727 lines
14 KiB
JavaScript

const blessed = require("neo-blessed");
var screen =
blessed.screen({
smartCSR: true
});
screen.key(['escape', 'C-c'], function(ch, key) {
return process.exit(0);
});
var screen_msg =
blessed.message({
parent:screen,
top:'center',
left:'center',
height:'shrink',
width:'shrink',
align:'center',
tags:true,
hidden:true,
border:'line'
});
const fs = require("fs");
// Read config
var config_file = fs.readFileSync("./settings.conf", "utf8");
config_file = config_file.split("\n");
config = {};
for(i=0; i<config_file.length; i++){
config_file[i] = config_file[i].trim();
if(
config_file[i] == "" ||
config_file[i][0] == "#"
){
continue;
}
var tmp = config_file[i].split("=");
config[tmp[0]] = tmp[1];
}
const websocket = require("ws");
const fetch = require("node-fetch");
const formdata = require("form-data");
const he = require("he");
const emitter = require("events");
const deek = new emitter();
var channels = [];
var channel_index = 0;
var ws = [];
var previous_msg = [];
var headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:107.0) Gecko/20100101 Firefox/107.0",
Origin: "https://deek.chat"
};
/*
Helper functions
*/
function removehtml(html){
html =
he.decode(
blessed.escape(html)
.replace(
/<img title='([^"]*)' src='[^"]+' class='emoji'>/g,
"{light-gray-fg}:$1:{/light-gray-fg}"
)
.replace(
/<[^>]+>/ig,
""
)
);
return html;
}
/*
Websocket functions
*/
async function send(channel, text/*, file = null, forcemime = null*/){
if(typeof channel == "object"){
channel = channel.channel;
}
//if(file === null){
ws.send(JSON.stringify({
type: "messageEnd",
data: text,
roomId: channel
}));
return;
//}
/*
Send file
*/
/*
if(forcemime === null){
var mimetype = await getmime(file);
}else{
var mimetype = forcemime;
}
var form_data = new formdata();
form_data.append("text", text);
form_data.append(
"files[]",
file,
{
contentType: mimetype[0],
name: "file",
filename: "file." + mimetype[1]
}
);
var headers_copy = headers;
headers_copy["Content-Type"] = form_data.getHeaders()["content-type"];
fetch("https://deek.chat/message/send/" + channel, {
method: 'POST',
body: form_data,
headers: headers_copy
})*/
}
/*
Handshake
*/
async function handshake(){
/*
Get cookie
*/
screen_msg.display("{light-gray-fg}Logging in as {bold}" + config.username + "{/bold}...{/light-gray-fg}");
const form = new formdata();
form.append("name", config.username);
form.append("password", config.password);
form.append("submit", "log+in");
try{
var login = await fetch(
"https://deek.chat/login/submit",
{
method: "POST",
redirect: "manual",
body: form,
headers: headers
}
);
}catch(err){
deek.emit("error", "Could not connect to Deekchat");
return;
}
var cookie = await login.headers.get("set-cookie");
var api_token = cookie.match(/api_token=([^;]+)/);
var session_id = cookie.match(/session_id=([^;]+)/);
if(
api_token === null ||
session_id === null
){
deek.emit("error", "Could not get api_token or session_id!!");
return;
}
headers.Cookie = "session_id=" + session_id[1] + "; api_token=" + api_token[1] + "; lastMessageTimestamps={}";
/*
Scrape channel list
*/
var subscribed = await fetch(
"https://deek.chat/rooms/fetch/subscribed",
{
method: "GET",
headers: headers
}
);
var res = await subscribed.buffer();
res = JSON.parse(res.toString("utf8"));
shittierloop:
for(var i=0; i<res.length; i++){
for(var k=0; k<channels.length; k++){
if(channels[k].id === res[i].room.id){
continue shittierloop;
}
}
channels.push({
name: res[i].room.name,
id: res[i].room.id,
users: []
});
}
var items = [];
var item_map = [];
for(var i=0; i<channels.length; i++){
items.push(channels[i].name + " (id:" + channels[i].id + ")");
item_map.push(channels[i].id);
}
var list =
blessed.list({
parent:screen,
label:'{bold}{cyan-fg}Pick a channel{/cyan-fg}{/bold}',
tags:true,
keys:true,
border:'line',
scrollbar:{
ch:'',
track:{
bg:'cyan'
},
style:{
inverse:true
}
},
style:{
item:{
hover:{
bg:'blue'
}
},
selected:{
bg:'blue',
bold:true
}
}
});
list.setItems(items);
list.focus();
screen.render();
list.on("select", async function(element, selected){
screen.remove(list);
screen_msg.display("{light-gray-fg}Connecting to {bold}#" + items[selected] + "{/bold}{/light-gray-fg}");
/*
Scrape users
*/
/*
var users = await fetch(
"https://deek.chat/users/" + item_map[selected],
{
method: "GET",
headers: headers
}
);
var res = await users.buffer();
res = JSON.parse(res.toString("utf8"));
if(res === null){
res = [];
}
for(var k=0; k<res.length; k++){
channels[selected].users.push({
name: res[k].name,
id: res[k].id,
phoneposter: res[k].isMobile,
country: {
name: res[k].countryName,
code: res[k].countryIso.toUpperCase()
},
picture: res[k].profilePicture == "" ? null : "https://deek.chat/storage/profilePictures/" + res[k].profilePicture
});
}*/
/*
Get previous messages
*/
/*
previous_msg = await fetch(
"https://deek.chat/message/fetch/" + item_map[selected],
{
method: "GET",
headers: headers
}
);
previous_msg = await previous_msg.buffer();
previous_msg = JSON.parse(previous_msg.toString("utf8"));
channel_index = item_map[selected];*/
/*
Connect to websocket serbers
*/
ws = new websocket(
"wss://deek.chat/ws",
{
protocolVersion: 13,
encoding: "utf8",
headers: headers
}
);
ws.once("open", function(){
deek.emit("login", channels[selected]);
});
ws.once("close", function(){
deek.emit("close");
});
ws.on("message", function(message, isbin){
if(isbin){ return; }
var m = JSON.parse(message.toString("utf8"));
if(typeof m.type == "undefined"){
return;
}
if(
typeof m.roomId != "undefined" &&
m.roomId != channels[selected].id
){
return;
}
switch(m.type){
case "message":
case "messageEnd":
for(var k=0; k<m.data.mentions.length; k++){
m.data.mentions[k].id = m.data.mentions[k].userId;
delete m.data.mentions[k].userId;
}
for(var k=0; k<m.data.replies.length; k++){
m.data.replies[k].id = m.data.replies[k].userId;
m.data.replies[k] = m.data.replies[k].replyMessageId;
delete m.data.replies[k].userId;
delete m.data.replies[k].replyMessageId;
}
m.data.files = m.data.files === null ? [] : m.data.files;
var files = [];
for(var k=0; k<m.data.files.length; k++){
files.push("https://deek.chat/storage/files/" + m.data.files[k].name);
}
deek.emit(
"message",
{
text: removehtml(m.data.text),
id: m.data.id,
files: files,
mentions: m.data.mentions,
replies: m.data.replies,
channel: m.roomId
},
{
name: m.data.name,
id: m.userId,
picture: m.data.profilePicture == "" ? null : "https://deek.chat/storage/profilePictures/" + m.data.profilePicture
}
);
break;
case "files":
var files = [];
if(m.data.files !== null){
for(var k=0; k<m.data.files.length; k++){
files.push("https://deek.chat/storage/files/" + m.data.files[k].name);
}
}
deek.emit(
"message",
{
text: removehtml(m.data.text),
id: m.data.id,
files: files,
mentions: m.data.mentions,
replies: m.data.replies,
channel: m.roomId
},
{
name: m.data.name,
id: m.data.userId,
picture: m.data.profilePicture == "" ? null : "https://deek.chat/storage/profilePictures/" + m.data.profilePicture
}
);
break;
case "enter":
var payload = {
name: m.data.name,
id: m.data.id,
phoneposter: m.data.isMobile,
robot: m.data.isRobot,
country: {
name: m.data.countryName == "" ? "idk lol" : m.data.countryName,
code: m.data.countryIso == "" ? "??" : m.data.countryIso,
},
picture: m.data.profilePicture == "" ? null : "https://deek.chat/storage/profilePictures/" + m.data.profilePicture
};
channels[selected].users.push(payload);
deek.emit(
"enter",
payload
);
break;
case "exit":
var payload = {
name: m.data.name,
id: m.data.id,
phoneposter: m.data.isMobile,
robot: m.data.isRobot,
country: {
name: m.data.countryName,
code: m.data.countryIso.toUpperCase()
},
picture: m.data.profilePicture == "" ? null : "https://deek.chat/storage/profilePictures/" + m.data.profilePicture
}
for(var i=0; i<channels[selected].users.length; i++){
if(channels[selected].users[i].id == payload.id){
payload = channels[selected].users[i];
channels[selected].users.splice(i, 1);
break;
}
}
deek.emit(
"exit",
payload
);
break;
default:
//console.warn(m);
break;
}
});
});
}
/*
User defined FUN-ctions!!!
*/
var textbuffer = "";
var first_append = true;
function appendmessage(msg, user, render = true){
var filetext = "";
for(var i=0; i<msg.files.length; i++){
if(i === 0){
filetext += "\n{light-blue-fg}";
}else{
filetext += "\n";
}
filetext += msg.files[i];
}
if(first_append === false){
textbuffer += "\n";
}else{
first_append = false;
}
textbuffer +=
"{bold}{red-fg}<" + blessed.escape(user.name) + ">{/red-fg}{/bold} " +
msg.text.trim()
.replace(
/^>[^>].*/gm,
function(match){
return "{light-green-fg}" + match + "{/light-green-fg}"
}
)
.replace(
/^<[^<].*/gm,
function(match){
return "{light-red-fg}" + match + "{/light-red-fg}"
}
) +
filetext;
messagelist.setContent(textbuffer);
if(render){
messagelist.setScrollPerc(100);
screen.render();
}
}
deek.on("login", function(channel){
messagelist =
blessed.box({
parent: screen,
label: '{bold}{cyan-fg}#' + channel.name + '{/cyan-fg}{/bold}',
tags: true,
border: 'line',
width: "100%",
top: 0,
left: 0,
bottom: 1,
scrollable: true,
scrollbar: {
ch:'',
track: {
bg: 'cyan'
},
style: {
inverse:true
}
}
});
var input =
blessed.textarea({
parent:screen,
bottom:0,
height:1,
inputOnFocus:true
});
/*
Append messages to list
*/
for(var i=0; i<previous_msg.length; i++){
for(var k=0; k<previous_msg[i].messages.length; k++){
var files = [];
for(var w=0; w<previous_msg[i].messages[k].files.length; w++){
files.push(
"https://deek.chat/storage/files/" + previous_msg[i].messages[k].files[w].name
);
}
appendmessage(
{
text: removehtml(previous_msg[i].messages[k].text),
id: previous_msg[i].messages[k].id,
files: files,
mentions: previous_msg[i].messages[k].mentions,
replies: previous_msg[i].messages[k].replies,
channel: channel_index
},
{
name: previous_msg[i].messages[k].user.name,
id: previous_msg[i].messages[k].user.id,
picture: previous_msg[i].messages[k].user.profilePicture == "" ? null : "https://deek.chat/storage/profilePictures/" + previous_msg[i].messages[k].user.profilePicture
},
false
);
}
}
//messagelist.pushLine("{light-gray-fg} * Connected to channel " + channel.name + " (id:" + channel.id + "){/light-gray-fg}");
input.focus();
messagelist.setScrollPerc(100);
screen.render();
input.key(['up', 'down'], function(ch, key){
if(key.name == "up"){
messagelist.scroll(-1);
}else{
messagelist.scroll(1);
}
screen.render();
});
input.key(['escape', 'C-c'], function(ch, key) {
return process.exit(0);
});
input.key("enter", async function(){
var sendmessage = this.getValue().trim();
if(sendmessage == ""){
return;
}
var check = false;
if(sendmessage[0] == "/"){
var cmd = sendmessage.split(" ")[0];
switch(cmd){
case "/help":
messagelist.pushLine("local command => {bold}/help{/bold}\n{light-gray-fg} * Client side commands:\n * /help\n * /list\n * /exit{/light-gray-fg}");
check = true;
break;
case "/list":
var users = "";
for(var i=0; i<channel.users.length; i++){
if(i !== 0){
users += ", ";
}
users += channel.users[i].name + " (" + channel.users[i].country.name + ")";
}
messagelist.pushLine("local command => {bold}/list{/bold}\n{light-gray-fg} * There are " + i + " deekers online:\n * " + users + "{/light-gray-fg}");
check = true;
break;
case "/exit":
process.exit(0);
break;
}
}
if(check === false){
send(channel.id, sendmessage);
}
this.clearValue();
messagelist.setScrollPerc(100);
screen.render();
});
});
deek.on("enter", async function(user){
//messagelist.pushLine("{light-gray-fg} * {bold}" + blessed.escape(user.name) + "{/bold} from " + user.country.name + " has joined{/light-gray-fg}");
messagelist.setScrollPerc(100);
screen.render();
});
deek.on("exit", async function(user){
//messagelist.pushLine("{light-gray-fg} * {bold}" + blessed.escape(user.name) + "{/bold} has left{/light-gray-fg}");
messagelist.setScrollPerc(100);
screen.render();
});
deek.on("message", async function(msg, user){
appendmessage(msg, user);
});
deek.on("close", async function(channel){
//messagelist.pushLine("{light-red-fg}It's over. Disconnected from channel " + channel.name + " (id:" + channel.id + "){/light-red-fg}");
messagelist.setScrollPerc(100);
screen.render();
});
deek.on("error", async function(message){
screen_msg.display("{light-red-fg}{bold}Serber error{/bold}\n" + message + ".\nUse CTRL+C to exit{/light-red-fg}");
screen.render();
});
// connect to serber
handshake();