-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.js
135 lines (115 loc) · 4.66 KB
/
server.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
const express = require('express');
const { exec } = require('child_process');
const fs = require('fs');
const helmet = require('helmet');
const os = require('os');
const path = require('path');
const validator = require('validator');
const app = express();
const port = process.env.PORT || 3000;
// Use Helmet to set security-related HTTP headers
if (process.env.SECURITY === 'enabled') {
app.use(helmet());
}
// Predefined presets mapping to specific categories of websites
const presets = {
'social media': ['Facebook', 'Twitter', 'Instagram', 'LinkedIn', 'Reddit', 'YouTube', 'TikTok'],
'nsfw': [
"APClips",
"AdmireMe.Vip",
"All Things Worn",
"BongaCams",
"ChaturBate",
"Erome",
"Heavy-R",
"Image Fap"
],
'blog sites': ['WordPress', 'Blogger', 'Medium', 'Tumblr']
};
// Serve static files from the 'public' directory
app.use(express.static('public'));
// Parse incoming JSON requests
app.use(express.json());
// Handle search requests from the front end
app.post('/search', (req, res) => {
const { username, nsfw, printAll, csv, preset } = req.body;
// Input validation for username
if (!username || typeof username !== 'string' || !/^[a-zA-Z0-9_-]+$/.test(username)) {
return res.status(400).json({ error: 'Invalid username. Only letters, numbers, underscores, and hyphens are allowed.' });
}
// Sanitize the username to prevent shell injection
let command = `sherlock ${validator.escape(username)}`;
// Add options for NSFW or printing all results
if (nsfw) command += ' --nsfw';
if (printAll) command += ' --print-all';
// Add preset sites if a valid preset is selected
if (preset && typeof preset === 'string' && presets[preset]) {
const sites = presets[preset];
sites.forEach(site => {
command += ` --site "${validator.escape(site)}"`; // Escape site names to avoid shell injection
});
}
let csvFilename = null;
// If CSV download is requested, generate a temporary CSV filename
if (csv) {
csvFilename = path.join(os.tmpdir(), `sherlock_${username}_${Date.now()}.csv`);
command += ` --csv --output "${csvFilename}"`;
}
// Execute the Sherlock command using child process
exec(command, { shell: '/bin/bash' }, (error, stdout, stderr) => {
if (error) {
// If there is an error, send a 500 response with the error message
return res.status(500).json({ error: stderr });
} else {
// Parse Sherlock's output to extract site names and URLs
const lines = stdout.split('\n');
const results = [];
lines.forEach(line => {
if (line.startsWith('[+]')) {
const content = line.substring(4).trim();
const colonIndex = content.indexOf(':');
if (colonIndex > -1) {
const siteName = content.substring(0, colonIndex).trim();
const url = content.substring(colonIndex + 1).trim();
results.push({ siteName, url });
}
}
});
// If CSV is requested, read the generated CSV file and return it along with the results
if (csv && csvFilename) {
fs.readFile(csvFilename, 'utf8', (err, csvData) => {
if (err) {
return res.status(500).json({ error: 'Failed to read CSV file' });
} else {
// Return the results and CSV data
res.json({ results, csv: csvData });
// Delete the temporary CSV file after sending the response
fs.unlink(csvFilename, (err) => {
if (err) console.error('Failed to delete CSV file:', err);
});
}
});
} else {
// If no CSV is requested, just return the results
res.json({ results });
}
}
});
});
// Serve the Terms of Service page
app.get('/terms', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'terms.html'));
});
// Serve the Privacy Policy page
app.get('/privacy', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'privacy.html'));
});
// Global error handling middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).json({ error: 'Internal Server Error' });
});
// Start the server and listen on the specified port
app.listen(port, () => {
console.log(`Sherlock Web UI running at http://localhost:${port}`);
});