From 6e3862d7ab3d0658218d1e4ece95956f155b872a Mon Sep 17 00:00:00 2001
From: Hidden Z
Date: Mon, 26 Oct 2015 18:55:35 +0000
Subject: [PATCH] Convert tabs to spaces
---
bin/py-i2phosts-builder | 32 +--
bin/py-i2phosts-checker | 98 +++----
bin/py-i2phosts-fetcher | 166 +++++------
bin/py-i2phosts-injector | 108 ++++----
bin/py-i2phosts-maint | 152 +++++-----
bin/py-i2phosts-master | 200 ++++++-------
pyi2phosts/api/urls.py | 2 +-
pyi2phosts/api/views.py | 16 +-
pyi2phosts/extsources/admin.py | 4 +-
pyi2phosts/extsources/models.py | 18 +-
pyi2phosts/jump/urls.py | 4 +-
pyi2phosts/jump/views.py | 80 +++---
pyi2phosts/latest/urls.py | 4 +-
pyi2phosts/latest/views.py | 36 +--
pyi2phosts/lib/generic.py | 80 +++---
pyi2phosts/lib/rss.py | 40 +--
pyi2phosts/lib/utils.py | 92 +++---
pyi2phosts/lib/validation.py | 212 +++++++-------
pyi2phosts/postkey/admin.py | 58 ++--
pyi2phosts/postkey/models.py | 42 +--
pyi2phosts/postkey/urls.py | 6 +-
pyi2phosts/postkey/views.py | 262 +++++++++---------
pyi2phosts/search/urls.py | 2 +-
pyi2phosts/search/views.py | 18 +-
pyi2phosts/settings.py | 10 +-
pyi2phosts/static-common/base.css | 144 +++++-----
pyi2phosts/static-common/inproxy.html | 10 +-
pyi2phosts/static-common/rss-grey-18.png | Bin 670 -> 676 bytes
pyi2phosts/templates/404.html | 2 +-
pyi2phosts/templates/500.html | 2 +-
pyi2phosts/templates/base.html | 108 ++++----
pyi2phosts/templates/browse.html | 8 +-
pyi2phosts/templates/contacts.html | 10 +-
pyi2phosts/templates/faq.html | 24 +-
pyi2phosts/templates/index.html | 88 +++---
pyi2phosts/templates/policy.html | 20 +-
pyi2phosts/templates/postkey.html | 12 +-
.../templates/subdomain_http_verify.html | 10 +-
pyi2phosts/urls.py | 28 +-
setup.py | 28 +-
40 files changed, 1121 insertions(+), 1115 deletions(-)
diff --git a/bin/py-i2phosts-builder b/bin/py-i2phosts-builder
index b7d27b1..d4810b2 100755
--- a/bin/py-i2phosts-builder
+++ b/bin/py-i2phosts-builder
@@ -7,32 +7,32 @@ import configobj
# parse command line options
parser = argparse.ArgumentParser(
- description='Hosts builder for py-i2phosts.',
- epilog='Report bugs to http://zzz.i2p/topics/733')
+ description='Hosts builder for py-i2phosts.',
+ epilog='Report bugs to http://zzz.i2p/topics/733')
parser.add_argument('-c', '--config', default='/etc/py-i2phosts/builder.conf', dest='config_file',
- help='config file to use')
+ help='config file to use')
parser.add_argument('-f', '--file',
- help='write hosts into specified file')
+ help='write hosts into specified file')
parser.add_argument('-d', '--debug', action='store_true',
- help='write debug messages to stdout')
+ help='write debug messages to stdout')
args = parser.parse_args()
# read config
spec = '''
- hostsfile = string(default=None)
- '''
+ hostsfile = string(default=None)
+ '''
spec = spec.split('\n')
config = configobj.ConfigObj(args.config_file, configspec=spec, file_error=True)
if 'include' in config:
- config_included = configobj.ConfigObj(config['include'])
- config.merge(config_included)
+ config_included = configobj.ConfigObj(config['include'])
+ config.merge(config_included)
# django setup
DJANGO_SETTINGS_MODULE = 'pyi2phosts.settings'
if 'DJANGO_PROJECT_PATH' in config:
- DJANGO_PROJECT_PATH = config['DJANGO_PROJECT_PATH']
+ DJANGO_PROJECT_PATH = config['DJANGO_PROJECT_PATH']
else:
- DJANGO_PROJECT_PATH = os.path.dirname(sys.argv[0]) + '/..'
+ DJANGO_PROJECT_PATH = os.path.dirname(sys.argv[0]) + '/..'
sys.path.insert(1, DJANGO_PROJECT_PATH)
os.environ['DJANGO_SETTINGS_MODULE'] = DJANGO_SETTINGS_MODULE
from pyi2phosts.postkey.models import i2phost
@@ -43,12 +43,12 @@ validate_config(config)
# result hosts.txt
if args.file:
- hostsfile = args.file
+ hostsfile = args.file
elif config['hostsfile'] != None:
- hostsfile = config['hostsfile']
+ hostsfile = config['hostsfile']
else:
- sys.stderr.write('Please specify "-f" or define "hostsfile" in config\n')
- sys.exit(1)
+ sys.stderr.write('Please specify "-f" or define "hostsfile" in config\n')
+ sys.exit(1)
f = open(hostsfile, 'w')
# get activated hosts
@@ -57,5 +57,5 @@ qs = i2phost.objects.filter(activated=True)
l = qs.values('name', 'b64hash')
# write final hosts.txt-format file
for entry in l:
- f.write(entry['name'] + '=' + entry['b64hash'] + '\n')
+ f.write(entry['name'] + '=' + entry['b64hash'] + '\n')
f.close()
diff --git a/bin/py-i2phosts-checker b/bin/py-i2phosts-checker
index 17d2954..f4c494f 100755
--- a/bin/py-i2phosts-checker
+++ b/bin/py-i2phosts-checker
@@ -10,34 +10,34 @@ import time
# parse command line options
parser = argparse.ArgumentParser(
- description='Hosts checker for py-i2phosts.',
- epilog='Report bugs to http://zzz.i2p/topics/733')
+ description='Hosts checker for py-i2phosts.',
+ epilog='Report bugs to http://zzz.i2p/topics/733')
parser.add_argument('-d', '--debug', action='store_true',
- help='set loglevel to debug and write messages to stdout'),
+ help='set loglevel to debug and write messages to stdout'),
parser.add_argument('-v', '--verbose', action='store_true',
- help='set loglevel to info and write messages to stdout'),
+ help='set loglevel to info and write messages to stdout'),
parser.add_argument('-c', '--config', default='/etc/py-i2phosts/checker.conf', dest='config_file',
- help='config file to use')
+ help='config file to use')
args = parser.parse_args()
# read config
spec = '''
- log_file = string(default='/var/log/py-i2phosts/master.log')
- log_level = option('debug', 'info', 'warning', 'error', 'critical', default='info')
- lookup_retries = integer(1, 20, default=2)
- '''
+ log_file = string(default='/var/log/py-i2phosts/master.log')
+ log_level = option('debug', 'info', 'warning', 'error', 'critical', default='info')
+ lookup_retries = integer(1, 20, default=2)
+ '''
spec = spec.split('\n')
config = configobj.ConfigObj(args.config_file, configspec=spec)
if 'include' in config:
- config_included = configobj.ConfigObj(config['include'])
- config.merge(config_included)
+ config_included = configobj.ConfigObj(config['include'])
+ config.merge(config_included)
# django setup
DJANGO_SETTINGS_MODULE = 'pyi2phosts.settings'
if 'DJANGO_PROJECT_PATH' in config:
- DJANGO_PROJECT_PATH = config['DJANGO_PROJECT_PATH']
+ DJANGO_PROJECT_PATH = config['DJANGO_PROJECT_PATH']
else:
- DJANGO_PROJECT_PATH = os.path.dirname(sys.argv[0]) + '/..'
+ DJANGO_PROJECT_PATH = os.path.dirname(sys.argv[0]) + '/..'
sys.path.insert(1, DJANGO_PROJECT_PATH)
os.environ['DJANGO_SETTINGS_MODULE'] = DJANGO_SETTINGS_MODULE
from pyi2phosts.postkey.models import i2phost
@@ -50,22 +50,22 @@ validate_config(config)
# configure logger
if args.debug == True:
- log_level = 'debug'
- log_file = None
+ log_level = 'debug'
+ log_file = None
elif args.verbose == True:
- log_level = 'info'
- log_file = None
+ log_level = 'info'
+ log_file = None
else:
- log_level = config['log_level']
- log_file = config['log_file']
+ log_level = config['log_level']
+ log_file = config['log_file']
log = get_logger(filename=log_file, log_level=log_level)
# determine BOB interface address
if 'bob_addr' in config:
- bob_addr = config['bob_addr']
+ bob_addr = config['bob_addr']
else:
- log.warning('BOB address isn\'t specified in config, falling back to localhost')
- bob_addr = '127.0.0.1:2827'
+ log.warning('BOB address isn\'t specified in config, falling back to localhost')
+ bob_addr = '127.0.0.1:2827'
# split bob_addr to ip and port
bob_ip, bob_port = bob_addr.split(':')
@@ -73,37 +73,37 @@ bob_ip, bob_port = bob_addr.split(':')
# connect to BOB
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
- s.connect((bob_ip, int(bob_port)))
- # just receive BOB's greeting
- time.sleep(1)
- data = s.recv(512)
- # make file object
- f = s.makefile('r')
+ s.connect((bob_ip, int(bob_port)))
+ # just receive BOB's greeting
+ time.sleep(1)
+ data = s.recv(512)
+ # make file object
+ f = s.makefile('r')
except socket.error, e:
- log.error('failed to connect to BOB: %s', e)
- sys.exit(1)
+ log.error('failed to connect to BOB: %s', e)
+ sys.exit(1)
all_hosts = i2phost.objects.all().order_by('-activated', '-last_seen')
log.info('starting check')
for host in all_hosts:
- log.debug('%s: testing...', host.name)
- # get b32 address from full dest key
- dest = host.b64hash
- b32dest = get_b32(dest)
- # do name lookup query with b32 address
- # it success only if host is alive
- for i in range(config['lookup_retries']):
- s.send('lookup %s\n' % b32dest)
- data = f.readline().rstrip('\n')
- if data == 'ERROR Address Not found.':
- log.debug('%s: unable to resolve, try: %s', host.name, i)
- elif data == 'OK ' + host.b64hash:
- log.info('alive host: %s', host.name)
- # update lastseen timestamp
- host.last_seen = datetime.datetime.utcnow()
- host.save()
- break
- else:
- log.warning('unexpected reply: %s', data)
+ log.debug('%s: testing...', host.name)
+ # get b32 address from full dest key
+ dest = host.b64hash
+ b32dest = get_b32(dest)
+ # do name lookup query with b32 address
+ # it success only if host is alive
+ for i in range(config['lookup_retries']):
+ s.send('lookup %s\n' % b32dest)
+ data = f.readline().rstrip('\n')
+ if data == 'ERROR Address Not found.':
+ log.debug('%s: unable to resolve, try: %s', host.name, i)
+ elif data == 'OK ' + host.b64hash:
+ log.info('alive host: %s', host.name)
+ # update lastseen timestamp
+ host.last_seen = datetime.datetime.utcnow()
+ host.save()
+ break
+ else:
+ log.warning('unexpected reply: %s', data)
s.close()
log.info('check finished')
diff --git a/bin/py-i2phosts-fetcher b/bin/py-i2phosts-fetcher
index 649dd55..ab05816 100755
--- a/bin/py-i2phosts-fetcher
+++ b/bin/py-i2phosts-fetcher
@@ -15,32 +15,32 @@ import socket
# parse command line options
parser = argparse.ArgumentParser(
- description='Hosts fetcher for py-i2phosts.',
- epilog='Report bugs to http://zzz.i2p/topics/733')
+ description='Hosts fetcher for py-i2phosts.',
+ epilog='Report bugs to http://zzz.i2p/topics/733')
parser.add_argument('-d', '--debug', action='store_true',
- help='write debug messages to stdout instead of log file'),
+ help='write debug messages to stdout instead of log file'),
parser.add_argument('-c', '--config', default='/etc/py-i2phosts/fetcher.conf', dest='config_file',
- help='config file to use')
+ help='config file to use')
args = parser.parse_args()
# read config
spec = '''
- proxyurl = string(default='http://localhost:4444/')
- log_file = string(default='/var/log/py-i2phosts/fetcher.log')
- log_level = option('debug', 'info', 'warning', 'error', 'critical', default='info')
- '''
+ proxyurl = string(default='http://localhost:4444/')
+ log_file = string(default='/var/log/py-i2phosts/fetcher.log')
+ log_level = option('debug', 'info', 'warning', 'error', 'critical', default='info')
+ '''
spec = spec.split('\n')
config = configobj.ConfigObj(args.config_file, configspec=spec, file_error=True)
if 'include' in config:
- config_included = configobj.ConfigObj(config['include'])
- config.merge(config_included)
+ config_included = configobj.ConfigObj(config['include'])
+ config.merge(config_included)
# django setup
DJANGO_SETTINGS_MODULE = 'pyi2phosts.settings'
if 'DJANGO_PROJECT_PATH' in config:
- DJANGO_PROJECT_PATH = config['DJANGO_PROJECT_PATH']
+ DJANGO_PROJECT_PATH = config['DJANGO_PROJECT_PATH']
else:
- DJANGO_PROJECT_PATH = os.path.dirname(sys.argv[0]) + '/..'
+ DJANGO_PROJECT_PATH = os.path.dirname(sys.argv[0]) + '/..'
sys.path.insert(1, DJANGO_PROJECT_PATH)
os.environ['DJANGO_SETTINGS_MODULE'] = DJANGO_SETTINGS_MODULE
from pyi2phosts.lib.utils import get_logger
@@ -52,11 +52,11 @@ validate_config(config)
# configure logger
if args.debug == True:
- log_level = 'debug'
- log_file = None
+ log_level = 'debug'
+ log_file = None
else:
- log_level = config['log_level']
- log_file = config['log_file']
+ log_level = config['log_level']
+ log_file = config['log_file']
log = get_logger(filename=log_file, log_level=log_level)
# we want open urls through proxy
@@ -66,70 +66,70 @@ opener = urllib2.build_opener(proxy_handler)
all_sources = ExternalSource.objects.filter(active=True)
for source in all_sources:
- log.debug('%s: starting work', source.name)
- if source.last_modified:
- last_modified = source.last_modified.strftime('%a, %d %b %Y %H:%M:%S GMT')
- # prevent redownloading of hosts-file by passing If-Modified-Since http header
- opener.addheaders = [('If-Modified-Since', last_modified)]
- log.debug('%s: appending If-Modified-Since: %s', source.name, last_modified)
- if source.etag:
- opener.addheaders = [('If-None-Match', source.etag)]
- log.debug('%s: appending If-None-Match: %s', source.name, source.etag)
- try:
- log.debug('%s: sending GET...', source.name)
- resp = opener.open(source.url, timeout=60)
- except socket.timeout:
- log.warning('%s: socket timeout', source.name)
- continue
- except urllib2.HTTPError, e:
- if e.code == 304:
- log.info('%s: not modified', source.name)
- source.last_success = datetime.datetime.utcnow()
- source.save()
- else:
- log.warning('%s: can\'t finish the request, error code: %s, reason: %s', source.name, e.code, e.reason)
- continue
- except urllib2.URLError, e:
- log.warning('%s: failed to reach server, reason: %s', source.name, e.reason)
- continue
- # read data from remote and write it to local file
- try:
- log.debug('%s: reading response data', source.name)
- content = resp.read()
- except:
- log.warning('%s: failed to read data', source.name)
- continue
- # save fetched content into temporary file
- fd, tmpfile = tempfile.mkstemp(text=True)
- f = os.fdopen(fd, 'w')
- f.write(content)
- f.close()
- # get last-modified info from header
- lm = resp.headers.get('Last-Modified')
- if lm:
- log.debug('%s: Last-Modified: %s', source.name, lm)
- source.last_modified = datetime.datetime.strptime(lm, '%a, %d %b %Y %H:%M:%S GMT')
- # get ETag
- etag = resp.headers.get('ETag')
- if etag:
- log.debug('%s: ETag: %s', source.name, etag)
- source.etag = etag
- # form command-line for invoke injector
- log.info('%s: adding hosts...', source.name)
- sp_args = ['py-i2phosts-injector', '-s', '-f', tmpfile, '-d',
- 'Auto-added from ' + source.name]
- try:
- p = subprocess.Popen(sp_args, shell=False, stdin=None,
- stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
- except OSError, e:
- log.error('failed to exec py-i2phosts-injector: %s', e)
- if e.errno == errno.ENOENT:
- log.error('check your PATH environment variable')
- sys.exit(1)
- out = p.communicate()[0]
- os.remove(tmpfile)
- log.info('%s: injector output: \n%s', source.name, out)
- # update last_success
- source.last_success = datetime.datetime.utcnow()
- log.debug('%s: updating last_success timestamp: %s', source.name, source.last_success)
- source.save()
+ log.debug('%s: starting work', source.name)
+ if source.last_modified:
+ last_modified = source.last_modified.strftime('%a, %d %b %Y %H:%M:%S GMT')
+ # prevent redownloading of hosts-file by passing If-Modified-Since http header
+ opener.addheaders = [('If-Modified-Since', last_modified)]
+ log.debug('%s: appending If-Modified-Since: %s', source.name, last_modified)
+ if source.etag:
+ opener.addheaders = [('If-None-Match', source.etag)]
+ log.debug('%s: appending If-None-Match: %s', source.name, source.etag)
+ try:
+ log.debug('%s: sending GET...', source.name)
+ resp = opener.open(source.url, timeout=60)
+ except socket.timeout:
+ log.warning('%s: socket timeout', source.name)
+ continue
+ except urllib2.HTTPError, e:
+ if e.code == 304:
+ log.info('%s: not modified', source.name)
+ source.last_success = datetime.datetime.utcnow()
+ source.save()
+ else:
+ log.warning('%s: can\'t finish the request, error code: %s, reason: %s', source.name, e.code, e.reason)
+ continue
+ except urllib2.URLError, e:
+ log.warning('%s: failed to reach server, reason: %s', source.name, e.reason)
+ continue
+ # read data from remote and write it to local file
+ try:
+ log.debug('%s: reading response data', source.name)
+ content = resp.read()
+ except:
+ log.warning('%s: failed to read data', source.name)
+ continue
+ # save fetched content into temporary file
+ fd, tmpfile = tempfile.mkstemp(text=True)
+ f = os.fdopen(fd, 'w')
+ f.write(content)
+ f.close()
+ # get last-modified info from header
+ lm = resp.headers.get('Last-Modified')
+ if lm:
+ log.debug('%s: Last-Modified: %s', source.name, lm)
+ source.last_modified = datetime.datetime.strptime(lm, '%a, %d %b %Y %H:%M:%S GMT')
+ # get ETag
+ etag = resp.headers.get('ETag')
+ if etag:
+ log.debug('%s: ETag: %s', source.name, etag)
+ source.etag = etag
+ # form command-line for invoke injector
+ log.info('%s: adding hosts...', source.name)
+ sp_args = ['py-i2phosts-injector', '-s', '-f', tmpfile, '-d',
+ 'Auto-added from ' + source.name]
+ try:
+ p = subprocess.Popen(sp_args, shell=False, stdin=None,
+ stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
+ except OSError, e:
+ log.error('failed to exec py-i2phosts-injector: %s', e)
+ if e.errno == errno.ENOENT:
+ log.error('check your PATH environment variable')
+ sys.exit(1)
+ out = p.communicate()[0]
+ os.remove(tmpfile)
+ log.info('%s: injector output: \n%s', source.name, out)
+ # update last_success
+ source.last_success = datetime.datetime.utcnow()
+ log.debug('%s: updating last_success timestamp: %s', source.name, source.last_success)
+ source.save()
diff --git a/bin/py-i2phosts-injector b/bin/py-i2phosts-injector
index 6fb8467..a167f30 100755
--- a/bin/py-i2phosts-injector
+++ b/bin/py-i2phosts-injector
@@ -10,34 +10,34 @@ from django.core.exceptions import ValidationError
# parse command line options
parser = argparse.ArgumentParser(
- description='Hosts injector for py-i2phosts.',
- epilog='Report bugs to http://zzz.i2p/topics/733')
+ description='Hosts injector for py-i2phosts.',
+ epilog='Report bugs to http://zzz.i2p/topics/733')
parser.add_argument('-c', '--config', default='/etc/py-i2phosts/injector.conf', dest='config_file',
- help='config file to use')
+ help='config file to use')
parser.add_argument('-f', '--file', dest='hostsfile',
- help='hosts.txt for parsing')
+ help='hosts.txt for parsing')
parser.add_argument('-d', '--description', default='Auto-added from external hosts.txt',
- help='provide custom description message')
+ help='provide custom description message')
parser.add_argument('-a', '--approve', action='store_true',
- help='add hosts as approved')
+ help='add hosts as approved')
parser.add_argument('-s', '--supress', action='store_true',
- help='supress warnings about already existed hostnames'),
+ help='supress warnings about already existed hostnames'),
parser.add_argument('-q', '--quiet', action='store_true',
- help='be completely quiet, print only errors')
+ help='be completely quiet, print only errors')
args = parser.parse_args()
# read config
config = configobj.ConfigObj(args.config_file)
if 'include' in config:
- config_included = configobj.ConfigObj(config['include'])
- config.merge(config_included)
+ config_included = configobj.ConfigObj(config['include'])
+ config.merge(config_included)
# django setup
DJANGO_SETTINGS_MODULE = 'pyi2phosts.settings'
if 'DJANGO_PROJECT_PATH' in config:
- DJANGO_PROJECT_PATH = config['DJANGO_PROJECT_PATH']
+ DJANGO_PROJECT_PATH = config['DJANGO_PROJECT_PATH']
else:
- DJANGO_PROJECT_PATH = os.path.dirname(sys.argv[0]) + '/..'
+ DJANGO_PROJECT_PATH = os.path.dirname(sys.argv[0]) + '/..'
sys.path.insert(1, DJANGO_PROJECT_PATH)
os.environ['DJANGO_SETTINGS_MODULE'] = DJANGO_SETTINGS_MODULE
from pyi2phosts.postkey.models import i2phost
@@ -46,57 +46,57 @@ from pyi2phosts.lib.validation import validate_b64hash
# determine approve hosts or not
if args.approve or config.as_bool('approve'):
- approved = True
+ approved = True
else:
- approved = False
+ approved = False
# turn on output supressing if quiet
if args.quiet:
- args.supress = True
+ args.supress = True
# determine what hosts.txt file we should parse
if args.hostsfile:
- hostsfile = args.hostsfile
+ hostsfile = args.hostsfile
else:
- env = os.environ
- if 'HOME' in env:
- hostsfile = os.environ['HOME'] + '/.i2p/hosts.txt'
- else:
- sys.stderr.write('unable to determine hosts file for parsing\n')
- sys.exit(1)
+ env = os.environ
+ if 'HOME' in env:
+ hostsfile = os.environ['HOME'] + '/.i2p/hosts.txt'
+ else:
+ sys.stderr.write('unable to determine hosts file for parsing\n')
+ sys.exit(1)
f = open(args.hostsfile, 'r')
for line in f:
- # ignore comments and empty lines
- if line.startswith('#') or line.isspace():
- continue
- if line.find('=') == -1:
- sys.stdout.write('Invalid line: %s\n' % line)
- continue
- # strip trailing '\n'
- line = line.rstrip('\n')
- entry = line.split('=', 1)
- try:
- hostname = validate_hostname(entry[0])
- base64 = validate_b64hash(entry[1], check_uniq=False) # don't require uniqueness
- except ValidationError, e:
- sys.stdout.write('validation error: %s: %s\n\n' % (e, line))
- else:
- # Check for already existed hosts in database to avoid unneeded INSERTs
- # beacuse they will fail anyway.
- try:
- h = i2phost.objects.get(name=hostname)
- except i2phost.DoesNotExist:
- if not args.quiet:
- sys.stdout.write('Adding %s\n' % hostname)
- host = i2phost(name=hostname, b64hash=base64,
- description=args.description,
- date_added=datetime.datetime.utcnow(),
- activated=False, external=True, approved=approved)
- host.save()
- else:
- if not args.supress:
- sys.stdout.write('Host %s already exists\n' % hostname)
- if h.b64hash != base64:
- sys.stdout.write('Key conflict for host: %s\n' % hostname)
+ # ignore comments and empty lines
+ if line.startswith('#') or line.isspace():
+ continue
+ if line.find('=') == -1:
+ sys.stdout.write('Invalid line: %s\n' % line)
+ continue
+ # strip trailing '\n'
+ line = line.rstrip('\n')
+ entry = line.split('=', 1)
+ try:
+ hostname = validate_hostname(entry[0])
+ base64 = validate_b64hash(entry[1], check_uniq=False) # don't require uniqueness
+ except ValidationError, e:
+ sys.stdout.write('validation error: %s: %s\n\n' % (e, line))
+ else:
+ # Check for already existed hosts in database to avoid unneeded INSERTs
+ # beacuse they will fail anyway.
+ try:
+ h = i2phost.objects.get(name=hostname)
+ except i2phost.DoesNotExist:
+ if not args.quiet:
+ sys.stdout.write('Adding %s\n' % hostname)
+ host = i2phost(name=hostname, b64hash=base64,
+ description=args.description,
+ date_added=datetime.datetime.utcnow(),
+ activated=False, external=True, approved=approved)
+ host.save()
+ else:
+ if not args.supress:
+ sys.stdout.write('Host %s already exists\n' % hostname)
+ if h.b64hash != base64:
+ sys.stdout.write('Key conflict for host: %s\n' % hostname)
f.close()
diff --git a/bin/py-i2phosts-maint b/bin/py-i2phosts-maint
index d445a01..95693f2 100755
--- a/bin/py-i2phosts-maint
+++ b/bin/py-i2phosts-maint
@@ -10,37 +10,37 @@ import configobj
# parse command line options
parser = argparse.ArgumentParser(
- description='Hosts maintainer for py-i2phosts.',
- epilog='Report bugs to http://zzz.i2p/topics/733')
+ description='Hosts maintainer for py-i2phosts.',
+ epilog='Report bugs to http://zzz.i2p/topics/733')
parser.add_argument('-d', '--debug', action='store_true',
- help='write debug messages to stdout')
+ help='write debug messages to stdout')
parser.add_argument('-c', '--config', default='/etc/py-i2phosts/maintainer.conf', dest='config_file',
- help='config file to use')
+ help='config file to use')
args = parser.parse_args()
# read config
spec = '''
- log_file = string(default='/var/log/py-i2phosts/maintainer.log')
- log_level = option('debug', 'info', 'warning', 'error', 'critical', default='info')
- external_inactive_max = integer(default=365)
- internal_inactive_max = integer(default=14)
- external_expires = integer(default=30)
- internal_expires = integer(default=30)
- activate_min_delay = integer(default=3)
- keep_expired = integer(default=730)
- '''
+ log_file = string(default='/var/log/py-i2phosts/maintainer.log')
+ log_level = option('debug', 'info', 'warning', 'error', 'critical', default='info')
+ external_inactive_max = integer(default=365)
+ internal_inactive_max = integer(default=14)
+ external_expires = integer(default=30)
+ internal_expires = integer(default=30)
+ activate_min_delay = integer(default=3)
+ keep_expired = integer(default=730)
+ '''
spec = spec.split('\n')
config = configobj.ConfigObj(args.config_file, configspec=spec)
if 'include' in config:
- config_included = configobj.ConfigObj(config['include'])
- config.merge(config_included)
+ config_included = configobj.ConfigObj(config['include'])
+ config.merge(config_included)
# django setup
DJANGO_SETTINGS_MODULE = 'pyi2phosts.settings'
if 'DJANGO_PROJECT_PATH' in config:
- DJANGO_PROJECT_PATH = config['DJANGO_PROJECT_PATH']
+ DJANGO_PROJECT_PATH = config['DJANGO_PROJECT_PATH']
else:
- DJANGO_PROJECT_PATH = os.path.dirname(sys.argv[0]) + '/..'
+ DJANGO_PROJECT_PATH = os.path.dirname(sys.argv[0]) + '/..'
sys.path.insert(1, DJANGO_PROJECT_PATH)
os.environ['DJANGO_SETTINGS_MODULE'] = DJANGO_SETTINGS_MODULE
from pyi2phosts.postkey.models import i2phost
@@ -52,68 +52,68 @@ validate_config(config)
# configure logger
if args.debug == True:
- log_level = 'debug'
- log_file = None
+ log_level = 'debug'
+ log_file = None
else:
- log_level = config['log_level']
- log_file = config['log_file']
+ log_level = config['log_level']
+ log_file = config['log_file']
log = get_logger(filename=log_file, log_level=log_level)
all_hosts = i2phost.objects.all()
log.info('starting maintenance')
for host in all_hosts:
- # how long host was added
- dl = datetime.datetime.utcnow() - host.date_added
- if host.last_seen == None:
- # delete external hosts which we never seen after X days of inactivity
- if host.external == True:
- if dl > datetime.timedelta(days=config['external_inactive_max']):
- log.info('deleting %s, reason: external host, never seen for %s days',
- host.name, config['external_inactive_max'])
- host.delete()
- continue
- # delete hosts added by us and never seen after X days of inactivity
- else:
- if dl > datetime.timedelta(days=config['internal_inactive_max']):
- log.info('deleting %s, reason: internal host, never seen for %s days',
- host.name, config['internal_inactive_max'])
- host.delete()
- continue
- else:
- # configure registration period for hosts
- if host.external == True:
- timedelta = datetime.timedelta(days=config['external_expires'])
- else:
- timedelta = datetime.timedelta(days=config['internal_expires'])
- # get current host expiration date from database
- if host.expires == None:
- # workaround for situation when we updating expires first time
- expires_current = datetime.datetime.utcnow().date()
- else:
- expires_current = host.expires
- # calculate new expiration date
- expires_new = host.last_seen + timedelta
- expires_new = expires_new.date()
- # update expiration date only if changed
- if expires_new > expires_current:
- log.debug('updating expires for %s', host.name)
- host.expires = expires_new
- # deactivate if expired
- min_dl = datetime.timedelta(days=config['activate_min_delay'])
- if host.expires < datetime.datetime.utcnow().date():
- if host.activated == True:
- log.info('deactivating %s, reason: expired', host.name)
- host.activated = False
- # if not expired and added more than X days ago and approved then activate
- elif dl > min_dl and host.activated == False and host.approved == True:
- log.info('activating %s, reason: host up and added more than %s days ago',
- host.name, config['activate_min_delay'])
- host.activated = True
- # if expired X days ago then delete
- dl_e = datetime.datetime.utcnow().date() - host.expires
- if dl_e > datetime.timedelta(days=config['keep_expired']):
- log.info('deleting %s, reason: expired %s days ago',
- host.name, config['keep_expired'])
- host.delete()
- continue
- host.save()
+ # how long host was added
+ dl = datetime.datetime.utcnow() - host.date_added
+ if host.last_seen == None:
+ # delete external hosts which we never seen after X days of inactivity
+ if host.external == True:
+ if dl > datetime.timedelta(days=config['external_inactive_max']):
+ log.info('deleting %s, reason: external host, never seen for %s days',
+ host.name, config['external_inactive_max'])
+ host.delete()
+ continue
+ # delete hosts added by us and never seen after X days of inactivity
+ else:
+ if dl > datetime.timedelta(days=config['internal_inactive_max']):
+ log.info('deleting %s, reason: internal host, never seen for %s days',
+ host.name, config['internal_inactive_max'])
+ host.delete()
+ continue
+ else:
+ # configure registration period for hosts
+ if host.external == True:
+ timedelta = datetime.timedelta(days=config['external_expires'])
+ else:
+ timedelta = datetime.timedelta(days=config['internal_expires'])
+ # get current host expiration date from database
+ if host.expires == None:
+ # workaround for situation when we updating expires first time
+ expires_current = datetime.datetime.utcnow().date()
+ else:
+ expires_current = host.expires
+ # calculate new expiration date
+ expires_new = host.last_seen + timedelta
+ expires_new = expires_new.date()
+ # update expiration date only if changed
+ if expires_new > expires_current:
+ log.debug('updating expires for %s', host.name)
+ host.expires = expires_new
+ # deactivate if expired
+ min_dl = datetime.timedelta(days=config['activate_min_delay'])
+ if host.expires < datetime.datetime.utcnow().date():
+ if host.activated == True:
+ log.info('deactivating %s, reason: expired', host.name)
+ host.activated = False
+ # if not expired and added more than X days ago and approved then activate
+ elif dl > min_dl and host.activated == False and host.approved == True:
+ log.info('activating %s, reason: host up and added more than %s days ago',
+ host.name, config['activate_min_delay'])
+ host.activated = True
+ # if expired X days ago then delete
+ dl_e = datetime.datetime.utcnow().date() - host.expires
+ if dl_e > datetime.timedelta(days=config['keep_expired']):
+ log.info('deleting %s, reason: expired %s days ago',
+ host.name, config['keep_expired'])
+ host.delete()
+ continue
+ host.save()
diff --git a/bin/py-i2phosts-master b/bin/py-i2phosts-master
index 0dc8d26..8dcc8ab 100755
--- a/bin/py-i2phosts-master
+++ b/bin/py-i2phosts-master
@@ -13,119 +13,125 @@ import threading
import daemon
# workaround for python-daemon >= 1.6
try:
+<<<<<<< HEAD
import daemon.pidlockfile as pidfile
except ImportError:
import daemon.pidfile as pidfile
+=======
+ import daemon.pidlockfile as pidfile
+except ImportError:
+ import daemon.pidfile as pidfile
+>>>>>>> 923b94f... Convert tabs to spaces
class Thread(threading.Thread):
- def __init__(self):
- threading.Thread.__init__(self)
- self.setDaemon(True)
+ def __init__(self):
+ threading.Thread.__init__(self)
+ self.setDaemon(True)
class FetcherThread(Thread):
- """ Run py-i2phosts-fetcher periodically """
+ """ Run py-i2phosts-fetcher periodically """
- def run(self):
- while True:
- run_prog('py-i2phosts-fetcher')
- time.sleep(float(config['fetch_interval']))
+ def run(self):
+ while True:
+ run_prog('py-i2phosts-fetcher')
+ time.sleep(float(config['fetch_interval']))
class CheckerThread(Thread):
- """ Run py-i2phosts-checker, py-i2phosts-maint, py-i2phosts-builder periodically """
+ """ Run py-i2phosts-checker, py-i2phosts-maint, py-i2phosts-builder periodically """
- def run(self):
- while True:
- run_prog('py-i2phosts-checker')
- run_prog('py-i2phosts-maint')
- run_prog('py-i2phosts-builder')
- time.sleep(float(config['check_interval']))
+ def run(self):
+ while True:
+ run_prog('py-i2phosts-checker')
+ run_prog('py-i2phosts-maint')
+ run_prog('py-i2phosts-builder')
+ time.sleep(float(config['check_interval']))
def run_prog(prog):
- try:
- log.info('starting: %s', prog)
- sp_args = [prog]
- if args.debug or args.verbose:
- sp_args.append('-d')
- p = subprocess.Popen(sp_args, shell=False)
- except OSError, e:
- log.error('failed to exec %s: %s', prog, e)
- if e.errno == errno.ENOENT:
- log.error(' maybe it isn\'t in PATH?')
- else:
- p.wait()
- log.info('finished: %s', prog)
+ try:
+ log.info('starting: %s', prog)
+ sp_args = [prog]
+ if args.debug or args.verbose:
+ sp_args.append('-d')
+ p = subprocess.Popen(sp_args, shell=False)
+ except OSError, e:
+ log.error('failed to exec %s: %s', prog, e)
+ if e.errno == errno.ENOENT:
+ log.error(' maybe it isn\'t in PATH?')
+ else:
+ p.wait()
+ log.info('finished: %s', prog)
def main():
- def run_fetcher():
- fetcher = FetcherThread()
- fetcher.start()
- return fetcher
-
- def run_checker():
- checker = CheckerThread()
- checker.start()
- return checker
-
- # if we're just started, wait while fetcher get some new hosts
- fetcher = run_fetcher()
- log.debug('just started, delaying checker run for 300 secs')
- fetcher.join(300) # wait for 5 mins
- # start checker and other
- checker = run_checker()
-
- while True:
- log.debug('checking fetcher and checker threads status')
- if fetcher.isAlive() == False:
- log.warning('fetcher thread is dead, respawning...')
- fetcher = run_fetcher()
- else:
- log.debug('fetcher thread: alive')
- if checker.isAlive() == False:
- log.warning('checker thread is dead, respawning...')
- checker = run_checker()
- else:
- log.debug('checker thread: alive')
- # do check every 30 mins
- time.sleep(1800)
+ def run_fetcher():
+ fetcher = FetcherThread()
+ fetcher.start()
+ return fetcher
+
+ def run_checker():
+ checker = CheckerThread()
+ checker.start()
+ return checker
+
+ # if we're just started, wait while fetcher get some new hosts
+ fetcher = run_fetcher()
+ log.debug('just started, delaying checker run for 300 secs')
+ fetcher.join(300) # wait for 5 mins
+ # start checker and other
+ checker = run_checker()
+
+ while True:
+ log.debug('checking fetcher and checker threads status')
+ if fetcher.isAlive() == False:
+ log.warning('fetcher thread is dead, respawning...')
+ fetcher = run_fetcher()
+ else:
+ log.debug('fetcher thread: alive')
+ if checker.isAlive() == False:
+ log.warning('checker thread is dead, respawning...')
+ checker = run_checker()
+ else:
+ log.debug('checker thread: alive')
+ # do check every 30 mins
+ time.sleep(1800)
# parse command line options
parser = argparse.ArgumentParser(
- description='Master daemon for py-i2phosts.',
- epilog='Report bugs to http://zzz.i2p/topics/733')
+ description='Master daemon for py-i2phosts.',
+ epilog='Report bugs to http://zzz.i2p/topics/733')
parser.add_argument('-d', '--debug', action='store_true',
- help='run in debug mode without detaching from terminal'),
+ help='run in debug mode without detaching from terminal'),
parser.add_argument('-v', '--verbose', action='store_true',
- help='run in verbose mode without detaching from terminal'),
+ help='run in verbose mode without detaching from terminal'),
parser.add_argument('-c', '--config', default='/etc/py-i2phosts/master.conf', dest='config_file',
- help='config file to use')
+ help='config file to use')
args = parser.parse_args()
# read and validate config
spec = '''
- log_file = string(default='/var/log/py-i2phosts/master.log')
- log_level = option('debug', 'info', 'warning', 'error', 'critical', default='info')
- pid_file = string(default='/var/run/py-i2phosts/master.pid')
- runas = string(default='_pyi2phosts')
- check_interval = integer(default=43200)
- fetch_interval = integer(default=1800)
- '''
+ log_file = string(default='/var/log/py-i2phosts/master.log')
+ log_level = option('debug', 'info', 'warning', 'error', 'critical', default='info')
+ pid_file = string(default='/var/run/py-i2phosts/master.pid')
+ runas = string(default='_pyi2phosts')
+ check_interval = integer(default=43200)
+ fetch_interval = integer(default=1800)
+ '''
spec = spec.split('\n')
config = configobj.ConfigObj(args.config_file, configspec=spec)
if 'include' in config:
- config_included = configobj.ConfigObj(config['include'])
- config.merge(config_included)
+ config_included = configobj.ConfigObj(config['include'])
+ config.merge(config_included)
# django setup
DJANGO_SETTINGS_MODULE = 'pyi2phosts.settings'
if 'DJANGO_PROJECT_PATH' in config:
- DJANGO_PROJECT_PATH = config['DJANGO_PROJECT_PATH']
+ DJANGO_PROJECT_PATH = config['DJANGO_PROJECT_PATH']
else:
- DJANGO_PROJECT_PATH = os.path.dirname(sys.argv[0]) + '/..'
+ DJANGO_PROJECT_PATH = os.path.dirname(sys.argv[0]) + '/..'
sys.path.insert(1, DJANGO_PROJECT_PATH)
os.environ['DJANGO_SETTINGS_MODULE'] = DJANGO_SETTINGS_MODULE
from pyi2phosts.lib.utils import get_logger
@@ -136,32 +142,32 @@ validate_config(config)
# configure logger
if args.debug == True:
- log_level = 'debug'
- log_file = None
+ log_level = 'debug'
+ log_file = None
elif args.verbose == True:
- log_level = 'info'
- log_file = None
+ log_level = 'info'
+ log_file = None
else:
- log_level = config['log_level']
- log_file = config['log_file']
+ log_level = config['log_level']
+ log_file = config['log_file']
if not args.debug and not args.verbose:
- # get pid object for daemon
- pid = pidfile.TimeoutPIDLockFile(config['pid_file'], 10)
- # create daemon context
- d = daemon.DaemonContext(pidfile=pid, umask=077)
- # write stderr to logfile # FIXME: and how we will deal with log rotation?
- logfile = open(config['log_file'], 'a')
- d.stderr = logfile
- d.stdout = logfile
- # drop privileges when started as root
- if os.getuid() == 0:
- runas = config['runas']
- pw_entry = pwd.getpwnam(runas)
- d.uid = pw_entry[2]
- d.gid = pw_entry[3]
- os.chown(config['log_file'], d.uid, d.gid)
- d.open() # become daemon
+ # get pid object for daemon
+ pid = pidfile.TimeoutPIDLockFile(config['pid_file'], 10)
+ # create daemon context
+ d = daemon.DaemonContext(pidfile=pid, umask=077)
+ # write stderr to logfile # FIXME: and how we will deal with log rotation?
+ logfile = open(config['log_file'], 'a')
+ d.stderr = logfile
+ d.stdout = logfile
+ # drop privileges when started as root
+ if os.getuid() == 0:
+ runas = config['runas']
+ pw_entry = pwd.getpwnam(runas)
+ d.uid = pw_entry[2]
+ d.gid = pw_entry[3]
+ os.chown(config['log_file'], d.uid, d.gid)
+ d.open() # become daemon
log = get_logger(filename=log_file, log_level=log_level)
log.info('started')
main()
diff --git a/pyi2phosts/api/urls.py b/pyi2phosts/api/urls.py
index 4d80e1e..fb0217c 100644
--- a/pyi2phosts/api/urls.py
+++ b/pyi2phosts/api/urls.py
@@ -1,5 +1,5 @@
from django.conf.urls import *
urlpatterns = patterns('pyi2phosts.api.views',
- url(r'^all/$', 'all'),
+ url(r'^all/$', 'all'),
)
diff --git a/pyi2phosts/api/views.py b/pyi2phosts/api/views.py
index 8ef3608..bfaf86c 100644
--- a/pyi2phosts/api/views.py
+++ b/pyi2phosts/api/views.py
@@ -6,11 +6,11 @@ from pyi2phosts.postkey.models import i2phost
from pyi2phosts.lib.utils import get_b32
def all(request):
- """Return all hosts in { "b32": "last seen timestamp" } form. Implemented by zzz request. """
- # all hosts seen at least once
- queryset = i2phost.objects.exclude(last_seen=None)
- json_dict = {}
- for host in queryset:
- # pass last_seen to json in unixtime
- json_dict[get_b32(host.b64hash)] = host.last_seen.strftime("%s")
- return HttpResponse(json.dumps(json_dict), mimetype="application/json")
+ """Return all hosts in { "b32": "last seen timestamp" } form. Implemented by zzz request. """
+ # all hosts seen at least once
+ queryset = i2phost.objects.exclude(last_seen=None)
+ json_dict = {}
+ for host in queryset:
+ # pass last_seen to json in unixtime
+ json_dict[get_b32(host.b64hash)] = host.last_seen.strftime("%s")
+ return HttpResponse(json.dumps(json_dict), mimetype="application/json")
diff --git a/pyi2phosts/extsources/admin.py b/pyi2phosts/extsources/admin.py
index ca35f7c..aaa83ab 100644
--- a/pyi2phosts/extsources/admin.py
+++ b/pyi2phosts/extsources/admin.py
@@ -4,7 +4,7 @@ from pyi2phosts.extsources.models import ExternalSource
class ExternalSourceAdmin(admin.ModelAdmin):
- list_display = ('name', 'url', 'description', 'last_success', 'last_modified', 'etag', 'active')
- list_editable = ['active']
+ list_display = ('name', 'url', 'description', 'last_success', 'last_modified', 'etag', 'active')
+ list_editable = ['active']
admin.site.register(ExternalSource, ExternalSourceAdmin)
diff --git a/pyi2phosts/extsources/models.py b/pyi2phosts/extsources/models.py
index 5c54351..de4824b 100644
--- a/pyi2phosts/extsources/models.py
+++ b/pyi2phosts/extsources/models.py
@@ -3,14 +3,14 @@ from django.db import models
from pyi2phosts.lib.validation import validate_i2purl
class ExternalSource(models.Model):
- name = models.CharField(max_length=128, unique=True)
- url = models.CharField(max_length=256, validators=[validate_i2purl])
- description = models.CharField(max_length=512, blank=True)
- last_modified = models.DateTimeField(null=True, blank=True)
- last_success = models.DateTimeField(null=True, blank=True)
- etag = models.CharField(max_length=256, blank=True)
- active = models.BooleanField(default=True)
+ name = models.CharField(max_length=128, unique=True)
+ url = models.CharField(max_length=256, validators=[validate_i2purl])
+ description = models.CharField(max_length=512, blank=True)
+ last_modified = models.DateTimeField(null=True, blank=True)
+ last_success = models.DateTimeField(null=True, blank=True)
+ etag = models.CharField(max_length=256, blank=True)
+ active = models.BooleanField(default=True)
- def __unicode__(self):
- return self.name
+ def __unicode__(self):
+ return self.name
diff --git a/pyi2phosts/jump/urls.py b/pyi2phosts/jump/urls.py
index 7fb61b2..fbd5d74 100644
--- a/pyi2phosts/jump/urls.py
+++ b/pyi2phosts/jump/urls.py
@@ -1,7 +1,7 @@
from django.conf.urls import *
urlpatterns = patterns('pyi2phosts.jump.views',
- (r'^([^$/]+)', 'jumper'),
- (r'', 'index'),
+ (r'^([^$/]+)', 'jumper'),
+ (r'', 'index'),
)
diff --git a/pyi2phosts/jump/views.py b/pyi2phosts/jump/views.py
index 757c5d1..8e2b547 100644
--- a/pyi2phosts/jump/views.py
+++ b/pyi2phosts/jump/views.py
@@ -10,45 +10,45 @@ from pyi2phosts.postkey.models import i2phost
from pyi2phosts.lib.validation import validate_hostname
def jumper(request, host):
- """Actually do jumps."""
- try:
- hostname = validate_hostname(host)
- except ValidationError, e:
- return render_to_response('jump-error.html', {
- 'title': settings.SITE_NAME,
- 'error': e,
- }, context_instance=RequestContext(request))
- try:
- h = i2phost.objects.get(name=hostname)
- except i2phost.DoesNotExist:
- return render_to_response('jump-unknown.html', {
- 'title': settings.SITE_NAME,
- }, context_instance=RequestContext(request))
- if h.activated == True:
- key = h.b64hash
- else:
- return redirect('/search/?q=' + hostname)
- # begin forming url
- url = 'http://' + hostname
- # get params from requst string, e.g. from 'example.i2p/smth/1?a=b&c=d' get 'smth/1?a=b&c=d'
- pattern = host + r'/(.+)'
- m = re.search(pattern, request.get_full_path())
- if m:
- params = m.group(1)
- url += '/' + params
- # determine how we should pass i2paddresshelper
- # http://zzz.i2p/oldnews.html#jump
- if params.find('?') == -1:
- suffix = '?'
- else:
- suffix = '&'
- url += suffix + 'i2paddresshelper=' + key
- else:
- url += '/?i2paddresshelper=' + key
- return render_to_response('jump.html', {
- 'title': settings.SITE_NAME,
- 'url': url,
- }, context_instance=RequestContext(request))
+ """Actually do jumps."""
+ try:
+ hostname = validate_hostname(host)
+ except ValidationError, e:
+ return render_to_response('jump-error.html', {
+ 'title': settings.SITE_NAME,
+ 'error': e,
+ }, context_instance=RequestContext(request))
+ try:
+ h = i2phost.objects.get(name=hostname)
+ except i2phost.DoesNotExist:
+ return render_to_response('jump-unknown.html', {
+ 'title': settings.SITE_NAME,
+ }, context_instance=RequestContext(request))
+ if h.activated == True:
+ key = h.b64hash
+ else:
+ return redirect('/search/?q=' + hostname)
+ # begin forming url
+ url = 'http://' + hostname
+ # get params from requst string, e.g. from 'example.i2p/smth/1?a=b&c=d' get 'smth/1?a=b&c=d'
+ pattern = host + r'/(.+)'
+ m = re.search(pattern, request.get_full_path())
+ if m:
+ params = m.group(1)
+ url += '/' + params
+ # determine how we should pass i2paddresshelper
+ # http://zzz.i2p/oldnews.html#jump
+ if params.find('?') == -1:
+ suffix = '?'
+ else:
+ suffix = '&'
+ url += suffix + 'i2paddresshelper=' + key
+ else:
+ url += '/?i2paddresshelper=' + key
+ return render_to_response('jump.html', {
+ 'title': settings.SITE_NAME,
+ 'url': url,
+ }, context_instance=RequestContext(request))
def index(request):
- return redirect('/')
+ return redirect('/')
diff --git a/pyi2phosts/latest/urls.py b/pyi2phosts/latest/urls.py
index 61e55ab..e378268 100644
--- a/pyi2phosts/latest/urls.py
+++ b/pyi2phosts/latest/urls.py
@@ -3,7 +3,7 @@ from pyi2phosts.lib.rss import LatestHostsFeed
from pyi2phosts.latest.views import LatestHostsListsView
urlpatterns = patterns('',
- url(r'^$', LatestHostsListsView.as_view(), name='latest'),
- url(r'^rss/$', LatestHostsFeed(), name='latest-rss'),
+ url(r'^$', LatestHostsListsView.as_view(), name='latest'),
+ url(r'^rss/$', LatestHostsFeed(), name='latest-rss'),
)
diff --git a/pyi2phosts/latest/views.py b/pyi2phosts/latest/views.py
index 54bcc0a..50a89d8 100644
--- a/pyi2phosts/latest/views.py
+++ b/pyi2phosts/latest/views.py
@@ -6,25 +6,25 @@ from pyi2phosts.postkey.models import i2phost
from pyi2phosts.lib.generic import LocalObjectList
def get_latest():
- now_date = datetime.datetime.utcnow()
- start_date = now_date - datetime.timedelta(days=settings.LATEST_DAY_COUNT)
- qs = i2phost.objects.filter(activated=True,
- date_added__range=(start_date, now_date)).order_by("-date_added")[:settings.LATEST_HOSTS_COUNT]
- return qs
+ now_date = datetime.datetime.utcnow()
+ start_date = now_date - datetime.timedelta(days=settings.LATEST_DAY_COUNT)
+ qs = i2phost.objects.filter(activated=True,
+ date_added__range=(start_date, now_date)).order_by("-date_added")[:settings.LATEST_HOSTS_COUNT]
+ return qs
class LatestHostsListsView(LocalObjectList):
- """ Renders list of latest active hosts added """
+ """ Renders list of latest active hosts added """
- def get_context_data(self, **kwargs):
- context = super(LatestHostsListsView, self).get_context_data(**kwargs)
- context.update({
- 'title': settings.SITE_NAME,
- 'day_count': settings.LATEST_DAY_COUNT,
- 'hosts_count': settings.LATEST_HOSTS_COUNT
- })
- return context
+ def get_context_data(self, **kwargs):
+ context = super(LatestHostsListsView, self).get_context_data(**kwargs)
+ context.update({
+ 'title': settings.SITE_NAME,
+ 'day_count': settings.LATEST_DAY_COUNT,
+ 'hosts_count': settings.LATEST_HOSTS_COUNT
+ })
+ return context
- queryset = get_latest()
- template_name = 'latest.html'
- context_object_name = 'host_list'
- paginate_by = 40
+ queryset = get_latest()
+ template_name = 'latest.html'
+ context_object_name = 'host_list'
+ paginate_by = 40
diff --git a/pyi2phosts/lib/generic.py b/pyi2phosts/lib/generic.py
index 53ed292..5085c60 100755
--- a/pyi2phosts/lib/generic.py
+++ b/pyi2phosts/lib/generic.py
@@ -9,58 +9,58 @@ from pyi2phosts.postkey.models import i2phost
from pyi2phosts.postkey.templatetags import paginator
class LocalTemplateView(TemplateView):
- """ Renders some template with passing some local config variables """
+ """ Renders some template with passing some local config variables """
- def get_context_data(self, **kwargs):
- context = super(LocalTemplateView, self).get_context_data(**kwargs)
- context.update({
- 'title': settings.SITE_NAME,
- 'domain': settings.DOMAIN,
- 'b64': settings.MY_B64,
- 'b32': get_b32(settings.MY_B64)
- })
- return context
+ def get_context_data(self, **kwargs):
+ context = super(LocalTemplateView, self).get_context_data(**kwargs)
+ context.update({
+ 'title': settings.SITE_NAME,
+ 'domain': settings.DOMAIN,
+ 'b64': settings.MY_B64,
+ 'b32': get_b32(settings.MY_B64)
+ })
+ return context
class LocalObjectList(ListView):
- """ Renders some list of objects """
+ """ Renders some list of objects """
- def get_context_data(self, **kwargs):
- context = super(LocalObjectList, self).get_context_data(**kwargs)
- context.update({
- 'title': settings.SITE_NAME,
- })
- return context
+ def get_context_data(self, **kwargs):
+ context = super(LocalObjectList, self).get_context_data(**kwargs)
+ context.update({
+ 'title': settings.SITE_NAME,
+ })
+ return context
class FaqView(LocalObjectList):
- """ Renders list of external sources for hosts.txt """
+ """ Renders list of external sources for hosts.txt """
- queryset = ExternalSource.objects.filter(active=True)
- template_name = 'faq.html'
- context_object_name = 'sources_list'
+ queryset = ExternalSource.objects.filter(active=True)
+ template_name = 'faq.html'
+ context_object_name = 'sources_list'
class HostsListsView(LocalObjectList):
- """ Renders list of active hosts """
+ """ Renders list of active hosts """
- def get_queryset(self):
- allowed_orders = ['name', 'last_seen', 'date_added']
- self.order_by = self.request.GET.get('order', 'name')
- if self.order_by not in allowed_orders:
- self.order_by = 'name'
- qs = super(HostsListsView, self).get_queryset()
- return qs.order_by(self.order_by)
+ def get_queryset(self):
+ allowed_orders = ['name', 'last_seen', 'date_added']
+ self.order_by = self.request.GET.get('order', 'name')
+ if self.order_by not in allowed_orders:
+ self.order_by = 'name'
+ qs = super(HostsListsView, self).get_queryset()
+ return qs.order_by(self.order_by)
- def get_context_data(self, **kwargs):
- """ we should pass order_by to template to not lose it while paginating """
- context = super(LocalObjectList, self).get_context_data(**kwargs)
- context.update({
- 'order': self.order_by,
- })
- return context
+ def get_context_data(self, **kwargs):
+ """ we should pass order_by to template to not lose it while paginating """
+ context = super(LocalObjectList, self).get_context_data(**kwargs)
+ context.update({
+ 'order': self.order_by,
+ })
+ return context
- queryset = i2phost.objects.filter(activated=True)
- template_name = 'browse.html'
- context_object_name = 'host_list'
- paginate_by = 40
+ queryset = i2phost.objects.filter(activated=True)
+ template_name = 'browse.html'
+ context_object_name = 'host_list'
+ paginate_by = 40
diff --git a/pyi2phosts/lib/rss.py b/pyi2phosts/lib/rss.py
index 5f7c6bf..5c680e9 100755
--- a/pyi2phosts/lib/rss.py
+++ b/pyi2phosts/lib/rss.py
@@ -5,33 +5,33 @@ from pyi2phosts.postkey.models import i2phost
from pyi2phosts.latest.views import get_latest
class AliveHostsFeed(Feed):
- """ Generate RSS feed with all alive hosts """
+ """ Generate RSS feed with all alive hosts """
- title = settings.DOMAIN + ' alive hosts'
- # FIXME: make this URL more dynamic
- link = 'http://' + settings.DOMAIN + '/browse/'
- description = 'All known active hosts inside I2P'
+ title = settings.DOMAIN + ' alive hosts'
+ # FIXME: make this URL more dynamic
+ link = 'http://' + settings.DOMAIN + '/browse/'
+ description = 'All known active hosts inside I2P'
- def items(self):
- return i2phost.objects.filter(activated=True).order_by('name')
+ def items(self):
+ return i2phost.objects.filter(activated=True).order_by('name')
- def item_title(self, item):
- return item.name
+ def item_title(self, item):
+ return item.name
- def item_link(self, item):
- return 'http://' + item.name + '/?i2paddresshelper=' + item.b64hash
+ def item_link(self, item):
+ return 'http://' + item.name + '/?i2paddresshelper=' + item.b64hash
- def item_description(self, item):
- return item.description
+ def item_description(self, item):
+ return item.description
class LatestHostsFeed(AliveHostsFeed):
- """ Generate RSS feed with freshly added hosts """
+ """ Generate RSS feed with freshly added hosts """
- title = settings.DOMAIN + ' latest hosts'
- # FIXME: make this URL more dynamic
- link = 'http://' + settings.DOMAIN + '/latest/'
- description = 'Freshly added hosts'
+ title = settings.DOMAIN + ' latest hosts'
+ # FIXME: make this URL more dynamic
+ link = 'http://' + settings.DOMAIN + '/latest/'
+ description = 'Freshly added hosts'
- def items(self):
- return get_latest()
+ def items(self):
+ return get_latest()
diff --git a/pyi2phosts/lib/utils.py b/pyi2phosts/lib/utils.py
index df8c362..0008902 100644
--- a/pyi2phosts/lib/utils.py
+++ b/pyi2phosts/lib/utils.py
@@ -8,59 +8,59 @@ import base64
from logging import handlers
def get_logger(filename=None, log_level='debug'):
- """ Prepare logger instance for our scripts """
+ """ Prepare logger instance for our scripts """
- # workaround for django
- if hasattr(logging, "web_logger"):
- return logging.web_logger
+ # workaround for django
+ if hasattr(logging, "web_logger"):
+ return logging.web_logger
- LEVELS = {
- 'debug': logging.DEBUG,
- 'info': logging.INFO,
- 'warning': logging.WARNING,
- 'error': logging.ERROR,
- 'critical': logging.CRITICAL
- }
- level = LEVELS.get(log_level, logging.NOTSET)
- format = '%(asctime)s %(module)s:%(lineno)d[%(process)d] %(levelname)s: %(message)s'
- formatter = logging.Formatter(format)
- logger = logging.getLogger(__name__)
- logger.setLevel(level)
- if filename:
- handler = logging.handlers.WatchedFileHandler(filename)
- else:
- handler = logging.StreamHandler()
- handler.setFormatter(formatter)
- logger.addHandler(handler)
+ LEVELS = {
+ 'debug': logging.DEBUG,
+ 'info': logging.INFO,
+ 'warning': logging.WARNING,
+ 'error': logging.ERROR,
+ 'critical': logging.CRITICAL
+ }
+ level = LEVELS.get(log_level, logging.NOTSET)
+ format = '%(asctime)s %(module)s:%(lineno)d[%(process)d] %(levelname)s: %(message)s'
+ formatter = logging.Formatter(format)
+ logger = logging.getLogger(__name__)
+ logger.setLevel(level)
+ if filename:
+ handler = logging.handlers.WatchedFileHandler(filename)
+ else:
+ handler = logging.StreamHandler()
+ handler.setFormatter(formatter)
+ logger.addHandler(handler)
- # workaround for django
- logging.web_logger = logger
+ # workaround for django
+ logging.web_logger = logger
- return logger
+ return logger
def validate_config(config):
- """ Validate configobj config """
- validator = validate.Validator()
- results = config.validate(validator)
- if results != True:
- for (section_list, key, _) in configobj.flatten_errors(config, results):
- if key is not None:
- sys.stderr.write('The "%s" key in the section "%s" failed validation' %
- (key, ', '.join(section_list)))
- else:
- sys.stderr.write('The following section was missing:%s ' %
- ', '.join(section_list))
- sys.exit(1)
+ """ Validate configobj config """
+ validator = validate.Validator()
+ results = config.validate(validator)
+ if results != True:
+ for (section_list, key, _) in configobj.flatten_errors(config, results):
+ if key is not None:
+ sys.stderr.write('The "%s" key in the section "%s" failed validation' %
+ (key, ', '.join(section_list)))
+ else:
+ sys.stderr.write('The following section was missing:%s ' %
+ ', '.join(section_list))
+ sys.exit(1)
def get_b32(dest):
- """ Calculate base32 hash from base64 """
- try:
- raw_key = base64.b64decode(dest.encode('utf-8'), '-~')
- except TypeError:
- return 'corrupted_base64_hash'
- else:
- hash = hashlib.sha256(raw_key)
- b32 = base64.b32encode(hash.digest()).lower().replace('=', '')+'.b32.i2p'
- return b32
+ """ Calculate base32 hash from base64 """
+ try:
+ raw_key = base64.b64decode(dest.encode('utf-8'), '-~')
+ except TypeError:
+ return 'corrupted_base64_hash'
+ else:
+ hash = hashlib.sha256(raw_key)
+ b32 = base64.b32encode(hash.digest()).lower().replace('=', '')+'.b32.i2p'
+ return b32
diff --git a/pyi2phosts/lib/validation.py b/pyi2phosts/lib/validation.py
index 3e00412..ca0de35 100755
--- a/pyi2phosts/lib/validation.py
+++ b/pyi2phosts/lib/validation.py
@@ -9,116 +9,116 @@ from pyi2phosts.postkey.models import i2phost
def validate_hostname(data):
- """
- Here we do hostname validation as described in
- http://www.i2p2.i2p/naming.html and some additional checks
- described in http://zzz.i2p/topics/739
- """
- # convert hostname to lowercase and strip leading and trailing whitespaces
- data = data.lower().strip()
- # do lenght check here for avoiding django.db.utils.DatabaseError exceptions
- # when trying to add too long hostname with py-i2phosts-injector
- if len(data) > 67:
- raise ValidationError(_('Too long hostname (should be 67 chars max)'))
- # Must end with '.i2p'.
- if re.match(r'.*\.i2p$', data) == None:
- raise ValidationError(_('Hostname doesn\'t ends with .i2p'))
- # Base 32 hostnames (*.b32.i2p) are not allowed
- if re.match(r'.*\.b32\.i2p$', data):
- raise ValidationError(_('Base32 hostnames are not allowed'))
- # prevent common errors
- if re.match(r'\.i2p$', data):
- raise ValidationError(_('Incomplete hostname'))
- if re.match(r'^http:/', data):
- raise ValidationError(_('Do not paste full URL, just domain'))
- # Must not contain '..'
- if re.search(r'\.\.', data):
- raise ValidationError(_('".." in hostname'))
- # Allow only 4ld domains and below
- if data.count('.') > 3:
- raise ValidationError(_('Subdomains deeper than 4LD are not allowed'))
- # Must contain only [a-z] [0-9] '.' and '-'
- h = re.match(r'([a-z0-9.-]+)\.i2p$', data)
- if h == None:
- raise ValidationError(_('Illegal characters in hostname'))
- else:
- namepart = h.groups()[0]
- # Must not start with '.' or '-'
- if re.match(r'^\.|-', namepart):
- raise ValidationError(_('Hostname must not starts with "." or "-"'))
- # Must not contain '.-' or '-.' (as of 0.6.1.33)
- if re.search(r'(\.-)|(-\.)', namepart):
- raise ValidationError(_('Hostname contain ".-" or "-."'))
- # Must not contain '--' except in 'xn--' for IDN
- if re.search(r'(? 67:
+ raise ValidationError(_('Too long hostname (should be 67 chars max)'))
+ # Must end with '.i2p'.
+ if re.match(r'.*\.i2p$', data) == None:
+ raise ValidationError(_('Hostname doesn\'t ends with .i2p'))
+ # Base 32 hostnames (*.b32.i2p) are not allowed
+ if re.match(r'.*\.b32\.i2p$', data):
+ raise ValidationError(_('Base32 hostnames are not allowed'))
+ # prevent common errors
+ if re.match(r'\.i2p$', data):
+ raise ValidationError(_('Incomplete hostname'))
+ if re.match(r'^http:/', data):
+ raise ValidationError(_('Do not paste full URL, just domain'))
+ # Must not contain '..'
+ if re.search(r'\.\.', data):
+ raise ValidationError(_('".." in hostname'))
+ # Allow only 4ld domains and below
+ if data.count('.') > 3:
+ raise ValidationError(_('Subdomains deeper than 4LD are not allowed'))
+ # Must contain only [a-z] [0-9] '.' and '-'
+ h = re.match(r'([a-z0-9.-]+)\.i2p$', data)
+ if h == None:
+ raise ValidationError(_('Illegal characters in hostname'))
+ else:
+ namepart = h.groups()[0]
+ # Must not start with '.' or '-'
+ if re.match(r'^\.|-', namepart):
+ raise ValidationError(_('Hostname must not starts with "." or "-"'))
+ # Must not contain '.-' or '-.' (as of 0.6.1.33)
+ if re.search(r'(\.-)|(-\.)', namepart):
+ raise ValidationError(_('Hostname contain ".-" or "-."'))
+ # Must not contain '--' except in 'xn--' for IDN
+ if re.search(r'(? 616:
- raise ValidationError(_('Specified base64 hash is bigger than 616 bytes'))
- # keys with cert may ends with anything, so check is relaxed
- if length > 516 and re.match(r'[a-zA-Z0-9\-~=]+$', data) == None:
- raise ValidationError(_('Invalid characters in base64 hash'))
- # base64-validity test
- if length > 516:
- # we need temporary variable here to avoid modifying main "data"
- test_data = data
- # add pad-characters needed for proper decoding cos i2p does not
- for i in range(4):
- quanta, leftover = divmod(len(test_data), 4)
- if leftover:
- test_data += '='
- else:
- break
- # if more than 2 pad chars were added, raise an error
- if i > 2:
- raise ValidationError(_('Corrupted base64 hash'))
- # base64-i2p
- if length == 516 and re.match(r'[a-zA-Z0-9\-~]+AA$', data) == None:
- raise ValidationError(_('Invalid base64 hash'))
- # check ECDSA validity
- if length == 524 and re.match(r'[a-zA-Z0-9\-~]+AEAAEAAA==$', data) == None:
+ """
+ Base64 hash validation
+ """
+ # strip leading and trailing whitespaces
+ data = data.strip()
+ length = len(data)
+ # check for b32 address misuse
+ if re.match(r'.*\.b32\.i2p$', data):
+ raise ValidationError(_('You should paste base64 hash, not a base32!'))
+ # fail if contains .i2p= (full foo.i2p=key)
+ if re.search(r'\.i2p=', data):
+ raise ValidationError(_('Do not paste full hosts.txt entry! Only base64 hash is needed'))
+ # check for pasting router hash
+ if length == 44:
+ raise ValidationError(_('Do not paste router hash! Go to i2ptunnel page and \
+ find a destination hash'))
+ # Minimum key length 516 bytes
+ if length < 516:
+ raise ValidationError(_('Specified base64 hash is less than 516 bytes'))
+ # Maximum key length 616 bytes
+ if length > 616:
+ raise ValidationError(_('Specified base64 hash is bigger than 616 bytes'))
+ # keys with cert may ends with anything, so check is relaxed
+ if length > 516 and re.match(r'[a-zA-Z0-9\-~=]+$', data) == None:
+ raise ValidationError(_('Invalid characters in base64 hash'))
+ # base64-validity test
+ if length > 516:
+ # we need temporary variable here to avoid modifying main "data"
+ test_data = data
+ # add pad-characters needed for proper decoding cos i2p does not
+ for i in range(4):
+ quanta, leftover = divmod(len(test_data), 4)
+ if leftover:
+ test_data += '='
+ else:
+ break
+ # if more than 2 pad chars were added, raise an error
+ if i > 2:
+ raise ValidationError(_('Corrupted base64 hash'))
+ # base64-i2p
+ if length == 516 and re.match(r'[a-zA-Z0-9\-~]+AA$', data) == None:
+ raise ValidationError(_('Invalid base64 hash'))
+ # check ECDSA validity
+ if length == 524 and re.match(r'[a-zA-Z0-9\-~]+AEAAEAAA==$', data) == None:
raise ValidationError(_('Invalid base64 ECDSA hash'))
- if check_uniq == True:
- # Avoid adding non-unique hashes
- qs = i2phost.objects.filter(b64hash=data)
- if qs.exists():
- raise ValidationError(_('Some host already have the same Base64 hash'))
- return data
+ if check_uniq == True:
+ # Avoid adding non-unique hashes
+ qs = i2phost.objects.filter(b64hash=data)
+ if qs.exists():
+ raise ValidationError(_('Some host already have the same Base64 hash'))
+ return data
def validate_i2purl(data):
- """ Basic I2P URL validator """
- # convert to lowercase and strip leading and trailing whitespaces
- data = data.lower().strip()
- # check for http://, .i2p in domain and GET validity
- if re.match(r'^http://(?:.+?\.i2p)(?:/?|[/?]\S+)$', data) == None:
- raise ValidationError(_('Bad I2P url'))
+ """ Basic I2P URL validator """
+ # convert to lowercase and strip leading and trailing whitespaces
+ data = data.lower().strip()
+ # check for http://, .i2p in domain and GET validity
+ if re.match(r'^http://(?:.+?\.i2p)(?:/?|[/?]\S+)$', data) == None:
+ raise ValidationError(_('Bad I2P url'))
diff --git a/pyi2phosts/postkey/admin.py b/pyi2phosts/postkey/admin.py
index 547d187..75a54ea 100644
--- a/pyi2phosts/postkey/admin.py
+++ b/pyi2phosts/postkey/admin.py
@@ -9,46 +9,46 @@ from pyi2phosts.lib.validation import validate_b64hash
class i2phostAdminForm(forms.ModelForm):
- """ Custom form for editing hosts via admin interface """
+ """ Custom form for editing hosts via admin interface """
- def clean_name(self):
- """Validate hostname"""
- data = self.cleaned_data['name']
- data = validate_hostname(data)
- return data
+ def clean_name(self):
+ """Validate hostname"""
+ data = self.cleaned_data['name']
+ data = validate_hostname(data)
+ return data
- def clean_b64hash(self):
- """Validate base64 hash"""
- data = self.cleaned_data['b64hash']
- data = validate_b64hash(data, check_uniq=False)
- return data
+ def clean_b64hash(self):
+ """Validate base64 hash"""
+ data = self.cleaned_data['b64hash']
+ data = validate_b64hash(data, check_uniq=False)
+ return data
class i2phostAdmin(admin.ModelAdmin):
- def url(self, hostname):
- return 'b32 '
+ def url(self, hostname):
+ return 'b32 '
- form = i2phostAdminForm
- url.allow_tags = True
- list_display = ('url', 'name', 'description', 'date_added', 'last_seen', 'expires',
- 'activated', 'external')
- list_display_links = ['name']
- list_filter = ('activated', 'external', 'approved')
- search_fields = ('name', 'b64hash')
- ordering = ['-date_added']
+ form = i2phostAdminForm
+ url.allow_tags = True
+ list_display = ('url', 'name', 'description', 'date_added', 'last_seen', 'expires',
+ 'activated', 'external')
+ list_display_links = ['name']
+ list_filter = ('activated', 'external', 'approved')
+ search_fields = ('name', 'b64hash')
+ ordering = ['-date_added']
class PendingAdmin(i2phostAdmin):
- def queryset(self, request):
- qs = super(PendingAdmin, self).queryset(request)
- return qs.filter(approved=False)
+ def queryset(self, request):
+ qs = super(PendingAdmin, self).queryset(request)
+ return qs.filter(approved=False)
- def approve_selected(modeladmin, request, queryset):
- queryset.update(approved=True)
+ def approve_selected(modeladmin, request, queryset):
+ queryset.update(approved=True)
- list_filter = []
- list_display = ('url', 'name', 'description', 'date_added', 'last_seen', 'expires', 'approved')
- actions = ['approve_selected']
+ list_filter = []
+ list_display = ('url', 'name', 'description', 'date_added', 'last_seen', 'expires', 'approved')
+ actions = ['approve_selected']
admin.site.register(i2phost, i2phostAdmin)
diff --git a/pyi2phosts/postkey/models.py b/pyi2phosts/postkey/models.py
index 7b57ae0..a07ddca 100644
--- a/pyi2phosts/postkey/models.py
+++ b/pyi2phosts/postkey/models.py
@@ -2,27 +2,27 @@ from django.db import models
from django.utils.translation import ugettext_lazy as _
class i2phost(models.Model):
- # Hostname limit is 67 characters maximum, including the '.i2p'.
- name = models.CharField(_('I2P hostname'), max_length=67, unique=True)
- # Maximum key length 616 bytes (to account for certs up to 100 bytes).
- b64hash = models.CharField(_('Base 64 hash'), max_length=616)
- description = models.CharField(_('Description'), max_length=4096, blank=True)
- date_added = models.DateTimeField(null=True, blank=True)
- # Last time this host was up
- last_seen = models.DateTimeField(null=True, blank=True)
- # Scheduled expiration date
- expires = models.DateField(null=True, blank=True)
- # Not-activated hosts will not appear in exported hosts.txt
- activated = models.BooleanField(default=False)
- # Indicator for hosts added from external source
- external = models.BooleanField(default=False)
- # Not approved hosts will not appear in exported hosts.txt
- approved = models.BooleanField(default=False)
+ # Hostname limit is 67 characters maximum, including the '.i2p'.
+ name = models.CharField(_('I2P hostname'), max_length=67, unique=True)
+ # Maximum key length 616 bytes (to account for certs up to 100 bytes).
+ b64hash = models.CharField(_('Base 64 hash'), max_length=616)
+ description = models.CharField(_('Description'), max_length=4096, blank=True)
+ date_added = models.DateTimeField(null=True, blank=True)
+ # Last time this host was up
+ last_seen = models.DateTimeField(null=True, blank=True)
+ # Scheduled expiration date
+ expires = models.DateField(null=True, blank=True)
+ # Not-activated hosts will not appear in exported hosts.txt
+ activated = models.BooleanField(default=False)
+ # Indicator for hosts added from external source
+ external = models.BooleanField(default=False)
+ # Not approved hosts will not appear in exported hosts.txt
+ approved = models.BooleanField(default=False)
- def __unicode__(self):
- return self.name
+ def __unicode__(self):
+ return self.name
class PendingHost(i2phost):
- """ Proxy model needed for displaying not approved hosts in django admin separatelly """
- class Meta:
- proxy = True
+ """ Proxy model needed for displaying not approved hosts in django admin separatelly """
+ class Meta:
+ proxy = True
diff --git a/pyi2phosts/postkey/urls.py b/pyi2phosts/postkey/urls.py
index d55cc9f..dbaf391 100644
--- a/pyi2phosts/postkey/urls.py
+++ b/pyi2phosts/postkey/urls.py
@@ -1,7 +1,7 @@
from django.conf.urls import *
urlpatterns = patterns('pyi2phosts.postkey.views',
- (r'^$', 'addkey'),
- (r'^success/', 'success'),
- (r'^subdomain/', 'subdomain'),
+ (r'^$', 'addkey'),
+ (r'^success/', 'success'),
+ (r'^subdomain/', 'subdomain'),
)
diff --git a/pyi2phosts/postkey/views.py b/pyi2phosts/postkey/views.py
index d303622..cbae2bc 100644
--- a/pyi2phosts/postkey/views.py
+++ b/pyi2phosts/postkey/views.py
@@ -17,147 +17,147 @@ from pyi2phosts.lib.validation import validate_hostname
from pyi2phosts.lib.validation import validate_b64hash
class AddForm(forms.ModelForm):
- """
- This is our class for host-add form. It's based on django's ModelForm
- and uses our model "i2phost" (see postkey/models.py)
- """
- class Meta:
- model = i2phost
- fields = ('name', 'b64hash', 'description')
- widgets = {
- 'name': forms.TextInput(attrs={'size': '67'}),
- 'b64hash': forms.Textarea(attrs={'rows': '1', 'cols': '100'}),
- 'description': forms.Textarea(attrs={'rows': '2', 'cols': '72'})
- }
- def clean_name(self):
- """Validate hostname"""
- data = self.cleaned_data['name']
- log.debug(u'hostname: %s', self.data['name'])
- data = validate_hostname(data)
- # Another set of reserved hostnames (suggested by zzz)
- if re.search(r'(^|\.)(i2p|i2p2|geti2p|mail|project|i2project|i2pproject|i2p-project).i2p$', data):
- raise forms.ValidationError(_('Trying to use hostname from additional reserved set'))
- return data
- def clean_b64hash(self):
- """Validate base64 hash"""
- data = self.cleaned_data['b64hash']
- log.debug(u'hash: %s', self.data['b64hash'])
- data = validate_b64hash(data)
- return data
- def is_valid(self):
- """Log validation errors"""
- is_valid = super(AddForm, self).is_valid()
- if not is_valid:
- for field in self.errors.keys():
- log.info('ValidationError: [%s]: \"%s\" %s',
- field, self.data[field], self.errors[field].as_text())
- return is_valid
+ """
+ This is our class for host-add form. It's based on django's ModelForm
+ and uses our model "i2phost" (see postkey/models.py)
+ """
+ class Meta:
+ model = i2phost
+ fields = ('name', 'b64hash', 'description')
+ widgets = {
+ 'name': forms.TextInput(attrs={'size': '67'}),
+ 'b64hash': forms.Textarea(attrs={'rows': '1', 'cols': '100'}),
+ 'description': forms.Textarea(attrs={'rows': '2', 'cols': '72'})
+ }
+ def clean_name(self):
+ """Validate hostname"""
+ data = self.cleaned_data['name']
+ log.debug(u'hostname: %s', self.data['name'])
+ data = validate_hostname(data)
+ # Another set of reserved hostnames (suggested by zzz)
+ if re.search(r'(^|\.)(i2p|i2p2|geti2p|mail|project|i2project|i2pproject|i2p-project).i2p$', data):
+ raise forms.ValidationError(_('Trying to use hostname from additional reserved set'))
+ return data
+ def clean_b64hash(self):
+ """Validate base64 hash"""
+ data = self.cleaned_data['b64hash']
+ log.debug(u'hash: %s', self.data['b64hash'])
+ data = validate_b64hash(data)
+ return data
+ def is_valid(self):
+ """Log validation errors"""
+ is_valid = super(AddForm, self).is_valid()
+ if not is_valid:
+ for field in self.errors.keys():
+ log.info('ValidationError: [%s]: \"%s\" %s',
+ field, self.data[field], self.errors[field].as_text())
+ return is_valid
class SubdomainVerifyForm(forms.Form):
- """Form for displaying verification filename and code when verifying a subdomain"""
- filename = forms.CharField(label=_('Filename'), widget=forms.TextInput(attrs={
- 'size': '20',
- 'readonly': 'readonly',
- 'onclick': 'this.select();',
- }))
+ """Form for displaying verification filename and code when verifying a subdomain"""
+ filename = forms.CharField(label=_('Filename'), widget=forms.TextInput(attrs={
+ 'size': '20',
+ 'readonly': 'readonly',
+ 'onclick': 'this.select();',
+ }))
def save_host(request):
- """Function for saving hosts after validation or subdomain verification"""
- # avoid race conditions
- try:
- h = i2phost.objects.get(name=request.session['hostname'])
- except i2phost.DoesNotExist:
- host = i2phost(name=request.session['hostname'],
- b64hash=request.session['b64hash'],
- description=request.session['description'],
- date_added=datetime.datetime.utcnow())
- host.save()
- return redirect('pyi2phosts.postkey.views.success')
- else:
- log.warning('refusing to save already existed host: %s', request.session['hostname'])
- request.session.flush()
- return redirect('/')
+ """Function for saving hosts after validation or subdomain verification"""
+ # avoid race conditions
+ try:
+ h = i2phost.objects.get(name=request.session['hostname'])
+ except i2phost.DoesNotExist:
+ host = i2phost(name=request.session['hostname'],
+ b64hash=request.session['b64hash'],
+ description=request.session['description'],
+ date_added=datetime.datetime.utcnow())
+ host.save()
+ return redirect('pyi2phosts.postkey.views.success')
+ else:
+ log.warning('refusing to save already existed host: %s', request.session['hostname'])
+ request.session.flush()
+ return redirect('/')
def addkey(request):
- if request.method == 'POST':
- form = AddForm(request.POST)
- if form.is_valid():
- request.session['hostname'] = form.cleaned_data['name']
- request.session['b64hash'] = form.cleaned_data['b64hash']
- request.session['description'] = form.cleaned_data['description']
- if form.cleaned_data['name'].count('.') > 1:
- return redirect('pyi2phosts.postkey.views.subdomain')
- else:
- log.debug('submit is valid, saving')
- s = save_host(request)
- return s
- else:
- form = AddForm()
- return render_to_response('postkey.html', {
- 'title': settings.SITE_NAME,
- 'form': form,
- }, context_instance=RequestContext(request))
+ if request.method == 'POST':
+ form = AddForm(request.POST)
+ if form.is_valid():
+ request.session['hostname'] = form.cleaned_data['name']
+ request.session['b64hash'] = form.cleaned_data['b64hash']
+ request.session['description'] = form.cleaned_data['description']
+ if form.cleaned_data['name'].count('.') > 1:
+ return redirect('pyi2phosts.postkey.views.subdomain')
+ else:
+ log.debug('submit is valid, saving')
+ s = save_host(request)
+ return s
+ else:
+ form = AddForm()
+ return render_to_response('postkey.html', {
+ 'title': settings.SITE_NAME,
+ 'form': form,
+ }, context_instance=RequestContext(request))
def success(request):
- if 'hostname' in request.session:
- hn = request.session['hostname']
- request.session.flush()
- return render_to_response('success_submission.html', {
- 'title': settings.SITE_NAME,
- 'hostname': hn,
- }, context_instance=RequestContext(request))
- else:
- return redirect('/')
+ if 'hostname' in request.session:
+ hn = request.session['hostname']
+ request.session.flush()
+ return render_to_response('success_submission.html', {
+ 'title': settings.SITE_NAME,
+ 'hostname': hn,
+ }, context_instance=RequestContext(request))
+ else:
+ return redirect('/')
def subdomain(request):
- """Subdomain verification"""
- if request.method == 'POST':
- form = SubdomainVerifyForm(request.POST)
- if form.is_valid():
- # do verification here, then redirect to success
- proxy_handler = urllib2.ProxyHandler({'http': settings.EEPROXY_URL})
- opener = urllib2.build_opener(proxy_handler)
- if 'topdomain' in request.session and 'v_filename' in request.session:
- url = 'http://' + request.session['topdomain'] + '/' + request.session['v_filename']
- else:
- log.warning('trying to call subdomain validation without a session')
- return redirect('/')
- log.info('starting http-verification of subdomain: %s', request.session['hostname'])
- try:
- log.debug('trying to open %s', url)
- resp = opener.open(url, timeout=60)
- except urllib2.URLError, e:
- if hasattr(e, 'reason'):
- log.warning('%s: failed to reach server, reason: %s', request.session['topdomain'], e.reason)
- elif hasattr(e, 'code'):
- log.warning('%s can\'t finish the request, error code: %s',
- request.session['topdomain'], e.code)
- return render_to_response('subdomain_http_verify_failure.html', {
- 'title': settings.SITE_NAME,
- 'code': e.code,
- }, context_instance=RequestContext(request))
- else:
- log.debug('subdomain verification success, saving host')
- s = save_host(request)
- return s
- else:
- # generate verification code and display info page to user
- v_filename = ''.join([random.choice(string.letters + string.digits) for x in xrange(16)])
- if 'hostname' in request.session:
- m = re.match('.+\.(.+\.i2p$)', request.session['hostname'])
- topdomain = m.group(1)
- else:
- return redirect('/')
- # save needed variables in session data because otherwise it will be lost
- request.session['v_filename'] = v_filename
- request.session['topdomain'] = topdomain
- form = SubdomainVerifyForm({'filename': v_filename})
- return render_to_response('subdomain_http_verify.html', {
- 'title': settings.SITE_NAME,
- 'hostname': request.session['hostname'],
- 'topdomain': topdomain,
- 'form': form,
- }, context_instance=RequestContext(request))
+ """Subdomain verification"""
+ if request.method == 'POST':
+ form = SubdomainVerifyForm(request.POST)
+ if form.is_valid():
+ # do verification here, then redirect to success
+ proxy_handler = urllib2.ProxyHandler({'http': settings.EEPROXY_URL})
+ opener = urllib2.build_opener(proxy_handler)
+ if 'topdomain' in request.session and 'v_filename' in request.session:
+ url = 'http://' + request.session['topdomain'] + '/' + request.session['v_filename']
+ else:
+ log.warning('trying to call subdomain validation without a session')
+ return redirect('/')
+ log.info('starting http-verification of subdomain: %s', request.session['hostname'])
+ try:
+ log.debug('trying to open %s', url)
+ resp = opener.open(url, timeout=60)
+ except urllib2.URLError, e:
+ if hasattr(e, 'reason'):
+ log.warning('%s: failed to reach server, reason: %s', request.session['topdomain'], e.reason)
+ elif hasattr(e, 'code'):
+ log.warning('%s can\'t finish the request, error code: %s',
+ request.session['topdomain'], e.code)
+ return render_to_response('subdomain_http_verify_failure.html', {
+ 'title': settings.SITE_NAME,
+ 'code': e.code,
+ }, context_instance=RequestContext(request))
+ else:
+ log.debug('subdomain verification success, saving host')
+ s = save_host(request)
+ return s
+ else:
+ # generate verification code and display info page to user
+ v_filename = ''.join([random.choice(string.letters + string.digits) for x in xrange(16)])
+ if 'hostname' in request.session:
+ m = re.match('.+\.(.+\.i2p$)', request.session['hostname'])
+ topdomain = m.group(1)
+ else:
+ return redirect('/')
+ # save needed variables in session data because otherwise it will be lost
+ request.session['v_filename'] = v_filename
+ request.session['topdomain'] = topdomain
+ form = SubdomainVerifyForm({'filename': v_filename})
+ return render_to_response('subdomain_http_verify.html', {
+ 'title': settings.SITE_NAME,
+ 'hostname': request.session['hostname'],
+ 'topdomain': topdomain,
+ 'form': form,
+ }, context_instance=RequestContext(request))
log = get_logger(filename=settings.LOG_FILE, log_level=settings.LOG_LEVEL)
diff --git a/pyi2phosts/search/urls.py b/pyi2phosts/search/urls.py
index 8196277..7a0b51c 100644
--- a/pyi2phosts/search/urls.py
+++ b/pyi2phosts/search/urls.py
@@ -2,5 +2,5 @@ from django.conf.urls import *
from pyi2phosts.search.views import SearchedHostsListsView
urlpatterns = patterns('',
- (r'^$', SearchedHostsListsView.as_view()),
+ (r'^$', SearchedHostsListsView.as_view()),
)
diff --git a/pyi2phosts/search/views.py b/pyi2phosts/search/views.py
index 343362c..71883c5 100644
--- a/pyi2phosts/search/views.py
+++ b/pyi2phosts/search/views.py
@@ -5,14 +5,14 @@ from pyi2phosts.lib.generic import HostsListsView
class SearchedHostsListsView(HostsListsView):
- """ Renders list of hosts matching search request """
+ """ Renders list of hosts matching search request """
- def get_queryset(self):
- q = self.request.GET.get('q', '')
- fil = Q(name__icontains=q) | Q(b64hash__contains=q)
- queryset = i2phost.objects.filter(fil)
- return queryset
+ def get_queryset(self):
+ q = self.request.GET.get('q', '')
+ fil = Q(name__icontains=q) | Q(b64hash__contains=q)
+ queryset = i2phost.objects.filter(fil)
+ return queryset
- template_name = 'search_results.html'
- template_object_name = 'host_list'
- paginate_by = 40
+ template_name = 'search_results.html'
+ template_object_name = 'host_list'
+ paginate_by = 40
diff --git a/pyi2phosts/settings.py b/pyi2phosts/settings.py
index 4f1d4fd..1e9b0dd 100644
--- a/pyi2phosts/settings.py
+++ b/pyi2phosts/settings.py
@@ -37,9 +37,9 @@ TIME_ZONE = 'America/Chicago'
LANGUAGE_CODE = 'en-us'
LANGUAGES = (
- ('en', 'English'),
- ('ru', 'Russian'),
- )
+ ('en', 'English'),
+ ('ru', 'Russian'),
+ )
SITE_ID = 1
@@ -139,6 +139,6 @@ EEPROXY_URL = 'http://127.0.0.1:4444'
# include local settings
try:
- from local_settings import *
+ from local_settings import *
except ImportError:
- pass
+ pass
diff --git a/pyi2phosts/static-common/base.css b/pyi2phosts/static-common/base.css
index ee70805..b37ba98 100644
--- a/pyi2phosts/static-common/base.css
+++ b/pyi2phosts/static-common/base.css
@@ -1,133 +1,133 @@
html, body {
- font-size: 12pt;
- background: #E6E6D1;
- color: #000000;
+ font-size: 12pt;
+ background: #E6E6D1;
+ color: #000000;
}
input, textarea {
- background-color: #AEB08D;
- color: #000;
- border: 1px solid #000;
+ background-color: #AEB08D;
+ color: #000;
+ border: 1px solid #000;
}
label {
- width: 8em;
- float: top;
- text-align: left;
- margin-right: 1em;
- display: block;
+ width: 8em;
+ float: top;
+ text-align: left;
+ margin-right: 1em;
+ display: block;
}
a {
- background: inherit;
- color: #6E735E;
- text-decoration: none;
+ background: inherit;
+ color: #6E735E;
+ text-decoration: none;
}
a:visited {
- background: inherit;
- color: #6E735E;
- text-decoration: none;
+ background: inherit;
+ color: #6E735E;
+ text-decoration: none;
}
a:hover {
- color: #000;
- background: inherit;
+ color: #000;
+ background: inherit;
}
table {
- border-collapse: collapse;
- width: 90%;
- margin: 10px 0px 10px 0px;
+ border-collapse: collapse;
+ width: 90%;
+ margin: 10px 0px 10px 0px;
}
tr:first-child {
- border: 1px solid #CCCCCC;
- font-weight: bold;
+ border: 1px solid #CCCCCC;
+ font-weight: bold;
}
tr {
- border: 1px dashed #CCCCCC;
+ border: 1px dashed #CCCCCC;
}
td {
- max-width: 220px;
+ max-width: 220px;
}
div.menu {
- float: left;
- margin: 0px 20px 20px 0px;
- padding: 10px 20px 20px 0px;
- border-left: solid 1px #CCCCCC;
- text-align: left;
- color: black;
- font-size: 8pt;
- clear: left; /* fixes a bug in Opera */
- width: 160px;
+ float: left;
+ margin: 0px 20px 20px 0px;
+ padding: 10px 20px 20px 0px;
+ border-left: solid 1px #CCCCCC;
+ text-align: left;
+ color: black;
+ font-size: 8pt;
+ clear: left; /* fixes a bug in Opera */
+ width: 160px;
}
.menu li {
- margin-left: .5em;
- margin-top: .4em;
- padding-left: .5em;
- line-height: 1.2;
- list-style-type: none;
- list-style-position: outside;
+ margin-left: .5em;
+ margin-top: .4em;
+ padding-left: .5em;
+ line-height: 1.2;
+ list-style-type: none;
+ list-style-position: outside;
}
.menu ol, ul {
- padding-left: 0em;
- margin-top: 0em;
- padding-top: 0em;
+ padding-left: 0em;
+ margin-top: 0em;
+ padding-top: 0em;
}
.errorlist {
- color: red;
- padding-left: 5em;
+ color: red;
+ padding-left: 5em;
}
div.main {
- margin: 0px 0px 0px 0px;
- padding: 22px 60px 20px 220px;
- text-align: justify;
- color: #000011;
+ margin: 0px 0px 0px 0px;
+ padding: 22px 60px 20px 220px;
+ text-align: justify;
+ color: #000011;
}
div.main li {
- margin-left: 15px;
+ margin-left: 15px;
}
div.footer {
- font-size: 8pt;
- text-align: center;
- padding: 8px 0 0 0;
+ font-size: 8pt;
+ text-align: center;
+ padding: 8px 0 0 0;
}
div.search_host {
- position:absolute;
- right: 15px;
+ position:absolute;
+ right: 15px;
}
div.search_host .input input {
- font-size: 10px;
- color: #6E735E;
- width: 200px;
+ font-size: 10px;
+ color: #6E735E;
+ width: 200px;
}
.pager {
- padding-top: 20px;
- padding-left: 100px;
- font-size: 8pt;
+ padding-top: 20px;
+ padding-left: 100px;
+ font-size: 8pt;
}
.pager .page a {
- border: 1px solid #bbbbbb;
- margin-left: 1px;
- margin-right: 1px;
- padding: 0px 5px 0px 5px;
- text-decoration: none;
- color: #000000;
+ border: 1px solid #bbbbbb;
+ margin-left: 1px;
+ margin-right: 1px;
+ padding: 0px 5px 0px 5px;
+ text-decoration: none;
+ color: #000000;
}
.pager .current {
- border: 2px solid #444444;
- margin-left: 2px;
- margin-right: 2px;
- padding: 0px 5px 0px 5px;
+ border: 2px solid #444444;
+ margin-left: 2px;
+ margin-right: 2px;
+ padding: 0px 5px 0px 5px;
}
diff --git a/pyi2phosts/static-common/inproxy.html b/pyi2phosts/static-common/inproxy.html
index d340f42..010af3a 100644
--- a/pyi2phosts/static-common/inproxy.html
+++ b/pyi2phosts/static-common/inproxy.html
@@ -1,13 +1,13 @@
- FAIL
+ FAIL
-
+
- Non-I2P access denied
+ Non-I2P access denied
- py-i2phosts instance
+ py-i2phosts instance
-
+
diff --git a/pyi2phosts/static-common/rss-grey-18.png b/pyi2phosts/static-common/rss-grey-18.png
index 19b8c923943fb03a21b0388724a22910a91e7cc7..306eabf6a920fb85c9a38d473e6f200e8a5c3ca1 100644
GIT binary patch
delta 39
ocmbQox`cH?oQwhx6nI1yGca%qgD@k*tT_@43=AOgjU`%40IEy}w*UYD
delta 33
mcmZ3&I*)ZioET?;M`SSr1Gg{;GcwGYBf-GHz`3zXiwOXMC404 Not Found
+ 404 Not Found
{% endblock %}
diff --git a/pyi2phosts/templates/500.html b/pyi2phosts/templates/500.html
index d430a40..c50af92 100644
--- a/pyi2phosts/templates/500.html
+++ b/pyi2phosts/templates/500.html
@@ -1,5 +1,5 @@
{% extends "base.html" %}
{% block content %}
- 500 Internal server error
+ 500 Internal server error
{% endblock %}
diff --git a/pyi2phosts/templates/base.html b/pyi2phosts/templates/base.html
index 9556961..a55ac1e 100644
--- a/pyi2phosts/templates/base.html
+++ b/pyi2phosts/templates/base.html
@@ -1,65 +1,65 @@
{% load i18n %}
-
-
- {% block title %}
- {{ title }}
- {% endblock %}
-
- {% block head %}
- {% endblock %}
-
-
-
-
-
-
+
+
+ {% block title %}
+ {{ title }}
+ {% endblock %}
+
+ {% block head %}
+ {% endblock %}
+
+
+
+
+
+
- {% block navigation %}
-
+ {% block navigation %}
+
-
+
- {% endblock %}
+ {% endblock %}
-
- {% block header %}
- {% endblock %}
+
+ {% block header %}
+ {% endblock %}
- {% block content %}
- {% endblock %}
-
+ {% block content %}
+ {% endblock %}
+
- {% block footer %}
-
-
- {% endblock %}
-
+ {% block footer %}
+
+
+ {% endblock %}
+
diff --git a/pyi2phosts/templates/browse.html b/pyi2phosts/templates/browse.html
index b061cd6..b15bc76 100644
--- a/pyi2phosts/templates/browse.html
+++ b/pyi2phosts/templates/browse.html
@@ -11,10 +11,10 @@
{% if is_paginated %}
diff --git a/pyi2phosts/templates/contacts.html b/pyi2phosts/templates/contacts.html
index f5ee3f6..7be1b89 100644
--- a/pyi2phosts/templates/contacts.html
+++ b/pyi2phosts/templates/contacts.html
@@ -5,17 +5,17 @@
{% blocktrans %}
Direct contact methods:
- IRC: #i2p-dev, nick "slow". This is the fastest contact method and should be used first.
- Email: hiddenz@mail.i2p. You can send your message here, but don't expect a fast reply.
+ IRC: #i2p-dev, nick "slow". This is the fastest contact method and should be used first.
+ Email: hiddenz@mail.i2p. You can send your message here, but don't expect a fast reply.
{% endblocktrans %}
{% blocktrans %}
Public discussions about service, feedback, proposals and feature requests
{% endblocktrans %}
{% endblock %}
diff --git a/pyi2phosts/templates/faq.html b/pyi2phosts/templates/faq.html
index 4af70da..986116f 100644
--- a/pyi2phosts/templates/faq.html
+++ b/pyi2phosts/templates/faq.html
@@ -4,24 +4,24 @@
{% block content %}
{% trans "How we are learning about new hosts" %}
- {% trans "Pulling from external sources:" %}
-
- {% for source in sources_list %}
- {{ source.url }}
- {% endfor %}
-
-
- {% trans "Adding through our service." %}
-
+ {% trans "Pulling from external sources:" %}
+
+ {% for source in sources_list %}
+ {{ source.url }}
+ {% endfor %}
+
+
+ {% trans "Adding through our service." %}
+
{% blocktrans %}
Publishing requirements
To get published a host must meet the following criteria:
- Must have been added at least 3 days ago
- Must be up
- Must be approved by admin
+ Must have been added at least 3 days ago
+ Must be up
+ Must be approved by admin
Admin's approval isn't really necessary, it is only needed in
order to eliminate possible hijacking and mass registration attempts.
diff --git a/pyi2phosts/templates/index.html b/pyi2phosts/templates/index.html
index 17edb91..d604a7c 100644
--- a/pyi2phosts/templates/index.html
+++ b/pyi2phosts/templates/index.html
@@ -2,55 +2,55 @@
{% load i18n %}
{% block content %}
- {% url 'faq' as faq_url %}
- {% blocktrans %}
-
About
- {{ title }} is a domain name registration service for I2P. Hostnames in I2P aren't
- globally unique. {{ title }} doesn't act as "central authority", it only provides a
- way to publish hosts as an easy means of access to them. You can read more about how
- I2P naming works in the official
- docs .
-
+ {% url 'faq' as faq_url %}
+ {% blocktrans %}
+ About
+ {{ title }} is a domain name registration service for I2P. Hostnames in I2P aren't
+ globally unique. {{ title }} doesn't act as "central authority", it only provides a
+ way to publish hosts as an easy means of access to them. You can read more about how
+ I2P naming works in the official
+ docs .
+
- To find out how we're registering and publishing hosts, look at
- FAQ page.
-
- {% endblocktrans %}
+ To find out how we're registering and publishing hosts, look at
+ FAQ page.
+
+ {% endblocktrans %}
- {% blocktrans %}
- Addressbook service
-
- To start getting new hostnames from {{ title }}, add this
- subscription link into your router's
- addressbook . Of course, you should add INR 's destination before.
-
- {% endblocktrans %}
+ {% blocktrans %}
+ Addressbook service
+
+ To start getting new hostnames from {{ title }}, add this
+ subscription link into your router's
+ addressbook . Of course, you should add INR 's destination before.
+
+ {% endblocktrans %}
- {% url 'pyi2phosts.jump.views.jumper' 'example.i2p' as jump_url %}
- {% url 'pyi2phosts.jump.views.index' as jump_index %}
- {% blocktrans %}
- Jump service
- {{ title }} also provides a jump service. For accessing hosts through it,
- use urls like
-
- http://{{ domain }}{{ jump_url }} .
- I2P since 0.8.3 gives possibility to add a custom jump-servers. Go to the i2ptunnel
- eeproxy configuration page
- and add http://{{ domain }}{{ jump_index }} to "Jump URL List" section.
-
- {% endblocktrans %}
+ {% url 'pyi2phosts.jump.views.jumper' 'example.i2p' as jump_url %}
+ {% url 'pyi2phosts.jump.views.index' as jump_index %}
+ {% blocktrans %}
+ Jump service
+ {{ title }} also provides a jump service. For accessing hosts through it,
+ use urls like
+
+ http://{{ domain }}{{ jump_url }} .
+ I2P since 0.8.3 gives possibility to add a custom jump-servers. Go to the i2ptunnel
+ eeproxy configuration page
+ and add http://{{ domain }}{{ jump_index }} to "Jump URL List" section.
+
+ {% endblocktrans %}
- {% url 'pyi2phosts.postkey.views.addkey' as addkey_url %}
- {% blocktrans %}
- Registration service
- If you are running an eepsite or another service and want a human-readable domain name
- for them, consider registering it .
-
- {% endblocktrans %}
+ {% url 'pyi2phosts.postkey.views.addkey' as addkey_url %}
+ {% blocktrans %}
+ Registration service
+ If you are running an eepsite or another service and want a human-readable domain name
+ for them, consider registering it .
+
+ {% endblocktrans %}
{% endblock %}
{% block footer-addon %}
- b32 | {% trans "add" %} |
+ b32 | {% trans "add" %} |
{% endblock %}
diff --git a/pyi2phosts/templates/policy.html b/pyi2phosts/templates/policy.html
index d484aff..4e32f7b 100644
--- a/pyi2phosts/templates/policy.html
+++ b/pyi2phosts/templates/policy.html
@@ -2,14 +2,14 @@
{% trans "Domain name registration policy" %}
- {% trans "Domain name registration is free." %}
- {% trans "Anyone can register a domain name." %}
- {% trans "Domain names are available on a 'first come, first serve' basis." %}
- {% trans "A domain name's destination must be active." %}
- {% trans "Inactive destinations cannot be published." %}
- {% trans "Domain name hoarding through mass registration (cybersquatting) is not allowed." %}
- {% trans "Domain name registrations will not be rejected based on content." %}
- {% trans "Domain name registrations will stop propagating after some period of inactivity." %}
- {% trans "Temporary or test sites should not be registered. Use b32 address instead." %}
- {% trans "Changing key for existing domains is prohibited." %}
+ {% trans "Domain name registration is free." %}
+ {% trans "Anyone can register a domain name." %}
+ {% trans "Domain names are available on a 'first come, first serve' basis." %}
+ {% trans "A domain name's destination must be active." %}
+ {% trans "Inactive destinations cannot be published." %}
+ {% trans "Domain name hoarding through mass registration (cybersquatting) is not allowed." %}
+ {% trans "Domain name registrations will not be rejected based on content." %}
+ {% trans "Domain name registrations will stop propagating after some period of inactivity." %}
+ {% trans "Temporary or test sites should not be registered. Use b32 address instead." %}
+ {% trans "Changing key for existing domains is prohibited." %}
diff --git a/pyi2phosts/templates/postkey.html b/pyi2phosts/templates/postkey.html
index 9946e4f..e1cd91e 100644
--- a/pyi2phosts/templates/postkey.html
+++ b/pyi2phosts/templates/postkey.html
@@ -3,10 +3,10 @@
{% block content %}
{% include "policy.html" %}
-
+
{% endblock %}
diff --git a/pyi2phosts/templates/subdomain_http_verify.html b/pyi2phosts/templates/subdomain_http_verify.html
index 0e1ba43..6d4dcdc 100644
--- a/pyi2phosts/templates/subdomain_http_verify.html
+++ b/pyi2phosts/templates/subdomain_http_verify.html
@@ -15,10 +15,10 @@ This file should be accessible via http://{{ topdomain }}/«filename»
{% endblocktrans %}
-
+
{% endblock %}
diff --git a/pyi2phosts/urls.py b/pyi2phosts/urls.py
index b3dde76..3b9e578 100644
--- a/pyi2phosts/urls.py
+++ b/pyi2phosts/urls.py
@@ -13,18 +13,18 @@ from pyi2phosts.lib.generic import HostsListsView
urlpatterns = patterns('',
- url(r'^$', LocalTemplateView.as_view(template_name='index.html'), name='index'),
- url(r'^contacts/$', LocalTemplateView.as_view(template_name='contacts.html'), name='contacts'),
- url(r'^faq/$', FaqView.as_view(), name='faq'),
- url(r'^browse/$', HostsListsView.as_view(), name='browse'),
- url(r'^browse/rss/$', AliveHostsFeed(), name='browse-rss'),
-
- (r'^latest/', include('pyi2phosts.latest.urls')),
- (r'^search/$', include('pyi2phosts.search.urls')),
- (r'^postkey/', include('pyi2phosts.postkey.urls')),
- (r'^jump/', include('pyi2phosts.jump.urls')),
- (r'^api/', include('pyi2phosts.api.urls')),
- (r'^i18n/', include('django.conf.urls.i18n')),
+ url(r'^$', LocalTemplateView.as_view(template_name='index.html'), name='index'),
+ url(r'^contacts/$', LocalTemplateView.as_view(template_name='contacts.html'), name='contacts'),
+ url(r'^faq/$', FaqView.as_view(), name='faq'),
+ url(r'^browse/$', HostsListsView.as_view(), name='browse'),
+ url(r'^browse/rss/$', AliveHostsFeed(), name='browse-rss'),
+
+ (r'^latest/', include('pyi2phosts.latest.urls')),
+ (r'^search/$', include('pyi2phosts.search.urls')),
+ (r'^postkey/', include('pyi2phosts.postkey.urls')),
+ (r'^jump/', include('pyi2phosts.jump.urls')),
+ (r'^api/', include('pyi2phosts.api.urls')),
+ (r'^i18n/', include('django.conf.urls.i18n')),
# Example:
# (r'^pyi2phosts.', include('pyi2phosts.foo.urls')),
@@ -37,5 +37,5 @@ urlpatterns = patterns('',
)
if settings.DEBUG:
- urlpatterns += patterns('', (r'static/(?P.*)$', 'django.views.static.serve',
- {'document_root': settings.MEDIA_ROOT, 'show_indexes':True}))
+ urlpatterns += patterns('', (r'static/(?P.*)$', 'django.views.static.serve',
+ {'document_root': settings.MEDIA_ROOT, 'show_indexes':True}))
diff --git a/setup.py b/setup.py
index 1ec93c3..abd83dc 100644
--- a/setup.py
+++ b/setup.py
@@ -8,28 +8,28 @@ setup(
author_email='hiddenz@mail.i2p',
url='http://py-i2phosts.i2p/',
packages=['pyi2phosts',
- 'pyi2phosts.postkey',
- 'pyi2phosts.postkey.templatetags',
- 'pyi2phosts.jump',
- 'pyi2phosts.extsources',
- 'pyi2phosts.lib',
- 'pyi2phosts.search',
- 'pyi2phosts.latest'],
+ 'pyi2phosts.postkey',
+ 'pyi2phosts.postkey.templatetags',
+ 'pyi2phosts.jump',
+ 'pyi2phosts.extsources',
+ 'pyi2phosts.lib',
+ 'pyi2phosts.search',
+ 'pyi2phosts.latest'],
package_dir = {'': ''},
package_data = {
- 'pyi2phosts': ['templates/*.html', 'static/*', 'locale/*/*/*']},
+ 'pyi2phosts': ['templates/*.html', 'static/*', 'locale/*/*/*']},
scripts=['bin/py-i2phosts-master', 'bin/py-i2phosts-builder', 'bin/py-i2phosts-checker',
- 'bin/py-i2phosts-fetcher', 'bin/py-i2phosts-injector', 'bin/py-i2phosts-maint'],
+ 'bin/py-i2phosts-fetcher', 'bin/py-i2phosts-injector', 'bin/py-i2phosts-maint'],
data_files=[('/etc/py-i2phosts', ['conf/master.conf', 'conf/checker.conf', 'conf/fetcher.conf',
- 'conf/maintainer.conf', 'conf/builder.conf', 'conf/common.conf', 'conf/injector.conf'],),
- ('/var/log/py-i2phosts', ['.placeholder'],),
- ('/var/run/py-i2phosts', ['.placeholder'],),],
+ 'conf/maintainer.conf', 'conf/builder.conf', 'conf/common.conf', 'conf/injector.conf'],),
+ ('/var/log/py-i2phosts', ['.placeholder'],),
+ ('/var/run/py-i2phosts', ['.placeholder'],),],
classifiers=[
'Development Status :: 4 - Beta',
- 'Environment :: Console',
+ 'Environment :: Console',
'Environment :: Web Environment',
'Intended Audience :: Developers',
- 'Intended Audience :: System Administrators',
+ 'Intended Audience :: System Administrators',
'License :: OSI Approved :: GPL License',
'Operating System :: Linux',
'Programming Language :: Python',