76 lines
		
	
	
		
			2.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			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({}),
 | 
						|
    };
 | 
						|
}
 |