authentik/website/netlify/functions/oci-proxy.js

76 lines
2.9 KiB
JavaScript

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}`);
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({}),
};
}