view farol/main.py @ 0:4a9f23230eba

Initial Release
author Benoît Allard <benoit.allard@greenbone.net>
date Wed, 24 Sep 2014 10:07:49 +0200
parents
children 63b00c10ada8
line wrap: on
line source
# -*- encoding: utf-8 -*-
# Description:
# Farol Web Application
#
# Authors:
# BenoƮt Allard <benoit.allard@greenbone.net>
#
# Copyright:
# Copyright (C) 2014 Greenbone Networks GmbH
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.

import os

from farolluz.cvrf import (CVRF, CVRFPublisher, CVRFTracking, CVRFTrackingID,
    CVRFGenerator, CVRFRevision, CVRFReference, CVRFAcknowledgment, CVRFNote,
    ValidationError, CVRFAggregateSeverity)
from farolluz.parsers.cvrf import parse, parseVersion, parseDate
from farolluz.py2 import urlopen
from farolluz.renderer import render as render_cvrf
from farolluz.utils import utcnow

from flask import Flask, request, render_template, redirect, url_for, flash, abort
from werkzeug import secure_filename

from .session import get_current, set_current, has_current, del_current, document_required
from .vulnerability import vulnerability
from .producttree import producttree

app = Flask(__name__)

app.register_blueprint(vulnerability, url_prefix='/vulnerability')
app.register_blueprint(producttree, url_prefix='/producttree')

@app.context_processor
def cache_content():
    """ List the documents in cache """
    if 'CACHE_DIRECTORY' not in app.config:
        return dict(cache=[])
    dirname = app.config['CACHE_DIRECTORY']
    if not os.path.exists(dirname):
        os.mkdir(dirname)
    l = []
    for path in os.listdir(dirname):
        name, ext = os.path.splitext(path)
        if ext == '.xml':
            l.append(name)
    return dict(cache=l)

@app.context_processor
def doc_properties():
    if not has_current():
        return {'has_current': False}
    cvrf = get_current()
    vulns = [(v.getTitle(), v._ordinal) for v in cvrf._vulnerabilities]
    prods = []
    if cvrf._producttree:
        prods = [(p._name, p._productid) for p in cvrf._producttree._products]
    try:
        cvrf.validate()
        error = None
    except ValidationError as ve:
        error = ve
    return dict(has_current=True, vulnerabilities=vulns, products=prods, error=error)

@app.template_filter('secure_filename')
def makeId(string):
    return secure_filename(string)

@app.route('/new', methods=['GET', 'POST'])
def new():
    if request.method != 'POST':
        return render_template('new.j2', has_document=has_current(), now=utcnow())

    if 'url' in request.form:
        set_current(parse(urlopen(request.form['url']).read()))
    elif 'local' in request.files:
        upload = request.files['local']
        if not upload.filename.endswith('.xml'):
            flash('Uploaded files should end in .xml', 'danger')
            return redirect(url_for('new'))
        fpath = os.path.join('/tmp', secure_filename(upload.filename))
        upload.save(fpath)
        with open(fpath, 'rt') as f:
            set_current(parse(f))
        os.remove(fpath)
    elif 'text' in request.form:
        set_current(parse(request.form['text'].encode('utf-8')))
    else:
        set_current(CVRF(request.form['title'], request.form['type']))
    return redirect(url_for('document'))

@app.route('/')
@document_required
def document():
    cvrf = get_current()
    return render_template('doc.j2', cvrf=cvrf)

@app.route('/title/edit', methods=['GET', 'POST'])
@document_required
def edit_title():
    if request.method != 'POST':
        return render_template('edit_title.j2', title = get_current()._title, _type = get_current()._type)


    get_current()._title = request.form['title']
    get_current()._type = request.form['type']
    return redirect(url_for('document'))

@app.route('/publisher/edit', methods=['GET', 'POST'])
@document_required
def edit_publisher():
    if request.method != 'POST':
        return render_template('edit_publisher.j2', publisher = get_current()._publisher or CVRFPublisher(''), types=CVRFPublisher.TYPES)

    publisher = CVRFPublisher(request.form['type'], request.form['vendorid'] or None)
    publisher.setContact(request.form['contact'] or None)
    publisher.setAuthority(request.form['authority'] or None)
    get_current().setPublisher(publisher)
    return redirect(url_for('document'))

@app.route('/tracking/edit', methods=['GET', 'POST'])
@document_required
def edit_tracking():
    wasNone = False
    tracking = get_current()._tracking
    if tracking is None:
        wasNone = True
        tracking = CVRFTracking(CVRFTrackingID(''), 'Draft', (0,), utcnow(), utcnow())
    generator = tracking._generator
    if not tracking._generator:
        generator = CVRFGenerator()
    if request.method != 'POST':
        return render_template('edit_tracking.j2', tracking=tracking, version='.'.join('%s'%v for v in tracking._version), generator=generator, now=utcnow(), statuses=tracking.STATUSES)

    tracking._identification._id = request.form['id']
    aliases = []
    if request.form['id_aliases']:
        aliases = [a.strip() for a in request.form['id_aliases'].split(',')]
    tracking._identification._aliases = aliases
    tracking._status = request.form['status']
    tracking._version = parseVersion(request.form['version'])
    tracking._initialDate = parseDate(request.form['initial'])
    tracking._currentDate = parseDate(request.form['current'])
    if wasNone:
        get_current().setTracking(tracking)
    if (not request.form['gen_engine']) and (not request.form['gen_date']):
        generator = None
    else:
        generator._engine = request.form['gen_engine'] or None
        if request.form['gen_date']:
            generator._date = parseDate(request.form['gen_date'])
        else:
            generator._date = None
    tracking.setGenerator(generator)
    return redirect(url_for('document'))

@app.route('/revision/<int:index>/edit', methods=['GET', 'POST'])
@document_required
def edit_revision(index):
    cvrf = get_current()
    if cvrf._tracking is None:
        abort(404)
    try:
        revision = cvrf._tracking._history[index]
    except IndexError:
        abort(404)
    if request.method != 'POST':
        return render_template('edit_revision.j2', number='.'.join('%s'%v for v in revision._number), date=revision._date, description=revision._description, action='Update')

    revision._number = parseVersion(request.form['number'])
    revision._date = parseDate(request.form['date'])
    revision._description = request.form['description']
    return redirect(url_for('document'))

@app.route('/revision/add', methods=['GET', 'POST'])
@document_required
def add_revision():
    tracking = get_current()._tracking
    if request.method != 'POST':
        version = tracking._version
        version = version[:-1] + (version[-1] + 1,)
        return render_template('edit_revision.j2', number='.'.join("%d"%v for v in version), date=utcnow(), action='Add')

    version = parseVersion(request.form['number'])
    date = parseDate(request.form['date'])
    revision = CVRFRevision(version, date, request.form['description'])
    tracking.addRevision(revision)
    if 'update_tracking' in request.form:
        tracking._version = version
        tracking._currentDate = date
    return redirect(url_for('document'))

@app.route('/distribution/edit', methods=['GET', 'POST'])
@document_required
def edit_distribution():
    if request.method != 'POST':
        return render_template('edit_distribution.j2', distribution=get_current()._distribution)

    get_current().setDistribution(request.form['distribution'])
    return redirect(url_for('document'))

@app.route('/severity/edit', methods=['GET', 'POST'])
@document_required
def edit_severity():
    severity = get_current()._aggregateseverity
    if severity is None:
        severity = CVRFAggregateSeverity('')
    if request.method != 'POST':
        return render_template('edit_severity.j2', severity=severity)
    if not request.form['severity']:
        severity = None
    else:
        severity._severity = request.form['severity']
        severity.setNamespace(request.form['namespace'] or None)
    get_current().setAggregateSeverity(severity)
    return redirect(url_for('document'))

@app.route('/note/<int:ordinal>')
@document_required
def view_note(ordinal):
    note = get_current().getNote(ordinal)
    if note is None:
        abort(404)
    return render_template('view_note.j2', note=note)

@app.route('/note/<int:ordinal>/edit', methods=['GET', 'POST'])
@document_required
def edit_note(ordinal):
    note = get_current().getNote(ordinal)
    if note is None:
        abort(404)
    if request.method != 'POST':
        return render_template('edit_note.j2', note=note, types = note.TYPES)

    note._type = request.form['type']
    note._ordinal = int(request.form['ordinal'])
    note._note = request.form['note']
    note._title = request.form['title'] or None
    note._audience = request.form['audience'] or None
    return redirect(url_for('view_note', ordinal=note._ordinal ))


@app.route('/note/add', methods=['GET', 'POST'])
@document_required
def add_note():
    if request.method != 'POST':
        next_ordinal = 1
        notes = get_current()._notes
        if notes:
            next_ordinal = notes[-1]._ordinal + 1
        return render_template('edit_note.j2', ordinal=next_ordinal, types=CVRFNote.TYPES, action='Add')

    title = None
    audience = None
    title = request.form['title'] or None
    audience = request.form['audience'] or None

    note = CVRFNote(request.form['type'], int(request.form['ordinal']), request.form['note'], title, audience)
    get_current().addNote(note)
    return redirect(url_for('document'))

@app.route('/reference/<int:index>/edit', methods=['GET', 'POST'])
@document_required
def edit_reference(index):
    try:
        ref = get_current()._references[index]
    except IndexError:
        abort(404)
    if request.method != 'POST':
        return render_template('edit_reference.j2', _type=ref._type, url=ref._url, description=ref._description, types=('',) + ref.TYPES)

    ref._type = request.form['type'] or None
    ref._url = request.form['url']
    ref._description = request.form['description']
    return redirect(url_for('document'))


@app.route('/reference/add', methods=['GET', 'POST'])
@document_required
def add_reference():
    if request.method != 'POST':
        return render_template('edit_reference.j2', action='Add', types=('',) + CVRFReference.TYPES)

    ref = CVRFReference(request.form['url'], request.form['description'], request.form['type'] or None)
    get_current().addReference(ref)
    return redirect(url_for('document'))

@app.route('/acknowledgment/<int:index>')
@document_required
def view_acknowledgment(index):
    try:
        ack = get_current()._acknowledgments[index]
    except IndexError:
        abort(404)
    return render_template('view_acknowledgment.j2', acknowledgment=ack, index=index, action='Update')

@app.route('/acknowledgment/<int:index>/edit', methods=['GET', 'POST'])
@document_required
def edit_acknowledgment(index):
    try:
        ack = get_current()._acknowledgments[index]
    except IndexError:
        abort(404)
    if request.method != 'POST':
        return render_template('edit_acknowledgment.j2', name=ack._name, organization=ack._organization, description=ack._description, url=ack._url, action='Update')

    ack._name = request.form['name'] or None
    ack._organization = request.form['organization'] or None
    ack._description = request.form['description'] or None
    ack._url = request.form['url'] or None
    return redirect(url_for('document'))

@app.route('/acknowledgment/add', methods=['GET', 'POST'])
@document_required
def add_acknowledgment():
    if request.method != 'POST':
        return render_template('edit_acknowledgment.j2', action='Add')

    ack = CVRFAcknowledgment()
    ack._name = request.form['name'] or None
    ack._organization = request.form['organization'] or None
    ack._description = request.form['description'] or None
    ack._url = request.form['url'] or None
    get_current().addAcknowledgment(ack)
    return redirect(url_for('document'))


@app.route('/render/<format_>')
@document_required
def render(format_):
    cvrf = get_current()
    doc = render_cvrf(cvrf, format_ + '.j2')
    return render_template('render.j2', format_=format_, title=cvrf._title, type_=cvrf._type, doc=doc )

@app.route('/save', methods=['GET', 'POST'])
@document_required
def save():
    if request.method != 'POST':
        return render_template('save.j2', id_=get_current()._tracking._identification._id)
    # Get some kind of filename, and save the cvrf on cache (disk)
    path = secure_filename(request.form['fname'])
    path, _ = os.path.splitext(path)
    with open(os.path.join(app.config['CACHE_DIRECTORY'], path + '.xml'), 'wt') as f:
        f.write(render_cvrf(get_current(), 'cvrf.j2').encode('utf-8'))
    flash('File saved as %s' % path)
    del_current()
    return redirect(url_for('new'))

@app.route('/load/<element>', methods=['GET', 'POST'])
def load(element):
    if request.method != 'POST':
        if has_current():
            # Suggest to save first
            return render_template('load.j2', element=element)

    fpath = os.path.join(app.config['CACHE_DIRECTORY'], element+'.xml')
    with open(fpath, 'rt') as f:
        set_current(parse(f))
    os.remove(fpath)
    flash('"%s" has been removed from cache' % element)
    # Get some kind of id, and load the file.
    return redirect(url_for('document'))

@app.route('/about')
def about():
    return render_template('about.j2')

http://farol.wald.intevation.org