Skip to content

Commit 0cddf7e

Browse files
committed
Add e2e tests, fix typo
1 parent 981dbf6 commit 0cddf7e

File tree

6 files changed

+193
-7
lines changed

6 files changed

+193
-7
lines changed

end2end/server/src/handlers/lists.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const {
22
getBlockedIPAddresses,
33
getBlockedUserAgents,
44
getAllowedIPAddresses,
5+
getBotSpoofingData,
56
} = require("../zen/config");
67

78
module.exports = function lists(req, res) {
@@ -12,6 +13,7 @@ module.exports = function lists(req, res) {
1213
const blockedIps = getBlockedIPAddresses(req.app);
1314
const blockedUserAgents = getBlockedUserAgents(req.app);
1415
const allowedIps = getAllowedIPAddresses(req.app);
16+
const botSpoofingData = getBotSpoofingData(req.app);
1517

1618
res.json({
1719
success: true,
@@ -37,5 +39,6 @@ module.exports = function lists(req, res) {
3739
},
3840
]
3941
: [],
42+
botSpoofingProtection: botSpoofingData,
4043
});
4144
};

end2end/server/src/handlers/updateLists.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ const {
22
updateBlockedIPAddresses,
33
updateBlockedUserAgents,
44
updateAllowedIPAddresses,
5+
updateBotSpoofingData,
56
} = require("../zen/config");
67

78
module.exports = function updateIPLists(req, res) {
@@ -46,5 +47,12 @@ module.exports = function updateIPLists(req, res) {
4647
updateAllowedIPAddresses(req.app, req.body.allowedIPAddresses);
4748
}
4849

50+
if (
51+
req.body.botSpoofingProtection &&
52+
Array.isArray(req.body.botSpoofingProtection)
53+
) {
54+
updateBotSpoofingData(req.app, req.body.botSpoofingProtection);
55+
}
56+
4957
res.json({ success: true });
5058
};

end2end/server/src/zen/config.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ function updateAppConfig(app, newConfig) {
4040
const blockedIPAddresses = [];
4141
const blockedUserAgents = [];
4242
const allowedIPAddresses = [];
43+
const botSpoofingData = [];
4344

4445
function updateBlockedIPAddresses(app, ips) {
4546
let entry = blockedIPAddresses.find((ip) => ip.serviceId === app.serviceId);
@@ -113,6 +114,30 @@ function getBlockedUserAgents(app) {
113114
return "";
114115
}
115116

117+
function updateBotSpoofingData(app, data) {
118+
let entry = botSpoofingData.find((d) => d.serviceId === app.serviceId);
119+
120+
if (entry) {
121+
entry.data = data;
122+
} else {
123+
entry = { serviceId: app.serviceId, data: data };
124+
botSpoofingData.push(entry);
125+
}
126+
127+
// Bump lastUpdatedAt
128+
updateAppConfig(app, {});
129+
}
130+
131+
function getBotSpoofingData(app) {
132+
const entry = botSpoofingData.find((d) => d.serviceId === app.serviceId);
133+
134+
if (entry) {
135+
return entry.data;
136+
}
137+
138+
return [];
139+
}
140+
116141
module.exports = {
117142
getAppConfig,
118143
updateAppConfig,
@@ -122,4 +147,6 @@ module.exports = {
122147
getBlockedUserAgents,
123148
getAllowedIPAddresses,
124149
updateAllowedIPAddresses,
150+
updateBotSpoofingData,
151+
getBotSpoofingData,
125152
};
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
const t = require("tap");
2+
const { spawn } = require("child_process");
3+
const { resolve } = require("path");
4+
const timeout = require("../timeout");
5+
6+
const pathToApp = resolve(
7+
__dirname,
8+
"../../sample-apps/hono-sqlite3",
9+
"app.js"
10+
);
11+
const testServerUrl = "http://localhost:5874";
12+
13+
let token;
14+
t.beforeEach(async () => {
15+
const response = await fetch(`${testServerUrl}/api/runtime/apps`, {
16+
method: "POST",
17+
});
18+
const body = await response.json();
19+
token = body.token;
20+
21+
const lists = await fetch(`${testServerUrl}/api/runtime/firewall/lists`, {
22+
method: "POST",
23+
headers: {
24+
"Content-Type": "application/json",
25+
Authorization: token,
26+
},
27+
body: JSON.stringify({
28+
allowedIPAddresses: [],
29+
blockedIPAddresses: [],
30+
blockedUserAgents: "",
31+
botSpoofingProtection: [
32+
{
33+
key: "google_test",
34+
uaPattern: "Googlebot|GoogleStoreBot",
35+
ips: ["1.2.3.4/24", "4.3.2.1"],
36+
hostnames: ["google.com", "googlebot.com"],
37+
},
38+
],
39+
}),
40+
});
41+
t.same(lists.status, 200);
42+
});
43+
44+
t.test("it blocks spoofed bots", (t) => {
45+
const server = spawn(`node`, [pathToApp, "4012"], {
46+
env: {
47+
...process.env,
48+
AIKIDO_DEBUG: "true",
49+
AIKIDO_BLOCK: "true",
50+
AIKIDO_TOKEN: token,
51+
AIKIDO_ENDPOINT: testServerUrl,
52+
},
53+
});
54+
55+
server.on("close", () => {
56+
t.end();
57+
});
58+
59+
server.on("error", (err) => {
60+
t.fail(err.message);
61+
});
62+
63+
let stdout = "";
64+
server.stdout.on("data", (data) => {
65+
stdout += data.toString();
66+
});
67+
68+
let stderr = "";
69+
server.stderr.on("data", (data) => {
70+
stderr += data.toString();
71+
});
72+
73+
// Wait for the server to start
74+
timeout(4000)
75+
.then(async () => {
76+
{
77+
const response = await fetch("http://127.0.0.1:4012/", {
78+
headers: {
79+
"user-agent": "Googlebot",
80+
"x-forwarded-for": "1.1.1.1",
81+
},
82+
signal: AbortSignal.timeout(5000),
83+
});
84+
t.same(response.status, 403);
85+
t.same(
86+
await response.text(),
87+
"You are not allowed to access this resource."
88+
);
89+
}
90+
{
91+
const response = await fetch("http://127.0.0.1:4012/", {
92+
headers: {
93+
"user-agent": "Googlebot",
94+
"x-forwarded-for": "127.0.0.1",
95+
},
96+
signal: AbortSignal.timeout(5000),
97+
});
98+
t.same(response.status, 200); // localhost is not blocked
99+
}
100+
{
101+
const response = await fetch("http://127.0.0.1:4012/", {
102+
headers: {
103+
"user-agent":
104+
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.4 Safari/605.1.15",
105+
"x-forwarded-for": "1.1.1.1",
106+
},
107+
signal: AbortSignal.timeout(5000),
108+
});
109+
t.same(response.status, 200); // not a protected bot
110+
}
111+
{
112+
const response = await fetch("http://127.0.0.1:4012/", {
113+
headers: {
114+
"user-agent": "Googlebot",
115+
"x-forwarded-for": "66.249.90.77",
116+
},
117+
signal: AbortSignal.timeout(5000),
118+
});
119+
t.same(response.status, 200); // Real Googlebot ip
120+
}
121+
{
122+
const response = await fetch("http://127.0.0.1:4012/", {
123+
headers: {
124+
"user-agent": "Googlebot",
125+
"x-forwarded-for": "1.2.3.4",
126+
},
127+
signal: AbortSignal.timeout(5000),
128+
});
129+
t.same(response.status, 200); // whitelisted ip
130+
}
131+
{
132+
const response = await fetch("http://127.0.0.1:4012/", {
133+
headers: {
134+
"user-agent": "Googlebot",
135+
"x-forwarded-for": "4.3.2.1",
136+
},
137+
signal: AbortSignal.timeout(5000),
138+
});
139+
t.same(response.status, 200); // whitelisted ip
140+
}
141+
})
142+
.catch((error) => {
143+
t.fail(error.message);
144+
})
145+
.finally(() => {
146+
server.kill();
147+
});
148+
});

library/agent/Agent.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -382,12 +382,12 @@ export class Agent {
382382
blockedIPAddresses,
383383
blockedUserAgents,
384384
allowedIPAddresses,
385-
botSpoofingData,
385+
botSpoofingProtection,
386386
} = await fetchBlockedLists(this.token);
387387
this.serviceConfig.updateBlockedIPAddresses(blockedIPAddresses);
388388
this.serviceConfig.updateBlockedUserAgents(blockedUserAgents);
389389
this.serviceConfig.updateAllowedIPAddresses(allowedIPAddresses);
390-
this.serviceConfig.updateBotSpoofingData(botSpoofingData);
390+
this.serviceConfig.updateBotSpoofingData(botSpoofingProtection);
391391
} catch (error: any) {
392392
console.error(`Aikido: Failed to update blocked lists: ${error.message}`);
393393
}

library/agent/api/fetchBlockedLists.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export async function fetchBlockedLists(token: Token): Promise<{
1919
blockedIPAddresses: IPList[];
2020
allowedIPAddresses: IPList[];
2121
blockedUserAgents: string;
22-
botSpoofingData: BotSpoofingData[];
22+
botSpoofingProtection: BotSpoofingData[];
2323
}> {
2424
const baseUrl = getAPIURL();
2525
const { body, statusCode } = await fetch({
@@ -46,7 +46,7 @@ export async function fetchBlockedLists(token: Token): Promise<{
4646
blockedIPAddresses: IPList[];
4747
allowedIPAddresses: IPList[];
4848
blockedUserAgents: string;
49-
botSpoofingData: BotSpoofingData[];
49+
botSpoofingProtection: BotSpoofingData[];
5050
} = JSON.parse(body);
5151

5252
return {
@@ -63,9 +63,9 @@ export async function fetchBlockedLists(token: Token): Promise<{
6363
result && typeof result.blockedUserAgents === "string"
6464
? result.blockedUserAgents
6565
: "",
66-
botSpoofingData:
67-
result && Array.isArray(result.botSpoofingData)
68-
? result.botSpoofingData
66+
botSpoofingProtection:
67+
result && Array.isArray(result.botSpoofingProtection)
68+
? result.botSpoofingProtection
6969
: [],
7070
};
7171
}

0 commit comments

Comments
 (0)