2 Commits

Author SHA1 Message Date
Yatmesh 2113ef90fa V002:Change the folder name 2026-07-30 16:22:39 +05:30
Yatmesh ca6b2316f3 V001:Initial login 2026-07-30 16:03:10 +05:30
23 changed files with 344 additions and 912 deletions
-3
View File
@@ -1,3 +0,0 @@
{
"liveServer.settings.port": 5501
}
-96
View File
@@ -1,96 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Wi-Fi Guest Policy</title>
</head>
<body>
<br>
<div class="container" style=" text-align: justify; margin-left: 80px; margin-right:80px;">
<h1 align="center" style="font-size:50px;">Wi-Fi Access Terms &amp; Conditions</h1>
<p align-content="center" style="font-size:20px;">&nbsp;&nbsp;&nbsp;&nbsp;Bhaktivedanta Hospital offers complimentary Wi-Fi Internet access to patients, attendants and visitors. To access our Internet service, please register with your mobile number and, if required, obtain the current password from the reception / help desk.</p>
<h3 style="font-size:30px;">Terms of service apply:</h3>
<div class="ul">
<li style="font-size:20px;">Wi-Fi access is available in designated patient, visitor and public areas of the hospital.</li>
<li style="font-size:20px;">It is provided free of charge to patients, attendants and visitors.</li>
<li style="font-size:20px;">Access is subject to the following terms and conditions. These terms and conditions may be revised at any time.</li>
</div>
<h3 style="font-size:30px;">Logging in and out of the Hotspot:</h3>
<div class="ul">
<li style="font-size:20px;">You must enter your mobile number to log in, and a password if one has been issued to you.</li>
<li style="font-size:20px;">You will need a wireless-enabled device with a browser and its own power source.</li>
<li style="font-size:20px;">You must agree to accept the terms and conditions of use by selecting 'I Agree'.</li>
</div>
<h3 style="font-size:30px;">You will be automatically logged out of the Hotspot if:</h3>
<div class="ul">
<li style="font-size:20px;">Your session time limit, set by the hospital, has been reached.</li>
<li style="font-size:20px;">You move out of Wi-Fi coverage or the wireless connection is lost.</li>
<li style="font-size:20px;">The hospital determines it necessary for network security or medical-equipment safety reasons.</li>
</div>
<div class="ul">
<li style="font-size:20px;">Your access is terminated by reason of a breach of these terms and conditions.</li>
<li style="font-size:20px;">The wireless connection of the Hotspot you are accessing is lost, disconnected or becomes out of range.</li>
<li style="font-size:20px;">Speed and reliability of the Hotspot.</li>
<li style="font-size:20px;">Bhaktivedanta Hospital does not guarantee continuous, stable, fault-free or secure access.</li>
<li style="font-size:20px;">The hospital will endeavor to rectify any malfunctions, faults or problems with our Hotspot but is not obliged to do so in any specified time frame.</li>
<li style="font-size:20px;">Wi-Fi speed may be higher or lower and will vary depending on many factors including the capabilities of your wireless device, the amount of traffic and general congestion of the network, your location within the hospital, and interference from medical equipment.</li>
</div>
<h3 style="font-size:30px;">Priority of Clinical Systems</h3>
<p style="font-size:20px;">Guest Wi-Fi is provided on a best-effort basis on a network that is logically separated from the hospital's clinical and administrative systems. The hospital reserves the right to limit, throttle, or suspend guest Wi-Fi access at any time to protect the performance, security, or availability of clinical networks and medical devices.</p>
<h3 style="font-size:30px;">Security</h3>
<p style="font-size:20px;">Your access and use of the Hotspot is at your own risk. You are solely responsible for protecting your usernames, passwords and security-based information. The onus is on you to ensure firewalls and virus protection is in place on your wireless device.</p>
<p style="font-size:20px;">Bhaktivedanta Hospital is not liable for any loss or damage you may sustain as a result of using the Hotspot.</p>
<h3 style="font-size:30px;">User Standards and Obligations</h3>
<p style="font-size:20px;">The Hotspot is intended to be used in a manner that is not offensive in any way to the community at large, and that does not disrupt hospital operations or patient care. Bhaktivedanta Hospital has absolute and sole discretion to limit or block access to unacceptable websites. This includes but is not limited to websites and/or content that:</p>
<div class="ul">
<li style="font-size:20px;">Could cause Bhaktivedanta Hospital to breach any law governing its conduct or to incur a liability to any third party.</li>
<li style="font-size:20px;">Could interfere with the integrity and/or performance of the Hotspot, the hospital's network, medical devices, or equipment.</li>
<li style="font-size:20px;">Depicts, alludes to, or promotes offensive or illegal behavior.</li>
<li style="font-size:20px;">Promotes racism, bigotry, hatred or physical harm to any group or individual.</li>
<li style="font-size:20px;">Harasses or promotes harassment of another person.</li>
<li style="font-size:20px;">Exploits people in a sexual or violent manner.</li>
<li style="font-size:20px;">Contains nudity, violence or offensive subject matter or which may connect to adult websites.</li>
<li style="font-size:20px;">Promotes conduct that is abusive, threatening, obscene or defamatory.</li>
<li style="font-size:20px;">Intentionally infringes copyright.</li>
<li style="font-size:20px;">Involves the transmission of junk mail, chain letters or unsolicited mailing, instant messaging or spamming.</li>
<li style="font-size:20px;">Promotes criminal activity.</li>
<li style="font-size:20px;">Contains viruses, Trojan horses, worms, time bombs, cancelbots, or other computer programming routines that may damage, interfere or intercept access.</li>
<li style="font-size:20px;">If Bhaktivedanta Hospital becomes aware that websites are accessed in contravention of these terms and conditions, it reserves the right to immediately terminate and block access without prior notice.</li>
<p style="font-size:20px;">
Users should be aware that the browsing or downloading of illegal information from the internet could lead to prosecution. In case of any breach of the above terms and conditions by the user which leads to a criminal investigation, the hospital shall abide by local laws and co-operate with investigating authorities by sharing necessary details about the user.</p>
</div>
<h3 style="font-size:30px;">Privacy:</h3>
<div class="ul">
<li style="font-size:20px;">Bhaktivedanta Hospital respects your right to privacy and will not capture any personal information while accessing the Hotspot beyond what is required to provide the service, unless your consent is granted.</li>
<li style="font-size:20px;">Once you access the Hotspot and open the internet browser application, the hospital may capture and process information about the web browser type and/or operating system used by your device in order to determine the most effective means of displaying the requested website on your device.</li>
<li style="font-size:20px;">Bhaktivedanta Hospital will collect and store the mobile number, IP address and MAC address of the device that has accessed the Hotspot, once the terms and conditions have been agreed to. This information is kept separate from your clinical / medical records.</li>
<li style="font-size:20px;">Bhaktivedanta Hospital is not liable for the privacy policies applied by owners or operators of websites. You are solely responsible for checking the terms of use and privacy policy of each website you visit and determining whether you accept such terms of use and privacy policies.</li>
</div>
<h3 style="font-size:30px;">Release and Indemnity</h3>
<p style="font-size:20px;">You release and discharge Bhaktivedanta Hospital from any liability which might arise from your use of the Bhaktivedanta Hospital Wi-Fi Hotspot service including liability in relation to defamatory or offensive material or any breach of copyright which may occur as a result of your use.</p>
<p style="font-size:20px;">You agree to indemnify and must defend and hold harmless Bhaktivedanta Hospital, its employees and agents, from and against all loss, damage, liability, charge, expense (including all reasonable legal and other professional costs on a full indemnity basis) of any nature or kind arising from your breach of these terms and conditions.</p>
</div>
</body>
</html>
-37
View File
@@ -1,37 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="refresh" content="2; url=$(link-redirect)">
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="expires" content="-1">
<title>Bhaktivedanta Hospital Wi-Fi - Redirect</title>
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="css/style.css">
<script>
function startClock() {
$(if popup == 'true')
open('$(link-status)', 'hotspot_status', 'toolbar=0,location=0,directories=0,status=0,menubars=0,resizable=1,width=290,height=200');
$(endif)
location.href = unescape('$(link-redirect-esc)');
}
</script>
</head>
<body onLoad="startClock()" style="background-image: linear-gradient(180deg, rgba(19,28,64,0.62), rgba(19,28,64,0.72)), url('img/background.jpg'); background-repeat: no-repeat; background-attachment: fixed; background-size: cover; background-position: center; width: 100%; height:100%">
<br><br><br><br>
<br><br><br><br>
<br><br><br><br>
<br><br><br><br>
<div class="ie-fixMinHeight">
<div class="main">
<h1 style="color:#ee9736; font-size: 48px;">You are connected!</h1>
<p class="info">If nothing happens, click <a href="$(link-redirect)">here</a></p>
</div>
</div>
</body>
</html>
-11
View File
@@ -1,11 +0,0 @@
{
"captive": $(if logged-in == 'yes')false$(else)true$(endif),
"user-portal-url": "$(link-login-only)",
$(if session-timeout-secs != 0)
"seconds-remaining": $(session-timeout-secs),
$(endif)
$(if remain-bytes-total)
"bytes-remaining": $(remain-bytes-total),
$(endif)
"can-extend-session": true
}
-1
View File
@@ -1 +0,0 @@
a,body,div,form,html,input,label,p,span{margin:0;padding:0;border:0;font-family:sans-serif,Arial}body,html{min-height:100%;overflow-x:hidden}body{background:#a2a09b;background:-webkit-linear-gradient(315deg,hsla(236.6,0%,53.52%,1) 0,hsla(236.6,0%,53.52%,0) 70%),-webkit-linear-gradient(65deg,hsla(220.75,34.93%,26.52%,1) 10%,hsla(220.75,34.93%,26.52%,0) 80%),-webkit-linear-gradient(135deg,hsla(46.42,36.62%,83.92%,1) 15%,hsla(46.42,36.62%,83.92%,0) 80%),-webkit-linear-gradient(205deg,hsla(191.32,50.68%,56.45%,1) 100%,hsla(191.32,50.68%,56.45%,0) 70%);background:linear-gradient(135deg,hsla(236.6,0%,53.52%,1) 0,hsla(236.6,0%,53.52%,0) 70%),linear-gradient(25deg,hsla(220.75,34.93%,26.52%,1) 10%,hsla(220.75,34.93%,26.52%,0) 80%),linear-gradient(315deg,hsla(46.42,36.62%,83.92%,1) 15%,hsla(46.42,36.62%,83.92%,0) 80%),linear-gradient(245deg,hsla(191.32,50.68%,56.45%,1) 100%,hsla(191.32,50.68%,56.45%,0) 70%)}a{color:#486173}input,label{vertical-align:middle;white-space:normal;background:0 0;line-height:1}label{position:relative;display:block}p::first-letter{text-transform:uppercase}.main{min-height:calc(100vh - 90px);width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.ie-fixMinHeight{display:-webkit-box;display:-ms-flexbox;display:flex}.ico{height:16px;position:absolute;top:0;left:0;margin-top:13px;margin-left:14px}.logo{max-width:200px;display:block;margin:0 auto 30px auto}.logo *{fill:#fff}.lite .logo *{fill:#444}h1{text-align:center;color:#ee9736;font-size:70px!important}*{-webkit-box-sizing:border-box;box-sizing:border-box;font-size:16px}.wrap{margin:auto;padding:40px;-webkit-transition:width .3s ease-in-out;transition:width .3s ease-in-out}@media only screen and (min-width:1px) and (max-width:575px){.wrap{width:100%}}form{width:100%;margin-bottom:20px}@-webkit-keyframes fadeIn{from{opacity:0}to{opacity:1}}@keyframes fadeIn{from{opacity:0}to{opacity:1}}.fadeIn{-webkit-animation-name:fadeIn;animation-name:fadeIn}.animated{-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.info{color:#fff;text-align:center;margin-bottom:30px}input{outline:0;}input:focus{outline:0}input[type=password],input[type=text]{width:100%;border:1px solid background-color: rgba(255,255,255,.8);height:44px;padding:3px 20px 3px 40px;margin-bottom:20px;border-radius:6px;background-color:rgba(255,255,255,.8);-webkit-transition:-webkit-box-shadow .3s ease-in-out;transition:-webkit-box-shadow .3s ease-in-out;transition:box-shadow .3s ease-in-out;transition:box-shadow .3s ease-in-out,-webkit-box-shadow .3s ease-in-out}input[type=password]:focus,input[type=text]:focus{-webkit-box-shadow:0 0 5px 0 rgba(255,255,255,1);box-shadow:0 0 5px 0 rgba(255,255,255,1)}.bt{opacity:.4}input[type=submit]{background:#3e4d59;color:#fff;border:0;cursor:pointer;text-align:center;width:100%;height:44px;border-radius:6px;-webkit-transition:background .3s ease-in-out;transition:background .3s ease-in-out}input[type=submit]:focus,input[type=submit]:hover{background:#33404a}table{border-collapse:collapse;width:100%;margin-bottom:20px}table td{color:#fff;border-bottom:1px solid #e6e6e6;padding:10px 4px 10px 0}table td:first-child{font-weight:700}.lite{background:#fff}.lite input[type=password],.lite input[type=text]{border:1px solid #c3c3c3}.lite .info,.lite h1,.lite table td{color:#444}.lite input[type=password]:focus,.lite input[type=text]:focus{-webkit-box-shadow:0 0 5px 0 rgba(62,77,89,.2);box-shadow:0 0 5px 0 rgba(62,77,89,.2)}.dark{background:#343434}.dark input[type=submit]{background:#dc3a41}.dark input[type=submit]:focus,.dark input[type=submit]:hover{background:#b92f35}.dark input[type=password],.dark input[type=text]{background-color:#fff}.dark a{color:#dc3a41}.dark table td{border-bottom:1px solid #505050}.info.alert{color:#da3d41}@media (min-width:576px){.wrap{width:410px}*{font-size:14px!important}}
-24
View File
@@ -1,24 +0,0 @@
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="expires" content="-1">
<title>Bhaktivedanta Hospital Wi-Fi - Error</title>
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<div class="ie-fixMinHeight">
<div class="main">
<div class="wrap">
<h1>Wi-Fi error: $(error)</h1>
<p class="info">Log in page: <a href="$(link-login)">$(link-login)</a></p>
</div>
</div>
</div>
</body>
</html>
-104
View File
@@ -1,104 +0,0 @@
# This file contains error messages which are shown to user, when http/https
# login is used.
# These messages can be changed to make user interface more friendly, including
# translations to different languages.
#
# Various variables can be used here as well. Most frequently used ones are:
# $(error-orig) - original error message from hotspot
# $(ip) - ip address of a client
# $(username) - username of client trying to log in
# internal-error
# It should never happen. If it will, error page will be shown
# displaying this error message (error-orig will describe what has happened)
internal-error = internal error ($(error-orig))
# config-error
# Should never happen if hotspot is configured properly.
config-error = configuration error ($(error-orig))
# not-logged-in
# Will happen, if status or logout page is requested by user,
# which actually is not logged in
not-logged-in = you are not logged in (ip $(ip))
# ippool-empty
# IP address for user is to be assigned from ip pool, but there are no more
# addresses in that pool
ippool-empty = cannot assign ip address - no more free addresses from pool
# shutting-down
# When shutdown is executed, new clients are not accepted
shutting-down = hotspot service is shutting down
# user-session-limit
# If user profile has limit of shared-users, then this error will be shown
# after reaching this limit
user-session-limit = no more sessions are allowed for user $(username)
# license-session-limit
# Depending on licence number of active hotspot clients is limited to
# one or another amount. If this limit is reached, following error is displayed.
license-session-limit = session limit reached ($(error-orig))
# wrong-mac-username
# If username looks like MAC address (12:34:56:78:9a:bc), but is not
# a MAC address of this client, login is rejected
wrong-mac-username = invalid username ($(username)): this MAC address is not yours
# chap-missing
# If http-chap login method is used, but hotspot program does not receive
# back encrypted password, this error message is shown.
# Possible reasons of failure:
# - JavaScript is not enabled in web browser;
# - login.html page is not valid;
# - challenge value has expired on server (more than 1h of inactivity);
# - http-chap login method is recently removed;
# If JavaScript is enabled and login.html page is valid,
# then retrying to login usually fixes this problem.
chap-missing = web browser did not send challenge response (try again, enable JavaScript)
# invalid-username
# Most general case of invalid username or password. If RADIUS server
# has sent an error string with Access-Reject message, then it will
# override this setting.
invalid-username = invalid username or password
# invalid-mac
# Local users (on hotspot server) can be bound to some MAC address. If login
# from different MAC is tried, this error message will be shown.
invalid-mac = user $(username) is not allowed to log in from this MAC address
# uptime-limit, traffic-limit
# For local hotspot users in case if limits are reached
uptime-limit = user $(username) has reached uptime limit
traffic-limit = user $(username) has reached traffic limit
# radius-timeout
# User is authenticated by RADIUS server, but no response is received from it,
# following error will be shown.
radius-timeout = RADIUS server is not responding
# auth-in-progress
# Authorization in progress. Client already has issued an authorization request
# which is not yet complete.
auth-in-progress = already authorizing, retry later
# radius-reply
# Radius server returned some custom error message
radius-reply = $(error-orig)
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Submodule
+1
Submodule hospital_wifi added at b631b53a66
Binary file not shown.

Before

Width:  |  Height:  |  Size: 285 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

-4
View File
@@ -1,4 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="70" height="70">
<circle cx="50" cy="50" r="48" fill="#ffffff" fill-opacity="0.08" stroke="#d4af37" stroke-width="2"/>
<path fill="#d4af37" d="M42 20h16v22h22v16H58v22H42V58H20V42h22V20z"/>
</svg>

Before

Width:  |  Height:  |  Size: 270 B

-1
View File
@@ -1 +0,0 @@
<svg aria-hidden="true" data-prefix="fas" data-icon="key" class="svg-inline--fa fa-key fa-w-16" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path fill="#464646" d="M512 176.001C512 273.203 433.202 352 336 352c-11.22 0-22.19-1.062-32.827-3.069l-24.012 27.014A23.999 23.999 0 0 1 261.223 384H224v40c0 13.255-10.745 24-24 24h-40v40c0 13.255-10.745 24-24 24H24c-13.255 0-24-10.745-24-24v-78.059c0-6.365 2.529-12.47 7.029-16.971l161.802-161.802C163.108 213.814 160 195.271 160 176 160 78.798 238.797.001 335.999 0 433.488-.001 512 78.511 512 176.001zM336 128c0 26.51 21.49 48 48 48s48-21.49 48-48-21.49-48-48-48-48 21.49-48 48z"/></svg>

Before

Width:  |  Height:  |  Size: 644 B

-1
View File
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="#464646" d="M6.6 10.8c1.4 2.8 3.7 5.1 6.5 6.5l2.2-2.2c.3-.3.7-.4 1-.2 1.1.4 2.3.6 3.5.6.6 0 1 .4 1 1V20c0 .6-.4 1-1 1C10.5 21 3 13.5 3 4.4c0-.6.4-1 1-1h3.5c.6 0 1 .4 1 1 0 1.2.2 2.4.6 3.5.1.4 0 .8-.2 1L6.6 10.8z"/></svg>

Before

Width:  |  Height:  |  Size: 293 B

-1
View File
@@ -1 +0,0 @@
<svg aria-hidden="true" data-prefix="fas" data-icon="user" class="svg-inline--fa fa-user fa-w-14" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="#464646" d="M224 256c70.7 0 128-57.3 128-128S294.7 0 224 0 96 57.3 96 128s57.3 128 128 128zm89.6 32h-16.7c-22.2 10.2-46.9 16-72.9 16s-50.6-5.8-72.9-16h-16.7C60.2 288 0 348.2 0 422.4V464c0 26.5 21.5 48 48 48h352c26.5 0 48-21.5 48-48v-41.6c0-74.2-60.2-134.4-134.4-134.4z"/></svg>

Before

Width:  |  Height:  |  Size: 444 B

@@ -0,0 +1,343 @@
#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
# FreeRADIUS 3 + MariaDB installer for Ubuntu 22.04/24.04.
# Run as root. Values can be overridden as environment variables; see --help.
DB_NAME="${DB_NAME:-radius}"
# Use a service-specific variable. Generic DB_USER is commonly exported by
# applications and previously caused FreeRADIUS to be configured as "hotspot".
RADIUS_DB_USER="${RADIUS_DB_USER:-radius}"
DB_USER="$RADIUS_DB_USER"
DB_PASSWORD="${DB_PASSWORD:-}"
RADIUS_CLIENT_NETWORK="${RADIUS_CLIENT_NETWORK:-127.0.0.2/32}"
RADIUS_CLIENT_SECRET="${RADIUS_CLIENT_SECRET:-}"
TEST_USERNAME="${TEST_USERNAME:-shree}"
TEST_PASSWORD="${TEST_PASSWORD:-test}"
CREATE_TEST_USER="${CREATE_TEST_USER:-yes}"
CREDENTIAL_FILE="${CREDENTIAL_FILE:-/root/freeradius-db-credentials}"
API_DOMAIN="${API_DOMAIN:-}"
API_PORT="${API_PORT:-}"
LE_EMAIL="${LE_EMAIL:-}"
usage() {
cat <<'EOF'
Usage: sudo [VAR=value ...] ./install_freeradius_mariadb.sh
Optional environment variables:
DB_NAME MariaDB database name (default: radius)
RADIUS_DB_USER MariaDB user, restricted to localhost (default: radius)
DB_PASSWORD Database password (random when omitted)
RADIUS_CLIENT_NETWORK Allowed NAS IP/CIDR (default: 127.0.0.2/32)
RADIUS_CLIENT_SECRET NAS shared secret (random when omitted)
CREATE_TEST_USER Create a test RADIUS user: yes/no (default: yes)
TEST_USERNAME SQL-backed test username (default: shree)
TEST_PASSWORD SQL-backed test password (default: test)
CREDENTIAL_FILE Root-only result file
API_DOMAIN Public API domain (prompted when omitted)
API_PORT Local API port (prompted; default: 8000)
LE_EMAIL Let's Encrypt email (prompted when omitted)
Example:
sudo RADIUS_CLIENT_NETWORK=10.10.0.0/24 \
RADIUS_CLIENT_SECRET='replace-with-a-long-secret' \
./install_freeradius_mariadb.sh
EOF
}
log() { printf '\n\033[1;34m==>\033[0m %s\n' "$*"; }
die() { printf '\nERROR: %s\n' "$*" >&2; exit 1; }
sql_escape() {
local escaped="${1//\\/\\\\}"
printf '%s' "${escaped//\'/\'\'}"
}
ini_escape() {
# Escape characters that are special in a double-quoted FreeRADIUS value or
# in the pipe-delimited sed replacement used below.
printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g; s/&/\\\&/g; s/|/\\|/g'
}
generate_secret() { openssl rand -base64 36 | tr -d '\n'; }
[[ "${1:-}" != "--help" && "${1:-}" != "-h" ]] || { usage; exit 0; }
[[ $EUID -eq 0 ]] || die "Run this script as root (sudo)."
[[ -r /etc/os-release ]] || die "Cannot identify the operating system."
# shellcheck disable=SC1091
. /etc/os-release
[[ "${ID:-}" == "ubuntu" ]] || die "This installer supports Ubuntu only."
[[ "$DB_NAME" =~ ^[A-Za-z0-9_]+$ ]] || die "DB_NAME may contain only letters, numbers, and underscores."
[[ "$DB_USER" =~ ^[A-Za-z0-9_]+$ ]] ||
die "RADIUS_DB_USER may contain only letters, numbers, and underscores."
[[ "$CREATE_TEST_USER" == "yes" || "$CREATE_TEST_USER" == "no" ]] ||
die "CREATE_TEST_USER must be yes or no."
[[ "$DB_PASSWORD$RADIUS_CLIENT_SECRET$TEST_USERNAME$TEST_PASSWORD" != *$'\n'* ]] ||
die "Credentials and usernames must not contain newline characters."
[[ -n "$API_DOMAIN" ]] || read -r -p "API domain name (example: api.example.com): " API_DOMAIN
[[ -n "$API_PORT" ]] || read -r -p "Local API port [8000]: " API_PORT
API_PORT="${API_PORT:-8000}"
[[ -n "$LE_EMAIL" ]] || read -r -p "Email for Let's Encrypt notices: " LE_EMAIL
API_DOMAIN="${API_DOMAIN,,}"
[[ "$API_DOMAIN" =~ ^([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$ ]] ||
die "Enter a valid public domain name."
[[ "$API_PORT" =~ ^[0-9]+$ ]] && (( API_PORT >= 1 && API_PORT <= 65535 )) ||
die "API port must be between 1 and 65535."
[[ "$LE_EMAIL" =~ ^[^[:space:]@]+@[^[:space:]@]+\.[^[:space:]@]+$ ]] ||
die "Enter a valid email address."
export DEBIAN_FRONTEND=noninteractive
log "Installing FreeRADIUS, MariaDB, Nginx, Certbot, and supporting packages"
apt-get update
apt-get install -y freeradius freeradius-mysql freeradius-utils mariadb-server \
openssl ca-certificates nginx certbot python3-certbot-nginx
systemctl enable --now mariadb
DB_PASSWORD="${DB_PASSWORD:-$(generate_secret)}"
RADIUS_CLIENT_SECRET="${RADIUS_CLIENT_SECRET:-$(generate_secret)}"
if [[ "$CREATE_TEST_USER" == "yes" ]]; then
TEST_PASSWORD="${TEST_PASSWORD:-test}"
fi
db_password_sql="$(sql_escape "$DB_PASSWORD")"
test_username_sql="$(sql_escape "$TEST_USERNAME")"
test_password_sql="$(sql_escape "$TEST_PASSWORD")"
log "Creating the MariaDB database and localhost-only service account"
mariadb <<SQL
CREATE DATABASE IF NOT EXISTS \`$DB_NAME\`
CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER IF NOT EXISTS '$DB_USER'@'localhost' IDENTIFIED BY '$db_password_sql';
ALTER USER '$DB_USER'@'localhost' IDENTIFIED BY '$db_password_sql';
GRANT SELECT, INSERT, UPDATE, DELETE ON \`$DB_NAME\`.* TO '$DB_USER'@'localhost';
FLUSH PRIVILEGES;
SQL
log "Verifying the FreeRADIUS MariaDB service account"
if ! MYSQL_PWD="$DB_PASSWORD" mariadb --protocol=socket \
--user="$DB_USER" --database="$DB_NAME" --batch --skip-column-names \
--execute="SELECT 1" | grep -qx 1; then
die "MariaDB login verification failed for '$DB_USER'@'localhost'."
fi
FR_DIR="/etc/freeradius/3.0"
SQL_SCHEMA="$FR_DIR/mods-config/sql/main/mariadb/schema.sql"
[[ -f "$SQL_SCHEMA" ]] || SQL_SCHEMA="/etc/freeradius/3.0/mods-config/sql/main/mysql/schema.sql"
[[ -f "$SQL_SCHEMA" ]] || die "FreeRADIUS MariaDB/MySQL schema was not installed."
if ! mariadb "$DB_NAME" -Nse "SHOW TABLES LIKE 'radcheck'" | grep -qx radcheck; then
log "Importing the official FreeRADIUS SQL schema"
mariadb "$DB_NAME" < "$SQL_SCHEMA"
else
log "FreeRADIUS SQL tables already exist; leaving them intact"
fi
sql_password_ini="$(ini_escape "$DB_PASSWORD")"
SQL_CONFIG="$FR_DIR/mods-available/sql"
[[ -e "$SQL_CONFIG" ]] || die "FreeRADIUS SQL module configuration was not found."
if [[ ! -e "${SQL_CONFIG}.before-aaa-installer" ]]; then
cp -a "$SQL_CONFIG" "${SQL_CONFIG}.before-aaa-installer"
fi
log "Configuring and enabling the FreeRADIUS SQL module"
sed -Ei \
-e 's|^[[:space:]]*dialect[[:space:]]*=.*|dialect = "mysql"|' \
-e 's|^[[:space:]]*driver[[:space:]]*=.*|driver = "rlm_sql_${dialect}"|' \
-e 's|^[[:space:]]*server[[:space:]]*=.*|server = "localhost"|' \
-e 's|^[[:space:]]*port[[:space:]]*=.*|port = 3306|' \
-e "s|^[[:space:]]*login[[:space:]]*=.*|login = \"$DB_USER\"|" \
-e "s|^[[:space:]]*password[[:space:]]*=.*|password = \"$sql_password_ini\"|" \
-e "s|^[[:space:]]*radius_db[[:space:]]*=.*|radius_db = \"$DB_NAME\"|" \
-e 's|^[[:space:]]*#[[:space:]]*read_clients[[:space:]]*=.*|read_clients = yes|' \
-e 's|^[[:space:]]*read_clients[[:space:]]*=.*|read_clients = yes|' \
"$SQL_CONFIG"
# MariaDB is localhost-only, so disable the sample SQL TLS block. This does not
# change RADIUS EAP/TLS. Use verified TLS instead if MariaDB is moved off-host.
sed -Ei '/^[[:space:]]*tls[[:space:]]*\{[[:space:]]*$/,/^[[:space:]]*\}[[:space:]]*$/ {
/^[[:space:]]*#/! s/^/#/
}' "$SQL_CONFIG"
ln -sfn ../mods-available/sql "$FR_DIR/mods-enabled/sql"
if ! grep -Fqx "login = \"$DB_USER\"" "$SQL_CONFIG" ||
! grep -Fqx "radius_db = \"$DB_NAME\"" "$SQL_CONFIG"; then
die "FreeRADIUS SQL login/database settings were not written correctly."
fi
enabled_sql_target="$(readlink -f "$FR_DIR/mods-enabled/sql")"
[[ "$enabled_sql_target" == "$(readlink -f "$SQL_CONFIG")" ]] ||
die "mods-enabled/sql does not point to the configured SQL module."
for site in "$FR_DIR/sites-enabled/default" "$FR_DIR/sites-enabled/inner-tunnel"; do
[[ -f "$site" ]] || continue
[[ -e "${site}.before-aaa-installer" ]] || cp -a "$site" "${site}.before-aaa-installer"
# Enable existing SQL calls in authorize/accounting/session/post-auth sections.
sed -Ei 's/^([[:space:]]*)-sql([[:space:]]*(#.*)?)$/\1sql\2/' "$site"
done
# Bind the public/default virtual server to every IPv4 interface. Do not expose
# inner-tunnel, which is intentionally a localhost-only internal listener.
sed -Ei 's/^([[:space:]]*)ipaddr[[:space:]]*=.*/\1ipaddr = */' \
"$FR_DIR/sites-enabled/default"
install -d -m 0750 "$FR_DIR/clients.d"
cat > "$FR_DIR/clients.d/aaa-installer.conf" <<EOF
# Managed by install_freeradius_mariadb.sh
# NAS clients are loaded from the MariaDB nas table by the SQL module.
EOF
chmod 0640 "$FR_DIR/clients.d/aaa-installer.conf"
if ! grep -Eq '^[[:space:]]*\$INCLUDE[[:space:]]+clients\.d/' "$FR_DIR/clients.conf"; then
printf '\n$INCLUDE clients.d/\n' >> "$FR_DIR/clients.conf"
fi
if [[ "$CREATE_TEST_USER" == "yes" ]]; then
log "Creating or updating the SQL-backed test user"
mariadb "$DB_NAME" <<SQL
DELETE FROM radcheck
WHERE username = '$test_username_sql' AND attribute = 'Cleartext-Password';
INSERT INTO radcheck (username, attribute, op, value)
VALUES ('$test_username_sql', 'Cleartext-Password', ':=', '$test_password_sql');
SQL
fi
log "Creating or updating SQL-backed NAS clients"
radius_client_network_sql="$(sql_escape "$RADIUS_CLIENT_NETWORK")"
radius_client_secret_sql="$(sql_escape "$RADIUS_CLIENT_SECRET")"
mariadb "$DB_NAME" <<SQL
DELETE FROM nas WHERE shortname IN ('aaa_nas_network', 'aaa_local_database_test');
INSERT INTO nas (nasname, shortname, type, ports, secret, server, community, description)
VALUES ('$radius_client_network_sql', 'aaa_nas_network', 'other', NULL,
'$radius_client_secret_sql', NULL, NULL, 'NAS network managed by installer');
SQL
if [[ "$RADIUS_CLIENT_NETWORK" != "127.0.0.2/32" ]]; then
mariadb "$DB_NAME" <<SQL
INSERT INTO nas (nasname, shortname, type, ports, secret, server, community, description)
VALUES ('127.0.0.2', 'aaa_local_database_test', 'other', NULL,
'$radius_client_secret_sql', NULL, NULL, 'Local SQL client loading test');
SQL
fi
log "Validating configuration and starting FreeRADIUS"
freeradius -XC
systemctl enable freeradius
systemctl restart freeradius
systemctl --no-pager --full is-active freeradius
ss -lunp | grep -E ':(1812|1813)[[:space:]]' ||
die "FreeRADIUS is running but UDP 1812/1813 listeners were not detected."
if [[ "$CREATE_TEST_USER" == "yes" ]]; then
log "Testing database-loaded NAS and SQL user authentication with radclient"
RADTEST_OUTPUT="$(
printf 'User-Name = "%s"\nUser-Password = "%s"\n' "$TEST_USERNAME" "$TEST_PASSWORD" |
radclient -x -i 127.0.0.2 127.0.0.1 auth "$RADIUS_CLIENT_SECRET" 2>&1
)" || {
printf '%s\n' "$RADTEST_OUTPUT" >&2
die "radclient failed. Inspect logs with: journalctl -u freeradius -n 100"
}
printf '%s\n' "$RADTEST_OUTPUT"
grep -q "Access-Accept" <<< "$RADTEST_OUTPUT" ||
die "SQL authentication test did not return Access-Accept."
printf 'SQL authentication test: PASS (Access-Accept for %s)\n' "$TEST_USERNAME"
fi
if command -v ufw >/dev/null 2>&1 && ufw status | grep -q '^Status: active'; then
log "Opening RADIUS authentication/accounting ports in active UFW"
ufw allow from "$RADIUS_CLIENT_NETWORK" to any port 1812 proto udp
ufw allow from "$RADIUS_CLIENT_NETWORK" to any port 1813 proto udp
fi
log "Configuring Nginx and requesting a Let's Encrypt certificate"
LE_WEBROOT="/var/www/letsencrypt"
NGINX_SITE="/etc/nginx/sites-available/hotspot-otp-api"
install -d -m 0755 "$LE_WEBROOT"
cat > "$NGINX_SITE" <<EOF
server {
listen 80;
listen [::]:80;
server_name $API_DOMAIN;
location /.well-known/acme-challenge/ { root $LE_WEBROOT; }
location / {
proxy_pass http://127.0.0.1:$API_PORT;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
}
}
EOF
ln -sfn "$NGINX_SITE" /etc/nginx/sites-enabled/hotspot-otp-api
rm -f /etc/nginx/sites-enabled/default
nginx -t
systemctl enable --now nginx
systemctl reload nginx
if command -v ufw >/dev/null 2>&1 && ufw status | grep -q '^Status: active'; then
ufw allow 'Nginx Full'
fi
certbot certonly --webroot -w "$LE_WEBROOT" -d "$API_DOMAIN" \
--email "$LE_EMAIL" --agree-tos --no-eff-email --non-interactive
cat > "$NGINX_SITE" <<EOF
limit_req_zone \$binary_remote_addr zone=hotspot_api_ip:10m rate=10r/m;
upstream hotspot_otp_api {
server 127.0.0.1:$API_PORT;
keepalive 16;
}
server {
listen 80;
listen [::]:80;
server_name $API_DOMAIN;
location /.well-known/acme-challenge/ { root $LE_WEBROOT; }
location / { return 301 https://\$host\$request_uri; }
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name $API_DOMAIN;
ssl_certificate /etc/letsencrypt/live/$API_DOMAIN/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/$API_DOMAIN/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 1d;
ssl_session_tickets off;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options nosniff always;
client_max_body_size 16k;
location / {
limit_req zone=hotspot_api_ip burst=10 nodelay;
proxy_pass http://hotspot_otp_api;
proxy_http_version 1.1;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \$scheme;
proxy_set_header X-Correlation-ID \$request_id;
proxy_connect_timeout 5s;
proxy_read_timeout 15s;
}
}
EOF
nginx -t
systemctl reload nginx
systemctl enable --now certbot.timer
cat > "$CREDENTIAL_FILE" <<EOF
Created: $(date --iso-8601=seconds)
MariaDB database: $DB_NAME
MariaDB user: $DB_USER
MariaDB password: $DB_PASSWORD
MariaDB host: localhost
Allowed RADIUS client network: $RADIUS_CLIENT_NETWORK
RADIUS client shared secret: $RADIUS_CLIENT_SECRET
Test user created: $CREATE_TEST_USER
Test username: $([[ "$CREATE_TEST_USER" == "yes" ]] && printf '%s' "$TEST_USERNAME" || printf 'N/A')
Test password: $([[ "$CREATE_TEST_USER" == "yes" ]] && printf '%s' "$TEST_PASSWORD" || printf 'N/A')
API URL: https://$API_DOMAIN
API local port: $API_PORT
EOF
chmod 0600 "$CREDENTIAL_FILE"
log "Installation completed"
printf 'Credentials were saved root-only at: %s\n' "$CREDENTIAL_FILE"
if [[ "$CREATE_TEST_USER" == "yes" ]]; then
printf 'Repeat the test using the radclient command documented in README.md.\n'
fi
printf 'Logs: journalctl -u freeradius -f\n'
printf 'API URL: https://%s\n' "$API_DOMAIN"
-215
View File
@@ -1,215 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="pragma" content="no-cache" />
<meta http-equiv="expires" content="-1" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Bhaktivedanta Hospital Wi-Fi - Log in</title>
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="css/style.css">
</head>
<style type="text/css">
textarea,input,select {
background-color: #FDFBFB;
border: 1px solid #BBBBBB;
padding: 2px;
margin: 1px;
font-size: 18px;
color: #808080;
}
label{
font-size:18px;
color:#ffffff;
}
a, a:link, a:visited, a:active { color: #AAAAAA; text-decoration: none; font-size: 10px; }
a:hover { border-bottom: 1px dotted #c1c1c1; color: #AAAAAA; }
img {border: none;}
#heading{
color:#ee9736 !important;
text-align:center;
font-size: 42px !important;
padding: 0 20px;
}
.hospital-logo-wrap{
text-align:center;
}
.wrap{
padding-bottom: 60px !important;
}
</style>
<body style="background-image: linear-gradient(180deg, rgba(19,28,64,0.62), rgba(19,28,64,0.72)), url('img/background.jpg'); background-repeat: no-repeat; background-attachment: fixed; background-size: cover; background-position: center; width: 100%; height:100%">
<br>
<h1 id="heading">Welcome to Bhaktivedanta Hospital</h1>
<!-- <p style="text-align:center;color:#eeeeee;font-size:16px;margin-top:-10px;">Complimentary Wi-Fi for Patients &amp; Visitors</p> -->
<!-- $(if chap-id)-->
<form name="sendin" action="$(link-login-only)" method="post" style="display:none">
<input type="hidden" name="username" />
<input type="hidden" name="password" />
<input type="hidden" name="dst" value="$(link-orig)" />
<input type="hidden" name="popup" value="true" />
</form>
<script src="/md5.js"></script>
<script>
function doLogin() {
document.sendin.username.value = document.login.username.value;
document.sendin.password.value = hexMD5('$(chap-id)' + document.login.password.value + '$(chap-challenge)');
document.sendin.submit();
return false;
}
</script>
<!--$(endif)-->
<div class="ie-fixMinHeight">
<div class="main">
<div class="wrap animated fadeIn">
<form name="login" action="$(link-login-only)" method="post" $(if chap-id) onSubmit="return doLogin()" $(endif)>
<input type="hidden" name="dst" value="$(link-orig)" />
<input type="hidden" name="popup" value="true" />
<div class="hospital-logo-wrap">
<a href="#" target="_blank" style="border: none;"><img src="img/logo.jpg" alt="Bhaktivedanta Hospital" width="90" height="90" style="border-radius:50%;border:3px solid #2c3c7b;" /></a>
<!-- <div style="color:#ffffff;font-size:20px;margin-top:8px;letter-spacing:1px;">BHAKTIVEDANTA HOSPITAL</div> -->
</div>
<br><br>
<!-- STEP 1: phone number entry -->
<div id="step-phone">
<label>
<img class="ico" src="img/phone.svg" alt="#" />
<input id="phone-input" name="username" type="text" inputmode="numeric" pattern="[0-9]{10}" maxlength="10" value="" placeholder="Mobile Number" required
onkeypress="if(event.key==='Enter'){event.preventDefault();requestOtp();}"
oninput="this.value=this.value.replace(/[^0-9]/g,'').slice(0,10);" />
</label>
<div style="display:flex;align-items:center;justify-content:center;gap:6px;white-space:nowrap;margin-top:10px;font-size:15px;">
<input id="terms-checkbox" type="checkbox" value="checkbox" style="width:18px;height:18px;margin:0;" required name="terms" />
<label for="terms-checkbox" style="color:#ffffff;font-size:15px;margin:0;"><b>I Agree to the</b></label>
<a href="Guestpolicy.html" style="color: #e08a6f; font-size:15px;">Terms and Conditions</a>
</div>
<input type="button" value="Get OTP" onclick="requestOtp()"
style="border-radius: 8px;color: #2c3c7b; width: 330px; height: 35px; outline: none; background-color: #ee9736; justified-content:center; font-size: 22px; font-weight:bold; margin-top:14px; cursor:pointer;" />
</div>
<!-- STEP 2: OTP entry + login -->
<div id="step-otp" style="display:none;">
<p style="color:#eeeeee;font-size:15px;margin-bottom:10px;">
OTP sent to <b id="masked-number"></b>
<!-- &nbsp;&middot;&nbsp;<a href="#" onclick="backToPhone();return false;" style="color:#ee9736;text-decoration:underline;font-size:14px;">Change number</a> -->
</p>
<label>
<img class="ico" src="img/password.svg" alt="#" />
<input id="otp-input" name="password" type="text" inputmode="numeric" pattern="[0-9]{6}" maxlength="6" placeholder="Enter OTP" />
</label>
<p style="margin-top:-4px;">
<a href="#" id="resendLink" onclick="resendOtp();return false;" style="color:#ee9736;text-decoration:underline;font-size:14px;">Resend OTP</a>
<span id="timer" style="color:#eeeeee;font-size:14px;"></span>
</p>
<br>
<input id="loginBtn" disabled style="border-radius: 8px;color: #2c3c7b; width: 330px; height: 35px; outline: none; background-color: #ee9736; justified-content:center; font-size: 25px; font-weight:bold; opacity:0.5;" type="submit" value="Login" />
</div>
</form>
<br><br>
<div align="center">
<a href="https://thecaoffice.com/" target="_blank" style="color: #c1c1c1; font-size: 15px">Powered by TheCAOffice</a>
</div>
</div>
</div>
</div>
<br><br><br>
<script>
var resendTimer;
function requestOtp() {
var phone = document.getElementById('phone-input').value;
if (phone.length < 10) {
alert('Please enter all 10 digits of your mobile number');
return;
}
if (!/^[0-9]{10}$/.test(phone)) {
alert('Please enter a valid 10-digit mobile number');
return;
}
if (!document.getElementById('terms-checkbox').checked) {
alert('Please agree to the Terms and Conditions to continue');
return;
}
// TODO: replace this block with a real call to your OTP/SMS provider, e.g.
// fetch('https://your-otp-api.example.com/send', {
// method: 'POST',
// headers: { 'Content-Type': 'application/json' },
// body: JSON.stringify({ mobile: phone })
// }).then(...);
// For now we just move to the OTP screen without actually sending an SMS.
document.getElementById('masked-number').innerText = phone.slice(0, 2) + 'XXXXXX' + phone.slice(-2);
document.getElementById('step-phone').style.display = 'none';
document.getElementById('step-otp').style.display = 'block';
document.getElementById('loginBtn').disabled = false;
document.getElementById('loginBtn').style.opacity = '1';
document.getElementById('otp-input').focus();
startResendTimer();
}
function backToPhone() {
clearInterval(resendTimer);
document.getElementById('step-otp').style.display = 'none';
document.getElementById('step-phone').style.display = 'block';
document.getElementById('loginBtn').disabled = true;
document.getElementById('loginBtn').style.opacity = '0.5';
document.getElementById('otp-input').value = '';
document.getElementById('phone-input').focus();
}
function resendOtp() {
var phone = document.getElementById('phone-input').value;
// TODO: replace this block with a real call to your OTP/SMS provider
// to resend the OTP to `phone`, same as in requestOtp() above.
startResendTimer();
}
function startResendTimer() {
var seconds = 30;
var resendLink = document.getElementById('resendLink');
var timerSpan = document.getElementById('timer');
resendLink.style.pointerEvents = 'none';
resendLink.style.opacity = '0.5';
clearInterval(resendTimer);
timerSpan.innerText = '(' + seconds + 's)';
resendTimer = setInterval(function () {
seconds--;
timerSpan.innerText = '(' + seconds + 's)';
if (seconds <= 0) {
clearInterval(resendTimer);
resendLink.style.pointerEvents = 'auto';
resendLink.style.opacity = '1';
timerSpan.innerText = '';
}
}, 1000);
}
</script>
</body>
</html>
-44
View File
@@ -1,44 +0,0 @@
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="expires" content="-1">
<title>Bhaktivedanta Hospital Wi-Fi - Log out</title>
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="css/style.css">
<script>
function openLogin() {
if (window.name != 'hotspot_logout') return true;
open('$(link-login)', '_blank', '');
window.close();
return false;
}
</script>
</head>
<body>
<div class="ie-fixMinHeight">
<div class="main">
<div class="wrap">
<h1>You have logged out</h1>
<table>
<tr><td>Mobile Number</td><td>$(username)</td></tr>
<tr><td>IP address</td><td>$(ip)</td></tr>
<tr><td>MAC address</td><td>$(mac)</td></tr>
<tr><td>Session time</td><td>$(uptime)</td></tr>
$(if session-time-left)
<tr><td>Time left</td><td>$(session-time-left)</td></tr>
$(endif)
<tr><td>Bytes up / down:</td><td>$(bytes-in-nice) / $(bytes-out-nice)</td></tr>
</table>
<form action="$(link-login)" name="login" onSubmit="return openLogin()">
<input type="submit" value="Log in">
</form>
</div>
</div>
</div>
</body>
</html>
-217
View File
@@ -1,217 +0,0 @@
/*
* A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
* Digest Algorithm, as defined in RFC 1321.
* Version 1.1 Copyright (C) Paul Johnston 1999 - 2002.
* Code also contributed by Greg Holt
* See http://pajhome.org.uk/site/legal.html for details.
*/
/*
* Add integers, wrapping at 2^32. This uses 16-bit operations internally
* to work around bugs in some JS interpreters.
*/
function safe_add(x, y)
{
var lsw = (x & 0xFFFF) + (y & 0xFFFF)
var msw = (x >> 16) + (y >> 16) + (lsw >> 16)
return (msw << 16) | (lsw & 0xFFFF)
}
/*
* Bitwise rotate a 32-bit number to the left.
*/
function rol(num, cnt)
{
return (num << cnt) | (num >>> (32 - cnt))
}
/*
* These functions implement the four basic operations the algorithm uses.
*/
function cmn(q, a, b, x, s, t)
{
return safe_add(rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b)
}
function ff(a, b, c, d, x, s, t)
{
return cmn((b & c) | ((~b) & d), a, b, x, s, t)
}
function gg(a, b, c, d, x, s, t)
{
return cmn((b & d) | (c & (~d)), a, b, x, s, t)
}
function hh(a, b, c, d, x, s, t)
{
return cmn(b ^ c ^ d, a, b, x, s, t)
}
function ii(a, b, c, d, x, s, t)
{
return cmn(c ^ (b | (~d)), a, b, x, s, t)
}
/*
* Calculate the MD5 of an array of little-endian words, producing an array
* of little-endian words.
*/
function coreMD5(x)
{
var a = 1732584193
var b = -271733879
var c = -1732584194
var d = 271733878
for(i = 0; i < x.length; i += 16)
{
var olda = a
var oldb = b
var oldc = c
var oldd = d
a = ff(a, b, c, d, x[i+ 0], 7 , -680876936)
d = ff(d, a, b, c, x[i+ 1], 12, -389564586)
c = ff(c, d, a, b, x[i+ 2], 17, 606105819)
b = ff(b, c, d, a, x[i+ 3], 22, -1044525330)
a = ff(a, b, c, d, x[i+ 4], 7 , -176418897)
d = ff(d, a, b, c, x[i+ 5], 12, 1200080426)
c = ff(c, d, a, b, x[i+ 6], 17, -1473231341)
b = ff(b, c, d, a, x[i+ 7], 22, -45705983)
a = ff(a, b, c, d, x[i+ 8], 7 , 1770035416)
d = ff(d, a, b, c, x[i+ 9], 12, -1958414417)
c = ff(c, d, a, b, x[i+10], 17, -42063)
b = ff(b, c, d, a, x[i+11], 22, -1990404162)
a = ff(a, b, c, d, x[i+12], 7 , 1804603682)
d = ff(d, a, b, c, x[i+13], 12, -40341101)
c = ff(c, d, a, b, x[i+14], 17, -1502002290)
b = ff(b, c, d, a, x[i+15], 22, 1236535329)
a = gg(a, b, c, d, x[i+ 1], 5 , -165796510)
d = gg(d, a, b, c, x[i+ 6], 9 , -1069501632)
c = gg(c, d, a, b, x[i+11], 14, 643717713)
b = gg(b, c, d, a, x[i+ 0], 20, -373897302)
a = gg(a, b, c, d, x[i+ 5], 5 , -701558691)
d = gg(d, a, b, c, x[i+10], 9 , 38016083)
c = gg(c, d, a, b, x[i+15], 14, -660478335)
b = gg(b, c, d, a, x[i+ 4], 20, -405537848)
a = gg(a, b, c, d, x[i+ 9], 5 , 568446438)
d = gg(d, a, b, c, x[i+14], 9 , -1019803690)
c = gg(c, d, a, b, x[i+ 3], 14, -187363961)
b = gg(b, c, d, a, x[i+ 8], 20, 1163531501)
a = gg(a, b, c, d, x[i+13], 5 , -1444681467)
d = gg(d, a, b, c, x[i+ 2], 9 , -51403784)
c = gg(c, d, a, b, x[i+ 7], 14, 1735328473)
b = gg(b, c, d, a, x[i+12], 20, -1926607734)
a = hh(a, b, c, d, x[i+ 5], 4 , -378558)
d = hh(d, a, b, c, x[i+ 8], 11, -2022574463)
c = hh(c, d, a, b, x[i+11], 16, 1839030562)
b = hh(b, c, d, a, x[i+14], 23, -35309556)
a = hh(a, b, c, d, x[i+ 1], 4 , -1530992060)
d = hh(d, a, b, c, x[i+ 4], 11, 1272893353)
c = hh(c, d, a, b, x[i+ 7], 16, -155497632)
b = hh(b, c, d, a, x[i+10], 23, -1094730640)
a = hh(a, b, c, d, x[i+13], 4 , 681279174)
d = hh(d, a, b, c, x[i+ 0], 11, -358537222)
c = hh(c, d, a, b, x[i+ 3], 16, -722521979)
b = hh(b, c, d, a, x[i+ 6], 23, 76029189)
a = hh(a, b, c, d, x[i+ 9], 4 , -640364487)
d = hh(d, a, b, c, x[i+12], 11, -421815835)
c = hh(c, d, a, b, x[i+15], 16, 530742520)
b = hh(b, c, d, a, x[i+ 2], 23, -995338651)
a = ii(a, b, c, d, x[i+ 0], 6 , -198630844)
d = ii(d, a, b, c, x[i+ 7], 10, 1126891415)
c = ii(c, d, a, b, x[i+14], 15, -1416354905)
b = ii(b, c, d, a, x[i+ 5], 21, -57434055)
a = ii(a, b, c, d, x[i+12], 6 , 1700485571)
d = ii(d, a, b, c, x[i+ 3], 10, -1894986606)
c = ii(c, d, a, b, x[i+10], 15, -1051523)
b = ii(b, c, d, a, x[i+ 1], 21, -2054922799)
a = ii(a, b, c, d, x[i+ 8], 6 , 1873313359)
d = ii(d, a, b, c, x[i+15], 10, -30611744)
c = ii(c, d, a, b, x[i+ 6], 15, -1560198380)
b = ii(b, c, d, a, x[i+13], 21, 1309151649)
a = ii(a, b, c, d, x[i+ 4], 6 , -145523070)
d = ii(d, a, b, c, x[i+11], 10, -1120210379)
c = ii(c, d, a, b, x[i+ 2], 15, 718787259)
b = ii(b, c, d, a, x[i+ 9], 21, -343485551)
a = safe_add(a, olda)
b = safe_add(b, oldb)
c = safe_add(c, oldc)
d = safe_add(d, oldd)
}
return [a, b, c, d]
}
/*
* Convert an array of little-endian words to a hex string.
*/
function binl2hex(binarray)
{
var hex_tab = "0123456789abcdef"
var str = ""
for(var i = 0; i < binarray.length * 4; i++)
{
str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
hex_tab.charAt((binarray[i>>2] >> ((i%4)*8)) & 0xF)
}
return str
}
/*
* Convert an array of little-endian words to a base64 encoded string.
*/
function binl2b64(binarray)
{
var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
var str = ""
for(var i = 0; i < binarray.length * 32; i += 6)
{
str += tab.charAt(((binarray[i>>5] << (i%32)) & 0x3F) |
((binarray[i>>5+1] >> (32-i%32)) & 0x3F))
}
return str
}
/*
* Convert an 8-bit character string to a sequence of 16-word blocks, stored
* as an array, and append appropriate padding for MD4/5 calculation.
* If any of the characters are >255, the high byte is silently ignored.
*/
function str2binl(str)
{
var nblk = ((str.length + 8) >> 6) + 1 // number of 16-word blocks
var blks = new Array(nblk * 16)
for(var i = 0; i < nblk * 16; i++) blks[i] = 0
for(var i = 0; i < str.length; i++)
blks[i>>2] |= (str.charCodeAt(i) & 0xFF) << ((i%4) * 8)
blks[i>>2] |= 0x80 << ((i%4) * 8)
blks[nblk*16-2] = str.length * 8
return blks
}
/*
* Convert a wide-character string to a sequence of 16-word blocks, stored as
* an array, and append appropriate padding for MD4/5 calculation.
*/
function strw2binl(str)
{
var nblk = ((str.length + 4) >> 5) + 1 // number of 16-word blocks
var blks = new Array(nblk * 16)
for(var i = 0; i < nblk * 16; i++) blks[i] = 0
for(var i = 0; i < str.length; i++)
blks[i>>1] |= str.charCodeAt(i) << ((i%2) * 16)
blks[i>>1] |= 0x80 << ((i%2) * 16)
blks[nblk*16-2] = str.length * 16
return blks
}
/*
* External interface
*/
function hexMD5 (str) { return binl2hex(coreMD5( str2binl(str))) }
function hexMD5w(str) { return binl2hex(coreMD5(strw2binl(str))) }
function b64MD5 (str) { return binl2b64(coreMD5( str2binl(str))) }
function b64MD5w(str) { return binl2b64(coreMD5(strw2binl(str))) }
/* Backward compatibility */
function calcMD5(str) { return binl2hex(coreMD5( str2binl(str))) }
-41
View File
@@ -1,41 +0,0 @@
<html>
<head>
<meta http-equiv="refresh" content="2; url=$(link-orig)">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="expires" content="-1">
<title>Bhaktivedanta Hospital Wi-Fi - Advertisement</title>
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="css/style.css">
<script>
var popup = '';
function openOrig() {
if (window.focus) popup.focus();
location.href = unescape('$(link-orig-esc)');
}
function openAd() {
location.href = unescape('$(link-redirect-esc)');
}
function openAdvert() {
if (window.name != 'hotspot_advert') {
popup = open('$(link-redirect)', 'hotspot_advert', '');
setTimeout("openOrig()", 1000);
return;
}
setTimeout("openAd()", 1000);
}
</script>
</head>
<body onLoad="openAdvert()">
<div class="ie-fixMinHeight">
<div class="main">
<div class="wrap">
<h1>Advertisement</h1>
<p class="info">If nothing happens, open <a href="$(link-redirect)" target="hotspot_advert">advertisement</a> manually.</p>
</div>
</div>
</div>
</body>
</html>
-12
View File
@@ -1,12 +0,0 @@
$(if http-status == 302)Hotspot redirect$(endif)
$(if http-header == "Location")$(link-redirect)$(endif)
<html>
<head>
<title>Bhaktivedanta Hospital Wi-Fi</title>
<meta http-equiv="refresh" content="0; url=$(link-redirect)">
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="expires" content="-1">
</head>
<body>
</body>
</html>
-27
View File
@@ -1,27 +0,0 @@
$(if http-status == 302)Hotspot login required$(endif)
$(if http-header == "Location")$(link-redirect)$(endif)
<html>
<!--
<?xml version="1.0" encoding="UTF-8"?>
<WISPAccessGatewayParam
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://$(hostname)/xml/WISPAccessGatewayParam.xsd">
<Redirect>
<AccessProcedure>1.0</AccessProcedure>
<AccessLocation>$(location-id)</AccessLocation>
<LocationName>$(location-name)</LocationName>
<LoginURL>$(link-login-only)?target=xml</LoginURL>
<MessageType>100</MessageType>
<ResponseCode>0</ResponseCode>
</Redirect>
</WISPAccessGatewayParam>
-->
<head>
<title>Bhaktivedanta Hospital Wi-Fi</title>
<meta http-equiv="refresh" content="0; url=$(link-redirect)">
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="expires" content="-1">
</head>
<body>
</body>
</html>
-73
View File
@@ -1,73 +0,0 @@
<html>
<head>
<!-- $(if refresh-timeout) -->
<meta http-equiv="refresh" content="$(refresh-timeout-secs)">
<!-- $(endif) -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="expires" content="-1">
<title>Bhaktivedanta Hospital Wi-Fi - Status</title>
<link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="stylesheet" href="css/style.css">
<script>
$(if advert-pending == 'yes')
var popup = '';
function focusAdvert() {
if (window.focus) popup.focus();
}
function openAdvert() {
popup = open('$(link-advert)', 'hotspot_advert', '');
setTimeout("focusAdvert()", 1000);
}
$(endif)
function openLogout() {
if (window.name != 'hotspot_status') return true;
open('$(link-logout)', 'hotspot_logout', 'toolbar=0,location=0,directories=0,status=0,menubars=0,resizable=1,width=280,height=250');
window.close();
return false;
}
</script>
</head>
<body $(if advert-pending == 'yes') onLoad="openAdvert()" $(endif) style="background-image: linear-gradient(180deg, rgba(19,28,64,0.62), rgba(19,28,64,0.72)), url('img/background.jpg'); background-repeat: no-repeat; background-attachment: fixed; background-size: cover; background-position: center; width: 100%; height:100%">
<br><br>
<div class="ie-fixMinHeight">
<div class="main">
<div class="wrap">
<div style="text-align:center;">
<img src="img/logo.jpg" alt="Bhaktivedanta Hospital" width="70" height="70" style="border-radius:50%;border:3px solid #2c3c7b;" />
</div>
<h1>Hi, $(username)!</h1>
<form action="$(link-logout)" name="logout" onSubmit="return openLogout()">
<table>
<tr><td>IP address</td><td>$(ip)</td></tr>
<tr><td>Bytes up / down</td><td>$(bytes-in-nice) / $(bytes-out-nice)</td></tr>
<!-- $(if session-time-left) -->
<tr><td>Connected / left</td><td>$(uptime) / $(session-time-left)</td></tr>
<!-- $(else) -->
<tr><td>Connected</td><td>$(uptime)</td></tr>
<!-- $(endif) -->
<!-- $(if blocked == 'yes') -->
<tr><td>Status</td><td>
<a href="$(link-advert)" target="hotspot_advert">Advertisement required</a></td>
</tr>
<!-- $(elif refresh-timeout) -->
<tr><td>Status refresh</td><td>$(refresh-timeout)</td></tr>
<!-- $(endif) -->
</table>
<!-- $(if login-by-mac != 'yes') -->
<br>
<input style="border-radius: 8px;color: #2c3c7b; width: 330px; height: 35px; outline: none; background-color: #ee9736; justified-content:center; font-size: 25px; font-weight:bold;" type="submit" value="Log out" />
<!-- $(endif) -->
</form>
</div>
</div>
</div>
</body>
</html>