1
0
mirror of https://github.com/Yubico/yubiadmin.git synced 2025-02-26 23:54:26 +01:00

Re-structured code.

This commit is contained in:
Dain Nilsson 2013-04-26 12:04:13 +02:00
parent f3c6be25e6
commit 7038ebe7fe
8 changed files with 265 additions and 295 deletions

View File

@ -2,7 +2,7 @@ import os
from wsgiref.simple_server import make_server
from webob.dec import wsgify
from yubiadmin.util import render
from yubiadmin.util.app import render
from yubiadmin.apps import apps

View File

@ -1,4 +1,5 @@
from yubiadmin.util import App, DBConfigForm
from yubiadmin.util.app import App
from yubiadmin.util.form import DBConfigForm
__all__ = [
'app'
@ -19,7 +20,8 @@ class YubikeyKsm(App):
"""
Database Settings
"""
return self.render_forms(request, [
DBConfigForm('/etc/yubico/ksm/config-db.php')])
dbform = DBConfigForm('/etc/yubico/ksm/config-db.php',
dbname='ykksm', dbuser='ykksmreader')
return self.render_forms(request, [dbform])
app = YubikeyKsm()

View File

@ -1,15 +1,20 @@
import re
from wtforms.fields import IntegerField, StringField, Field
from wtforms.widgets import TextInput
import os
from wtforms.fields import IntegerField
from wtforms.validators import NumberRange
from yubiadmin.util import App, DBConfigForm, ConfigForm, FileConfig
from yubiadmin.util.app import App
from yubiadmin.util.config import ValueHandler, FileConfig
from yubiadmin.util.form import ConfigForm, DBConfigForm, ListField
__all__ = [
'app'
]
COMMENT = re.compile(r'/\*.*?\*/')
VALUE = re.compile(r'\s*[\'"](.*)[\'"]\s*')
def yk_read(varname, prefix='', suffix='', flags=None):
def yk_pattern(varname, prefix='', suffix='', flags=None):
regex = r'(?m)^(?!#)\$baseParams\[\'__YKVAL_%s__\'\]\s*=' \
'\s*%s(.*?)%s\s*;\s*$' % (varname, prefix, suffix)
if flags:
@ -22,141 +27,76 @@ def yk_write(varname, prefix='', suffix=''):
(varname, prefix, x, suffix)
def yk_read_str(varname):
return yk_read(varname, '[\'"]', '[\'"]')
def yk_handler(varname, default):
return ValueHandler(yk_pattern(varname), yk_write(varname),
default=default)
def yk_write_str(varname):
return yk_write(varname, '"', '"')
def strip_quotes(value):
match = VALUE.match(value)
if match:
return match.group(1)
return value
def strip_comments(value):
return COMMENT.sub('', value)
def yk_parse_arraystring(value):
value = strip_comments(value).strip()
return [strip_quotes(x) for x in value.split(',')]
def yk_array_handler(varname):
pattern = yk_pattern(varname, 'array\(', '\)', 's')
str_write = yk_write(varname, 'array(' + os.linesep, os.linesep + ')')
writer = lambda xs: str_write((',' + os.linesep)
.join(['\t"%s"' % x for x in xs]))
reader = lambda match: yk_parse_arraystring(match.group(1))
return ValueHandler(pattern, writer, reader, [])
ykval_config = FileConfig(
'/home/dain/yubico/yubiadmin/ykval-config.php',
[
('sync_default', yk_handler('SYNC_DEFAULT_LEVEL', 60)),
('sync_secure', yk_handler('SYNC_SECURE_LEVEL', 40)),
('sync_fast', yk_handler('SYNC_FAST_LEVEL', 1)),
('default_timeout', yk_handler('SYNC_DEFAULT_TIMEOUT', 1)),
('sync_interval', yk_handler('SYNC_INTERVAL', 10)),
('resync_timeout', yk_handler('SYNC_RESYNC_TIMEOUT', 30)),
('old_limit', yk_handler('SYNC_OLD_LIMIT', 10)),
('sync_pool', yk_array_handler('SYNC_POOL'))
]
)
class SyncLevelsForm(ConfigForm):
legend = 'Sync Levels'
config = ykval_config
sync_default = IntegerField('Default', [NumberRange(1, 100)])
sync_secure = IntegerField('Secure', [NumberRange(1, 100)])
sync_fast = IntegerField('Fast', [NumberRange(1, 100)])
config = FileConfig(
'/home/dain/yubico/yubiadmin/ykval-config.php',
[
(
'sync_default',
yk_read('SYNC_DEFAULT_LEVEL'),
yk_write('SYNC_DEFAULT_LEVEL'),
60
), (
'sync_secure',
yk_read('SYNC_SECURE_LEVEL'),
yk_write('SYNC_SECURE_LEVEL'),
40
), (
'sync_fast',
yk_read('SYNC_FAST_LEVEL'),
yk_write('SYNC_FAST_LEVEL'),
1
),
]
)
class MiscForm(ConfigForm):
legend = 'Misc'
config = ykval_config
default_timeout = IntegerField('Default Timeout', [NumberRange(0)])
config = FileConfig(
'/home/dain/yubico/yubiadmin/ykval-config.php',
[(
'default_timeout',
yk_read('SYNC_DEFAULT_TIMEOUT'),
yk_write('SYNC_DEFAULT_TIMEOUT'),
1
)]
)
class ListField(Field):
COMMENT = re.compile(r'/\*.*?\*/')
VALUE = re.compile(r'\s*[\'"](.*)[\'"]\s*')
widget = TextInput()
def process_formdata(self, values):
if values:
self.data = filter(None, [x.strip() for x in values[0].split(',')])
def process_data(self, value):
if value:
data = []
value = self.COMMENT.sub('', value)
for val in value.split(','):
match = self.VALUE.match(val)
if match:
data.append(match.group(1))
self.data = data
else:
self.data = []
def _value(self):
if self.data:
return ', '.join(self.data)
else:
return ''
def yk_array_write(varname):
str_write = yk_write(varname, 'array(', ')')
return lambda xs: str_write(', '.join(['"%s"' % x for x in xs]))
class SyncPoolForm(ConfigForm):
legend = 'Sync Settings'
config = ykval_config
attrs = {'sync_pool': {'rows': 5, 'class': 'input-xlarge'}}
sync_interval = IntegerField('Sync Interval', [NumberRange(1)])
resync_timeout = IntegerField('Resync Timeout', [NumberRange(1)])
old_limit = IntegerField('Old Limit', [NumberRange(1)])
sync_pool = ListField('Servers')
sync_pool_add = StringField('Add Server')
config = FileConfig(
'/home/dain/yubico/yubiadmin/ykval-config.php',
[
(
'sync_interval',
yk_read('SYNC_INTERVAL'),
yk_write('SYNC_INTERVAL'),
10
), (
'resync_timeout',
yk_read('SYNC_RESYNC_TIMEOUT'),
yk_write('SYNC_RESYNC_TIMEOUT'),
30
), (
'old_limit',
yk_read('SYNC_OLD_LIMIT'),
yk_write('SYNC_OLD_LIMIT'),
10
), (
'sync_pool',
yk_read('SYNC_POOL', 'array\(', '\)', 's'),
yk_array_write('SYNC_POOL'),
''
)
]
)
def validate(self):
if super(SyncPoolForm, self).validate():
if self.sync_pool_add.data:
self.sync_pool.data.append(self.sync_pool_add.data)
self.sync_pool_add.process_data(None)
return True
return False
COMMENT = re.compile(r'/\*.*?\*/')
def remove_comments(content):
return COMMENT.sub('', content)
class YubikeyVal(App):
@ -179,8 +119,9 @@ class YubikeyVal(App):
"""
Database Settings
"""
return self.render_forms(request, [
DBConfigForm('/home/dain/yubico/yubiadmin/config-db.php')])
dbform = DBConfigForm('/home/dain/yubico/yubiadmin/config-db.php',
dbname='ykval', dbuser='ykval_verifier')
return self.render_forms(request, [dbform])
def syncpool(self, request):
"""
@ -189,8 +130,7 @@ class YubikeyVal(App):
sync_pool_form = SyncPoolForm()
form_page = self.render_forms(request, [sync_pool_form])
print 'Sync pool: %s' % \
remove_comments(sync_pool_form.config['sync_pool'])
print 'Sync pool: %r' % sync_pool_form.config['sync_pool']
return form_page
def ksms(self, request):

View File

@ -1,171 +0,0 @@
import os
import re
from UserDict import DictMixin
from wtforms import Form, StringField, IntegerField, PasswordField
from wtforms.widgets import PasswordInput
from wtforms.validators import Optional, NumberRange
from jinja2 import Environment, FileSystemLoader
__all__ = [
'App',
'FileConfig',
'ConfigForm',
'DBConfigForm',
'render',
'populate_forms',
]
cwd = os.path.dirname(__file__)
base_dir = os.path.abspath(os.path.join(cwd, os.pardir))
template_dir = os.path.join(base_dir, 'templates')
env = Environment(loader=FileSystemLoader(template_dir))
def render(tmpl, **kwargs):
template = env.get_template('%s.html' % tmpl)
return template.render(**kwargs)
def populate_forms(forms, data):
if not data:
for form in forms:
form.load()
else:
errors = False
for form in forms:
form.process(data)
errors = not form.validate() or errors
if not errors:
for form in forms:
form.save()
else:
print 'Errors!'
class App(object):
name = None
sections = []
def render_forms(self, request, forms):
populate_forms(forms, request.params)
return render('form', target=request.path, fieldsets=forms)
class ValueHandler(object):
def __init__(self, pattern, writer, default=None, group=1):
self.pattern = re.compile(pattern)
self.writer = writer
self.default = default
self.group = group
def read(self, content):
match = self.pattern.search(content)
if match:
return match.group(self.group)
return self.default
def write(self, content, value):
if value is None:
value = ''
if self.pattern.search(content):
content = self.pattern.sub(self.writer(value), content, 1)
else:
content += os.linesep + self.writer(value)
return content
class FileConfig(DictMixin):
"""
Maps key-value pairs to a backing config file.
You can manually edit the file by modifying self.content.
"""
def __init__(self, filename, params=[]):
self.filename = filename
self.params = {}
for param in params:
self.add_param(*param)
def read(self):
try:
with open(self.filename, 'r') as file:
self.content = file.read()
except IOError as e:
print e
self.content = ''
def commit(self):
with open(self.filename, 'w+') as file:
file.write(self.content)
def add_param(self, key, pattern, writer, default=None, group=1):
self.params[key] = ValueHandler(pattern, writer, default, group)
def __getitem__(self, key):
return self.params[key].read(self.content)
def __setitem__(self, key, value):
self.content = self.params[key].write(self.content, value)
def keys(self):
return self.params.keys()
def __delitem__(self, key):
del self.params[key]
class ConfigForm(Form):
"""
Form that can load and save data to a config.
"""
config = None
def load(self):
self.config.read()
for field in self:
if field.id in self.config:
field.process_data(self.config[field.id])
def save(self):
self.config.read()
for field in self:
if field.id in self.config:
self.config[field.id] = field.data
self.config.commit()
def db_read(varname):
return r'\$db%s=\'(.*)\';' % varname
def db_write(varname):
return lambda x: '$db%s=\'%s\';' % (varname, x)
class DBConfigForm(ConfigForm):
"""
Complete form for editing a dbconfig-common generated for PHP.
"""
legend = 'Database'
dbtype = StringField('DB type')
dbserver = StringField('Host')
dbport = IntegerField('Port', [Optional(), NumberRange(1, 65535)])
dbname = StringField('DB name')
dbuser = StringField('DB username')
dbpass = PasswordField('DB password',
widget=PasswordInput(hide_value=False))
config = FileConfig(
'/dev/null',
[
('dbtype', db_read('type'), db_write('type'), 'mysql'),
('dbserver', db_read('server'), db_write('server'), 'localhost'),
('dbport', db_read('port'), db_write('port'), ''),
('dbname', db_read('name'), db_write('name'), 'ykval'),
('dbuser', db_read('user'), db_write('user'), 'ykval_verifier'),
('dbpass', db_read('pass'), db_write('pass'), ''),
]
)
def __init__(self, filename, *args, **kwargs):
self.__class__.config.filename = filename
super(DBConfigForm, self).__init__(*args, **kwargs)

View File

43
yubiadmin/util/app.py Normal file
View File

@ -0,0 +1,43 @@
import os
from jinja2 import Environment, FileSystemLoader
__all__ = [
'App',
'render',
'populate_forms',
]
cwd = os.path.dirname(__file__)
base_dir = os.path.abspath(os.path.join(cwd, os.pardir, os.pardir))
template_dir = os.path.join(base_dir, 'templates')
env = Environment(loader=FileSystemLoader(template_dir))
def render(tmpl, **kwargs):
template = env.get_template('%s.html' % tmpl)
return template.render(**kwargs)
def populate_forms(forms, data):
if not data:
for form in forms:
form.load()
else:
errors = False
for form in forms:
form.process(data)
errors = not form.validate() or errors
if not errors:
for form in forms:
form.save()
else:
print 'Errors!'
class App(object):
name = None
sections = []
def render_forms(self, request, forms, template='form'):
populate_forms(forms, request.params)
return render(template, target=request.path, fieldsets=forms)

71
yubiadmin/util/config.py Normal file
View File

@ -0,0 +1,71 @@
import os
import re
from UserDict import DictMixin
__all__ = [
'ValueHandler',
'FileConfig'
]
class ValueHandler(object):
def __init__(self, pattern, writer, reader=lambda x: x.group(1),
default=None):
self.pattern = re.compile(pattern)
self.writer = writer
self.reader = reader
self.default = default
def read(self, content):
match = self.pattern.search(content)
if match:
return self.reader(match)
return self.default
def write(self, content, value):
if value is None:
value = ''
if self.pattern.search(content):
content = self.pattern.sub(self.writer(value), content, 1)
else:
content += os.linesep + self.writer(value)
return content
class FileConfig(DictMixin):
"""
Maps key-value pairs to a backing config file.
You can manually edit the file by modifying self.content.
"""
def __init__(self, filename, params=[]):
self.filename = filename
self.params = {}
for param in params:
self.add_param(*param)
def read(self):
try:
with open(self.filename, 'r') as file:
self.content = file.read()
except IOError as e:
print e
self.content = ''
def commit(self):
with open(self.filename, 'w+') as file:
file.write(self.content)
def add_param(self, key, handler):
self.params[key] = handler
def __getitem__(self, key):
return self.params[key].read(self.content)
def __setitem__(self, key, value):
self.content = self.params[key].write(self.content, value)
def keys(self):
return self.params.keys()
def __delitem__(self, key):
del self.params[key]

85
yubiadmin/util/form.py Normal file
View File

@ -0,0 +1,85 @@
from wtforms import Form, StringField, IntegerField, PasswordField, Field
from wtforms.widgets import PasswordInput, TextArea
from wtforms.validators import Optional, NumberRange
from yubiadmin.util.config import ValueHandler, FileConfig
__all__ = [
'ListField',
'ConfigForm',
'DBConfigForm'
]
class ListField(Field):
widget = TextArea()
def process_formdata(self, values):
if values:
self.data = filter(None, [x.strip() for x in values[0].split()])
def _value(self):
if self.data:
return '\n'.join(self.data)
else:
return ''
class ConfigForm(Form):
"""
Form that can load and save data to a config.
"""
config = None
def load(self):
self.config.read()
for field in self:
if field.id in self.config:
field.process_data(self.config[field.id])
def save(self):
self.config.read()
for field in self:
if field.id in self.config:
self.config[field.id] = field.data
self.config.commit()
class DBConfigForm(ConfigForm):
"""
Complete form for editing a dbconfig-common generated for PHP.
"""
legend = 'Database'
dbtype = StringField('DB type')
dbserver = StringField('Host')
dbport = IntegerField('Port', [Optional(), NumberRange(1, 65535)])
dbname = StringField('DB name')
dbuser = StringField('DB username')
dbpass = PasswordField('DB password',
widget=PasswordInput(hide_value=False))
def db_handler(self, varname, default):
pattern = r'\$%s=\'(.*)\';' % varname
writer = lambda x: '$%s=\'%s\';' % (varname, x)
return ValueHandler(pattern, writer, default=default)
def __init__(self, filename, *args, **kwargs):
if not self.config:
self.config = FileConfig(
filename,
[
('dbtype', self.db_handler(
'dbtype', kwargs.pop('dbtype', 'mysql'))),
('dbserver', self.db_handler(
'dbserver', kwargs.pop('dbserver', 'localhost'))),
('dbport', self.db_handler(
'dbport', kwargs.pop('dbport', ''))),
('dbname', self.db_handler(
'dbname', kwargs.pop('dbname', ''))),
('dbuser', self.db_handler(
'dbuser', kwargs.pop('dbuser', ''))),
('dbpass', self.db_handler(
'dbpass', kwargs.pop('dbpass', ''))),
]
)
super(DBConfigForm, self).__init__(*args, **kwargs)