Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
midgetspy committed Feb 13, 2012
2 parents 437b691 + 0cf08c0 commit 32123d9
Show file tree
Hide file tree
Showing 11 changed files with 400 additions and 98 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ config.ini
Logs/*
sickbeard.db*
autoProcessTV/autoProcessTV.cfg
server.crt
server.key

# Compiled source #
######################
Expand Down
6 changes: 4 additions & 2 deletions SickBeard.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,8 +266,6 @@ def main():
else:
webhost = '0.0.0.0'

logger.log(u"Starting Sick Beard on http://" + str(webhost) + ":" + str(startPort) + "/")

try:
initWebServer({
'port': startPort,
Expand All @@ -277,6 +275,10 @@ def main():
'log_dir': log_dir,
'username': sickbeard.WEB_USERNAME,
'password': sickbeard.WEB_PASSWORD,
'enable_https': sickbeard.ENABLE_HTTPS,
'https_port': sickbeard.HTTPS_PORT,
'https_cert': sickbeard.HTTPS_CERT,
'https_key': sickbeard.HTTPS_KEY,
})
except IOError:
logger.log(u"Unable to start web server, is something else running on port %d?" % startPort, logger.ERROR)
Expand Down
3 changes: 2 additions & 1 deletion autoProcessTV/autoProcessTV.cfg.sample
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@ host=localhost
port=8081
username=
password=
web_root=
web_root=
ssl=0
8 changes: 7 additions & 1 deletion autoProcessTV/autoProcessTV.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ def processEpisode(dirName, nzbName=None):
port = config.get("SickBeard", "port")
username = config.get("SickBeard", "username")
password = config.get("SickBeard", "password")
ssl = config.get("SickBeard", "ssl")

try:
web_root = config.get("SickBeard", "web_root")
Expand All @@ -73,7 +74,12 @@ def processEpisode(dirName, nzbName=None):

myOpener = AuthURLOpener(username, password)

url = "http://" + host + ":" + port + web_root + "/home/postprocess/processEpisode?" + urllib.urlencode(params)
if ssl:
protocol = "https://"
else:
protocol = "http://"

url = protocol + host + ":" + port + web_root + "/home/postprocess/processEpisode?" + urllib.urlencode(params)

print "Opening URL:", url

Expand Down
56 changes: 55 additions & 1 deletion data/interfaces/default/config_general.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,60 @@

<div id="core-component-group3" class="component-group clearfix">

<div class="component-group-desc">
<h3>HTTPS Support</h3>
<p><b>Some options may require a manual restart to take effect.</b></p>
</div>

<fieldset class="component-group-list">
<div class="field-pair">
<label class="clearfix">
<input type="checkbox" name="enable_https" class="enabler" id="enable_https" #if $sickbeard.ENABLE_HTTPS then "checked=\"checked\"" else ""#/>
<span class="component-title">Enable HTTPS</span>
<span class="component-desc">Enable accessing the interface from a HTTPS address.</span>
</label>
</div>
<div id="content_enable_https">
<div class="field-pair">
<label class="nocheck clearfix">
<span class="component-title">HTTPS Port</span>
<input type="text" name="https_port" value="$sickbeard.HTTPS_PORT" size="10" />
</label>
<label class="nocheck clearfix">
<span class="component-title">&nbsp;</span>
<span class="component-desc">If empty, the standard port will only listen to HTTPS.</span>
</label>
</div>

<div class="field-pair">
<label class="nocheck clearfix">
<span class="component-title">HTTPS Certificate</span>
<input type="text" name="https_cert" value="$sickbeard.HTTPS_CERT" size="35" />
</label>
<label class="nocheck clearfix">
<span class="component-title">&nbsp;</span>
<span class="component-desc">File name or path to HTTPS Certificate.</span>
</label>
</div>

<div class="field-pair">
<label class="nocheck clearfix">
<span class="component-title">HTTPS Key</span>
<input type="text" name="https_key" value="$sickbeard.HTTPS_KEY" size="35" />
</label>
<label class="nocheck clearfix">
<span class="component-title">&nbsp;</span>
<span class="component-desc">File name or path to HTTPS Key.</span>
</label>
</div>
</div>

<input type="submit" class="config_submitter" value="Save Changes" />
</fieldset>
</div><!-- /component-group3 -->

<div id="core-component-group4" class="component-group clearfix">

<div class="component-group-desc">
<h3>API</h3>
<p>Allow 3rd party programs to interact with Sick-Beard.</p>
Expand Down Expand Up @@ -157,7 +211,7 @@

<input type="submit" class="config_submitter" value="Save Changes" />
</fieldset>
</div><!-- /component-group3 //-->
</div><!-- /component-group4 //-->

<br/><input type="submit" class="config_submitter" value="Save Changes" /><br/>
</div><!-- /config-components -->
Expand Down
82 changes: 82 additions & 0 deletions lib/certgen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# -*- coding: latin-1 -*-
#
# Copyright (C) Martin Sjögren and AB Strakt 2001, All rights reserved
# Copyright (C) Jean-Paul Calderone 2008, All rights reserved
# This file is licenced under the GNU LESSER GENERAL PUBLIC LICENSE Version 2.1 or later (aka LGPL v2.1)
# Please see LGPL2.1.txt for more information
"""
Certificate generation module.
"""

from OpenSSL import crypto
import time

TYPE_RSA = crypto.TYPE_RSA
TYPE_DSA = crypto.TYPE_DSA

serial = int(time.time())


def createKeyPair(type, bits):
"""
Create a public/private key pair.
Arguments: type - Key type, must be one of TYPE_RSA and TYPE_DSA
bits - Number of bits to use in the key
Returns: The public/private key pair in a PKey object
"""
pkey = crypto.PKey()
pkey.generate_key(type, bits)
return pkey

def createCertRequest(pkey, digest="md5", **name):
"""
Create a certificate request.
Arguments: pkey - The key to associate with the request
digest - Digestion method to use for signing, default is md5
**name - The name of the subject of the request, possible
arguments are:
C - Country name
ST - State or province name
L - Locality name
O - Organization name
OU - Organizational unit name
CN - Common name
emailAddress - E-mail address
Returns: The certificate request in an X509Req object
"""
req = crypto.X509Req()
subj = req.get_subject()

for (key,value) in name.items():
setattr(subj, key, value)

req.set_pubkey(pkey)
req.sign(pkey, digest)
return req

def createCertificate(req, (issuerCert, issuerKey), serial, (notBefore, notAfter), digest="md5"):
"""
Generate a certificate given a certificate request.
Arguments: req - Certificate reqeust to use
issuerCert - The certificate of the issuer
issuerKey - The private key of the issuer
serial - Serial number for the certificate
notBefore - Timestamp (relative to now) when the certificate
starts being valid
notAfter - Timestamp (relative to now) when the certificate
stops being valid
digest - Digest method to use for signing, default is md5
Returns: The signed certificate in an X509 object
"""
cert = crypto.X509()
cert.set_serial_number(serial)
cert.gmtime_adj_notBefore(notBefore)
cert.gmtime_adj_notAfter(notAfter)
cert.set_issuer(issuerCert.get_subject())
cert.set_subject(req.get_subject())
cert.set_pubkey(req.get_pubkey())
cert.sign(issuerKey, digest)
return cert
33 changes: 31 additions & 2 deletions sickbeard/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@
USE_API = False
API_KEY = None

ENABLE_HTTPS = False
HTTPS_PORT = None
HTTPS_CERT = None
HTTPS_KEY = None

LAUNCH_BROWSER = None
CACHE_DIR = None
ACTUAL_CACHE_DIR = None
Expand Down Expand Up @@ -362,7 +367,7 @@ def initialize(consoleLogging=True):

with INIT_LOCK:

global LOG_DIR, WEB_PORT, WEB_LOG, WEB_ROOT, WEB_USERNAME, WEB_PASSWORD, WEB_HOST, WEB_IPV6, USE_API, API_KEY, \
global LOG_DIR, WEB_PORT, WEB_LOG, WEB_ROOT, WEB_USERNAME, WEB_PASSWORD, WEB_HOST, WEB_IPV6, USE_API, API_KEY, ENABLE_HTTPS, HTTPS_PORT, HTTPS_CERT, HTTPS_KEY, \
USE_NZBS, USE_TORRENTS, NZB_METHOD, NZB_DIR, DOWNLOAD_PROPERS, \
SAB_USERNAME, SAB_PASSWORD, SAB_APIKEY, SAB_CATEGORY, SAB_HOST, \
NZBGET_PASSWORD, NZBGET_CATEGORY, NZBGET_HOST, currentSearchScheduler, backlogSearchScheduler, \
Expand Down Expand Up @@ -434,6 +439,20 @@ def initialize(consoleLogging=True):

USE_API = bool(check_setting_int(CFG, 'General', 'use_api', 0))
API_KEY = check_setting_str(CFG, 'General', 'api_key', '')

ENABLE_HTTPS = bool(check_setting_int(CFG, 'General', 'enable_https', 0))

try:
HTTPS_PORT = check_setting_str(CFG, 'General', 'https_port', '9091')
except:
HTTPS_PORT = '9091'

if HTTPS_PORT:
if int(HTTPS_PORT) < 21 or int(HTTPS_PORT) > 65535:
HTTPS_PORT = '9091'

HTTPS_CERT = check_setting_str(CFG, 'General', 'https_cert', 'server.crt')
HTTPS_KEY = check_setting_str(CFG, 'General', 'https_key', 'server.key')

ACTUAL_CACHE_DIR = check_setting_str(CFG, 'General', 'cache_dir', 'cache')
# fix bad configs due to buggy code
Expand Down Expand Up @@ -970,6 +989,10 @@ def save_config():
new_config['General']['web_password'] = WEB_PASSWORD
new_config['General']['use_api'] = int(USE_API)
new_config['General']['api_key'] = API_KEY
new_config['General']['enable_https'] = int(ENABLE_HTTPS)
new_config['General']['https_port'] = HTTPS_PORT
new_config['General']['https_cert'] = HTTPS_CERT
new_config['General']['https_key'] = HTTPS_KEY
new_config['General']['use_nzbs'] = int(USE_NZBS)
new_config['General']['use_torrents'] = int(USE_TORRENTS)
new_config['General']['nzb_method'] = NZB_METHOD
Expand Down Expand Up @@ -1157,7 +1180,13 @@ def save_config():
def launchBrowser(startPort=None):
if not startPort:
startPort = WEB_PORT
browserURL = 'http://localhost:%d%s' % (startPort, WEB_ROOT)
if ENABLE_HTTPS:
if HTTPS_PORT:
browserURL = 'https://localhost:%d%s' % (int(HTTPS_PORT), WEB_ROOT)
else:
browserURL = 'https://localhost:%d%s' % (startPort, WEB_ROOT)
else:
browserURL = 'http://localhost:%d%s' % (startPort, WEB_ROOT)
try:
webbrowser.open(browserURL, 2, 1)
except:
Expand Down
30 changes: 30 additions & 0 deletions sickbeard/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,36 @@
naming_sep_type = (" - ", " ")
naming_sep_type_text = (" - ", "space")

def change_HTTPS_CERT(https_cert):

if https_cert == '':
sickbeard.HTTPS_CERT = ''
return True

if os.path.normpath(sickbeard.HTTPS_CERT) != os.path.normpath(https_cert):
if helpers.makeDir(os.path.dirname(os.path.abspath(https_cert))):
sickbeard.HTTPS_CERT = os.path.normpath(https_cert)
logger.log(u"Changed https cert path to " + https_cert)
else:
return False

return True

def change_HTTPS_KEY(https_key):

if https_key == '':
sickbeard.HTTPS_KEY = ''
return True

if os.path.normpath(sickbeard.HTTPS_KEY) != os.path.normpath(https_key):
if helpers.makeDir(os.path.dirname(os.path.abspath(https_key))):
sickbeard.HTTPS_KEY = os.path.normpath(https_key)
logger.log(u"Changed https key path to " + https_key)
else:
return False

return True

def change_LOG_DIR(log_dir):

if os.path.normpath(sickbeard.LOG_DIR) != os.path.normpath(log_dir):
Expand Down
30 changes: 30 additions & 0 deletions sickbeard/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,36 @@ def sanitizeSceneName (name, ezrss=False):

return name

def create_https_certificates(ssl_cert, ssl_key):
""" Create self-signed HTTPS certificares and store in paths 'ssl_cert' and 'ssl_key'
"""
try:
from OpenSSL import crypto
from lib.certgen import createKeyPair, createCertRequest, createCertificate, \
TYPE_RSA, serial
except:
logger.log(u"pyopenssl module missing, please install for https access", logger.WARNING)
return False

# Create the CA Certificate
cakey = createKeyPair(TYPE_RSA, 1024)
careq = createCertRequest(cakey, CN='Certificate Authority')
cacert = createCertificate(careq, (careq, cakey), serial, (0, 60*60*24*365*10)) # ten years

cname = 'SickBeard'
pkey = createKeyPair(TYPE_RSA, 1024)
req = createCertRequest(pkey, CN=cname)
cert = createCertificate(req, (cacert, cakey), serial, (0, 60*60*24*365*10)) # ten years

# Save the key and certificate to disk
try:
open(ssl_key, 'w').write(crypto.dump_privatekey(crypto.FILETYPE_PEM, pkey))
open(ssl_cert, 'w').write(crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
except:
logger.log(u"Error creating SSL key and certificate", logger.ERROR)
return False

return True

if __name__ == '__main__':
import doctest
Expand Down
Loading

0 comments on commit 32123d9

Please sign in to comment.