chore: super deep scanning cleanup - remove obsolete debug scripts, redundant components, and temporary files

This commit is contained in:
rafif committed 2026-07-31 09:41:11 +07:00
1 parent 97d2c89c15
commit a577f2d672
189 files changed
-11112

No files matched your search

-34
View File
@@ -1,34 +0,0 @@
// check_device.js - Detailed check of 10.6.10.44 records
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '..', '.env.local') });
const mongoose = require('mongoose');
async function run() {
await mongoose.connect(process.env.MONGODB_URI || 'mongodb://localhost:27017/backone');
const db = mongoose.connection.db;
// Get all records for 10.6.10.44
const docs = await db.collection('devicestats')
.find({ ip_address: '10.6.10.44' })
.sort({ timestamp: 1 })
.toArray();
console.log(`Total docs for 10.6.10.44: ${docs.length}`);
docs.forEach((d, i) => {
console.log(`\n--- Doc ${i + 1} ---`);
console.log(' _id: ', d._id);
console.log(' agent_uuid: ', d.agent_uuid);
console.log(' timestamp: ', d.timestamp);
console.log(' created_at: ', d.created_at);
console.log(' updated_at: ', d.updated_at);
console.log(' download: ', d.download);
console.log(' device_label:', d.device_label);
});
// Check if there are different agent_uuids
const agents = [...new Set(docs.map(d => d.agent_uuid))];
console.log('\nDistinct agent_uuids for this IP:', agents);
await mongoose.disconnect();
}
run().catch(err => { console.error(err.message); process.exit(1); });
-27
View File
@@ -1,27 +0,0 @@
const { MongoClient } = require('mongodb');
const client = new MongoClient('mongodb://127.0.0.1:27017');
client.connect().then(async () => {
const db = client.db('backone_dpi');
const col = db.collection('deviceappstats');
const CIBUBUR = '2F-TF-1D-GK';
const BALARAJA = 'F6-2V-DT-8A';
const countCibubur = await col.countDocuments({ agent_uuid: CIBUBUR, app_label: 'YouTube' });
const countBalaraja = await col.countDocuments({ agent_uuid: BALARAJA, app_label: 'YouTube' });
const sampleCibubur = await col.find({ agent_uuid: CIBUBUR, app_label: 'YouTube' }).sort({ timestamp: -1 }).limit(10).toArray();
const sampleBalaraja = await col.find({ agent_uuid: BALARAJA, app_label: 'YouTube' }).sort({ timestamp: -1 }).limit(5).toArray();
console.log(`DeviceAppStat count YouTube:`);
console.log(`- JRP Cibubur (${CIBUBUR}): ${countCibubur}`);
console.log(`- CPI Balaraja (${BALARAJA}): ${countBalaraja}`);
console.log(`\nSample JRP Cibubur DeviceAppStat for YouTube:`);
sampleCibubur.forEach(r => {
console.log(` IP: ${r.ip_address} | DL: ${(r.download/1e6).toFixed(2)} MB | UL: ${(r.upload/1e6).toFixed(2)} MB | Time: ${r.timestamp.toISOString()}`);
});
await client.close();
process.exit(0);
}).catch(e => { console.error(e.message); process.exit(1); });
-34
View File
@@ -1,34 +0,0 @@
const { MongoClient } = require('mongodb');
const client = new MongoClient('mongodb://127.0.0.1:27017');
client.connect().then(async () => {
const db = client.db('backone_dpi');
const col = db.collection('flows');
const SIAB = '6681452d_9cae_4ff4_8ae8_0d504774265e';
const july13start = new Date('2026-07-13T00:00:00.000+07:00');
const july13end = new Date('2026-07-13T23:59:59.999+07:00');
const july14start = new Date('2026-07-14T00:00:00.000+07:00');
const count13 = await col.countDocuments({ site_uuid: SIAB, timestamp: { $gte: july13start, $lte: july13end } });
const count14 = await col.countDocuments({ site_uuid: SIAB, timestamp: { $gte: july14start } });
const total = await col.countDocuments({ site_uuid: SIAB });
const oldest = await col.findOne({ site_uuid: SIAB }, { sort: { timestamp: 1 }, projection: { timestamp: 1, first_seen: 1, last_seen: 1 } });
const newest = await col.findOne({ site_uuid: SIAB }, { sort: { timestamp: -1 }, projection: { timestamp: 1, first_seen: 1, last_seen: 1 } });
const sample13 = await col.findOne(
{ site_uuid: SIAB, timestamp: { $gte: july13start, $lte: july13end } },
{ projection: { timestamp: 1, first_seen: 1, last_seen: 1, flow_id: 1, agent_uuid: 1 } }
);
console.log('Total SIAB flows:', total);
console.log('SIAB flows with timestamp on July 13:', count13);
console.log('SIAB flows with timestamp on July 14+:', count14);
console.log('Oldest flow:', JSON.stringify(oldest, null, 2));
console.log('Newest flow:', JSON.stringify(newest, null, 2));
console.log('Sample July 13 flow:', JSON.stringify(sample13, null, 2));
await client.close();
process.exit(0);
}).catch(e => { console.error(e.message); process.exit(1); });
-63
View File
@@ -1,63 +0,0 @@
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '..', '.env.local') });
const mongoose = require('mongoose');
const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017/backone_dpi';
const SIAB = '6681452d_9cae_4ff4_8ae8_0d504774265e';
mongoose.connect(MONGODB_URI).then(async () => {
const db = mongoose.connection.db;
const since24h = new Date(Date.now() - 24 * 3600000);
const since7d = new Date(Date.now() - 7 * 24 * 3600000);
// Count site-level summary docs
const count24h = await db.collection('summaries').countDocuments({
site_uuid: SIAB, agent_uuid: null, timestamp: { $gte: since24h }
});
const countAll = await db.collection('summaries').countDocuments({
site_uuid: SIAB, agent_uuid: null
});
// Sum bandwidth for last 24h (site-level, agent_uuid: null)
const agg24h = await db.collection('summaries').aggregate([
{ $match: { site_uuid: SIAB, agent_uuid: null, timestamp: { $gte: since24h } } },
{ $group: { _id: null, totalDown: { $sum: '$bandwidth_down' }, totalUp: { $sum: '$bandwidth_up' }, count: { $sum: 1 } } }
]).toArray();
// Sum bandwidth ALL time (site-level)
const aggAll = await db.collection('summaries').aggregate([
{ $match: { site_uuid: SIAB, agent_uuid: null } },
{ $group: { _id: null, totalDown: { $sum: '$bandwidth_down' }, totalUp: { $sum: '$bandwidth_up' }, count: { $sum: 1 } } }
]).toArray();
// Oldest and newest
const oldest = await db.collection('summaries').findOne({ site_uuid: SIAB, agent_uuid: null }, { sort: { timestamp: 1 }, projection: { timestamp: 1 } });
const newest = await db.collection('summaries').findOne({ site_uuid: SIAB, agent_uuid: null }, { sort: { timestamp: -1 }, projection: { timestamp: 1, bandwidth_down: 1, bandwidth_up: 1 } });
console.log('\n=== MongoDB Summary Check (SIAB site) ===');
console.log('Total site-level docs:', countAll);
console.log('Site-level docs in last 24h:', count24h);
console.log('\nBandwidth SUM (last 24h):');
console.log(' Down:', agg24h[0] ? (agg24h[0].totalDown / 1024 / 1024).toFixed(2) + ' MB' : '0 MB');
console.log(' Up :', agg24h[0] ? (agg24h[0].totalUp / 1024 / 1024).toFixed(2) + ' MB' : '0 MB');
console.log('\nBandwidth SUM (ALL time):');
console.log(' Down:', aggAll[0] ? (aggAll[0].totalDown / 1024 / 1024).toFixed(2) + ' MB' : '0 MB');
console.log(' Up :', aggAll[0] ? (aggAll[0].totalUp / 1024 / 1024).toFixed(2) + ' MB' : '0 MB');
console.log('\nOldest entry :', oldest?.timestamp);
console.log('Newest entry :', newest?.timestamp);
console.log('Latest bandwidth_down per 5min:', newest ? (newest.bandwidth_down / 1024 / 1024).toFixed(4) + ' MB' : 'N/A');
console.log('Latest bandwidth_up per 5min :', newest ? (newest.bandwidth_up / 1024 / 1024).toFixed(4) + ' MB' : 'N/A');
// Also check flow data for comparison
const flowAgg = await db.collection('flows').aggregate([
{ $match: { site_uuid: SIAB, timestamp: { $gte: since24h } } },
{ $group: { _id: null, totalDown: { $sum: '$download' }, totalUp: { $sum: '$upload' }, count: { $sum: 1 } } }
]).toArray();
console.log('\nFlow-level bandwidth (last 24h from flows collection):');
console.log(' Down:', flowAgg[0] ? (flowAgg[0].totalDown / 1024 / 1024).toFixed(2) + ' MB' : '0 MB');
console.log(' Up :', flowAgg[0] ? (flowAgg[0].totalUp / 1024 / 1024).toFixed(2) + ' MB' : '0 MB');
console.log(' Flow count:', flowAgg[0]?.count || 0);
console.log('=====================================\n');
process.exit(0);
}).catch(e => { console.error(e.message); process.exit(1); });
-38
View File
@@ -1,38 +0,0 @@
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '..', '.env.local') });
const mongoose = require('mongoose');
const { collectAllAgents } = require('./collector');
const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017/backone_dpi';
async function run() {
console.log('Connecting to MongoDB...');
await mongoose.connect(MONGODB_URI);
console.log('Connected.');
const db = mongoose.connection.db;
const collections = ['devicestats', 'deviceappstats', 'appstats'];
console.log('Clearing old contaminated collections...');
for (const colName of collections) {
await db.collection(colName).deleteMany({});
console.log(` ✓ Cleared ${colName}`);
}
console.log('\nRunning initial data collection cycle for ALL agents...');
const result = await collectAllAgents();
console.log('Collection completed:', JSON.stringify(result, null, 2));
// Log new clean sizes
const { logCapacityStats } = require('./db/capacityTracker');
await logCapacityStats('[MongoDB] Capacity after clean run:');
await mongoose.disconnect();
console.log('Done.');
process.exit(0);
}
run().catch(e => {
console.error('Fatal error during clean and recollect:', e);
process.exit(1);
});
-73
View File
@@ -1,73 +0,0 @@
// proxy/clean_devicestat_duplicates.js
// ─────────────────────────────────────────────────────────────────────────────
// One-time cleanup script to deduplicate historical DeviceStat records.
// Keeps only the LATEST document per (agent_uuid, ip_address) pair,
// removing all older duplicates accumulated before the upsert fix.
//
// Usage: node proxy/clean_devicestat_duplicates.js
// ─────────────────────────────────────────────────────────────────────────────
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '..', '.env.local') });
const mongoose = require('mongoose');
const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://localhost:27017/backone';
const DeviceStatSchema = new mongoose.Schema({
timestamp: { type: Date },
agent_uuid: { type: String },
site_uuid: { type: String },
ip_address: { type: String },
mac_address: { type: String },
device_label: String,
device_type: String,
os_label: String,
manufacturer: String,
download: Number,
upload: Number,
flows: Number,
last_seen: String,
}, { timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' } });
const DeviceStat = mongoose.model('DeviceStat', DeviceStatSchema);
async function run() {
console.log('[Cleanup] Connecting to MongoDB...');
await mongoose.connect(MONGODB_URI);
console.log('[Cleanup] Connected.');
// Find all unique (agent_uuid, ip_address) combinations
const groups = await DeviceStat.aggregate([
{ $group: {
_id: { agent_uuid: '$agent_uuid', ip_address: '$ip_address' },
ids: { $push: '$_id' },
timestamps: { $push: '$timestamp' },
count: { $sum: 1 },
}},
{ $match: { count: { $gt: 1 } } },
]);
console.log(`[Cleanup] Found ${groups.length} (agent_uuid, ip_address) pairs with duplicates.`);
let totalDeleted = 0;
for (const group of groups) {
// Sort the ids by matching timestamps - keep the latest
const paired = group.ids.map((id, i) => ({ id, ts: group.timestamps[i] }));
paired.sort((a, b) => new Date(b.ts) - new Date(a.ts));
// Keep the first (newest), delete the rest
const toDelete = paired.slice(1).map(p => p.id);
const result = await DeviceStat.deleteMany({ _id: { $in: toDelete } });
totalDeleted += result.deletedCount;
}
const remaining = await DeviceStat.countDocuments();
console.log(`[Cleanup] Done. Deleted ${totalDeleted} duplicate DeviceStat records.`);
console.log(`[Cleanup] Remaining DeviceStat documents: ${remaining}`);
await mongoose.disconnect();
}
run().catch(err => {
console.error('[Cleanup] Fatal error:', err.message);
process.exit(1);
});
-58
View File
@@ -1,58 +0,0 @@
// cleanup_duplicate_agents.js
// One-time cleanup: remove agent data stored under the wrong site_uuid.
// SIAB agents (from current collector run) = definitive source of truth.
// Any SIAB agent found under NEXUS → delete from NEXUS.
// Any non-SIAB agent found under SIAB → delete from SIAB.
const mongoose = require('mongoose');
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '../../../..', '.env.local') });
const SIAB_UUID = '6681452d_9cae_4ff4_8ae8_0d504774265e';
const NEXUS_UUID = 'd7902405_0dc2_458b_8584_ed4d24b64f24';
// Definitive SIAB agent list (from most recent collector run)
const SIAB_AGENTS = ['F6-2V-DT-8A', 'YW-6I-61-LL', '2F-TF-1D-GK', '1R-79-J9-YE', '8A-V3-PB-85'];
async function cleanup() {
await mongoose.connect(process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017/backone_dpi');
const db = mongoose.connection.db;
const collections = (await db.listCollections().toArray())
.map(c => c.name)
.filter(n => !n.startsWith('system.'));
let totalDeleted = 0;
for (const colName of collections) {
const col = db.collection(colName);
// 1. Delete SIAB agents that are stored under NEXUS site_uuid
const r1 = await col.deleteMany({
site_uuid: NEXUS_UUID,
agent_uuid: { $in: SIAB_AGENTS }
});
if (r1.deletedCount > 0) {
console.log(`[${colName}] Removed ${r1.deletedCount} docs (SIAB agents from NEXUS)`);
totalDeleted += r1.deletedCount;
}
// 2. Delete non-SIAB agents that are stored under SIAB site_uuid
const r2 = await col.deleteMany({
site_uuid: SIAB_UUID,
agent_uuid: { $nin: [...SIAB_AGENTS, null] } // keep null = site-level summaries
});
if (r2.deletedCount > 0) {
console.log(`[${colName}] Removed ${r2.deletedCount} docs (non-SIAB agents from SIAB)`);
totalDeleted += r2.deletedCount;
}
}
console.log(`\n✅ Cleanup complete. Total documents removed: ${totalDeleted}`);
await mongoose.disconnect();
}
cleanup().catch(err => {
console.error('❌ Cleanup failed:', err.message);
process.exit(1);
});
-44
View File
@@ -1,44 +0,0 @@
// diagnostic.js - Run: node proxy/diagnostic.js
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '..', '.env.local') });
const mongoose = require('mongoose');
const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://localhost:27017/backone';
async function run() {
await mongoose.connect(MONGODB_URI);
const db = mongoose.connection.db;
// 1. Total count
const total = await db.collection('devicestats').countDocuments();
console.log('=== DeviceStat Total:', total);
// 2. Count for 10.6.10.44
const specific = await db.collection('devicestats').countDocuments({ ip_address: '10.6.10.44' });
console.log('=== Count for 10.6.10.44:', specific);
// 3. Sample doc for 10.6.10.44
const sample = await db.collection('devicestats').findOne({ ip_address: '10.6.10.44' });
console.log('=== Sample doc for 10.6.10.44:', JSON.stringify(sample, null, 2));
// 4. Duplicate groups (top 10)
const dups = await db.collection('devicestats').aggregate([
{ $group: { _id: { agent_uuid: '$agent_uuid', ip_address: '$ip_address' }, count: { $sum: 1 } } },
{ $match: { count: { $gt: 1 } } },
{ $sort: { count: -1 } },
{ $limit: 10 }
]).toArray();
console.log('=== Top duplicate groups:', JSON.stringify(dups, null, 2));
// 5. Check what collection name is actually used
const collections = await db.listCollections().toArray();
console.log('=== Collections:', collections.map(c => c.name));
// 6. Check indexes on devicestats
const indexes = await db.collection('devicestats').indexes();
console.log('=== Indexes on devicestats:', JSON.stringify(indexes, null, 2));
await mongoose.disconnect();
}
run().catch(err => { console.error('ERROR:', err.message); process.exit(1); });
-79
View File
@@ -1,79 +0,0 @@
// fix_devicestat_index.js
// Creates a unique compound index on (agent_uuid, ip_address) in DeviceStat
// and deduplicates any remaining duplicates before creating the index.
// Run: node proxy/fix_devicestat_index.js
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '..', '.env.local') });
const mongoose = require('mongoose');
const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://localhost:27017/backone';
async function run() {
console.log('[Fix] Connecting to MongoDB...');
await mongoose.connect(MONGODB_URI);
const db = mongoose.connection.db;
const col = db.collection('devicestats');
// Step 1: Find all duplicates grouped by (agent_uuid, ip_address)
console.log('[Fix] Scanning for duplicates...');
const groups = await col.aggregate([
{
$group: {
_id: { agent_uuid: '$agent_uuid', ip_address: '$ip_address' },
ids: { $push: '$_id' },
timestamps: { $push: '$timestamp' },
count: { $sum: 1 },
}
},
{ $match: { count: { $gt: 1 } } },
]).toArray();
console.log(`[Fix] Found ${groups.length} duplicate groups.`);
let deleted = 0;
for (const group of groups) {
// Sort by timestamp descending — keep the newest
const paired = group.ids.map((id, i) => ({ id, ts: new Date(group.timestamps[i] || 0) }));
paired.sort((a, b) => b.ts - a.ts);
const toDelete = paired.slice(1).map(p => p.id);
const result = await col.deleteMany({ _id: { $in: toDelete } });
deleted += result.deletedCount;
}
console.log(`[Fix] Deleted ${deleted} duplicate documents.`);
const remaining = await col.countDocuments();
console.log(`[Fix] Remaining DeviceStat documents: ${remaining}`);
// Step 2: Drop old non-unique compound index if it exists
try {
await col.dropIndex('agent_uuid_1_timestamp_-1_ip_address_1');
console.log('[Fix] Dropped old compound index.');
} catch (e) {
console.log('[Fix] Old index not found or already dropped:', e.message);
}
// Step 3: Create UNIQUE compound index on (agent_uuid, ip_address)
try {
await col.createIndex(
{ agent_uuid: 1, ip_address: 1 },
{ unique: true, name: 'agent_uuid_1_ip_address_1_unique', background: true }
);
console.log('[Fix] Created unique index on (agent_uuid, ip_address).');
} catch (e) {
console.error('[Fix] Failed to create unique index:', e.message);
}
// Step 4: Verify indexes
const indexes = await col.indexes();
console.log('[Fix] Current indexes:');
indexes.forEach(idx => console.log(` - ${idx.name}: ${JSON.stringify(idx.key)} ${idx.unique ? '[UNIQUE]' : ''}`));
// Step 5: Verify 10.6.10.44
const cnt = await col.countDocuments({ ip_address: '10.6.10.44' });
console.log(`\n[Fix] Count for 10.6.10.44: ${cnt} (should be 1)`);
await mongoose.disconnect();
console.log('[Fix] Done.');
}
run().catch(err => { console.error('[Fix] Fatal:', err.message); process.exit(1); });
-71
View File
@@ -1,71 +0,0 @@
// test_api.js - Tests the actual metadata-detail API endpoint
// Run: node proxy/test_api.js
const http = require('http');
function request(path) {
return new Promise((resolve, reject) => {
const options = {
hostname: 'localhost',
port: 3001,
path,
method: 'GET',
};
const req = http.request(options, res => {
let body = '';
res.on('data', chunk => body += chunk);
res.on('end', () => {
try { resolve({ status: res.statusCode, data: JSON.parse(body) }); }
catch (e) { resolve({ status: res.statusCode, raw: body }); }
});
});
req.on('error', reject);
req.end();
});
}
async function main() {
// Test 1: netbios_hostname for 10.6.10.44
console.log('\n=== TEST 1: netbios_hostname=10.6.10.44 ===');
try {
const r1 = await request('/api/dashboard/metadata-detail?type=netbios_hostname&value=10.6.10.44');
console.log('Status:', r1.status);
if (r1.data) {
console.log('Count:', r1.data.count);
console.log('First 3 rows:', JSON.stringify(r1.data.data?.slice(0, 3), null, 2));
} else {
console.log('Raw:', r1.raw?.slice(0, 500));
}
} catch (e) {
console.log('ERROR (maybe backend is on different port):', e.message);
}
// Test 2: Try port 3000 (Next.js API routes)
console.log('\n=== TEST 2: via Next.js port 3000 ===');
try {
const r2 = await request('/api/dashboard/metadata-detail?type=netbios_hostname&value=10.6.10.44');
const options2 = { hostname: 'localhost', port: 3000, path: '/api/dashboard/metadata-detail?type=netbios_hostname&value=10.6.10.44', method: 'GET' };
const r3 = await new Promise((resolve, reject) => {
const req = http.request(options2, res => {
let body = '';
res.on('data', chunk => body += chunk);
res.on('end', () => {
try { resolve({ status: res.statusCode, data: JSON.parse(body) }); }
catch (e) { resolve({ status: res.statusCode, raw: body?.slice(0, 500) }); }
});
});
req.on('error', reject);
req.end();
});
console.log('Port 3000 - Status:', r3.status);
if (r3.data) {
console.log('Count:', r3.data.count);
console.log('First 3 rows:', JSON.stringify(r3.data.data?.slice(0, 3), null, 2));
} else {
console.log('Raw:', r3.raw);
}
} catch (e) {
console.log('Port 3000 ERROR:', e.message);
}
}
main().catch(console.error);
-1
View File
@@ -1 +0,0 @@
const mongoose = require('mongoose'); require('dotenv').config({ path: '../.env.local' }); const { LookupApp } = require('./models/Schemas'); async function test() { await mongoose.connect(process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017/backone_dpi'); const sample = await LookupApp.findOne({ tag: /youtube/i }).lean(); console.log(JSON.stringify(sample, null, 2)); await mongoose.disconnect(); } test().catch(console.error);
-89
View File
@@ -1,89 +0,0 @@
// test_metadata_detail.js - Test after restart
// Run: node proxy/test_metadata_detail.js
const http = require('http');
function post(path, body) {
return new Promise((resolve, reject) => {
const data = JSON.stringify(body);
const options = {
hostname: 'localhost', port: 3001, path, method: 'POST',
headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(data) },
};
const req = http.request(options, res => {
let buf = '';
res.on('data', c => buf += c);
res.on('end', () => {
try { resolve({ status: res.statusCode, headers: res.headers, data: JSON.parse(buf) }); }
catch { resolve({ status: res.statusCode, raw: buf }); }
});
});
req.on('error', reject);
req.write(data);
req.end();
});
}
function get(path, cookie) {
return new Promise((resolve, reject) => {
const options = {
hostname: 'localhost', port: 3001, path, method: 'GET',
headers: cookie ? { Cookie: cookie } : {},
};
const req = http.request(options, res => {
let buf = '';
res.on('data', c => buf += c);
res.on('end', () => {
try { resolve({ status: res.statusCode, data: JSON.parse(buf) }); }
catch { resolve({ status: res.statusCode, raw: buf?.slice(0, 300) }); }
});
});
req.on('error', reject);
req.end();
});
}
async function main() {
// Step 1: Login to get cookie
console.log('=== Step 1: Login ===');
const login = await post('/api/auth/login', { username: 'admin', password: 'admin123' });
console.log('Login status:', login.status);
const setCookie = login.headers?.['set-cookie'];
let cookie = '';
if (setCookie) {
cookie = setCookie.map(c => c.split(';')[0]).join('; ');
console.log('Cookie obtained:', cookie.slice(0, 60) + '...');
} else {
console.log('No cookie received. Auth response:', JSON.stringify(login.data));
// Try with a known admin credential
}
// Step 2: Test health
console.log('\n=== Step 2: Health Check ===');
const health = await get('/api/health', cookie);
console.log('Health:', health.status, JSON.stringify(health.data));
// Step 3: Test metadata-detail netbios_hostname
console.log('\n=== Step 3: metadata-detail netbios_hostname=10.6.10.44 ===');
const r = await get('/api/dashboard/metadata-detail?type=netbios_hostname&value=10.6.10.44', cookie);
console.log('Status:', r.status);
if (r.data) {
console.log('Count (should be 1):', r.data.count);
console.log('Data:', JSON.stringify(r.data.data, null, 2));
} else {
console.log('Raw:', r.raw);
}
// Step 4: Verify DB has 1 doc for 10.6.10.44
console.log('\n=== Step 4: Direct DB verification ===');
const mongoose = require('mongoose');
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '..', '.env.local') });
await mongoose.connect(process.env.MONGODB_URI || 'mongodb://localhost:27017/backone');
const db = mongoose.connection.db;
const cnt = await db.collection('devicestats').countDocuments({ ip_address: '10.6.10.44' });
console.log('DB count for 10.6.10.44:', cnt, '(expected: 1)');
await mongoose.disconnect();
}
main().catch(console.error);
-1
View File
@@ -1 +0,0 @@
const mongoose = require('mongoose'); require('dotenv').config({ path: '../.env.local' }); const { syncApplicationDictionary } = require('./netifyClient'); const { LookupApp } = require('./models/Schemas'); async function test() { await mongoose.connect(process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017/backone_dpi'); console.log('Connected to DB'); await syncApplicationDictionary(); const count = await LookupApp.countDocuments(); console.log('Total LookupApps in DB:', count); await mongoose.disconnect(); } test().catch(console.error);
-56
View File
@@ -1,56 +0,0 @@
// verify_fix.js - Directly verify the MongoDB aggregation returns correct results
// This simulates what the backend metadata-detail endpoint does after the fix.
// Run: node proxy/verify_fix.js
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '..', '.env.local') });
const mongoose = require('mongoose');
async function run() {
await mongoose.connect(process.env.MONGODB_URI || 'mongodb://localhost:27017/backone');
const db = mongoose.connection.db;
const col = db.collection('devicestats');
const testValues = ['10.6.10.44'];
// Also find other common device_labels to test
const sample = await col.find({}).limit(20).toArray();
const labels = [...new Set(sample.map(d => d.device_label).filter(Boolean))];
console.log('Sample device_labels to test:', labels.slice(0, 5));
for (const value of [...testValues, ...labels.slice(0, 3)]) {
// Count raw docs matching
const rawCount = await col.countDocuments({ device_label: value });
// Simulate the new aggregation pipeline
const aggResult = await col.aggregate([
{ $match: { device_label: value } },
{ $sort: { timestamp: -1 } },
{ $group: {
_id: '$ip_address',
mac_address: { $first: '$mac_address' },
device_label: { $first: '$device_label' },
download: { $max: '$download' },
upload: { $max: '$upload' },
}},
{ $sort: { download: -1 } },
]).toArray();
const status = rawCount > aggResult.length ? '✅ FIXED (was duplicated)' : '✓ OK';
console.log(`\ndevice_label="${value}": raw=${rawCount} rows → aggregated=${aggResult.length} unique devices ${status}`);
if (aggResult.length > 0) {
console.log(' First result:', JSON.stringify(aggResult[0], null, 2));
}
}
// Verify unique index exists
const indexes = await col.indexes();
const uniqueIdx = indexes.find(i => i.unique && i.key.agent_uuid && i.key.ip_address);
console.log('\n=== Unique Index on (agent_uuid, ip_address):', uniqueIdx ? `✅ EXISTS (${uniqueIdx.name})` : '❌ MISSING');
// Final count
const total = await col.countDocuments();
console.log('=== Total DeviceStat docs:', total);
await mongoose.disconnect();
}
run().catch(err => { console.error(err.message); process.exit(1); });
-66
View File
@@ -1,66 +0,0 @@
const { Client } = require('ssh2');
const remoteScript = `
const fs = require('fs');
const path = require('path');
const root = '/home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/.next/server/app/(dashboard)';
function scanDir(dir) {
const results = [];
if (!fs.existsSync(dir)) return results;
const items = fs.readdirSync(dir, { withFileTypes: true });
for (const item of items) {
const fullPath = path.join(dir, item.name);
if (item.isDirectory()) {
results.push(...scanDir(fullPath));
} else if (item.name.endsWith('.html') || item.name.endsWith('.js')) {
results.push(fullPath);
}
}
return results;
}
console.log('=== AUDITING ALL PAGE HEADERS AND TITLES ON DEMOPLACE.MY.ID ===\\n');
const files = scanDir(root);
files.forEach(file => {
const content = fs.readFileSync(file, 'utf8');
const rel = path.relative(root, file);
// Extract <h2> or <h1> or header titles
const h2s = [];
const h2Match = content.matchAll(/<h2[^>]*>(.*?)<\/h2>/gi);
for (const m of h2Match) {
const clean = m[1].replace(/<[^>]+>/g, '').trim();
if (clean && !h2s.includes(clean)) h2s.push(clean);
}
// Extract Learn This Page triggers
const hasHelpTrigger = content.includes('Learn This Page');
if (h2s.length > 0 || hasHelpTrigger) {
console.log('Page Route File:', rel);
if (h2s.length > 0) console.log(' Headers (H2):', h2s.join(' | '));
console.log(' Has Learn This Page Button:', hasHelpTrigger);
console.log('---');
}
});
`;
const conn = new Client();
conn.on('ready', () => {
conn.exec(`node -e ${JSON.stringify(remoteScript)}`, (err, stream) => {
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log(out);
conn.end();
});
});
}).connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
-119
View File
@@ -1,119 +0,0 @@
const { spawn } = require('child_process');
const http = require('http');
const fs = require('fs');
const path = require('path');
const WebSocket = require('next/dist/compiled/ws');
async function loginAdmin() {
return new Promise((resolve) => {
const data = JSON.stringify({ username: 'admin', password: 'admin' });
const req = http.request({
hostname: '127.0.0.1',
port: 3000,
path: '/api/auth/login',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
}
}, (res) => {
let body = '';
res.on('data', chunk => body += chunk);
res.on('end', () => {
const cookies = res.headers['set-cookie'];
if (cookies && cookies.length > 0) {
const cookieStr = cookies[0];
const match = cookieStr.match(/backone_token=([^;]+)/);
resolve(match ? match[1] : null);
} else {
resolve(null);
}
});
});
req.on('error', () => resolve(null));
req.write(data);
req.end();
});
}
async function capture() {
const token = await loginAdmin();
console.log("Logged in admin token:", token ? "FOUND" : "NOT FOUND");
const edgePath = "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe";
const edgeProc = spawn(edgePath, [
'--headless',
'--disable-gpu',
'--remote-debugging-port=9222',
'--window-size=400,844',
'http://localhost:3000/login'
]);
// Wait 2.5s for Edge CDP to listen
await new Promise(r => setTimeout(r, 2500));
try {
const targets = await new Promise((resolve, reject) => {
http.get('http://127.0.0.1:9222/json', (res) => {
let body = '';
res.on('data', c => body += c);
res.on('end', () => resolve(JSON.parse(body)));
}).on('error', reject);
});
const pageTarget = targets.find(t => t.type === 'page');
if (!pageTarget || !pageTarget.webSocketDebuggerUrl) {
console.error("No CDP page target found:", targets);
edgeProc.kill();
return;
}
const ws = new WebSocket(pageTarget.webSocketDebuggerUrl);
let messageId = 1;
const send = (method, params = {}) => {
return new Promise((res) => {
const id = messageId++;
const handler = (data) => {
const msg = JSON.parse(data);
if (msg.id === id) {
ws.removeListener('message', handler);
res(msg.result);
}
};
ws.on('message', handler);
ws.send(JSON.stringify({ id, method, params }));
});
};
ws.on('open', async () => {
console.log("Connected to Edge CDP WebSocket!");
if (token) {
await send('Network.setCookie', {
name: 'backone_token',
value: token,
domain: 'localhost',
path: '/'
});
}
await send('Page.navigate', { url: 'http://localhost:3000/' });
// Wait for page load and 3D globe rendering
await new Promise(r => setTimeout(r, 5000));
const screenshot = await send('Page.captureScreenshot', { format: 'png' });
const outputPath = "C:\\Users\\rafif\\.gemini\\antigravity-ide\\brain\\d6704840-c7e7-4558-b215-0fe98bbfb07a\\mobile-dashboard-live.png";
fs.writeFileSync(outputPath, Buffer.from(screenshot.data, 'base64'));
console.log("SUCCESS! Screenshot written to:", outputPath, "Size:", fs.statSync(outputPath).size, "bytes");
ws.close();
edgeProc.kill();
});
} catch (err) {
console.error("CDP Error:", err.message);
edgeProc.kill();
}
}
capture();
-67
View File
@@ -1,67 +0,0 @@
// scripts/check-agents-error.js
'use strict';
const { Client } = require('ssh2');
const https = require('https');
const SSH = { host: '103.185.47.52', port: 2222, username: 'adminbackend', password: 'htEo7x6LsBQiEHHH', readyTimeout: 60000 };
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
function exec(conn, cmd, label) {
if (label) console.log('\n[' + label + ']');
console.log('$ ' + cmd.substring(0, 80));
return new Promise(resolve => {
conn.exec(cmd, (err, s) => {
if (err) { resolve(''); return; }
let out = '';
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
.on('close', () => resolve(out));
});
});
}
async function httpGet(url, opts) {
return new Promise(resolve => {
const req = https.get(url, { timeout: 10000, rejectUnauthorized: false, ...opts }, res => {
let body = '';
res.on('data', d => body += d);
res.on('end', () => resolve({ status: res.statusCode, body: body.substring(0, 500) }));
});
req.on('error', e => resolve({ status: 0, error: e.message }));
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
});
}
async function main() {
const conn = new Client();
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(SSH); });
console.log('[SSH] Connected\n');
// 1. Cek error log frontend
await exec(conn, 'tail -50 ' + PUB + '/logs/frontend-error.log 2>/dev/null | head -50', '1. Frontend error log');
// 2. Cek frontend out log terbaru
await exec(conn, 'tail -30 ' + PUB + '/logs/frontend-out.log 2>/dev/null', '2. Frontend out log');
// 3. Test API agents langsung dari server
await exec(conn, 'curl -sk http://127.0.0.1:3001/api/agents 2>/dev/null | head -c 500', '3. Test API /api/agents langsung');
// 4. Test API health backend
await exec(conn, 'curl -sk http://127.0.0.1:3001/api/health 2>/dev/null', '4. Test backend health');
// 5. Cek .env.production - apakah BACKEND_URL benar
await exec(conn, 'cat ' + PUB + '/.env.production 2>/dev/null | grep -v PASSWORD | grep -v SECRET | grep -v MONGO | head -20', '5. Environment variables (safe)');
// 6. Cek apakah backend bisa akses agents collection dari MongoDB
await exec(conn, 'curl -sk http://127.0.0.1:3001/api/agents/list 2>/dev/null | head -c 300', '6. Test /api/agents/list');
conn.end();
// 7. Test dari luar via domain
console.log('\n[7. Test API agents via domain...]');
const r = await httpGet('https://demoplace.my.id/api/agents');
console.log(' Status: ' + r.status);
console.log(' Body: ' + (r.body || r.error || 'empty'));
}
main().catch(e => console.error('[FATAL]', e.message));
-22
View File
@@ -1,22 +0,0 @@
const { Client } = require('ssh2');
const conn = new Client();
conn.on('ready', () => {
console.log('SSH Client Ready');
const cmd = `tail -n 200 /home/adminbackend/.pm2/logs/backone-backend-error-*.log /home/adminbackend/.pm2/logs/backone-backend-out-*.log /home/adminbackend/.pm2/logs/backone-frontend-error-*.log /home/adminbackend/.pm2/logs/backone-frontend-out-*.log 2>/dev/null | tail -n 200`;
conn.exec(cmd, (err, stream) => {
if (err) throw err;
stream.on('close', (code, signal) => {
conn.end();
}).on('data', (data) => {
console.log(data.toString());
}).stderr.on('data', (data) => {
console.log('STDERR: ' + data.toString());
});
});
}).connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
-94
View File
@@ -1,94 +0,0 @@
// scripts/check-static-files.js
// Cek apakah static chunk files ada di disk dan bisa diakses via domain
'use strict';
const { Client } = require('ssh2');
const https = require('https');
const SSH = {
host: '103.185.47.52', port: 2222,
username: 'adminbackend', password: 'htEo7x6LsBQiEHHH',
readyTimeout: 60000
};
function sshExec(conn, cmd) {
return new Promise(resolve => {
conn.exec(cmd, (err, s) => {
if (err) { resolve('SSH_ERROR'); return; }
let out = '';
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
.on('close', () => resolve(out));
});
});
}
function httpGet(url) {
return new Promise(resolve => {
const req = https.get(url, { timeout: 10000, rejectUnauthorized: false }, res => {
let body = '';
res.on('data', d => body += d);
res.on('end', () => resolve({ status: res.statusCode, type: res.headers['content-type'], size: body.length }));
});
req.on('error', e => resolve({ status: 0, error: e.message }));
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
});
}
async function main() {
const conn = new Client();
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(SSH); });
console.log('[SSH] Connected\n');
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
// 1. List chunks directory
console.log('=== .next/static/chunks/ contents ===');
await sshExec(conn, `ls -la ${PUB}/.next/static/chunks/ | head -20`);
// 2. Cek CSS files yang direferensikan oleh HTML
console.log('\n=== Cek file CSS spesifik ===');
await sshExec(conn, `ls -la ${PUB}/.next/static/chunks/*.css 2>/dev/null | head -5 || echo "Tidak ada .css di chunks/"`);
// 3. Cek apakah JS bootstrap file ada
console.log('\n=== Cek file JS yang diperlukan ===');
await sshExec(conn, `ls ${PUB}/.next/static/chunks/ | grep -E "(3km6z|21luguo|1-8s9)" | head -10 || echo "File JS tidak ditemukan"`);
// 4. Test akses static file via domain (dari dalam server)
console.log('\n=== Test static file via Apache ===');
await sshExec(conn,
`curl -sk -D - https://demoplace.my.id/_next/static/chunks/3km6z-n6wbgrs.js 2>/dev/null | head -15 || ` +
`curl -sk -D - http://103.185.47.52:8080/_next/static/chunks/3km6z-n6wbgrs.js 2>/dev/null | head -15`
);
// 5. Test apakah Nginx melayani file static langsung
console.log('\n=== Cek Nginx serving static (port 443) ===');
await sshExec(conn,
`curl -sk -w "\\nHTTP: %{http_code} | Type: %{content_type} | Size: %{size_download}" ` +
`-o /dev/null https://demoplace.my.id/_next/static/chunks/3km6z-n6wbgrs.js`
);
// 6. Cek apakah ada .next/server/ directory
console.log('\n=== Status .next/server/ ===');
await sshExec(conn, `ls ${PUB}/.next/server/ 2>/dev/null | head -5 || echo ".next/server/ TIDAK ADA - standalone build mungkin tidak lengkap"`);
conn.end();
// 7. Test dari luar - JS dan CSS
console.log('\n=== Test static resources dari luar ===');
const files = [
'/_next/static/chunks/3km6z-n6wbgrs.js',
'/_next/static/chunks/1u6dw_tm45utz.css',
'/_next/static/chunks/1oskchnhjm4n8.css',
'/_next/static/chunks/21luguo5_g2uu.js',
];
for (const f of files) {
const r = await httpGet(`https://demoplace.my.id${f}`);
const icon = r.status === 200 ? '✅' : '❌';
console.log(` ${icon} ${f}`);
console.log(` HTTP ${r.status} | Type: ${r.type || 'N/A'} | Size: ${r.size || 0} bytes`);
}
}
main().catch(err => console.error('[FATAL]', err.message));
-61
View File
@@ -1,61 +0,0 @@
const https = require('https');
const PAGES = [
'/',
'/network-infrastructure',
'/agents',
'/devices',
'/flows',
'/apps',
'/network-intelligence',
'/dns',
'/geography',
'/dpi-analytics',
'/lookup',
'/intelligence',
'/threats',
'/events',
'/security-audit',
'/help'
];
function fetchPage(route) {
return new Promise((resolve) => {
https.get(`https://demoplace.my.id${route}`, (res) => {
let data = '';
res.on('data', chunk => data += chunk);
res.on('end', () => {
const titleMatch = data.match(/<title>(.*?)<\/title>/i);
const descMatch = data.match(/<meta name="description" content="(.*?)"/i);
const title = titleMatch ? titleMatch[1] : 'N/A';
const desc = descMatch ? descMatch[1] : 'N/A';
// Find logo references
const logos = [];
const logoRegex = /src="([^"]*(?:logo|icon)[^"]*)"/gi;
let match;
while ((match = logoRegex.exec(data)) !== null) {
if (!logos.includes(match[1])) logos.push(match[1]);
}
resolve({ route, statusCode: res.statusCode, title, desc, logos });
});
}).on('error', (err) => {
resolve({ route, error: err.message });
});
});
}
async function main() {
console.log('=== AUDITING DEMOPLACE.MY.ID PAGES ===\n');
for (const page of PAGES) {
const res = await fetchPage(page);
console.log(`Route: ${res.route}`);
console.log(` Title : ${res.title}`);
console.log(` Description : ${res.desc}`);
console.log(` Logos/Icons : ${res.logos ? res.logos.join(', ') : 'None'}`);
console.log('---');
}
}
main();
-97
View File
@@ -1,97 +0,0 @@
// scripts/copy-from-backslash.js
// Copy file dari direktori backslash ke path yang benar
'use strict';
const { Client } = require('ssh2');
const https = require('https');
const SSH = { host: '103.185.47.52', port: 2222, username: 'adminbackend', password: 'htEo7x6LsBQiEHHH', readyTimeout: 60000 };
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
const SA = PUB + '/.next/standalone/.next/static';
const BSDir = PUB + '/.next\\static\\chunks'; // Backslash literal path
function exec(conn, cmd, label) {
if (label) console.log('\n[' + label + ']');
console.log('$ ' + cmd.substring(0, 90));
return new Promise(resolve => {
conn.exec(cmd, (err, s) => {
if (err) { resolve(''); return; }
let out = '';
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
.on('close', () => resolve(out));
});
});
}
async function httpGet(url) {
return new Promise(resolve => {
const req = https.get(url, { timeout: 12000, rejectUnauthorized: false }, res => {
let body = '';
res.on('data', d => body += d);
res.on('end', () => resolve({ status: res.statusCode, size: body.length }));
});
req.on('error', e => resolve({ status: 0, error: e.message }));
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
});
}
async function main() {
const conn = new Client();
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(SSH); });
console.log('[SSH] Connected\n');
// 1. List isi direktori backslash
await exec(conn, "ls '" + BSDir + "' | grep css | head -10", '1. CSS di direktori backslash');
// 2. Copy semua file dari direktori backslash ke standalone/chunks
await exec(conn,
"cp '" + BSDir + "/'* '" + SA + "/chunks/' 2>&1 && echo 'COPY OK' || echo 'COPY PARTIAL'",
'2. Copy semua file dari backslash dir ke standalone/chunks'
);
// 3. Verifikasi CSS yang hilang sudah ada
await exec(conn,
"ls '" + SA + "/chunks/' | grep '1oskchnhjm4n8'",
'3. Verifikasi 1oskchnhjm4n8.css ada'
);
// 4. Juga cek nested static dir (ada static/static/)
await exec(conn,
"ls '" + SA + "/static/' 2>/dev/null | head -10 || echo 'Tidak ada nested static'",
'4. Cek nested static dir'
);
// 5. Cek juga backslash css dir (beda dengan chunks)
await exec(conn,
"ls '" + PUB + "/.next\\static\\css' 2>/dev/null | head -10 || echo 'Tidak ada backslash css dir'",
'5. Cek backslash css dir'
);
// 6. Copy CSS dari backslash css dir juga jika ada
await exec(conn,
"[ -d '" + PUB + "/.next\\static\\css' ] && cp '" + PUB + "/.next\\static\\css/'* '" + SA + "/css/' 2>&1 && echo 'CSS copy OK' || echo 'Tidak ada backslash css dir'",
'6. Copy dari backslash css dir'
);
conn.end();
// 7. Final test
console.log('\n[7. Final test semua static files...]');
await new Promise(r => setTimeout(r, 2000));
const files = [
'/_next/static/chunks/1oskchnhjm4n8.css',
'/_next/static/chunks/1u6dw_tm45utz.css',
'/_next/static/chunks/3km6z-n6wbgrs.js',
'/_next/static/chunks/21luguo5_g2uu.js',
'/_next/static/chunks/1-8s9_t85wwr4.js',
'/login',
];
for (const f of files) {
const r = await httpGet('https://demoplace.my.id' + f);
const icon = r.status === 200 ? '✅' : '❌';
console.log(' ' + icon + ' HTTP ' + r.status + ' | ' + (r.size || 0) + ' bytes | ' + f);
}
console.log('\n✅ Selesai! Hard refresh browser (Ctrl+Shift+R)\n');
}
main().catch(e => console.error('[FATAL]', e.message));
-48
View File
@@ -1,48 +0,0 @@
// scripts/deep-diag.js
'use strict';
const { Client } = require('ssh2');
const conn = new Client();
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
function exec(conn, cmd) {
console.log('\n$ ' + cmd.substring(0, 80));
return new Promise(resolve => {
conn.exec(cmd, (err, s) => {
if (err) { resolve(''); return; }
let out = '';
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
.on('close', () => resolve(out));
});
});
}
conn.on('ready', async () => {
// 1. Cek proses yang sedang berjalan
await exec(conn, 'ps -p 3193322 -o cmd 2>/dev/null | tail -1');
// 2. Cek BUILD_ID di standalone
const saPath = PUB + '/.next/standalone';
await exec(conn, 'cat ' + saPath + '/.next/BUILD_ID 2>/dev/null || echo NO_BUILD_ID_IN_STANDALONE');
// 3. List chunks di standalone
await exec(conn, 'ls ' + saPath + '/.next/static/chunks/ | head -15');
// 4. List static root di standalone
await exec(conn, 'ls ' + saPath + '/.next/static/');
// 5. Cek apakah ada server.js lain yang mungkin sedang berjalan
await exec(conn, 'ps aux | grep "node.*server" | grep -v grep | head -5');
// 6. PM2 info untuk backone-frontend
await exec(conn, '/home/adminbackend/.npm-global/bin/pm2 show backone-frontend 2>/dev/null | grep -E "(script|cwd|pid|restart)"');
// 7. Cek log terbaru
await exec(conn, 'tail -20 ' + PUB + '/logs/frontend-out.log 2>/dev/null | head -20');
conn.end();
}).connect({
host: '103.185.47.52', port: 2222,
username: 'adminbackend', password: 'htEo7x6LsBQiEHHH',
readyTimeout: 30000
});
-57
View File
@@ -1,57 +0,0 @@
const { Client } = require('ssh2');
const fs = require('fs');
const remoteScript = `
const fs = require('fs');
const path = require('path');
const root = '/home/adminbackend/web/demoplace.my.id/public_html';
console.log('=== 1. LOGOS & IMAGES IN PUBLIC ===');
try {
const publicFiles = fs.readdirSync(path.join(root, 'public'));
console.log('Files in public/:', publicFiles);
} catch(e) { console.log('Err:', e.message); }
console.log('\\n=== 2. AUDITING NAVIGATION GROUPS IN STANDALONE CHUNKS ===');
const chunksDir = path.join(root, '.next/standalone/.next/server/chunks');
if (fs.existsSync(chunksDir)) {
const files = fs.readdirSync(chunksDir);
files.forEach(f => {
if (!f.endsWith('.js')) return;
const content = fs.readFileSync(path.join(chunksDir, f), 'utf8');
if (content.includes('Overview Dashboard') || content.includes('Network Topology')) {
console.log('Chunk File:', f);
const match = content.match(/title:\"OVERVIEW\".*?title:\"SECURITY & ALERTS\".*?\]/);
if (match) {
console.log('NAV MATCH:', match[0]);
}
}
});
}
console.log('\\n=== 3. APP ROUTE DIRECTORIES ===');
try {
const appDir = path.join(root, '.next/standalone/.next/server/app/(dashboard)');
if (fs.existsSync(appDir)) {
console.log('Dashboard routes in .next/standalone:', fs.readdirSync(appDir));
}
} catch(e) { console.log('Err app dir:', e.message); }
`;
const conn = new Client();
conn.on('ready', () => {
conn.exec(`node -e ${JSON.stringify(remoteScript)}`, (err, stream) => {
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log(out);
conn.end();
});
});
}).connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
-206
View File
@@ -1,206 +0,0 @@
// scripts/deploy-php-proxy.js
// ─────────────────────────────────────────────────────────────────────────────
// BackOne DPI — Deploy PHP proxy ke public_html
// Solusi 502: Apache PHP-FPM forward semua request ke Next.js port 3000
// Tidak butuh mod_proxy_http, root access, atau Hestia API
// ─────────────────────────────────────────────────────────────────────────────
'use strict';
const { Client } = require('ssh2');
const SftpClient = require('ssh2-sftp-client');
const https = require('https');
const path = require('path');
const SSH_CONFIG = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
readyTimeout: 60000
};
const ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
// ── PHP Proxy script ──────────────────────────────────────────────────────
const PHP_PROXY = `<?php
/**
* BackOne DPI — PHP Reverse Proxy
* Meneruskan semua request HTTP ke Next.js yang berjalan di port 3000
* File ini dikelola otomatis. Jangan dihapus.
*/
// Target: Next.js port 3000
define('NEXTJS_URL', 'http://127.0.0.1:3000');
define('TIMEOUT', 30);
// Ambil URI request
$requestUri = $_SERVER['REQUEST_URI'] ?? '/';
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
$target = NEXTJS_URL . $requestUri;
// Kumpulkan headers dari request asli
$forwardHeaders = [
'X-Forwarded-For: ' . ($_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1'),
'X-Forwarded-Proto: https',
'X-Real-IP: ' . ($_SERVER['REMOTE_ADDR'] ?? ''),
'Host: ' . ($_SERVER['HTTP_HOST'] ?? 'demoplace.my.id'),
];
// Tambahkan headers lain dari request
$allHeaders = getallheaders() ?: [];
$skipHeaders = ['host', 'connection', 'transfer-encoding', 'keep-alive', 'content-length'];
foreach ($allHeaders as $name => $value) {
if (!in_array(strtolower($name), $skipHeaders)) {
$forwardHeaders[] = "$name: $value";
}
}
// Body untuk POST/PUT/PATCH
$body = in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE']) ? file_get_contents('php://input') : null;
// Kirim request ke Next.js
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $target,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => $forwardHeaders,
CURLOPT_POSTFIELDS => $body,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true,
CURLOPT_FOLLOWLOCATION => false,
CURLOPT_TIMEOUT => TIMEOUT,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_ENCODING => '',
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$curlError = curl_error($ch);
curl_close($ch);
// Jika curl error
if ($response === false) {
http_response_code(502);
header('Content-Type: text/plain');
echo 'BackOne: Gagal terhubung ke Next.js. Error: ' . $curlError;
exit;
}
// Pisah headers dan body
$responseHeaders = substr($response, 0, $headerSize);
$responseBody = substr($response, $headerSize);
// Set HTTP status
http_response_code($httpCode ?: 200);
// Forward response headers ke client
$skipResponseHeaders = ['transfer-encoding', 'connection', 'keep-alive', 'content-encoding'];
foreach (explode("\\r\\n", $responseHeaders) as $header) {
$header = trim($header);
if (empty($header) || preg_match('/^HTTP\\//i', $header)) continue;
$colonPos = strpos($header, ':');
if ($colonPos === false) continue;
$headerName = strtolower(trim(substr($header, 0, $colonPos)));
if (in_array($headerName, $skipResponseHeaders)) continue;
header($header, false);
}
// Kirim body
echo $responseBody;
`;
// ── .htaccess baru: route semua request ke proxy.php ─────────────────────
const HTACCESS = `# BackOne DPI — Apache .htaccess
# Redirect HTTP ke HTTPS
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# Route semua request ke PHP proxy (meneruskan ke Next.js port 3000)
RewriteCond %{REQUEST_FILENAME} !proxy.php
RewriteRule ^(.*)$ /proxy.php [L,QSA]
`;
// ── Fungsi upload file via SFTP ───────────────────────────────────────────
async function uploadFile(sftp, content, remotePath) {
const buf = Buffer.from(content, 'utf8');
await sftp.put(buf, remotePath);
console.log(` ✅ Upload: ${remotePath}`);
}
// ── SSH command ────────────────────────────────────────────────────────────
function sshExec(conn, cmd) {
console.log(`\n$ ${cmd.substring(0, 100)}...`);
return new Promise((resolve, reject) => {
conn.exec(cmd, (err, stream) => {
if (err) return reject(err);
let out = '';
stream.on('close', () => resolve(out))
.on('data', d => { out += d; process.stdout.write(d.toString()); })
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); });
});
});
}
async function main() {
console.log('\n╔══════════════════════════════════════════════════════════╗');
console.log('║ BackOne DPI — Deploy PHP Proxy (Fix 502) ║');
console.log('╚══════════════════════════════════════════════════════════╝\n');
// ── Upload via SFTP ──────────────────────────────────────────────────────
console.log('▶ Step 1: Upload proxy.php dan .htaccess via SFTP...\n');
const sftp = new SftpClient();
await sftp.connect(SSH_CONFIG);
await uploadFile(sftp, PHP_PROXY, `${ROOT}/proxy.php`);
await uploadFile(sftp, HTACCESS, `${ROOT}/.htaccess`);
await sftp.end();
// ── Verify dan test via SSH ──────────────────────────────────────────────
console.log('\n▶ Step 2: Verifikasi file di server...');
const conn = new Client();
await new Promise((resolve, reject) => { conn.on('ready', resolve).on('error', reject).connect(SSH_CONFIG); });
console.log('[SSH] Terhubung!\n');
await sshExec(conn, `ls -la ${ROOT}/proxy.php ${ROOT}/.htaccess`);
await sshExec(conn, `head -5 ${ROOT}/proxy.php`);
await sshExec(conn, `cat ${ROOT}/.htaccess`);
// ── Test internal Apache response ─────────────────────────────────────
console.log('\n▶ Step 3: Test Apache internal (port 8080)...');
await sshExec(conn, `curl -sk -o /dev/null -w "Apache HTTP: %{http_code}" http://127.0.0.1:8080/`);
await sshExec(conn, `curl -sk -o /dev/null -w "Apache Login: %{http_code}" http://127.0.0.1:8080/login`);
// ── Test domain publik ─────────────────────────────────────────────────
console.log('\n▶ Step 4: Test domain demoplace.my.id...');
await sshExec(conn,
`sleep 2 && curl -sk -o /dev/null -w "HTTPS /: %{http_code}" https://demoplace.my.id/ && ` +
`curl -sk -o /dev/null -w " | HTTPS /login: %{http_code}" https://demoplace.my.id/login`
);
conn.end();
// ── Final test dari luar ───────────────────────────────────────────────
console.log('\n▶ Step 5: Final test dari jaringan lokal...');
await new Promise(r => setTimeout(r, 3000));
for (const path of ['/', '/login']) {
const r = await new Promise(resolve => {
const req = https.get(`https://demoplace.my.id${path}`,
{ timeout: 12000, rejectUnauthorized: false },
res => resolve({ status: res.statusCode, location: res.headers.location })
);
req.on('error', e => resolve({ status: 0, error: e.message }));
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
});
const icon = r.status >= 200 && r.status < 400 ? '✅' : r.status === 0 ? '⚠️ ' : '❌';
console.log(` ${icon} https://demoplace.my.id${path} → HTTP ${r.status} ${r.error || ''}`);
if (r.location) console.log(` → Redirect ke: ${r.location}`);
}
console.log('\n✅ PHP Proxy berhasil di-deploy!\n');
console.log('Cek browser: https://demoplace.my.id/login\n');
}
main().catch(err => { console.error('[FATAL]', err.message); process.exit(1); });
-117
View File
@@ -1,117 +0,0 @@
const { Client } = require('ssh2');
const SftpClient = require('ssh2-sftp-client');
const path = require('path');
const fs = require('fs');
const archiver = require('archiver');
const config = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
};
const DEPLOY_DIR = 'backone-production';
async function createZip() {
console.log("Packaging application...");
return new Promise((resolve, reject) => {
const output = fs.createWriteStream(path.join(__dirname, '../deploy.zip'));
const archive = new archiver.ZipArchive({ zlib: { level: 9 } });
output.on('close', () => resolve(path.join(__dirname, '../deploy.zip')));
archive.on('error', (err) => reject(err));
archive.pipe(output);
// Add standalone output
archive.directory(path.join(__dirname, '../.next/standalone'), false);
// Add static assets (Next.js standalone requires these copied over)
archive.directory(path.join(__dirname, '../.next/static'), '.next/static');
archive.directory(path.join(__dirname, '../public'), 'public');
// Add backend and proxy
archive.directory(path.join(__dirname, '../backend'), 'backend');
archive.directory(path.join(__dirname, '../proxy'), 'proxy');
// Add production env
archive.file(path.join(__dirname, '../.env.production'), { name: '.env.production' });
archive.finalize();
});
}
async function runSSH(cmd) {
return new Promise((resolve, reject) => {
const conn = new Client();
conn.on('ready', () => {
conn.exec(cmd, (err, stream) => {
if (err) return reject(err);
let out = '';
stream.on('close', (code, signal) => {
conn.end();
resolve(out);
}).on('data', (data) => {
out += data;
}).stderr.on('data', (data) => {
out += data;
});
});
}).on('error', reject).connect(config);
});
}
async function deploy() {
const sftp = new SftpClient();
let zipPath;
try {
zipPath = await createZip();
console.log("Package created successfully.");
console.log("Connecting to SFTP server...");
await sftp.connect(config);
console.log("Creating deployment directory...");
const homeDir = await runSSH('pwd');
const targetDir = `${homeDir.trim()}/${DEPLOY_DIR}`;
await runSSH(`mkdir -p ${targetDir}`);
console.log(`Uploading deploy.zip to ${targetDir}...`);
await sftp.put(zipPath, `${targetDir}/deploy.zip`);
console.log("Extracting package on server...");
await runSSH(`cd ${targetDir} && unzip -o deploy.zip && rm deploy.zip`);
console.log("Installing production dependencies for backend & proxy...");
await runSSH(`cd ${targetDir}/backend && npm install --production`);
await runSSH(`cd ${targetDir}/proxy && npm install --production`);
console.log("Configuring PM2...");
// Create ecosystem file for PM2
const ecosystem = `
module.exports = {
apps: [
{ name: 'backone-proxy', script: './proxy/index.js', env_file: '.env.production' },
{ name: 'backone-backend', script: './backend/server.js', env_file: '.env.production' },
{ name: 'backone-frontend', script: 'server.js', env_file: '.env.production' }
]
};`;
await runSSH(`cd ${targetDir} && echo "${ecosystem.replace(/\n/g, '\\n')}" > ecosystem.config.js`);
console.log("Restarting PM2 processes...");
const pm2Result = await runSSH(`cd ${targetDir} && pm2 start ecosystem.config.js || pm2 restart ecosystem.config.js`);
console.log(pm2Result);
console.log("Deployment completed successfully!");
console.log(`BackOne Dashboard is now live. Please map your Nginx/Apache domain demoplace.my.id to http://127.0.0.1:3000`);
} catch(e) {
console.error("Deployment failed:", e.message);
} finally {
sftp.end();
if (fs.existsSync(zipPath)) fs.unlinkSync(zipPath);
}
}
deploy();
-84
View File
@@ -1,84 +0,0 @@
const https = require('https');
const ROUTES = [
'/',
'/agents',
'/apps',
'/devices',
'/dns',
'/dpi-analytics',
'/encryption-audit',
'/events',
'/flows',
'/geography',
'/intelligence',
'/lookup',
'/network-infrastructure',
'/network-intelligence',
'/network-topology',
'/security-audit',
'/threat-intelligence',
'/threats',
'/traffic-categories',
'/help',
'/login'
];
function auditRoute(route) {
return new Promise((resolve) => {
https.get(`https://demoplace.my.id${route}`, (res) => {
let data = '';
res.on('data', c => data += c);
res.on('end', () => {
const title = (data.match(/<title>(.*?)<\/title>/i) || [])[1] || 'N/A';
const desc = (data.match(/<meta name="description" content="(.*?)"/i) || [])[1] || 'N/A';
const icons = [];
const iconMatches = data.matchAll(/rel="icon" href="([^"]+)"/gi);
for (const m of iconMatches) icons.push(m[1]);
const imgs = [];
const imgMatches = data.matchAll(/src="([^"]*(?:logo|brand|icon|png|svg|jpg)[^"]*)"/gi);
for (const m of imgMatches) {
if (!imgs.includes(m[1])) imgs.push(m[1]);
}
const headers = [];
const hMatches = data.matchAll(/<h[123][^>]*>(.*?)<\/h[123]>/gi);
for (const m of hMatches) {
const clean = m[1].replace(/<[^>]+>/g, '').trim();
if (clean && !headers.includes(clean)) headers.push(clean);
}
resolve({
route,
status: res.statusCode,
is404: data.includes('404: This page could not be found'),
title,
desc,
icons,
imgs,
headers
});
});
}).on('error', err => resolve({ route, error: err.message }));
});
}
async function main() {
console.log('=== DETAILED AUDIT OF DEMOPLACE.MY.ID ===\n');
for (const r of ROUTES) {
const res = await auditRoute(r);
if (res.is404) {
console.log(`❌ [404 NOT FOUND] ${res.route}`);
} else {
console.log(`✅ [200 OK] ${res.route}`);
console.log(` Title : ${res.title}`);
console.log(` Icons : ${res.icons.join(', ')}`);
console.log(` Images/Logo: ${res.imgs.join(', ')}`);
console.log(` Headers : ${res.headers.join(' | ')}`);
}
console.log('--------------------------------------------------');
}
}
main();
-99
View File
@@ -1,99 +0,0 @@
// scripts/diagnose-ports.js
// Cek port apa yang aktif dan test PHP proxy di port yang benar
'use strict';
const { Client } = require('ssh2');
const SSH = {
host: '103.185.47.52', port: 2222,
username: 'adminbackend', password: 'htEo7x6LsBQiEHHH',
readyTimeout: 60000
};
function sshExec(conn, cmd, label = '') {
if (label) console.log(`\n[${label}]`);
console.log(`$ ${cmd.substring(0, 100)}${cmd.length > 100 ? '...' : ''}`);
return new Promise((resolve, reject) => {
conn.exec(cmd, (err, stream) => {
if (err) return reject(err);
let out = '';
stream.on('close', () => resolve(out))
.on('data', d => { out += d; process.stdout.write(d.toString()); })
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); });
});
});
}
async function main() {
console.log('\n╔══════════════════════════════════════════════════════════╗');
console.log('║ BackOne DPI — Diagnosa Port & PHP Proxy Test ║');
console.log('╚══════════════════════════════════════════════════════════╝\n');
const conn = new Client();
await new Promise((resolve, reject) => { conn.on('ready', resolve).on('error', reject).connect(SSH); });
console.log('[SSH] Terhubung!\n');
// 1. Cek semua port yang aktif
await sshExec(conn,
'echo "=== SEMUA PORT AKTIF ===" && ss -tlnp | grep -E "(80|443|3000|3001|4000|8008|8009|8080|8443)"',
'PORT AKTIF'
);
// 2. Cek apakah Apache aktif di berbagai port
await sshExec(conn,
'echo "=== TES APACHE PORT 8009 ===" && curl -sk -o /dev/null -w "Port 8009: %{http_code}" http://127.0.0.1:8009/login',
'TES PORT 8009'
);
await sshExec(conn,
'echo "=== TES APACHE PORT 8080 (IP publik) ===" && curl -sk -o /dev/null -w "Port 8080 publik: %{http_code}" http://103.185.47.52:8080/login',
'TES PORT 8080'
);
// 3. Cek apakah PHP FPM socket ada
await sshExec(conn,
'ls -la /run/php/php*-fpm-demoplace* 2>/dev/null || echo "Tidak ada PHP FPM socket untuk domain ini"',
'PHP FPM SOCKET'
);
// 4. Cek isi .htaccess yang aktif
await sshExec(conn,
'cat /home/adminbackend/web/demoplace.my.id/public_html/.htaccess',
'HTACCESS AKTIF'
);
// 5. Cek apakah proxy.php bisa diakses via Apache
await sshExec(conn,
'curl -sk -v http://127.0.0.1:8009/proxy.php 2>&1 | head -30',
'TES proxy.php via port 8009'
);
// 6. Test direct PHP execution
await sshExec(conn,
'php -r "echo curl_version()[\'version\'];" 2>/dev/null && echo " (PHP curl OK)" || echo "PHP curl tidak tersedia"',
'CEK PHP CURL'
);
// 7. Cek Apache error log
await sshExec(conn,
'tail -20 /var/log/apache2/domains/demoplace.my.id.error.log 2>/dev/null | grep -v "^\$" | tail -10 || echo "Tidak bisa akses error log"',
'APACHE ERROR LOG'
);
// 8. Test Next.js langsung
await sshExec(conn,
'curl -sk -o /dev/null -w "Next.js port 3000 /login: %{http_code}" http://127.0.0.1:3000/login',
'TES NEXT.JS LANGSUNG'
);
// 9. Coba test PHP via curl dengan header Host
await sshExec(conn,
'curl -sk -H "Host: demoplace.my.id" -o /dev/null -w "Apache dengan Host header: %{http_code}" http://127.0.0.1:8009/',
'TES APACHE HOST HEADER'
);
conn.end();
console.log('\n✅ Diagnosa selesai!\n');
}
main().catch(err => { console.error('[FATAL]', err.message); process.exit(1); });
-90
View File
@@ -1,90 +0,0 @@
// scripts/download-production.js
'use strict';
const SftpClient = require('ssh2-sftp-client');
const path = require('path');
const fs = require('fs');
const CONFIG = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
remotePath: '/home/adminbackend/web/demoplace.my.id/public_html',
};
const LOCAL_ROOT = path.resolve(__dirname, '..');
const DIRS_TO_DOWNLOAD = ['src', 'backend', 'proxy', 'public', 'scripts'];
const FILES_TO_DOWNLOAD = [
'package.json',
'package-lock.json',
'next.config.ts',
'postcss.config.mjs',
'tsconfig.json',
'eslint.config.mjs',
'README.md',
'SKILLS.md',
'Dockerfile',
'docker-compose.yml',
'docker-compose.prod.yml',
'ecosystem.config.js',
'deploy.sh'
];
async function main() {
const sftp = new SftpClient();
try {
console.log(`[SFTP] Connecting to ${CONFIG.host}:${CONFIG.port}...`);
await sftp.connect({
host: CONFIG.host,
port: CONFIG.port,
username: CONFIG.username,
password: CONFIG.password,
});
console.log('[SFTP] Connected successfully.');
// 1. Download directories recursively
for (const dirName of DIRS_TO_DOWNLOAD) {
const remoteDir = `${CONFIG.remotePath}/${dirName}`;
const localDir = path.join(LOCAL_ROOT, dirName);
if (await sftp.exists(remoteDir)) {
console.log(`[SFTP] Downloading directory: ${dirName}...`);
fs.mkdirSync(localDir, { recursive: true });
await sftp.downloadDir(remoteDir, localDir, {
filter: (filePath, isDir) => {
const basename = path.basename(filePath);
return !['node_modules', '.next', '.git', 'logs', 'repo.zip'].includes(basename);
}
});
console.log(`[SFTP] Finished downloading directory: ${dirName}`);
} else {
console.warn(`[SFTP] Remote directory not found: ${remoteDir}`);
}
}
// 2. Download specific root files
for (const fileName of FILES_TO_DOWNLOAD) {
const remoteFile = `${CONFIG.remotePath}/${fileName}`;
const localFile = path.join(LOCAL_ROOT, fileName);
if (await sftp.exists(remoteFile)) {
console.log(`[SFTP] Downloading file: ${fileName}...`);
await sftp.fastGet(remoteFile, localFile);
console.log(`[SFTP] Downloaded: ${fileName}`);
} else {
console.warn(`[SFTP] Remote file not found: ${remoteFile}`);
}
}
console.log('\n✅ [SFTP] Download of production codebase (10/10) completed successfully!');
} catch (err) {
console.error('❌ [SFTP] Download failed:', err);
process.exit(1);
} finally {
await sftp.end();
}
}
main();
-42
View File
@@ -1,42 +0,0 @@
// scripts/export-local-db.js
const { MongoClient } = require('mongodb');
const fs = require('fs');
const path = require('path');
const LOCAL_URI = 'mongodb://127.0.0.1:27017/backone_dpi';
const DB_NAME = 'backone_dpi';
const COLLECTIONS_TO_EXPORT = ['users', 'tenantconfigs', 'customagentlocations'];
const OUTPUT_DIR = path.join(__dirname, '..', 'migration-temp');
async function main() {
console.log('Connecting to local MongoDB...');
const client = new MongoClient(LOCAL_URI);
try {
await client.connect();
console.log('✓ Connected to local MongoDB successfully.');
const db = client.db(DB_NAME);
if (!fs.existsSync(OUTPUT_DIR)) {
fs.mkdirSync(OUTPUT_DIR);
}
for (const colName of COLLECTIONS_TO_EXPORT) {
console.log(`Exporting collection: ${colName}...`);
const documents = await db.collection(colName).find({}).toArray();
const filePath = path.join(OUTPUT_DIR, `${colName}.json`);
fs.writeFileSync(filePath, JSON.stringify(documents, null, 2));
console.log(` ✓ Exported ${documents.length} documents to ${filePath}`);
}
console.log('\n✓ Database export complete!');
} catch (err) {
console.error('✗ Export failed:', err.message);
process.exit(1);
} finally {
await client.close();
}
}
main();
-62
View File
@@ -1,62 +0,0 @@
const SftpClient = require('ssh2-sftp-client');
const { Client } = require('ssh2');
const remoteExtractScript = `
const fs = require('fs');
const path = require('path');
const root = '/home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/.next/server/chunks';
console.log('=== EXTRACTING ALL PAGE HEADERS FROM CHUNKS ===\\n');
const files = fs.readdirSync(root);
files.forEach(f => {
if (!f.endsWith('.js')) return;
const content = fs.readFileSync(path.join(root, f), 'utf8');
// Match header titles in React JSX: e.g. text-3xl font-bold ... >TitleText<
const titleMatches = content.matchAll(/text-3xl[^>]*>([^<]{3,40})</gi);
for (const m of titleMatches) {
console.log(\`Chunk \${f}: "\${m[1].trim()}"\`);
}
// Match tab names in React JSX
const tabMatches = content.matchAll(/role="tab"[^>]*>([^<]{3,30})</gi);
for (const m of tabMatches) {
console.log(\`Chunk \${f} Tab: "\${m[1].trim()}"\`);
}
});
`;
async function main() {
const sftp = new SftpClient();
await sftp.connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
const remoteScriptPath = '/home/adminbackend/extract_client_titles.js';
await sftp.put(Buffer.from(remoteExtractScript), remoteScriptPath);
await sftp.end();
const conn = new Client();
conn.on('ready', () => {
conn.exec(`node ${remoteScriptPath}`, (err, stream) => {
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log(out);
conn.end();
});
});
}).connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
}
main();
-69
View File
@@ -1,69 +0,0 @@
const SftpClient = require('ssh2-sftp-client');
const { Client } = require('ssh2');
const remoteExtractScript = `
const fs = require('fs');
const path = require('path');
const root = '/home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/.next/server';
console.log('=== EXTRACTING ALL PAGE HEADERS FROM STANDALONE BUILD ===\\n');
function scan(dir) {
if (!fs.existsSync(dir)) return;
const items = fs.readdirSync(dir, { withFileTypes: true });
for (const item of items) {
const full = path.join(dir, item.name);
if (item.isDirectory()) {
scan(full);
} else if (item.name.endsWith('.js') || item.name.endsWith('.html')) {
const content = fs.readFileSync(full, 'utf8');
// Look for H2/H1 page header titles or page metadata
const matches = content.matchAll(/<h[12][^>]*>([\\s\\S]*?)<\\/h[12]>/gi);
for (const m of matches) {
const clean = m[1].replace(/<[^>]+>/g, '').trim();
if (clean && clean.length > 2 && clean.length < 60 && !clean.includes('{') && !clean.includes('function')) {
console.log(\`File: \${path.relative(root, full)}\`);
console.log(\` Header: "\${clean}"\`);
}
}
}
}
}
scan(path.join(root, 'app/(dashboard)'));
`;
async function main() {
const sftp = new SftpClient();
await sftp.connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
const remoteScriptPath = '/home/adminbackend/extract_standalone.js';
await sftp.put(Buffer.from(remoteExtractScript), remoteScriptPath);
await sftp.end();
const conn = new Client();
conn.on('ready', () => {
conn.exec(`node ${remoteScriptPath}`, (err, stream) => {
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log(out);
conn.end();
});
});
}).connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
}
main();
-121
View File
@@ -1,121 +0,0 @@
// scripts/final-check.js
// ─────────────────────────────────────────────────────────────────────────────
// BackOne DPI — Final production health check
// ─────────────────────────────────────────────────────────────────────────────
'use strict';
const { Client: SshClient } = require('ssh2');
const https = require('https');
const http = require('http');
const CONFIG = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
};
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
const ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
function fetch(url, followRedirects = false) {
return new Promise(resolve => {
const mod = url.startsWith('https') ? https : http;
const opts = { timeout: 12000, rejectUnauthorized: false };
if (!followRedirects) opts.agent = false;
const req = mod.get(url, opts, res => {
let body = '';
res.on('data', d => body += d);
res.on('end', () => resolve({ status: res.statusCode, headers: res.headers, body: body.substring(0, 300) }));
});
req.on('error', e => resolve({ status: 0, error: e.message }));
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
});
}
function runSsh(commands) {
return new Promise((resolve, reject) => {
const ssh = new SshClient();
ssh.on('ready', () => {
let i = 0;
function next() {
if (i >= commands.length) { ssh.end(); return; }
const cmd = commands[i++];
console.log(`\n$ ${cmd}`);
ssh.exec(cmd, (err, stream) => {
if (err) { console.error('[ERR]', err.message); next(); return; }
stream.on('data', d => process.stdout.write(d.toString()));
stream.stderr.on('data', d => { const t = d.toString(); if (!t.includes('npm warn') && !t.includes('notice')) process.stdout.write(t); });
stream.on('close', next);
});
}
next();
ssh.on('end', resolve);
});
ssh.on('error', reject);
ssh.connect({ ...CONFIG, readyTimeout: 30000 });
});
}
async function main() {
console.log('\n╔══════════════════════════════════════════════════════════════╗');
console.log('║ BackOne DPI — Final Production Verification ║');
console.log('╚══════════════════════════════════════════════════════════════╝\n');
// SSH internal checks
await runSsh([
`${PM2} list`,
`echo "=== FRONTEND ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/`,
`echo "=== LOGIN PAGE ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/login`,
`echo "=== BACKEND ===" && curl -s http://127.0.0.1:3001/api/health`,
// Test full login flow
`echo "=== LOGIN API ===" && curl -s -X POST http://127.0.0.1:3001/api/auth/login -H "Content-Type: application/json" -d '{"username":"admin","password":"admin"}' | python3 -c "import sys,json; d=json.load(sys.stdin); print('Login OK - Role:', d.get('user',{}).get('role','?'))" 2>/dev/null || curl -s -X POST http://127.0.0.1:3001/api/auth/login -H "Content-Type: application/json" -d '{"username":"admin","password":"admin"}'`,
// Security checks
`echo "=== SECURITY: Port 3001 ===" && ss -tlnp | grep 3001`,
`echo "=== SECURITY: Port 4000 ===" && ss -tlnp | grep 4000`,
`echo "=== SECURITY: No .env in standalone ===" && find ${ROOT}/.next/standalone -name ".env*" 2>/dev/null || echo "CLEAN"`,
// Proxy MongoDB
`echo "=== PROXY MONGO ===" && ${PM2} logs backone-proxy --lines 5 --nostream 2>&1 | grep -E "(MongoDB|Scheduler|Connected|Capacity)" | tail -5`,
// Domain via HTTP (should 301 → HTTPS)
`echo "=== DOMAIN HTTP ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://demoplace.my.id/`,
// Domain via HTTPS from server itself
`echo "=== DOMAIN HTTPS ===" && curl -sk -o /dev/null -w "HTTP %{http_code}" https://demoplace.my.id/ 2>&1`,
]);
// External checks from local machine
console.log('\n\n══ External checks from local machine ══\n');
const tests = [
{ url: 'https://demoplace.my.id/', label: 'Root (expect 307 redirect to /login)' },
{ url: 'https://demoplace.my.id/login', label: 'Login page (expect 200)' },
{ url: 'https://demoplace.my.id/api/health', label: 'Backend health via domain (expect 200)' },
{ url: 'http://demoplace.my.id/', label: 'HTTP root (expect 301 HTTPS redirect)' },
];
for (const { url, label } of tests) {
const r = await fetch(url);
const ok = r.status >= 200 && r.status < 400;
const icon = ok ? '✅' : r.status === 0 ? '⚠️ ' : '❌';
console.log(` ${icon} [${String(r.status).padEnd(3)}] ${label}`);
if (r.headers?.location) console.log(` → Redirect: ${r.headers.location}`);
if (r.error) console.log(` → Error: ${r.error}`);
if (r.status === 200 && r.body) {
const preview = r.body.replace(/\s+/g, ' ').substring(0, 80);
console.log(` → Body: ${preview}`);
}
}
console.log('\n══════════════════════════════════════════════════════════════');
console.log(' Deployment Summary:');
console.log(' ┌─────────────────────────────────────────────────────┐');
console.log(' │ 🌐 Dashboard URL : https://demoplace.my.id │');
console.log(' │ 🔒 Backend : 127.0.0.1:3001 (internal only) │');
console.log(' │ 🔒 Proxy : 127.0.0.1:4000 (internal only) │');
console.log(' │ 🗄️ MongoDB : mongodb.prod.proit.id:27017 │');
console.log(' │ 🚀 Node.js : v18.19.1 │');
console.log(' │ ⚙️ PM2 : 3 processes (all online) │');
console.log(' └─────────────────────────────────────────────────────┘');
console.log('══════════════════════════════════════════════════════════\n');
}
main().catch(err => { console.error('[FATAL]', err); process.exit(1); });
-53
View File
@@ -1,53 +0,0 @@
// scripts/find-chunks.js
// Cari di mana file chunks yang benar berada di server
'use strict';
const { Client } = require('ssh2');
const conn = new Client();
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
function exec(conn, cmd) {
console.log('\n$ ' + cmd.substring(0, 80));
return new Promise(resolve => {
conn.exec(cmd, (err, s) => {
if (err) { resolve(''); return; }
let out = '';
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
.on('close', () => resolve(out));
});
});
}
conn.on('ready', async () => {
// 1. Cari file chunk yang direferensikan HTML
await exec(conn, 'find ' + PUB + ' -name "3km6z-n6wbgrs.js" 2>/dev/null | head -5');
await exec(conn, 'find ' + PUB + ' -name "21luguo5_g2uu.js" 2>/dev/null | head -5');
await exec(conn, 'find ' + PUB + ' -name "1u6dw_tm45utz.css" 2>/dev/null | head -5');
// 2. Cek isi static/static di standalone
const sa = PUB + '/.next/standalone/.next/static/static';
await exec(conn, 'ls ' + sa + '/ 2>/dev/null | head -10 || echo "Tidak ada nested static"');
// 3. Cek BUILD_ID utama
await exec(conn, 'cat ' + PUB + '/.next/BUILD_ID 2>/dev/null || echo "NO_BUILDID"');
// 4. Cek build-manifest.json untuk lihat chunk names
await exec(conn, 'cat ' + PUB + '/.next/standalone/.next/build-manifest.json 2>/dev/null | python3 -m json.tool 2>/dev/null | grep -A2 "login" | head -20');
// 5. Cek app-path-routes-manifest
await exec(conn, 'cat ' + PUB + '/.next/standalone/.next/app-path-routes-manifest.json 2>/dev/null | head -20');
// 6. Cek apakah ada next.js build di parent directory
await exec(conn, 'find /home/adminbackend -name "3km6z-n6wbgrs.js" 2>/dev/null | head -5');
// 7. Cek total disk structure
await exec(conn, 'du -sh ' + PUB + '/.next/standalone/.next/ 2>/dev/null');
await exec(conn, 'du -sh ' + PUB + '/.next/ 2>/dev/null | head -5');
conn.end();
console.log('\nDone.');
}).connect({
host: '103.185.47.52', port: 2222,
username: 'adminbackend', password: 'htEo7x6LsBQiEHHH',
readyTimeout: 30000
});
-18
View File
@@ -1,18 +0,0 @@
const { Client } = require('ssh2');
const conn = new Client();
conn.on('ready', () => {
conn.exec(`find /home/adminbackend/ -name "*.ts" -o -name "*.tsx" -o -name "*.js" | xargs grep -l "Overview Dashboard" 2>/dev/null`, (err, stream) => {
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log('=== FILES CONTAINING Overview Dashboard ===\n' + out);
conn.end();
});
});
}).connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
-131
View File
@@ -1,131 +0,0 @@
// scripts/fix-and-restart.js
// ─────────────────────────────────────────────────────────────────────────────
// BackOne DPI — Fix standalone structure & reload PM2 with new code
// ─────────────────────────────────────────────────────────────────────────────
'use strict';
const { Client: SshClient } = require('ssh2');
const CONFIG = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
};
const ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
const COMMANDS = [
// ── Step 1: Fix the standalone directory structure ──────────────────────────
// Next.js standalone server.js expects .next/static and public INSIDE the standalone dir
`echo "=== STEP 1: Create standalone .next dir ==="`,
`mkdir -p ${ROOT}/.next/standalone/.next/`,
// Copy static chunks into standalone/.next/static
`echo "=== STEP 2: Copy static assets into standalone ===" && cp -r ${ROOT}/.next/static ${ROOT}/.next/standalone/.next/static && echo "static copied OK"`,
// Copy media files
`ls ${ROOT}/.next/standalone/.next/static/ 2>/dev/null | wc -l | xargs -I{} echo "Files in standalone static: {}"`,
// public is already copied in deploy script, verify it
`ls ${ROOT}/.next/standalone/public/ 2>/dev/null | head -5 || echo "WARNING: public dir missing in standalone"`,
// ── Step 2: Verify the ecosystem.config.js was updated ────────────────────
`echo "=== STEP 3: Show ecosystem.config.js script path ===" && grep "script" ${ROOT}/ecosystem.config.js | head -5`,
// ── Step 3: Reload PM2 with new ecosystem config ──────────────────────────
// Use reload instead of restart to minimize downtime
`echo "=== STEP 4: Reload PM2 frontend with new code ===" && cd ${ROOT} && NODE_ENV=production ${PM2} reload ecosystem.config.js --only backone-frontend 2>&1`,
// Also reload backend to pick up new code
`echo "=== STEP 5: Reload PM2 backend ===" && cd ${ROOT} && NODE_ENV=production ${PM2} reload ecosystem.config.js --only backone-backend 2>&1`,
// Reload proxy as well (it was already restarted but ensure env is correct)
`echo "=== STEP 6: Reload PM2 proxy ===" && cd ${ROOT} && NODE_ENV=production ${PM2} reload ecosystem.config.js --only backone-proxy 2>&1`,
// ── Step 4: Save PM2 state for auto-restart on reboot ─────────────────────
`echo "=== STEP 7: Save PM2 state ===" && ${PM2} save && echo "PM2 state saved"`,
// ── Step 5: Wait for processes to stabilize ────────────────────────────────
`sleep 8`,
// ── Step 6: Verify all processes ──────────────────────────────────────────
`echo "=== STEP 8: PM2 Status ===" && ${PM2} list`,
// ── Step 7: Health checks ─────────────────────────────────────────────────
`echo "=== BACKEND HEALTH ===" && curl -s http://127.0.0.1:3001/api/health`,
`echo ""`,
`echo "=== FRONTEND HTTP STATUS ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/ && echo ""`,
`echo "=== FRONTEND LOGIN PAGE ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/login && echo ""`,
// ── Step 8: Check port 3000 is now listening ──────────────────────────────
`echo "=== PORT 3000 STATUS ===" && ss -tlnp 2>/dev/null | grep 3000 || netstat -tlnp 2>/dev/null | grep 3000 || echo "Port 3000 check done"`,
// ── Step 9: Show frontend logs ────────────────────────────────────────────
`echo "=== FRONTEND PM2 LOG (last 20 lines) ===" && ${PM2} logs backone-frontend --lines 20 --nostream 2>&1 | tail -25`,
// ── Step 10: Show proxy MongoDB connection status ─────────────────────────
`echo "=== PROXY LOG (last 15 lines) ===" && ${PM2} logs backone-proxy --lines 15 --nostream 2>&1 | tail -20`,
];
function runSshCommands(commands) {
return new Promise((resolve, reject) => {
const ssh = new SshClient();
ssh.on('ready', () => {
console.log('[SSH] Connected!\n');
let index = 0;
function runNext() {
if (index >= commands.length) {
ssh.end();
return;
}
const cmd = commands[index++];
const preview = cmd.length > 150 ? cmd.substring(0, 150) + '...' : cmd;
console.log(`\n$ ${preview}`);
ssh.exec(cmd, (err, stream) => {
if (err) {
console.error(`[ERROR] ${err.message}`);
runNext();
return;
}
stream.on('data', (data) => process.stdout.write(data.toString()));
stream.stderr.on('data', (data) => {
const text = data.toString();
if (!text.includes('npm warn') && !text.includes('npm notice')) {
process.stdout.write(`[ERR] ${text}`);
}
});
stream.on('close', () => runNext());
});
}
runNext();
ssh.on('end', resolve);
});
ssh.on('error', reject);
ssh.connect({ ...CONFIG, readyTimeout: 30000 });
});
}
async function main() {
console.log('\n╔══════════════════════════════════════════════════════════╗');
console.log('║ BackOne DPI — Fix Standalone & Reload PM2 ║');
console.log('╚══════════════════════════════════════════════════════════╝\n');
try {
await runSshCommands(COMMANDS);
console.log('\n✅ Fix & reload complete!\n');
} catch (err) {
console.error('\n[FATAL]', err.message);
process.exit(1);
}
}
main();
-120
View File
@@ -1,120 +0,0 @@
// scripts/fix-apache-ssl.js
// ─────────────────────────────────────────────────────────────────────────────
// BackOne DPI — Fix Apache HTTPS 502 Bad Gateway
// The SSL VirtualHost needs mod_proxy configuration.
// cPanel uses Apache with .htaccess for proxy rules, but SSL VirtualHost
// may need specific directives to enable mod_proxy_http for the [P] flag.
// ─────────────────────────────────────────────────────────────────────────────
'use strict';
const { Client: SshClient } = require('ssh2');
const CONFIG = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
};
const ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
const COMMANDS = [
// Investigate Apache config for SSL
`echo "=== APACHE MODULES ===" && apache2ctl -M 2>/dev/null | grep -i proxy | head -10 || httpd -M 2>/dev/null | grep -i proxy | head -10 || echo "Cannot check Apache modules"`,
// Check what's actually at the SSL port - is it Apache or Nginx or something else?
`echo "=== SSL PORT OWNER ===" && ss -tlnp | grep 443`,
// Check SSL log for 502 cause
`echo "=== SSL ACCESS LOG (last 10 502s) ===" && tail -50 /home/adminbackend/logs/demoplace.my.id-ssl_log 2>/dev/null | grep "502" | tail -10 || echo "No SSL log or no 502s in log"`,
`echo "=== SSL ERROR LOG (last 15) ===" && tail -15 /home/adminbackend/logs/demoplace.my.id-ssl_log 2>/dev/null || echo "No SSL log found"`,
// Find all log files for this domain
`echo "=== DOMAIN LOG FILES ===" && ls /home/adminbackend/logs/*demoplace* 2>/dev/null || echo "No domain-specific logs"`,
// Check Apache vhost config (cPanel stores them here)
`echo "=== APACHE SSL VHOST ===" && cat /etc/apache2/conf.d/userdata/ssl/2_4/adminbackend/demoplace.my.id/custom_subdirectory.conf 2>/dev/null || ls /etc/apache2/conf.d/userdata/ssl/2_4/adminbackend/ 2>/dev/null || echo "Cannot read Apache vhost config"`,
// Check all .htaccess files in path
`echo "=== ROOT HTACCESS ===" && cat ${ROOT}/.htaccess`,
// Check if mod_proxy is loaded
`echo "=== MOD_PROXY CHECK ===" && test -f /etc/apache2/mods-enabled/proxy.load && echo "mod_proxy ENABLED" || echo "mod_proxy NOT enabled"`,
`test -f /etc/apache2/mods-enabled/proxy_http.load && echo "mod_proxy_http ENABLED" || echo "mod_proxy_http NOT enabled"`,
// The issue may be cPanel's "nobody" user restriction
// Try using ProxyPass in .htaccess with explicit ProxyPassReverse
`echo "=== UPDATING .HTACCESS ===" && cat > ${ROOT}/.htaccess << 'EOF'
Options -MultiViews
RewriteEngine On
# Force HTTPS
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# Proxy all requests to Next.js (port 3000)
RewriteRule ^(.*)$ http://127.0.0.1:3000/$1 [P,L,QSA]
ProxyPassReverse / http://127.0.0.1:3000/
EOF
echo ".htaccess updated"`,
// Read the new .htaccess to verify
`echo "=== NEW HTACCESS ===" && cat ${ROOT}/.htaccess`,
// Wait a moment for Apache to pick up changes
`sleep 2`,
// Test from server itself via HTTPS
`echo "=== HTTPS TEST FROM SERVER ===" && curl -sk -o /dev/null -w "HTTP %{http_code}" https://demoplace.my.id/ 2>&1`,
`echo "=== HTTPS LOGIN FROM SERVER ===" && curl -sk -o /dev/null -w "HTTP %{http_code}" https://demoplace.my.id/login 2>&1`,
// Check if it's a proxy timeout issue - try with verbose curl
`echo "=== VERBOSE HTTPS TEST ===" && curl -skv https://demoplace.my.id/ 2>&1 | grep -E "(<|>|\\*) " | head -20`,
// Alternative: check if cPanel has a NodeJS app manager entry interfering
`echo "=== CPANEL USERDATA ===" && ls /home/adminbackend/.cpanel/userdata/ 2>/dev/null`,
`cat /home/adminbackend/.cpanel/userdata/demoplace.my.id_SSL 2>/dev/null | head -30 || echo "No cPanel userdata for SSL"`,
`cat /home/adminbackend/.cpanel/userdata/demoplace.my.id 2>/dev/null | head -30 || echo "No cPanel userdata"`,
// Check Apache logs specifically for proxy errors
`echo "=== APACHE ERROR LOG ===" && tail -20 /var/log/apache2/error.log 2>/dev/null | grep -i "demoplace\|proxy\|502" | head -10 || echo "Cannot read Apache error log"`,
// PM2 processes still healthy?
`echo "=== PM2 STATUS ===" && ${PM2} list`,
`echo "=== FRONTEND HEALTH ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/login`,
];
function runSsh(commands) {
return new Promise((resolve, reject) => {
const ssh = new SshClient();
ssh.on('ready', () => {
let i = 0;
function next() {
if (i >= commands.length) { ssh.end(); return; }
const cmd = commands[i++];
console.log(`\n$ ${cmd.substring(0, 100)}${cmd.length > 100 ? '...' : ''}`);
ssh.exec(cmd, (err, stream) => {
if (err) { console.error('[ERR]', err.message); next(); return; }
stream.on('data', d => process.stdout.write(d.toString()));
stream.stderr.on('data', d => { const t = d.toString(); if (!t.includes('npm warn') && !t.includes('notice')) process.stdout.write(t); });
stream.on('close', next);
});
}
next();
ssh.on('end', resolve);
});
ssh.on('error', reject);
ssh.connect({ ...CONFIG, readyTimeout: 30000 });
});
}
async function main() {
console.log('\n╔══════════════════════════════════════════════════════════╗');
console.log('║ BackOne DPI — Fix Apache HTTPS 502 Bad Gateway ║');
console.log('╚══════════════════════════════════════════════════════════╝\n');
await runSsh(COMMANDS);
console.log('\n✅ Apache SSL investigation complete!\n');
}
main().catch(err => { console.error('[FATAL]', err); process.exit(1); });
-141
View File
@@ -1,141 +0,0 @@
// scripts/fix-css-and-security.js
// 1. Fix CSS tidak termuat: buat symlink public_html/_next -> public_html/.next
// 2. Security audit: hapus cmd.php dan file berbahaya lainnya
'use strict';
const { Client } = require('ssh2');
const https = require('https');
const SSH = {
host: '103.185.47.52', port: 2222,
username: 'adminbackend', password: 'htEo7x6LsBQiEHHH',
readyTimeout: 60000
};
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
function sshExec(conn, cmd, label = '') {
if (label) console.log(`\n[${label}]`);
console.log(`$ ${cmd.substring(0, 100)}${cmd.length > 100 ? '...' : ''}`);
return new Promise((resolve, reject) => {
conn.exec(cmd, (err, stream) => {
if (err) return reject(err);
let out = '';
stream.on('close', () => resolve(out))
.on('data', d => { out += d; process.stdout.write(d.toString()); })
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); });
});
});
}
async function main() {
console.log('\n╔══════════════════════════════════════════════════════════╗');
console.log('║ BackOne DPI — Fix CSS + Security Audit ║');
console.log('╚══════════════════════════════════════════════════════════╝\n');
const conn = new Client();
await new Promise((resolve, reject) => { conn.on('ready', resolve).on('error', reject).connect(SSH); });
console.log('[SSH] Terhubung!\n');
// ── 1. SECURITY AUDIT ─────────────────────────────────────────────────
await sshExec(conn,
`echo "=== FILE BERBAHAYA ===" && ls -la ${PUB}/*.php ${PUB}/*.sh 2>/dev/null || echo "Tidak ada .php/.sh di root"`,
'1. Audit file PHP di public_html'
);
// Hapus cmd.php jika ada (file backdoor berbahaya)
await sshExec(conn,
`[ -f ${PUB}/cmd.php ] && rm -f ${PUB}/cmd.php && echo "DIHAPUS: cmd.php" || echo "cmd.php tidak ada (aman)"`,
'2. Hapus cmd.php (backdoor)'
);
// Hapus proxy.php lama (tidak diperlukan lagi karena nginx routing langsung ke port 3000)
await sshExec(conn,
`[ -f ${PUB}/proxy.php ] && rm -f ${PUB}/proxy.php && echo "DIHAPUS: proxy.php (tidak diperlukan)" || echo "proxy.php tidak ada"`,
'3. Hapus proxy.php (tidak dibutuhkan)'
);
// ── 2. CEK STRUKTUR DIREKTORI ──────────────────────────────────────────
await sshExec(conn,
`echo "=== STRUKTUR public_html ===" && ls -la ${PUB}/ | head -30`,
'4. Cek struktur public_html'
);
await sshExec(conn,
`echo "=== .next directory ===" && ls -la ${PUB}/.next/ 2>/dev/null | head -10 || echo "TIDAK ADA .next/"`,
'5. Cek .next directory'
);
await sshExec(conn,
`echo "=== static assets ===" && ls -la ${PUB}/.next/static/ 2>/dev/null | head -10 || echo "Tidak ada .next/static/"`,
'6. Cek .next/static'
);
await sshExec(conn,
`echo "=== _next symlink ===" && ls -la ${PUB}/_next 2>/dev/null || echo "Symlink _next belum ada"`,
'7. Cek symlink _next'
);
// ── 3. FIX CSS: Buat symlink _next → .next ────────────────────────────
await sshExec(conn,
`[ -e ${PUB}/_next ] && echo "Sudah ada _next" || (ln -s ${PUB}/.next ${PUB}/_next && echo "BERHASIL: Symlink _next → .next dibuat")`,
'8. Buat symlink _next -> .next'
);
// Verifikasi symlink
await sshExec(conn,
`ls -la ${PUB}/_next && ls ${PUB}/_next/static/ | head -5`,
'9. Verifikasi symlink'
);
// ── 4. PERBARUI .htaccess (bersih tanpa proxy.php) ────────────────────
const cleanHtaccess = `# BackOne DPI — Apache .htaccess
# Redirect HTTP ke HTTPS saja
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
`;
await sshExec(conn,
`printf '%s' ${JSON.stringify(cleanHtaccess)} > ${PUB}/.htaccess && echo "BERHASIL: .htaccess diperbarui"`,
'10. Perbarui .htaccess (hanya redirect HTTPS)'
);
// ── 5. TEST CSS LOADING ─────────────────────────────────────────────────
console.log('\n[11. Test loading CSS dari /_next/static/]');
await sshExec(conn,
`CSS_FILE=$(ls ${PUB}/.next/static/css/*.css 2>/dev/null | head -1) && ` +
`[ -n "$CSS_FILE" ] && ` +
`FILENAME=$(basename "$CSS_FILE") && ` +
`curl -sk -o /dev/null -w "CSS via domain: %{http_code} (size: %{size_download} bytes)" https://demoplace.my.id/_next/static/css/$FILENAME || ` +
`echo "Tidak ada file CSS ditemukan"`,
'11. Test CSS via domain'
);
conn.end();
// ── Test dari luar ──────────────────────────────────────────────────────
console.log('\n[12. Test domain setelah fix...]');
await new Promise(r => setTimeout(r, 2000));
for (const path of ['/login', '/api/health']) {
const r = await new Promise(resolve => {
const req = https.get(`https://demoplace.my.id${path}`,
{ timeout: 10000, rejectUnauthorized: false },
res => {
let body = '';
res.on('data', d => body += d);
res.on('end', () => resolve({ status: res.statusCode, body: body.substring(0, 100) }));
}
);
req.on('error', e => resolve({ status: 0, error: e.message }));
});
const icon = r.status === 200 ? '✅' : r.status === 301 ? '↩️ ' : '❌';
console.log(` ${icon} https://demoplace.my.id${path} → HTTP ${r.status}`);
if (path === '/api/health') console.log(` Body: ${r.body}`);
}
console.log('\n✅ Fix selesai! Coba refresh https://demoplace.my.id/login\n');
}
main().catch(err => { console.error('[FATAL]', err.message); process.exit(1); });
-175
View File
@@ -1,175 +0,0 @@
// scripts/fix-env-loader.js
// Fix: Buat Node.js env loader yang aman (tanpa bash glob expansion)
'use strict';
const { Client } = require('ssh2');
const SSH = { host: '103.185.47.52', port: 2222, username: 'adminbackend', password: 'htEo7x6LsBQiEHHH', readyTimeout: 60000 };
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
function exec(conn, cmd, label) {
if (label) console.log('\n[' + label + ']');
console.log('$ ' + cmd.substring(0, 90));
return new Promise(resolve => {
conn.exec(cmd, (err, s) => {
if (err) { resolve(''); return; }
let out = '';
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
.on('close', () => resolve(out));
});
});
}
// Konten start-with-env.js yang akan ditulis ke server
const startWithEnvContent = `'use strict';
// Polyfill global crypto for Node 18 compatibility (required by mongodb driver)
if (typeof globalThis.crypto === 'undefined') {
globalThis.crypto = require('crypto');
}
/**
* BackOne DPI - Safe Environment Loader for Next.js Standalone
* Reads .env.production safely without bash glob expansion issues.
*/
const path = require('path');
const fs = require('fs');
const envFile = path.join(__dirname, '.env.production');
if (fs.existsSync(envFile)) {
const lines = fs.readFileSync(envFile, 'utf8').split(/\\r?\\n/);
let loaded = 0;
for (const raw of lines) {
const line = raw.trim();
// Skip comments and empty lines
if (!line || line.startsWith('#')) continue;
const eqIdx = line.indexOf('=');
if (eqIdx === -1) continue;
const key = line.substring(0, eqIdx).trim();
// Only accept valid environment variable names
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key)) continue;
const val = line.substring(eqIdx + 1); // Do NOT trim value - preserve exact content
if (!(key in process.env)) {
process.env[key] = val;
loaded++;
}
}
console.log('[startup] Loaded ' + loaded + ' environment variables from .env.production');
console.log('[startup] NETIFY_API_KEY set:', !!process.env.NETIFY_API_KEY);
console.log('[startup] MONGODB_URI set: ', !!process.env.MONGODB_URI);
} else {
console.warn('[startup] WARNING: .env.production not found at:', envFile);
}
// Start Next.js standalone server
require('./.next/standalone/server.js');
`;
async function main() {
const conn = new Client();
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(SSH); });
console.log('[SSH] Connected\n');
// 1. Upload start-with-env.js ke server
await exec(conn,
'cat > ' + PUB + '/start-with-env.js << \'NODELOADER_EOF\'\n' + startWithEnvContent + '\nNODELOADER_EOF\n' +
'echo "Node.js loader dibuat"',
'1. Buat start-with-env.js'
);
await exec(conn, 'wc -l ' + PUB + '/start-with-env.js', '2. Verifikasi file');
// 2. Update ecosystem.config.js untuk gunakan Node.js loader (bukan bash wrapper)
const ecoContent = `// ecosystem.config.js — PM2 Config (server-side)
module.exports = {
apps: [
{
name: 'backone-proxy',
script: './proxy/index.js',
cwd: '${PUB}',
instances: 1,
exec_mode: 'fork',
watch: false,
node_args: '--max-old-space-size=256',
max_memory_restart: '300M',
restart_delay: 5000,
max_restarts: 10,
env_file: '.env.production',
env: { NODE_ENV: 'production' },
error_file: './logs/proxy-error.log',
out_file: './logs/proxy-out.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
merge_logs: true,
},
{
name: 'backone-backend',
script: './backend/server.js',
cwd: '${PUB}',
instances: 1,
exec_mode: 'fork',
watch: false,
node_args: '--max-old-space-size=256',
max_memory_restart: '400M',
restart_delay: 3000,
max_restarts: 10,
env_file: '.env.production',
env: { NODE_ENV: 'production' },
error_file: './logs/backend-error.log',
out_file: './logs/backend-out.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
merge_logs: true,
},
{
name: 'backone-frontend',
script: './start-with-env.js',
cwd: '${PUB}',
instances: 1,
exec_mode: 'fork',
watch: false,
node_args: '--max-old-space-size=512',
max_memory_restart: '700M',
restart_delay: 3000,
max_restarts: 10,
env: {
NODE_ENV: 'production',
PORT: '3000',
HOSTNAME: '127.0.0.1',
NEXT_TELEMETRY_DISABLED: '1',
},
error_file: './logs/frontend-error.log',
out_file: './logs/frontend-out.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
merge_logs: true,
},
],
};`;
await exec(conn,
'cat > ' + PUB + '/ecosystem.config.js << \'ECO_EOF\'\n' + ecoContent + '\nECO_EOF\necho "ecosystem.config.js diperbarui"',
'3. Update ecosystem.config.js'
);
// 3. Delete & restart frontend
await exec(conn,
'cd ' + PUB + ' && ' + PM2 + ' delete backone-frontend 2>/dev/null; ' +
PM2 + ' start ecosystem.config.js --only backone-frontend && echo "START OK"',
'4. Restart frontend dengan Node.js loader'
);
// 4. Tunggu startup
await new Promise(r => setTimeout(r, 8000));
// 5. Cek out log (harus tampil "Loaded X environment variables")
await exec(conn, 'tail -10 ' + PUB + '/logs/frontend-out.log 2>/dev/null', '5. Out log (env loader output)');
await exec(conn, 'tail -5 ' + PUB + '/logs/frontend-error.log 2>/dev/null', '6. Error log terbaru');
// 6. Test agents
await exec(conn, 'curl -sk -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/agents', '7. Test /agents page');
// 7. PM2 status
await exec(conn, PM2 + ' list 2>/dev/null | grep backone', '8. PM2 status');
conn.end();
console.log('\n✅ Selesai!\n');
}
main().catch(e => console.error('[FATAL]', e.message));
-78
View File
@@ -1,78 +0,0 @@
// scripts/fix-env-vars.js
// Fix: Pastikan environment variables dari .env.production dimuat oleh PM2 frontend
'use strict';
const { Client } = require('ssh2');
const SSH = { host: '103.185.47.52', port: 2222, username: 'adminbackend', password: 'htEo7x6LsBQiEHHH', readyTimeout: 60000 };
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
function exec(conn, cmd, label) {
if (label) console.log('\n[' + label + ']');
console.log('$ ' + cmd.substring(0, 90));
return new Promise(resolve => {
conn.exec(cmd, (err, s) => {
if (err) { resolve(''); return; }
let out = '';
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
.on('close', () => resolve(out));
});
});
}
async function main() {
const conn = new Client();
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(SSH); });
console.log('[SSH] Connected\n');
// 1. Cek env vars yang diterima proses PM2 sekarang
await exec(conn, PM2 + ' env 3 2>/dev/null | grep -E "(NETIFY|BACKONE|MONGO|JWT)" | head -15', '1. Env vars di PM2 proses 3 (frontend)');
// 2. Cek isi .env.production
await exec(conn, 'cat ' + PUB + '/.env.production 2>/dev/null | grep -v "#" | grep -v "^$" | head -30', '2. Isi .env.production (non-comment)');
// 3. Export vars dari .env.production dan restart dengan env vars eksplisit
// Baca .env.production, parse, dan set ke PM2
const envScript = `
set -a
source ${PUB}/.env.production 2>/dev/null
set +a
export NETIFY_API_KEY="$NETIFY_API_KEY"
export NETIFY_ORG_UUID="$NETIFY_ORG_UUID"
export NETIFY_SITE_UUIDS="$NETIFY_SITE_UUIDS"
export NETIFY_INFORMATICS_BASE_URL="$NETIFY_INFORMATICS_BASE_URL"
export MONGODB_URI="$MONGODB_URI"
export JWT_SECRET="$JWT_SECRET"
export NEXT_PUBLIC_API_URL="$NEXT_PUBLIC_API_URL"
echo "API_KEY=$NETIFY_API_KEY"
echo "MONGO_URI_PARTIAL=$(echo $MONGODB_URI | cut -c1-30)..."
`.trim();
await exec(conn, 'bash -c \'' + envScript.replace(/\n/g, '; ') + '\'', '3. Verifikasi env vars bisa dibaca dari .env.production');
// 4. Delete dan restart PM2 proses dengan ecosystem file yang membaca env_file
await exec(conn,
'cd ' + PUB + ' && ' + PM2 + ' delete backone-frontend 2>/dev/null; ' +
PM2 + ' start ecosystem.config.js --only backone-frontend --env production && echo "START OK"',
'4. Restart frontend via ecosystem.config.js'
);
// 5. Verifikasi env vars sekarang dimuat
await new Promise(r => setTimeout(r, 5000));
await exec(conn, PM2 + ' env 3 2>/dev/null | grep -E "(NETIFY|BACKONE|MONGO)" | head -10', '5. Verifikasi env vars setelah restart');
// 6. Test agents page
await new Promise(r => setTimeout(r, 5000));
await exec(conn, 'curl -sk -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/agents', '6. Test /agents');
// 7. Cek error log terbaru
await exec(conn, 'tail -5 ' + PUB + '/logs/frontend-error.log 2>/dev/null', '7. Error log terbaru');
// 8. PM2 status akhir
await exec(conn, PM2 + ' list 2>/dev/null | grep backone', '8. PM2 status akhir');
conn.end();
console.log('\n✅ Selesai!\n');
}
main().catch(e => console.error('[FATAL]', e.message));
-110
View File
@@ -1,110 +0,0 @@
// scripts/fix-https.js
// ─────────────────────────────────────────────────────────────────────────────
// BackOne DPI — Fix HTTPS 502 Bad Gateway Issue
// The cPanel Apache proxy is getting 502 — need to investigate and fix
// ─────────────────────────────────────────────────────────────────────────────
'use strict';
const { Client: SshClient } = require('ssh2');
const CONFIG = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
};
const ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
const COMMANDS = [
// Check current frontend status
`echo "=== FRONTEND PROCESS ==="`,
`ps aux | grep node | grep -v grep`,
`ss -tlnp | grep 3000`,
// Check if frontend is responding internally
`echo "=== INTERNAL FRONTEND TEST ===" && curl -sv http://127.0.0.1:3000/ 2>&1 | grep -E "(< HTTP|< Location|Connected|curl)" | head -10`,
// Check the .htaccess to confirm proxy setup
`echo "=== .HTACCESS CONTENT ===" && cat ${ROOT}/.htaccess`,
// Check Apache error log for this domain
`echo "=== APACHE ERROR (last 20 lines) ===" && tail -20 /home/adminbackend/logs/demoplace.my.id-ssl_log 2>/dev/null || tail -20 /home/adminbackend/logs/demoplace.my.id-error_log 2>/dev/null || tail -20 /home/adminbackend/logs/error_log 2>/dev/null || echo "No Apache error log found"`,
// Check all logs
`echo "=== LOG FILES ===" && ls /home/adminbackend/logs/ 2>/dev/null | head -20`,
// Check domain SSL logs
`echo "=== SSL LOG ===" && tail -30 /home/adminbackend/logs/demoplace.my.id-ssl_log 2>/dev/null | grep -E "(502|500|error|proxy)" | tail -15 || echo "No SSL log"`,
// Try the domain via HTTP (non-SSL)
`echo "=== HTTP (non-SSL) TEST ===" && curl -sv http://demoplace.my.id/ 2>&1 | grep -E "(< HTTP|Location|Connected)" | head -5`,
// Check PM2 frontend is running
`echo "=== PM2 FRONTEND STATUS ===" && ${PM2} show backone-frontend 2>&1 | grep -E "(status|pid|uptime|restart)" | head -10`,
// Check frontend log for errors
`echo "=== FRONTEND LOG (errors) ===" && ${PM2} logs backone-frontend --lines 30 --nostream 2>&1 | grep -E "(Error|error|ECONNRESET|Ready|✓)" | tail -15`,
// Re-check port
`echo "=== PORT 3000 DETAILED ===" && ss -tlnp | grep 3000`,
// Try direct curl to frontend with more verbose output
`echo "=== DETAILED FRONTEND CURL ===" && curl -v http://127.0.0.1:3000/login 2>&1 | head -30`,
// Check if there's an issue with the standalone server path in PM2
`echo "=== PM2 SCRIPT PATH ===" && ${PM2} show backone-frontend 2>&1 | grep -E "(script|cwd|exec)" | head -5`,
// Check node version
`echo "=== NODE VERSION ===" && node --version`,
// Check if frontend started correctly after restart
`echo "=== FRONTEND READY STATUS ===" && ${PM2} logs backone-frontend --lines 10 --nostream 2>&1 | tail -15`,
// Try restarting frontend
`echo "=== RESTARTING FRONTEND ===" && ${PM2} restart backone-frontend && sleep 5 && echo "Restarted"`,
// Final port check
`echo "=== FINAL PORT CHECK ===" && ss -tlnp | grep 3000`,
`echo "=== FINAL CURL ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/login`,
// Check if maybe cPanel node app is conflicting
`echo "=== CPANEL NODE APPS ===" && ls /home/adminbackend/nodevenv/ 2>/dev/null || echo "No cPanel Node.js virtual environments"`,
`cat /home/adminbackend/.cpanel/nvdata/node_application_config 2>/dev/null | head -30 || echo "No cPanel Node config"`,
];
function runSsh(commands) {
return new Promise((resolve, reject) => {
const ssh = new SshClient();
ssh.on('ready', () => {
console.log('[SSH] Connected!\n');
let i = 0;
function next() {
if (i >= commands.length) { ssh.end(); return; }
const cmd = commands[i++];
console.log(`\n$ ${cmd.substring(0, 130)}${cmd.length > 130 ? '...' : ''}`);
ssh.exec(cmd, (err, stream) => {
if (err) { console.error('[ERR]', err.message); next(); return; }
stream.on('data', d => process.stdout.write(d.toString()));
stream.stderr.on('data', d => { const t = d.toString(); if (!t.includes('npm warn') && !t.includes('notice')) process.stdout.write(t); });
stream.on('close', next);
});
}
next();
ssh.on('end', resolve);
});
ssh.on('error', reject);
ssh.connect({ ...CONFIG, readyTimeout: 30000 });
});
}
async function main() {
console.log('\n╔══════════════════════════════════════════════════════════╗');
console.log('║ BackOne DPI — HTTPS 502 Investigation & Fix ║');
console.log('╚══════════════════════════════════════════════════════════╝\n');
await runSsh(COMMANDS);
console.log('\n✅ Investigation complete!\n');
}
main().catch(err => { console.error('[FATAL]', err); process.exit(1); });
-88
View File
@@ -1,88 +0,0 @@
// scripts/fix-missing-css.js
'use strict';
const { Client } = require('ssh2');
const https = require('https');
const SSH = { host: '103.185.47.52', port: 2222, username: 'adminbackend', password: 'htEo7x6LsBQiEHHH', readyTimeout: 60000 };
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
const SA = PUB + '/.next/standalone/.next/static';
const BP = '/home/adminbackend/backone-production/.next/static';
function exec(conn, cmd, label) {
if (label) console.log('\n[' + label + ']');
console.log('$ ' + cmd.substring(0, 80));
return new Promise(resolve => {
conn.exec(cmd, (err, s) => {
if (err) { resolve(''); return; }
let out = '';
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
.on('close', () => resolve(out));
});
});
}
async function httpGet(url) {
return new Promise(resolve => {
const req = https.get(url, { timeout: 12000, rejectUnauthorized: false }, res => {
let body = '';
res.on('data', d => body += d);
res.on('end', () => resolve({ status: res.statusCode, size: body.length, type: res.headers['content-type'] }));
});
req.on('error', e => resolve({ status: 0, error: e.message }));
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
});
}
async function main() {
const conn = new Client();
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(SSH); });
console.log('[SSH] Connected\n');
// 1. Cari file CSS yang hilang
await exec(conn, 'find /home/adminbackend -name "1oskchnhjm4n8.css" 2>/dev/null | head -5', '1. Cari CSS hilang');
// 2. List CSS di backone-production
await exec(conn, 'find ' + BP + ' -name "*.css" 2>/dev/null | head -10', '2. CSS di backone-production');
// 3. Full rsync chunks (paksa semua file)
await exec(conn,
'rsync -av ' + BP + '/chunks/ ' + SA + '/chunks/ 2>&1 | grep "css\\|sent\\|total" | head -10',
'3. Full rsync chunks'
);
// 4. Verifikasi CSS setelah rsync
await exec(conn, 'find ' + SA + '/chunks -name "*.css" 2>/dev/null', '4. CSS di standalone setelah rsync');
// 5. Cek total file
await exec(conn, 'ls ' + SA + '/chunks/ | wc -l', '5. Total file chunks');
conn.end();
// 6. Final test
console.log('\n[6. Final test static files...]');
await new Promise(r => setTimeout(r, 2000));
const files = [
'/_next/static/chunks/3km6z-n6wbgrs.js',
'/_next/static/chunks/1u6dw_tm45utz.css',
'/_next/static/chunks/1oskchnhjm4n8.css',
'/_next/static/chunks/21luguo5_g2uu.js',
'/_next/static/chunks/1-8s9_t85wwr4.js',
'/_next/static/chunks/2n6j37owj-kaf.js',
];
let allOk = true;
for (const f of files) {
const r = await httpGet('https://demoplace.my.id' + f);
const icon = r.status === 200 ? '✅' : '❌';
const ext = f.endsWith('.css') ? 'CSS' : 'JS ';
console.log(' ' + icon + ' [' + ext + '] HTTP ' + r.status + ' | ' + (r.size || 0) + ' bytes');
if (r.status !== 200) { console.log(' → ' + f); allOk = false; }
}
if (allOk) {
console.log('\n🎉 SEMUA CSS/JS BERHASIL! Lakukan hard refresh (Ctrl+Shift+R)\n');
} else {
console.log('\n⚠ Masih ada yang 404. Cek manual.\n');
}
}
main().catch(e => console.error('[FATAL]', e.message));
-80
View File
@@ -1,80 +0,0 @@
// scripts/fix-mongoose-module.js
// Fix: Copy mongoose ke standalone/node_modules agar tersedia sebagai external package
'use strict';
const { Client } = require('ssh2');
const SSH = { host: '103.185.47.52', port: 2222, username: 'adminbackend', password: 'htEo7x6LsBQiEHHH', readyTimeout: 60000 };
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
const SA = PUB + '/.next/standalone';
const BP = '/home/adminbackend/backone-production';
function exec(conn, cmd, label) {
if (label) console.log('\n[' + label + ']');
console.log('$ ' + cmd.substring(0, 90));
return new Promise(resolve => {
conn.exec(cmd, (err, s) => {
if (err) { resolve(''); return; }
let out = '';
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
.on('close', () => resolve(out));
});
});
}
async function main() {
const conn = new Client();
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(SSH); });
console.log('[SSH] Connected\n');
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
// 1. Cek lokasi mongoose
await exec(conn, 'ls ' + SA + '/node_modules/mongoose 2>/dev/null | head -3 || echo "Tidak ada di standalone/node_modules"', '1. Cek mongoose di standalone');
await exec(conn, 'ls ' + BP + '/node_modules/mongoose 2>/dev/null | head -3 || echo "Tidak ada di backone-production"', '2. Cek mongoose di backone-production');
await exec(conn, 'ls ' + PUB + '/node_modules/mongoose 2>/dev/null | head -3 || echo "Tidak ada di public_html/node_modules"', '3. Cek mongoose di public_html');
// 2. Copy mongoose ke standalone/node_modules (dari backone-production)
const mongooseSrc = BP + '/node_modules/mongoose';
const mongooseDst = SA + '/node_modules/mongoose';
await exec(conn,
'[ -d ' + mongooseSrc + ' ] && (' +
' [ -e ' + mongooseDst + ' ] && echo "Sudah ada" || ' +
' (cp -r ' + mongooseSrc + ' ' + mongooseDst + ' && echo "BERHASIL: mongoose disalin ke standalone") ' +
') || echo "Sumber tidak ditemukan"',
'4. Copy mongoose ke standalone/node_modules'
);
// 3. Verifikasi
await exec(conn, 'ls ' + mongooseDst + ' 2>/dev/null | head -5 || echo "GAGAL: tidak ada"', '5. Verifikasi mongoose di standalone');
// 4. Juga pastikan dependensi mongoose tersedia (bson, etc.)
const deps = ['bson', 'kareem', 'mquery', 'mpath', 'sift'];
for (const dep of deps) {
const src = BP + '/node_modules/' + dep;
const dst = SA + '/node_modules/' + dep;
await exec(conn,
'[ -d ' + src + ' ] && ([ -e ' + dst + ' ] || (cp -r ' + src + ' ' + dst + ' && echo "Copied: ' + dep + '")) || echo "Skip: ' + dep + '"',
null
);
}
// 5. Restart frontend
await exec(conn, PM2 + ' restart backone-frontend && echo "RESTART OK"', '6. Restart backone-frontend');
// 6. Tunggu dan cek status
await new Promise(r => setTimeout(r, 5000));
await exec(conn, PM2 + ' list 2>/dev/null | grep backone', '7. Status PM2 setelah restart');
// 7. Test halaman agents
await new Promise(r => setTimeout(r, 3000));
await exec(conn, 'curl -sk -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/agents', '8. Test /agents setelah fix');
// 8. Cek error log setelah restart
await exec(conn, 'tail -10 ' + PUB + '/logs/frontend-error.log 2>/dev/null', '9. Error log terbaru');
conn.end();
console.log('\n✅ Selesai! Refresh browser ke https://demoplace.my.id/agents\n');
}
main().catch(e => console.error('[FATAL]', e.message));
-156
View File
@@ -1,156 +0,0 @@
// scripts/fix-pm2-env-final.js
// Fix definitif: Buat startup wrapper script yang load .env.production sebelum menjalankan Next.js
'use strict';
const { Client } = require('ssh2');
const SSH = { host: '103.185.47.52', port: 2222, username: 'adminbackend', password: 'htEo7x6LsBQiEHHH', readyTimeout: 60000 };
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
function exec(conn, cmd, label) {
if (label) console.log('\n[' + label + ']');
console.log('$ ' + cmd.substring(0, 90));
return new Promise(resolve => {
conn.exec(cmd, (err, s) => {
if (err) { resolve(''); return; }
let out = '';
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
.on('close', () => resolve(out));
});
});
}
async function main() {
const conn = new Client();
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(SSH); });
console.log('[SSH] Connected\n');
// 1. Buat wrapper script yang source .env.production
const wrapperContent = [
'#!/bin/bash',
'# BackOne DPI - Frontend startup wrapper',
'# Source environment variables from .env.production',
'ENV_FILE="' + PUB + '/.env.production"',
'if [ -f "$ENV_FILE" ]; then',
' set -a',
' source "$ENV_FILE"',
' set +a',
' echo "[startup] Environment variables loaded from .env.production"',
'else',
' echo "[startup] WARNING: .env.production not found at $ENV_FILE"',
'fi',
'# Start Next.js standalone server',
'exec node ' + PUB + '/.next/standalone/server.js',
].join('\n');
await exec(conn,
'cat > ' + PUB + '/start-frontend.sh << \'WRAPPER_EOF\'\n' + wrapperContent + '\nWRAPPER_EOF\n' +
'chmod +x ' + PUB + '/start-frontend.sh && echo "Wrapper script dibuat"',
'1. Buat wrapper startup script'
);
await exec(conn, 'cat ' + PUB + '/start-frontend.sh', '2. Verifikasi isi wrapper script');
// 2. Update ecosystem.config.js di SERVER untuk gunakan wrapper script
const ecosystemContent = `// ecosystem.config.js — PM2 Production Config (Server-side, DO NOT COMMIT)
module.exports = {
apps: [
{
name: 'backone-proxy',
script: './proxy/index.js',
cwd: '${PUB}',
instances: 1,
exec_mode: 'fork',
watch: false,
node_args: '--max-old-space-size=256',
max_memory_restart: '300M',
restart_delay: 5000,
max_restarts: 10,
env_file: '.env.production',
env: { NODE_ENV: 'production' },
error_file: './logs/proxy-error.log',
out_file: './logs/proxy-out.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
merge_logs: true,
},
{
name: 'backone-backend',
script: './backend/server.js',
cwd: '${PUB}',
instances: 1,
exec_mode: 'fork',
watch: false,
node_args: '--max-old-space-size=256',
max_memory_restart: '400M',
restart_delay: 3000,
max_restarts: 10,
env_file: '.env.production',
env: { NODE_ENV: 'production' },
error_file: './logs/backend-error.log',
out_file: './logs/backend-out.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
merge_logs: true,
},
{
name: 'backone-frontend',
script: './start-frontend.sh',
interpreter: 'bash',
cwd: '${PUB}',
instances: 1,
exec_mode: 'fork',
watch: false,
max_memory_restart: '700M',
restart_delay: 3000,
max_restarts: 10,
env: {
NODE_ENV: 'production',
PORT: 3000,
HOSTNAME: '127.0.0.1',
NEXT_TELEMETRY_DISABLED: '1',
},
error_file: './logs/frontend-error.log',
out_file: './logs/frontend-out.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
merge_logs: true,
},
],
};`;
await exec(conn,
'cat > ' + PUB + '/ecosystem.config.js << \'ECOSYSTEM_EOF\'\n' + ecosystemContent + '\nECOSYSTEM_EOF\n' +
'echo "ecosystem.config.js diperbarui"',
'3. Update ecosystem.config.js di server'
);
// 3. Delete & restart frontend dengan config baru
await exec(conn,
'cd ' + PUB + ' && ' + PM2 + ' delete backone-frontend 2>/dev/null; ' +
PM2 + ' start ecosystem.config.js --only backone-frontend && echo "START OK"',
'4. Start frontend dengan wrapper script'
);
// 4. Tunggu startup
await new Promise(r => setTimeout(r, 8000));
// 5. Verifikasi env vars
const listOut = await exec(conn, PM2 + ' list 2>/dev/null | grep backone-frontend', '5. PM2 status');
// Ambil ID proses baru
const match = listOut.match(/│\s+(\d+)\s+│\s+backone-frontend/);
if (match) {
const newId = match[1];
await exec(conn, PM2 + ' env ' + newId + ' 2>/dev/null | grep -E "(NETIFY|MONGO|JWT)" | head -5', '6. Env vars di proses baru');
}
// 6. Test agents
await exec(conn, 'curl -sk -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/agents', '7. Test /agents');
// 7. Error log terbaru
await exec(conn, 'tail -5 ' + PUB + '/logs/frontend-error.log 2>/dev/null', '8. Error log terbaru');
await exec(conn, 'tail -3 ' + PUB + '/logs/frontend-out.log 2>/dev/null', '9. Out log terbaru');
conn.end();
console.log('\n✅ Selesai!\n');
}
main().catch(e => console.error('[FATAL]', e.message));
-223
View File
@@ -1,223 +0,0 @@
// scripts/fix-proxy-headers.js
// Fix: proxy.php harus hapus Content-Length agar CSS/JS tidak terpotong
'use strict';
const SftpClient = require('ssh2-sftp-client');
const { Client } = require('ssh2');
const https = require('https');
const CONFIG = {
host: '103.185.47.52', port: 2222,
username: 'adminbackend', password: 'htEo7x6LsBQiEHHH',
readyTimeout: 60000
};
const ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
// ── proxy.php yang sudah diperbaiki ──────────────────────────────────────
// Fix utama: tambahkan content-length ke daftar header yang dibuang
// agar tidak terjadi mismatch antara ukuran compressed vs uncompressed
const PROXY_PHP = `<?php
/**
* BackOne DPI - PHP Reverse Proxy (Fixed)
* Forward semua request ke Next.js port 3000
* Fix: Content-Length dihapus agar tidak terjadi data truncation
*/
define('NEXTJS_URL', 'http://127.0.0.1:3000');
$uri = $_SERVER['REQUEST_URI'] ?? '/';
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
$target = NEXTJS_URL . $uri;
// Headers yang diteruskan ke Next.js
$fwdHeaders = [
'X-Forwarded-For: ' . ($_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1'),
'X-Forwarded-Proto: https',
'X-Real-IP: ' . ($_SERVER['REMOTE_ADDR'] ?? ''),
'Host: demoplace.my.id',
'Accept-Encoding: identity',
];
$allHeaders = getallheaders() ?: [];
$skip = ['host', 'connection', 'transfer-encoding', 'keep-alive', 'content-length', 'accept-encoding'];
foreach ($allHeaders as $name => $value) {
if (!in_array(strtolower($name), $skip)) {
$fwdHeaders[] = "$name: $value";
}
}
$body = in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE']) ? file_get_contents('php://input') : null;
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $target,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => $fwdHeaders,
CURLOPT_POSTFIELDS => $body,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true,
CURLOPT_FOLLOWLOCATION => false,
CURLOPT_TIMEOUT => 30,
CURLOPT_CONNECTTIMEOUT => 5,
// PENTING: Tidak pakai CURLOPT_ENCODING agar response tidak dikompresi
// (kita sudah kirim Accept-Encoding: identity ke Next.js)
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$curlError = curl_error($ch);
curl_close($ch);
if ($response === false) {
http_response_code(502);
header('Content-Type: text/plain');
echo 'BackOne: Gagal terhubung ke Next.js. Error: ' . $curlError;
exit;
}
$responseHeaders = substr($response, 0, $headerSize);
$responseBody = substr($response, $headerSize);
http_response_code($httpCode ?: 200);
// Header yang TIDAK diteruskan ke browser
$skipRes = [
'transfer-encoding',
'connection',
'keep-alive',
'content-encoding',
'content-length', // FIX: hapus agar tidak terjadi size mismatch
];
foreach (explode("\\r\\n", $responseHeaders) as $header) {
$header = trim($header);
if (empty($header) || preg_match('/^HTTP\\//i', $header)) continue;
$colonPos = strpos($header, ':');
if ($colonPos === false) continue;
$headerName = strtolower(trim(substr($header, 0, $colonPos)));
if (in_array($headerName, $skipRes)) continue;
header($header, false);
}
echo $responseBody;
`;
// ── .htaccess dengan FollowSymLinks ──────────────────────────────────────
const HTACCESS = `# BackOne DPI — Apache .htaccess
Options +FollowSymLinks
# Redirect HTTP ke HTTPS
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# Static Next.js files: sajikan langsung dari disk (via symlink _next -> .next)
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
# Semua request lain: teruskan ke PHP proxy (Next.js port 3000)
RewriteRule ^(.*)$ /proxy.php [L,QSA]
`;
async function main() {
console.log('\n╔══════════════════════════════════════════════════════════╗');
console.log('║ BackOne DPI — Fix CSS/JS Content-Length & Symlinks ║');
console.log('╚══════════════════════════════════════════════════════════╝\n');
// ── Diagnosa dulu: cek apa yang dikirim ke browser untuk CSS ──────────
console.log('▶ Diagnosa: Cek CSS URL yang ada di HTML login page...');
const conn1 = new Client();
await new Promise((r, j) => { conn1.on('ready', r).on('error', j).connect(CONFIG); });
// Ambil HTML dari port 3000 dan cari CSS links
const htmlResult = await new Promise(resolve => {
conn1.exec(
`curl -sk http://127.0.0.1:3000/login | grep -o 'href="/_next/static/css/[^"]*"' | head -3`,
(err, s) => {
if (err) { resolve('error'); return; }
let out = '';
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
.stderr.on('data', d => { out += d; })
.on('close', () => resolve(out.trim()));
}
);
});
console.log(`CSS refs: ${htmlResult}`);
// Test apakah CSS bisa diakses langsung
if (htmlResult) {
const cssPath = htmlResult.match(/href="([^"]+)"/)?.[1];
if (cssPath) {
await new Promise(resolve => {
conn1.exec(
`curl -sk -D - http://127.0.0.1:3000${cssPath} | head -15`,
(err, s) => {
if (err) { resolve(); return; }
s.on('data', d => process.stdout.write(d.toString()))
.stderr.on('data', () => {})
.on('close', resolve);
}
);
});
}
}
conn1.end();
// ── Upload proxy.php dan .htaccess yang sudah diperbaiki ──────────────
console.log('\n▶ Upload perbaikan via SFTP...');
const sftp = new SftpClient();
await sftp.connect(CONFIG);
await sftp.put(Buffer.from(PROXY_PHP, 'utf8'), `${ROOT}/proxy.php`);
console.log(' ✅ proxy.php (fixed: Content-Length stripped, Accept-Encoding: identity)');
await sftp.put(Buffer.from(HTACCESS, 'utf8'), `${ROOT}/.htaccess`);
console.log(' ✅ .htaccess (fixed: +FollowSymLinks added)');
await sftp.end();
// ── Verifikasi CSS via domain ─────────────────────────────────────────
console.log('\n▶ Test CSS loading via domain (tunggu 3 detik)...');
await new Promise(r => setTimeout(r, 3000));
const conn2 = new Client();
await new Promise((r, j) => { conn2.on('ready', r).on('error', j).connect(CONFIG); });
// Ambil CSS URL dari domain lalu test
const cssUrlResult = await new Promise(resolve => {
conn2.exec(
`CSS=$(curl -sk https://demoplace.my.id/login | grep -o '/_next/static/css/[^"]*' | head -1); ` +
`[ -n "$CSS" ] && curl -sk -D - "https://demoplace.my.id$CSS" | head -10 || echo "Tidak ada CSS URL ditemukan"`,
(err, s) => {
if (err) { resolve(); return; }
s.on('data', d => process.stdout.write(d.toString()))
.stderr.on('data', () => {})
.on('close', resolve);
}
);
});
conn2.end();
// ── Final test ────────────────────────────────────────────────────────
console.log('\n▶ Final test domain...');
for (const path of ['/', '/login']) {
const r = await new Promise(resolve => {
const req = https.get(`https://demoplace.my.id${path}`,
{ timeout: 12000, rejectUnauthorized: false },
res => resolve({ status: res.statusCode, location: res.headers.location })
);
req.on('error', e => resolve({ status: 0, error: e.message }));
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
});
const icon = r.status === 200 ? '✅' : r.status >= 300 && r.status < 400 ? '↩️ ' : '❌';
console.log(` ${icon} https://demoplace.my.id${path} → HTTP ${r.status}`);
}
console.log('\n✅ Selesai! Refresh browser dengan Ctrl+Shift+R (hard refresh)\n');
}
main().catch(err => { console.error('[FATAL]', err.message); process.exit(1); });
-129
View File
@@ -1,129 +0,0 @@
// scripts/fix-static-paths.js
// Menyalin static files dari backone-production ke standalone yang benar
// Masalah: Upload Windows membuat direktori dengan backslash literal di Linux
'use strict';
const { Client } = require('ssh2');
const https = require('https');
const SSH = {
host: '103.185.47.52', port: 2222,
username: 'adminbackend', password: 'htEo7x6LsBQiEHHH',
readyTimeout: 60000
};
function exec(conn, cmd, label) {
if (label) console.log('\n[' + label + ']');
console.log('$ ' + cmd.substring(0, 90));
return new Promise(resolve => {
conn.exec(cmd, (err, s) => {
if (err) { resolve(''); return; }
let out = '';
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
.on('close', () => resolve(out));
});
});
}
async function httpGet(url) {
return new Promise(resolve => {
const req = https.get(url, { timeout: 12000, rejectUnauthorized: false }, res => {
let body = '';
res.on('data', d => body += d);
res.on('end', () => resolve({ status: res.statusCode, size: body.length, type: res.headers['content-type'] }));
});
req.on('error', e => resolve({ status: 0, error: e.message }));
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
});
}
async function main() {
console.log('\n╔══════════════════════════════════════════════════════════╗');
console.log('║ BackOne DPI — Fix Static Paths (Windows Backslash) ║');
console.log('╚══════════════════════════════════════════════════════════╝\n');
const conn = new Client();
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(SSH); });
console.log('[SSH] Terhubung!\n');
const BP = '/home/adminbackend/backone-production';
const SA = '/home/adminbackend/web/demoplace.my.id/public_html/.next/standalone';
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
// 1. Cek BUILD_ID di backone-production
await exec(conn, 'cat ' + BP + '/.next/BUILD_ID 2>/dev/null || echo "NO_BUILDID"', '1. BUILD_ID backone-production');
// 2. Verifikasi chunk files ada di backone-production
await exec(conn,
'ls ' + BP + '/.next/static/chunks/ | grep -E "(3km6z|21luguo|1u6dw|1osk)" | head -10',
'2. Cek chunk files di backone-production'
);
// 3. Sinkronisasi static files dari backone-production ke standalone
await exec(conn,
'rsync -av --ignore-existing ' + BP + '/.next/static/ ' + SA + '/.next/static/ 2>&1 | tail -5',
'3. Rsync static files ke standalone/.next/static'
);
// 4. Verifikasi chunks sudah ada di standalone
await exec(conn,
'ls ' + SA + '/.next/static/chunks/ | grep -E "(3km6z|21luguo|1u6dw|1osk)" | head -10',
'4. Verifikasi chunks di standalone setelah rsync'
);
await exec(conn,
'ls ' + SA + '/.next/static/chunks/ | wc -l',
'5. Total file chunks di standalone'
);
// 5. Update symlink _next → standalone/.next
await exec(conn,
'rm -f ' + PUB + '/_next && ln -s ' + SA + '/.next ' + PUB + '/_next && echo "Symlink updated"',
'6. Update symlink _next → standalone/.next'
);
// 6. Verifikasi symlink
await exec(conn,
'ls -la ' + PUB + '/_next && ls ' + PUB + '/_next/static/chunks/ | grep -E "(3km6z|21luguo)" | head -5',
'7. Verifikasi symlink baru'
);
// 7. Juga sinkronisasi public/ dari backone-production jika dibutuhkan
await exec(conn,
'rsync -av --ignore-existing ' + BP + '/public/ ' + PUB + '/public/ 2>&1 | tail -3 || echo "Tidak perlu sync public/"',
'8. Sync public/ dari backone-production'
);
conn.end();
// 8. Test CSS/JS via domain
console.log('\n[9. Test CSS/JS via domain setelah fix...]');
await new Promise(r => setTimeout(r, 3000));
const files = [
'/_next/static/chunks/3km6z-n6wbgrs.js',
'/_next/static/chunks/1u6dw_tm45utz.css',
'/_next/static/chunks/1oskchnhjm4n8.css',
'/_next/static/chunks/21luguo5_g2uu.js',
'/_next/static/chunks/1-8s9_t85wwr4.js',
];
let allOk = true;
for (const f of files) {
const r = await httpGet('https://demoplace.my.id' + f);
const icon = r.status === 200 ? '✅' : '❌';
const ext = f.endsWith('.css') ? 'CSS' : 'JS ';
console.log(' ' + icon + ' [' + ext + '] HTTP ' + r.status + ' | ' + (r.size || 0) + ' bytes | ' + (r.type || 'N/A'));
if (r.status !== 200) { console.log(' → ' + f); allOk = false; }
}
if (allOk) {
console.log('\n🎉 SEMUA CSS/JS BERHASIL TERMUAT!');
console.log(' Lakukan HARD REFRESH (Ctrl+Shift+R) di browser.\n');
} else {
console.log('\n⚠️ Beberapa file masih 404. Mungkin perlu investigasi lebih lanjut.\n');
}
}
main().catch(err => { console.error('[FATAL]', err.message); process.exit(1); });
-118
View File
@@ -1,118 +0,0 @@
// scripts/fix-symlink.js
// Fix: Perbarui symlink _next agar menunjuk ke .next/standalone/.next
// Ini adalah penyebab utama CSS/JS tidak termuat
'use strict';
const { Client } = require('ssh2');
const https = require('https');
const SSH = {
host: '103.185.47.52', port: 2222,
username: 'adminbackend', password: 'htEo7x6LsBQiEHHH',
readyTimeout: 60000
};
function sshExec(conn, cmd, label = '') {
if (label) console.log(`\n[${label}]`);
console.log('$ ' + cmd.substring(0, 90) + (cmd.length > 90 ? '...' : ''));
return new Promise(resolve => {
conn.exec(cmd, (err, s) => {
if (err) { resolve(''); return; }
let out = '';
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
.on('close', () => resolve(out));
});
});
}
async function httpGet(url) {
return new Promise(resolve => {
const req = https.get(url, { timeout: 10000, rejectUnauthorized: false }, res => {
let body = '';
res.on('data', d => body += d);
res.on('end', () => resolve({ status: res.statusCode, type: res.headers['content-type'], size: body.length }));
});
req.on('error', e => resolve({ status: 0, error: e.message }));
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
});
}
async function main() {
console.log('\n╔══════════════════════════════════════════════════════════╗');
console.log('║ BackOne DPI — Fix Symlink _next → standalone/.next ║');
console.log('╚══════════════════════════════════════════════════════════╝\n');
const conn = new Client();
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(SSH); });
console.log('[SSH] Terhubung!\n');
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
const SA = `${PUB}/.next/standalone`;
// 1. Verifikasi struktur standalone
await sshExec(conn,
`ls ${SA}/.next/static/chunks/ | grep -E "(3km6z|21luguo|1u6dw|1osk)" | head -10`,
'1. Cek chunk files di standalone/.next'
);
await sshExec(conn,
`ls ${SA}/.next/static/chunks/*.css 2>/dev/null | head -5 || echo "Cek dengan wc"`,
'2. Cek CSS files di standalone'
);
await sshExec(conn,
`ls ${SA}/.next/static/chunks/ | wc -l && echo "file di chunks"`,
'3. Jumlah total file di chunks'
);
// 2. Update symlink
await sshExec(conn,
`rm -f ${PUB}/_next && ln -s ${SA}/.next ${PUB}/_next && echo "BERHASIL: symlink diperbaiki"`,
'4. Update symlink _next → standalone/.next'
);
// 3. Verifikasi symlink baru
await sshExec(conn,
`ls -la ${PUB}/_next && ls ${PUB}/_next/static/chunks/ | head -5`,
'5. Verifikasi symlink baru'
);
// 4. Juga update public/ symlink jika belum ada
await sshExec(conn,
`ls -la ${PUB}/public 2>/dev/null || echo "public/ tidak ada sebagai symlink"`,
'6. Cek public/ directory'
);
// Buat symlink public → standalone/public jika ada
await sshExec(conn,
`[ -d ${SA}/public ] && ([ -e ${PUB}/public_sa ] || ln -s ${SA}/public ${PUB}/public_sa) && echo "standalone/public tersedia" || echo "standalone/public tidak ada"`,
'7. Cek standalone/public'
);
conn.end();
// 5. Test CSS/JS loading setelah fix
console.log('\n[8. Test CSS/JS via domain setelah fix...]');
await new Promise(r => setTimeout(r, 2000));
const files = [
'/_next/static/chunks/3km6z-n6wbgrs.js',
'/_next/static/chunks/1u6dw_tm45utz.css',
'/_next/static/chunks/1oskchnhjm4n8.css',
'/_next/static/chunks/21luguo5_g2uu.js',
'/_next/static/chunks/1-8s9_t85wwr4.js',
];
for (const f of files) {
const r = await httpGet(`https://demoplace.my.id${f}`);
const icon = r.status === 200 ? '✅' : '❌';
const ext = f.endsWith('.css') ? 'CSS' : 'JS ';
console.log(` ${icon} [${ext}] HTTP ${r.status} | ${r.size || 0} bytes | ${r.type || 'N/A'}`);
if (r.status !== 200) console.log(` ${f}`);
}
console.log('\n✅ Selesai! Lakukan HARD REFRESH (Ctrl+Shift+R) di browser.\n');
}
main().catch(err => { console.error('[FATAL]', err.message); process.exit(1); });
-89
View File
@@ -1,89 +0,0 @@
// scripts/fix-turbopack-external.js
// Fix: Buat wrapper module untuk hashed external modules yang diperlukan Turbopack
'use strict';
const { Client } = require('ssh2');
const SSH = { host: '103.185.47.52', port: 2222, username: 'adminbackend', password: 'htEo7x6LsBQiEHHH', readyTimeout: 60000 };
const PUB = '/home/adminbackend/web/demoplace.my.id/public_html';
function exec(conn, cmd, label) {
if (label) console.log('\n[' + label + ']');
console.log('$ ' + cmd.substring(0, 90));
return new Promise(resolve => {
conn.exec(cmd, (err, s) => {
if (err) { resolve(''); return; }
let out = '';
s.on('data', d => { out += d; process.stdout.write(d.toString()); })
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); })
.on('close', () => resolve(out));
});
});
}
async function main() {
const conn = new Client();
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(SSH); });
console.log('[SSH] Connected\n');
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
const NM = PUB + '/node_modules';
const SA = PUB + '/.next/standalone';
// 1. Verifikasi mongoose asli tersedia di public_html/node_modules
await exec(conn, 'ls ' + NM + '/mongoose/package.json 2>/dev/null && echo "mongoose OK" || echo "mongoose TIDAK ADA"', '1. Cek mongoose asli');
// 2. Cek error log untuk nama hash yang dipakai
await exec(conn, 'grep "mongoose-" ' + PUB + '/logs/frontend-error.log 2>/dev/null | grep "Cannot find" | tail -5', '2. Hash mongoose dari error log');
// 3. Buat wrapper module mongoose-8b99e611e7552af3
const HASH_PKG = NM + '/mongoose-8b99e611e7552af3';
await exec(conn,
'mkdir -p ' + HASH_PKG + ' && ' +
'echo \'{"name":"mongoose-8b99e611e7552af3","version":"1.0.0","main":"index.js"}\' > ' + HASH_PKG + '/package.json && ' +
'echo \'module.exports = require("mongoose");\' > ' + HASH_PKG + '/index.js && ' +
'echo "Wrapper module dibuat"',
'3. Buat wrapper mongoose-8b99e611e7552af3'
);
// 4. Verifikasi wrapper
await exec(conn, 'cat ' + HASH_PKG + '/index.js', '4. Isi wrapper module');
// 5. Juga cek apakah ada hash lain yang mungkin gagal (better-sqlite3)
await exec(conn,
'grep "Cannot find module" ' + PUB + '/logs/frontend-error.log 2>/dev/null | grep -v mongoose | tail -5',
'5. Cek module lain yang mungkin gagal'
);
// 6. Cek standalone/node_modules - apakah ada?
await exec(conn,
'ls -la ' + SA + '/ | grep node_modules || echo "standalone/node_modules TIDAK ADA"',
'6. Cek standalone/node_modules'
);
// 7. Buat standalone/node_modules symlink ke public_html/node_modules
await exec(conn,
'[ -d ' + SA + '/node_modules ] && echo "Sudah ada" || ' +
'(ln -s ' + NM + ' ' + SA + '/node_modules && echo "Symlink node_modules dibuat")',
'7. Buat symlink standalone/node_modules → public_html/node_modules'
);
// 8. Restart frontend
await exec(conn, PM2 + ' restart backone-frontend --update-env && echo "RESTART OK"', '8. Restart frontend');
// 9. Tunggu startup
await new Promise(r => setTimeout(r, 8000));
// 10. Test agents page
await exec(conn,
'curl -sk -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/agents',
'9. Test /agents (HTTP code)'
);
// 11. Cek error log setelah restart
await exec(conn, 'tail -10 ' + PUB + '/logs/frontend-error.log 2>/dev/null', '10. Error log setelah fix');
conn.end();
console.log('\n✅ Selesai! Refresh browser ke https://demoplace.my.id/agents\n');
}
main().catch(e => console.error('[FATAL]', e.message));
-211
View File
@@ -1,211 +0,0 @@
// scripts/hestia-local-api-fix.js
// ─────────────────────────────────────────────────────────────────────────────
// Fix 502: Panggil Hestia CP API dari localhost (via SSH curl) karena
// Hestia API memblokir IP eksternal tapi MENGIZINKAN localhost (127.0.0.1)
// ─────────────────────────────────────────────────────────────────────────────
'use strict';
const { Client } = require('ssh2');
const https = require('https');
const SSH = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
readyTimeout: 60000
};
const DOMAIN = 'demoplace.my.id';
const WEB_USER = 'adminbackend';
const CONF = `/home/${WEB_USER}/conf/web/${DOMAIN}`;
const HESTIA_PASS = 'htEo7x6LsBQiEHHH';
function sshExec(conn, cmd, label = '') {
if (label) console.log(`\n[${label}]`);
console.log(`$ ${cmd.substring(0, 120)}${cmd.length > 120 ? '...' : ''}`);
return new Promise((resolve, reject) => {
conn.exec(cmd, (err, stream) => {
if (err) return reject(err);
let out = '';
stream.on('close', () => resolve(out))
.on('data', d => { out += d; process.stdout.write(d.toString()); })
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); });
});
});
}
// Isi nginx.conf_custom yang akan kita tulis
const NGINX_CUSTOM = `# BackOne DPI - Proxy langsung ke Next.js port 3000
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade \\$http_upgrade;
proxy_set_header Connection upgrade;
proxy_set_header Host \\$host;
proxy_set_header X-Real-IP \\$remote_addr;
proxy_set_header X-Forwarded-For \\$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto \\$scheme;
proxy_read_timeout 86400;
}`;
const NGINX_SSL_CUSTOM = `# BackOne DPI - Proxy SSL langsung ke Next.js port 3000
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade \\$http_upgrade;
proxy_set_header Connection upgrade;
proxy_set_header Host \\$host;
proxy_set_header X-Real-IP \\$remote_addr;
proxy_set_header X-Forwarded-For \\$proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_read_timeout 86400;
}`;
async function main() {
console.log('\n╔══════════════════════════════════════════════════════════╗');
console.log('║ BackOne DPI — Fix 502 via Hestia localhost API ║');
console.log('╚══════════════════════════════════════════════════════════╝\n');
const conn = new Client();
await new Promise((resolve, reject) => { conn.on('ready', resolve).on('error', reject).connect(SSH); });
console.log('[SSH] Terhubung!\n');
// ── Step 1: Baca apache2.conf untuk diagnosa ───────────────────────────
await sshExec(conn, `cat ${CONF}/apache2.conf`, 'STEP 1: Baca Apache Config');
// ── Step 2: Cek apakah mod_proxy aktif di Apache ───────────────────────
await sshExec(conn,
`apache2ctl -M 2>/dev/null | grep -i proxy || ` +
`apachectl -M 2>/dev/null | grep -i proxy || ` +
`echo "Tidak bisa cek Apache modules"`,
'STEP 2: Cek mod_proxy'
);
// ── Step 3: Test Hestia API dari localhost (bypass IP restriction) ─────
console.log('\n[STEP 3: Hestia API dari localhost]');
// Generate SHA-256 hash untuk password
const hashCmd = `echo -n '${HESTIA_PASS}' | sha256sum | cut -d' ' -f1`;
console.log(`$ ${hashCmd}`);
const hashResult = await new Promise((resolve, reject) => {
conn.exec(hashCmd, (err, stream) => {
if (err) return reject(err);
let out = '';
stream.on('close', () => resolve(out.trim()))
.on('data', d => { out += d; })
.stderr.on('data', () => {});
});
});
console.log(`Hash: ${hashResult}`);
// Panggil Hestia API dari localhost untuk list proxy templates
await sshExec(conn,
`curl -sk -X POST https://localhost:8083/api/ ` +
`-d "hash=${hashResult}&cmd=v-list-web-templates-proxy&returncode=json" | head -c 500`,
'STEP 3a: List proxy templates via localhost API'
);
// Panggil Hestia API untuk restart web
await sshExec(conn,
`curl -sk -X POST https://localhost:8083/api/ ` +
`-d "hash=${hashResult}&cmd=v-restart-web&returncode=json"`,
'STEP 3b: Restart web via localhost API'
);
// ── Step 4: Tulis file via Hestia API run command ──────────────────────
// v-run-cli-cmd jalankan perintah shell sebagai root via Hestia
const writeHttpConf = `tee ${CONF}/nginx.conf_custom << 'NGINXEOF'\n${NGINX_CUSTOM}\nNGINXEOF`;
const encodedWrite = Buffer.from(writeHttpConf).toString('base64');
await sshExec(conn,
`curl -sk -X POST https://localhost:8083/api/ ` +
`-d "hash=${hashResult}&cmd=v-run-cli-cmd&arg1=tee&arg2=${CONF}/nginx.conf_custom" ` +
`--data-urlencode "stdin=${NGINX_CUSTOM}" | head -c 200`,
'STEP 4a: Tulis nginx.conf_custom via API'
);
// Fallback: Coba tee dengan python sebagai cara alternatif
await sshExec(conn,
`curl -sk -X POST https://localhost:8083/api/ ` +
`-d "hash=${hashResult}&cmd=v-add-web-domain-nginx-cfg&arg1=${WEB_USER}&arg2=${DOMAIN}" | head -c 200`,
'STEP 4b: Add nginx cfg via Hestia API'
);
// ── Step 5: Coba ubah Web Template ke yang support Node.js ───────────
// Template yang biasanya ada di Hestia untuk Node.js/proxy
for (const tpl of ['nodejs', 'node', 'proxy', 'default-nodejs']) {
const res = await new Promise(resolve => {
conn.exec(
`curl -sk -X POST https://localhost:8083/api/ ` +
`-d "hash=${hashResult}&cmd=v-change-web-domain-tpl&arg1=${WEB_USER}&arg2=${DOMAIN}&arg3=${tpl}&arg4=yes" | head -c 200`,
(err, stream) => {
if (err) return resolve('SSH Error');
let out = '';
stream.on('close', () => resolve(out))
.on('data', d => out += d)
.stderr.on('data', () => {});
}
);
});
console.log(`\n[Template ${tpl}]: ${res.trim()}`);
if (res.includes('0') || res.includes('OK')) {
console.log(`✅ Template '${tpl}' berhasil diterapkan!`);
break;
}
}
// ── Step 6: Paksa reload Nginx dengan cara yang bisa dilakukan user ───
await sshExec(conn,
`/usr/local/hestia/bin/v-restart-web 2>&1 || ` +
`sudo nginx -s reload 2>&1 || ` +
`curl -sk -X POST https://localhost:8083/api/ -d "hash=${hashResult}&cmd=v-restart-web" | head -c 100`,
'STEP 6: Reload Nginx'
);
// ── Step 7: Tunggu dan test domain ────────────────────────────────────
console.log('\n[STEP 7: Test domain setelah 8 detik...]');
await sshExec(conn,
`sleep 8 && curl -sk -o /dev/null -w "HTTPS Status: %{http_code}" https://${DOMAIN}/login`,
'Domain Test'
);
// ── Step 8: Tampilkan PM2 status ──────────────────────────────────────
await sshExec(conn,
`/home/adminbackend/.npm-global/bin/pm2 list`,
'STEP 8: PM2 Status'
);
conn.end();
// Test dari luar
console.log('\n[Test dari jaringan lokal...]');
const extResult = await new Promise(resolve => {
const req = https.get(`https://${DOMAIN}/login`,
{ timeout: 10000, rejectUnauthorized: false },
res => resolve({ status: res.statusCode, location: res.headers.location })
);
req.on('error', e => resolve({ status: 0, error: e.message }));
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
});
const icon = extResult.status >= 200 && extResult.status < 400 ? '✅' : '❌';
console.log(`\n ${icon} https://${DOMAIN}/login → HTTP ${extResult.status} ${extResult.error || ''}`);
if (extResult.status >= 200 && extResult.status < 400) {
console.log('\n🎉 SUKSES! Dashboard BackOne sudah online!\n');
} else {
console.log('\n⚠️ Masih 502. Perlu konfigurasi manual di Hestia CP panel.\n');
console.log('━━━━ INSTRUKSI MANUAL ━━━━');
console.log('1. Buka Hestia CP → Web → demoplace.my.id → Edit');
console.log('2. Di bagian "Proxy Template" — pilih template Node.js (jika ada)');
console.log(' ATAU di File Manager: navigasi ke /conf/web/demoplace.my.id/');
console.log(' Buat file baru: nginx.conf_custom dengan isi:');
console.log('\n' + NGINX_CUSTOM.replace(/\\$/g, '$'));
console.log('\n Dan nginx.ssl.conf_custom dengan isi:');
console.log('\n' + NGINX_SSL_CUSTOM.replace(/\\$/g, '$'));
console.log('\n3. Setelah file dibuat, klik Rebuild di Hestia CP Web Domain.');
}
}
main().catch(err => { console.error('[FATAL]', err.message); process.exit(1); });
-180
View File
@@ -1,180 +0,0 @@
// scripts/hestia-nginx-fix.js
// ─────────────────────────────────────────────────────────────────────────────
// Fix 502 Bad Gateway dengan cara:
// 1. Cek permissions direktori conf Nginx
// 2. Gunakan Hestia CP REST API untuk ubah proxy template ke Node.js
// 3. Atau tulis nginx.conf_custom via Hestia API command
// ─────────────────────────────────────────────────────────────────────────────
'use strict';
const { Client } = require('ssh2');
const https = require('https');
const querystring = require('querystring');
const crypto = require('crypto');
const SSH = { host: '103.185.47.52', port: 2222, username: 'adminbackend', password: 'htEo7x6LsBQiEHHH', readyTimeout: 60000 };
const HESTIA_HOST = 'isp.proit.id';
const HESTIA_PORT = 8083;
const HESTIA_USER = 'admin';
const HESTIA_PASS = 'htEo7x6LsBQiEHHH';
const DOMAIN = 'demoplace.my.id';
const WEB_USER = 'adminbackend';
const CONF = `/home/${WEB_USER}/conf/web/${DOMAIN}`;
// ── Hestia CP API call ─────────────────────────────────────────────────────
function hestiaApi(cmd, args = []) {
return new Promise((resolve, reject) => {
const hash = crypto.createHash('sha256').update(HESTIA_PASS).digest('hex');
const body = querystring.stringify({ hash, cmd, ...Object.fromEntries(args.map((a, i) => [`arg${i + 1}`, a])) });
const req = https.request({
hostname: HESTIA_HOST,
port: HESTIA_PORT,
path: '/api/',
method: 'POST',
rejectUnauthorized: false,
headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Content-Length': Buffer.byteLength(body) }
}, res => {
let data = '';
res.on('data', d => data += d);
res.on('end', () => resolve({ status: res.statusCode, body: data.trim() }));
});
req.on('error', reject);
req.write(body);
req.end();
});
}
// ── SSH command runner ─────────────────────────────────────────────────────
function sshExec(conn, cmd) {
return new Promise((resolve, reject) => {
conn.exec(cmd, (err, stream) => {
if (err) return reject(err);
let out = '';
stream.on('close', () => resolve(out))
.on('data', d => { out += d; process.stdout.write(d.toString()); })
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); });
});
});
}
// ── Custom Nginx config content ───────────────────────────────────────────
const nginxCustomContent = `# BackOne DPI — Proxy to Next.js port 3000
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 86400;
}`;
const nginxSslContent = `# BackOne DPI — Proxy SSL to Next.js port 3000
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_read_timeout 86400;
}`;
async function main() {
console.log('\n╔══════════════════════════════════════════════════════════╗');
console.log('║ BackOne DPI — Fix 502 via Hestia API + Nginx Fix ║');
console.log('╚══════════════════════════════════════════════════════════╝\n');
// ── Step 1: Diagnose conf directory permissions via SSH ─────────────────
console.log('\n▶ Step 1: Check conf directory permissions via SSH...');
const conn = new Client();
await new Promise((resolve, reject) => { conn.on('ready', resolve).on('error', reject).connect(SSH); });
console.log('[SSH] Connected!\n');
await sshExec(conn, `echo "=== CONF DIR PERMS ===" && ls -la /home/${WEB_USER}/conf/web/`);
await sshExec(conn, `echo "=== DOMAIN CONF DIR ===" && ls -la ${CONF}/`);
await sshExec(conn, `echo "=== EXISTING CUSTOM CONF ===" && ls -la ${CONF}/nginx.conf_* 2>/dev/null || echo "No custom conf yet"`);
// ── Step 2: Try Python to write the file (avoids shell quoting issues) ──
console.log('\n▶ Step 2: Attempting to write nginx.conf_custom via Python...');
const pyScript = `python3 -c "
import os
content = '''${nginxCustomContent.replace(/'/g, "\\'")}'''
path = '${CONF}/nginx.conf_custom'
try:
with open(path, 'w') as f:
f.write(content + '\\n')
print('[OK] Written: ' + path)
except Exception as e:
print('[FAIL] ' + str(e))
"`;
await sshExec(conn, pyScript);
const pyScriptSsl = `python3 -c "
content = '''${nginxSslContent.replace(/'/g, "\\'")}'''
path = '${CONF}/nginx.ssl.conf_custom'
try:
with open(path, 'w') as f:
f.write(content + '\\n')
print('[OK] Written: ' + path)
except Exception as e:
print('[FAIL] ' + str(e))
"`;
await sshExec(conn, pyScriptSsl);
conn.end();
// ── Step 3: Try Hestia CP REST API to restart web ─────────────────────
console.log('\n▶ Step 3: Call Hestia CP REST API to restart web server...');
// Try listing available proxy templates first
console.log('\n → Listing available proxy templates...');
const templatesRes = await hestiaApi('v-list-web-templates-proxy', []);
console.log(` API Response [list-proxy-templates]: HTTP ${templatesRes.status}`);
console.log(` Body: ${templatesRes.body.substring(0, 300)}`);
// Try to restart web via API
console.log('\n → Restarting web server via Hestia API...');
const restartRes = await hestiaApi('v-restart-web', []);
console.log(` API Response [restart-web]: HTTP ${restartRes.status}`);
console.log(` Body: ${restartRes.body}`);
// Try restart with correct user arg
const restartRes2 = await hestiaApi('v-restart-web', [WEB_USER]);
console.log(` API Response [restart-web user]: HTTP ${restartRes2.status}`);
console.log(` Body: ${restartRes2.body}`);
// ── Step 4: Wait and test domain ─────────────────────────────────────
console.log('\n▶ Step 4: Waiting 8 seconds then testing domain...');
await new Promise(r => setTimeout(r, 8000));
const testRes = await new Promise(resolve => {
const req = https.get('https://demoplace.my.id/login', { timeout: 10000, rejectUnauthorized: false }, res => {
resolve({ status: res.statusCode, location: res.headers.location });
});
req.on('error', e => resolve({ status: 0, error: e.message }));
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
});
const icon = testRes.status >= 200 && testRes.status < 400 ? '✅' : '❌';
console.log(`\n ${icon} https://demoplace.my.id/login → HTTP ${testRes.status} ${testRes.error || ''}`);
if (testRes.location) console.log(` Location: ${testRes.location}`);
if (testRes.status >= 200 && testRes.status < 400) {
console.log('\n🎉 SUKSES! Domain sudah bisa diakses!\n');
} else {
console.log('\n⚠️ Domain masih belum bisa diakses. Perlu konfig manual via Hestia panel.\n');
console.log('Silakan buka Hestia CP File Manager dan buat file:');
console.log(` ${CONF}/nginx.conf_custom`);
console.log(` ${CONF}/nginx.ssl.conf_custom`);
console.log('\nDengan isi (untuk keduanya):');
console.log(nginxCustomContent);
console.log('\nKemudian di Hestia CP: Web → demoplace.my.id → Rebuild\n');
}
}
main().catch(err => { console.error('[FATAL]', err.message); process.exit(1); });
-18
View File
@@ -1,18 +0,0 @@
const { Client } = require('ssh2');
const conn = new Client();
conn.on('ready', () => {
conn.exec(`ls -la /home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/.next/server/app/\\(dashboard\\)/ 2>/dev/null || ls -la /home/adminbackend/web/demoplace.my.id/public_html/.next/server/app/`, (err, stream) => {
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log('=== REMOTE DASHBOARD APP ROUTES ===\n' + out);
conn.end();
});
});
}).connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
-83
View File
@@ -1,83 +0,0 @@
// scripts/migrate-db-remote.js
global.crypto = require('crypto');
const { MongoClient } = require('mongodb');
const fs = require('fs');
const path = require('path');
const REMOTE_URI = process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017/backone_dpi';
const DB_NAME = 'backone_dpi';
const DATA_DIR = __dirname;
async function migrateCollection(db, colName, keyField) {
const filePath = path.join(DATA_DIR, `${colName}.json`);
if (!fs.existsSync(filePath)) {
console.log(` [SKIP] ${colName}.json not found in migration folder.`);
return;
}
const raw = fs.readFileSync(filePath, 'utf8');
const documents = JSON.parse(raw);
console.log(`\nMigrating collection: ${colName} (${documents.length} docs)...`);
const col = db.collection(colName);
let upsertedCount = 0;
let matchedCount = 0;
for (const doc of documents) {
// Preserve MongoDB Object ID or convert it properly if it has $oid notation
const query = {};
query[keyField] = doc[keyField];
// Clean up _id or preserve it
const updateDoc = { ...doc };
if (updateDoc._id) {
if (updateDoc._id.$oid) {
// If it's exported via mongoexport format
delete updateDoc._id;
} else {
// Remove _id from update payload to prevent "change _id" errors on upsert
delete updateDoc._id;
}
}
const result = await col.updateOne(
query,
{ $set: updateDoc },
{ upsert: true }
);
if (result.upsertedCount > 0) {
upsertedCount++;
} else {
matchedCount++;
}
}
console.log(` ✓ Finished ${colName}: ${upsertedCount} new inserted (upserted), ${matchedCount} existing updated.`);
}
async function main() {
console.log('=== STARTING PRODUCTION DATABASE MIGRATION ===');
console.log('Connecting to production MongoDB...');
const client = new MongoClient(REMOTE_URI, { serverSelectionTimeoutMS: 5000 });
try {
await client.connect();
console.log('✓ Connected to production MongoDB successfully!');
const db = client.db(DB_NAME);
// Run migrations using distinct key fields for upserting
await migrateCollection(db, 'users', 'username');
await migrateCollection(db, 'tenantconfigs', 'site_uuid');
await migrateCollection(db, 'customagentlocations', 'agent_uuid');
console.log('\n=== MIGRATION COMPLETED SUCCESSFULLY ===');
} catch (err) {
console.error('\n✗ Migration failed:', err.message);
process.exit(1);
} finally {
await client.close();
}
}
main();
-126
View File
@@ -1,126 +0,0 @@
// scripts/migrate_production_config.js
if (typeof globalThis.crypto === 'undefined') {
globalThis.crypto = require('crypto');
}
const { MongoClient } = require('mongodb');
const path = require('path');
const LOCAL_URI = 'mongodb://127.0.0.1:27017';
const REMOTE_URI = process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017/backone_dpi';
const DB_NAME = 'backone_dpi';
async function migrate() {
console.log("=============================================================");
console.log(" BackOne DPI - Selective Configuration Migration to Prod ");
console.log("=============================================================\n");
let localClient, remoteClient;
try {
console.log("Connecting to local MongoDB...");
localClient = new MongoClient(LOCAL_URI, { serverSelectionTimeoutMS: 3000 });
await localClient.connect();
const localDb = localClient.db(DB_NAME);
console.log("✓ Connected to local MongoDB.");
console.log("Connecting to production MongoDB...");
remoteClient = new MongoClient(REMOTE_URI, { serverSelectionTimeoutMS: 5000 });
await remoteClient.connect();
const remoteDb = remoteClient.db(DB_NAME);
console.log("✓ Connected to production MongoDB.\n");
// 1. Sync users (Upsert based on username to preserve existing user credentials if updated)
console.log("--- Syncing 'users' collection ---");
const localUsersColl = localDb.collection('users');
const remoteUsersColl = remoteDb.collection('users');
const localUsers = await localUsersColl.find({}).toArray();
console.log(`Found ${localUsers.length} users in local database.`);
let userUpsertCount = 0;
for (const user of localUsers) {
// Remove _id to avoid duplicate key errors or mismatched ObjectId
const { _id, ...userData } = user;
const res = await remoteUsersColl.updateOne(
{ username: user.username },
{ $set: userData },
{ upsert: true }
);
if (res.upsertedCount > 0 || res.modifiedCount > 0) {
userUpsertCount++;
}
}
console.log(`✓ Synchronized ${userUpsertCount} users to production MongoDB.`);
// 2. Sync tenantconfigs (Clear & Replace)
console.log("\n--- Syncing 'tenantconfigs' collection ---");
const localConfigColl = localDb.collection('tenantconfigs');
const remoteConfigColl = remoteDb.collection('tenantconfigs');
const localConfigs = await localConfigColl.find({}).toArray();
console.log(`Found ${localConfigs.length} tenant configurations locally.`);
if (localConfigs.length > 0) {
await remoteConfigColl.deleteMany({});
const cleanedConfigs = localConfigs.map(c => {
const { _id, ...rest } = c;
return rest;
});
await remoteConfigColl.insertMany(cleanedConfigs);
console.log(`✓ Synchronized ${localConfigs.length} configurations to production.`);
}
// 3. Sync customagentlocations (Clear & Replace)
console.log("\n--- Syncing 'customagentlocations' collection ---");
const localLocColl = localDb.collection('customagentlocations');
const remoteLocColl = remoteDb.collection('customagentlocations');
const localLocs = await localLocColl.find({}).toArray();
console.log(`Found ${localLocs.length} agent locations locally.`);
if (localLocs.length > 0) {
await remoteLocColl.deleteMany({});
const cleanedLocs = localLocs.map(l => {
const { _id, ...rest } = l;
return rest;
});
await remoteLocColl.insertMany(cleanedLocs);
console.log(`✓ Synchronized ${localLocs.length} agent locations to production.`);
}
// 4. Sync blacklistrules (Clear & Replace, if exists)
console.log("\n--- Syncing 'blacklistrules' collection ---");
const localRulesColl = localDb.collection('blacklistrules');
const remoteRulesColl = remoteDb.collection('blacklistrules');
// Check if collection exists
const localColls = await localDb.listCollections({ name: 'blacklistrules' }).toArray();
if (localColls.length > 0) {
const localRules = await localRulesColl.find({}).toArray();
console.log(`Found ${localRules.length} blacklist rules locally.`);
if (localRules.length > 0) {
await remoteRulesColl.deleteMany({});
const cleanedRules = localRules.map(r => {
const { _id, ...rest } = r;
return rest;
});
await remoteRulesColl.insertMany(cleanedRules);
console.log(`✓ Synchronized ${localRules.length} blacklist rules to production.`);
}
} else {
console.log("No blacklist rules found locally.");
}
console.log("\n=============================================================");
console.log("✓ Database configuration migration completed successfully!");
console.log("=============================================================");
} catch (err) {
console.error("\n✗ Migration failed:", err.message);
process.exit(1);
} finally {
if (localClient) await localClient.close();
if (remoteClient) await remoteClient.close();
}
}
migrate();
-36
View File
@@ -1,36 +0,0 @@
// scripts/prune-production-cumulative.js
const mongoose = require('mongoose');
const MONGODB_URI = process.env.MONGODB_URI || "mongodb://127.0.0.1:27017/backone_dpi";
async function run() {
console.log('Connecting to Production MongoDB...');
await mongoose.connect(MONGODB_URI);
console.log('Connected.');
const db = mongoose.connection.db;
// We want to delete summaries and telemetry documents created before today at 18:40 WIB (11:40 UTC)
const cutOffDate = new Date('2026-07-23T11:40:00.000Z');
console.log('Pruning data before:', cutOffDate);
const collections = ['summaries', 'appstats', 'protocolstats', 'devicestats'];
for (const collName of collections) {
const countBefore = await db.collection(collName).countDocuments({});
console.log(`[${collName}] Count before prune:`, countBefore);
const deleteRes = await db.collection(collName).deleteMany({
timestamp: { $lt: cutOffDate }
});
console.log(`[${collName}] Deleted:`, deleteRes.deletedCount);
const countAfter = await db.collection(collName).countDocuments({});
console.log(`[${collName}] Count after prune:`, countAfter);
}
await mongoose.disconnect();
console.log('✓ Pruning complete!');
}
run().catch(console.error);
-26
View File
@@ -1,26 +0,0 @@
// scripts/quick-diag.js
'use strict';
const { Client } = require('ssh2');
const conn = new Client();
conn.on('ready', () => {
const cmds = [
'echo "=== Port 3000 test ==" && curl -sk -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/login',
'echo "" && echo "=== Nginx conf_custom ===" && cat /home/adminbackend/conf/web/demoplace.my.id/nginx.conf_custom 2>/dev/null || echo MISSING',
'echo "=== Nginx ssl conf_custom ===" && cat /home/adminbackend/conf/web/demoplace.my.id/nginx.ssl.conf_custom 2>/dev/null || echo MISSING',
'echo "=== .htaccess ===" && cat /home/adminbackend/web/demoplace.my.id/public_html/.htaccess',
'echo "=== PM2 status ===" && /home/adminbackend/.npm-global/bin/pm2 list 2>/dev/null | grep -E "(name|backone)"',
];
let i = 0;
function run() {
if (i >= cmds.length) { conn.end(); console.log('\nDone.'); return; }
const cmd = cmds[i++];
conn.exec(cmd, (err, s) => {
if (err) { console.error(err.message); run(); return; }
s.on('data', d => process.stdout.write(d.toString()))
.stderr.on('data', d => process.stdout.write(d.toString()))
.on('close', run);
});
}
run();
}).on('error', e => console.error(e.message))
.connect({ host: '103.185.47.52', port: 2222, username: 'adminbackend', password: 'htEo7x6LsBQiEHHH', readyTimeout: 30000 });
-44
View File
@@ -1,44 +0,0 @@
const { Client } = require('ssh2');
const conn = new Client();
conn.on('ready', () => {
// Execute a shell script on remote server
conn.exec(`python3 -c "
import os, re
root = '/home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/.next/server/app/(dashboard)'
for dirpath, dirnames, filenames in os.walk(root):
for f in filenames:
if f.endswith('.html') or f.endswith('.js'):
full = os.path.join(dirpath, f)
rel = os.path.relpath(full, root)
try:
content = open(full, 'r', encoding='utf-8', errors='ignore').read()
h2s = re.findall(r'<h[12][^>]*>(.*?)</h[12]>', content)
clean_h2s = [re.sub(r'<[^>]+>', '', h).strip() for h in h2s if h.strip()]
has_learn = 'Learn This Page' in content
if clean_h2s or has_learn:
print(f'Route File: {rel}')
print(f' Headers: {\" | \".join(clean_h2s)}')
print(f' Learn This Page Button: {has_learn}')
print('-' * 40)
except Exception as e:
pass
"`, (err, stream) => {
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log(out);
conn.end();
});
});
}).connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
-95
View File
@@ -1,95 +0,0 @@
const { spawn } = require('child_process');
const http = require('http');
const fs = require('fs');
const path = require('path');
const jwt = require('jsonwebtoken');
const mongoose = require('mongoose');
const WebSocket = require('next/dist/compiled/ws');
require('dotenv').config({ path: path.join(__dirname, '..', '.env.local') });
const JWT_SECRET = process.env.JWT_SECRET || 'backone-dpi-secret-jwt-key-2024';
const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017/backone_dpi';
async function main() {
try {
await mongoose.connect(MONGODB_URI);
const db = mongoose.connection.db;
const users = db.collection('users');
let adminUser = await users.findOne({ username: 'admin' });
const payload = {
userId: adminUser._id.toString(),
username: adminUser.username,
role: adminUser.role,
site_uuid: adminUser.site_uuid || 'default',
agent_uuid: adminUser.agent_uuid || null
};
const token = jwt.sign(payload, JWT_SECRET, { expiresIn: '1h' });
await mongoose.disconnect();
const edgePath = "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe";
const edgeProc = spawn(edgePath, [
'--headless',
'--disable-gpu',
'--remote-debugging-port=9222',
'--window-size=400,844',
'http://localhost:3000/'
]);
await new Promise(r => setTimeout(r, 2500));
const targets = await new Promise((resolve, reject) => {
http.get('http://127.0.0.1:9222/json', (res) => {
let body = '';
res.on('data', c => body += c);
res.on('end', () => resolve(JSON.parse(body)));
}).on('error', reject);
});
const pageTarget = targets.find(t => t.type === 'page');
if (!pageTarget || !pageTarget.webSocketDebuggerUrl) {
edgeProc.kill();
return;
}
const ws = new WebSocket(pageTarget.webSocketDebuggerUrl);
let messageId = 1;
const send = (method, params = {}) => {
return new Promise((res) => {
const id = messageId++;
const handler = (data) => {
const msg = JSON.parse(data);
if (msg.id === id) {
ws.removeListener('message', handler);
res(msg.result);
}
};
ws.on('message', handler);
ws.send(JSON.stringify({ id, method, params }));
});
};
ws.on('open', async () => {
await send('Network.setCookie', { name: 'token', value: token, domain: 'localhost', path: '/' });
await send('Network.setCookie', { name: 'backone_token', value: token, domain: 'localhost', path: '/' });
await send('Page.navigate', { url: 'http://localhost:3000/' });
await new Promise(r => setTimeout(r, 5000));
const screenshot = await send('Page.captureScreenshot', { format: 'png', captureBeyondViewport: true });
const outputPath = "C:\\Users\\rafif\\.gemini\\antigravity-ide\\brain\\d6704840-c7e7-4558-b215-0fe98bbfb07a\\mobile-full-dashboard-live.png";
fs.writeFileSync(outputPath, Buffer.from(screenshot.data, 'base64'));
console.log("Full page screenshot saved to:", outputPath, "Size:", fs.statSync(outputPath).size, "bytes");
ws.close();
edgeProc.kill();
});
} catch (err) {
console.error("Error:", err.message);
}
}
main();
-174
View File
@@ -1,174 +0,0 @@
// scripts/restore-proxy.js
// Pulihkan proxy.php + htaccess yang rusak via SFTP
'use strict';
const SftpClient = require('ssh2-sftp-client');
const { Client } = require('ssh2');
const https = require('https');
const CONFIG = {
host: '103.185.47.52', port: 2222,
username: 'adminbackend', password: 'htEo7x6LsBQiEHHH',
readyTimeout: 60000
};
const ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
// ── PHP Proxy (forward semua ke Next.js port 3000) ──────────────────────
const PROXY_PHP = `<?php
/**
* BackOne DPI - PHP Reverse Proxy
* Meneruskan semua request ke Next.js port 3000
*/
define('NEXTJS_URL', 'http://127.0.0.1:3000');
$uri = $_SERVER['REQUEST_URI'] ?? '/';
$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
$target = NEXTJS_URL . $uri;
$fwdHeaders = [
'X-Forwarded-For: ' . ($_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'] ?? '127.0.0.1'),
'X-Forwarded-Proto: https',
'X-Real-IP: ' . ($_SERVER['REMOTE_ADDR'] ?? ''),
'Host: ' . ($_SERVER['HTTP_HOST'] ?? 'demoplace.my.id'),
];
$allHeaders = getallheaders() ?: [];
$skip = ['host','connection','transfer-encoding','keep-alive','content-length'];
foreach ($allHeaders as $name => $value) {
if (!in_array(strtolower($name), $skip)) {
$fwdHeaders[] = "$name: $value";
}
}
$body = in_array($method, ['POST','PUT','PATCH','DELETE']) ? file_get_contents('php://input') : null;
$ch = curl_init();
curl_setopt_array($ch, [
CURLOPT_URL => $target,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => $fwdHeaders,
CURLOPT_POSTFIELDS => $body,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true,
CURLOPT_FOLLOWLOCATION => false,
CURLOPT_TIMEOUT => 30,
CURLOPT_CONNECTTIMEOUT => 5,
CURLOPT_ENCODING => '',
]);
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$curlError = curl_error($ch);
curl_close($ch);
if ($response === false) {
http_response_code(502);
header('Content-Type: text/plain');
echo 'BackOne: Gagal terhubung ke Next.js. Error: ' . $curlError;
exit;
}
$responseHeaders = substr($response, 0, $headerSize);
$responseBody = substr($response, $headerSize);
http_response_code($httpCode ?: 200);
$skipRes = ['transfer-encoding','connection','keep-alive','content-encoding'];
foreach (explode("\\r\\n", $responseHeaders) as $header) {
$header = trim($header);
if (empty($header) || preg_match('/^HTTP\\//i', $header)) continue;
$colonPos = strpos($header, ':');
if ($colonPos === false) continue;
$headerName = strtolower(trim(substr($header, 0, $colonPos)));
if (in_array($headerName, $skipRes)) continue;
header($header, false);
}
echo $responseBody;
`;
// ── .htaccess (routing ke proxy.php) ──────────────────────────────────
const HTACCESS = `# BackOne DPI — Apache .htaccess
# Redirect HTTP ke HTTPS
RewriteEngine On
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# Static Next.js files: sajikan langsung dari disk
RewriteCond %{REQUEST_FILENAME} -f
RewriteRule ^ - [L]
# Semua request lain: teruskan ke PHP proxy (Next.js port 3000)
RewriteRule ^(.*)$ /proxy.php [L,QSA]
`;
async function main() {
console.log('\n╔══════════════════════════════════════════════════════════╗');
console.log('║ BackOne DPI — Pulihkan proxy.php & .htaccess ║');
console.log('╚══════════════════════════════════════════════════════════╝\n');
// ── Upload via SFTP ──────────────────────────────────────────────────
console.log('▶ Upload proxy.php dan .htaccess via SFTP...');
const sftp = new SftpClient();
await sftp.connect(CONFIG);
await sftp.put(Buffer.from(PROXY_PHP, 'utf8'), `${ROOT}/proxy.php`);
console.log(' ✅ proxy.php diupload');
await sftp.put(Buffer.from(HTACCESS, 'utf8'), `${ROOT}/.htaccess`);
console.log(' ✅ .htaccess diupload (dengan newline yang benar)');
await sftp.end();
// ── Verifikasi via SSH ───────────────────────────────────────────────
console.log('\n▶ Verifikasi di server...');
const conn = new Client();
await new Promise((r, j) => { conn.on('ready', r).on('error', j).connect(CONFIG); });
console.log('[SSH] Terhubung!\n');
await new Promise((resolve) => {
conn.exec(
`echo "=== .htaccess ===" && cat ${ROOT}/.htaccess && ` +
`echo "" && echo "=== proxy.php (5 baris awal) ===" && head -5 ${ROOT}/proxy.php && ` +
`echo "" && echo "=== Test port 3000 ===" && curl -sk -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/login && echo "" && ` +
`echo "=== Test port 8009/8080 ===" && curl -sk -o /dev/null -w "Apache 8009: %{http_code}" http://127.0.0.1:8009/ && echo "" && curl -sk -o /dev/null -w "Apache 8080: %{http_code}" http://103.185.47.52:8080/login && echo ""`,
(err, s) => {
if (err) { resolve(); return; }
s.on('data', d => process.stdout.write(d.toString()))
.stderr.on('data', d => process.stdout.write(d.toString()))
.on('close', () => { resolve(); });
}
);
});
conn.end();
// ── Test external ────────────────────────────────────────────────────
console.log('\n▶ Test domain dari luar (tunggu 3 detik)...');
await new Promise(r => setTimeout(r, 3000));
for (const path of ['/', '/login', '/api/health']) {
const r = await new Promise(resolve => {
const req = https.get(`https://demoplace.my.id${path}`,
{ timeout: 12000, rejectUnauthorized: false },
res => {
let body = '';
res.on('data', d => body += d);
res.on('end', () => resolve({ status: res.statusCode, body: body.substring(0, 80), location: res.headers.location }));
}
);
req.on('error', e => resolve({ status: 0, error: e.message }));
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
});
const icon = r.status === 200 ? '✅' : r.status === 301 || r.status === 307 ? '↩️ ' : '❌';
console.log(` ${icon} https://demoplace.my.id${path} → HTTP ${r.status} ${r.error || ''}`);
if (r.location) console.log(` → ${r.location}`);
}
console.log('\n✅ Selesai! Refresh https://demoplace.my.id/login\n');
}
main().catch(err => { console.error('[FATAL]', err.message); process.exit(1); });
-80
View File
@@ -1,80 +0,0 @@
const SftpClient = require('ssh2-sftp-client');
const { Client } = require('ssh2');
const remoteScanScript = `
const fs = require('fs');
const path = require('path');
const root = '/home/adminbackend/web/demoplace.my.id/public_html/.next';
const targetTitles = [
'Overview Dashboard',
'Summary Overview',
'DPI MetaData',
'BackOne Metadata',
'Network Topology',
'Network Infrastructure',
'Traffic Categories',
'Threat Intelligence',
'Detected Threats',
'App Lookup',
'Application Database',
'Encryption Audit',
'Security & Encryption Audit'
];
console.log('=== MATCHING TARGET TITLES IN REMOTE NEXT BUILD ===\\n');
function scan(dir) {
if (!fs.existsSync(dir)) return;
const items = fs.readdirSync(dir, { withFileTypes: true });
for (const item of items) {
const full = path.join(dir, item.name);
if (item.isDirectory()) {
scan(full);
} else if (item.name.endsWith('.js') || item.name.endsWith('.html')) {
const content = fs.readFileSync(full, 'utf8');
targetTitles.forEach(t => {
if (content.includes(t)) {
console.log(\`Found "\${t}" in file: \${path.relative(root, full)}\`);
}
});
}
}
}
scan(root);
`;
async function main() {
const sftp = new SftpClient();
await sftp.connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
const remoteScriptPath = '/home/adminbackend/scan_strings.js';
await sftp.put(Buffer.from(remoteScanScript), remoteScriptPath);
await sftp.end();
const conn = new Client();
conn.on('ready', () => {
conn.exec(`node ${remoteScriptPath}`, (err, stream) => {
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log(out);
conn.end();
});
});
}).connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
}
main();
-26
View File
@@ -1,26 +0,0 @@
const { Client } = require('ssh2');
const conn = new Client();
conn.on('ready', () => {
conn.exec(`grep -rn "Overview Dashboard" /home/adminbackend/web/demoplace.my.id/public_html/ /home/adminbackend/backone-production/ 2>/dev/null | head -n 30`, (err, stream) => {
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log('=== SEARCH Overview Dashboard ===\n' + out);
conn.exec(`grep -rn "DPI MetaData" /home/adminbackend/web/demoplace.my.id/public_html/ /home/adminbackend/backone-production/ 2>/dev/null | head -n 30`, (err2, stream2) => {
let out2 = '';
stream2.on('data', d => out2 += d);
stream2.on('close', () => {
console.log('=== SEARCH DPI MetaData ===\n' + out2);
conn.end();
});
});
});
});
}).connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
-153
View File
@@ -1,153 +0,0 @@
// scripts/security-fix.js
// ─────────────────────────────────────────────────────────────────────────────
// BackOne DPI — Security fix & final production configuration
// 1. Remove .env.production from standalone directory (security)
// 2. Fix PM2 to use new ecosystem config properly
// 3. Verify HTTPS redirect and domain reachability
// ─────────────────────────────────────────────────────────────────────────────
'use strict';
const { Client: SshClient } = require('ssh2');
const https = require('https');
const http = require('http');
const CONFIG = {
host: process.env.SSH_HOST || '127.0.0.1',
port: parseInt(process.env.SSH_PORT || '2222'),
username: process.env.SSH_USER || 'adminbackend',
password: process.env.SSH_PASSWORD || '',
};
const ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
const COMMANDS = [
// ── CRITICAL SECURITY: Remove .env files from Next.js standalone build ────
`echo "=== SECURITY FIX: Remove .env from standalone ==="`,
`rm -f ${ROOT}/.next/standalone/.env.production && echo "REMOVED: .env.production from standalone"`,
`rm -f ${ROOT}/.next/standalone/.env.local && echo "REMOVED: .env.local from standalone (if existed)"`,
// Verify removal
`echo "=== VERIFY: No .env in standalone ===" && find ${ROOT}/.next/standalone -name ".env*" 2>/dev/null | head -5 || echo "CLEAN: No .env files in standalone"`,
// Also check if any secrets in the static JS bundles (client-side code)
`echo "=== VERIFY: No API key in client JS ===" && grep -r "sk_db_live" ${ROOT}/.next/static/ 2>/dev/null | head -3 || echo "CLEAN: No Netify API key in client-side JS"`,
`echo "=== VERIFY: No MongoDB creds in client JS ===" && grep -r "SusuKudaLiar" ${ROOT}/.next/static/ 2>/dev/null | head -3 || echo "CLEAN: No MongoDB password in client-side JS"`,
`echo "=== VERIFY: No JWT_SECRET in client JS ===" && grep -r "1a1716874d7576" ${ROOT}/.next/static/ 2>/dev/null | head -3 || echo "CLEAN: No JWT secret in client-side JS"`,
// ── Update the deploy script to prevent future accidental uploads ─────────
// Make .env.production NOT included in standalone (it shouldn't be anyway)
`echo "=== Checking if standalone has package.json with correct env ===" && cat ${ROOT}/.next/standalone/package.json 2>/dev/null | head -5`,
// ── Fix ecosystem.config.js to use correct cwd and path ──────────────────
// The PM2 frontend shows version 0.1.0 (old package.json from inside standalone)
// The cwd in ecosystem.config.js points to the root, which is correct
`echo "=== Current ecosystem.config.js ===" && cat ${ROOT}/ecosystem.config.js`,
// ── Restart PM2 frontend with updated ecosystem config ────────────────────
`echo "=== Restart frontend with updated config ===" && cd ${ROOT} && NODE_ENV=production ${PM2} restart backone-frontend --update-env && echo "Frontend restarted"`,
// Wait for stabilization
`sleep 5`,
// ── Full health check ─────────────────────────────────────────────────────
`echo "=== FINAL PM2 STATUS ===" && ${PM2} list`,
// Internal endpoint checks
`echo "=== BACKEND /api/health ===" && curl -s http://127.0.0.1:3001/api/health`,
`echo "=== FRONTEND / ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/`,
`echo "=== FRONTEND /login ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/login`,
// ── Test login API endpoint ────────────────────────────────────────────────
`echo ""`,
`echo "=== TEST LOGIN API ===" && curl -s -X POST http://127.0.0.1:3001/api/auth/login -H "Content-Type: application/json" -d '{"username":"admin","password":"admin"}' | head -c 200`,
// ── Show proxy MongoDB connection ─────────────────────────────────────────
`echo ""`,
`echo "=== PROXY MONGODB STATUS ===" && ${PM2} logs backone-proxy --lines 20 --nostream 2>&1 | grep -E "(MongoDB|Connected|Capacity|Scheduler|Started|Mode)" | tail -10`,
// ── Check if cPanel is configured to serve on port 8083 ──────────────────
`echo "=== CPANEL PORT CHECK ===" && ss -tlnp 2>/dev/null | grep -E "(8083|80|443|3000)" | head -10`,
// ── Check Apache/nginx proxy config ──────────────────────────────────────
`echo "=== CHECK PROXY CONFIG ===" && cat /home/adminbackend/.htaccess 2>/dev/null | head -20 || echo "No .htaccess at home"`,
`echo "=== CHECK WEB ROOT HTACCESS ===" && cat ${ROOT}/.htaccess 2>/dev/null | head -20 || echo "No .htaccess in web root"`,
// ── Summary ───────────────────────────────────────────────────────────────
`echo ""`,
`echo "╔══════════════════════════════════════════════════════╗"`,
`echo "║ BackOne DPI — Security & Health Verification ║"`,
`echo "╠══════════════════════════════════════════════════════╣"`,
`echo "║ ✅ Backend : http://127.0.0.1:3001 (internal) ║"`,
`echo "║ ✅ Proxy : http://127.0.0.1:4000 (internal) ║"`,
`echo "║ ✅ Frontend : http://127.0.0.1:3000 (internal) ║"`,
`echo "║ ✅ MongoDB : mongodb.prod.proit.id:27017 ║"`,
`echo "║ 🌐 Domain : https://demoplace.my.id ║"`,
`echo "╚══════════════════════════════════════════════════════╝"`,
];
function runSsh(commands) {
return new Promise((resolve, reject) => {
const ssh = new SshClient();
ssh.on('ready', () => {
console.log('[SSH] Connected!\n');
let i = 0;
function next() {
if (i >= commands.length) { ssh.end(); return; }
const cmd = commands[i++];
console.log(`\n$ ${cmd.substring(0, 130)}${cmd.length > 130 ? '...' : ''}`);
ssh.exec(cmd, (err, stream) => {
if (err) { console.error('[ERR]', err.message); next(); return; }
stream.on('data', d => process.stdout.write(d.toString()));
stream.stderr.on('data', d => { const t = d.toString(); if (!t.includes('npm warn') && !t.includes('notice')) process.stdout.write(t); });
stream.on('close', next);
});
}
next();
ssh.on('end', resolve);
});
ssh.on('error', reject);
ssh.connect({ ...CONFIG, readyTimeout: 30000 });
});
}
// Check HTTPS domain
function checkHttps(url) {
return new Promise(resolve => {
const req = https.get(url, { timeout: 10000, rejectUnauthorized: false }, res => {
let body = '';
res.on('data', d => body += d);
res.on('end', () => resolve({ status: res.statusCode, body: body.substring(0, 200), location: res.headers.location }));
});
req.on('error', e => resolve({ status: 0, error: e.message }));
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
});
}
async function main() {
console.log('\n╔══════════════════════════════════════════════════════════╗');
console.log('║ BackOne DPI — Security Fix & Final Verification ║');
console.log('╚══════════════════════════════════════════════════════════╝\n');
await runSsh(COMMANDS);
// Check HTTPS
console.log('\n▶ Testing HTTPS access...\n');
const urls = [
'https://demoplace.my.id/',
'https://demoplace.my.id/login',
'https://demoplace.my.id/api/health',
];
for (const url of urls) {
const r = await checkHttps(url);
const icon = r.status >= 200 && r.status < 400 ? '✅' : r.status === 0 ? '⚠️' : '❌';
console.log(` ${icon} ${url} → HTTP ${r.status} ${r.error || ''}`);
if (r.location) console.log(` Redirects to: ${r.location}`);
if (r.body && r.status === 200) console.log(` Body: ${r.body.substring(0, 80)}...`);
}
console.log('\n✅ Security fix & verification complete!\n');
}
main().catch(err => { console.error('[FATAL]', err); process.exit(1); });
-123
View File
@@ -1,123 +0,0 @@
// scripts/server-setup.js
// ─────────────────────────────────────────────────────────────────────────────
// BackOne DPI — Server Investigation & PM2 Setup Script
// Runs SSH commands to check server state and install PM2 locally
// ─────────────────────────────────────────────────────────────────────────────
'use strict';
const { Client: SshClient } = require('ssh2');
const CONFIG = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
};
const REMOTE_ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
// Commands to investigate server state, install PM2 locally, and start all services
const COMMANDS = [
// 1. Check Node.js version and PATH
'echo "=== NODE VERSION ===" && node --version 2>&1 || echo "node not in PATH"',
'echo "=== NPM VERSION ===" && npm --version 2>&1 || echo "npm not in PATH"',
'echo "=== CURRENT PATH ===" && echo $PATH',
'echo "=== HOME DIR ===" && echo $HOME',
// 2. Find any existing pm2 installation
'echo "=== FIND PM2 ===" && which pm2 2>/dev/null || find /home/adminbackend -name "pm2" -type f 2>/dev/null | head -5 || echo "pm2 not found"',
'echo "=== NPM GLOBAL LIST ===" && npm list -g --depth=0 2>&1 | head -20',
// 3. Check currently running Node.js processes
'echo "=== RUNNING NODE PROCESSES ===" && ps aux | grep node | grep -v grep || echo "No node processes running"',
// 4. Check if cPanel Node.js App is configured
'echo "=== CPANEL NODEAPP CONFIG ===" && ls /home/adminbackend/.cpanel/ 2>/dev/null || ls /home/adminbackend/nodevenv/ 2>/dev/null || echo "No cPanel node venv found"',
'echo "=== NODE VENV CHECK ===" && ls /home/adminbackend/nodevenv/ 2>/dev/null | head -10 || echo "No nodevenv"',
// 5. Install PM2 locally to user home prefix (no root needed)
'echo "=== INSTALLING PM2 LOCALLY ===" && npm install pm2 --prefix /home/adminbackend/.local 2>&1 | tail -5',
'echo "=== PM2 PATH ===" && /home/adminbackend/.local/bin/pm2 --version 2>&1 || echo "pm2 local install failed"',
// 6. Kill any existing BackOne processes to avoid port conflicts
`echo "=== KILLING EXISTING PROCESSES ===" && pkill -f "proxy/index.js" 2>/dev/null || true && pkill -f "backend/server.js" 2>/dev/null || true && pkill -f "standalone/server.js" 2>/dev/null || true && sleep 2 && echo "Done"`,
// 7. Start backend server
`echo "=== STARTING BACKEND ===" && cd ${REMOTE_ROOT} && NODE_ENV=production $(cat .env.production | grep -v '^#' | grep -v '^$' | xargs) node backend/server.js > logs/backend-out.log 2>logs/backend-error.log &`,
// 8. Start proxy server
`echo "=== STARTING PROXY ===" && cd ${REMOTE_ROOT} && NODE_ENV=production node proxy/index.js > logs/proxy-out.log 2>logs/proxy-error.log &`,
// 9. Start Next.js frontend
`echo "=== STARTING FRONTEND ===" && cd ${REMOTE_ROOT} && NODE_ENV=production PORT=3000 HOSTNAME=127.0.0.1 node .next/standalone/server.js > logs/frontend-out.log 2>logs/frontend-error.log &`,
// 10. Wait and verify
'sleep 6',
// 11. Check processes
'echo "=== RUNNING PROCESSES AFTER START ===" && ps aux | grep node | grep -v grep',
// 12. Test health endpoints
'echo "=== BACKEND HEALTH ===" && curl -s http://127.0.0.1:3001/api/health 2>&1 || echo "Backend not responding"',
'echo "=== FRONTEND HEALTH ===" && curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:3000/ 2>&1 || echo "Frontend not responding"',
// 13. Show recent logs
'echo "=== BACKEND LOG (last 10 lines) ===" && tail -10 /home/adminbackend/web/demoplace.my.id/public_html/logs/backend-out.log 2>/dev/null || echo "No backend log"',
'echo "=== PROXY LOG (last 5 lines) ===" && tail -5 /home/adminbackend/web/demoplace.my.id/public_html/logs/proxy-out.log 2>/dev/null || echo "No proxy log"',
];
function runSshCommands(commands) {
return new Promise((resolve, reject) => {
const ssh = new SshClient();
ssh.on('ready', () => {
console.log('[SSH] Connected to server!\n');
let index = 0;
function runNext() {
if (index >= commands.length) {
console.log('\n[SSH] All commands complete. Disconnecting...');
ssh.end();
return;
}
const cmd = commands[index++];
console.log(`\n$ ${cmd.substring(0, 100)}${cmd.length > 100 ? '...' : ''}`);
ssh.exec(cmd, (err, stream) => {
if (err) {
console.error(`[ERROR] ${err.message}`);
runNext();
return;
}
stream.on('data', (data) => process.stdout.write(data.toString()));
stream.stderr.on('data', (data) => process.stdout.write(`[ERR] ${data}`));
stream.on('close', () => runNext());
});
}
runNext();
ssh.on('end', resolve);
});
ssh.on('error', reject);
ssh.connect({ ...CONFIG, readyTimeout: 30000 });
});
}
async function main() {
console.log('\n╔══════════════════════════════════════════════════╗');
console.log('║ BackOne DPI — Server Setup & Process Manager ║');
console.log('╚══════════════════════════════════════════════════╝\n');
try {
await runSshCommands(COMMANDS);
console.log('\n✅ Server setup complete!\n');
} catch (err) {
console.error('\n[FATAL]', err.message);
process.exit(1);
}
}
main();
-133
View File
@@ -1,133 +0,0 @@
// scripts/start-frontend.js
// ─────────────────────────────────────────────────────────────────────────────
// BackOne DPI — Start Frontend & Fix PM2 Setup on Server
// ─────────────────────────────────────────────────────────────────────────────
'use strict';
const { Client: SshClient } = require('ssh2');
const CONFIG = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
};
const REMOTE_ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
const COMMANDS = [
// Check what's currently running on port 3000
'echo "=== PORT 3000 CHECK ===" && ss -tlnp 2>/dev/null | grep 3000 || netstat -tlnp 2>/dev/null | grep 3000 || echo "Port 3000 not in use"',
// Check if standalone server.js exists
`echo "=== STANDALONE CHECK ===" && ls -la ${REMOTE_ROOT}/.next/standalone/server.js 2>/dev/null || echo "standalone server.js NOT FOUND"`,
// List standalone directory structure
`echo "=== STANDALONE DIRECTORY ===" && ls ${REMOTE_ROOT}/.next/standalone/ 2>/dev/null | head -20`,
// Check static assets copied correctly
`echo "=== STATIC IN STANDALONE ===" && ls ${REMOTE_ROOT}/.next/standalone/.next/ 2>/dev/null || echo "No .next dir in standalone"`,
// Find the correct npm bin directory for npx pm2
'echo "=== NPM BIN DIR ===" && npm bin 2>/dev/null || npm config get prefix',
// Check npx pm2 path
'echo "=== NPX PM2 PATH ===" && find /home/adminbackend/.npm -name "pm2" -type f 2>/dev/null | grep "/bin/pm2" | head -3',
// Install PM2 using npm to user's npm prefix
'echo "=== SET NPM PREFIX ===" && npm config set prefix /home/adminbackend/.npm-global && npm install -g pm2 2>&1 | tail -5',
'echo "=== PM2 INSTALLED ===" && /home/adminbackend/.npm-global/bin/pm2 --version 2>&1 || echo "Still not found"',
// Try npx approach
`echo "=== USING NPX PM2 ===" && cd ${REMOTE_ROOT} && npx pm2 --version 2>&1`,
// Start frontend standalone server if not running
`echo "=== CHECKING STANDALONE SERVER ===" && ls -la ${REMOTE_ROOT}/.next/standalone/server.js`,
// Start with nohup (works on cPanel)
`echo "=== STARTING FRONTEND NOHUP ===" && cd ${REMOTE_ROOT} && NODE_ENV=production PORT=3000 HOSTNAME=0.0.0.0 NEXT_PUBLIC_API_URL=http://127.0.0.1:3001 nohup node .next/standalone/server.js >> logs/frontend-out.log 2>&1 & echo "PID: $!"`,
// Wait and check
'sleep 5',
// Verify port 3000 is now listening
'echo "=== PORT 3000 AFTER START ===" && ss -tlnp | grep 3000 || netstat -tlnp | grep 3000 || echo "Port 3000 still not in use"',
// Check all running processes
'echo "=== ALL NODE PROCESSES ===" && ps aux | grep node | grep -v grep',
// Test all endpoints
'echo "=== BACKEND HEALTH ===" && curl -s http://127.0.0.1:3001/api/health',
'echo "=== FRONTEND RESPONSE ===" && curl -s -o /dev/null -w "HTTP Status: %{http_code}" http://127.0.0.1:3000/ 2>&1',
// Show frontend log
`echo "=== FRONTEND LOG ===" && tail -20 ${REMOTE_ROOT}/logs/frontend-out.log 2>/dev/null || echo "No frontend log"`,
// Check proxy connection to MongoDB
`echo "=== PROXY LOG ===" && tail -10 ${REMOTE_ROOT}/logs/proxy-out.log 2>/dev/null || echo "No proxy log"`,
// Show existing pm2 in npx cache and start all services via npx pm2
`echo "=== STARTING WITH NPX PM2 ===" && cd ${REMOTE_ROOT} && NODE_ENV=production npx pm2 list 2>&1 | head -20`,
];
function runSshCommands(commands) {
return new Promise((resolve, reject) => {
const ssh = new SshClient();
const results = [];
ssh.on('ready', () => {
console.log('[SSH] Connected!\n');
let index = 0;
function runNext() {
if (index >= commands.length) {
ssh.end();
return;
}
const cmd = commands[index++];
const preview = cmd.length > 120 ? cmd.substring(0, 120) + '...' : cmd;
console.log(`\n$ ${preview}`);
ssh.exec(cmd, { env: { PATH: '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' } }, (err, stream) => {
if (err) {
console.error(`[ERROR] ${err.message}`);
runNext();
return;
}
stream.on('data', (data) => process.stdout.write(data.toString()));
stream.stderr.on('data', (data) => {
const text = data.toString();
if (!text.includes('npm warn') && !text.includes('npm notice')) {
process.stdout.write(`[ERR] ${text}`);
}
});
stream.on('close', () => runNext());
});
}
runNext();
ssh.on('end', () => resolve(results));
});
ssh.on('error', reject);
ssh.connect({ ...CONFIG, readyTimeout: 30000 });
});
}
async function main() {
console.log('\n╔══════════════════════════════════════════════════╗');
console.log('║ BackOne DPI — Frontend Startup & PM2 Fix ║');
console.log('╚══════════════════════════════════════════════════╝\n');
try {
await runSshCommands(COMMANDS);
console.log('\n✅ Frontend startup attempt complete!\n');
} catch (err) {
console.error('\n[FATAL]', err.message);
process.exit(1);
}
}
main();
-93
View File
@@ -1,93 +0,0 @@
const { spawnSync } = require('child_process');
const path = require('path');
const fs = require('fs');
const http = require('http');
function loginAndGetCookie() {
return new Promise((resolve) => {
const data = JSON.stringify({ username: 'admin', password: 'admin' });
const req = http.request({
hostname: '127.0.0.1',
port: 3000,
path: '/api/auth/login',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': data.length
}
}, (res) => {
let body = '';
res.on('data', chunk => body += chunk);
res.on('end', () => {
console.log("Login HTTP Status:", res.statusCode);
const setCookieHeader = res.headers['set-cookie'];
if (setCookieHeader && setCookieHeader.length > 0) {
const cookieVal = setCookieHeader[0].split(';')[0];
console.log("Authenticated Cookie:", cookieVal);
resolve(cookieVal);
} else {
console.log("No Set-Cookie header returned:", body);
resolve(null);
}
});
});
req.on('error', (err) => {
console.error("Login request error:", err.message);
resolve(null);
});
req.write(data);
req.end();
});
}
async function run() {
const cookieHeader = await loginAndGetCookie();
if (!cookieHeader) {
console.error("Failed to authenticate with admin/admin");
return;
}
// We can write a small local page or fetch the authenticated pages
// Or launch edge with cookie set via devtools protocol or curl
console.log("Fetching authenticated HTML for / ...");
const req = http.request({
hostname: '127.0.0.1',
port: 3000,
path: '/',
method: 'GET',
headers: {
'Cookie': cookieHeader
}
}, (res) => {
console.log("Dashboard GET Status:", res.statusCode);
});
req.end();
// Save cookie into edge user data folder or launch edge with custom session
const userDataDir = path.join(__dirname, 'edge_session_dir');
if (!fs.existsSync(userDataDir)) {
fs.mkdirSync(userDataDir, { recursive: true });
}
const edgePath = "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe";
const outputDir = "C:\\Users\\rafif\\.gemini\\antigravity-ide\\brain\\d6704840-c7e7-4558-b215-0fe98bbfb07a";
const outputFile = path.join(outputDir, "mobile-dashboard-overview.png");
// In order to inject cookie into headless Edge, we can pass --app with cookie or use curl/chrome-remote-interface
console.log("Executing Edge capture...");
const res = spawnSync(edgePath, [
'--headless',
'--disable-gpu',
`--user-data-dir=${userDataDir}`,
'--window-size=400,844',
`--screenshot=${outputFile}`,
'http://localhost:3000/'
], { encoding: 'utf-8', timeout: 15000 });
console.log("Done! Exit code:", res.status);
}
run();
-24
View File
@@ -1,24 +0,0 @@
const { spawnSync } = require('child_process');
const path = require('path');
const fs = require('fs');
const edgePath = "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe";
const outputDir = "C:\\Users\\rafif\\.gemini\\antigravity-ide\\brain\\d6704840-c7e7-4558-b215-0fe98bbfb07a";
const outputFile = path.join(outputDir, "mobile-localhost.png");
console.log("Launching Edge headless to capture screenshot of http://localhost:3000 ...");
const res = spawnSync(edgePath, [
'--headless',
'--disable-gpu',
'--window-size=400,844',
`--screenshot=${outputFile}`,
'http://localhost:3000'
], { encoding: 'utf-8', timeout: 15000 });
console.log("Exit code:", res.status);
if (fs.existsSync(outputFile)) {
console.log("Screenshot successfully saved to:", outputFile, "Size:", fs.statSync(outputFile).size, "bytes");
} else {
console.log("Screenshot file not found.");
}
-37
View File
@@ -1,37 +0,0 @@
const http = require('http');
function testUrl(url) {
return new Promise((resolve) => {
const start = Date.now();
console.log(`[TEST] Fetching ${url}...`);
const req = http.get(url, { timeout: 5000 }, (res) => {
let data = '';
res.on('data', (chunk) => { data += chunk; });
res.on('end', () => {
const duration = Date.now() - start;
console.log(`[TEST] ${url} -> Status: ${res.statusCode}, Time: ${duration}ms, Bytes: ${data.length}`);
resolve({ url, status: res.statusCode, duration, bytes: data.length });
});
});
req.on('error', (err) => {
const duration = Date.now() - start;
console.log(`[TEST] ${url} -> ERROR: ${err.message}, Time: ${duration}ms`);
resolve({ url, error: err.message, duration });
});
req.on('timeout', () => {
req.destroy();
const duration = Date.now() - start;
console.log(`[TEST] ${url} -> TIMEOUT after ${duration}ms`);
resolve({ url, timeout: true, duration });
});
});
}
async function run() {
console.log('=== STARTING DASHBOARD ROUTE SPEED TEST ===');
await testUrl('http://127.0.0.1:3001/api/dashboard/devices');
await testUrl('http://127.0.0.1:3001/api/dashboard/summary');
console.log('=== TEST COMPLETE ===');
}
run();
-28
View File
@@ -1,28 +0,0 @@
if (typeof globalThis.crypto === 'undefined') {
globalThis.crypto = require('crypto');
}
const mongoose = require('mongoose');
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '..', '.env.production') });
const MONGODB_URI = process.env.MONGODB_URI;
const { collectAllAgents } = require('../proxy/collector');
async function run() {
console.log('[Trigger] Connecting to MongoDB...');
await mongoose.connect(MONGODB_URI);
console.log('[Trigger] Connected. Starting collection cycle...');
try {
const res = await collectAllAgents();
console.log('[Trigger] Collection cycle finished successfully:', res);
} catch (err) {
console.error('[Trigger] Collection cycle failed:', err);
} finally {
await mongoose.connection.close();
console.log('[Trigger] MongoDB connection closed.');
}
}
run();
-132
View File
@@ -1,132 +0,0 @@
// scripts/update-pm2-config.js
// ─────────────────────────────────────────────────────────────────────────────
// BackOne DPI — Update PM2 to use correct standalone script path
// The frontend PM2 process is currently running the OLD server.js from root.
// We need to delete and re-create the PM2 process with the correct script.
// ─────────────────────────────────────────────────────────────────────────────
'use strict';
const { Client: SshClient } = require('ssh2');
const https = require('https');
const CONFIG = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
};
const ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
const COMMANDS = [
// Show current PM2 state
`echo "=== CURRENT PM2 STATE ===" && ${PM2} list`,
`echo "=== CURRENT FRONTEND SCRIPT ===" && ${PM2} show backone-frontend 2>&1 | grep -E "(script|cwd)" | head -5`,
// Delete old frontend process and start fresh with correct script
`echo "=== DELETING OLD FRONTEND PROCESS ===" && ${PM2} delete backone-frontend && echo "Deleted"`,
// Start frontend using the new ecosystem config (which points to .next/standalone/server.js)
`echo "=== STARTING FRONTEND WITH NEW CONFIG ===" && cd ${ROOT} && NODE_ENV=production ${PM2} start ecosystem.config.js --only backone-frontend && echo "Started"`,
// Wait for startup
`sleep 6`,
// Verify new process
`echo "=== NEW PM2 STATUS ===" && ${PM2} list`,
`echo "=== NEW FRONTEND SCRIPT ===" && ${PM2} show backone-frontend 2>&1 | grep -E "(script|cwd|version|status)" | head -8`,
// Test frontend response
`echo "=== FRONTEND INTERNAL TEST ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/`,
`echo "=== FRONTEND LOGIN TEST ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/login`,
// Save PM2 state
`echo "=== SAVING PM2 STATE ===" && ${PM2} save && echo "PM2 state saved"`,
// Show frontend log to confirm new code
`echo "=== FRONTEND LOG ===" && ${PM2} logs backone-frontend --lines 10 --nostream 2>&1 | tail -15`,
// Check HTTPS now
`echo "=== HTTPS VIA CURL ===" && curl -s -o /dev/null -w "HTTP %{http_code}" -L --max-redirs 3 https://demoplace.my.id/ 2>&1 || echo "HTTPS not accessible from server itself"`,
// Check HTTP (which should redirect to HTTPS per .htaccess)
`echo "=== HTTP CHECK ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://demoplace.my.id/ 2>&1`,
// Check Apache config for this domain
`echo "=== APACHE VHOST CONFIG ===" && cat /etc/apache2/conf.d/userdata/ssl/2_4/adminbackend/demoplace.my.id/*.conf 2>/dev/null | head -30 || ls /etc/apache2/conf.d/userdata/ 2>/dev/null | head -5 || echo "No Apache vhost config accessible"`,
// Check cPanel proxy config
`echo "=== CPANEL PROXY CONF ===" && cat /home/adminbackend/.cpanel/ea4/php.conf 2>/dev/null || echo "No cPanel PHP conf"`,
`cat /home/adminbackend/etc/apache_conf 2>/dev/null || echo "No Apache conf in home"`,
// Final summary
`echo ""`,
`echo "╔══════════════════════════════════════════════════════╗"`,
`echo "║ BackOne DPI — PM2 Update Complete ║"`,
`${PM2} list 2>/dev/null | grep -E "(online|error)" | awk '{print "║ " $2 " " $10 " " $6 " ║"}'`,
`echo "╚══════════════════════════════════════════════════════╝"`,
];
function runSsh(commands) {
return new Promise((resolve, reject) => {
const ssh = new SshClient();
ssh.on('ready', () => {
console.log('[SSH] Connected!\n');
let i = 0;
function next() {
if (i >= commands.length) { ssh.end(); return; }
const cmd = commands[i++];
console.log(`\n$ ${cmd.substring(0, 130)}${cmd.length > 130 ? '...' : ''}`);
ssh.exec(cmd, (err, stream) => {
if (err) { console.error('[ERR]', err.message); next(); return; }
stream.on('data', d => process.stdout.write(d.toString()));
stream.stderr.on('data', d => { const t = d.toString(); if (!t.includes('npm warn') && !t.includes('notice')) process.stdout.write(t); });
stream.on('close', next);
});
}
next();
ssh.on('end', resolve);
});
ssh.on('error', reject);
ssh.connect({ ...CONFIG, readyTimeout: 30000 });
});
}
async function checkHttps(url) {
return new Promise(resolve => {
const req = https.get(url, { timeout: 10000, rejectUnauthorized: false }, res => {
let body = '';
res.on('data', d => body += d);
res.on('end', () => resolve({ status: res.statusCode, location: res.headers.location, body: body.substring(0, 150) }));
});
req.on('error', e => resolve({ status: 0, error: e.message }));
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
});
}
async function main() {
console.log('\n╔══════════════════════════════════════════════════════════╗');
console.log('║ BackOne DPI — Fix PM2 Script & HTTPS Verification ║');
console.log('╚══════════════════════════════════════════════════════════╝\n');
await runSsh(COMMANDS);
console.log('\n\n▶ External HTTPS checks (from local machine)...\n');
const checks = [
'https://demoplace.my.id/',
'https://demoplace.my.id/login',
'https://demoplace.my.id/api/health',
];
for (const url of checks) {
const r = await checkHttps(url);
const icon = r.status >= 200 && r.status < 400 ? '✅' : r.status === 0 ? '⚠️' : '❌';
console.log(` ${icon} ${url} → HTTP ${r.status} ${r.error || ''}`);
if (r.location) console.log(` → Redirects to: ${r.location}`);
if (r.status === 200 && r.body) console.log(` Body preview: ${r.body.substring(0, 100)}`);
}
console.log('\n✅ Done!\n');
}
main().catch(err => { console.error('[FATAL]', err); process.exit(1); });
-94
View File
@@ -1,94 +0,0 @@
const SftpClient = require('ssh2-sftp-client');
const { Client } = require('ssh2');
const remoteAuditScript = `
const fs = require('fs');
const path = require('path');
const root = '/home/adminbackend/web/demoplace.my.id/public_html';
console.log('====================================================');
console.log(' FULL COMPONENT & PAGE AUDIT OF DEMOPLACE.MY.ID ');
console.log('====================================================');
// 1. Audit Client/Server Chunks for Page Headers & HelpTriggers
const chunksDir = path.join(root, '.next/standalone/.next/server/chunks');
if (fs.existsSync(chunksDir)) {
const files = fs.readdirSync(chunksDir);
files.forEach(f => {
if (!f.endsWith('.js')) return;
const content = fs.readFileSync(path.join(chunksDir, f), 'utf8');
// Look for page headers or title definitions
const headerMatch = content.match(/["']([A-Z][A-Za-z0-9\\s]{3,35})["'],\\s*description:/);
if (headerMatch) {
console.log(\`[Chunk \${f}] Found Header Definition: "\${headerMatch[1]}"\`);
}
if (content.includes('Learn This Page')) {
console.log(\`[Chunk \${f}] Contains "Learn This Page" button\`);
}
});
}
// 2. Audit Page Source files in src/app/(dashboard)
const appSrcDir = path.join(root, 'src/app/(dashboard)');
if (fs.existsSync(appSrcDir)) {
function scan(dir) {
const items = fs.readdirSync(dir, { withFileTypes: true });
for (const item of items) {
const full = path.join(dir, item.name);
if (item.isDirectory()) {
scan(full);
} else if (item.name === 'page.tsx' || item.name.endsWith('.tsx')) {
const content = fs.readFileSync(full, 'utf8');
const rel = path.relative(appSrcDir, full);
// Find H2 or H1
const h2 = content.match(/<h[12][^>]*>([\\s\\S]*?)<\\/h[12]>/i);
const titleText = h2 ? h2[1].replace(/<[^>]+>/g, '').trim().split('\\n')[0] : 'None';
const hasHelp = content.includes('HelpTrigger') || content.includes('Learn This Page');
console.log(\`Page File: \${rel}\`);
console.log(\` Header Title : \${titleText}\`);
console.log(\` Has HelpButton: \${hasHelp}\`);
console.log('----------------------------------------------------');
}
}
}
scan(appSrcDir);
}
`;
async function main() {
const sftp = new SftpClient();
await sftp.connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
const remoteScriptPath = '/home/adminbackend/audit_remote.js';
await sftp.put(Buffer.from(remoteAuditScript), remoteScriptPath);
await sftp.end();
const conn = new Client();
conn.on('ready', () => {
conn.exec(`node ${remoteScriptPath}`, (err, stream) => {
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log(out);
conn.end();
});
});
}).connect({
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
});
}
main();
-87
View File
@@ -1,87 +0,0 @@
// scripts/upload-profile-pictures.js
// Upload semua foto profil dari lokal ke server production
'use strict';
const SftpClient = require('ssh2-sftp-client');
const { Client: SshClient } = require('ssh2');
const fs = require('fs');
const path = require('path');
const CONFIG = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
readyTimeout: 30000,
retries: 3,
retry_factor: 2,
retry_minTimeout: 2000,
};
const LOCAL_DIR = path.join(__dirname, '..', 'backend', 'public', 'api', 'uploads');
const REMOTE_DIR = '/home/adminbackend/web/demoplace.my.id/public_html/api/uploads';
function sshExec(cmd) {
return new Promise((resolve, reject) => {
const conn = new SshClient();
conn.on('ready', () => {
conn.exec(cmd, (err, stream) => {
if (err) { conn.end(); return reject(err); }
let out = '';
stream
.on('data', d => { out += d; })
.stderr.on('data', d => { out += d; });
stream.on('close', () => { conn.end(); resolve(out); });
});
}).on('error', reject)
.connect({ host: CONFIG.host, port: CONFIG.port, username: CONFIG.username, password: CONFIG.password, readyTimeout: CONFIG.readyTimeout });
});
}
async function main() {
if (!fs.existsSync(LOCAL_DIR)) {
console.log('Folder uploads lokal tidak ditemukan:', LOCAL_DIR);
return;
}
const files = fs.readdirSync(LOCAL_DIR).filter(f => /\.(png|jpg|jpeg|webp)$/i.test(f));
if (files.length === 0) {
console.log('Tidak ada file gambar di folder uploads lokal.');
return;
}
console.log(`Ditemukan ${files.length} file foto profil untuk diupload:\n ${files.join('\n ')}\n`);
// Buat direktori di server jika belum ada
await sshExec(`mkdir -p ${REMOTE_DIR} && chmod 755 ${REMOTE_DIR}`);
console.log(`[Server] Direktori ${REMOTE_DIR} siap\n`);
// Upload semua file via SFTP
const sftp = new SftpClient();
await sftp.connect(CONFIG);
console.log('[SFTP] Terhubung ke server\n');
let uploaded = 0;
let failed = 0;
for (const file of files) {
const localPath = path.join(LOCAL_DIR, file);
const remotePath = `${REMOTE_DIR}/${file}`;
try {
await sftp.put(localPath, remotePath);
console.log(`✅ Upload: ${file}`);
uploaded++;
} catch (err) {
console.error(`❌ Gagal upload ${file}:`, err.message);
failed++;
}
}
await sftp.end();
// Verifikasi
const remoteList = await sshExec(`ls -lh ${REMOTE_DIR}`);
console.log('\n[Server] Isi folder uploads:\n' + remoteList);
console.log(`\n✅ Selesai! ${uploaded} berhasil, ${failed} gagal.`);
}
main().catch(e => console.error('[FATAL]', e.message));
-147
View File
@@ -1,147 +0,0 @@
// scripts/upload-standalone-next.js
// ─────────────────────────────────────────────────────────────────────────────
// BackOne DPI — Upload missing .next/standalone/.next/ directory to server
// This fixes: "Could not find a production build in the './.next' directory"
// ─────────────────────────────────────────────────────────────────────────────
'use strict';
const path = require('path');
const fs = require('fs');
const SftpClient = require('ssh2-sftp-client');
const { Client: SshClient } = require('ssh2');
const LOCAL_ROOT = path.resolve(__dirname, '..');
const REMOTE_ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
const CONFIG = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
};
// Recursively upload a local directory to remote (skipping node_modules and .git)
async function uploadDir(sftp, localPath, remotePath) {
const items = fs.readdirSync(localPath, { withFileTypes: true });
try { await sftp.mkdir(remotePath, true); } catch {}
for (const item of items) {
if (['node_modules', '.git'].includes(item.name)) continue;
if (item.name.endsWith('.log')) continue;
const lp = path.join(localPath, item.name);
const rp = remotePath + '/' + item.name;
if (item.isDirectory()) {
process.stdout.write(` [DIR] ${rp}\n`);
await uploadDir(sftp, lp, rp);
} else {
process.stdout.write(` [UP] ${rp} ...`);
await sftp.put(lp, rp);
process.stdout.write(' done\n');
}
}
}
function runSsh(commands) {
return new Promise((resolve, reject) => {
const ssh = new SshClient();
ssh.on('ready', () => {
let i = 0;
function next() {
if (i >= commands.length) { ssh.end(); return; }
const cmd = commands[i++];
console.log(`\n$ ${cmd.substring(0, 120)}${cmd.length > 120 ? '...' : ''}`);
ssh.exec(cmd, (err, stream) => {
if (err) { console.error('[ERR]', err.message); next(); return; }
stream.on('data', d => process.stdout.write(d.toString()));
stream.stderr.on('data', d => { const t = d.toString(); if (!t.includes('npm warn') && !t.includes('notice')) process.stdout.write(t); });
stream.on('close', next);
});
}
next();
ssh.on('end', resolve);
});
ssh.on('error', reject);
ssh.connect({ ...CONFIG, readyTimeout: 30000 });
});
}
async function main() {
console.log('\n╔══════════════════════════════════════════════════════════╗');
console.log('║ BackOne DPI — Upload Standalone Build Artifacts ║');
console.log('║ Uploading: .next/standalone/.next/ (BUILD_ID + server) ║');
console.log('╚══════════════════════════════════════════════════════════╝\n');
const localStandaloneNext = path.join(LOCAL_ROOT, '.next', 'standalone', '.next');
if (!fs.existsSync(localStandaloneNext)) {
console.error('✗ ERROR: .next/standalone/.next not found locally!');
console.error(' Run: npm run build');
process.exit(1);
}
// Verify BUILD_ID exists
const buildId = fs.existsSync(path.join(localStandaloneNext, 'BUILD_ID'))
? fs.readFileSync(path.join(localStandaloneNext, 'BUILD_ID'), 'utf8').trim()
: null;
console.log(`✓ Build ID: ${buildId || 'NOT FOUND'}`);
console.log(`✓ Local path: ${localStandaloneNext}`);
const sftp = new SftpClient();
try {
await sftp.connect(CONFIG);
console.log('[SFTP] Connected!\n');
const remotePath = `${REMOTE_ROOT}/.next/standalone/.next`;
console.log(`\n[DIR] Uploading .next/standalone/.next/ → ${remotePath}\n`);
await uploadDir(sftp, localStandaloneNext, remotePath);
console.log('\n[SFTP] Upload complete!\n');
} finally {
await sftp.end();
}
// Post-upload: restart PM2 frontend, verify
console.log('\n▶ Restarting PM2 frontend with new build...\n');
await runSsh([
// Verify BUILD_ID now exists on server
`echo "=== VERIFY BUILD_ID ===" && cat ${REMOTE_ROOT}/.next/standalone/.next/BUILD_ID`,
// Also verify static dir exists
`echo "=== VERIFY STATIC ===" && ls ${REMOTE_ROOT}/.next/standalone/.next/static/ 2>/dev/null | wc -l | xargs echo "Static files:"`,
// Restart frontend PM2 process
`echo "=== RESTARTING FRONTEND ===" && ${PM2} restart backone-frontend --update-env && echo "Restarted"`,
// Wait
`sleep 6`,
// Check PM2 status
`echo "=== PM2 STATUS ===" && ${PM2} list`,
// Test internal endpoints
`echo "=== FRONTEND / ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/`,
`echo "=== FRONTEND /login ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/login`,
`echo "=== BACKEND HEALTH ===" && curl -s http://127.0.0.1:3001/api/health`,
// Show frontend log
`echo "=== FRONTEND LOG ===" && ${PM2} logs backone-frontend --lines 10 --nostream 2>&1 | tail -15`,
// Test via domain (HTTP which redirects to HTTPS via .htaccess)
`echo "=== DOMAIN HTTP TEST ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://demoplace.my.id/`,
// Check port 3000
`echo "=== PORT 3000 ===" && ss -tlnp | grep 3000`,
]);
console.log('\n══════════════════════════════════════════════════════════');
console.log(' ✅ Standalone build artifacts uploaded & frontend restarted!');
console.log(' 🌐 Dashboard: https://demoplace.my.id');
console.log('══════════════════════════════════════════════════════════\n');
}
main().catch(err => {
console.error('\n[FATAL]', err.message);
process.exit(1);
});
-148
View File
@@ -1,148 +0,0 @@
// scripts/verify-deployment.js
// ─────────────────────────────────────────────────────────────────────────────
// BackOne DPI — Post-Deployment Verification Script
// Tests: frontend, backend, security headers, proxy, MongoDB
// ─────────────────────────────────────────────────────────────────────────────
'use strict';
const { Client: SshClient } = require('ssh2');
const https = require('https');
const http = require('http');
const CONFIG = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
};
const PM2 = '/home/adminbackend/.npm-global/bin/pm2';
const ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
// HTTP request helper
function httpGet(url) {
return new Promise((resolve) => {
const mod = url.startsWith('https') ? https : http;
const req = mod.get(url, { timeout: 10000 }, (res) => {
let body = '';
res.on('data', (d) => body += d);
res.on('end', () => resolve({ status: res.statusCode, headers: res.headers, body: body.substring(0, 300) }));
});
req.on('error', (e) => resolve({ status: 0, error: e.message }));
req.on('timeout', () => { req.destroy(); resolve({ status: 0, error: 'timeout' }); });
});
}
const SSH_COMMANDS = [
// Check PM2 process list
`echo "=== PM2 STATUS ===" && ${PM2} list`,
// Check backend health
`echo "=== BACKEND HEALTH ===" && curl -s http://127.0.0.1:3001/api/health`,
// Check frontend pages
`echo "=== FRONTEND / ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/`,
`echo "=== FRONTEND /login ===" && curl -s -o /dev/null -w "HTTP %{http_code}" http://127.0.0.1:3000/login`,
// Security audit: ensure backend and proxy ports are NOT publicly accessible
`echo "=== SECURITY: Port 3001 external test ===" && ss -tlnp | grep 3001`,
`echo "=== SECURITY: Port 4000 external test ===" && ss -tlnp | grep 4000`,
// Check upload directory permissions
`echo "=== UPLOAD DIR PERMS ===" && ls -la ${ROOT}/backend/public/api/uploads/ 2>/dev/null || echo "Upload dir does not exist yet (will be created on first upload)"`,
// Check proxy MongoDB connection
`echo "=== PROXY STATUS ===" && ${PM2} logs backone-proxy --lines 5 --nostream 2>&1 | grep -E "(MongoDB|Connected|Capacity|Scheduler)" | tail -10`,
// Verify no secrets in Next.js build output (sanity check)
`echo "=== SECURITY AUDIT: Check no API key in build ===" && grep -r "sk_db_live" ${ROOT}/.next/standalone/ 2>/dev/null | head -3 || echo "CLEAN: No Netify API key found in build output"`,
`echo "=== SECURITY AUDIT: Check no MongoDB URI in build ===" && grep -r "backone_user" ${ROOT}/.next/standalone/ 2>/dev/null | head -3 || echo "CLEAN: No MongoDB credentials in build output"`,
// Check frontend log for readiness
`echo "=== FRONTEND READY LOG ===" && ${PM2} logs backone-frontend --lines 5 --nostream 2>&1 | grep -E "(Ready|Error|Next.js)" | tail -10`,
// Check disk usage for uploads dir
`echo "=== DISK USAGE ===" && df -h /home/adminbackend/web/ 2>/dev/null | tail -2`,
// Final summary
`echo ""`,
`echo "╔════════════════════════════════════════════╗"`,
`echo "║ BackOne DPI Production — Service Status ║"`,
`echo "╠════════════════════════════════════════════╣"`,
`${PM2} list 2>/dev/null | grep -E "(online|error|stopped)" | awk '{printf "║ %-12s %-10s %-8s ║\\n", $2, $10, $8}'`,
`echo "╚════════════════════════════════════════════╝"`,
];
function runSshChecks(commands) {
return new Promise((resolve, reject) => {
const ssh = new SshClient();
ssh.on('ready', () => {
console.log('[SSH] Connected for verification!\n');
let index = 0;
function runNext() {
if (index >= commands.length) {
ssh.end();
return;
}
const cmd = commands[index++];
console.log(`\n$ ${cmd.substring(0, 120)}${cmd.length > 120 ? '...' : ''}`);
ssh.exec(cmd, (err, stream) => {
if (err) { console.error(`[ERROR] ${err.message}`); runNext(); return; }
stream.on('data', (d) => process.stdout.write(d.toString()));
stream.stderr.on('data', (d) => {
const t = d.toString();
if (!t.includes('npm warn') && !t.includes('npm notice')) process.stdout.write(t);
});
stream.on('close', runNext);
});
}
runNext();
ssh.on('end', resolve);
});
ssh.on('error', reject);
ssh.connect({ ...CONFIG, readyTimeout: 30000 });
});
}
async function main() {
console.log('\n╔══════════════════════════════════════════════════════════╗');
console.log('║ BackOne DPI — Post-Deployment Verification ║');
console.log('╚══════════════════════════════════════════════════════════╝\n');
// ── SSH internal checks ───────────────────────────────────────────────────
console.log('▶ Running internal server checks via SSH...');
await runSshChecks(SSH_COMMANDS);
// ── External HTTP checks (from this machine) ──────────────────────────────
console.log('\n\n▶ Running external HTTP checks from local machine...\n');
const checks = [
{ url: 'http://demoplace.my.id/', label: 'Domain root (redirect expected)' },
{ url: 'http://demoplace.my.id/login', label: 'Login page' },
{ url: 'http://demoplace.my.id/api/health', label: 'Backend health via domain' },
];
for (const { url, label } of checks) {
const result = await httpGet(url);
const status = result.status;
const icon = (status >= 200 && status < 400) ? '✅' : (status === 0 ? '⚠️' : '❌');
console.log(` ${icon} ${label}: HTTP ${status} ${result.error || ''}`);
if (result.body && status >= 200 && status < 300) {
console.log(` Body preview: ${result.body.substring(0, 100)}`);
}
}
console.log('\n══════════════════════════════════════════════════════════');
console.log(' Production deployment verification complete!');
console.log(' URL: https://demoplace.my.id');
console.log('══════════════════════════════════════════════════════════\n');
}
main().catch((err) => {
console.error('[FATAL]', err.message);
process.exit(1);
});
@@ -1,85 +0,0 @@
"use client";
import React from "react";
import { Activity, ChevronDown } from "lucide-react";
import { cn } from "@/lib/utils";
interface SidebarSiteSwitcherProps {
user: { role?: string; site_uuid?: string | null } | null;
selectedSite: string;
isSiteDropdownOpen: boolean;
setIsSiteDropdownOpen: (open: boolean) => void;
siteDropdownRef: React.RefObject<HTMLDivElement | null>;
handleSiteSelect: (val: string) => void;
getSiteLabel: (uuid: string) => string;
}
export function SidebarSiteSwitcher({
user,
selectedSite,
isSiteDropdownOpen,
setIsSiteDropdownOpen,
siteDropdownRef,
handleSiteSelect,
getSiteLabel,
}: SidebarSiteSwitcherProps) {
const isGlobalUser = user?.role === 'SUPER_ADMIN' ||
user?.role === 'EXECUTIVE' ||
((!user?.site_uuid || user?.site_uuid === 'default') && ['SOC_ANALYST', 'ENGINEER'].includes(user?.role || ''));
if (!user || !isGlobalUser) {
return null;
}
return (
<div className="relative w-full px-2" ref={siteDropdownRef}>
<button
onClick={() => setIsSiteDropdownOpen(!isSiteDropdownOpen)}
className="flex w-full items-center justify-between gap-2 rounded-xl border border-white/5 bg-white/[0.02] hover:bg-white/[0.05] p-2.5 text-xs text-slate-300 transition-colors"
>
<div className="flex items-center gap-2 truncate">
<Activity className="h-3.5 w-3.5 text-primary shrink-0" />
<div className="flex flex-col items-start truncate leading-normal">
<span className="font-semibold text-[10px] text-primary uppercase tracking-wider">Active Site</span>
<span className="truncate max-w-[130px]">{getSiteLabel(selectedSite)}</span>
</div>
</div>
<ChevronDown className={cn("h-3.5 w-3.5 text-muted-foreground transition-transform duration-300", isSiteDropdownOpen && "rotate-180")} />
</button>
<div
className={cn(
"absolute top-full left-2 right-2 mt-1 rounded-xl border border-white/10 bg-slate-950 p-1.5 shadow-2xl z-50 origin-top transition-all duration-300 ease-out",
isSiteDropdownOpen
? "opacity-100 scale-100 pointer-events-auto translate-y-0"
: "opacity-0 scale-95 pointer-events-none -translate-y-2"
)}
>
<div className="flex flex-col gap-0.5">
<button
onClick={() => handleSiteSelect('6681452d_9cae_4ff4_8ae8_0d504774265e')}
className={cn(
"w-full rounded-lg px-2.5 py-1.5 text-left text-xs transition-colors",
selectedSite === '6681452d_9cae_4ff4_8ae8_0d504774265e'
? "bg-primary/20 text-white font-medium"
: "text-slate-400 hover:bg-white/5 hover:text-white"
)}
>
SIAB
</button>
<button
onClick={() => handleSiteSelect('d7902405_0dc2_458b_8584_ed4d24b64f24')}
className={cn(
"w-full rounded-lg px-2.5 py-1.5 text-left text-xs transition-colors",
selectedSite === 'd7902405_0dc2_458b_8584_ed4d24b64f24'
? "bg-primary/20 text-white font-medium"
: "text-slate-400 hover:bg-white/5 hover:text-white"
)}
>
Nexus
</button>
</div>
</div>
</div>
);
}
@@ -1,77 +0,0 @@
"use client";
import React from "react";
import { Calendar, ChevronDown } from "lucide-react";
import { cn } from "@/lib/utils";
interface TimeOption {
readonly value: "5m" | "30m" | "1h" | "1d" | "7d";
readonly label: string;
}
interface SidebarTimeFilterProps {
timeRange: string;
setTimeRange: (range: any) => void;
isTimeDropdownOpen: boolean;
setIsTimeDropdownOpen: (open: boolean) => void;
timeDropdownRef: React.RefObject<HTMLDivElement | null>;
selectedTimeOption: TimeOption;
timeOptions: readonly TimeOption[];
}
export function SidebarTimeFilter({
timeRange,
setTimeRange,
isTimeDropdownOpen,
setIsTimeDropdownOpen,
timeDropdownRef,
selectedTimeOption,
timeOptions,
}: SidebarTimeFilterProps) {
return (
<div className="relative w-full px-2 pb-2" ref={timeDropdownRef}>
<button
onClick={() => setIsTimeDropdownOpen(!isTimeDropdownOpen)}
className="flex w-full items-center justify-between gap-2 rounded-xl border border-white/5 bg-white/[0.02] hover:bg-white/[0.05] p-2.5 text-xs text-slate-300 transition-colors"
>
<div className="flex items-center gap-2 truncate">
<Calendar className="h-3.5 w-3.5 text-primary shrink-0" />
<div className="flex flex-col items-start truncate leading-normal">
<span className="font-semibold text-[10px] text-primary uppercase tracking-wider">Time Filter</span>
<span className="truncate max-w-[130px]">{selectedTimeOption.label}</span>
</div>
</div>
<ChevronDown className={cn("h-3.5 w-3.5 text-muted-foreground transition-transform duration-300", isTimeDropdownOpen && "rotate-180")} />
</button>
<div
className={cn(
"absolute top-full left-2 right-2 mt-1 rounded-xl border border-white/10 bg-slate-950 p-1.5 shadow-2xl z-50 origin-top transition-all duration-300 ease-out",
isTimeDropdownOpen
? "opacity-100 scale-100 pointer-events-auto translate-y-0"
: "opacity-0 scale-95 pointer-events-none -translate-y-2"
)}
>
<div className="flex flex-col gap-0.5 max-h-60 overflow-y-auto custom-scrollbar">
{timeOptions.map((opt) => (
<button
key={opt.value}
onClick={() => {
setTimeRange(opt.value);
setIsTimeDropdownOpen(false);
}}
className={cn(
"w-full rounded-lg px-2.5 py-1.5 text-left text-xs transition-colors",
timeRange === opt.value
? "bg-primary/20 text-white font-medium"
: "text-slate-400 hover:bg-white/5 hover:text-white"
)}
>
{opt.label}
</button>
))}
</div>
</div>
</div>
);
}
-175
View File
@@ -1,175 +0,0 @@
// test/agent_geolocation_test.js
const mongoose = require('../backend/node_modules/mongoose');
const path = require('path');
// Load environment variables
require('dotenv').config({ path: path.join(__dirname, '../.env.local') });
const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017/backone_dpi';
const { CustomAgentLocation, DeviceStat, Flow } = require('../backend/models/Schemas');
let testCount = 0;
let passedCount = 0;
function assert(label, condition) {
testCount++;
if (condition) {
console.log(` ✓ PASSED: ${label}`);
passedCount++;
} else {
console.error(` ✗ FAILED: ${label}`);
}
}
async function runTests() {
console.log('\n=========================================');
console.log(' RUNNING TDD TESTS FOR GEOLOCATION & FLOWS');
console.log('=========================================\n');
try {
// 1. Connect to DB
await mongoose.connect(MONGODB_URI);
console.log('✓ Connected to MongoDB');
// 2. Validate Geolocation Seeding
const count = await CustomAgentLocation.countDocuments();
assert('CustomAgentLocation collection should have seeded documents', count >= 3);
const balarajaLoc = await CustomAgentLocation.findOne({ agent_uuid: 'F6-2V-DT-8A' });
assert('CPI Balaraja Agent location should exist', !!balarajaLoc);
if (balarajaLoc) {
assert('CPI Balaraja latitude matches', balarajaLoc.latitude === -6.2263304);
assert('CPI Balaraja longitude matches', balarajaLoc.longitude === 106.4247322);
assert('CPI Balaraja belongs to SIAB site', balarajaLoc.site_uuid === '6681452d_9cae_4ff4_8ae8_0d504774265e');
}
const cibuburLoc = await CustomAgentLocation.findOne({ agent_uuid: '2F-TF-1D-GK' });
assert('JRP Cibubur Agent location should exist', !!cibuburLoc);
if (cibuburLoc) {
assert('JRP Cibubur latitude matches', cibuburLoc.latitude === -6.3763318);
assert('JRP Cibubur longitude matches', cibuburLoc.longitude === 106.8983017);
}
const ifgLoc = await CustomAgentLocation.findOne({ agent_uuid: '8A-V3-PB-85' });
assert('IFG LT.18 Agent location should exist', !!ifgLoc);
if (ifgLoc) {
assert('IFG LT.18 latitude matches', ifgLoc.latitude === -6.2253265);
assert('IFG LT.18 longitude matches', ifgLoc.longitude === 106.8061484);
}
// 3. Test Location Updates (Simulation of POST API)
const testUuid = 'TEST-AGENT-UUID';
const testSite = 'test-site-uuid';
// Remove if exists
await CustomAgentLocation.deleteOne({ agent_uuid: testUuid });
const updated = await CustomAgentLocation.findOneAndUpdate(
{ agent_uuid: testUuid },
{
agent_uuid: testUuid,
site_uuid: testSite,
latitude: -6.1234,
longitude: 106.1234,
label: 'Test Location Label'
},
{ new: true, upsert: true }
);
assert('Location upsert should return the saved document', !!updated);
assert('Upserted latitude matches', updated.latitude === -6.1234);
assert('Upserted longitude matches', updated.longitude === 106.1234);
assert('Upserted label matches', updated.label === 'Test Location Label');
// 4. Test Location Reset (Simulation of DELETE API)
const delRes = await CustomAgentLocation.deleteOne({ agent_uuid: testUuid });
assert('Location delete should succeed', delRes.deletedCount > 0);
const checkedDel = await CustomAgentLocation.findOne({ agent_uuid: testUuid });
assert('Location should no longer exist after delete', !checkedDel);
// 5. Test Inter-Agent Flow Aggregation Logic
// Let's seed a mock device belonging to Cibubur agent and a flow from Balaraja to Cibubur's device IP.
const mockDestIp = '192.168.99.123';
// Cleanup if existing
await DeviceStat.deleteOne({ ip_address: mockDestIp });
await Flow.deleteMany({ dst_ip: mockDestIp });
// Seed mock device monitored by Cibubur agent (2F-TF-1D-GK)
await DeviceStat.create({
timestamp: new Date(),
ip_address: mockDestIp,
agent_uuid: '2F-TF-1D-GK',
site_uuid: '6681452d_9cae_4ff4_8ae8_0d504774265e',
mac_address: '00:11:22:33:44:55',
});
// Seed mock flow from Balaraja agent (F6-2V-DT-8A) to mockDestIp
await Flow.create({
timestamp: new Date(),
agent_uuid: 'F6-2V-DT-8A',
site_uuid: '6681452d_9cae_4ff4_8ae8_0d504774265e',
src_ip: '192.168.10.50',
dst_ip: mockDestIp,
download: 15000000,
upload: 5000000,
});
// Run the aggregation logic
const devices = await DeviceStat.find({ site_uuid: '6681452d_9cae_4ff4_8ae8_0d504774265e' }).select('ip_address agent_uuid').lean();
const deviceIpToAgent = {};
for (const dev of devices) {
if (dev.ip_address && dev.agent_uuid) {
deviceIpToAgent[dev.ip_address] = dev.agent_uuid;
}
}
const flows = await Flow.find({ site_uuid: '6681452d_9cae_4ff4_8ae8_0d504774265e' }).select('agent_uuid src_ip dst_ip download upload').lean();
const flowMap = {};
for (const flow of flows) {
const srcAgent = flow.agent_uuid;
const dstAgent = deviceIpToAgent[flow.dst_ip];
if (srcAgent && dstAgent && srcAgent !== dstAgent) {
const key = `${srcAgent}->${dstAgent}`;
if (!flowMap[key]) {
flowMap[key] = {
source: srcAgent,
target: dstAgent,
bytes: 0,
flowsCount: 0
};
}
flowMap[key].bytes += ((flow.download || 0) + (flow.upload || 0));
flowMap[key].flowsCount += 1;
}
}
const result = Object.values(flowMap);
assert('Inter-agent flows aggregation should detect flows', result.length > 0);
const detectedFlow = result.find(f => f.source === 'F6-2V-DT-8A' && f.target === '2F-TF-1D-GK');
assert('Mock flow from Balaraja to Cibubur should be detected', !!detectedFlow);
if (detectedFlow) {
assert('Mock flow bytes matches (15MB down + 5MB up = 20MB)', detectedFlow.bytes >= 20000000);
assert('Mock flow connection count is correct', detectedFlow.flowsCount >= 1);
}
// Cleanup mock telemetry
await DeviceStat.deleteOne({ ip_address: mockDestIp });
await Flow.deleteMany({ dst_ip: mockDestIp });
console.log('\n=========================================');
console.log(` RESULT: ${passedCount} / ${testCount} tests passed.`);
console.log('=========================================\n');
await mongoose.disconnect();
} catch (err) {
console.error('TDD Test run error:', err);
process.exit(1);
}
}
runTests();
-101
View File
@@ -1,101 +0,0 @@
// test/analyze_inter_agent_flows.js — diagnostic script
// Checks if there are real inter-agent flows in MongoDB
const mongoose = require('../backend/node_modules/mongoose');
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '../.env.local') });
const MONGODB_URI = process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017/backone_dpi';
const { DeviceStat, Flow } = require('../backend/models/Schemas');
const { CustomAgentLocation } = require('../backend/models/SchemasAux');
async function run() {
await mongoose.connect(MONGODB_URI);
console.log('\n✓ Connected to MongoDB\n');
const SIAB_SITE = '6681452d_9cae_4ff4_8ae8_0d504774265e';
// 1. List registered agent coordinates
const locations = await CustomAgentLocation.find({ site_uuid: SIAB_SITE }).lean();
const agentUuids = locations.map(l => l.agent_uuid);
console.log(`=== Agent Locations Registered (${locations.length}) ===`);
for (const loc of locations) {
console.log(` • ${loc.agent_uuid} → ${loc.label || '(no label)'} [${loc.latitude}, ${loc.longitude}]`);
}
// 2. Build IP → agent_uuid map from DeviceStat
const devices = await DeviceStat.find({ site_uuid: SIAB_SITE }).select('ip_address agent_uuid').lean();
const ipToAgent = {};
for (const d of devices) {
if (d.ip_address && d.agent_uuid) ipToAgent[d.ip_address] = d.agent_uuid;
}
console.log(`\n=== DeviceStat Records (total ${devices.length}) ===`);
const agentDeviceCount = {};
for (const [ip, agent] of Object.entries(ipToAgent)) {
agentDeviceCount[agent] = (agentDeviceCount[agent] || 0) + 1;
}
for (const [agent, count] of Object.entries(agentDeviceCount)) {
console.log(` • Agent ${agent}: ${count} unique IP(s) tracked`);
}
// 3. Sample flows to see dst_ip patterns
const since24h = new Date(Date.now() - 24 * 60 * 60 * 1000);
const flowCount = await Flow.countDocuments({ site_uuid: SIAB_SITE, timestamp: { $gte: since24h } });
const flows = await Flow.find({ site_uuid: SIAB_SITE, timestamp: { $gte: since24h } })
.select('agent_uuid src_ip dst_ip download upload app_label')
.limit(200)
.lean();
console.log(`\n=== Flows in Last 24h: ${flowCount} total (inspecting up to 200) ===`);
const interAgentFlowMap = {};
let matchCount = 0;
for (const flow of flows) {
const srcAgent = flow.agent_uuid;
const dstAgent = ipToAgent[flow.dst_ip];
if (srcAgent && dstAgent && srcAgent !== dstAgent) {
matchCount++;
const key = `${srcAgent} → ${dstAgent}`;
if (!interAgentFlowMap[key]) {
interAgentFlowMap[key] = { bytes: 0, count: 0, examples: [] };
}
interAgentFlowMap[key].bytes += (flow.download || 0) + (flow.upload || 0);
interAgentFlowMap[key].count++;
if (interAgentFlowMap[key].examples.length < 2) {
interAgentFlowMap[key].examples.push({ src: flow.src_ip, dst: flow.dst_ip, app: flow.app_label });
}
}
}
console.log(`\n=== Inter-Agent Flows Detected: ${matchCount} (from ${flows.length} sampled) ===`);
if (Object.keys(interAgentFlowMap).length > 0) {
for (const [pair, data] of Object.entries(interAgentFlowMap)) {
const mb = (data.bytes / 1024 / 1024).toFixed(2);
console.log(` ✓ ${pair} — ${data.count} flows, ${mb} MB`);
for (const ex of data.examples) {
console.log(` Example: ${ex.src} → ${ex.dst} (${ex.app || 'Unclassified'})`);
}
}
} else {
console.log(' ✗ No inter-agent flows detected in sampled data.');
console.log('\n — Checking sample of dst_ip values that appear in flows...');
const dstIps = [...new Set(flows.map(f => f.dst_ip).filter(Boolean))].slice(0, 10);
console.log(' dst_ip samples:', dstIps);
const matched = dstIps.filter(ip => ipToAgent[ip]);
console.log(' dst_ip matched to agents:', matched.map(ip => `${ip} → ${ipToAgent[ip]}`));
}
// 4. Check if any flows have dst_ip in the devicestats table at all
const allDstIps = [...new Set(flows.map(f => f.dst_ip).filter(Boolean))];
let trackedCount = 0;
for (const ip of allDstIps) {
if (ipToAgent[ip]) trackedCount++;
}
console.log(`\n=== dst_ip Resolution: ${trackedCount} / ${allDstIps.length} unique dst IPs found in DeviceStat ===`);
await mongoose.disconnect();
console.log('\n✓ Done.\n');
}
run().catch(err => { console.error(err); process.exit(1); });
-15
View File
@@ -1,15 +0,0 @@
const mongoose = require('mongoose');
const { LookupApp } = require('../backend/models/Schemas');
async function main() {
const uri = 'mongodb://127.0.0.1:27017/backone_dpi';
await mongoose.connect(uri);
console.log('Connected to:', mongoose.connection.name);
const count = await LookupApp.countDocuments({});
console.log('LookupApp model count in backend schema:', count);
await mongoose.disconnect();
}
main().catch(console.error);
-19
View File
@@ -1,19 +0,0 @@
const proxyMongoose = require('../proxy/node_modules/mongoose');
require('dotenv').config({ path: './.env.local' });
async function main() {
const uri = process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017/backone_dpi';
await proxyMongoose.connect(uri);
console.log('--- CONNECTION DETAILS ---');
console.log('Host:', proxyMongoose.connection.host);
console.log('Port:', proxyMongoose.connection.port);
console.log('DB Name:', proxyMongoose.connection.name);
console.log('URI used:', uri);
const collections = await proxyMongoose.connection.db.listCollections().toArray();
console.log('Collections list:', collections.map(c => c.name));
await proxyMongoose.disconnect();
}
main().catch(console.error);
-33
View File
@@ -1,33 +0,0 @@
module.paths.unshift('c:\\Users\\demo\\Downloads\\Deep Package Inspection\\node_modules');
const { Client } = require('ssh2');
const SSH = { host: '103.185.47.52', port: 2222, username: 'adminbackend', password: 'htEo7x6LsBQiEHHH', readyTimeout: 60000 };
async function main() {
const conn = new Client();
await new Promise((resolve, reject) => {
conn.on('ready', resolve).on('error', reject).connect(SSH);
});
console.log('SSH connected.');
const runCmd = (cmd) => {
return new Promise((resolve) => {
conn.exec(cmd, (err, stream) => {
if (err) { resolve(`Err: ${err.message}`); return; }
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => resolve(out.trim()));
});
});
};
const lsFonts = await runCmd('ls -la /home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/public/fonts || echo "No fonts folder"');
console.log('=== STANDALONE FONTS DIR ===\n', lsFonts);
const lsPublicFonts = await runCmd('ls -la /home/adminbackend/web/demoplace.my.id/public_html/public/fonts || echo "No public fonts folder"');
console.log('=== SOURCE PUBLIC FONTS DIR ===\n', lsPublicFonts);
conn.end();
}
main().catch(console.error);
-22
View File
@@ -1,22 +0,0 @@
// test/check-ip-mongo.js
const { MongoClient } = require('mongodb');
const URI = process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017/backone_dpi';
async function main() {
console.log('Connecting to MongoDB via IP 103.80.237.29...');
const client = new MongoClient(URI, { serverSelectionTimeoutMS: 5000 });
try {
await client.connect();
console.log('✓ Successfully connected to MongoDB via IP!');
const db = client.db('backone_dpi');
const cols = await db.listCollections().toArray();
console.log('Collections:', cols.map(c => c.name));
} catch (err) {
console.error('✗ Connection failed:', err.message);
} finally {
await client.close();
}
}
main();
-20
View File
@@ -1,20 +0,0 @@
require('dotenv').config({ path: './.env.local' });
const mongoose = require('mongoose');
const { LookupApp } = require('../proxy/models/Schemas');
async function main() {
const uri = process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017/backone_dpi';
console.log('Using URI from env:', uri);
await mongoose.connect(uri);
console.log('Connected to:', mongoose.connection.name, 'on host:', mongoose.connection.host);
const count = await LookupApp.countDocuments({});
console.log('LookupApp model count:', count);
const rawCount = await mongoose.connection.db.collection('lookupapps').countDocuments({});
console.log('Raw collection count:', rawCount);
await mongoose.disconnect();
}
main().catch(console.error);
-11
View File
@@ -1,11 +0,0 @@
// test/check-logo-size.js
const axios = require('axios');
async function main() {
const url = 'https://demoplace.my.id/nexus-logo.png';
const res = await axios.head(url);
console.log('Remote nexus-logo.png content-length:', res.headers['content-length']);
console.log('Remote nexus-logo.png content-type:', res.headers['content-type']);
}
main().catch(err => console.error(err.message));
-22
View File
@@ -1,22 +0,0 @@
const { Client } = require('ssh2');
const SSH = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
readyTimeout: 60000
};
const conn = new Client();
conn.on('ready', () => {
conn.exec("/home/adminbackend/.npm-global/bin/pm2 show backone-frontend", (err, stream) => {
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log('--- PM2 SHOW FRONTEND ---');
console.log(out);
conn.end();
});
});
}).connect(SSH);
-22
View File
@@ -1,22 +0,0 @@
const { Client } = require('ssh2');
const SSH = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
readyTimeout: 60000
};
const conn = new Client();
conn.on('ready', () => {
conn.exec("/home/adminbackend/.npm-global/bin/pm2 status; ps -ef | grep node", (err, stream) => {
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log('--- PM2 & PROCESSES ---');
console.log(out);
conn.end();
});
});
}).connect(SSH);
-23
View File
@@ -1,23 +0,0 @@
const { Client } = require('ssh2');
const SSH = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
readyTimeout: 60000
};
const conn = new Client();
conn.on('ready', () => {
console.log('Querying remote Nginx config and PM2 details...');
conn.exec("cat /etc/nginx/conf.d/*.conf /etc/nginx/sites-enabled/* /etc/nginx/nginx.conf 2>/dev/null | grep -i -A 10 -B 2 'demoplace.my.id'; /home/adminbackend/.npm-global/bin/pm2 env 2", (err, stream) => {
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log('--- REMOTE NGINX & PM2 ENV ---');
console.log(out);
conn.end();
});
});
}).connect(SSH);
-23
View File
@@ -1,23 +0,0 @@
const { Client } = require('ssh2');
const SSH = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
readyTimeout: 60000
};
const conn = new Client();
conn.on('ready', () => {
console.log('Checking PM2 status and errors...');
conn.exec("/home/adminbackend/.npm-global/bin/pm2 list; tail -n 50 /home/adminbackend/web/demoplace.my.id/public_html/logs/frontend-error.log", (err, stream) => {
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log('--- PM2 STATUS & FRONTEND ERRORS ---');
console.log(out);
conn.end();
});
});
}).connect(SSH);
-33
View File
@@ -1,33 +0,0 @@
module.paths.unshift('c:\\Users\\demo\\Downloads\\Deep Package Inspection\\node_modules');
const { Client } = require('ssh2');
const SSH = { host: '103.185.47.52', port: 2222, username: 'adminbackend', password: 'htEo7x6LsBQiEHHH', readyTimeout: 60000 };
async function main() {
const conn = new Client();
await new Promise((resolve, reject) => {
conn.on('ready', resolve).on('error', reject).connect(SSH);
});
console.log('SSH connected.');
const runCmd = (cmd) => {
return new Promise((resolve) => {
conn.exec(cmd, (err, stream) => {
if (err) { resolve(`Err: ${err.message}`); return; }
let out = '';
stream.on('data', d => out += d);
stream.stderr.on('data', d => out += `[stderr] ${d}`);
stream.on('close', () => resolve(out.trim()));
});
});
};
const remoteNodeCmd = `const mongoose = require('/home/adminbackend/web/demoplace.my.id/public_html/proxy/node_modules/mongoose'); mongoose.connect('mongodb://127.0.0.1:27017/backone_dpi').then(() => mongoose.connection.db.collection('lookupapps').countDocuments()).then(c => { console.log('COUNT:', c); process.exit(0); }).catch(e => { console.error(e); process.exit(1); })`;
const countRes = await runCmd(`node -e ${JSON.stringify(remoteNodeCmd)}`);
console.log('=== REMOTE LOOKUP COUNT ===\n', countRes);
conn.end();
}
main().catch(console.error);
-27
View File
@@ -1,27 +0,0 @@
const { Client } = require('ssh2');
const SSH = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
readyTimeout: 60000
};
const conn = new Client();
conn.on('ready', () => {
conn.exec('cat /home/adminbackend/web/demoplace.my.id/public_html/proxy/.env /home/adminbackend/web/demoplace.my.id/public_html/backend/.env /home/adminbackend/web/demoplace.my.id/public_html/.env.production', (err, stream) => {
if (err) {
console.error(err);
conn.end();
return;
}
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log('--- REMOTE ENVS ---');
console.log(out);
conn.end();
});
});
}).on('error', console.error).connect(SSH);
-22
View File
@@ -1,22 +0,0 @@
const { Client } = require('ssh2');
const SSH = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
readyTimeout: 60000
};
const conn = new Client();
conn.on('ready', () => {
conn.exec("find /home/adminbackend/web/demoplace.my.id/public_html/.next/standalone -path '*agents*' -ls", (err, stream) => {
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log('--- REMOTE NEXT AGENTS FILES ---');
console.log(out);
conn.end();
});
});
}).connect(SSH);
-22
View File
@@ -1,22 +0,0 @@
const { Client } = require('ssh2');
const SSH = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
readyTimeout: 60000
};
const conn = new Client();
conn.on('ready', () => {
conn.exec("ls -ld /home/adminbackend/web/demoplace.my.id/public_html/.next; ls -l /home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/server.js", (err, stream) => {
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log('--- REMOTE NEXT DATE ---');
console.log(out);
conn.end();
});
});
}).connect(SSH);
-33
View File
@@ -1,33 +0,0 @@
module.paths.unshift('c:\\Users\\demo\\Downloads\\Deep Package Inspection\\node_modules');
const { Client } = require('ssh2');
const SSH = { host: '103.185.47.52', port: 2222, username: 'adminbackend', password: 'htEo7x6LsBQiEHHH', readyTimeout: 60000 };
async function main() {
const conn = new Client();
await new Promise((resolve, reject) => {
conn.on('ready', resolve).on('error', reject).connect(SSH);
});
console.log('SSH connected.');
const runCmd = (cmd) => {
return new Promise((resolve) => {
conn.exec(cmd, (err, stream) => {
if (err) { resolve(`Err: ${err.message}`); return; }
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => resolve(out.trim()));
});
});
};
const lsStandalone = await runCmd('ls -la /home/adminbackend/web/demoplace.my.id/public_html/.next/standalone');
console.log('=== STANDALONE DIR ===\n', lsStandalone);
const lsStandalonePublic = await runCmd('ls -la /home/adminbackend/web/demoplace.my.id/public_html/.next/standalone/public || echo "No public folder in standalone"');
console.log('=== STANDALONE PUBLIC DIR ===\n', lsStandalonePublic);
conn.end();
}
main().catch(console.error);
-30
View File
@@ -1,30 +0,0 @@
// test/check_local_db.js
const { MongoClient } = require('mongodb');
const LOCAL_URI = 'mongodb://127.0.0.1:27017';
const DB_NAME = 'backone_dpi';
async function main() {
const client = new MongoClient(LOCAL_URI, { serverSelectionTimeoutMS: 2000 });
try {
await client.connect();
console.log("✓ Connected to local MongoDB successfully!");
const db = client.db(DB_NAME);
const collections = await db.listCollections().toArray();
console.log("Collections in local database:", collections.map(c => c.name));
if (collections.some(c => c.name === 'users')) {
const users = await db.collection('users').find({}).toArray();
console.log(`Users in local database (${users.length}):`);
users.forEach(u => console.log(`- Username: ${u.username}, Role: ${u.role}, Email: ${u.email || 'N/A'}`));
} else {
console.log("No 'users' collection locally.");
}
} catch (err) {
console.error("✗ Local MongoDB connection failed:", err.message);
} finally {
await client.close();
}
}
main();
-27
View File
@@ -1,27 +0,0 @@
// test/check_pm2_restarts.js
const { Client } = require('ssh2');
const sshConfig = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
};
async function main() {
const conn = new Client();
conn.on('ready', () => {
conn.exec('. ~/.nvm/nvm.sh && nvm use 20 && npx pm2 list', (err, stream) => {
if (err) throw err;
let out = '';
stream.on('close', () => {
conn.end();
console.log(out);
}).on('data', (data) => {
out += data;
});
});
}).connect(sshConfig);
}
main();
-30
View File
@@ -1,30 +0,0 @@
// test/check_prod_after_migration.js
const { MongoClient } = require('mongodb');
const REMOTE_URI = process.env.MONGODB_URI || 'mongodb://127.0.0.1:27017/backone_dpi';
const DB_NAME = 'backone_dpi';
async function main() {
const client = new MongoClient(REMOTE_URI, { serverSelectionTimeoutMS: 5000 });
try {
await client.connect();
console.log("✓ Connected to production MongoDB successfully!");
const db = client.db(DB_NAME);
const collections = await db.listCollections().toArray();
console.log("Collections in production database:", collections.map(c => c.name));
const users = await db.collection('users').find({}).toArray();
console.log(`Users in production MongoDB (${users.length}):`);
users.forEach(u => console.log(`- Username: ${u.username}, Role: ${u.role}, Site UUID: ${u.site_uuid || 'N/A'}`));
const configCount = await db.collection('tenantconfigs').countDocuments();
const locCount = await db.collection('customagentlocations').countDocuments();
console.log(`\nConfig entries: ${configCount}, Custom location entries: ${locCount}`);
} catch (err) {
console.error("✗ Production MongoDB connection failed:", err.message);
} finally {
await client.close();
}
}
main();
-90
View File
@@ -1,90 +0,0 @@
// test/check_remote_env.js
// Fix 502: Write Nginx custom config to proxy directly to Next.js port 3000
'use strict';
const { Client } = require('ssh2');
const sshConfig = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
readyTimeout: 60000
};
function runSSHCommand(conn, cmd) {
return new Promise((resolve, reject) => {
conn.exec(cmd, (err, stream) => {
if (err) return reject(err);
let out = '';
stream.on('close', () => resolve(out))
.on('data', d => { out += d; process.stdout.write(d.toString()); })
.stderr.on('data', d => { out += d; process.stdout.write(d.toString()); });
});
});
}
async function main() {
const conn = new Client();
await new Promise((resolve, reject) => {
conn.on('ready', resolve).on('error', reject).connect(sshConfig);
});
console.log('[SSH] Connected!\n');
const CONF = '/home/adminbackend/conf/web/demoplace.my.id';
// The Nginx config includes nginx.conf_custom and nginx.ssl.conf_custom
// We override the location / block to proxy directly to Next.js port 3000
const httpCustom = [
'# BackOne DPI — Direct proxy to Next.js',
'location / {',
' proxy_pass http://127.0.0.1:3000;',
' proxy_http_version 1.1;',
' proxy_set_header Upgrade $http_upgrade;',
' proxy_set_header Connection "upgrade";',
' proxy_set_header Host $host;',
' proxy_set_header X-Real-IP $remote_addr;',
' proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;',
' proxy_set_header X-Forwarded-Proto $scheme;',
' proxy_read_timeout 86400;',
'}',
].join('\n');
const sslCustom = [
'# BackOne DPI — Direct SSL proxy to Next.js',
'location / {',
' proxy_pass http://127.0.0.1:3000;',
' proxy_http_version 1.1;',
' proxy_set_header Upgrade $http_upgrade;',
' proxy_set_header Connection "upgrade";',
' proxy_set_header Host $host;',
' proxy_set_header X-Real-IP $remote_addr;',
' proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;',
' proxy_set_header X-Forwarded-Proto https;',
' proxy_read_timeout 86400;',
'}',
].join('\n');
const commands = [
// Write HTTP custom config
`printf '%s\n' ${JSON.stringify(httpCustom)} > ${CONF}/nginx.conf_custom && echo "[OK] HTTP custom config written"`,
// Write SSL custom config
`printf '%s\n' ${JSON.stringify(sslCustom)} > ${CONF}/nginx.ssl.conf_custom && echo "[OK] SSL custom config written"`,
// Verify files
`echo "=== HTTP CUSTOM ===" && cat ${CONF}/nginx.conf_custom`,
`echo "=== SSL CUSTOM ===" && cat ${CONF}/nginx.ssl.conf_custom`,
// Reload Nginx via Hestia
`echo "=== RELOADING ===" && sudo /usr/local/hestia/bin/v-restart-web 2>&1 | tail -5 || nginx -s reload 2>&1 | tail -5 || echo "Reload attempt done"`,
// Test after reload
`sleep 6 && echo "=== DOMAIN TEST ===" && curl -sk -o /dev/null -w "HTTPS Status: %{http_code}" https://demoplace.my.id/login`,
];
for (const cmd of commands) {
console.log(`\n$ ${cmd.substring(0, 100)}${cmd.length > 100 ? '...' : ''}`);
await runSSHCommand(conn, cmd);
}
conn.end();
console.log('\n\n✅ Selesai! Cek https://demoplace.my.id/login di browser.\n');
}
main().catch(err => { console.error('[FATAL]', err.message); process.exit(1); });
-23
View File
@@ -1,23 +0,0 @@
const { Client } = require('ssh2');
const SSH = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
readyTimeout: 60000
};
const conn = new Client();
conn.on('ready', () => {
console.log('Cleaning up backslash files/folders on remote server...');
conn.exec("find /home/adminbackend/web/demoplace.my.id/public_html -name '*\\\\*' -depth -exec rm -rf {} \\; -print", (err, stream) => {
let out = '';
stream.on('data', d => out += d);
stream.on('close', () => {
console.log('--- CLEANED UP REMOTE FILES ---');
console.log(out);
conn.end();
});
});
}).connect(SSH);
-32
View File
@@ -1,32 +0,0 @@
const mongoose = require('../backend/node_modules/mongoose');
const dotenv = require('../backend/node_modules/dotenv');
const path = require('path');
// Load environment variables from .env.local
dotenv.config({ path: path.join(__dirname, '../.env.local') });
const mongoUri = process.env.MONGO_URI || 'mongodb://127.0.0.1:27017/backone_dpi';
async function main() {
try {
console.log(`Connecting to: ${mongoUri}`);
await mongoose.connect(mongoUri);
console.log('Connected! Deleting all demo user accounts (all except admin, siab, and nexus)...');
const db = mongoose.connection.db;
const usernamesToKeep = ['admin', 'siab', 'nexus'];
const res = await db.collection('users').deleteMany({
username: { $nin: usernamesToKeep }
});
console.log(`Deleted ${res.deletedCount} demo users.`);
await mongoose.disconnect();
console.log('Done!');
} catch (err) {
console.error('Error deleting users:', err);
process.exit(1);
}
}
main();
-32
View File
@@ -1,32 +0,0 @@
const mongoose = require('../backend/node_modules/mongoose');
const dotenv = require('../backend/node_modules/dotenv');
const path = require('path');
// Load environment variables from .env.local
dotenv.config({ path: path.join(__dirname, '../.env.local') });
const mongoUri = process.env.MONGO_URI || 'mongodb://127.0.0.1:27017/backone_dpi';
async function main() {
try {
console.log(`Connecting to: ${mongoUri}`);
await mongoose.connect(mongoUri);
console.log('Connected! Deleting superadmin external accounts...');
const db = mongoose.connection.db;
const usernamesToDelete = ['super_analyst', 'super_engineer', 'sulist', 'suner'];
const res = await db.collection('users').deleteMany({
username: { $in: usernamesToDelete }
});
console.log(`Deleted ${res.deletedCount} users:`, usernamesToDelete);
await mongoose.disconnect();
console.log('Done!');
} catch (err) {
console.error('Error deleting users:', err);
process.exit(1);
}
}
main();
-30
View File
@@ -1,30 +0,0 @@
module.paths.unshift('c:\\Users\\demo\\Downloads\\Deep Package Inspection\\node_modules');
const { Client } = require('ssh2');
const fs = require('fs');
const SSH = { host: '103.185.47.52', port: 2222, username: 'adminbackend', password: 'htEo7x6LsBQiEHHH', readyTimeout: 60000 };
const REMOTE_PATH = '/home/adminbackend/web/demoplace.my.id/public_html/.env.production';
const LOCAL_PATH = 'c:\\Users\\demo\\Downloads\\Deep Package Inspection\\.env.production';
async function main() {
const conn = new Client();
await new Promise((resolve, reject) => {
conn.on('ready', resolve).on('error', reject).connect(SSH);
});
console.log('SSH connected. Downloading .env.production...');
await new Promise((resolve, reject) => {
conn.sftp((err, sftp) => {
if (err) return reject(err);
sftp.fastGet(REMOTE_PATH, LOCAL_PATH, {}, (err2) => {
if (err2) return reject(err2);
resolve();
});
});
});
console.log('Downloaded successfully to:', LOCAL_PATH);
conn.end();
}
main().catch(console.error);
-83
View File
@@ -1,83 +0,0 @@
const { Client } = require('ssh2');
const path = require('path');
const fs = require('fs');
const SSH = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH',
readyTimeout: 60000
};
const REMOTE_ROOT = '/home/adminbackend/web/demoplace.my.id/public_html';
const LOCAL_ROOT = path.join(__dirname, '..');
const filesToDownload = [
'src/app/(dashboard)/agents/page.tsx',
'src/app/(dashboard)/apps/page.tsx',
'src/app/(dashboard)/devices/page.tsx',
'src/app/(dashboard)/dns/page.tsx',
'src/app/(dashboard)/dpi-analytics/page.tsx',
'src/app/(dashboard)/events/page.tsx',
'src/app/(dashboard)/flows/page.tsx',
'src/app/(dashboard)/geography/page.tsx',
'src/app/(dashboard)/intelligence/page.tsx',
'src/app/(dashboard)/lookup/page.tsx',
'src/app/(dashboard)/network-infrastructure/page.tsx',
'src/app/(dashboard)/network-intelligence/page.tsx',
'src/app/(dashboard)/page.tsx',
'src/app/(dashboard)/security-audit/page.tsx',
'src/app/(dashboard)/threats/page.tsx',
'src/components/admin/ExternalAccountModal.tsx',
'src/components/layout/Sidebar.tsx',
'src/components/layout/SidebarData.ts',
'src/components/ui/SafeImage.tsx',
'src/lib/actions/agents.ts',
'src/lib/admin-api.ts',
'package.json'
];
const conn = new Client();
conn.on('ready', () => {
console.log('✓ SSH Connection ready for SFTP...');
conn.sftp((err, sftp) => {
if (err) {
console.error('SFTP Error:', err.message);
conn.end();
return;
}
let downloadedCount = 0;
let failedCount = 0;
filesToDownload.forEach((relPath) => {
const remotePath = `${REMOTE_ROOT}/${relPath}`;
const localPath = path.join(LOCAL_ROOT, relPath);
// Ensure target directory exists
const localDir = path.dirname(localPath);
if (!fs.existsSync(localDir)) {
fs.mkdirSync(localDir, { recursive: true });
}
console.log(`Downloading: ${relPath} ...`);
sftp.fastGet(remotePath, localPath, (sftpErr) => {
if (sftpErr) {
console.error(`✗ Failed to download ${relPath}:`, sftpErr.message);
failedCount++;
} else {
console.log(`✓ Downloaded ${relPath}`);
downloadedCount++;
}
if (downloadedCount + failedCount === filesToDownload.length) {
console.log(`\n=========================================`);
console.log(` DOWNLOAD COMPLETED: ${downloadedCount} Succeeded, ${failedCount} Failed.`);
console.log(`=========================================\n`);
conn.end();
}
});
});
});
}).on('error', console.error).connect(SSH);
-78
View File
@@ -1,78 +0,0 @@
const { Client } = require('ssh2');
const fs = require('fs');
const path = require('path');
const SSH_CONFIG = {
host: '103.185.47.52',
port: 2222,
username: 'adminbackend',
password: 'htEo7x6LsBQiEHHH'
};
const remoteDir = '/home/adminbackend/web/demoplace.my.id/public_html/api/uploads';
const localDir = path.join(__dirname, '../public/api/uploads');
// Ensure local directory exists
if (!fs.existsSync(localDir)) {
fs.mkdirSync(localDir, { recursive: true });
}
console.log('Connecting to SSH...');
const conn = new Client();
conn.on('ready', () => {
console.log('SSH Connection ready. Starting SFTP...');
conn.sftp(async (err, sftp) => {
if (err) {
console.error('SFTP Error:', err.message);
conn.end();
return;
}
console.log('Listing remote uploads directory:', remoteDir);
sftp.readdir(remoteDir, async (err, list) => {
if (err) {
console.error('Readdir Error:', err.message);
conn.end();
return;
}
const files = list.filter(item => item.attrs.isFile());
console.log(`Found ${files.length} upload files on remote server.`);
if (files.length === 0) {
conn.end();
return;
}
// Download files sequentially using a helper function
async function downloadFile(index) {
if (index >= files.length) {
console.log('\n=========================================');
console.log(' ALL UPLOADS DOWNLOAD COMPLETED.');
console.log('=========================================');
conn.end();
return;
}
const name = files[index].filename;
const remoteFile = path.posix.join(remoteDir, name);
const localFile = path.join(localDir, name);
console.log(`[${index + 1}/${files.length}] Downloading: ${name} ...`);
sftp.fastGet(remoteFile, localFile, {}, (err) => {
if (err) {
console.error(`Failed to download ${name}:`, err.message);
} else {
console.log(`✓ Completed ${name}`);
}
// Proceed to next file
setTimeout(() => downloadFile(index + 1), 50);
});
}
// Start the sequential download
await downloadFile(0);
});
});
}).connect(SSH_CONFIG);
Loaded 100 of 189 files, more files were not shown because too many files have changed in this diff. Show more