From 5b956b9c7d4a01bf03a5407f410709db8fb04ba1 Mon Sep 17 00:00:00 2001 From: Scott Kitterman Date: Tue, 29 Oct 2019 01:50:28 -0400 Subject: [PATCH] Refactor SigningTable and KeyTables based on more careful reading of the documentation --- dkimpy_milter/config.py | 58 ++++++++++++++++------------------------- dkimpy_milter/util.py | 24 +++++++---------- tests/runtests | 20 +++++++------- 3 files changed, 43 insertions(+), 59 deletions(-) diff --git a/dkimpy_milter/config.py b/dkimpy_milter/config.py index b3c9159..001f6a2 100644 --- a/dkimpy_milter/config.py +++ b/dkimpy_milter/config.py @@ -261,26 +261,10 @@ def _make_authserv_id(as_id): as_id = socket.gethostname() return as_id -def _dataset_multiline(dst, dataset): - """Convert one list element per line on multi-line datasets to a list of - lists""" - result = [] - for row in dataset: - rowl = row.split(',') - for element in rowl: - rowl[rowl.index(element)] = element.strip().strip(',') - if dst == 'KeyTable' and len(rowl) != 3: - raise dkim.ParameterError('Invalid {0} element (need three paramters per row): {1}' - .format(str(dst), str(rowl))) - if dst == 'SigningTable' and len(rowl) > 2: - raise dkim.ParameterError('Invalid {0} element (need one or two paramters per row): {1}' - .format(str(dst), str(rowl))) - result.append(rowl) - return result - def _dataset_to_list(dataset): """Convert a dataset (as defined in dkimpymilter.8) and return a python - list of values.""" + list of values. For multiline datasets like KeyTable and SigningTable a + key : values dictionary is returned""" if not isinstance(dataset, str): # If it was a csl with more than one value, it's already a list, we # only need to remove the name from the first value. @@ -290,23 +274,34 @@ def _dataset_to_list(dataset): dataset[dataset.index(item)] = item.strip().strip(',') return dataset elif isinstance(dataset, str): - if dataset[0] == '/' or dataset[:5] == 'file:': - # This is a flat file dataset + if dataset[0] == '/' or dataset[:5] == 'file:' or dataset[:7] == 'refile:': + # This is a flat file dataset, which are key value:value stores ds = [] + dsd = {} if dataset[0] == '/': dsname = dataset - if dataset[:5] == 'file:': + elif dataset[:5] == 'file:': dsname = dataset[5:] + elif dataset[:7] == 'refile:': + dsname = dataset[7:] dsf = open(dsname, 'r') for line in dsf.readlines(): if line[0] != '#': - if len(line.split(':')) == 1: - ds.append(line.strip()) - else: - for element in line.split(':'): - ds.append(element.strip().strip(':')) + if len(line.split()) == 1: + if len(line.split(':')) == 1: + ds.append(line.strip()) + else: + for element in line.split(':'): + ds.append(element.strip().strip(':')) + elif len(line.split()) == 2: # key value:value:value + key, values = line.split() + values = values.split(':') + dsd.update({key:values}) dsf.close() - return ds + if ds: + return ds + elif dsd: + return dsd # If it's a str and csl, it has one value and we return a list if dataset[:4] == 'csl:': return [dataset[4:].strip().strip(',')] @@ -428,14 +423,7 @@ def _readConfigFile(path, configData=None, configGlobal={}): elif conversion == 'int': configData[name] = int(value) elif conversion == 'dataset': - interim_value = _dataset_to_list(value) - # These are the only multi-line dataset types - if name == 'KeyTable' or name == 'KeyTableEd25519': - configData[name] = _dataset_multiline('KeyTable', interim_value) - elif name == 'SigningTable': - configData[name] = _dataset_multiline('SigningTable', interim_value) - else: - configData[name] = interim_value + configData[name] = _dataset_to_list(value) else: syslog.syslog(str('name: ' + name + ' value: ' + value + ' conversion: ' + conversion)) diff --git a/dkimpy_milter/util.py b/dkimpy_milter/util.py index 114d894..36a42be 100644 --- a/dkimpy_milter/util.py +++ b/dkimpy_milter/util.py @@ -187,25 +187,19 @@ def read_keyfile(keyfile, milterconfig): key += line return key -def read_keytable(tablelist, milterconfig): +def read_keytable(tabledict, milterconfig): """Read keytables into in memory configuration data so all keys are read before priviledges are dropped. - tablelist contains a list of KeyTable rows (three elements, comma separated): - domain, selector, key file location - When loaded, KeyTableData is a dict: - {domain: [selector, key]}""" + When loaded, tabeldict is a dict: + {searchkey: [donamin, selector, key]} + If key is a file (startswith('/'), then the key is returned in its place.""" import dkim import syslog - keytabledata = {} - for row in tablelist: - for element in row: - row[row.index(element)] = element.strip().strip(',') - if len(row) != 3: - raise dkim.ParameterError('Invalid KeyTable element (need three paramters per row): {0}' - .format(str(row))) - key = read_keyfile(row[2], milterconfig) - keytabledata.update({row[0]:[row[1], key]}) - return keytabledata + for dictkey, values in tabledict.items(): + if values[-1][:1] == '/': + key = read_keyfile(values[-1], milterconfig) + tabledict[dictkey] = [values[0], values[1], key] + return tabledict def get_keys(milterconfig): """Read keys (table or file) into memory before dropping priviledges""" diff --git a/tests/runtests b/tests/runtests index 4b479eb..5dee9c9 100755 --- a/tests/runtests +++ b/tests/runtests @@ -77,21 +77,23 @@ debugLevel 5 EOF cat > "$keytype.table.verify.conf" < "$keytype-table" < "signing-table" <