comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:4a9f23230eba
1 # -*- encoding: utf-8 -*-
2 # Description:
3 # Farol Web Application
4 #
5 # Authors:
6 # BenoƮt Allard <benoit.allard@greenbone.net>
7 #
8 # Copyright:
9 # Copyright (C) 2014 Greenbone Networks GmbH
10 #
11 # This program is free software; you can redistribute it and/or
12 # modify it under the terms of the GNU General Public License
13 # as published by the Free Software Foundation; either version 2
14 # of the License, or (at your option) any later version.
15 #
16 # This program is distributed in the hope that it will be useful,
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 # GNU General Public License for more details.
20 #
21 # You should have received a copy of the GNU General Public License
22 # along with this program; if not, write to the Free Software
23 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24
25 import os
26
27 from farolluz.cvrf import (CVRF, CVRFPublisher, CVRFTracking, CVRFTrackingID,
28 CVRFGenerator, CVRFRevision, CVRFReference, CVRFAcknowledgment, CVRFNote,
29 ValidationError, CVRFAggregateSeverity)
30 from farolluz.parsers.cvrf import parse, parseVersion, parseDate
31 from farolluz.py2 import urlopen
32 from farolluz.renderer import render as render_cvrf
33 from farolluz.utils import utcnow
34
35 from flask import Flask, request, render_template, redirect, url_for, flash, abort
36 from werkzeug import secure_filename
37
38 from .session import get_current, set_current, has_current, del_current, document_required
39 from .vulnerability import vulnerability
40 from .producttree import producttree
41
42 app = Flask(__name__)
43
44 app.register_blueprint(vulnerability, url_prefix='/vulnerability')
45 app.register_blueprint(producttree, url_prefix='/producttree')
46
47 @app.context_processor
48 def cache_content():
49 """ List the documents in cache """
50 if 'CACHE_DIRECTORY' not in app.config:
51 return dict(cache=[])
52 dirname = app.config['CACHE_DIRECTORY']
53 if not os.path.exists(dirname):
54 os.mkdir(dirname)
55 l = []
56 for path in os.listdir(dirname):
57 name, ext = os.path.splitext(path)
58 if ext == '.xml':
59 l.append(name)
60 return dict(cache=l)
61
62 @app.context_processor
63 def doc_properties():
64 if not has_current():
65 return {'has_current': False}
66 cvrf = get_current()
67 vulns = [(v.getTitle(), v._ordinal) for v in cvrf._vulnerabilities]
68 prods = []
69 if cvrf._producttree:
70 prods = [(p._name, p._productid) for p in cvrf._producttree._products]
71 try:
72 cvrf.validate()
73 error = None
74 except ValidationError as ve:
75 error = ve
76 return dict(has_current=True, vulnerabilities=vulns, products=prods, error=error)
77
78 @app.template_filter('secure_filename')
79 def makeId(string):
80 return secure_filename(string)
81
82 @app.route('/new', methods=['GET', 'POST'])
83 def new():
84 if request.method != 'POST':
85 return render_template('new.j2', has_document=has_current(), now=utcnow())
86
87 if 'url' in request.form:
88 set_current(parse(urlopen(request.form['url']).read()))
89 elif 'local' in request.files:
90 upload = request.files['local']
91 if not upload.filename.endswith('.xml'):
92 flash('Uploaded files should end in .xml', 'danger')
93 return redirect(url_for('new'))
94 fpath = os.path.join('/tmp', secure_filename(upload.filename))
95 upload.save(fpath)
96 with open(fpath, 'rt') as f:
97 set_current(parse(f))
98 os.remove(fpath)
99 elif 'text' in request.form:
100 set_current(parse(request.form['text'].encode('utf-8')))
101 else:
102 set_current(CVRF(request.form['title'], request.form['type']))
103 return redirect(url_for('document'))
104
105 @app.route('/')
106 @document_required
107 def document():
108 cvrf = get_current()
109 return render_template('doc.j2', cvrf=cvrf)
110
111 @app.route('/title/edit', methods=['GET', 'POST'])
112 @document_required
113 def edit_title():
114 if request.method != 'POST':
115 return render_template('edit_title.j2', title = get_current()._title, _type = get_current()._type)
116
117
118 get_current()._title = request.form['title']
119 get_current()._type = request.form['type']
120 return redirect(url_for('document'))
121
122 @app.route('/publisher/edit', methods=['GET', 'POST'])
123 @document_required
124 def edit_publisher():
125 if request.method != 'POST':
126 return render_template('edit_publisher.j2', publisher = get_current()._publisher or CVRFPublisher(''), types=CVRFPublisher.TYPES)
127
128 publisher = CVRFPublisher(request.form['type'], request.form['vendorid'] or None)
129 publisher.setContact(request.form['contact'] or None)
130 publisher.setAuthority(request.form['authority'] or None)
131 get_current().setPublisher(publisher)
132 return redirect(url_for('document'))
133
134 @app.route('/tracking/edit', methods=['GET', 'POST'])
135 @document_required
136 def edit_tracking():
137 wasNone = False
138 tracking = get_current()._tracking
139 if tracking is None:
140 wasNone = True
141 tracking = CVRFTracking(CVRFTrackingID(''), 'Draft', (0,), utcnow(), utcnow())
142 generator = tracking._generator
143 if not tracking._generator:
144 generator = CVRFGenerator()
145 if request.method != 'POST':
146 return render_template('edit_tracking.j2', tracking=tracking, version='.'.join('%s'%v for v in tracking._version), generator=generator, now=utcnow(), statuses=tracking.STATUSES)
147
148 tracking._identification._id = request.form['id']
149 aliases = []
150 if request.form['id_aliases']:
151 aliases = [a.strip() for a in request.form['id_aliases'].split(',')]
152 tracking._identification._aliases = aliases
153 tracking._status = request.form['status']
154 tracking._version = parseVersion(request.form['version'])
155 tracking._initialDate = parseDate(request.form['initial'])
156 tracking._currentDate = parseDate(request.form['current'])
157 if wasNone:
158 get_current().setTracking(tracking)
159 if (not request.form['gen_engine']) and (not request.form['gen_date']):
160 generator = None
161 else:
162 generator._engine = request.form['gen_engine'] or None
163 if request.form['gen_date']:
164 generator._date = parseDate(request.form['gen_date'])
165 else:
166 generator._date = None
167 tracking.setGenerator(generator)
168 return redirect(url_for('document'))
169
170 @app.route('/revision/<int:index>/edit', methods=['GET', 'POST'])
171 @document_required
172 def edit_revision(index):
173 cvrf = get_current()
174 if cvrf._tracking is None:
175 abort(404)
176 try:
177 revision = cvrf._tracking._history[index]
178 except IndexError:
179 abort(404)
180 if request.method != 'POST':
181 return render_template('edit_revision.j2', number='.'.join('%s'%v for v in revision._number), date=revision._date, description=revision._description, action='Update')
182
183 revision._number = parseVersion(request.form['number'])
184 revision._date = parseDate(request.form['date'])
185 revision._description = request.form['description']
186 return redirect(url_for('document'))
187
188 @app.route('/revision/add', methods=['GET', 'POST'])
189 @document_required
190 def add_revision():
191 tracking = get_current()._tracking
192 if request.method != 'POST':
193 version = tracking._version
194 version = version[:-1] + (version[-1] + 1,)
195 return render_template('edit_revision.j2', number='.'.join("%d"%v for v in version), date=utcnow(), action='Add')
196
197 version = parseVersion(request.form['number'])
198 date = parseDate(request.form['date'])
199 revision = CVRFRevision(version, date, request.form['description'])
200 tracking.addRevision(revision)
201 if 'update_tracking' in request.form:
202 tracking._version = version
203 tracking._currentDate = date
204 return redirect(url_for('document'))
205
206 @app.route('/distribution/edit', methods=['GET', 'POST'])
207 @document_required
208 def edit_distribution():
209 if request.method != 'POST':
210 return render_template('edit_distribution.j2', distribution=get_current()._distribution)
211
212 get_current().setDistribution(request.form['distribution'])
213 return redirect(url_for('document'))
214
215 @app.route('/severity/edit', methods=['GET', 'POST'])
216 @document_required
217 def edit_severity():
218 severity = get_current()._aggregateseverity
219 if severity is None:
220 severity = CVRFAggregateSeverity('')
221 if request.method != 'POST':
222 return render_template('edit_severity.j2', severity=severity)
223 if not request.form['severity']:
224 severity = None
225 else:
226 severity._severity = request.form['severity']
227 severity.setNamespace(request.form['namespace'] or None)
228 get_current().setAggregateSeverity(severity)
229 return redirect(url_for('document'))
230
231 @app.route('/note/<int:ordinal>')
232 @document_required
233 def view_note(ordinal):
234 note = get_current().getNote(ordinal)
235 if note is None:
236 abort(404)
237 return render_template('view_note.j2', note=note)
238
239 @app.route('/note/<int:ordinal>/edit', methods=['GET', 'POST'])
240 @document_required
241 def edit_note(ordinal):
242 note = get_current().getNote(ordinal)
243 if note is None:
244 abort(404)
245 if request.method != 'POST':
246 return render_template('edit_note.j2', note=note, types = note.TYPES)
247
248 note._type = request.form['type']
249 note._ordinal = int(request.form['ordinal'])
250 note._note = request.form['note']
251 note._title = request.form['title'] or None
252 note._audience = request.form['audience'] or None
253 return redirect(url_for('view_note', ordinal=note._ordinal ))
254
255
256 @app.route('/note/add', methods=['GET', 'POST'])
257 @document_required
258 def add_note():
259 if request.method != 'POST':
260 next_ordinal = 1
261 notes = get_current()._notes
262 if notes:
263 next_ordinal = notes[-1]._ordinal + 1
264 return render_template('edit_note.j2', ordinal=next_ordinal, types=CVRFNote.TYPES, action='Add')
265
266 title = None
267 audience = None
268 title = request.form['title'] or None
269 audience = request.form['audience'] or None
270
271 note = CVRFNote(request.form['type'], int(request.form['ordinal']), request.form['note'], title, audience)
272 get_current().addNote(note)
273 return redirect(url_for('document'))
274
275 @app.route('/reference/<int:index>/edit', methods=['GET', 'POST'])
276 @document_required
277 def edit_reference(index):
278 try:
279 ref = get_current()._references[index]
280 except IndexError:
281 abort(404)
282 if request.method != 'POST':
283 return render_template('edit_reference.j2', _type=ref._type, url=ref._url, description=ref._description, types=('',) + ref.TYPES)
284
285 ref._type = request.form['type'] or None
286 ref._url = request.form['url']
287 ref._description = request.form['description']
288 return redirect(url_for('document'))
289
290
291 @app.route('/reference/add', methods=['GET', 'POST'])
292 @document_required
293 def add_reference():
294 if request.method != 'POST':
295 return render_template('edit_reference.j2', action='Add', types=('',) + CVRFReference.TYPES)
296
297 ref = CVRFReference(request.form['url'], request.form['description'], request.form['type'] or None)
298 get_current().addReference(ref)
299 return redirect(url_for('document'))
300
301 @app.route('/acknowledgment/<int:index>')
302 @document_required
303 def view_acknowledgment(index):
304 try:
305 ack = get_current()._acknowledgments[index]
306 except IndexError:
307 abort(404)
308 return render_template('view_acknowledgment.j2', acknowledgment=ack, index=index, action='Update')
309
310 @app.route('/acknowledgment/<int:index>/edit', methods=['GET', 'POST'])
311 @document_required
312 def edit_acknowledgment(index):
313 try:
314 ack = get_current()._acknowledgments[index]
315 except IndexError:
316 abort(404)
317 if request.method != 'POST':
318 return render_template('edit_acknowledgment.j2', name=ack._name, organization=ack._organization, description=ack._description, url=ack._url, action='Update')
319
320 ack._name = request.form['name'] or None
321 ack._organization = request.form['organization'] or None
322 ack._description = request.form['description'] or None
323 ack._url = request.form['url'] or None
324 return redirect(url_for('document'))
325
326 @app.route('/acknowledgment/add', methods=['GET', 'POST'])
327 @document_required
328 def add_acknowledgment():
329 if request.method != 'POST':
330 return render_template('edit_acknowledgment.j2', action='Add')
331
332 ack = CVRFAcknowledgment()
333 ack._name = request.form['name'] or None
334 ack._organization = request.form['organization'] or None
335 ack._description = request.form['description'] or None
336 ack._url = request.form['url'] or None
337 get_current().addAcknowledgment(ack)
338 return redirect(url_for('document'))
339
340
341 @app.route('/render/<format_>')
342 @document_required
343 def render(format_):
344 cvrf = get_current()
345 doc = render_cvrf(cvrf, format_ + '.j2')
346 return render_template('render.j2', format_=format_, title=cvrf._title, type_=cvrf._type, doc=doc )
347
348 @app.route('/save', methods=['GET', 'POST'])
349 @document_required
350 def save():
351 if request.method != 'POST':
352 return render_template('save.j2', id_=get_current()._tracking._identification._id)
353 # Get some kind of filename, and save the cvrf on cache (disk)
354 path = secure_filename(request.form['fname'])
355 path, _ = os.path.splitext(path)
356 with open(os.path.join(app.config['CACHE_DIRECTORY'], path + '.xml'), 'wt') as f:
357 f.write(render_cvrf(get_current(), 'cvrf.j2').encode('utf-8'))
358 flash('File saved as %s' % path)
359 del_current()
360 return redirect(url_for('new'))
361
362 @app.route('/load/<element>', methods=['GET', 'POST'])
363 def load(element):
364 if request.method != 'POST':
365 if has_current():
366 # Suggest to save first
367 return render_template('load.j2', element=element)
368
369 fpath = os.path.join(app.config['CACHE_DIRECTORY'], element+'.xml')
370 with open(fpath, 'rt') as f:
371 set_current(parse(f))
372 os.remove(fpath)
373 flash('"%s" has been removed from cache' % element)
374 # Get some kind of id, and load the file.
375 return redirect(url_for('document'))
376
377 @app.route('/about')
378 def about():
379 return render_template('about.j2')
380

http://farol.wald.intevation.org