oras-pull
Version:
ORAS pull for ghcr.io
86 lines (85 loc) • 3.24 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const node_process_1 = __importDefault(require("node:process"));
const node_stream_1 = __importDefault(require("node:stream"));
const cross_fetch_1 = __importDefault(require("cross-fetch"));
const tar_1 = __importDefault(require("tar"));
async function oauth(repo) {
const token = node_process_1.default.env.GITHUB_TOKEN;
if (token === undefined || token.startsWith("gh") === false) {
return "QQ==";
}
console.log("Token: \t" + repo);
const tokenResponse = await (0, cross_fetch_1.default)(`https://ghcr.io/token?service=ghcr.io&scope=repository:${repo}:pull&client_id=npm-js-oras-pull`, {
headers: {
authorization: "Basic " + Buffer.from("foo:" + node_process_1.default.env.GITHUB_TOKEN).toString("base64"),
}
});
if (tokenResponse.status !== 200) {
console.dir(await tokenResponse.json());
node_process_1.default.exit(1);
}
return (await tokenResponse.json()).token;
}
async function run() {
const imageName = node_process_1.default.argv[2];
if (imageName === undefined) {
console.log("Supply argument");
node_process_1.default.exit(1);
}
console.log("Pull: \t" + imageName);
let [url, tag] = imageName.split(":");
const repo = url.replace("ghcr.io/", "").split("/").splice(0, 2).join("/");
const bearer = await oauth(repo);
url = url.replace("ghcr.io", "https://ghcr.io/v2");
const manifestResponse = await (0, cross_fetch_1.default)(url + '/manifests/' + tag, {
headers: {
accept: "application/vnd.oci.image.manifest.v1+json",
authorization: "Bearer " + bearer
}
});
if (manifestResponse.status !== 200) {
console.dir(await manifestResponse.json());
node_process_1.default.exit(1);
}
const manifest = await manifestResponse.json();
const layer = manifest.layers[0];
console.log("Digest: " + layer.digest);
console.log("Size: \t" + layer.size + " bytes");
const blobResponse = await (0, cross_fetch_1.default)(url + '/blobs/' + layer.digest, {
headers: {
authorization: "Bearer " + bearer
}
});
if (blobResponse.status !== 200) {
console.dir(await manifestResponse.json());
node_process_1.default.exit(1);
}
const responseBuffer = Buffer.from(await blobResponse.arrayBuffer());
const readableStream = node_stream_1.default.Readable.from(responseBuffer);
console.log("");
let count = 0;
const st = readableStream.pipe(tar_1.default.extract({
onentry: entry => {
count++;
if (count < 10) {
console.log("Extract: " + entry.path);
}
else if (count % 100 === 0) {
console.log(count);
}
}
}));
st.on('finish', () => {
console.log(count + " folders/files extracted");
});
}
run().then(() => {
// process.exit();
}).catch((err) => {
console.log(err);
node_process_1.default.exit(1);
});