This repository has been archived by the owner on Mar 26, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathserver.js
249 lines (208 loc) Β· 5.72 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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
// Import packages
const express = require("express");
const app = express();
const lowdb = require("lowdb");
const fs = require("lowdb/adapters/FileSync");
const adapter = new fs("db.json");
const db = lowdb(adapter);
const ratelimit = require("express-rate-limit-ide");
const body = require("body-parser").json();
// Ratelimit the API
const apilimiter = ratelimit({
windowMs: 60000, // 1m
max: 30, // 60 requests per minute
message: {
success: false,
error: "Too many requests received. Try again in a minute."
}
});
// Apply ratelimit to routes starting with /api/
app.use("/api/", apilimiter);
// Serve static files in the public folder
app.use(express.static("public"));
// Set JSON indentation
app.set("json spaces", 2);
// Homepage
app.get("/", (req, res) => {
res.sendFile(__dirname + "/views/index.html");
});
// Stats Page
app.get("/stats", (req, res) => {
res.sendFile(__dirname + "/views/stats.html");
});
// Delete Page
app.get("/delete", (req, res) => {
res.sendFile(__dirname + "/views/delete.html");
});
// API Homepage
app.get("/api", (req, res) => {
res.sendFile(__dirname + "/views/api.html");
});
// Create API
app.post("/api/create", body, (req, res) => {
// Get variables from request body
var url = req.body.url;
var slug = req.body.slug;
// Check if URL exists
if (!url)
return res
.status(400)
.json({ success: false, error: "No URL was provided." });
// Check if input is URL
if (checkurl(url) === false)
return res
.status(400)
.json({ success: false, error: "The URL provided is invalid" });
// Check if URL points to the URL shorteners domain
if (url.includes(req.get("host")))
return res.status(400).json({
success: false,
error: "Long URLs cannot point to the URL shortener domain."
});
// Generate delete token
const token = random(30);
// If there is a custom slug
if (slug) {
// Check if the slug contains bad characters
if (!slug.match(/^[A-Za-z0-9_-]+$/))
return res.status(400).json({
success: false,
error: "Slug may only contain letters, numbers, dashes and underscores."
});
// Check if slug is taken
if (
db
.get("urls")
.find({ slug: slug })
.value()
)
return res.status(400).json({
success: false,
error: "The requested slug is already in use."
});
// Add to db
db.get("urls")
.push({ slug: slug, url: url, token: token, stats: 0 })
.write();
// Return URL
return res
.status(200)
.json({ success: true, slug: slug, url: url, token: token });
// If there is no custom slug
} else {
// Generate random stuff
var slug = random(5);
// Check if slug is taken
while (
db
.get("urls")
.find({ slug: slug })
.value()
) {
slug = random(5);
}
// Add to db
db.get("urls")
.push({ slug: slug, url: url, token: token, stats: 0 })
.write();
// Return URL
return res
.status(200)
.json({ success: true, slug: slug, url: url, token: token });
}
});
app.post("/api/stats", body, (req, res) => {
// Get variables from request body
var slug = req.body.slug;
// Check if slug is provided
if (!slug)
return res.status(400).json({ success: false, error: "Slug is missing." });
// Check if slug in the database
const result = db
.get("urls")
.find({ slug: slug })
.value();
// If no slug exists with that name
if (!result)
return res.status(400).json({ success: false, error: "Invalid slug." });
// Return info
return res.status(200).json({
success: true,
slug: result.slug,
url: result.url,
stats: result.stats
});
});
// Delete API
app.post("/api/delete", body, (req, res) => {
// Get variables from request body
var token = req.body.token;
var slug = req.body.slug;
// Check if slug and token are provided
if (!slug || !token)
return res
.status(400)
.json({ success: false, error: "Slug or token is missing." });
// Check if slug and token exist in the database
const result = db
.get("urls")
.find({ slug: slug, token: token })
.value();
// If token or slug doesn't exist
if (!result)
return res
.status(400)
.json({ success: false, error: "Invalid slug or token." });
// Delete slug
db.get("urls")
.remove({ slug: slug, token: token })
.write();
// Send success message
return res.status(200).json({ success: true });
});
// Slugs redirect + 404
app.get("*", (req, res) => {
// Get current path and slice off the first slash
const slug = req.path.slice(1);
// Get info for current url
const result = db
.get("urls")
.find({ slug: slug })
.value();
// If there is no matching slug, return 404 page
if (!result) return res.status(404).sendFile(__dirname + "/views/404.html");
// Add 1 to the stats count for that slug
db.get("urls")
.find({ slug: slug })
.assign({ stats: result.stats + 1 })
.write();
// Redirect to URL
return res.redirect(result.url);
});
// Start app
const listener = app.listen(8080, () => {
console.log("Your app is listening on port " + listener.address().port);
});
// Function to check if URL is valid
function checkurl(string) {
var url = "";
try {
url = new URL(string);
} catch (_) {
return false;
}
return url.protocol === "http:" || url.protocol === "https:";
}
// Random character generator
function random(length) {
var result = "";
const characters = "abcdefghijkmnopqrstuvwxyz0123456789";
for (var i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * characters.length));
}
return result;
}
// Set defaults for database
db.defaults({
urls: []
}).write();