Merge remote-tracking branch 'sm0svx/master' into tetra-contrib
This commit is contained in:
commit
7b60282e43
|
|
@ -60,6 +60,7 @@ jobs:
|
|||
# uses a compiled language
|
||||
|
||||
- run: |
|
||||
sudo apt update
|
||||
sudo apt install g++ cmake make libsigc++-2.0-dev libgsm1-dev libpopt-dev tcl-dev libgcrypt11-dev libspeex-dev libasound2-dev libopus-dev librtlsdr-dev libjsoncpp-dev libcurl4-openssl-dev qtbase5-dev qttools5-dev qttools5-dev-tools
|
||||
mkdir -p src/build
|
||||
cd src/build
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
README.html
|
||||
db
|
||||
|
|
@ -0,0 +1,103 @@
|
|||
= SvxReflector Password Generator
|
||||
:toc2:
|
||||
|
||||
== Introduction
|
||||
This is a simple web utility used to safely generate a password for a SvxLink
|
||||
node to log in to the SvxReflector. The utility offer random generated
|
||||
passwords to a client which can then be picked up by the reflector sysop to be
|
||||
configured in the reflector configuration file. The generated password is
|
||||
protected in transit by using a SSL/TLS encrypted connection.
|
||||
|
||||
|
||||
== Installation
|
||||
This utility should be installed on a webserver where the SvxReflector sysop
|
||||
have shell access. It does not have to be the same server as where the
|
||||
SvxReflector server is running.
|
||||
|
||||
The Apache webserver must be installed as a prerequisite. That setup is not
|
||||
described in this documentation. The webserver also need to be set up with a
|
||||
valid SSL/TLS server certificate.
|
||||
|
||||
It is of course possible to use other web servers but this is not described in
|
||||
this document.
|
||||
|
||||
In short, the installation is done by installing a couple of dependencies and
|
||||
then copy the genpw files in place.
|
||||
|
||||
[source,bash]
|
||||
----
|
||||
apt update
|
||||
apt install libapache2-mod-wsgi-py3 python3-flask
|
||||
mkdir -p /var/www/genpw/db
|
||||
cp genpw.* /var/www/genpw/
|
||||
cp getpw.py /usr/local/bin/
|
||||
useradd -rU svxlink
|
||||
chown svxlink:svxlink /var/www/genpw/db
|
||||
chmod 2770 /var/www/genpw/db
|
||||
usermod -aG sysop1 svxlink
|
||||
usermod -aG sysop2 svxlink
|
||||
----
|
||||
|
||||
|
||||
== Apache Config Example
|
||||
When all genpw files have been put in place by following the instructions above
|
||||
Apache must be configured with something like the example below.
|
||||
|
||||
[source,apache]
|
||||
----
|
||||
<IfModule mod_ssl.c>
|
||||
<VirtualHost *:443>
|
||||
# ...
|
||||
# Other setup
|
||||
# ...
|
||||
|
||||
# Make sure that SSL/TLS encryption is enabled/required
|
||||
SSLEngine on
|
||||
SSLCertificateFile /etc/ssl/certs/example.org.crt
|
||||
SSLCertificateKeyFile /etc/ssl/private/example.org.key
|
||||
SSLCertificateChainFile /etc/ssl/certs/example.org-intermediate.pem
|
||||
SSLProtocol -all +TLSv1.2 +TLSv1.3
|
||||
|
||||
WSGIDaemonProcess genpw user=svxlink group=svxlink threads=1 home=/var/www/genpw
|
||||
WSGIScriptAlias /genpw /var/www/genpw/genpw.wsgi
|
||||
|
||||
<Directory /var/www/genpw>
|
||||
WSGIProcessGroup genpw
|
||||
WSGIApplicationGroup %{GLOBAL}
|
||||
Order deny,allow
|
||||
Allow from all
|
||||
</Directory>
|
||||
</VirtualHost>
|
||||
</IfModule>
|
||||
----
|
||||
|
||||
[source,bash]
|
||||
----
|
||||
systemctl restart apache2
|
||||
----
|
||||
|
||||
|
||||
== Usage
|
||||
Send a URL to the SvxLink node sysop that look something like the one below.
|
||||
|
||||
https://www.example.com/genpw?callsign=SM0XYZ
|
||||
|
||||
A new password will be generated each time the link is clicked. After the
|
||||
SvxLink node sysop have clicked on the link to generate a password he should
|
||||
send back the timestamp to the SvxReflector sysop in order for him to verify
|
||||
that the password with the correct timestamp is used.
|
||||
|
||||
The SvxLink node sysop must not reload the page after generating a password
|
||||
that is then used to configure the SvxLink node. Since the SvxReflector sysop
|
||||
only see the latest generated password it will then be overwritten and thus
|
||||
wrong.
|
||||
|
||||
The SvxReflector node sysop will run the getpw.py script on the webserver to retrieve the password to configure.
|
||||
|
||||
$ getpw.py SM0XYZ
|
||||
SM0XYZ: "{"remote_addr": "11.22.33.44", "ts": "2021-02-14T19:51:30.291Z", "password": "!_2>4kGUHM7vorUctVJFaxZ!<!dzln"}"
|
||||
|
||||
The password will be removed from the database when accessed once.
|
||||
|
||||
It is also possible to list all callsigns in the database by running the script
|
||||
above with no arguments.
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
from flask import Flask, escape, request, make_response, jsonify, render_template_string
|
||||
import random
|
||||
import string
|
||||
import dbm
|
||||
import time
|
||||
import json
|
||||
import os
|
||||
import math
|
||||
|
||||
page_template = '''
|
||||
<!doctype html>
|
||||
<html>
|
||||
<head>
|
||||
<title>SvxReflector Password Generator</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>SvxReflector Password Generator</h1>
|
||||
Copy the callsign and password configuration to your SvxLink ReflectorLogic
|
||||
configuration. A new password is generated every time this page is reloaded so
|
||||
when you have settled for a password, don't reload. Send the timestamp to the
|
||||
SvxReflector administrator as a verification of that the correct password
|
||||
generation is chosen.
|
||||
<p/>
|
||||
Timestamp: {{ data.ts }}
|
||||
<p/>
|
||||
<pre>
|
||||
[ReflectorLogic]
|
||||
...
|
||||
CALLSIGN={{ data.callsign }}
|
||||
AUTH_KEY="{{ data.password }}"
|
||||
...
|
||||
</pre>
|
||||
<hr/>
|
||||
</body>
|
||||
</html>
|
||||
'''
|
||||
|
||||
def random_pw_string(length):
|
||||
alphabet = string.ascii_letters + string.digits \
|
||||
+ '!#$%&*+:;<=>?_'
|
||||
alphabet.translate({ord('"'): None, ord('\\'): None})
|
||||
result_str = ''.join((random.choice(alphabet) for i in range(length)))
|
||||
return result_str
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
@app.route('/')
|
||||
def genpw():
|
||||
callsign = escape(request.args.get("callsign"))
|
||||
if callsign == 'None' or len(callsign) == 0:
|
||||
response = make_response('BAD REQUEST\n', 400)
|
||||
response.mimetype = "text/plain"
|
||||
else:
|
||||
frac, epoch = math.modf(time.time())
|
||||
frac_ms = int(1000 * frac)
|
||||
ts = '%s.%03uZ' % (time.strftime('%Y-%m-%dT%H:%M:%S', \
|
||||
time.gmtime(epoch)), frac_ms)
|
||||
pw = random_pw_string(30)
|
||||
data = {
|
||||
'remote_addr': request.remote_addr,
|
||||
'ts': ts,
|
||||
'password': pw
|
||||
}
|
||||
os.umask(0o007)
|
||||
with dbm.open('db/svxreflector-genpw', 'c', 0o660) as db:
|
||||
db[callsign] = json.dumps(data)
|
||||
data['callsign']=callsign
|
||||
#print(data)
|
||||
response = make_response(render_template_string(page_template, data=data), 200)
|
||||
return response
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(debug=True)
|
||||
|
|
@ -0,0 +1 @@
|
|||
from genpw import app as application
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import dbm
|
||||
import sys
|
||||
import os
|
||||
|
||||
os.umask(0o007)
|
||||
with dbm.open('/var/www/genpw/db/svxreflector-genpw', 'c', 0o660) as db:
|
||||
if len(sys.argv) > 1:
|
||||
callsign = sys.argv[1]
|
||||
print(callsign + ': "' + db[callsign].decode() + '"')
|
||||
del db[callsign]
|
||||
else:
|
||||
for k in db.keys():
|
||||
print(k.decode() + ': ' + db[k].decode())
|
||||
Loading…
Reference in New Issue