Updates v2.6.1

+ Added reverse proxy TLS skip verification
+ Added basic auth
+ Edit proxy settings
+ Whitelist
+ TCP Proxy (experimental)
+ Info (Utilities page)
This commit is contained in:
Toby Chui
2023-05-31 22:22:47 +08:00
parent 5952a1b55f
commit 20fd8e9a49
42 changed files with 87636 additions and 1165 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,714 +0,0 @@
<div class="standardContainer">
<div class="ui basic segment">
<h2>Blacklist</h2>
<p>Setup blacklist based on estimated IP geographic location or IP address</p>
</div>
<div class="ui divider"></div>
<div class="ui toggle checkbox">
<input type="checkbox" id="enableBlacklist">
<label>Enable Blacklist</label>
</div>
<div id="toggleSucc" style="float: right; display:none; color: #2abd4d;" >
<i class="ui green checkmark icon"></i> Setting Saved
</div>
<div class="ui message">
<i class="info circle icon"></i> Blacklist function require complex checking logic to validate each incoming request. Not recommend enabling this feature on servers with low end hardware.
</div>
<h4>Country Blacklist</h4>
<p><i class="yellow exclamation triangle icon"></i>
This will block all requests from the selected country. The requester's location is estimated from their IP address and may not be 100% accurate.</p>
<div class="ui form">
<div class="field">
<label>Select Country</label>
<div id="countrySelector" class="ui fluid search selection dropdown">
<input type="hidden" name="country">
<i class="dropdown icon"></i>
<div class="default text">Select Country</div>
<div class="menu">
<div class="item" data-value="af"><i class="af flag"></i>Afghanistan</div>
<div class="item" data-value="ax"><i class="ax flag"></i>Aland Islands</div>
<div class="item" data-value="al"><i class="al flag"></i>Albania</div>
<div class="item" data-value="dz"><i class="dz flag"></i>Algeria</div>
<div class="item" data-value="as"><i class="as flag"></i>American Samoa</div>
<div class="item" data-value="ad"><i class="ad flag"></i>Andorra</div>
<div class="item" data-value="ao"><i class="ao flag"></i>Angola</div>
<div class="item" data-value="ai"><i class="ai flag"></i>Anguilla</div>
<div class="item" data-value="ag"><i class="ag flag"></i>Antigua</div>
<div class="item" data-value="ar"><i class="ar flag"></i>Argentina</div>
<div class="item" data-value="am"><i class="am flag"></i>Armenia</div>
<div class="item" data-value="aw"><i class="aw flag"></i>Aruba</div>
<div class="item" data-value="au"><i class="au flag"></i>Australia</div>
<div class="item" data-value="at"><i class="at flag"></i>Austria</div>
<div class="item" data-value="az"><i class="az flag"></i>Azerbaijan</div>
<div class="item" data-value="bs"><i class="bs flag"></i>Bahamas</div>
<div class="item" data-value="bh"><i class="bh flag"></i>Bahrain</div>
<div class="item" data-value="bd"><i class="bd flag"></i>Bangladesh</div>
<div class="item" data-value="bb"><i class="bb flag"></i>Barbados</div>
<div class="item" data-value="by"><i class="by flag"></i>Belarus</div>
<div class="item" data-value="be"><i class="be flag"></i>Belgium</div>
<div class="item" data-value="bz"><i class="bz flag"></i>Belize</div>
<div class="item" data-value="bj"><i class="bj flag"></i>Benin</div>
<div class="item" data-value="bm"><i class="bm flag"></i>Bermuda</div>
<div class="item" data-value="bt"><i class="bt flag"></i>Bhutan</div>
<div class="item" data-value="bo"><i class="bo flag"></i>Bolivia</div>
<div class="item" data-value="ba"><i class="ba flag"></i>Bosnia</div>
<div class="item" data-value="bw"><i class="bw flag"></i>Botswana</div>
<div class="item" data-value="bv"><i class="bv flag"></i>Bouvet Island</div>
<div class="item" data-value="br"><i class="br flag"></i>Brazil</div>
<div class="item" data-value="vg"><i class="vg flag"></i>British Virgin Islands</div>
<div class="item" data-value="bn"><i class="bn flag"></i>Brunei</div>
<div class="item" data-value="bg"><i class="bg flag"></i>Bulgaria</div>
<div class="item" data-value="bf"><i class="bf flag"></i>Burkina Faso</div>
<div class="item" data-value="mm"><i class="mm flag"></i>Burma</div>
<div class="item" data-value="bi"><i class="bi flag"></i>Burundi</div>
<div class="item" data-value="tc"><i class="tc flag"></i>Caicos Islands</div>
<div class="item" data-value="kh"><i class="kh flag"></i>Cambodia</div>
<div class="item" data-value="cm"><i class="cm flag"></i>Cameroon</div>
<div class="item" data-value="ca"><i class="ca flag"></i>Canada</div>
<div class="item" data-value="cv"><i class="cv flag"></i>Cape Verde</div>
<div class="item" data-value="ky"><i class="ky flag"></i>Cayman Islands</div>
<div class="item" data-value="cf"><i class="cf flag"></i>Central African Republic</div>
<div class="item" data-value="td"><i class="td flag"></i>Chad</div>
<div class="item" data-value="cl"><i class="cl flag"></i>Chile</div>
<div class="item" data-value="cn"><i class="cn flag"></i>China</div>
<div class="item" data-value="cx"><i class="cx flag"></i>Christmas Island</div>
<div class="item" data-value="cc"><i class="cc flag"></i>Cocos Islands</div>
<div class="item" data-value="co"><i class="co flag"></i>Colombia</div>
<div class="item" data-value="km"><i class="km flag"></i>Comoros</div>
<div class="item" data-value="cg"><i class="cg flag"></i>Congo Brazzaville</div>
<div class="item" data-value="cd"><i class="cd flag"></i>Congo</div>
<div class="item" data-value="ck"><i class="ck flag"></i>Cook Islands</div>
<div class="item" data-value="cr"><i class="cr flag"></i>Costa Rica</div>
<div class="item" data-value="ci"><i class="ci flag"></i>Cote Divoire</div>
<div class="item" data-value="hr"><i class="hr flag"></i>Croatia</div>
<div class="item" data-value="cu"><i class="cu flag"></i>Cuba</div>
<div class="item" data-value="cy"><i class="cy flag"></i>Cyprus</div>
<div class="item" data-value="cz"><i class="cz flag"></i>Czech Republic</div>
<div class="item" data-value="dk"><i class="dk flag"></i>Denmark</div>
<div class="item" data-value="dj"><i class="dj flag"></i>Djibouti</div>
<div class="item" data-value="dm"><i class="dm flag"></i>Dominica</div>
<div class="item" data-value="do"><i class="do flag"></i>Dominican Republic</div>
<div class="item" data-value="ec"><i class="ec flag"></i>Ecuador</div>
<div class="item" data-value="eg"><i class="eg flag"></i>Egypt</div>
<div class="item" data-value="sv"><i class="sv flag"></i>El Salvador</div>
<div class="item" data-value="gb"><i class="gb flag"></i>England</div>
<div class="item" data-value="gq"><i class="gq flag"></i>Equatorial Guinea</div>
<div class="item" data-value="er"><i class="er flag"></i>Eritrea</div>
<div class="item" data-value="ee"><i class="ee flag"></i>Estonia</div>
<div class="item" data-value="et"><i class="et flag"></i>Ethiopia</div>
<div class="item" data-value="eu"><i class="eu flag"></i>European Union</div>
<div class="item" data-value="fk"><i class="fk flag"></i>Falkland Islands</div>
<div class="item" data-value="fo"><i class="fo flag"></i>Faroe Islands</div>
<div class="item" data-value="fj"><i class="fj flag"></i>Fiji</div>
<div class="item" data-value="fi"><i class="fi flag"></i>Finland</div>
<div class="item" data-value="fr"><i class="fr flag"></i>France</div>
<div class="item" data-value="gf"><i class="gf flag"></i>French Guiana</div>
<div class="item" data-value="pf"><i class="pf flag"></i>French Polynesia</div>
<div class="item" data-value="tf"><i class="tf flag"></i>French Territories</div>
<div class="item" data-value="ga"><i class="ga flag"></i>Gabon</div>
<div class="item" data-value="gm"><i class="gm flag"></i>Gambia</div>
<div class="item" data-value="ge"><i class="ge flag"></i>Georgia</div>
<div class="item" data-value="de"><i class="de flag"></i>Germany</div>
<div class="item" data-value="gh"><i class="gh flag"></i>Ghana</div>
<div class="item" data-value="gi"><i class="gi flag"></i>Gibraltar</div>
<div class="item" data-value="gr"><i class="gr flag"></i>Greece</div>
<div class="item" data-value="gl"><i class="gl flag"></i>Greenland</div>
<div class="item" data-value="gd"><i class="gd flag"></i>Grenada</div>
<div class="item" data-value="gp"><i class="gp flag"></i>Guadeloupe</div>
<div class="item" data-value="gu"><i class="gu flag"></i>Guam</div>
<div class="item" data-value="gt"><i class="gt flag"></i>Guatemala</div>
<div class="item" data-value="gw"><i class="gw flag"></i>Guinea-Bissau</div>
<div class="item" data-value="gn"><i class="gn flag"></i>Guinea</div>
<div class="item" data-value="gy"><i class="gy flag"></i>Guyana</div>
<div class="item" data-value="ht"><i class="ht flag"></i>Haiti</div>
<div class="item" data-value="hm"><i class="hm flag"></i>Heard Island</div>
<div class="item" data-value="hn"><i class="hn flag"></i>Honduras</div>
<div class="item" data-value="hk"><i class="hk flag"></i>Hong Kong</div>
<div class="item" data-value="hu"><i class="hu flag"></i>Hungary</div>
<div class="item" data-value="is"><i class="is flag"></i>Iceland</div>
<div class="item" data-value="in"><i class="in flag"></i>India</div>
<div class="item" data-value="io"><i class="io flag"></i>Indian Ocean Territory</div>
<div class="item" data-value="id"><i class="id flag"></i>Indonesia</div>
<div class="item" data-value="ir"><i class="ir flag"></i>Iran</div>
<div class="item" data-value="iq"><i class="iq flag"></i>Iraq</div>
<div class="item" data-value="ie"><i class="ie flag"></i>Ireland</div>
<div class="item" data-value="il"><i class="il flag"></i>Israel</div>
<div class="item" data-value="it"><i class="it flag"></i>Italy</div>
<div class="item" data-value="jm"><i class="jm flag"></i>Jamaica</div>
<div class="item" data-value="jp"><i class="jp flag"></i>Japan</div>
<div class="item" data-value="jo"><i class="jo flag"></i>Jordan</div>
<div class="item" data-value="kz"><i class="kz flag"></i>Kazakhstan</div>
<div class="item" data-value="ke"><i class="ke flag"></i>Kenya</div>
<div class="item" data-value="ki"><i class="ki flag"></i>Kiribati</div>
<div class="item" data-value="kw"><i class="kw flag"></i>Kuwait</div>
<div class="item" data-value="kg"><i class="kg flag"></i>Kyrgyzstan</div>
<div class="item" data-value="la"><i class="la flag"></i>Laos</div>
<div class="item" data-value="lv"><i class="lv flag"></i>Latvia</div>
<div class="item" data-value="lb"><i class="lb flag"></i>Lebanon</div>
<div class="item" data-value="ls"><i class="ls flag"></i>Lesotho</div>
<div class="item" data-value="lr"><i class="lr flag"></i>Liberia</div>
<div class="item" data-value="ly"><i class="ly flag"></i>Libya</div>
<div class="item" data-value="li"><i class="li flag"></i>Liechtenstein</div>
<div class="item" data-value="lt"><i class="lt flag"></i>Lithuania</div>
<div class="item" data-value="lu"><i class="lu flag"></i>Luxembourg</div>
<div class="item" data-value="mo"><i class="mo flag"></i>Macau</div>
<div class="item" data-value="mk"><i class="mk flag"></i>Macedonia</div>
<div class="item" data-value="mg"><i class="mg flag"></i>Madagascar</div>
<div class="item" data-value="mw"><i class="mw flag"></i>Malawi</div>
<div class="item" data-value="my"><i class="my flag"></i>Malaysia</div>
<div class="item" data-value="mv"><i class="mv flag"></i>Maldives</div>
<div class="item" data-value="ml"><i class="ml flag"></i>Mali</div>
<div class="item" data-value="mt"><i class="mt flag"></i>Malta</div>
<div class="item" data-value="mh"><i class="mh flag"></i>Marshall Islands</div>
<div class="item" data-value="mq"><i class="mq flag"></i>Martinique</div>
<div class="item" data-value="mr"><i class="mr flag"></i>Mauritania</div>
<div class="item" data-value="mu"><i class="mu flag"></i>Mauritius</div>
<div class="item" data-value="yt"><i class="yt flag"></i>Mayotte</div>
<div class="item" data-value="mx"><i class="mx flag"></i>Mexico</div>
<div class="item" data-value="fm"><i class="fm flag"></i>Micronesia</div>
<div class="item" data-value="md"><i class="md flag"></i>Moldova</div>
<div class="item" data-value="mc"><i class="mc flag"></i>Monaco</div>
<div class="item" data-value="mn"><i class="mn flag"></i>Mongolia</div>
<div class="item" data-value="me"><i class="me flag"></i>Montenegro</div>
<div class="item" data-value="ms"><i class="ms flag"></i>Montserrat</div>
<div class="item" data-value="ma"><i class="ma flag"></i>Morocco</div>
<div class="item" data-value="mz"><i class="mz flag"></i>Mozambique</div>
<div class="item" data-value="na"><i class="na flag"></i>Namibia</div>
<div class="item" data-value="nr"><i class="nr flag"></i>Nauru</div>
<div class="item" data-value="np"><i class="np flag"></i>Nepal</div>
<div class="item" data-value="an"><i class="an flag"></i>Netherlands Antilles</div>
<div class="item" data-value="nl"><i class="nl flag"></i>Netherlands</div>
<div class="item" data-value="nc"><i class="nc flag"></i>New Caledonia</div>
<div class="item" data-value="pg"><i class="pg flag"></i>New Guinea</div>
<div class="item" data-value="nz"><i class="nz flag"></i>New Zealand</div>
<div class="item" data-value="ni"><i class="ni flag"></i>Nicaragua</div>
<div class="item" data-value="ne"><i class="ne flag"></i>Niger</div>
<div class="item" data-value="ng"><i class="ng flag"></i>Nigeria</div>
<div class="item" data-value="nu"><i class="nu flag"></i>Niue</div>
<div class="item" data-value="nf"><i class="nf flag"></i>Norfolk Island</div>
<div class="item" data-value="kp"><i class="kp flag"></i>North Korea</div>
<div class="item" data-value="mp"><i class="mp flag"></i>Northern Mariana Islands</div>
<div class="item" data-value="no"><i class="no flag"></i>Norway</div>
<div class="item" data-value="om"><i class="om flag"></i>Oman</div>
<div class="item" data-value="pk"><i class="pk flag"></i>Pakistan</div>
<div class="item" data-value="pw"><i class="pw flag"></i>Palau</div>
<div class="item" data-value="ps"><i class="ps flag"></i>Palestine</div>
<div class="item" data-value="pa"><i class="pa flag"></i>Panama</div>
<div class="item" data-value="py"><i class="py flag"></i>Paraguay</div>
<div class="item" data-value="pe"><i class="pe flag"></i>Peru</div>
<div class="item" data-value="ph"><i class="ph flag"></i>Philippines</div>
<div class="item" data-value="pn"><i class="pn flag"></i>Pitcairn Islands</div>
<div class="item" data-value="pl"><i class="pl flag"></i>Poland</div>
<div class="item" data-value="pt"><i class="pt flag"></i>Portugal</div>
<div class="item" data-value="pr"><i class="pr flag"></i>Puerto Rico</div>
<div class="item" data-value="qa"><i class="qa flag"></i>Qatar</div>
<div class="item" data-value="re"><i class="re flag"></i>Reunion</div>
<div class="item" data-value="ro"><i class="ro flag"></i>Romania</div>
<div class="item" data-value="ru"><i class="ru flag"></i>Russia</div>
<div class="item" data-value="rw"><i class="rw flag"></i>Rwanda</div>
<div class="item" data-value="sh"><i class="sh flag"></i>Saint Helena</div>
<div class="item" data-value="kn"><i class="kn flag"></i>Saint Kitts and Nevis</div>
<div class="item" data-value="lc"><i class="lc flag"></i>Saint Lucia</div>
<div class="item" data-value="pm"><i class="pm flag"></i>Saint Pierre</div>
<div class="item" data-value="vc"><i class="vc flag"></i>Saint Vincent</div>
<div class="item" data-value="ws"><i class="ws flag"></i>Samoa</div>
<div class="item" data-value="sm"><i class="sm flag"></i>San Marino</div>
<div class="item" data-value="gs"><i class="gs flag"></i>Sandwich Islands</div>
<div class="item" data-value="st"><i class="st flag"></i>Sao Tome</div>
<div class="item" data-value="sa"><i class="sa flag"></i>Saudi Arabia</div>
<div class="item" data-value="sn"><i class="sn flag"></i>Senegal</div>
<div class="item" data-value="cs"><i class="cs flag"></i>Serbia</div>
<div class="item" data-value="rs"><i class="rs flag"></i>Serbia</div>
<div class="item" data-value="sc"><i class="sc flag"></i>Seychelles</div>
<div class="item" data-value="sl"><i class="sl flag"></i>Sierra Leone</div>
<div class="item" data-value="sg"><i class="sg flag"></i>Singapore</div>
<div class="item" data-value="sk"><i class="sk flag"></i>Slovakia</div>
<div class="item" data-value="si"><i class="si flag"></i>Slovenia</div>
<div class="item" data-value="sb"><i class="sb flag"></i>Solomon Islands</div>
<div class="item" data-value="so"><i class="so flag"></i>Somalia</div>
<div class="item" data-value="za"><i class="za flag"></i>South Africa</div>
<div class="item" data-value="kr"><i class="kr flag"></i>South Korea</div>
<div class="item" data-value="es"><i class="es flag"></i>Spain</div>
<div class="item" data-value="lk"><i class="lk flag"></i>Sri Lanka</div>
<div class="item" data-value="sd"><i class="sd flag"></i>Sudan</div>
<div class="item" data-value="sr"><i class="sr flag"></i>Suriname</div>
<div class="item" data-value="sj"><i class="sj flag"></i>Svalbard</div>
<div class="item" data-value="sz"><i class="sz flag"></i>Swaziland</div>
<div class="item" data-value="se"><i class="se flag"></i>Sweden</div>
<div class="item" data-value="ch"><i class="ch flag"></i>Switzerland</div>
<div class="item" data-value="sy"><i class="sy flag"></i>Syria</div>
<div class="item" data-value="tw"><i class="tw flag"></i>Taiwan</div>
<div class="item" data-value="tj"><i class="tj flag"></i>Tajikistan</div>
<div class="item" data-value="tz"><i class="tz flag"></i>Tanzania</div>
<div class="item" data-value="th"><i class="th flag"></i>Thailand</div>
<div class="item" data-value="tl"><i class="tl flag"></i>Timorleste</div>
<div class="item" data-value="tg"><i class="tg flag"></i>Togo</div>
<div class="item" data-value="tk"><i class="tk flag"></i>Tokelau</div>
<div class="item" data-value="to"><i class="to flag"></i>Tonga</div>
<div class="item" data-value="tt"><i class="tt flag"></i>Trinidad</div>
<div class="item" data-value="tn"><i class="tn flag"></i>Tunisia</div>
<div class="item" data-value="tr"><i class="tr flag"></i>Turkey</div>
<div class="item" data-value="tm"><i class="tm flag"></i>Turkmenistan</div>
<div class="item" data-value="tv"><i class="tv flag"></i>Tuvalu</div>
<div class="item" data-value="ug"><i class="ug flag"></i>Uganda</div>
<div class="item" data-value="ua"><i class="ua flag"></i>Ukraine</div>
<div class="item" data-value="ae"><i class="ae flag"></i>United Arab Emirates</div>
<div class="item" data-value="us"><i class="us flag"></i>United States</div>
<div class="item" data-value="uy"><i class="uy flag"></i>Uruguay</div>
<div class="item" data-value="um"><i class="um flag"></i>Us Minor Islands</div>
<div class="item" data-value="vi"><i class="vi flag"></i>Us Virgin Islands</div>
<div class="item" data-value="uz"><i class="uz flag"></i>Uzbekistan</div>
<div class="item" data-value="vu"><i class="vu flag"></i>Vanuatu</div>
<div class="item" data-value="va"><i class="va flag"></i>Vatican City</div>
<div class="item" data-value="ve"><i class="ve flag"></i>Venezuela</div>
<div class="item" data-value="vn"><i class="vn flag"></i>Vietnam</div>
<div class="item" data-value="wf"><i class="wf flag"></i>Wallis and Futuna</div>
<div class="item" data-value="eh"><i class="eh flag"></i>Western Sahara</div>
<div class="item" data-value="ye"><i class="ye flag"></i>Yemen</div>
<div class="item" data-value="zm"><i class="zm flag"></i>Zambia</div>
<div class="item" data-value="zw"><i class="zw flag"></i>Zimbabwe</div>
</div>
</div>
</div>
<button class="ui basic red button" id="ban-btn" onclick="addCountryToBlacklist();"><i class="ui red ban icon"></i> Blacklist Country</button>
</div>
<table class="ui unstackable basic celled table">
<thead>
<tr>
<th>ISO Code</th>
<th>Remove</th>
</tr>
</thead>
<tbody id="banned-list">
</tbody>
</table>
<h4>IP Blacklist</h4>
<p>Black a certain IP or IP range</p>
<div class="ui form">
<div class="field">
<label>IP Address</label>
<input id="ipAddressInput" type="text" placeholder="IP Address">
</div>
<button id="addIpButton" onclick="addIpBlacklist();" class="ui basic red icon button">
<i class="ban icon"></i> Blacklist IP
</button>
</div>
<div class="ui message">
<i class="ui info circle icon"></i> IP Address support the following formats
<div class="ui bulleted list">
<div class="item">Fixed IP Address (e.g. 192.128.4.100)</div>
<div class="item">IP Wildcard (e.g. 172.164.*.*)</div>
<div class="item">CIDR String (e.g. 128.32.0.1/16)</div>
</div>
</div>
<table class="ui unstackable basic celled table">
<thead>
<tr>
<th>IP Address</th>
<th>Remove</th>
</tr>
</thead>
<tbody id="blacklistIpTable">
</tbody>
</table>
<div class="ui divider"></div>
<h4>Visitor IP list</h4>
<button style="margin-top: -1em;" onclick="initBlacklistQuickBanTable();" class="ui green small right floated circular basic icon button"><i class="ui refresh icon"></i></button>
<p>Observe strange traffic on your sites? Ban them in the list below.</p>
<table class="ui celled unstackable table" id="ipTable">
<thead>
<tr>
<th>IP</th>
<th>Access Count</th>
<th>Blacklist</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="pagination"></div>
</div>
<script>
$(".dropdown").dropdown();
function filterCountries(codesToShow) {
// get all items in the dropdown
const items = document.querySelectorAll('.ui.fluid.search.selection.dropdown .menu .item');
// loop through all items
items.forEach(item => {
// get the value of the item (i.e. the country code)
const code = item.dataset.value;
// if the code is in the array of codes to show, show the item
if (codesToShow.includes(code)) {
item.style.display = 'none';
}
// otherwise, hide the item
else {
item.style.display = 'block';
}
});
}
//Get the country name from the dropdown
function getCountryName(countryCode) {
return $('#countrySelector .item[data-value="' + countryCode.toLowerCase() + '"]').text().trim();
}
function initBannedCountryList(){
$.get("/api/blacklist/list?type=country", function(data) {
let bannedListHtml = '';
data.forEach((countryCode) => {
bannedListHtml += `
<tr>
<td><i class="${countryCode} flag"></i> ${getCountryName(countryCode)} (${countryCode.toUpperCase()})</td>
<td><button class="ui red basic mini icon button" onclick="removeFromBannedList('${countryCode}')"><i class="trash icon"></i></button></td>
</tr>
`;
});
$('#banned-list').html(bannedListHtml);
filterCountries(data);
if (data.length === 0) {
$('#banned-list').append(`
<tr>
<td colspan="2">
<i class="green check circle icon"></i>
There are no blacklisted countries
</td>
</tr>
`);
}
});
}
initBannedCountryList();
function addCountryToBlacklist() {
var countryCode = $("#countrySelector").dropdown("get value").toLowerCase();
$('#countrySelector').dropdown('clear');
$.ajax({
type: "POST",
url: "/api/blacklist/country/add",
data: { cc: countryCode },
success: function(response) {
if (response.error != undefined){
alert(response.error);
}
initBannedCountryList();
},
error: function(xhr, status, error) {
// handle error response
}
});
}
function removeFromBannedList(countryCode){
if (confirm("Confirm removing " + getCountryName(countryCode) + " from blacklist?")){
countryCode = countryCode.toLowerCase();
$.ajax({
url: "/api/blacklist/country/remove",
method: "POST",
data: { cc: countryCode },
success: function(response) {
if (response.error != undefined){
alert(response.error);
}
initBannedCountryList();
},
error: function(xhr, status, error) {
console.error("Error removing country from blacklist: " + error);
// Handle error response
}
});
}
}
function initIpBanTable(){
$.get('/api/blacklist/list?type=ip', function(data) {
$('#blacklistIpTable').html("");
if (data.length === 0) {
$('#blacklistIpTable').append(`
<tr>
<td colspan="2"><i class="green check circle icon"></i>There are no blacklisted IP addresses</td>
</tr>
`);
} else {
$.each(data, function(index, ip) {
let icon = "globe icon";
if (isLAN(ip)){
icon = "desktop icon";
}else if (isHomeAddr(ip)){
icon = "home icon";
}
$('#blacklistIpTable').append(`
<tr class="blacklistItem" ip="${encodeURIComponent(ip)}">
<td><i class="${icon}"></i> ${ip}</td>
<td><button class="ui icon basic mini red button" onclick="removeIpBlacklist('${ip}');"><i class="trash alternate icon"></i></button></td>
</tr>
`);
});
}
initBlacklistQuickBanTable();
});
}
initIpBanTable();
//Check if a input is a valid IP address, wildcard of a IP address or a CIDR string
function isValidIpFilter(input) {
// Check if input is a valid IP address
const isValidIp = /^([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])$/.test(input);
if (isValidIp) {
return true;
}
// Check if input is a wildcard IP address
const isValidWildcardIp = /^([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\.([01]?[0-9]?[0-9]|\*|\*\/[0-9]|[01]?[0-9]?[0-9]-[01]?[0-9]?[0-9]|\[\d+,\d+\])\.([01]?[0-9]?[0-9]|\*|\*\/[0-9]|[01]?[0-9]?[0-9]-[01]?[0-9]?[0-9]|\[\d+,\d+\])\.([01]?[0-9]?[0-9]|\*|\*\/[0-9]|[01]?[0-9]?[0-9]-[01]?[0-9]?[0-9]|\[\d+,\d+\])$/.test(input);
if (isValidWildcardIp) {
return true;
}
// Check if input is a valid CIDR address string
const isValidCidr = /^([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\.([01]?[0-9]?[0-9]|2[0-4][0-9]|25[0-5])\/([0-9]|[1-2][0-9]|3[0-2])$/.test(input);
if (isValidCidr) {
return true;
}
// Input is not a valid IP address, wildcard IP address, or CIDR address string
return false;
}
$("#ipAddressInput").on("input", function() {
$(this).val($(this).val().trim());
var ipAddress = $(this).val();
if (!isValidIpFilter(ipAddress)) {
$(this).parent().addClass("error");
} else {
$(this).parent().removeClass("error");
}
});
function isLAN(ipAddress) {
function ip2long(ipAddress) {
// Convert the IP address to a 32-bit integer
const parts = ipAddress.split(".");
return (
(parseInt(parts[0]) << 24) |
(parseInt(parts[1]) << 16) |
(parseInt(parts[2]) << 8) |
parseInt(parts[3])
);
}
// Define the LAN IP address ranges
const LAN_RANGES = [
{ start: "10.0.0.0", end: "10.255.255.255" },
{ start: "172.16.0.0", end: "172.31.255.255" },
{ start: "192.168.0.0", end: "192.168.255.255" }
];
// Check if the IP address is within any of the LAN ranges
for (let i = 0; i < LAN_RANGES.length; i++) {
const rangeStart = ip2long(LAN_RANGES[i].start);
const rangeEnd = ip2long(LAN_RANGES[i].end);
const ipAddressLong = ip2long(ipAddress);
if (ipAddressLong >= rangeStart && ipAddressLong <= rangeEnd) {
return true;
}
}
return false;
}
function isHomeAddr(ipAddress) {
const specialIpAddresses = ['0.0.0.0', '127.0.0.1', '::1'];
return specialIpAddresses.includes(ipAddress);
}
function addIpBlacklist(){
let targetIp = $("#ipAddressInput").val().trim();
if (targetIp == ""){
alert("IP address is empty")
return
}
if (!isValidIpFilter(targetIp)){
if (!confirm("This doesn't seems like a valid IP address. Continue anyway?")){
return;
}
}
$.ajax({
url: "/api/blacklist/ip/add",
type: "POST",
data: {ip: targetIp.toLowerCase()},
success: function(response) {
if (response.error !== undefined) {
alert(response.error);
} else {
initIpBanTable();
}
$("#ipAddressInput").val("");
$("#ipAddressInput").parent().remvoeClass("error");
},
error: function() {
alert("Failed to add IP address to blacklist.");
}
});
}
function removeIpBlacklist(ipaddr){
if (confirm("Confirm remove blacklist for " + ipaddr + " ?")){
$.ajax({
url: "/api/blacklist/ip/remove",
type: "POST",
data: {ip: ipaddr.toLowerCase()},
success: function(response) {
if (response.error !== undefined) {
alert(response.error);
} else {
initIpBanTable();
}
},
error: function() {
alert("Failed to remove IP address from blacklist.");
}
});
}
}
//function to check for blacklist enable
function enableBlacklist() {
var isChecked = $('#enableBlacklist').is(':checked');
$.ajax({
type: 'POST',
url: '/api/blacklist/enable',
data: { enable: isChecked },
success: function(data){
$("#toggleSucc").stop().finish().fadeIn("fast").delay(3000).fadeOut("fast");
}
});
}
function initBlacklistEnableState(){
$.get('/api/blacklist/enable', function(data){
if (data == true){
$('#enableBlacklist').parent().checkbox("set checked");
}
//Register on change event
$("#enableBlacklist").on("change", function(){
enableBlacklist();
})
});
}
initBlacklistEnableState();
//Load the summary to ip access table
function initBlacklistQuickBanTable(){
$.get("/api/stats/summary", function(data){
initIpAccessTable(data.RequestClientIp);
})
}
initBlacklistQuickBanTable();
var blacklist_entriesPerPage = 30;
var blacklist_currentPage = 1;
var blacklist_totalPages = 0;
function initIpAccessTable(ipAccessCounts){
blacklist_totalPages = Math.ceil(Object.keys(ipAccessCounts).length / blacklist_entriesPerPage);
function sortkv(obj) {
var sortable = [];
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
sortable.push([key, obj[key]]);
}
}
sortable.sort(function(a, b) {
return b[1] - a[1];
});
var sortedObj = {};
sortable.forEach(function(item) {
sortedObj[item[0]] = item[1];
});
return sortedObj;
}
ipAccessCounts = sortkv(ipAccessCounts);
function renderTable() {
var tableBody = $("#ipTable tbody");
tableBody.empty();
var startIndex = (blacklist_currentPage - 1) * blacklist_entriesPerPage;
var endIndex = startIndex + blacklist_entriesPerPage;
var slicedEntries = Object.entries(ipAccessCounts).slice(startIndex, endIndex);
slicedEntries.forEach(function([ip, accessCount]) {
var row = $("<tr>").appendTo(tableBody);
$("<td>").text(ip).appendTo(row);
$("<td>").text(accessCount).appendTo(row);
if (ipInBlacklist(ip)){
$("<td>").html(`<button class="ui basic green small icon button" title"Unban IP" onclick="handleUnban('${ip}');"><i class="green check icon"></i></button>`).appendTo(row);
}else{
$("<td>").html(`<button class="ui basic red small icon button" title"Ban IP" onclick="handleBanIp('${ip}');"><i class="red ban icon"></i></button>`).appendTo(row);
}
});
}
function renderPagination() {
var paginationDiv = $(".pagination");
paginationDiv.empty();
for (var i = 1; i <= blacklist_totalPages; i++) {
var button = $("<button>").text(i).addClass("ui small basic compact button");
if (i === blacklist_currentPage) {
button.addClass("disabled");
}
button.click(function() {
blacklist_currentPage = parseInt($(this).text());
renderTable();
renderPagination();
});
button.appendTo(paginationDiv);
}
}
renderTable();
renderPagination();
}
function ipInBlacklist(targetIp){
let inBlacklist = false;
$(".blacklistItem").each(function(){
if ($(this).attr("ip") == encodeURIComponent(targetIp)){
inBlacklist = true;
}
});
return inBlacklist;
}
function handleBanIp(targetIp){
$("#ipAddressInput").val(targetIp);
addIpBlacklist();
}
function handleUnban(targetIp){
removeIpBlacklist(targetIp);
}
</script>

View File

@@ -39,15 +39,16 @@
<input type="text" id="certdomain" placeholder="example.com / blog.example.com">
</div>
<div class="field">
<label>Public Key</label>
<label>Public Key (.pem)</label>
<input type="file" id="pubkeySelector" onchange="handleFileSelect(event, 'pub')">
</div>
<div class="field">
<label>Private Key</label>
<label>Private Key (.key)</label>
<input type="file" id="prikeySelector" onchange="handleFileSelect(event, 'pri')">
</div>
</div>
<button class="ui basic button" onclick="handleDomainUploadByKeypress();"><i class="ui teal upload icon"></i> Upload</button>
<button class="ui basic button" onclick="handleDomainUploadByKeypress();"><i class="ui teal upload icon"></i> Upload</button><br>
<small>You have intermediate certificate? <a style="cursor:pointer;" onclick="showSideWrapper('snippet/intermediateCertConv.html');">Open Conversion Tool</a></small>
</div>
<div id="certUploadSuccMsg" class="ui green message" style="display:none;">
<i class="ui checkmark icon"></i> Certificate for domain <span id="certUploadingDomain"></span> uploaded.
@@ -100,19 +101,25 @@
//List the stored certificates
function initManagedDomainCertificateList(){
$("#certifiedDomainList").html("");
$.get("/api/cert/list?date=true", function(data){
if (data.error != undefined){
msgbox(data.error, false, 5000);
}else{
$("#certifiedDomainList").html("");
data.forEach(entry => {
$("#certifiedDomainList").append(`<tr>
<td>${entry.Domain}</td>
<td>${entry.LastModifiedDate}</td>
<td>${entry.ExpireDate}</td>
<td><button title="Delete key-pair" class="ui mini basic red icon button" onclick="deleteCertificate('${entry.Domain}');"><i class="ui red trash icon"></i></button></td>
<td>${entry.Domain}</td>
<td>${entry.LastModifiedDate}</td>
<td>${entry.ExpireDate}</td>
<td><button title="Delete key-pair" class="ui mini basic red icon button" onclick="deleteCertificate('${entry.Domain}');"><i class="ui red trash icon"></i></button></td>
</tr>`);
})
});
if (data.length == 0){
$("#certifiedDomainList").append(`<tr>
<td colspan="4"><i class="ui times circle icon"></i> No valid keypairs found</td>
</tr>`);
}
}
})
}

View File

@@ -126,7 +126,7 @@
var nodeCount = 0;
data.forEach(function(gan){
$("#GANetList").append(`<tr class="ganetEntry" addr="${gan.nwid}">
<td>${gan.nwid}</td>
<td><a href="#" onclick="event.preventDefault(); openGANetDetails('${gan.nwid}');">${gan.nwid}</a></td>
<td>${gan.name}</td>
<td class="gandesc" addr="${gan.nwid}"></td>
<td class="ganetSubnet"></td>

View File

@@ -11,7 +11,7 @@
<a class="nettools item bluefont" data-tab="tab3">Interface</a>
</div>
<div class="ui bottom attached tab segment active" data-tab="tab1">
<div class="ui bottom attached tab segment nettoolstab active" data-tab="tab1">
<h2>Multicast DNS (mDNS) Scanner</h2>
<p>Discover mDNS enabled service in this gateway forwarded network</p>
<button class="ui basic larger circular button" onclick="launchToolWithSize('./tools/mdns.html',1000, 640);">View Discovery</button>
@@ -21,7 +21,7 @@
<button class="ui basic larger circular button" onclick="launchToolWithSize('./tools/ipscan.html',1000, 640);">Start Scanner</button>
</div>
<div class="ui bottom attached tab segment" data-tab="tab2">
<div class="ui bottom attached tab segment nettoolstab" data-tab="tab2">
<div id="websshTool" style="position: relative;">
<h2>Web SSH</h2>
<p>Connect to a network node within the local area network of the gateway</p>
@@ -101,7 +101,7 @@
<button class="ui basic button" onclick="listWoL();"><i class="ui green refresh icon"></i> Refresh</button>
</div>
<div class="ui bottom attached tab segment" data-tab="tab3">
<div class="ui bottom attached tab segment nettoolstab" data-tab="tab3">
<h2>Network Interfaces</h2>
<p>Network Interface Card (NIC) currently installed on this host</p>
<table id="network-interfaces-table" class="ui selectable inverted striped celled table">
@@ -125,10 +125,10 @@
// Switch tabs when clicking on the menu items
$('.menu .nettools.item').on('click', function() {
$('.menu .item').removeClass('active');
$('.menu .nettools.item').removeClass('active');
$(this).addClass('active');
var tab = $(this).attr('data-tab');
$('.tab.segment').removeClass('active');
$('.nettoolstab.tab.segment').removeClass('active');
$('div[data-tab="' + tab + '"]').addClass('active');
});

View File

@@ -299,4 +299,142 @@
const regex = /^(localhost|[a-z0-9]+([\-.]{1}[a-z0-9]+)*\.[a-z]{2,}|[a-z0-9]+([\-.]{1}[a-z0-9]+)*\.[a-z]{2,}\.)$/i;
return regex.test(str);
}
/*
Inline editor for subd.html and vdir.html
*/
function editEndpoint(endpointType, uuid) {
var row = $('tr[eptuuid="' + uuid + '"]');
var columns = row.find('td[data-label]');
var payload = $(row).attr("payload");
payload = JSON.parse(decodeURIComponent(payload));
//console.log(payload);
columns.each(function(index) {
var column = $(this);
var oldValue = column.text().trim();
if ($(this).attr("editable") == "false"){
//This col do not allow edit. Skip
return;
}
// Create an input element based on the column content
var input;
var datatype = $(this).attr("datatype");
if (datatype == "domain"){
let domain = payload.Domain;
let tls = payload.RequireTLS;
if (tls){
tls = "checked";
}else{
tls = "";
}
input = `
<div class="ui mini fluid input">
<input type="text" class="Domain" value="${domain}">
</div>
<div class="ui checkbox" style="margin-top: 0.4em;">
<input type="checkbox" class="RequireTLS" ${tls}>
<label>Require TLS</label>
</div>
`;
column.empty().append(input);
}else if (datatype == "skipver"){
let skipTLSValidation = payload.SkipCertValidations;
let checkstate = "";
if (skipTLSValidation){
checkstate = "checked";
}
column.empty().append(`<div class="ui checkbox" style="margin-top: 0.4em;">
<input type="checkbox" class="SkipCertValidations" ${checkstate}>
<label>Skip Verification</label>
<small>Check this if you are using self signed certificates</small>
</div>`);
}else if (datatype == "basicauth"){
let requireBasicAuth = payload.RequireBasicAuth;
let checkstate = "";
if (requireBasicAuth){
checkstate = "checked";
}
column.empty().append(`<div class="ui checkbox" style="margin-top: 0.4em;">
<input type="checkbox" class="RequireBasicAuth" ${checkstate}>
<label>Require Basic Auth</label>
</div> <button class="ui basic tiny button" style="margin-left: 0.4em;" onclick="editBasicAuthCredentials('${endpointType}','${uuid}');"><i class="ui blue lock icon"></i> Edit Credentials</button>`);
}else if (datatype == 'action'){
column.empty().append(`
<button title="Cancel" onclick="exitProxyInlineEdit('${endpointType}');" class="ui basic small circular icon button"><i class="ui remove icon"></i></button>
<button title="Save" onclick="saveProxyInlineEdit('${uuid}');" class="ui basic small circular icon button"><i class="ui green save icon"></i></button>
`);
}else{
//Unknown field. Leave it untouched
}
});
$("#" + endpointType).find(".editBtn").addClass("disabled");
}
function exitProxyInlineEdit(){
listSubd();
listVdirs();
$("#" + endpointType).find(".editBtn").removeClass("disabled");
}
function saveProxyInlineEdit(uuid){
var row = $('tr[eptuuid="' + uuid + '"]');
if (row.length == 0){
return;
}
var epttype = $(row).attr("class");
if (epttype == "subdEntry"){
epttype = "subd";
}else if (epttype == "vdirEntry"){
epttype = "vdir";
}
let newDomain = $(row).find(".Domain").val();
let requireTLS = $(row).find(".RequireTLS")[0].checked;
let skipCertValidations = $(row).find(".SkipCertValidations")[0].checked;
let requireBasicAuth = $(row).find(".RequireBasicAuth")[0].checked;
console.log(newDomain, requireTLS, skipCertValidations, requireBasicAuth)
$.ajax({
url: "/api/proxy/edit",
method: "POST",
data: {
"type": epttype,
"rootname": uuid,
"ep":newDomain,
"tls" :requireTLS,
"tlsval": skipCertValidations,
"bauth" :requireBasicAuth,
},
success: function(data){
if (data.error !== undefined){
msgbox(data.error, false, 6000);
}else{
msgbox("Proxy endpoint updated");
if (epttype == "subd"){
listSubd();
}else if (epttype == "vdir"){
listVdirs();
}
}
}
})
}
function editBasicAuthCredentials(endpointType, uuid){
let payload = encodeURIComponent(JSON.stringify({
ept: endpointType,
ep: uuid
}));
showSideWrapper("snippet/basicAuthEditor.html?t=" + Date.now() + "#" + payload);
}
</script>

View File

@@ -212,7 +212,7 @@
}else{
//Two dates are given and they are not identical
loadStatisticByRange(startdate, enddate);
console.log(startdate, enddate);
//console.log(startdate, enddate);
}
}
@@ -270,7 +270,7 @@
function loadStatisticByRange(startdate, endDate){
$.getJSON("/api/analytic/loadRange?start=" + startdate + "&end=" + endDate, function(data){
console.log(data);
//console.log(data);
//Destroy all the previous charts
statisticCharts.forEach(function(thisChart){
@@ -368,7 +368,6 @@
function renderRefererTable(refererList){
const sortedEntries = Object.entries(refererList).sort(([, valueA], [, valueB]) => valueB - valueA);
console.log(sortedEntries);
$("#stats_RefererTable").html("");
let endStop = 100;
if (sortedEntries.length < 100){

View File

@@ -547,10 +547,7 @@
//Bind event to tab switch
tabSwitchEventBind["status"] = function(){
//On switch over to this page, resize the chart
$("#networkActivityPlaceHolder").hide();
$("#networkActivity").show().delay(100, function(){
updateChartSize();
});
handleChartAccumulateResize();
}
@@ -558,11 +555,6 @@
handleChartAccumulateResize();
});
document.addEventListener("visibilitychange", () => {
// it could be either hidden or visible
//handleChartAccumulateResize();
});
//Initialize chart data
initChart();

View File

@@ -22,10 +22,11 @@
<button class="ui icon right floated basic button" onclick="listSubd();"><i class="green refresh icon"></i> Refresh</button>
<br><br>
</div>
<script>
function listSubd(){
$("#subdList").html(``);
$.get("/api/proxy/list?type=subd", function(data){
$("#subdList").html(``);
if (data.error !== undefined){
$("#subdList").append(`<tr>
<td data-label="" colspan="3"><i class="remove icon"></i> ${data.error}</td>
@@ -37,23 +38,24 @@
}else{
data.forEach(subd => {
let tlsIcon = "";
let subdData = encodeURIComponent(JSON.stringify(subd));
if (subd.RequireTLS){
tlsIcon = `<i class="green lock icon" title="TLS Mode"></i>`;
}
$("#subdList").append(`<tr>
<td data-label="">${subd.RootOrMatchingDomain}</td>
<td data-label="">${subd.Domain} ${tlsIcon}</td>
<td data-label="">${!subd.SkipCertValidations?`<i class="ui green check icon"></i>`:`<i class="ui yellow exclamation circle icon" title="TLS/SSL Verification will be skipped on this host"></i>`}</td>
<td data-label="">${subd.RequireBasicAuth?`<i class="ui green check icon"></i>`:`<i class="ui grey remove icon"></i>`}</td>
<td class="center aligned" data-label="">
<button class="ui circular mini basic icon button" onclick='editEndpoint("subd","${subd.RootOrMatchingDomain}")'><i class="edit icon"></i></button>
$("#subdList").append(`<tr eptuuid="${subd.RootOrMatchingDomain}" payload="${subdData}" class="subdEntry">
<td data-label="" editable="false">${subd.RootOrMatchingDomain}</td>
<td data-label="" editable="true" datatype="domain">${subd.Domain} ${tlsIcon}</td>
<td data-label="" editable="true" datatype="skipver">${!subd.SkipCertValidations?`<i class="ui green check icon"></i>`:`<i class="ui yellow exclamation circle icon" title="TLS/SSL Verification will be skipped on this host"></i>`}</td>
<td data-label="" editable="true" datatype="basicauth">${subd.RequireBasicAuth?`<i class="ui green check icon"></i>`:`<i class="ui grey remove icon"></i>`}</td>
<td class="center aligned" editable="true" datatype="action" data-label="">
<button class="ui circular mini basic icon button editBtn" onclick='editEndpoint("subd","${subd.RootOrMatchingDomain}")'><i class="edit icon"></i></button>
<button class="ui circular mini red basic icon button" onclick='deleteEndpoint("subd","${subd.RootOrMatchingDomain}")'><i class="trash icon"></i></button>
</td>
</tr>`);
});
}
});
}
}
//Bind on tab switch events
tabSwitchEventBind["subd"] = function(){

View File

@@ -41,81 +41,21 @@
</div>
<button id="addTcpProxyButton" class="ui basic button" type="submit"><i class="ui blue add icon"></i> Create</button>
<button id="editTcpProxyButton" class="ui basic button" onclick="confirmEditTCPProxyConfig(event);"><i class="ui blue save icon"></i> Update</button>
<table class="ui celled padded table">
<thead>
<tr><th class="single line">Mode</th>
<th>Public-IP</th>
<th>Concurrent Access</th>
<th>Flow Diagram</th>
</tr></thead>
<tbody>
<tr>
<td>
<h3 class="ui center aligned header">Listen</h3>
</td>
<td class="single line">
Server: <i class="ui green check icon"></i><br>
A: <i class="ui remove icon"></i><br>
B: <i class="ui remove icon"></i><br>
</td>
<td>
<i class="ui red times icon"></i>
</td>
<td>Port A (e.g. 8080) <i class="arrow right icon"></i> Server<br>
Port B (e.g. 8081) <i class="arrow right icon"></i> Server<br>
<small>Server will act as a bridge to proxy traffic between Port A and B</small>
</td>
</tr>
<tr>
<td>
<h3 class="ui center aligned header">Transport</h3>
</td>
<td class="single line">
Server: <i class="ui green check icon"></i><br>
A: <i class="ui remove icon"></i><br>
B: <i class="ui green check icon"></i> (or same LAN)<br>
</td>
<td>
<i class="ui green check icon"></i>
</td>
<td>Port A (e.g. 25565) <i class="arrow right icon"></i> Server<br>
Server <i class="arrow right icon"></i> Port B (e.g. 192.168.0.2:25565)<br>
<small>Traffic from Port A will be forward to Port B's (IP if provided and) Port</small>
</td>
</tr>
<tr>
<td>
<h3 class="ui center aligned header">Starter</h3>
</td>
<td class="single line">
Server: <i class="ui times icon"></i><br>
A: <i class="ui green check icon"></i><br>
B: <i class="ui green check icon"></i><br>
</td>
<td>
<i class="ui red times icon"></i>
</td>
<td>Server <i class="arrow right icon"></i> Port A (e.g. remote.local.:8080) <br>
Server <i class="arrow right icon"></i> Port B (e.g. recv.local.:8081) <br>
<small>Port A and B will be actively bridged</small>
</td>
</tr>
</tbody>
</table>
<button class="ui basic red button" onclick="event.preventDefault(); cancelTCPProxyEdit(event);"><i class="ui red remove icon"></i> Cancel</button>
</form>
<div class="ui divider"></div>
</div>
<div class="ui basic segment">
<div style="overflow-x: auto;">
<h3>TCP Proxy Configs</h3>
<p>A list of TCP proxy configs created on this host. To enable them, use the toggle button on the right.</p>
<table id="proxyTable" class="ui basic celled unstackable table">
<h3>TCP Proxy Configs</h3>
<p>A list of TCP proxy configs created on this host. To enable them, use the toggle button on the right.</p>
<div style="overflow-x: auto; min-height: 400px;">
<table id="proxyTable" class="ui celled unstackable table">
<thead>
<tr>
<th>Name</th>
<th>PortA</th>
<th>PortB</th>
<th>Port/Addr A</th>
<th>Port/Addr B</th>
<th>Mode</th>
<th>Timeout (s)</th>
<th>Actions</th>
@@ -127,6 +67,72 @@
</table>
</div>
</div>
<div class="ui basic inverted segment" style="background-color: #414141; border-radius: 0.6em;">
<h3>Proxy Mode</h3>
<p>TCP Proxy support the following TCP sockets proxy modes</p>
<table class="ui celled padded inverted basic table">
<thead>
<tr><th class="single line">Mode</th>
<th>Public-IP</th>
<th>Concurrent Access</th>
<th>Flow Diagram</th>
</tr></thead>
<tbody>
<tr>
<td>
<h4 class="ui center aligned inverted header">Transport</h4>
</td>
<td class="single line">
Server: <i class="ui green check icon"></i><br>
A: <i class="ui remove icon"></i><br>
B: <i class="ui green check icon"></i> (or same LAN)<br>
</td>
<td>
<i class="ui green check icon"></i>
</td>
<td>Port A (e.g. 25565) <i class="arrow right icon"></i> Server<br>
Server <i class="arrow right icon"></i> Port B (e.g. 192.168.0.2:25565)<br>
<small>Traffic from Port A will be forward to Port B's (IP if provided and) Port</small>
</td>
</tr>
<tr>
<td>
<h4 class="ui center aligned inverted header">Listen</h4>
</td>
<td class="single line">
Server: <i class="ui green check icon"></i><br>
A: <i class="ui remove icon"></i><br>
B: <i class="ui remove icon"></i><br>
</td>
<td>
<i class="ui red times icon"></i>
</td>
<td>Port A (e.g. 8080) <i class="arrow right icon"></i> Server<br>
Port B (e.g. 8081) <i class="arrow right icon"></i> Server<br>
<small>Server will act as a bridge to proxy traffic between Port A and B</small>
</td>
</tr>
<tr>
<td>
<h4 class="ui center aligned inverted header">Starter</h4>
</td>
<td class="single line">
Server: <i class="ui times icon"></i><br>
A: <i class="ui green check icon"></i><br>
B: <i class="ui green check icon"></i><br>
</td>
<td>
<i class="ui red times icon"></i>
</td>
<td>Server <i class="arrow right icon"></i> Port A (e.g. remote.local.:8080) <br>
Server <i class="arrow right icon"></i> Port B (e.g. recv.local.:8081) <br>
<small>Port A and B will be actively bridged</small>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<script>
let editingTCPProxyConfigUUID = ""; //The current editing TCP Proxy config UUID
@@ -171,11 +177,30 @@
function clearTCPProxyAddEditForm(){
$('#tcpProxyForm input, #tcpProxyForm select').val('');
$('#tcpProxyForm select').dropdown('clear');
}
function cancelTCPProxyEdit(event) {
clearTCPProxyAddEditForm();
$('#addproxyConfig').slideUp('fast');
}
function validateTCPProxyConfig(form){
//Check if name is filled. If not, generate a random name for it
var name = form.find('input[name="name"]').val()
if (name == ""){
let randomName = "Proxy Rule (#" + Math.round(Date.now()/1000) + ")";
form.find('input[name="name"]').val(randomName);
}
// Validate timeout is an integer
var timeout = parseInt(form.find('input[name="timeout"]').val());
if (form.find('input[name="timeout"]').val() == ""){
//Not set. Assign a random one to it
form.find('input[name="timeout"]').val("10");
timeout = 10;
}
if (isNaN(timeout)) {
form.find('input[name="timeout"]').parent().addClass("error");
msgbox('Timeout must be a valid integer', false, 5000);
@@ -206,10 +231,10 @@
proxyConfigs.forEach(function(config) {
var runningLogo = '<i class="red circle icon"></i>';
var startButton = `<button onclick="startTcpProx('${config.UUID}');" class="ui button" title="Start Proxy"><i class="play icon"></i></button>`;
var startButton = `<button onclick="startTcpProx('${config.UUID}');" class="ui button" title="Start Proxy"><i class="play icon"></i> Start Proxy</button>`;
if (config.Running){
runningLogo = '<i class="green circle icon"></i>';
startButton = `<button onclick="stopTcpProx('${config.UUID}');" class="ui button" title="Start Proxy"><i class="red stop icon"></i></button>`;
startButton = `<button onclick="stopTcpProx('${config.UUID}');" class="ui button" title="Start Proxy"><i class="red stop icon"></i> Stop Proxy</button>`;
}
var modeText = "Unknown";
@@ -230,11 +255,11 @@
row.append($('<td>').text(modeText));
row.append($('<td>').text(config.Timeout));
row.append($('<td>').html(`
<div class="ui basic icon buttons">
<button class="ui button" onclick="validateProxyConfig('${config.UUID}', this);" title="Validate Config"><i class="teal question circle outline icon"></i></button>
<div class="ui basic vertical fluid tiny buttons">
<button class="ui button" onclick="validateProxyConfig('${config.UUID}', this);" title="Validate Config"><i class="teal question circle outline icon"></i> CXN Test</button>
${startButton}
<button onclick="editTCPProxyConfig('${config.UUID}');" class="ui button" title="Edit Config"><i class="edit icon"></i></button>
<button onclick="deleteTCPProxyConfig('${config.UUID}');" class="ui red button" title="Delete Config"><i class="trash icon"></i></button>
<button onclick="editTCPProxyConfig('${config.UUID}');" class="ui button" title="Edit Config"><i class="edit icon"></i> Edit </button>
<button onclick="deleteTCPProxyConfig('${config.UUID}');" class="ui red basic button" title="Delete Config"><i class="trash icon"></i> Remove</button>
</div>
`));
tableBody.append(row);
@@ -261,10 +286,11 @@
data: {uuid: configUUID},
success: function(data){
if (data.error != undefined){
$(btn).html(`<i class="red times icon"></i>`);
let errormsg = data.error.charAt(0).toUpperCase() + data.error.slice(1);
$(btn).html(`<i class="red times icon"></i> ${errormsg}`);
msgbox(data.error, false, 6000);
}else{
$(btn).html(`<i class="green check icon"></i>`);
$(btn).html(`<i class="green check icon"></i> Config Valid`);
msgbox("Config Check Passed");
}
}
@@ -335,7 +361,55 @@
}
function deleteTCPProxyConfig(configUUID){
$.ajax({
url: "/api/tcpprox/config/delete",
method: "POST",
data: {uuid: configUUID},
success: function(data){
if (data.error != undefined){
msgbox(data.error, false, 6000);
}else{
msgbox("Proxy Config Removed");
initProxyConfigList();
}
}
})
}
//Start a TCP proxy by their config UUID
function startTcpProx(configUUID){
$.ajax({
url: "/api/tcpprox/config/start",
method: "POST",
data: {uuid: configUUID},
success: function(data){
if (data.error != undefined){
msgbox(data.error, false, 6000);
}else{
msgbox("Service Started");
initProxyConfigList();
}
}
});
}
//Stop a TCP proxy by their config UUID
function stopTcpProx(configUUID){
$.ajax({
url: "/api/tcpprox/config/stop",
method: "POST",
data: {uuid: configUUID},
success: function(data){
if (data.error != undefined){
msgbox(data.error, false, 6000);
}else{
msgbox("Service Stopped");
initProxyConfigList();
}
}
});
}
function initProxyConfigList(){

View File

@@ -4,6 +4,8 @@
<p>You might find these tools or information helpful when setting up your gateway server</p>
</div>
<div class="ui divider"></div>
<div class="selfauthOnly">
<h3>Account Management</h3>
<p>Functions to help management the current account</p>
@@ -34,6 +36,11 @@
<p>The following SMTP settings help you to reset your password in case you have lost your management account.</p>
<form id="email-form" class="ui form">
<div class="field">
<label>Sender Address</label>
<input type="text" name="senderAddr" placeholder="E.g. noreply@zoraxy.arozos.com">
</div>
<div class="field">
<p><i class="caret down icon"></i> Connection setup for email service provider</p>
<div class="fields">
<div class="twelve wide field">
<label>SMTP Provider Hostname</label>
@@ -46,36 +53,35 @@
</div>
</div>
</div>
<div class="field">
<label>Sender Domain</label>
<input type="text" name="domain" min="1" max="65534" placeholder="E.g. arozos.com">
</div>
<div class="field">
<label>Sender Address</label>
<input type="text" name="senderAddr" placeholder="E.g. admin@zoraxy.arozos.com">
</div>
<div class="field">
<p><i class="caret down icon"></i> Credentials for SMTP server authentications</p>
<div class="two fields">
<div class="field">
<label>Sender Username</label>
<input type="text" name="username" placeholder="Username of the email account">
<input type="text" name="username" placeholder="E.g. admin">
</div>
<div class="field">
<label>Sender Password</label>
<input type="password" name="password" placeholder="Password of the email account">
<small>Leave empty to use the old password</small>
<label>Sender Domain</label>
<div class="ui labeled input">
<div class="ui basic label">
@
</div>
<input type="text" name="domain" min="1" max="65534" placeholder="E.g. arozos.com">
</div>
</div>
</div>
</div>
<div class="ui divider"></div>
<p> Email for sending account reset link</p>
<div class="field">
<label>Admin Address</label>
<label>Sender Password</label>
<input type="password" name="password" placeholder="Password of the email account">
<small>Leave empty to use the old password</small>
</div>
<p> <i class="caret down icon"></i> Email for sending account reset link</p>
<div class="field">
<label>Admin / Receiver Address</label>
<input type="text" name="recvAddr" placeholder="E.g. personalEmail@gmail.com">
</div>
@@ -83,7 +89,7 @@
<button class="ui basic button" onclick="event.preventDefault(); sendTestEmail(this);"><i class="teal mail icon"></i> Send Test Email</button>
</form>
</div>
<div class="ui divider"></div>
<h3> IP Address to CIDR</h3>
<p>No experience with CIDR notations? Here are some tools you can use to make setting up easier.</p>
<div class="ui basic segment">
@@ -110,6 +116,45 @@
</div>
<p>Results: <div id="ipRangeOutput">N/A</div></p>
</div>
<div class="ui divider"></div>
<div id="zoraxyinfo">
<h3 class="ui header">
System Information
</h3>
<p>Basic information about this zoraxy host</p>
<table class="ui very basic collapsing celled table">
<tbody>
<tr>
<td>Host UUID</td>
<td class="uuid"></td>
</tr>
<tr>
<td>Version</td>
<td class="version"></td>
</tr>
<tr>
<td>Build</td>
<td class="development"></td>
</tr>
<tr>
<td>Running Since</td>
<td class="boottime"></td>
</tr>
<tr>
<td>ZeroTier Linked</td>
<td class="zt"></td>
</tr>
<tr>
<td>Enable SSH Loopback</td>
<td class="sshlb"></td>
</tr>
</tbody>
</table>
<p>Zoraxy is developed by tobychui for <a href="//imuslab.com" target="_blank">imuslab</a> and open source under <a href="https://www.gnu.org/licenses/agpl-3.0.txt">AGPL</a></p>
</div>
<br>
</div>
<script>
@@ -122,7 +167,44 @@
//Using external auth manager. Hide options
$(".selfauthOnly").hide();
}
})
});
$.get("/api/info/x", function(data){
function timeConverter(UNIX_timestamp){
var a = new Date(UNIX_timestamp * 1000);
var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
var year = a.getFullYear();
var month = months[a.getMonth()];
var date = a.getDate();
var hour = a.getHours();
var min = a.getMinutes();
var sec = a.getSeconds();
var time = date + ' ' + month + ' ' + year + ' ' + hour + ':' + min + ':' + sec ;
return time;
}
function secondsToDhms(seconds) {
seconds = Number(seconds);
var d = Math.floor(seconds / (3600*24));
var h = Math.floor(seconds % (3600*24) / 3600);
var m = Math.floor(seconds % 3600 / 60);
var s = Math.floor(seconds % 60);
var dDisplay = d > 0 ? d + (d == 1 ? " day, " : " days, ") : "";
var hDisplay = h > 0 ? h + (h == 1 ? " hour, " : " hours, ") : "";
var mDisplay = m > 0 ? m + (m == 1 ? " minute, " : " minutes, ") : "";
var sDisplay = s > 0 ? s + (s == 1 ? " second" : " seconds") : "";
return dDisplay + hDisplay + mDisplay + sDisplay;
}
console.log(data);
$("#zoraxyinfo .uuid").text(data.NodeUUID);
$("#zoraxyinfo .development").text(data.Development?"Development":"Release");
$("#zoraxyinfo .version").text(data.Version);
$("#zoraxyinfo .boottime").text(timeConverter(data.BootTime) + ` ( ${secondsToDhms(parseInt(Date.now()/1000) - data.BootTime)} ago)`);
$("#zoraxyinfo .zt").html(data.ZerotierConnected?`<i class="ui green check icon"></i> Connected`:`<i class="ui red times icon"></i> Link Error`);
$("#zoraxyinfo .sshlb").html(data.EnableSshLoopback?`<i class="ui yellow exclamation triangle icon"></i> Enabled`:`Disabled`);
});
function changePassword() {
const oldPassword = document.getElementsByName('oldPassword')[0].value;

View File

@@ -27,8 +27,8 @@
<script>
//Virtual directories functions
function listVdirs(){
$("#vdirList").html(``);
$.get("/api/proxy/list?type=vdir", function(data){
$("#vdirList").html(``);
if (data.error !== undefined){
$("#vdirList").append(`<tr>
<td data-label="" colspan="3"><i class="remove icon"></i> ${data.error}</td>
@@ -40,16 +40,17 @@
}else{
data.forEach(vdir => {
let tlsIcon = "";
let vdirData = encodeURIComponent(JSON.stringify(vdir));
if (vdir.RequireTLS){
tlsIcon = `<i class="green lock icon" title="TLS Mode"></i>`;
}
$("#vdirList").append(`<tr>
<td data-label="">${vdir.RootOrMatchingDomain}</td>
<td data-label="">${vdir.Domain} ${tlsIcon}</td>
<td data-label="">${!subd.SkipCertValidations?`<i class="ui green check icon"></i>`:`<i class="ui yellow exclamation circle icon" title="TLS/SSL Verification will be skipped on this host"></i>`}</td>
<td data-label="">${subd.RequireBasicAuth?`<i class="ui green check icon"></i>`:`<i class="ui grey remove icon"></i>`}</td>
<td class="center aligned" data-label="">
<button class="ui circular mini basic icon button" onclick='editEndpoint("vdir","${vdir.RootOrMatchingDomain}")'><i class="edit icon"></i></button>
$("#vdirList").append(`<tr eptuuid="${vdir.RootOrMatchingDomain}" payload="${vdirData}" class="vdirEntry">
<td data-label="" editable="false">${vdir.RootOrMatchingDomain}</td>
<td data-label="" editable="true" datatype="domain">${vdir.Domain} ${tlsIcon}</td>
<td data-label="" editable="true" datatype="skipver">${!vdir.SkipCertValidations?`<i class="ui green check icon"></i>`:`<i class="ui yellow exclamation circle icon" title="TLS/SSL Verification will be skipped on this host"></i>`}</td>
<td data-label="" editable="true" datatype="basicauth">${vdir.RequireBasicAuth?`<i class="ui green check icon"></i>`:`<i class="ui grey remove icon"></i>`}</td>
<td class="center aligned" editable="true" datatype="action" data-label="">
<button class="ui circular mini basic icon button editBtn" onclick='editEndpoint("vdir","${vdir.RootOrMatchingDomain}")'><i class="edit icon"></i></button>
<button class="ui circular mini red basic icon button" onclick='deleteEndpoint("vdir","${vdir.RootOrMatchingDomain}")'><i class="trash icon"></i></button>
</td>
</tr>`);