Merge lp:~tsyrus/pastebinit/pastebinthat-gpg into lp:pastebinit
- pastebinthat-gpg
- Merge into trunk
Proposed by
Terence Syrus
Status: | Work in progress | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Proposed branch: | lp:~tsyrus/pastebinit/pastebinthat-gpg | ||||||||||||
Merge into: | lp:pastebinit | ||||||||||||
Diff against target: |
1589 lines (+775/-500) 22 files modified
README (+16/-13) pastebin.d/cxg.de.conf (+4/-7) pastebin.d/dpaste.com.conf (+17/-0) pastebin.d/fpaste.org.conf (+1/-1) pastebin.d/lpaste.net.conf (+2/-3) pastebin.d/p.defau.lt.conf (+2/-5) pastebin.d/paste.debian.net.conf (+1/-1) pastebin.d/paste.drizzle.org.conf (+6/-9) pastebin.d/paste.kde.org.conf (+10/-14) pastebin.d/paste.openstack.org.conf (+6/-9) pastebin.d/paste.pound-python.org.conf (+1/-1) pastebin.d/paste.ubuntu.com.conf (+1/-1) pastebin.d/paste.ubuntu.org.cn.conf (+1/-1) pastebin.d/paste2.org.conf (+1/-1) pastebin.d/pastebin.com.conf (+4/-5) pastebin.d/pastebin.mate-desktop.org.conf (+7/-9) pastebin.d/pb.daviey.com.conf (+4/-5) pastebin.d/slexy.org.conf (+2/-3) pastebin.d/sprunge.us.conf (+3/-5) pastebinit (+537/-402) test.py (+135/-0) test.sh (+14/-5) |
||||||||||||
To merge this branch: | bzr merge lp:~tsyrus/pastebinit/pastebinthat-gpg | ||||||||||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Pastebinit Developers | Pending | ||
Review via email:
|
Commit message
Description of the change
Includes pastebinthat and pastebinthat-
support for GPG signing and encrypting, support for https, support for reviewing keys and content before pasting
To post a comment you must log in.
Unmerged revisions
- 226. By Terence Syrus <email address hidden>
-
more cleanup
- 225. By Terence Syrus <email address hidden>
-
minor cleanup
- 224. By Terence Syrus <email address hidden>
-
finished first round of gpg support changes
- 223. By Terence Syrus <email address hidden>
-
added support for signing pastes
- 222. By Terence Syrus <email address hidden>
-
added review option
- 221. By Terence Syrus <email address hidden>
-
variable renaming and cleanup
- 220. By Terence Syrus <email address hidden>
-
variable renaming
- 219. By Terence Syrus <email address hidden>
-
minor code cleanup
- 218. By Terence Syrus <email address hidden>
-
removed debug
- 217. By Terence Syrus <email address hidden>
-
removed unused method
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'README' |
2 | --- README 2009-12-30 13:35:24 +0000 |
3 | +++ README 2014-12-07 21:54:13 +0000 |
4 | @@ -28,10 +28,25 @@ |
5 | this domain name should not contain |
6 | possible sub-domains in use. |
7 | |
8 | - regexp - a regular expression that matches the |
9 | + id_regexp - a regular expression that matches the |
10 | basename, as well as any sub-domains that |
11 | may be in use. |
12 | |
13 | + page - used to specify a page from which to |
14 | + post data. It is the actual URL of |
15 | + the pastebin's form. |
16 | + |
17 | + result_regexp - used to specify a regexp to execute |
18 | + on the resulting page after posting. |
19 | + This is useful to deal with special |
20 | + pastebins that don't redirect you |
21 | + to the new post's URL. |
22 | + |
23 | + result_type - the type of the result (not required) |
24 | + id: The result_regexp matches an id. |
25 | + The basename will be prepended to the result |
26 | + url: The result_regexp matches a full url. |
27 | + |
28 | |
29 | THE FORMAT SECTION |
30 | |
31 | @@ -75,18 +90,6 @@ |
32 | jabberid - contains the jabberid for the poster |
33 | as set at the command line. |
34 | |
35 | -Two additional special parameters are available for use: |
36 | - |
37 | - page - used to specify a page from which to |
38 | - post data. It is the actual URL of |
39 | - the pastebin's form. |
40 | - |
41 | - regexp - used to specify a regexp to execute |
42 | - on the resulting page after posting. |
43 | - This is useful to deal with special |
44 | - pastebins that don't redirect you |
45 | - to the new post's URL. |
46 | - |
47 | Add any other fields in use for the specific pastebin you are setting up may be |
48 | added to the "[format]" section using the same syntax. |
49 | |
50 | |
51 | === modified file 'pastebin.d/cxg.de.conf' |
52 | --- pastebin.d/cxg.de.conf 2012-06-13 16:41:21 +0000 |
53 | +++ pastebin.d/cxg.de.conf 2014-12-07 21:54:13 +0000 |
54 | @@ -1,14 +1,11 @@ |
55 | [pastebin] |
56 | basename = cxg.de |
57 | -regexp = http://cxg.de |
58 | +id_regexp = http://cxg.de |
59 | +result_type = url |
60 | +result_regexp = href="(http://cxg.de/.*)" |
61 | +page = /paste.php |
62 | |
63 | [format] |
64 | user = desc |
65 | content = pastetext |
66 | format = lang |
67 | -page = page |
68 | -regexp = regexp |
69 | - |
70 | -[defaults] |
71 | -page = /paste.php |
72 | -regexp = href="http://cxg.de/(.*)" |
73 | |
74 | === added file 'pastebin.d/dpaste.com.conf' |
75 | --- pastebin.d/dpaste.com.conf 1970-01-01 00:00:00 +0000 |
76 | +++ pastebin.d/dpaste.com.conf 2014-12-07 21:54:13 +0000 |
77 | @@ -0,0 +1,17 @@ |
78 | +[pastebin] |
79 | +basename = dpaste.com |
80 | +id_regexp = http://dpaste.com |
81 | +page = /api/v1/ |
82 | + |
83 | +[format] |
84 | +user = poster |
85 | +content = content |
86 | +title = title |
87 | +format = language |
88 | +hold = hold |
89 | + |
90 | +[defaults] |
91 | +# Empty means "Plain". |
92 | +format = |
93 | +# Keep it for 30 days after last access. Otherwise only for 7 days. |
94 | +hold = on |
95 | |
96 | === modified file 'pastebin.d/fpaste.org.conf' |
97 | --- pastebin.d/fpaste.org.conf 2014-01-06 20:58:13 +0000 |
98 | +++ pastebin.d/fpaste.org.conf 2014-12-07 21:54:13 +0000 |
99 | @@ -1,6 +1,6 @@ |
100 | [pastebin] |
101 | basename = fpaste.org |
102 | -regexp = http://fpaste.org |
103 | +id_regexp = http://fpaste.org |
104 | |
105 | [format] |
106 | user = paste_user |
107 | |
108 | === modified file 'pastebin.d/lpaste.net.conf' |
109 | --- pastebin.d/lpaste.net.conf 2014-01-06 22:59:43 +0000 |
110 | +++ pastebin.d/lpaste.net.conf 2014-12-07 21:54:13 +0000 |
111 | @@ -1,6 +1,7 @@ |
112 | [pastebin] |
113 | basename = lpaste.net |
114 | -regexp = http://lpaste.net |
115 | +id_regexp = http://lpaste.net |
116 | +page = new |
117 | |
118 | [format] |
119 | public = public |
120 | @@ -10,10 +11,8 @@ |
121 | channel = channel |
122 | content = paste |
123 | email = email |
124 | -page = page |
125 | |
126 | [defaults] |
127 | -page = new |
128 | public = Public |
129 | channel = |
130 | email = |
131 | |
132 | === modified file 'pastebin.d/p.defau.lt.conf' |
133 | --- pastebin.d/p.defau.lt.conf 2012-06-13 16:41:21 +0000 |
134 | +++ pastebin.d/p.defau.lt.conf 2014-12-07 21:54:13 +0000 |
135 | @@ -1,10 +1,7 @@ |
136 | [pastebin] |
137 | basename = p.defau.lt |
138 | -regexp = http://p.defau.lt |
139 | +id_regexp = http://p.defau.lt |
140 | +page = /submit.php |
141 | |
142 | [format] |
143 | content = code |
144 | -page = page |
145 | - |
146 | -[defaults] |
147 | -page = /submit.php |
148 | |
149 | === modified file 'pastebin.d/paste.debian.net.conf' |
150 | --- pastebin.d/paste.debian.net.conf 2012-06-13 16:41:21 +0000 |
151 | +++ pastebin.d/paste.debian.net.conf 2014-12-07 21:54:13 +0000 |
152 | @@ -1,6 +1,6 @@ |
153 | [pastebin] |
154 | basename = paste.debian.net |
155 | -regexp = http://paste.debian.net |
156 | +id_regexp = https?://paste.debian.net |
157 | |
158 | [format] |
159 | user = poster |
160 | |
161 | === modified file 'pastebin.d/paste.drizzle.org.conf' |
162 | --- pastebin.d/paste.drizzle.org.conf 2012-06-13 16:41:21 +0000 |
163 | +++ pastebin.d/paste.drizzle.org.conf 2014-12-07 21:54:13 +0000 |
164 | @@ -1,18 +1,15 @@ |
165 | [pastebin] |
166 | basename = paste.drizzle.org |
167 | -regexp = http://paste.drizzle.org |
168 | +id_regexp = http://paste.drizzle.org |
169 | +target_url = http://paste.drizzle.org/show/ |
170 | +result_type = id |
171 | +result_regexp = \"data\": \"([^"]*) |
172 | +post_format = json |
173 | +page = /json/?method=pastes.newPaste |
174 | |
175 | [format] |
176 | lang = language |
177 | -page = page |
178 | content = code |
179 | -post_format = post_format |
180 | -regexp = regexp |
181 | -target_url = target_url |
182 | |
183 | [defaults] |
184 | -page = /json/?method=pastes.newPaste |
185 | -post_format = json |
186 | lang = |
187 | -regexp = \"data\": \"([^"]*) |
188 | -target_url = http://paste.drizzle.org/show/ |
189 | |
190 | === modified file 'pastebin.d/paste.kde.org.conf' |
191 | --- pastebin.d/paste.kde.org.conf 2012-06-13 16:41:21 +0000 |
192 | +++ pastebin.d/paste.kde.org.conf 2014-12-07 21:54:13 +0000 |
193 | @@ -1,22 +1,18 @@ |
194 | [pastebin] |
195 | basename = paste.kde.org |
196 | -regexp = http://paste.kde.org |
197 | +id_regexp = http://paste.kde.org |
198 | +result_type = id |
199 | +result_regexp = <id>(.*)</id> |
200 | +page = /api/xml/create |
201 | |
202 | [format] |
203 | -user = paste_user |
204 | -format = paste_lang |
205 | -content = paste_data |
206 | -password = paste_password |
207 | -expire = paste_expire |
208 | -private = paste_private |
209 | -api = api_submit |
210 | -mode = mode |
211 | -regexp = regexp |
212 | +format = language |
213 | +content = data |
214 | +expire = expire |
215 | +private = private |
216 | +title = title |
217 | +password = password |
218 | |
219 | [defaults] |
220 | -private = 0 |
221 | format = text |
222 | expire = 86400 |
223 | -api = 1 |
224 | -mode = xml |
225 | -regexp = <id>(.*)</id> |
226 | |
227 | === modified file 'pastebin.d/paste.openstack.org.conf' |
228 | --- pastebin.d/paste.openstack.org.conf 2012-06-13 17:15:59 +0000 |
229 | +++ pastebin.d/paste.openstack.org.conf 2014-12-07 21:54:13 +0000 |
230 | @@ -1,18 +1,15 @@ |
231 | [pastebin] |
232 | basename = paste.openstack.org |
233 | -regexp = http://paste.openstack.org |
234 | +id_regexp = http://paste.openstack.org |
235 | +result_type = id |
236 | +result_regexp = \"data\": \"([^"]*) |
237 | +target_url = http://paste.openstack.org/show/ |
238 | +post_format = json |
239 | +page = /json/?method=pastes.newPaste |
240 | |
241 | [format] |
242 | lang = language |
243 | -page = page |
244 | content = code |
245 | -post_format = post_format |
246 | -regexp = regexp |
247 | -target_url = target_url |
248 | |
249 | [defaults] |
250 | -page = /json/?method=pastes.newPaste |
251 | -post_format = json |
252 | lang = |
253 | -regexp = \"data\": \"([^"]*) |
254 | -target_url = http://paste.openstack.org/show/ |
255 | |
256 | === modified file 'pastebin.d/paste.pound-python.org.conf' |
257 | --- pastebin.d/paste.pound-python.org.conf 2012-06-13 16:41:21 +0000 |
258 | +++ pastebin.d/paste.pound-python.org.conf 2014-12-07 21:54:13 +0000 |
259 | @@ -1,6 +1,6 @@ |
260 | [pastebin] |
261 | basename = paste.pound-python.org |
262 | -regexp = http://paste.pound-python.org |
263 | +id_regexp = http://paste.pound-python.org |
264 | |
265 | [format] |
266 | content = code |
267 | |
268 | === modified file 'pastebin.d/paste.ubuntu.com.conf' |
269 | --- pastebin.d/paste.ubuntu.com.conf 2012-06-13 16:41:21 +0000 |
270 | +++ pastebin.d/paste.ubuntu.com.conf 2014-12-07 21:54:13 +0000 |
271 | @@ -1,6 +1,6 @@ |
272 | [pastebin] |
273 | basename = paste.ubuntu.com |
274 | -regexp = http://paste.ubuntu.com |
275 | +id_regexp = http://paste.ubuntu.com |
276 | |
277 | [format] |
278 | user = poster |
279 | |
280 | === modified file 'pastebin.d/paste.ubuntu.org.cn.conf' |
281 | --- pastebin.d/paste.ubuntu.org.cn.conf 2012-06-13 16:41:21 +0000 |
282 | +++ pastebin.d/paste.ubuntu.org.cn.conf 2014-12-07 21:54:13 +0000 |
283 | @@ -1,6 +1,6 @@ |
284 | [pastebin] |
285 | basename = paste.ubuntu.org.cn |
286 | -regexp = http://paste.ubuntu.org.cn |
287 | +id_regexp = http://paste.ubuntu.org.cn |
288 | |
289 | [format] |
290 | user = poster |
291 | |
292 | === modified file 'pastebin.d/paste2.org.conf' |
293 | --- pastebin.d/paste2.org.conf 2014-01-06 23:16:01 +0000 |
294 | +++ pastebin.d/paste2.org.conf 2014-12-07 21:54:13 +0000 |
295 | @@ -1,6 +1,6 @@ |
296 | [pastebin] |
297 | basename = paste2.org |
298 | -regexp = http://paste2.org |
299 | +id_regexp = http://paste2.org |
300 | |
301 | [format] |
302 | title = description |
303 | |
304 | === modified file 'pastebin.d/pastebin.com.conf' |
305 | --- pastebin.d/pastebin.com.conf 2012-06-13 17:15:59 +0000 |
306 | +++ pastebin.d/pastebin.com.conf 2014-12-07 21:54:13 +0000 |
307 | @@ -1,6 +1,9 @@ |
308 | [pastebin] |
309 | basename = pastebin.com |
310 | -regexp = http://((([a-zA-Z0-9\-_\.]*)(pastebin\.com))) |
311 | +id_regexp = http://((([a-zA-Z0-9\-_\.]*)(pastebin\.com))) |
312 | +result_type = url |
313 | +result_regexp = (.*) |
314 | +page = /api/api_post.php |
315 | |
316 | [format] |
317 | content = api_paste_code |
318 | @@ -10,9 +13,7 @@ |
319 | expiry = api_paste_expire_date |
320 | format = api_paste_format |
321 | email = api_paste_email |
322 | -page = page |
323 | submit = submit |
324 | -regexp = regexp |
325 | api_dev_key = api_dev_key |
326 | api_option = api_option |
327 | |
328 | @@ -25,5 +26,3 @@ |
329 | email = |
330 | api_dev_key = 253ce2f0a45140ee0a44ca99aa492260 |
331 | api_option = paste |
332 | -page = /api/api_post.php |
333 | -regexp = (.*) |
334 | |
335 | === modified file 'pastebin.d/pastebin.mate-desktop.org.conf' |
336 | --- pastebin.d/pastebin.mate-desktop.org.conf 2014-01-06 20:40:29 +0000 |
337 | +++ pastebin.d/pastebin.mate-desktop.org.conf 2014-12-07 21:54:13 +0000 |
338 | @@ -1,14 +1,12 @@ |
339 | [pastebin] |
340 | basename = pastebin.mate-desktop.org |
341 | -regexp = http://pastebin.mate-desktop.org |
342 | +page = /api/json/create |
343 | +id_regexp = http://pastebin.mate-desktop.org |
344 | +result_type = id |
345 | +result_regexp = "id": "([^"]*)" |
346 | +post_format = json |
347 | |
348 | [format] |
349 | -content = text |
350 | +content = data |
351 | user = name |
352 | -format = lang |
353 | -page = page |
354 | -regexp = regexp |
355 | - |
356 | -[defaults] |
357 | -page = /api/create |
358 | -regexp = (.*) |
359 | +format = language |
360 | |
361 | === modified file 'pastebin.d/pb.daviey.com.conf' |
362 | --- pastebin.d/pb.daviey.com.conf 2012-06-13 17:15:59 +0000 |
363 | +++ pastebin.d/pb.daviey.com.conf 2014-12-07 21:54:13 +0000 |
364 | @@ -1,16 +1,15 @@ |
365 | [pastebin] |
366 | basename = pb.daviey.com |
367 | -regexp = http://pb.daviey.com |
368 | +id_regexp = http://pb.daviey.com |
369 | +result_regexp = "/(.*/)".* |
370 | +result_type = id |
371 | +page = api/?_call=new |
372 | |
373 | [format] |
374 | user = author |
375 | content = content |
376 | -page = page |
377 | expire_options = expires |
378 | title = title |
379 | -regexp = regexp |
380 | |
381 | [defaults] |
382 | -page = api/?_call=new |
383 | -regexp = "/(.*/)".* |
384 | expire_options = 7889232 |
385 | |
386 | === modified file 'pastebin.d/slexy.org.conf' |
387 | --- pastebin.d/slexy.org.conf 2012-06-13 17:15:59 +0000 |
388 | +++ pastebin.d/slexy.org.conf 2014-12-07 21:54:13 +0000 |
389 | @@ -1,12 +1,12 @@ |
390 | [pastebin] |
391 | basename = slexy.org |
392 | -regexp = http://slexy.org |
393 | +id_regexp = http://slexy.org |
394 | +page = /index.php/submit |
395 | |
396 | [format] |
397 | user = author |
398 | content = raw_paste |
399 | title = desc |
400 | -page = page |
401 | language = language |
402 | permissions = permissions |
403 | linenumbers = linenumbers |
404 | @@ -16,7 +16,6 @@ |
405 | |
406 | [defaults] |
407 | submit = Submit Paste |
408 | -page = /index.php/submit |
409 | language = text |
410 | permissions = 0 |
411 | comment = |
412 | |
413 | === modified file 'pastebin.d/sprunge.us.conf' |
414 | --- pastebin.d/sprunge.us.conf 2012-06-13 16:41:21 +0000 |
415 | +++ pastebin.d/sprunge.us.conf 2014-12-07 21:54:13 +0000 |
416 | @@ -1,11 +1,9 @@ |
417 | [pastebin] |
418 | basename = sprunge.us |
419 | -regexp = http://sprunge.us |
420 | +id_regexp = http://sprunge.us |
421 | +result_regexp=http://sprunge.us/(.*)$ |
422 | +result_type = id |
423 | |
424 | [format] |
425 | content = sprunge |
426 | format = lang |
427 | -regexp = regexp |
428 | - |
429 | -[defaults] |
430 | -regexp=http://sprunge.us/(.*)$ |
431 | |
432 | === modified file 'pastebinit' |
433 | --- pastebinit 2014-01-18 04:51:35 +0000 |
434 | +++ pastebinit 2014-12-07 21:54:13 +0000 |
435 | @@ -4,7 +4,7 @@ |
436 | # Author: Stéphane Graber <stgraber@ubuntu.com> |
437 | # Written by Stéphane Graber <stgraber@stgraber.org> |
438 | # Daniel Bartlett <dan@f-box.org> |
439 | -# Last modification : Mon Jan 6 18:46:46 EST 2014 |
440 | +# Last modification : Mon Nov 24 15:07:45 EST 2014 |
441 | |
442 | # This program is free software; you can redistribute it and/or modify |
443 | # it under the terms of the GNU General Public License as published by |
444 | @@ -23,224 +23,52 @@ |
445 | from __future__ import print_function |
446 | |
447 | import sys |
448 | +import os |
449 | +import re |
450 | +import getopt |
451 | +import gettext |
452 | +import socket |
453 | +import xml.dom.minidom |
454 | + |
455 | if sys.version[0] == "2": |
456 | - from ConfigParser import SafeConfigParser |
457 | + from ConfigParser import SafeConfigParser, NoOptionError, NoSectionError |
458 | from urllib import urlencode |
459 | from urllib import FancyURLopener |
460 | else: |
461 | - from configparser import SafeConfigParser |
462 | + #SafeConfigParser is now a deprecated alias to ConfigParser |
463 | + from configparser import \ |
464 | + ConfigParser as SafeConfigParser, NoOptionError, NoSectionError |
465 | from urllib.parse import urlencode |
466 | from urllib.request import FancyURLopener |
467 | |
468 | -# Set the default pastebin |
469 | -defaultPB = "http://pastebin.com" |
470 | - |
471 | -# Now try to override it with a distributor pastebin |
472 | -try: |
473 | - import lsb_release |
474 | - release = lsb_release.get_distro_information()['ID'].lower() |
475 | - if release == 'debian': |
476 | - defaultPB = "http://paste.debian.net" |
477 | - elif release == 'fedora': |
478 | - defaultPB = "http://fpaste.org" |
479 | - elif release == 'ubuntu': |
480 | - defaultPB = "http://paste.ubuntu.com" |
481 | -except ImportError: |
482 | - pass |
483 | - |
484 | -try: |
485 | - import getopt |
486 | - import gettext |
487 | - import os |
488 | - import re |
489 | - import socket |
490 | - import xml.dom.minidom |
491 | - |
492 | - try: |
493 | - import json |
494 | - except ImportError: |
495 | - json = None |
496 | - |
497 | - _ = gettext.gettext |
498 | - gettext.textdomain("pastebinit") |
499 | - |
500 | - # Timeout after 5s |
501 | - socket.setdefaulttimeout(5) |
502 | - |
503 | - # Version number to show in the usage |
504 | - version = "1.4.1" |
505 | - configfile = os.path.expanduser("~/.pastebinit.xml") |
506 | - |
507 | - # Custom urlopener to handle 401's |
508 | - class pasteURLopener(FancyURLopener): |
509 | - version = "Pastebinit v%s" % version |
510 | - |
511 | - def http_error_401(self, url, fp, errcode, errmsg, headers, data=None): |
512 | - return None |
513 | - |
514 | - def preloadPastebins(): |
515 | - # Check several places for config files: |
516 | - # - global config in /etc/pastebin.d |
517 | - # - for source checkout, config in the checkout |
518 | - # - user's overrides in ~/.pastebin.d |
519 | - # Files found later override files found earlier. |
520 | - pastebind = {} |
521 | - for confdir in ['/usr/share/pastebin.d', '/etc/pastebin.d', |
522 | - '/usr/local/etc/pastebin.d', |
523 | - os.path.expanduser('~/.pastebin.d'), |
524 | - os.path.join( |
525 | - os.path.dirname( |
526 | - os.path.realpath(__file__)), 'pastebin.d')]: |
527 | - try: |
528 | - confdirlist = os.listdir(confdir) |
529 | - except OSError: |
530 | - continue |
531 | - |
532 | - for fileitem in confdirlist: |
533 | - if fileitem.startswith('.') or not fileitem.endswith('.conf'): |
534 | - continue |
535 | - |
536 | - filename = os.path.join(confdir, fileitem) |
537 | - instance = SafeConfigParser() |
538 | - try: |
539 | - instance.read(filename) |
540 | - except UnicodeError: |
541 | - continue |
542 | - |
543 | - if not instance.has_section('pastebin'): |
544 | - print(_('%s: no section [pastebin]') % filename, |
545 | - file=sys.stderr) |
546 | - continue |
547 | - |
548 | - if not instance.has_option('pastebin', 'basename'): |
549 | - print(_("%s: no 'basename' in [pastebin]") % filename, |
550 | - file=sys.stderr) |
551 | - continue |
552 | - |
553 | - pastebind[instance.get('pastebin', 'basename')] = instance |
554 | - return pastebind |
555 | - |
556 | - # pastey.net obfuscates parent ids for replies. Rather than taking the |
557 | - # post ID given as the parent ID, we must handle this by going to that |
558 | - # post page and looking up what the invisible parent ID field will be |
559 | - # set to for children. |
560 | - def doParentFixup(website, paramname, parentid): |
561 | - if parentid == "": |
562 | - return "" |
563 | - url_opener = pasteURLopener() |
564 | - page = url_opener.open(website + '/' + parentid, None) |
565 | - matches = re.split('<input.*?name="' + paramname + '".*?value="(.*?)"', |
566 | - page.read()) |
567 | - if len(matches) <= 1 or re.match(parentid, matches[1]) is None: |
568 | - # The obfuscated version didn't begin with the partial version, |
569 | - # or unable to find the obfuscated version for some reason! |
570 | - # Create a paste with no parent (should we throw, instead?) |
571 | - return "" |
572 | - return matches[1] |
573 | - |
574 | - #Return the parameters depending of the pastebin used |
575 | - def getParameters(website, pastebind, content, user, jabberid, version, |
576 | - format, parentpid, permatag, title, username, |
577 | - password): |
578 | - "Return the parameters array for the selected pastebin" |
579 | - params = {} |
580 | - for paste_name, paste_config in pastebind.items(): |
581 | - basename = paste_config.get('pastebin', 'basename') |
582 | - if basename == website or paste_name == website: |
583 | - website = "http://%s" % basename |
584 | - |
585 | - if re.search(paste_config.get('pastebin', 'regexp'), website): |
586 | - if paste_config.has_option('pastebin', 'sizelimit'): |
587 | - params['sizelimit'] = paste_config.get('pastebin', |
588 | - 'sizelimit') |
589 | - |
590 | - for param in paste_config.options('format'): |
591 | - paramname = paste_config.get('format', param) |
592 | - if param == 'user': |
593 | - params[paramname] = user |
594 | - elif param == 'content': |
595 | - params[paramname] = content |
596 | - elif param == 'title': |
597 | - params[paramname] = title |
598 | - elif param == 'version': |
599 | - params[paramname] = version |
600 | - elif param == 'format': |
601 | - params[paramname] = format |
602 | - elif param == 'parentpid': |
603 | - params[paramname] = doParentFixup(website, paramname, |
604 | - parentpid) |
605 | - elif param == 'permatag': |
606 | - params[paramname] = permatag |
607 | - elif param == 'username': |
608 | - params[paramname] = username |
609 | - elif param == 'password': |
610 | - params[paramname] = password |
611 | - elif param == 'jabberid': |
612 | - params[paramname] = jabberid |
613 | - else: |
614 | - params[paramname] = paste_config.get('defaults', param) |
615 | - if params: |
616 | - return website, params |
617 | - else: |
618 | - print(_("Unknown website, please post a bugreport to request " |
619 | - "this pastebin to be added (%s)") % website, |
620 | - file=sys.stderr) |
621 | - sys.exit(1) |
622 | - |
623 | - #XML Handling methods |
624 | - def getText(nodelist): |
625 | - rc = "" |
626 | - for node in nodelist: |
627 | - if node.nodeType == node.TEXT_NODE: |
628 | - rc = rc + node.data |
629 | - return rc |
630 | - |
631 | - def getNodes(nodes, title): |
632 | - return nodes.getElementsByTagName(title) |
633 | - |
634 | - def getFirstNode(nodes, title): |
635 | - return getNodes(nodes, title)[0] |
636 | - |
637 | - def getFirstNodeText(nodes, title): |
638 | - return getText(getFirstNode(nodes, title).childNodes) |
639 | - |
640 | - # Display usage instructions |
641 | - def Usage(fd=sys.stdout): |
642 | - print("pastebinit v" + version, file=fd) |
643 | - print(_("Reads on stdin for input or takes a list of filenames " |
644 | - "as parameters"), file=fd) |
645 | - print(_("Optional arguments (not supported by all pastebins):"), |
646 | - file=fd) |
647 | - print(_("\t-a <author:default is '%s'>") % user, file=fd) |
648 | - print(_("\t-b <pastebin url:default is '%s'>") % website, file=fd) |
649 | - print(_("\t-f <format of paste:default is '%s'>") % format, file=fd) |
650 | - print(_("\t-h This help screen"), file=fd) |
651 | - print(_("\t-i <input file>"), file=fd) |
652 | - print(_("\t-l List all supported pastebins"), file=fd) |
653 | - print(_("\t-j <jabberid for notifications:default is '%s'>") % |
654 | - jabberid, file=fd) |
655 | - print(_("\t-m <permatag for all versions of a post:default is blank>"), |
656 | - file=fd) |
657 | - print(_("\t-r <parent posts ID:defaults to none>"), file=fd) |
658 | - print(_("\t-t <title of paste:default is blank>"), file=fd) |
659 | - print(_("\t-u <username> -p <password>"), file=fd) |
660 | - print(_("\t-v Print the version number"), file=fd) |
661 | - |
662 | - # Set defaults |
663 | - website = defaultPB |
664 | - user = os.environ.get('USER') |
665 | - jabberid = "" |
666 | - title = "" |
667 | - permatag = "" |
668 | - format = "text" |
669 | - username = "" |
670 | - password = "" |
671 | - filenames = [] |
672 | - content = "" |
673 | - parentpid = "" |
674 | - |
675 | - #Example configuration file string |
676 | - configexample = """\ |
677 | +try: |
678 | + import gnupg |
679 | +except ImportError: |
680 | + gnupg = None |
681 | + |
682 | +try: |
683 | + import json |
684 | +except ImportError: |
685 | + json = None |
686 | + |
687 | +#Enables input redirection during tests |
688 | +stdin = sys.stdin |
689 | +stderr = sys.stderr |
690 | +stdout = sys.stdout |
691 | + |
692 | +_ = gettext.gettext |
693 | +gettext.textdomain("pastebinit") |
694 | + |
695 | +# Timeout after 5s |
696 | +socket.setdefaulttimeout(5) |
697 | + |
698 | +# Version number to show in the usage |
699 | +version = "1.4.1" |
700 | +config_path = os.path.expanduser("~/.pastebinit.xml") |
701 | +verbose = False |
702 | + |
703 | +#Example configuration file string |
704 | +config_example = """\ |
705 | <pastebinit> |
706 | <pastebin>http://paste.debian.net</pastebin> |
707 | <author>A pastebinit user</author> |
708 | @@ -249,201 +77,508 @@ |
709 | </pastebinit> |
710 | """ |
711 | |
712 | - #Open configuration file if it exists |
713 | - try: |
714 | - f = open(configfile) |
715 | - configtext = f.read() |
716 | + |
717 | +def get_default_pastebin(): |
718 | + default = "http://pastebin.com" |
719 | + try: |
720 | + import lsb_release |
721 | + return { |
722 | + 'debian': "http://paste.debian.net", |
723 | + 'fedora': "http://fpaste.org", |
724 | + 'ubuntu': "http://paste.ubuntu.com", |
725 | + }[lsb_release.get_distro_information()['ID'].lower()] |
726 | + except KeyError: |
727 | + return default |
728 | + except ImportError: |
729 | + return default |
730 | + |
731 | + |
732 | +defaults = { |
733 | + 'gpg_sign': False, |
734 | + 'gpg_encrypt': False, |
735 | + 'gpg_recipients': '', |
736 | + 'gpg_dir': os.path.expanduser("~/.gnupg"), |
737 | + 'gpg_key': None, |
738 | + 'website': get_default_pastebin(), |
739 | + 'user': os.environ.get('USER'), |
740 | + 'format': "text", |
741 | + 'jabberid': "", |
742 | + 'title': "", |
743 | + 'permatag': "", |
744 | + 'username': "", |
745 | + 'password': "", |
746 | + 'review': False, |
747 | + 'parentpid': "", |
748 | + 'verbose': False, |
749 | +} |
750 | + |
751 | + |
752 | +class PasteURLopener(FancyURLopener): |
753 | + """Custom urlopener to handle 401's""" |
754 | + version = "Pastebinit v%s" % version |
755 | + |
756 | + def __init__(self, settings): |
757 | + self.settings = settings |
758 | + FancyURLopener.__init__(self) |
759 | + |
760 | + def http_error_401(self, url, fp, errcode, errmsg, headers, data=None): |
761 | + return None |
762 | + |
763 | + def format_params(self, params): |
764 | + if self.settings.get('format', '') == 'json': |
765 | + if not json: |
766 | + print(_("Could not find any json library."), file=stderr) |
767 | + sys.exit(1) |
768 | + return json.dumps(params) |
769 | + else: |
770 | + return urlencode(params) |
771 | + |
772 | + def make_request(self, url, params): |
773 | + post_params = self.format_params(params) |
774 | + |
775 | + if self.settings.get('format', '') == 'json': |
776 | + self.addheader('Content-type', 'text/json') |
777 | + |
778 | + if self.settings.get('verbose', False): |
779 | + print("POSTing to: %s" % url, file=stderr) |
780 | + print("\nParams: %s" % str(post_params), file=stderr) |
781 | + |
782 | + try: |
783 | + return self.open(url, post_params) |
784 | + except KeyboardInterrupt: |
785 | + print(_("KeyboardInterrupt caught."), file=stderr) |
786 | + sys.exit(1) |
787 | + except Exception as e: |
788 | + print(_("Failed to contact the server: %s") % e, file=stderr) |
789 | + sys.exit(1) |
790 | + |
791 | + |
792 | +def usage(fd): |
793 | + print("pastebinit v" + version, file=fd) |
794 | + print(_("Reads on stdin for input or takes a list of filenames " |
795 | + "as parameters"), file=fd) |
796 | + print(_("Optional arguments (not supported by all pastebins):"), file=fd) |
797 | + print(_("\t-a <author:default is '%s'>") % defaults['user'], file=fd) |
798 | + print(_("\t-b <pastebin url:default is '%s'>") % defaults['website'], |
799 | + file=fd) |
800 | + print(_("\t-f <format of paste:default is '%s' " |
801 | + "(or from pastebin config)>") % defaults['format'], file=fd) |
802 | + print(_("\t-h This help screen"), file=fd) |
803 | + print(_("\t-i <input file>" |
804 | + "This may be used multiple times (-i file1 -i file2)"), file=fd) |
805 | + print(_("\t-l List all supported pastebins"), file=fd) |
806 | + print(_("\t-j <jabberid for notifications:default is '%s'>") % |
807 | + defaults['jabberid'], file=fd) |
808 | + print(_("\t-m <permatag for all versions of a post:default is blank>"), |
809 | + file=fd) |
810 | + print(_("\t-R Review before pasting"), file=fd) |
811 | + print(_("\t-r <parent posts ID:defaults to none>"), file=fd) |
812 | + print(_("\t-t <title of paste:default is blank>"), file=fd) |
813 | + print(_("\t-u <username> -p <password>"), file=fd) |
814 | + print(_("\t-v Print the version number"), file=fd) |
815 | + print(_("\t--verbose Verbose output to stderr"), file=fd) |
816 | + |
817 | + print(_("Encryption (In case you don't just pipe through gpg)"), file=fd) |
818 | + print(_("\t-e <recipient> " |
819 | + "Encrypt the pasted content for the given recipient. " |
820 | + "This may be used multiple times (-e recip1 -e recipt2)"), file=fd) |
821 | + print(_("\t-s Sign the pasted content"), file=fd) |
822 | + print(_("\t-G <GPG home directory:default is %s>" % defaults['gpg_dir']), |
823 | + file=fd) |
824 | + print(_("\t-g <GPG key id:default is %s> " |
825 | + "This can be an email address or a name." |
826 | + "Supply -R to confirm the key." % defaults['gpg_key']), file=fd) |
827 | + |
828 | + |
829 | +def preloadPastebins(): |
830 | + """ |
831 | + Check several places for config files: |
832 | + - global config in /etc/pastebin.d |
833 | + - for source checkout, config in the checkout |
834 | + - user's overrides in ~/.pastebin.d |
835 | + Files found later override files found earlier. |
836 | + """ |
837 | + pastebind = {} |
838 | + for confdir in ['/usr/share/pastebin.d', |
839 | + '/etc/pastebin.d', |
840 | + '/usr/local/etc/pastebin.d', |
841 | + os.path.expanduser('~/.pastebin.d'), |
842 | + os.path.join( |
843 | + os.path.dirname(os.path.realpath(__file__)), |
844 | + 'pastebin.d'), |
845 | + ]: |
846 | + try: |
847 | + confdirfiles = [ |
848 | + os.path.join(confdir, x) for x in os.listdir(confdir) |
849 | + if x.endswith('.conf') and not x.startswith('.') |
850 | + ] |
851 | + except OSError: |
852 | + continue |
853 | + |
854 | + for fname in confdirfiles: |
855 | + parser = SafeConfigParser() |
856 | + try: |
857 | + parser.read(fname) |
858 | + except UnicodeError: |
859 | + print(_('%s: Unicode Error') % fname, file=stderr) |
860 | + continue |
861 | + |
862 | + if not parser.has_section('pastebin'): |
863 | + print(_('%s: no section [pastebin]') % fname, file=stderr) |
864 | + continue |
865 | + |
866 | + if not parser.has_option('pastebin', 'basename'): |
867 | + print(_("%s: no 'basename' in [pastebin]") % fname, file=stderr) |
868 | + continue |
869 | + |
870 | + pastebind[parser.get('pastebin', 'basename')] = parser |
871 | + return pastebind |
872 | + |
873 | + |
874 | +def doParentFixup(paramname, settings): |
875 | + """ |
876 | + pastey.net obfuscates parent ids for replies. Rather than taking the |
877 | + post ID given as the parent ID, we must handle this by going to that |
878 | + post page and looking up what the invisible parent ID field will be |
879 | + set to for children. |
880 | + """ |
881 | + website = settings['website'] |
882 | + parentid = settings['parentid'] |
883 | + if not parentid: |
884 | + return "" |
885 | + if not website.endswith("/"): |
886 | + website += "/" |
887 | + matches = re.split( |
888 | + '<input.*?name="' + paramname + '".*?value="(.*?)"', |
889 | + PasteURLopener(settings.get('post_format', '')).open( |
890 | + website + parentid.lstrip('/'), None).read() |
891 | + ) |
892 | + if len(matches) <= 1 or re.match(parentid, matches[1]) is None: |
893 | + # The obfuscated version didn't begin with the partial version, |
894 | + # or unable to find the obfuscated version for some reason! |
895 | + # Create a paste with no parent (should we throw, instead?) |
896 | + return "" |
897 | + return matches[1] |
898 | + |
899 | + |
900 | +def getPasteConfig(website): |
901 | + for paste_name, paste_config in preloadPastebins().items(): |
902 | + basename = paste_config.get('pastebin', 'basename') |
903 | + if basename == website or paste_name == website: |
904 | + website = "http://%s" % basename |
905 | + if re.search(paste_config.get('pastebin', 'id_regexp'), website): |
906 | + if not website.endswith("/"): |
907 | + website += "/" |
908 | + return paste_config, website |
909 | + |
910 | + print(_("Unknown website, please post a bugreport to request this " |
911 | + "pastebin to be added (%s)") % website, |
912 | + file=stderr) |
913 | + sys.exit(1) |
914 | + |
915 | + |
916 | +def readPasteConfig(paste_config, settings): |
917 | + """Return the parameters array for the selected pastebin""" |
918 | + |
919 | + for param in paste_config.options('pastebin'): |
920 | + settings[param] = paste_config.get('pastebin', param) |
921 | + |
922 | + post_params = {} |
923 | + for param in paste_config.options('format'): |
924 | + paramname = paste_config.get('format', param) |
925 | + |
926 | + if param == 'content': |
927 | + pass |
928 | + elif param == 'parentpid': |
929 | + post_params[paramname] = doParentFixup(paramname, settings) |
930 | + else: |
931 | + try: |
932 | + post_params[paramname] = paste_config.get('defaults', param) |
933 | + except NoOptionError: |
934 | + pass |
935 | + except NoSectionError: |
936 | + pass |
937 | + |
938 | + try: |
939 | + post_params[paramname] = settings[param] |
940 | + except KeyError: |
941 | + pass |
942 | + |
943 | + return post_params |
944 | + |
945 | + |
946 | +def getText(parent_node): |
947 | + """Read the text from an XML node""" |
948 | + rc = "" |
949 | + for node in parent_node.childNodes: |
950 | + if node.nodeType == node.TEXT_NODE: |
951 | + rc += node.data |
952 | + else: |
953 | + rc += getText(node) |
954 | + return rc |
955 | + |
956 | + |
957 | +def readFile(location, mode="r"): |
958 | + f = open(location, mode) |
959 | + try: |
960 | + return f.read() |
961 | + except KeyboardInterrupt: |
962 | + print(_("KeyboardInterrupt caught."), file=stderr) |
963 | + sys.exit(1) |
964 | + except: |
965 | + print(_("Unable to read from: %s") % location, file=stderr) |
966 | + sys.exit(1) |
967 | + finally: |
968 | f.close() |
969 | - gotconfigxml = True |
970 | + |
971 | + |
972 | +def readConfigFile(config_text): |
973 | + """Update settings from config XML""" |
974 | + try: |
975 | + settings = {} |
976 | + configxml = xml.dom.minidom.parseString(config_text) |
977 | + for xml_var, setting in (('pastebin', 'website'), |
978 | + ('author', 'user'), |
979 | + ('format', 'format'), |
980 | + ('jabberid', 'jabberid')): |
981 | + try: |
982 | + settings[setting] = getText( |
983 | + configxml.getElementsByTagName(xml_var)[0]) |
984 | + except IndexError: |
985 | + pass |
986 | + return settings |
987 | except KeyboardInterrupt: |
988 | - print(_("KeyboardInterrupt caught."), file=sys.stderr) |
989 | + print(_("KeyboardInterrupt caught."), file=stderr) |
990 | sys.exit(1) |
991 | except: |
992 | - gotconfigxml = False |
993 | - |
994 | - #Parse configuration file |
995 | - if gotconfigxml: |
996 | + print(_("Error parsing configuration file!"), file=stderr) |
997 | + print(_("Please ensure that your configuration file looks " |
998 | + "similar to the following:"), file=stderr) |
999 | + print(config_example, file=stderr) |
1000 | + sys.exit(1) |
1001 | + |
1002 | + |
1003 | +def getOpts(args=sys.argv[1:]): |
1004 | + try: |
1005 | + optlist, arglist = getopt.getopt( |
1006 | + args, 'sRhvli:e:G:g:f:b:a:r:j:t:m:u:p:', ('verbose',)) |
1007 | + except getopt.GetoptError as e: |
1008 | + print(_("Invalid arguments: %s!" % e) + "\n", file=stderr) |
1009 | + usage(stderr) |
1010 | + sys.exit(1) |
1011 | + opts = dict(optlist) |
1012 | + opts['-e'] = [opt[1] for opt in optlist if opt[0] == "-e"] |
1013 | + opts['-i'] = [opt[1] for opt in optlist if opt[0] == "-i"] + arglist |
1014 | + return opts |
1015 | + |
1016 | + |
1017 | +def readOptions(opts): |
1018 | + settings = {} |
1019 | + |
1020 | + # Die if support information is requested |
1021 | + if "-h" in opts: |
1022 | + usage(stdout) |
1023 | + sys.exit(0) |
1024 | + if "-v" in opts: |
1025 | + print("pastebinit v" + version, file=stdout) |
1026 | + sys.exit(0) |
1027 | + if "-l" in opts: |
1028 | + print(_("Supported pastebins:"), file=stdout) |
1029 | + for pastebin in sorted(preloadPastebins()): |
1030 | + print("- %s" % pastebin, file=stdout) |
1031 | + sys.exit(0) |
1032 | + |
1033 | + # Configure the environment |
1034 | + def setFromOpt(opt, label): |
1035 | try: |
1036 | - configxml = xml.dom.minidom.parseString(configtext) |
1037 | - for variable, key in (('pastebin', 'website'), ('author', 'user'), |
1038 | - ('format', 'format'), |
1039 | - ('jabberid', 'jabberid')): |
1040 | - try: |
1041 | - value = getFirstNodeText(configxml, variable) |
1042 | - vars()[key] = value |
1043 | - except: |
1044 | - pass |
1045 | - except KeyboardInterrupt: |
1046 | - print(_("KeyboardInterrupt caught."), file=sys.stderr) |
1047 | - sys.exit(1) |
1048 | - except: |
1049 | - print(_("Error parsing configuration file!"), file=sys.stderr) |
1050 | - print(_("Please ensure that your configuration file looks " |
1051 | - "similar to the following:"), file=sys.stderr) |
1052 | - print(configexample, file=sys.stderr) |
1053 | - sys.exit(1) |
1054 | - |
1055 | - # Get options |
1056 | - try: |
1057 | - optlist, arglist = getopt.getopt(sys.argv[1:], |
1058 | - 'hvli:f:b:a:r:j:t:m:u:p:') |
1059 | - except KeyboardInterrupt: |
1060 | - print(_("KeyboardInterrupt caught."), file=sys.stderr) |
1061 | - sys.exit(1) |
1062 | - except getopt.GetoptError: |
1063 | - print(_("Invalid arguments!\n"), file=sys.stderr) |
1064 | - Usage(sys.stderr) |
1065 | - sys.exit(1) |
1066 | - |
1067 | - # Get the config |
1068 | - pastebind = preloadPastebins() |
1069 | - |
1070 | - # Iterate through options |
1071 | - for opt in optlist: |
1072 | - if opt[0] == "-h": |
1073 | - Usage() |
1074 | - sys.exit(0) |
1075 | - if opt[0] == "-i": |
1076 | - filenames.append(opt[1]) |
1077 | - elif opt[0] == "-f": |
1078 | - format = opt[1] |
1079 | - elif opt[0] == "-b": |
1080 | - website = opt[1] |
1081 | - elif opt[0] == "-a": |
1082 | - user = opt[1] |
1083 | - elif opt[0] == "-r": |
1084 | - parentpid = opt[1] |
1085 | - elif opt[0] == "-j": |
1086 | - jabberid = opt[1] |
1087 | - elif opt[0] == "-l": |
1088 | - print(_("Supported pastebins:")) |
1089 | - for pastebin in sorted(pastebind): |
1090 | - print("- %s" % pastebin) |
1091 | - sys.exit(0) |
1092 | - elif opt[0] == "-t": |
1093 | - title = opt[1] |
1094 | - elif opt[0] == "-m": |
1095 | - permatag = opt[1] |
1096 | - elif opt[0] == "-u": |
1097 | - username = opt[1] |
1098 | - elif opt[0] == "-p": |
1099 | - password = opt[1] |
1100 | - elif opt[0] == "-v": |
1101 | - print("pastebinit v" + version) |
1102 | - sys.exit(0) |
1103 | - |
1104 | - filenames += arglist |
1105 | - |
1106 | - if not filenames: |
1107 | - filenames.append("-") |
1108 | - |
1109 | - contents = [] |
1110 | - for filename in filenames: |
1111 | - # If - is specified as a filename read from stdin |
1112 | - # otherwise load the specified files. |
1113 | - if filename == "-": |
1114 | - content = sys.stdin.read() |
1115 | + settings[label] = opts[opt] |
1116 | + except KeyError: |
1117 | + pass |
1118 | + |
1119 | + setFromOpt('-b', 'website') |
1120 | + setFromOpt('-a', 'user') |
1121 | + setFromOpt('-f', 'format') |
1122 | + setFromOpt('-j', 'jabberid') |
1123 | + setFromOpt('-t', 'title') |
1124 | + setFromOpt('-m', 'permatag') |
1125 | + setFromOpt('-u', 'username') |
1126 | + setFromOpt('-p', 'password') |
1127 | + setFromOpt('-r', 'parentpid') |
1128 | + setFromOpt('-g', 'gpg_key') |
1129 | + setFromOpt('-e', 'gpg_recipients') |
1130 | + try: |
1131 | + settings['gpg_dir'] = os.path.expanduser(opts['-G']) |
1132 | + except KeyError: |
1133 | + pass |
1134 | + settings['verbose'] = "--verbose" in opts |
1135 | + settings['review'] = "-R" in opts |
1136 | + settings['gpg_encrypt'] = bool(opts['-e']) |
1137 | + settings['gpg_sign'] = '-s' in opts |
1138 | + |
1139 | + settings['contents'] = [readFile(fname, "rb") for fname in opts['-i']] |
1140 | + if not settings['contents']: |
1141 | + settings['contents'].append(stdin.read()) |
1142 | + return settings |
1143 | + |
1144 | + |
1145 | +def readPageURL(page, settings): |
1146 | + website = settings['website'] |
1147 | + result_type = settings.get('result_type', None) |
1148 | + try: |
1149 | + # Check if we have to apply a regexp |
1150 | + if result_type: |
1151 | + result = page.read().decode('utf-8') |
1152 | + result_regex = settings.get('result_regexp', None) |
1153 | + if result_regex: |
1154 | + result = re.split(result_regex, result)[1] |
1155 | + |
1156 | + if result_type == 'url': |
1157 | + page_url = result.strip() |
1158 | + elif result_type == 'id': |
1159 | + page_url = settings.get('target_url', website) + result.strip() |
1160 | + else: |
1161 | + raise ValueError(_("Unsupported result_type: %s" % result_type)) |
1162 | else: |
1163 | - try: |
1164 | - with open(filename, "rb") as fd: |
1165 | - content = fd.read() |
1166 | - except KeyboardInterrupt: |
1167 | - print(_("KeyboardInterrupt caught."), file=sys.stderr) |
1168 | - sys.exit(1) |
1169 | - except: |
1170 | - print(_("Unable to read from: %s") % filename, file=sys.stderr) |
1171 | - sys.exit(1) |
1172 | - |
1173 | + page_url = page.url |
1174 | + |
1175 | + # You may have posted to https:, but were given an http: url |
1176 | + if website.startswith('https:'): |
1177 | + page_url = page_url.replace('http:', 'https:') |
1178 | + return page_url |
1179 | + |
1180 | + except KeyboardInterrupt: |
1181 | + print(_("KeyboardInterrupt caught."), file=stderr) |
1182 | + sys.exit(1) |
1183 | + except: |
1184 | + print(_("Unable to read or parse the result page, it could be a " |
1185 | + "server timeout or a change server side, " |
1186 | + "try with another pastebin."), file=stderr) |
1187 | + sys.exit(1) |
1188 | + |
1189 | + |
1190 | +def validateContents(settings): |
1191 | + """Check for invalid contents""" |
1192 | + for content in settings['contents']: |
1193 | if not content: |
1194 | print(_("You are trying to send an empty document, exiting."), |
1195 | - file=sys.stderr) |
1196 | - sys.exit(1) |
1197 | - |
1198 | - contents.append(content) |
1199 | - |
1200 | - for content in contents: |
1201 | - # Get the parameter array |
1202 | - website, params = getParameters(website, pastebind, content, user, |
1203 | - jabberid, version, format, parentpid, |
1204 | - permatag, title, username, password) |
1205 | - |
1206 | - if not website.endswith("/"): |
1207 | - website += "/" |
1208 | - |
1209 | - if "sizelimit" in params: |
1210 | - if len(content) > int(params['sizelimit']): |
1211 | - print(_("The content you are trying to send exceeds " |
1212 | - "the pastebin's size limit."), file=sys.stderr) |
1213 | - sys.exit(1) |
1214 | - else: |
1215 | - del params['sizelimit'] |
1216 | - |
1217 | - reLink = None |
1218 | - tmp_page = "" |
1219 | - if "page" in params: |
1220 | - website += params['page'] |
1221 | - tmp_page = params['page'] |
1222 | - del params["page"] |
1223 | - if "regexp" in params: |
1224 | - reLink = params['regexp'] |
1225 | - del params["regexp"] |
1226 | - if "target_url" in params: |
1227 | - target_url = params["target_url"] |
1228 | - del params["target_url"] |
1229 | - else: |
1230 | - target_url = None |
1231 | - if 'post_format' in params: |
1232 | - post_format = params['post_format'] |
1233 | - del params['post_format'] |
1234 | - else: |
1235 | - post_format = 'standard' |
1236 | - |
1237 | - url_opener = pasteURLopener() |
1238 | - |
1239 | - if post_format == 'json': |
1240 | - if json: |
1241 | - params = json.dumps(params) |
1242 | - url_opener.addheader('Content-type', 'text/json') |
1243 | - else: |
1244 | - print(_("Could not find any json library."), file=sys.stderr) |
1245 | - sys.exit(1) |
1246 | - else: |
1247 | - # Convert to a format usable with the HTML POST |
1248 | - params = urlencode(params) |
1249 | - |
1250 | - # Send the informations and be redirected to the final page |
1251 | - try: |
1252 | - page = url_opener.open(website, params) |
1253 | - except Exception as e: |
1254 | - print(_("Failed to contact the server: %s") % e, file=sys.stderr) |
1255 | - sys.exit(1) |
1256 | - |
1257 | - try: |
1258 | - # Check if we have to apply a regexp |
1259 | - if reLink: |
1260 | - if target_url: |
1261 | - website = target_url |
1262 | - else: |
1263 | - website = website.replace(tmp_page, "") |
1264 | - |
1265 | - if reLink == '(.*)': |
1266 | - print(page.read().decode('utf-8').strip()) |
1267 | - else: |
1268 | - # Print the result of the regexp |
1269 | - print(website + re.split(reLink, |
1270 | - page.read().decode('utf-8'))[1]) |
1271 | - else: |
1272 | - # Get the final page and show the url |
1273 | - print(page.url) |
1274 | - except KeyboardInterrupt: |
1275 | - print(_("KeyboardInterrupt caught."), file=sys.stderr) |
1276 | - sys.exit(1) |
1277 | - except: |
1278 | - print(_("Unable to read or parse the result page, it could be a " |
1279 | - "server timeout or a change server side, " |
1280 | - "try with another pastebin."), file=sys.stderr) |
1281 | - sys.exit(1) |
1282 | - |
1283 | -except KeyboardInterrupt: |
1284 | - print(_("KeyboardInterrupt caught."), file=sys.stderr) |
1285 | - sys.exit(1) |
1286 | + file=stderr) |
1287 | + sys.exit(1) |
1288 | + |
1289 | + if len(content) > int(settings.get('sizelimit', sys.maxsize)): |
1290 | + print(_("The content you are trying to send exceeds " |
1291 | + "the pastebin's size limit."), file=stderr) |
1292 | + sys.exit(1) |
1293 | + |
1294 | + |
1295 | +def confirm(): |
1296 | + fd_tty = open("/dev/tty", "r") |
1297 | + answer = fd_tty.readline().rstrip('\n') |
1298 | + fd_tty.close() |
1299 | + return not answer or answer.upper().startswith("Y") |
1300 | + |
1301 | + |
1302 | +def findKey(gpg, settings): |
1303 | + try: |
1304 | + if not settings['gpg_key']: |
1305 | + return gpg.list_keys()[0] |
1306 | + else: |
1307 | + for k in gpg.list_keys(): |
1308 | + for uid in k['uids']: |
1309 | + if settings['gpg_key'].lower() in uid.lower(): |
1310 | + return k |
1311 | + print(_("Could not find key with value: %s" % settings['gpg_key']), |
1312 | + file=stderr) |
1313 | + sys.exit(1) |
1314 | + except IndexError: |
1315 | + print(_('Tried to sign but no keys available.'), file=stderr) |
1316 | + sys.exit(1) |
1317 | + |
1318 | + |
1319 | +def reviewKey(key, settings): |
1320 | + if settings['review']: |
1321 | + print(_("Review: Use this key '%s' [Y|n] ?" % key['uids']), file=stderr) |
1322 | + if not confirm(): |
1323 | + print(_("Paste Aborted: key rejected by user"), file=stderr) |
1324 | + sys.exit(2) |
1325 | + |
1326 | + |
1327 | +def getGPG(settings): |
1328 | + if not gnupg: |
1329 | + print(_("Please install python-gnupg."), file=stderr) |
1330 | + sys.exit(1) |
1331 | + return gnupg.GPG(gnupghome=settings['gpg_dir']) |
1332 | + |
1333 | + |
1334 | +def reviewContent(content, settings): |
1335 | + if not settings['review']: |
1336 | + return True |
1337 | + |
1338 | + print("-" * 15 + " REVIEW " + "-" * 15, file=stdout) |
1339 | + print(content, file=stdout) |
1340 | + print("-" * 15 + " REVIEW " + "-" * 15, file=stdout) |
1341 | + print(_("Review: do you wish to paste to %s [Y|n] ?" % |
1342 | + settings['website']), file=stdout) |
1343 | + # need to directly open the terminal to get input |
1344 | + # since stdin is likely to have been redirected from a pipe |
1345 | + return confirm() |
1346 | + |
1347 | + |
1348 | +def handleEncryption(settings): |
1349 | + #Sign contents |
1350 | + if settings['gpg_sign'] and not settings['gpg_encrypt']: |
1351 | + gpg = getGPG(settings) |
1352 | + key = findKey(gpg, settings) |
1353 | + reviewKey(key, settings) |
1354 | + return [ |
1355 | + gpg.sign(c, keyid=key['keyid']) |
1356 | + for c in settings['contents'] |
1357 | + ] |
1358 | + |
1359 | + #Encrypt contents |
1360 | + if settings['gpg_encrypt'] and not settings['gpg_sign']: |
1361 | + gpg = getGPG(settings) |
1362 | + return [ |
1363 | + gpg.encrypt(c, settings['gpg_recipients']) |
1364 | + for c in settings['contents'] |
1365 | + ] |
1366 | + |
1367 | + #Encrypt and sign contents |
1368 | + if settings['gpg_encrypt'] and settings['gpg_sign']: |
1369 | + gpg = getGPG(settings) |
1370 | + key = findKey(gpg, settings) |
1371 | + reviewKey(key, settings) |
1372 | + return [ |
1373 | + gpg.encrypt(c, settings['gpg_recipients'], sign=key['keyid']) |
1374 | + for c in settings['contents'] |
1375 | + ] |
1376 | + |
1377 | + return settings['contents'] |
1378 | + |
1379 | + |
1380 | +def main(): |
1381 | + try: |
1382 | + settings = defaults.copy() |
1383 | + settings.update(readConfigFile(readFile(config_path))) |
1384 | + settings.update(readOptions(getOpts())) |
1385 | + |
1386 | + paste_config, settings['website'] = getPasteConfig(settings['website']) |
1387 | + params = readPasteConfig(paste_config, settings) |
1388 | + |
1389 | + validateContents(settings) |
1390 | + opener = PasteURLopener(settings) |
1391 | + |
1392 | + url = settings['website'] + settings.get('page', '').lstrip("/") |
1393 | + settings['contents'] = handleEncryption(settings) |
1394 | + for content in settings['contents']: |
1395 | + params[paste_config.get('format', 'content')] = content |
1396 | + if not reviewContent(content, settings): |
1397 | + print(_("Paste aborted"), file=stderr) |
1398 | + continue |
1399 | + page = opener.make_request(url, params) |
1400 | + print(readPageURL(page, settings), file=stdout) |
1401 | + except KeyboardInterrupt: |
1402 | + print(_("KeyboardInterrupt caught."), file=stderr) |
1403 | + sys.exit(1) |
1404 | + |
1405 | +if __name__ == '__main__': |
1406 | + main() |
1407 | \ No newline at end of file |
1408 | |
1409 | === added symlink 'pastebinit.py' |
1410 | === target is u'pastebinit' |
1411 | === added file 'test.py' |
1412 | --- test.py 1970-01-01 00:00:00 +0000 |
1413 | +++ test.py 2014-12-07 21:54:13 +0000 |
1414 | @@ -0,0 +1,135 @@ |
1415 | +import unittest |
1416 | +import pastebinit |
1417 | +try: |
1418 | + from StringIO import StringIO |
1419 | +except ImportError: |
1420 | + from io import StringIO |
1421 | + |
1422 | +pastebinit.stdin = StringIO('') |
1423 | +pastebinit.stdout = StringIO('') |
1424 | +pastebinit.stderr = StringIO('') |
1425 | + |
1426 | + |
1427 | +class ConfigXMLTests(unittest.TestCase): |
1428 | + |
1429 | + def test_config_xml_parse(self): |
1430 | + xml = """\ |
1431 | + <pastebinit> |
1432 | + <pastebin>http://paste.debian.net</pastebin> |
1433 | + <author>A pastebinit user</author> |
1434 | + <jabberid>nobody@nowhere.org</jabberid> |
1435 | + <format>text</format> |
1436 | + </pastebinit> |
1437 | + """ |
1438 | + out = { |
1439 | + 'website': u'http://paste.debian.net', |
1440 | + 'user': u'A pastebinit user', |
1441 | + 'jabberid': u'nobody@nowhere.org', |
1442 | + 'format': u'text', |
1443 | + } |
1444 | + assert pastebinit.readConfigFile(xml) == out, 'readConfigFile failed' |
1445 | + |
1446 | + def test_config_xml_parse_missing(self): |
1447 | + xml = """\ |
1448 | + <pastebinit> |
1449 | + <author>A pastebinit user</author> |
1450 | + <jabberid>nobody@nowhere.org</jabberid> |
1451 | + <format>text</format> |
1452 | + </pastebinit> |
1453 | + """ |
1454 | + out = { |
1455 | + 'user': u'A pastebinit user', |
1456 | + 'jabberid': u'nobody@nowhere.org', |
1457 | + 'format': u'text', |
1458 | + } |
1459 | + assert pastebinit.readConfigFile(xml) == out, 'readConfigFile failed' |
1460 | + |
1461 | + def test_config_xml_parse_additional(self): |
1462 | + xml = """\ |
1463 | + <pastebinit> |
1464 | + <author>A pastebinit user</author> |
1465 | + <jabberid>nobody@nowhere.org</jabberid> |
1466 | + <format>text</format> |
1467 | + <test>nonsense</test> |
1468 | + </pastebinit> |
1469 | + """ |
1470 | + out = { |
1471 | + 'user': u'A pastebinit user', |
1472 | + 'jabberid': u'nobody@nowhere.org', |
1473 | + 'format': u'text', |
1474 | + } |
1475 | + assert pastebinit.readConfigFile(xml) == out, 'readConfigFile failed' |
1476 | + |
1477 | + def test_config_xml_parse_invalid(self): |
1478 | + try: |
1479 | + pastebinit.readConfigFile("invalid") |
1480 | + assert False, "Invalid file was parsed without error." |
1481 | + except SystemExit: |
1482 | + pass |
1483 | + |
1484 | + |
1485 | +class GetOptsTests(unittest.TestCase): |
1486 | + |
1487 | + def _check_arg(self, argname, settingname): |
1488 | + settings = pastebinit.readOptions(pastebinit.getOpts([argname, 'test'])) |
1489 | + assert settings[settingname] == 'test', "Failed to read " + argname |
1490 | + |
1491 | + def test_help(self): |
1492 | + try: |
1493 | + pastebinit.readOptions(['-h']) |
1494 | + assert False, "Failed to quit after help option" |
1495 | + except SystemExit: |
1496 | + pass |
1497 | + |
1498 | + def test_list(self): |
1499 | + try: |
1500 | + pastebinit.readOptions(['-l']) |
1501 | + assert False, "Failed to quit after list option" |
1502 | + except SystemExit: |
1503 | + pass |
1504 | + |
1505 | + def test_version(self): |
1506 | + try: |
1507 | + pastebinit.readOptions(['-v']) |
1508 | + assert False, "Failed to quit after version option" |
1509 | + except SystemExit: |
1510 | + pass |
1511 | + |
1512 | + def test_website(self): |
1513 | + self._check_arg('-b', 'website') |
1514 | + |
1515 | + def test_user(self): |
1516 | + self._check_arg('-a', 'user') |
1517 | + |
1518 | + def test_format(self): |
1519 | + self._check_arg('-f', 'format') |
1520 | + |
1521 | + def test_jabberid(self): |
1522 | + self._check_arg('-j', 'jabberid') |
1523 | + |
1524 | + def test_title(self): |
1525 | + self._check_arg('-t', 'title') |
1526 | + |
1527 | + def test_permatag(self): |
1528 | + self._check_arg('-m', 'permatag') |
1529 | + |
1530 | + def test_username(self): |
1531 | + self._check_arg('-u', 'username') |
1532 | + |
1533 | + def test_password(self): |
1534 | + self._check_arg('-p', 'password') |
1535 | + |
1536 | + def test_parentpid(self): |
1537 | + self._check_arg('-r', 'parentpid') |
1538 | + |
1539 | + def test_filenames(self): |
1540 | + opts = pastebinit.getOpts(['-i', 'testa', |
1541 | + '-i', 'testb', |
1542 | + '-i', 'testc', |
1543 | + ]) |
1544 | + assert opts['-i'] == [ |
1545 | + 'testa','testb','testc'], "Failed to read filenames" |
1546 | + |
1547 | + |
1548 | +if __name__ == "__main__": |
1549 | + unittest.main() |
1550 | |
1551 | === modified file 'test.sh' |
1552 | --- test.sh 2014-01-06 23:23:28 +0000 |
1553 | +++ test.sh 2014-12-07 21:54:13 +0000 |
1554 | @@ -1,11 +1,16 @@ |
1555 | #!/bin/sh |
1556 | -teststring="blah blah blah" |
1557 | +#paste.debian.net needs 3 lines |
1558 | +teststring="""\ |
1559 | +test from pastebinit |
1560 | +test from pastebinit |
1561 | +test from pastebinit |
1562 | +""" |
1563 | |
1564 | for interpreter in python python3; do |
1565 | - for pastebin in $($interpreter pastebinit -l | egrep "^-" | sed "s/^- //g") |
1566 | + for pastebin in $(ls pastebin.d/*.conf | sed 's~^pastebin.d/\(.*\)\.conf$~\1~') |
1567 | do |
1568 | echo "Trying http://$pastebin ($interpreter)" |
1569 | - URL=$(echo "$teststring\n$teststring\n$teststring" | $interpreter pastebinit -b http://$pastebin) |
1570 | + URL=$(echo teststring | $interpreter ./pastebinit.py -b http://$pastebin) |
1571 | |
1572 | if [ "$pastebin" = "paste.ubuntu.org.cn" ]; then |
1573 | out=$(wget -O - -q "$URL" | gzip -d | grep "$teststring") |
1574 | @@ -14,9 +19,13 @@ |
1575 | fi |
1576 | |
1577 | if [ -n "$out" ]; then |
1578 | - echo "PASS: http://$pastebin ($URL) ($interpreter)" |
1579 | + echo "PASS: http://$pastebin" |
1580 | + echo " ($URL)" |
1581 | + echo " ($interpreter)" |
1582 | else |
1583 | - echo "FAIL: http://$pastebin ($URL) ($interpreter)" |
1584 | + echo "FAIL: http://$pastebin" |
1585 | + echo " ($URL)" |
1586 | + echo " ($interpreter)" |
1587 | fi |
1588 | echo "" |
1589 | done |
Looks like this is based on the pastebinit rewrite/rework from your other branch, mark this work in progress until we can sort out the other one.