102 lines
3.2 KiB
JavaScript
102 lines
3.2 KiB
JavaScript
const jwt = require('jsonwebtoken');
|
|
const http = require('http');
|
|
const { execSync } = require('child_process');
|
|
const fs = require('fs');
|
|
|
|
const KEY = 'user:1022172:47';
|
|
const SECRET = 'da4e4367277668aa6e048b0a04d1a417ba8bad630f4ac37ccdcea064a9de151e';
|
|
|
|
function makeJWT() {
|
|
return jwt.sign({
|
|
iss: KEY, jti: Math.random().toString(36).slice(2),
|
|
iat: Math.floor(Date.now() / 1000), exp: Math.floor(Date.now() / 1000) + 300
|
|
}, SECRET);
|
|
}
|
|
|
|
function proxyGet(url, auth) {
|
|
return new Promise((resolve, reject) => {
|
|
const u = new URL(url);
|
|
const req = http.request({
|
|
hostname: 'localhost', port: 12334,
|
|
path: url, method: 'GET',
|
|
headers: { 'Host': u.hostname, 'Authorization': auth }
|
|
}, res => {
|
|
const chunks = [];
|
|
res.on('data', c => chunks.push(c));
|
|
res.on('end', () => resolve({ status: res.statusCode, body: Buffer.concat(chunks) }));
|
|
});
|
|
req.on('error', reject);
|
|
req.end();
|
|
});
|
|
}
|
|
|
|
async function main() {
|
|
const token = makeJWT();
|
|
const auth = 'JWT ' + token;
|
|
|
|
const versionId = 6297193;
|
|
const addonId = 'verstak-bridge@verstak.app';
|
|
|
|
// Get full version details
|
|
console.log('==> Getting full version details...');
|
|
const url = `https://addons.mozilla.org/api/v5/addons/addon/${addonId}/versions/${versionId}/`;
|
|
const res = await proxyGet(url, auth);
|
|
const data = JSON.parse(res.body.toString());
|
|
|
|
// The file info is in data.file (singular), not data.files
|
|
const file = data.file;
|
|
if (!file) {
|
|
console.log('No file object in response');
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log(` File ID: ${file.id}`);
|
|
console.log(` Status: ${file.status}`);
|
|
console.log(` Size: ${file.size}`);
|
|
console.log(` Hash: ${file.hash}`);
|
|
console.log(` URL: ${file.url}`);
|
|
console.log(` Download URL: ${file.download_url || file.url}`);
|
|
|
|
const downloadUrl = file.download_url || file.url;
|
|
if (!downloadUrl) {
|
|
console.log('No download URL found');
|
|
console.log('Full file object:', JSON.stringify(file, null, 2));
|
|
process.exit(1);
|
|
}
|
|
|
|
// Download
|
|
console.log(`==> Downloading signed XPI...`);
|
|
fs.mkdirSync('release/firefox', { recursive: true });
|
|
const outPath = 'release/firefox/verstak-firefox-1.0.1.xpi';
|
|
|
|
try {
|
|
execSync(
|
|
`curl -s -x http://localhost:12334 -L "${downloadUrl}" -H "Authorization: ${auth}" -H "User-Agent: verstak-release/1.0" -o "${outPath}"`,
|
|
{ timeout: 60000 }
|
|
);
|
|
const size = fs.statSync(outPath).size;
|
|
console.log(` Saved: ${outPath} (${(size / 1024).toFixed(1)} KB)`);
|
|
|
|
// Verify ZIP magic
|
|
const fd = fs.openSync(outPath, 'r');
|
|
const magic = Buffer.alloc(4);
|
|
fs.readSync(fd, magic, 0, 4, 0);
|
|
fs.closeSync(fd);
|
|
const isZip = magic[0] === 0x50 && magic[1] === 0x4B;
|
|
console.log(` ZIP magic: ${isZip ? 'VALID ✓' : 'INVALID ✗'} (${magic.toString('hex')})`);
|
|
|
|
if (!isZip || size < 1000) {
|
|
console.log(' WARNING: File may not be a valid XPI');
|
|
console.log(' Content:', fs.readFileSync(outPath).toString('utf8').substring(0, 200));
|
|
process.exit(1);
|
|
}
|
|
|
|
console.log('==> DONE ✓');
|
|
} catch (e) {
|
|
console.error(' Download failed:', e.message);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
main().catch(e => { console.error('FATAL:', e.message); process.exit(1); });
|