/usr/lib/python2.7/dist-packages/keysign/Keyserver.py is in gnome-keysign 0.9-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 | #!/usr/bin/env python
# Copyright 2014 Tobias Mueller <muelli@cryptobitch.de>
# Copyright 2014 Andrei Macavei <andrei.macavei89@gmail.com>
# Copyright 2015 Jody Hansen <jobediah.hansen@gmail.com>
#
# This file is part of GNOME Keysign.
#
# GNOME Keysign is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GNOME Keysign is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GNOME Keysign. If not, see <http://www.gnu.org/licenses/>.
try:
from http.server import BaseHTTPRequestHandler, HTTPServer
from socketserver import ThreadingMixIn
except ImportError:
from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer
from SocketServer import ThreadingMixIn
import logging
import os
import socket
from threading import Thread
# This is probably really bad... But doing relative imports only
# works for modules. However, I want to be able to call this Keyserver.py
# for testing purposes.
if __name__ == "__main__" and __package__ is None:
logging.getLogger().error("You seem to be trying to execute " +
"this script directly which is discouraged. " +
"Try python -m instead.")
parent_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
os.sys.path.insert(0, parent_dir)
os.sys.path.insert(0, os.path.join(parent_dir, 'monkeysign'))
import keysign
#mod = __import__('keysign')
#sys.modules["keysign"] = mod
__package__ = str('keysign')
from .__init__ import __version__
from .network.AvahiPublisher import AvahiPublisher
from .gpgmh import fingerprint_from_keydata
log = logging.getLogger(__name__)
class KeyRequestHandlerBase(BaseHTTPRequestHandler):
'''This is the "base class" which needs to be given access
to the key to be served. So you will not use this class,
but create a use one inheriting from this class. The subclass
must also define a keydata field.
'''
server_version = 'GNOME-Keysign/' + '%s' % __version__
# As per RFC 2015 Section 7
# https://tools.ietf.org/html/rfc2015#section-7
ctype = 'application/pgp-keys'
def do_GET(self):
f = self.send_head(self.keydata)
self.wfile.write(self.keydata)
def send_head(self, keydata=None):
kd = keydata if keydata else self.keydata
self.send_response(200)
self.send_header('Content-Type', self.ctype)
self.send_header('Content-Length', len(kd))
self.end_headers()
return kd
class ThreadedKeyserver(ThreadingMixIn, HTTPServer):
'''The keyserver in a threaded fashion'''
address_family = socket.AF_INET6
def __init__(self, server_address, *args, **kwargs):
if issubclass(self.__class__, object):
super(ThreadedKeyserver, self).__init__(*args, **kwargs)
else:
HTTPServer.__init__(self, server_address, *args, **kwargs)
# WTF? There is no __init__..?
# ThreadingMixIn.__init__(self, server_address, *args, **kwargs)
def server_bind(self):
# Override this method to be sure v6only is false: we want to
# listen to both IPv4 and IPv6!
self.socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, False)
HTTPServer.server_bind(self)
class ServeKeyThread(Thread):
'''Serves requests and manages the server in separates threads.
You can create an object and call start() to let it run.
If you want to stop serving, call shutdown().
'''
def __init__(self, data, fpr, port=9001, *args, **kwargs):
'''Initializes the server to serve the data'''
self.keydata = data
self.fpr = fpr
self.port = port
super(ServeKeyThread, self).__init__(*args, **kwargs)
self.daemon = True
self.httpd = None
def start(self, data=None, fpr=None, port=None, *args, **kwargs):
'''This is run in the same thread as the caller.
This calls run() in a separate thread.
In order to resolve DBus issues, most things
are done here.
However, you probably need to start
dbus.mainloop.glib.DBusGMainLoop (set_as_default=True)
in order for this work.
'''
port = port or self.port or 9001
fpr = fpr or self.fpr
tries = 10
kd = data if data else self.keydata
class KeyRequestHandler(KeyRequestHandlerBase):
'''You will need to create this during runtime'''
keydata = kd
HandlerClass = KeyRequestHandler
for port_i in (port + p for p in range(tries)):
try:
log.info('Trying port %d', port_i)
server_address = ('', port_i)
self.httpd = ThreadedKeyserver(server_address, HandlerClass, **kwargs)
###
# This is a bit of a hack, it really should be
# in some lower layer, such as the place were
# the socket is created and listen()ed on.
service_txt = {
'fingerprint': fpr,
'version': __version__,
}
log.info('Requesting Avahi with txt: %s', service_txt)
self.avahi_publisher = ap = AvahiPublisher(
service_port = port_i,
service_name = 'HTTP Keyserver %s' % fpr,
service_txt = service_txt,
# self.keydata is too big for Avahi; it crashes
service_type = '_gnome-keysign._tcp',
)
log.info('Trying to add Avahi Service')
ap.add_service()
except socket.error as value:
errno = value.errno
if errno == 10054 or errno == 32:
# This seems to be harmless
break
else:
break
finally:
pass
super(ServeKeyThread, self).start(*args, **kwargs)
def serve_key(self, poll_interval=0.15):
'''An HTTPd is started and being put to serve_forever.
You need to call shutdown() in order to stop
serving.
'''
#sa = self.httpd.socket.getsockname()
try:
log.info('Serving now on %s, this is probably blocking...',
self.httpd.socket.getsockname())
self.httpd.serve_forever(poll_interval=poll_interval)
finally:
log.info('finished serving')
#httpd.dispose()
def run(self):
'''This is being run by Thread in a separate thread
after you call start()'''
self.serve_key()
def shutdown(self):
'''Sends shutdown to the underlying httpd'''
log.info("Removing Avahi Service")
self.avahi_publisher.remove_service()
log.info("Shutting down httpd %r", self.httpd)
self.httpd.shutdown()
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG)
import dbus, time
dbus.mainloop.glib.DBusGMainLoop (set_as_default=True)
def stop_thread(t, seconds=5):
log.info('Sleeping %d seconds, then stopping', seconds)
time.sleep(seconds)
t.shutdown()
import sys
if len(sys.argv) >= 2:
fname = sys.argv[1]
KEYDATA = open(fname, 'r').read()
# FIXME: Someone needs to determine the fingerprint
# of the data just read
fpr = fingerprint_from_keydata(KEYDATA)
else:
KEYDATA = 'Example data'
fpr = ''.join('F289 F7BA 977D F414 3AE9 FDFB F70A 0290 6C30 1813'.split())
if len(sys.argv) >= 3:
timeout = int(sys.argv[2])
else:
timeout = 5
t = ServeKeyThread(KEYDATA, fpr)
stop_t = Thread(target=stop_thread, args=(t,timeout))
stop_t.daemon = True
t.start()
stop_t.start()
while True:
log.info('joining stop %s', stop_t.isAlive())
stop_t.join(1)
log.info('joining t %s', t.isAlive())
t.join(1)
if not t.isAlive() or not stop_t.isAlive():
break
log.warn('Last line')
|