Extensions: send access token for HTTP requests

- The access token is used when connecting to the server.
- Mention an invalid access token as a possible cause for 403 errors.

Based on !122234.

Co-authored-by: Dalai Felinto <dalai@blender.org>
This commit is contained in:
Campbell Barton
2024-05-28 19:09:20 +10:00
parent a55c3f503c
commit 171319d9ef
4 changed files with 63 additions and 6 deletions

View File

@@ -170,6 +170,7 @@ def sync_status_generator(repos_notify):
directory=repo_item.directory,
remote_url=repo_item.remote_url,
online_user_agent=bl_extension_ops.online_user_agent_from_blender(),
access_token=repo_item.access_token if repo_item.use_access_token else "",
# Never sleep while there is no input, as this blocks Blender.
use_idle=False,
# Needed so the user can exit blender without warnings about a broken pipe.

View File

@@ -264,6 +264,7 @@ class RepoItem(NamedTuple):
remote_url: str
module: str
use_cache: bool
access_token: str
def repo_cache_store_refresh_from_prefs(include_disabled=False):
@@ -483,6 +484,7 @@ def extension_repos_read_index(index, *, include_disabled=False):
remote_url=remote_url,
module=repo_item.module,
use_cache=repo_item.use_cache,
access_token=repo_item.access_token if repo_item.use_access_token else "",
)
index_test += 1
return None
@@ -519,6 +521,7 @@ def extension_repos_read(*, include_disabled=False, use_active_only=False):
remote_url=remote_url,
module=repo_item.module,
use_cache=repo_item.use_cache,
access_token=repo_item.access_token if repo_item.use_access_token else "",
))
return result
@@ -1002,6 +1005,7 @@ class BlPkgRepoSync(Operator, _BlPkgCmdMixIn):
directory=directory,
remote_url=repo_item.remote_url,
online_user_agent=online_user_agent_from_blender(),
access_token=repo_item.access_token,
use_idle=is_modal,
)
)
@@ -1078,6 +1082,7 @@ class BlPkgRepoSyncAll(Operator, _BlPkgCmdMixIn):
directory=repo_item.directory,
remote_url=repo_item.remote_url,
online_user_agent=online_user_agent_from_blender(),
access_token=repo_item.access_token,
use_idle=is_modal,
))
@@ -1206,6 +1211,7 @@ class BlPkgPkgUpgradeAll(Operator, _BlPkgCmdMixIn):
remote_url=repo_item.remote_url,
pkg_id_sequence=pkg_id_sequence,
online_user_agent=online_user_agent_from_blender(),
access_token=repo_item.access_token,
use_cache=repo_item.use_cache,
use_idle=is_modal,
))
@@ -1305,6 +1311,7 @@ class BlPkgPkgInstallMarked(Operator, _BlPkgCmdMixIn):
remote_url=repo_item.remote_url,
pkg_id_sequence=pkg_id_sequence,
online_user_agent=online_user_agent_from_blender(),
access_token=repo_item.access_token,
use_cache=repo_item.use_cache,
use_idle=is_modal,
))
@@ -1822,6 +1829,7 @@ class BlPkgPkgInstall(Operator, _BlPkgCmdMixIn):
remote_url=repo_item.remote_url,
pkg_id_sequence=(pkg_id,),
online_user_agent=online_user_agent_from_blender(),
access_token=repo_item.access_token,
use_cache=repo_item.use_cache,
use_idle=is_modal,
)

View File

@@ -286,6 +286,7 @@ def repo_sync(
directory: str,
remote_url: str,
online_user_agent: str,
access_token: str,
use_idle: bool,
force_exit_ok: bool = False,
extension_override: str = "",
@@ -299,6 +300,7 @@ def repo_sync(
"--local-dir", directory,
"--remote-url", remote_url,
"--online-user-agent", online_user_agent,
"--access-token", access_token,
*(("--force-exit-ok",) if force_exit_ok else ()),
*(("--extension-override", extension_override) if extension_override else ()),
], use_idle=use_idle)
@@ -310,6 +312,7 @@ def repo_upgrade(
directory: str,
remote_url: str,
online_user_agent: str,
access_token: str,
use_idle: bool,
) -> Generator[InfoItemSeq, None, None]:
"""
@@ -321,6 +324,7 @@ def repo_upgrade(
"--local-dir", directory,
"--remote-url", remote_url,
"--online-user-agent", online_user_agent,
"--access-token", access_token,
], use_idle=use_idle)
yield [COMPLETE_ITEM]
@@ -367,6 +371,7 @@ def pkg_install(
remote_url: str,
pkg_id_sequence: Sequence[str],
online_user_agent: str,
access_token: str,
use_cache: bool,
use_idle: bool,
) -> Generator[InfoItemSeq, None, None]:
@@ -379,6 +384,7 @@ def pkg_install(
"--local-dir", directory,
"--remote-url", remote_url,
"--online-user-agent", online_user_agent,
"--access-token", access_token,
"--local-cache", str(int(use_cache)),
], use_idle=use_idle)
yield [COMPLETE_ITEM]

View File

@@ -906,8 +906,6 @@ class PathPatternMatch:
# URL Downloading
# Originally based on `urllib.request.urlretrieve`.
def url_retrieve_to_data_iter(
url: str,
*,
@@ -1079,6 +1077,10 @@ def url_retrieve_exception_as_message(
if isinstance(ex, TimeoutError):
return "{:s}: timeout ({:s}) reading {!r}!".format(prefix, str(ex), url)
if isinstance(ex, urllib.error.URLError):
if isinstance(ex, urllib.error.HTTPError):
if ex.code == 403:
return "{:s}: HTTP error (403) access token may be incorrect, reading {!r}!".format(prefix, url)
return "{:s}: HTTP error ({:s}) reading {!r}!".format(prefix, str(ex), url)
return "{:s}: URL error ({:s}) reading {!r}!".format(prefix, str(ex), url)
return "{:s}: unexpected error ({:s}) reading {!r}!".format(prefix, str(ex), url)
@@ -1498,7 +1500,7 @@ def pkg_manifest_is_valid_or_error_all(
# Standalone Utilities
def url_request_headers_create(*, accept_json: bool, user_agent: str) -> Dict[str, str]:
def url_request_headers_create(*, accept_json: bool, user_agent: str, access_token: str) -> Dict[str, str]:
headers = {}
if accept_json:
# Default for JSON requests this allows top-level URL's to be used.
@@ -1507,6 +1509,10 @@ def url_request_headers_create(*, accept_json: bool, user_agent: str) -> Dict[st
if user_agent:
# Typically: `Blender/4.2.0 (Linux x84_64; cycle=alpha)`.
headers["User-Agent"] = user_agent
if access_token:
headers["Authorization"] = "Bearer {:s}".format(access_token)
return headers
@@ -1624,6 +1630,7 @@ def repo_sync_from_remote(
remote_url: str,
local_dir: str,
online_user_agent: str,
access_token: str,
timeout_in_seconds: float,
extension_override: str,
) -> bool:
@@ -1659,7 +1666,11 @@ def repo_sync_from_remote(
for (read, size) in url_retrieve_to_filepath_iter_or_filesystem(
remote_json_url,
local_json_path_temp,
headers=url_request_headers_create(accept_json=True, user_agent=online_user_agent),
headers=url_request_headers_create(
accept_json=True,
user_agent=online_user_agent,
access_token=access_token,
),
chunk_size=CHUNK_SIZE_DEFAULT,
timeout_in_seconds=timeout_in_seconds,
):
@@ -1937,6 +1948,19 @@ def generic_arg_online_user_agent(subparse: argparse.ArgumentParser) -> None:
)
def generic_arg_access_token(subparse: argparse.ArgumentParser) -> None:
subparse.add_argument(
"--access-token",
dest="access_token",
type=str,
help=(
"Access token for remote repositories which require authorized access."
),
default="",
required=False,
)
def generic_arg_timeout(subparse: argparse.ArgumentParser) -> None:
subparse.add_argument(
"--timeout",
@@ -2077,6 +2101,7 @@ class subcmd_client:
msg_fn: MessageFn,
remote_url: str,
online_user_agent: str,
access_token: str,
timeout_in_seconds: float,
) -> bool:
remote_json_url = remote_url_get(remote_url)
@@ -2086,7 +2111,11 @@ class subcmd_client:
result = io.BytesIO()
for block in url_retrieve_to_data_iter_or_filesystem(
remote_json_url,
headers=url_request_headers_create(accept_json=True, user_agent=online_user_agent),
headers=url_request_headers_create(
accept_json=True,
user_agent=online_user_agent,
access_token=access_token,
),
chunk_size=CHUNK_SIZE_DEFAULT,
timeout_in_seconds=timeout_in_seconds,
):
@@ -2122,6 +2151,7 @@ class subcmd_client:
remote_url: str,
local_dir: str,
online_user_agent: str,
access_token: str,
timeout_in_seconds: float,
force_exit_ok: bool,
extension_override: str,
@@ -2134,6 +2164,7 @@ class subcmd_client:
remote_url=remote_url,
local_dir=local_dir,
online_user_agent=online_user_agent,
access_token=access_token,
timeout_in_seconds=timeout_in_seconds,
extension_override=extension_override,
)
@@ -2281,6 +2312,7 @@ class subcmd_client:
local_cache: bool,
packages: Sequence[str],
online_user_agent: str,
access_token: str,
timeout_in_seconds: float,
) -> bool:
# Extract...
@@ -2375,7 +2407,11 @@ class subcmd_client:
with open(filepath_local_cache_archive, "wb") as fh_cache:
for block in url_retrieve_to_data_iter_or_filesystem(
filepath_remote_archive,
headers=url_request_headers_create(accept_json=False, user_agent=online_user_agent),
headers=url_request_headers_create(
accept_json=False,
user_agent=online_user_agent,
access_token=access_token,
),
chunk_size=CHUNK_SIZE_DEFAULT,
timeout_in_seconds=timeout_in_seconds,
):
@@ -2937,6 +2973,7 @@ def argparse_create_client_list(subparsers: "argparse._SubParsersAction[argparse
generic_arg_remote_url(subparse)
generic_arg_local_dir(subparse)
generic_arg_online_user_agent(subparse)
generic_arg_access_token(subparse)
generic_arg_output_type(subparse)
generic_arg_timeout(subparse)
@@ -2946,6 +2983,7 @@ def argparse_create_client_list(subparsers: "argparse._SubParsersAction[argparse
msg_fn_from_args(args),
args.remote_url,
online_user_agent=args.online_user_agent,
access_token=args.access_token,
timeout_in_seconds=args.timeout,
),
)
@@ -2965,6 +3003,7 @@ def argparse_create_client_sync(subparsers: "argparse._SubParsersAction[argparse
generic_arg_remote_url(subparse)
generic_arg_local_dir(subparse)
generic_arg_online_user_agent(subparse)
generic_arg_access_token(subparse)
generic_arg_output_type(subparse)
generic_arg_timeout(subparse)
@@ -2977,6 +3016,7 @@ def argparse_create_client_sync(subparsers: "argparse._SubParsersAction[argparse
remote_url=args.remote_url,
local_dir=args.local_dir,
online_user_agent=args.online_user_agent,
access_token=args.access_token,
timeout_in_seconds=args.timeout,
force_exit_ok=args.force_exit_ok,
extension_override=args.extension_override,
@@ -3018,6 +3058,7 @@ def argparse_create_client_install(subparsers: "argparse._SubParsersAction[argpa
generic_arg_local_dir(subparse)
generic_arg_local_cache(subparse)
generic_arg_online_user_agent(subparse)
generic_arg_access_token(subparse)
generic_arg_output_type(subparse)
generic_arg_timeout(subparse)
@@ -3030,6 +3071,7 @@ def argparse_create_client_install(subparsers: "argparse._SubParsersAction[argpa
local_cache=args.local_cache,
packages=args.packages.split(","),
online_user_agent=args.online_user_agent,
access_token=args.access_token,
timeout_in_seconds=args.timeout,
),
)