Skip to content

Commit

Permalink
Full signatures & remove signatures from health_check (#931)
Browse files Browse the repository at this point in the history
* Add option to avoid signature computation

* Add full_response as part of full API responses

* Put back backwards compat

* Do not sign version check
  • Loading branch information
raymondjacobson committed Oct 14, 2020
1 parent 7204f26 commit 5496c36
Show file tree
Hide file tree
Showing 11 changed files with 56 additions and 45 deletions.
8 changes: 7 additions & 1 deletion discovery-provider/src/api/v1/helpers.py
Expand Up @@ -3,8 +3,8 @@
from src.utils.config import shared_config
from hashids import Hashids
from flask_restx import fields, reqparse
from src.queries.search_queries import SearchKind
from datetime import datetime
from .models.common import full_response

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -244,6 +244,12 @@ def make_response(name, namespace, modelType):
"data": modelType,
})

def make_full_response(name, namespace, modelType):
return namespace.clone(name, full_response, {
"data": modelType
})


def to_dict(multi_dict):
"""Converts a multi dict into a dict where only list entries are not flat"""
return {k: v if len(v) > 1 else v[0] for (k, v) in multi_dict.to_dict(flat=False).items()}
Expand Down
1 change: 0 additions & 1 deletion discovery-provider/src/api/v1/models/common.py
Expand Up @@ -26,7 +26,6 @@
"latest_indexed_block": fields.Integer(required=True),
"owner_wallet": fields.Integer(required=True),
"signature": fields.String(required=True),
"success": fields.Boolean(required=True),
"timestamp": fields.String(required=True),
"version": fields.Nested(version_metadata, required=True),
})
2 changes: 0 additions & 2 deletions discovery-provider/src/api/v1/models/search.py
@@ -1,5 +1,3 @@
from flask_restx.fields import Boolean
from src.api.v1.helpers import make_response
from flask_restx import fields
from .common import ns
from .tracks import track_full
Expand Down
2 changes: 0 additions & 2 deletions discovery-provider/src/api/v1/models/tracks.py
@@ -1,5 +1,3 @@
from flask_restx.fields import Boolean, Integer
from src.api.v1.helpers import make_response
from flask_restx import fields
from .users import user_model, user_model_full
from .common import favorite, ns, repost
Expand Down
2 changes: 1 addition & 1 deletion discovery-provider/src/api/v1/models/users.py
@@ -1,4 +1,3 @@
from src.api.v1.helpers import make_response
from flask_restx import fields
from .common import ns

Expand Down Expand Up @@ -32,6 +31,7 @@

user_model_full = ns.clone("user_full", user_model, {
"blocknumber": fields.Integer(required=True),
"wallet": fields.String(required=True),
"created_at": fields.String(required=True),
"creator_node_endpoint": fields.String,
"current_user_followee_follow_count": fields.Integer(required=True),
Expand Down
8 changes: 4 additions & 4 deletions discovery-provider/src/api/v1/playlists.py
Expand Up @@ -5,7 +5,7 @@
from src.queries.get_playlists import get_playlists
from flask_restx import Resource, Namespace, fields, reqparse
from src.queries.get_playlist_tracks import get_playlist_tracks
from src.api.v1.helpers import abort_not_found, decode_with_abort, extend_playlist, extend_track,\
from src.api.v1.helpers import abort_not_found, decode_with_abort, extend_playlist, extend_track, make_full_response,\
make_response, success_response, search_parser, abort_bad_request_param, decode_string_id, \
extend_user, get_default_max, get_current_user_id
from .models.tracks import track
Expand All @@ -21,7 +21,7 @@
full_ns = Namespace('playlists', description='Full playlist related operations')

playlists_response = make_response("playlist_response", ns, fields.List(fields.Nested(playlist_model)))
full_playlists_response = make_response("full_playlist_response", full_ns, fields.List(fields.Nested(full_playlist_model)))
full_playlists_response = make_full_response("full_playlist_response", full_ns, fields.List(fields.Nested(full_playlist_model)))

def get_playlist(playlist_id, current_user_id):
"""Returns a single playlist, or None"""
Expand Down Expand Up @@ -181,7 +181,7 @@ def get(self):
playlist_favorites_route_parser.add_argument('user_id', required=False)
playlist_favorites_route_parser.add_argument('limit', required=False, type=int)
playlist_favorites_route_parser.add_argument('offset', required=False, type=int)
playlist_favorites_response = make_response("following_response", full_ns, fields.List(fields.Nested(user_model_full)))
playlist_favorites_response = make_full_response("following_response", full_ns, fields.List(fields.Nested(user_model_full)))
@full_ns.route("/<string:playlist_id>/favorites")
class FullTrackFavorites(Resource):
@full_ns.expect(playlist_favorites_route_parser)
Expand Down Expand Up @@ -221,7 +221,7 @@ def get(self, playlist_id):
playlist_reposts_route_parser.add_argument('user_id', required=False)
playlist_reposts_route_parser.add_argument('limit', required=False, type=int)
playlist_reposts_route_parser.add_argument('offset', required=False, type=int)
playlist_reposts_response = make_response("following_response", full_ns, fields.List(fields.Nested(user_model_full)))
playlist_reposts_response = make_full_response("following_response", full_ns, fields.List(fields.Nested(user_model_full)))
@full_ns.route("/<string:playlist_id>/reposts")
class FullPlaylistReposts(Resource):
@full_ns.expect(playlist_reposts_route_parser)
Expand Down
6 changes: 3 additions & 3 deletions discovery-provider/src/api/v1/search.py
@@ -1,6 +1,6 @@
import logging # pylint: disable=C0302
from flask_restx import Resource, Namespace, fields, reqparse
from src.api.v1.helpers import extend_track, make_response, \
from src.api.v1.helpers import extend_track, make_full_response, \
success_response, format_offset, format_limit, decode_string_id, \
extend_user, extend_track, extend_playlist, get_current_user_id
from src.queries.search_queries import SearchKind, search
Expand Down Expand Up @@ -41,7 +41,7 @@ def extend_search(resp):
search_route_parser.add_argument('query', required=True, type=str)
search_route_parser.add_argument('limit', required=False, type=int)
search_route_parser.add_argument('offset', required=False, type=int)
search_full_response = make_response("search_full_response", full_ns, fields.Nested(search_model))
search_full_response = make_full_response("search_full_response", full_ns, fields.Nested(search_model))
@full_ns.route("/full")
class FullSearch(Resource):
@full_ns.expect(search_route_parser)
Expand Down Expand Up @@ -83,7 +83,7 @@ def get(self):

return success_response(resp)

search_autocomplete_response = make_response("search_autocomplete_response", full_ns, fields.Nested(search_model))
search_autocomplete_response = make_full_response("search_autocomplete_response", full_ns, fields.Nested(search_model))
@full_ns.route("/autocomplete")
class FullSearch(Resource):
@full_ns.expect(search_route_parser)
Expand Down
16 changes: 8 additions & 8 deletions discovery-provider/src/api/v1/tracks.py
Expand Up @@ -5,7 +5,7 @@
from src.queries.get_tracks import get_tracks
from src.queries.get_track_user_creator_node import get_track_user_creator_node
from src.api.v1.helpers import abort_not_found, decode_with_abort, \
extend_track, make_response, search_parser, extend_user, get_default_max, \
extend_track, make_full_response, make_response, search_parser, extend_user, get_default_max, \
trending_parser, full_trending_parser, success_response, abort_bad_request_param, to_dict, \
format_offset, format_limit, decode_string_id, stem_from_track, \
get_current_user_id
Expand Down Expand Up @@ -33,12 +33,12 @@
full_ns = Namespace('tracks', description='Full track operations')

track_response = make_response("track_response", ns, fields.Nested(track))
full_track_response = make_response(
full_track_response = make_full_response(
"full_track_response", full_ns, fields.Nested(track_full))

tracks_response = make_response(
"tracks_response", ns, fields.List(fields.Nested(track)))
full_tracks_response = make_response(
full_tracks_response = make_full_response(
"full_tracks_response", full_ns, fields.List(fields.Nested(track_full))
)

Expand Down Expand Up @@ -303,7 +303,7 @@ def get(self):
track_favorites_route_parser.add_argument('user_id', required=False)
track_favorites_route_parser.add_argument('limit', required=False, type=int)
track_favorites_route_parser.add_argument('offset', required=False, type=int)
track_favorites_response = make_response(
track_favorites_response = make_full_response(
"following_response", full_ns, fields.List(fields.Nested(user_model_full)))


Expand Down Expand Up @@ -348,7 +348,7 @@ def get(self, track_id):
track_reposts_route_parser.add_argument('user_id', required=False)
track_reposts_route_parser.add_argument('limit', required=False, type=int)
track_reposts_route_parser.add_argument('offset', required=False, type=int)
track_reposts_response = make_response(
track_reposts_response = make_full_response(
"following_response", full_ns, fields.List(fields.Nested(user_model_full)))
@full_ns.route("/<string:track_id>/reposts")
class FullTrackReposts(Resource):
Expand Down Expand Up @@ -385,7 +385,7 @@ def get(self, track_id):
users = list(map(extend_user, users))
return success_response(users)

track_stems_response = make_response(
track_stems_response = make_full_response(
"stems_response", full_ns, fields.List(fields.Nested(stem_full)))

@full_ns.route("/<string:track_id>/stems")
Expand All @@ -399,7 +399,7 @@ def get(self, track_id):
return success_response(stems)


remixes_response = make_response(
remixes_response = make_full_response(
"remixes_response", full_ns, fields.Nested(remixes_response))
remixes_parser = reqparse.RequestParser()
remixes_parser.add_argument('user_id', required=False)
Expand All @@ -426,7 +426,7 @@ def get(self, track_id):
response["tracks"] = list(map(extend_track, response["tracks"]))
return success_response(response)

remixing_response = make_response(
remixing_response = make_full_response(
"remixing_response", full_ns, fields.List(fields.Nested(track_full)))
remixing_parser = reqparse.RequestParser()
remixing_parser.add_argument('user_id', required=False)
Expand Down
18 changes: 9 additions & 9 deletions discovery-provider/src/api/v1/users.py
Expand Up @@ -14,7 +14,7 @@
from src.queries.get_followers_for_user import get_followers_for_user

from src.api.v1.helpers import abort_not_found, decode_with_abort, extend_activity, extend_favorite, extend_track, \
extend_user, format_limit, format_offset, get_current_user_id, make_response, search_parser, success_response, abort_bad_request_param, \
extend_user, format_limit, format_offset, get_current_user_id, make_full_response, make_response, search_parser, success_response, abort_bad_request_param, \
get_default_max
from .models.tracks import track, track_full
from .models.activities import activity_model, activity_model_full
Expand All @@ -28,7 +28,7 @@
full_ns = Namespace('users', description='Full user operations')

user_response = make_response("user_response", ns, fields.Nested(user_model))
full_user_response = make_response(
full_user_response = make_full_response(
"full_user_response", full_ns, fields.List(fields.Nested(user_model_full)))

def get_single_user(user_id, current_user_id):
Expand Down Expand Up @@ -150,7 +150,7 @@ def get(self, user_id):
tracks = list(map(extend_track, tracks))
return success_response(tracks)

full_tracks_response = make_response("full_tracks", full_ns, fields.List(fields.Nested(track_full)))
full_tracks_response = make_full_response("full_tracks", full_ns, fields.List(fields.Nested(track_full)))
@full_ns.route(USER_TRACKS_ROUTE)
class FullTrackList(Resource):
@record_metrics
Expand Down Expand Up @@ -244,7 +244,7 @@ def get(self, handle):
user_reposts_route_parser.add_argument('limit', required=False, type=int)
user_reposts_route_parser.add_argument('offset', required=False, type=int)

reposts_response = make_response("reposts", full_ns, fields.List(fields.Nested(activity_model)))
reposts_response = make_full_response("reposts", full_ns, fields.List(fields.Nested(activity_model)))
@ns.route(USER_REPOSTS_ROUTE)
class RepostList(Resource):
@record_metrics
Expand Down Expand Up @@ -285,7 +285,7 @@ def get(self, user_id):

return success_response(activities)

full_reposts_response = make_response("full_reposts", full_ns, fields.List(fields.Nested(activity_model_full)))
full_reposts_response = make_full_response("full_reposts", full_ns, fields.List(fields.Nested(activity_model_full)))
@full_ns.route(USER_REPOSTS_ROUTE)
class FullRepostList(Resource):
@record_metrics
Expand Down Expand Up @@ -397,7 +397,7 @@ def get(self, user_id):
favorite_route_parser.add_argument('user_id', required=False, type=str)
favorite_route_parser.add_argument('limit', required=False, type=int)
favorite_route_parser.add_argument('offset', required=False, type=int)
favorites_response = make_response("favorites_response", ns, fields.List(fields.Nested(activity_model_full)))
favorites_response = make_full_response("favorites_response", full_ns, fields.List(fields.Nested(activity_model_full)))
@full_ns.route("/<string:user_id>/favorites/tracks")
class FavoritedTracks(Resource):
@record_metrics
Expand Down Expand Up @@ -475,7 +475,7 @@ def get(self):
followers_route_parser.add_argument('limit', required=False, type=int)
followers_route_parser.add_argument('offset', required=False, type=int)

followers_response = make_response("followers_response", full_ns, fields.List(fields.Nested(user_model_full)))
followers_response = make_full_response("followers_response", full_ns, fields.List(fields.Nested(user_model_full)))
@full_ns.route("/<string:user_id>/followers")
class FollowerUsers(Resource):
@record_metrics
Expand Down Expand Up @@ -516,7 +516,7 @@ def get(self, user_id):
following_route_parser.add_argument('user_id', required=False)
following_route_parser.add_argument('limit', required=False, type=int)
following_route_parser.add_argument('offset', required=False, type=int)
following_response = make_response("following_response", full_ns, fields.List(fields.Nested(user_model_full)))
following_response = make_full_response("following_response", full_ns, fields.List(fields.Nested(user_model_full)))
@full_ns.route("/<string:user_id>/following")
class FollowingUsers(Resource):
@record_metrics
Expand Down Expand Up @@ -556,7 +556,7 @@ def get(self, user_id):
top_genre_users_route_parser.add_argument('genre', required=False, action='append')
top_genre_users_route_parser.add_argument('limit', required=False, type=int)
top_genre_users_route_parser.add_argument('offset', required=False, type=int)
top_genre_users_response = make_response("top_genre_users_response", full_ns, fields.List(fields.Nested(user_model_full)))
top_genre_users_response = make_full_response("top_genre_users_response", full_ns, fields.List(fields.Nested(user_model_full)))
@full_ns.route("/genre/top")
class FullTopGenreUsers(Resource):
@full_ns.expect(top_genre_users_route_parser)
Expand Down
21 changes: 11 additions & 10 deletions discovery-provider/src/api_helpers.py
Expand Up @@ -32,21 +32,21 @@ def error_response(error, error_code=500):

# Create a response dict with just data, signature, and timestamp
# This response will contain a duplicate of response_entity
def success_response_backwards_compat(response_entity=None, status=200):
def success_response_backwards_compat(response_entity=None, status=200, sign_response=True):
starting_response_dictionary = {'data': response_entity, **response_entity}
response_dictionary = response_dict_with_metadata(starting_response_dictionary)
response_dictionary = response_dict_with_metadata(starting_response_dictionary, sign_response)
return jsonify(response_dictionary), status

# Create a response dict with metadata, data, signature, and timestamp
def success_response(response_entity=None, status=200, to_json=True):
def success_response(response_entity=None, status=200, to_json=True, sign_response=True):
starting_response_dictionary = {'data': response_entity}
response_dictionary = response_dict_with_metadata(starting_response_dictionary)
response_dictionary = response_dict_with_metadata(starting_response_dictionary, sign_response)
response = jsonify(response_dictionary) if to_json else response_dictionary
return response, status

# Create a response dict with metadata fields of success, latest_indexed_block, latest_chain_block,
# version, and owner_wallet
def response_dict_with_metadata(response_dictionary):
def response_dict_with_metadata(response_dictionary, sign_response):
response_dictionary['success'] = True

latest_indexed_block = redis.get(most_recent_indexed_block_redis_key)
Expand All @@ -57,12 +57,13 @@ def response_dict_with_metadata(response_dictionary):
response_dictionary['version'] = disc_prov_version
response_dictionary['signer'] = shared_config['delegate']['owner_wallet']

# generate timestamp with format HH:MM:SS.sssZ
timestamp = datetime.datetime.now().isoformat(timespec='milliseconds') + 'Z'
response_dictionary['timestamp'] = timestamp
if sign_response:
# generate timestamp with format HH:MM:SS.sssZ
timestamp = datetime.datetime.now().isoformat(timespec='milliseconds') + 'Z'
response_dictionary['timestamp'] = timestamp

signature = generate_signature(response_dictionary)
response_dictionary['signature'] = signature
signature = generate_signature(response_dictionary)
response_dictionary['signature'] = signature

return response_dictionary

Expand Down
17 changes: 13 additions & 4 deletions discovery-provider/src/queries/health_check.py
Expand Up @@ -16,7 +16,10 @@

@bp.route("/version", methods=["GET"])
def version():
return success_response_backwards_compat(disc_prov_version)
return success_response_backwards_compat(
disc_prov_version,
sign_response=False
)

# Health check for server, db, and redis. Consumes latest block data from redis instead of chain.
# Optional boolean "verbose" flag to output db connection info.
Expand All @@ -34,7 +37,8 @@ def health_check():
(health_results, error) = get_health(args)
return success_response_backwards_compat(
health_results,
500 if error else 200
500 if error else 200,
sign_response=False
)


Expand All @@ -50,7 +54,8 @@ def block_check():
(health_results, error) = get_health(args, use_redis_cache=False)
return success_response_backwards_compat(
health_results,
500 if error else 200
500 if error else 200,
sign_response=False
)

# Health check for latest play stored in the db
Expand All @@ -68,4 +73,8 @@ def play_check():
# Error if max drift was provided and the drift is greater than max_drift
error = max_drift and drift > max_drift

return success_response(latest_play, 500 if error else 200)
return success_response(
latest_play,
500 if error else 200,
sign_response=False
)

0 comments on commit 5496c36

Please sign in to comment.