Skip to content

Instantly share code, notes, and snippets.

@seven1m
Last active October 22, 2025 01:43
Show Gist options
  • Save seven1m/3689a08639fe2959b58ad84daad7c136 to your computer and use it in GitHub Desktop.
Save seven1m/3689a08639fe2959b58ad84daad7c136 to your computer and use it in GitHub Desktop.
A stupid simple Ruby cgi script to connect/disconnect AllStarLink nodes, with favorites! (An alternative to allmon)
#!/usr/bin/env ruby
# WARNING: DO NOT EXPOSE THIS TO THE INTERNET. IT HAS NO SECURITY!
# WARNING: DO NOT EXPOSE THIS TO THE INTERNET. IT HAS NO SECURITY!
# WARNING: DO NOT EXPOSE THIS TO THE INTERNET. IT HAS NO SECURITY!
#
# FOR REAL: I mean it. This script doesn't do any validation of the commands,
# so some bad person could do more than just connect/disconnect stuff.
# They could inject anything into your system with this tool. I WARNED YOU.
#
# Install Ruby:
#
# sudo apt-get install ruby
#
# Apache setup:
#
# sudo a2enmod cgi
# sudo systemctl restart apache2
#
# Place this file at /usr/lib/cgi-bin/asl.rb
# Change the THIS_NODE number and FAVORITES list.
#
# Then make the file executable:
#
# sudo chmod 755 /usr/lib/cgi-bin/asl.rb
#
# Visit the page at http://YOUR_NODE_IP/cgi-bin/asl.rb
#
# WARNING: DO NOT EXPOSE THIS TO THE INTERNET. IT HAS NO SECURITY!
# WARNING: DO NOT EXPOSE THIS TO THE INTERNET. IT HAS NO SECURITY!
# WARNING: DO NOT EXPOSE THIS TO THE INTERNET. IT HAS NO SECURITY!
require 'cgi'
require 'net/http'
require 'json'
require 'uri'
require 'erb'
THIS_NODE = 512345
FAVORITES = {
49562 => 'RCWA',
584801 => 'ECG',
}
cgi = CGI.new
# Handle POST actions
message = nil
if ENV['REQUEST_METHOD'] == 'POST'
node = cgi.params['node']&.first
if node =~ /^\d+$/
op = cgi.params['op']&.first
message = `sudo -u asterisk /usr/sbin/rasterisk -x 'rpt cmd #{THIS_NODE} ilink #{op} #{node}'`
sleep 1
end
end
# Get connected nodes
nodes = []
begin
nodes_output = `sudo -u asterisk rasterisk -x "rpt stats #{THIS_NODE}"`
connected_nodes = nodes_output.match(/Nodes currently connected to us.*?([\d, ]+)/)
if connected_nodes
nodes = connected_nodes[1].strip.split(', ').map(&:to_i)
end
rescue
nodes = []
end
node_details = nodes.map do |node|
details = JSON.parse(Net::HTTP.get(URI("https://stats.allstarlink.org/api/stats/#{node}")))['node']
{ id: node, callsign: details['callsign'], frequency: details['node_frequency'] }
rescue
{ id: node, callsign: 'N/A', frequency: 'N/A' }
end
template = <<~HTML
Content-Type: text/html
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>asl.rb</title>
<style>
table { border-collapse: collapse; }
td, th { border: 1px solid #ccc; padding: 0.3em 0.5em; }
form { display: inline; }
</style>
</head>
<body>
<h1>ASL - #{THIS_NODE}</h1>
<% if message %>
<p><%= message %></p>
<% end %>
<form method="post">
<input type="hidden" name="op" value="3"/>
<input name="node" placeholder="node number"/>
<input type="submit" value="connect"/>
</form>
<h2>Connected Nodes</h2>
<table>
<tr><th>Node</th><th>Callsign</th><th>Frequency</th><th>Action</th></tr>
<% node_details.each do |node| %>
<tr>
<td><%= node[:id] %></td>
<td><%= node[:callsign] %></td>
<td><%= node[:frequency] %></td>
<td>
<form method="post">
<input type="hidden" name="op" value="1"/>
<input type="hidden" name="node" value="<%= node[:id] %>"/>
<input type="submit" value="disconnect"/>
</form>
</td>
</tr>
<% end %>
</table>
<h2>Favorites</h2>
<% FAVORITES.each do |fav, name| %>
<form method="post">
<input type="hidden" name="op" value="3"/>
<input type="hidden" name="node" value="<%= fav %>"/>
<input type="submit" value="<%= fav %> - <%= name %>"/>
</form>
<% end %>
</body>
</html>
HTML
puts ERB.new(template).result(binding)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment