This commit is contained in:
2023-11-07 08:04:56 -05:00
parent 64b090ee05
commit 785452873f
59 changed files with 2592 additions and 1277 deletions

View File

@@ -318,11 +318,23 @@ if(image_class !== null){
image_url = htmlspecialchars_decode(image_url);
}
var w = Math.round(click.target.naturalWidth);
var h = Math.round(click.target.naturalHeight);
if(
w === 0 ||
h === 0
){
w = 100;
h = 100;
}
collection = [
{
"url": image_url,
"width": Math.round(click.target.naturalWidth),
"height": Math.round(click.target.naturalHeight)
"width": w,
"height": h
}
];
@@ -362,10 +374,22 @@ if(image_class !== null){
var imagesize = elem.getElementsByTagName("img")[0];
var imagesize_w = 0;
var imagesize_h = 0;
if(imagesize.complete){
var imagesize_w = imagesize.naturalWidth;
var imagesize_h = imagesize.naturalHeight;
imagesize_w = imagesize.naturalWidth;
imagesize_h = imagesize.naturalHeight;
}
if(
imagesize_w === 0 ||
imagesize_h === 0
){
imagesize_w = 100;
imagesize_h = 100;
}
for(var i=0; i<collection.length; i++){

495
static/serverping.js Normal file
View File

@@ -0,0 +1,495 @@
function htmlspecialchars(str){
if(str === null){
return "<i>&lt;Empty&gt;</i>";
}
var map = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#039;'
}
return str.replace(/[&<>"']/g, function(m){return map[m];});
}
// initialize garbage
var list = [];
var pinged_list = [];
var reqs = 0;
var errors = 0;
var sort = 0; // lower ping first
// check for instance redirect stuff
var redir = "";
var target = "/web?";
new URL(window.location.href)
.searchParams
.forEach(
function(value, key){
if(key == "target"){
target = "/" + encodeURIComponent(value) + "?";
return;
}
if(key == "npt"){ return; }
redir += encodeURIComponent(key) + "=" + encodeURIComponent(value)
}
);
if(redir != ""){
redir = target + redir;
}
var quote = document.createElement("div");
quote.className = "quote";
quote.innerHTML = 'Pinged <b>0</b> servers (<b>0</b> failed requests)';
var [div_servercount, div_failedreqs] =
quote.getElementsByTagName("b");
var noscript = document.getElementsByTagName("noscript")[0];
document.body.insertBefore(quote, noscript.nextSibling);
// create table
var table = document.createElement("table");
table.innerHTML =
'<thead>' +
'<tr>' +
'<th><div class="arrow up"></div>Ping</th>' +
'<th class="extend">Server</th>' +
'<th>Address</th>' +
'<th>Bot protection</th>' +
'<th title="Amount of legit requests processed since the last APCU cache clear (usually happens at midnight)">Real reqs (?)</th>' +
'<th title="Amount of filtered requests processed since the last APCU cache clear (usually happens at midnight)">Bot reqs (?)</th>' +
'<th>API</th>' +
'<th>Version</th>' +
'</tr>' +
'</thead>' +
'<tbody></tbody>';
document.body.insertBefore(table, quote.nextSibling);
// handle sorting clicks
var tbody = table.getElementsByTagName("tbody")[0];
var th = table.getElementsByTagName("th");
for(var i=0; i<th.length; i++){
th[i].addEventListener("click", function(event){
if(event.target.className.includes("arrow")){
var div = event.target.parentElement;
}else{
var div = event.target;
}
var arrow = div.getElementsByClassName("arrow");
var orientation = 0; // up
if(arrow.length === 0){
// delete arrow and add new one
arrow = document.getElementsByClassName("arrow");
arrow[0].remove();
arrow = document.createElement("div");
arrow.className = "arrow up";
div.insertBefore(arrow, event.target.firstChild);
}else{
// switch arrow position
if(arrow[0].className == "arrow down"){
arrow[0].className = "arrow up";
}else{
arrow[0].className = "arrow down";
orientation = 1;
}
}
switch(div.textContent.toLowerCase()){
case "ping": sort = orientation; break;
case "server": sort = 2 + orientation; break;
case "address": sort = 4 + orientation; break;
case "bot protection": sort = 6 + orientation; break;
case "real reqs (?)": sort = 8 + orientation; break;
case "bot reqs (?)": sort = 10 + orientation; break;
case "api": sort = 12 + orientation; break;
case "version": sort = 14 + orientation; break;
}
render_list();
});
}
function validate_url(url, allow_http = false){
try{
url = new URL(url);
if(
url.protocol == "https:" ||
(
(
allow_http === true ||
window.location.protocol == "http:"
) &&
url.protocol == "http:"
)
){
return true;
}
}catch(error){} // do nothing
return false;
}
function number_format(int){
return new Intl.NumberFormat().format(int);
}
// parse initial server list
fetch_server(window.location.origin);
async function fetch_server(server){
if(!validate_url(server)){
console.warn("Invalid server URL: " + server);
return;
}
// make sure baseURL is origin
server = new URL(server).origin;
// prevent multiple fetches
for(var i=0; i<list.length; i++){
if(list[i] == server){
// serber was already fetched
console.info("Already checked server: " + server);
return;
}
}
// prevent future fetches
list.push(server);
var data = null;
var ping = new Date().getTime();
try{
data = await fetch(
server + "/ami4get"
);
if(data.status !== 200){
// endpoint is not available
errors++;
div_failedreqs.textContent = number_format(errors);
console.warn(server + ": Invalid HTTP code " + data.status);
return;
}
data = await data.json();
data.server.ping = new Date().getTime() - ping;
}catch(error){
errors++;
div_failedreqs.textContent = number_format(errors);
console.warn(server + ": Could not fetch or decode JSON");
return;
}
// sanitize data
if(
typeof data.status != "string" ||
data.status != "ok" ||
typeof data.server != "object" ||
!(
typeof data.server.name == "string" ||
(
typeof data.server.name == "object" &&
data.server.name === null
)
) ||
typeof data.service != "string" ||
data.service != "4get" ||
(
typeof data.server.description != "string" &&
data.server.description !== null
) ||
typeof data.server.bot_protection != "number" ||
typeof data.server.real_requests != "number" ||
typeof data.server.bot_requests != "number" ||
typeof data.server.api_enabled != "boolean" ||
typeof data.server.alt_addresses != "object" ||
typeof data.server.version != "number" ||
typeof data.instances != "object"
){
errors++;
div_failedreqs.textContent = number_format(errors);
console.warn(server + ": Malformed JSON");
return;
}
data.server.ip = server;
reqs++;
div_servercount.textContent = number_format(reqs);
var total = pinged_list.push(data) - 1;
pinged_list[total].index = total;
render_list();
// get more serbers
for(var i=0; i<data.instances.length; i++){
fetch_server(data.instances[i]);
}
}
function sorta(object, element, order){
return object.slice().sort(
function(a, b){
if(order){
return a.server[element] - b.server[element];
}
return b.server[element] - a.server[element];
}
);
}
function textsort(object, element, order){
var sort = object.slice().sort(
function(a, b){
return a.server[element].localeCompare(b.server[element]);
}
);
if(!order){
return sort.reverse();
}
return sort;
}
function render_list(){
var sorted_list = [];
// sort
var filter = Boolean(sort % 2);
switch(sort){
case 0:
case 1:
sorted_list = sorta(pinged_list, "ping", filter === true ? false : true);
break;
case 2:
case 3:
sorted_list = textsort(pinged_list, "name", filter === true ? false : true);
break;
case 4:
case 5:
sorted_list = textsort(pinged_list, "ip", filter === true ? false : true);
break;
case 6:
case 7:
sorted_list = sorta(pinged_list, "bot_protection", filter === true ? false : true);
break;
case 8:
case 9:
sorted_list = sorta(pinged_list, "real_requests", filter);
break;
case 10:
case 11:
sorted_list = sorta(pinged_list, "bot_requests", filter);
break;
case 12:
case 13:
sorted_list = sorta(pinged_list, "api_enabled", filter);
break;
case 14:
case 15:
sorted_list = sorta(pinged_list, "version", filter);
break;
}
// render tabloid
var html = "";
for(var k=0; k<sorted_list.length; k++){
html += '<tr onclick="show_server(' + sorted_list[k].index + ');">';
for(var i=0; i<8; i++){
html += '<td';
switch(i){
case 0: // server ping
if(sorted_list[k].server.ping <= 100){
html += '><span style="color:var(--green);">' + sorted_list[k].server.ping + '</span>';
break;
}
if(sorted_list[k].server.ping <= 200){
html += '><span style="color:var(--yellow);">' + sorted_list[k].server.ping + '</span>';
break;
}
html += '><span style="color:var(--red);">' + number_format(sorted_list[k].server.ping) + '</span>';
break;
// server name
case 1: html += ' class="extend">' + htmlspecialchars(sorted_list[k].server.name); break;
case 2: html += '>' + htmlspecialchars(new URL(sorted_list[k].server.ip).host); break;
case 3: // bot protection
switch(sorted_list[k].server.bot_protection){
case 0:
html += '><span style="color:var(--green);">Disabled</span>';
break;
case 1:
html += '><span style="color:var(--yellow);">Image captcha</span>';
break;
case 2:
html += '><span style="color:var(--red);">Invite only</span>';
break;
default:
html += '>Unknown';
}
break;
case 4: // real reqs
html += '>' + number_format(sorted_list[k].server.real_requests);
break;
case 5: // bot reqs
html += '>' + number_format(sorted_list[k].server.bot_requests);
break;
case 6: // api enabled
if(sorted_list[k].server.api_enabled){
html += '><span style="color:var(--green);">Yes</span>';
}else{
html += '><span style="color:var(--red);">No</span>';
}
break;
// version
case 7: html += ">v" + sorted_list[k].server.version; break;
}
html += '</td>';
}
html += '</tr>';
}
tbody.innerHTML = html;
}
var popup_bg = document.getElementById("popup-bg");
var popup_wrapper = document.getElementsByClassName("popup-wrapper")[0];
var popup = popup_wrapper.getElementsByClassName("popup")[0];
var popup_shown = false;
popup_bg.addEventListener("click", function(){
popup_wrapper.style.display = "none";
popup_bg.style.display = "none";
});
function show_server(serverid){
var html =
'<h2>' + htmlspecialchars(pinged_list[serverid].server.name) + '</h2>' +
'Description' +
'<div class="code">' + htmlspecialchars(pinged_list[serverid].server.description) + '</div>';
var url_obj = new URL(pinged_list[serverid].server.ip);
var url = htmlspecialchars(url_obj.origin);
var domain = url_obj.hostname;
html +=
'URL: <a rel="noreferer" target="_BLANK" href="' + url + redir + '">' + url + '</a> <a rel="noreferer" target="_BLANK" href="https://browserleaks.com/ip/' + encodeURIComponent(domain) + '">(IP lookup)</a>' +
'<br><br>Alt addresses:';
var len = pinged_list[serverid].server.alt_addresses.length;
if(len === 0){
html += ' <i>&lt;Empty&gt;</i>';
}else{
html += '<ul>';
for(var i=0; i<len; i++){
var url_obj = new URL(pinged_list[serverid].server.alt_addresses[i]);
var url = htmlspecialchars(url_obj.origin);
var domain = url_obj.hostname;
if(validate_url(pinged_list[serverid].server.alt_addresses[i], true)){
html += '<li><a rel="noreferer" href="' + url + redir + '" target="_BLANK">' + url + '</a> <a rel="noreferer" target="_BLANK" href="https://browserleaks.com/ip/' + encodeURIComponent(domain) + '">(IP lookup)</a></li>';
}else{
console.warn(pinged_list[serverid].server.ip + ": Invalid peer URL => " + pinged_list[serverid].server.alt_addresses[i]);
}
}
html += '</ul>';
}
popup.innerHTML = html;
popup_wrapper.style.display = "block";
popup_bg.style.display = "block";
}
function hide_server(){
popup_wrapper.style.display = "none";
popup_bg.style.display = "none";
}

View File

@@ -1,7 +1,3 @@
/*
Global styles
*/
:root{
/* background */
--1d2021: #1d2021;
@@ -21,31 +17,11 @@
--default: #d4be98;
--keyword: #d8a657;
--string: #7daea7;
}
.theme-white{
/* background */
--1d2021: #bdae93;
--282828: #a89984;
--3c3836: #a89984;
--504945: #504945;
/* font */
--928374: #1d2021;
--a89984: #282828;
--bdae93: #3c3836;
--8ec07c: #52520e;
--ebdbb2: #1d2021;
/* code highlighter */
--comment: #6a4400;
--default: #d4be98;
--keyword: #4a4706;
--string: #076678;
}
.theme-white .autocomplete .entry:hover{
background:#928374;
/* color codes for instance list */
--green: #b8bb26;
--yellow: #d8a657;
--red: #fb4934;
}
audio{
@@ -516,6 +492,7 @@ h3,h4,h5,h6{
.web .favicon img,
.favicon-dropdown img{
margin:3px 7px 0 0;
width:16px;
height:16px;
font-size:12px;
line-height:16px;
@@ -1020,6 +997,7 @@ table tr a:last-child{
cursor:grab;
user-select:none;
pointer-events:none;
z-index:5;
}
#popup:active{
@@ -1046,6 +1024,7 @@ table tr a:last-child{
height:35px;
background:var(--1d2021);
border-bottom:1px solid var(--928374);
z-index:4;
}
#popup-bg{
@@ -1057,6 +1036,7 @@ table tr a:last-child{
width:100%;
height:100%;
display:none;
z-index:3;
}
#popup-status select{
@@ -1166,6 +1146,108 @@ table tr a:last-child{
color:var(--string);
}
/*
Instances page
*/
.instances table{
white-space:nowrap;
margin-top:17px;
}
.instances a{
color:var(--bdae93);
}
.instances tbody tr:nth-child(even){
background:var(--282828);
}
.instances thead{
outline:1px solid var(--928374);
outline-offset:-1px;
background:var(--3c3836);
user-select:none;
z-index:2;
position:sticky;
top:0;
}
.instances th{
cursor:row-resize;
}
.instances th:hover{
background:var(--504945);
}
.instances tbody{
outline:1px solid var(--504945);
outline-offset:-1px;
position:relative;
top:-1px;
}
.instances tbody tr:hover{
background:var(--3c3836);
cursor:pointer;
}
.instances .arrow{
display:inline-block;
position:relative;
top:6px;
margin-right:7px;
width:0;
height:0;
border:6px solid transparent;
border-top:10px solid var(--bdae93);
}
.instances .arrow.up{
top:0;
border:6px solid transparent;
border-bottom:10px solid var(--bdae93);
}
.instances th, .instances td{
padding:4px 7px;
width:0;
}
.instances .extend{
width:unset;
overflow:hidden;
max-width:200px;
}
.instances .popup-wrapper{
display:none;
position:fixed;
left:50%;
top:50%;
transform:translate(-50%, -50%);
width:800px;
max-width:100%;
max-height:100%;
overflow-x:auto;
padding:17px;
box-sizing:border-box;
pointer-events:none;
z-index:3;
}
.instances .popup{
border:1px solid var(--928374);
background:var(--282828);
padding:7px 10px;
pointer-events:initial;
}
.instances ul{
padding-left:20px;
}
/*
Responsive image
*/
@@ -1221,7 +1303,7 @@ table tr a:last-child{
width:100%;
}
table td{
body:not(.instances) table td{
display:block;
width:100%;
}

31
static/themes/Cream.css Normal file
View File

@@ -0,0 +1,31 @@
:root{
/* background */
--1d2021: #bdae93;
--282828: #a89984;
--3c3836: #a89984;
--504945: #504945;
/* font */
--928374: #1d2021;
--a89984: #282828;
--bdae93: #3c3836;
--8ec07c: #52520e;
--ebdbb2: #1d2021;
/* code highlighter */
--comment: #6a4400;
--default: #d4be98;
--keyword: #4a4706;
--string: #076678;
/* color codes for instance list */
--green: #636311;
--yellow: #8a6214;
--red: #711410;
}
.autocomplete .entry:hover,
.instances th:hover
{
background:#928374;
}