diff --git a/common/arg.cpp b/common/arg.cpp index 54df2df87276c..65ee2c59eeb6f 100644 --- a/common/arg.cpp +++ b/common/arg.cpp @@ -813,11 +813,74 @@ std::pair> common_remote_get_content(const std::string & // Docker registry functions // +// Read Docker credentials from ~/.docker/config.json +static std::string common_docker_get_credentials() { + const char * home = std::getenv("HOME"); + if (!home) { +#ifdef _WIN32 + home = std::getenv("USERPROFILE"); + if (!home) { + return ""; + } +#else + return ""; +#endif + } + + std::filesystem::path config_path = std::filesystem::path(home) / ".docker" / "config.json"; + std::ifstream config_file(config_path); + if (!config_file.is_open()) { + return ""; + } + + try { + // Check file size to prevent memory exhaustion (Docker config should be small) + config_file.seekg(0, std::ios::end); + const auto file_size = config_file.tellg(); + config_file.seekg(0, std::ios::beg); + + if (file_size > 1024 * 1024) { // Limit to 1MB + LOG_DBG("%s: Docker config file too large: %ld bytes\n", __func__, static_cast(file_size)); + return ""; + } + + nlohmann::ordered_json config; + config_file >> config; + + // Docker Hub registry can be listed as "https://index.docker.io/v1/" or similar + std::vector registry_urls = { + "https://index.docker.io/v1/", + "index.docker.io", + "docker.io", + }; + + for (const auto & registry_url : registry_urls) { + if (config.contains("auths") && config["auths"].contains(registry_url)) { + const auto & auth_entry = config["auths"][registry_url]; + if (auth_entry.contains("auth") && auth_entry["auth"].is_string()) { + return auth_entry["auth"].get(); + } + } + } + } catch (const std::exception & e) { + LOG_DBG("%s: Failed to parse Docker config at %s: %s\n", __func__, config_path.string().c_str(), e.what()); + } + + return ""; +} + static std::string common_docker_get_token(const std::string & repo) { std::string url = "https://auth.docker.io/token?service=registry.docker.io&scope=repository:" + repo + ":pull"; common_remote_params params; - auto res = common_remote_get_content(url, params); + + // Add Docker credentials if available + std::string credentials = common_docker_get_credentials(); + if (!credentials.empty()) { + params.headers.push_back("Authorization: Basic " + credentials); + } + + auto res = common_remote_get_content(url, params); if (res.first != 200) { throw std::runtime_error("Failed to get Docker registry token, HTTP code: " + std::to_string(res.first));