mirror of
https://github.com/gnh1201/caterpillar.git
synced 2024-11-26 15:31:45 +00:00
288 lines
12 KiB
HTML
288 lines
12 KiB
HTML
<!doctype html>
|
|
<html>
|
|
<head>
|
|
<title>Caterpillar Proxy Web Console</title>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
|
<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">
|
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/jquery.terminal/2.42.0/css/jquery.terminal.min.css" rel="stylesheet" type="text/css">
|
|
<link href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" rel="stylesheet" type="text/css">
|
|
<style type="text/css">/*<!--<![CDATA[*/
|
|
body {
|
|
background: #2e8d36 url(https://pub-1a7a176eea68479cb5423e44273657ad.r2.dev/bg.jpg) no-repeat;
|
|
background-size: cover;
|
|
background-position: center;
|
|
}
|
|
h1, p {
|
|
color: #093923;
|
|
}
|
|
p a {
|
|
color: #fff;
|
|
padding: 0 2px;
|
|
text-decoration: none;
|
|
border-bottom: 2px solid #fff;
|
|
}
|
|
main {
|
|
width: 640px;
|
|
margin: 0 auto;
|
|
}
|
|
.terminal, .cmd {
|
|
background: #093923;
|
|
}
|
|
/*]]>-->*/</style>
|
|
</head>
|
|
<body>
|
|
<main>
|
|
<h1>Caterpillar Proxy Web Console</h1>
|
|
<p>Download an worker script of <a href="https://github.com/gnh1201/caterpillar">Caterpillar Proxy</a>.</p>
|
|
<div id="console"></div>
|
|
<div id="map"></div>
|
|
<p><a href="https://github.com/gnh1201/caterpillar">Fork me. gnh1201/caterpillar (GitHub)</a></p>
|
|
</main>
|
|
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.7.1/jquery.min.js" type="text/javascript"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.terminal/2.42.0/js/jquery.terminal.min.js" type="text/javascript" ></script>
|
|
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" type="text/javascript"></script>
|
|
<script type="text/javascript">//<!--<![CDATA[
|
|
var env = {
|
|
"target": "http://localhost/",
|
|
"method": "",
|
|
"filename": null
|
|
};
|
|
var pretty_jsonify = function(data) {
|
|
return JSON.stringify(data, null, 4);
|
|
};
|
|
var download_text = function(filename, text) {
|
|
var element = document.createElement('a');
|
|
element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
|
|
element.setAttribute('download', filename);
|
|
element.style.display = 'none';
|
|
document.body.appendChild(element);
|
|
element.click();
|
|
document.body.removeChild(element);
|
|
}
|
|
var jsonrpc2_request = function(term, method, params) {
|
|
var requestData = {
|
|
jsonrpc: "2.0",
|
|
method: method,
|
|
params: params,
|
|
id: null
|
|
};
|
|
|
|
$.ajax({
|
|
url: env.target,
|
|
type: 'POST',
|
|
contentType: 'application/json',
|
|
dataType: 'text',
|
|
data: JSON.stringify(requestData),
|
|
beforeSend: function(xhr) {
|
|
xhr.setRequestHeader("X-User-Agent", "php-httpproxy/0.1.5 (Client; WebConsole; abuse@catswords.net)");
|
|
},
|
|
success: function(response) {
|
|
var responseData = {
|
|
"error": {
|
|
"message": "Unknown error"
|
|
}
|
|
};
|
|
var process_corrupted_json = function(s) {
|
|
// for dirty response (e.g., magic header, advertise logo)
|
|
try {
|
|
var start = s.indexOf('{');
|
|
var end = s.lastIndexOf('}');
|
|
if (start > -1 && end > -1 && end > start) {
|
|
responseData = JSON.parse(s.substring(start, end + 1));
|
|
} else {
|
|
throw new Error("It does not seem like a JSON format.");
|
|
}
|
|
} catch (e) {
|
|
responseData.error.message = e.message
|
|
+ "\r\nRaw response data:"
|
|
+ "\r\n" + response;
|
|
}
|
|
};
|
|
|
|
try {
|
|
if (response.trim() == "") {
|
|
responseData.error.message = "Received an empty response data";
|
|
} else {
|
|
responseData = JSON.parse(response);
|
|
}
|
|
} catch (e) {
|
|
responseData.error.message = e.message;
|
|
process_corrupted_json(response);
|
|
}
|
|
|
|
var text = "";
|
|
if ("error" in responseData) {
|
|
text = responseData.error.message;
|
|
} else {
|
|
if (typeof responseData.result.data === "object") {
|
|
text = pretty_jsonify(responseData.result.data);
|
|
} else {
|
|
text = responseData.result.data;
|
|
}
|
|
}
|
|
term.echo(text);
|
|
|
|
// save as a file
|
|
if (env.filename != null) {
|
|
download_text(env.filename, text);
|
|
}
|
|
|
|
// method(relay_get_geolocation)
|
|
if (env.method == "relay_get_geolocation") {
|
|
var geodata = responseData.result.data;
|
|
|
|
term.echo('', {
|
|
finalize: function($div) {
|
|
$div.children().last().append($("#map").css("height", "130px"));
|
|
map.setView([geodata.lat, geodata.lon], 13);
|
|
var circle = L.circle([geodata.lat, geodata.lon], {
|
|
color: 'red',
|
|
fillColor: '#f03',
|
|
fillOpacity: 0.5,
|
|
radius: 500
|
|
}).addTo(map);
|
|
term.echo();
|
|
}
|
|
});
|
|
}
|
|
},
|
|
error: function(xhr, status, error) {
|
|
term.echo(error);
|
|
}
|
|
});
|
|
};
|
|
|
|
jQuery(function($, undefined) {
|
|
$('#console').terminal({
|
|
set: function(k, v) {
|
|
if (k == "env") {
|
|
this.echo("env is the reserved word");
|
|
return;
|
|
}
|
|
|
|
env[k] = v || null;
|
|
|
|
if (k == "method") {
|
|
this.set_prompt('method([[b;red;black]' + env.method + '])> ');
|
|
|
|
if (env.method == "relay_mysql_query") {
|
|
var _env = {
|
|
"mysql_hostname": "localhost",
|
|
"mysql_username": "root",
|
|
"mysql_password": null,
|
|
"mysql_database": null,
|
|
"mysql_port": "3306",
|
|
"mysql_charset": "utf8"
|
|
};
|
|
|
|
for (k in _env) {
|
|
if (!(k in env)) {
|
|
env[k] = _env[k];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
show: function(k) {
|
|
var v = env[k];
|
|
|
|
if (typeof env[k] === "object") {
|
|
this.echo(pretty_jsonify(v));
|
|
} else if (k == "env") {
|
|
this.echo(pretty_jsonify(env));
|
|
} else {
|
|
this.echo(v);
|
|
}
|
|
},
|
|
do: function(...args) {
|
|
if (env.method == "") {
|
|
this.echo("Please set a method");
|
|
return;
|
|
}
|
|
|
|
// method(relay_invoke_method)
|
|
if (env.method == "relay_invoke_method") {
|
|
if (args.length < 1) {
|
|
this.echo("Please set a callback");
|
|
return;
|
|
}
|
|
|
|
jsonrpc2_request(this, env.method, {
|
|
"callback": args[0],
|
|
"args": args.slice(1)
|
|
});
|
|
return;
|
|
}
|
|
|
|
// method(relay_dns_get_record)
|
|
if (env.method == "relay_dns_get_record") {
|
|
if (args.length < 1) {
|
|
this.echo("Please set a hostname");
|
|
return;
|
|
}
|
|
|
|
jsonrpc2_request(this, env.method, {
|
|
"hostname": args[0]
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
// method(relay_fetch_url)
|
|
if (env.method == "relay_fetch_url") {
|
|
if (args.length < 1) {
|
|
this.echo("Please set a URL");
|
|
return;
|
|
}
|
|
|
|
jsonrpc2_request(this, env.method, {
|
|
"url": args[0]
|
|
});
|
|
|
|
return;
|
|
}
|
|
|
|
// method(relay_mysql_query)
|
|
if (env.method == "relay_mysql_query") {
|
|
var _this = this;
|
|
var do_query = function(query) {
|
|
jsonrpc2_request(_this, env.method, {
|
|
"hostname": env.mysql_hostname,
|
|
"username": env.mysql_username,
|
|
"password": env.mysql_password,
|
|
"database": env.mysql_database,
|
|
"port": env.mysql_port,
|
|
"charset": env.mysql_charset,
|
|
"query": query
|
|
});
|
|
}
|
|
|
|
if (args.length < 1) {
|
|
this.read("Enter MySQL query:\r\n", do_query);
|
|
} else {
|
|
do_query(args.join(' '));
|
|
}
|
|
return;
|
|
}
|
|
|
|
// method(*)
|
|
jsonrpc2_request(this, env.method, {});
|
|
}
|
|
}, {
|
|
height: 480,
|
|
width: 640,
|
|
prompt: '> ',
|
|
checkArity: false
|
|
});
|
|
});
|
|
|
|
var map = L.map('map');
|
|
L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', {
|
|
maxZoom: 19,
|
|
attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>'
|
|
}).addTo(map);
|
|
//]]>--></script>
|
|
</body>
|
|
</html>
|