Uses 1113K of libraries. Click here for Pure Java version (10741L/56K).
1 | !7 |
2 | |
3 | sclass IPInfo { |
4 | S ip; |
5 | Timestamp firstSeen, lastSeen, blockUntil; |
6 | long passwordFails, passwordSuccesses; |
7 | Timestamp lastPasswordSuccess, lastPasswordFail; |
8 | long blockedRequests; |
9 | Bool allowed; |
10 | |
11 | bool isEvil() { ret blockUntil != null; } |
12 | } |
13 | |
14 | static MapSO _renameClasses = litmap("SalterService" := "ScreenshotService"); |
15 | |
16 | cm ScreenshotService > DynPrintLogAndEnabled { |
17 | !include early #1029545 // API for Eleu |
18 | |
19 | switchable S password = aGlobalID(); |
20 | switchable int badPWBlockSeconds = 30; |
21 | |
22 | Map<S, IPInfo> ipsSeen = syncLinkedHashMap(); |
23 | |
24 | start { // to show warnings early |
25 | canServe(); |
26 | printIPsSeen(); |
27 | } |
28 | |
29 | void printIPsSeen aka printStats() { |
30 | var list = cloneValues(ipsSeen); |
31 | print(n2(list, "IP") + " seen." + stringIf(empty(list), " I am a virgin.")); |
32 | for (IPInfo info : list) |
33 | print("Known client IP: " + info.ip |
34 | + appendBracketed_comma( |
35 | info.isEvil() ? "evil" : "good", |
36 | info.passwordFails == 0 ? "" |
37 | : n2(info.passwordSuccesses, "normal request") + ", last: " |
38 | + info.lastPasswordSuccess, |
39 | info.passwordFails == 0 ? "" |
40 | : n2(info.passwordFails, "password failures") + ", last: " + info.lastPasswordFail, |
41 | n2UnlessZero(info.blockedRequests, "blocked requests"))); |
42 | } |
43 | |
44 | O html(IWebRequest req) ctex { |
45 | if (!canServe()) ret "Can't serve"; |
46 | |
47 | S ip = req.clientIP(); |
48 | IPInfo ipInfo = getOrCreate(ipsSeen, ip, () -> { |
49 | print("New client IP!! " + ip); |
50 | new IPInfo info; |
51 | info.ip = ip; |
52 | info.lastSeen = new Timestamp; |
53 | if (info.firstSeen == null) info.firstSeen = info.lastSeen; |
54 | change(); |
55 | ret info; |
56 | }); |
57 | |
58 | // Don't allow brute-force password checking |
59 | |
60 | if (ipInfo.blockUntil != null && cmp(ipInfo.blockUntil, new Timestamp) > 0) { |
61 | print("Request from blocked IP: " + ip); |
62 | ipInfo.blockedRequests++; |
63 | change(); |
64 | ret print("Not allowed (evil IP)"); |
65 | } |
66 | |
67 | S uri = req.uri(); |
68 | print("Serving to IP " + ip + ": " + uri); |
69 | |
70 | if (isFalse(ipInfo.allowed)) |
71 | ret print("Not allowed (bad IP)"); |
72 | |
73 | S suppliedPW = req.get("password"); |
74 | if (empty(suppliedPW)) ret "Need password"; |
75 | |
76 | if (!eq(password, suppliedPW)) { |
77 | ++ipInfo.passwordFails; |
78 | ipInfo.lastPasswordFail = new Timestamp; |
79 | change(); |
80 | print("Password FAIL from " + ip + " OK"); |
81 | if ((ipInfo.passwordFails % 10) == 0) { |
82 | infoMessage(n2(ipInfo.passwordFails) + " password fails from " + ip + "!!!!"); |
83 | print("Blocking " + ip + " for " + badPWBlockSeconds + " seconds"); |
84 | ipInfo.blockUntil = new Timestamp(nowPlusSeconds(badPWBlockSeconds)); |
85 | change(); |
86 | } |
87 | ret "Bad PW"; |
88 | } |
89 | |
90 | ++ipInfo.passwordSuccesses; |
91 | ipInfo.lastPasswordSuccess = new Timestamp; |
92 | change(); |
93 | print("Password from " + ip + " OK"); |
94 | |
95 | ret subBot_serveJPEG(shootScreen2()); |
96 | } |
97 | |
98 | bool canServe() { |
99 | if (!enabled) ret false with print("Disabled"); |
100 | if (l(password) < 4) ret false with warn("Not starting - password too short!!"); |
101 | true; |
102 | } |
103 | |
104 | void forgetIPsSeen() { |
105 | ipsSeen.clear(); |
106 | change(); |
107 | print("Mandatory memory wipe done."); |
108 | printIPsSeen(); |
109 | } |
110 | |
111 | enhanceFrame { |
112 | addInternalFrameTitleMenuItem(f/JInternalFrame, "Print Stats", rThreadEnter printStats); |
113 | } |
114 | } |
Began life as a copy of #1031702
download show line numbers debug dex old transpilations
Travelled to 3 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx
No comments. add comment
Snippet ID: | #1032110 |
Snippet name: | Screenshot Service (use with #1032109) |
Eternal ID of this version: | #1032110/28 |
Text MD5: | 87219990f2a03b647b03f581e581a2b5 |
Transpilation MD5: | cff253e7030ac4056c9905ea00cd7403 |
Author: | stefan |
Category: | javax |
Type: | JavaX source code (Dynamic Module) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2021-08-14 02:26:41 |
Source code size: | 3457 bytes / 114 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 225 / 1739 |
Version history: | 27 change(s) |
Referenced in: | [show references] |