1
0

basicAuthEditor.html 14 KB

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