@@ -1506,7 +1506,7 @@ <h1 class="page-title"><i data-lucide="shield-check"></i> Security & Bans</h1>
15061506 < h2 > Ban Address or Range</ h2 >
15071507 < div class ="card ">
15081508 < form action ="/admin/add-banned-ip " method ="POST "
1509- onsubmit ="return submitForm(event, false ) ">
1509+ onsubmit ="return submitForm(event, true ) ">
15101510 < input type ="hidden " name ="csrf " value ="{{$.CSRFToken}} ">
15111511 < div class ="form-group ">
15121512 < label > IP Address or CIDR Range</ label >
@@ -1554,8 +1554,7 @@ <h2>Banned IP List</h2>
15541554 < section >
15551555 < h2 > Whitelist Address or Range</ h2 >
15561556 < div class ="card ">
1557- < form action ="/admin/add-whitelisted-ip " method ="POST "
1558- onsubmit ="return submitForm(event, false) ">
1557+ < form action ="/admin/add-whitelisted-ip " method ="POST ">
15591558 < input type ="hidden " name ="csrf " value ="{{$.CSRFToken}} ">
15601559 < div class ="form-group ">
15611560 < label > IP Address or CIDR Range</ label >
@@ -1575,21 +1574,20 @@ <h2>Whitelisted IP List</h2>
15751574 < th style ="width:30% "> Action</ th >
15761575 </ tr >
15771576 </ thead >
1578- < tbody >
1577+ < tbody id =" whitelist-tbody " >
15791578 {{range .Config.WhitelistedIPs}}
15801579 < tr >
15811580 < td > {{.}}</ td >
15821581 < td >
1583- < form action ="/admin/remove-whitelisted-ip " method ="POST "
1584- onsubmit ="return submitForm(event, false) ">
1582+ < form action ="/admin/remove-whitelisted-ip " method ="POST " class ="remove-whitelist-form ">
15851583 < input type ="hidden " name ="csrf " value ="{{$.CSRFToken}} ">
15861584 < input type ="hidden " name ="ip " value ="{{.}} ">
15871585 < button type ="submit " class ="btn btn-outline btn-sm "> Remove</ button >
15881586 </ form >
15891587 </ td >
15901588 </ tr >
15911589 {{else}}
1592- < tr >
1590+ < tr id =" no-whitelist-ips-row " >
15931591 < td colspan ="2 " style ="text-align:center; padding:2rem "> No IPs whitelisted.</ td >
15941592 </ tr >
15951593 {{end}}
@@ -2565,6 +2563,110 @@ <h2>Edit AutoDJ</h2>
25652563 if ( window . location . hash ) { var it = window . location . hash . substring ( 1 ) ; if ( document . getElementById ( it ) ) { showTab ( it , false ) ; } }
25662564 } ) ( ) ;
25672565 </ script >
2566+ < script >
2567+ document . addEventListener ( 'DOMContentLoaded' , function ( ) {
2568+ const addWhitelistForm = document . querySelector ( 'form[action="/admin/add-whitelisted-ip"]' ) ;
2569+ const whitelistTbody = document . getElementById ( 'whitelist-tbody' ) ;
2570+
2571+ // --- Handle ADDING a whitelisted IP ---
2572+ if ( addWhitelistForm ) {
2573+ addWhitelistForm . addEventListener ( 'submit' , function ( event ) {
2574+ event . preventDefault ( ) ;
2575+ const form = event . target ;
2576+ const ipInput = form . querySelector ( 'input[name="ip"]' ) ;
2577+ const ip = ipInput . value . trim ( ) ;
2578+
2579+ if ( ! ip ) {
2580+ alert ( 'IP address cannot be empty.' ) ;
2581+ return ;
2582+ }
2583+
2584+ // Client-side duplicate check
2585+ const existingIPs = Array . from ( whitelistTbody . querySelectorAll ( 'tr td:first-child' ) ) . map ( td => td . textContent . trim ( ) ) ;
2586+ if ( existingIPs . includes ( ip ) ) {
2587+ alert ( 'This IP address is already in the whitelist.' ) ;
2588+ return ;
2589+ }
2590+
2591+ const formData = new FormData ( form ) ;
2592+
2593+ fetch ( form . action , {
2594+ method : 'POST' ,
2595+ body : formData
2596+ } )
2597+ . then ( response => {
2598+ if ( response . ok ) {
2599+ return response . json ( ) ;
2600+ }
2601+ return response . text ( ) . then ( text => { throw new Error ( text || 'An unknown error occurred.' ) } ) ;
2602+ } )
2603+ . then ( data => {
2604+ if ( data . status === 'added' ) {
2605+ const noIpRow = document . getElementById ( 'no-whitelist-ips-row' ) ;
2606+ if ( noIpRow ) {
2607+ noIpRow . remove ( ) ;
2608+ }
2609+
2610+ const newRow = document . createElement ( 'tr' ) ;
2611+ newRow . innerHTML = `
2612+ <td>${ data . ip } </td>
2613+ <td>
2614+ <form action="/admin/remove-whitelisted-ip" method="POST" class="remove-whitelist-form">
2615+ <input type="hidden" name="csrf" value="${ csrfToken } ">
2616+ <input type="hidden" name="ip" value="${ data . ip } ">
2617+ <button type="submit" class="btn btn-outline btn-sm">Remove</button>
2618+ </form>
2619+ </td>
2620+ ` ;
2621+ whitelistTbody . appendChild ( newRow ) ;
2622+ newRow . querySelector ( '.remove-whitelist-form' ) . addEventListener ( 'submit' , handleRemoveSubmit ) ;
2623+ ipInput . value = '' ;
2624+ }
2625+ } )
2626+ . catch ( error => {
2627+ alert ( 'Failed to add IP: ' + error . message ) ;
2628+ } ) ;
2629+ } ) ;
2630+ }
2631+
2632+ // --- Handle REMOVING a whitelisted IP ---
2633+ const handleRemoveSubmit = function ( event ) {
2634+ event . preventDefault ( ) ;
2635+ const form = event . target ;
2636+ const row = form . closest ( 'tr' ) ;
2637+ const formData = new FormData ( form ) ;
2638+
2639+ fetch ( form . action , {
2640+ method : 'POST' ,
2641+ body : formData
2642+ } )
2643+ . then ( response => {
2644+ if ( response . ok ) {
2645+ return response . json ( ) ;
2646+ }
2647+ return response . text ( ) . then ( text => { throw new Error ( text || 'An unknown error occurred.' ) } ) ;
2648+ } )
2649+ . then ( data => {
2650+ if ( data . status === 'removed' ) {
2651+ row . remove ( ) ;
2652+ if ( whitelistTbody . childElementCount === 0 ) {
2653+ const noIpRow = document . createElement ( 'tr' ) ;
2654+ noIpRow . id = 'no-whitelist-ips-row' ;
2655+ noIpRow . innerHTML = '<td colspan="2" style="text-align:center; padding:2rem">No IPs whitelisted.</td>' ;
2656+ whitelistTbody . appendChild ( noIpRow ) ;
2657+ }
2658+ }
2659+ } )
2660+ . catch ( error => {
2661+ alert ( 'Failed to remove IP: ' + error . message ) ;
2662+ } ) ;
2663+ } ;
2664+
2665+ document . querySelectorAll ( '.remove-whitelist-form' ) . forEach ( form => {
2666+ form . addEventListener ( 'submit' , handleRemoveSubmit ) ;
2667+ } ) ;
2668+ } ) ;
2669+ </ script >
25682670</ body >
25692671
25702672</ html >
0 commit comments