fix(gateway): deploy native in-project soc-gateway-live container artifact, eliminate ttyd terminal, clean up external static apps, and update English security reports
This commit is contained in:
@@ -0,0 +1,258 @@
|
||||
const fs = require('fs');
|
||||
const crypto = require('crypto');
|
||||
const zlib = require('zlib');
|
||||
const { getAuth } = require('./auth_manager');
|
||||
|
||||
const REPO_NAME = 'soc-gateway';
|
||||
|
||||
function createTar(files) {
|
||||
const chunks = [];
|
||||
for (const file of files) {
|
||||
const name = file.name;
|
||||
const content = Buffer.isBuffer(file.content) ? file.content : Buffer.from(file.content, 'utf8');
|
||||
const size = content.length;
|
||||
|
||||
const header = Buffer.alloc(512);
|
||||
header.write(name, 0, 100, 'utf8');
|
||||
header.write('0000644\0', 100, 8, 'utf8');
|
||||
header.write('0000000\0', 108, 8, 'utf8');
|
||||
header.write('0000000\0', 116, 8, 'utf8');
|
||||
header.write(size.toString(8).padStart(11, '0') + '\0', 124, 12, 'utf8');
|
||||
const mtime = Math.floor(Date.now() / 1000);
|
||||
header.write(mtime.toString(8).padStart(11, '0') + '\0', 136, 12, 'utf8');
|
||||
header.write(' ', 148, 8, 'utf8');
|
||||
header.write('0', 156, 1, 'utf8');
|
||||
header.write('ustar\0', 257, 6, 'utf8');
|
||||
header.write('00', 263, 2, 'utf8');
|
||||
|
||||
let sum = 0;
|
||||
for (let i = 0; i < 512; i++) sum += header[i];
|
||||
header.write(sum.toString(8).padStart(6, '0') + '\0 ', 148, 8, 'utf8');
|
||||
|
||||
chunks.push(header);
|
||||
chunks.push(content);
|
||||
|
||||
const remainder = size % 512;
|
||||
if (remainder > 0) chunks.push(Buffer.alloc(512 - remainder));
|
||||
}
|
||||
chunks.push(Buffer.alloc(1024));
|
||||
return Buffer.concat(chunks);
|
||||
}
|
||||
|
||||
async function uploadBlobToGhaymah(blobBuffer, digest, userId) {
|
||||
let authData = await getAuth();
|
||||
let auth = Buffer.from(userId + ':' + authData.token).toString('base64');
|
||||
|
||||
// Check if blob already exists
|
||||
let checkRes = await fetch(`https://registry.ghaymah.systems/v2/${userId}/${REPO_NAME}/blobs/${digest}`, {
|
||||
method: 'HEAD',
|
||||
headers: { 'Authorization': 'Basic ' + auth }
|
||||
});
|
||||
if (checkRes.status === 401) {
|
||||
authData = await getAuth(true);
|
||||
auth = Buffer.from(userId + ':' + authData.token).toString('base64');
|
||||
checkRes = await fetch(`https://registry.ghaymah.systems/v2/${userId}/${REPO_NAME}/blobs/${digest}`, {
|
||||
method: 'HEAD',
|
||||
headers: { 'Authorization': 'Basic ' + auth }
|
||||
});
|
||||
}
|
||||
if (checkRes.ok) {
|
||||
console.log(`Blob ${digest.substring(0, 19)} already exists on Ghaymah!`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Initiate upload
|
||||
let initRes = await fetch(`https://registry.ghaymah.systems/v2/${userId}/${REPO_NAME}/blobs/uploads/`, {
|
||||
method: 'POST',
|
||||
headers: { 'Authorization': 'Basic ' + auth }
|
||||
});
|
||||
if (initRes.status === 401) {
|
||||
authData = await getAuth(true);
|
||||
auth = Buffer.from(userId + ':' + authData.token).toString('base64');
|
||||
initRes = await fetch(`https://registry.ghaymah.systems/v2/${userId}/${REPO_NAME}/blobs/uploads/`, {
|
||||
method: 'POST',
|
||||
headers: { 'Authorization': 'Basic ' + auth }
|
||||
});
|
||||
}
|
||||
if (initRes.status !== 202) {
|
||||
throw new Error(`Failed to initiate blob upload: ${initRes.status} ${await initRes.text()}`);
|
||||
}
|
||||
let uploadUrl = initRes.headers.get('location');
|
||||
if (uploadUrl.startsWith('/')) {
|
||||
uploadUrl = 'https://registry.ghaymah.systems' + uploadUrl;
|
||||
}
|
||||
const separator = uploadUrl.includes('?') ? '&' : '?';
|
||||
const putUrl = `${uploadUrl}${separator}digest=${digest}`;
|
||||
|
||||
const putRes = await fetch(putUrl, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Authorization': 'Basic ' + auth,
|
||||
'Content-Type': 'application/octet-stream',
|
||||
'Content-Length': blobBuffer.length.toString()
|
||||
},
|
||||
body: blobBuffer
|
||||
});
|
||||
if (putRes.status !== 201) {
|
||||
throw new Error(`Failed to put blob ${digest}: ${putRes.status} ${await putRes.text()}`);
|
||||
}
|
||||
console.log(`Uploaded blob ${digest.substring(0, 19)} (${blobBuffer.length} bytes)`);
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const { token, userId } = await getAuth();
|
||||
const auth = Buffer.from(userId + ':' + token).toString('base64');
|
||||
|
||||
console.log('=== Step 1: Getting Docker Hub Token for nginx:alpine ===');
|
||||
const dAuth = await (await fetch('https://auth.docker.io/token?service=registry.docker.io&scope=repository:library/nginx:pull')).json();
|
||||
const dToken = dAuth.token;
|
||||
|
||||
console.log('=== Step 2: Fetching linux/amd64 Manifest ===');
|
||||
const manListRes = await fetch('https://registry-1.docker.io/v2/library/nginx/manifests/alpine', {
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + dToken,
|
||||
'Accept': 'application/vnd.docker.distribution.manifest.list.v2+json, application/vnd.oci.image.index.v1+json'
|
||||
}
|
||||
});
|
||||
const manList = await manListRes.json();
|
||||
const amd64 = manList.manifests?.find(m => m.platform?.architecture === 'amd64' && m.platform?.os === 'linux');
|
||||
const manifestDigest = amd64 ? amd64.digest : 'alpine';
|
||||
|
||||
const manifestRes = await fetch(`https://registry-1.docker.io/v2/library/nginx/manifests/${manifestDigest}`, {
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + dToken,
|
||||
'Accept': 'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json'
|
||||
}
|
||||
});
|
||||
const manifest = await manifestRes.json();
|
||||
console.log(`Base image has ${manifest.layers.length} layers, config: ${manifest.config.digest}`);
|
||||
|
||||
console.log('\n=== Step 3: Copying Base Layers from Docker Hub to Ghaymah Registry ===');
|
||||
for (let i = 0; i < manifest.layers.length; i++) {
|
||||
const layer = manifest.layers[i];
|
||||
console.log(`[Layer ${i + 1}/${manifest.layers.length}] Fetching ${layer.digest.substring(0, 19)}...`);
|
||||
const layerRes = await fetch(`https://registry-1.docker.io/v2/library/nginx/blobs/${layer.digest}`, {
|
||||
headers: { 'Authorization': 'Bearer ' + dToken }
|
||||
});
|
||||
const layerBuf = Buffer.from(await layerRes.arrayBuffer());
|
||||
await uploadBlobToGhaymah(layerBuf, layer.digest, userId);
|
||||
}
|
||||
|
||||
console.log('\n=== Step 4: Fetching Base Config ===');
|
||||
const configRes = await fetch(`https://registry-1.docker.io/v2/library/nginx/blobs/${manifest.config.digest}`, {
|
||||
headers: { 'Authorization': 'Bearer ' + dToken }
|
||||
});
|
||||
const baseConfig = await configRes.json();
|
||||
|
||||
console.log('\n=== Step 5: Packaging SOC Command Center Files ===');
|
||||
const htmlContent = fs.readFileSync('D:/cumin/ghaymah_dns_net_sec_tests/soc_gateway_ui/index.html', 'utf8');
|
||||
const nginxConf = `server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
location /proxy/ {
|
||||
proxy_pass http://soc-backend-d1895c70f6b2:4000/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_read_timeout 10s;
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
// Create uncompressed tar
|
||||
const tarBuf = createTar([
|
||||
{ name: 'usr/share/nginx/html/index.html', content: htmlContent },
|
||||
{ name: 'etc/nginx/conf.d/default.conf', content: nginxConf }
|
||||
]);
|
||||
const diffId = 'sha256:' + crypto.createHash('sha256').update(tarBuf).digest('hex');
|
||||
|
||||
// Gzip compress
|
||||
const gzipBuf = zlib.gzipSync(tarBuf);
|
||||
const customLayerDigest = 'sha256:' + crypto.createHash('sha256').update(gzipBuf).digest('hex');
|
||||
const customLayerSize = gzipBuf.length;
|
||||
|
||||
console.log(`Custom layer: ${customLayerDigest} (size: ${customLayerSize}, diffId: ${diffId})`);
|
||||
await uploadBlobToGhaymah(gzipBuf, customLayerDigest, userId);
|
||||
|
||||
console.log('\n=== Step 6: Creating and Uploading Custom Image Config ===');
|
||||
const newConfig = { ...baseConfig };
|
||||
newConfig.rootfs = {
|
||||
type: 'layers',
|
||||
diff_ids: [...(baseConfig.rootfs?.diff_ids || []), diffId]
|
||||
};
|
||||
newConfig.history = [
|
||||
...(baseConfig.history || []),
|
||||
{
|
||||
created: new Date().toISOString(),
|
||||
created_by: 'ADD soc_gateway_ui /usr/share/nginx/html'
|
||||
}
|
||||
];
|
||||
|
||||
const newConfigBuf = Buffer.from(JSON.stringify(newConfig));
|
||||
const newConfigDigest = 'sha256:' + crypto.createHash('sha256').update(newConfigBuf).digest('hex');
|
||||
console.log(`New config digest: ${newConfigDigest}`);
|
||||
await uploadBlobToGhaymah(newConfigBuf, newConfigDigest, userId);
|
||||
|
||||
console.log('\n=== Step 7: Publishing Image Manifest as latest ===');
|
||||
const newManifest = {
|
||||
schemaVersion: 2,
|
||||
mediaType: 'application/vnd.docker.distribution.manifest.v2+json',
|
||||
config: {
|
||||
mediaType: 'application/vnd.docker.container.image.v1+json',
|
||||
size: newConfigBuf.length,
|
||||
digest: newConfigDigest
|
||||
},
|
||||
layers: [
|
||||
...manifest.layers.map(l => ({
|
||||
mediaType: 'application/vnd.docker.image.rootfs.diff.tar.gzip',
|
||||
size: l.size,
|
||||
digest: l.digest
|
||||
})),
|
||||
{
|
||||
mediaType: 'application/vnd.docker.image.rootfs.diff.tar.gzip',
|
||||
size: customLayerSize,
|
||||
digest: customLayerDigest
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
let curAuth = await getAuth();
|
||||
let putAuth = Buffer.from(userId + ':' + curAuth.token).toString('base64');
|
||||
let putManRes = await fetch(`https://registry.ghaymah.systems/v2/${userId}/${REPO_NAME}/manifests/latest`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Authorization': 'Basic ' + putAuth,
|
||||
'Content-Type': 'application/vnd.docker.distribution.manifest.v2+json'
|
||||
},
|
||||
body: JSON.stringify(newManifest)
|
||||
});
|
||||
if (putManRes.status === 401) {
|
||||
curAuth = await getAuth(true);
|
||||
putAuth = Buffer.from(userId + ':' + curAuth.token).toString('base64');
|
||||
putManRes = await fetch(`https://registry.ghaymah.systems/v2/${userId}/${REPO_NAME}/manifests/latest`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Authorization': 'Basic ' + putAuth,
|
||||
'Content-Type': 'application/vnd.docker.distribution.manifest.v2+json'
|
||||
},
|
||||
body: JSON.stringify(newManifest)
|
||||
});
|
||||
}
|
||||
|
||||
console.log('Manifest PUT Status:', putManRes.status, putManRes.statusText);
|
||||
if (!putManRes.ok) {
|
||||
throw new Error('Manifest upload failed: ' + (await putManRes.text()));
|
||||
}
|
||||
|
||||
console.log('\n>>> SUCCESS! DOCKER IMAGE SUCCESSFULLY PUSHED TO REGISTRY.GHAYMAH.SYSTEMS! <<<');
|
||||
console.log(`Image: registry.ghaymah.systems/${userId}/${REPO_NAME}:latest`);
|
||||
}
|
||||
|
||||
main().catch(console.error);
|
||||
Reference in New Issue
Block a user