comparison sat/memory/params.py @ 2624:56f94936df1e

code style reformatting using black
author Goffi <goffi@goffi.org>
date Wed, 27 Jun 2018 20:14:46 +0200
parents 26edcf3a30eb
children e9cd473a2f46
comparison
equal deleted inserted replaced
2623:49533de4540b 2624:56f94936df1e
22 from sat.core import exceptions 22 from sat.core import exceptions
23 from sat.core.constants import Const as C 23 from sat.core.constants import Const as C
24 from sat.memory.crypto import BlockCipher, PasswordHasher 24 from sat.memory.crypto import BlockCipher, PasswordHasher
25 from xml.dom import minidom, NotFoundErr 25 from xml.dom import minidom, NotFoundErr
26 from sat.core.log import getLogger 26 from sat.core.log import getLogger
27
27 log = getLogger(__name__) 28 log = getLogger(__name__)
28 from twisted.internet import defer 29 from twisted.internet import defer
29 from twisted.python.failure import Failure 30 from twisted.python.failure import Failure
30 from twisted.words.xish import domish 31 from twisted.words.xish import domish
31 from twisted.words.protocols.jabber import jid 32 from twisted.words.protocols.jabber import jid
41 42
42 @param jids(iterable[id.jID]): jids to use 43 @param jids(iterable[id.jID]): jids to use
43 @return (generator[domish.Element]): <jid/> elements 44 @return (generator[domish.Element]): <jid/> elements
44 """ 45 """
45 for jid_ in jids: 46 for jid_ in jids:
46 jid_elt = domish.Element((None, 'jid')) 47 jid_elt = domish.Element((None, "jid"))
47 jid_elt.addContent(jid_.full()) 48 jid_elt.addContent(jid_.full())
48 yield jid_elt 49 yield jid_elt
49 50
50 51
51 class Params(object): 52 class Params(object):
52 """This class manage parameters with xml""" 53 """This class manage parameters with xml"""
54
53 ### TODO: add desciption in params 55 ### TODO: add desciption in params
54 56
55 #TODO: when priority is changed, a new presence stanza must be emitted 57 # TODO: when priority is changed, a new presence stanza must be emitted
56 #TODO: int type (Priority should be int instead of string) 58 # TODO: int type (Priority should be int instead of string)
57 default_xml = u""" 59 default_xml = u"""
58 <params> 60 <params>
59 <general> 61 <general>
60 </general> 62 </general>
61 <individual> 63 <individual>
75 <param name="autodisconnect" label="%(autodisconnect_label)s" value="false" type="bool" security="50" /> 77 <param name="autodisconnect" label="%(autodisconnect_label)s" value="false" type="bool" security="50" />
76 </category> 78 </category>
77 </individual> 79 </individual>
78 </params> 80 </params>
79 """ % { 81 """ % {
80 'category_general': D_("General"), 82 "category_general": D_("General"),
81 'category_connection': D_("Connection"), 83 "category_connection": D_("Connection"),
82 'history_param': C.HISTORY_LIMIT, 84 "history_param": C.HISTORY_LIMIT,
83 'history_label': D_('Chat history limit'), 85 "history_label": D_("Chat history limit"),
84 'show_offline_contacts': C.SHOW_OFFLINE_CONTACTS, 86 "show_offline_contacts": C.SHOW_OFFLINE_CONTACTS,
85 'show_offline_contacts_label': D_('Show offline contacts'), 87 "show_offline_contacts_label": D_("Show offline contacts"),
86 'show_empty_groups': C.SHOW_EMPTY_GROUPS, 88 "show_empty_groups": C.SHOW_EMPTY_GROUPS,
87 'show_empty_groups_label': D_('Show empty groups'), 89 "show_empty_groups_label": D_("Show empty groups"),
88 'force_server_param': C.FORCE_SERVER_PARAM, 90 "force_server_param": C.FORCE_SERVER_PARAM,
89 'force_port_param': C.FORCE_PORT_PARAM, 91 "force_port_param": C.FORCE_PORT_PARAM,
90 'new_account_label': D_("Register new account"), 92 "new_account_label": D_("Register new account"),
91 'autoconnect_label': D_('Connect on frontend startup'), 93 "autoconnect_label": D_("Connect on frontend startup"),
92 'autodisconnect_label': D_('Disconnect on frontend closure'), 94 "autodisconnect_label": D_("Disconnect on frontend closure"),
93 } 95 }
94 96
95 def load_default_params(self): 97 def load_default_params(self):
96 self.dom = minidom.parseString(Params.default_xml.encode('utf-8')) 98 self.dom = minidom.parseString(Params.default_xml.encode("utf-8"))
97 99
98 def _mergeParams(self, source_node, dest_node): 100 def _mergeParams(self, source_node, dest_node):
99 """Look for every node in source_node and recursively copy them to dest if they don't exists""" 101 """Look for every node in source_node and recursively copy them to dest if they don't exists"""
100 102
101 def getNodesMap(children): 103 def getNodesMap(children):
102 ret = {} 104 ret = {}
103 for child in children: 105 for child in children:
104 if child.nodeType == child.ELEMENT_NODE: 106 if child.nodeType == child.ELEMENT_NODE:
105 ret[(child.tagName, child.getAttribute('name'))] = child 107 ret[(child.tagName, child.getAttribute("name"))] = child
106 return ret 108 return ret
109
107 source_map = getNodesMap(source_node.childNodes) 110 source_map = getNodesMap(source_node.childNodes)
108 dest_map = getNodesMap(dest_node.childNodes) 111 dest_map = getNodesMap(dest_node.childNodes)
109 source_set = set(source_map.keys()) 112 source_set = set(source_map.keys())
110 dest_set = set(dest_map.keys()) 113 dest_set = set(dest_map.keys())
111 to_add = source_set.difference(dest_set) 114 to_add = source_set.difference(dest_set)
118 self._mergeParams(source_map[node_key], dest_map[node_key]) 121 self._mergeParams(source_map[node_key], dest_map[node_key])
119 122
120 def load_xml(self, xml_file): 123 def load_xml(self, xml_file):
121 """Load parameters template from xml file""" 124 """Load parameters template from xml file"""
122 self.dom = minidom.parse(xml_file) 125 self.dom = minidom.parse(xml_file)
123 default_dom = minidom.parseString(Params.default_xml.encode('utf-8')) 126 default_dom = minidom.parseString(Params.default_xml.encode("utf-8"))
124 self._mergeParams(default_dom.documentElement, self.dom.documentElement) 127 self._mergeParams(default_dom.documentElement, self.dom.documentElement)
125 128
126 def loadGenParams(self): 129 def loadGenParams(self):
127 """Load general parameters data from storage 130 """Load general parameters data from storage
128 131
138 @param cache: if not None, will be used to store the value, as a short time cache 141 @param cache: if not None, will be used to store the value, as a short time cache
139 @return: deferred triggered once params are loaded 142 @return: deferred triggered once params are loaded
140 """ 143 """
141 if cache is None: 144 if cache is None:
142 self.params[profile] = {} 145 self.params[profile] = {}
143 return self.storage.loadIndParams(self.params[profile] if cache is None else cache, profile) 146 return self.storage.loadIndParams(
147 self.params[profile] if cache is None else cache, profile
148 )
144 149
145 def purgeProfile(self, profile): 150 def purgeProfile(self, profile):
146 """Remove cache data of a profile 151 """Remove cache data of a profile
147 152
148 @param profile: %(doc_profile)s 153 @param profile: %(doc_profile)s
149 """ 154 """
150 try: 155 try:
151 del self.params[profile] 156 del self.params[profile]
152 except KeyError: 157 except KeyError:
153 log.error(_(u"Trying to purge cache of a profile not in memory: [%s]") % profile) 158 log.error(
159 _(u"Trying to purge cache of a profile not in memory: [%s]") % profile
160 )
154 161
155 def save_xml(self, filename): 162 def save_xml(self, filename):
156 """Save parameters template to xml file""" 163 """Save parameters template to xml file"""
157 with open(filename, 'wb') as xml_file: 164 with open(filename, "wb") as xml_file:
158 xml_file.write(self.dom.toxml('utf-8')) 165 xml_file.write(self.dom.toxml("utf-8"))
159 166
160 def __init__(self, host, storage): 167 def __init__(self, host, storage):
161 log.debug("Parameters init") 168 log.debug("Parameters init")
162 self.host = host 169 self.host = host
163 self.storage = storage 170 self.storage = storage
172 @param component(unicode): entry point if profile is a component 179 @param component(unicode): entry point if profile is a component
173 @param callback: called when the profile actually exists in database and memory 180 @param callback: called when the profile actually exists in database and memory
174 @return: a Deferred instance 181 @return: a Deferred instance
175 """ 182 """
176 if self.storage.hasProfile(profile): 183 if self.storage.hasProfile(profile):
177 log.info(_('The profile name already exists')) 184 log.info(_("The profile name already exists"))
178 return defer.fail(Failure(exceptions.ConflictError)) 185 return defer.fail(Failure(exceptions.ConflictError))
179 if not self.host.trigger.point("ProfileCreation", profile): 186 if not self.host.trigger.point("ProfileCreation", profile):
180 return defer.fail(Failure(exceptions.CancelError)) 187 return defer.fail(Failure(exceptions.CancelError))
181 return self.storage.createProfile(profile, component or None) 188 return self.storage.createProfile(profile, component or None)
182 189
187 @param force: force the deletion even if the profile is connected. 194 @param force: force the deletion even if the profile is connected.
188 To be used for direct calls only (not through the bridge). 195 To be used for direct calls only (not through the bridge).
189 @return: a Deferred instance 196 @return: a Deferred instance
190 """ 197 """
191 if not self.storage.hasProfile(profile): 198 if not self.storage.hasProfile(profile):
192 log.info(_('Trying to delete an unknown profile')) 199 log.info(_("Trying to delete an unknown profile"))
193 return defer.fail(Failure(exceptions.ProfileUnknownError(profile))) 200 return defer.fail(Failure(exceptions.ProfileUnknownError(profile)))
194 if self.host.isConnected(profile): 201 if self.host.isConnected(profile):
195 if force: 202 if force:
196 self.host.disconnect(profile) 203 self.host.disconnect(profile)
197 else: 204 else:
208 @param return_profile_keys: if True, return unmanaged profile keys (like C.PROF_KEY_ALL). This keys must be managed by the caller 215 @param return_profile_keys: if True, return unmanaged profile keys (like C.PROF_KEY_ALL). This keys must be managed by the caller
209 @return: requested profile name 216 @return: requested profile name
210 @raise exceptions.ProfileUnknownError: profile doesn't exists 217 @raise exceptions.ProfileUnknownError: profile doesn't exists
211 @raise exceptions.ProfileNotSetError: if C.PROF_KEY_NONE is used 218 @raise exceptions.ProfileNotSetError: if C.PROF_KEY_NONE is used
212 """ 219 """
213 if profile_key == '@DEFAULT@': 220 if profile_key == "@DEFAULT@":
214 default = self.host.memory.memory_data.get('Profile_default') 221 default = self.host.memory.memory_data.get("Profile_default")
215 if not default: 222 if not default:
216 log.info(_('No default profile, returning first one')) 223 log.info(_("No default profile, returning first one"))
217 try: 224 try:
218 default = self.host.memory.memory_data['Profile_default'] = self.storage.getProfilesList()[0] 225 default = self.host.memory.memory_data[
226 "Profile_default"
227 ] = self.storage.getProfilesList()[0]
219 except IndexError: 228 except IndexError:
220 log.info(_('No profile exist yet')) 229 log.info(_("No profile exist yet"))
221 raise exceptions.ProfileUnknownError(profile_key) 230 raise exceptions.ProfileUnknownError(profile_key)
222 return default # FIXME: temporary, must use real default value, and fallback to first one if it doesn't exists 231 return (
232 default
233 ) # FIXME: temporary, must use real default value, and fallback to first one if it doesn't exists
223 elif profile_key == C.PROF_KEY_NONE: 234 elif profile_key == C.PROF_KEY_NONE:
224 raise exceptions.ProfileNotSetError 235 raise exceptions.ProfileNotSetError
225 elif return_profile_keys and profile_key in [C.PROF_KEY_ALL]: 236 elif return_profile_keys and profile_key in [C.PROF_KEY_ALL]:
226 return profile_key # this value must be managed by the caller 237 return profile_key # this value must be managed by the caller
227 if not self.storage.hasProfile(profile_key): 238 if not self.storage.hasProfile(profile_key):
228 log.error(_(u'Trying to access an unknown profile (%s)') % profile_key) 239 log.error(_(u"Trying to access an unknown profile (%s)") % profile_key)
229 raise exceptions.ProfileUnknownError(profile_key) 240 raise exceptions.ProfileUnknownError(profile_key)
230 return profile_key 241 return profile_key
231 242
232 def __get_unique_node(self, parent, tag, name): 243 def __get_unique_node(self, parent, tag, name):
233 """return node with given tag 244 """return node with given tag
237 @param name: name to check (e.g. "JID") 248 @param name: name to check (e.g. "JID")
238 @return: node if it exist or None 249 @return: node if it exist or None
239 """ 250 """
240 for node in parent.childNodes: 251 for node in parent.childNodes:
241 if node.nodeName == tag and node.getAttribute("name") == name: 252 if node.nodeName == tag and node.getAttribute("name") == name:
242 #the node already exists 253 # the node already exists
243 return node 254 return node
244 #the node is new 255 # the node is new
245 return None 256 return None
246 257
247 def updateParams(self, xml, security_limit=C.NO_SECURITY_LIMIT, app=''): 258 def updateParams(self, xml, security_limit=C.NO_SECURITY_LIMIT, app=""):
248 """import xml in parameters, update if the param already exists 259 """import xml in parameters, update if the param already exists
249 260
250 If security_limit is specified and greater than -1, the parameters 261 If security_limit is specified and greater than -1, the parameters
251 that have a security level greater than security_limit are skipped. 262 that have a security level greater than security_limit are skipped.
252 @param xml: parameters in xml form 263 @param xml: parameters in xml form
253 @param security_limit: -1 means no security, 0 is the maximum security then the higher the less secure 264 @param security_limit: -1 means no security, 0 is the maximum security then the higher the less secure
254 @param app: name of the frontend registering the parameters or empty value 265 @param app: name of the frontend registering the parameters or empty value
255 """ 266 """
256 # TODO: should word with domish.Element 267 # TODO: should word with domish.Element
257 src_parent = minidom.parseString(xml.encode('utf-8')).documentElement 268 src_parent = minidom.parseString(xml.encode("utf-8")).documentElement
258 269
259 def pre_process_app_node(src_parent, security_limit, app): 270 def pre_process_app_node(src_parent, security_limit, app):
260 """Parameters that are registered from a frontend must be checked""" 271 """Parameters that are registered from a frontend must be checked"""
261 to_remove = [] 272 to_remove = []
262 for type_node in src_parent.childNodes: 273 for type_node in src_parent.childNodes:
263 if type_node.nodeName != C.INDIVIDUAL: 274 if type_node.nodeName != C.INDIVIDUAL:
264 to_remove.append(type_node) # accept individual parameters only 275 to_remove.append(type_node) # accept individual parameters only
265 continue 276 continue
266 for cat_node in type_node.childNodes: 277 for cat_node in type_node.childNodes:
267 if cat_node.nodeName != 'category': 278 if cat_node.nodeName != "category":
268 to_remove.append(cat_node) 279 to_remove.append(cat_node)
269 continue 280 continue
270 to_remove_count = 0 # count the params to be removed from current category 281 to_remove_count = (
282 0
283 ) # count the params to be removed from current category
271 for node in cat_node.childNodes: 284 for node in cat_node.childNodes:
272 if node.nodeName != "param" or not self.checkSecurityLimit(node, security_limit): 285 if node.nodeName != "param" or not self.checkSecurityLimit(
286 node, security_limit
287 ):
273 to_remove.append(node) 288 to_remove.append(node)
274 to_remove_count += 1 289 to_remove_count += 1
275 continue 290 continue
276 node.setAttribute('app', app) 291 node.setAttribute("app", app)
277 if len(cat_node.childNodes) == to_remove_count: # remove empty category 292 if (
293 len(cat_node.childNodes) == to_remove_count
294 ): # remove empty category
278 for dummy in xrange(0, to_remove_count): 295 for dummy in xrange(0, to_remove_count):
279 to_remove.pop() 296 to_remove.pop()
280 to_remove.append(cat_node) 297 to_remove.append(cat_node)
281 for node in to_remove: 298 for node in to_remove:
282 node.parentNode.removeChild(node) 299 node.parentNode.removeChild(node)
283 300
284 def import_node(tgt_parent, src_parent): 301 def import_node(tgt_parent, src_parent):
285 for child in src_parent.childNodes: 302 for child in src_parent.childNodes:
286 if child.nodeName == '#text': 303 if child.nodeName == "#text":
287 continue 304 continue
288 node = self.__get_unique_node(tgt_parent, child.nodeName, child.getAttribute("name")) 305 node = self.__get_unique_node(
306 tgt_parent, child.nodeName, child.getAttribute("name")
307 )
289 if not node: # The node is new 308 if not node: # The node is new
290 tgt_parent.appendChild(child.cloneNode(True)) 309 tgt_parent.appendChild(child.cloneNode(True))
291 else: 310 else:
292 if child.nodeName == "param": 311 if child.nodeName == "param":
293 # The child updates an existing parameter, we replace the node 312 # The child updates an existing parameter, we replace the node
308 @param xml: XML definition of the parameters to be added 327 @param xml: XML definition of the parameters to be added
309 @param security_limit: -1 means no security, 0 is the maximum security then the higher the less secure 328 @param security_limit: -1 means no security, 0 is the maximum security then the higher the less secure
310 @param app: name of the frontend registering the parameters 329 @param app: name of the frontend registering the parameters
311 """ 330 """
312 if not app: 331 if not app:
313 log.warning(_(u"Trying to register frontends parameters with no specified app: aborted")) 332 log.warning(
333 _(
334 u"Trying to register frontends parameters with no specified app: aborted"
335 )
336 )
314 return 337 return
315 if not hasattr(self, "frontends_cache"): 338 if not hasattr(self, "frontends_cache"):
316 self.frontends_cache = [] 339 self.frontends_cache = []
317 if app in self.frontends_cache: 340 if app in self.frontends_cache:
318 log.debug(_(u"Trying to register twice frontends parameters for %(app)s: aborted" % {"app": app})) 341 log.debug(
342 _(
343 u"Trying to register twice frontends parameters for %(app)s: aborted"
344 % {"app": app}
345 )
346 )
319 return 347 return
320 self.frontends_cache.append(app) 348 self.frontends_cache.append(app)
321 self.updateParams(xml, security_limit, app) 349 self.updateParams(xml, security_limit, app)
322 log.debug(u"Frontends parameters registered for %(app)s" % {'app': app}) 350 log.debug(u"Frontends parameters registered for %(app)s" % {"app": app})
323 351
324 def __default_ok(self, value, name, category): 352 def __default_ok(self, value, name, category):
325 #FIXME: will not work with individual parameters 353 # FIXME: will not work with individual parameters
326 self.setParam(name, value, category) 354 self.setParam(name, value, category)
327 355
328 def __default_ko(self, failure, name, category): 356 def __default_ko(self, failure, name, category):
329 log.error(_(u"Can't determine default value for [%(category)s/%(name)s]: %(reason)s") % {'category': category, 'name': name, 'reason': str(failure.value)}) 357 log.error(
358 _(u"Can't determine default value for [%(category)s/%(name)s]: %(reason)s")
359 % {"category": category, "name": name, "reason": str(failure.value)}
360 )
330 361
331 def setDefault(self, name, category, callback, errback=None): 362 def setDefault(self, name, category, callback, errback=None):
332 """Set default value of parameter 363 """Set default value of parameter
333 364
334 'default_cb' attibute of parameter must be set to 'yes' 365 'default_cb' attibute of parameter must be set to 'yes'
335 @param name: name of the parameter 366 @param name: name of the parameter
336 @param category: category of the parameter 367 @param category: category of the parameter
337 @param callback: must return a string with the value (use deferred if needed) 368 @param callback: must return a string with the value (use deferred if needed)
338 @param errback: must manage the error with args failure, name, category 369 @param errback: must manage the error with args failure, name, category
339 """ 370 """
340 #TODO: send signal param update if value changed 371 # TODO: send signal param update if value changed
341 #TODO: manage individual paramaters 372 # TODO: manage individual paramaters
342 log.debug ("setDefault called for %(category)s/%(name)s" % {"category": category, "name": name}) 373 log.debug(
343 node = self._getParamNode(name, category, '@ALL@') 374 "setDefault called for %(category)s/%(name)s"
375 % {"category": category, "name": name}
376 )
377 node = self._getParamNode(name, category, "@ALL@")
344 if not node: 378 if not node:
345 log.error(_(u"Requested param [%(name)s] in category [%(category)s] doesn't exist !") % {'name': name, 'category': category}) 379 log.error(
380 _(
381 u"Requested param [%(name)s] in category [%(category)s] doesn't exist !"
382 )
383 % {"name": name, "category": category}
384 )
346 return 385 return
347 if node[1].getAttribute('default_cb') == 'yes': 386 if node[1].getAttribute("default_cb") == "yes":
348 # del node[1].attributes['default_cb'] # default_cb is not used anymore as a flag to know if we have to set the default value, 387 # del node[1].attributes['default_cb'] # default_cb is not used anymore as a flag to know if we have to set the default value,
349 # and we can still use it later e.g. to call a generic setDefault method 388 # and we can still use it later e.g. to call a generic setDefault method
350 value = self._getParam(category, name, C.GENERAL) 389 value = self._getParam(category, name, C.GENERAL)
351 if value is None: # no value set by the user: we have the default value 390 if value is None: # no value set by the user: we have the default value
352 log.debug ("Default value to set, using callback") 391 log.debug("Default value to set, using callback")
353 d = defer.maybeDeferred(callback) 392 d = defer.maybeDeferred(callback)
354 d.addCallback(self.__default_ok, name, category) 393 d.addCallback(self.__default_ok, name, category)
355 d.addErrback(errback or self.__default_ko, name, category) 394 d.addErrback(errback or self.__default_ko, name, category)
356 395
357 def _getAttr_internal(self, node, attr, value): 396 def _getAttr_internal(self, node, attr, value):
362 @param node: XML param node 401 @param node: XML param node
363 @param attr: name of the attribute to get (e.g.: 'value' or 'type') 402 @param attr: name of the attribute to get (e.g.: 'value' or 'type')
364 @param value: user defined value 403 @param value: user defined value
365 @return: value (can be str, bool, int, list, None) 404 @return: value (can be str, bool, int, list, None)
366 """ 405 """
367 if attr == 'value': 406 if attr == "value":
368 value_to_use = value if value is not None else node.getAttribute(attr) # we use value (user defined) if it exist, else we use node's default value 407 value_to_use = (
369 if node.getAttribute('type') == 'bool': 408 value if value is not None else node.getAttribute(attr)
409 ) # we use value (user defined) if it exist, else we use node's default value
410 if node.getAttribute("type") == "bool":
370 return C.bool(value_to_use) 411 return C.bool(value_to_use)
371 if node.getAttribute('type') == 'int': 412 if node.getAttribute("type") == "int":
372 return int(value_to_use) 413 return int(value_to_use)
373 elif node.getAttribute('type') == 'list': 414 elif node.getAttribute("type") == "list":
374 if not value_to_use: # no user defined value, take default value from the XML 415 if (
375 options = [option for option in node.childNodes if option.nodeName == 'option'] 416 not value_to_use
376 selected = [option for option in options if option.getAttribute('selected') == 'true'] 417 ): # no user defined value, take default value from the XML
377 cat, param = node.parentNode.getAttribute('name'), node.getAttribute('name') 418 options = [
419 option
420 for option in node.childNodes
421 if option.nodeName == "option"
422 ]
423 selected = [
424 option
425 for option in options
426 if option.getAttribute("selected") == "true"
427 ]
428 cat, param = (
429 node.parentNode.getAttribute("name"),
430 node.getAttribute("name"),
431 )
378 if len(selected) == 1: 432 if len(selected) == 1:
379 value_to_use = selected[0].getAttribute('value') 433 value_to_use = selected[0].getAttribute("value")
380 log.info(_("Unset parameter (%(cat)s, %(param)s) of type list will use the default option '%(value)s'") % 434 log.info(
381 {'cat': cat, 'param': param, 'value': value_to_use}) 435 _(
436 "Unset parameter (%(cat)s, %(param)s) of type list will use the default option '%(value)s'"
437 )
438 % {"cat": cat, "param": param, "value": value_to_use}
439 )
382 return value_to_use 440 return value_to_use
383 if len(selected) == 0: 441 if len(selected) == 0:
384 log.error(_(u'Parameter (%(cat)s, %(param)s) of type list has no default option!') % {'cat': cat, 'param': param}) 442 log.error(
443 _(
444 u"Parameter (%(cat)s, %(param)s) of type list has no default option!"
445 )
446 % {"cat": cat, "param": param}
447 )
385 else: 448 else:
386 log.error(_(u'Parameter (%(cat)s, %(param)s) of type list has more than one default option!') % {'cat': cat, 'param': param}) 449 log.error(
450 _(
451 u"Parameter (%(cat)s, %(param)s) of type list has more than one default option!"
452 )
453 % {"cat": cat, "param": param}
454 )
387 raise exceptions.DataError 455 raise exceptions.DataError
388 elif node.getAttribute('type') == 'jids_list': 456 elif node.getAttribute("type") == "jids_list":
389 if value_to_use: 457 if value_to_use:
390 jids = value_to_use.split('\t') # FIXME: it's not good to use tabs as separator ! 458 jids = value_to_use.split(
459 "\t"
460 ) # FIXME: it's not good to use tabs as separator !
391 else: # no user defined value, take default value from the XML 461 else: # no user defined value, take default value from the XML
392 jids = [getText(jid_) for jid_ in node.getElementsByTagName("jid")] 462 jids = [getText(jid_) for jid_ in node.getElementsByTagName("jid")]
393 to_delete = [] 463 to_delete = []
394 for idx, value in enumerate(jids): 464 for idx, value in enumerate(jids):
395 try: 465 try:
396 jids[idx] = jid.JID(value) 466 jids[idx] = jid.JID(value)
397 except (RuntimeError, jid.InvalidFormat, AttributeError): 467 except (RuntimeError, jid.InvalidFormat, AttributeError):
398 log.warning(u"Incorrect jid value found in jids list: [{}]".format(value)) 468 log.warning(
469 u"Incorrect jid value found in jids list: [{}]".format(value)
470 )
399 to_delete.append(value) 471 to_delete.append(value)
400 for value in to_delete: 472 for value in to_delete:
401 jids.remove(value) 473 jids.remove(value)
402 return jids 474 return jids
403 return value_to_use 475 return value_to_use
410 @param node: XML param node 482 @param node: XML param node
411 @param attr: name of the attribute to get (e.g.: 'value' or 'type') 483 @param attr: name of the attribute to get (e.g.: 'value' or 'type')
412 @param value: user defined value 484 @param value: user defined value
413 @return (unicode, bool, int, list): value to retrieve 485 @return (unicode, bool, int, list): value to retrieve
414 """ 486 """
415 if attr == 'value' and node.getAttribute('type') == 'password': 487 if attr == "value" and node.getAttribute("type") == "password":
416 raise exceptions.InternalError('To retrieve password values, use _asyncGetAttr instead of _getAttr') 488 raise exceptions.InternalError(
489 "To retrieve password values, use _asyncGetAttr instead of _getAttr"
490 )
417 return self._getAttr_internal(node, attr, value) 491 return self._getAttr_internal(node, attr, value)
418 492
419 def _asyncGetAttr(self, node, attr, value, profile=None): 493 def _asyncGetAttr(self, node, attr, value, profile=None):
420 """Get attribute value. 494 """Get attribute value.
421 495
426 @param value: user defined value 500 @param value: user defined value
427 @param profile: %(doc_profile)s 501 @param profile: %(doc_profile)s
428 @return (unicode, bool, int, list): Deferred value to retrieve 502 @return (unicode, bool, int, list): Deferred value to retrieve
429 """ 503 """
430 value = self._getAttr_internal(node, attr, value) 504 value = self._getAttr_internal(node, attr, value)
431 if attr != 'value' or node.getAttribute('type') != 'password': 505 if attr != "value" or node.getAttribute("type") != "password":
432 return defer.succeed(value) 506 return defer.succeed(value)
433 param_cat = node.parentNode.getAttribute('name') 507 param_cat = node.parentNode.getAttribute("name")
434 param_name = node.getAttribute('name') 508 param_name = node.getAttribute("name")
435 if ((param_cat, param_name) == C.PROFILE_PASS_PATH) or not value: 509 if ((param_cat, param_name) == C.PROFILE_PASS_PATH) or not value:
436 return defer.succeed(value) # profile password and empty passwords are returned "as is" 510 return defer.succeed(
511 value
512 ) # profile password and empty passwords are returned "as is"
437 if not profile: 513 if not profile:
438 raise exceptions.ProfileNotSetError('The profile is needed to decrypt a password') 514 raise exceptions.ProfileNotSetError(
515 "The profile is needed to decrypt a password"
516 )
439 d = self.host.memory.decryptValue(value, profile) 517 d = self.host.memory.decryptValue(value, profile)
440 518
441 def gotPlainPassword(password): 519 def gotPlainPassword(password):
442 if password is None: # empty value means empty password, None means decryption failure 520 if (
443 raise exceptions.InternalError(_('The stored password could not be decrypted!')) 521 password is None
522 ): # empty value means empty password, None means decryption failure
523 raise exceptions.InternalError(
524 _("The stored password could not be decrypted!")
525 )
444 return password 526 return password
445 527
446 return d.addCallback(gotPlainPassword) 528 return d.addCallback(gotPlainPassword)
447 529
448 def __type_to_string(self, result): 530 def __type_to_string(self, result):
453 return str(result) 535 return str(result)
454 return result 536 return result
455 537
456 def getStringParamA(self, name, category, attr="value", profile_key=C.PROF_KEY_NONE): 538 def getStringParamA(self, name, category, attr="value", profile_key=C.PROF_KEY_NONE):
457 """ Same as getParamA but for bridge: convert non string value to string """ 539 """ Same as getParamA but for bridge: convert non string value to string """
458 return self.__type_to_string(self.getParamA(name, category, attr, profile_key=profile_key)) 540 return self.__type_to_string(
459 541 self.getParamA(name, category, attr, profile_key=profile_key)
460 def getParamA(self, name, category, attr="value", use_default=True, profile_key=C.PROF_KEY_NONE): 542 )
543
544 def getParamA(
545 self, name, category, attr="value", use_default=True, profile_key=C.PROF_KEY_NONE
546 ):
461 """Helper method to get a specific attribute. 547 """Helper method to get a specific attribute.
462 548
463 /!\ This method would return encrypted password values, 549 /!\ This method would return encrypted password values,
464 to get the plain values you have to use _asyncGetParamA. 550 to get the plain values you have to use _asyncGetParamA.
465 @param name: name of the parameter 551 @param name: name of the parameter
472 """ 558 """
473 # FIXME: looks really dirty and buggy, need to be reviewed/refactored 559 # FIXME: looks really dirty and buggy, need to be reviewed/refactored
474 # FIXME: security_limit is not managed here ! 560 # FIXME: security_limit is not managed here !
475 node = self._getParamNode(name, category) 561 node = self._getParamNode(name, category)
476 if not node: 562 if not node:
477 log.error(_(u"Requested param [%(name)s] in category [%(category)s] doesn't exist !") % {'name': name, 'category': category}) 563 log.error(
564 _(
565 u"Requested param [%(name)s] in category [%(category)s] doesn't exist !"
566 )
567 % {"name": name, "category": category}
568 )
478 raise exceptions.NotFound 569 raise exceptions.NotFound
479 570
480 if attr == 'value' and node[1].getAttribute('type') == 'password': 571 if attr == "value" and node[1].getAttribute("type") == "password":
481 raise exceptions.InternalError('To retrieve password values, use asyncGetParamA instead of getParamA') 572 raise exceptions.InternalError(
573 "To retrieve password values, use asyncGetParamA instead of getParamA"
574 )
482 575
483 if node[0] == C.GENERAL: 576 if node[0] == C.GENERAL:
484 value = self._getParam(category, name, C.GENERAL) 577 value = self._getParam(category, name, C.GENERAL)
485 if value is None and attr=='value' and not use_default: 578 if value is None and attr == "value" and not use_default:
486 return value 579 return value
487 return self._getAttr(node[1], attr, value) 580 return self._getAttr(node[1], attr, value)
488 581
489 assert node[0] == C.INDIVIDUAL 582 assert node[0] == C.INDIVIDUAL
490 583
491 profile = self.getProfileName(profile_key) 584 profile = self.getProfileName(profile_key)
492 if not profile: 585 if not profile:
493 log.error(_('Requesting a param for an non-existant profile')) 586 log.error(_("Requesting a param for an non-existant profile"))
494 raise exceptions.ProfileUnknownError(profile_key) 587 raise exceptions.ProfileUnknownError(profile_key)
495 588
496 if profile not in self.params: 589 if profile not in self.params:
497 log.error(_('Requesting synchronous param for not connected profile')) 590 log.error(_("Requesting synchronous param for not connected profile"))
498 raise exceptions.ProfileNotConnected(profile) 591 raise exceptions.ProfileNotConnected(profile)
499 592
500 if attr == "value": 593 if attr == "value":
501 value = self._getParam(category, name, profile=profile) 594 value = self._getParam(category, name, profile=profile)
502 if value is None and attr=='value' and not use_default: 595 if value is None and attr == "value" and not use_default:
503 return value 596 return value
504 return self._getAttr(node[1], attr, value) 597 return self._getAttr(node[1], attr, value)
505 598
506 def asyncGetStringParamA(self, name, category, attr="value", security_limit=C.NO_SECURITY_LIMIT, profile_key=C.PROF_KEY_NONE): 599 def asyncGetStringParamA(
600 self,
601 name,
602 category,
603 attr="value",
604 security_limit=C.NO_SECURITY_LIMIT,
605 profile_key=C.PROF_KEY_NONE,
606 ):
507 d = self.asyncGetParamA(name, category, attr, security_limit, profile_key) 607 d = self.asyncGetParamA(name, category, attr, security_limit, profile_key)
508 d.addCallback(self.__type_to_string) 608 d.addCallback(self.__type_to_string)
509 return d 609 return d
510 610
511 def asyncGetParamA(self, name, category, attr="value", security_limit=C.NO_SECURITY_LIMIT, profile_key=C.PROF_KEY_NONE): 611 def asyncGetParamA(
612 self,
613 name,
614 category,
615 attr="value",
616 security_limit=C.NO_SECURITY_LIMIT,
617 profile_key=C.PROF_KEY_NONE,
618 ):
512 """Helper method to get a specific attribute. 619 """Helper method to get a specific attribute.
513 620
514 @param name: name of the parameter 621 @param name: name of the parameter
515 @param category: category of the parameter 622 @param category: category of the parameter
516 @param attr: name of the attribute (default: "value") 623 @param attr: name of the attribute (default: "value")
517 @param profile: owner of the param (@ALL@ for everyone) 624 @param profile: owner of the param (@ALL@ for everyone)
518 @return (defer.Deferred): parameter value, with corresponding type (bool, int, list, etc) 625 @return (defer.Deferred): parameter value, with corresponding type (bool, int, list, etc)
519 """ 626 """
520 node = self._getParamNode(name, category) 627 node = self._getParamNode(name, category)
521 if not node: 628 if not node:
522 log.error(_(u"Requested param [%(name)s] in category [%(category)s] doesn't exist !") % {'name': name, 'category': category}) 629 log.error(
630 _(
631 u"Requested param [%(name)s] in category [%(category)s] doesn't exist !"
632 )
633 % {"name": name, "category": category}
634 )
523 raise ValueError("Requested param doesn't exist") 635 raise ValueError("Requested param doesn't exist")
524 636
525 if not self.checkSecurityLimit(node[1], security_limit): 637 if not self.checkSecurityLimit(node[1], security_limit):
526 log.warning(_(u"Trying to get parameter '%(param)s' in category '%(cat)s' without authorization!!!" 638 log.warning(
527 % {'param': name, 'cat': category})) 639 _(
640 u"Trying to get parameter '%(param)s' in category '%(cat)s' without authorization!!!"
641 % {"param": name, "cat": category}
642 )
643 )
528 raise exceptions.PermissionError 644 raise exceptions.PermissionError
529 645
530 if node[0] == C.GENERAL: 646 if node[0] == C.GENERAL:
531 value = self._getParam(category, name, C.GENERAL) 647 value = self._getParam(category, name, C.GENERAL)
532 return self._asyncGetAttr(node[1], attr, value) 648 return self._asyncGetAttr(node[1], attr, value)
533 649
534 assert node[0] == C.INDIVIDUAL 650 assert node[0] == C.INDIVIDUAL
535 651
536 profile = self.getProfileName(profile_key) 652 profile = self.getProfileName(profile_key)
537 if not profile: 653 if not profile:
538 raise exceptions.InternalError(_('Requesting a param for a non-existant profile')) 654 raise exceptions.InternalError(
655 _("Requesting a param for a non-existant profile")
656 )
539 657
540 if attr != "value": 658 if attr != "value":
541 return defer.succeed(node[1].getAttribute(attr)) 659 return defer.succeed(node[1].getAttribute(attr))
542 try: 660 try:
543 value = self._getParam(category, name, profile=profile) 661 value = self._getParam(category, name, profile=profile)
544 return self._asyncGetAttr(node[1], attr, value, profile) 662 return self._asyncGetAttr(node[1], attr, value, profile)
545 except exceptions.ProfileNotInCacheError: 663 except exceptions.ProfileNotInCacheError:
546 #We have to ask data to the storage manager 664 # We have to ask data to the storage manager
547 d = self.storage.getIndParam(category, name, profile) 665 d = self.storage.getIndParam(category, name, profile)
548 return d.addCallback(lambda value: self._asyncGetAttr(node[1], attr, value, profile)) 666 return d.addCallback(
667 lambda value: self._asyncGetAttr(node[1], attr, value, profile)
668 )
549 669
550 def asyncGetParamsValuesFromCategory(self, category, security_limit, profile_key): 670 def asyncGetParamsValuesFromCategory(self, category, security_limit, profile_key):
551 """Get all parameters "attribute" for a category 671 """Get all parameters "attribute" for a category
552 672
553 @param category(unicode): the desired category 673 @param category(unicode): the desired category
555 Otherwise sole the params which have a security level defined *and* 675 Otherwise sole the params which have a security level defined *and*
556 lower or equal to the specified value are returned. 676 lower or equal to the specified value are returned.
557 @param profile_key: %(doc_profile_key)s 677 @param profile_key: %(doc_profile_key)s
558 @return (dict): key: param name, value: param value (converted to string if needed) 678 @return (dict): key: param name, value: param value (converted to string if needed)
559 """ 679 """
560 #TODO: manage category of general type (without existant profile) 680 # TODO: manage category of general type (without existant profile)
561 profile = self.getProfileName(profile_key) 681 profile = self.getProfileName(profile_key)
562 if not profile: 682 if not profile:
563 log.error(_("Asking params for inexistant profile")) 683 log.error(_("Asking params for inexistant profile"))
564 return "" 684 return ""
565 685
570 ret = {} 690 ret = {}
571 names_d_list = [] 691 names_d_list = []
572 for category_node in prof_xml.getElementsByTagName("category"): 692 for category_node in prof_xml.getElementsByTagName("category"):
573 if category_node.getAttribute("name") == category: 693 if category_node.getAttribute("name") == category:
574 for param_node in category_node.getElementsByTagName("param"): 694 for param_node in category_node.getElementsByTagName("param"):
575 name = param_node.getAttribute('name') 695 name = param_node.getAttribute("name")
576 if not name: 696 if not name:
577 log.warning(u"ignoring attribute without name: {}".format(param_node.toxml())) 697 log.warning(
698 u"ignoring attribute without name: {}".format(
699 param_node.toxml()
700 )
701 )
578 continue 702 continue
579 d = self.asyncGetStringParamA(name, category, security_limit=security_limit, profile_key=profile) 703 d = self.asyncGetStringParamA(
704 name,
705 category,
706 security_limit=security_limit,
707 profile_key=profile,
708 )
580 d.addCallback(setValue, ret, name) 709 d.addCallback(setValue, ret, name)
581 names_d_list.append(d) 710 names_d_list.append(d)
582 break 711 break
583 712
584 prof_xml.unlink() 713 prof_xml.unlink()
585 dlist = defer.gatherResults(names_d_list) 714 dlist = defer.gatherResults(names_d_list)
586 dlist.addCallback(lambda dummy: ret) 715 dlist.addCallback(lambda dummy: ret)
587 return ret 716 return ret
588 717
589 d = self._constructProfileXml(security_limit, '', profile) 718 d = self._constructProfileXml(security_limit, "", profile)
590 return d.addCallback(returnCategoryXml) 719 return d.addCallback(returnCategoryXml)
591 720
592 def _getParam(self, category, name, type_=C.INDIVIDUAL, cache=None, profile=C.PROF_KEY_NONE): 721 def _getParam(
722 self, category, name, type_=C.INDIVIDUAL, cache=None, profile=C.PROF_KEY_NONE
723 ):
593 """Return the param, or None if it doesn't exist 724 """Return the param, or None if it doesn't exist
594 725
595 @param category: param category 726 @param category: param category
596 @param name: param name 727 @param name: param name
597 @param type_: GENERAL or INDIVIDUAL 728 @param type_: GENERAL or INDIVIDUAL
606 assert type_ == C.INDIVIDUAL 737 assert type_ == C.INDIVIDUAL
607 if profile == C.PROF_KEY_NONE: 738 if profile == C.PROF_KEY_NONE:
608 raise exceptions.ProfileNotSetError 739 raise exceptions.ProfileNotSetError
609 if profile in self.params: 740 if profile in self.params:
610 cache = self.params[profile] # if profile is in main cache, we use it, 741 cache = self.params[profile] # if profile is in main cache, we use it,
611 # ignoring the temporary cache 742 # ignoring the temporary cache
612 elif cache is None: # else we use the temporary cache if it exists, or raise an exception 743 elif (
744 cache is None
745 ): # else we use the temporary cache if it exists, or raise an exception
613 raise exceptions.ProfileNotInCacheError 746 raise exceptions.ProfileNotInCacheError
614 if (category, name) not in cache: 747 if (category, name) not in cache:
615 return None 748 return None
616 return cache[(category, name)] 749 return cache[(category, name)]
617 750
627 @return: a deferred that fire a minidom.Document of the profile xml (cf warning above) 760 @return: a deferred that fire a minidom.Document of the profile xml (cf warning above)
628 """ 761 """
629 762
630 def checkNode(node): 763 def checkNode(node):
631 """Check the node against security_limit and app""" 764 """Check the node against security_limit and app"""
632 return self.checkSecurityLimit(node, security_limit) and self.checkApp(node, app) 765 return self.checkSecurityLimit(node, security_limit) and self.checkApp(
766 node, app
767 )
633 768
634 def constructProfile(ignore, profile_cache): 769 def constructProfile(ignore, profile_cache):
635 # init the result document 770 # init the result document
636 prof_xml = minidom.parseString('<params/>') 771 prof_xml = minidom.parseString("<params/>")
637 cache = {} 772 cache = {}
638 773
639 for type_node in self.dom.documentElement.childNodes: 774 for type_node in self.dom.documentElement.childNodes:
640 if type_node.nodeName != C.GENERAL and type_node.nodeName != C.INDIVIDUAL: 775 if type_node.nodeName != C.GENERAL and type_node.nodeName != C.INDIVIDUAL:
641 continue 776 continue
642 # we use all params, general and individual 777 # we use all params, general and individual
643 for cat_node in type_node.childNodes: 778 for cat_node in type_node.childNodes:
644 if cat_node.nodeName != 'category': 779 if cat_node.nodeName != "category":
645 continue 780 continue
646 category = cat_node.getAttribute('name') 781 category = cat_node.getAttribute("name")
647 dest_params = {} # result (merged) params for category 782 dest_params = {} # result (merged) params for category
648 if category not in cache: 783 if category not in cache:
649 # we make a copy for the new xml 784 # we make a copy for the new xml
650 cache[category] = dest_cat = cat_node.cloneNode(True) 785 cache[category] = dest_cat = cat_node.cloneNode(True)
651 to_remove = [] 786 to_remove = []
653 if node.nodeName != "param": 788 if node.nodeName != "param":
654 continue 789 continue
655 if not checkNode(node): 790 if not checkNode(node):
656 to_remove.append(node) 791 to_remove.append(node)
657 continue 792 continue
658 dest_params[node.getAttribute('name')] = node 793 dest_params[node.getAttribute("name")] = node
659 for node in to_remove: 794 for node in to_remove:
660 dest_cat.removeChild(node) 795 dest_cat.removeChild(node)
661 new_node = True 796 new_node = True
662 else: 797 else:
663 # It's not a new node, we use the previously cloned one 798 # It's not a new node, we use the previously cloned one
666 params = cat_node.getElementsByTagName("param") 801 params = cat_node.getElementsByTagName("param")
667 802
668 for param_node in params: 803 for param_node in params:
669 # we have to merge new params (we are parsing individual parameters, we have to add them 804 # we have to merge new params (we are parsing individual parameters, we have to add them
670 # to the previously parsed general ones) 805 # to the previously parsed general ones)
671 name = param_node.getAttribute('name') 806 name = param_node.getAttribute("name")
672 if not checkNode(param_node): 807 if not checkNode(param_node):
673 continue 808 continue
674 if name not in dest_params: 809 if name not in dest_params:
675 # this is reached when a previous category exists 810 # this is reached when a previous category exists
676 dest_params[name] = param_node.cloneNode(True) 811 dest_params[name] = param_node.cloneNode(True)
677 dest_cat.appendChild(dest_params[name]) 812 dest_cat.appendChild(dest_params[name])
678 813
679 profile_value = self._getParam(category, 814 profile_value = self._getParam(
680 name, type_node.nodeName, 815 category,
681 cache=profile_cache, profile=profile) 816 name,
817 type_node.nodeName,
818 cache=profile_cache,
819 profile=profile,
820 )
682 if profile_value is not None: 821 if profile_value is not None:
683 # there is a value for this profile, we must change the default 822 # there is a value for this profile, we must change the default
684 if dest_params[name].getAttribute('type') == 'list': 823 if dest_params[name].getAttribute("type") == "list":
685 for option in dest_params[name].getElementsByTagName("option"): 824 for option in dest_params[name].getElementsByTagName(
686 if option.getAttribute('value') == profile_value: 825 "option"
687 option.setAttribute('selected', 'true') 826 ):
827 if option.getAttribute("value") == profile_value:
828 option.setAttribute("selected", "true")
688 else: 829 else:
689 try: 830 try:
690 option.removeAttribute('selected') 831 option.removeAttribute("selected")
691 except NotFoundErr: 832 except NotFoundErr:
692 pass 833 pass
693 elif dest_params[name].getAttribute('type') == 'jids_list': 834 elif dest_params[name].getAttribute("type") == "jids_list":
694 jids = profile_value.split('\t') 835 jids = profile_value.split("\t")
695 for jid_elt in dest_params[name].getElementsByTagName("jid"): 836 for jid_elt in dest_params[name].getElementsByTagName(
696 dest_params[name].removeChild(jid_elt) # remove all default 837 "jid"
838 ):
839 dest_params[name].removeChild(
840 jid_elt
841 ) # remove all default
697 for jid_ in jids: # rebuilt the children with use values 842 for jid_ in jids: # rebuilt the children with use values
698 try: 843 try:
699 jid.JID(jid_) 844 jid.JID(jid_)
700 except (RuntimeError, jid.InvalidFormat, AttributeError): 845 except (
701 log.warning(u"Incorrect jid value found in jids list: [{}]".format(jid_)) 846 RuntimeError,
847 jid.InvalidFormat,
848 AttributeError,
849 ):
850 log.warning(
851 u"Incorrect jid value found in jids list: [{}]".format(
852 jid_
853 )
854 )
702 else: 855 else:
703 jid_elt = prof_xml.createElement('jid') 856 jid_elt = prof_xml.createElement("jid")
704 jid_elt.appendChild(prof_xml.createTextNode(jid_)) 857 jid_elt.appendChild(prof_xml.createTextNode(jid_))
705 dest_params[name].appendChild(jid_elt) 858 dest_params[name].appendChild(jid_elt)
706 else: 859 else:
707 dest_params[name].setAttribute('value', profile_value) 860 dest_params[name].setAttribute("value", profile_value)
708 if new_node: 861 if new_node:
709 prof_xml.documentElement.appendChild(dest_cat) 862 prof_xml.documentElement.appendChild(dest_cat)
710 863
711 to_remove = [] 864 to_remove = []
712 for cat_node in prof_xml.documentElement.childNodes: 865 for cat_node in prof_xml.documentElement.childNodes:
719 872
720 if profile in self.params: 873 if profile in self.params:
721 d = defer.succeed(None) 874 d = defer.succeed(None)
722 profile_cache = self.params[profile] 875 profile_cache = self.params[profile]
723 else: 876 else:
724 #profile is not in cache, we load values in a short time cache 877 # profile is not in cache, we load values in a short time cache
725 profile_cache = {} 878 profile_cache = {}
726 d = self.loadIndParams(profile, profile_cache) 879 d = self.loadIndParams(profile, profile_cache)
727 880
728 return d.addCallback(constructProfile, profile_cache) 881 return d.addCallback(constructProfile, profile_cache)
729 882
759 return defer.succeed("") 912 return defer.succeed("")
760 913
761 def returnXML(prof_xml): 914 def returnXML(prof_xml):
762 return_xml = prof_xml.toxml() 915 return_xml = prof_xml.toxml()
763 prof_xml.unlink() 916 prof_xml.unlink()
764 return '\n'.join((line for line in return_xml.split('\n') if line)) 917 return "\n".join((line for line in return_xml.split("\n") if line))
765 918
766 return self._constructProfileXml(security_limit, app, profile).addCallback(returnXML) 919 return self._constructProfileXml(security_limit, app, profile).addCallback(
920 returnXML
921 )
767 922
768 def _getParamNode(self, name, category, type_="@ALL@"): # FIXME: is type_ useful ? 923 def _getParamNode(self, name, category, type_="@ALL@"): # FIXME: is type_ useful ?
769 """Return a node from the param_xml 924 """Return a node from the param_xml
770 @param name: name of the node 925 @param name: name of the node
771 @param category: category of the node 926 @param category: category of the node
774 @GENERAL@ only search in general type 929 @GENERAL@ only search in general type
775 @INDIVIDUAL@ only search in individual type 930 @INDIVIDUAL@ only search in individual type
776 @return: a tuple (node type, node) or None if not found""" 931 @return: a tuple (node type, node) or None if not found"""
777 932
778 for type_node in self.dom.documentElement.childNodes: 933 for type_node in self.dom.documentElement.childNodes:
779 if (((type_ == "@ALL@" or type_ == "@GENERAL@") and type_node.nodeName == C.GENERAL) 934 if (
780 or ((type_ == "@ALL@" or type_ == "@INDIVIDUAL@") and type_node.nodeName == C.INDIVIDUAL)): 935 (type_ == "@ALL@" or type_ == "@GENERAL@")
781 for node in type_node.getElementsByTagName('category'): 936 and type_node.nodeName == C.GENERAL
937 ) or (
938 (type_ == "@ALL@" or type_ == "@INDIVIDUAL@")
939 and type_node.nodeName == C.INDIVIDUAL
940 ):
941 for node in type_node.getElementsByTagName("category"):
782 if node.getAttribute("name") == category: 942 if node.getAttribute("name") == category:
783 params = node.getElementsByTagName("param") 943 params = node.getElementsByTagName("param")
784 for param in params: 944 for param in params:
785 if param.getAttribute("name") == name: 945 if param.getAttribute("name") == name:
786 return (type_node.nodeName, param) 946 return (type_node.nodeName, param)
793 name = cat.getAttribute("name") 953 name = cat.getAttribute("name")
794 if name not in categories: 954 if name not in categories:
795 categories.append(cat.getAttribute("name")) 955 categories.append(cat.getAttribute("name"))
796 return categories 956 return categories
797 957
798 def setParam(self, name, value, category, security_limit=C.NO_SECURITY_LIMIT, profile_key=C.PROF_KEY_NONE): 958 def setParam(
959 self,
960 name,
961 value,
962 category,
963 security_limit=C.NO_SECURITY_LIMIT,
964 profile_key=C.PROF_KEY_NONE,
965 ):
799 """Set a parameter, return None if the parameter is not in param xml. 966 """Set a parameter, return None if the parameter is not in param xml.
800 967
801 Parameter of type 'password' that are not the SàT profile password are 968 Parameter of type 'password' that are not the SàT profile password are
802 stored encrypted (if not empty). The profile password is stored hashed 969 stored encrypted (if not empty). The profile password is stored hashed
803 (if not empty). 970 (if not empty).
811 """ 978 """
812 # FIXME: setParam should accept the right type for value, not only str ! 979 # FIXME: setParam should accept the right type for value, not only str !
813 if profile_key != C.PROF_KEY_NONE: 980 if profile_key != C.PROF_KEY_NONE:
814 profile = self.getProfileName(profile_key) 981 profile = self.getProfileName(profile_key)
815 if not profile: 982 if not profile:
816 log.error(_(u'Trying to set parameter for an unknown profile')) 983 log.error(_(u"Trying to set parameter for an unknown profile"))
817 raise exceptions.ProfileUnknownError(profile_key) 984 raise exceptions.ProfileUnknownError(profile_key)
818 985
819 node = self._getParamNode(name, category, '@ALL@') 986 node = self._getParamNode(name, category, "@ALL@")
820 if not node: 987 if not node:
821 log.error(_(u'Requesting an unknown parameter (%(category)s/%(name)s)') 988 log.error(
822 % {'category': category, 'name': name}) 989 _(u"Requesting an unknown parameter (%(category)s/%(name)s)")
990 % {"category": category, "name": name}
991 )
823 return defer.succeed(None) 992 return defer.succeed(None)
824 993
825 if not self.checkSecurityLimit(node[1], security_limit): 994 if not self.checkSecurityLimit(node[1], security_limit):
826 log.warning(_(u"Trying to set parameter '%(param)s' in category '%(cat)s' without authorization!!!" 995 log.warning(
827 % {'param': name, 'cat': category})) 996 _(
997 u"Trying to set parameter '%(param)s' in category '%(cat)s' without authorization!!!"
998 % {"param": name, "cat": category}
999 )
1000 )
828 return defer.succeed(None) 1001 return defer.succeed(None)
829 1002
830 type_ = node[1].getAttribute("type") 1003 type_ = node[1].getAttribute("type")
831 if type_ == 'int': 1004 if type_ == "int":
832 if not value: # replace with the default value (which might also be '') 1005 if not value: # replace with the default value (which might also be '')
833 value = node[1].getAttribute("value") 1006 value = node[1].getAttribute("value")
834 else: 1007 else:
835 try: 1008 try:
836 int(value) 1009 int(value)
837 except ValueError: 1010 except ValueError:
838 log.debug(_(u"Trying to set parameter '%(param)s' in category '%(cat)s' with an non-integer value" 1011 log.debug(
839 % {'param': name, 'cat': category})) 1012 _(
1013 u"Trying to set parameter '%(param)s' in category '%(cat)s' with an non-integer value"
1014 % {"param": name, "cat": category}
1015 )
1016 )
840 return defer.succeed(None) 1017 return defer.succeed(None)
841 if node[1].hasAttribute("constraint"): 1018 if node[1].hasAttribute("constraint"):
842 constraint = node[1].getAttribute("constraint") 1019 constraint = node[1].getAttribute("constraint")
843 try: 1020 try:
844 min_, max_ = [int(limit) for limit in constraint.split(";")] 1021 min_, max_ = [int(limit) for limit in constraint.split(";")]
845 except ValueError: 1022 except ValueError:
846 raise exceptions.InternalError("Invalid integer parameter constraint: %s" % constraint) 1023 raise exceptions.InternalError(
1024 "Invalid integer parameter constraint: %s" % constraint
1025 )
847 value = str(min(max(int(value), min_), max_)) 1026 value = str(min(max(int(value), min_), max_))
848 1027
849 1028 log.info(
850 log.info(_("Setting parameter (%(category)s, %(name)s) = %(value)s") % 1029 _("Setting parameter (%(category)s, %(name)s) = %(value)s")
851 {'category': category, 'name': name, 'value': value if type_ != 'password' else '********'}) 1030 % {
1031 "category": category,
1032 "name": name,
1033 "value": value if type_ != "password" else "********",
1034 }
1035 )
852 1036
853 if node[0] == C.GENERAL: 1037 if node[0] == C.GENERAL:
854 self.params_gen[(category, name)] = value 1038 self.params_gen[(category, name)] = value
855 self.storage.setGenParam(category, name, value) 1039 self.storage.setGenParam(category, name, value)
856 for profile in self.storage.getProfilesList(): 1040 for profile in self.storage.getProfilesList():
857 if self.host.memory.isSessionStarted(profile): 1041 if self.host.memory.isSessionStarted(profile):
858 self.host.bridge.paramUpdate(name, value, category, profile) 1042 self.host.bridge.paramUpdate(name, value, category, profile)
859 self.host.trigger.point("paramUpdateTrigger", name, value, category, node[0], profile) 1043 self.host.trigger.point(
1044 "paramUpdateTrigger", name, value, category, node[0], profile
1045 )
860 return defer.succeed(None) 1046 return defer.succeed(None)
861 1047
862 assert node[0] == C.INDIVIDUAL 1048 assert node[0] == C.INDIVIDUAL
863 assert profile_key != C.PROF_KEY_NONE 1049 assert profile_key != C.PROF_KEY_NONE
864 1050
865 if type_ == "button": 1051 if type_ == "button":
866 log.debug(u"Clicked param button %s" % node.toxml()) 1052 log.debug(u"Clicked param button %s" % node.toxml())
867 return defer.succeed(None) 1053 return defer.succeed(None)
868 elif type_ == "password": 1054 elif type_ == "password":
869 try: 1055 try:
870 personal_key = self.host.memory.auth_sessions.profileGetUnique(profile)[C.MEMORY_CRYPTO_KEY] 1056 personal_key = self.host.memory.auth_sessions.profileGetUnique(profile)[
1057 C.MEMORY_CRYPTO_KEY
1058 ]
871 except TypeError: 1059 except TypeError:
872 raise exceptions.InternalError(_('Trying to encrypt a password while the personal key is undefined!')) 1060 raise exceptions.InternalError(
1061 _("Trying to encrypt a password while the personal key is undefined!")
1062 )
873 if (category, name) == C.PROFILE_PASS_PATH: 1063 if (category, name) == C.PROFILE_PASS_PATH:
874 # using 'value' as the encryption key to encrypt another encryption key... could be confusing! 1064 # using 'value' as the encryption key to encrypt another encryption key... could be confusing!
875 d = self.host.memory.encryptPersonalData(data_key=C.MEMORY_CRYPTO_KEY, 1065 d = self.host.memory.encryptPersonalData(
876 data_value=personal_key, 1066 data_key=C.MEMORY_CRYPTO_KEY,
877 crypto_key=value, 1067 data_value=personal_key,
878 profile=profile) 1068 crypto_key=value,
879 d.addCallback(lambda dummy: PasswordHasher.hash(value)) # profile password is hashed (empty value stays empty) 1069 profile=profile,
1070 )
1071 d.addCallback(
1072 lambda dummy: PasswordHasher.hash(value)
1073 ) # profile password is hashed (empty value stays empty)
880 elif value: # other non empty passwords are encrypted with the personal key 1074 elif value: # other non empty passwords are encrypted with the personal key
881 d = BlockCipher.encrypt(personal_key, value) 1075 d = BlockCipher.encrypt(personal_key, value)
882 else: 1076 else:
883 d = defer.succeed(value) 1077 d = defer.succeed(value)
884 else: 1078 else:
886 1080
887 def gotFinalValue(value): 1081 def gotFinalValue(value):
888 if self.host.memory.isSessionStarted(profile): 1082 if self.host.memory.isSessionStarted(profile):
889 self.params[profile][(category, name)] = value 1083 self.params[profile][(category, name)] = value
890 self.host.bridge.paramUpdate(name, value, category, profile) 1084 self.host.bridge.paramUpdate(name, value, category, profile)
891 self.host.trigger.point("paramUpdateTrigger", name, value, category, node[0], profile) 1085 self.host.trigger.point(
1086 "paramUpdateTrigger", name, value, category, node[0], profile
1087 )
892 return self.storage.setIndParam(category, name, value, profile) 1088 return self.storage.setIndParam(category, name, value, profile)
893 else: 1089 else:
894 raise exceptions.ProfileNotConnected 1090 raise exceptions.ProfileNotConnected
895 1091
896 d.addCallback(gotFinalValue) 1092 d.addCallback(gotFinalValue)
910 - key is a couple (attribute category, attribute name) 1106 - key is a couple (attribute category, attribute name)
911 - value is a node 1107 - value is a node
912 """ 1108 """
913 ret = {} 1109 ret = {}
914 for type_node in self.dom.documentElement.childNodes: 1110 for type_node in self.dom.documentElement.childNodes:
915 if (((node_type == "@ALL@" or node_type == "@GENERAL@") and type_node.nodeName == C.GENERAL) or 1111 if (
916 ((node_type == "@ALL@" or node_type == "@INDIVIDUAL@") and type_node.nodeName == C.INDIVIDUAL)): 1112 (node_type == "@ALL@" or node_type == "@GENERAL@")
917 for cat_node in type_node.getElementsByTagName('category'): 1113 and type_node.nodeName == C.GENERAL
918 cat = cat_node.getAttribute('name') 1114 ) or (
1115 (node_type == "@ALL@" or node_type == "@INDIVIDUAL@")
1116 and type_node.nodeName == C.INDIVIDUAL
1117 ):
1118 for cat_node in type_node.getElementsByTagName("category"):
1119 cat = cat_node.getAttribute("name")
919 params = cat_node.getElementsByTagName("param") 1120 params = cat_node.getElementsByTagName("param")
920 for param in params: 1121 for param in params:
921 if param.getAttribute("type") == attr_type: 1122 if param.getAttribute("type") == attr_type:
922 ret[(cat, param.getAttribute("name"))] = param 1123 ret[(cat, param.getAttribute("name"))] = param
923 return ret 1124 return ret