Repository navigation
Expand file tree
/
Copy pathMachine Fetch
More file actions
107 lines (93 loc) · 3.93 KB
/
Copy pathMachine Fetch
File metadata and controls
107 lines (93 loc) · 3.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#Login to HTB, open Machines page, open Console and paste below:
(async () => {
// --- Авто-поиск токена ---
const token = (() => {
const val = localStorage.getItem('htb-token');
if (val && val.startsWith('eyJ')) return val;
for (const s of [localStorage, sessionStorage]) {
for (let i = 0; i < s.length; i++) {
const key = s.key(i);
const v = s.getItem(key);
if (v && typeof v === 'string' && v.startsWith('eyJ') && v.length > 100) return v;
}
}
return null;
})();
if (!token) { console.error('Токен не найден'); return; }
console.log('Токен получен');
// --- Загружаем ВСЕ машины (retired + active) ---
const base = 'https://labs.hackthebox.com/api/v5/machines';
const states = ['retired', 'active'];
let allMachines = [];
const seenIds = new Set();
for (const state of states) {
let page = 1, totalPages = 1;
const params = new URLSearchParams({
per_page: 100,
state: state
});
do {
params.set('page', page);
const res = await fetch(`${base}?${params}`, {
headers: { 'Authorization': `Bearer ${token}`, 'Accept': 'application/json' }
});
if (!res.ok) {
const text = await res.text();
throw new Error(`HTTP ${res.status}: ${text}`);
}
const data = await res.json();
const machines = data.data || data.machines || [];
for (const m of machines) {
if (!seenIds.has(m.id)) {
seenIds.add(m.id);
allMachines.push(m);
}
}
totalPages = data.meta?.last_page || data.total_pages || 1;
console.log(`State=${state}, Page ${page}: ${machines.length} машин (уникальных всего: ${allMachines.length})`);
page++;
} while (page <= totalPages);
}
console.log(`Всего уникальных машин: ${allMachines.length}`);
// --- Используем поле difficultyText для сортировки ---
const diffOrder = { 'Easy': 0, 'Medium': 1, 'Hard': 2, 'Insane': 3 };
// --- Формируем список с правильным полем difficultyText ---
const list = allMachines.map(m => ({
name: m.name || '',
os: m.os || 'Unknown',
difficulty: m.difficultyText || 'Unknown' // теперь берём текстовую метку
}));
// --- Сортировка по сложности, затем по ОС (Windows > Linux) ---
list.sort((a, b) => {
if (diffOrder[a.difficulty] !== diffOrder[b.difficulty])
return diffOrder[a.difficulty] - diffOrder[b.difficulty];
if (a.os === 'Windows' && b.os !== 'Windows') return -1;
if (a.os !== 'Windows' && b.os === 'Windows') return 1;
return a.name.localeCompare(b.name);
});
// --- Группировка и чередование Windows/Linux внутри каждой сложности ---
const grouped = {};
for (const m of list) {
if (!grouped[m.difficulty]) grouped[m.difficulty] = [];
grouped[m.difficulty].push(m);
}
const sorted = [];
for (const diff of ['Easy', 'Medium', 'Hard', 'Insane']) {
const group = grouped[diff] || [];
const windows = group.filter(m => m.os === 'Windows');
const linux = group.filter(m => m.os === 'Linux');
const other = group.filter(m => m.os !== 'Windows' && m.os !== 'Linux');
const maxLen = Math.max(windows.length, linux.length);
const interleaved = [];
for (let i = 0; i < maxLen; i++) {
if (i < windows.length) interleaved.push(windows[i]);
if (i < linux.length) interleaved.push(linux[i]);
}
sorted.push(...interleaved, ...other);
}
console.log(`Отсортировано ${sorted.length} машин:`);
console.table(sorted.map(m => ({ name: m.name, os: m.os, difficulty: m.difficulty })));
// --- Скопировать JSON в буфер обмена (раскомментируй) ---
// copy(JSON.stringify(sorted, null, 2));
return sorted;
})();