Merge branch 'feature/docs' into develop
commit
7ae48bdfdf
46
README.md
46
README.md
|
@ -1,10 +1,11 @@
|
||||||
# python-gnupg #
|
# python-gnupg #
|
||||||
================
|
================
|
||||||
|
|
||||||
Fork of python-gnupg-0.3.2, patched to remove Popen([...], shell=True).
|
Fork of python-gnupg-0.3.2, patched to remove ```Popen([...], shell=True)```.
|
||||||
|
|
||||||
### Installation ###
|
### Installation ###
|
||||||
--------------------
|
|
||||||
|
#### From this git repository ####
|
||||||
To install this package from this git repository, do:
|
To install this package from this git repository, do:
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -19,15 +20,44 @@ Optionally to build the documentation after installation, do:
|
||||||
make docs
|
make docs
|
||||||
```
|
```
|
||||||
|
|
||||||
To get started using python-gnupg's API, see the documentation online at [XXX
|
To get started using python-gnupg's API, see the [online documentation](https://python-gnupg.readthedocs.org/en/latest/),
|
||||||
FIXME add readthedocs link](), and import the module like so:
|
and import the module like so:
|
||||||
```
|
```
|
||||||
>>> import gnupg
|
>>> import gnupg
|
||||||
```
|
```
|
||||||
|
|
||||||
|
The primary interface class you'll likely want to interact with is
|
||||||
|
[```gnupg.GPG```](https://python-gnupg.readthedocs.org/en/latest/gnupg.html#gpg):
|
||||||
|
```
|
||||||
|
>>> gpg = gnupg.GPG(gpgbinary='/usr/bin/gpg',
|
||||||
|
... gpghome='./keys',
|
||||||
|
... pubring='pubring.gpg',
|
||||||
|
... secring='secring.gpg')
|
||||||
|
>>> batch_key_input = gpg.gen_key_input()
|
||||||
|
>>> print batch_key_input
|
||||||
|
Key-Type: RSA
|
||||||
|
Name-Email: isis@wintermute
|
||||||
|
Name-Comment: Generated by gnupg.py
|
||||||
|
Key-Length: 4096
|
||||||
|
Name-Real: Autogenerated Key
|
||||||
|
%pubring /home/isis/code/python-gnupg/keys/pubring.gpg
|
||||||
|
%secring /home/isis/code/python-gnupg/keys/secring.gpg
|
||||||
|
%commit
|
||||||
|
|
||||||
To install this package from a tarballed source distribution, do the following:
|
>>> key = gpg.gen_key(batch_key_input)
|
||||||
|
>>> print key.fingerprint
|
||||||
|
245D8FA30F543B742053949F553C0E154F2E7A98
|
||||||
|
|
||||||
1. Extract all the files in the distribution archive to some directory on your system.
|
```
|
||||||
2. In that directory, run "python setup.py install".
|
|
||||||
3. Optionally, run "python test_gnupg.py" to ensure that the package is working as expected.
|
#### From PyPI ####
|
||||||
|
Hold your horses, boy. I haven't finished development, so the packages on
|
||||||
|
[PyPI](https://pypi.python.org) are still the old versions belonging to the
|
||||||
|
other authors.
|
||||||
|
|
||||||
|
### Bug Reports & Feature Requests ###
|
||||||
|
Our bugtracker is [here](https://leap.se/code/projects/eip_server/issue/new).
|
||||||
|
|
||||||
|
Please use that for bug reports and feature requests instead of github's
|
||||||
|
tracker. We're using github for code commenting and review between
|
||||||
|
collaborators.
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,260 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#-*- coding: utf-8 -*-
|
||||||
|
'''
|
||||||
|
report-a-bug
|
||||||
|
------------
|
||||||
|
File a bug against python-gnupg.
|
||||||
|
|
||||||
|
:authors: Wade Leftwich,
|
||||||
|
Will Holcomb, <wholcomb@gmail.com>
|
||||||
|
Isis Lovecruft, <isis@leap.se>
|
||||||
|
:license: AGPLv3, see LICENSE and COPYRIGHT files
|
||||||
|
:copyright: © 2002-2013 Wade Leftwich
|
||||||
|
© 2006 Will Holcomb
|
||||||
|
© 2013 Isis Agora Lovecruft
|
||||||
|
:date: 11 April 2013
|
||||||
|
:version: 0.0.1
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
from cStringIO import StringIO
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
import cookielib
|
||||||
|
import mimetools
|
||||||
|
import mimetypes
|
||||||
|
#import httplib
|
||||||
|
import os
|
||||||
|
import stat
|
||||||
|
import tempfile
|
||||||
|
import urllib
|
||||||
|
import urllib2
|
||||||
|
|
||||||
|
# Controls how sequences are uncoded. If true, elements may be given multiple
|
||||||
|
# values by assigning a sequence.
|
||||||
|
doseq = 1
|
||||||
|
|
||||||
|
def _has_py3k():
|
||||||
|
"""Check if we're running on Python>=3.0."""
|
||||||
|
try:
|
||||||
|
unicode
|
||||||
|
return False
|
||||||
|
except NameError:
|
||||||
|
return True
|
||||||
|
|
||||||
|
## patch the stupid Python2.x input() problem:
|
||||||
|
if not _has_py3k():
|
||||||
|
input = raw_input
|
||||||
|
|
||||||
|
def _today():
|
||||||
|
"""Get the current date as a string in the form %Y-%m-%d."""
|
||||||
|
now_string = datetime.now().__str__()
|
||||||
|
return now_string.split(' ', 1)[0]
|
||||||
|
|
||||||
|
def _create_upload_list():
|
||||||
|
"""Create a dictionary containing information about files to upload."""
|
||||||
|
|
||||||
|
upload_list = list()
|
||||||
|
|
||||||
|
WANT_UPLOAD = True
|
||||||
|
FILE_NUMBER = 1
|
||||||
|
FILENAME_FIELD = 'attachments[' + str(FILE_NUMBER) + '][file]'
|
||||||
|
FILEDESC_FIELD = 'attachments[' + str(FILE_NUMBER) + '][description]'
|
||||||
|
|
||||||
|
while WANT_UPLOAD:
|
||||||
|
do_upload = input("Would you like to attach a file to this ticket? "
|
||||||
|
+ "(y/N) ")
|
||||||
|
if do_upload.strip() == "":
|
||||||
|
WANT_UPLOAD = False
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
WANT_UPLOAD = True
|
||||||
|
|
||||||
|
upload = input("Please specify the file to upload, as a filesystem "
|
||||||
|
+ "absolute path or as relative to this directory (%s): "
|
||||||
|
% os.getcwd()).strip()
|
||||||
|
|
||||||
|
if len(upload) > 0:
|
||||||
|
if upload.startswith('~'):
|
||||||
|
upload = os.path.expanduser(upload)
|
||||||
|
if not os.path.isabs(upload):
|
||||||
|
upload = os.path.abspath(upload)
|
||||||
|
try:
|
||||||
|
assert os.path.isfile(upload), "is not a file"
|
||||||
|
except AssertionError as ae:
|
||||||
|
print("Skipping: '%s' %s" % (upload, ae.message))
|
||||||
|
else:
|
||||||
|
upload_fields = {'fields': [FILENAME_FIELD, FILEDESC_FIELD],
|
||||||
|
'filepath': upload,}
|
||||||
|
upload_list.append(upload_fields)
|
||||||
|
FILE_NUMBER += 1
|
||||||
|
return upload_list
|
||||||
|
|
||||||
|
def _create_fields_and_headers(host, url, assign_to=None,
|
||||||
|
category=None, target_version=None):
|
||||||
|
REPO_NAME = os.getcwd().rsplit(os.path.sep, 1)[1]
|
||||||
|
|
||||||
|
subject = input("Please provide a brief subject line for the ticket: ")
|
||||||
|
subject = REPO_NAME + ": " + subject
|
||||||
|
descript = input("Ticket description:\n ")
|
||||||
|
whatisit = input("Is this a feature request or a bug report? "
|
||||||
|
+ "(1=feature, 2=bug) ")
|
||||||
|
if whatisit not in ['1', '2']:
|
||||||
|
whatisit = '2'
|
||||||
|
serious = input("How important is this? (1=important, 2=normal, 3=trivial) ")
|
||||||
|
if serious not in ['1', '2', '3']:
|
||||||
|
serious = '2'
|
||||||
|
|
||||||
|
headers = {
|
||||||
|
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
||||||
|
'Accept-Encoding': 'gzip, deflate',
|
||||||
|
'Accept-Language': 'en-us,en-gb;q=0.9,en;',
|
||||||
|
'Connection': 'keep-alive',
|
||||||
|
'DNT': '1',
|
||||||
|
'Host': host,
|
||||||
|
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; rv:10.0) Gecko/20100101 Firefox/10.0', }
|
||||||
|
|
||||||
|
fields = {
|
||||||
|
'issue[tracker_id]': whatisit,
|
||||||
|
'issue[subject]': subject,
|
||||||
|
'issue[description]': descript,
|
||||||
|
'issue[status_id]': '2',
|
||||||
|
'issue[priority_id]': serious,
|
||||||
|
'issue[assigned_to_id]': assign_to,
|
||||||
|
'issue[category_id]': category,
|
||||||
|
'issue[fixed_version_id]': target_version,
|
||||||
|
'issue[start_date]': _today(),
|
||||||
|
'issue[due_date]': '',
|
||||||
|
'issue[estimated_hours]': '',
|
||||||
|
'issue[done_ratio]': '0',
|
||||||
|
'issue[custom_field_values][3]': '',
|
||||||
|
'issue[custom_field_values][4]': '',
|
||||||
|
'issue[custom_field_values][5]': '0',
|
||||||
|
'send_notification': '0',
|
||||||
|
'send_notification': '1',
|
||||||
|
'commit': 'Create', }
|
||||||
|
|
||||||
|
return fields, headers
|
||||||
|
|
||||||
|
|
||||||
|
class Callable:
|
||||||
|
def __init__(self, anycallable):
|
||||||
|
self.__call__ = anycallable
|
||||||
|
|
||||||
|
class MultipartPostHandler(urllib2.BaseHandler):
|
||||||
|
handler_order = urllib2.HTTPHandler.handler_order - 10 # needs to run first
|
||||||
|
|
||||||
|
def http_request(self, request):
|
||||||
|
data = request.get_data()
|
||||||
|
if data is not None and type(data) != str:
|
||||||
|
v_files = []
|
||||||
|
v_vars = []
|
||||||
|
try:
|
||||||
|
for (key, value) in data.items():
|
||||||
|
if type(value) == file:
|
||||||
|
v_files.append((key, value))
|
||||||
|
else:
|
||||||
|
v_vars.append((key, value))
|
||||||
|
except TypeError:
|
||||||
|
systype, value, traceback = sys.exc_info()
|
||||||
|
raise TypeError("not non-string sequence or mapping object\n%s"
|
||||||
|
% traceback)
|
||||||
|
|
||||||
|
if len(v_files) == 0:
|
||||||
|
data = urllib.urlencode(v_vars, doseq)
|
||||||
|
else:
|
||||||
|
boundary, data = self.multipart_encode(v_vars, v_files)
|
||||||
|
contenttype = 'multipart/form-data; boundary=%s' % boundary
|
||||||
|
if (request.has_header('Content-Type') and request.get_header(
|
||||||
|
'Content-Type').find('multipart/form-data') != 0):
|
||||||
|
print("Replacing %s with %s"
|
||||||
|
% (request.get_header('content-type'),
|
||||||
|
'multipart/form-data'))
|
||||||
|
request.add_unredirected_header('Content-Type', contenttype)
|
||||||
|
request.add_data(data)
|
||||||
|
return request
|
||||||
|
|
||||||
|
def multipart_encode(self, fields=None, upload_list=None,
|
||||||
|
boundary=None, buf=None):
|
||||||
|
if fields is None:
|
||||||
|
fields = self.fields
|
||||||
|
if upload_list is None:
|
||||||
|
upload_list = self.upload_list
|
||||||
|
if boundary is None:
|
||||||
|
boundary = mimetools.choose_boundary()
|
||||||
|
if buf is None:
|
||||||
|
buf = StringIO()
|
||||||
|
|
||||||
|
for (key, value) in fields:
|
||||||
|
buf.write('--%s\r\n' % boundary)
|
||||||
|
buf.write('Content-Disposition: form-data; name="%s"' % key)
|
||||||
|
buf.write('\r\n\r\n' + value + '\r\n')
|
||||||
|
|
||||||
|
if isinstance(upload_list, list) and len(upload_list) > 0:
|
||||||
|
for upload in upload_list:
|
||||||
|
for (name, filepath) in upload:
|
||||||
|
with open(filepath) as fd:
|
||||||
|
file_size = os.fstat(fd.fileno())[stat.ST_SIZE]
|
||||||
|
filename = fd.name.split('/')[-1]
|
||||||
|
contenttype = mimetypes.guess_type(filename)[0] \
|
||||||
|
or 'application/octet-stream'
|
||||||
|
buf.write('--%s\r\n' % boundary)
|
||||||
|
buf.write('Content-Disposition: form-data; ')
|
||||||
|
buf.write('name="%s"; filename="%s"'
|
||||||
|
% (name[0], filename))
|
||||||
|
buf.write('Content-Type: %s\r\n' % contenttype)
|
||||||
|
# buf.write('Content-Length: %s\r\n' % file_size)
|
||||||
|
fd.seek(0)
|
||||||
|
buf.write('\r\n' + fd.read() + '\r\n')
|
||||||
|
buf.write('--' + boundary + '--\r\n\r\n')
|
||||||
|
buf.write('--%s\r\n' % boundary)
|
||||||
|
buf.write('Content-Disposition: form-data; ')
|
||||||
|
buf.write('name="%s"; filename="%s"'
|
||||||
|
% (name[1], filename))
|
||||||
|
buf.write('\r\n\r\n')
|
||||||
|
buf.write('--' + boundary + '--\r\n\r\n')
|
||||||
|
|
||||||
|
buf = buf.getvalue()
|
||||||
|
return boundary, buf
|
||||||
|
multipart_encode = Callable(multipart_encode)
|
||||||
|
|
||||||
|
https_request = http_request
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
raise SystemExit("Please fix me! This script needs a login handler.\n"
|
||||||
|
+ "Everything else is finished.")
|
||||||
|
|
||||||
|
## if you're reusing this script please change these!
|
||||||
|
host = 'leap.se'
|
||||||
|
selector = '/code/projects/eip-server/issues/new'
|
||||||
|
assign_to = '30' ## isis
|
||||||
|
category = '26' ## email
|
||||||
|
target_version = '29' ## the close future
|
||||||
|
|
||||||
|
url = 'https://' + host + selector
|
||||||
|
fields, headers = _create_fields_and_headers(host, selector, assign_to,
|
||||||
|
category, target_version)
|
||||||
|
upload_list = _create_upload_list()
|
||||||
|
cookies = cookielib.CookieJar()
|
||||||
|
opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookies),
|
||||||
|
MultipartPostHandler())
|
||||||
|
urllib2.install_opener(opener)
|
||||||
|
|
||||||
|
temp = tempfile.mkstemp(suffix=".html")
|
||||||
|
temp1 = tempfile.mkstemp(suffix=".html")
|
||||||
|
os.write(temp[0], opener.open('https://'+host+'/code/login',
|
||||||
|
{'username': 'cypherpunks',
|
||||||
|
'password': 'writecode'}).read())
|
||||||
|
|
||||||
|
for index,upload in enumerate(upload_list):
|
||||||
|
for (field, filepath) in upload:
|
||||||
|
fields['file'+'-'+index] = open(filepath, 'rb')
|
||||||
|
res = opener.open(url, fields)
|
||||||
|
print("Posted to: %s" % res.geturl())
|
||||||
|
print("Server response: %s " % res.code)
|
||||||
|
print(res.info())
|
||||||
|
print(res.read())
|
||||||
|
os.remove(temp[1])
|
Loading…
Reference in New Issue