Spaces:
Configuration error
Configuration error
Upload 5 files
Browse files- server/firebase.js +11 -0
- server/routes.js +0 -0
- server/server.js +86 -0
- server/serviceAccountKey.json +13 -0
- server/upload.js +30 -0
server/firebase.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// server/firebase.js
|
| 2 |
+
const admin = require('firebase-admin');
|
| 3 |
+
const serviceAccount = require('./serviceAccountKey.json'); // download from Firebase Console
|
| 4 |
+
|
| 5 |
+
admin.initializeApp({
|
| 6 |
+
credential: admin.credential.cert(serviceAccount)
|
| 7 |
+
});
|
| 8 |
+
|
| 9 |
+
const db = admin.firestore();
|
| 10 |
+
|
| 11 |
+
module.exports = { db };
|
server/routes.js
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
server/server.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
const express = require("express");
|
| 2 |
+
const cors = require("cors");
|
| 3 |
+
const axios = require("axios");
|
| 4 |
+
const helmet = require("helmet");
|
| 5 |
+
const path = require("path");
|
| 6 |
+
|
| 7 |
+
const app = express();
|
| 8 |
+
const PORT = process.env.PORT || 3001;
|
| 9 |
+
|
| 10 |
+
// Security headers
|
| 11 |
+
app.use(helmet());
|
| 12 |
+
|
| 13 |
+
// CORS (restrict in production)
|
| 14 |
+
app.use(
|
| 15 |
+
cors({
|
| 16 |
+
origin: process.env.CLIENT_URL || "*",
|
| 17 |
+
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
|
| 18 |
+
allowedHeaders: ["Content-Type", "Authorization"],
|
| 19 |
+
})
|
| 20 |
+
);
|
| 21 |
+
|
| 22 |
+
app.use(express.json({ limit: "50mb" }));
|
| 23 |
+
app.use(express.urlencoded({ extended: true, limit: "50mb" }));
|
| 24 |
+
|
| 25 |
+
// =============================
|
| 26 |
+
// Serve Frontend (React/Vite)
|
| 27 |
+
// =============================
|
| 28 |
+
app.use(
|
| 29 |
+
express.static(path.join(__dirname, "dist"), {
|
| 30 |
+
setHeaders: (res, filePath) => {
|
| 31 |
+
if (filePath.endsWith(".js") || filePath.endsWith(".css")) {
|
| 32 |
+
// Cache hashed assets for 1 year
|
| 33 |
+
res.setHeader("Cache-Control", "public, max-age=31536000, immutable");
|
| 34 |
+
} else {
|
| 35 |
+
// Cache other assets (images, etc.) for 1 hour
|
| 36 |
+
res.setHeader("Cache-Control", "public, max-age=3600");
|
| 37 |
+
}
|
| 38 |
+
},
|
| 39 |
+
})
|
| 40 |
+
);
|
| 41 |
+
|
| 42 |
+
// SPA fallback → always return index.html
|
| 43 |
+
app.get("*", (req, res, next) => {
|
| 44 |
+
if (req.path.startsWith("/api")) return next(); // skip API routes
|
| 45 |
+
res.sendFile(path.join(__dirname, "dist", "index.html"));
|
| 46 |
+
});
|
| 47 |
+
|
| 48 |
+
// =============================
|
| 49 |
+
// Proxy /api requests
|
| 50 |
+
// =============================
|
| 51 |
+
app.use("/api", async (req, res, next) => {
|
| 52 |
+
try {
|
| 53 |
+
const url = `https://humanizerx.pro/api/routes.php${req.originalUrl.replace(
|
| 54 |
+
"/api",
|
| 55 |
+
""
|
| 56 |
+
)}`;
|
| 57 |
+
const method = req.method.toLowerCase();
|
| 58 |
+
|
| 59 |
+
const { data, status } = await axios({
|
| 60 |
+
url,
|
| 61 |
+
method,
|
| 62 |
+
headers: {
|
| 63 |
+
"Content-Type": req.headers["content-type"],
|
| 64 |
+
Authorization: req.headers["authorization"],
|
| 65 |
+
},
|
| 66 |
+
data: req.body,
|
| 67 |
+
});
|
| 68 |
+
|
| 69 |
+
res.status(status).json(data);
|
| 70 |
+
} catch (error) {
|
| 71 |
+
console.error("API Proxy Error:", error.message);
|
| 72 |
+
res.status(error.response?.status || 500).json({
|
| 73 |
+
success: false,
|
| 74 |
+
error: error.message,
|
| 75 |
+
});
|
| 76 |
+
}
|
| 77 |
+
});
|
| 78 |
+
|
| 79 |
+
// Test route
|
| 80 |
+
app.get("/test", (req, res) => {
|
| 81 |
+
res.json({ msg: "Hello from Humanizer X backend 🚀" });
|
| 82 |
+
});
|
| 83 |
+
|
| 84 |
+
app.listen(PORT, () => {
|
| 85 |
+
console.log(`✅ Humanizer X Backend running on http://localhost:${PORT}`);
|
| 86 |
+
});
|
server/serviceAccountKey.json
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"type": "service_account",
|
| 3 |
+
"project_id": "humanizer-x-16baa",
|
| 4 |
+
"private_key_id": "21350178209a3ac2f49055fb1fad3dc739826af1",
|
| 5 |
+
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC5INQBpCty2UU0\nLEBXlt2nopHFuf7Wfb+FC6dkGW6RKQO5TU0VnydJnXeD43bB3GkJZ47DYa7cccSo\nGze74UxsghT6CpZ8zGVDu57kCICSsIy/evUfX9IQjYB5a7mJFT/rPmQuBFAt0hSP\nj3J9y2DGU4JsT3xJlfglOuF2DwSGpjAbExbPdu3egsXR8tB3MHe3/hvOO+gZegzT\nYf90fs1No7efrhTll4nCGMzmiAu9OXiYO9oAzCaQFo3zibitwVeBwPHIS+e9tmRJ\nyxT72CiVpq1CxaWUEgU3cS0AQN9FBEXDoF71j6o5Wd8OQekkwhh1EYWfZ5OwioeU\nL6aUKAajAgMBAAECggEAPdLGuh2XHO2N/NRiUF3je94AjGWGwx6PXOD9b6JGmFd4\nFOPJwFS8DAt4JCVMPYVb1nYs6PawLJIZuIIOZMHigcIXO0FZ7CdeEfaQI1rrhRFM\nj42CWo3nWvvGUcY12Z+tDuRxFCUAmay0jRS8iWHn2ZN91KneubxJeDVnocN2IXjA\n1xx4QsgBzgIBRm4DhtcoAgaU5sIFHOFbKvLzxSLOEGRBqITb+sgNvWwgD9MahBAz\n4VoQmcaCoGQu9xEz+PEwFY8s+a0qOCLsd1la57VCOPV0l+RVbMqfQbCw1hjeIjvI\ncsIGoNvG/GAjTmd5IzJ2Fwmzy2xV8b11bWaViEuLcQKBgQDfrsfqajvTW3Wfn6Xe\nI8R1Ba59pqIqggX7UKmFOJisT/jvwuYTw+AO0Y0M3elNFp75iw82UIFVd57ZVllY\nmPUyQNhc3i8CnHQpJMFO7iVTatoXMCdwspFySqBDvN858Jhu5HWCxU6KQ99GCqll\ntuloRrbkvovxbsyYsNCKbsKBfwKBgQDT4A4TZWQ5KGbrkO/6wtbdOp7jmH0tl2Cy\nmQl7eQtDsYoZSaaRkfXjojl6ycUzTYLMg5hefb+SP7aSlad2NdDt5QyUJ+sFNhDi\n2kvtw5WpRxAVP/fQOhg2g+sPOO2D+wKy7qwMdphi1yWub8Kgu961c1hfdKjOYH0S\nS+tAj2fE3QKBgQCUkVlVWHQeAQxSFk6sCeOtujVYXbouM6hXcQ73Xk0BfiigzznT\n/PCvxv1Bg4821YSHyJY1BCmzI72NK24yi32ogCt1G1nsCRCaV0BR9ZkzG7B5YFGB\n6Aj0+Z4S/7rgl+4XEYT/c5+j9EqzEdfLqD7FNNq7edgnZulbrW0F1WU5bwKBgQC0\njTJxhO2rZ6qNA639WxwO2m2cNc42k9FrYM6b0cKvpROyCPlRA7kuiofBA0BxP5Q/\nA8VMgIxH7NOAhtd1/NZWY+IcPwggILqzFqOtsgZPgqdJ9IERiPApRLGC/1goKDdc\nk9c5p7akRANwavzITFC0/95HOfrAI6lxdhC7q3kaYQKBgDyzp7RQMfNI/n3fzN5h\nISbyx4KEBhd/6qCyQ0xfNu2pIgBakQ7pka07rWSyhBizdzkicSDQ1hwME+J9N63f\nG4pZ9MvXBkO6muv4nSzvQ0bJwf5v/4c4uVQr8RRzk/l1tKl9XLZJq5NEGgCAXMOz\ngYb6NAwZ6QpbbBfQYv92FjS5\n-----END PRIVATE KEY-----\n",
|
| 6 |
+
"client_email": "firebase-adminsdk-fbsvc@humanizer-x-16baa.iam.gserviceaccount.com",
|
| 7 |
+
"client_id": "114780934799698707217",
|
| 8 |
+
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
| 9 |
+
"token_uri": "https://oauth2.googleapis.com/token",
|
| 10 |
+
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
| 11 |
+
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/firebase-adminsdk-fbsvc%40humanizer-x-16baa.iam.gserviceaccount.com",
|
| 12 |
+
"universe_domain": "googleapis.com"
|
| 13 |
+
}
|
server/upload.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// backend/upload.js
|
| 2 |
+
const path = require('path');
|
| 3 |
+
const multer = require('multer');
|
| 4 |
+
const fs = require('fs');
|
| 5 |
+
|
| 6 |
+
// Ensure uploads folder exists
|
| 7 |
+
const uploadsDir = path.join(__dirname, 'uploads');
|
| 8 |
+
if (!fs.existsSync(uploadsDir)) {
|
| 9 |
+
fs.mkdirSync(uploadsDir, { recursive: true });
|
| 10 |
+
}
|
| 11 |
+
|
| 12 |
+
const upload = multer({
|
| 13 |
+
dest: uploadsDir, // Absolute path to uploads folder
|
| 14 |
+
limits: { fileSize: 15 * 1024 * 1024 }, // 15MB max
|
| 15 |
+
fileFilter: (req, file, cb) => {
|
| 16 |
+
const allowedTypes = [
|
| 17 |
+
'application/pdf',
|
| 18 |
+
'application/msword',
|
| 19 |
+
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
| 20 |
+
'text/plain'
|
| 21 |
+
];
|
| 22 |
+
if (allowedTypes.includes(file.mimetype)) {
|
| 23 |
+
cb(null, true);
|
| 24 |
+
} else {
|
| 25 |
+
cb(new Error('Invalid file type. Only PDF, Word, and TXT files are allowed.'));
|
| 26 |
+
}
|
| 27 |
+
}
|
| 28 |
+
});
|
| 29 |
+
|
| 30 |
+
module.exports = upload;
|