Anjay / index.js
maylinejix's picture
Create index.js
ff0130c verified
// 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('');
});