switch to http basic auth

This commit is contained in:
James Brumond 2023-08-18 22:47:09 -07:00
parent 09228f4f08
commit ac5141c79a
Signed by: james
GPG Key ID: E8F2FC44BAA3357A
3 changed files with 205 additions and 179 deletions

191
dist/index.js vendored
View File

@ -2918,18 +2918,22 @@ function parse_tags(tags) {
async function get_manifest(input) {
const path = `/v2/${input.manifest.image}/manifests/${input.manifest.tag}`;
let { status, headers, body } = await http_req('GET', input.registry_url + path, {
const req_headers = {
accept: manifest_media_type,
});
};
if (status === 401 && headers['www-authenticate']) {
await get_token(headers['www-authenticate'], input);
http_basic_auth(req_headers, input);
let { status, headers, body } = await http_req('GET', input.registry_url + path, req_headers);
// if (status === 401 && headers['www-authenticate']) {
// await get_token(headers['www-authenticate'], input);
({ status, headers, body } = await http_req('GET', input.registry_url + path, {
accept: manifest_media_type,
authorization: `Bearer ${input.token}`,
}));
}
// ({ status, headers, body } = await http_req('GET', input.registry_url + path, {
// accept: manifest_media_type,
// authorization: `Bearer ${input.token}`,
// }));
// }
if (status !== 200) {
console.error('get manifest response', { status, headers, body });
@ -2945,9 +2949,11 @@ async function put_manifest(new_tag, manifest, input) {
'content-type': manifest_media_type,
};
if (input.token) {
req_headers.authorization = `Bearer ${input.token}`;
}
http_basic_auth(req_headers, input);
// if (input.token) {
// req_headers.authorization = `Bearer ${input.token}`;
// }
const { status, headers, body } = await http_req('PUT', input.registry_url + path, req_headers, manifest);
@ -2957,40 +2963,47 @@ async function put_manifest(new_tag, manifest, input) {
}
}
async function get_token(www_authenticate, input) {
const params = parse_www_authenticate(www_authenticate);
if (! input.username || ! input.password) {
throw new Error('registry requested authentication, but not credentials were provided');
}
const query_params = {
service: params.service,
scope: `repository:${input.manifest.image}:pull,push`,
grant_type: 'password',
username: input.username,
password: input.password,
};
const { status, headers, body } = await http_req('GET', params.realm + '?' + querystring.stringify(query_params), {
'content-type': 'application/x-www-form-urlencoded',
});
if (status !== 200) {
console.error('get token response', { status, headers, body });
throw new Error('error response from get token request');
}
try {
const { token } = JSON.parse(body);
input.token = token;
}
catch (error) {
throw new Error('invalid response from get token request');
function http_basic_auth(headers, input) {
if (input.username) {
const credentials = Buffer.from(`${input.username}:${input.password}`, 'utf8').toString('base64');
headers.authorization = `Basic ${credentials}`;
}
}
// async function get_token(www_authenticate, input) {
// const params = parse_www_authenticate(www_authenticate);
// if (! input.username || ! input.password) {
// throw new Error('registry requested authentication, but not credentials were provided');
// }
// const query_params = {
// service: params.service,
// scope: `repository:${input.manifest.image}:pull,push`,
// grant_type: 'password',
// username: input.username,
// password: input.password,
// };
// const { status, headers, body } = await http_req('GET', params.realm + '?' + querystring.stringify(query_params), {
// 'content-type': 'application/x-www-form-urlencoded',
// });
// if (status !== 200) {
// console.error('get token response', { status, headers, body });
// throw new Error('error response from get token request');
// }
// try {
// const { token } = JSON.parse(body);
// input.token = token;
// }
// catch (error) {
// throw new Error('invalid response from get token request');
// }
// }
async function http_req(method, url_str, headers, body) {
const url = new URL(url_str);
const make_request
@ -3055,68 +3068,68 @@ async function http_req(method, url_str, headers, body) {
});
}
function parse_www_authenticate(www_authenticate) {
if (! www_authenticate.startsWith('Bearer ')) {
throw new Error('invalid www-authenticate header (no "Bearer " prefix)');
}
// function parse_www_authenticate(www_authenticate) {
// if (! www_authenticate.startsWith('Bearer ')) {
// throw new Error('invalid www-authenticate header (no "Bearer " prefix)');
// }
let remaining = www_authenticate.slice(7);
const parameters = Object.create(null);
// let remaining = www_authenticate.slice(7);
// const parameters = Object.create(null);
while (remaining) {
const eq_index = remaining.indexOf('=');
// while (remaining) {
// const eq_index = remaining.indexOf('=');
if (eq_index < 0) {
parameters[remaining] = '';
break;
}
// if (eq_index < 0) {
// parameters[remaining] = '';
// break;
// }
const key = remaining.slice(0, eq_index);
remaining = remaining.slice(eq_index + 1);
// const key = remaining.slice(0, eq_index);
// remaining = remaining.slice(eq_index + 1);
if (! remaining) {
parameters[key] = '';
break;
}
// if (! remaining) {
// parameters[key] = '';
// break;
// }
if (remaining[0] === '"') {
const close_index = remaining.slice(1).indexOf('"');
// if (remaining[0] === '"') {
// const close_index = remaining.slice(1).indexOf('"');
if (close_index < 0) {
throw new Error('invalid www-authenticate header (unclosed quotes)');
}
// if (close_index < 0) {
// throw new Error('invalid www-authenticate header (unclosed quotes)');
// }
parameters[key] = remaining.slice(1, close_index + 1);
remaining = remaining.slice(close_index + 2);
// parameters[key] = remaining.slice(1, close_index + 1);
// remaining = remaining.slice(close_index + 2);
if (remaining && remaining[0] !== ',') {
throw new Error('invalid www-authenticate header (expected comma after closing quote)');
}
// if (remaining && remaining[0] !== ',') {
// throw new Error('invalid www-authenticate header (expected comma after closing quote)');
// }
remaining = remaining.slice(1);
}
// remaining = remaining.slice(1);
// }
else {
const comma_index = remaining.indexOf(',');
// else {
// const comma_index = remaining.indexOf(',');
if (comma_index < 0) {
parameters[key] = remaining;
break;
}
// if (comma_index < 0) {
// parameters[key] = remaining;
// break;
// }
parameters[key] = remaining.slice(1, comma_index);
remaining = remaining.slice(comma_index + 1);
}
}
// parameters[key] = remaining.slice(1, comma_index);
// remaining = remaining.slice(comma_index + 1);
// }
// }
const { realm, service, scope } = parameters;
// const { realm, service, scope } = parameters;
if (! realm || ! service || ! scope) {
throw new Error('invalid www-authenticate header (missing "realm", "service", or "scope")');
}
// if (! realm || ! service || ! scope) {
// throw new Error('invalid www-authenticate header (missing "realm", "service", or "scope")');
// }
return parameters;
}
// return parameters;
// }
})();

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

191
index.js
View File

@ -57,18 +57,22 @@ function parse_tags(tags) {
async function get_manifest(input) {
const path = `/v2/${input.manifest.image}/manifests/${input.manifest.tag}`;
let { status, headers, body } = await http_req('GET', input.registry_url + path, {
const req_headers = {
accept: manifest_media_type,
});
};
if (status === 401 && headers['www-authenticate']) {
await get_token(headers['www-authenticate'], input);
http_basic_auth(req_headers, input);
let { status, headers, body } = await http_req('GET', input.registry_url + path, req_headers);
// if (status === 401 && headers['www-authenticate']) {
// await get_token(headers['www-authenticate'], input);
({ status, headers, body } = await http_req('GET', input.registry_url + path, {
accept: manifest_media_type,
authorization: `Bearer ${input.token}`,
}));
}
// ({ status, headers, body } = await http_req('GET', input.registry_url + path, {
// accept: manifest_media_type,
// authorization: `Bearer ${input.token}`,
// }));
// }
if (status !== 200) {
console.error('get manifest response', { status, headers, body });
@ -84,9 +88,11 @@ async function put_manifest(new_tag, manifest, input) {
'content-type': manifest_media_type,
};
if (input.token) {
req_headers.authorization = `Bearer ${input.token}`;
}
http_basic_auth(req_headers, input);
// if (input.token) {
// req_headers.authorization = `Bearer ${input.token}`;
// }
const { status, headers, body } = await http_req('PUT', input.registry_url + path, req_headers, manifest);
@ -96,40 +102,47 @@ async function put_manifest(new_tag, manifest, input) {
}
}
async function get_token(www_authenticate, input) {
const params = parse_www_authenticate(www_authenticate);
if (! input.username || ! input.password) {
throw new Error('registry requested authentication, but not credentials were provided');
}
const query_params = {
service: params.service,
scope: `repository:${input.manifest.image}:pull,push`,
grant_type: 'password',
username: input.username,
password: input.password,
};
const { status, headers, body } = await http_req('GET', params.realm + '?' + querystring.stringify(query_params), {
'content-type': 'application/x-www-form-urlencoded',
});
if (status !== 200) {
console.error('get token response', { status, headers, body });
throw new Error('error response from get token request');
}
try {
const { token } = JSON.parse(body);
input.token = token;
}
catch (error) {
throw new Error('invalid response from get token request');
function http_basic_auth(headers, input) {
if (input.username) {
const credentials = Buffer.from(`${input.username}:${input.password}`, 'utf8').toString('base64');
headers.authorization = `Basic ${credentials}`;
}
}
// async function get_token(www_authenticate, input) {
// const params = parse_www_authenticate(www_authenticate);
// if (! input.username || ! input.password) {
// throw new Error('registry requested authentication, but not credentials were provided');
// }
// const query_params = {
// service: params.service,
// scope: `repository:${input.manifest.image}:pull,push`,
// grant_type: 'password',
// username: input.username,
// password: input.password,
// };
// const { status, headers, body } = await http_req('GET', params.realm + '?' + querystring.stringify(query_params), {
// 'content-type': 'application/x-www-form-urlencoded',
// });
// if (status !== 200) {
// console.error('get token response', { status, headers, body });
// throw new Error('error response from get token request');
// }
// try {
// const { token } = JSON.parse(body);
// input.token = token;
// }
// catch (error) {
// throw new Error('invalid response from get token request');
// }
// }
async function http_req(method, url_str, headers, body) {
const url = new URL(url_str);
const make_request
@ -194,65 +207,65 @@ async function http_req(method, url_str, headers, body) {
});
}
function parse_www_authenticate(www_authenticate) {
if (! www_authenticate.startsWith('Bearer ')) {
throw new Error('invalid www-authenticate header (no "Bearer " prefix)');
}
// function parse_www_authenticate(www_authenticate) {
// if (! www_authenticate.startsWith('Bearer ')) {
// throw new Error('invalid www-authenticate header (no "Bearer " prefix)');
// }
let remaining = www_authenticate.slice(7);
const parameters = Object.create(null);
// let remaining = www_authenticate.slice(7);
// const parameters = Object.create(null);
while (remaining) {
const eq_index = remaining.indexOf('=');
// while (remaining) {
// const eq_index = remaining.indexOf('=');
if (eq_index < 0) {
parameters[remaining] = '';
break;
}
// if (eq_index < 0) {
// parameters[remaining] = '';
// break;
// }
const key = remaining.slice(0, eq_index);
remaining = remaining.slice(eq_index + 1);
// const key = remaining.slice(0, eq_index);
// remaining = remaining.slice(eq_index + 1);
if (! remaining) {
parameters[key] = '';
break;
}
// if (! remaining) {
// parameters[key] = '';
// break;
// }
if (remaining[0] === '"') {
const close_index = remaining.slice(1).indexOf('"');
// if (remaining[0] === '"') {
// const close_index = remaining.slice(1).indexOf('"');
if (close_index < 0) {
throw new Error('invalid www-authenticate header (unclosed quotes)');
}
// if (close_index < 0) {
// throw new Error('invalid www-authenticate header (unclosed quotes)');
// }
parameters[key] = remaining.slice(1, close_index + 1);
remaining = remaining.slice(close_index + 2);
// parameters[key] = remaining.slice(1, close_index + 1);
// remaining = remaining.slice(close_index + 2);
if (remaining && remaining[0] !== ',') {
throw new Error('invalid www-authenticate header (expected comma after closing quote)');
}
// if (remaining && remaining[0] !== ',') {
// throw new Error('invalid www-authenticate header (expected comma after closing quote)');
// }
remaining = remaining.slice(1);
}
// remaining = remaining.slice(1);
// }
else {
const comma_index = remaining.indexOf(',');
// else {
// const comma_index = remaining.indexOf(',');
if (comma_index < 0) {
parameters[key] = remaining;
break;
}
// if (comma_index < 0) {
// parameters[key] = remaining;
// break;
// }
parameters[key] = remaining.slice(1, comma_index);
remaining = remaining.slice(comma_index + 1);
}
}
// parameters[key] = remaining.slice(1, comma_index);
// remaining = remaining.slice(comma_index + 1);
// }
// }
const { realm, service, scope } = parameters;
// const { realm, service, scope } = parameters;
if (! realm || ! service || ! scope) {
throw new Error('invalid www-authenticate header (missing "realm", "service", or "scope")');
}
// if (! realm || ! service || ! scope) {
// throw new Error('invalid www-authenticate header (missing "realm", "service", or "scope")');
// }
return parameters;
}
// return parameters;
// }