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