calcurse-caldav: improve config file error handling
The previous implementation allowed sections and keys other than those used by the script which led to a variety of bug reports due to typos in the configuration. Disallow entries other than those explicitly used and make both section and key names case-sensitive (previously, only section names where case-sensitive). Check that Hostname and Path are set before using them. Addresses GitHub issues #327 and #350. Signed-off-by: Lukas Fleischer <lfleischer@calcurse.org>
This commit is contained in:
parent
4777c60056
commit
594bd62378
@ -22,6 +22,70 @@ except ModuleNotFoundError:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
_map = {}
|
||||||
|
|
||||||
|
def __init__(self, fn):
|
||||||
|
self._map = {
|
||||||
|
'Auth': {
|
||||||
|
'Password': None,
|
||||||
|
'Username': None,
|
||||||
|
},
|
||||||
|
'CustomHeaders': {},
|
||||||
|
'General': {
|
||||||
|
'AuthMethod': 'basic',
|
||||||
|
'Binary': 'calcurse',
|
||||||
|
'Debug': False,
|
||||||
|
'DryRun': True,
|
||||||
|
'HTTPS': True,
|
||||||
|
'Hostname': None,
|
||||||
|
'InsecureSSL': False,
|
||||||
|
'Path': None,
|
||||||
|
'SyncFilter': 'cal,todo',
|
||||||
|
'Verbose': False,
|
||||||
|
},
|
||||||
|
'OAuth2': {
|
||||||
|
'ClientID': None,
|
||||||
|
'ClientSecret': None,
|
||||||
|
'RedirectURI': 'http://127.0.0.1',
|
||||||
|
'Scope': None,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
config = configparser.RawConfigParser()
|
||||||
|
config.optionxform = str
|
||||||
|
if verbose:
|
||||||
|
print('Loading configuration from ' + configfn + '...')
|
||||||
|
try:
|
||||||
|
config.read_file(open(fn))
|
||||||
|
except FileNotFoundError as e:
|
||||||
|
die('Configuration file not found: {}'.format(fn))
|
||||||
|
|
||||||
|
for sec in config.sections():
|
||||||
|
if sec not in self._map:
|
||||||
|
die('Unexpected config section: {}'.format(sec))
|
||||||
|
|
||||||
|
if not self._map[sec]:
|
||||||
|
# Import section with custom key-value pairs.
|
||||||
|
self._map[sec] = dict(config.items(sec))
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Import section with predefined keys.
|
||||||
|
for key, val in config.items(sec):
|
||||||
|
if key not in self._map[sec]:
|
||||||
|
die('Unexpected config key in section {}: {}'.format(sec, key))
|
||||||
|
if type(self._map[sec][key]) == bool:
|
||||||
|
self._map[sec][key] = config.getboolean(sec, key)
|
||||||
|
else:
|
||||||
|
self._map[sec][key] = val
|
||||||
|
|
||||||
|
def section(self, section):
|
||||||
|
return self._map[section]
|
||||||
|
|
||||||
|
def get(self, section, key):
|
||||||
|
return self._map[section][key]
|
||||||
|
|
||||||
|
|
||||||
def msgfmt(msg, prefix=''):
|
def msgfmt(msg, prefix=''):
|
||||||
lines = []
|
lines = []
|
||||||
for line in msg.splitlines():
|
for line in msg.splitlines():
|
||||||
@ -592,101 +656,46 @@ debug_raw = args.debug_raw
|
|||||||
password = os.getenv('CALCURSE_CALDAV_PASSWORD')
|
password = os.getenv('CALCURSE_CALDAV_PASSWORD')
|
||||||
|
|
||||||
# Read configuration.
|
# Read configuration.
|
||||||
config = configparser.RawConfigParser()
|
config = Config(configfn)
|
||||||
if verbose:
|
|
||||||
print('Loading configuration from ' + configfn + '...')
|
|
||||||
try:
|
|
||||||
config.read_file(open(configfn))
|
|
||||||
except FileNotFoundError as e:
|
|
||||||
die('Configuration file not found: {}'.format(configfn))
|
|
||||||
|
|
||||||
if config.has_option('General', 'InsecureSSL'):
|
authmethod = config.get('General', 'AuthMethod').lower()
|
||||||
insecure_ssl = config.getboolean('General', 'InsecureSSL')
|
calcurse = [config.get('General', 'Binary')]
|
||||||
else:
|
debug = debug or config.get('General', 'Debug')
|
||||||
insecure_ssl = False
|
dry_run = config.get('General', 'DryRun')
|
||||||
|
hostname = config.get('General', 'Hostname')
|
||||||
|
https = config.get('General', 'HTTPS')
|
||||||
|
insecure_ssl = config.get('General', 'InsecureSSL')
|
||||||
|
path = config.get('General', 'Path')
|
||||||
|
sync_filter = config.get('General', 'SyncFilter')
|
||||||
|
verbose = verbose or config.get('General', 'Verbose')
|
||||||
|
|
||||||
# Read config for "HTTPS" option (default=True)
|
password = password or config.get('Auth', 'Password')
|
||||||
if config.has_option('General', 'HTTPS'):
|
username = config.get('Auth', 'Username')
|
||||||
https = config.getboolean('General', 'HTTPS')
|
|
||||||
else:
|
|
||||||
https = True
|
|
||||||
|
|
||||||
if config.has_option('General', 'Binary'):
|
client_id = config.get('OAuth2', 'ClientID')
|
||||||
calcurse = [config.get('General', 'Binary')]
|
client_secret = config.get('OAuth2', 'ClientSecret')
|
||||||
else:
|
redirect_uri = config.get('OAuth2', 'RedirectURI')
|
||||||
calcurse = ['calcurse']
|
scope = config.get('OAuth2', 'Scope')
|
||||||
|
|
||||||
|
custom_headers = config.section('CustomHeaders')
|
||||||
|
|
||||||
|
# Append data directory to calcurse command.
|
||||||
if datadir:
|
if datadir:
|
||||||
check_dir(datadir)
|
check_dir(datadir)
|
||||||
calcurse += ['-D', datadir]
|
calcurse += ['-D', datadir]
|
||||||
|
|
||||||
if config.has_option('General', 'DryRun'):
|
# Validate sync filter.
|
||||||
dry_run = config.getboolean('General', 'DryRun')
|
invalid_filter_values = validate_sync_filter()
|
||||||
else:
|
if len(invalid_filter_values):
|
||||||
dry_run = True
|
|
||||||
|
|
||||||
if not verbose and config.has_option('General', 'Verbose'):
|
|
||||||
verbose = config.getboolean('General', 'Verbose')
|
|
||||||
|
|
||||||
if not debug and config.has_option('General', 'Debug'):
|
|
||||||
debug = config.getboolean('General', 'Debug')
|
|
||||||
|
|
||||||
if config.has_option('General', 'AuthMethod'):
|
|
||||||
authmethod = config.get('General', 'AuthMethod').lower()
|
|
||||||
else:
|
|
||||||
authmethod = 'basic'
|
|
||||||
|
|
||||||
if config.has_option('General', 'SyncFilter'):
|
|
||||||
sync_filter = config.get('General', 'SyncFilter')
|
|
||||||
|
|
||||||
invalid_filter_values = validate_sync_filter()
|
|
||||||
|
|
||||||
if len(invalid_filter_values):
|
|
||||||
die('Invalid value(s) in SyncFilter option: ' + ', '.join(invalid_filter_values))
|
die('Invalid value(s) in SyncFilter option: ' + ', '.join(invalid_filter_values))
|
||||||
else:
|
|
||||||
sync_filter = 'cal,todo'
|
|
||||||
|
|
||||||
if config.has_option('Auth', 'UserName'):
|
# Ensure host name and path are defined and initialize *_uri.
|
||||||
username = config.get('Auth', 'UserName')
|
if not hostname:
|
||||||
else:
|
die('Hostname missing in configuration.')
|
||||||
username = None
|
if not path:
|
||||||
|
die('Path missing in configuration.')
|
||||||
if config.has_option('Auth', 'Password') and not password:
|
urlprefix = "https://" if https else "http://"
|
||||||
password = config.get('Auth', 'Password')
|
path = '/{}/'.format(path.strip('/'))
|
||||||
|
|
||||||
if config.has_section('CustomHeaders'):
|
|
||||||
custom_headers = dict(config.items('CustomHeaders'))
|
|
||||||
else:
|
|
||||||
custom_headers = {}
|
|
||||||
|
|
||||||
if config.has_option('OAuth2', 'ClientID'):
|
|
||||||
client_id = config.get('OAuth2', 'ClientID')
|
|
||||||
else:
|
|
||||||
client_id = None
|
|
||||||
|
|
||||||
if config.has_option('OAuth2', 'ClientSecret'):
|
|
||||||
client_secret = config.get('OAuth2', 'ClientSecret')
|
|
||||||
else:
|
|
||||||
client_secret = None
|
|
||||||
|
|
||||||
if config.has_option('OAuth2', 'Scope'):
|
|
||||||
scope = config.get('OAuth2', 'Scope')
|
|
||||||
else:
|
|
||||||
scope = None
|
|
||||||
|
|
||||||
if config.has_option('OAuth2', 'RedirectURI'):
|
|
||||||
redirect_uri = config.get('OAuth2', 'RedirectURI')
|
|
||||||
else:
|
|
||||||
redirect_uri = 'http://127.0.0.1'
|
|
||||||
|
|
||||||
# Change URl prefix according to HTTP/HTTPS
|
|
||||||
if https:
|
|
||||||
urlprefix = "https://"
|
|
||||||
else:
|
|
||||||
urlprefix = "http://"
|
|
||||||
|
|
||||||
hostname = config.get('General', 'HostName')
|
|
||||||
path = '/' + config.get('General', 'Path').strip('/') + '/'
|
|
||||||
hostname_uri = urlprefix + hostname
|
hostname_uri = urlprefix + hostname
|
||||||
absolute_uri = hostname_uri + path
|
absolute_uri = hostname_uri + path
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user