|
49 | 49 | #pragma GCC diagnostic pop |
50 | 50 | #endif |
51 | 51 |
|
| 52 | +#ifdef verify |
| 53 | + #define JWT_HAS_VERIFY_MACRO |
| 54 | + #define OLD_VERIFY verify |
| 55 | + #undef verify |
| 56 | +#endif |
| 57 | + |
| 58 | +#include "jwt-cpp/jwt.h" |
| 59 | +#include "nlohmann/json.hpp" |
| 60 | + |
| 61 | +#ifdef JWT_HAS_VERIFY_MACRO |
| 62 | + //Force an error if verify macro is used in any of the following code |
| 63 | + #undef verify |
| 64 | +#endif |
| 65 | + |
52 | 66 | #ifdef _USE_OPENSSL |
53 | 67 | #include <opensslcommon.hpp> |
54 | 68 | #include <openssl/x509v3.h> |
@@ -2427,3 +2441,70 @@ void maskSecret(StringBuffer & maskedSecret, const char * originalSecret, unsign |
2427 | 2441 | maskedSecret.append(originalSecret[i]); |
2428 | 2442 | } |
2429 | 2443 | } |
| 2444 | + |
| 2445 | +std::string generateGithubIAT(const char * appId, const char * appKey, const char * installationId) |
| 2446 | +{ |
| 2447 | + try |
| 2448 | + { |
| 2449 | + auto now = std::chrono::system_clock::now(); |
| 2450 | + auto token = jwt::create() |
| 2451 | + .set_issuer(appId) |
| 2452 | + .set_issued_at(now) |
| 2453 | + .set_expires_at(now + std::chrono::minutes(10)) |
| 2454 | + .sign(jwt::algorithm::rs256("", appKey)); |
| 2455 | + |
| 2456 | + httplib::SSLClient cli("api.github.com"); |
| 2457 | + cli.set_bearer_token_auth(token.c_str()); |
| 2458 | + cli.set_default_headers({ |
| 2459 | + {"User-Agent", "ECL-Compiler/1.0"}, |
| 2460 | + {"Accept", "application/vnd.github.v3+json"} |
| 2461 | + }); |
| 2462 | + |
| 2463 | + // Generate Access Token |
| 2464 | + std::string tokenPath = "/app/installations/"; |
| 2465 | + tokenPath += installationId; |
| 2466 | + tokenPath += "/access_tokens"; |
| 2467 | + auto postRes = cli.Post(tokenPath.c_str()); |
| 2468 | + if (!postRes || postRes->status != 201) |
| 2469 | + { |
| 2470 | + DBGLOG("Failed to generate GitHub IAT. HTTP status: %d", postRes ? postRes->status : -1); |
| 2471 | + return ""; |
| 2472 | + } |
| 2473 | + |
| 2474 | + auto tokenJson = nlohmann::json::parse(postRes->body); |
| 2475 | + return tokenJson["token"].get<std::string>(); |
| 2476 | + } |
| 2477 | + catch (const std::exception& e) |
| 2478 | + { |
| 2479 | + DBGLOG("Exception generating GitHub IAT: %s", e.what()); |
| 2480 | + } |
| 2481 | + |
| 2482 | + return ""; |
| 2483 | +} |
| 2484 | + |
| 2485 | +IFile * getFileWithGitAccessToken(const char * gitUser) |
| 2486 | +{ |
| 2487 | + Owned<const IPropertyTree> secret = getSecret("git", gitUser); |
| 2488 | + if (!secret) |
| 2489 | + { |
| 2490 | + DBGLOG("No secret found for git user %s", gitUser); |
| 2491 | + return nullptr; |
| 2492 | + } |
| 2493 | + |
| 2494 | + MemoryBuffer gitKey; |
| 2495 | + if (getSecretKeyValue(gitKey, secret, "password")) |
| 2496 | + return writeToProtectedTempFile("eclcc", "git", gitKey.length(), gitKey.toByteArray()); |
| 2497 | + |
| 2498 | + StringBuffer appId, appKey, installationId; |
| 2499 | + if (getSecretKeyValue(appId, secret, "appid") && getSecretKeyValue(appKey, secret, "appkey") && getSecretKeyValue(installationId, secret, "installationid")) |
| 2500 | + { |
| 2501 | + // Generate an Installation Access Token (IAT) from the App ID, Private Key, and Installation ID |
| 2502 | + std::string iat = generateGithubIAT(appId.str(), appKey.str(), installationId.str()); |
| 2503 | + if (!iat.empty()) |
| 2504 | + return writeToProtectedTempFile("eclcc", "git", iat.length(), iat.c_str()); |
| 2505 | + return nullptr; |
| 2506 | + } |
| 2507 | + |
| 2508 | + DBGLOG("Secret doesn't contain password or github app credentials for git user %s", gitUser); |
| 2509 | + return nullptr; |
| 2510 | +} |
0 commit comments