From 05cd81c671b092cf0062445012af754ad4d51de0 Mon Sep 17 00:00:00 2001 From: Emilien GUILMINEAU Date: Fri, 29 Mar 2024 11:46:56 +0100 Subject: [PATCH] :construction: Add a 'modern' REST API --- snappass/main.py | 41 ++++++++++++++ tests.py | 143 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 184 insertions(+) diff --git a/snappass/main.py b/snappass/main.py index 597c797..0740519 100644 --- a/snappass/main.py +++ b/snappass/main.py @@ -217,6 +217,47 @@ def api_handle_password(): return jsonify(link=link, ttl=ttl) else: abort(500) + +@app.route('/api/v2/passwords/', methods=['POST']) +def api_v2_set_password(): + password = request.json.get('password') + ttl = int(request.json.get('ttl', DEFAULT_API_TTL)) + if not password: + # Add ProblemDetails expliciting issue with Password and/or TTL + abort(400) + + if not isinstance(ttl, int) or ttl > MAX_TTL: + else: + # Return ProblemDetails expliciting issue + abort(400) + + token = set_password(password, ttl) + base_url = set_base_url(request) + link = base_url + quote_plus(token) + return jsonify(link=link, ttl=ttl) + +@app.route('/api/v2/passwords/', methods=['HEAD']) +def api_v2_check_password(): + password_key = unquote_plus(password_key) + if not password_exists(password_key): + # Return NotFound, to indicate that password does not exists (anymore or at all) + # With ProblemDetails expliciting issue (just password not found) + abort(404) + else: + # Return OK, to indicate that password still exists + abort(200) + +@app.route('/api/v2/passwords/', methods=['GET']) +def api_v2_retrieve_password(): + password_key = unquote_plus(password_key) + password = get_password(password_key) + if not password: + # Return NotFound, to indicate that password does not exists (anymore or at all) + # With ProblemDetails expliciting issue (just password not found) + abort(404) + else: + # Return OK and the password in JSON message + return jsonify(passwork=passwork) @app.route('/', methods=['GET']) diff --git a/tests.py b/tests.py index 4ef7f0d..e143bca 100644 --- a/tests.py +++ b/tests.py @@ -201,6 +201,149 @@ class SnapPassRoutesTestCase(TestCase): frozen_time.move_to("2020-05-22 12:00:00") self.assertIsNone(snappass.get_password(key)) + def test_set_password_api_v2(self): + with freeze_time("2020-05-08 12:00:00") as frozen_time: + password = 'my name is my passport. verify me.' + rv = self.app.post( + '/api/v2/passwords/', + headers={'Accept': 'application/json'}, + json={'password': password, 'ttl': '1209600'}, + ) + + json_content = rv.get_json() + key = re.search(r'https://localhost/([^"]+)', json_content['link']).group(1) + key = unquote(key) + + frozen_time.move_to("2020-05-22 11:59:59") + self.assertEqual(snappass.get_password(key), password) + + frozen_time.move_to("2020-05-22 12:00:00") + self.assertIsNone(snappass.get_password(key)) + + def test_set_password_api_v2_default_ttl(self): + with freeze_time("2020-05-08 12:00:00") as frozen_time: + password = 'my name is my passport. verify me.' + rv = self.app.post( + '/api/set_password/', + headers={'Accept': 'application/json'}, + json={'password': password}, + ) + + json_content = rv.get_json() + key = re.search(r'https://localhost/([^"]+)', json_content['link']).group(1) + key = unquote(key) + + frozen_time.move_to("2020-05-22 11:59:59") + self.assertEqual(snappass.get_password(key), password) + + frozen_time.move_to("2020-05-22 12:00:00") + self.assertIsNone(snappass.get_password(key)) + + def test_set_password_api_v2_no_password(self): + with freeze_time("2020-05-08 12:00:00") as frozen_time: + rv = self.app.post( + '/api/set_password/', + headers={'Accept': 'application/json'}, + json={'password': None}, + ) + + self.assertEqual(rv.status, 400) + + json_content = rv.get_json() + key = re.search(r'https://localhost/([^"]+)', json_content['link']).group(1) + key = unquote(key) + + # TODO : Search for ProblemDetails propreties about Password + + def test_set_password_api_v2_too_big_ttl(self): + with freeze_time("2020-05-08 12:00:00") as frozen_time: + password = 'my name is my passport. verify me.' + rv = self.app.post( + '/api/v2/passwords/', + headers={'Accept': 'application/json'}, + json={'password': password, 'ttl': '1209600000'}, + ) + + self.assertEqual(rv.status, 400) + + json_content = rv.get_json() + key = re.search(r'https://localhost/([^"]+)', json_content['link']).group(1) + key = unquote(key) + + # TODO : Search for ProblemDetails propreties about TTL + + def test_check_password_api_v2(self): + with freeze_time("2020-05-08 12:00:00") as frozen_time: + password = 'my name is my passport. verify me.' + rv = self.app.post( + '/api/v2/password/', + headers={'Accept': 'application/json'}, + json={'password': password}, + ) + + json_content = rv.get_json() + key = re.search(r'https://localhost/([^"]+)', json_content['link']).group(1) + key = unquote(key) + + rvc = self.app.head('/api/v2/password/' + quote(key)) + self.assertEqual(rv.status, 200) + + def test_check_password_api_v2_bad_keys(self): + with freeze_time("2020-05-08 12:00:00") as frozen_time: + password = 'my name is my passport. verify me.' + rv = self.app.post( + '/api/v2/password/', + headers={'Accept': 'application/json'}, + json={'password': password}, + ) + + json_content = rv.get_json() + key = re.search(r'https://localhost/([^"]+)', json_content['link']).group(1) + key = unquote(key) + + rvc = self.app.head('/api/v2/password/' + quote(key + key)) + self.assertEqual(rv.status, 404) + + # TODO : Search for ProblemDetails propreties about Password + + def test_retrieve_password_api_v2(self): + with freeze_time("2020-05-08 12:00:00") as frozen_time: + password = 'my name is my passport. verify me.' + rv = self.app.post( + '/api/v2/password/', + headers={'Accept': 'application/json'}, + json={'password': password}, + ) + + json_content = rv.get_json() + key = re.search(r'https://localhost/([^"]+)', json_content['link']).group(1) + key = unquote(key) + + rvc = self.app.get('/api/v2/password/' + quote(key)) + self.assertEqual(rv.status, 200) + + json_content_retrieved = rvc.get_json() + retrieved_password = json_content['password'] + self.assertEqual(retrieved_password, password) + + def test_retrieve_password_api_v2_bad_keys(self): + with freeze_time("2020-05-08 12:00:00") as frozen_time: + password = 'my name is my passport. verify me.' + rv = self.app.post( + '/api/v2/password/', + headers={'Accept': 'application/json'}, + json={'password': password}, + ) + + json_content = rv.get_json() + key = re.search(r'https://localhost/([^"]+)', json_content['link']).group(1) + key = unquote(key) + + rvc = self.app.head('/api/v2/password/' + quote(key + key)) + self.assertEqual(rv.status, 404) + + # TODO : Search for ProblemDetails propreties about Password + if __name__ == '__main__': unittest.main()