basicAuthEditor.html 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <!-- Notes: This should be open in its original path-->
  5. <meta charset="utf-8">
  6. <meta name="zoraxy.csrf.Token" content="{{.csrfToken}}">
  7. <link rel="stylesheet" href="../script/semantic/semantic.min.css">
  8. <script src="../script/jquery-3.6.0.min.js"></script>
  9. <script src="../script/semantic/semantic.min.js"></script>
  10. <script src="../script/utils.js"></script>
  11. </head>
  12. <body>
  13. <link rel="stylesheet" href="../darktheme.css">
  14. <script src="../script/darktheme.js"></script>
  15. <br>
  16. <div class="ui container">
  17. <div class="ui header">
  18. <div class="content">
  19. Basic Auth Settings
  20. <div class="sub header" id="epname"></div>
  21. </div>
  22. </div>
  23. <div class="ui divider"></div>
  24. <h3 class="ui header">Basic Auth Credential</h3>
  25. <div class="scrolling content ui form">
  26. <div id="inlineEditBasicAuthCredentials" class="field">
  27. <p>Enter the username and password for allowing them to access this proxy endpoint</p>
  28. <table class="ui very basic compacted unstackable celled table">
  29. <thead>
  30. <tr>
  31. <th>Username</th>
  32. <th>Password</th>
  33. <th>Remove</th>
  34. </tr></thead>
  35. <tbody id="inlineEditBasicAuthCredentialTable">
  36. <tr>
  37. <td colspan="3"><i class="ui green circle check icon"></i> No Entered Credential</td>
  38. </tr>
  39. </tbody>
  40. </table>
  41. <div class="three small fields credentialEntry">
  42. <div class="field">
  43. <input id="inlineEditBasicAuthCredUsername" type="text" placeholder="Username" autocomplete="off">
  44. </div>
  45. <div class="field">
  46. <input id="inlineEditBasicAuthCredPassword" type="password" placeholder="Password" autocomplete="off">
  47. </div>
  48. <div class="field" >
  49. <button class="ui basic button" onclick="addCredentialsToEditingList();"><i class="green add icon"></i> Add Credential</button>
  50. </div>
  51. <div class="ui divider"></div>
  52. </div>
  53. </div>
  54. </div>
  55. <div class="ui divider"></div>
  56. <h3 class="ui header">Authentication Exclusion Paths</h3>
  57. <div class="scrolling content ui form">
  58. <p>Exclude specific directories / paths which contains the following subpath prefix from authentication. Useful if you are hosting services require remote API access.</p>
  59. <table class="ui very basic compacted unstackable celled table">
  60. <thead>
  61. <tr>
  62. <th>Path Prefix</th>
  63. <th>Remove</th>
  64. </tr></thead>
  65. <tbody id="exclusionPaths">
  66. <tr>
  67. <td colspan="2"><i class="ui green circle check icon"></i> No Path Excluded</td>
  68. </tr>
  69. </tbody>
  70. </table>
  71. <div class="field">
  72. <input id="newExclusionPath" type="text" placeholder="/public/api/" autocomplete="off">
  73. <small>Make sure you add the tailing slash for only selecting the files / folder inside that path.</small>
  74. </div>
  75. <div class="field" >
  76. <button class="ui basic button" onclick="addExceptionPath();"><i class="yellow add icon"></i> Add Exception</button>
  77. </div>
  78. <div class="field">
  79. <div class="ui basic message">
  80. <h4>How to use set excluded paths?</h4>
  81. <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>
  82. <code>/public/res/</code><br>
  83. <br>
  84. 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>
  85. <code>/public/res/photo.png</code><br>
  86. <code>/public/res/far/boo/</code></p>
  87. </div>
  88. </div>
  89. <div class="ui divider"></div>
  90. <div class="field" >
  91. <button class="ui basic button" style="float: right;" onclick="closeThisWrapper();">Close</button>
  92. </div>
  93. </div>
  94. <br><br><br><br>
  95. </div>
  96. <script>
  97. let editingCredentials = [];
  98. let editingEndpoint = {};
  99. if (window.location.hash.length > 1){
  100. let payloadHash = window.location.hash.substr(1);
  101. try{
  102. payloadHash = JSON.parse(decodeURIComponent(payloadHash));
  103. loadBasicAuthCredentials(payloadHash.ep);
  104. $("#epname").text(payloadHash.ep);
  105. editingEndpoint = payloadHash;
  106. }catch(ex){
  107. console.log("Unable to load endpoint data from hash")
  108. }
  109. }
  110. function loadBasicAuthCredentials(uuid){
  111. $.ajax({
  112. url: "/api/proxy/updateCredentials",
  113. method: "GET",
  114. data: {
  115. ep: uuid,
  116. },
  117. success: function(data){
  118. //Push the existing account to list
  119. for(var i = 0; i < data.length; i++){
  120. // Create a new credential object
  121. var credential = {
  122. username: data[i],
  123. password: ""
  124. };
  125. // Add the credential to the global credentials array
  126. editingCredentials.push(credential);
  127. }
  128. console.log(data);
  129. updateEditingCredentialList();
  130. }
  131. })
  132. }
  133. function addCredentialsToEditingList() {
  134. // Retrieve the username and password input values
  135. var username = $('#inlineEditBasicAuthCredUsername').val();
  136. var password = $('#inlineEditBasicAuthCredPassword').val();
  137. if(username == "" || password == ""){
  138. parent.msgbox("Username or password cannot be empty", false, 5000);
  139. return;
  140. }
  141. if (alreadyExists(username)){
  142. parent.msgbox("Credential with same username already exists", false, 5000);
  143. return;
  144. }
  145. // Create a new credential object
  146. var credential = {
  147. username: username,
  148. password: password
  149. };
  150. // Add the credential to the global credentials array
  151. editingCredentials.push(credential);
  152. // Clear the input fields
  153. $('#inlineEditBasicAuthCredUsername').val('');
  154. $('#inlineEditBasicAuthCredPassword').val('');
  155. // Update the table body with the credentials
  156. updateEditingCredentialList();
  157. //Save the table
  158. saveCredentials();
  159. }
  160. function addExceptionPath(){
  161. // Retrieve the username and password input values
  162. var newExclusionPathMatchingPrefix = $('#newExclusionPath').val().trim();
  163. if (newExclusionPathMatchingPrefix == ""){
  164. parent.msgbox("Matching prefix cannot be empty!", false, 5000);
  165. return;
  166. }
  167. $.cjax({
  168. url: "/api/proxy/auth/exceptions/add",
  169. data:{
  170. ep: editingEndpoint.ep,
  171. prefix: newExclusionPathMatchingPrefix
  172. },
  173. method: "POST",
  174. success: function(data){
  175. if (data.error != undefined){
  176. parent.msgbox(data.error, false, 5000);
  177. }else{
  178. initExceptionPaths();
  179. parent.msgbox("New exception path added", true);
  180. $('#newExclusionPath').val("");
  181. }
  182. }
  183. });
  184. }
  185. function removeExceptionPath(object){
  186. let matchingPrefix = $(object).attr("prefix");
  187. $.cjax({
  188. url: "/api/proxy/auth/exceptions/delete",
  189. data:{
  190. ep: editingEndpoint.ep,
  191. prefix: matchingPrefix
  192. },
  193. method: "POST",
  194. success: function(data){
  195. if (data.error != undefined){
  196. parent.msgbox(data.error, false, 5000);
  197. }else{
  198. initExceptionPaths();
  199. parent.msgbox("Exception path removed", true);
  200. }
  201. }
  202. });
  203. }
  204. //Load exception paths from server
  205. function initExceptionPaths(){
  206. $.get(`/api/proxy/auth/exceptions/list?ptype=${editingEndpoint.ept}&ep=${editingEndpoint.ep}`, function(data){
  207. if (data.error != undefined){
  208. parent.msgbox(data.error, false, 5000);
  209. }else{
  210. if (data.length == 0){
  211. $("#exclusionPaths").html(` <tr>
  212. <td colspan="2"><i class="ui green circle check icon"></i> No Path Excluded</td>
  213. </tr>`);
  214. }else{
  215. $("#exclusionPaths").html("");
  216. data.forEach(function(rule){
  217. $("#exclusionPaths").append(` <tr>
  218. <td>${rule.PathPrefix}</td>
  219. <td><button class="ui red basic mini icon button" onclick="removeExceptionPath(this);" prefix="${rule.PathPrefix}"><i class="ui red times icon"></i></button></td>
  220. </tr>`);
  221. })
  222. }
  223. }
  224. });
  225. }
  226. initExceptionPaths();
  227. function updateEditingCredentialList() {
  228. var tableBody = $('#inlineEditBasicAuthCredentialTable');
  229. tableBody.empty();
  230. if (editingCredentials.length === 0) {
  231. tableBody.append('<tr><td colspan="3"><i class="ui green circle check icon"></i> No Entered Credential</td></tr>');
  232. } else {
  233. for (var i = 0; i < editingCredentials.length; i++) {
  234. var credential = editingCredentials[i];
  235. var username = credential.username;
  236. var password = credential.password.replace(/./g, '*'); // Replace each character with '*'
  237. if (credential.password == ""){
  238. password = `<span style="color: #c9c9c9;"><i class="eye slash outline icon"></i> Hidden<span>`;
  239. }
  240. var row = '<tr>' +
  241. '<td>' + username + '</td>' +
  242. '<td>' + password + '</td>' +
  243. '<td><button class="ui basic button" onclick="removeCredentialFromEditingList(' + i + ');"><i class="red remove icon"></i> Remove</button></td>' +
  244. '</tr>';
  245. tableBody.append(row);
  246. }
  247. }
  248. }
  249. function removeCredentialFromEditingList(index) {
  250. // Remove the credential from the credentials array
  251. editingCredentials.splice(index, 1);
  252. // Update the table body
  253. updateEditingCredentialList();
  254. saveCredentials();
  255. }
  256. function alreadyExists(username){
  257. let isExists = false;
  258. editingCredentials.forEach(function(cred){
  259. if (cred.username == username){
  260. isExists = true;
  261. }
  262. });
  263. return isExists;
  264. }
  265. function closeThisWrapper(){
  266. parent.hideSideWrapper(true);
  267. }
  268. function saveCredentials(){
  269. $.cjax({
  270. url: "/api/proxy/updateCredentials",
  271. method: "POST",
  272. data: {
  273. ep: editingEndpoint.ep,
  274. creds: JSON.stringify(editingCredentials)
  275. },
  276. success: function(data){
  277. if (data.error != undefined){
  278. parent.msgbox(data.error, false, 6000);
  279. }else{
  280. parent.msgbox("Credentials Updated");
  281. //parent.hideSideWrapper(true);
  282. }
  283. }
  284. })
  285. }
  286. </script>
  287. </body>
  288. </html>