Browse Source

Implement update check

master
NGnius (Graham) 5 years ago
parent
commit
0795579902
6 changed files with 87 additions and 14 deletions
  1. +1
    -0
      requirements.txt
  2. +39
    -13
      rxsmserver/__init__.py
  3. +8
    -0
      rxsmserver/make-token.py
  4. +34
    -0
      rxsmserver/server-tester.py
  5. +1
    -1
      scripts/install-requirements.sh
  6. +4
    -0
      scripts/test.sh

+ 1
- 0
requirements.txt View File

@@ -1 +1,2 @@
flask
requests

+ 39
- 13
rxsmserver/__init__.py View File

@@ -6,10 +6,10 @@ from os import getcwd
from threading import get_ident
from time import time

database_path = "rxsm-update.db"
database_path = 'rxsm-update.db'

database_connections = dict()
app = Flask("rxsm-update-server")
app = Flask('rxsm-update-server')

def get_or_create_connection():
global database_connections, database_path
@@ -24,46 +24,72 @@ def create_or_modify_release():
req_json = request.get_json(force=True)
token = req_json['token']
version = req_json['version']
platform = req_json['platform']
url = req_json['url']
except:
return jsonify({'status':400, 'reason':'Invalid request; missing parameter or invalid JSON'}), 400

with open(".token", "r") as f:
with open('.token', 'r') as f:
master_token = f.read()
if sha512(token.encode()).hexdigest() != master_token:
return jsonify({'status':403, 'reason':'Permission denied; invalid token'}), 403

db_connection = get_or_create_connection()
cursor = db_connection.cursor()
cursor.execute("SELECT version FROM releases WHERE version=?", (version,))
cursor.execute('SELECT version FROM releases WHERE version=? AND platform=?', (version, platform))
result = cursor.fetchone()
operation = ""
operation = ''
if result is None:
cursor.execute("INSERT INTO releases (version, url, created_date) VALUES (?,?,?)", (version, url, int(time())))
operation = "create"
cursor.execute('INSERT INTO releases (version, platform, url, created_date) VALUES (?,?,?,?)', (version, platform, url, int(time())))
operation = 'create'
else:
cursor.execute("UPDATE releases SET url=?, created_date=? WHERE version=?", (url, int(time()), version))
operation = "update"
cursor.execute('UPDATE releases SET url=?, created_date=? WHERE version=? and platform=?', (url, int(time()), version, platform))
operation = 'update'
db_connection.commit()

return jsonify({'status':200, 'reason':'Version %s %sd successfully' % (version, operation)}), 200

@app.route('/db', methods=['GET'])
@app.route('/database', methods=['GET'])
def download_database():
return send_file(database_path, cache_timeout=1, as_attachment=True, attachment_filename="rxsm.sqlite")
return send_file(database_path, cache_timeout=1, as_attachment=True, attachment_filename='rxsm.sqlite')

@app.route('/update', methods=['POST'])
@app.route('/check-for-update', methods=['POST'])
def check_for_update():
start = time()
collect_anonymous_stats = str(request.headers.get('DNT')).strip() != '1'
# TODO: add hit counter
try:
req_json = request.get_json(force=True)
current_version = req_json['version']
platform = req_json['platform']
except:
return jsonify({'status':400, 'reason':'Invalid request; missing parameter or invalid JSON'}), 400
db_connection = get_or_create_connection()
cursor = db_connection.cursor()
cursor.execute('SELECT version, url FROM releases WHERE platform=? ORDER BY created_date DESC', (platform,))
result = cursor.fetchone()
if result is None:
return jsonify({'status':404, 'reason':'Platform not found (%ss)' % (time()-start), 'url':'', 'out-of-date':False}), 404
elif result[0] != current_version:
return jsonify({'status':200, 'reason':'Ok (%ss)' % (time()-start), 'url':result[1], 'out-of-date':True}), 200
else:
return jsonify({'status':200, 'reason':'Ok (%ss)' % (time()-start), 'url':result[1], 'out-of-date':False}), 200

# always try to create db table(s)
conn = get_or_create_connection()
cursor = conn.cursor()
cursor.execute(\
"""CREATE TABLE IF NOT EXISTS releases (
'''CREATE TABLE IF NOT EXISTS releases (
id INTEGER PRIMARY KEY,
version TEXT UNIQUE NOT NULL,
url TEXT NOT NULL,
platform TEXT NOT NULL,
created_date INTEGER NOT NULL
)""" )
)''' )
conn.commit()

if __name__ == '__main__':
print("Working directory: " + getcwd())
print('Working directory: ' + getcwd())
app.run(host='0.0.0.0', port=9080, threaded=True)

+ 8
- 0
rxsmserver/make-token.py View File

@@ -0,0 +1,8 @@
# Created 2019-09-11 by NGnius

from hashlib import sha512

password = input('password: ')

with open('.token', 'w') as f:
f.write(sha512(password.encode()).hexdigest())

+ 34
- 0
rxsmserver/server-tester.py View File

@@ -0,0 +1,34 @@
# Created 2019-09-11 by NGnius

import requests

# this is mainly smoke-testing since
# writing complete and proper unit testing for a single-file server is out of scope

# /release test
print('Testing /release')
raw_token = input('token password: ')
release_resp = requests.post('http://localhost:9080/release', json={'token':raw_token, 'version':'v42.0.0a', 'platform':'fake-i386', 'url':'https://google.com'})
print(release_resp.json())
assert release_resp.status_code == 200
print('Release Ok')

# /database test
print('Testing /database')
database_resp = requests.get('http://localhost:9080/database')
assert database_resp.status_code == 200
print('Database Ok')

# /update test
print('Testing /update existing platform')
update_resp = requests.post('http://localhost:9080/update', json={'version':'v0.42.0a', 'platform':'fake-i386'})
print(update_resp.json())
assert update_resp.status_code == 200
assert update_resp.json()['url'] == 'https://google.com'

print('Testing /update missing platform')
update_resp = requests.post('http://localhost:9080/update', json={'version':'v0.42.0a', 'platform':'fake-amd64'})
print(update_resp.json())
assert update_resp.status_code == 404
assert update_resp.json()['url'] == ''
print('Update Ok')

+ 1
- 1
scripts/install-requirements.sh View File

@@ -1,3 +1,3 @@
#!/bin/sh

sudo python3 -m install -r requirements.txt
python3 -m pip install -r requirements.txt

+ 4
- 0
scripts/test.sh View File

@@ -0,0 +1,4 @@
#!/bin/sh

python3 rxsmserver/make-token.py
python3 rxsmserver/server-tester.py