// ==UserScript==
// @name Xat Plus
// @namespace http://sulptax.io/
// @version 0.4.7
// @description Unaffiliated extension for the Xat HTML5 Chatbox. RIP Xat Edition.
// @author sulptax
// @match https://xat.com/content/web/*/box/www/classic.html
// @require http://code.jquery.com/jquery-3.5.1.js
// @require https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.0.0/crypto-js.min.js
// @grant unsafeWindow
// ==/UserScript==
const secret = 'sulptax';
function xp_encrypt(str) {
return CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(str));
}
function xp_decrypt(str) {
return CryptoJS.enc.Base64.parse(str).toString(CryptoJS.enc.Utf8);
}
function xp_aes_encrypt(str) {
return CryptoJS.AES.encrypt(str, secret).toString();
}
function xp_aes_decrypt(str) {
var bytes = CryptoJS.AES.decrypt(str, secret);
return bytes.toString(CryptoJS.enc.Utf8);
}
// Allow functions below to be used in the console, not like these are used for storing important data anyways.
// You must be at the chat directly for these to work:
// https://xat.com/content/web/R00022/box/www/classic.html
unsafeWindow.xp_encrypt = xp_encrypt;
unsafeWindow.xp_decrypt = xp_decrypt;
var users = {
"585435788": {
"type": "color", // color, pawn, pawn2
"reghide": true, // like reghide power
"v": "000001", // the color value
},
"400444434": {
"type": "color",
"v": "y",
"effective": true, // overwrites the message pawn as well if true, This is the case by default.
"persistent": true // keep the pawn color regardless of the pawn used in the list
},
"287773358": { // Shadez bot is here for demonstration purposes, because it's everywhere.
"type": "pawn2", // pawn2 changes the pawn type
"v": "p1bot" // examples: p1bot, p1emerald, p1pwn
},
"981989": {
"type": "pawn2",
"v": "p1emerald#y" // can also use color codes in pawn2 value
},
"30000013": {
"type":"pawn2",
"v": "p1emerald#r#r"
}
}
var effectiveChanges = {}
const observer = new MutationObserver((mutationList, observer) => {
mutationList.forEach((mutation) => {
if (mutation.type === "childList") {
if (mutation.target.id == "idvisitors" || mutation.target.id == "idfriends" || mutation.target.id == "messages") {
mutation.addedNodes.forEach((node) => {
Object.keys(users).forEach(function(user) {
var color = "";
var holder = $(node).find(".holder:first");
var res = holder.attr("data-sm");
if ($(node).attr("data-user") == user) {
var str = res
if (res.split("#")[1] != "ff0000" && res.split("#")[1] != "ff0000)_20") {
if (users[$(node).attr("data-user")]['type'] == "color") {
color = users[$(node).attr("data-user")]['v']
res = str.split("#");
res[1] = color;
res = res.join("#");
res = res + ")_20"
}
if (users[$(node).attr("data-user")]['type'] == "pawn") {
res = users[$(node).attr("data-user")]['v']
}
var res3 = "";
if (users[$(node).attr("data-user")]['type'] == "pawn2") {
var res2 = str.split("#");
res2[0] = res2[0].split("(")[0] + "(" + users[$(node).attr("data-user")]['v'];
res = res2.join("#")
res3 = res.split("#", 2).join("#") + ")_20";
} else {
res3 = res;
}
if (Object.keys(users[$(node).attr("data-user")]).includes("reghide")) {
$(node).find(".relIcon2").hide();
}
var filters = "";
if (Object.keys(users[$(node).attr("data-user")]).includes("glow")) {
if(isColor(users[$(node).attr("data-user")]['glow'])) {
filters = filters + "drop-shadow(0px 0px 0.2rem " + users[$(node).attr("data-user")]['glow'] + ") "
}
}
if(filters) {
holder.css("filter", filters);
}
if (!(Object.keys(users[$(node).attr("data-user")]).includes("effective") && !(users[$(node).attr("data-user")]['effective'] == true))) {
effectiveChanges[$(node).find(".message").text()] = res3
} else if (color && (Object.keys(users[$(node).attr("data-user")]).includes("persistent") && users[$(node).attr("data-user")]['persistent'])) {
effectiveChanges[$(node).find(".message").text()] = "s_(p1pwn#" + color + ")_20"
}
holder.attr("data-sm", res)
}
}
});
});
}
}
});
});
messages.addMessageP = messages.addMessage
messages.addMessage = function(t) {
messages.addMessageP(t);
}
visitors.addVisitorP = visitors.addVisitor
visitors.addVisitor = function(e, l) {
visitors.addVisitorP(e, l);
var e_parsed = JSON.parse(e);
if (Object.keys(e_parsed).includes("image")) {
e_parsed['image'].split("#").forEach((im) => {
if (true) { // im.toString(CryptoJS.enc.Utf8)
try {
var checkForPawn = xp_decrypt(im)
if (checkForPawn && (checkForPawn.startsWith('{') && checkForPawn.endsWith('}'))) {
// example JSON
// {"type":"pawn2", "v":"p1emerald#y#hat3#w1i0ic#y", "reghide": true}
// {"type":"pawn2", "v":"p1emerald#y#hat3#w1i0ic#y", "reghide": true, "glow":"red"}
console.log("JSON PAWN DETECTED IN avatar/image:", checkForPawn);
try {
users[e_parsed['id']] = JSON.parse(checkForPawn);
} catch (e) {
console.log("Error parsing pawn code");
}
} else if (checkForPawn && checkForPawn.substring(0, 2) == "p1") {
console.log("NORMAL PAWN DETECTED IN avatar/image:", checkForPawn);
users[e_parsed['id']] = {
"type": "pawn2",
"v": checkForPawn
}
}
} catch(e) {
// decrypt error?
}
}
})
}
}
const observer2 = new MutationObserver((mutationList, observer) => {
mutationList.forEach((mutation) => {
if (mutation.type === "childList") {
mutation.addedNodes.forEach((node) => {
if (Object.keys(effectiveChanges).includes($(node).find(".messagesName").find(".message").text())) {
$(node).find(".messagesName").find(".holder:first").attr("data-sm", effectiveChanges[$(node).find(".messagesName").find(".message").text()])
}
});
}
});
});
observer.observe(document.querySelector("#visitorsContainer"), {
childList: true,
subtree: true
});
observer2.observe(document.querySelector("#messagesContainer"), {
childList: true,
subtree: true
});
function isColor(color) {
var div = $("<div>");
div.css("border", "1px solid " + color);
return (div.css("border-color") != "")
}