Download Jar. Libraryless. Click here for Pure Java version (21521L/137K).
1 | !7 |
2 | |
3 | static int id = 1400000; |
4 | |
5 | concept FileMeta { |
6 | int fileID; |
7 | S name; |
8 | S md5; |
9 | bool authed; |
10 | int redirectTo; |
11 | |
12 | *() {} |
13 | *(int *fileID, S *name) { _doneLoading(); change(); } |
14 | |
15 | void _doneLoading() { |
16 | //print("_doneLoading " + fileID); |
17 | metaMap.put(fileID, this); |
18 | } |
19 | } |
20 | |
21 | static Map<Int, FileMeta> metaMap = synchroMap(); |
22 | |
23 | p { |
24 | load("id"); |
25 | dbIndexing(FileMeta, 'fileID, FileMeta, 'name, FileMeta, 'md5); |
26 | } |
27 | |
28 | svoid setMD5(FileMeta meta) { |
29 | if (nempty(meta.md5)) ret; |
30 | S md5 = "error"; |
31 | pcall { |
32 | md5 = md5(fileFile(meta.fileID)); |
33 | } |
34 | cset(meta, +md5); |
35 | } |
36 | |
37 | static File filesDir() { |
38 | ret prepareProgramDir("files"); |
39 | } |
40 | |
41 | synchronized html { |
42 | print("uri: " + uri); |
43 | uri = dropPrefix("/", uri); |
44 | new Matches mm; |
45 | |
46 | if (eq(uri, "latest-id")) |
47 | ret get fileID(highestByField created(list(FileMeta))); |
48 | |
49 | if (startsWith(uri, "info/", mm) && isInteger(mm.rest())) |
50 | ret htitle("File #" + mm.rest()) |
51 | + fileIDToHTML(parseInt(mm.rest())); |
52 | |
53 | if (startsWith(uri, "name/", mm) && isInteger(mm.rest())) { |
54 | int id = parseInt(mm.rest()); |
55 | FileMeta meta = metaMap.get(id); |
56 | if (meta == null) ret subBot_serve404("ID not found: " + id); |
57 | ret serveText(unnull(meta.name)); |
58 | } |
59 | |
60 | S possibleID = beforeSlash_orAll(uri); |
61 | if (isInteger(possibleID)) { |
62 | // serve file |
63 | |
64 | int id = parseInt(possibleID); |
65 | FileMeta c = findMetaWithRedirect(id); |
66 | if (c == null) ret subBot_serve404("Not found"); |
67 | if (nempty(params.get("remd5"))) { |
68 | cset(c, md5 := null); |
69 | setMD5(c); |
70 | } |
71 | File file = fileFile(c.fileID); |
72 | |
73 | S givenName = urldecode(afterSlash(uri)); |
74 | S serveAs = or2(givenName, c.name); |
75 | S mimeType = or2(params.get("contentType"), params.get("ct")); |
76 | if (empty(mimeType)) |
77 | mimeType = or2(extensionToMimeType(c.name), "application/binary"); |
78 | print("givenName=" + givenName + ", serveAs=" + serveAs + ", mimeType=" + mimeType); |
79 | |
80 | ret addHeader("Content-Disposition", "attachment; filename=" + quote(serveAs), |
81 | call(getMainBot(), 'serveFile_maxCache, file, mimeType)); |
82 | } |
83 | |
84 | // Note: returns only authed files |
85 | if (startsWith(uri, "latest-file-named/", mm)) { |
86 | S name = urldecode(mm.get(0)); |
87 | FileMeta m = first(findAuthedFiles(name)); |
88 | ret struct(m == null ? null : ll(m.fileID, m.md5)); |
89 | } |
90 | |
91 | if (!webAuthed(params)) ret ahref(relativeBotLink(#1002590), "please log in"); |
92 | |
93 | // AUTHED FROM HERE ON |
94 | |
95 | if (startsWith(uri, "delete/", mm) && isInteger(mm.rest())) { |
96 | FileMeta m = conceptWhere(FileMeta, fileID := parseInt(mm.rest())); |
97 | if (m == null) ret "Not found"; |
98 | deleteFile(fileFile(m.fileID)); |
99 | deleteConcept(m); |
100 | ret "Deleted"; |
101 | } |
102 | |
103 | if (uri.startsWith("md5/")) { |
104 | uri = dropPrefix("md5/", uri); |
105 | FileMeta meta = findConcept(FileMeta, md5 := uri); |
106 | if (meta == null) |
107 | ret subBot_serve404("Not found"); |
108 | ret call(getMainBot(), "serveFile_maxCache", fileFile(meta.fileID), "application/binary"); |
109 | } |
110 | |
111 | // finds a file by md5 |
112 | if (uri.startsWith("checkmd5/")) { |
113 | uri = dropPrefix("checkmd5/", uri); |
114 | FileMeta meta = findConcept(FileMeta, md5 := uri); |
115 | ret meta == null ? "Not found" : str(meta.fileID); |
116 | } |
117 | |
118 | if (eq(uri, "setRedirect")) { |
119 | int from = parseInt(params.get("from")); |
120 | int to = parseInt(params.get("to")); |
121 | FileMeta meta = findConcept(FileMeta, fileID := from); |
122 | if (meta == null) ret "Not found"; |
123 | cset(meta, redirectTo := to); |
124 | ret "Redirected " + str(meta.fileID) + " to " + to; |
125 | } |
126 | |
127 | if (eq(uri, "upload")) { |
128 | print("upload called"); |
129 | S name = params.get("name"); |
130 | |
131 | SS files = getUploadFiles(); |
132 | print("got files: " + l(files)); |
133 | int id = parseInt(params.get('id)); |
134 | if (id != 0 && hasConcept(FileMeta, fileID := id)) |
135 | ret "File exists: " + id; |
136 | if (id == 0) id = newFileID(); |
137 | |
138 | S data = params.get("data"); |
139 | if (data != null) { |
140 | print("got data: " + l(data)); |
141 | saveBinaryFile(fileFile(id), hexToBytes(data)); |
142 | } else { |
143 | String tmpfile = files.get("thefile"); |
144 | String originalName = params.get("thefile"); |
145 | name = or2(name, originalName); |
146 | assertNotNull(tmpfile); |
147 | File tmp = new File(tmpfile); |
148 | long l = tmp.length(); |
149 | if (l == 0) ret "Empty file, exiting"; |
150 | copyFile(tmp, fileFile(id)); |
151 | } |
152 | FileMeta m = cregister(new FileMeta(id, unnull(name))); |
153 | cset(m, authed := webAuthed(params)); |
154 | setMD5(m); |
155 | ret hrefresh(2, rawLink()) + p("OK:<br>" + ahref(rawLink(str(id)), fsI(id) + " - " + or2(name, "?"))) |
156 | + ahref(rawLink(), "[back]"); |
157 | } |
158 | |
159 | if (eq(uri, "uploadform")) ret htitle("Upload") |
160 | + hmobilefix() |
161 | + uploadform(); |
162 | |
163 | if (eq(uri, "ids-and-md5s")) |
164 | ret struct(flattenList(map(list(FileMeta), func(FileMeta m) { ll(m.fileID, m.md5) }))); |
165 | |
166 | if (eq(uri, "typical-set")) { |
167 | L<FileMeta> l = findAuthedFiles( |
168 | "Circles From tvejysmllsmz.gz", |
169 | "Webs from program #1011161 on tvejysmllsmz.gz"); |
170 | ret struct(flattenList(map(l, func(FileMeta m) { ll(m.fileID, m.md5) }))); |
171 | } |
172 | |
173 | if (eq(uri, "")) { |
174 | // main list |
175 | |
176 | S msg = ""; |
177 | |
178 | L<int> ids = collect(conceptsSortedByFieldDesc(FileMeta, 'created), 'fileID); |
179 | ret htitle("General File Server") |
180 | + (nempty(msg) ? p(msg) : "") |
181 | + h3("Upload") + uploadform() |
182 | + "<hr>" |
183 | + p(n(ids, "File") + (empty(ids) ? "." : ":")) |
184 | + ul(map(ids, func(int id) -> S { fileIDToHTML(id) })) |
185 | //+ p(ahref(pageLink("/uploadform"), "Upload a file")) |
186 | ; |
187 | } |
188 | |
189 | null; |
190 | } |
191 | |
192 | static synchronized int newFileID() { |
193 | while (fileFile(id).exists()) |
194 | ++id; |
195 | int i = id++; |
196 | save("id"); |
197 | ret i; |
198 | } |
199 | |
200 | static File fileFile(int id) { |
201 | ret new File(filesDir(), str(id)); |
202 | } |
203 | |
204 | sS uploadform() { |
205 | ret huploadform( |
206 | p("File to upload: " + hfileupload()) |
207 | + p("Optional name: " + hinputfield("name")) |
208 | + p(hsubmit("OK")), |
209 | "action", rawLink("upload")); |
210 | } |
211 | |
212 | static L<FileMeta> findAuthedFiles(S... names) { |
213 | new L<FileMeta> l; |
214 | for (S name : names) |
215 | addIfNotNull(l, highestByField('id, conceptsWhere(FileMeta, +name, authed := true))); |
216 | ret l; |
217 | } |
218 | |
219 | sS fileIDToHTML(int id) { |
220 | FileMeta meta = metaMap.get(id); |
221 | S title = or2(getString(meta, "name"), "Untitled"); |
222 | S linkText = "#" + id + " - " + htmlencode(title); |
223 | //S dumbLink = rawLink(str(id)); |
224 | S coolLink = "https://botcompany.de/files/" + id + "/" + urlencode(title); |
225 | S s = ahref(coolLink, linkText); |
226 | s += " " + n(fileSize(fileFile(id)), "byte"); |
227 | if (meta != null) { |
228 | s += " [" + formatDateGMT(meta.created) + ", md5: " + ahref(rawLink("md5/" + meta.md5), meta.md5) + "]"; |
229 | if (meta.authed) s += " " + dottedSpan("*", "Authorized Upload"); |
230 | if (meta.redirectTo != 0) s = "redirected to #" + meta.redirectTo + " - " + s; |
231 | } |
232 | ret s; |
233 | } |
234 | |
235 | static FileMeta findMetaWithRedirect(int id) { |
236 | FileMeta c = findConcept(FileMeta, fileID := id); |
237 | if (c != null && c.redirectTo != 0) |
238 | c = findConcept(FileMeta, fileID := c.redirectTo); |
239 | ret c; |
240 | } |
Began life as a copy of #1010474
download show line numbers debug dex old transpilations
Travelled to 15 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, irmadwmeruwu, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt, xrpafgyirdlv
No comments. add comment
Snippet ID: | #1015408 |
Snippet name: | General File Server (authed upload, anonymous download) |
Eternal ID of this version: | #1015408/38 |
Text MD5: | 01d30fcc0e3ad131fa04aaf68afca1eb |
Transpilation MD5: | fbef496764800aff882fb7cef3acbe93 |
Author: | stefan |
Category: | javax / networking |
Type: | JavaX source code (desktop) |
Public (visible to everyone): | Yes |
Archived (hidden from active list): | No |
Created/modified: | 2021-08-24 20:41:36 |
Source code size: | 7179 bytes / 240 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 748 / 3548 |
Version history: | 37 change(s) |
Referenced in: | [show references] |