From 113046fe376bcd362b5e5631668ea75b90d8e1cb Mon Sep 17 00:00:00 2001 From: Javier Arias Date: Thu, 14 Feb 2019 09:44:46 +0000 Subject: [PATCH 1/6] allow disabling auth --- src/api.py | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/api.py b/src/api.py index f2c25e7..988b9f1 100644 --- a/src/api.py +++ b/src/api.py @@ -24,13 +24,24 @@ import json from aux import logger_instance, debug_mode from errors import Error, internal_error, not_found, \ - FATAL, NORESULT, BADFILTERS, UNAUTHORIZED, FORBIDDEN + NORESULT, BADFILTERS, UNAUTHORIZED, FORBIDDEN # get logging interface logger = logger_instance(__name__) web.config.debug = debug_mode() -# Get secret key to check jwt against -SECRET_KEY = os.environ['SECRET_KEY'] +# You may disable JWT auth. when implementing the API in a local network +JWT_DISABLED = False +# Get secret key to check JWT +SECRET_KEY = "" +try: + if 'JWT_DISABLED' in os.environ: + JWT_DISABLED = os.environ['JWT_DISABLED'] in ('true', 'True') + if 'SECRET_KEY' in os.environ: + SECRET_KEY = os.environ['SECRET_KEY'] + assert JWT_DISABLED or SECRET_KEY +except AssertionError as error: + logger.error(error) + raise # Define routes urls = ( @@ -50,7 +61,7 @@ db=os.environ['IDENTIFIERSDB_DB']) except Exception as error: logger.error(error) - raise Error(FATAL) + raise def api_response(fn): @@ -82,15 +93,16 @@ def response(self, *args, **kw): def check_token(fn): """Decorator to act as middleware, checking authentication token""" def response(self, *args, **kw): - intoken = get_token_from_header() - try: - jwt.decode(intoken, SECRET_KEY) - except jwt.exceptions.DecodeError: - raise Error(FORBIDDEN) - except jwt.ExpiredSignatureError: - raise Error(UNAUTHORIZED, msg="Signature expired.") - except jwt.InvalidTokenError: - raise Error(UNAUTHORIZED, msg="Invalid token.") + if not JWT_DISABLED: + intoken = get_token_from_header() + try: + jwt.decode(intoken, SECRET_KEY) + except jwt.exceptions.DecodeError: + raise Error(FORBIDDEN) + except jwt.ExpiredSignatureError: + raise Error(UNAUTHORIZED, msg="Signature expired.") + except jwt.InvalidTokenError: + raise Error(UNAUTHORIZED, msg="Invalid token.") return fn(self, *args, **kw) return response From aefc5436f3fab3e36accdb38e008b95de219c474 Mon Sep 17 00:00:00 2001 From: Javier Arias Date: Thu, 14 Feb 2019 09:46:02 +0000 Subject: [PATCH 2/6] add jwt flag --- config/api.env.example | 1 + 1 file changed, 1 insertion(+) diff --git a/config/api.env.example b/config/api.env.example index c6f7abe..371edb6 100644 --- a/config/api.env.example +++ b/config/api.env.example @@ -1,4 +1,5 @@ API_DEBUG=False +JWT_DISABLED=False SECRET_KEY=an_up_to_255_bytes_random_key TOKEN_LIFETIME=3600 PBKDF2_ITERATIONS=10000 From b3b8e5eae248e307fda3c49bc4dd400bed8743f9 Mon Sep 17 00:00:00 2001 From: Javier Arias Date: Thu, 14 Feb 2019 09:48:26 +0000 Subject: [PATCH 3/6] remove unnecessary vars --- config/api.env.example | 2 -- 1 file changed, 2 deletions(-) diff --git a/config/api.env.example b/config/api.env.example index 371edb6..475949d 100644 --- a/config/api.env.example +++ b/config/api.env.example @@ -1,6 +1,4 @@ API_DEBUG=False JWT_DISABLED=False SECRET_KEY=an_up_to_255_bytes_random_key -TOKEN_LIFETIME=3600 -PBKDF2_ITERATIONS=10000 ALLOW_ORIGIN=https://metrics-broker.com From 7a3fc81d066f7cc07d4e01576365d11e7fddb5d9 Mon Sep 17 00:00:00 2001 From: Javier Arias Date: Thu, 14 Feb 2019 09:52:59 +0000 Subject: [PATCH 4/6] add more meaningful example --- config/api.env.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/api.env.example b/config/api.env.example index 475949d..b4730fb 100644 --- a/config/api.env.example +++ b/config/api.env.example @@ -1,4 +1,4 @@ API_DEBUG=False JWT_DISABLED=False SECRET_KEY=an_up_to_255_bytes_random_key -ALLOW_ORIGIN=https://metrics-broker.com +ALLOW_ORIGIN=https://openbookpublishers.com From 8b891a2bf77cb788e8aeb9b360e775412b72c73d Mon Sep 17 00:00:00 2001 From: Javier Arias Date: Thu, 14 Feb 2019 09:53:38 +0000 Subject: [PATCH 5/6] check all files in src --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b6a5a80..c12794a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,4 +4,4 @@ python: install: - pip install -r ./config/requirements.txt script: - - flake8 --ignore=E221,E241 ./src/ + - flake8 --ignore=E221,E241 ./src/* From ba7a44b50174db294cefbeab894547be2017b876 Mon Sep 17 00:00:00 2001 From: Javier Arias Date: Thu, 14 Feb 2019 13:53:10 +0000 Subject: [PATCH 6/6] upgrade to python 3 --- .travis.yml | 2 +- Dockerfile | 2 +- config/requirements.txt | 6 ++---- src/api.py | 10 ++++------ src/aux.py | 6 +++--- src/errors.py | 2 +- src/models.py | 4 +--- src/relationsctrl.py | 2 +- src/titlesctrl.py | 2 +- src/translator.py | 8 +++++--- src/urisctrl.py | 2 +- src/worksctrl.py | 4 ++-- 12 files changed, 23 insertions(+), 27 deletions(-) diff --git a/.travis.yml b/.travis.yml index c12794a..2d35087 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: python python: - - "2.7" + - "3.5" install: - pip install -r ./config/requirements.txt script: diff --git a/Dockerfile b/Dockerfile index 9f39c13..ad5a08c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM python:2 +FROM python:3.5 RUN apt-get update && apt-get upgrade -y && \ pip install --upgrade pip diff --git a/config/requirements.txt b/config/requirements.txt index 28c25df..8cb4e25 100644 --- a/config/requirements.txt +++ b/config/requirements.txt @@ -1,7 +1,5 @@ -flake8==3.6.0 -pbkdf2==1.3 PyJWT==1.6.1 +flake8==3.6.0 psycopg2-binary==2.7.5 uri==2.0.0 -urllib3==1.23 -web.py==0.39 +web.py==0.40-dev1 diff --git a/src/api.py b/src/api.py index 988b9f1..18d10ea 100644 --- a/src/api.py +++ b/src/api.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Identifier Translator JSON API. Simple web.py based API to a @@ -10,12 +10,10 @@ Use of this software is governed by the terms of the MIT license Dependencies: - pbkdf2==1.3 - PyJWT==1.6.1 + PyJWT==1.7.1 psycopg2-binary==2.7.5 uri==2.0.0 - urllib3==1.20 - web.py==0.39 + web.py==0.40-dev1 """ import os @@ -136,7 +134,7 @@ def build_parms(filters): raise Error(BADFILTERS, msg="Unknown filter '%s'" % (p)) process = {"work_type": types, "uri_scheme": schemes, "canonical": canoncl} - for key, values in process.items(): + for key, values in list(process.items()): if len(values) > 0: try: andclause, ops = build_clause(key, values) diff --git a/src/aux.py b/src/aux.py index 5a27055..0b0bfb6 100644 --- a/src/aux.py +++ b/src/aux.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- import os @@ -17,7 +17,7 @@ def logger_instance(name): def strtolist(data): - if isinstance(data, basestring): + if isinstance(data, str): return [data] - elif type(data) is list: + elif isinstance(data, list): return data diff --git a/src/errors.py b/src/errors.py index 41b17d6..0636a08 100644 --- a/src/errors.py +++ b/src/errors.py @@ -65,7 +65,7 @@ def __init__(self, level=DEFAULT, msg='', data=[]): httpcode = self.get_code(level) headers = {'Content-Type': 'application/json'} message = self.get_message(level) - params = web.input() if web.input() else web.data() + params = web.input() if web.input() else web.data().decode('utf-8') output = json.dumps( self.make_output(httpcode, message, msg, params, data)) diff --git a/src/models.py b/src/models.py index 7d60121..64d8b16 100644 --- a/src/models.py +++ b/src/models.py @@ -416,12 +416,10 @@ def results_to_works(results, include_relatives=False): uris = [] # temp array of work URIs (strings, used for comparison) uris_fmt = [] # temporary array of work URIs (Identifier objects) last = len(results) - 1 + cur = results[0] i = 0 for e in results: - if i == 0: - # we can't do cur=results[0] outsise--it moves IterBetter's pointer - cur = e if e["work_id"] != cur["work_id"]: cur["titles"] = titles cur["URI"] = uris_fmt diff --git a/src/relationsctrl.py b/src/relationsctrl.py index 444c02f..e826849 100644 --- a/src/relationsctrl.py +++ b/src/relationsctrl.py @@ -24,7 +24,7 @@ def POST(self, name): """Create a work relation""" logger.debug("Data: %s" % (web.data())) - data = json.loads(web.data()) + data = json.loads(web.data().decode('utf-8')) parent_uuid = data.get('parent_UUID') or data.get('parent_uuid') child_uuid = data.get('child_UUID') or data.get('child_uuid') diff --git a/src/titlesctrl.py b/src/titlesctrl.py index 8b077ef..c3926d0 100644 --- a/src/titlesctrl.py +++ b/src/titlesctrl.py @@ -26,7 +26,7 @@ def POST(self, name): """Add titles to an existing work""" logger.debug("Data: %s" % (web.data())) - data = json.loads(web.data()) + data = json.loads(web.data().decode('utf-8')) title = data.get('title') work_id = data.get('UUID') or data.get('uuid') diff --git a/src/translator.py b/src/translator.py index 1f9d69a..816bee5 100644 --- a/src/translator.py +++ b/src/translator.py @@ -1,5 +1,7 @@ import web -import urllib +import urllib.request +import urllib.parse +import urllib.error from aux import logger_instance, debug_mode from api import build_parms, json_response, api_response, check_token from errors import Error, BADPARAMS, NORESULT, NOTALLOWED, \ @@ -41,7 +43,7 @@ def GET(self, name): scheme, value = Identifier.split_uri(uri) assert scheme and value if title: - title = urllib.unquote(title.strip()) + title = urllib.parse.unquote(title.strip()) assert title assert uri or title except BaseException: @@ -60,7 +62,7 @@ def GET(self, name): if not results: raise Error(NORESULT) - return self.process_results(results, strict) + return self.process_results(list(results), strict) def POST(self, name): raise Error(NOTALLOWED) diff --git a/src/urisctrl.py b/src/urisctrl.py index 829d6a3..ba26147 100644 --- a/src/urisctrl.py +++ b/src/urisctrl.py @@ -24,7 +24,7 @@ def POST(self, name): """Add identifiers to an existing work""" logger.debug("Data: %s" % (web.data())) - data = json.loads(web.data()) + data = json.loads(web.data().decode('utf-8')) uri = data.get('URI') or data.get('uri') canonical = data.get('canonical') in (True, "true", "True") work_id = data.get('UUID') or data.get('uuid') diff --git a/src/worksctrl.py b/src/worksctrl.py index 72fe443..e3d194d 100644 --- a/src/worksctrl.py +++ b/src/worksctrl.py @@ -42,7 +42,7 @@ def GET(self, name): raise Error(NORESULT) include_relatives = work_id is not None - data = results_to_works(results, include_relatives) + data = results_to_works(list(results), include_relatives) if sort: reverse = order == "desc" @@ -59,7 +59,7 @@ def POST(self, name): """Create a work""" logger.debug("Data: %s" % (web.data())) - data = json.loads(web.data()) + data = json.loads(web.data().decode('utf-8')) wtype = data.get('type') title = data.get('title') uri = data.get('URI') or data.get('uri')