Beispiel #1
0
    def _internal_init(self):
        """Internal: Initialize all class members to their default value"""

        if not os.path.exists(self.profile):
            os.makedirs(self.profile)

        # Preferences files written to
        self.written_prefs = set()

        # Our magic markers
        nonce = '%s %s' % (str(time.time()), uuid.uuid4())
        self.delimeters = ('#MozRunner Prefs Start %s' % nonce,
                           '#MozRunner Prefs End %s' % nonce)

        # If sub-classes want to set default preferences
        if hasattr(self.__class__, 'preferences'):
            self.set_preferences(self.__class__.preferences)
        # Set additional preferences
        self.set_preferences(self._preferences)

        self.permissions = Permissions(self.profile, self._locations)
        prefs_js, user_js = self.permissions.network_prefs(self._proxy)
        self.set_preferences(prefs_js, 'prefs.js')
        self.set_preferences(user_js)

        # handle add-on installation
        self.addon_manager = AddonManager(self.profile, restore=self.restore)
        self.addon_manager.install_addons(self._addons, self._addon_manifests)

        # handle webapps
        self.webapps = WebappCollection(profile=self.profile, apps=self._apps)
        self.webapps.update_manifests()
Beispiel #2
0
 def get_permissions(cls, reference):
     perm = Permissions(0)
     perm.set_mode('u', 'r', True)
     perm.set_mode('u', 'w', True)
     perm.set_mode('g', 'r', True)
     perm.set_mode('o', 'r', True)
     return perm
    def __init__(
        self,
        profile=None,  # Path to the profile
        addons=None,  # String of one or list of addons to install
        addon_manifests=None,  # Manifest for addons, see http://ahal.ca/blog/2011/bulk-installing-fx-addons/
        preferences=None,  # Dictionary or class of preferences
        locations=None,  # locations to proxy
        proxy=None,  # setup a proxy - dict of server-loc,server-port,ssl-port
        restore=True  # If true remove all installed addons preferences when cleaning up
    ):

        # if true, remove installed addons/prefs afterwards
        self.restore = restore

        # prefs files written to
        self.written_prefs = set()

        # our magic markers
        nonce = '%s %s' % (str(time.time()), uuid.uuid4())
        self.delimeters = ('#MozRunner Prefs Start %s' % nonce,
                           '#MozRunner Prefs End %s' % nonce)

        # Handle profile creation
        self.create_new = not profile
        if profile:
            # Ensure we have a full path to the profile
            self.profile = os.path.abspath(os.path.expanduser(profile))
            if not os.path.exists(self.profile):
                os.makedirs(self.profile)
        else:
            self.profile = self.create_new_profile()

        # set preferences
        if hasattr(self.__class__, 'preferences'):
            # class preferences
            self.set_preferences(self.__class__.preferences)
        self._preferences = preferences
        if preferences:
            # supplied preferences
            if isinstance(preferences, dict):
                # unordered
                preferences = preferences.items()
            # sanity check
            assert not [i for i in preferences if len(i) != 2]
        else:
            preferences = []
        self.set_preferences(preferences)

        # set permissions
        self._locations = locations  # store this for reconstruction
        self._proxy = proxy
        self.permissions = Permissions(self.profile, locations)
        prefs_js, user_js = self.permissions.network_prefs(proxy)
        self.set_preferences(prefs_js, 'prefs.js')
        self.set_preferences(user_js)

        # handle addon installation
        self.addon_manager = AddonManager(self.profile)
        self.addon_manager.install_addons(addons, addon_manifests)
Beispiel #4
0
 def on_server_sync(self, msg):
     self.max_bandwidth = msg.max_bandwidth
     self.welcome_text = msg.welcome_text
     if msg.permissions:
         if not self.permissions:
             self.permissions = Permissions(msg.permissions)
         else:
             self.permissions.update(msg.permissions)
     self.bot.connected()
Beispiel #5
0
def invoke(update, *_):
    # raw_user should not be able to log out e_user
    raw_user = raw_whois(update)
    if raw_user == Permissions.e_whois(update):
        raise DispatcherHandlerContinue
    # If invoked by e_user
    try:
        Permissions.remove_user_translation(raw_user)
        reply(update, 'Success')
    except AssertionError as err:
        logging.error(str(err))
        reply(update, 'Error: ' + str(err))
def test_authorized_scopes():
    permissions = Permissions()
    for scope in permissions.authorized_scopes:
        permissions.grant(scope, 'persona', 'topic')
        assert permissions.authorize(scope, 'persona', 'topic') is True
        assert permissions.authorize('*unknown*', 'persona', 'topic') is False
        assert permissions.authorize(scope, '*unknown*', 'topic') is False
        assert permissions.authorize(scope, 'persona', '*unknown*') is False
Beispiel #7
0
 def get_permissions(cls, reference):
     path = unicode(reference.path)
     try:
         mode = stat(path)[0]
     except UnicodeEncodeError:
         mode = stat(path.encode('utf-8'))[0]
     return Permissions(mode)
Beispiel #8
0
    def _internal_init(self):
        """Internal: Initialize all class members to their default value"""

        if not os.path.exists(self.profile):
            os.makedirs(self.profile)

        # Preferences files written to
        self.written_prefs = set()

        # Our magic markers
        nonce = '%s %s' % (str(time.time()), uuid.uuid4())
        self.delimeters = ('#MozRunner Prefs Start %s' % nonce,
                           '#MozRunner Prefs End %s' % nonce)

        # If sub-classes want to set default preferences
        if hasattr(self.__class__, 'preferences'):
            self.set_preferences(self.__class__.preferences)
        # Set additional preferences
        self.set_preferences(self._preferences)

        self.permissions = Permissions(self.profile, self._locations)
        prefs_js, user_js = self.permissions.network_prefs(self._proxy)
        self.set_preferences(prefs_js, 'prefs.js')
        self.set_preferences(user_js)

        # handle add-on installation
        self.addon_manager = AddonManager(self.profile, restore=self.restore)
        self.addon_manager.install_addons(self._addons, self._addon_manifests)
 def __init__(self, permissions=None, store=None, emitter=None):
     self.secret_attributes = ['password']
     self.permissions = permissions or Permissions(
         path='fixtures/permissions.yaml')
     self.store = store or Users()
     self.emitter = emitter
     self.replay_stamp = None
     self.page_size = 10
     self.record_maximum_size = 100000
     self.routes = []
     self._add_url_rule('/login', 'login', self.login, methods=['POST'])
     self._add_url_rule('/signin', 'signin', self.signin, methods=['POST'])
     self._add_url_rule('/check',
                        'check',
                        self.check_bearer,
                        methods=['GET', 'POST'])
     self._add_url_rule('/renew',
                        'renew',
                        self.renew_bearer,
                        methods=['GET', 'POST'])
     self._add_url_rule('/users', 'index', self.index)
     self._add_url_rule('/users/page/<token>', 'page', self.page)
     self._add_url_rule('/register', 'post', self.post, methods=['POST'])
     self._add_url_rule('/users/<id>', 'get', self.get)
     self._add_url_rule('/users/<id>', 'put', self.put, methods=['PUT'])
     self._add_url_rule('/users/<id>',
                        'delete',
                        self.delete,
                        methods=['DELETE'])
Beispiel #10
0
def delete_item_by_id(category_id, item_id):
    """
    HTML endpoint providing a form to delete an item
    """
    if not UserUtils.is_authenticated():
        UserUtils.set_preauthentication_url()
        flash('sign in to delete an item')
        return redirect('/login')

    item = session.query(Item).filter_by(id=item_id).one()

    # Users may delete only items they created
    if not Permissions.get_user_permissions_for_item(item).delete:
        flash('you may delete only items you created')
        return redirect(url_for('get_category_by_id', category_id=category_id))

    if request.method == 'POST':
        session.delete(item)
        session.commit()

        flash('item deleted')

        return redirect(url_for('get_category_by_id', category_id=category_id))
    else:
        category = session.query(Category).filter_by(id=category_id).one()

        return UserUtils.render_user_template('item_delete.html',
                                              category=category,
                                              category_id=category_id,
                                              item=item,
                                              page_title="%s %s Item" %
                                              ("Delete", item.title))
def delete_category_by_id(category_id):
    """
    HTML endpoint providing a form to delete a category
    """
    if not UserUtils.is_authenticated():
        UserUtils.set_preauthentication_url()
        flash('sign in to delete categories')
        return redirect('/login')

    category = session.query(Category).filter_by(id=category_id).one()

    if not Permissions.get_user_permissions_for_category(category).delete:
        flash('you may delete only empty categories you created')
        return redirect(url_for(
            'get_categories'))

    if request.method == 'POST':
        session.delete(category)
        session.commit()

        flash('category deleted')

        return redirect(url_for(
            'get_categories'))
    else:
        return UserUtils.render_user_template(
            'category_delete.html',
            category=category,
            page_title="%s %s Category" % ("Delete", category.name))
Beispiel #12
0
    def __init__(self, profile=None, addons=None, addon_manifests=None,  
                 preferences=None, locations=None, proxy=None, restore=True):
        """
        :param profile: Path to the profile
        :param addons: String of one or list of addons to install
        :param addon_manifests: Manifest for addons, see http://ahal.ca/blog/2011/bulk-installing-fx-addons/
        :param preferences: Dictionary or class of preferences
        :param locations: locations to proxy
        :param proxy: setup a proxy - dict of server-loc,server-port,ssl-port
        :param restore: If true remove all installed addons preferences when cleaning up
        """

        # if true, remove installed addons/prefs afterwards
        self.restore = restore

        # prefs files written to
        self.written_prefs = set()

        # our magic markers
        nonce = '%s %s' % (str(time.time()), uuid.uuid4())
        self.delimeters = ('#MozRunner Prefs Start %s' % nonce,'#MozRunner Prefs End %s' % nonce)

        # Handle profile creation
        self.create_new = not profile
        if profile:
            # Ensure we have a full path to the profile
            self.profile = os.path.abspath(os.path.expanduser(profile))
            if not os.path.exists(self.profile):
                os.makedirs(self.profile)
        else:
            self.profile = self.create_new_profile()

        # set preferences
        if hasattr(self.__class__, 'preferences'):
            # class preferences
            self.set_preferences(self.__class__.preferences)
        self._preferences = preferences
        if preferences:
            # supplied preferences
            if isinstance(preferences, dict):
                # unordered
                preferences = preferences.items()
            # sanity check
            assert not [i for i in preferences
                        if len(i) != 2]
        else:
            preferences = []
        self.set_preferences(preferences)

        # set permissions
        self._locations = locations # store this for reconstruction
        self._proxy = proxy
        self.permissions = Permissions(self.profile, locations)
        prefs_js, user_js = self.permissions.network_prefs(proxy)
        self.set_preferences(prefs_js, 'prefs.js')
        self.set_preferences(user_js)

        # handle addon installation
        self.addon_manager = AddonManager(self.profile)
        self.addon_manager.install_addons(addons, addon_manifests)
Beispiel #13
0
 def __init__(self,
              permissions=None,
              users=None,
              channels=None,
              state_file=None):
     self.permissions = permissions or Permissions(
         path='fixtures/permissions.yaml')
     self.users = users
     self.channels = channels
     self.state_file = state_file or 'fixtures/state.yaml'
     if state_file:
         try:
             with open(state_file, 'r') as stream:
                 logger.info(f"loading '{state_file}'...")
                 self.import_content(stream)
         except FileNotFoundError:
             logger.warning(f"can not load '{state_file}'")
     self.routes = []
     self._add_url_rule('/ping', 'ping', self.ping, methods=['GET', 'POST'])
     self._add_url_rule('/snapshot',
                        'snapshot',
                        self.snapshot,
                        methods=['GET', 'POST'])
     self._add_url_rule('/restore',
                        'restore',
                        self.restore,
                        methods=['POST'])
Beispiel #14
0
def invoke(update, context, _):
    if 'logout' not in Loader.loaded():
        reply(update, 'Refusing to login, logout module is not loaded')
        return
    try:
        user = Permissions.e_whois(update)
        new_u = context.args[0]
        try:
            Permissions.add_user_translation(user, new_u)
            msg = '@' + user + ' logged in as @' + new_u
            logging.info(msg)
            reply(update, msg)
        except AssertionError as err:
            reply(update, 'Error: ' + str(err))
    except IndexError:
        reply(update, 'usage: /login <user>')
Beispiel #15
0
    def _internal_init(self):
        """Internal: Initialize all class members to their default value"""

        if not os.path.exists(self.profile):
            os.makedirs(self.profile)

        # Preferences files written to
        self.written_prefs = set()

        # Our magic markers
        nonce = '%s %s' % (str(time.time()), uuid.uuid4())
        self.delimeters = ('#MozRunner Prefs Start %s' % nonce,
                           '#MozRunner Prefs End %s' % nonce)

        # If sub-classes want to set default preferences
        if hasattr(self.__class__, 'preferences'):
            self.set_preferences(self.__class__.preferences)
        # Set additional preferences
        self.set_preferences(self._preferences)

        self.permissions = Permissions(self.profile, self._locations)
        prefs_js, user_js = self.permissions.network_prefs(self._proxy)

        if self._whitelistpaths:
            # On macOS we don't want to support a generalized read whitelist,
            # and the macOS sandbox policy language doesn't have support for
            # lists, so we handle these specially.
            if platform.system() == "Darwin":
                assert len(self._whitelistpaths) <= 2
                if len(self._whitelistpaths) == 2:
                    prefs_js.append(
                        ("security.sandbox.content.mac.testing_read_path2",
                         self._whitelistpaths[1]))
                prefs_js.append(
                    ("security.sandbox.content.mac.testing_read_path1",
                     self._whitelistpaths[0]))
            else:
                prefs_js.append(
                    ("security.sandbox.content.read_path_whitelist",
                     ",".join(self._whitelistpaths)))
        self.set_preferences(prefs_js, 'prefs.js')
        self.set_preferences(user_js)

        # handle add-on installation
        self.addon_manager = AddonManager(self.profile, restore=self.restore)
        self.addon_manager.install_addons(self._addons, self._addon_manifests)
Beispiel #16
0
def update_item_by_id(category_id, item_id):
    """
    HTML endpoint providing a form to edit an item
    """
    if not UserUtils.is_authenticated():
        UserUtils.set_preauthentication_url()
        flash('sign in to edit an item')
        return redirect('/login')

    item = session.query(Item).filter_by(id=item_id).one()

    # Users may update only items they created
    if not Permissions.get_user_permissions_for_item(item).update:
        flash('you may edit only items you created')
        return redirect(url_for('get_category_by_id', category_id=category_id))

    category = session.query(Category).filter_by(id=category_id).one()

    if request.method == 'POST':
        # Extract and validate the form inputs

        (title, title_error) = \
            extract_and_validate_item_title(request.form)

        (description, description_error) = \
            extract_and_validate_item_description(request.form)

        if title_error or description_error:
            return UserUtils.render_user_template(
                'item_update.html',
                category=category,
                category_id=category_id,
                item=item,
                page_title="%s %s Item" % ("Edit", item.title),
                title=title,
                title_error=title_error,
                description=description,
                description_error=description_error)

        # Create the item in the data store

        item.title = title
        item.description = description
        session.add(item)
        session.commit()

        flash('item updated')

        return redirect(url_for('get_category_by_id', category_id=category_id))
    else:
        return UserUtils.render_user_template('item_update.html',
                                              category=category,
                                              category_id=category_id,
                                              item=item,
                                              page_title="%s %s Item" %
                                              ("Edit", item.title),
                                              title=item.title,
                                              description=item.description)
Beispiel #17
0
 def on_server_sync(self, msg):
   self.max_bandwidth = msg.max_bandwidth
   self.welcome_text = msg.welcome_text
   if msg.permissions:
     if not self.permissions:
       self.permissions = Permissions(msg.permissions)
     else:
       self.permissions.update(msg.permissions)
   self.bot.connected()
Beispiel #18
0
    def __init__(self, profile=None, addons=None, addon_manifests=None, apps=None,
                 preferences=None, locations=None, proxy=None, restore=True):

        # if true, remove installed addons/prefs afterwards
        self.restore = restore

        # prefs files written to
        self.written_prefs = set()

        # our magic markers
        nonce = '%s %s' % (str(time.time()), uuid.uuid4())
        self.delimeters = ('#MozRunner Prefs Start %s' % nonce,'#MozRunner Prefs End %s' % nonce)

        # Handle profile creation
        self.create_new = not profile
        if profile:
            # Ensure we have a full path to the profile
            self.profile = os.path.abspath(os.path.expanduser(profile))
            if not os.path.exists(self.profile):
                os.makedirs(self.profile)
        else:
            self.profile = self.create_new_profile()

        # set preferences
        if hasattr(self.__class__, 'preferences'):
            # class preferences
            self.set_preferences(self.__class__.preferences)
        self._preferences = preferences
        if preferences:
            # supplied preferences
            if isinstance(preferences, dict):
                # unordered
                preferences = preferences.items()
            # sanity check
            assert not [i for i in preferences
                        if len(i) != 2]
        else:
            preferences = []
        self.set_preferences(preferences)

        # set permissions
        self._locations = locations # store this for reconstruction
        self._proxy = proxy
        self.permissions = Permissions(self.profile, locations)
        prefs_js, user_js = self.permissions.network_prefs(proxy)
        self.set_preferences(prefs_js, 'prefs.js')
        self.set_preferences(user_js)

        # handle addon installation
        self.addon_manager = AddonManager(self.profile, restore=self.restore)
        self.addon_manager.install_addons(addons, addon_manifests)

        # handle webapps
        self.webapps = WebappCollection(profile=self.profile, apps=apps)
        self.webapps.update_manifests()
Beispiel #19
0
def invoke(update, context, _):

    # Ignore unprivileged people
    who = Permissions.e_whois(update)
    if not Permissions.is_user(who):
        return

    # If /help admin was requested
    admin_mods = Permissions.admin_modules()
    if Permissions.is_admin and len(context.args) > 0:
        if context.args[0] == 'admin':
            help_admin(update, admin_mods)
            return

    # Get descriptions of the loaded modules that the user may invoke
    mods = set(Loader.loaded()) & set(Permissions.user_modules(who))
    mods -= set(['start', 'logout'])
    mod_list = list(mods - admin_mods)
    if who != raw_whois(update):
        mod_list.append('logout')
    descs = ['/' + i + ': ' + Permissions.info(i) for i in mod_list]

    # Reply
    if Permissions.is_admin(who):
        descs.insert(0, 'Admin: /help admin for admin modules')
    reply(update, '@' + who + ' may use:' + djoin(descs))
Beispiel #20
0
 def get_permissions(cls, reference):
     perm = Permissions(0)
     perm.set_mode('u', 'r', True)
     perm.set_mode('u', 'w', True)
     perm.set_mode('g', 'r', True)
     perm.set_mode('o', 'r', True)
     return perm
Beispiel #21
0
    def __init__(self, config_file):
        self.config_file = config_file
        self.config = json.load(open(self.config_file))
        self.me = self.config["me"]
        self.net = self.config["network"]
        self.module_manager = ModuleManager(self)
        self.hook_manager = HookManager(self)
        self.perms = Permissions(self)
        self.connection = IRCConnection(self.net["address"], self.net["port"], self.net["ssl"], self.config["proxies"].get(self.net.get("proxy", "none"), None), self.net.get("flood_interval", 0.0))
        self.running = True
        self.state = {}  # Dict used to hold stuff like last line received and last message etc...
        self.db = Database("etc/buhirc.db")
        self.db.connect()
        logging.basicConfig(level=getattr(logging, self.config["misc"]["loglevel"]), format='[%(asctime)s] %(levelname)s: %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
        self.requests_session = requests.session()
        if self.config["misc"].get("http_proxy", "none") != "none":
            proxy = self.config["proxies"].get(self.config["misc"]["http_proxy"], "none")
            if proxy != "none":
                self.requests_session.proxies = {"http": proxy, "https": proxy}

        self.flood_verbs = [x.lower() for x in self.net.get("flood_verbs", [])]
        self.help = {}
Beispiel #22
0
def main(_):
    setup_logs()

    # For security
    if not is_in_container():
        logging.error('Error: Not executing from container!')
        sys.exit(1)

    # Telegram API setup
    updater = None
    with open('token.priv') as f:
        updater = Updater(f.read().strip(), use_context=True)
    dp = updater.dispatcher

    # Create handler registration
    Permissions.setup(permisions_f)
    invoke_extra_args = {
        'mmj_lic': ro_path,
        'pubkey': ro_path,
        'shopping': rw_path + '/shopping/',
        'log': log_file
    }
    Loader.setup(dp, module_ordered_path, invoke_extra_args, unknown, error)

    # Load modules
    for mod in Permissions.modules():
        try:
            Loader.load(mod)
        except ModuleNotFoundError as err:
            logging.warning(str(err))

    # Start the Bot
    logging.info('Initiating polling.')
    updater.start_polling()

    # Block until you press Ctrl-C or the process receives SIGINT, SIGTERM or
    # SIGABRT. This should be used most of the time, since start_polling() is
    # non-blocking and will stop the bot gracefully.
    updater.idle()
def get_category_by_id(category_id):
    """
    HTML endpoint providing details for a given category
    """
    category = session.query(Category).filter_by(id=category_id).one()

    items = session.query(Item).filter_by(category_id=category_id).all()

    return UserUtils.render_user_template(
        'category_items.html',
        category=category,
        items=items,
        page_title="%s Category" % category.name,
        can=Permissions.get_user_permissions_for_category(category))
Beispiel #24
0
def reset_modules(update, _):
    for i in list(Loader.loaded()):
        Loader.unload(i)
    reply(update, 'All modules unloaded. Loading modules.')
    success = []
    for mod in Permissions.modules():
        try:
            Loader.load(mod)
            success.append(mod)
        except ModuleNotFoundError as err:
            reply(update, str(err))
            logging.warning(str(err))
    if len(success) > 0:
        msg = 'Successfully loaded:' + djoin(success)
        reply(update, msg)
def get_item_by_id(category_id, item_id):
    """
    HTML endpoint providing details for a given item within a category
    """
    category = session.query(Category).filter_by(id=category_id).one()

    item = session.query(Item).filter_by(id=item_id).one()

    return UserUtils.render_user_template(
        'item_read.html',
        category=category,
        category_id=category_id,
        item=item,
        page_title="%s Item" % item.title,
        can=Permissions.get_user_permissions_for_item(item))
Beispiel #26
0
 def __init__(self, name='', permissions=None, store=None, emitter=None):
     self.name = name or 'universe'
     self.prefix = '' if name == 'universe' else name
     self.permissions = permissions or Permissions(
         path='fixtures/permissions.yaml')
     self.store = store or Records()
     self.emitter = emitter
     self.replay_stamp = None
     self.record_maximum_size = 1000000
     self.page_size = 10
     self.routes = []
     self._add_url_rule('/', 'index', self.index)
     self._add_url_rule('/page/<token>', 'page', self.page)
     self._add_url_rule('/', 'post', self.post, methods=['POST'])
     self._add_url_rule('/<id>', 'get', self.get)
     self._add_url_rule('/<id>', 'put', self.put, methods=['PUT'])
     self._add_url_rule('/<id>', 'delete', self.delete, methods=['DELETE'])
def update_category_by_id(category_id):
    """
    HTML endpoint providing a form to edit a category
    """
    if not UserUtils.is_authenticated():
        UserUtils.set_preauthentication_url()
        flash('sign in to edit categories')
        return redirect('/login')

    category = session.query(Category).filter_by(id=category_id).one()

    if not Permissions.get_user_permissions_for_category(category).update:
        flash('you may edit only categories you created')
        return redirect(url_for(
            'get_categories'))

    if request.method == 'POST':
        # Extract and validate the form inputs
        (name, name_error) = \
            extract_and_validate_category_name(request.form)

        if name_error:
            return UserUtils.render_user_template(
                'category_update.html',
                category=category,
                page_title="%s %s Category" % ("Edit", category.name),
                name=name,
                name_error=name_error)

        # Create the item in the data store

        category.name = name
        session.add(category)
        session.commit()

        flash('category updated')

        return redirect(url_for(
            'get_category_by_id',
            category_id=category_id))
    else:
        return UserUtils.render_user_template(
            'category_update.html',
            category=category,
            page_title="%s %s Category" % ("Edit", category.name),
            name=category.name)
Beispiel #28
0
 def load(cls, module):
     assert module not in cls._installed, 'module already loaded'
     assert Permissions.is_protected(module), 'module not authorized'
     # Priority given to earlier dirs
     for dir_ in cls._ordered_dirs:
         try:
             cls._load(module, dir_)
             logging.info('Successfully loaded ' + module)
             # Only one module of this name peritted
             return
         except ModuleNotFoundError:
             pass
         except Exception as err:
             logging.error('Error loading ' + module +
                           traceback.format_exc())
             break
     msg = 'Load("' + module + '") failed'
     raise ModuleNotFoundError(msg)
Beispiel #29
0
def load_module(update, args, *, cmd='load'):
    mod = ''
    try:
        mod = args[0]
        Loader.load(mod)
        reply(update, mod + ' successfully loaded')
        return True
    except (AssertionError, IndexError) as e:
        msg = 'Usage: /module ' + cmd + ' <module>'
        unloaded = [
            i for i in Permissions.modules() if i not in Loader.loaded()
        ]
        msg += '\nUnloaded modules:' + djoin(unloaded)
        reply(update, msg)
        return False
    except ModuleNotFoundError as err:
        logging.error('Failed to load module "' + mod + '" with error: ' +
                      str(err))
        reply(update, 'Failed to load module.')
        raise
Beispiel #30
0
    def _install_handler(cls, module, install_me):
        # Secure the function and ensure dispatch termination when complete
        def packaged_fn(update, context):
            try:
                extra_args = cls._pass[module] if module in cls._pass else None
                install_me(update, context, extra_args)
            except DispatcherHandlerContinue:
                return
            except DispatcherHandlerStop:
                raise
            except Exception as err:
                msg = 'Error invoking ' + module + '.invoke: '
                msg += traceback.format_exc()
                logging.error(msg)
                reply(update, 'Internal error.')
            raise DispatcherHandlerStop()

        cls._pre_protection_fns[module] = packaged_fn
        safe = Permissions.secure_module(module, packaged_fn)
        # Install the handler
        c_handler = CommandHandler(module, safe)
        cls._dp.add_handler(c_handler, cls._g)
        cls._installed[module] = c_handler
class Profile(object):
    """Handles all operations regarding profile. Created new profiles, installs extensions,
    sets preferences and handles cleanup."""
    def __init__(self,
                 profile=None,
                 addons=None,
                 addon_manifests=None,
                 apps=None,
                 preferences=None,
                 locations=None,
                 proxy=None,
                 restore=True):
        """
        :param profile: Path to the profile
        :param addons: String of one or list of addons to install
        :param addon_manifests: Manifest for addons, see http://ahal.ca/blog/2011/bulk-installing-fx-addons/
        :param apps: Dictionary or class of webapps to install
        :param preferences: Dictionary or class of preferences
        :param locations: locations to proxy
        :param proxy: setup a proxy - dict of server-loc,server-port,ssl-port
        :param restore: If true remove all installed addons preferences when cleaning up
        """

        # if true, remove installed addons/prefs afterwards
        self.restore = restore

        # prefs files written to
        self.written_prefs = set()

        # our magic markers
        nonce = '%s %s' % (str(time.time()), uuid.uuid4())
        self.delimeters = ('#MozRunner Prefs Start %s' % nonce,
                           '#MozRunner Prefs End %s' % nonce)

        # Handle profile creation
        self.create_new = not profile
        if profile:
            # Ensure we have a full path to the profile
            self.profile = os.path.abspath(os.path.expanduser(profile))
            if not os.path.exists(self.profile):
                os.makedirs(self.profile)
        else:
            self.profile = self.create_new_profile()

        # set preferences
        if hasattr(self.__class__, 'preferences'):
            # class preferences
            self.set_preferences(self.__class__.preferences)
        self._preferences = preferences
        if preferences:
            # supplied preferences
            if isinstance(preferences, dict):
                # unordered
                preferences = preferences.items()
            # sanity check
            assert not [i for i in preferences if len(i) != 2]
        else:
            preferences = []
        self.set_preferences(preferences)

        # set permissions
        self._locations = locations  # store this for reconstruction
        self._proxy = proxy
        self.permissions = Permissions(self.profile, locations)
        prefs_js, user_js = self.permissions.network_prefs(proxy)
        self.set_preferences(prefs_js, 'prefs.js')
        self.set_preferences(user_js)

        # handle addon installation
        self.addon_manager = AddonManager(self.profile)
        self.addon_manager.install_addons(addons, addon_manifests)

        # handle webapps
        self.webapps = WebappCollection(profile=self.profile, apps=apps)
        self.webapps.update_manifests()

    def exists(self):
        """returns whether the profile exists or not"""
        return os.path.exists(self.profile)

    def reset(self):
        """
        reset the profile to the beginning state
        """
        self.cleanup()
        if self.create_new:
            profile = None
        else:
            profile = self.profile
        self.__init__(profile=profile,
                      addons=self.addon_manager.installed_addons,
                      addon_manifests=self.addon_manager.installed_manifests,
                      preferences=self._preferences,
                      locations=self._locations,
                      proxy=self._proxy)

    @classmethod
    def clone(cls, path_from, path_to=None, **kwargs):
        """Instantiate a temporary profile via cloning
        - path: path of the basis to clone
        - kwargs: arguments to the profile constructor
        """
        if not path_to:
            tempdir = tempfile.mkdtemp()  # need an unused temp dir name
            rmtree(tempdir)  # copytree requires that dest does not exist
            path_to = tempdir
        copytree(path_from, path_to)

        def cleanup_clone(fn):
            """Deletes a cloned profile when restore is True"""
            def wrapped(self):
                fn(self)
                if self.restore and os.path.exists(self.profile):
                    rmtree(self.profile, onerror=self._cleanup_error)

            return wrapped

        c = cls(path_to, **kwargs)
        c.__del__ = c.cleanup = types.MethodType(cleanup_clone(cls.cleanup), c)
        return c

    def create_new_profile(self):
        """Create a new clean temporary profile which is a simple empty folder"""
        return tempfile.mkdtemp(suffix='.mozrunner')

    ### methods for preferences

    def set_preferences(self, preferences, filename='user.js'):
        """Adds preferences dict to profile preferences"""

        # append to the file
        prefs_file = os.path.join(self.profile, filename)
        f = open(prefs_file, 'a')

        if preferences:

            # note what files we've touched
            self.written_prefs.add(filename)

            # opening delimeter
            f.write('\n%s\n' % self.delimeters[0])

            # write the preferences
            Preferences.write(f, preferences)

            # closing delimeter
            f.write('%s\n' % self.delimeters[1])

        f.close()

    def pop_preferences(self, filename):
        """
        pop the last set of preferences added
        returns True if popped
        """

        lines = file(os.path.join(self.profile, filename)).read().splitlines()

        def last_index(_list, value):
            """
            returns the last index of an item;
            this should actually be part of python code but it isn't
            """
            for index in reversed(range(len(_list))):
                if _list[index] == value:
                    return index

        s = last_index(lines, self.delimeters[0])
        e = last_index(lines, self.delimeters[1])

        # ensure both markers are found
        if s is None:
            assert e is None, '%s found without %s' % (self.delimeters[1],
                                                       self.delimeters[0])
            return False  # no preferences found
        elif e is None:
            assert s is None, '%s found without %s' % (self.delimeters[0],
                                                       self.delimeters[1])

        # ensure the markers are in the proper order
        assert e > s, '%s found at %s, while %s found at %s' % (
            self.delimeters[1], e, self.delimeters[0], s)

        # write the prefs
        cleaned_prefs = '\n'.join(lines[:s] + lines[e + 1:])
        f = file(os.path.join(self.profile, 'user.js'), 'w')
        f.write(cleaned_prefs)
        f.close()
        return True

    def clean_preferences(self):
        """Removed preferences added by mozrunner."""
        for filename in self.written_prefs:
            if not os.path.exists(os.path.join(self.profile, filename)):
                # file has been deleted
                break
            while True:
                if not self.pop_preferences(filename):
                    break

    ### cleanup

    def _cleanup_error(self, function, path, excinfo):
        """ Specifically for windows we need to handle the case where the windows
            process has not yet relinquished handles on files, so we do a wait/try
            construct and timeout if we can't get a clear road to deletion
        """

        try:
            from exceptions import WindowsError
            from time import sleep

            def is_file_locked():
                return excinfo[0] is WindowsError and excinfo[1].winerror == 32

            if excinfo[0] is WindowsError and excinfo[1].winerror == 32:
                # Then we're on windows, wait to see if the file gets unlocked
                # we wait 10s
                count = 0
                while count < 10:
                    sleep(1)
                    try:
                        function(path)
                        break
                    except:
                        count += 1
        except ImportError:
            # We can't re-raise an error, so we'll hope the stuff above us will throw
            pass

    def cleanup(self):
        """Cleanup operations for the profile."""
        if self.restore:
            if self.create_new:
                if os.path.exists(self.profile):
                    rmtree(self.profile, onerror=self._cleanup_error)
            else:
                self.clean_preferences()
                self.addon_manager.clean_addons()
                self.permissions.clean_db()
                self.webapps.clean()

    __del__ = cleanup
Beispiel #32
0
class Profile(object):
    """Handles all operations regarding profile. Created new profiles, installs extensions,
    sets preferences and handles cleanup."""

    def __init__(self, profile=None, addons=None, addon_manifests=None,  
                 preferences=None, locations=None, proxy=None, restore=True):
        """
        :param profile: Path to the profile
        :param addons: String of one or list of addons to install
        :param addon_manifests: Manifest for addons, see http://ahal.ca/blog/2011/bulk-installing-fx-addons/
        :param preferences: Dictionary or class of preferences
        :param locations: locations to proxy
        :param proxy: setup a proxy - dict of server-loc,server-port,ssl-port
        :param restore: If true remove all installed addons preferences when cleaning up
        """

        # if true, remove installed addons/prefs afterwards
        self.restore = restore

        # prefs files written to
        self.written_prefs = set()

        # our magic markers
        nonce = '%s %s' % (str(time.time()), uuid.uuid4())
        self.delimeters = ('#MozRunner Prefs Start %s' % nonce,'#MozRunner Prefs End %s' % nonce)

        # Handle profile creation
        self.create_new = not profile
        if profile:
            # Ensure we have a full path to the profile
            self.profile = os.path.abspath(os.path.expanduser(profile))
            if not os.path.exists(self.profile):
                os.makedirs(self.profile)
        else:
            self.profile = self.create_new_profile()

        # set preferences
        if hasattr(self.__class__, 'preferences'):
            # class preferences
            self.set_preferences(self.__class__.preferences)
        self._preferences = preferences
        if preferences:
            # supplied preferences
            if isinstance(preferences, dict):
                # unordered
                preferences = preferences.items()
            # sanity check
            assert not [i for i in preferences
                        if len(i) != 2]
        else:
            preferences = []
        self.set_preferences(preferences)

        # set permissions
        self._locations = locations # store this for reconstruction
        self._proxy = proxy
        self.permissions = Permissions(self.profile, locations)
        prefs_js, user_js = self.permissions.network_prefs(proxy)
        self.set_preferences(prefs_js, 'prefs.js')
        self.set_preferences(user_js)

        # handle addon installation
        self.addon_manager = AddonManager(self.profile)
        self.addon_manager.install_addons(addons, addon_manifests)

    def exists(self):
        """returns whether the profile exists or not"""
        return os.path.exists(self.profile)

    def reset(self):
        """
        reset the profile to the beginning state
        """
        self.cleanup()
        if self.create_new:
            profile = None
        else:
            profile = self.profile
        self.__init__(profile=profile,
                      addons=self.addon_manager.installed_addons,
                      addon_manifests=self.addon_manager.installed_manifests,
                      preferences=self._preferences,
                      locations=self._locations,
                      proxy = self._proxy)

    def create_new_profile(self):
        """Create a new clean profile in tmp which is a simple empty folder"""
        profile = tempfile.mkdtemp(suffix='.mozrunner')
        return profile


    ### methods for preferences

    def set_preferences(self, preferences, filename='user.js'):
        """Adds preferences dict to profile preferences"""

        # append to the file
        prefs_file = os.path.join(self.profile, filename)
        f = open(prefs_file, 'a')

        if preferences:

            # note what files we've touched
            self.written_prefs.add(filename)


            if isinstance(preferences, dict):
                # order doesn't matter
                preferences = preferences.items()

            # write the preferences
            f.write('\n%s\n' % self.delimeters[0])
            _prefs = [(json.dumps(k), json.dumps(v) )
                      for k, v in preferences]
            for _pref in _prefs:
                f.write('user_pref(%s, %s);\n' % _pref)
            f.write('%s\n' % self.delimeters[1])
        f.close()

    def pop_preferences(self, filename):
        """
        pop the last set of preferences added
        returns True if popped
        """

        lines = file(os.path.join(self.profile, filename)).read().splitlines()
        def last_index(_list, value):
            """
            returns the last index of an item;
            this should actually be part of python code but it isn't
            """
            for index in reversed(range(len(_list))):
                if _list[index] == value:
                    return index
        s = last_index(lines, self.delimeters[0])
        e = last_index(lines, self.delimeters[1])

        # ensure both markers are found
        if s is None:
            assert e is None, '%s found without %s' % (self.delimeters[1], self.delimeters[0])
            return False # no preferences found
        elif e is None:
            assert s is None, '%s found without %s' % (self.delimeters[0], self.delimeters[1])

        # ensure the markers are in the proper order
        assert e > s, '%s found at %s, while %s found at %s' % (self.delimeters[1], e, self.delimeters[0], s)

        # write the prefs
        cleaned_prefs = '\n'.join(lines[:s] + lines[e+1:])
        f = file(os.path.join(self.profile, 'user.js'), 'w')
        f.write(cleaned_prefs)
        f.close()
        return True

    def clean_preferences(self):
        """Removed preferences added by mozrunner."""
        for filename in self.written_prefs:
            if not os.path.exists(os.path.join(self.profile, filename)):
                # file has been deleted
                break
            while True:
                if not self.pop_preferences(filename):
                    break

    ### cleanup

    def _cleanup_error(self, function, path, excinfo):
        """ Specifically for windows we need to handle the case where the windows
            process has not yet relinquished handles on files, so we do a wait/try
            construct and timeout if we can't get a clear road to deletion
        """

        try:
            from exceptions import WindowsError
            from time import sleep
            def is_file_locked():
                return excinfo[0] is WindowsError and excinfo[1].winerror == 32

            if excinfo[0] is WindowsError and excinfo[1].winerror == 32:
                # Then we're on windows, wait to see if the file gets unlocked
                # we wait 10s
                count = 0
                while count < 10:
                    sleep(1)
                    try:
                        function(path)
                        break
                    except:
                        count += 1
        except ImportError:
            # We can't re-raise an error, so we'll hope the stuff above us will throw
            pass

    def cleanup(self):
        """Cleanup operations for the profile."""
        if self.restore:
            if self.create_new:
                if os.path.exists(self.profile):
                    rmtree(self.profile, onerror=self._cleanup_error)
            else:
                self.clean_preferences()
                self.addon_manager.clean_addons()
                self.permissions.clean_db()

    __del__ = cleanup
Beispiel #33
0
class Profile(object):
    """Handles all operations regarding profile.

    Creating new profiles, installing add-ons, setting preferences and
    handling cleanup.
    """
    def __init__(self,
                 profile=None,
                 addons=None,
                 addon_manifests=None,
                 apps=None,
                 preferences=None,
                 locations=None,
                 proxy=None,
                 restore=True):
        """
        :param profile: Path to the profile
        :param addons: String of one or list of addons to install
        :param addon_manifests: Manifest for addons (see http://bit.ly/17jQ7i6)
        :param apps: Dictionary or class of webapps to install
        :param preferences: Dictionary or class of preferences
        :param locations: ServerLocations object
        :param proxy: Setup a proxy
        :param restore: Flag for removing all custom settings during cleanup
        """
        self._addons = addons
        self._addon_manifests = addon_manifests
        self._apps = apps
        self._locations = locations
        self._proxy = proxy

        # Prepare additional preferences
        if preferences:
            if isinstance(preferences, dict):
                # unordered
                preferences = preferences.items()

            # sanity check
            assert not [i for i in preferences if len(i) != 2]
        else:
            preferences = []
        self._preferences = preferences

        # Handle profile creation
        self.create_new = not profile
        if profile:
            # Ensure we have a full path to the profile
            self.profile = os.path.abspath(os.path.expanduser(profile))
        else:
            self.profile = tempfile.mkdtemp(suffix='.mozrunner')

        self.restore = restore

        # Initialize all class members
        self._internal_init()

    def _internal_init(self):
        """Internal: Initialize all class members to their default value"""

        if not os.path.exists(self.profile):
            os.makedirs(self.profile)

        # Preferences files written to
        self.written_prefs = set()

        # Our magic markers
        nonce = '%s %s' % (str(time.time()), uuid.uuid4())
        self.delimeters = ('#MozRunner Prefs Start %s' % nonce,
                           '#MozRunner Prefs End %s' % nonce)

        # If sub-classes want to set default preferences
        if hasattr(self.__class__, 'preferences'):
            self.set_preferences(self.__class__.preferences)
        # Set additional preferences
        self.set_preferences(self._preferences)

        self.permissions = Permissions(self.profile, self._locations)
        prefs_js, user_js = self.permissions.network_prefs(self._proxy)
        self.set_preferences(prefs_js, 'prefs.js')
        self.set_preferences(user_js)

        # handle add-on installation
        self.addon_manager = AddonManager(self.profile, restore=self.restore)
        self.addon_manager.install_addons(self._addons, self._addon_manifests)

        # handle webapps
        self.webapps = WebappCollection(profile=self.profile, apps=self._apps)
        self.webapps.update_manifests()

    def __del__(self):
        self.cleanup()

    ### cleanup

    def cleanup(self):
        """Cleanup operations for the profile."""

        if self.restore:
            # If copies of those class instances exist ensure we correctly
            # reset them all (see bug 934484)
            self.clean_preferences()
            if getattr(self, 'addon_manager', None) is not None:
                self.addon_manager.clean()
            if getattr(self, 'permissions', None) is not None:
                self.permissions.clean_db()
            if getattr(self, 'webapps', None) is not None:
                self.webapps.clean()

            # If it's a temporary profile we have to remove it
            if self.create_new:
                mozfile.remove(self.profile)

    def reset(self):
        """
        reset the profile to the beginning state
        """
        self.cleanup()

        self._internal_init()

    def clean_preferences(self):
        """Removed preferences added by mozrunner."""
        for filename in self.written_prefs:
            if not os.path.exists(os.path.join(self.profile, filename)):
                # file has been deleted
                break
            while True:
                if not self.pop_preferences(filename):
                    break

    @classmethod
    def clone(cls, path_from, path_to=None, **kwargs):
        """Instantiate a temporary profile via cloning
        - path: path of the basis to clone
        - kwargs: arguments to the profile constructor
        """
        if not path_to:
            tempdir = tempfile.mkdtemp()  # need an unused temp dir name
            mozfile.remove(
                tempdir)  # copytree requires that dest does not exist
            path_to = tempdir
        copytree(path_from, path_to)

        def cleanup_clone(fn):
            """Deletes a cloned profile when restore is True"""
            def wrapped(self):
                fn(self)
                if self.restore and os.path.exists(self.profile):
                    mozfile.remove(self.profile)

            return wrapped

        c = cls(path_to, **kwargs)
        c.__del__ = c.cleanup = types.MethodType(cleanup_clone(cls.cleanup), c)
        return c

    def exists(self):
        """returns whether the profile exists or not"""
        return os.path.exists(self.profile)

    ### methods for preferences

    def set_preferences(self, preferences, filename='user.js'):
        """Adds preferences dict to profile preferences"""

        # append to the file
        prefs_file = os.path.join(self.profile, filename)
        f = open(prefs_file, 'a')

        if preferences:

            # note what files we've touched
            self.written_prefs.add(filename)

            # opening delimeter
            f.write('\n%s\n' % self.delimeters[0])

            # write the preferences
            Preferences.write(f, preferences)

            # closing delimeter
            f.write('%s\n' % self.delimeters[1])

        f.close()

    def set_persistent_preferences(self, preferences):
        """
        Adds preferences dict to profile preferences and save them during a
        profile reset
        """

        # this is a dict sometimes, convert
        if isinstance(preferences, dict):
            preferences = preferences.items()

        # add new prefs to preserve them during reset
        for new_pref in preferences:
            # if dupe remove item from original list
            self._preferences = [
                pref for pref in self._preferences
                if not new_pref[0] == pref[0]
            ]
            self._preferences.append(new_pref)

        self.set_preferences(preferences, filename='user.js')

    def pop_preferences(self, filename):
        """
        pop the last set of preferences added
        returns True if popped
        """

        path = os.path.join(self.profile, filename)
        with file(path) as f:
            lines = f.read().splitlines()

        def last_index(_list, value):
            """
            returns the last index of an item;
            this should actually be part of python code but it isn't
            """
            for index in reversed(range(len(_list))):
                if _list[index] == value:
                    return index

        s = last_index(lines, self.delimeters[0])
        e = last_index(lines, self.delimeters[1])

        # ensure both markers are found
        if s is None:
            assert e is None, '%s found without %s' % (self.delimeters[1],
                                                       self.delimeters[0])
            return False  # no preferences found
        elif e is None:
            assert s is None, '%s found without %s' % (self.delimeters[0],
                                                       self.delimeters[1])

        # ensure the markers are in the proper order
        assert e > s, '%s found at %s, while %s found at %s' % (
            self.delimeters[1], e, self.delimeters[0], s)

        # write the prefs
        cleaned_prefs = '\n'.join(lines[:s] + lines[e + 1:])
        with file(path, 'w') as f:
            f.write(cleaned_prefs)
        return True

    ### methods for introspection

    def summary(self, return_parts=False):
        """
        returns string summarizing profile information.
        if return_parts is true, return the (Part_name, value) list
        of tuples instead of the assembled string
        """

        parts = [('Path', self.profile)]  # profile path

        # directory tree
        parts.append(('Files', '\n%s' % mozfile.tree(self.profile)))

        # preferences
        for prefs_file in ('user.js', 'prefs.js'):
            path = os.path.join(self.profile, prefs_file)
            if os.path.exists(path):

                # prefs that get their own section
                # This is currently only 'network.proxy.autoconfig_url'
                # but could be expanded to include others
                section_prefs = ['network.proxy.autoconfig_url']
                line_length = 80
                line_length_buffer = 10  # buffer for 80 character display: length = 80 - len(key) - len(': ') - line_length_buffer
                line_length_buffer += len(': ')

                def format_value(key, value):
                    if key not in section_prefs:
                        return value
                    max_length = line_length - len(key) - line_length_buffer
                    if len(value) > max_length:
                        value = '%s...' % value[:max_length]
                    return value

                prefs = Preferences.read_prefs(path)
                if prefs:
                    prefs = dict(prefs)
                    parts.append((prefs_file, '\n%s' % ('\n'.join([
                        '%s: %s' % (key, format_value(key, prefs[key]))
                        for key in sorted(prefs.keys())
                    ]))))

                    # Currently hardcorded to 'network.proxy.autoconfig_url'
                    # but could be generalized, possibly with a generalized (simple)
                    # JS-parser
                    network_proxy_autoconfig = prefs.get(
                        'network.proxy.autoconfig_url')
                    if network_proxy_autoconfig and network_proxy_autoconfig.strip(
                    ):
                        network_proxy_autoconfig = network_proxy_autoconfig.strip(
                        )
                        lines = network_proxy_autoconfig.replace(
                            ';', ';\n').splitlines()
                        lines = [line.strip() for line in lines]
                        origins_string = 'var origins = ['
                        origins_end = '];'
                        if origins_string in lines[0]:
                            start = lines[0].find(origins_string)
                            end = lines[0].find(origins_end, start)
                            splitline = [
                                lines[0][:start],
                                lines[0][start:start + len(origins_string) -
                                         1],
                            ]
                            splitline.extend(
                                lines[0][start +
                                         len(origins_string):end].replace(
                                             ',', ',\n').splitlines())
                            splitline.append(lines[0][end:])
                            lines[0:1] = [i.strip() for i in splitline]
                        parts.append(
                            ('Network Proxy Autoconfig, %s' % (prefs_file),
                             '\n%s' % '\n'.join(lines)))

        if return_parts:
            return parts

        retval = '%s\n' % ('\n\n'.join(
            ['[%s]: %s' % (key, value) for key, value in parts]))
        return retval

    __str__ = summary
def test_load_file():
    store = Permissions()
    store.load(open('fixtures/permissions.yaml', 'r'))

    assert store.authorize('access-content', 'x', 'universe') is False
    assert store.authorize('access-content', 'x', 'community') is False
    assert store.authorize('access-content', 'x', 'board') is False
    assert store.authorize('access-content', 'leader', 'universe') is True
    assert store.authorize('access-content', 'leader', 'community') is True
    assert store.authorize('access-content', 'leader', 'board') is True

    assert store.authorize('manage-content', 'member', 'universe') is False
    assert store.authorize('manage-content', 'member', 'community') is False
    assert store.authorize('manage-content', 'member', 'board') is False
    assert store.authorize('manage-content', 'leader', 'universe') is True
    assert store.authorize('manage-content', 'leader', 'community') is True
    assert store.authorize('manage-content', 'leader', 'board') is True

    assert store.authorize('manage-identities', 'leader', 'member') is False
    assert store.authorize('manage-identities', 'leader', 'leader') is False
    assert store.authorize('manage-identities', 'leader', 'support') is False
    assert store.authorize('manage-identities', 'leader', 'robot') is False
    assert store.authorize('manage-identities', 'support', 'member') is True
    assert store.authorize('manage-identities', 'support', 'leader') is True
    assert store.authorize('manage-identities', 'support', 'support') is False
    assert store.authorize('manage-identities', 'support', 'robot') is True

    assert store.authorize('manage-identities', 'leader',
                           'update-any-to-registered') is True
    assert store.authorize('manage-identities', 'leader',
                           'update-any-to-leader') is True
    assert store.authorize('manage-identities', 'leader',
                           'update-any-to-support') is False
    assert store.authorize('manage-identities', 'leader',
                           'update-any- to-robot') is False
def test_init():
    permissions = Permissions()
    assert permissions.count() == 0
def test_grant_all():
    scopes = ['alpha', 'beta', 'gamma']
    items = [
        dict(topic='with_list', personas=['a', 'b', 'c']),
        dict(topic='with_item', persona='a'),
    ]

    permissions = Permissions(authorized_scopes=scopes)

    for scope in scopes:  # nothing is authorized
        assert permissions.authorize(scope, 'a', 'with_list') is False
        assert permissions.authorize(scope, 'b', 'with_list') is False
        assert permissions.authorize(scope, 'c', 'with_list') is False
        assert permissions.authorize(scope, 'x', 'with_list') is False
        assert permissions.authorize(scope, 'a', 'with_item') is False
        assert permissions.authorize(scope, 'x', 'with_item') is False

    for scope in scopes:  # set permissions
        permissions.grant_all(scope, items)

    for scope in scopes:  # some actions are authorized
        assert permissions.authorize(scope, 'a', 'with_list') is True
        assert permissions.authorize(scope, 'b', 'with_list') is True
        assert permissions.authorize(scope, 'c', 'with_list') is True
        assert permissions.authorize(scope, 'x', 'with_list') is False
        assert permissions.authorize(scope, 'a', 'with_item') is True
        assert permissions.authorize(scope, 'x', 'with_item') is False

    with py_raises(ValueError) as error:
        permissions.grant_all(scope='*alien*', items=items)
Beispiel #37
0
class BotState(object):
  def __init__(self, bot):
    self.bot = bot
    self.channels_by_id = {}
    self.users_by_session = {}
    self.users_by_id = {}
    self.root = None
    self.permissions = None
    # The user object representing the bot.
    self.user = None
    # The current channel the bot is in.
    self.channel = None

  def get_actor(self, session_id):
    if not session_id in self.users_by_session:
      LOGGER.warning('Invalid session ID: %d.' % session_id)
      return None
    else:
      return self.users_by_session[session_id]

  def get_channel(self, chan_id):
    if not chan_id in self.channels_by_id:
      LOGGER.warning('Invalid Channel ID: %d.' % chan_id)
      return None
    else:
      return self.channels_by_id[chan_id]

  def on_version(self, msg):
    self.version = msg.version
    self.release = msg.release
    self.os = msg.os
    self.os_version = msg.os_version

  def on_voice_ping(self, session_id):
    self.bot.on_voice_ping(session_id)

  def on_voice_talk(self, from_id, sequence, data):
    self.bot.on_voice_talk(self.get_actor(from_id), sequence, data)

  def on_voice_whisper_chan(self, from_id, sequence, data):
    pass

  def on_voice_whisper_self(self, from_id, sequence, data):
    pass

  def on_pingback(self, ping_msec, msg):
    self.ping = ping_msec
    self.packet_stats = (msg.good, msg.late, msg.lost)
    self.udp_stats = (msg.udp_packets, msg.udp_ping_avg, msg.udp_ping_var)

  def on_reject(self, msg):
    self.rejected = True
    self.reject_type = msg.type
    self.reject_reason = msg.reason
    self.bot.rejected()

  def on_server_config(self, msg):
    self.welcome_text = msg.welcome_text
    self.allow_html = msg.allow_html

  def on_server_sync(self, msg):
    self.max_bandwidth = msg.max_bandwidth
    self.welcome_text = msg.welcome_text
    if msg.permissions:
      if not self.permissions:
        self.permissions = Permissions(msg.permissions)
      else:
        self.permissions.update(msg.permissions)
    self.bot.connected()

  def on_channel_state(self, msg):
    if msg.channel_id not in self.channels_by_id:
      chan = Channel(self.bot, msg.channel_id)
      self.channels_by_id[msg.channel_id] = chan
    else:
      chan = self.channels_by_id[msg.channel_id]
    chan.update(msg)

    if msg.parent == msg.channel_id:
      if not msg.channel_id == 0:
        LOGGER.warning('Root channel not ID 0.')
      if self.root and self.root != chan:
        LOGGER.error('Received 2 different roots...?')
        raise Exception('Two roots.')
      self.root = chan
    elif chan.parent:
      if chan.parent.id != msg.parent:
        chan.parent.remove_child(chan)
        self.channels_by_id[msg.parent].add_child(chan)
    else:
      if not msg.parent in self.channels_by_id:
        LOGGER.error('Parent ID passed by server is not in the channel list.')
        raise Exception('Invalid Parent.')
      self.channels_by_id[msg.parent].add_child(chan)

  def on_user_state(self, msg):
    if msg.session not in self.users_by_session:
      user = User(self.bot, msg.session)
      self.users_by_session[msg.session] = user
      if msg.user_id is not None:
        self.users_by_id[msg.user_id] = user
    else:
      user = self.users_by_session[msg.session]
    user.update(msg)
    if self.user is None:
      self.user = user

  def on_text_message(self, msg):
    self.bot.on_text_message(from_user = self.get_actor(msg.actor),
                             to_users = [self.get_actor(x)
                                 for x in msg.session],
                             to_channels = [self.get_channel(x)
                                 for x in msg.channel_id],
                             tree_ids = msg.tree_id,
                             message = "%s" % msg.message)

  def on_crypt_setup(self, msg):
    pass

  def on_user_stats(self, msg):
    assert msg.session in self.users_by_session
    self.users_by_session[msg.session].update_stats(msg)

  def on_unknown(self, type, msg):
    LOGGER.warning("Unknown message received: type(%s), '%s'" % (type, msg))
Beispiel #38
0
class Profile(object):
    """Handles all operations regarding profile.

    Creating new profiles, installing add-ons, setting preferences and
    handling cleanup.

    The files associated with the profile will be removed automatically after
    the object is garbage collected: ::

      profile = Profile()
      print profile.profile  # this is the path to the created profile
      del profile
      # the profile path has been removed from disk

    :meth:`cleanup` is called under the hood to remove the profile files. You
    can ensure this method is called (even in the case of exception) by using
    the profile as a context manager: ::

      with Profile() as profile:
          # do things with the profile
          pass
      # profile.cleanup() has been called here
    """

    def __init__(self, profile=None, addons=None, addon_manifests=None,
                 preferences=None, locations=None, proxy=None, restore=True):
        """
        :param profile: Path to the profile
        :param addons: String of one or list of addons to install
        :param addon_manifests: Manifest for addons (see http://bit.ly/17jQ7i6)
        :param preferences: Dictionary or class of preferences
        :param locations: ServerLocations object
        :param proxy: Setup a proxy
        :param restore: Flag for removing all custom settings during cleanup
        """
        self._addons = addons
        self._addon_manifests = addon_manifests
        self._locations = locations
        self._proxy = proxy

        # Prepare additional preferences
        if preferences:
            if isinstance(preferences, dict):
                # unordered
                preferences = preferences.items()

            # sanity check
            assert not [i for i in preferences if len(i) != 2]
        else:
            preferences = []
        self._preferences = preferences

        # Handle profile creation
        self.create_new = not profile
        if profile:
            # Ensure we have a full path to the profile
            self.profile = os.path.abspath(os.path.expanduser(profile))
        else:
            self.profile = tempfile.mkdtemp(suffix='.mozrunner')

        self.restore = restore

        # Initialize all class members
        self._internal_init()

    def _internal_init(self):
        """Internal: Initialize all class members to their default value"""

        if not os.path.exists(self.profile):
            os.makedirs(self.profile)

        # Preferences files written to
        self.written_prefs = set()

        # Our magic markers
        nonce = '%s %s' % (str(time.time()), uuid.uuid4())
        self.delimeters = ('#MozRunner Prefs Start %s' % nonce,
                           '#MozRunner Prefs End %s' % nonce)

        # If sub-classes want to set default preferences
        if hasattr(self.__class__, 'preferences'):
            self.set_preferences(self.__class__.preferences)
        # Set additional preferences
        self.set_preferences(self._preferences)

        self.permissions = Permissions(self.profile, self._locations)
        prefs_js, user_js = self.permissions.network_prefs(self._proxy)
        self.set_preferences(prefs_js, 'prefs.js')
        self.set_preferences(user_js)

        # handle add-on installation
        self.addon_manager = AddonManager(self.profile, restore=self.restore)
        self.addon_manager.install_addons(self._addons, self._addon_manifests)

    def __enter__(self):
        return self

    def __exit__(self, type, value, traceback):
        self.cleanup()

    def __del__(self):
        self.cleanup()

    # cleanup

    def cleanup(self):
        """Cleanup operations for the profile."""

        if self.restore:
            # If copies of those class instances exist ensure we correctly
            # reset them all (see bug 934484)
            self.clean_preferences()
            if getattr(self, 'addon_manager', None) is not None:
                self.addon_manager.clean()
            if getattr(self, 'permissions', None) is not None:
                self.permissions.clean_db()

            # If it's a temporary profile we have to remove it
            if self.create_new:
                mozfile.remove(self.profile)

    def reset(self):
        """
        reset the profile to the beginning state
        """
        self.cleanup()

        self._internal_init()

    def clean_preferences(self):
        """Removed preferences added by mozrunner."""
        for filename in self.written_prefs:
            if not os.path.exists(os.path.join(self.profile, filename)):
                # file has been deleted
                break
            while True:
                if not self.pop_preferences(filename):
                    break

    @classmethod
    def clone(cls, path_from, path_to=None, **kwargs):
        """Instantiate a temporary profile via cloning
        - path: path of the basis to clone
        - kwargs: arguments to the profile constructor
        """
        if not path_to:
            tempdir = tempfile.mkdtemp()  # need an unused temp dir name
            mozfile.remove(tempdir)  # copytree requires that dest does not exist
            path_to = tempdir
        copytree(path_from, path_to)

        c = cls(path_to, **kwargs)
        c.create_new = True  # deletes a cloned profile when restore is True
        return c

    def exists(self):
        """returns whether the profile exists or not"""
        return os.path.exists(self.profile)

    # methods for preferences

    def set_preferences(self, preferences, filename='user.js'):
        """Adds preferences dict to profile preferences"""

        # append to the file
        prefs_file = os.path.join(self.profile, filename)
        f = open(prefs_file, 'a')

        if preferences:

            # note what files we've touched
            self.written_prefs.add(filename)

            # opening delimeter
            f.write('\n%s\n' % self.delimeters[0])

            # write the preferences
            Preferences.write(f, preferences)

            # closing delimeter
            f.write('%s\n' % self.delimeters[1])

        f.close()

    def set_persistent_preferences(self, preferences):
        """
        Adds preferences dict to profile preferences and save them during a
        profile reset
        """

        # this is a dict sometimes, convert
        if isinstance(preferences, dict):
            preferences = preferences.items()

        # add new prefs to preserve them during reset
        for new_pref in preferences:
            # if dupe remove item from original list
            self._preferences = [
                pref for pref in self._preferences if not new_pref[0] == pref[0]]
            self._preferences.append(new_pref)

        self.set_preferences(preferences, filename='user.js')

    def pop_preferences(self, filename):
        """
        pop the last set of preferences added
        returns True if popped
        """

        path = os.path.join(self.profile, filename)
        with file(path) as f:
            lines = f.read().splitlines()

        def last_index(_list, value):
            """
            returns the last index of an item;
            this should actually be part of python code but it isn't
            """
            for index in reversed(range(len(_list))):
                if _list[index] == value:
                    return index
        s = last_index(lines, self.delimeters[0])
        e = last_index(lines, self.delimeters[1])

        # ensure both markers are found
        if s is None:
            assert e is None, '%s found without %s' % (self.delimeters[1], self.delimeters[0])
            return False  # no preferences found
        elif e is None:
            assert s is None, '%s found without %s' % (self.delimeters[0], self.delimeters[1])

        # ensure the markers are in the proper order
        assert e > s, '%s found at %s, while %s found at %s' % (self.delimeters[1], e,
                                                                self.delimeters[0], s)

        # write the prefs
        cleaned_prefs = '\n'.join(lines[:s] + lines[e + 1:])
        with file(path, 'w') as f:
            f.write(cleaned_prefs)
        return True

    # methods for introspection

    def summary(self, return_parts=False):
        """
        returns string summarizing profile information.
        if return_parts is true, return the (Part_name, value) list
        of tuples instead of the assembled string
        """

        parts = [('Path', self.profile)]  # profile path

        # directory tree
        parts.append(('Files', '\n%s' % mozfile.tree(self.profile)))

        # preferences
        for prefs_file in ('user.js', 'prefs.js'):
            path = os.path.join(self.profile, prefs_file)
            if os.path.exists(path):

                # prefs that get their own section
                # This is currently only 'network.proxy.autoconfig_url'
                # but could be expanded to include others
                section_prefs = ['network.proxy.autoconfig_url']
                line_length = 80
                # buffer for 80 character display:
                # length = 80 - len(key) - len(': ') - line_length_buffer
                line_length_buffer = 10
                line_length_buffer += len(': ')

                def format_value(key, value):
                    if key not in section_prefs:
                        return value
                    max_length = line_length - len(key) - line_length_buffer
                    if len(value) > max_length:
                        value = '%s...' % value[:max_length]
                    return value

                prefs = Preferences.read_prefs(path)
                if prefs:
                    prefs = dict(prefs)
                    parts.append((prefs_file,
                                  '\n%s' % ('\n'.join(
                                      ['%s: %s' % (key, format_value(key, prefs[key]))
                                       for key in sorted(prefs.keys())]))))

                    # Currently hardcorded to 'network.proxy.autoconfig_url'
                    # but could be generalized, possibly with a generalized (simple)
                    # JS-parser
                    network_proxy_autoconfig = prefs.get('network.proxy.autoconfig_url')
                    if network_proxy_autoconfig and network_proxy_autoconfig.strip():
                        network_proxy_autoconfig = network_proxy_autoconfig.strip()
                        lines = network_proxy_autoconfig.replace(';', ';\n').splitlines()
                        lines = [line.strip() for line in lines]
                        origins_string = 'var origins = ['
                        origins_end = '];'
                        if origins_string in lines[0]:
                            start = lines[0].find(origins_string)
                            end = lines[0].find(origins_end, start)
                            splitline = [lines[0][:start],
                                         lines[0][start:start + len(origins_string) - 1],
                                         ]
                            splitline.extend(lines[0][start + len(origins_string):end].replace(
                                ',', ',\n').splitlines())
                            splitline.append(lines[0][end:])
                            lines[0:1] = [i.strip() for i in splitline]
                        parts.append(('Network Proxy Autoconfig, %s' % (prefs_file),
                                      '\n%s' % '\n'.join(lines)))

        if return_parts:
            return parts

        retval = '%s\n' % ('\n\n'.join(['[%s]: %s' % (key, value)
                                        for key, value in parts]))
        return retval

    __str__ = summary
Beispiel #39
0
class Profile(object):
    """Handles all operations regarding profile.

    Creating new profiles, installing add-ons, setting preferences and
    handling cleanup.
    """

    def __init__(
        self,
        profile=None,
        addons=None,
        addon_manifests=None,
        apps=None,
        preferences=None,
        locations=None,
        proxy=None,
        restore=True,
    ):
        """
        :param profile: Path to the profile
        :param addons: String of one or list of addons to install
        :param addon_manifests: Manifest for addons (see http://bit.ly/17jQ7i6)
        :param apps: Dictionary or class of webapps to install
        :param preferences: Dictionary or class of preferences
        :param locations: ServerLocations object
        :param proxy: Setup a proxy
        :param restore: Flag for removing all custom settings during cleanup
        """
        self._addons = addons
        self._addon_manifests = addon_manifests
        self._apps = apps
        self._locations = locations
        self._proxy = proxy

        # Prepare additional preferences
        if preferences:
            if isinstance(preferences, dict):
                # unordered
                preferences = preferences.items()

            # sanity check
            assert not [i for i in preferences if len(i) != 2]
        else:
            preferences = []
        self._preferences = preferences

        # Handle profile creation
        self.create_new = not profile
        if profile:
            # Ensure we have a full path to the profile
            self.profile = os.path.abspath(os.path.expanduser(profile))
        else:
            self.profile = tempfile.mkdtemp(suffix=".mozrunner")

        self.restore = restore

        # Initialize all class members
        self._internal_init()

    def _internal_init(self):
        """Internal: Initialize all class members to their default value"""

        if not os.path.exists(self.profile):
            os.makedirs(self.profile)

        # Preferences files written to
        self.written_prefs = set()

        # Our magic markers
        nonce = "%s %s" % (str(time.time()), uuid.uuid4())
        self.delimeters = ("#MozRunner Prefs Start %s" % nonce, "#MozRunner Prefs End %s" % nonce)

        # If sub-classes want to set default preferences
        if hasattr(self.__class__, "preferences"):
            self.set_preferences(self.__class__.preferences)
        # Set additional preferences
        self.set_preferences(self._preferences)

        self.permissions = Permissions(self.profile, self._locations)
        prefs_js, user_js = self.permissions.network_prefs(self._proxy)
        self.set_preferences(prefs_js, "prefs.js")
        self.set_preferences(user_js)

        # handle add-on installation
        self.addon_manager = AddonManager(self.profile, restore=self.restore)
        self.addon_manager.install_addons(self._addons, self._addon_manifests)

        # handle webapps
        self.webapps = WebappCollection(profile=self.profile, apps=self._apps)
        self.webapps.update_manifests()

    def __del__(self):
        self.cleanup()

    ### cleanup

    def cleanup(self):
        """Cleanup operations for the profile."""

        if self.restore:
            # If copies of those class instances exist ensure we correctly
            # reset them all (see bug 934484)
            self.clean_preferences()
            if getattr(self, "addon_manager", None) is not None:
                self.addon_manager.clean()
            if getattr(self, "permissions", None) is not None:
                self.permissions.clean_db()
            if getattr(self, "webapps", None) is not None:
                self.webapps.clean()

            # If it's a temporary profile we have to remove it
            if self.create_new:
                mozfile.remove(self.profile)

    def reset(self):
        """
        reset the profile to the beginning state
        """
        self.cleanup()

        self._internal_init()

    def clean_preferences(self):
        """Removed preferences added by mozrunner."""
        for filename in self.written_prefs:
            if not os.path.exists(os.path.join(self.profile, filename)):
                # file has been deleted
                break
            while True:
                if not self.pop_preferences(filename):
                    break

    @classmethod
    def clone(cls, path_from, path_to=None, **kwargs):
        """Instantiate a temporary profile via cloning
        - path: path of the basis to clone
        - kwargs: arguments to the profile constructor
        """
        if not path_to:
            tempdir = tempfile.mkdtemp()  # need an unused temp dir name
            mozfile.remove(tempdir)  # copytree requires that dest does not exist
            path_to = tempdir
        copytree(path_from, path_to)

        def cleanup_clone(fn):
            """Deletes a cloned profile when restore is True"""

            def wrapped(self):
                fn(self)
                if self.restore and os.path.exists(self.profile):
                    mozfile.remove(self.profile)

            return wrapped

        c = cls(path_to, **kwargs)
        c.__del__ = c.cleanup = types.MethodType(cleanup_clone(cls.cleanup), c)
        return c

    def exists(self):
        """returns whether the profile exists or not"""
        return os.path.exists(self.profile)

    ### methods for preferences

    def set_preferences(self, preferences, filename="user.js"):
        """Adds preferences dict to profile preferences"""

        # append to the file
        prefs_file = os.path.join(self.profile, filename)
        f = open(prefs_file, "a")

        if preferences:

            # note what files we've touched
            self.written_prefs.add(filename)

            # opening delimeter
            f.write("\n%s\n" % self.delimeters[0])

            # write the preferences
            Preferences.write(f, preferences)

            # closing delimeter
            f.write("%s\n" % self.delimeters[1])

        f.close()

    def pop_preferences(self, filename):
        """
        pop the last set of preferences added
        returns True if popped
        """

        path = os.path.join(self.profile, filename)
        with file(path) as f:
            lines = f.read().splitlines()

        def last_index(_list, value):
            """
            returns the last index of an item;
            this should actually be part of python code but it isn't
            """
            for index in reversed(range(len(_list))):
                if _list[index] == value:
                    return index

        s = last_index(lines, self.delimeters[0])
        e = last_index(lines, self.delimeters[1])

        # ensure both markers are found
        if s is None:
            assert e is None, "%s found without %s" % (self.delimeters[1], self.delimeters[0])
            return False  # no preferences found
        elif e is None:
            assert s is None, "%s found without %s" % (self.delimeters[0], self.delimeters[1])

        # ensure the markers are in the proper order
        assert e > s, "%s found at %s, while %s found at %s" % (self.delimeters[1], e, self.delimeters[0], s)

        # write the prefs
        cleaned_prefs = "\n".join(lines[:s] + lines[e + 1 :])
        with file(path, "w") as f:
            f.write(cleaned_prefs)
        return True

    ### methods for introspection

    def summary(self, return_parts=False):
        """
        returns string summarizing profile information.
        if return_parts is true, return the (Part_name, value) list
        of tuples instead of the assembled string
        """

        parts = [("Path", self.profile)]  # profile path

        # directory tree
        parts.append(("Files", "\n%s" % mozfile.tree(self.profile)))

        # preferences
        for prefs_file in ("user.js", "prefs.js"):
            path = os.path.join(self.profile, prefs_file)
            if os.path.exists(path):

                # prefs that get their own section
                # This is currently only 'network.proxy.autoconfig_url'
                # but could be expanded to include others
                section_prefs = ["network.proxy.autoconfig_url"]
                line_length = 80
                line_length_buffer = (
                    10
                )  # buffer for 80 character display: length = 80 - len(key) - len(': ') - line_length_buffer
                line_length_buffer += len(": ")

                def format_value(key, value):
                    if key not in section_prefs:
                        return value
                    max_length = line_length - len(key) - line_length_buffer
                    if len(value) > max_length:
                        value = "%s..." % value[:max_length]
                    return value

                prefs = Preferences.read_prefs(path)
                if prefs:
                    prefs = dict(prefs)
                    parts.append(
                        (
                            prefs_file,
                            "\n%s"
                            % (
                                "\n".join(
                                    ["%s: %s" % (key, format_value(key, prefs[key])) for key in sorted(prefs.keys())]
                                )
                            ),
                        )
                    )

                    # Currently hardcorded to 'network.proxy.autoconfig_url'
                    # but could be generalized, possibly with a generalized (simple)
                    # JS-parser
                    network_proxy_autoconfig = prefs.get("network.proxy.autoconfig_url")
                    if network_proxy_autoconfig and network_proxy_autoconfig.strip():
                        network_proxy_autoconfig = network_proxy_autoconfig.strip()
                        lines = network_proxy_autoconfig.replace(";", ";\n").splitlines()
                        lines = [line.strip() for line in lines]
                        origins_string = "var origins = ["
                        origins_end = "];"
                        if origins_string in lines[0]:
                            start = lines[0].find(origins_string)
                            end = lines[0].find(origins_end, start)
                            splitline = [lines[0][:start], lines[0][start : start + len(origins_string) - 1]]
                            splitline.extend(
                                lines[0][start + len(origins_string) : end].replace(",", ",\n").splitlines()
                            )
                            splitline.append(lines[0][end:])
                            lines[0:1] = [i.strip() for i in splitline]
                        parts.append(("Network Proxy Autoconfig, %s" % (prefs_file), "\n%s" % "\n".join(lines)))

        if return_parts:
            return parts

        retval = "%s\n" % ("\n\n".join(["[%s]: %s" % (key, value) for key, value in parts]))
        return retval

    __str__ = summary
Beispiel #40
0
class Profile(object):
    """Handles all operations regarding profile.

    Creating new profiles, installing add-ons, setting preferences and
    handling cleanup.
    """

    def __init__(self, profile=None, addons=None, addon_manifests=None, apps=None,
                 preferences=None, locations=None, proxy=None, restore=True):
        """
        :param profile: Path to the profile
        :param addons: String of one or list of addons to install
        :param addon_manifests: Manifest for addons (see http://bit.ly/17jQ7i6)
        :param apps: Dictionary or class of webapps to install
        :param preferences: Dictionary or class of preferences
        :param locations: ServerLocations object
        :param proxy: Setup a proxy
        :param restore: Flag for removing all custom settings during cleanup
        """
        self._addons = addons
        self._addon_manifests = addon_manifests
        self._apps = apps
        self._locations = locations
        self._proxy = proxy

        # Prepare additional preferences
        if preferences:
            if isinstance(preferences, dict):
                # unordered
                preferences = preferences.items()

            # sanity check
            assert not [i for i in preferences if len(i) != 2]
        else:
            preferences = []
        self._preferences = preferences

        # Handle profile creation
        self.create_new = not profile
        if profile:
            # Ensure we have a full path to the profile
            self.profile = os.path.abspath(os.path.expanduser(profile))
        else:
            self.profile = tempfile.mkdtemp(suffix='.mozrunner')

        self.restore = restore

        # Initialize all class members
        self._internal_init()

    def _internal_init(self):
        """Internal: Initialize all class members to their default value"""

        if not os.path.exists(self.profile):
            os.makedirs(self.profile)

        # Preferences files written to
        self.written_prefs = set()

        # Our magic markers
        nonce = '%s %s' % (str(time.time()), uuid.uuid4())
        self.delimeters = ('#MozRunner Prefs Start %s' % nonce,
                           '#MozRunner Prefs End %s' % nonce)

        # If sub-classes want to set default preferences
        if hasattr(self.__class__, 'preferences'):
            self.set_preferences(self.__class__.preferences)
        # Set additional preferences
        self.set_preferences(self._preferences)

        self.permissions = Permissions(self.profile, self._locations)
        prefs_js, user_js = self.permissions.network_prefs(self._proxy)
        self.set_preferences(prefs_js, 'prefs.js')
        self.set_preferences(user_js)

        # handle add-on installation
        self.addon_manager = AddonManager(self.profile, restore=self.restore)
        self.addon_manager.install_addons(self._addons, self._addon_manifests)

        # handle webapps
        self.webapps = WebappCollection(profile=self.profile, apps=self._apps)
        self.webapps.update_manifests()

    def __del__(self):
      self.cleanup()

    ### cleanup

    def cleanup(self):
        """Cleanup operations for the profile."""

        if self.restore:
            # If copies of those class instances exist ensure we correctly
            # reset them all (see bug 934484)
            self.addon_manager.clean()
            self.clean_preferences()
            self.permissions.clean_db()
            self.webapps.clean()

            # If it's a temporary profile we have to remove it
            if self.create_new:
                if os.path.exists(self.profile):
                    rmtree(self.profile, onerror=self._cleanup_error)

    def reset(self):
        """
        reset the profile to the beginning state
        """
        self.cleanup()

        self._internal_init()

    def _cleanup_error(self, function, path, excinfo):
        """ Specifically for windows we need to handle the case where the windows
            process has not yet relinquished handles on files, so we do a wait/try
            construct and timeout if we can't get a clear road to deletion
        """

        try:
            from exceptions import WindowsError
            from time import sleep
            def is_file_locked():
                return excinfo[0] is WindowsError and excinfo[1].winerror == 32

            if excinfo[0] is WindowsError and excinfo[1].winerror == 32:
                # Then we're on windows, wait to see if the file gets unlocked
                # we wait 10s
                count = 0
                while count < 10:
                    sleep(1)
                    try:
                        function(path)
                        break
                    except:
                        count += 1
        except ImportError:
            # We can't re-raise an error, so we'll hope the stuff above us will throw
            pass

    def clean_preferences(self):
        """Removed preferences added by mozrunner."""
        for filename in self.written_prefs:
            if not os.path.exists(os.path.join(self.profile, filename)):
                # file has been deleted
                break
            while True:
                if not self.pop_preferences(filename):
                    break

    @classmethod
    def clone(cls, path_from, path_to=None, **kwargs):
        """Instantiate a temporary profile via cloning
        - path: path of the basis to clone
        - kwargs: arguments to the profile constructor
        """
        if not path_to:
            tempdir = tempfile.mkdtemp() # need an unused temp dir name
            rmtree(tempdir) # copytree requires that dest does not exist
            path_to = tempdir
        copytree(path_from, path_to)

        def cleanup_clone(fn):
            """Deletes a cloned profile when restore is True"""
            def wrapped(self):
                fn(self)
                if self.restore and os.path.exists(self.profile):
                        rmtree(self.profile, onerror=self._cleanup_error)
            return wrapped

        c = cls(path_to, **kwargs)
        c.__del__ = c.cleanup = types.MethodType(cleanup_clone(cls.cleanup), c)
        return c

    def exists(self):
        """returns whether the profile exists or not"""
        return os.path.exists(self.profile)

    ### methods for preferences

    def set_preferences(self, preferences, filename='user.js'):
        """Adds preferences dict to profile preferences"""

        # append to the file
        prefs_file = os.path.join(self.profile, filename)
        f = open(prefs_file, 'a')

        if preferences:

            # note what files we've touched
            self.written_prefs.add(filename)

            # opening delimeter
            f.write('\n%s\n' % self.delimeters[0])

            # write the preferences
            Preferences.write(f, preferences)

            # closing delimeter
            f.write('%s\n' % self.delimeters[1])

        f.close()

    def pop_preferences(self, filename):
        """
        pop the last set of preferences added
        returns True if popped
        """

        path = os.path.join(self.profile, filename)
        with file(path) as f:
            lines = f.read().splitlines()
        def last_index(_list, value):
            """
            returns the last index of an item;
            this should actually be part of python code but it isn't
            """
            for index in reversed(range(len(_list))):
                if _list[index] == value:
                    return index
        s = last_index(lines, self.delimeters[0])
        e = last_index(lines, self.delimeters[1])

        # ensure both markers are found
        if s is None:
            assert e is None, '%s found without %s' % (self.delimeters[1], self.delimeters[0])
            return False # no preferences found
        elif e is None:
            assert s is None, '%s found without %s' % (self.delimeters[0], self.delimeters[1])

        # ensure the markers are in the proper order
        assert e > s, '%s found at %s, while %s found at %s' % (self.delimeters[1], e, self.delimeters[0], s)

        # write the prefs
        cleaned_prefs = '\n'.join(lines[:s] + lines[e+1:])
        with file(path, 'w') as f:
            f.write(cleaned_prefs)
        return True

    ### methods for introspection

    def summary(self, return_parts=False):
        """
        returns string summarizing profile information.
        if return_parts is true, return the (Part_name, value) list
        of tuples instead of the assembled string
        """

        parts = [('Path', self.profile)] # profile path

        # directory tree
        parts.append(('Files', '\n%s' % tree(self.profile)))

        # preferences
        for prefs_file in ('user.js', 'prefs.js'):
            path = os.path.join(self.profile, prefs_file)
            if os.path.exists(path):

                # prefs that get their own section
                # This is currently only 'network.proxy.autoconfig_url'
                # but could be expanded to include others
                section_prefs = ['network.proxy.autoconfig_url']
                line_length = 80
                line_length_buffer = 10 # buffer for 80 character display: length = 80 - len(key) - len(': ') - line_length_buffer
                line_length_buffer += len(': ')
                def format_value(key, value):
                    if key not in section_prefs:
                        return value
                    max_length = line_length - len(key) - line_length_buffer
                    if len(value) > max_length:
                        value = '%s...' % value[:max_length]
                    return value

                prefs = Preferences.read_prefs(path)
                if prefs:
                    prefs = dict(prefs)
                    parts.append((prefs_file,
                    '\n%s' %('\n'.join(['%s: %s' % (key, format_value(key, prefs[key]))
                                        for key in sorted(prefs.keys())
                                        ]))))

                    # Currently hardcorded to 'network.proxy.autoconfig_url'
                    # but could be generalized, possibly with a generalized (simple)
                    # JS-parser
                    network_proxy_autoconfig = prefs.get('network.proxy.autoconfig_url')
                    if network_proxy_autoconfig and network_proxy_autoconfig.strip():
                        network_proxy_autoconfig = network_proxy_autoconfig.strip()
                        lines = network_proxy_autoconfig.replace(';', ';\n').splitlines()
                        lines = [line.strip() for line in lines]
                        origins_string = 'var origins = ['
                        origins_end = '];'
                        if origins_string in lines[0]:
                            start = lines[0].find(origins_string)
                            end = lines[0].find(origins_end, start);
                            splitline = [lines[0][:start],
                                         lines[0][start:start+len(origins_string)-1],
                                         ]
                            splitline.extend(lines[0][start+len(origins_string):end].replace(',', ',\n').splitlines())
                            splitline.append(lines[0][end:])
                            lines[0:1] = [i.strip() for i in splitline]
                        parts.append(('Network Proxy Autoconfig, %s' % (prefs_file),
                                      '\n%s' % '\n'.join(lines)))

        if return_parts:
            return parts

        retval = '%s\n' % ('\n\n'.join(['[%s]: %s' % (key, value)
                                        for key, value in parts]))
        return retval

    __str__ = summary
Beispiel #41
0
class BuhIRC:
    def __init__(self, config_file):
        self.config_file = config_file
        self.config = json.load(open(self.config_file))
        self.me = self.config["me"]
        self.net = self.config["network"]
        self.module_manager = ModuleManager(self)
        self.hook_manager = HookManager(self)
        self.perms = Permissions(self)
        self.connection = IRCConnection(self.net["address"], self.net["port"], self.net["ssl"], self.config["proxies"].get(self.net.get("proxy", "none"), None), self.net.get("flood_interval", 0.0))
        self.running = True
        self.state = {}  # Dict used to hold stuff like last line received and last message etc...
        self.db = Database("etc/buhirc.db")
        self.db.connect()
        logging.basicConfig(level=getattr(logging, self.config["misc"]["loglevel"]), format='[%(asctime)s] %(levelname)s: %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
        self.requests_session = requests.session()
        if self.config["misc"].get("http_proxy", "none") != "none":
            proxy = self.config["proxies"].get(self.config["misc"]["http_proxy"], "none")
            if proxy != "none":
                self.requests_session.proxies = {"http": proxy, "https": proxy}

        self.flood_verbs = [x.lower() for x in self.net.get("flood_verbs", [])]
        self.help = {}

    def run(self):
        self.connection.connect()
        if self.config["network"]["sasl"]["use"]:
            self.raw("CAP REQ :sasl")
        self.raw("NICK %s" % self.me["nicks"][0])  # Nicks thing is a temp hack
        self.raw("USER %s * * :%s" % (self.me["ident"], self.me["gecos"]))

        for module in self.config["modules"]:
            self.module_manager.load_module(module)

        while self.running:
            if not self.loop():
                self.stop()

    def raw(self, line):
        """
        Send a raw IRC line to the server.
        @param line: The raw line to send, without a trailing carriage return or newline.
        """
        logging.debug("[IRC] <- %s" % line)
        ln = Line.parse(line)
        force = True  # Whether we bypass flood protection or not.
        if ln.command.lower() in self.flood_verbs:
            force = False

        self.connection.write_line(line, force)

    def parse_line(self, ln):
        logging.debug("[IRC] -> %s" % ln.linestr)
        if ln.command == "PING":
            self.raw(ln.linestr.replace("PING", "PONG"))
        elif ln.command == "376":
            for channel in self.net["channels"]:
                self.join(channel)
        elif ln.command == "CAP":
            if ln.params[1] == "ACK" and ln.params[-1] == "sasl" and self.net["sasl"]["use"]:
                self.raw("AUTHENTICATE PLAIN")
        elif ln.command == "AUTHENTICATE":
            magic = "%s\x00%s\x00%s" % (self.net["sasl"]["username"], self.net["sasl"]["username"], self.net["sasl"]["password"])
            magic = base64.b64encode(magic.encode("ascii"))
            self.raw("AUTHENTICATE %s" % magic)
        elif ln.command == "903":
            self.raw("CAP END")
        elif ln.command == "904":
            logging.warning("SASL authentication failed, continuing login anyways...")
            self.raw("CAP END")

    def loop(self):
        if not self.connection.loop():
            return False

        for line in self.connection.buffer:
            ln = Line.parse(line)
            self.state["last_line"] = ln
            self.parse_line(ln)
            self.hook_manager.run_irc_hooks(ln)

        return True

    def stop(self):
        self.raw("QUIT :Bye!")
        self.connection.disconnect()
        self.running = False

    def rehash(self):
        """
        Rehash (reread and reparse) the bot's configuration file.
        """
        self.config = json.load(open(self.config_file))

    # Helper functions
    def hook_command(self, cmd, callback, help_text=None):
        """
        Register a command hook to the bot.
        @param cmd: Command name to hook.
        @param callback: Event callback function to call when this command is ran.
        @param help_text: Help text for this command, no help if not specified.
        @return: ID of the new hook. (Used for removal later)
        """
        cmd = cmd.lower()

        if help_text:
            self.help[cmd] = help_text

        return self.hook_manager.add_hook(Hook("command_%s" % cmd, callback))

    def hook_numeric(self, numeric, callback):
        """
        Register a raw numeric hook to the bot.
        @param numeric: The raw IRC numeric (or command, such as PRIVMSG) to hook.
        @param callback: Event callback function to call when this numeric/command is received from the server.
        @return: ID of the new hook. (Used for removal later)
        """
        return self.hook_manager.add_hook(Hook("irc_raw_%s" % numeric, callback))

    def list_commands(self):
        """
        Get a list of all commands the bot knows about.
        @return: list of command names
        """
        return [hook[8:] for hook in self.hook_manager.hooks.keys() if hook.startswith("command_")]  # len("command_") == 8

    def unhook_something(self, the_id):
        """
        Unhook any sort of hook. (Command, numeric, or event.)
        @param the_id: The ID of the hook to remove, returned by a hook adding function.
        """
        self.hook_manager.remove_hook(the_id)

    def is_admin(self, hostmask=None):
        """
        Check if a hostmask is a bot admin.
        @param hostmask: The hostmask to check.
        @return: True if admin, False if not.
        """
        if hostmask is None:
            hostmask = self.state["last_line"].hostmask

        return self.perms.check_permission(hostmask, "admin")

    def check_condition(self, condition, false_message="Sorry, you may not do that.", reply_func=None):
        """
        Check a condition and return it, calling reply_func with false_message if the condition is False.
        @param condition: The condition to check.
        @param false_message: The message to be passed to reply_func
        @param reply_func: The function to call with false_message as argument if condition is False.
        @return:
        """
        if reply_func is None:
            reply_func = self.reply

        if condition:
            return True

        reply_func(false_message)
        return False

    def check_permission(self, permission="admin", error_reply="Sorry, you do not have permission to do that!",
                         reply_func=None):
        """
        Check a bot permission against the hostmask of the last line received, and return whether it matches.
        Calls reply_func with error_reply as argument if condition is False
        @param permission: The permission to check.
        @param error_reply: The message to be passed to reply_func
        @param reply_func: The function to call with error_reply as argument if condition is False.
        @return:
        """
        if reply_func is None:
            reply_func = self.reply_notice

        return self.check_condition(self.perms.check_permission(self.state["last_line"].hostmask, permission),
                                    error_reply, reply_func)

    # IRC-related stuff begins here
    def _msg_like(self, verb, target, message):
        self.raw("%s %s :%s" % (verb, target, message))

    def privmsg(self, target, message):
        """
        Send a PRIVMSG (channel or user message) to a user/channel.
        @param target: The target to send this message to. (Can be nickname or channel.)
        @param message: The actual message to send.
        """
        self._msg_like("PRIVMSG", target, message)

    def act(self, target, action):
        """
        Send a CTCP ACTION (/me) to a user/channel.
        @param target: The target to send this ACTION to. (Can be nickname or channel.)
        @param action: The actual action to send.
        """
        self.privmsg(target, "\x01ACTION %s\x01" % action)

    def notice(self, target, message):
        """
        Send a NOTICE to a user/channel.
        @param target: The user or channel to send this notice to.
        @param message: The actual notice text.
        """
        self._msg_like("NOTICE", target, message)

    def join(self, channel):
        """
        Send a raw channel JOIN message to the server. (Join a channel)
        @param channel: The channel to join. (Key can be passed in the same argument, separated by a space.)
        """
        self.raw("JOIN %s" % channel)

    def part(self, channel):
        """
        Send a raw channel PART to the server. (Leave a channel)
        @param channel: The channel to leave.
        """
        self.raw("PART %s" % channel)

    # IRC-related stuff that involves state.
    def reply(self, message):
        """
        Send a PRIVMSG (channel or user message) to the last channel or user we received a message in.
        @param message: The reply message to send.
        """
        ln = self.state["last_line"]
        reply_to = ln.hostmask.nick

        if ln.params[0][0] == "#":
            reply_to = ln.params[0]

        self.privmsg(reply_to, message)

    def reply_act(self, action):
        """
        Send a CTCP ACTION (/me) to the last channel or user we received a message in.
        @param action: The action to send.
        """
        self.reply("\x01ACTION %s\x01" % action)

    def reply_notice(self, message):
        """
        Send a NOTICE to the last channel or user we received a message in.
        @param message: The notice text to send.
        """
        ln = self.state["last_line"]
        self.notice(ln.hostmask.nick, message)

    # Web stuff.
    def http_get(self, url, **kwargs):
        """
        Perform an HTTP GET using requests.
        @param url: The URL to GET.
        @param kwargs: Any arguments to pass to requests.get()
        @return: requests.Response object.
        """
        return self.requests_session.get(url, **kwargs)

    def http_post(self, url, **kwargs):
        """
        Perform an HTTP POST using requests.
        @param url: The URL to POST to.
        @param kwargs: Any arguments to pass to requests.get()
        @return: requests.Response object.
        """
        return self.requests_session.post(url, **kwargs)