Skip to content

Commit

Permalink
Prevent keys from leaking across registries
Browse files Browse the repository at this point in the history
Signed-off-by: Prabhu Subramanian <[email protected]>
  • Loading branch information
prabhu committed Nov 20, 2023
1 parent 6d2ebe2 commit f0a48bc
Showing 1 changed file with 51 additions and 32 deletions.
83 changes: 51 additions & 32 deletions docker.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,14 @@ export const getOnlyDirs = (srcpath, dirName) => {
].filter((d) => d.endsWith(dirName));
};

const getDefaultOptions = () => {
const getDefaultOptions = (forRegistry) => {
let authTokenSet = false;
if (!forRegistry && process.env.DOCKER_SERVER_ADDRESS) {
forRegistry = process.env.DOCKER_SERVER_ADDRESS;
}
if (forRegistry) {
forRegistry = forRegistry.replace("http://", "").replace("https://", "");
}
const opts = {
enableUnixSockets: true,
throwHttpErrors: true,
Expand All @@ -129,11 +135,7 @@ const getDefaultOptions = () => {
if (configJson.auths) {
// Check if there are hardcoded tokens
for (const serverAddress of Object.keys(configJson.auths)) {
if (
process.env.DOCKER_SERVER_ADDRESS &&
process.env.DOCKER_SERVER_ADDRESS.trim().length &&
process.env.DOCKER_SERVER_ADDRESS !== serverAddress
) {
if (forRegistry && forRegistry !== serverAddress) {
continue;
}
if (configJson.auths[serverAddress].auth) {
Expand All @@ -150,11 +152,7 @@ const getDefaultOptions = () => {
} else if (configJson.credHelpers) {
// Support for credential helpers
for (const serverAddress of Object.keys(configJson.credHelpers)) {
if (
process.env.DOCKER_SERVER_ADDRESS &&
process.env.DOCKER_SERVER_ADDRESS.trim().length &&
process.env.DOCKER_SERVER_ADDRESS !== serverAddress
) {
if (forRegistry && forRegistry !== serverAddress) {
continue;
}
if (configJson.credHelpers[serverAddress]) {
Expand Down Expand Up @@ -191,15 +189,12 @@ const getDefaultOptions = () => {
process.env.DOCKER_USER &&
process.env.DOCKER_PASSWORD &&
process.env.DOCKER_EMAIL &&
process.env.DOCKER_SERVER_ADDRESS
forRegistry
) {
const authPayload = {
username: process.env.DOCKER_USER,
email: process.env.DOCKER_EMAIL,
serveraddress: process.env.DOCKER_SERVER_ADDRESS.replace(
"http://",
""
).replace("https://", "")
serveraddress: forRegistry
};
if (process.env.DOCKER_USER === "<token>") {
authPayload.IdentityToken = process.env.DOCKER_PASSWORD;
Expand Down Expand Up @@ -264,11 +259,11 @@ const getDefaultOptions = () => {
return opts;
};

export const getConnection = async (options) => {
export const getConnection = async (options, forRegistry) => {
if (isContainerd) {
return undefined;
} else if (!dockerConn) {
const defaultOptions = getDefaultOptions();
const defaultOptions = getDefaultOptions(forRegistry);
const opts = Object.assign(
{},
{
Expand Down Expand Up @@ -360,8 +355,8 @@ export const getConnection = async (options) => {
return dockerConn;
};

export const makeRequest = async (path, method = "GET") => {
const client = await getConnection();
export const makeRequest = async (path, method = "GET", forRegistry) => {
const client = await getConnection({}, forRegistry);
if (!client) {
return undefined;
}
Expand Down Expand Up @@ -451,7 +446,7 @@ export const parseImageName = (fullImageName) => {
export const getImage = async (fullImageName) => {
let localData = undefined;
let pullData = undefined;
const { repo, tag, digest } = parseImageName(fullImageName);
const { registry, repo, tag, digest } = parseImageName(fullImageName);
let repoWithTag = `${repo}:${tag !== "" ? tag : ":latest"}`;
// Fetch only the latest tag if none is specified
if (tag === "" && digest === "") {
Expand Down Expand Up @@ -505,18 +500,26 @@ export const getImage = async (fullImageName) => {
}
}
try {
localData = await makeRequest(`images/${repoWithTag}/json`);
localData = await makeRequest(
`images/${repoWithTag}/json`,
"GET",
registry
);
if (localData) {
return localData;
}
} catch (err) {
// ignore
}
try {
localData = await makeRequest(`images/${repo}/json`);
localData = await makeRequest(`images/${repo}/json`, "GET", registry);
} catch (err) {
try {
localData = await makeRequest(`images/${fullImageName}/json`);
localData = await makeRequest(
`images/${fullImageName}/json`,
"GET",
registry
);
if (localData) {
return localData;
}
Expand All @@ -532,7 +535,8 @@ export const getImage = async (fullImageName) => {
try {
pullData = await makeRequest(
`images/create?fromImage=${fullImageName}`,
"POST"
"POST",
registry
);
if (
pullData &&
Expand All @@ -554,7 +558,8 @@ export const getImage = async (fullImageName) => {
}
pullData = await makeRequest(
`images/create?fromImage=${repoWithTag}`,
"POST"
"POST",
registry
);
} catch (err) {
// continue regardless of error
Expand All @@ -564,7 +569,11 @@ export const getImage = async (fullImageName) => {
if (DEBUG_MODE) {
console.log(`Trying with ${repoWithTag}`);
}
localData = await makeRequest(`images/${repoWithTag}/json`);
localData = await makeRequest(
`images/${repoWithTag}/json`,
"GET",
registry
);
if (localData) {
return localData;
}
Expand All @@ -573,7 +582,7 @@ export const getImage = async (fullImageName) => {
if (DEBUG_MODE) {
console.log(`Trying with ${repo}`);
}
localData = await makeRequest(`images/${repo}/json`);
localData = await makeRequest(`images/${repo}/json`, "GET", registry);
if (localData) {
return localData;
}
Expand All @@ -584,7 +593,11 @@ export const getImage = async (fullImageName) => {
if (DEBUG_MODE) {
console.log(`Trying with ${fullImageName}`);
}
localData = await makeRequest(`images/${fullImageName}/json`);
localData = await makeRequest(
`images/${fullImageName}/json`,
"GET",
registry
);
} catch (err) {
// continue regardless of error
}
Expand Down Expand Up @@ -804,7 +817,7 @@ export const exportImage = async (fullImageName) => {
if (!localData) {
return undefined;
}
const { tag, digest } = parseImageName(fullImageName);
const { registry, tag, digest } = parseImageName(fullImageName);
// Fetch only the latest tag if none is specified
if (tag === "" && digest === "") {
fullImageName = fullImageName + ":latest";
Expand Down Expand Up @@ -842,10 +855,16 @@ export const exportImage = async (fullImageName) => {
}
}
} else {
const client = await getConnection();
const client = await getConnection({}, registry);
try {
if (DEBUG_MODE) {
console.log(`About to export image ${fullImageName} to ${tempDir}`);
if (registry && registry.trim().length) {
console.log(
`About to export image ${fullImageName} from ${registry} to ${tempDir}`
);
} else {
console.log(`About to export image ${fullImageName} to ${tempDir}`);
}
}
await stream.pipeline(
client.stream(`images/${fullImageName}/get`),
Expand Down

0 comments on commit f0a48bc

Please sign in to comment.