Initial commit but hopefully working application.

This commit is contained in:
Amritanshu 2013-12-03 00:11:03 +05:30
commit 107be1af8c
10 changed files with 311 additions and 0 deletions

7
.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
*.pyc
env
.project
.pydevproject
*/__pycache__/
.idea/
*.egg-info/

4
CHANGES.txt Normal file
View File

@ -0,0 +1,4 @@
0.0
---
- Initial version

2
MANIFEST.in Normal file
View File

@ -0,0 +1,2 @@
include *.txt *.ini *.cfg *.rst
recursive-include bifrost *.txt

10
README.txt Normal file
View File

@ -0,0 +1,10 @@
This application provides a dyndns server style updater for using webfaction domain as dyndns.
the url to be used in updating is as follows
http://[USERNAME]:[PASSWORD]@tanshu.com/update?hostname=[DOMAIN]
or with custom ip address
http://[USERNAME]:[PASSWORD]@tanshu.com/update?hostname=[DOMAIN]&ip=[IP]
The users are maintained in the .htpasswd file in the production.ini directory.
The way to add/update users is "htpasswd .htpasswd [USERNAME]
the domains should be in the "dns_info" file in the format "domain:ipaddress"
The location of both the files can be changed in the ini file.
Also, the webfaction username and password needs to be configured in the ini file.

39
bifrost/__init__.py Normal file
View File

@ -0,0 +1,39 @@
from crypt import crypt
import os
from pyramid.authentication import BasicAuthAuthenticationPolicy
from pyramid.authorization import ACLAuthorizationPolicy
from pyramid.config import Configurator
from pyramid.security import Authenticated, Allow, Everyone
def main(global_config, **settings):
config = Configurator(settings=settings, authentication_policy=BasicAuthAuthenticationPolicy(htpasswd),
authorization_policy=ACLAuthorizationPolicy(), root_factory='bifrost.RootFactory')
config.add_route('update', '/update')
config.scan()
return config.make_wsgi_app()
def htpasswd(username, password, request):
settings = request.registry.settings
file = settings['biforst.auth']
if not os.path.isfile(file):
return None
users = {}
with open(file) as f:
for line in f:
login, pwd = line.split(':')
users[login] = pwd.rstrip('\n')
if username in users and crypt(password, users[username]) == users[username]:
return [Authenticated]
return None
class RootFactory(object):
@property
def __acl__(self):
acl = [(Allow, Authenticated, Authenticated)]
return acl
def __init__(self, request):
pass

58
bifrost/views.py Normal file
View File

@ -0,0 +1,58 @@
import logging
import os
import xmlrpc.client
from pyramid.httpexceptions import HTTPUnauthorized
from pyramid.security import forget, Authenticated
from pyramid.view import view_config, forbidden_view_config
log = logging.getLogger('bifrost.updater')
@view_config(route_name='update', request_param='domain', renderer='json', permission=Authenticated)
def update_view(request):
file = request.registry.settings['biforst.file']
username = request.registry.settings['webfaction.username']
password = request.registry.settings['webfaction.password']
current_ip = request.GET.get('ip',None)
if current_ip is None:
current_ip = request.remote_addr
domain = request.GET['domain']
db = load(file)
if domain in db and db[domain] != current_ip:
server = xmlrpc.client.ServerProxy('https://api.webfaction.com/')
session_id, account = server.login(username, password)
server.delete_dns_override(session_id, domain)
server.create_dns_override(session_id, domain, current_ip, '', '', '', '')
db[domain] = current_ip
update(file, db)
log.info('{0} updated to {1} at {3}'.format(domain, current_ip))
else:
log.info('{0} not updated'.format(domain))
return {}
def load(file):
if not os.path.isfile(file):
return {}
current = {}
with open(file) as f:
for line in f:
domain, ip = line.split(':')
current[domain] = ip.rstrip('\n')
return current
def update(file, db):
with open(file, 'w') as f:
f.writelines(['{0}:{1}'.format(key, value) for key, value in db.items()])
@forbidden_view_config()
def basic_challenge(request):
response = HTTPUnauthorized()
response.headers.update(forget(request))
return response

63
development.ini Normal file
View File

@ -0,0 +1,63 @@
###
# app configuration
# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
use = egg:bifrost
pyramid.reload_templates = false
pyramid.debug_authorization = false
pyramid.debug_notfound = false
pyramid.debug_routematch = false
pyramid.default_locale_name = en
biforst.file = %(here)s/dns_info
biforst.auth = %(here)s/.htpasswd
webfaction.username =
webfaction.password =
###
# wsgi server configuration
###
[server:main]
use = egg:waitress#main
host = 0.0.0.0
port = 6543
###
# logging configuration
# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
keys = root, bifrost, bifrost.updater
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = INFO
handlers = console
[logger_bifrost]
level = DEBUG
handlers =
qualname = bifrost
[logger_bifrost.updater]
level = INFO
handlers =
qualname = bifrost.updater
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s

63
production.ini Normal file
View File

@ -0,0 +1,63 @@
###
# app configuration
# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/environment.html
###
[app:main]
use = egg:bifrost
pyramid.reload_templates = false
pyramid.debug_authorization = false
pyramid.debug_notfound = false
pyramid.debug_routematch = false
pyramid.default_locale_name = en
biforst.file = %(here)s/dns_info
biforst.auth = %(here)s/.htpasswd
webfaction.username =
webfaction.password =
###
# wsgi server configuration
###
[server:main]
use = egg:waitress#main
host = 0.0.0.0
port = 6543
###
# logging configuration
# http://docs.pylonsproject.org/projects/pyramid/en/latest/narr/logging.html
###
[loggers]
keys = root, bifrost, bifrost.updater
[handlers]
keys = console
[formatters]
keys = generic
[logger_root]
level = WARN
handlers = console
[logger_bifrost]
level = WARN
handlers =
qualname = bifrost
[logger_bifrost.updater]
level = INFO
handlers =
qualname = bifrost.updater
[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic
[formatter_generic]
format = %(asctime)s %(levelname)-5.5s [%(name)s][%(threadName)s] %(message)s

27
setup.cfg Normal file
View File

@ -0,0 +1,27 @@
[nosetests]
match = ^test
nocapture = 1
cover-package = bifrost
with-coverage = 1
cover-erase = 1
[compile_catalog]
directory = bifrost/locale
domain = bifrost
statistics = true
[extract_messages]
add_comments = TRANSLATORS:
output_file = bifrost/locale/bifrost.pot
width = 80
[init_catalog]
domain = bifrost
input_file = bifrost/locale/bifrost.pot
output_dir = bifrost/locale
[update_catalog]
domain = bifrost
input_file = bifrost/locale/bifrost.pot
output_dir = bifrost/locale
previous = true

38
setup.py Normal file
View File

@ -0,0 +1,38 @@
import os
from setuptools import setup, find_packages
here = os.path.abspath(os.path.dirname(__file__))
README = open(os.path.join(here, 'README.txt')).read()
CHANGES = open(os.path.join(here, 'CHANGES.txt')).read()
requires = [
'pyramid',
'waitress',
]
setup(name='bifrost',
version='0.0',
description='bifrost',
long_description=README + '\n\n' + CHANGES,
classifiers=[
"Programming Language :: Python",
"Framework :: Pyramid",
"Topic :: Internet :: WWW/HTTP",
"Topic :: Internet :: WWW/HTTP :: WSGI :: Application",
],
author='',
author_email='',
url='',
keywords='web pyramid pylons',
packages=find_packages(),
include_package_data=True,
zip_safe=False,
install_requires=requires,
tests_require=requires,
test_suite="bifrost",
entry_points="""\
[paste.app_factory]
main = bifrost:main
""",
)