Exemplo n.º 1
0
class DomainsController(BaseController):
    def __before__(self):
        "set context"
        BaseController.__before__(self)
        if self.identity:
            c.user = self.identity['user']
        else:
            c.user = None
        c.selectedtab = 'domains'

    def _get_server(self, destinationid):
        "utility"
        try:
            cachekey = u'deliveryserver-%s' % destinationid
            q = Session.query(DeliveryServer)\
                    .filter(DeliveryServer.id==destinationid)\
                    .options(FromCache('sql_cache_med', cachekey))
            if self.invalidate:
                q.invalidate()
            server = q.one()
        except NoResultFound:
            server = None
        return server

    def _get_organizations(self, orgid=None):
        "Get organizations"
        query = Session.query(Group)
        if orgid:
            query = query.filter(Group.id == orgid)
        return query

    def _get_authserver(self, authid):
        "Get an auth server"
        try:
            cachekey = u'authserver-%s' % authid
            q = Session.query(AuthServer).filter(AuthServer.id==authid)\
                .options(FromCache('sql_cache_med', cachekey))
            if self.invalidate:
                q.invalidate()
            server = q.one()
        except NoResultFound:
            server = None
        return server

    def _get_alias(self, aliasid):
        "Get a domain alias"
        try:
            cachekey = u'domainalias-%s' % aliasid
            q = Session.query(DomainAlias).filter(DomainAlias.id==aliasid)\
                .options(FromCache('sql_cache_med', cachekey))
            if self.invalidate:
                q.invalidate()
            alias = q.one()
        except NoResultFound:
            alias = None
        return alias

    def index(self, page=1, orgid=None, format=None):
        "Browse domains"
        num_items = session.get('domains_num_items', 10)
        c.form = BulkDelDomains(request.POST, csrf_context=session)
        if request.POST:
            if c.form.domainid.data and c.form.whatdo.data == 'disable':
                Session.query(Domain).filter(
                    Domain.id.in_(c.form.domainid.data)).update(
                        {'status': False}, synchronize_session='fetch')
                Session.commit()
            if c.form.domainid.data and c.form.whatdo.data == 'enable':
                Session.query(Domain).filter(
                    Domain.id.in_(c.form.domainid.data)).update(
                        {'status': True}, synchronize_session='fetch')
                Session.commit()
            if c.form.domainid.data and c.form.whatdo.data == 'delete':
                session['bulk_domain_delete'] = c.form.domainid.data
                session.save()
                # redirect for confirmation
                redirect(url('domains-confirm-delete'))
        domains = Session.query(Domain).options(
            joinedload(Domain.organizations))
        domcount = Session.query(Domain.id)

        if orgid and c.user.is_superadmin:
            domains = domains.join(domain_owners).filter(
                domain_owners.c.organization_id == orgid)
            domcount = domcount.join(domain_owners).filter(
                domain_owners.c.organization_id == orgid)
        if c.user.is_domain_admin:
            domains = domains.join(domain_owners,
                    (oa, domain_owners.c.organization_id == oa.c.organization_id))\
                    .filter(oa.c.user_id == c.user.id)
            domcount = domcount.join(domain_owners,
                    (oa, domain_owners.c.organization_id == oa.c.organization_id))\
                    .filter(oa.c.user_id == c.user.id)

        pages = paginate.Page(domains,
                              page=int(page),
                              items_per_page=num_items,
                              item_count=domcount.count())
        if format == 'json':
            response.headers['Content-Type'] = 'application/json'
            data = convert_dom_to_json(pages, orgid)
            return data

        c.orgid = orgid
        c.page = pages
        return render('/domains/index.html')

    def search(self, format=None):
        "Search for domains"
        total_found = 0
        search_time = 0
        num_items = session.get('domains_num_items', 10)
        q = request.GET.get('q', '')
        org = request.GET.get('o', None)
        page = int(request.GET.get('p', 1))
        # if q:
        kwds = {'presliced_list': True}
        conn = SphinxClient()
        conn.SetMatchMode(SPH_MATCH_EXTENDED2)
        if page == 1:
            conn.SetLimits(0, num_items, 500)
        else:
            offset = (page - 1) * num_items
            conn.SetLimits(offset, num_items, 500)
        if org:
            conn.SetFilter('orgs', [int(org)])
        if c.user.is_domain_admin:
            crcs = get_dom_crcs(Session, c.user)
            conn.SetFilter('domain_name', crcs)
        q = clean_sphinx_q(q)
        results = conn.Query(q, 'domains, domains_rt')
        q = restore_sphinx_q(q)
        if results and results['matches']:
            ids = [hit['id'] for hit in results['matches']]
            domains = Session.query(Domain)\
                    .options(joinedload('organizations'))\
                    .filter(Domain.id.in_(ids))\
                    .all()
            total_found = results['total_found']
            search_time = results['time']
            domaincount = total_found
        else:
            domains = []
            domaincount = 0

        c.page = paginate.Page(domains,
                               page=page,
                               items_per_page=num_items,
                               item_count=domaincount,
                               **kwds)
        c.q = q
        c.org = org
        c.total_found = total_found
        c.search_time = search_time
        return render('/domains/searchresults.html')

    @ActionProtector(OnlySuperUsers())
    def add(self, orgid=None):
        "Add a domain"
        c.form = AddDomainForm(request.POST, csrf_context=session)
        c.form.organizations.query = self._get_organizations(orgid)
        if request.POST and c.form.validate():
            try:
                domain = Domain()
                for field in c.form:
                    if field.name != 'csrf_token':
                        setattr(domain, field.name, field.data)
                Session.add(domain)
                Session.commit()
                update_serial.delay()
                info = ADDDOMAIN_MSG % dict(d=domain.name)
                audit_log(c.user.username, 3, info, request.host,
                          request.remote_addr, now())
                flash(
                    _('The domain: %(dom)s has been created') %
                    dict(dom=domain.name))
                redirect(url(controller='domains'))
            except IntegrityError:
                Session.rollback()
                flash_alert(
                    _('The domain name %(dom)s already exists') %
                    dict(dom=domain.name))

        return render('/domains/new.html')

    @ActionProtector(OwnsDomain())
    def detail(self, domainid):
        "Domain details"
        domain = self._get_domain(domainid)
        if not domain:
            abort(404)
        c.domain = domain
        return render('/domains/detail.html')

    @ActionProtector(OwnsDomain())
    def edit(self, domainid):
        "Edit a domain"
        domain = self._get_domain(domainid)
        if not domain:
            abort(404)
        c.form = AddDomainForm(request.POST, domain, csrf_context=session)
        if c.user.is_superadmin:
            c.form.organizations.query_factory = self._get_organizations
        else:
            del c.form.organizations
        c.id = domainid
        if request.POST and c.form.validate():
            updated = False
            kw = {'domainid': domain.id}
            for field in c.form:
                intfields = [
                    'spam_actions', 'highspam_actions', 'delivery_mode',
                    'report_every'
                ]
                if (field.name in intfields
                        and int(field.data) == getattr(domain, field.name)):
                    continue
                if (field.name != 'csrf_token'
                        and field.data != getattr(domain, field.name)):
                    setattr(domain, field.name, field.data)
                    updated = True
            if updated:
                try:
                    Session.add(domain)
                    Session.commit()
                    update_serial.delay()
                    info = UPDATEDOMAIN_MSG % dict(d=domain.name)
                    audit_log(c.user.username, 2, info, request.host,
                              request.remote_addr, now())
                    flash(
                        _('The domain: %(dom)s has been updated') %
                        dict(dom=domain.name))
                    kw['uc'] = 1
                except IntegrityError:
                    Session.rollback()
                    flash(
                        _('The domain %(dom)s could not be updated') %
                        dict(dom=domain.name))
            else:
                flash_info(_('No changes were made to the domain'))
            redirect(url('domain-detail', **kw))
        return render('/domains/edit.html')

    @ActionProtector(OwnsDomain())
    def delete(self, domainid):
        "Delete a domain"
        domain = self._get_domain(domainid)
        if not domain:
            abort(404)
        c.form = AddDomainForm(request.POST, domain, csrf_context=session)
        del c.form.organizations
        c.id = domainid
        if request.POST and c.form.validate():
            name = domain.name
            Session.delete(domain)
            Session.commit()
            update_serial.delay()
            info = DELETEDOMAIN_MSG % dict(d=name)
            audit_log(c.user.username, 4, info, request.host,
                      request.remote_addr, now())
            flash(_('The domain has been deleted'))
            redirect(url(controller='domains'))
        else:
            flash(
                _('The domain: %(name)s and all associated data will'
                  ' be deleted, This action cannot be reversed.') %
                dict(name=domain.name))
        return render('/domains/delete.html')

    def confirm_delete(self):
        "Confirm bulk delete of domains"
        domainids = session.get('bulk_domain_delete', [])
        if not domainids:
            redirect(url(controller='domains', action='index'))

        num_items = 10
        if len(domainids) > num_items and len(domainids) <= 20:
            num_items = 20
        if len(domainids) > num_items and len(domainids) <= 50:
            num_items = 50
        if len(domainids) > num_items and len(domainids) <= 100:
            num_items = 100

        domains = Session.query(Domain).filter(Domain.id.in_(domainids))\
                    .options(joinedload('organizations'))
        domcount = Session.query(Domain.id).filter(Domain.id.in_(domainids))

        if c.user.is_domain_admin:
            domains = domains.join(domain_owners,
                        (oa,
                        domain_owners.c.organization_id ==
                        oa.c.organization_id))\
                        .filter(oa.c.user_id == c.user.id)
            domcount = domcount.join(domain_owners,
                        (oa, domain_owners.c.organization_id ==
                        oa.c.organization_id))\
                        .filter(oa.c.user_id == c.user.id)

        if request.POST:
            tasks = []
            for domain in domains.all():
                info = DELETEDOMAIN_MSG % dict(d=domain.name)
                tasks.append((c.user.username, 4, info, request.host,
                              request.remote_addr, now()))
                Session.delete(domain)
            Session.commit()
            del session['bulk_domain_delete']
            session.save()
            for task in tasks:
                audit_log(*task)
            flash(_('The domains have been deleted'))
            redirect(url(controller='domains'))
        else:
            flash(
                _('The following domains are about to be deleted,'
                  ' this action is not reversible, Do you wish to'
                  ' continue ?'))

        try:
            c.page = paginate.Page(domains,
                                   page=1,
                                   items_per_page=num_items,
                                   item_count=domcount.count())
        except DataError:
            flash_alert(_('An error occured try again'))
            redirect(url(controller='domains', action='index'))
        return render('/domains/confirmbulkdel.html')

    @ActionProtector(OwnsDomain())
    def adddestination(self, domainid):
        "Add a destination server"
        domain = self._get_domain(domainid)
        if not domain:
            abort(404)
        c.form = AddDeliveryServerForm(request.POST, csrf_context=session)
        c.id = domainid
        if request.POST and c.form.validate():
            server = DeliveryServer()
            for field in c.form:
                if field.name != 'csrf_token':
                    setattr(server, field.name, field.data)
            try:
                domain.servers.append(server)
                Session.add(server)
                Session.add(domain)
                Session.commit()
                info = ADDDELSVR_MSG % dict(d=domain.name, ds=server.address)
                audit_log(c.user.username, 3, info, request.host,
                          request.remote_addr, now())
                flash(_('The destination server has been created'))
                redirect(
                    url(controller='domains',
                        action='detail',
                        domainid=domain.id))
            except IntegrityError:
                Session.rollback()
                flash_alert(
                    _('The destination server %(dest)s already exists ') %
                    dict(dest=server.address))
        return render('/domains/adddestination.html')

    @ActionProtector(OwnsDomain())
    def editdestination(self, destinationid):
        "Edit destination server"
        server = self._get_server(destinationid)
        if not server:
            abort(404)
        c.form = AddDeliveryServerForm(request.POST,
                                       server,
                                       csrf_context=session)
        if request.POST and c.form.validate():
            updated = False
            kw = dict(domainid=server.domain_id)
            for field in c.form:
                if (field.name != 'csrf_token'
                        and field.data != getattr(server, field.name)):
                    setattr(server, field.name, field.data)
                    updated = True
            if updated:
                try:
                    Session.add(server)
                    Session.commit()
                    flash(_('The destination server has been updated'))
                    info = UPDATEDELSVR_MSG % dict(d=server.domains.name,
                                                   ds=server.address)
                    audit_log(c.user.username, 2, info, request.host,
                              request.remote_addr, now())
                    self.invalidate = 1
                    self._get_server(destinationid)
                    redirect(url('domain-detail', **kw))
                except IntegrityError:
                    Session.rollback()
                    flash_alert(_('The update failed'))
            else:
                flash_info(_('No changes were made to the destination server'))
                redirect(url('domain-detail', **kw))
        c.id = destinationid
        c.domainid = server.domain_id
        return render('/domains/editdestination.html')

    @ActionProtector(OwnsDomain())
    def testdestination(self, destinationid):
        "Test mail destination server"
        server = self._get_server(destinationid)
        if not server:
            abort(404)

        taskid = request.GET.get('taskid', None)
        if not taskid:
            to_addr = 'postmaster@%s' % server.domains.name
            task = test_smtp_server.apply_async(args=[
                server.address, server.port, '<>', to_addr, server.id, 3
            ])
            taskid = task.task_id
            session['taskids'].append(taskid)
            session['testdest-count'] = 1
            session.save()
            redirect(url.current(taskid=taskid))
        else:
            result = AsyncResult(taskid)
            if result is None or taskid not in session['taskids']:
                flash(_('The connection test failed try again later'))
                redirect(url('domain-detail', domainid=server.domain_id))
            if result.ready():
                if ('smtp' in result.result and 'ping' in result.result
                        and result.result['smtp'] and result.result['ping']):
                    flash(
                        _('The server: %s is up and accepting mail from us' %
                          server.address))
                else:
                    if 'ping' in result.result['errors']:
                        errors = result.result['errors']['ping']
                    else:
                        errors = result.result['errors']['smtp']
                    flash(
                        _('The server: %s is not accepting mail from us: %s') %
                        (server.address, errors))
                redirect(url('domain-detail', domainid=server.domain_id))
            else:
                session['testdest-count'] += 1
                session.save()
                if (session['testdest-count'] >= 10
                        and result.state in ['PENDING', 'RETRY', 'FAILURE']):
                    result.revoke()
                    del session['testdest-count']
                    session.save()
                    flash_alert('Failed to initialize backend,'
                                ' try again later')
                    redirect(url('domain-detail', domainid=server.domain_id))

        c.server = server
        c.domainid = server.domain_id
        c.taskid = taskid
        c.finished = False
        return render('/domains/testdestination.html')

    @ActionProtector(OwnsDomain())
    def deletedestination(self, destinationid):
        "Delete destination server"
        server = self._get_server(destinationid)
        if not server:
            abort(404)
        c.form = AddDeliveryServerForm(request.POST,
                                       server,
                                       csrf_context=session)
        if request.POST and c.form.validate():
            name = server.domains.name
            server_addr = server.address
            domainid = server.domain_id
            Session.delete(server)
            Session.commit()
            flash(_('The destination server has been deleted'))
            info = DELETEDELSVR_MSG % dict(d=name, ds=server_addr)
            audit_log(c.user.username, 4, info, request.host,
                      request.remote_addr, now())
            redirect(url('domain-detail', domainid=domainid))
        else:
            flash(
                _('The destination server: %(s)s will be deleted,'
                  ' This action is not reversible') % dict(s=server.address))
        c.id = destinationid
        c.domainid = server.domain_id
        return render('/domains/deletedestination.html')

    @ActionProtector(OwnsDomain())
    def add_auth(self, domainid):
        "Add auth server"
        domain = self._get_domain(domainid)
        if not domain:
            abort(404)
        c.form = AddAuthForm(request.POST, csrf_context=session)
        if request.POST and c.form.validate():
            server = AuthServer()
            for field in c.form:
                if field.data and field.name != 'csrf_token':
                    setattr(server, field.name, field.data)
            try:
                domain.authservers.append(server)
                Session.add(server)
                Session.add(domain)
                Session.commit()
                info = ADDAUTHSVR_MSG % dict(d=domain.name, ds=server.address)
                audit_log(c.user.username, 3, info, request.host,
                          request.remote_addr, now())
                flash(_('The authentication settings have been created'))
                redirect(
                    url(controller='domains',
                        action='detail',
                        domainid=domain.id))
            except IntegrityError:
                Session.rollback()
                auth = dict(AUTH_PROTOCOLS)[str(server.protocol)]
                flash_alert(
                    _('The host %(dest)s already configured for %(auth)s '
                      'authentication for this domain') %
                    dict(dest=server.address, auth=auth))
        c.domainid = domainid
        c.domainname = domain.name
        return render('/domains/addauth.html')

    @ActionProtector(OwnsDomain())
    def edit_auth(self, authid):
        "Edit auth server"
        server = self._get_authserver(authid)
        if not server:
            abort(404)
        c.form = AddAuthForm(request.POST, server, csrf_context=session)
        #del c.form.protocol
        if request.POST and c.form.validate():
            updated = False
            kw = dict(domainid=server.domain_id)
            for field in c.form:
                if field.name == 'protocol' or field.name == 'csrf_token':
                    continue
                if (field.data != getattr(server, field.name)
                        and field.data != ''):
                    setattr(server, field.name, field.data)
                    updated = True
                if (field.name == 'user_map_template'
                        and field.data != getattr(server, field.name)):
                    setattr(server, field.name, field.data)
                    updated = True
            if updated:
                try:
                    Session.add(server)
                    Session.commit()
                    flash(_('The authentication settings have been updated'))
                    self.invalidate = 1
                    self._get_authserver(authid)
                    info = UPDATEAUTHSVR_MSG % dict(d=server.domains.name,
                                                    ds=server.address)
                    audit_log(c.user.username, 2, info, request.host,
                              request.remote_addr, now())
                    redirect(url('domain-detail', **kw))
                except IntegrityError:
                    Session.rollback()
                    flash_alert(_('The authentication settings update failed'))
            else:
                flash_info(
                    _('No changes were made to the '
                      'authentication settings'))
                redirect(url('domain-detail', **kw))
        c.domainid = server.domains.id
        c.domainname = server.domains.name
        c.authid = authid
        return render('/domains/editauth.html')

    @ActionProtector(OwnsDomain())
    def delete_auth(self, authid):
        "Delete auth server"
        server = self._get_authserver(authid)
        if not server:
            abort(404)
        c.form = AddAuthForm(request.POST, server, csrf_context=session)
        if request.POST and c.form.validate():
            name = server.domains.name
            server_addr = server.address
            domainid = server.domains.id
            Session.delete(server)
            Session.commit()
            flash(_('The authentication settings have been deleted'))
            info = DELETEAUTHSVR_MSG % dict(d=name, ds=server_addr)
            audit_log(c.user.username, 4, info, request.host,
                      request.remote_addr, now())
            redirect(url('domain-detail', domainid=domainid))
        else:
            flash(
                _('The authentication server: %(s)s will be deleted,'
                  ' This action is not reversible') % dict(s=server.address))
        c.domainid = server.domains.id
        c.domainname = server.domains.name
        c.authid = authid
        return render('/domains/deleteauth.html')

    @ActionProtector(OwnsDomain())
    def auth_settings(self, domainid, proto=5):
        "Authentication settings"
        domain = self._get_domain(domainid)
        if not domain:
            abort(404)
        try:
            protocols = {
                '4': 'radius',
                '5': 'ldap',
                '6': 'yubikey',
                '7': 'oauth'
            }
            protocol = protocols[proto]
            server = Session.query(AuthServer)\
                    .filter(AuthServer.domain_id == domainid)\
                    .filter(AuthServer.protocol == proto).one()
        except KeyError:
            flash_alert(_('The protocol supplied does not use extra settings'))
            redirect(
                url(controller='domains', action='detail', domainid=domain.id))
        except NoResultFound:
            flash_alert(
                _('Please add an authentication server for the '
                  '%(proto)s protocol Before attempting to configure '
                  'the %(proto)s settings') % dict(proto=proto))
            redirect(
                url(controller='domains', action='detail', domainid=domain.id))
        forms = {'4': AddRadiusSettingsForm, '5': AddLDAPSettingsForm}
        form = forms[proto]
        if (hasattr(server, protocol + 'settings')
                and getattr(server, protocol + 'settings')):
            authobj = getattr(server, protocol + 'settings')[0]
            c.form = form(request.POST, authobj, csrf_context=session)
        else:
            authobj = None
            c.form = form(request.POST, csrf_context=session)
        if request.POST and c.form.validate():
            updated = False
            if authobj:
                settings = getattr(server, protocol + 'settings')[0]
            else:
                settingsdict = {'4': RadiusSettings, '5': LDAPSettings}
                settings = settingsdict[proto]()
            for field in c.form:
                if field.name == 'csrf_token':
                    continue
                if authobj:
                    if getattr(settings, field.name) != field.data:
                        setattr(settings, field.name, field.data)
                        updated = True
                else:
                    setattr(settings, field.name, field.data)
            try:
                if authobj is None:
                    settings.auth_id = server.id
                if updated or authobj is None:
                    Session.add(settings)
                    Session.commit()
                if authobj:
                    flash(
                        _('The %(proto)s settings have been updated') %
                        dict(proto=protocol))
                else:
                    flash(
                        _('The %(proto)s settings have been created') %
                        dict(proto=protocol))
                info = AUTHSETTINGS_MSG % dict(d=domain.name, a=proto)
                audit_log(c.user.username, 2, info, request.host,
                          request.remote_addr, now())
                redirect(
                    url(controller='domains',
                        action='detail',
                        domainid=domain.id))
            except IntegrityError:
                Session.rollback()
                flash_alert(
                    _('The auth settings already exist, '
                      'use update to modify them'))
        else:
            if proto == '4' and 'authobj' in locals():
                flash(
                    _('The Radius secret is not be displayed in'
                      ' the form, To update type the new secret in '
                      '"Radius secret" below.'))
        c.domain = domain
        c.proto = proto
        return render('/domains/authsettings.html')

    @ActionProtector(OwnsDomain())
    def rulesets(self, domainid):
        "Scanner rulesets"
        domain = self._get_domain(domainid)
        if not domain:
            abort(404)
        c.domainid = domain.id
        c.domainname = domain.name
        return render('/domains/rulesets.html')

    @ActionProtector(OwnsDomain())
    def addalias(self, domainid):
        "Add alias domain"
        domain = self._get_domain(domainid)
        if not domain:
            abort(404)

        c.form = AddDomainAlias(request.POST, csrf_context=session)
        c.form.domain.query = Session.query(Domain).filter(
            Domain.id == domainid)
        if request.POST and c.form.validate():
            alias = DomainAlias()
            for field in c.form:
                if field.data and field.name != 'csrf_token':
                    setattr(alias, field.name, field.data)
            try:
                domain.aliases.append(alias)
                Session.add(alias)
                Session.add(domain)
                Session.commit()
                update_serial.delay()
                info = ADDDOMALIAS_MSG % dict(d=alias.name)
                audit_log(c.user.username, 3, info, request.host,
                          request.remote_addr, now())
                flash(_('The domain alias: %s has been created') % alias.name)
                redirect(
                    url(controller='domains',
                        action='detail',
                        domainid=domain.id))
            except IntegrityError:
                Session.rollback()
                flash_alert(
                    _('The domain alias: %s already exists') % alias.name)

        c.domainid = domain.id
        c.domainname = domain.name
        return render('/domains/addalias.html')

    def editalias(self, aliasid):
        "Edit alias domain"
        alias = self._get_alias(aliasid)
        if not alias:
            abort(404)

        c.form = EditDomainAlias(request.POST, alias, csrf_context=session)
        c.form.domain.query = Session.query(Domain)\
                            .filter(Domain.id==alias.domain_id)
        if request.POST and c.form.validate():
            updated = False
            for field in c.form:
                if (field.name != 'csrf_token'
                        and field.data != getattr(alias, field.name)):
                    setattr(alias, field.name, field.data)
                    updated = True
            if updated:
                try:
                    Session.add(alias)
                    Session.commit()
                    update_serial.delay()
                    info = UPDATEDOMALIAS_MSG % dict(d=alias.name)
                    audit_log(c.user.username, 2, info, request.host,
                              request.remote_addr, now())
                    flash(
                        _('The domain alias: %s has been updated') %
                        alias.name)
                    redirect(url('domain-detail', domainid=alias.domain_id))
                except IntegrityError:
                    Session.rollback()
                    flash_alert(_('The update failed'))
            else:
                flash_info(_('No changes were made to the domain alias'))
                redirect(url('domain-detail', domainid=alias.domain_id))

        c.aliasid = aliasid
        c.domainid = alias.domain_id
        c.domainname = alias.domain.name
        return render('/domains/editalias.html')

    def deletealias(self, aliasid):
        "Delete alias domain"
        alias = self._get_alias(aliasid)
        if not alias:
            abort(404)

        c.form = AddDomainAlias(request.POST, alias, csrf_context=session)
        c.form.domain.query = Session.query(Domain)\
                            .filter(Domain.id==alias.domain_id)
        if request.POST and c.form.validate():
            domainid = alias.domain_id
            aliasname = alias.name
            Session.delete(alias)
            Session.commit()
            update_serial.delay()
            info = DELETEDOMALIAS_MSG % dict(d=aliasname)
            audit_log(c.user.username, 4, info, request.host,
                      request.remote_addr, now())
            flash(_('The domain alias: %s has been deleted') % aliasname)
            redirect(url('domain-detail', domainid=domainid))

        c.aliasid = aliasid
        c.domainid = alias.domain_id
        c.domainname = alias.domain.name
        return render('/domains/deletealias.html')

    def export_domains(self, orgid=None):
        "export domains"
        task = exportdomains.apply_async(args=[c.user.id, orgid])
        session['taskids'].append(task.task_id)
        session['dexport-count'] = 1
        session.save()
        flash(_('Domains export is being processed'))
        redirect(url('domains-export-status', taskid=task.task_id))

    def export_status(self, taskid):
        "export status"
        result = AsyncResult(taskid)
        if result is None or taskid not in session['taskids']:
            flash(_('The task status requested has expired or does not exist'))
            redirect(url(controller='domains', action='index'))

        if result.ready():
            finished = True
            flash.pop_messages()
            if isinstance(result.result, Exception):
                if c.user.is_superadmin:
                    flash_alert(
                        _('Error occured in processing %s') % result.result)
                else:
                    flash_alert(_('Backend error occured during processing.'))
                redirect(url(controller='domains'))
            results = dict(
                f=True if not result.result['global_error'] else False,
                id=taskid,
                global_error=result.result['global_error'])
        else:
            session['dexport-count'] += 1
            if (session['dexport-count'] >= 10
                    and result.state in ['PENDING', 'RETRY', 'FAILURE']):
                result.revoke()
                flash_alert(
                    _('The export could not be processed,'
                      ' try again later'))
                del session['dexport-count']
                session.save()
                redirect(url(controller='domains'))
            finished = False
            results = dict(f=None, global_error=None)

        c.finished = finished
        c.results = results
        c.success = result.successful()
        d = request.GET.get('d', None)
        if finished and (d and d == 'y'):
            info = EXPORTDOM_MSG % dict(d='all')
            audit_log(c.user.username, 5, info, request.host,
                      request.remote_addr, now())
            response.content_type = 'text/csv'
            response.headers['Cache-Control'] = 'max-age=0'
            csvdata = result.result['f']
            disposition = 'attachment; filename=domains-export-%s.csv' % taskid
            response.headers['Content-Disposition'] = str(disposition)
            response.headers['Content-Length'] = len(csvdata)
            return csvdata
        return render('/domains/exportstatus.html')

    def setnum(self, format=None):
        "Set number of items returned"
        num = check_num_param(request)

        if num and num in [10, 20, 50, 100]:
            session['domains_num_items'] = num
            session.save()
        nextpage = request.headers.get('Referer', '/')
        if '://' in nextpage:
            from_url = urlparse(nextpage)
            nextpage = from_url[2]
        redirect(nextpage)
Exemplo n.º 2
0
class SettingsController(BaseController):
    #@ActionProtector(not_anonymous())
    def __before__(self):
        "set context"
        BaseController.__before__(self)
        if self.identity:
            c.user = self.identity['user']
        else:
            c.user = None
        c.selectedtab = 'settings'

    def _get_server(self, serverid):
        "returns server object"
        try:
            server = Session.query(Server).get(serverid)
        except NoResultFound:
            server = None
        return server

    def _get_setting(self, server, name):
        "return a configsettings object"
        try:
            conf_setting = Session.query(ConfigSettings)\
                            .filter_by(
                                        server_id=server,
                                        internal=name
                            ).one()
        except NoResultFound:
            conf_setting = None
        return conf_setting

    def _get_domsign(self, sigid):
        "domain signature"
        try:
            sign = Session.query(DomSignature).get(sigid)
        except NoResultFound:
            sign = None
        return sign

    def _get_usrsign(self, sigid):
        "user signature"
        try:
            sign = Session.query(UserSignature).get(sigid)
        except NoResultFound:
            sign = None
        return sign

    @ActionProtector(OnlySuperUsers())
    def index(self, page=1, format=None):
        "Index"
        num_items = session.get('settings_num_items', 10)
        servers = Session.query(Server).filter(
            Server.hostname != 'default').order_by(desc('id')).all()
        items = paginate.Page(servers,
                              page=int(page),
                              items_per_page=num_items)
        if format == 'json':
            response.headers['Content-Type'] = 'application/json'
            data = convert_settings_to_json(items)
            return data

        c.page = items
        return render('/settings/index.html')

    @ActionProtector(OnlySuperUsers())
    def new_server(self):
        "Add scan server"
        c.form = ServerForm(request.POST, csrf_context=session)
        if request.POST and c.form.validate():
            try:
                server = Server(hostname=c.form.hostname.data,
                                enabled=c.form.enabled.data)
                Session.add(server)
                Session.commit()
                info = HOSTADD_MSG % dict(n=server.hostname)
                audit_log(c.user.username, 3, info, request.host,
                          request.remote_addr, now())
                flash(_('The scanning server has been added'))
                redirect(url(controller='settings'))
            except IntegrityError:
                Session.rollback()
                flash_info(_('The server already exists'))

        return render('/settings/addserver.html')

    @ActionProtector(OnlySuperUsers())
    def edit_server(self, serverid):
        "Edit scan server"
        server = self._get_server(serverid)
        if not server:
            abort(404)

        c.form = ServerForm(request.POST, server, csrf_context=session)
        c.id = server.id
        if request.POST and c.form.validate():
            if (server.hostname != c.form.hostname.data
                    or server.enabled != c.form.enabled.data):
                try:
                    server.hostname = c.form.hostname.data
                    server.enabled = c.form.enabled.data
                    Session.add(server)
                    Session.commit()
                    update_serial.delay()
                    info = HOSTUPDATE_MSG % dict(n=server.hostname)
                    audit_log(c.user.username, 2, info, request.host,
                              request.remote_addr, now())
                    flash(_('The scanning server has been updated'))
                except IntegrityError:
                    Session.rollback()
                    flash(_('Update of server failed'))
            else:
                flash_info(_('No changes were made to the server'))
            redirect(url(controller='settings'))
        return render('/settings/editserver.html')

    @ActionProtector(OnlySuperUsers())
    def delete_server(self, serverid):
        "Delete a scan server"
        server = self._get_server(serverid)
        if not server:
            abort(404)

        c.form = ServerForm(request.POST, server, csrf_context=session)
        c.id = server.id
        if request.POST and c.form.validate():
            hostname = server.hostname
            Session.delete(server)
            Session.commit()
            update_serial.delay()
            info = HOSTDELETE_MSG % dict(n=hostname)
            audit_log(c.user.username, 4, info, request.host,
                      request.remote_addr, now())
            flash(_('The scanning server has been deleted'))
            redirect(url(controller='settings'))
        return render('/settings/deleteserver.html')

    @ActionProtector(OnlySuperUsers())
    def section(self, serverid=1, sectionid='1'):
        "Settings section"
        server = self._get_server(serverid)
        if not server:
            abort(404)

        if not int(sectionid) in CONFIG_SECTIONS:
            abort(404)

        c.serverid = serverid
        c.sectionid = sectionid
        c.scanner = server
        c.sections = CONFIG_SECTIONS
        c.form = settings_forms[sectionid](request.POST, csrf_context=session)
        if not request.POST:
            for field in c.form:
                if (sectionid == '1' and '_' in field.name
                        and not field.name == 'csrf_token'):
                    internal = global_settings_dict[field.name]
                else:
                    internal = field.name
                conf = self._get_setting(serverid, internal)
                if conf:
                    attr = getattr(c.form, field.name)
                    attr.data = conf.value

        updated = None
        if request.POST and c.form.validate():
            for field in c.form:
                if field.data and not field.name == 'csrf_token':
                    if sectionid == '1':
                        if '_' in field.name:
                            external = global_settings_dict[field.name]
                            internal = external
                        else:
                            external = CONFIG_RE.sub(u'',
                                                     unicode(field.label.text))
                            internal = field.name
                    else:
                        external = CONFIG_RE.sub(u'',
                                                 unicode(field.label.text))
                        internal = field.name
                    conf = self._get_setting(serverid, internal)
                    if conf is None:
                        if field.data != field.default:
                            conf = ConfigSettings(internal=internal,
                                                  external=external,
                                                  section=sectionid)
                            conf.value = field.data
                            conf.server = server
                            updated = True
                            Session.add(conf)
                            Session.commit()
                            subs = dict(svr=server.hostname,
                                        s=external,
                                        a=conf.value)
                            info = HOSTSETTING_MSG % subs
                            audit_log(c.user.username, 3, info, request.host,
                                      request.remote_addr, now())
                    else:
                        if conf.value != field.data:
                            conf.value = field.data
                            updated = True
                            Session.add(conf)
                            Session.commit()
                            subs = dict(svr=conf.server.hostname,
                                        s=external,
                                        a=conf.value)
                            info = HOSTSETTING_MSG % subs
                            audit_log(c.user.username, 2, info, request.host,
                                      request.remote_addr, now())
            if updated:
                flash(
                    _('%(settings)s updated') %
                    dict(settings=CONFIG_SECTIONS[int(sectionid)]))
                update_serial.delay()
            else:
                flash_info(_('No configuration changes made'))
            #redirect(url('settings-scanner', serverid=serverid))
        return render('/settings/section.html')

    @ActionProtector(OwnsDomain())
    def domain_settings(self, domainid):
        "Domain settings landing"
        domain = self._get_domain(domainid)
        if not domain:
            abort(404)
        c.domain = domain
        return render('/settings/domain_settings.html')

    @ActionProtector(OwnsDomain())
    def domain_dkim(self, domainid):
        "Domain DKIM settings"
        domain = self._get_domain(domainid)
        if not domain:
            abort(404)
        c.domain = domain
        return render('/settings/domain_dkim.html')

    @ActionProtector(OwnsDomain())
    def domain_dkim_generate(self, domainid):
        "Domain DKIM generate keys"
        domain = self._get_domain(domainid)
        if not domain:
            abort(404)
        pub_key, pri_key = make_key_pair()
        if domain.dkimkeys:
            dkimkeys = domain.dkimkeys[0]
        else:
            dkimkeys = DKIMKeys()
        dkimkeys.pub_key = pub_key
        dkimkeys.pri_key = pri_key
        try:
            if domain.dkimkeys:
                domain.dkimkeys[0] = dkimkeys
            else:
                domain.dkimkeys.append(dkimkeys)
            Session.add(dkimkeys)
            Session.add(domain)
            Session.commit()
            info = DKIMGEN_MSG % dict(d=domain.name)
            audit_log(c.user.username, 3, info, request.host,
                      request.remote_addr, now())
            flash(_('DKIM keys successfully generated'))
        except DatabaseError:
            flash_alert(_('Generation of DKIM keys failed'))
        redirect(url('domain-dkim', domainid=domain.id))

    @ActionProtector(OwnsDomain())
    def domain_dkim_enable(self, domainid):
        "Enable or disable DKIM signing"
        domain = self._get_domain(domainid)
        if not domain or not domain.dkimkeys:
            abort(404)
        c.form = DKIMForm(request.POST,
                          domain.dkimkeys[0],
                          csrf_context=session)
        if request.POST and c.form.validate():
            dkimkeys = domain.dkimkeys[0]
            if dkimkeys.enabled != c.form.enabled.data:
                dkimkeys.enabled = c.form.enabled.data
                Session.add(dkimkeys)
                Session.commit()
                if c.form.enabled.data:
                    state = _('enabled')
                    save_dkim_key.apply_async(
                        args=[domain.name, dkimkeys.pri_key],
                        queue='msbackend')
                    info = DKIMENABLED_MSG % dict(d=domain.name)
                else:
                    info = DKIMDISABLED_MSG % dict(d=domain.name)
                    delete_dkim_key.apply_async(args=[domain.name],
                                                queue='msbackend')
                    state = _('disabled')
                audit_log(c.user.username, 2, info, request.host,
                          request.remote_addr, now())
                reload_exim.delay()
                flash(
                    _('DKIM signing for: %s has been %s') %
                    (domain.name, state))
            else:
                flash(_('DKIM signing status: No changes made'))
            redirect(url('domain-dkim', domainid=domain.id))
        c.domain = domain
        return render('/settings/domain_dkim_enable.html')

    @ActionProtector(OwnsDomain())
    def domain_sigs(self, domainid):
        "Domain signatures landing"
        domain = self._get_domain(domainid)
        if not domain:
            abort(404)
        c.domain = domain
        return render('/settings/domain_sigs.html')

    @ActionProtector(OwnsDomain())
    def domain_rules(self, domainid):
        "Domain rulesets"
        domain = self._get_domain(domainid)
        if not domain:
            abort(404)
        c.domain = domain
        return render('/settings/domain_rules.html')

    @ActionProtector(OwnsDomain())
    def add_domain_sigs(self, domainid):
        "Add domain signature"
        domain = self._get_domain(domainid)
        if not domain:
            abort(404)

        c.form = SigForm(request.POST, csrf_context=session)
        if request.POST and c.form.validate():
            try:
                sig = DomSignature()
                for field in c.form:
                    if field.name != 'csrf_token':
                        setattr(sig, field.name, field.data)
                domain.signatures.append(sig)
                Session.add(sig)
                Session.add(domain)
                Session.commit()
                save_dom_sig.apply_async(args=[sig.id], queue='msbackend')
                info = ADDDOMSIG_MSG % dict(d=domain.name)
                audit_log(c.user.username, 3, info, request.host,
                          request.remote_addr, now())
                flash(_('The signature has been created'))
                redirect(url('domain-settings-sigs', domainid=domainid))
            except IntegrityError:
                Session.rollback()
                flash(_('This signature type already exists'))
        c.domain = domain
        return render('/settings/domain_addsig.html')

    @ActionProtector(OwnsDomain())
    def edit_domain_sigs(self, sigid):
        "Edit domain signatures"
        sign = self._get_domsign(sigid)
        if not sign:
            abort(404)

        c.form = SigForm(request.POST, sign, csrf_context=session)
        del c.form['signature_type']
        if request.POST and c.form.validate():
            try:
                updated = False
                for field in c.form:
                    if (field.name != 'csrf_token'
                            and field.data != getattr(sign, field.name)):
                        updated = True
                        setattr(sign, field.name, field.data)
                if updated:
                    Session.add(sign)
                    Session.commit()
                    save_dom_sig.apply_async(args=[sigid], queue='msbackend')
                    info = UPDATEDOMSIG_MSG % dict(d=sign.domain.name)
                    audit_log(c.user.username, 2, info, request.host,
                              request.remote_addr, now())
                    flash(_('The signature has been updated'))
                else:
                    flash(_('No changes made, signature not updated'))
                redirect(url('domain-settings-sigs', domainid=sign.domain_id))
            except IntegrityError:
                Session.rollback()
                flash(_('Error occured updating the signature'))
        c.sign = sign
        return render('/settings/domain_editsig.html')

    @ActionProtector(OwnsDomain())
    def delete_domain_sigs(self, sigid):
        "Delete domain signature"
        sign = self._get_domsign(sigid)
        if not sign:
            abort(404)

        c.form = SigForm(request.POST, sign, csrf_context=session)
        del c.form['signature_type']
        if request.POST and c.form.validate():
            domain_id = sign.domain_id
            domain_name = sign.domain.name
            files = []
            basedir = config.get('ms.signatures.base',
                                 '/etc/MailScanner/signatures')
            if sign.signature_type == 1:
                domain = self._get_domain(domain_id)
                if domain:
                    sigfile = os.path.join(basedir, 'domains', domain.name,
                                           'sig.txt')
                    files.append(sigfile)
            else:
                if sign.image:
                    imgfile = os.path.join(basedir, 'domains', domain.name,
                                           sign.image.name)
                    files.append(imgfile)
                sigfile = os.path.join(basedir, 'domains', domain.name,
                                       'sig.html')
                files.append(sigfile)
            Session.delete(sign)
            Session.commit()
            delete_sig.apply_async(args=[files], queue='msbackend')
            info = DELETEDOMSIG_MSG % dict(d=domain_name)
            audit_log(c.user.username, 4, info, request.host,
                      request.remote_addr, now())
            flash(_('The signature has been deleted'))
            redirect(url('domain-settings-sigs', domainid=domain_id))
        c.sign = sign
        return render('/settings/domain_deletesig.html')

    @ActionProtector(CanAccessAccount())
    def add_account_sigs(self, userid):
        "Add account signature"
        account = self._get_user(userid)
        if not account:
            abort(404)

        c.form = SigForm(request.POST, csrf_context=session)
        if request.POST and c.form.validate():
            try:
                sig = UserSignature()
                for field in c.form:
                    if field.name != 'csrf_token':
                        setattr(sig, field.name, field.data)
                account.signatures.append(sig)
                Session.add(sig)
                Session.add(account)
                Session.commit()
                save_user_sig.apply_async(args=[sig.id], queue='msbackend')
                info = ADDACCSIG_MSG % dict(u=account.username)
                audit_log(c.user.username, 3, info, request.host,
                          request.remote_addr, now())
                flash(_('The signature has been created'))
                redirect(url('account-detail', userid=userid))
            except IntegrityError:
                Session.rollback()
                flash(_('This signature type already exists'))
        c.account = account
        return render('/settings/account_addsig.html')

    @ActionProtector(CanAccessAccount())
    def edit_account_sigs(self, sigid):
        "Edit account signatures"
        sign = self._get_usrsign(sigid)
        if not sign:
            abort(404)

        c.form = SigForm(request.POST, sign, csrf_context=session)
        del c.form['signature_type']
        if request.POST and c.form.validate():
            try:
                updated = False
                for field in c.form:
                    if (field.name != 'csrf_token'
                            and field.data != getattr(sign, field.name)):
                        updated = True
                        setattr(sign, field.name, field.data)
                if updated:
                    Session.add(sign)
                    Session.commit()
                    save_user_sig.apply_async(args=[sigid], queue='msbackend')
                    info = UPDATEACCSIG_MSG % dict(u=sign.user.username)
                    audit_log(c.user.username, 2, info, request.host,
                              request.remote_addr, now())
                    flash(_('The signature has been updated'))
                else:
                    flash(_('No changes made, signature not updated'))
                redirect(url('account-detail', userid=sign.user_id))
            except IntegrityError:
                Session.rollback()
                flash(_('Error occured updating the signature'))
        c.sign = sign
        return render('/settings/account_editsig.html')

    @ActionProtector(CanAccessAccount())
    def delete_account_sigs(self, sigid):
        "Delete account signatures"
        sign = self._get_usrsign(sigid)
        if not sign:
            abort(404)

        c.form = SigForm(request.POST, sign, csrf_context=session)
        del c.form['signature_type']
        if request.POST and c.form.validate():
            user_id = sign.user_id
            user_name = sign.user.username
            files = []
            basedir = config.get('ms.signatures.base',
                                 '/etc/MailScanner/signatures')
            if sign.signature_type == 1:
                user = self._get_user(user_id)
                if user:
                    sigfile = os.path.join(basedir, 'users', user.username,
                                           'sig.txt')
                    files.append(sigfile)
            else:
                if sign.image:
                    imgfile = os.path.join(basedir, 'users', user.username,
                                           sign.image.name)
                    files.append(imgfile)
                sigfile = os.path.join(basedir, 'users', user.username,
                                       'sig.html')
                files.append(sigfile)
            Session.delete(sign)
            Session.commit()
            delete_sig.apply_async(args=[files], queue='msbackend')
            info = DELETEACCSIG_MSG % dict(u=user_name)
            audit_log(c.user.username, 4, info, request.host,
                      request.remote_addr, now())
            flash(_('The signature has been deleted'))
            redirect(url('account-detail', userid=user_id))
        c.sign = sign
        return render('/settings/account_deletesig.html')

    @ActionProtector(OnlySuperUsers())
    def setnum(self, format=None):
        "Set number of items returned"
        num = check_num_param(request)

        if num and num in [10, 20, 50, 100]:
            session['settings_num_items'] = num
            session.save()
        nextpage = request.headers.get('Referer', '/')
        if '://' in nextpage:
            from_url = urlparse(nextpage)
            nextpage = from_url[2]
        redirect(nextpage)
Exemplo n.º 3
0
from baruwa.model.meta import Session
from baruwa.lib.audit import audit_log
from baruwa.lib.auth.predicates import OnlySuperUsers
from baruwa.tasks.settings import update_serial
from baruwa.model.accounts import Group, User, Relay
from baruwa.model.domains import Domain
from baruwa.forms.organizations import OrgForm, RelayForm, RelayEditForm
from baruwa.forms.organizations import DelOrgForm
from baruwa.forms.organizations import ImportCSVForm
from baruwa.tasks import importdomains
from baruwa.lib.audit.msgs.organizations import *

log = logging.getLogger(__name__)


@ControllerProtector(All(not_anonymous(), OnlySuperUsers()))
class OrganizationsController(BaseController):
    def __before__(self):
        "set context"
        BaseController.__before__(self)
        if self.identity:
            c.user = self.identity['user']
        else:
            c.user = None
        c.selectedtab = 'organizations'

    def _get_org(self, orgid):
        "Get organization"
        try:
            org = Session.query(Group).options(
                joinedload('domains')).get(orgid)
Exemplo n.º 4
0
class StatusController(BaseController):
    def __before__(self):
        "set context"
        BaseController.__before__(self)
        if self.identity:
            c.user = self.identity['user']
        else:
            c.user = None
        c.selectedtab = 'status'

    def _get_server(self, serverid):
        "utility"
        try:
            server = Session.query(Server).get(serverid)
        except NoResultFound:
            server = None
        return server

    @ActionProtector(OnlyAdminUsers())
    def index(self):
        "System status"
        c.servers = Session.query(Server).filter(
                    Server.hostname != 'default').all()
        labels = dict(clean=_('Clean'),
                    highspam=_('High scoring spam'),
                    lowspam=_('Low scoring spam'),
                    virii=_('Virus infected'),
                    infected=_('Policy blocked'))
        pie_colors = dict(clean='#006400',
                    highspam='#FF0000',
                    lowspam='#ffa07a',
                    virii='#000000',
                    infected='#d2691e')
        jsondata = [dict(tooltip=labels[attr],
                    y=getattr(c.baruwa_totals, attr),
                    stroke='black',
                    color=pie_colors[attr])
                    for attr in ['clean', 'highspam', 'lowspam', 'virii',
                    'infected'] if getattr(c.baruwa_totals, attr)]
        c.chart_data = json.dumps(jsondata)
        return render('/status/index.html')

    def graph(self, nodeid=None):
        "Generate graphical system status"
        totals = DailyTotals(Session, c.user)
        if nodeid:
            server = self._get_server(nodeid)
            if not server:
                abort(404)
            baruwa_totals = totals.get(hostname=server.hostname)
        else:
            baruwa_totals = totals.get()

        if not baruwa_totals.total:
            abort(404)

        piedata = []
        labels = []
        for attr in ['clean', 'highspam', 'lowspam', 'virii', 'infected']:
            value = getattr(baruwa_totals, attr) or 0
            piedata.append(value)
            if baruwa_totals.total > 0:
                labels.append(("%.1f%% %s" % ((1.0 * value /
                        baruwa_totals.total) * 100, attr)))
            else:
                labels.append('0%')
        pie = PieChart(350, 264)
        pie.chart.labels = labels
        pie.chart.data = piedata
        pie.chart.width = 180
        pie.chart.height = 180
        pie.chart.x = 90
        pie.chart.y = 30
        pie.chart.slices.strokeWidth = 1
        pie.chart.slices.strokeColor = colors.black
        pie.chart.slices[0].fillColor = PIE_CHART_COLORS[5]
        pie.chart.slices[1].fillColor = PIE_CHART_COLORS[0]
        pie.chart.slices[2].fillColor = PIE_CHART_COLORS[1]
        pie.chart.slices[3].fillColor = PIE_CHART_COLORS[9]
        pie.chart.slices[4].fillColor = PIE_CHART_COLORS[3]
        self.imgfile = StringIO()
        renderPM.drawToFile(pie,
                            self.imgfile, 'PNG',
                            bg=colors.HexColor('#ffffff'))
        response.content_type = 'image/png'
        response.headers['Cache-Control'] = 'max-age=0'
        return self.imgfile.getvalue()

    def mailq(self, serverid=None, queue='inbound', page=1, direction='dsc',
        order_by='timestamp'):
        "Display mailqueue"
        server = None
        if not serverid is None:
            server = self._get_server(serverid)
            if not server:
                abort(404)

        c.queue = queue
        c.server = server
        c.direction = direction
        c.order_by = desc(order_by) if direction == 'dsc' else order_by
        if queue == 'inbound':
            qdirection = 1
        else:
            qdirection = 2

        num_items = session.get('mailq_num_items', 10)

        query = Session.query(MailQueueItem).filter(
                MailQueueItem.direction == qdirection).order_by(order_by)

        if server:
            query = query.filter(MailQueueItem.hostname == server.hostname)

        uquery = UserFilter(Session, c.user, query, model=MailQueueItem)
        query = uquery.filter()

        c.form = MailQueueProcessForm(request.POST, csrf_context=session)
        pages = paginate.Page(query, page=int(page), items_per_page=num_items)
        choices = [(str(item.id), item.id) for item in pages.items]
        session['queue_choices'] = choices
        session.save()

        c.page = paginate.Page(query, page=int(page),
                                items_per_page=num_items)
        return render('/status/mailq.html')

    def process_mailq(self):
        "Process mailq"
        sendto = url('mailq-status')
        choices = session.get('queue_choices', [])
        form = MailQueueProcessForm(request.POST, csrf_context=session)
        form.id.choices = choices

        if request.POST and form.validate() and choices:
            queueids = form.id.data
            if form.queue_action.data != '0':
                hosts = {}
                direction = None
                queueitems = Session.query(MailQueueItem)\
                            .filter(MailQueueItem.id.in_(queueids))\
                            .all()
                for item in queueitems:
                    if not item.hostname in hosts:
                        hosts[item.hostname] = []
                    if not direction:
                        direction = item.direction
                    hosts[item.hostname].append(item.messageid)
                for hostname in hosts:
                    process_queued_msgs.apply_async(args=[hosts[hostname],
                                                    form.queue_action.data,
                                                    direction],
                                                    queue=hostname)
                flash(_('The request has been queued for processing'))
            session['queue_choices'] = []
            session.save()

        referer = request.headers.get('Referer', None)
        if referer and '/mailq' in referer:
            sendto = referer
        redirect(sendto)

    def mailq_detail(self, queueid):
        "View a queued message's details"
        query = Session.query(MailQueueItem)
        uquery = UserFilter(Session, c.user, query, model=MailQueueItem)
        query = uquery.filter()

        try:
            mailqitem = query.filter(MailQueueItem.id == queueid).one()
        except NoResultFound:
            #abort(404)
            flash_alert(_('The requested queued message was not found.'))
            redirect(url('mailq-status'))

        c.mailqitem = mailqitem
        c.form = MailQueueProcessForm(request.POST, csrf_context=session)
        session['queue_choices'] = [(queueid, queueid),]
        session.save()
        return render('/status/detail.html')

    def mailq_preview(self, queueid, attachid=None, imgid=None, allowimgs=None):
        "preview a queued message"
        query = Session.query(MailQueueItem)
        uquery = UserFilter(Session, c.user, query, model=MailQueueItem)
        query = uquery.filter()

        try:
            mailqitem = query.filter(MailQueueItem.id == queueid).one()
        except NoResultFound:
            flash_alert(_('The requested queued message was not found.'))
            redirect(url('mailq-status'))

        try:
            task = preview_queued_msg.apply_async(args=[mailqitem.messageid,
                    mailqitem.direction, attachid, imgid],
                    queue=mailqitem.hostname)
            task.wait(30)
            if task.result:
                if imgid:
                    response.content_type = task.result['content_type']
                    if task.result and 'img' in task.result:
                        info = QUEUEDOWNLOAD_MSG % dict(m=mailqitem.messageid,
                                                        a=task.result['name'])
                        audit_log(c.user.username,
                                1, info, request.host,
                                request.remote_addr, datetime.now())
                        return base64.decodestring(task.result['img'])
                    abort(404)
                if attachid:
                    info = QUEUEDOWNLOAD_MSG % dict(m=mailqitem.messageid,
                                                    a=task.result['name'])
                    audit_log(c.user.username,
                            1, info, request.host,
                            request.remote_addr, datetime.now())
                    response.content_type = task.result['mimetype']
                    dispos = 'attachment; filename="%s"' % task.result['name']
                    response.headers['Content-Disposition'] = dispos
                    content_len = len(task.result['attachment'])
                    response.headers['Content-Length'] = content_len
                    response.headers['Pragma'] = 'public'
                    response.headers['Cache-Control'] = 'max-age=0'
                    return base64.decodestring(task.result['attachment'])
                for part in task.result['parts']:
                    if part['type'] == 'html':
                        html = fromstring(part['content'])
                        for element, attribute, link, pos in iterlinks(html):
                            if not link.startswith('cid:'):
                                if not allowimgs and attribute == 'src':
                                    element.attrib['src'] = '%simgs/blocked.gif' % media_url()
                                    element.attrib['title'] = link
                                    flash(_('This message contains external images, which have been blocked. ') +
                                    literal(link_to(_('Display images'),
                                    url('queue-preview-with-imgs', queueid=queueid), class_='uline')))
                            else:
                                imgname = link.replace('cid:', '')
                                element.attrib['src'] = url('queue-preview-img',
                                                        imgid=imgname.replace('/', '__xoxo__'),
                                                        queueid=queueid)
                        part['content'] = tostring(html)
                c.message = task.result
                info = QUEUEPREVIEW_MSG % dict(m=mailqitem.messageid)
                audit_log(c.user.username,
                        1, info, request.host,
                        request.remote_addr, datetime.now())
            else:
                raise TimeoutError
        except (TimeoutError, QueueNotFound):
            flash_alert(_('The message could not be processed'))
            redirect(url('mailq-status'))
        c.queueid = queueid
        c.messageid = mailqitem.messageid
        return render('/status/preview.html')

    @ActionProtector(OnlySuperUsers())
    def server_status(self, serverid):
        "Display server status"
        server = self._get_server(serverid)
        if not server:
            abort(404)

        totals = DailyTotals(Session, c.user)
        mailq = MailQueue(Session, c.user)
        totals = totals.get(server.hostname)
        inbound = mailq.get(1, server.hostname)[0]
        outbound = mailq.get(2, server.hostname)[0]

        statusdict = dict(total=totals.total,
                        mta=0,
                        scanners=0,
                        av=0,
                        clean_mail=totals.clean,
                        high_spam=totals.highspam,
                        virii=totals.virii,
                        spam_mail=totals.lowspam,
                        inq=inbound,
                        outq=outbound,
                        otherinfected=totals.infected,
                        uptime='Unknown',
                        load=(0, 0, 0),
                        mem=dict(free=0, used=0, total=0,
                                percent=0),
                        partitions=[],
                        net={},
                        cpu=0)
        try:
            task = systemstatus.apply_async(queue=server.hostname)
            task.wait(30)
            hoststatus = task.result
            statusdict.update(hoststatus)
            info = HOSTSTATUS_MSG % dict(n=server.hostname)
            audit_log(c.user.username,
                    1, info, request.host,
                    request.remote_addr, datetime.now())
        except (TimeoutError, QueueNotFound):
            pass

        c.server = server
        c.status = statusdict
        return render('/status/serverstatus.html')

    @ActionProtector(OnlySuperUsers())
    def server_bayes_status(self, serverid):
        "Display bayes stats"
        server = self._get_server(serverid)
        if not server:
            abort(404)

        try:
            task = bayesinfo.apply_async(queue=server.hostname)
            task.wait(30)
            result = task.result
            info = HOSTBAYES_MSG % dict(n=server.hostname)
            audit_log(c.user.username,
                    1, info, request.host,
                    request.remote_addr, datetime.now())
        except (TimeoutError, QueueNotFound):
            result = {}
        c.server = server
        c.data = result
        return render('/status/bayes.html')

    @ActionProtector(OnlySuperUsers())
    def server_salint_stat(self, serverid):
        "Display server salint output"
        server = self._get_server(serverid)
        if not server:
            abort(404)

        try:
            task = salint.apply_async(queue=server.hostname)
            task.wait(30)
            result = task.result
            info = HOSTSALINT_MSG % dict(n=server.hostname)
            audit_log(c.user.username,
                    1, info, request.host,
                    request.remote_addr, datetime.now())
        except (TimeoutError, QueueNotFound):
            result = []
        c.server = server
        c.data = result
        return render('/status/salint.html')

    @ActionProtector(OnlySuperUsers())
    def audit(self, page=1, format=None):
        "Audit log"
        total_found = 0
        search_time = 0
        num_items = session.get('auditlog_num_items', 50)
        q = request.GET.get('q', None)
        kwds = {}
        if q:
            conn = SphinxClient()
            conn.SetMatchMode(SPH_MATCH_EXTENDED2)
            if page == 1:
                conn.SetLimits(0, num_items, 500)
            else:
                page = int(page)
                offset = (page - 1) * num_items
                conn.SetLimits(offset, num_items, 500)
            q = clean_sphinx_q(q)
            results = conn.Query(q, 'auditlog, auditlog_rt')
            q = restore_sphinx_q(q)
            if results and results['matches']:
                ids = [hit['id'] for hit in results['matches']]
                query = Session.query(AuditLog)\
                        .filter(AuditLog.id.in_(ids))\
                        .order_by(desc('timestamp'))\
                        .all()
                total_found = results['total_found']
                search_time = results['time']
                logcount = total_found
                kwds['presliced_list'] = True
            else:
                query = []
                lcount = 0
                logcount = 0
        else:
            query = Session.query(AuditLog)\
                    .order_by(desc('timestamp'))
            lcount = Session.query(AuditLog)\
                    .order_by(desc('timestamp'))
        if not 'logcount' in locals():
            logcount = lcount.count()
        items = paginate.Page(query, page=int(page),
                            items_per_page=num_items,
                            item_count=logcount, **kwds)
        if format == 'json':
            response.headers['Content-Type'] = 'application/json'
            jdict = convert_settings_to_json(items)
            if q:
                encoded = json.loads(jdict)
                encoded['q'] = q
                jdict = json.dumps(encoded)
            return jdict

        c.page = items
        c.q = q
        c.total_found = total_found
        c.search_time = search_time
        return render('/status/audit.html')

    @ActionProtector(OnlySuperUsers())
    def audit_export(self, isquery=None, format=None):
        "Export audit logs"
        query = request.GET.get('q', None)
        if isquery and query is None:
            flash_alert(_('No query specified for audit log export'))
            redirect(url('status-audit-logs'))

        task = export_auditlog.apply_async(args=[format, query])
        if not 'taskids' in session:
            session['taskids'] = []
        session['taskids'].append(task.task_id)
        session['exportauditlog-counter'] = 1
        session.save()
        redirect(url('status-auditlog-export-status', taskid=task.task_id))

    @ActionProtector(OnlySuperUsers())
    def audit_export_status(self, taskid):
        "Audit log export status"
        result = AsyncResult(taskid)
        if result is None or taskid not in session['taskids']:
            flash(_('The task status requested has expired or does not exist'))
            redirect(url('status-audit-logs'))

        if result.ready():
            finished = True
            flash.pop_messages()
            if isinstance(result.result, Exception):
                if c.user.is_superadmin:
                    flash_alert(_('Error occured in processing %s') %
                                result.result)
                else:
                    flash_alert(_('Backend error occured during processing.'))
                redirect(url('status-audit-logs'))
        else:
            session['exportauditlog-counter'] += 1
            session.save()
            if (session['exportauditlog-counter'] >= 20 and
                result.state in ['PENDING', 'RETRY', 'FAILURE']):
                result.revoke()
                del session['exportauditlog-counter']
                session.save()
                flash_alert(_('The audit log export failed, try again later'))
                redirect(url('status-audit-logs'))
            finished = False

        c.finished = finished
        c.results = result.result
        c.success = result.successful()
        d = request.GET.get('d', None)
        if finished and (d and d == 'y'):
            audit_log(c.user.username,
                    5, AUDITLOGEXPORT_MSG, request.host,
                    request.remote_addr, datetime.now())
            response.content_type = result.result['content_type']
            response.headers['Cache-Control'] = 'max-age=0'
            respdata = result.result['f']
            disposition = 'attachment; filename=%s' % result.result['filename']
            response.headers['Content-Disposition'] = disposition
            response.headers['Content-Length'] = len(respdata)
            return respdata
        return render('/status/auditexportstatus.html')

    def setnum(self, format=None):
        "Set number of items to return for auditlog/mailq"
        app = request.GET.get('ac', 'mailq')
        num = check_num_param(request)

        if num and num in [10, 20, 50, 100]:
            if app == 'auditlog':
                session['auditlog_num_items'] = num
            else:
                session['mailq_num_items'] = num
            session.save()
        nextpage = request.headers.get('Referer', '/')
        if '://' in nextpage:
            from_url = urlparse(nextpage)
            nextpage = from_url[2]
        redirect(nextpage)
Exemplo n.º 5
0
class DomainsController(BaseController):
    "Domains controller"

    def __before__(self):
        "set context"
        BaseController.__before__(self)
        if self.identity:
            c.user = self.identity['user']
        else:
            c.user = None
        c.selectedtab = 'domains'

    def _get_server(self, destinationid):
        "utility"
        try:
            cachekey = u'deliveryserver-%s' % destinationid
            qry = Session.query(DeliveryServer)\
                    .filter(DeliveryServer.id == destinationid)\
                    .options(FromCache('sql_cache_med', cachekey))
            if self.invalidate:
                qry.invalidate()
            server = qry.one()
        except NoResultFound:
            server = None
        return server

    def _get_authserver(self, authid):
        "Get an auth server"
        try:
            cachekey = u'authserver-%s' % authid
            qry = Session.query(AuthServer).filter(AuthServer.id == authid)\
                .options(FromCache('sql_cache_med', cachekey))
            if self.invalidate:
                qry.invalidate()
            server = qry.one()
        except NoResultFound:
            server = None
        return server

    def _get_alias(self, aliasid):
        "Get a domain alias"
        try:
            cachekey = u'domainalias-%s' % aliasid
            qry = Session.query(DomainAlias).filter(DomainAlias.id == aliasid)\
                .options(FromCache('sql_cache_med', cachekey))
            if self.invalidate:
                qry.invalidate()
            alias = qry.one()
        except NoResultFound:
            alias = None
        return alias

    def index(self, page=1, orgid=None, format=None):
        "Browse domains"
        num_items = session.get('domains_num_items', 10)
        c.form = BulkDelDomains(request.POST, csrf_context=session)
        if request.method == 'POST':
            if c.form.domainid.data and c.form.whatdo.data == 'disable':
                Session.query(Domain).filter(
                    Domain.id.in_(c.form.domainid.data)).update(
                        {'status': False}, synchronize_session='fetch')
                Session.commit()
            if c.form.domainid.data and c.form.whatdo.data == 'enable':
                Session.query(Domain).filter(
                    Domain.id.in_(c.form.domainid.data)).update(
                        {'status': True}, synchronize_session='fetch')
                Session.commit()
            if c.form.domainid.data and c.form.whatdo.data == 'delete':
                session['bulk_domain_delete'] = c.form.domainid.data
                session.save()
                # redirect for confirmation
                redirect(url('domains-confirm-delete'))
        domains = Session.query(Domain).options(
            joinedload(Domain.organizations))
        domcount = Session.query(Domain.id)

        if orgid and c.user.is_superadmin:
            domains = domains.join(domain_owners).filter(
                domain_owners.c.organization_id == orgid)
            domcount = domcount.join(domain_owners).filter(
                domain_owners.c.organization_id == orgid)
        if c.user.is_domain_admin:
            domains = domains.join(domain_owners,
                    (oa, domain_owners.c.organization_id ==
                        oa.c.organization_id))\
                    .filter(oa.c.user_id == c.user.id)
            domcount = domcount.join(domain_owners,
                    (oa, domain_owners.c.organization_id ==
                        oa.c.organization_id))\
                    .filter(oa.c.user_id == c.user.id)

        pages = paginate.Page(domains,
                              page=int(page),
                              items_per_page=num_items,
                              item_count=domcount.count())
        if format == 'json':
            response.headers['Content-Type'] = 'application/json'
            data = convert_dom_to_json(pages, orgid)
            return data

        c.orgid = orgid
        c.page = pages
        return self.render('/domains/index.html')

    def search(self, format=None):
        "Search for domains"
        total_found = 0
        search_time = 0
        num_items = session.get('domains_num_items', 10)
        qry = request.GET.get('q', '')
        org = request.GET.get('o', None)
        page = int(request.GET.get('p', 1))
        # if q:
        kwds = {'presliced_list': True}
        conn = SphinxClient()
        sphinxopts = extract_sphinx_opts(config['sphinx.url'])
        conn.SetServer(sphinxopts.get('host', '127.0.0.1'))
        conn.SetMatchMode(SPH_MATCH_EXTENDED2)
        if page == 1:
            conn.SetLimits(0, num_items, 500)
        else:
            offset = (page - 1) * num_items
            conn.SetLimits(offset, num_items, 500)
        if org:
            conn.SetFilter('orgs', [int(org)])
        if c.user.is_domain_admin:
            crcs = get_dom_crcs(Session, c.user)
            conn.SetFilter('domain_name', crcs)
        qry = clean_sphinx_q(qry)
        try:
            results = conn.Query(qry, 'domains, domains_rt')
        except (socket.timeout, struct.error):
            redirect(request.path_qs)
        qry = restore_sphinx_q(qry)
        if results and results['matches']:
            ids = [hit['id'] for hit in results['matches']]
            domains = Session.query(Domain)\
                    .options(joinedload('organizations'))\
                    .filter(Domain.id.in_(ids))\
                    .all()
            total_found = results['total_found']
            search_time = results['time']
            domaincount = total_found
        else:
            domains = []
            domaincount = 0

        c.page = paginate.Page(domains,
                               page=page,
                               items_per_page=num_items,
                               item_count=domaincount,
                               **kwds)
        c.q = qry
        c.org = org
        c.total_found = total_found
        c.search_time = search_time
        return self.render('/domains/searchresults.html')

    @ActionProtector(OwnsDomain())
    def detail(self, domainid):
        "Domain details"
        domain = self._get_domain(domainid)
        if not domain:
            abort(404)
        c.domain = domain
        return self.render('/domains/detail.html')

    @ActionProtector(OnlySuperUsers())
    def add(self, orgid=None):
        "Add a domain"
        c.form = AddDomainForm(request.POST, csrf_context=session)
        c.form.organizations.query = get_organizations(orgid)
        if request.method == 'POST' and c.form.validate():
            try:
                domain = create_domain(c.form, c.user, request.host,
                                       request.remote_addr)
                try:
                    from baruwa.tasks.invite import create_mx_records
                    create_mx_records.apply_async(args=[domain.name])
                except ImportError:
                    pass
                flash(
                    _('The domain: %(dom)s has been created') %
                    dict(dom=domain.name))
                redirect(url(controller='domains'))
            except IntegrityError:
                Session.rollback()
                msg = _('The domain name %(dom)s already exists') % \
                        dict(dom=domain.name)
                flash_alert(msg)
                log.info(msg)

        return self.render('/domains/new.html')

    @ActionProtector(OwnsDomain())
    def edit(self, domainid):
        "Edit a domain"
        domain = self._get_domain(domainid)
        if not domain:
            abort(404)

        c.id = domainid
        c.form = domain_update_form(c.user, request.POST, domain,
                                    get_organizations, session)
        if request.method == 'POST' and c.form.validate():
            kwd = dict(domainid=domain.id)
            if domain_update_if_changed(c.form, domain):
                try:
                    update_domain(domain, c.user, request.host,
                                  request.remote_addr)
                    flash(
                        _('The domain: %(dom)s has been updated') %
                        dict(dom=domain.name))
                    kwd['uc'] = 1
                except IntegrityError:
                    Session.rollback()
                    msg = _('The domain %(dom)s could not be updated') % \
                            dict(dom=domain.name)
                    flash(msg)
                    log.info(msg)
            else:
                msg = _('No changes were made to the domain')
                flash_info(msg)
                log.info(msg)
            redirect(url('domain-detail', **kwd))
        return self.render('/domains/edit.html')

    @ActionProtector(OwnsDomain())
    def delete(self, domainid):
        "Delete a domain"
        domain = self._get_domain(domainid)
        if not domain:
            abort(404)

        c.id = domainid
        c.form = EditDomainForm(request.POST, domain, csrf_context=session)
        del c.form.organizations
        if request.method == 'POST':
            if c.form.validate():
                delete_domain(domain, c.user, request.host,
                              request.remote_addr)
                flash(_('The domain has been deleted'))
                redirect(url(controller='domains'))
        else:
            flash(
                _('The domain: %(name)s and all associated data will'
                  ' be deleted, This action cannot be reversed.') %
                dict(name=domain.name))
        return self.render('/domains/delete.html')

    def confirm_delete(self):
        "Confirm bulk delete of domains"
        domainids = session.get('bulk_domain_delete', [])
        if not domainids:
            redirect(url(controller='domains', action='index'))

        num_items = 10
        if len(domainids) > num_items and len(domainids) <= 20:
            num_items = 20
        if len(domainids) > num_items and len(domainids) <= 50:
            num_items = 50
        if len(domainids) > num_items and len(domainids) <= 100:
            num_items = 100

        domains = Session.query(Domain).filter(Domain.id.in_(domainids))\
                    .options(joinedload('organizations'))
        domcount = Session.query(Domain.id).filter(Domain.id.in_(domainids))

        if c.user.is_domain_admin:
            domains = domains.join(domain_owners,
                        (oa,
                        domain_owners.c.organization_id ==
                        oa.c.organization_id))\
                        .filter(oa.c.user_id == c.user.id)
            domcount = domcount.join(domain_owners,
                        (oa, domain_owners.c.organization_id ==
                        oa.c.organization_id))\
                        .filter(oa.c.user_id == c.user.id)

        if request.method == 'POST':
            tasks = []
            for domain in domains.all():
                info = auditmsgs.DELETEDOMAIN_MSG % dict(d=domain.name)
                tasks.append((c.user.username, 4, unicode(info), request.host,
                              request.remote_addr, arrow.utcnow().datetime))
                Session.delete(domain)
            Session.commit()
            del session['bulk_domain_delete']
            update_domain_backend(None, True)
            session.save()
            for task in tasks:
                audit_log(*task)
            flash(_('The domains have been deleted'))
            redirect(url(controller='domains'))
        else:
            flash(
                _('The following domains are about to be deleted,'
                  ' this action is not reversible, Do you wish to'
                  ' continue ?'))

        try:
            c.page = paginate.Page(domains,
                                   page=1,
                                   items_per_page=num_items,
                                   item_count=domcount.count())
        except DataError, error:
            msg = _('An error occured try again')
            flash_alert(msg)
            msg = _('An error occured try again: %s' % error)
            log.info(msg)
            redirect(url(controller='domains', action='index'))
        return self.render('/domains/confirmbulkdel.html')
Exemplo n.º 6
0
                          request.remote_addr,
                          arrow.utcnow().datetime)
            else:
                raise TimeoutError
        except (TimeoutError, QueueNotFound), error:
            msg = _('The message could not be processed')
            flash_alert(msg)
            msg = _('The message could not be processed: %s') % error
            log.info(msg)
            redirect(url('mailq-status'))
        c.queueid = queueid
        c.messageid = mailqitem.messageid
        c.richformat = richformat
        return self.render('/status/preview.html')

    @ActionProtector(OnlySuperUsers())
    def server_status(self, serverid):
        "Display server status"
        server = self._get_server(serverid)
        if not server:
            abort(404)

        totals = DailyTotals(Session, c.user)
        mailq = MailQueue(Session, c.user)
        totals = totals.get(server.hostname)
        inbound = mailq.get(1, server.hostname)[0]
        outbound = mailq.get(2, server.hostname)[0]

        statusdict = dict(total=totals.total,
                          mta=0,
                          scanners=0,