diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 17c009b0..08fd95b0 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -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
diff --git a/src/svxlink/reflector/genpw/.gitignore b/src/svxlink/reflector/genpw/.gitignore
new file mode 100644
index 00000000..76dfb233
--- /dev/null
+++ b/src/svxlink/reflector/genpw/.gitignore
@@ -0,0 +1,2 @@
+README.html
+db
diff --git a/src/svxlink/reflector/genpw/README.adoc b/src/svxlink/reflector/genpw/README.adoc
new file mode 100644
index 00000000..e90c0098
--- /dev/null
+++ b/src/svxlink/reflector/genpw/README.adoc
@@ -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]
+----
+
+
+ # ...
+ # 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
+
+
+ WSGIProcessGroup genpw
+ WSGIApplicationGroup %{GLOBAL}
+ Order deny,allow
+ Allow from all
+
+
+
+----
+
+[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!
+
+
+ SvxReflector Password Generator
+
+
+SvxReflector Password Generator
+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.
+
+Timestamp: {{ data.ts }}
+
+
+[ReflectorLogic]
+...
+CALLSIGN={{ data.callsign }}
+AUTH_KEY="{{ data.password }}"
+...
+
+
+
+
+'''
+
+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)
diff --git a/src/svxlink/reflector/genpw/genpw.wsgi b/src/svxlink/reflector/genpw/genpw.wsgi
new file mode 100644
index 00000000..42140694
--- /dev/null
+++ b/src/svxlink/reflector/genpw/genpw.wsgi
@@ -0,0 +1 @@
+from genpw import app as application
diff --git a/src/svxlink/reflector/genpw/getpw.py b/src/svxlink/reflector/genpw/getpw.py
new file mode 100755
index 00000000..a84564c5
--- /dev/null
+++ b/src/svxlink/reflector/genpw/getpw.py
@@ -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())