diff --git a/README.md b/README.md index 885c49b..001e53c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,37 @@ # rxsm-server -RXSM update server \ No newline at end of file +RXSM update server for storing and retrieving updates. +This is a single file application; all server functionality is stored in `rxsmserver/__init__.py`. + +## API +`/db` +> **GET** request to download the sqlite database. +> The database stores version information and a daily hit counter (requests to `/update` per day). +> This is publicly accessibly by design, for transparency. + +`/update` +> **POST** request to check for updates. +> +> The body of the request must be a JSON like +> +> `{'version':'[version number]', 'platform':'[platform]'}` +> +> The response will be a JSON like +> +> `{'status':200, 'reason':'Ok', 'url':'[url to download latest version]', 'out-of-date':true/false}` +> +> The status and reason may be different, and url and out-of-date may not be included if the request is invalid or an error occurs. + +`/release` +> **POST** request to create/update a new release. +> This is password-protected to prevent users from adding malicious code into releases. +> +> The body of the request must be a JSON like +> +> `{'token':'[server password]', 'version':'[version number]', 'platform':'[platform]', 'url':'[url to download version]'}` +> +> The response will be a JSON like +> +> `{'status':200, 'reason':'Version created successfully'}` +> +> The status and reason may be different, especially if the request is invalid or an error occurs. diff --git a/rxsmserver/__init__.py b/rxsmserver/__init__.py index 72e6b0c..65e1134 100644 --- a/rxsmserver/__init__.py +++ b/rxsmserver/__init__.py @@ -5,6 +5,7 @@ from hashlib import sha512 from os import getcwd from threading import get_ident from time import time +from datetime import datetime database_path = 'rxsm-update.db' @@ -58,16 +59,26 @@ def download_database(): @app.route('/check-for-update', methods=['POST']) def check_for_update(): start = time() + db_connection = get_or_create_connection() + cursor = db_connection.cursor() collect_anonymous_stats = str(request.headers.get('DNT')).strip() != '1' - # TODO: add hit counter + # hit counter + if collect_anonymous_stats: + today = datetime.today().date().isoformat() + cursor.execute('SELECT count FROM hits WHERE date=?', (today,)) + result = cursor.fetchone() + if result is not None: + cursor.execute('UPDATE hits SET count=count+1 WHERE date=?', (today,)) + else: + cursor.execute('INSERT INTO hits (date, count) VALUES (?,?)', (today, 1)) + db_connection.commit() + # update lookup 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: @@ -88,6 +99,11 @@ cursor.execute(\ platform TEXT NOT NULL, created_date INTEGER NOT NULL )''' ) +cursor.execute(\ + '''CREATE TABLE IF NOT EXISTS hits ( + date TEXT UNIQUE NOT NULL, + count INTEGER NOT NULL + )''' ) conn.commit() if __name__ == '__main__': diff --git a/rxsmserver/make-release.py b/rxsmserver/make-release.py new file mode 100644 index 0000000..bf02069 --- /dev/null +++ b/rxsmserver/make-release.py @@ -0,0 +1,9 @@ +import requests +raw_token = input('token password: ') +url = input('update server: ')+'/release' +version = input('version: ') +platform = input('platform: ') +download_url = input('download link: ') +release_resp = requests.post(url, json={'token':raw_token, 'version':version, 'platform':platform, 'url':download_url}) +print(release_resp.status_code) +print(release_resp.json()) diff --git a/rxsmserver/server-tester.py b/rxsmserver/server-tester.py index fe319f4..dbaf2a1 100644 --- a/rxsmserver/server-tester.py +++ b/rxsmserver/server-tester.py @@ -32,3 +32,10 @@ print(update_resp.json()) assert update_resp.status_code == 404 assert update_resp.json()['url'] == '' print('Update Ok') + +print('Testing /update DNT') +update_resp = requests.post('http://localhost:9080/update', json={'version':'v0.42.0a', 'platform':'fake-i386'}, headers={"DNT": "1"}) +print(update_resp.json()) +assert update_resp.status_code == 200 +assert update_resp.json()['url'] == 'https://google.com' +print('Update Ok')