diff --git a/website/netlify.toml b/website/netlify.toml index 1b07e6453..431b54756 100644 --- a/website/netlify.toml +++ b/website/netlify.toml @@ -1,11 +1,18 @@ [[redirects]] - from = "/v2/" - to = "https://ghcr.registry.beryju.org/v2/" + from = "/*" + to = "/.netlify/functions/go-get" + status = 200 + force = true + query = {go-get = "1"} + +[[redirects]] + from = "/v2" + to = "/.netlify/functions/oci-proxy" status = 200 force = true [[redirects]] from = "/v2/*" - to = "https://ghcr.registry.beryju.org/v2/goauthentik/:splat" + to = "https://ghcr.io/v2/goauthentik/:splat" status = 200 force = true diff --git a/website/netlify/functions/go-get.js b/website/netlify/functions/go-get.js new file mode 100644 index 000000000..c1dbe3471 --- /dev/null +++ b/website/netlify/functions/go-get.js @@ -0,0 +1,23 @@ +const gitHubNamespace = "goauthentik.io"; + +exports.handler = async function (event, context) { + let repo = ""; + switch (event.path) { + case "/": + repo = "/authentik.git"; + break; + case "/api": + repo = "/client-go.git"; + break; + default: + repo = `${event.path}.git`; + break; + } + return { + statusCode: 200, + headers: { + "content-type": "text/html", + }, + body: `` + }; +} diff --git a/website/netlify/functions/oci-proxy.js b/website/netlify/functions/oci-proxy.js new file mode 100644 index 000000000..276a44a1c --- /dev/null +++ b/website/netlify/functions/oci-proxy.js @@ -0,0 +1,75 @@ +const config = { + namespace: "goauthentik/", + // Settings for GHCR + registryTokenEndpoint: "https://ghcr.io/token", + registryService: "ghcr.io", + // Settings for Harbor + // registryTokenEndpoint: "https://docker.beryju.org/service/token", + // registryService: "harbor-registry", +}; + +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} body '${tokenResult}'`) + 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({}), + }; +}