attachments, in order:
(1) 0...the proposed patch to sugar
(2) suga..9.1 sugar part of a draft patch for 9.1, only read it if you're
interested, scarcely tested.
(3) 0...s-l proposed patch for sugar-toolkit
(4) tool...9.1 the sugar-toolkit part of the draft 9.1 patch
(5) 0...fixes some minor pylint cleanup to sugar, to be applied after
patch 1 above.
So, the important parts here are (1) and (3). Patch (1) makes sugar registry
service not add bundles unless they're in ~/Activities. (The registry can
add such bundles, but the service will refuse to). Patch (3) makes
activitybundle.py refuse to install loopholed activities unless called with
securitycheck=False.
From 4db7faf72edc7eaa2aa4631a98aa29819f2e5ec8 Mon Sep 17 00:00:00 2001
From: Jameson Quinn <[EMAIL PROTECTED]>
Date: Mon, 4 Aug 2008 19:17:11 -0600
Subject: [PATCH] bug #5657 - don't add bundles to registry unless they're in ~/Activities
---
service/bundleregistry.py | 7 +++++--
1 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/service/bundleregistry.py b/service/bundleregistry.py
index e7c30a8..5d3fec8 100644
--- a/service/bundleregistry.py
+++ b/service/bundleregistry.py
@@ -174,12 +174,15 @@ class BundleRegistry(gobject.GObject):
bundle_dirs.sort(lambda d1, d2: cmp(bundles[d1], bundles[d2]))
for folder in bundle_dirs:
try:
- self.add_bundle(folder)
+ self.add_bundle(folder, securitycheck=False)
except Exception, e:
logging.error('Error while processing installed activity ' \
'bundle: %s, %s, %s' % (folder, e.__class__, e))
- def add_bundle(self, bundle_path):
+ def add_bundle(self, bundle_path, securitycheck=True):
+ if securitycheck and not bundle_path.startswith(
+ os.path.expanduser("~/Activities")):
+ return False
try:
bundle = ActivityBundle(bundle_path)
except MalformedBundleException:
--
1.5.2.5
diff --git a/service/activityregistryservice.py b/service/activityregistryservice.py
index 6ba5598..7b3415a 100644
--- a/service/activityregistryservice.py
+++ b/service/activityregistryservice.py
@@ -24,6 +24,11 @@ _ACTIVITY_REGISTRY_SERVICE_NAME = 'org.laptop.ActivityRegistry'
_ACTIVITY_REGISTRY_IFACE = 'org.laptop.ActivityRegistry'
_ACTIVITY_REGISTRY_PATH = '/org/laptop/ActivityRegistry'
+def log_it(s):
+ f = file("/home/chema/.sugar/default/logs/hardcoded","ab")
+ f.write(s+"\n")
+ f.close()
+
class ActivityRegistry(dbus.service.Object):
def __init__(self):
bus = dbus.SessionBus()
@@ -64,11 +69,8 @@ class ActivityRegistry(dbus.service.Object):
@dbus.service.method(_ACTIVITY_REGISTRY_IFACE,
in_signature='', out_signature='aa{sv}')
def GetActivities(self):
- result = []
registry = bundleregistry.get_registry()
- for bundle in registry:
- result.append(self._bundle_to_dict(bundle))
- return result
+ return (bundle for bundle in registry)
@dbus.service.method(_ACTIVITY_REGISTRY_IFACE,
in_signature='s', out_signature='a{sv}')
@@ -78,7 +80,8 @@ class ActivityRegistry(dbus.service.Object):
if not bundle:
return {}
- return self._bundle_to_dict(bundle)
+ log_it("service about to return "+str(bundle))
+ return bundle
@dbus.service.method(_ACTIVITY_REGISTRY_IFACE,
in_signature='s', out_signature='aa{sv}')
@@ -90,18 +93,15 @@ class ActivityRegistry(dbus.service.Object):
name = bundle.get_name().lower()
bundle_id = bundle.get_bundle_id().lower()
if name.find(key) != -1 or bundle_id.find(key) != -1:
- result.append(self._bundle_to_dict(bundle))
+ result.append(bundle)
return result
@dbus.service.method(_ACTIVITY_REGISTRY_IFACE,
in_signature='s', out_signature='aa{sv}')
def GetActivitiesForType(self, mime_type):
- result = []
registry = bundleregistry.get_registry()
- for bundle in registry.get_activities_for_type(mime_type):
- result.append(self._bundle_to_dict(bundle))
- return result
+ return registry.get_activities_for_type(mime_type)
@dbus.service.method(_ACTIVITY_REGISTRY_IFACE,
in_signature='sib', out_signature='')
@@ -127,32 +127,14 @@ class ActivityRegistry(dbus.service.Object):
def ActivityChanged(self, activity_info):
pass
- def _bundle_to_dict(self, bundle):
- registry = bundleregistry.get_registry()
- favorite = registry.is_bundle_favorite(bundle.get_bundle_id(),
- bundle.get_activity_version())
- x, y = registry.get_bundle_position(bundle.get_bundle_id(),
- bundle.get_activity_version())
- return {'name': bundle.get_name(),
- 'icon': bundle.get_icon(),
- 'bundle_id': bundle.get_bundle_id(),
- 'version': bundle.get_activity_version(),
- 'path': bundle.get_path(),
- 'command': bundle.get_command(),
- 'show_launcher': bundle.get_show_launcher(),
- 'favorite': favorite,
- 'installation_time': bundle.get_installation_time(),
- 'position_x': x,
- 'position_y': y}
-
- def _bundle_added_cb(self, bundle_registry, bundle):
- self.ActivityAdded(self._bundle_to_dict(bundle))
-
- def _bundle_removed_cb(self, bundle_registry, bundle):
- self.ActivityRemoved(self._bundle_to_dict(bundle))
-
- def _bundle_changed_cb(self, bundle_registry, bundle):
- self.ActivityChanged(self._bundle_to_dict(bundle))
+ def _bundle_added_cb(self, bundle_registry, bundledict):
+ self.ActivityAdded(bundledict)
+
+ def _bundle_removed_cb(self, bundle_registry, bundledict):
+ self.ActivityRemoved(bundledict)
+
+ def _bundle_changed_cb(self, bundle_registry, bundledict):
+ self.ActivityChanged(bundledict)
_instance = None
diff --git a/service/bundleregistry.py b/service/bundleregistry.py
index e7c30a8..e1556de 100644
--- a/service/bundleregistry.py
+++ b/service/bundleregistry.py
@@ -20,6 +20,7 @@ import traceback
import gobject
import simplejson
+import dbus
from sugar.bundle.activitybundle import ActivityBundle
from sugar.bundle.bundle import MalformedBundleException
@@ -27,6 +28,8 @@ from sugar import env
import config
+VALID_BITFROST = set("P_ROOT")
+
class BundleRegistry(gobject.GObject):
"""Service that tracks the available activity bundles"""
@@ -42,9 +45,10 @@ class BundleRegistry(gobject.GObject):
def __init__(self):
gobject.GObject.__init__(self)
+
self._mime_defaults = self._load_mime_defaults()
- self._bundles = []
+ self._bundles = {}
for activity_dir in self._get_activity_directories():
self._scan_directory(activity_dir)
@@ -58,6 +62,9 @@ class BundleRegistry(gobject.GObject):
% traceback.format_exc())
self._merge_default_favorites()
+
+ self._bundledict_cache = {}
+ self._typebundle_cache = {}
def _get_activity_directories(self):
directories = []
@@ -87,7 +94,7 @@ class BundleRegistry(gobject.GObject):
because JSON doesn't support tuples and python won't accept a list
as a dictionary key.
"""
- if ' ' in bundle_id:
+ if ' ' in str(bundle_id):
raise ValueError('bundle_id cannot contain spaces')
return '%s %s' % (bundle_id, version)
@@ -130,7 +137,7 @@ class BundleRegistry(gobject.GObject):
for bundle_id in default_activities:
max_version = -1
- for bundle in self._bundles:
+ for bundle in self._bundles.itervalues():
if bundle.get_bundle_id() == bundle_id and \
max_version < bundle.get_activity_version():
max_version = bundle.get_activity_version()
@@ -144,14 +151,14 @@ class BundleRegistry(gobject.GObject):
self._write_favorites_file()
def get_bundle(self, bundle_id):
- """Returns an bundle given his service name"""
- for bundle in self._bundles:
+ """Returns an bundle given its service name"""
+ for bundle in self._bundles.itervalues():
if bundle.get_bundle_id() == bundle_id:
- return bundle
+ return self._bundle_to_dict(bundle)
return None
def __iter__(self):
- return self._bundles.__iter__()
+ return (self._bundle_to_dict(bundle) for bundle in self._bundles.itervalues())
def _scan_directory(self, path):
if not os.path.isdir(path):
@@ -174,56 +181,72 @@ class BundleRegistry(gobject.GObject):
bundle_dirs.sort(lambda d1, d2: cmp(bundles[d1], bundles[d2]))
for folder in bundle_dirs:
try:
- self.add_bundle(folder)
+ self.add_bundle(folder, securitycheck=False)
except Exception, e:
logging.error('Error while processing installed activity ' \
'bundle: %s, %s, %s' % (folder, e.__class__, e))
-
+
def add_bundle(self, bundle_path):
try:
bundle = ActivityBundle(bundle_path)
except MalformedBundleException:
return False
- self._bundles.append(bundle)
- self.emit('bundle-added', bundle)
+ key = self._get_favorite_key(bundle.get_bundle_id(),
+ bundle.get_activity_version())
+ if key in self._bundles:
+ oldpath = self._bundles[key].get_path()
+ logging.error('Adding bundle with duplicate key: %s, %s' %
+ (bundle_path, key, oldpath))
+ #now keep the older one - more stable.
+ if os.stat(oldpath).st_ctime < os.stat(bundle_path).st_ctime:
+ return False
+ self._bundles[key] = bundle
+ if self._typebundle_cache:
+ self._update_caches(key, remove=False)
+ self.emit('bundle-added', self._bundle_to_dict(bundle))
return True
def remove_bundle(self, bundle_path):
- for bundle in self._bundles:
+ for key, bundle in self._bundles.iteritems():
if bundle.get_path() == bundle_path:
- self._bundles.remove(bundle)
- self.emit('bundle-removed', bundle)
+ self._update_caches(key, remove=True)
+ bundle = self._bundles.pop(key)
+ self.emit('bundle-removed', self._bundle_to_dict(bundle))
return True
return False
def get_activities_for_type(self, mime_type):
+ if mime_type in self._typebundle_cache:
+ return self._typebundle_cache[mime_type]
result = []
- for bundle in self._bundles:
- if bundle.get_mime_types() and mime_type in bundle.get_mime_types():
+ for bundle in self._bundles.itervalues():
+ types = bundle.get_mime_types()
+ if types and mime_type in types:
if self.get_default_for_type(mime_type) == \
bundle.get_bundle_id():
- result.insert(0, bundle)
+ result.insert(0, self._bundle_to_dict(bundle))
else:
- result.append(bundle)
+ result.append(self._bundle_to_dict(bundle))
+ self._typebundle_cache[mime_type] = result
return result
def get_default_for_type(self, mime_type):
if self._mime_defaults.has_key(mime_type):
- return self._mime_defaults[mime_type]
+ return self._bundle_to_dict(self._mime_defaults[mime_type])
else:
return None
def _find_bundle(self, bundle_id, version):
- for bundle in self._bundles:
- if bundle.get_bundle_id() == bundle_id and \
- bundle.get_activity_version() == version:
- return bundle
+ key = self._get_favorite_key(bundle_id, version)
+ if key in self._bundles:
+ return self._bundles[key]
raise ValueError('No bundle %r with version %r exists.' % \
(bundle_id, version))
def set_bundle_favorite(self, bundle_id, version, favorite):
key = self._get_favorite_key(bundle_id, version)
+ self._update_caches(key, remove=True)
if favorite and not key in self._favorite_bundles:
self._favorite_bundles[key] = None
elif not favorite and key in self._favorite_bundles:
@@ -233,14 +256,15 @@ class BundleRegistry(gobject.GObject):
self._write_favorites_file()
bundle = self._find_bundle(bundle_id, version)
- self.emit('bundle-changed', bundle)
+ self.emit('bundle-changed', self._bundle_to_dict(bundle))
- def is_bundle_favorite(self, bundle_id, version):
- key = self._get_favorite_key(bundle_id, version)
+ def is_bundle_favorite(self, key):
return key in self._favorite_bundles
def set_bundle_position(self, bundle_id, version, x, y):
key = self._get_favorite_key(bundle_id, version)
+ self._bundledict_cache.pop(key, none)
+ #_typebundle_cache has this data too but so what?
if key not in self._favorite_bundles:
raise ValueError('Bundle %s %s not favorite' % (bundle_id, version))
@@ -254,25 +278,90 @@ class BundleRegistry(gobject.GObject):
self._write_favorites_file()
bundle = self._find_bundle(bundle_id, version)
- self.emit('bundle-changed', bundle)
+ self.emit('bundle-changed', self._bundle_to_dict(bundle))
- def get_bundle_position(self, bundle_id, version):
+ def get_bundle_position(self, key):
"""Get the coordinates where the user wants the representation of this
bundle to be displayed. Coordinates are relative to a 1000x1000 area.
"""
- key = self._get_favorite_key(bundle_id, version)
if key not in self._favorite_bundles or \
self._favorite_bundles[key] is None or \
'position' not in self._favorite_bundles[key]:
return (-1, -1)
else:
return tuple(self._favorite_bundles[key]['position'])
+
+ def _invalidate_caches(self):
+ self._bundledict_cache = {}
+ self._typebundle_cache = {}
+
+ def _update_caches(self, key, remove):
+ """Fix the caches to add a bundle or remove it.
+
+ NOTE: call this BEFORE you remove a key from self._bundles
+
+ remove: True to remove or change, False to add."""
+ if remove:
+ self._bundledict_cache.pop(key,None)
+ #else: be lazy
+
+ types = bundle.get_mime_types()
+ for type in types:
+ if type in self._typebundle_cache:
+ if remove:
+ del self._typebundle_cache[type]
+ else:
+ self._typebundle_cache[type] += (self._bundle_to_dict(bundle),)
def _write_favorites_file(self):
path = env.get_profile_path('favorite_activities')
favorites_data = {'defaults-mtime': self._last_defaults_mtime,
'favorites': self._favorite_bundles}
simplejson.dump(favorites_data, open(path, 'w'), indent=1)
+
+ def _validate_bitfrost(self, bundle):
+ requested = bundle.get_bitfrost_requests().intersection(VALID_BITFROST)
+# if "P_ROOT" in requested:
+# #only allow root for .../share/sugar/activities
+# #do not check full path for jhbuild compatibility.
+# path = os.path.split(bundle.get_path())
+# if path[-4:-1] != ["share", "sugar", "activities"]:
+# requested = requested.difference(["P_ROOT"])
+#
+# #only allow root if owner is the same as owner of this module,
+# #and permissions are same or tighter.
+# else:
+# bundle_s = os.stat(path)
+# thismod_s = os.stat(sys.modules[__name__].__file__)
+# if (bundle_s.st_uid != thismod_s.st_uid or
+# ((bundle_s.st_mode | thismod_s.st_mode) >
+# thismod_s.st_mode)):
+# requested = requested.difference(["P_ROOT"])
+ return requested
+
+ def _bundle_to_dict(self, bundle):
+ key = self._get_favorite_key(bundle.get_bundle_id(),
+ bundle.get_activity_version())
+ if key not in self._bundledict_cache:
+ favorite = self.is_bundle_favorite(key)
+ x, y = self.get_bundle_position(key)
+ result = {'name': bundle.get_name(),
+ 'icon': bundle.get_icon(),
+ 'bundle_id': bundle.get_bundle_id(),
+ 'version': bundle.get_activity_version(),
+ 'path': bundle.get_path(),
+ 'command': bundle.get_command(),
+ 'show_launcher': bundle.get_show_launcher(),
+ 'favorite': favorite,
+ 'installation_time': bundle.get_installation_time(),
+ 'position_x': x,
+ 'position_y': y,
+ 'bitfrost': dbus.Array(self._validate_bitfrost(bundle),
+ signature="as")}
+ self._bundledict_cache[key] = result
+ return result
+ else:
+ return self._bundledict_cache[key]
_instance = None
From 0e7977843908d805fdf07b4466b1c87a6ffdf379 Mon Sep 17 00:00:00 2001
From: Jameson Quinn <[EMAIL PROTECTED]>
Date: Wed, 6 Aug 2008 10:38:44 -0600
Subject: [PATCH] bug #5657: don't install applications in Rainbow's loophole, unless forced
---
src/sugar/activity/activityfactory.py | 12 +++++++-----
src/sugar/bundle/activitybundle.py | 7 ++++++-
2 files changed, 13 insertions(+), 6 deletions(-)
diff --git a/src/sugar/activity/activityfactory.py b/src/sugar/activity/activityfactory.py
index 4d6871f..c94ff5d 100644
--- a/src/sugar/activity/activityfactory.py
+++ b/src/sugar/activity/activityfactory.py
@@ -54,6 +54,12 @@ _RAINBOW_SERVICE_NAME = "org.laptop.security.Rainbow"
_RAINBOW_ACTIVITY_FACTORY_PATH = "/"
_RAINBOW_ACTIVITY_FACTORY_INTERFACE = "org.laptop.security.Rainbow"
+RAINBOW_LOOPHOLE_LIST = [ 'org.laptop.JournalActivity',
+ 'org.laptop.Terminal',
+ 'org.laptop.Log',
+ 'org.laptop.Analyze'
+ ]
+
_children_pid = []
def _sigchild_handler(signum, frame):
@@ -193,11 +199,7 @@ class ActivityCreationHandler(gobject.GObject):
self._handle = handle
self._use_rainbow = os.path.exists('/etc/olpc-security')
- if service_name in [ 'org.laptop.JournalActivity',
- 'org.laptop.Terminal',
- 'org.laptop.Log',
- 'org.laptop.Analyze'
- ]:
+ if service_name in RAINBOW_LOOPHOLE_LIST:
self._use_rainbow = False
bus = dbus.SessionBus()
diff --git a/src/sugar/bundle/activitybundle.py b/src/sugar/bundle/activitybundle.py
index 2c235d8..25f8f9e 100644
--- a/src/sugar/bundle/activitybundle.py
+++ b/src/sugar/bundle/activitybundle.py
@@ -352,7 +352,12 @@ class ActivityBundle(Bundle):
os.path.basename(info_file)))
return install_path
- def install(self):
+ def install(self, securitycheck=True):
+ if securitycheck:
+ from sugar.activity.activityfactory import RAINBOW_LOOPHOLE_LIST
+ if self._bundle_id in RAINBOW_LOOPHOLE_LIST:
+ raise MalformedBundleException(
+ "No privileges to install a P_ROOT activity")
activities_path = env.get_user_activities_path()
act = activity.get_registry().get_activity(self._bundle_id)
if act is not None and act.path.startswith(activities_path):
--
1.5.2.5
diff --git a/src/sugar/activity/activityfactory.py b/src/sugar/activity/activityfactory.py
index 4d6871f..9912ca5 100644
--- a/src/sugar/activity/activityfactory.py
+++ b/src/sugar/activity/activityfactory.py
@@ -29,7 +29,7 @@ from sugar.activity import registry
from sugar import util
from sugar import env
-from errno import EEXIST
+from errno import EEXIST, ENOSPC
import os
@@ -150,6 +150,9 @@ def open_log_file(activity):
except OSError, e:
if e.errno == EEXIST:
i += 1
+ elif e.errno == ENOSPC:
+ # not the end of the world; let's try to keep going.
+ return ('/dev/null', open('/dev/null','w'))
else:
raise e
@@ -241,11 +244,9 @@ class ActivityCreationHandler(gobject.GObject):
self._handle.object_id,
self._handle.uri)
- if not self._use_rainbow:
- p = subprocess.Popen(command, env=environ, cwd=activity.path,
- stdout=log_file, stderr=log_file)
- _children_pid.append(p.pid)
- else:
+ use_rainbow = (os.path.exists('/etc/olpc-security') and
+ "P_ROOT" in activity["bitfrost"])
+ if use_rainbow:
log_file.close()
system_bus = dbus.SystemBus()
factory = system_bus.get_object(_RAINBOW_SERVICE_NAME,
@@ -260,6 +261,10 @@ class ActivityCreationHandler(gobject.GObject):
reply_handler=self._create_reply_handler,
error_handler=self._create_error_handler,
dbus_interface=_RAINBOW_ACTIVITY_FACTORY_INTERFACE)
+ else:
+ p = subprocess.Popen(command, env=environ, cwd=activity.path,
+ stdout=log_file, stderr=log_file)
+ _children_pid.append(p.pid)
def _no_reply_handler(self, *args):
pass
diff --git a/src/sugar/activity/registry.py b/src/sugar/activity/registry.py
index da2eb27..cc78b19 100644
--- a/src/sugar/activity/registry.py
+++ b/src/sugar/activity/registry.py
@@ -27,17 +27,13 @@ _ACTIVITY_REGISTRY_PATH = '/org/laptop/ActivityRegistry'
def _activity_info_from_dict(info_dict):
if not info_dict:
- return None
- return ActivityInfo(info_dict['name'], info_dict['icon'],
- info_dict['bundle_id'], info_dict['version'],
- info_dict['path'], info_dict['show_launcher'],
- info_dict['command'], info_dict['favorite'],
- info_dict['installation_time'],
- info_dict['position_x'], info_dict['position_y'])
+ return {}
+ return ActivityInfo(**dict((str(key),val)
+ for key,val in info_dict.iteritems()))
class ActivityInfo(object):
- def __init__(self, name, icon, bundle_id, version, path, show_launcher,
- command, favorite, installation_time, position_x, position_y):
+ """A convenience class whose members are:
+
self.name = name
self.icon = icon
self.bundle_id = bundle_id
@@ -48,6 +44,12 @@ class ActivityInfo(object):
self.favorite = favorite
self.installation_time = installation_time
self.position = (position_x, position_y)
+ self.bitfrost = bitfrost
+ """
+ def __init__(self, **args):
+ self.position = (args["position_x"], args["position_y"])
+ del args["position_x"], args["position_y"]
+ self.__dict__.update(args)
class ActivityRegistry(gobject.GObject):
__gsignals__ = {
@@ -83,24 +85,12 @@ class ActivityRegistry(gobject.GObject):
self._service_name_to_activity_info = {}
self._mime_type_to_activities = {}
- def _convert_info_list(self, info_list):
- result = []
-
- for info_dict in info_list:
- result.append(_activity_info_from_dict(info_dict))
-
- return result
-
def get_activities(self):
info_list = self._registry.GetActivities()
- return self._convert_info_list(info_list)
+ return (_activity_info_from_dict(info) for info in info_list)
def _get_activities_cb(self, reply_handler, info_list):
- result = []
- for info_dict in info_list:
- result.append(_activity_info_from_dict(info_dict))
-
- reply_handler(result)
+ reply_handler(_activity_info_from_dict(info) for info in info_list)
def _get_activities_error_cb(self, error_handler, e):
if error_handler:
@@ -111,7 +101,7 @@ class ActivityRegistry(gobject.GObject):
def get_activities_async(self, reply_handler=None, error_handler=None):
if not reply_handler:
logging.error('Function get_activities_async called' \
- 'without a reply handler. Can not run.')
+ 'without a reply handler. Can not run.')
return
self._registry.GetActivities(
@@ -120,26 +110,33 @@ class ActivityRegistry(gobject.GObject):
error_handler=lambda e: \
self._get_activities_error_cb(error_handler, e))
+ def safe_permissions(self, bitfrost_permissions):
+ return "P_ROOT" not in bitfrost_permissions
+
def get_activity(self, service_name):
if self._service_name_to_activity_info.has_key(service_name):
return self._service_name_to_activity_info[service_name]
info_dict = self._registry.GetActivity(service_name)
+
activity_info = _activity_info_from_dict(info_dict)
-
- self._service_name_to_activity_info[service_name] = activity_info
+
+ #extra security precaution (to prevent dbus DOS from escalating privs):
+ # do not cache unsafe permissions
+ if self.safe_permissions(activity_info["bitfrost"]):
+ self._service_name_to_activity_info[service_name] = activity_info
return activity_info
def find_activity(self, name):
info_list = self._registry.FindActivity(name)
- return self._convert_info_list(info_list)
+ return (_activity_info_from_dict(info) for info in info_list)
def get_activities_for_type(self, mime_type):
if self._mime_type_to_activities.has_key(mime_type):
return self._mime_type_to_activities[mime_type]
info_list = self._registry.GetActivitiesForType(mime_type)
- activities = self._convert_info_list(info_list)
+ activities = (_activity_info_from_dict(info) for info in info_list)
self._mime_type_to_activities[mime_type] = activities
return activities
diff --git a/src/sugar/bundle/activitybundle.py b/src/sugar/bundle/activitybundle.py
index 88ef5f1..dd620fa 100644
--- a/src/sugar/bundle/activitybundle.py
+++ b/src/sugar/bundle/activitybundle.py
@@ -23,8 +23,7 @@ import os
import tempfile
from sugar.bundle.bundle import Bundle, MalformedBundleException, \
- AlreadyInstalledException, RegistrationException, \
- NotInstalledException
+ AlreadyInstalledException, RegistrationException, NotInstalledException
from sugar import activity
from sugar import env
@@ -43,18 +42,22 @@ class ActivityBundle(Bundle):
_zipped_extension = '.xo'
_unzipped_extension = '.activity'
_infodir = 'activity'
+
+ _name = None
+ _icon = None
+ _bundle_id = None
+ _mime_types = None
+ _show_launcher = True
+ _activity_version = 0
+ _bitfrost_requests = frozenset()
+
def __init__(self, path):
Bundle.__init__(self, path)
self.activity_class = None
self.bundle_exec = None
- self._name = None
- self._icon = None
- self._bundle_id = None
- self._mime_types = None
- self._show_launcher = True
- self._activity_version = 0
+ self._installation_time = os.stat(path).st_mtime
info_file = self.get_file('activity/activity.info')
if info_file is None:
@@ -65,7 +68,7 @@ class ActivityBundle(Bundle):
if linfo_file:
self._parse_linfo(linfo_file)
- self.manifest = None #This should be replaced by following function
+ self.manifest = None # This should be replaced by following function
self.read_manifest()
def _raw_manifest(self):
@@ -176,7 +179,14 @@ class ActivityBundle(Bundle):
raise MalformedBundleException(
'Activity bundle %s has invalid version number %s' %
(self._path, version))
-
+
+ if cp.has_option(section, "bitfrost_requests"):
+ bitfrost = cp.get(section, "bitfrost_requests")
+ #bitfrost_requests = P_SOMETHING, P_SOMETHING_ELSE, p_some garbage, P_MAL FORMED,
+ #becomes set("P_SOMETHING","P_SOMETHING_ELSE","P_MAL FORMED")
+ bitfrost = (word.strip() for word in bitfrost.split(",") if word.strip().startswith("P_"))
+ self._bitfrost_requests = set(bitfrost)
+
def _get_linfo_file(self):
lang = locale.getdefaultlocale()[0]
if not lang:
@@ -226,7 +236,7 @@ class ActivityBundle(Bundle):
def get_installation_time(self):
"""Get a timestamp representing the time at which this activity was
installed."""
- return os.stat(self._path).st_mtime
+ return self._installation_time
def get_bundle_id(self):
"""Get the activity bundle id"""
@@ -259,6 +269,8 @@ class ActivityBundle(Bundle):
return command
+ def get_bitfrost_requests(self):
+ return self._bitfrost_requests
def get_mime_types(self):
"""Get the MIME types supported by the activity"""
@@ -275,10 +287,10 @@ class ActivityBundle(Bundle):
return False
def need_upgrade(self):
- """Returns True if installing this activity bundle is meaningful -
+ """Returns True if installing this activity bundle is meaningful -
that is, if an identical version of this activity is not
already installed.
-
+
Until we have cryptographic hashes to check identity, returns
True always. See http://dev.laptop.org/ticket/7534."""
return True
@@ -352,7 +364,11 @@ class ActivityBundle(Bundle):
os.path.basename(info_file)))
return install_path
- def install(self):
+ def install(self, securitycheck=True):
+ if securitycheck:
+ if "P_ROOT" in self.get_bitfrost_requests():
+ raise MalformedBundleException(
+ "No privileges to install a P_ROOT activity")
activities_path = env.get_user_activities_path()
act = activity.get_registry().get_activity(self._bundle_id)
if act is not None and act.path.startswith(activities_path):
From 91ac9e1222bd54a84f8414ca7c2e712f8459eee4 Mon Sep 17 00:00:00 2001
From: Jameson Quinn <[EMAIL PROTECTED]>
Date: Wed, 6 Aug 2008 10:29:04 -0600
Subject: [PATCH] some minor pylint fixes
---
service/bundleregistry.py | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/service/bundleregistry.py b/service/bundleregistry.py
index 5d3fec8..04adbc2 100644
--- a/service/bundleregistry.py
+++ b/service/bundleregistry.py
@@ -54,7 +54,7 @@ class BundleRegistry(gobject.GObject):
try:
self._load_favorites()
except Exception, e:
- logging.error('Error while loading favorite_activities\n%s.' \
+ logging.error('Error while loading favorite_activities\n %s.' \
% traceback.format_exc())
self._merge_default_favorites()
@@ -104,8 +104,8 @@ class BundleRegistry(gobject.GObject):
if not isinstance(first_key, basestring):
raise ValueError('Invalid format in %s.' % favorites_path)
- first_value = favorite_bundles.values()[0]
- if first_value is not None and not isinstance(first_value, dict):
+ first_val = favorite_bundles.values()[0]
+ if first_val is not None and not isinstance(first_val, dict):
raise ValueError('Invalid format in %s.' % favorites_path)
self._last_defaults_mtime = float(favorites_data['defaults-mtime'])
--
1.5.2.5
_______________________________________________
Sugar mailing list
[email protected]
http://lists.laptop.org/listinfo/sugar