Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
D
douban-api-proxy
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
captainwong
douban-api-proxy
Commits
27a18d60
Commit
27a18d60
authored
Feb 19, 2020
by
Ozzieisaacs
Browse files
Options
Browse Files
Download
Plain Diff
Merge remote-tracking branch 'fix/robust_proxy' into Develop
# Conflicts: # cps/kobo.py
parents
68936352
df3eb40e
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
97 additions
and
71 deletions
+97
-71
kobo.py
cps/kobo.py
+97
-71
No files found.
cps/kobo.py
View file @
27a18d60
...
...
@@ -75,8 +75,26 @@ CONNECTION_SPECIFIC_HEADERS = [
def
get_kobo_activated
():
return
config
.
config_kobo_sync
def
redirect_or_proxy_request
(
proxy
=
False
):
if
config
.
config_kobo_proxy
or
proxy
==
True
:
def
make_request_to_kobo_store
(
sync_token
=
None
):
outgoing_headers
=
Headers
(
request
.
headers
)
outgoing_headers
.
remove
(
"Host"
)
if
sync_token
:
sync_token
.
set_kobo_store_header
(
outgoing_headers
)
store_response
=
requests
.
request
(
method
=
request
.
method
,
url
=
get_store_url_for_current_request
(),
headers
=
outgoing_headers
,
data
=
request
.
get_data
(),
allow_redirects
=
False
,
timeout
=
(
2
,
10
)
)
return
store_response
def
redirect_or_proxy_request
():
if
config
.
config_kobo_proxy
:
if
request
.
method
==
"GET"
:
return
redirect
(
get_store_url_for_current_request
(),
307
)
if
request
.
method
==
"DELETE"
:
...
...
@@ -84,15 +102,7 @@ def redirect_or_proxy_request(proxy=False):
return
make_response
(
jsonify
({}))
else
:
# The Kobo device turns other request types into GET requests on redirects, so we instead proxy to the Kobo store ourselves.
outgoing_headers
=
Headers
(
request
.
headers
)
outgoing_headers
.
remove
(
"Host"
)
store_response
=
requests
.
request
(
method
=
request
.
method
,
url
=
get_store_url_for_current_request
(),
headers
=
outgoing_headers
,
data
=
request
.
get_data
(),
allow_redirects
=
False
,
)
store_response
=
make_request_to_kobo_store
()
response_headers
=
store_response
.
headers
for
header_key
in
CONNECTION_SPECIFIC_HEADERS
:
...
...
@@ -104,6 +114,7 @@ def redirect_or_proxy_request(proxy=False):
else
:
return
make_response
(
jsonify
({}))
@
kobo
.
route
(
"/v1/library/sync"
)
@
requires_kobo_auth
@
download_required
...
...
@@ -162,35 +173,24 @@ def HandleSyncRequest():
def
generate_sync_response
(
request
,
sync_token
,
entitlements
):
# We first merge in sync results from the official Kobo store.
outgoing_headers
=
Headers
(
request
.
headers
)
outgoing_headers
.
remove
(
"Host"
)
sync_token
.
set_kobo_store_header
(
outgoing_headers
)
store_response
=
requests
.
request
(
method
=
request
.
method
,
url
=
get_store_url_for_current_request
(),
headers
=
outgoing_headers
,
data
=
request
.
get_data
(),
)
extra_headers
=
{}
if
config
.
config_kobo_proxy
:
# Merge in sync results from the official Kobo store.
try
:
store_response
=
make_request_to_kobo_store
(
sync_token
)
store_entitlements
=
store_response
.
json
()
entitlements
+=
store_entitlements
sync_token
.
merge_from_store_response
(
store_response
)
extra_headers
[
"x-kobo-sync"
]
=
store_response
.
headers
.
get
(
"x-kobo-sync"
)
extra_headers
[
"x-kobo-sync-mode"
]
=
store_response
.
headers
.
get
(
"x-kobo-sync-mode"
)
extra_headers
[
"x-kobo-recent-reads"
]
=
store_response
.
headers
.
get
(
"x-kobo-recent-reads"
)
except
Exception
as
e
:
log
.
error
(
"Failed to receive or parse response from Kobo's sync endpoint: "
+
str
(
e
))
sync_token
.
to_headers
(
extra_headers
)
store_entitlements
=
store_response
.
json
()
entitlements
+=
store_entitlements
sync_token
.
merge_from_store_response
(
store_response
)
response
=
make_response
(
jsonify
(
entitlements
))
sync_token
.
to_headers
(
response
.
headers
)
try
:
# These headers could probably use some more investigation.
response
.
headers
[
"x-kobo-sync"
]
=
store_response
.
headers
[
"x-kobo-sync"
]
response
.
headers
[
"x-kobo-sync-mode"
]
=
store_response
.
headers
[
"x-kobo-sync-mode"
]
response
.
headers
[
"x-kobo-recent-reads"
]
=
store_response
.
headers
[
"x-kobo-recent-reads"
]
except
KeyError
:
pass
response
=
make_response
(
jsonify
(
entitlements
),
extra_headers
)
return
response
...
...
@@ -379,6 +379,7 @@ def HandleUnimplementedRequest(dummy=None, book_uuid=None, shelf_name=None, tag_
log
.
debug
(
"Alternative Request received:"
)
return
redirect_or_proxy_request
()
# TODO: Implement the following routes
@
kobo
.
route
(
"/v1/user/loyalty/<dummy>"
,
methods
=
[
"GET"
,
"POST"
])
@
kobo
.
route
(
"/v1/user/profile"
,
methods
=
[
"GET"
,
"POST"
])
...
...
@@ -386,9 +387,21 @@ def HandleUnimplementedRequest(dummy=None, book_uuid=None, shelf_name=None, tag_
@
kobo
.
route
(
"/v1/user/recommendations"
,
methods
=
[
"GET"
,
"POST"
])
@
kobo
.
route
(
"/v1/analytics/<dummy>"
,
methods
=
[
"GET"
,
"POST"
])
def
HandleUserRequest
(
dummy
=
None
):
log
.
debug
(
"Unimplemented Request received:
%
s"
,
request
.
base_url
)
log
.
debug
(
"Unimplemented User Request received:
%
s"
,
request
.
base_url
)
return
redirect_or_proxy_request
()
@
kobo
.
route
(
"/v1/products/<dummy>/prices"
,
methods
=
[
"GET"
,
"POST"
])
@
kobo
.
route
(
"/v1/products/<dummy>/recommendations"
,
methods
=
[
"GET"
,
"POST"
])
@
kobo
.
route
(
"/v1/products/<dummy>/nextread"
,
methods
=
[
"GET"
,
"POST"
])
@
kobo
.
route
(
"/v1/products/<dummy>/reviews"
,
methods
=
[
"GET"
,
"POST"
])
@
kobo
.
route
(
"/v1/products/books/<dummy>"
,
methods
=
[
"GET"
,
"POST"
])
@
kobo
.
route
(
"/v1/products/dailydeal"
,
methods
=
[
"GET"
,
"POST"
])
def
HandleProductsRequest
(
dummy
=
None
):
log
.
debug
(
"Unimplemented Products Request received:
%
s"
,
request
.
base_url
)
return
redirect_or_proxy_request
()
@
kobo
.
app_errorhandler
(
404
)
def
handle_404
(
err
):
# This handler acts as a catch-all for endpoints that we don't have an interest in
...
...
@@ -397,11 +410,9 @@ def handle_404(err):
return
redirect_or_proxy_request
()
@
kobo
.
route
(
"/v1/auth/device"
,
methods
=
[
"POST"
])
@
requires_kobo_auth
def
HandleAuthRequest
():
# Missing feature: Authentication :)
log
.
debug
(
'Kobo Auth request'
)
def
make_calibre_web_auth_response
():
# As described in kobo_auth.py, CalibreWeb doesn't make use practical use of this auth/device API call for
# authentation (nor for authorization). We return a dummy response just to keep the device happy.
content
=
request
.
get_json
()
AccessToken
=
base64
.
b64encode
(
os
.
urandom
(
24
))
.
decode
(
'utf-8'
)
RefreshToken
=
base64
.
b64encode
(
os
.
urandom
(
24
))
.
decode
(
'utf-8'
)
...
...
@@ -419,12 +430,32 @@ def HandleAuthRequest():
}
)
)
@
kobo
.
route
(
"/v1/auth/device"
,
methods
=
[
"POST"
])
@
requires_kobo_auth
def
HandleAuthRequest
():
log
.
debug
(
'Kobo Auth request'
)
if
config
.
config_kobo_proxy
:
try
:
return
redirect_or_proxy_request
()
except
:
log
.
error
(
"Failed to receive or parse response from Kobo's auth endpoint. Falling back to un-proxied mode."
)
return
make_calibre_web_auth_response
()
def
make_calibre_web_init_response
(
calibre_web_url
):
resources
=
NATIVE_KOBO_RESOURCES
(
calibre_web_url
)
response
=
make_response
(
jsonify
({
"Resources"
:
resources
}))
response
.
headers
[
"x-kobo-apitoken"
]
=
"e30="
return
response
@
kobo
.
route
(
"/v1/initialization"
)
@
requires_kobo_auth
def
HandleInitRequest
():
log
.
info
(
'Init'
)
if
not
current_app
.
wsgi_app
.
is_proxied
:
log
.
debug
(
'Kobo: Received unproxied request, changed request port to server port'
)
calibre_web_url
=
"{url_scheme}://{url_base}:{url_port}"
.
format
(
...
...
@@ -434,34 +465,29 @@ def HandleInitRequest():
)
else
:
calibre_web_url
=
url_for
(
"web.index"
,
_external
=
True
)
.
strip
(
"/"
)
if
config
.
config_kobo_proxy
:
outgoing_headers
=
Headers
(
request
.
headers
)
outgoing_headers
.
remove
(
"Host"
)
store_response
=
requests
.
request
(
method
=
request
.
method
,
url
=
get_store_url_for_current_request
(),
headers
=
outgoing_headers
,
data
=
request
.
get_data
(),
)
store_response_json
=
store_response
.
json
()
if
"Resources"
in
store_response_json
:
kobo_resources
=
store_response_json
[
"Resources"
]
# calibre_web_url = url_for("web.index", _external=True).strip("/")
kobo_resources
[
"image_host"
]
=
calibre_web_url
kobo_resources
[
"image_url_quality_template"
]
=
unquote
(
calibre_web_url
+
url_for
(
"kobo.HandleCoverImageRequest"
,
auth_token
=
kobo_auth
.
get_auth_token
(),
book_uuid
=
"{ImageId}"
))
kobo_resources
[
"image_url_template"
]
=
unquote
(
calibre_web_url
+
url_for
(
"kobo.HandleCoverImageRequest"
,
auth_token
=
kobo_auth
.
get_auth_token
(),
book_uuid
=
"{ImageId}"
))
if
config
.
config_kobo_proxy
:
try
:
store_response
=
make_request_to_kobo_store
()
store_response_json
=
store_response
.
json
()
if
"Resources"
in
store_response_json
:
kobo_resources
=
store_response_json
[
"Resources"
]
# calibre_web_url = url_for("web.index", _external=True).strip("/")
kobo_resources
[
"image_host"
]
=
calibre_web_url
kobo_resources
[
"image_url_quality_template"
]
=
unquote
(
calibre_web_url
+
url_for
(
"kobo.HandleCoverImageRequest"
,
auth_token
=
kobo_auth
.
get_auth_token
(),
book_uuid
=
"{ImageId}"
))
kobo_resources
[
"image_url_template"
]
=
unquote
(
calibre_web_url
+
url_for
(
"kobo.HandleCoverImageRequest"
,
auth_token
=
kobo_auth
.
get_auth_token
(),
book_uuid
=
"{ImageId}"
))
return
make_response
(
store_response_json
,
store_response
.
status_code
)
except
:
log
.
error
(
"Failed to receive or parse response from Kobo's init endpoint. Falling back to un-proxied mode."
)
return
make_calibre_web_init_response
(
calibre_web_url
)
return
make_response
(
store_response_json
,
store_response
.
status_code
)
else
:
resources
=
NATIVE_KOBO_RESOURCES
(
calibre_web_url
)
response
=
make_response
(
jsonify
({
"Resources"
:
resources
}))
response
.
headers
[
"x-kobo-apitoken"
]
=
"e30="
return
response
def
NATIVE_KOBO_RESOURCES
(
calibre_web_url
):
return
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment