const config = { namespace: "goauthentik/", registryTokenEndpoint: "https://ghcr.io/token", registryService: "ghcr.io", }; async function getToken(event) { const fetch = await import("node-fetch"); const querystring = await import("querystring"); let scope = event.queryStringParameters["scope"]; let tokenParams = { service: config.registryService, }; delete event.headers.host; let forwardHeaders = event.headers; if (scope && scope.includes(":")) { const repo = scope.split(":")[1]; console.debug(`oci-proxy[token]: original scope: ${scope}`); scope = `repository:${config.namespace}${repo}:pull`; console.debug(`oci-proxy[token]: rewritten scope: ${scope}`); tokenParams["scope"] = scope; // We only need to forward headers for authentication requests forwardHeaders = {}; } else { console.debug(`oci-proxy[token]: no scope`); // For non-scoped requests, we need to forward some URL parameters ["account", "client_id", "offline_token", "token"].forEach((param) => { tokenParams[param] = event.queryStringParameters[param]; }); } const tokenUrl = `${config.registryTokenEndpoint}?${querystring.stringify( tokenParams, )}`; console.debug(`oci-proxy[token]: final URL to fetch: ${tokenUrl}`); const tokenRes = await fetch.default(tokenUrl, { headers: forwardHeaders, }); const tokenResult = await tokenRes.text(); console.debug(`oci-proxy[token]: Status ${tokenRes.status}`); return { statusCode: tokenRes.status, body: tokenResult, }; } exports.handler = async function (event, context) { console.debug(`oci-proxy: URL ${event.httpMethod} ${event.rawUrl}`); if (event.queryStringParameters.hasOwnProperty("token")) { console.debug("oci-proxy: handler=token proxy"); return await getToken(event); } if ( event.headers.authorization && event.headers.authorization.startsWith("Bearer ") ) { console.debug("oci-proxy: authenticated root handler, returning 200"); return { statusCode: 200, headers: { "Docker-Distribution-API-Version": "registry/2.0", "content-type": "application/json", }, body: JSON.stringify({}), }; } console.debug( "oci-proxy: root handler, returning 401 with www-authenticate", ); return { statusCode: 401, headers: { "www-authenticate": `Bearer realm="https://${event.headers.host}/v2?token",service="${event.headers.host}",scope="repository:user/image:pull"`, "Docker-Distribution-API-Version": "registry/2.0", "content-type": "application/json", }, body: JSON.stringify({}), }; };