benoit@0: # -*- encoding: utf-8 -*- benoit@0: # Description: benoit@0: # Farol Web Application benoit@0: # benoit@0: # Authors: benoit@0: # BenoƮt Allard benoit@0: # benoit@0: # Copyright: benoit@0: # Copyright (C) 2014 Greenbone Networks GmbH benoit@0: # benoit@0: # This program is free software; you can redistribute it and/or benoit@0: # modify it under the terms of the GNU General Public License benoit@0: # as published by the Free Software Foundation; either version 2 benoit@0: # of the License, or (at your option) any later version. benoit@0: # benoit@0: # This program is distributed in the hope that it will be useful, benoit@0: # but WITHOUT ANY WARRANTY; without even the implied warranty of benoit@0: # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the benoit@0: # GNU General Public License for more details. benoit@0: # benoit@0: # You should have received a copy of the GNU General Public License benoit@0: # along with this program; if not, write to the Free Software benoit@0: # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. benoit@0: benoit@0: import os benoit@13: import logging benoit@13: from logging import FileHandler benoit@19: import platform benoit@17: import urllib2 benoit@17: from xml.etree import ElementTree as ET benoit@0: benoit@15: import farolluz benoit@7: from farolluz.cvrf import CVRF, ValidationError benoit@7: from farolluz.parsers.cvrf import parse benoit@0: from farolluz.renderer import render as render_cvrf benoit@0: from farolluz.utils import utcnow benoit@0: benoit@15: import flask benoit@29: from flask import (Flask, request, render_template, redirect, url_for, flash, benoit@141: make_response, abort) benoit@0: from werkzeug import secure_filename benoit@146: import jinja2 benoit@0: benoit@15: from . import __version__, cache benoit@7: from .document import document benoit@12: from .session import get_current, set_current, has_current, document_required benoit@0: from .vulnerability import vulnerability benoit@0: from .producttree import producttree benoit@0: benoit@1: app = Flask(__name__, instance_relative_config=True) benoit@1: app.config.from_object('farol.config.Config') benoit@1: app.config.from_pyfile('farol.cfg', silent=True) benoit@0: benoit@12: app.register_blueprint(cache.mod, url_prefix='/cache') benoit@7: app.register_blueprint(document, url_prefix='/document') benoit@0: app.register_blueprint(vulnerability, url_prefix='/vulnerability') benoit@0: app.register_blueprint(producttree, url_prefix='/producttree') benoit@0: benoit@13: file_handler = FileHandler(os.path.join(app.instance_path, 'farol.log')) benoit@13: file_handler.setLevel(logging.WARNING) benoit@13: app.logger.addHandler(file_handler) benoit@3: benoit@0: @app.context_processor benoit@0: def cache_content(): benoit@0: """ List the documents in cache """ benoit@12: return dict(caching=cache.caching_type(), benoit@12: cache=cache.cache_content()) benoit@0: benoit@0: @app.context_processor benoit@0: def doc_properties(): benoit@0: if not has_current(): benoit@0: return {'has_current': False} benoit@0: cvrf = get_current() benoit@0: vulns = [(v.getTitle(), v._ordinal) for v in cvrf._vulnerabilities] benoit@0: prods = [] benoit@0: if cvrf._producttree: benoit@0: prods = [(p._name, p._productid) for p in cvrf._producttree._products] benoit@0: try: benoit@0: cvrf.validate() benoit@0: error = None benoit@0: except ValidationError as ve: benoit@0: error = ve benoit@102: return dict(has_current=True, vulnerabilities=vulns, products=prods, benoit@102: error=error, current_id=cvrf.getDocId()) benoit@0: benoit@0: @app.template_filter('secure_filename') benoit@0: def makeId(string): benoit@0: return secure_filename(string) benoit@0: benoit@140: @app.errorhandler(400) benoit@140: @app.errorhandler(404) benoit@140: @app.errorhandler(405) benoit@140: @app.errorhandler(500) benoit@140: def error_page(error): benoit@140: return render_template('error.j2', e=error), getattr(error, 'code', 500) benoit@140: benoit@141: @app.route('/500') benoit@141: def boom(): benoit@141: abort(500) benoit@141: benoit@7: @app.route('/') benoit@7: def welcome(): benoit@125: return render_template('welcome.j2', benoit@125: version=__version__, benoit@125: imports=[('New', 100), ('CVRF', 100)], benoit@125: exports=[('CVRF', 100), ('OpenVAS NASL from RHSA', 85), ('OVAL', 5) ], benoit@125: use_cases=[('Create a security advisory and publish as CVRF', 100), benoit@125: ('Edit a security advisory in CVRF format', 100)] benoit@125: ) benoit@7: benoit@155: def download_url(url): benoit@155: proxy_host = app.config.get('PROXY_HOST', '') benoit@155: if proxy_host: benoit@155: proxy = urllib2.ProxyHandler({'http': proxy_host, 'https': proxy_host}) benoit@155: opener = urllib2.build_opener(proxy) benoit@155: urllib2.install_opener(opener) benoit@155: try: content = urllib2.urlopen(url).read() benoit@17: except urllib2.HTTPError as e: benoit@17: flash('Unable to retrieve %s: %s' % (url, e)) benoit@17: return benoit@18: set_text(content) benoit@17: benoit@17: def set_RHSA(id_): benoit@17: # validate input benoit@17: if ':' not in id_: benoit@17: flash('Wrong RHSA id: %s' % id_) benoit@17: return benoit@17: year, index = id_.split(':', 1) benoit@17: try: benoit@17: int(year) benoit@17: int(index) benoit@17: except ValueError: benoit@17: flash('Wrong RHSA id: %s' % id_) benoit@17: return benoit@17: # Process it benoit@155: download_url("https://www.redhat.com/security/data/cvrf/%(year)s/cvrf-rhsa-%(year)s-%(index)s.xml" % {'year': year, 'index': index}) benoit@17: benoit@17: def set_oracle(id_): benoit@17: try: int(id_) benoit@17: except ValueError: benoit@17: flash('Wrong Oracle id: %s' % id_) benoit@17: return benoit@155: download_url("http://www.oracle.com/ocom/groups/public/@otn/documents/webcontent/%s.xml" % id_) benoit@17: benoit@17: def set_cisco(id_): benoit@17: if id_.count('-') < 2: benoit@17: flash('Wrong cisco id: %s' % id_) benoit@17: return benoit@17: kind, date, name = id_.split('-', 2) benoit@17: try: kind = {'sa': 'Advisory', 'sr': 'Response'}[kind] benoit@17: except KeyError: benoit@17: flash('Wrong cisco id: %s' % id_) benoit@17: return benoit@155: download_url("http://tools.cisco.com/security/center/contentxml/CiscoSecurity%(kind)s/cisco-%(id)s/cvrf/cisco-%(id)s_cvrf.xml" % {'kind': kind, 'id': id_}) benoit@8: benoit@18: def set_text(text): benoit@19: try: doc = parse(text) benoit@18: except ET.ParseError as e: benoit@19: flash('Unable to parse Document: %s' % e) benoit@18: return benoit@18: set_current(doc) benoit@18: benoit@0: @app.route('/new', methods=['GET', 'POST']) benoit@0: def new(): benoit@0: if request.method != 'POST': benoit@102: return render_template('new.j2', has_document=has_current(), now=utcnow()) benoit@12: benoit@8: if 'rhsa' in request.form: benoit@17: set_RHSA(request.form['id']) benoit@8: elif 'oracle' in request.form: benoit@17: set_oracle(request.form['id']) benoit@8: elif 'cisco' in request.form: benoit@17: set_cisco(request.form['id']) benoit@8: elif 'nasl' in request.form: benoit@8: flash("I'm not able to parse NASL scripts yet", 'danger') benoit@8: return redirect(url_for('new')) benoit@8: elif 'url' in request.form: benoit@155: download_url(request.form['url']) benoit@0: elif 'local' in request.files: benoit@0: upload = request.files['local'] benoit@18: fpath = os.path.join(app.instance_path, 'tmp', benoit@18: secure_filename(upload.filename)) benoit@21: if not os.path.exists(os.path.dirname(fpath)): benoit@21: os.makedirs(os.path.dirname(fpath)) benoit@0: upload.save(fpath) benoit@0: with open(fpath, 'rt') as f: benoit@18: set_text(f.read()) benoit@0: os.remove(fpath) benoit@0: elif 'text' in request.form: benoit@18: set_text(request.form['text'].encode('utf-8')) benoit@0: else: benoit@0: set_current(CVRF(request.form['title'], request.form['type'])) benoit@7: return redirect(url_for('document.view')) benoit@0: benoit@0: @app.route('/render/') benoit@0: @document_required benoit@0: def render(format_): benoit@0: cvrf = get_current() benoit@0: doc = render_cvrf(cvrf, format_ + '.j2') benoit@29: if 'raw' not in request.args: benoit@29: return render_template('render.j2', format_=format_, title=cvrf._title, type_=cvrf._type, doc=doc) benoit@29: response = make_response(doc) benoit@33: filename = secure_filename(cvrf.getDocId()) + "." + format_ benoit@29: response.headers["content-disposition"] = 'attachement; filename=' + filename benoit@29: response.headers["content-type"] = 'text/plain' benoit@29: return response benoit@0: benoit@0: @app.route('/about') benoit@0: def about(): benoit@19: versions = ((platform.python_implementation(), platform.python_version()), benoit@19: ('Farol', __version__), ('FarolLuz', farolluz.__version__), benoit@146: ('Flask', flask.__version__), ('Jinja', jinja2.__version__)) benoit@15: return render_template('about.j2', instance_dir=app.instance_path, versions=versions) benoit@0: