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:
parent
f3c6be25e6
commit
7038ebe7fe
@ -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
|
||||
|
||||
|
||||
|
@ -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()
|
||||
|
@ -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):
|
||||
|
@ -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)
|
0
yubiadmin/util/__init__.py
Normal file
0
yubiadmin/util/__init__.py
Normal file
43
yubiadmin/util/app.py
Normal file
43
yubiadmin/util/app.py
Normal 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
71
yubiadmin/util/config.py
Normal 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
85
yubiadmin/util/form.py
Normal 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)
|
Loading…
x
Reference in New Issue
Block a user