fix: implement ban lease
Hee Sung Son committed
Nov 27, 2025 at 21:10 UTC
9f98d163616ad25ce5f88f706f1c6613e1ff7175
4 files changed
+37
-27
cmd/relay-server/frontend/src/hooks/useAdmin.ts
+15
-10
@@ -39,10 +39,18 @@ export function useAdmin() {
39
}
40
41
const leasesData = await leasesRes.json();
42
- const bannedData = await bannedRes.json();
42
+ const bannedData: string[] = await bannedRes.json();
43
44
setLeases(leasesData || []);
45
- setBannedLeases(bannedData || []);
45
+ // bannedData is base64 encoded byte arrays, decode them
46
+ const decodedBanned = (bannedData || []).map((b64: string) => {
47
+ try {
48
+ return atob(b64);
49
+ } catch {
50
+ return b64;
51
+ }
52
+ });
53
+ setBannedLeases(decodedBanned);
54
} catch (err: any) {
55
setError(err.message);
56
} finally {
@@ -54,15 +62,12 @@ export function useAdmin() {
62
fetchData();
63
}, [fetchData]);
64
57
- const toUrlSafe = (base64: string) => {
58
- return base64.replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
59
- };
60
-
61
- const handleBanStatus = async (base64Id: string, isBan: boolean) => {
65
+ const handleBanStatus = async (leaseId: string, isBan: boolean) => {
66
try {
63
- const safeId = toUrlSafe(base64Id);
64
- await fetch(`/admin/leases/${safeId}/ban`, {
65
- method: isBan ? "POST" : "DELETE"
67
+ // URL-safe base64 encode the lease ID
68
+ const safeId = btoa(leaseId).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
69
+ await fetch(`/admin/leases/${safeId}/ban`, {
70
+ method: isBan ? "POST" : "DELETE"
71
});
72
fetchData();
73
} catch (err) {
cmd/relay-server/view.go
+22
@@ -277,6 +277,11 @@ func convertLeaseEntriesToRows(serv *portal.RelayServer) []leaseRow {
277
lease := leaseEntry.Lease
278
identityID := string(lease.Identity.Id)
279
280
+ // Skip banned leases for user-facing list
281
+ if isLeaseBanned(serv, identityID) {
282
+ continue
283
+ }
284
+
285
// Metadata parsing
286
var meta sdk.Metadata
287
_ = json.Unmarshal([]byte(lease.Metadata), &meta)
@@ -388,3 +393,20 @@ func isLocalhost(r *http.Request) bool {
393
return host == "127.0.0.1" || host == "::1"
394
}
395
396
+// isLeaseBanned checks if a lease ID is in the banned list
397
+func isLeaseBanned(serv *portal.RelayServer, leaseID string) bool {
398
+ bannedList := serv.GetLeaseManager().GetBannedLeases()
399
+ for _, banned := range bannedList {
400
+ bannedStr := string(banned)
401
+ log.Debug().
402
+ Str("checking_lease", leaseID).
403
+ Str("banned_entry", bannedStr).
404
+ Bool("match", bannedStr == leaseID).
405
+ Msg("[BanCheck] Comparing lease IDs")
406
+ if bannedStr == leaseID {
407
+ return true
408
+ }
409
+ }
410
+ return false
411
+}
412
+
portal/lease.go
-5
@@ -158,11 +158,6 @@ func (lm *LeaseManager) GetLease(identity *rdsec.Identity) (*LeaseEntry, bool) {
158
defer lm.leasesLock.RUnlock()
159
160
identityID := string(identity.Id)
161
-
162
- // Check if banned
163
- if _, banned := lm.bannedLeases[identityID]; banned {
164
- return nil, false
165
- }
161
162
lease, exists := lm.leases[identityID]
163
if !exists {
portal/relay.go
-12
@@ -301,18 +301,6 @@ func (g *RelayServer) IsConnectionActive(connectionID int64) bool {
301
return exists
302
}
303
304
-// CloseConnection closes the connection with the given ID
305
-func (g *RelayServer) CloseConnection(connectionID int64) {
306
- g.connectionsLock.Lock()
307
- connection, exists := g.connections[connectionID]
308
- g.connectionsLock.Unlock()
309
-
310
- if exists {
311
- log.Info().Int64("conn_id", connectionID).Msg("[RelayServer] Force closing connection")
312
- connection.conn.Close()
313
- }
314
-}
315
-
304
// GetAllLeaseEntries returns all lease entries from the lease manager
305
func (g *RelayServer) GetAllLeaseEntries() []*LeaseEntry {
306
g.leaseManager.leasesLock.RLock()