zoraxy/src/web/snippet/basicAuthEditor.html
Toby Chui 4f7f60188f Added basic auth exception paths
Added feature request from #25
2023-08-22 23:46:54 +08:00

311 lines
14 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<!-- Notes: This should be open in its original path-->
<link rel="stylesheet" href="../script/semantic/semantic.min.css">
<script src="../script/jquery-3.6.0.min.js"></script>
<script src="../script/semantic/semantic.min.js"></script>
</head>
<body>
<br>
<div class="ui container">
<div class="ui header">
<div class="content">
Basic Auth Settings
<div class="sub header" id="epname"></div>
</div>
</div>
<div class="ui divider"></div>
<h3 class="ui header">Basic Auth Credential</h3>
<div class="scrolling content ui form">
<div id="inlineEditBasicAuthCredentials" class="field">
<p>Enter the username and password for allowing them to access this proxy endpoint</p>
<table class="ui very basic compacted unstackable celled table">
<thead>
<tr>
<th>Username</th>
<th>Password</th>
<th>Remove</th>
</tr></thead>
<tbody id="inlineEditBasicAuthCredentialTable">
<tr>
<td colspan="3"><i class="ui green circle check icon"></i> No Entered Credential</td>
</tr>
</tbody>
</table>
<div class="three small fields credentialEntry">
<div class="field">
<input id="inlineEditBasicAuthCredUsername" type="text" placeholder="Username" autocomplete="off">
</div>
<div class="field">
<input id="inlineEditBasicAuthCredPassword" type="password" placeholder="Password" autocomplete="off">
</div>
<div class="field" >
<button class="ui basic button" onclick="addCredentialsToEditingList();"><i class="blue add icon"></i> Add Credential</button>
<button class="ui basic button" style="float: right;" onclick="saveCredentials();"><i class="green save icon"></i> Save Credential</button>
</div>
<div class="ui divider"></div>
</div>
</div>
</div>
<div class="ui divider"></div>
<h3 class="ui header">Authentication Exclusion Paths</h3>
<div class="scrolling content ui form">
<p>Exclude specific directories / paths which contains the following subpath prefix from authentication. Useful if you are hosting services require remote API access.</p>
<table class="ui very basic compacted unstackable celled table">
<thead>
<tr>
<th>Path Prefix</th>
<th>Remove</th>
</tr></thead>
<tbody id="exclusionPaths">
<tr>
<td colspan="2"><i class="ui green circle check icon"></i> No Path Excluded</td>
</tr>
</tbody>
</table>
<div class="field">
<input id="newExclusionPath" type="text" placeholder="/public/api/" autocomplete="off">
<small>Make sure you add the tailing slash for only selecting the files / folder inside that path.</small>
</div>
<div class="field" >
<button class="ui basic button" onclick="addExceptionPath();"><i class="blue add icon"></i> Add Exception</button>
</div>
<div class="field">
<div class="ui basic message">
<h4>How to use set excluded paths?</h4>
<p>All request URI that contains the given prefix will be allowed to bypass authentication and <b>the prefix must start with a slash.</b> For example, given the following prefix.<br>
<code>/public/res/</code><br>
<br>
Zoraxy will allow authentication bypass of any subdirectories or resources under the /public/res/ directory. For example, the following paths access will be able to bypass basic auth mechanism under this setting.<br>
<code>/public/res/photo.png</code><br>
<code>/public/res/far/boo/</code></p>
</div>
</div>
<div class="ui divider"></div>
<div class="field" >
<button class="ui basic button" style="float: right;" onclick="closeThisWrapper();">Close</button>
</div>
</div>
<br><br><br><br>
</div>
<script>
let editingCredentials = [];
let editingEndpoint = {};
if (window.location.hash.length > 1){
let payloadHash = window.location.hash.substr(1);
try{
payloadHash = JSON.parse(decodeURIComponent(payloadHash));
loadBasicAuthCredentials(payloadHash.ept, payloadHash.ep);
$("#epname").text(payloadHash.ep);
editingEndpoint = payloadHash;
}catch(ex){
console.log("Unable to load endpoint data from hash")
}
}
function loadBasicAuthCredentials(endpointType, uuid){
$.ajax({
url: "/api/proxy/updateCredentials",
method: "GET",
data: {
ep: uuid,
ptype: endpointType
},
success: function(data){
//Push the existing account to list
for(var i = 0; i < data.length; i++){
// Create a new credential object
var credential = {
username: data[i],
password: ""
};
// Add the credential to the global credentials array
editingCredentials.push(credential);
}
console.log(data);
updateEditingCredentialList();
}
})
}
function addCredentialsToEditingList() {
// Retrieve the username and password input values
var username = $('#inlineEditBasicAuthCredUsername').val();
var password = $('#inlineEditBasicAuthCredPassword').val();
if(username == "" || password == ""){
parent.msgbox("Username or password cannot be empty", false, 5000);
return;
}
if (alreadyExists(username)){
parent.msgbox("Credential with same username already exists", false, 5000);
return;
}
// Create a new credential object
var credential = {
username: username,
password: password
};
// Add the credential to the global credentials array
editingCredentials.push(credential);
// Clear the input fields
$('#inlineEditBasicAuthCredUsername').val('');
$('#inlineEditBasicAuthCredPassword').val('');
// Update the table body with the credentials
updateEditingCredentialList();
}
function addExceptionPath(){
// Retrieve the username and password input values
var newExclusionPathMatchingPrefix = $('#newExclusionPath').val().trim();
if (newExclusionPathMatchingPrefix == ""){
parent.msgbox("Matching prefix cannot be empty!", false, 5000);
return;
}
$.ajax({
url: "/api/proxy/auth/exceptions/add",
data:{
ptype: editingEndpoint.ept,
ep: editingEndpoint.ep,
prefix: newExclusionPathMatchingPrefix
},
method: "POST",
success: function(data){
if (data.error != undefined){
parent.msgbox(data.error, false, 5000);
}else{
initExceptionPaths();
parent.msgbox("New exception path added", true);
$('#newExclusionPath').val("");
}
}
});
}
function removeExceptionPath(object){
let matchingPrefix = $(object).attr("prefix");
$.ajax({
url: "/api/proxy/auth/exceptions/delete",
data:{
ptype: editingEndpoint.ept,
ep: editingEndpoint.ep,
prefix: matchingPrefix
},
method: "POST",
success: function(data){
if (data.error != undefined){
parent.msgbox(data.error, false, 5000);
}else{
initExceptionPaths();
parent.msgbox("Exception path removed", true);
}
}
});
}
//Load exception paths from server
function initExceptionPaths(){
$.get(`/api/proxy/auth/exceptions/list?ptype=${editingEndpoint.ept}&ep=${editingEndpoint.ep}`, function(data){
if (data.error != undefined){
parent.msgbox(data.error, false, 5000);
}else{
if (data.length == 0){
$("#exclusionPaths").html(` <tr>
<td colspan="2"><i class="ui green circle check icon"></i> No Path Excluded</td>
</tr>`);
}else{
$("#exclusionPaths").html("");
data.forEach(function(rule){
$("#exclusionPaths").append(` <tr>
<td>${rule.PathPrefix}</td>
<td><button class="ui red basic mini icon button" onclick="removeExceptionPath(this);" prefix="${rule.PathPrefix}"><i class="ui red times icon"></i></button></td>
</tr>`);
})
}
}
});
}
initExceptionPaths();
function updateEditingCredentialList() {
var tableBody = $('#inlineEditBasicAuthCredentialTable');
tableBody.empty();
if (editingCredentials.length === 0) {
tableBody.append('<tr><td colspan="3"><i class="ui green circle check icon"></i> No Entered Credential</td></tr>');
} else {
for (var i = 0; i < editingCredentials.length; i++) {
var credential = editingCredentials[i];
var username = credential.username;
var password = credential.password.replace(/./g, '*'); // Replace each character with '*'
if (credential.password == ""){
password = `<span style="color: #c9c9c9;"><i class="eye slash outline icon"></i> Hidden<span>`;
}
var row = '<tr>' +
'<td>' + username + '</td>' +
'<td>' + password + '</td>' +
'<td><button class="ui basic button" onclick="removeCredentialFromEditingList(' + i + ');"><i class="red remove icon"></i> Remove</button></td>' +
'</tr>';
tableBody.append(row);
}
}
}
function removeCredentialFromEditingList(index) {
// Remove the credential from the credentials array
editingCredentials.splice(index, 1);
// Update the table body
updateEditingCredentialList();
}
function alreadyExists(username){
let isExists = false;
editingCredentials.forEach(function(cred){
if (cred.username == username){
isExists = true;
}
});
return isExists;
}
function closeThisWrapper(){
parent.hideSideWrapper(true);
}
function saveCredentials(){
$.ajax({
url: "/api/proxy/updateCredentials",
method: "POST",
data: {
ep: editingEndpoint.ep,
ptype: editingEndpoint.ept,
creds: JSON.stringify(editingCredentials)
},
success: function(data){
if (data.error != undefined){
parent.msgbox(data.error, false, 6000);
}else{
parent.msgbox("Credentials Updated");
//parent.hideSideWrapper(true);
}
}
})
}
</script>
</body>
</html>