From 5b63cbe6af1fe6a9e7fc74cff9fbc404e7dfa246 Mon Sep 17 00:00:00 2001 From: marysieek Date: Wed, 18 Nov 2020 11:55:00 +0100 Subject: [PATCH 1/5] Add approve and report commands --- castle/api/approve_device.py | 8 ++++++++ castle/api/report_device.py | 8 ++++++++ castle/commands/approve_device.py | 15 +++++++++++++++ castle/commands/report_device.py | 15 +++++++++++++++ 4 files changed, 46 insertions(+) create mode 100644 castle/api/approve_device.py create mode 100644 castle/api/report_device.py create mode 100644 castle/commands/approve_device.py create mode 100644 castle/commands/report_device.py diff --git a/castle/api/approve_device.py b/castle/api/approve_device.py new file mode 100644 index 0000000..81c18b1 --- /dev/null +++ b/castle/api/approve_device.py @@ -0,0 +1,8 @@ +from castle.api_request import APIRequest +from castle.commands.get_device import CommandsApproveDevice + + +class APIApproveDevice(object): + @staticmethod + def retrieve(device_token): + return APIRequest().call(CommandsApproveDevice.build(device_token)) diff --git a/castle/api/report_device.py b/castle/api/report_device.py new file mode 100644 index 0000000..3cb91cd --- /dev/null +++ b/castle/api/report_device.py @@ -0,0 +1,8 @@ +from castle.api_request import APIRequest +from castle.commands.get_device import CommandsReportDevice + + +class APIReportDevice(object): + @staticmethod + def retrieve(device_token): + return APIRequest().call(CommandsReportDevice.build(device_token)) diff --git a/castle/commands/approve_device.py b/castle/commands/approve_device.py new file mode 100644 index 0000000..ea77533 --- /dev/null +++ b/castle/commands/approve_device.py @@ -0,0 +1,15 @@ +from castle.command import Command +from castle.validators.present import ValidatorsPresent + + +class CommandsApproveDevice(object): + + @staticmethod + def build(device_token): + ValidatorsPresent.call({'device_token': device_token}, 'device_token') + + return Command( + method='put', + path="devices/{device_token}/approve".format(device_token=device_token), + data=None + ) diff --git a/castle/commands/report_device.py b/castle/commands/report_device.py new file mode 100644 index 0000000..208a25a --- /dev/null +++ b/castle/commands/report_device.py @@ -0,0 +1,15 @@ +from castle.command import Command +from castle.validators.present import ValidatorsPresent + + +class CommandsReportDevice(object): + + @staticmethod + def build(device_token): + ValidatorsPresent.call({'device_token': device_token}, 'device_token') + + return Command( + method='put', + path="devices/{device_token}/report".format(device_token=device_token), + data=None + ) From 301f1db64fd49bab46876ff07a8b5c3d8413ef7b Mon Sep 17 00:00:00 2001 From: marysieek Date: Wed, 18 Nov 2020 12:21:58 +0100 Subject: [PATCH 2/5] Add tests to init file --- castle/test/__init__.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/castle/test/__init__.py b/castle/test/__init__.py index d11aa83..9aa67a4 100644 --- a/castle/test/__init__.py +++ b/castle/test/__init__.py @@ -5,18 +5,22 @@ TEST_MODULES = [ + 'castle.test.api.approve_device_test', 'castle.test.api.get_device_test', 'castle.test.api.get_devices_test', + 'castle.test.api.report_device_test', 'castle.test.api.review_test', 'castle.test.api_request_test', 'castle.test.client_id.extract_test', 'castle.test.client_test', 'castle.test.command_test', + 'castle.test.commands.approve_device_test', 'castle.test.commands.authenticate_test', - 'castle.test.commands.identify_test', - 'castle.test.commands.impersonate_test', 'castle.test.commands.get_device_test', 'castle.test.commands.get_devices_test', + 'castle.test.commands.identify_test', + 'castle.test.commands.impersonate_test', + 'castle.test.commands.report_device_test', 'castle.test.commands.review_test', 'castle.test.commands.track_test', 'castle.test.configuration_test', From 7b82ca4a832560896f9260fe901a9f8a3ed322e4 Mon Sep 17 00:00:00 2001 From: marysieek Date: Wed, 18 Nov 2020 13:32:25 +0100 Subject: [PATCH 3/5] Add approve and report api test --- castle/test/api/approve_device_test.py | 27 ++++++++++++++++++++++++++ castle/test/api/report_device_test.py | 27 ++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 castle/test/api/approve_device_test.py create mode 100644 castle/test/api/report_device_test.py diff --git a/castle/test/api/approve_device_test.py b/castle/test/api/approve_device_test.py new file mode 100644 index 0000000..36073e7 --- /dev/null +++ b/castle/test/api/approve_device_test.py @@ -0,0 +1,27 @@ +import json +import responses + +from castle.test import unittest +from castle.api.approve_device import APIApproveDevice +from castle.configuration import configuration + + +class APIApproveDeviceTestCase(unittest.TestCase): + def setUp(self): + configuration.api_secret = 'test' + + def tearDown(self): + configuration.api_secret = None + + @responses.activate + def test_retrieve(self): + # pylint: disable=line-too-long + response_text = "{\"token\":\"1234\",\"risk\":\"0.0\",\"approved_at\":\"2020-11-18T03:04:05.678\"}" + responses.add( + responses.PUT, + 'https://api.castle.io/v1/devices/1234/approve', + body=response_text, + status=200 + ) + device_token = '1234' + self.assertEqual(APIApproveDevice.retrieve(device_token), json.loads(response_text)) diff --git a/castle/test/api/report_device_test.py b/castle/test/api/report_device_test.py new file mode 100644 index 0000000..fe58d8e --- /dev/null +++ b/castle/test/api/report_device_test.py @@ -0,0 +1,27 @@ +import json +import responses + +from castle.test import unittest +from castle.api.report_device import APIReportDevice +from castle.configuration import configuration + + +class APIReportDeviceTestCase(unittest.TestCase): + def setUp(self): + configuration.api_secret = 'test' + + def tearDown(self): + configuration.api_secret = None + + @responses.activate + def test_retrieve(self): + # pylint: disable=line-too-long + response_text = "{\"token\":\"1234\",\"risk\":\"0.0\",\"escalated_at\":\"2020-11-18T03:04:05.678\"}" + responses.add( + responses.PUT, + 'https://api.castle.io/v1/devices/1234/report', + body=response_text, + status=200 + ) + device_token = '1234' + self.assertEqual(APIReportDevice.retrieve(device_token), json.loads(response_text)) From 8323502f5fdbf4861ddb6608c6e9fd28763d8a61 Mon Sep 17 00:00:00 2001 From: marysieek Date: Wed, 18 Nov 2020 13:35:02 +0100 Subject: [PATCH 4/5] Update the tests --- castle/api/approve_device.py | 2 +- castle/api/report_device.py | 2 +- castle/test/commands/approve_device_test.py | 21 +++++++++++++++++++++ castle/test/commands/report_device_test.py | 21 +++++++++++++++++++++ 4 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 castle/test/commands/approve_device_test.py create mode 100644 castle/test/commands/report_device_test.py diff --git a/castle/api/approve_device.py b/castle/api/approve_device.py index 81c18b1..7593a34 100644 --- a/castle/api/approve_device.py +++ b/castle/api/approve_device.py @@ -1,5 +1,5 @@ from castle.api_request import APIRequest -from castle.commands.get_device import CommandsApproveDevice +from castle.commands.approve_device import CommandsApproveDevice class APIApproveDevice(object): diff --git a/castle/api/report_device.py b/castle/api/report_device.py index 3cb91cd..26d9bd6 100644 --- a/castle/api/report_device.py +++ b/castle/api/report_device.py @@ -1,5 +1,5 @@ from castle.api_request import APIRequest -from castle.commands.get_device import CommandsReportDevice +from castle.commands.report_device import CommandsReportDevice class APIReportDevice(object): diff --git a/castle/test/commands/approve_device_test.py b/castle/test/commands/approve_device_test.py new file mode 100644 index 0000000..2fddef3 --- /dev/null +++ b/castle/test/commands/approve_device_test.py @@ -0,0 +1,21 @@ +from castle.test import unittest +from castle.command import Command +from castle.commands.approve_device import CommandsApproveDevice +from castle.errors import InvalidParametersError + + +def device_token(): + return '1234' + + +class CommandsApproveDeviceTestCase(unittest.TestCase): + def test_build_no_device_token(self): + with self.assertRaises(InvalidParametersError): + CommandsApproveDevice.build('') + + def test_build(self): + command = CommandsApproveDevice.build(device_token()) + self.assertIsInstance(command, Command) + self.assertEqual(command.method, 'put') + self.assertEqual(command.path, 'devices/1234/approve') + self.assertEqual(command.data, None) diff --git a/castle/test/commands/report_device_test.py b/castle/test/commands/report_device_test.py new file mode 100644 index 0000000..a11f298 --- /dev/null +++ b/castle/test/commands/report_device_test.py @@ -0,0 +1,21 @@ +from castle.test import unittest +from castle.command import Command +from castle.commands.report_device import CommandsReportDevice +from castle.errors import InvalidParametersError + + +def device_token(): + return '1234' + + +class CommandsReportDeviceTestCase(unittest.TestCase): + def test_build_no_device_token(self): + with self.assertRaises(InvalidParametersError): + CommandsReportDevice.build('') + + def test_build(self): + command = CommandsReportDevice.build(device_token()) + self.assertIsInstance(command, Command) + self.assertEqual(command.method, 'put') + self.assertEqual(command.path, 'devices/1234/report') + self.assertEqual(command.data, None) From 106ddd80469a592546be09a82b18449d824405cb Mon Sep 17 00:00:00 2001 From: marysieek Date: Wed, 18 Nov 2020 13:50:28 +0100 Subject: [PATCH 5/5] Add realistic responses --- castle/test/api/approve_device_test.py | 2 +- castle/test/api/get_device_test.py | 2 +- castle/test/api/get_devices_test.py | 2 +- castle/test/api/report_device_test.py | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/castle/test/api/approve_device_test.py b/castle/test/api/approve_device_test.py index 36073e7..837974b 100644 --- a/castle/test/api/approve_device_test.py +++ b/castle/test/api/approve_device_test.py @@ -16,7 +16,7 @@ def tearDown(self): @responses.activate def test_retrieve(self): # pylint: disable=line-too-long - response_text = "{\"token\":\"1234\",\"risk\":\"0.0\",\"approved_at\":\"2020-11-18T03:04:05.678\"}" + response_text = "{\"token\":\"token\",\"created_at\":\"2020-08-13T11:26:47.401Z\",\"last_seen_at\":\"2020-10-18T18:37:22.855Z\",\"user_id\":\"4\",\"approved_at\":\"2020-11-18T12:48:41.112Z\",\"escalated_at\":null,\"mitigated_at\":null,\"context\":{\"ip\":\"127.0.0.1\",\"location\":{\"country_code\":\"PL\",\"country\":\"Poland\"},\"user_agent\":{\"raw\":\"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/86.0.4240.75 Safari\/537.36\",\"browser\":\"Chrome\",\"version\":\"86.0.4240\",\"os\":\"Mac OS X 10.15.6\",\"mobile\":false,\"platform\":\"Mac OS X\",\"device\":\"Mac\",\"family\":\"Chrome\"},\"properties\":{},\"type\":\"desktop\"},\"is_current_device\":false}" responses.add( responses.PUT, 'https://api.castle.io/v1/devices/1234/approve', diff --git a/castle/test/api/get_device_test.py b/castle/test/api/get_device_test.py index f5b94e4..d56b970 100644 --- a/castle/test/api/get_device_test.py +++ b/castle/test/api/get_device_test.py @@ -16,7 +16,7 @@ def tearDown(self): @responses.activate def test_retrieve(self): # pylint: disable=line-too-long - response_text = "{\"id\":\"d_id\",\"manufacturer\":\"d_manufacturer\",\"model\":\"d_model\",\"name\":\"d_name\",\"type\":\"d_type\"}" + response_text = "{\"token\":\"token\",\"created_at\":\"2020-08-13T11:26:47.401Z\",\"last_seen_at\":\"2020-10-18T18:37:22.855Z\",\"user_id\":\"4\",\"approved_at\":null,\"escalated_at\":null,\"mitigated_at\":null,\"context\":{\"ip\":\"127.0.0.1\",\"location\":{\"country_code\":\"PL\",\"country\":\"Poland\"},\"user_agent\":{\"raw\":\"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/86.0.4240.75 Safari\/537.36\",\"browser\":\"Chrome\",\"version\":\"86.0.4240\",\"os\":\"Mac OS X 10.15.6\",\"mobile\":false,\"platform\":\"Mac OS X\",\"device\":\"Mac\",\"family\":\"Chrome\"},\"properties\":{},\"type\":\"desktop\"},\"is_current_device\":false}" responses.add( responses.GET, 'https://api.castle.io/v1/devices/1234', diff --git a/castle/test/api/get_devices_test.py b/castle/test/api/get_devices_test.py index 8854787..174c096 100644 --- a/castle/test/api/get_devices_test.py +++ b/castle/test/api/get_devices_test.py @@ -16,7 +16,7 @@ def tearDown(self): @responses.activate def test_retrieve(self): # pylint: disable=line-too-long - response_text = "{\"total_count\":1,\"data\":[{\"token\":\"abcdefg12345\",\"risk\":0.0,\"created_at\":\"2018-06-15T16:36:22.916Z\",\"last_seen_at\":\"2018-07-19T23:09:29.681Z\",\"context\":{\"ip\":\"1.1.1.1\",\"user_agent\":{\"raw\":\"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36 OPR/54.0.2952.51\",\"browser\":\"Opera\",\"version\":\"54.0.2952\",\"os\":\"Mac OS X 10.13.6\",\"mobile\":false,\"platform\":\"Mac OS X\",\"device\":\"Unknown\",\"family\":\"Opera\"},\"type\":\"desktop\"},\"is_current_device\":true}]}" + response_text = "{\"total_count\":2,\"data\":[{\"token\":\"token\",\"created_at\":\"2020-08-01T18:55:45.352Z\",\"last_seen_at\":\"2020-10-18T21:11:57.476Z\",\"user_id\":\"4\",\"approved_at\":\"2020-08-13T09:55:19.286Z\",\"escalated_at\":null,\"mitigated_at\":null,\"context\":{\"ip\":\"127.0.0.1\",\"location\":{\"country_code\":\"PL\",\"country\":\"Poland\"},\"user_agent\":{\"raw\":\"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/86.0.4240.75 Safari\/537.36\",\"browser\":\"Chrome\",\"version\":\"86.0.4240\",\"os\":\"Mac OS X 10.15.6\",\"mobile\":false,\"platform\":\"Mac OS X\",\"device\":\"Mac\",\"family\":\"Chrome\"},\"properties\":{},\"type\":\"desktop\"},\"is_current_device\":false},{\"token\":\"token2\",\"created_at\":\"2020-08-13T11:26:47.401Z\",\"last_seen_at\":\"2020-10-18T18:37:22.855Z\",\"user_id\":\"4\",\"approved_at\":null,\"escalated_at\":null,\"mitigated_at\":null,\"context\":{\"ip\":\"127.0.0.1\",\"location\":{\"country_code\":\"PL\",\"country\":\"Poland\"},\"user_agent\":{\"raw\":\"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/86.0.4240.75 Safari\/537.36\",\"browser\":\"Chrome\",\"version\":\"86.0.4240\",\"os\":\"Mac OS X 10.15.6\",\"mobile\":false,\"platform\":\"Mac OS X\",\"device\":\"Mac\",\"family\":\"Chrome\"},\"properties\":{},\"type\":\"desktop\"},\"is_current_device\":false}]}" responses.add( responses.GET, 'https://api.castle.io/v1/users/1234/devices', diff --git a/castle/test/api/report_device_test.py b/castle/test/api/report_device_test.py index fe58d8e..610d2a3 100644 --- a/castle/test/api/report_device_test.py +++ b/castle/test/api/report_device_test.py @@ -16,7 +16,7 @@ def tearDown(self): @responses.activate def test_retrieve(self): # pylint: disable=line-too-long - response_text = "{\"token\":\"1234\",\"risk\":\"0.0\",\"escalated_at\":\"2020-11-18T03:04:05.678\"}" + response_text = "{\"token\":\"token\",\"created_at\":\"2020-08-13T11:26:47.401Z\",\"last_seen_at\":\"2020-10-18T18:37:22.855Z\",\"user_id\":\"4\",\"approved_at\":\"2020-11-18T12:48:41.112Z\",\"escalated_at\":null,\"mitigated_at\":null,\"context\":{\"ip\":\"127.0.0.1\",\"location\":{\"country_code\":\"PL\",\"country\":\"Poland\"},\"user_agent\":{\"raw\":\"Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/86.0.4240.75 Safari\/537.36\",\"browser\":\"Chrome\",\"version\":\"86.0.4240\",\"os\":\"Mac OS X 10.15.6\",\"mobile\":false,\"platform\":\"Mac OS X\",\"device\":\"Mac\",\"family\":\"Chrome\"},\"properties\":{},\"type\":\"desktop\"},\"is_current_device\":false}" responses.add( responses.PUT, 'https://api.castle.io/v1/devices/1234/report',