summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimeon Simeonov2015-04-14 23:08:21 +0200
committerSimeon Simeonov2015-04-14 23:08:21 +0200
commita5a26cba29ba37f3ef7c4f60c6cbf3f663161b27 (patch)
treeb7fa2ed496cee78ad67c14338039a08a30742814
parent36dda1cca9503fc00c15ed22c4c5969e80edc1f7 (diff)
beinc_generic_client.py v.2.0 almost fone
-rwxr-xr-xbeinc_generic_client.py129
-rwxr-xr-xbeinc_server_.py13
2 files changed, 91 insertions, 51 deletions
diff --git a/beinc_generic_client.py b/beinc_generic_client.py
index b46d3fd..da671f2 100755
--- a/beinc_generic_client.py
+++ b/beinc_generic_client.py
@@ -1,7 +1,7 @@
1#!/usr/bin/env python 1#!/usr/bin/env python
2# -*- coding: utf-8 -*- 2# -*- coding: utf-8 -*-
3 3
4# Blackmore's Enhanced IRC-Notification Collection (BEINC) v1.0 4# Blackmore's Enhanced IRC-Notification Collection (BEINC) v2.0
5# Copyright (C) 2013-2015 Simeon Simeonov 5# Copyright (C) 2013-2015 Simeon Simeonov
6 6
7# This program is free software: you can redistribute it and/or modify 7# This program is free software: you can redistribute it and/or modify
@@ -21,12 +21,12 @@
21import argparse 21import argparse
22import errno 22import errno
23import getpass 23import getpass
24import httplib 24import httplib # for Python < 2.7.9
25import socket 25import os
26import socket # for Python < 2.7.9
26import ssl 27import ssl
27import sys 28import sys
28import urllib 29import xmlrpclib
29import urllib2
30 30
31 31
32__author__ = 'Simeon Simeonov' 32__author__ = 'Simeon Simeonov'
@@ -34,62 +34,91 @@ __version__ = '1.0'
34__license__ = 'GPL3' 34__license__ = 'GPL3'
35 35
36 36
37class ValidHTTPSConnection(httplib.HTTPConnection): 37class BEINCCustomHTTPSConnection(httplib.HTTPConnection):
38 """
39 Implements a simple CERT verification functionality
40 """ 38 """
39 This class allows communication via SSL.
41 40
41 It is a reimplementation of httplib.HTTPSConnection and
42 allows the server certificate to be validated against CA
43 This functionality lacks in Python < 2.7.9
44 """
42 default_port = httplib.HTTPS_PORT 45 default_port = httplib.HTTPS_PORT
43 46
44 def __init__(self, *args, **kwargs): 47 def __init__(self, host, port=None, key_file=None, cert_file=None,
45 httplib.HTTPConnection.__init__(self, *args, **kwargs) 48 strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
49 source_address=None, ca_cert=None):
50 httplib.HTTPConnection.__init__(self, host, port, strict, timeout,
51 source_address)
52 self.key_file = key_file
53 self.cert_file = cert_file
54 self.ca_cert = ca_cert
46 55
47 def connect(self): 56 def connect(self):
57 "Connect to a host on a given (SSL) port."
48 sock = socket.create_connection((self.host, self.port), 58 sock = socket.create_connection((self.host, self.port),
49 self.timeout, self.source_address) 59 self.timeout, self.source_address)
50 if self._tunnel_host: 60 if self._tunnel_host:
51 self.sock = sock 61 self.sock = sock
52 self._tunnel() 62 self._tunnel()
53 self.sock = ssl.wrap_socket(sock, 63 self.sock = ssl.wrap_socket(sock,
54 ca_certs=global_beinc_cert_file, 64 self.key_file,
55 cert_reqs=ssl.CERT_REQUIRED) 65 self.cert_file,
56 66 cert_reqs=ssl.CERT_REQUIRED,
67 ca_certs=self.ca_cert)
57 68
58class ValidHTTPSHandler(urllib2.HTTPSHandler): 69class BEINCCustomSafeTransport(xmlrpclib.Transport):
59 """
60 Implements a simple CERT verification functionality
61 """
62 70
63 def https_open(self, req): 71 def __init__(self, use_datetime=0, ca_cert=None):
64 return self.do_open(ValidHTTPSConnection, req) 72 xmlrpclib.Transport.__init__(self, use_datetime=use_datetime)
73 self.ca_cert = ca_cert
74
75 def make_connection(self, host):
76 if self._connection and host == self._connection[0]:
77 return self._connection[1]
78 try:
79 HTTPS = BEINCCustomHTTPSConnection
80 except AttributeError:
81 raise NotImplementedError(
82 "your version of httplib doesn't support HTTPS"
83 )
84 else:
85 chost, self._extra_headers, x509 = self.get_host_info(host)
86 self._connection = host, HTTPS(chost,
87 None,
88 ca_cert=self.ca_cert,
89 **(x509 or {}))
90 return self._connection[1]
65 91
66 92
67def action_push(args): 93def action_execute(args):
68 """ 94 """
69 """ 95 """
70 try: 96 try:
71 post_values = {'title': args.title, 97 if sys.hexversion >= 0x20709f0:
72 'message': args.message, 98 # Python >= 2.7.9
73 'password': args.password} 99 context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
74 data = urllib.urlencode(post_values) 100 context.verify_mode = ssl.CERT_REQUIRED
75 req = urllib2.Request(args.url, data) 101 context.check_hostname = False
76 if args.cert: # check for cert validity 102 context.load_verify_locations(os.path.expanduser(args.cert))
77 global global_beinc_cert_file # ugly hack 103 transport = xmlrpclib.SafeTransport(context=context)
78 global_beinc_cert_file = args.cert 104 else:
79 opener = urllib2.build_opener(ValidHTTPSHandler) 105 # Python < 2.7.9
80 response = opener.open(req) 106 transport = BEINCCustomSafeTransport(
81 else: # ... or don't 107 ca_cert=os.path.expanduser(args.cert))
82 response = urllib2.urlopen(req) 108 server = xmlrpclib.ServerProxy(args.url,
83 res_code = response.code 109 transport=transport)
84 if res_code == 200: 110 if args.pull:
85 print('Server responded: OK') 111 print(server.pull(args.rname, args.password))
86 else: 112 else:
87 print('Server responded: {0}'.format(res_code)) 113 print(server.push(args.rname,
88 print('Body:\n{0}'.format(response.read())) 114 args.password,
89 response.close() 115 args.title,
90 except urllib2.HTTPError as e: 116 args.message))
91 sys.stderr.write('BEINC-server error ({0} - {1})\n'.format(e.code, 117 except xmlrpclib.Fault as fault:
92 e.reason)) 118 sys.stderr.write(
119 'BEINC server answered with errorCode={0}: {1}\n'.format(
120 fault.faultCode,
121 fault.faultString))
93 except Exception as e: 122 except Exception as e:
94 sys.stderr.write('BEINC generic client error: {0}\n'.format(e)) 123 sys.stderr.write('BEINC generic client error: {0}\n'.format(e))
95 sys.exit(errno.EPERM) 124 sys.exit(errno.EPERM)
@@ -101,8 +130,6 @@ def main():
101 parser.add_argument('url', 130 parser.add_argument('url',
102 metavar='URL', 131 metavar='URL',
103 type=str, 132 type=str,
104 #dest='url',
105 #required=True,
106 help='Destination URL') 133 help='Destination URL')
107 parser.add_argument('-c', '--cert-file', 134 parser.add_argument('-c', '--cert-file',
108 metavar='FILE', 135 metavar='FILE',
@@ -116,12 +143,24 @@ def main():
116 dest='message', 143 dest='message',
117 default='BEINC message', 144 default='BEINC message',
118 help='BEINC message') 145 help='BEINC message')
146 parser.add_argument('-n', '--resource-name',
147 metavar='NAME',
148 type=str,
149 dest='rname',
150 required=True,
151 help='The name of the BEINC-resource on '
152 'the remote server')
119 parser.add_argument('-p', '--password', 153 parser.add_argument('-p', '--password',
120 metavar='PASSWORD', 154 metavar='PASSWORD',
121 type=str, 155 type=str,
122 dest='password', 156 dest='password',
123 default='', 157 default='',
124 help='Password') 158 help='Password')
159 parser.add_argument('--pull',
160 action='store_true',
161 dest='pull',
162 default=False,
163 help='Perform a pull operation (default: push)')
125 parser.add_argument('-t', '--title', 164 parser.add_argument('-t', '--title',
126 metavar='TITLE', 165 metavar='TITLE',
127 type=str, 166 type=str,
@@ -139,9 +178,9 @@ def main():
139 except Exception as e: 178 except Exception as e:
140 sys.stderr.write('Prompt terminated\n') 179 sys.stderr.write('Prompt terminated\n')
141 sys.exit(errno.EACCES) 180 sys.exit(errno.EACCES)
142 action_push(args) 181 action_execute(args)
143 sys.exit(0) 182 sys.exit(0)
144 183
145 184
146if __name__ == '__main__': 185if __name__ == '__main__':
147 main() 186 main()
diff --git a/beinc_server_.py b/beinc_server_.py
index 36cbcd5..ec920c2 100755
--- a/beinc_server_.py
+++ b/beinc_server_.py
@@ -31,7 +31,7 @@ from functools import wraps
31 31
32from twisted.web import xmlrpc, server 32from twisted.web import xmlrpc, server
33from twisted.internet import protocol, reactor, ssl 33from twisted.internet import protocol, reactor, ssl
34from twisted.python.filepath import FilePath 34from twisted.python import filepath, log
35 35
36try: 36try:
37 import pynotify 37 import pynotify
@@ -188,9 +188,9 @@ class BEINCInstance(object):
188 """ 188 """
189 Reruens a json representation of the message queue 189 Reruens a json representation of the message queue
190 """ 190 """
191 jstr = json.dumps(self.__message_queue) 191 r_value = self.__message_queue
192 self.__message_queue = list() 192 self.__message_queue = list()
193 return jstr 193 return r_value
194 194
195 def __send_pynotify_messaage(self, title, message): 195 def __send_pynotify_messaage(self, title, message):
196 """ 196 """
@@ -339,13 +339,14 @@ def main():
339 action='version', 339 action='version',
340 version='%(prog)s {0}'.format(__version__), 340 version='%(prog)s {0}'.format(__version__),
341 help='Display program-version and exit') 341 help='Display program-version and exit')
342 log.startLogging(sys.stdout)
342 args = parser.parse_args() 343 args = parser.parse_args()
343 try: 344 try:
344 with open(args.config_file, 'r') as fp: 345 with open(args.config_file, 'r') as fp:
345 config_dict = json.load(fp) 346 config_dict = json.load(fp)
346 except Exception as e: 347 except Exception as e:
347 sys.stderr.write('Unable to parse {0}: {1}\n'.format(args.config_file, 348 sys.stderr.write('Unable to parse {0}: {1}\n'.format(args.config_file,
348 e)) 349 e))
349 sys.exit(errno.EIO) 350 sys.exit(errno.EIO)
350 try: 351 try:
351 if config_dict.get('config_version') != 2: 352 if config_dict.get('config_version') != 2:
@@ -364,8 +365,8 @@ def main():
364 beinc_server = XMLRPCNotifyServer(config_dict) 365 beinc_server = XMLRPCNotifyServer(config_dict)
365 if ssl_certificate and ssl_private_key: 366 if ssl_certificate and ssl_private_key:
366 # SSL connection 367 # SSL connection
367 cert_path = FilePath(ssl_certificate) 368 cert_path = filepath.FilePath(ssl_certificate)
368 key_path = FilePath(ssl_private_key) 369 key_path = filepath.FilePath(ssl_private_key)
369 private_certificate = ssl.PrivateCertificate.loadPEM( 370 private_certificate = ssl.PrivateCertificate.loadPEM(
370 key_path.getContent() + cert_path.getContent()) 371 key_path.getContent() + cert_path.getContent())
371 options = private_certificate.options() 372 options = private_certificate.options()