Support passing the Auth token as a url param.

This is required to support ebook downloads which the Kobo device emits
without any auth headers.

* Also some other small bug fixes discovered during device testing.
This commit is contained in:
Michael Shavit 2019-12-07 22:44:36 -05:00
parent 0926ae530c
commit fffa2d5a1b
3 changed files with 31 additions and 9 deletions

View File

@ -445,7 +445,7 @@ def get_book_cover_with_uuid(book_uuid,
def get_book_cover_internal(book, def get_book_cover_internal(book,
use_generic_cover_on_failure): use_generic_cover_on_failure):
if book.has_cover: if book and book.has_cover:
if config.config_use_google_drive: if config.config_use_google_drive:
try: try:
if not gd.is_gdrive_ready(): if not gd.is_gdrive_ready():

View File

@ -1,6 +1,7 @@
#!/usr/bin/env python #!/usr/bin/env python
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import base64
import copy import copy
import uuid import uuid
import os import os
@ -25,8 +26,6 @@ kobo_auth.disable_failed_auth_redirect_for_blueprint(kobo)
log = logger.create() log = logger.create()
import base64
def b64encode(data): def b64encode(data):
return base64.b64encode(data) return base64.b64encode(data)
@ -92,10 +91,12 @@ class SyncToken:
if "." in sync_token_header: if "." in sync_token_header:
return SyncToken(raw_kobo_store_token=sync_token_header) return SyncToken(raw_kobo_store_token=sync_token_header)
sync_token_json = json.loads(
base64.b64decode(sync_token_header + "=" * (-len(sync_token_header) % 4))
)
try: try:
sync_token_json = json.loads(
base64.b64decode(
sync_token_header + "=" * (-len(sync_token_header) % 4)
)
)
validate(sync_token_json, SyncToken.token_schema) validate(sync_token_json, SyncToken.token_schema)
if sync_token_json["version"] < SyncToken.MIN_VERSION: if sync_token_json["version"] < SyncToken.MIN_VERSION:
raise ValueError raise ValueError
@ -217,8 +218,10 @@ def get_metadata__v1(book_uuid):
def get_download_url_for_book(book): def get_download_url_for_book(book):
return "{url_base}/download/{book_id}/kepub".format( return "{url_base}/download/{book_id}/kepub?{auth_token_param}".format(
url_base=config.config_server_url, book_id=book.id url_base=config.config_server_url,
book_id=book.id,
auth_token_param=kobo_auth.get_auth_url_param(request),
) )

View File

@ -50,6 +50,8 @@ from werkzeug.security import check_password_hash
from . import logger, ub, lm from . import logger, ub, lm
USER_KEY_HEADER = "x-kobo-userkey" USER_KEY_HEADER = "x-kobo-userkey"
USER_KEY_URL_PARAM = "kobo_userkey"
log = logger.create() log = logger.create()
@ -59,7 +61,7 @@ def disable_failed_auth_redirect_for_blueprint(bp):
@lm.request_loader @lm.request_loader
def load_user_from_kobo_request(request): def load_user_from_kobo_request(request):
user_key = request.headers.get(USER_KEY_HEADER) user_key = get_auth_token_from_request(request)
if user_key: if user_key:
for user in ( for user in (
ub.session.query(ub.User).filter(ub.User.kobo_user_key_hash != "").all() ub.session.query(ub.User).filter(ub.User.kobo_user_key_hash != "").all()
@ -68,3 +70,20 @@ def load_user_from_kobo_request(request):
return user return user
log.info("Received Kobo request without a recognizable UserKey.") log.info("Received Kobo request without a recognizable UserKey.")
return None return None
def get_auth_token_from_request(request):
user_key = request.headers.get(USER_KEY_HEADER)
if not user_key:
user_key = request.args.get(USER_KEY_URL_PARAM)
return user_key
def get_auth_url_param(request):
# Some of the API requests emitted by the Kobo device don't set any headers. To
# support those calls, authorization on those endpoints can only rely on URL params.
# Since the raw UserKey in already leaked in headers, it is probably not *that* much
# worse to also leak it over url params.
# Ideally however, we should be generating short-lived tokens that grant limited
# access instead..
return USER_KEY_URL_PARAM + "=" + get_auth_token_from_request(request)