Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 39 additions & 8 deletions rmcl/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,18 @@
DocumentNotFound,
ApiError,)
from .const import (RFC3339Nano,
DEFAULT_TOKEN_SERVER_URL,
DEFAULT_SERVICE_MGR_SERVER_URL,
USER_AGENT,
DEVICE_TOKEN_URL,
USER_TOKEN_URL,
DEVICE_TOKEN_PATH,
USER_TOKEN_PATH,
USER_TOKEN_VALIDITY,
DEVICE_REGISTER_URL,
DEVICE,
NBYTES,
FILE_LIST_VALIDITY,
ROOT_ID,
SERVICE_MGR_URL,
SERVICE_MGR_PATH,
TRASH_ID,
FileType)

Expand Down Expand Up @@ -115,13 +117,15 @@ async def request(self, method: str, path: str,

log.debug("Got 401 code; trying to renew token")
await self.renew_token()
return await self.request(method, path, data, body, headers, params, stream, False)

#return await self.request(method, path, data, body, headers, params, stream, False)

async def base_url(self):
if self._base_url is None:
resp = await self.request("GET", SERVICE_MGR_URL)
resp = await self.request("GET", self.config['service_mgr_url'])
try:
self._base_url = resp.json().get("Host")
#self._base_url = 'rmfakecloud.bruckbu.de'
except json.decoder.JSONDecodeError:
raise ApiError("Failed to get service URL", resp)
return self._base_url
Expand Down Expand Up @@ -150,14 +154,41 @@ async def register_device(self, code: str):
"deviceID": uuid,

}
response = await self.request("POST", DEVICE_TOKEN_URL, body=body, allow_renew=False)
response = await self.request("POST", self.config['device_token_url'], body=body, allow_renew=False)
if response.status_code == 200:
self.config["devicetoken"] = response.text
return True
else:
raise AuthError(f"Could not register device (status code {response.status_code})")

async def prompt_set_server_url(self):
if self.config.get('device_token_url'):
return

print(f"""
Please state the adress (including https://) of your remarkable cloud:
(default: https://webapp-production-dot-remarkable-production.appspot.com for the official reMarkable™ Connect™ cloud™ powered by Google™ blobstorage™.)
""")
server_url = input("\nPlease enter cloud storage url (including https://) or leave empty for official cloud: ")
if server_url == "":
token_server_url = DEFAULT_TOKEN_SERVER_URL
service_mgr_server_url = DEFAULT_SERVICE_MGR_SERVER_URL
device_register_url = DEVICE_REGISTER_URL
else:
token_server_url = server_url
service_mgr_server_url = server_url
device_register_url = server_url + '/generatecode'

self.config['device_token_url'] = token_server_url + DEVICE_TOKEN_PATH
self.config['user_token_url'] = token_server_url + USER_TOKEN_PATH
self.config['service_mgr_url'] = service_mgr_server_url + SERVICE_MGR_PATH
self.config['device_register_url'] = device_register_url


async def prompt_register_device(self):
if 'device_token_url' not in self.config.keys():
await self.prompt_set_server_url()

if self.config.get("devicetoken"):
return

Expand All @@ -167,7 +198,7 @@ async def prompt_register_device(self):
print(textwrap.dedent(f"""
This reMarkable client needs to be registered with the reMarkable
cloud. To do this, please visit
{DEVICE_REGISTER_URL}
{self.config['device_register_url']}
to get a one-time code.

(You may be prompted to log into your reMarkable cloud account. If
Expand Down Expand Up @@ -196,7 +227,7 @@ async def renew_token(self):
if not self.config.get("devicetoken"):
raise AuthError("Please register a device first")
headers = {"Authorization": f'Bearer {self.config["devicetoken"]}'}
response = await self.request("POST", USER_TOKEN_URL,
response = await self.request("POST", self.config['user_token_url'],
headers=headers, allow_renew=False)
if response.status_code < 400:
self.config.update({
Expand Down
14 changes: 10 additions & 4 deletions rmcl/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,19 @@
import enum

RFC3339Nano = "%Y-%m-%dT%H:%M:%SZ"

DEFAULT_TOKEN_SERVER_URL = "https://webapp-production-dot-remarkable-production.appspot.com"
DEFAULT_SERVICE_MGR_SERVER_URL = "https://service-manager-production-dot-remarkable-production.appspot.com"
DEVICE_REGISTER_URL = "https://my.remarkable.com/device/desktop/connect"

USER_AGENT = "rmcl <https://github.com/rschroll/rmcl>"
DEVICE_TOKEN_URL = "https://webapp-production-dot-remarkable-production.appspot.com/token/json/2/device/new"
USER_TOKEN_URL = "https://webapp-production-dot-remarkable-production.appspot.com/token/json/2/user/new"

DEVICE_TOKEN_PATH = "/token/json/2/device/new"
USER_TOKEN_PATH = "/token/json/2/user/new"
SERVICE_MGR_PATH = "/service/json/1/document-storage?environment=production&group=auth0%7C5a68dc51cb30df3877a1d7c4&apiVer=2" # noqa

USER_TOKEN_VALIDITY = 24 * 60 * 60 # Guessing one day
DEVICE_REGISTER_URL = "https://my.remarkable.com/connect/desktop"
DEVICE = "desktop-windows"
SERVICE_MGR_URL = "https://service-manager-production-dot-remarkable-production.appspot.com/service/json/1/document-storage?environment=production&group=auth0%7C5a68dc51cb30df3877a1d7c4&apiVer=2" # noqa
# Number of bytes of file to request to get file size of source doc
# For notes, the central directory runs 5 pages / KB, as a rough guess
NBYTES = 1024*100
Expand Down