Repository navigation
Expand file tree
/
Copy pathbackend.js
More file actions
122 lines (104 loc) · 3.82 KB
/
Copy pathbackend.js
File metadata and controls
122 lines (104 loc) · 3.82 KB
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
// Basic Setup
const jwt = require("jsonwebtoken");
const fs = require("fs");
const express = require("express");
const dotenv = require("dotenv");
const path = require("path");
const { validate } = require("@telegram-apps/init-data-node");
dotenv.config();
const app = express();
app.use(express.json()); // Middleware to parse JSON requests
const { TELEGRAM_BOT_TOKEN, JWT_KEY_ID, APP_URL } = process.env;
const privateKey = fs.readFileSync(path.resolve(__dirname, "privateKey.pem"), "utf8");
// CORS Configuration
// Define allowed origins
const allowedOrigins = [APP_URL];
// CORS configuration
app.use((req, res, next) => {
const origin = req.headers.origin;
if (allowedOrigins.includes(origin)) {
res.setHeader("Access-Control-Allow-Origin", origin);
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
res.setHeader(
"Access-Control-Allow-Headers",
"Content-Type, Authorization, X-Requested-With, Accept",
);
res.setHeader("Access-Control-Allow-Credentials", "true");
}
if (req.method === "OPTIONS") {
res.setHeader(
"Access-Control-Allow-Headers",
"Content-Type, Authorization, X-Requested-With, Accept",
);
return res.sendStatus(204);
}
next();
});
// Rate Limiting
const RateLimit = require("express-rate-limit");
const limiter = RateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100, // Max 100 requests per IP
message: "Too many requests from this IP, please try again later.",
});
app.use(limiter);
// Helper Function to Generate JWT Token
const generateJwtToken = (userData) => {
const payload = {
telegram_id: userData.id,
username: userData.username,
avatar_url: userData.photo_url || "https://www.gravatar.com/avatar",
sub: userData.id.toString(),
name: userData.first_name,
iss: "https://api.telegram.org",
iat: Math.floor(Date.now() / 1000),
exp: Math.floor(Date.now() / 1000) + 60 * 60, // Token valid for 1 hour
};
return jwt.sign(payload, privateKey, { algorithm: "RS256", keyid: JWT_KEY_ID });
};
// Routes
// Route 1: Test route to verify server is running
app.get("/test", (req, res) => {
res.json({ message: "Connection successful. Server is running!" });
});
// Route 2: Telegram authentication route
app.post("/auth/telegram", async (req, res) => {
const { initDataRaw, isMocked, photoUrl } = req.body; // Extract photoUrl from request body
if (!initDataRaw) {
return res.status(400).json({ error: "initDataRaw is required" });
}
if (isMocked) {
// Handle mock data parsing
const data = new URLSearchParams(initDataRaw);
const user = JSON.parse(decodeURIComponent(data.get("user")));
const mockUser = {
id: user.id,
username: user.username,
photo_url: photoUrl || user.photo_url || "https://www.gravatar.com/avatar",
first_name: user.first_name,
};
const JWTtoken = generateJwtToken(mockUser);
return res.json({ token: JWTtoken });
}
try {
// Validate the real initDataRaw using @telegram-apps/init-data-node
validate(initDataRaw, TELEGRAM_BOT_TOKEN);
// If validation is successful, parse the data
const data = new URLSearchParams(initDataRaw);
const user = JSON.parse(decodeURIComponent(data.get("user")));
const validatedUser = {
...user,
photo_url: photoUrl || user.photo_url || "https://www.gravatar.com/avatar",
};
// Generate the JWT token
const JWTtoken = generateJwtToken(validatedUser);
res.json({ token: JWTtoken });
} catch (error) {
console.error("Error validating Telegram data:", error);
res.status(400).json({ error: "Invalid Telegram data" });
}
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}`);
});