Mercurial > libervia-backend
view libervia/cli/cmd_param.py @ 4212:5f2d496c633f
core: get rid of `pickle`:
Use of `pickle` to serialise data was a technical legacy that was causing trouble to store
in database, to update (if a class was serialised, a change could break update), and to
security (pickle can lead to code execution).
This patch remove all use of Pickle in favour in JSON, notably:
- for caching data, a Pydantic model is now used instead
- for SQLAlchemy model, the LegacyPickle is replaced by JSON serialisation
- in XEP-0373 a class `PublicKeyMetadata` was serialised. New method `from_dict` and
`to_dict` method have been implemented to do serialisation.
- new methods to (de)serialise data can now be specified with Identity data types. It is
notably used to (de)serialise `path` of avatars.
A migration script has been created to convert data (for upgrade or downgrade), with
special care for XEP-0373 case. Depending of size of database, this migration script can
be long to run.
rel 443
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 23 Feb 2024 13:31:04 +0100 |
parents | 47401850dec6 |
children | 0d7bb4df2343 |
line wrap: on
line source
#!/usr/bin/env python3 # Libervia CLI # Copyright (C) 2009-2021 Jérôme Poisson (goffi@goffi.org) # Copyright (C) 2013-2016 Adrien Cossa (souliane@mailoo.org) # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. from . import base from libervia.backend.core.i18n import _ from .constants import Const as C __commands__ = ["Param"] class Get(base.CommandBase): def __init__(self, host): super(Get, self).__init__( host, "get", need_connect=False, help=_("get a parameter value") ) def add_parser_options(self): self.parser.add_argument( "category", nargs="?", help=_("category of the parameter") ) self.parser.add_argument("name", nargs="?", help=_("name of the parameter")) self.parser.add_argument( "-a", "--attribute", type=str, default="value", help=_("name of the attribute to get"), ) self.parser.add_argument( "--security-limit", type=int, default=-1, help=_("security limit") ) async def start(self): if self.args.category is None: categories = await self.host.bridge.params_categories_get() print("\n".join(categories)) elif self.args.name is None: try: values_dict = await self.host.bridge.params_values_from_category_get_async( self.args.category, self.args.security_limit, "", "", self.profile ) except Exception as e: self.disp( _("can't find requested parameters: {e}").format(e=e), error=True ) self.host.quit(C.EXIT_NOT_FOUND) else: for name, value in values_dict.items(): print(f"{name}\t{value}") else: try: value = await self.host.bridge.param_get_a_async( self.args.name, self.args.category, self.args.attribute, self.args.security_limit, self.profile, ) except Exception as e: self.disp( _("can't find requested parameter: {e}").format(e=e), error=True ) self.host.quit(C.EXIT_NOT_FOUND) else: print(value) self.host.quit() class Set(base.CommandBase): def __init__(self, host): super(Set, self).__init__( host, "set", need_connect=False, help=_("set a parameter value") ) def add_parser_options(self): self.parser.add_argument("category", help=_("category of the parameter")) self.parser.add_argument("name", help=_("name of the parameter")) self.parser.add_argument("value", help=_("name of the parameter")) self.parser.add_argument( "--security-limit", type=int, default=-1, help=_("security limit") ) async def start(self): try: await self.host.bridge.param_set( self.args.name, self.args.value, self.args.category, self.args.security_limit, self.profile, ) except Exception as e: self.disp(_("can't set requested parameter: {e}").format(e=e), error=True) self.host.quit(C.EXIT_BRIDGE_ERRBACK) else: self.host.quit() class SaveTemplate(base.CommandBase): # FIXME: this should probably be removed, it's not used and not useful for end-user def __init__(self, host): super(SaveTemplate, self).__init__( host, "save", use_profile=False, help=_("save parameters template to xml file"), ) def add_parser_options(self): self.parser.add_argument("filename", type=str, help=_("output file")) async def start(self): """Save parameters template to XML file""" try: await self.host.bridge.params_template_save(self.args.filename) except Exception as e: self.disp(_("can't save parameters to file: {e}").format(e=e), error=True) self.host.quit(C.EXIT_BRIDGE_ERRBACK) else: self.disp( _("parameters saved to file {filename}").format( filename=self.args.filename ) ) self.host.quit() class LoadTemplate(base.CommandBase): # FIXME: this should probably be removed, it's not used and not useful for end-user def __init__(self, host): super(LoadTemplate, self).__init__( host, "load", use_profile=False, help=_("load parameters template from xml file"), ) def add_parser_options(self): self.parser.add_argument("filename", type=str, help=_("input file")) async def start(self): """Load parameters template from xml file""" try: self.host.bridge.params_template_load(self.args.filename) except Exception as e: self.disp(_("can't load parameters from file: {e}").format(e=e), error=True) self.host.quit(C.EXIT_BRIDGE_ERRBACK) else: self.disp( _("parameters loaded from file {filename}").format( filename=self.args.filename ) ) self.host.quit() class Param(base.CommandBase): subcommands = (Get, Set, SaveTemplate, LoadTemplate) def __init__(self, host): super(Param, self).__init__( host, "param", use_profile=False, help=_("Save/load parameters template") )