nuggt69

Untitled

Nov 6th, 2019 (edited)
208
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 23.02 KB | None | 0 0
  1. // ==/UserScript==
  2. "use strict";
  3.  
  4. // fix for Chrome users who don't have Array.concat
  5. if(Array.concat === undefined) {
  6. Array.concat = function() {
  7. let arrs = Array.from(arguments);
  8. let arr0 = arrs.shift();
  9. return Array.prototype.concat.apply(arr0, arrs);
  10. };
  11. }
  12.  
  13. // hopefully these advice functions should be helpful for hooking internal events in a cleaner way in future revisions
  14. function withAdviceAround(advised, advice) {
  15. return function() {
  16. return advice.apply(this, Array.concat([advised], arguments));
  17. };
  18. }
  19. function withAdviceBefore(advised, advice) {
  20. return function() {
  21. advice.apply(this, arguments);
  22. return advised.apply(this, arguments);
  23. };
  24. }
  25.  
  26. let typerDelay = 125;
  27.  
  28. var ignoredusers = {
  29. ["chocolatebot"]: 1,
  30. ["ha3orx"]: 1,
  31. ["eeveevulpix"]: 1,
  32. ["inspector gadget bot"]: 1,
  33. ["grok gimme cock"]: 1,
  34. ["fuck you 1337"]: 1
  35. };
  36. var hideusers = /^(666|afk|c3po)$/i;
  37. var guests = /^guest\d+$/i;
  38.  
  39. var chatbox = document.getElementById("chat-box");
  40. var onlineusers = document.getElementById("online-users");
  41. var chatpanel = document.getElementById("chat-panel");
  42. var chatinput = document.getElementById("chat-input");
  43.  
  44. if(chatbox && onlineusers && chatpanel) {
  45. var rootButtonHolder = document.querySelector("#osk-btn").parentElement; // added by cat
  46. var initial = 1;
  47. var changedusers = [];
  48. var sentmessages = [];
  49. var sentindex = -1;
  50. var lastli;
  51. var lastdiv;
  52. var ignoredialog = element(
  53. document.body,
  54. ["div#ignoredialog", {
  55. class: "ignoredialog",
  56. tabIndex: -1
  57. },
  58. ["div", {
  59. onclick: function(event) {
  60. ignoredialog.blur();
  61. var name = event.currentTarget.parentNode.dataset.name.toLowerCase();
  62. var add;
  63. if(ignoredusers[name]) {
  64. ignoredusers[name] = 0;
  65. } else {
  66. ignoredusers[name] = 1;
  67. add = 1;
  68. }
  69. var usernames = document.querySelectorAll("#chat-box .username");
  70. for(var i = 0; i < usernames.length; i++) {
  71. if(usernames[i].firstChild.nodeValue.toLowerCase() == name) {
  72. usernames[i].parentNode.parentNode.style.display = add ? "none" : "";
  73. }
  74. }
  75. }
  76. }, "Ignore user"]
  77. ]
  78. ).ignoredialog;
  79.  
  80. // Detect changes in user list
  81. new MutationObserver(function(mutations) {
  82. mutations.forEach(function(mutation) {
  83. for(var thisnode of mutation.addedNodes) {
  84. let name = thisnode.firstChild.nodeValue;
  85. if(hideusers.test(name)) {
  86. thisnode.style.display = "none";
  87. } else if(!guests.test(name)) {
  88. changedusers.push([1, name]);
  89. asyncStrToColor(name).then(color => thisnode.style.color = color);
  90. }
  91. thisnode.addEventListener("contextmenu", function(event) {
  92. event.preventDefault();
  93. ignoredialog.style.left = (document.body.scrollLeft+event.clientX + 5) +"px";
  94. ignoredialog.style.top = (document.body.scrollTop + event.clientY + 5) + "px";
  95. ignoredialog.dataset.name = name;
  96. if(ignoredusers[name.toLowerCase()]) {
  97. ignoredialog.classList.add("ignored");
  98. } else {
  99. ignoredialog.classList.remove("ignored");
  100. }
  101. ignoredialog.focus();
  102. });
  103. }
  104. for(var removedNode of mutation.removedNodes) {
  105. let name = removedNode.firstChild.nodeValue;
  106. if(!hideusers.test(name)&&!guests.test(name)) {
  107. changedusers.push([-1, name]);
  108. }
  109. }
  110. });
  111. }).observe(onlineusers, {childList: 1});
  112.  
  113. // Detect changes in chat
  114. new MutationObserver(function(mutations) {
  115. var date = new Date();
  116. mutations.forEach(function(mutation) {
  117. for(var thisnode of mutation.addedNodes) {
  118. var username = thisnode.getElementsByClassName("username")[0];
  119. if(!initial)
  120. thisnode.firstChild.dataset.time = date.toLocaleTimeString(undefined, {
  121. hour12: false
  122. });
  123. if(username) {
  124. var user = username.firstChild.nodeValue;
  125. if(ignoredusers[user.toLowerCase()]) {
  126. thisnode.style.display = "none";
  127. } else {
  128. changedusers = [];
  129. lastli = lastdiv = null;
  130. }
  131. if(!guests.test(user)) {
  132. asyncStrToColor(user).then(color => username.style.color = color);
  133. }
  134. var textnode = thisnode.firstChild.lastChild;
  135. var text = textnode.nodeValue;
  136. textnode.nodeValue = text = text.replace(/(\\x[\da-f]{2}|\\u[\da-f]{4}|\\u{1[\da-f]{4}})+/g, function(ucode) {
  137. return String.fromCharCode(parseInt(ucode.substring(3, -1)));
  138. });
  139. const textClasses = [[">", "greentext"],
  140. ["<", "redtext"],
  141. ["^", "bluetext"],
  142. ["{", "blindyourasstext"]];
  143. for(let textClass of textClasses) {
  144. if(text[0] == textClass[0]) {
  145. textnode = element(
  146. ["span#textnode", {
  147. class: textClass[1]
  148. }, text]
  149. ).textnode;
  150. thisnode.firstChild.replaceChild(textnode, thisnode.firstChild.lastChild);
  151. textnode = textnode.firstChild;
  152. }
  153. }
  154. // added by cat
  155. if(text.startsWith("upd8-v0:")) {
  156. var chatnode = document.createElement("span");
  157. chatnode.classList.add("cvmutils-upd8-notif");
  158. var updMsg = document.createTextNode("This person is offering an encrypted update to CVMUtils. Do you want to install it? (This update will do nothing unless its creator has the release key, obtainable only from CVMUtils's code itself; in addition, your userscript manager may allow you to preview it before installing it.) ");
  159. var updURL = text.slice(5);
  160. var updBtn = document.createElement("button");
  161. updBtn.addEventListener("click", function() {
  162. asyncTryInstallUpdate(updURL);
  163. });
  164. updBtn.textContent = "Yes";
  165. chatnode.appendChild(updMsg);
  166. chatnode.appendChild(updBtn);
  167. thisnode.firstChild.replaceChild(chatnode, thisnode.firstChild.lastChild);
  168. textnode = null;
  169. }
  170. if(textnode != null) {
  171. // end of cat stuff
  172. var pos = [];
  173. var found;
  174. var nameregex = new RegExp(window.username, "ig");
  175. while((found = nameregex.exec(text)) != null) {
  176. pos.push([found.index, found[0].length]);
  177. }
  178. var urlregex = /(^|\b)(https?:\/\/[\w-]+(\.[\w-]+)+([\w., @?^=%&:/~+#\-()]*[\w@?^=%&/~+#\-()])?|(i\.)?imgur\.com\/[\w\-.?#]+)/ig;
  179. while((found = urlregex.exec(text)) != null) {
  180. pos.push([found.index, found[0].length]);
  181. }
  182. pos.sort((a, b) => b - a);
  183. for(let j = 0; j < pos.length; j++) {
  184. var rightpart = text.slice(pos[j][0] + pos[j][1]);
  185. var highlighttext = text.slice(pos[j][0], pos[j][0] + pos[j][1]);
  186. text = text.slice(0, pos[j][0]);
  187. textnode.nodeValue = text;
  188. let highlight;
  189. if(nameregex.test(highlighttext)) {
  190. highlight = element(
  191. ["span#highlight", {
  192. class: "mentioned"
  193. }, highlighttext]
  194. ).highlight;
  195. } else {
  196. highlight = element(
  197. ["a#highlight", {
  198. href: highlighttext,
  199. target: "_blank",
  200. rel: "noreferrer"
  201. }, highlighttext]
  202. ).highlight;
  203. }
  204. insertAfter(highlight, textnode);
  205. insertAfter(document.createTextNode(rightpart), highlight);
  206. }
  207. } // ending cat's if() statement
  208. }
  209. }
  210. });
  211. chatpanel.scrollTop = chatpanel.scrollHeight - chatpanel.offsetHeight;
  212. initial = 0;
  213. }).observe(chatbox, {childList: 1});
  214.  
  215. // Notify when a user joins or leaves in chat
  216. // TODO: make this actually in response to joining or leaving, rather than on an interval
  217. setInterval(function() {
  218. if(initial) {
  219. if(changedusers.length) {
  220. initial = 0;
  221. changedusers = [];
  222. }
  223. } else {
  224. var actualchanges = {};
  225. for(let i = 0; i < changedusers.length; i++) {
  226. // maintain a running tally of all the times that someone has joined or left
  227. // so that we can see if it cancels out
  228. actualchanges[changedusers[i][1]] = (actualchanges[changedusers[i][1]] || 0) + changedusers[i][0];
  229. }
  230. // parse the running tally
  231. var joined = [];
  232. var left = [];
  233. for(let i in actualchanges) {
  234. if(!ignoredusers[i.toLowerCase()]) {
  235. if(actualchanges[i] > 0) {
  236. joined.push(i);
  237. } else if(actualchanges[i] < 0) {
  238. left.push(i);
  239. }
  240. }
  241. }
  242. // assemble into a chat message
  243. var message = [];
  244. if(left.length) {
  245. message.push(left.join(", ") + " left");
  246. }
  247. if(joined.length) {
  248. message.push(joined.join(", ") + " joined");
  249. }
  250. message = message.join(". ");
  251. // overwrite previous joined/left message or make a new one
  252. if(message) {
  253. if(lastdiv) {
  254. lastdiv.firstChild.nodeValue = message;
  255. } else {
  256. chatmessage(message);
  257. }
  258. } else if(lastdiv) {
  259. chatbox.removeChild(lastli);
  260. lastli = lastdiv = null;
  261. }
  262. }
  263. }, 1000);
  264.  
  265. // Chat box extensions
  266. chatinput.maxLength = maxChatMsgLen;
  267. chatinput.onkeydown = function(event) {
  268. if(event.keyCode == 13) { // Enter
  269. event.preventDefault();
  270. var text = event.currentTarget.value;
  271. sentmessages.unshift(text);
  272. sentindex = -1;
  273. event.currentTarget.value = text.replace(/[^\da-z`~!@#$%^&*()\-_=+[\]{};"\\:"|, .\/<>? ]+/gi, jsesc).slice(0, maxChatMsgLen);
  274. document.getElementById("chat-send-btn").click();
  275. } else if(event.keyCode == 38) { // Up
  276. event.preventDefault();
  277. sentindex++;
  278. if(sentindex >= sentmessages.length) {
  279. sentindex = sentmessages.length - 1;
  280. }
  281. if(sentindex > -1) {
  282. event.currentTarget.value = sentmessages[sentindex];
  283. event.currentTarget.selectionStart = event.currentTarget.selectionEnd = event.currentTarget.value.length;
  284. }
  285. } else if(event.keyCode == 40) { // Down
  286. event.preventDefault();
  287. sentindex--;
  288. if(sentindex < 0) {
  289. sentindex = -1;
  290. event.currentTarget.value = "";
  291. } else {
  292. event.currentTarget.value = sentmessages[sentindex];
  293. event.currentTarget.selectionStart = event.currentTarget.selectionEnd=event.currentTarget.value.length;
  294. }
  295. }
  296. };
  297.  
  298. function blurchat() {
  299. var canvas = document.querySelector("#display>div>div>div");
  300. if(canvas && !canvas.onmousedown) {
  301. canvas.onmousedown = function() {
  302. document.getElementById("chat-input").blur();
  303. };
  304. }
  305. }
  306. blurchat();
  307. setInterval(blurchat, 500);
  308.  
  309. // cat stuff
  310. document.querySelector("#vote-btn").textContent = "Vote Yes";
  311. addButton("Vote No", voteNoForReset, rootButtonHolder);
  312. var cannedKeysHolder = document.createElement("div");
  313. addButton("Go to serial0", goToSerial0, cannedKeysHolder);
  314. addButton("Come from serial0", comeFromSerial0, cannedKeysHolder);
  315. addButton("C-M-<del>", ctrlAltDel, cannedKeysHolder);
  316. rootButtonHolder.appendChild(cannedKeysHolder);
  317. var typeHolder = document.createElement("div");
  318. addButton("Autotyper", typePrompt, typeHolder);
  319. addButton("Set autotyper speed", setAutotyperSpeed, typeHolder);
  320. rootButtonHolder.appendChild(typeHolder);
  321. var otpHolder = document.createElement("div");
  322. addButton("Show Daily 1TP", alertDailyPassword, otpHolder);
  323. addButton("Type Daily 1TP", typeDailyPassword, otpHolder);
  324. addButton("Show Daily Insecure/Leaked 1TP", alertLeakedDailyPassword, otpHolder);
  325. rootButtonHolder.appendChild(otpHolder);
  326. // end cat stuff
  327. }
  328.  
  329.  
  330. element(
  331. document.head,
  332. ["style", `
  333. .greentext{
  334. color:#789922;
  335. }
  336. .redtext{
  337. color:#f04747;
  338. }
  339. .bluetext{
  340. color:#208d99;
  341. }
  342. .blindyourasstext{
  343. color:#000000;
  344. background-color:#ffffff;
  345. }
  346. .mentioned{
  347. background-color: #000;
  348. color:#ffff88;
  349. }
  350. [data-time]::before{
  351. content:attr(data-time);
  352. font-size:12px;
  353. padding-right:3px;
  354. }
  355. .ignoredialog{
  356. position:absolute;
  357. background:#eee;
  358. cursor:default;
  359. z-index:1;
  360. outline:none;
  361. }
  362. .ignoredialog:not(:focus) {
  363. top:-999px!important
  364. }
  365. .ignoredialog>div{
  366. min-width:150px;
  367. overflow:hidden;
  368. display:flex;
  369. justify-content:center;
  370. flex-direction:column;
  371. padding:5px;
  372. padding:5px 5px 5px calc(1em + 5px);
  373. }
  374. .ignoredialog>div:hover{
  375. background:#e6e6e6;
  376. }
  377. .ignoredialog.ignored>div::before {
  378. content:"\\2713";
  379. position:absolute;
  380. margin-left:-1em;
  381. }
  382. #display :not(:first-child) {
  383. pointer-events:none;
  384. }
  385. #chat-box a {
  386. color: #00f;
  387. }
  388. .cvmutils-upd8-notif {
  389. background-color: #fcc;
  390. font-weight: bold;
  391. color: #000;
  392. }
  393. `]
  394. )
  395. // functions added by cat
  396.  
  397. function voteNoForReset() {
  398. tunnel.sendMessage("vote", "0");
  399. }
  400.  
  401. function goToSerial0() {
  402. tunnel.sendMessage("key", 65507, 1); // enable CTRL
  403. tunnel.sendMessage("key", 65513, 1); // enable ALT
  404. tunnel.sendMessage("key", 50, 1); // 2
  405. tunnel.sendMessage("key", 50, 0);
  406. tunnel.sendMessage("key", 65513, 0);
  407. tunnel.sendMessage("key", 65507, 0);
  408. }
  409.  
  410. function comeFromSerial0() {
  411. tunnel.sendMessage("key", 65507, 1); // enable CTRL
  412. tunnel.sendMessage("key", 65513, 1); // enable ALT
  413. tunnel.sendMessage("key", 49, 1); // 1
  414. tunnel.sendMessage("key", 49, 0);
  415. tunnel.sendMessage("key", 65513, 0);
  416. tunnel.sendMessage("key", 65507, 0);
  417. }
  418.  
  419. function ctrlAltDel() {
  420. tunnel.sendMessage("key", 65507, 1); // enable CTRL
  421. tunnel.sendMessage("key", 65513, 1); // enable ALT
  422. tunnel.sendMessage("key", 65535, 1); // DEL
  423. tunnel.sendMessage("key", 65535, 0);
  424. tunnel.sendMessage("key", 65513, 0);
  425. tunnel.sendMessage("key", 65507, 0);
  426. }
  427.  
  428. function turn() {
  429. tunnel.sendMessage("turn");
  430. }
  431.  
  432.  
  433.  
  434. // chars that we have to press SHIFT to type
  435. var shiftSpecialCharsStr = "!\"#$%&()*+:<>?@|~{}_";
  436. var shiftSpecialChars = (function(str) {
  437. var x = new Array(str.length);
  438. for(var i = 0; i < str.length; i++) {
  439. x[i] = str.charCodeAt(i);
  440. }
  441. return x;
  442. })(shiftSpecialCharsStr);
  443.  
  444. function writeRawCharacter(character) {
  445. turn();
  446. console.log("writing character", String.fromCharCode(character));
  447. var s = shiftSpecialChars.indexOf(character);
  448. if(s === -1) {
  449. tunnel.sendMessage("key", 65505, 0);
  450. tunnel.sendMessage("key", character, 1);
  451. tunnel.sendMessage("key", character, 0);
  452. } else {
  453. tunnel.sendMessage("key", 65505, 1);
  454. tunnel.sendMessage("key", character, 1);
  455. tunnel.sendMessage("key", character, 0);
  456. tunnel.sendMessage("key", 65505, 0);
  457. }
  458. }
  459.  
  460. function writeRawString(rawString) {
  461. var isString = typeof rawString == "string";
  462. for(var i = 0; i < rawString.length; i++) {
  463. var character = isString ? rawString.charCodeAt(i) : rawString[i];
  464. console.log("preparing to write raw character", String.fromCharCode(character));
  465. setTimeout(writeRawCharacter.bind(null, character), typerDelay * i);
  466. }
  467. }
  468.  
  469. function setAutotyperSpeed() {
  470. typerDelay = parseInt(prompt("How many milliseconds between characters? (Default 125; too fast may cause errors)")) || 125;
  471. }
  472.  
  473. function leftRotate(number, bits, totalBits) {
  474. var mask = 0xff;
  475. bits &= mask;
  476. return ((number << bits) & (1 << totalBits - 1)) | (number >> (-bits & mask));
  477. }
  478.  
  479. function generatorAsyncDailySecret(mode) {
  480. if(mode === undefined) mode = 1;
  481. const leakedSecret = [0xee, 0x03, 0x20, 0x0a, 0x7d, 0x3f, 0x3c, 0xb2, 0x30, 0x9d, 0xac, 0x91, 0xcb, 0x79, 0x7e, 0x89, 0x7e, 0x71, 0x4d, 0x4d, 0x93, 0xdf, 0xcd, 0xc7, 0x96, 0x78, 0x3b, 0xb5]; // icattellyou posted a version of the script containing this secret to the collabvm discord; it is now no longer to be used for secure purposes, only for quick, insecure interoperability with old script versions
  482. const trueSecret = [0x12, 0xb7, 0xdf, 0xcb, 0x0e, 0xa6, 0xdb, 0xd1, 0x84, 0x2b, 0x33, 0x21, 0x60, 0xa1, 0xbc, 0x41, 0x3f, 0xf2, 0x29, 0x6f, 0xde, 0x77, 0x96, 0x44, 0x44, 0xbc, 0xee, 0x88];
  483. const secretModes = [leakedSecret, trueSecret];
  484. var secret = secretModes[mode];
  485. var memoizedSecret;
  486. return function() {
  487. if(memoizedSecret === undefined) {
  488. var unixTime = new Date().getTime();
  489. var dayNumber = (unixTime / 86400000) | 0;
  490. var dayNumberBytes = [dayNumber & 0xff, (dayNumber >> 8) & 0xff, (dayNumber >> 16) & 0xff, (dayNumber >> 24) & 0xff];
  491. var dailyBytes = Array.concat(secret, dayNumberBytes);
  492. return crypto.subtle.digest("SHA-256", Uint8Array.from(dailyBytes)).then(function(digest) {
  493. memoizedSecret = new Uint8Array(digest);
  494. return memoizedSecret;
  495. });
  496. } else {
  497. return new Promise((resolve, reject) => resolve(memoizedSecret));
  498. }
  499. };
  500. }
  501.  
  502. var asyncGenerateDailySecret = generatorAsyncDailySecret();
  503.  
  504. var asyncGenerateDailyPassword = function() {
  505. return asyncGenerateDailySecret().then(secret => btoa(String.fromCharCode.apply(null, secret)));
  506. };
  507.  
  508. var asyncGenerateLeakedDailySecret = generatorAsyncDailySecret(0);
  509. var asyncGenerateLeakedDailyPassword = function() {
  510. return asyncGenerateLeakedDailySecret().then(secret => btoa(String.fromCharCode.apply(null, secret)));
  511. };
  512.  
  513. function alertDailyPassword() {
  514. asyncGenerateDailyPassword().then(alert);
  515. }
  516.  
  517. function alertLeakedDailyPassword() {
  518. asyncGenerateLeakedDailyPassword().then(alert);
  519. }
  520.  
  521. function typeDailyPassword() {
  522. asyncGenerateDailyPassword().then(writeRawString);
  523. }
  524.  
  525. function typePrompt() {
  526. var str = prompt("What do you want to type into the VM?");
  527. if(str != null) {
  528. writeRawString(str);
  529. }
  530. }
  531.  
  532. const updateSymmetricKey = Uint8Array.of(0xfb, 0xf0, 0x87, 0xdc, 0x0c, 0x96, 0x9f, 0x2f, 0xd5, 0x1f, 0xa4, 0x9e, 0x0f, 0xc5, 0xc2, 0xa1, 0x80, 0xb7, 0x76, 0xc2, 0x85, 0xd3, 0xf3, 0x39, 0x15, 0xa6, 0x9f, 0xa1, 0xda, 0x69, 0x9c, 0xef);
  533.  
  534. function asyncDecryptUpdate(bytes) {
  535. let iv = bytes.slice(0, 16);
  536. let encryptedData = bytes.slice(16);
  537. return new Promise((resolve, reject) =>
  538. crypto.subtle.importKey("raw",
  539. updateSymmetricKey,
  540. { "name": "aes-cbc" },
  541. false,
  542. ["decrypt"]).then(function(key) {
  543. crypto.decrypt({
  544. name: "AES-CBC",
  545. iv: iv
  546. }, key, encryptedData).then(resolve).catch(reject);
  547. }).catch(reject));
  548. }
  549.  
  550. function asyncVerifyUpdate(bytes) {
  551. let ubytes = Uint8Array.from(bytes);
  552. let sha256expected = ubytes.slice(0, 32);
  553. let protectedData = ubytes.slice(32);
  554. return new Promise((resolve, reject) =>
  555. crypto.subtle.digest("SHA-256", protectedData).then(sha256actual => {
  556. let udigest = Uint8Array.from(sha256actual);
  557. let ok = true;
  558. for(let i = 0; i < 32; i++)
  559. if(udigest[i] !== sha256expected[i]) {
  560. ok = false;
  561. reject("Digest mismatch; apparent tampering by courier!");
  562. }
  563. if(ok)
  564. resolve(protectedData);
  565. }).catch(reject));
  566. }
  567.  
  568. function asyncFetchAndDecryptUpdate(url) {
  569. return new Promise((resolve, reject) => {
  570. var rq = new XMLHttpRequest();
  571. rq.responseType = "arraybuffer";
  572. rq.onreadystatechange = function() {
  573. if(rq.readyState == 4) {
  574. if(rq.status >= 200 && rq.status < 300) {
  575. asyncDecryptUpdate(rq.response).then(function(bytes) {
  576. asyncVerifyUpdate(bytes).then(resolve).catch(reject);
  577. }).catch(reject);
  578. } else {
  579. reject(rq.statusText);
  580. }
  581. }
  582. };
  583. rq.open("GET", url, true);
  584. rq.send();
  585. });
  586. }
  587.  
  588. function asyncTryInstallUpdate(url) {
  589. asyncFetchAndDecryptUpdate(url).then(bytes => {
  590. // verify magic header
  591. // (ASCII text // ==)
  592. if(bytes[0] != 0x2f ||
  593. bytes[1] != 0x2f ||
  594. bytes[2] != 0x20 ||
  595. bytes[3] != 0x3d ||
  596. bytes[4] != 0x3d) {
  597. alert("Corrupt script or decryption failure");
  598. } else {
  599. window.open("data:text/javascript;base64, " + btoa(String.fromCharCode.apply(null, bytes)));
  600. }
  601. }).catch(error => alert("Encountered error while fetching and decrypting: " + error));
  602. }
  603.  
  604. function addButton(name, funct, holder) {
  605. var button = document.createElement("button");
  606. button.classList.add("btn");
  607. button.classList.add("btn-default");
  608. button.textContent = name;
  609. button.addEventListener("click", funct);
  610. holder.appendChild(button);
  611. }
  612.  
  613. window.installTunnelHook = function () { // designed to be manually invoked to log all tunnel messages to reverse-engineer the CollabVM client's controls
  614. tunnel.sendMessage = withAdviceBefore(tunnel.sendMessage, console.log);
  615. };
  616. // end of cat stuff
  617.  
  618. function chatmessage(text) {
  619. lastli = document.createElement("li");
  620. lastdiv = document.createElement("div");
  621. lastdiv.appendChild(document.createTextNode(text));
  622. lastli.appendChild(lastdiv);
  623. chatbox.appendChild(lastli);
  624. }
  625. function asyncStrToColor(str) {
  626. // chrome is ass
  627. /*
  628. let zx = [];
  629. for(let i = 0; i < str.length; i++) {
  630. // assuming this is a single UTF-16 bytepair!!!!!!
  631. let utf16bp = str.charCodeAt(i);
  632. zx[i] = utf16bp;
  633. }
  634. return crypto.subtle.digest("SHA-256", Uint16Array.from(zx)).then(digest => "#" + Array.from(new Uint8Array(digest).slice(0, 3)).map(byte => byte.toString(16).padStart(2, "0")).join(""));
  635. */
  636. let zx = [];
  637. for(let i = 0; i < str.length; i++) {
  638. let utf16bp = str.charCodeAt(i);
  639. zx[i] = utf16bp;
  640. }
  641. let r = 0;
  642. let g = 0;
  643. let b = 0;
  644. for(let i = 0; i < str.length; i += 3) {
  645. r ^= (zx[i] || 0) >> (g & 1);
  646. g ^= (zx[i + 1] || 0) >> (b & 1);
  647. b ^= (zx[i + 2] || 0) >> (r & 1);
  648. }
  649. return new Promise((resolve, reject) => resolve("#" + (r & 0xff).toString(16).padStart(2, "0") + (g & 0xff).toString(16).padStart(2, "0") + (b & 0xff).toString(16).padStart(2, "0")));
  650. }
  651. function element() {
  652. var parent;
  653. var lasttag;
  654. var createdtag;
  655. var toreturn = {};
  656. for(var i = 0; i < arguments.length; i++) {
  657. var current = arguments[i];
  658. if(current) {
  659. if(current.nodeType) {
  660. parent = lasttag = current;
  661. } else if(Array.isArray(current) && current.length > 0) {
  662. if(typeof current[0] == "string") {
  663. var tagNameSplitIdx = current[0].indexOf("#");
  664. var tagName = tagNameSplitIdx === -1 ? current[0] : current[0].substring(0, tagNameSplitIdx);
  665. var tagId = tagNameSplitIdx === -1 ? undefined : current[0].substring(tagNameSplitIdx + 1);
  666. lasttag = createdtag = document.createElement(tagName);
  667. if(tagId !== undefined)
  668. toreturn[tagId] = createdtag;
  669. }
  670. for(var j = 1; j < current.length; j++) {
  671. if(current[j]) {
  672. if(current[j].constructor == Object) {
  673. if(lasttag) {
  674. for(var value in current[j]) {
  675. if(value != "style" && value in lasttag) {
  676. lasttag[value] = current[j][value];
  677. } else {
  678. lasttag.setAttribute(value, current[j][value]);
  679. }
  680. }
  681. }
  682. } else {
  683. var returned = element(lasttag, current[j]);
  684. for(var k = 0; k < returned.length; k++) {
  685. toreturn[k] = returned[k];
  686. }
  687. }
  688. }
  689. }
  690. } else if(current) {
  691. createdtag = document.createTextNode(current);
  692. }
  693. if(parent&&createdtag) {
  694. parent.appendChild(createdtag);
  695. }
  696. createdtag = 0;
  697. }
  698. }
  699. return toreturn;
  700. }
  701. function insertAfter(append, target) {
  702. var parent = target.parentNode;
  703. var next = target.nextSibling;
  704. if(next) {
  705. parent.insertBefore(append, next);
  706. } else {
  707. parent.appendChild(append);
  708. }
  709. }
  710. function jsesc(str) {
  711. let result = [];
  712. for(let codePoint of str) {
  713. let codePointValue = codePoint.codePointAt(0);
  714. result.push(codePointValue > 0xff
  715. ? codePointValue > 0xffff ? `\\u{${codePointValue.toString(16)}}`
  716. : `\\u${codePointValue.toString(16).padStart(4, "0")}`
  717. : `\\x${codePointValue.toString(16).padStart(2, "0")}`);
  718. }
  719. return result.join("");
  720. }
Add Comment
Please, Sign In to add comment