summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Torres <atorresj@hotmail.be>2017-10-11 12:03:05 +0200
committerGitHub <noreply@github.com>2017-10-11 12:03:05 +0200
commit64d52cf85fc38a474c63ff36e2f100e304f27478 (patch)
tree273725c24b9faf1eb1c92cd3f4e66bc4b0256b86
parentc418d73445da7ab2acb591e637921643c2ed35b2 (diff)
[IMP] base_import_module: Add layer of security (#19175)
Previous to this commit, anyone could import studio customizations into a community db, this was troublesome since some people would just install studio, do their customizations and then move them into a community db, not paying anything at all. This commit fixes this by checking whether the exported views were created with studio or not and if studio is installed
-rw-r--r--addons/base_import_module/models/ir_module.py51
1 files changed, 46 insertions, 5 deletions
diff --git a/addons/base_import_module/models/ir_module.py b/addons/base_import_module/models/ir_module.py
index 5bad5ea53eb..a28ee6bf429 100644
--- a/addons/base_import_module/models/ir_module.py
+++ b/addons/base_import_module/models/ir_module.py
@@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
+import ast
import base64
import logging
+import lxml
import os
import sys
import zipfile
@@ -32,8 +34,17 @@ class IrModule(models.Model):
values = self.get_values_from_terp(terp)
unmet_dependencies = set(terp['depends']).difference(installed_mods)
+
if unmet_dependencies:
- raise UserError(_("Unmet module dependencies: %s") % ', '.join(unmet_dependencies))
+ if _is_studio_custom(path):
+ err = _("Studio customizations require Studio")
+ else:
+ err = _("Unmet module dependencies: %s") % ', '.join(
+ unmet_dependencies,
+ )
+ raise UserError(err)
+ elif 'web_studio' not in installed_mods and _is_studio_custom(path):
+ raise UserError(_("Studio customizations require Studio"))
mod = known_mods_names.get(module)
if mod:
@@ -52,7 +63,7 @@ class IrModule(models.Model):
continue
_logger.info("module %s: loading %s", module, filename)
noupdate = False
- if filename.endswith('.csv') and kind in ('init', 'init_xml'):
+ if ext == '.csv' and kind in ('init', 'init_xml'):
noupdate = True
pathname = opj(path, filename)
idref = {}
@@ -101,9 +112,9 @@ class IrModule(models.Model):
raise UserError(_("File '%s' exceed maximum allowed file size") % zf.filename)
with tempdir() as module_dir:
- import odoo.modules as addons
+ import odoo.modules.module as module
try:
- addons.module.ad_paths.append(module_dir)
+ module.ad_paths.append(module_dir)
z.extractall(module_dir)
dirs = [d for d in os.listdir(module_dir) if os.path.isdir(opj(module_dir, d))]
for mod_name in dirs:
@@ -117,8 +128,38 @@ class IrModule(models.Model):
_logger.exception('Error while importing module')
errors[mod_name] = exception_to_unicode(e)
finally:
- addons.module.ad_paths.remove(module_dir)
+ module.ad_paths.remove(module_dir)
r = ["Successfully imported module '%s'" % mod for mod in success]
for mod, error in errors.items():
r.append("Error while importing module '%s': %r" % (mod, error))
return '\n'.join(r), module_names
+
+
+def _is_studio_custom(path):
+ """
+ Checks the to-be-imported records to see if there are any references to
+ studio, which would mean that the module was created using studio
+
+ Returns True if any of the records contains a context with the key
+ studio in it, False if none of the records do
+ """
+ path = os.path.join(path, 'data')
+ filenames = next(iter(os.walk(path)))[2]
+ filenames = [f for f in filenames if f.lower().endswith('.xml')]
+
+ for filename in filenames:
+ root = lxml.etree.parse(os.path.join(path, filename)).getroot()
+
+ for record in root:
+ # there might not be a context if it's a non-studio module
+ try:
+ # ast.literal_eval is like eval(), but safer
+ # context is a string representing a python dict
+ ctx = ast.literal_eval(record.get('context'))
+ # there are no cases in which studio is false
+ # so just checking for its existence is enough
+ if ctx and ctx.get('studio'):
+ return True
+ except Exception:
+ continue
+ return False