v0.0.58: ВМ-загрузка (паттерн ВМ-буфер+pull) — PUT на ВМ + /api/upload_refs (egress), nginx /drhider-upload/ + CORS + TTL
Deploy drhider / validate (push) Canceled after 0s

This commit is contained in:
“Naeel”
2026-08-21 15:40:24 +03:00
parent 705b39ab7d
commit 04f6d7f81a
6 changed files with 5308 additions and 26 deletions
+38 -24
View File
@@ -198,6 +198,7 @@ let fileMeta = new Map(); // имя -> {size, mtime} для дедупа/суф
let overNames = new Set(); // имена файлов сверх лимита (не участвуют в обфускации)
const MAX_FILE_BYTES = 100 * 1024 * 1024; // 100 МБ на файл
const MAX_SESSION_BYTES = 1024 * 1024 * 1024; // 1 ГБ суммарно
const VM_UPLOAD_URL = 'https://contracts.kube5s.ru/drhider-upload/'; // ВМ-буфер: PUT больших файлов (шлюз кластера их рвёт)
let currentSid = '';
let activeES = null; // активный EventSource
let activeXHR = null; // активный XHR
@@ -434,23 +435,22 @@ async function uploadFiles() {
const total = toSend.length;
if (total === 0) { st.className = 'status error'; st.textContent = 'Нет файлов для обфускации (все превышают лимит).'; ub.disabled = false; return; }
// Фаза 1: загрузка (XMLHttpRequest — прогресс в строке)
// Фаза 1: загрузка на ВМ-буфер (PUT напрямую на nginx ВМ, минуя шлюз кластера)
const token = crypto.randomUUID();
const refs = []; // {name, size, url} — для POST /api/upload_refs
for (let k = 0; k < total; k++) {
const f = toSend[k];
const i = sendIdx[k]; // индекс в sf для вывода прогресса
const n = k + 1;
st.className = 'status progress';
st.textContent = 'Загрузка (этап 1/2) ' + n + '/' + total + ': ' + f.name;
st.textContent = 'Загрузка на ВМ (этап 1/2) ' + n + '/' + total + ': ' + f.name;
try {
const t0 = performance.now();
const vmUrl = VM_UPLOAD_URL + token + '_' + k; // имя файла в URL не несём (токен-ключ)
await new Promise((resolve, reject) => {
const fd = new FormData();
fd.append('files', f, f.name);
if (currentSid) fd.append('session', currentSid);
const url = '/api/upload?_=' + Date.now();
const xhr = new XMLHttpRequest();
xhr.open('POST', url);
xhr.timeout = 300000; // 300с: загрузка больших файлов нестабильна через шлюз
xhr.open('PUT', vmUrl);
xhr.timeout = 300000; // 300с: большие файлы
xhr.upload.onprogress = function(e) {
if (e.lengthComputable) {
const pct = Math.round(e.loaded / e.total * 100);
@@ -458,35 +458,49 @@ async function uploadFiles() {
}
};
xhr.onload = function() {
if (xhr.status === 200) {
const data = JSON.parse(xhr.responseText);
if (data.ok) {
const elapsed = (performance.now() - t0) / 1000;
const speed = f.size / elapsed;
ss(i, '<span style="color:#22c55e">✓ ' + fs(speed) + '/s</span>');
currentSid = data.session;
resolve();
} else {
reject(new Error(data.error));
}
if (xhr.status >= 200 && xhr.status < 300) {
const elapsed = (performance.now() - t0) / 1000;
const speed = f.size / elapsed;
ss(i, '<span style="color:#22c55e">✓ ' + fs(speed) + '/s</span>');
refs.push({ name: f.name, size: f.size, url: vmUrl });
resolve();
} else {
reject(new Error('HTTP ' + xhr.status));
reject(new Error('ВМ: HTTP ' + xhr.status));
}
};
xhr.onerror = function() { reject(new Error('Сеть')); };
xhr.ontimeout = function() { reject(new Error('Таймаут 300с')); };
xhr.onerror = function() { reject(new Error('Сеть (ВМ)')); };
xhr.ontimeout = function() { reject(new Error('Таймаут 300с (ВМ)')); };
activeXHR = xhr;
xhr.send(fd);
xhr.send(f); // сырое тело файла
});
} catch (err) {
ss(i, '<span style="color:#ef4444">✗</span>');
st.className = 'status error';
st.textContent = 'Ошибка загрузки: ' + err.message;
st.textContent = 'Ошибка загрузки на ВМ: ' + err.message;
ub.disabled = false;
return;
}
}
// Шаг 1b: один маленький POST во Flask со ссылками на файлы ВМ (<64КБ)
st.className = 'status progress';
st.textContent = 'Передача ссылок в сервис…';
try {
const resp = await fetch('/api/upload_refs', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ session: currentSid, files: refs })
});
const data = await resp.json();
if (!data.ok) throw new Error(data.error || 'HTTP ' + resp.status);
currentSid = data.session;
} catch (err) {
st.className = 'status error';
st.textContent = 'Ошибка передачи ссылок: ' + err.message;
ub.disabled = false;
return;
}
// Фаза 2: обработка (SSE — прогресс по каждому файлу)
// Сброс загрузочных статусов — теперь этап обработки (только отправленные)
for (let k = 0; k < total; k++) ss(sendIdx[k], '<span style="color:#2563eb">⏳</span>');