Skip to content

Commit 7fbc589

Browse files
authored
Fix DockerHub library images default pulling case (ciiiii#20)
1 parent 109f2d4 commit 7fbc589

File tree

1 file changed

+30
-6
lines changed

1 file changed

+30
-6
lines changed

src/index.js

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@ addEventListener("fetch", (event) => {
33
event.respondWith(handleRequest(event.request));
44
});
55

6+
const dockerHub = "https://registry-1.docker.io";
7+
68
const routes = {
7-
"docker.libcuda.so": "https://registry-1.docker.io",
9+
"docker.libcuda.so": dockerHub,
810
"quay.libcuda.so": "https://quay.io",
911
"gcr.libcuda.so": "https://gcr.io",
1012
"k8s-gcr.libcuda.so": "https://k8s.gcr.io",
@@ -36,6 +38,7 @@ async function handleRequest(request) {
3638
}
3739
);
3840
}
41+
const isDockerHub = upstream == dockerHub;
3942
const authorization = request.headers.get("Authorization");
4043
if (url.pathname == "/v2/") {
4144
const newUrl = new URL(upstream + "/v2/");
@@ -84,7 +87,28 @@ async function handleRequest(request) {
8487
return resp;
8588
}
8689
const wwwAuthenticate = parseAuthenticate(authenticateStr);
87-
return await fetchToken(wwwAuthenticate, url.searchParams, authorization);
90+
let scope = url.searchParams.get("scope");
91+
// autocomplete repo part into scope for DockerHub library images
92+
// Example: repository:busybox:pull => repository:library/busybox:pull
93+
if (scope && isDockerHub) {
94+
let scopeParts = scope.split(":");
95+
if (scopeParts.length == 3 && !scopeParts[1].includes("/")) {
96+
scopeParts[1] = "library/" + scopeParts[1];
97+
scope = scopeParts.join(":");
98+
}
99+
}
100+
return await fetchToken(wwwAuthenticate, scope, authorization);
101+
}
102+
// redirect for DockerHub library images
103+
// Example: /v2/busybox/manifests/latest => /v2/library/busybox/manifests/latest
104+
if (isDockerHub) {
105+
const pathParts = url.pathname.split("/");
106+
if (pathParts.length == 5) {
107+
pathParts.splice(2, 0, "library");
108+
const redirectUrl = new URL(url);
109+
redirectUrl.pathname = pathParts.join("/");
110+
return Response.redirect(redirectUrl, 301);
111+
}
88112
}
89113
// foward requests
90114
const newUrl = new URL(upstream + url.pathname);
@@ -101,7 +125,7 @@ function parseAuthenticate(authenticateStr) {
101125
// match strings after =" and before "
102126
const re = /(?<=\=")(?:\\.|[^"\\])*(?=")/g;
103127
const matches = authenticateStr.match(re);
104-
if (matches === null || matches.length < 2) {
128+
if (matches == null || matches.length < 2) {
105129
throw new Error(`invalid Www-Authenticate Header: ${authenticateStr}`);
106130
}
107131
return {
@@ -110,13 +134,13 @@ function parseAuthenticate(authenticateStr) {
110134
};
111135
}
112136

113-
async function fetchToken(wwwAuthenticate, searchParams, authorization) {
137+
async function fetchToken(wwwAuthenticate, scope, authorization) {
114138
const url = new URL(wwwAuthenticate.realm);
115139
if (wwwAuthenticate.service.length) {
116140
url.searchParams.set("service", wwwAuthenticate.service);
117141
}
118-
if (searchParams.get("scope")) {
119-
url.searchParams.set("scope", searchParams.get("scope"));
142+
if (scope) {
143+
url.searchParams.set("scope", scope);
120144
}
121145
headers = new Headers();
122146
if (authorization) {

0 commit comments

Comments
 (0)