Spaces:
Sleeping
Sleeping
| // server.js - Node.js Backend with Express and Tesseract OCR | |
| const express = require('express'); | |
| const multer = require('multer'); | |
| const Tesseract = require('tesseract.js'); | |
| const path = require('path'); | |
| const fs = require('fs'); | |
| const app = express(); | |
| const PORT = process.env.PORT || 7860; | |
| // Multer configuration for file uploads | |
| const upload = multer({ | |
| dest: 'uploads/', | |
| limits: { fileSize: 10 * 1024 * 1024 } // 10MB limit | |
| }); | |
| // Middleware | |
| app.use(express.json()); | |
| app.use(express.urlencoded({ extended: true })); | |
| app.use(express.static('public')); | |
| // Database configuration | |
| const DB_FILE = './database.json'; | |
| const ADMIN_PASSWORD = 'BTXHZ'; | |
| const ADMIN_TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhZG1pbiI6dHJ1ZX0.dummytoken'; | |
| // Initialize database file if doesn't exist | |
| if (!fs.existsSync(DB_FILE)) { | |
| fs.writeFileSync(DB_FILE, JSON.stringify([])); | |
| console.log('π Database file created'); | |
| } | |
| // Initialize uploads folder if doesn't exist | |
| if (!fs.existsSync('uploads')) { | |
| fs.mkdirSync('uploads'); | |
| console.log('π Uploads folder created'); | |
| } | |
| // Database helper functions | |
| const getDB = () => { | |
| try { | |
| const data = fs.readFileSync(DB_FILE, 'utf8'); | |
| return JSON.parse(data); | |
| } catch (error) { | |
| console.error('Error reading database:', error); | |
| return []; | |
| } | |
| }; | |
| const saveDB = (data) => { | |
| try { | |
| fs.writeFileSync(DB_FILE, JSON.stringify(data, null, 2)); | |
| return true; | |
| } catch (error) { | |
| console.error('Error saving database:', error); | |
| return false; | |
| } | |
| }; | |
| // Authentication middleware | |
| const authMiddleware = (req, res, next) => { | |
| const authHeader = req.headers.authorization; | |
| if (!authHeader || !authHeader.startsWith('Bearer ')) { | |
| return res.status(401).json({ | |
| success: false, | |
| error: 'Unauthorized - No token provided' | |
| }); | |
| } | |
| const token = authHeader.replace('Bearer ', ''); | |
| if (token !== ADMIN_TOKEN) { | |
| return res.status(401).json({ | |
| success: false, | |
| error: 'Unauthorized - Invalid token' | |
| }); | |
| } | |
| next(); | |
| }; | |
| // ============================================ | |
| // HTML ROUTES | |
| // ============================================ | |
| // Root route - redirect to home | |
| app.get('/', (req, res) => { | |
| res.redirect('/home'); | |
| }); | |
| // Home page | |
| app.get('/home', (req, res) => { | |
| res.sendFile(path.join(__dirname, 'public', 'home.html')); | |
| }); | |
| // Admin create page | |
| app.get('/home/admin/create', (req, res) => { | |
| res.sendFile(path.join(__dirname, 'public', 'admin.html')); | |
| }); | |
| // Verification page | |
| app.get('/home/url/:name/:id', (req, res) => { | |
| res.sendFile(path.join(__dirname, 'public', 'verify.html')); | |
| }); | |
| // ============================================ | |
| // API ROUTES | |
| // ============================================ | |
| // Login endpoint | |
| app.post('/api/login', (req, res) => { | |
| const { password } = req.body; | |
| if (!password) { | |
| return res.status(400).json({ | |
| success: false, | |
| error: 'Password is required' | |
| }); | |
| } | |
| if (password === ADMIN_PASSWORD) { | |
| res.json({ | |
| success: true, | |
| token: ADMIN_TOKEN, | |
| message: 'Login successful' | |
| }); | |
| } else { | |
| res.status(401).json({ | |
| success: false, | |
| error: 'Invalid password' | |
| }); | |
| } | |
| }); | |
| // Create short link endpoint (protected) | |
| app.post('/api/create', authMiddleware, (req, res) => { | |
| const { title, redirect, name, verify } = req.body; | |
| // Validation | |
| if (!title || !redirect || !name) { | |
| return res.status(400).json({ | |
| success: false, | |
| error: 'Title, redirect, and name are required' | |
| }); | |
| } | |
| // Check if name already exists | |
| const db = getDB(); | |
| const existingLink = db.find(link => link.name === name); | |
| if (existingLink) { | |
| return res.status(400).json({ | |
| success: false, | |
| error: 'Short name already exists' | |
| }); | |
| } | |
| // Create new link | |
| const id = Date.now().toString(); | |
| const newLink = { | |
| id, | |
| title, | |
| redirect, | |
| name, | |
| verify: verify === true, | |
| createdAt: new Date().toISOString() | |
| }; | |
| db.push(newLink); | |
| if (saveDB(db)) { | |
| console.log(`β New link created: ${name} (ID: ${id})`); | |
| res.json({ | |
| success: true, | |
| link: newLink, | |
| message: 'Short link created successfully' | |
| }); | |
| } else { | |
| res.status(500).json({ | |
| success: false, | |
| error: 'Failed to save link' | |
| }); | |
| } | |
| }); | |
| // Get all links endpoint | |
| app.get('/api/links', (req, res) => { | |
| const db = getDB(); | |
| res.json(db); | |
| }); | |
| // Get specific link endpoint | |
| app.get('/api/link/:name/:id', (req, res) => { | |
| const { name, id } = req.params; | |
| const db = getDB(); | |
| const link = db.find(l => l.name === name && l.id === id); | |
| if (link) { | |
| res.json(link); | |
| } else { | |
| res.status(404).json({ | |
| error: 'Link not found', | |
| message: 'The requested short link does not exist' | |
| }); | |
| } | |
| }); | |
| // OCR Verification endpoint | |
| app.post('/api/verify', upload.single('image'), async (req, res) => { | |
| if (!req.file) { | |
| return res.status(400).json({ | |
| success: false, | |
| error: 'No image file uploaded' | |
| }); | |
| } | |
| const filePath = req.file.path; | |
| console.log(`π Processing OCR for file: ${req.file.originalname}`); | |
| try { | |
| // Perform OCR using Tesseract | |
| const { data: { text } } = await Tesseract.recognize( | |
| filePath, | |
| 'eng', | |
| { | |
| logger: info => { | |
| if (info.status === 'recognizing text') { | |
| console.log(`OCR Progress: ${Math.round(info.progress * 100)}%`); | |
| } | |
| } | |
| } | |
| ); | |
| console.log('π OCR Text extracted:', text.substring(0, 100) + '...'); | |
| // Clean up uploaded file | |
| fs.unlinkSync(filePath); | |
| // Normalize text for better matching | |
| const normalizedText = text.toLowerCase(); | |
| // Check for required conditions | |
| const hasNotmebotz = normalizedText.includes('notmebotz') || | |
| normalizedText.includes('notme botz'); | |
| const hasFollowButton = normalizedText.includes('follow channel') || | |
| normalizedText.includes('follow') && normalizedText.includes('channel'); | |
| const hasPrivacy = normalizedText.includes('added privacy') || | |
| normalizedText.includes('this channel has added privacy'); | |
| // Verification logic | |
| const verified = hasNotmebotz && !hasFollowButton && !hasPrivacy; | |
| console.log(`β Verification result: ${verified ? 'PASSED' : 'FAILED'}`); | |
| console.log(` - Channel: ${hasNotmebotz ? 'NOTMEBOTZ β' : 'NOT FOUND β'}`); | |
| console.log(` - Follow Button: ${hasFollowButton ? 'PRESENT β' : 'ABSENT β'}`); | |
| console.log(` - Privacy Text: ${hasPrivacy ? 'PRESENT β' : 'ABSENT β'}`); | |
| res.json({ | |
| success: true, | |
| verified, | |
| channelName: hasNotmebotz ? 'NOTMEBOTZ' : 'UNKNOWN', | |
| hasFollowButton, | |
| hasPrivacy, | |
| extractedText: text.substring(0, 200) // Return first 200 chars for debugging | |
| }); | |
| } catch (error) { | |
| console.error('β OCR Error:', error); | |
| // Clean up file if it still exists | |
| if (fs.existsSync(filePath)) { | |
| fs.unlinkSync(filePath); | |
| } | |
| res.status(500).json({ | |
| success: false, | |
| error: 'OCR processing failed', | |
| message: error.message | |
| }); | |
| } | |
| }); | |
| // Delete link endpoint (optional - for admin) | |
| app.delete('/api/link/:id', authMiddleware, (req, res) => { | |
| const { id } = req.params; | |
| const db = getDB(); | |
| const index = db.findIndex(link => link.id === id); | |
| if (index !== -1) { | |
| const deletedLink = db.splice(index, 1)[0]; | |
| saveDB(db); | |
| console.log(`ποΈ Link deleted: ${deletedLink.name} (ID: ${id})`); | |
| res.json({ | |
| success: true, | |
| message: 'Link deleted successfully', | |
| deletedLink | |
| }); | |
| } else { | |
| res.status(404).json({ | |
| success: false, | |
| error: 'Link not found' | |
| }); | |
| } | |
| }); | |
| // Health check endpoint | |
| app.get('/api/health', (req, res) => { | |
| res.json({ | |
| status: 'OK', | |
| uptime: process.uptime(), | |
| timestamp: new Date().toISOString() | |
| }); | |
| }); | |
| // ============================================ | |
| // ERROR HANDLING | |
| // ============================================ | |
| // 404 handler | |
| app.use((req, res) => { | |
| res.status(404).json({ | |
| error: 'Not Found', | |
| message: 'The requested endpoint does not exist', | |
| path: req.path | |
| }); | |
| }); | |
| // Global error handler | |
| app.use((err, req, res, next) => { | |
| console.error('β Server Error:', err); | |
| res.status(err.status || 500).json({ | |
| error: 'Internal Server Error', | |
| message: err.message || 'Something went wrong' | |
| }); | |
| }); | |
| // ============================================ | |
| // START SERVER | |
| // ============================================ | |
| app.listen(PORT, () => { | |
| console.log(''); | |
| console.log('ββββββββββββββββββββββββββββββββββββββββββ'); | |
| console.log('β π ShortLink OCR Server Running β'); | |
| console.log('ββββββββββββββββββββββββββββββββββββββββββ'); | |
| console.log(''); | |
| console.log(`π Server: http://localhost:${PORT}`); | |
| console.log(`π Admin Panel: http://localhost:${PORT}/home/admin/create`); | |
| console.log(`π Admin Password: ${ADMIN_PASSWORD}`); | |
| console.log(''); | |
| console.log('π Database:', DB_FILE); | |
| console.log('π Uploads:', path.join(__dirname, 'uploads')); | |
| console.log(''); | |
| console.log('Press Ctrl+C to stop the server'); | |
| console.log(''); | |
| }); |