changeset 133:b4bb5966af01

merged
author Benoît Allard <benoit.allard@greenbone.net>
date Fri, 24 Oct 2014 12:59:45 +0200
parents 812e613cbbb4 (diff) b74bf98ff879 (current diff)
children 50f15280dfee
files
diffstat 10 files changed, 86 insertions(+), 48 deletions(-) [+]
line wrap: on
line diff
--- a/farol/controller.py	Fri Oct 17 16:11:08 2014 +0200
+++ b/farol/controller.py	Fri Oct 24 12:59:45 2014 +0200
@@ -35,10 +35,10 @@
 except ImportError:
     from farolluz.py2 import FixedTimeZone as timezone
 
-from flask import request
+from flask import request, flash
 
 from farolluz.cvrf import CVRFNote, CVRFReference, CVRFAcknowledgment
-from farolluz.parsers.cvrf import parseDate as parseXMLDate
+from farolluz.parsers.cvrf import parseDate as parseXMLDate, parseVersion as parseXMLVersion
 
 def split_fields(field, separator=','):
     if not field:
@@ -89,5 +89,15 @@
     except AttributeError: pass
     # Absorb AttributeError, and try to parse it a second time ...
     m = re.match('(\d{4})-(\d{2})-(\d{2})', string)
+    if m is None:
+        flash('Cannot parse date: "%s"' % string, 'warning')
+        return None
     return datetime(int(m.group(1)), int(m.group(2)), int(m.group(3)),
                     tzinfo=timezone(timedelta(hours=0, minutes=0)))
+
+def parseVersion(string):
+    """ An extended version, one that doesn't throw exceptions """
+    try: return parseXMLVersion(string)
+    except ValueError:
+        flash('Cannot parse Version string: "%s"' % string)
+        return None
--- a/farol/document.py	Fri Oct 17 16:11:08 2014 +0200
+++ b/farol/document.py	Fri Oct 24 12:59:45 2014 +0200
@@ -25,7 +25,6 @@
 from flask import (Blueprint, render_template, abort, redirect, request,
     url_for, flash)
 
-from farolluz.parsers.cvrf import parseVersion
 from farolluz.cvrf import (CVRFNote, CVRFReference, CVRFPublisher,
     CVRFTracking, CVRFTrackingID, CVRFGenerator, CVRFRevision,
     CVRFAggregateSeverity)
@@ -34,8 +33,8 @@
 from .controller import (update_note_from_request, create_note_from_request,
     update_reference_from_request, create_reference_from_request,
     update_acknowledgment_from_request, create_acknowledgment_from_request,
-    split_fields, parseDate)
-from .session import document_required, get_current
+    split_fields, parseDate, parseVersion)
+from .session import document_required, get_current, del_current
 
 
 document = Blueprint('document', __name__)
@@ -46,6 +45,11 @@
     cvrf = get_current()
     return render_template('document/view.j2', cvrf=cvrf)
 
+@document.route('/delete', methods=['POST'])
+def delete():
+    del_current()
+    return redirect(url_for('welcome'))
+
 @document.route('/title/edit', methods=['GET', 'POST'])
 @document_required
 def edit_title():
@@ -87,7 +91,9 @@
     aliases = split_fields(request.form['id_aliases'])
     tracking._identification._aliases = aliases
     tracking._status = request.form['status']
-    tracking._version = parseVersion(request.form['version'])
+    version = parseVersion(request.form['version'])
+    if version is not None:
+        tracking._version = version
     tracking._initialDate = parseDate(request.form['initial'])
     tracking._currentDate = parseDate(request.form['current'])
     if wasNone:
@@ -116,7 +122,9 @@
     if request.method != 'POST':
         return render_template('document/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'])
+    version = parseVersion(request.form['number'])
+    if version is not None:
+        revision._number = version
     revision._date = parseDate(request.form['date'])
     revision._description = request.form['description']
     return redirect(url_for('.view'))
@@ -133,7 +141,7 @@
         version = version[:-1] + (version[-1] + 1,)
         return render_template('document/edit_revision.j2', number='.'.join("%d"%v for v in version), date=utcnow(), action='Add')
 
-    version = parseVersion(request.form['number'])
+    version = parseVersion(request.form['number']) or (0,0)
     date = parseDate(request.form['date'])
     revision = CVRFRevision(version, date, request.form['description'])
     tracking.addRevision(revision)
--- a/farol/main.py	Fri Oct 17 16:11:08 2014 +0200
+++ b/farol/main.py	Fri Oct 24 12:59:45 2014 +0200
@@ -89,7 +89,13 @@
 
 @app.route('/')
 def welcome():
-    return render_template('welcome.j2')
+    return render_template('welcome.j2',
+        version=__version__,
+        imports=[('New', 100), ('CVRF', 100)],
+        exports=[('CVRF', 100), ('OpenVAS NASL from RHSA', 85), ('OVAL', 5) ],
+        use_cases=[('Create a security advisory and publish as CVRF', 100),
+                   ('Edit a security advisory in CVRF format', 100)]
+    )
 
 def set_url(url):
     try: content = urlopen(url).read()
@@ -156,9 +162,6 @@
         set_url(request.form['url'])
     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(app.instance_path, 'tmp',
                              secure_filename(upload.filename))
         if not os.path.exists(os.path.dirname(fpath)):
--- a/farol/templates/about.j2	Fri Oct 17 16:11:08 2014 +0200
+++ b/farol/templates/about.j2	Fri Oct 24 12:59:45 2014 +0200
@@ -30,14 +30,12 @@
 
 {% block content %}
 <div class="page-header">
-<h1>Farol <small>A Security Advisory Management (Web) Platform</small></h1>
+<h1>Farol <small>The Security Advisory Management Platform</small></h1>
 </div>
 
 <div>
-  <p>Security Advisories have existed for ever. Whenever someone discovered a danger, a vulnerability, he immediately started spreading the words about it.</p>
-  <p>In the IT World, each Party involved with security vulnerabilities have its own way of dealing with the matter, and although standards exist they aren't used much to their full extend.<p>
-  <p>This Platform is an attempt at bringing all those worlds together.<p>
-  <p>In the current version, Advisories not currently saved are kept in memory of the running process. If the process terminates, and they are not saved, documents are lost.</p>
+  <p>This web platform offers to review, create, edit and transform security advisories supporting various input and output formats.</p>
+  <p>During your session the advisory is stored in a cache from which you should save your changes to your local file system.</p>
   {% if config.DEBUG and not config.DEBUG_SURE %}
     <hr>
     <h3 id="debug">Debug Mode</h3>
--- a/farol/templates/base.j2	Fri Oct 17 16:11:08 2014 +0200
+++ b/farol/templates/base.j2	Fri Oct 24 12:59:45 2014 +0200
@@ -65,7 +65,7 @@
                 <a role="menuitem" tabindex="-1" href="{{ url_for('producttree.view') }}">View Product Tree</a>
               </li>
               <li role="presentation" class="divider"></li>
-              {% for name, productid in products %}
+              {% for name, productid in products | sort %}
                 <li><a href="{{ url_for('producttree.view_product', productid=productid) }}">{{ name }}</a></li>
               {% endfor %}
             </ul>
@@ -84,15 +84,15 @@
         </ul>
         {% if has_current %}
           {% if error %}
-            <p class="navbar-text">Document is <a id="error-popover" href="#" tabindex="0" class="navbar-link" data-toggle="popover" data-trigger="focus" data-placement="bottom" title="First Error:" data-content="{{ error }}"><strong>invalid</strong></a></p>
+            <p class="navbar-text">Document is <a id="error-popover" href="#" tabindex="0" class="navbar-link" data-toggle="popover" data-trigger="focus" data-placement="bottom" title="First Error:" data-content="{{ error }}"><strong>invalid</strong></a> <span class="badge progress-bar-danger"><strong>&#x2717;</strong></span></p>
           {% else %}
-            <p class="navbar-text">Document looks valid</p>
+            <p class="navbar-text">Document looks valid <span class="badge progress-bar-success"><strong>&#x2713;</strong></span></p>
           {% endif %}
         {% endif %}
         <ul class="nav navbar-nav navbar-right">
           {% if has_current %}
           <li class="dropdown{{ ' active' if active == 'render' }}">
-            <a href="#" class="dropdown-toggle" data-toggle="dropdown">Render <span class="caret"></span></a>
+            <a href="#" class="dropdown-toggle" data-toggle="dropdown">Export <span class="caret"></span></a>
             <ul class="dropdown-menu" role="menu">
               {% for format in ('cvrf', 'nasl', 'oval') %}<li><a href="{{ url_for('render', format_=format)}}">as {{ format | upper }}</a></li>{% endfor %}
             </ul>
--- a/farol/templates/document/edit_revision.j2	Fri Oct 17 16:11:08 2014 +0200
+++ b/farol/templates/document/edit_revision.j2	Fri Oct 24 12:59:45 2014 +0200
@@ -30,7 +30,7 @@
 {% block content %}
 <p><strong>Revision</strong> contains all the elements required to track the evolution of a CVRF document. Each change to a CVRF document should be accompanied by <strong>Number</strong>, <strong>Date</strong>, and <strong>Description</strong> elements.</p>
 <form role="form" method="POST">
-  {% call textinput("number", "Number", "a.b.c.d", number, required=True) %}
+  {% call textinput("number", "Number", "a.b.c.d", number, required=True, regex='(0|[1-9][0-9]*)(\.(0|[1-9][0-9]*)){0,3}') %}
   <p><strong>Number</strong> should contain the numeric version of the document. Like the <strong>Version</strong> element above, it is a numeric tokenized field of the format “nn” with up to four fields “nn.nn.nn.nn”. It is recommended that this be a monotonically increasing value. Minor revisions should be used for less-significant changes (for example, <samp>1.0.0.0</samp> to <samp>1.0.0.1</samp>). Major, actionable changes should lead to a major increase of the version number (for example, <samp>1.0</samp> to <samp>2.0</samp>).</p>
   <p>Examples of such changes include:</p>
   <ul>
--- a/farol/templates/document/edit_tracking.j2	Fri Oct 17 16:11:08 2014 +0200
+++ b/farol/templates/document/edit_tracking.j2	Fri Oct 24 12:59:45 2014 +0200
@@ -52,7 +52,7 @@
 </dl>
 <p>Issuing parties are strongly recommended to set <strong>Status</strong> to <samp>Draft</samp> when initiating a new document and to implement procedures to ensure that the status is changed to the appropriate value before the document is released.</p>
 {% endcall %}
-{% call textinput("version", "Version", value=version, required=True) %}
+{% call textinput("version", "Version", value=version, required=True, regex='(0|[1-9][0-9]*)(\.(0|[1-9][0-9]*)){0,3}') %}
 <p>Version is a simple counter to track the version of the document. This is a numeric tokenized field of the format “nn” – “nn.nn.nn.nn”. It may be incremented in either major or minor notation to denote clearly the evolution of the content of the document. Issuing parties must ensure that this field is incremented appropriately, even for the least editorial or grammatical changes, when the field is used. It is validated using the following regular expression: <code>(0|[1-9][0-9]*)(\.(0|[1-9][0-9]*)){0,3}</code>.</p>
 {{ examples(['1.0', '1.0.1', '1.0.0.1']) }}
 {% endcall %}
--- a/farol/templates/document/view.j2	Fri Oct 17 16:11:08 2014 +0200
+++ b/farol/templates/document/view.j2	Fri Oct 24 12:59:45 2014 +0200
@@ -169,4 +169,13 @@
     {% endcall %}
   </div>
 </div>
+<div class="pull-right"><a href="#delete_modal" data-toggle="modal" class="btn btn-danger btn-xs" role="btn">delete</a></div>
+{% call modal('delete_modal', 'Delete document') %}
+  <p>This will delete the document <strong>{{ current_id }}</strong>.</p>
+  <p>Are you sure ?</p>
+</div>
+<div class="modal-footer">
+  <button type="button" class="btn btn-link" data-dismiss="modal">Cancel</button>
+  {{ POST_button(url_for('.delete'), text="Delete " + cvrf.getDocId(), style="btn-danger") }}
+{% endcall %}
 {% endblock %}
--- a/farol/templates/macros.j2	Fri Oct 17 16:11:08 2014 +0200
+++ b/farol/templates/macros.j2	Fri Oct 24 12:59:45 2014 +0200
@@ -23,7 +23,7 @@
 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 -#}
 
-{% macro textinput(name, label, placeholder="", value=None, required=False, type="text", extras={}, help='') %}
+{% macro textinput(name, label, placeholder="", value=None, required=False, type="text", extras={}, help='', regex=None) %}
 <div class="form-group">
   {% if caller %}
     {% set content=caller () %}
@@ -42,6 +42,9 @@
      id="{{ name }}" name="{{ name }}"
      {%- if placeholder %} placeholder="{{ placeholder }}"{% endif %}
      {%- if value %} value="{{ value }}"{% endif %}
+     {%- if regex %} pattern="{{ regex }}"
+     {%- elif type == "datetime" %} pattern="\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?([+-]\d+(:\d+)?|Z)?)?"
+     {%- endif %}
      {%- if required %} required{% endif %}
      {{- extras | xmlattr }}>
   {% if type == "datetime" %}
--- a/farol/templates/welcome.j2	Fri Oct 17 16:11:08 2014 +0200
+++ b/farol/templates/welcome.j2	Fri Oct 24 12:59:45 2014 +0200
@@ -24,36 +24,43 @@
 -#}
 
 {% extends "base.j2" %}
+{% from "macros.j2" import panel %}
+
+{% macro progress_label(progress) -%}
+<span class="label label-
+{%- if progress < 70 %}danger{% elif progress < 95 %}warning{% else %}success{% endif -%}
+">{{ progress }}%</span>
+{%- endmacro %}
 
 {% block title %}Welcome{% endblock %}
 
 {% block content %}
-<div class="jumbotron">
-  <h1>Farol <small>A Security Advisory Management Platform</small></h1>
-  <p>Farol is a web platform to manipulate Security Advisories. The main structure is highly inspired from the structure of a CVRF document.</p>
-  <p>This platform is meant as a way to review / create / edit / publish Security Advisories in an accessible way.</p>
-  <p><a class="btn btn-primary btn-lg" role="button" href="{{ url_for('new') }}">Start !</a></p>
+<div class="well well-lg">
+  <h1>Farol <small>The Security Advisory Management Platform</small></h1>
+  <div class="pull-right"><a class="btn btn-primary btn-lg" role="button" href="{{ url_for('new') }}" >Start !</a></div>
+  <p>This web platform offers to review, create, edit and transform security advisories supporting various input and output formats. During your session the advisory is stored in a cache from which you should save your changes to your local file system.</p>
 </div>
-<img src="{{ url_for('static', filename="flower.png") }}" class="img-responsive img-thumbnail" alt="Security Advisories interactions">
 <div class="row">
-  <div class="col-sm-6">
-    <div class="thumbnail">
-      <h3>Security Advisories</h3>
-      <p>A Security Advisory is about the <em>communication</em> of the information that some <em>vulnerability</em> is present in some <em>product</em>.</p>
-      <dl>
-        <dt>communication</dt>
-        <dd>In order to be fully effective, Security Advisories should be sahred.</dd>
-        <dt>vulnerability</dt>
-        <dd>A vulnerability is a weakness which allows an attacker to reduce a system's information assurance. <cite>(Wikipedia)</cite></dd>
-        <dt>product</dt>
-        <dd>A product contains vulnerabilities.</dd>
-    </div>
-  </div>
-  <div class="col-sm-6">
-    <div class="thumbnail">
-      <h3>Advisory formats</h3>
-      <p>Each Party publish Advisories in a format that fit them ...</p>
-    </div>
+  <div class="col-sm-9"><img src="{{ url_for('static', filename="flower.png") }}" class="img-responsive img-thumbnail" alt="Security Advisories interactions"></div>
+  <div class="col-sm-3">
+    {% call panel(heading="Platform status", collapsible=False) %}
+    <div><span class="pull-right badge">{{ version }}</span>Farol version:</div>
+    {% endcall %}
+    {% call panel(heading="Supported input formats", collapsible=False) %}
+      {% for format, progress in imports %}
+        <div>{{ format }} <span class="pull-right">{{ progress_label(progress) }}</span></div>
+      {% endfor %}
+    {% endcall %}
+    {% call panel(heading="Supported output formats", collapsible=False) %}
+      {% for format, progress in exports %}
+        <div>{{ format }} <span class="pull-right">{{ progress_label(progress) }}</span></div>
+      {% endfor %}
+    {% endcall %}
+    {% call panel(heading="Supported use cases", collapsible=False) %}
+      {% for use_case, progress in use_cases %}
+        <div><span class="pull-right">{{ progress_label(progress) }}</span>{{ use_case }}</div>
+      {% endfor %}
+    {% endcall %}
   </div>
 </div>
 {% endblock %}

http://farol.wald.intevation.org