From 92dbc295cababcb581b23f14dbf0d451fbefa114 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCllenhaupt?= Date: Wed, 4 May 2016 08:59:59 +0200 Subject: [PATCH 01/34] make the server compatible with the new JSON format --- server/lobbyconnection.py | 68 ++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/server/lobbyconnection.py b/server/lobbyconnection.py index 52f17390b..44253cdd6 100644 --- a/server/lobbyconnection.py +++ b/server/lobbyconnection.py @@ -528,34 +528,56 @@ def decodeUniqueId(self, serialized_uniqueid): encoded = message[24:-40] key = (base64.b64decode(message[-40:])) + # The JSON string is AES encrypted + # first decrypt the AES key with our rsa private key AESkey = rsa.decrypt(key, PRIVATE_KEY) - # What the hell is this? + # now decrypt the message cipher = AES.new(AESkey, AES.MODE_CBC, iv) DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).decode('utf-8') decoded = DecodeAES(cipher, encoded)[:-trailing] - regexp = re.compile(r'[0-9a-zA-Z\\]("")') - decoded = regexp.sub('"', decoded) - decoded = decoded.replace("\\", "\\\\") - regexp = re.compile('[^\x09\x0A\x0D\x20-\x7F]') - decoded = regexp.sub('', decoded) - jstring = json.loads(decoded) - - if str(jstring["session"]) != str(self.session) : - self.sendJSON(dict(command="notice", style="error", text="Your session is corrupted. Try relogging")) - return None - - machine = jstring["machine"] - - UUID = str(machine.get('UUID', 0)).encode() - mem_SerialNumber = str(machine.get('mem_SerialNumber', 0)).encode() - DeviceID = str(machine.get('DeviceID', 0)).encode() - Manufacturer = str(machine.get('Manufacturer', 0)).encode() - Name = str(machine.get('Name', 0)).encode() - ProcessorId = str(machine.get('ProcessorId', 0)).encode() - SMBIOSBIOSVersion = str(machine.get('SMBIOSBIOSVersion', 0)).encode() - SerialNumber = str(machine.get('SerialNumber', 0)).encode() - VolumeSerialNumber = str(machine.get('VolumeSerialNumber', 0)).encode() + + # since the legacy uid.dll generated JSON is flawed, + # there's a new JSON format, starting with '2' as magic byte + if decoded.startswith('2'): + data = json.loads(decoded[1:]) + if str(data["session"]) != str(session) : + self.sendJSON(dict(command="notice", style="error", text="Your session is corrupted. Try relogging")) + return None + UUID = data['machine']['uuid'] + mem_SerialNumber = data['machine']['memory']['serial0'] + DeviceID = data['machine']['disks']['controller_id'] + Manufacturer = data['machine']['manufacturer'] + Name = data['machine']['processor']['name'] + ProcessorId = data['machine']['processor']['id'] + SMBIOSBIOSVersion = data['machine']['bios']['smbbversion'] + SerialNumber = data['machine']['bios']['serial'] + VolumeSerialNumber = data['machine']['disks']['vserial'] + else: + # the old JSON format contains unescaped backspaces in the device id + # of the IDE controller, which now needs to be corrected to get valid JSON + regexp = re.compile(r'[0-9a-zA-Z\\]("")') + decoded = regexp.sub('"', decoded) + decoded = decoded.replace("\\", "\\\\") + regexp = re.compile('[^\x09\x0A\x0D\x20-\x7F]') + decoded = regexp.sub('', decoded) + jstring = json.loads(decoded) + + if str(jstring["session"]) != str(self.session) : + self.sendJSON(dict(command="notice", style="error", text="Your session is corrupted. Try relogging")) + return None + + machine = jstring["machine"] + + UUID = str(machine.get('UUID', 0)).encode() + mem_SerialNumber = str(machine.get('mem_SerialNumber', 0)).encode() # serial number of first memory module + DeviceID = str(machine.get('DeviceID', 0)).encode() # device id of the IDE controller + Manufacturer = str(machine.get('Manufacturer', 0)).encode() # BIOS manufacturer + Name = str(machine.get('Name', 0)).encode() # verbose processor name + ProcessorId = str(machine.get('ProcessorId', 0)).encode() + SMBIOSBIOSVersion = str(machine.get('SMBIOSBIOSVersion', 0)).encode() + SerialNumber = str(machine.get('SerialNumber', 0)).encode() # BIOS serial number + VolumeSerialNumber = str(machine.get('VolumeSerialNumber', 0)).encode() # https://www.raymond.cc/blog/changing-or-spoofing-hard-disk-hardware-serial-number-and-volume-id/ for i in machine.values() : low = i.lower() From f637bf3341022d942c43159533e072061c92caba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCllenhaupt?= Date: Wed, 4 May 2016 09:05:16 +0200 Subject: [PATCH 02/34] use the correct Manufacturer for hashing --- server/lobbyconnection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/lobbyconnection.py b/server/lobbyconnection.py index 44253cdd6..b4d384a42 100644 --- a/server/lobbyconnection.py +++ b/server/lobbyconnection.py @@ -547,7 +547,7 @@ def decodeUniqueId(self, serialized_uniqueid): UUID = data['machine']['uuid'] mem_SerialNumber = data['machine']['memory']['serial0'] DeviceID = data['machine']['disks']['controller_id'] - Manufacturer = data['machine']['manufacturer'] + Manufacturer = data['machine']['bios']['manufacturer'] Name = data['machine']['processor']['name'] ProcessorId = data['machine']['processor']['id'] SMBIOSBIOSVersion = data['machine']['bios']['smbbversion'] From aece52272837d20dddd6d2199af57e425878a8e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCllenhaupt?= Date: Sat, 7 May 2016 22:25:32 +0200 Subject: [PATCH 03/34] correctly indent VM check --- server/lobbyconnection.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/lobbyconnection.py b/server/lobbyconnection.py index b4d384a42..172085588 100644 --- a/server/lobbyconnection.py +++ b/server/lobbyconnection.py @@ -579,10 +579,10 @@ def decodeUniqueId(self, serialized_uniqueid): SerialNumber = str(machine.get('SerialNumber', 0)).encode() # BIOS serial number VolumeSerialNumber = str(machine.get('VolumeSerialNumber', 0)).encode() # https://www.raymond.cc/blog/changing-or-spoofing-hard-disk-hardware-serial-number-and-volume-id/ - for i in machine.values() : - low = i.lower() - if "vmware" in low or "virtual" in low or "innotek" in low or "qemu" in low or "parallels" in low or "bochs" in low : - return "VM" + for i in machine.values() : + low = i.lower() + if "vmware" in low or "virtual" in low or "innotek" in low or "qemu" in low or "parallels" in low or "bochs" in low : + return "VM" m = hashlib.md5() m.update(UUID + mem_SerialNumber + DeviceID + Manufacturer + Name + ProcessorId + SMBIOSBIOSVersion + SerialNumber + VolumeSerialNumber) From e35e13378745cbe5f91a27066e1c7ac804ba934e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCllenhaupt?= Date: Fri, 13 May 2016 12:03:55 +0200 Subject: [PATCH 04/34] fix session variable --- server/lobbyconnection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/lobbyconnection.py b/server/lobbyconnection.py index 172085588..3b82d3da9 100644 --- a/server/lobbyconnection.py +++ b/server/lobbyconnection.py @@ -541,7 +541,7 @@ def decodeUniqueId(self, serialized_uniqueid): # there's a new JSON format, starting with '2' as magic byte if decoded.startswith('2'): data = json.loads(decoded[1:]) - if str(data["session"]) != str(session) : + if str(data['session']) != str(self.session) : self.sendJSON(dict(command="notice", style="error", text="Your session is corrupted. Try relogging")) return None UUID = data['machine']['uuid'] From def0da0767cf75dd88c1f8cc51a7187976ed242a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCllenhaupt?= Date: Fri, 13 May 2016 12:14:35 +0200 Subject: [PATCH 05/34] encode unicode before hashing --- server/lobbyconnection.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/server/lobbyconnection.py b/server/lobbyconnection.py index 3b82d3da9..abf5b4d16 100644 --- a/server/lobbyconnection.py +++ b/server/lobbyconnection.py @@ -544,15 +544,15 @@ def decodeUniqueId(self, serialized_uniqueid): if str(data['session']) != str(self.session) : self.sendJSON(dict(command="notice", style="error", text="Your session is corrupted. Try relogging")) return None - UUID = data['machine']['uuid'] - mem_SerialNumber = data['machine']['memory']['serial0'] - DeviceID = data['machine']['disks']['controller_id'] - Manufacturer = data['machine']['bios']['manufacturer'] - Name = data['machine']['processor']['name'] - ProcessorId = data['machine']['processor']['id'] - SMBIOSBIOSVersion = data['machine']['bios']['smbbversion'] - SerialNumber = data['machine']['bios']['serial'] - VolumeSerialNumber = data['machine']['disks']['vserial'] + UUID = data['machine']['uuid'].encode() + mem_SerialNumber = data['machine']['memory']['serial0'].encode() + DeviceID = data['machine']['disks']['controller_id'].encode() + Manufacturer = data['machine']['bios']['manufacturer'].encode() + Name = data['machine']['processor']['name'].encode() + ProcessorId = data['machine']['processor']['id'].encode() + SMBIOSBIOSVersion = data['machine']['bios']['smbbversion'].encode() + SerialNumber = data['machine']['bios']['serial'].encode() + VolumeSerialNumber = data['machine']['disks']['vserial'].encode() else: # the old JSON format contains unescaped backspaces in the device id # of the IDE controller, which now needs to be corrected to get valid JSON From 0b530231e085a276cd330ce99e6b158e7cd9b90d Mon Sep 17 00:00:00 2001 From: Sheeo Date: Sat, 14 May 2016 13:47:06 +0200 Subject: [PATCH 06/34] Don't recommend the use of / in docker name --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fa7e8db08..dd0c3c363 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ Install [docker](https://www.docker.com). Follow the steps to get [faf-db](https://github.com/FAForever/db) setup, the following assumes the db container is called `faf-db`. - docker build -t faf/server . - docker run --link faf-db:db -p 8001:8001 -p 30351:30351 faf/server + docker build -t faf-server . + docker run --link faf-db:db -p 8001:8001 -p 30351:30351 faf-server ## Running the tests From 90398a47b22a02b93c985f44f23c75b4930dc89f Mon Sep 17 00:00:00 2001 From: IDragonfire Date: Sat, 14 May 2016 15:22:10 +0200 Subject: [PATCH 07/34] Example for docker run -e --- README.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dd0c3c363..9e14c9936 100644 --- a/README.md +++ b/README.md @@ -12,16 +12,25 @@ master|develop Install [docker](https://www.docker.com). -Follow the steps to get [faf-db](https://github.com/FAForever/db) setup, the following assumes the db container is called `faf-db`. +Follow the steps to get [faf-db](https://github.com/FAForever/db) setup, the following assumes the db container is called `faf-db` and the database is called `faf_test` and the root password ist `banana`. docker build -t faf-server . docker run --link faf-db:db -p 8001:8001 -p 30351:30351 faf-server +Check if the container is running with + + docker ps + +If you have a differnet root password, database name then the default (see [config.py](https://github.com/FAForever/server/blob/develop/server/config.py#L43)), you must pass it over the environment parameter of docker, e.g. + + docker run --link faf-db:db -p 8001:8001 -p 30351:30351 -e FAF_DB_PASSWORD= -e FAF_DB_NAME= faf-server + + ## Running the tests Run `py.test` - docker run --link faf-db:db faf/server bash -c py.test + docker run --link faf-db:db faf-server bash -c py.test # Contributing From 56401af75820258361af488e71f40d21ab43a499 Mon Sep 17 00:00:00 2001 From: IDragonfire Date: Sat, 14 May 2016 15:34:57 +0200 Subject: [PATCH 08/34] Add some notes about debugging --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9e14c9936..5478b78c3 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,12 @@ Check if the container is running with docker ps -If you have a differnet root password, database name then the default (see [config.py](https://github.com/FAForever/server/blob/develop/server/config.py#L43)), you must pass it over the environment parameter of docker, e.g. +If you cannot find `faf-server`in the list, run `docker run` without `-d` to see what happen. + +If you have a different root password, database name then the default (see [config.py](https://github.com/FAForever/server/blob/develop/server/config.py#L43)), you must pass it over the environment parameter of docker, e.g. docker run --link faf-db:db -p 8001:8001 -p 30351:30351 -e FAF_DB_PASSWORD= -e FAF_DB_NAME= faf-server - ## Running the tests Run `py.test` From 18ef1afe384116868ce60bd090b5fccf35f7b889 Mon Sep 17 00:00:00 2001 From: Dragonfire Date: Sat, 14 May 2016 14:00:26 +0200 Subject: [PATCH 09/34] Use explicit path as entrypoint --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 7e2ef4120..068c8179e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,7 @@ WORKDIR /code/ RUN python3.5 -m pip install -e . # Main entrypoint and the default command that will be run -CMD ["./server.py"] +CMD ["/usr/local/bin/python3.5", "server.py"] # Game server runs on 8000/tcp, lobby server runs on 8001/tcp, nat echo server runs on 30351/udp EXPOSE 8000 8001 30351 From 60cce9ea92c84efee1d845eb2d6c921f925992c5 Mon Sep 17 00:00:00 2001 From: Sheeo Date: Sun, 15 May 2016 14:33:56 +0200 Subject: [PATCH 10/34] Describe that server expects faf-server.pem Closes #131 --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 5478b78c3..bd013b3d2 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,13 @@ Install [docker](https://www.docker.com). Follow the steps to get [faf-db](https://github.com/FAForever/db) setup, the following assumes the db container is called `faf-db` and the database is called `faf_test` and the root password ist `banana`. + +The server needs an RSA key to decode uniqueid messages, we've provided an example key in the repo as `faf-server.example.pem`. The server expects this to be named `faf-server.pem` at runtime, so first copy this + + cp faf-server.example.pem faf-server.pem + +Then use Docker to build and run the server as follows + docker build -t faf-server . docker run --link faf-db:db -p 8001:8001 -p 30351:30351 faf-server From 0c7458133fc6e181b807cf137aebe0616ea0a49d Mon Sep 17 00:00:00 2001 From: Christian Schmidt Date: Mon, 16 May 2016 22:03:37 +0200 Subject: [PATCH 11/34] Login data: test user passwords now get correctly hashed --- tests/data/db-fixtures.sql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/data/db-fixtures.sql b/tests/data/db-fixtures.sql index 69b40542f..7b54fbf28 100644 --- a/tests/data/db-fixtures.sql +++ b/tests/data/db-fixtures.sql @@ -2,9 +2,9 @@ use faf_test; -- Login table delete from login; -insert into login (id, login, email, password) values (1, 'test', 'test@example.com', 'test_password'); -insert into login (id, login, email, password) values (2, 'Dostya', 'dostya@cybran.example.com', 'vodka'); -insert into login (id, login, email, password) values (3, 'Rhiza', 'rhiza@aeon.example.com', 'puff_the_magic_dragon'); +insert into login (id, login, email, password) values (1, 'test', 'test@example.com', SHA2('test_password', 256)); +insert into login (id, login, email, password) values (2, 'Dostya', 'dostya@cybran.example.com', SHA2('vodka', 256)); +insert into login (id, login, email, password) values (3, 'Rhiza', 'rhiza@aeon.example.com', SHA2('puff_the_magic_dragon', 256)); -- global rating delete from global_rating; From 592ac4c22d7e26fe3714303aa5c08fcdb1acfaa7 Mon Sep 17 00:00:00 2001 From: Sheeo Date: Tue, 17 May 2016 01:18:13 +0200 Subject: [PATCH 12/34] Allocate a tty and forward signals during test run Closes #135 --- .travis.yml | 2 +- scripts/run_and_report_coverage.sh | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b83757ffa..2218a21e0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,4 +18,4 @@ install: - docker build -t faf-server . script: - - docker run --link faf-db:db -e FAF_DB_PASSWORD=banana -e COVERALLS_REPO_TOKEN=Vl36DD3XeJI1KjzoyGgxpV3wsVohnJW22 faf-server bash scripts/run_and_report_coverage.sh + - docker run -it --link faf-db:db -e FAF_DB_PASSWORD=banana -e COVERALLS_REPO_TOKEN=Vl36DD3XeJI1KjzoyGgxpV3wsVohnJW22 faf-server bash scripts/run_and_report_coverage.sh diff --git a/scripts/run_and_report_coverage.sh b/scripts/run_and_report_coverage.sh index f2368ddff..b00fa4a95 100755 --- a/scripts/run_and_report_coverage.sh +++ b/scripts/run_and_report_coverage.sh @@ -1,3 +1,4 @@ #!/usr/bin/env bash +set -e py.test --cov-report term-missing --cov=server coveralls From 8999eb72e8538563056686463516bdfc8b6980fc Mon Sep 17 00:00:00 2001 From: Christian Schmidt Date: Tue, 17 May 2016 10:26:57 +0200 Subject: [PATCH 13/34] Changed perform_login to use sha256-hash of given credentials-pw --- tests/integration_tests/test_server.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/integration_tests/test_server.py b/tests/integration_tests/test_server.py index 76acbe95b..75eab9183 100644 --- a/tests/integration_tests/test_server.py +++ b/tests/integration_tests/test_server.py @@ -1,4 +1,5 @@ import pytest +import hashlib from server import VisibilityState @@ -44,11 +45,12 @@ def get_session(proto): @asyncio.coroutine def perform_login(proto, credentials): login, pw = credentials + pw_hash = hashlib.sha256(pw.encode('utf-8')) proto.send_message({'command': 'hello', 'version': '1.0.0-dev', 'user_agent': 'faf-client', 'login': login, - 'password': pw, + 'password': pw_hash.hexdigest(), 'unique_id': 'some_id' }) yield from proto.drain() From 8cba3c3454a64377d30720ff30703ebf72174660 Mon Sep 17 00:00:00 2001 From: Michel Jung Date: Wed, 18 May 2016 19:01:56 +0200 Subject: [PATCH 14/34] Fix OAuth access to faf-api which has been broken with c12c76c --- requirements.txt | 1 + server/api/api_accessor.py | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/requirements.txt b/requirements.txt index ad9f44ea8..d7519b70f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -19,3 +19,4 @@ aiocron marisa-trie oauth2client git+https://github.com/FAForever/faftools.git@develop#egg=faftools +pyopenssl \ No newline at end of file diff --git a/server/api/api_accessor.py b/server/api/api_accessor.py index 7d445efad..284236355 100644 --- a/server/api/api_accessor.py +++ b/server/api/api_accessor.py @@ -8,8 +8,12 @@ class ApiAccessor: def __init__(self): - with open("faf-server.pem", "rb") as f: - self.private_key = f.read() + self._service_account_credentials = ServiceAccountCredentials.from_p12_keyfile( + 'faf-server', + 'faf-server.pem', + scopes='write_achievements write_events' + ) + self._service_account_credentials.token_uri = API_TOKEN_URI async def api_get(self, path, player_id): loop = asyncio.get_event_loop() @@ -26,9 +30,5 @@ async def api_post(self, path, player_id, data=None, headers=None): return result def http(self, sub=None): - credentials = ServiceAccountCredentials.from_p12_keyfile( - 'faf-server', - 'faf-server.pem', - scopes='write_achievements write_events' - ) + credentials = self._service_account_credentials.create_delegated(sub) return credentials.authorize(Http()) From 668a63c3a62016752a36e3c117ea6c4908eb4984 Mon Sep 17 00:00:00 2001 From: Michel Jung Date: Thu, 19 May 2016 22:49:10 +0200 Subject: [PATCH 15/34] Add "Custom Missions" to allowed coop map types Fixes #137 --- server/lobbyconnection.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/lobbyconnection.py b/server/lobbyconnection.py index 52f17390b..4f2ac67bb 100644 --- a/server/lobbyconnection.py +++ b/server/lobbyconnection.py @@ -351,6 +351,8 @@ async def send_coop_maps(self): jsonToSend["type"] = "Cybran Vanilla Campaign" elif type == 3: jsonToSend["type"] = "UEF Vanilla Campaign" + elif type == 4: + jsonToSend["type"] = "Custom Missions" else: # Don't sent corrupt data to the client... self._logger.error("Unknown coop type!") From fc7a8cfa90afe93655dc9fc0040775b8909980c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCllenhaupt?= Date: Tue, 24 May 2016 18:30:54 +0200 Subject: [PATCH 16/34] add string conversion --- server/lobbyconnection.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/server/lobbyconnection.py b/server/lobbyconnection.py index abf5b4d16..070e7415c 100644 --- a/server/lobbyconnection.py +++ b/server/lobbyconnection.py @@ -544,15 +544,18 @@ def decodeUniqueId(self, serialized_uniqueid): if str(data['session']) != str(self.session) : self.sendJSON(dict(command="notice", style="error", text="Your session is corrupted. Try relogging")) return None - UUID = data['machine']['uuid'].encode() - mem_SerialNumber = data['machine']['memory']['serial0'].encode() - DeviceID = data['machine']['disks']['controller_id'].encode() - Manufacturer = data['machine']['bios']['manufacturer'].encode() - Name = data['machine']['processor']['name'].encode() - ProcessorId = data['machine']['processor']['id'].encode() - SMBIOSBIOSVersion = data['machine']['bios']['smbbversion'].encode() - SerialNumber = data['machine']['bios']['serial'].encode() - VolumeSerialNumber = data['machine']['disks']['vserial'].encode() + # We're bound to generate to _old_ hashes from the new JSON structure, + # so we still use hashlib.md5().update() to generate the MD5 hash from concatenated bytearrays. + # Therefore all needed JSON elements are converted to strings and encoded to bytearrays. + UUID = str(data['machine']['uuid']).encode() + mem_SerialNumber = str(data['machine']['memory']['serial0']).encode() + DeviceID = str(data['machine']['disks']['controller_id']).encode() + Manufacturer = str(data['machine']['bios']['manufacturer']).encode() + Name = str(data['machine']['processor']['name']).encode() + ProcessorId = str(data['machine']['processor']['id']).encode() + SMBIOSBIOSVersion = str(data['machine']['bios']['smbbversion']).encode() + SerialNumber = str(data['machine']['bios']['serial']).encode() + VolumeSerialNumber = str(data['machine']['disks']['vserial']).encode() else: # the old JSON format contains unescaped backspaces in the device id # of the IDE controller, which now needs to be corrected to get valid JSON From f658b1bb233b8e1344b503235447233a99153f09 Mon Sep 17 00:00:00 2001 From: Michel Jung Date: Wed, 25 May 2016 12:22:22 +0200 Subject: [PATCH 17/34] Version 0.2 --- server/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/__init__.py b/server/__init__.py index 98e793a35..480f59be9 100644 --- a/server/__init__.py +++ b/server/__init__.py @@ -26,8 +26,8 @@ from .ladder_service import LadderService from .control import init as run_control_server -__version__ = '0.1' -__author__ = 'Chris Kitching, Dragonfire, Gael Honorez, Jeroen De Dauw, Crotalus, Michael Søndergaard' +__version__ = '0.2' +__author__ = 'Chris Kitching, Dragonfire, Gael Honorez, Jeroen De Dauw, Crotalus, Michael Søndergaard, Michel Jung' __contact__ = 'admin@faforever.com' __license__ = 'GPLv3' __copyright__ = 'Copyright (c) 2011-2015 ' + __author__ From e2713757c0a7514b708fd2f2a536d7f24f5ead0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCllenhaupt?= Date: Wed, 4 May 2016 08:59:59 +0200 Subject: [PATCH 18/34] make the server compatible with the new JSON format --- server/lobbyconnection.py | 68 ++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 23 deletions(-) diff --git a/server/lobbyconnection.py b/server/lobbyconnection.py index 52f17390b..44253cdd6 100644 --- a/server/lobbyconnection.py +++ b/server/lobbyconnection.py @@ -528,34 +528,56 @@ def decodeUniqueId(self, serialized_uniqueid): encoded = message[24:-40] key = (base64.b64decode(message[-40:])) + # The JSON string is AES encrypted + # first decrypt the AES key with our rsa private key AESkey = rsa.decrypt(key, PRIVATE_KEY) - # What the hell is this? + # now decrypt the message cipher = AES.new(AESkey, AES.MODE_CBC, iv) DecodeAES = lambda c, e: c.decrypt(base64.b64decode(e)).decode('utf-8') decoded = DecodeAES(cipher, encoded)[:-trailing] - regexp = re.compile(r'[0-9a-zA-Z\\]("")') - decoded = regexp.sub('"', decoded) - decoded = decoded.replace("\\", "\\\\") - regexp = re.compile('[^\x09\x0A\x0D\x20-\x7F]') - decoded = regexp.sub('', decoded) - jstring = json.loads(decoded) - - if str(jstring["session"]) != str(self.session) : - self.sendJSON(dict(command="notice", style="error", text="Your session is corrupted. Try relogging")) - return None - - machine = jstring["machine"] - - UUID = str(machine.get('UUID', 0)).encode() - mem_SerialNumber = str(machine.get('mem_SerialNumber', 0)).encode() - DeviceID = str(machine.get('DeviceID', 0)).encode() - Manufacturer = str(machine.get('Manufacturer', 0)).encode() - Name = str(machine.get('Name', 0)).encode() - ProcessorId = str(machine.get('ProcessorId', 0)).encode() - SMBIOSBIOSVersion = str(machine.get('SMBIOSBIOSVersion', 0)).encode() - SerialNumber = str(machine.get('SerialNumber', 0)).encode() - VolumeSerialNumber = str(machine.get('VolumeSerialNumber', 0)).encode() + + # since the legacy uid.dll generated JSON is flawed, + # there's a new JSON format, starting with '2' as magic byte + if decoded.startswith('2'): + data = json.loads(decoded[1:]) + if str(data["session"]) != str(session) : + self.sendJSON(dict(command="notice", style="error", text="Your session is corrupted. Try relogging")) + return None + UUID = data['machine']['uuid'] + mem_SerialNumber = data['machine']['memory']['serial0'] + DeviceID = data['machine']['disks']['controller_id'] + Manufacturer = data['machine']['manufacturer'] + Name = data['machine']['processor']['name'] + ProcessorId = data['machine']['processor']['id'] + SMBIOSBIOSVersion = data['machine']['bios']['smbbversion'] + SerialNumber = data['machine']['bios']['serial'] + VolumeSerialNumber = data['machine']['disks']['vserial'] + else: + # the old JSON format contains unescaped backspaces in the device id + # of the IDE controller, which now needs to be corrected to get valid JSON + regexp = re.compile(r'[0-9a-zA-Z\\]("")') + decoded = regexp.sub('"', decoded) + decoded = decoded.replace("\\", "\\\\") + regexp = re.compile('[^\x09\x0A\x0D\x20-\x7F]') + decoded = regexp.sub('', decoded) + jstring = json.loads(decoded) + + if str(jstring["session"]) != str(self.session) : + self.sendJSON(dict(command="notice", style="error", text="Your session is corrupted. Try relogging")) + return None + + machine = jstring["machine"] + + UUID = str(machine.get('UUID', 0)).encode() + mem_SerialNumber = str(machine.get('mem_SerialNumber', 0)).encode() # serial number of first memory module + DeviceID = str(machine.get('DeviceID', 0)).encode() # device id of the IDE controller + Manufacturer = str(machine.get('Manufacturer', 0)).encode() # BIOS manufacturer + Name = str(machine.get('Name', 0)).encode() # verbose processor name + ProcessorId = str(machine.get('ProcessorId', 0)).encode() + SMBIOSBIOSVersion = str(machine.get('SMBIOSBIOSVersion', 0)).encode() + SerialNumber = str(machine.get('SerialNumber', 0)).encode() # BIOS serial number + VolumeSerialNumber = str(machine.get('VolumeSerialNumber', 0)).encode() # https://www.raymond.cc/blog/changing-or-spoofing-hard-disk-hardware-serial-number-and-volume-id/ for i in machine.values() : low = i.lower() From e1bbbaf133795778a88a5c463832fcc82c02233a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCllenhaupt?= Date: Wed, 4 May 2016 09:05:16 +0200 Subject: [PATCH 19/34] use the correct Manufacturer for hashing --- server/lobbyconnection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/lobbyconnection.py b/server/lobbyconnection.py index 44253cdd6..b4d384a42 100644 --- a/server/lobbyconnection.py +++ b/server/lobbyconnection.py @@ -547,7 +547,7 @@ def decodeUniqueId(self, serialized_uniqueid): UUID = data['machine']['uuid'] mem_SerialNumber = data['machine']['memory']['serial0'] DeviceID = data['machine']['disks']['controller_id'] - Manufacturer = data['machine']['manufacturer'] + Manufacturer = data['machine']['bios']['manufacturer'] Name = data['machine']['processor']['name'] ProcessorId = data['machine']['processor']['id'] SMBIOSBIOSVersion = data['machine']['bios']['smbbversion'] From 88ae28112c6822d51b8838826cab9a2648e6c476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCllenhaupt?= Date: Sat, 7 May 2016 22:25:32 +0200 Subject: [PATCH 20/34] correctly indent VM check --- server/lobbyconnection.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/server/lobbyconnection.py b/server/lobbyconnection.py index b4d384a42..172085588 100644 --- a/server/lobbyconnection.py +++ b/server/lobbyconnection.py @@ -579,10 +579,10 @@ def decodeUniqueId(self, serialized_uniqueid): SerialNumber = str(machine.get('SerialNumber', 0)).encode() # BIOS serial number VolumeSerialNumber = str(machine.get('VolumeSerialNumber', 0)).encode() # https://www.raymond.cc/blog/changing-or-spoofing-hard-disk-hardware-serial-number-and-volume-id/ - for i in machine.values() : - low = i.lower() - if "vmware" in low or "virtual" in low or "innotek" in low or "qemu" in low or "parallels" in low or "bochs" in low : - return "VM" + for i in machine.values() : + low = i.lower() + if "vmware" in low or "virtual" in low or "innotek" in low or "qemu" in low or "parallels" in low or "bochs" in low : + return "VM" m = hashlib.md5() m.update(UUID + mem_SerialNumber + DeviceID + Manufacturer + Name + ProcessorId + SMBIOSBIOSVersion + SerialNumber + VolumeSerialNumber) From 0d1842230bdbbfe0287ba3d569134c6e5e02cc9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCllenhaupt?= Date: Fri, 13 May 2016 12:03:55 +0200 Subject: [PATCH 21/34] fix session variable --- server/lobbyconnection.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/lobbyconnection.py b/server/lobbyconnection.py index 172085588..3b82d3da9 100644 --- a/server/lobbyconnection.py +++ b/server/lobbyconnection.py @@ -541,7 +541,7 @@ def decodeUniqueId(self, serialized_uniqueid): # there's a new JSON format, starting with '2' as magic byte if decoded.startswith('2'): data = json.loads(decoded[1:]) - if str(data["session"]) != str(session) : + if str(data['session']) != str(self.session) : self.sendJSON(dict(command="notice", style="error", text="Your session is corrupted. Try relogging")) return None UUID = data['machine']['uuid'] From 3736f464083bf706d53260f4df58a7277028d441 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCllenhaupt?= Date: Fri, 13 May 2016 12:14:35 +0200 Subject: [PATCH 22/34] encode unicode before hashing --- server/lobbyconnection.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/server/lobbyconnection.py b/server/lobbyconnection.py index 3b82d3da9..abf5b4d16 100644 --- a/server/lobbyconnection.py +++ b/server/lobbyconnection.py @@ -544,15 +544,15 @@ def decodeUniqueId(self, serialized_uniqueid): if str(data['session']) != str(self.session) : self.sendJSON(dict(command="notice", style="error", text="Your session is corrupted. Try relogging")) return None - UUID = data['machine']['uuid'] - mem_SerialNumber = data['machine']['memory']['serial0'] - DeviceID = data['machine']['disks']['controller_id'] - Manufacturer = data['machine']['bios']['manufacturer'] - Name = data['machine']['processor']['name'] - ProcessorId = data['machine']['processor']['id'] - SMBIOSBIOSVersion = data['machine']['bios']['smbbversion'] - SerialNumber = data['machine']['bios']['serial'] - VolumeSerialNumber = data['machine']['disks']['vserial'] + UUID = data['machine']['uuid'].encode() + mem_SerialNumber = data['machine']['memory']['serial0'].encode() + DeviceID = data['machine']['disks']['controller_id'].encode() + Manufacturer = data['machine']['bios']['manufacturer'].encode() + Name = data['machine']['processor']['name'].encode() + ProcessorId = data['machine']['processor']['id'].encode() + SMBIOSBIOSVersion = data['machine']['bios']['smbbversion'].encode() + SerialNumber = data['machine']['bios']['serial'].encode() + VolumeSerialNumber = data['machine']['disks']['vserial'].encode() else: # the old JSON format contains unescaped backspaces in the device id # of the IDE controller, which now needs to be corrected to get valid JSON From 1d6143d61b6ee80dfdee981c3c69aac4ad5d21cc Mon Sep 17 00:00:00 2001 From: Sheeo Date: Sat, 14 May 2016 13:47:06 +0200 Subject: [PATCH 23/34] Don't recommend the use of / in docker name --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fa7e8db08..dd0c3c363 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ Install [docker](https://www.docker.com). Follow the steps to get [faf-db](https://github.com/FAForever/db) setup, the following assumes the db container is called `faf-db`. - docker build -t faf/server . - docker run --link faf-db:db -p 8001:8001 -p 30351:30351 faf/server + docker build -t faf-server . + docker run --link faf-db:db -p 8001:8001 -p 30351:30351 faf-server ## Running the tests From e73677a152c5e6dca3a652d1db6b10f4f79907cd Mon Sep 17 00:00:00 2001 From: IDragonfire Date: Sat, 14 May 2016 15:22:10 +0200 Subject: [PATCH 24/34] Example for docker run -e --- README.md | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index dd0c3c363..9e14c9936 100644 --- a/README.md +++ b/README.md @@ -12,16 +12,25 @@ master|develop Install [docker](https://www.docker.com). -Follow the steps to get [faf-db](https://github.com/FAForever/db) setup, the following assumes the db container is called `faf-db`. +Follow the steps to get [faf-db](https://github.com/FAForever/db) setup, the following assumes the db container is called `faf-db` and the database is called `faf_test` and the root password ist `banana`. docker build -t faf-server . docker run --link faf-db:db -p 8001:8001 -p 30351:30351 faf-server +Check if the container is running with + + docker ps + +If you have a differnet root password, database name then the default (see [config.py](https://github.com/FAForever/server/blob/develop/server/config.py#L43)), you must pass it over the environment parameter of docker, e.g. + + docker run --link faf-db:db -p 8001:8001 -p 30351:30351 -e FAF_DB_PASSWORD= -e FAF_DB_NAME= faf-server + + ## Running the tests Run `py.test` - docker run --link faf-db:db faf/server bash -c py.test + docker run --link faf-db:db faf-server bash -c py.test # Contributing From 71b937b945126992645647eeba5841511d9601c6 Mon Sep 17 00:00:00 2001 From: IDragonfire Date: Sat, 14 May 2016 15:34:57 +0200 Subject: [PATCH 25/34] Add some notes about debugging --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9e14c9936..5478b78c3 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,12 @@ Check if the container is running with docker ps -If you have a differnet root password, database name then the default (see [config.py](https://github.com/FAForever/server/blob/develop/server/config.py#L43)), you must pass it over the environment parameter of docker, e.g. +If you cannot find `faf-server`in the list, run `docker run` without `-d` to see what happen. + +If you have a different root password, database name then the default (see [config.py](https://github.com/FAForever/server/blob/develop/server/config.py#L43)), you must pass it over the environment parameter of docker, e.g. docker run --link faf-db:db -p 8001:8001 -p 30351:30351 -e FAF_DB_PASSWORD= -e FAF_DB_NAME= faf-server - ## Running the tests Run `py.test` From 41b72448adc0a5a8c1143fd17dec3bb3e81f81fa Mon Sep 17 00:00:00 2001 From: Dragonfire Date: Sat, 14 May 2016 14:00:26 +0200 Subject: [PATCH 26/34] Use explicit path as entrypoint --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 7e2ef4120..068c8179e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -14,7 +14,7 @@ WORKDIR /code/ RUN python3.5 -m pip install -e . # Main entrypoint and the default command that will be run -CMD ["./server.py"] +CMD ["/usr/local/bin/python3.5", "server.py"] # Game server runs on 8000/tcp, lobby server runs on 8001/tcp, nat echo server runs on 30351/udp EXPOSE 8000 8001 30351 From b31800255fec06745f8591cedbd2f137be229924 Mon Sep 17 00:00:00 2001 From: Sheeo Date: Sun, 15 May 2016 14:33:56 +0200 Subject: [PATCH 27/34] Describe that server expects faf-server.pem Closes #131 --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 5478b78c3..bd013b3d2 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,13 @@ Install [docker](https://www.docker.com). Follow the steps to get [faf-db](https://github.com/FAForever/db) setup, the following assumes the db container is called `faf-db` and the database is called `faf_test` and the root password ist `banana`. + +The server needs an RSA key to decode uniqueid messages, we've provided an example key in the repo as `faf-server.example.pem`. The server expects this to be named `faf-server.pem` at runtime, so first copy this + + cp faf-server.example.pem faf-server.pem + +Then use Docker to build and run the server as follows + docker build -t faf-server . docker run --link faf-db:db -p 8001:8001 -p 30351:30351 faf-server From c4f2530438c0697f537b37ac0b904695e0f57be9 Mon Sep 17 00:00:00 2001 From: Christian Schmidt Date: Mon, 16 May 2016 22:03:37 +0200 Subject: [PATCH 28/34] Login data: test user passwords now get correctly hashed --- tests/data/db-fixtures.sql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/data/db-fixtures.sql b/tests/data/db-fixtures.sql index 69b40542f..7b54fbf28 100644 --- a/tests/data/db-fixtures.sql +++ b/tests/data/db-fixtures.sql @@ -2,9 +2,9 @@ use faf_test; -- Login table delete from login; -insert into login (id, login, email, password) values (1, 'test', 'test@example.com', 'test_password'); -insert into login (id, login, email, password) values (2, 'Dostya', 'dostya@cybran.example.com', 'vodka'); -insert into login (id, login, email, password) values (3, 'Rhiza', 'rhiza@aeon.example.com', 'puff_the_magic_dragon'); +insert into login (id, login, email, password) values (1, 'test', 'test@example.com', SHA2('test_password', 256)); +insert into login (id, login, email, password) values (2, 'Dostya', 'dostya@cybran.example.com', SHA2('vodka', 256)); +insert into login (id, login, email, password) values (3, 'Rhiza', 'rhiza@aeon.example.com', SHA2('puff_the_magic_dragon', 256)); -- global rating delete from global_rating; From 230e11b9cc991be14ff4c4f4c4f1d9c6d3c6f7f7 Mon Sep 17 00:00:00 2001 From: Sheeo Date: Tue, 17 May 2016 01:18:13 +0200 Subject: [PATCH 29/34] Allocate a tty and forward signals during test run Closes #135 --- .travis.yml | 2 +- scripts/run_and_report_coverage.sh | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b83757ffa..2218a21e0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,4 +18,4 @@ install: - docker build -t faf-server . script: - - docker run --link faf-db:db -e FAF_DB_PASSWORD=banana -e COVERALLS_REPO_TOKEN=Vl36DD3XeJI1KjzoyGgxpV3wsVohnJW22 faf-server bash scripts/run_and_report_coverage.sh + - docker run -it --link faf-db:db -e FAF_DB_PASSWORD=banana -e COVERALLS_REPO_TOKEN=Vl36DD3XeJI1KjzoyGgxpV3wsVohnJW22 faf-server bash scripts/run_and_report_coverage.sh diff --git a/scripts/run_and_report_coverage.sh b/scripts/run_and_report_coverage.sh index f2368ddff..b00fa4a95 100755 --- a/scripts/run_and_report_coverage.sh +++ b/scripts/run_and_report_coverage.sh @@ -1,3 +1,4 @@ #!/usr/bin/env bash +set -e py.test --cov-report term-missing --cov=server coveralls From 50ffcde68fba97a8ac68c30f10d5c67c491c3cd0 Mon Sep 17 00:00:00 2001 From: Christian Schmidt Date: Tue, 17 May 2016 10:26:57 +0200 Subject: [PATCH 30/34] Changed perform_login to use sha256-hash of given credentials-pw --- tests/integration_tests/test_server.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/integration_tests/test_server.py b/tests/integration_tests/test_server.py index 76acbe95b..75eab9183 100644 --- a/tests/integration_tests/test_server.py +++ b/tests/integration_tests/test_server.py @@ -1,4 +1,5 @@ import pytest +import hashlib from server import VisibilityState @@ -44,11 +45,12 @@ def get_session(proto): @asyncio.coroutine def perform_login(proto, credentials): login, pw = credentials + pw_hash = hashlib.sha256(pw.encode('utf-8')) proto.send_message({'command': 'hello', 'version': '1.0.0-dev', 'user_agent': 'faf-client', 'login': login, - 'password': pw, + 'password': pw_hash.hexdigest(), 'unique_id': 'some_id' }) yield from proto.drain() From f129cd2d889016dc18159ad651be4de9c4cd223f Mon Sep 17 00:00:00 2001 From: Michel Jung Date: Wed, 18 May 2016 19:01:56 +0200 Subject: [PATCH 31/34] Fix OAuth access to faf-api which has been broken with c12c76c --- requirements.txt | 1 + server/api/api_accessor.py | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/requirements.txt b/requirements.txt index ad9f44ea8..d7519b70f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -19,3 +19,4 @@ aiocron marisa-trie oauth2client git+https://github.com/FAForever/faftools.git@develop#egg=faftools +pyopenssl \ No newline at end of file diff --git a/server/api/api_accessor.py b/server/api/api_accessor.py index 7d445efad..284236355 100644 --- a/server/api/api_accessor.py +++ b/server/api/api_accessor.py @@ -8,8 +8,12 @@ class ApiAccessor: def __init__(self): - with open("faf-server.pem", "rb") as f: - self.private_key = f.read() + self._service_account_credentials = ServiceAccountCredentials.from_p12_keyfile( + 'faf-server', + 'faf-server.pem', + scopes='write_achievements write_events' + ) + self._service_account_credentials.token_uri = API_TOKEN_URI async def api_get(self, path, player_id): loop = asyncio.get_event_loop() @@ -26,9 +30,5 @@ async def api_post(self, path, player_id, data=None, headers=None): return result def http(self, sub=None): - credentials = ServiceAccountCredentials.from_p12_keyfile( - 'faf-server', - 'faf-server.pem', - scopes='write_achievements write_events' - ) + credentials = self._service_account_credentials.create_delegated(sub) return credentials.authorize(Http()) From e3875bedef16b68c5dfa4aa9b3673178b75636d3 Mon Sep 17 00:00:00 2001 From: Michel Jung Date: Thu, 19 May 2016 22:49:10 +0200 Subject: [PATCH 32/34] Add "Custom Missions" to allowed coop map types Fixes #137 --- server/lobbyconnection.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/lobbyconnection.py b/server/lobbyconnection.py index abf5b4d16..461e1cb53 100644 --- a/server/lobbyconnection.py +++ b/server/lobbyconnection.py @@ -351,6 +351,8 @@ async def send_coop_maps(self): jsonToSend["type"] = "Cybran Vanilla Campaign" elif type == 3: jsonToSend["type"] = "UEF Vanilla Campaign" + elif type == 4: + jsonToSend["type"] = "Custom Missions" else: # Don't sent corrupt data to the client... self._logger.error("Unknown coop type!") From 86080523fbac1d7892ac556b8e509262946b9298 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20M=C3=BCllenhaupt?= Date: Tue, 24 May 2016 18:30:54 +0200 Subject: [PATCH 33/34] add string conversion --- server/lobbyconnection.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/server/lobbyconnection.py b/server/lobbyconnection.py index 461e1cb53..a36efb576 100644 --- a/server/lobbyconnection.py +++ b/server/lobbyconnection.py @@ -546,15 +546,18 @@ def decodeUniqueId(self, serialized_uniqueid): if str(data['session']) != str(self.session) : self.sendJSON(dict(command="notice", style="error", text="Your session is corrupted. Try relogging")) return None - UUID = data['machine']['uuid'].encode() - mem_SerialNumber = data['machine']['memory']['serial0'].encode() - DeviceID = data['machine']['disks']['controller_id'].encode() - Manufacturer = data['machine']['bios']['manufacturer'].encode() - Name = data['machine']['processor']['name'].encode() - ProcessorId = data['machine']['processor']['id'].encode() - SMBIOSBIOSVersion = data['machine']['bios']['smbbversion'].encode() - SerialNumber = data['machine']['bios']['serial'].encode() - VolumeSerialNumber = data['machine']['disks']['vserial'].encode() + # We're bound to generate to _old_ hashes from the new JSON structure, + # so we still use hashlib.md5().update() to generate the MD5 hash from concatenated bytearrays. + # Therefore all needed JSON elements are converted to strings and encoded to bytearrays. + UUID = str(data['machine']['uuid']).encode() + mem_SerialNumber = str(data['machine']['memory']['serial0']).encode() + DeviceID = str(data['machine']['disks']['controller_id']).encode() + Manufacturer = str(data['machine']['bios']['manufacturer']).encode() + Name = str(data['machine']['processor']['name']).encode() + ProcessorId = str(data['machine']['processor']['id']).encode() + SMBIOSBIOSVersion = str(data['machine']['bios']['smbbversion']).encode() + SerialNumber = str(data['machine']['bios']['serial']).encode() + VolumeSerialNumber = str(data['machine']['disks']['vserial']).encode() else: # the old JSON format contains unescaped backspaces in the device id # of the IDE controller, which now needs to be corrected to get valid JSON From 50dc06e1f785e8c0ba4a29d9fac0d8c7c0c561f8 Mon Sep 17 00:00:00 2001 From: Michel Jung Date: Wed, 25 May 2016 12:22:22 +0200 Subject: [PATCH 34/34] Version 0.2 --- server/__init__.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/__init__.py b/server/__init__.py index 98e793a35..480f59be9 100644 --- a/server/__init__.py +++ b/server/__init__.py @@ -26,8 +26,8 @@ from .ladder_service import LadderService from .control import init as run_control_server -__version__ = '0.1' -__author__ = 'Chris Kitching, Dragonfire, Gael Honorez, Jeroen De Dauw, Crotalus, Michael Søndergaard' +__version__ = '0.2' +__author__ = 'Chris Kitching, Dragonfire, Gael Honorez, Jeroen De Dauw, Crotalus, Michael Søndergaard, Michel Jung' __contact__ = 'admin@faforever.com' __license__ = 'GPLv3' __copyright__ = 'Copyright (c) 2011-2015 ' + __author__