Completed
Pull Request — dev-skf (#90)
by Simon
01:47
created

add_function()   C

Complexity

Conditions 7

Size

Total Lines 43

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 7
dl 0
loc 43
rs 5.5
c 1
b 0
f 0
1
# -*- coding: utf-8 -*-
2
"""
3
    Security Knowledge Framework is an expert system application 
4
    that uses OWASP Application Security Verification Standard, code examples,
5
    helps developers in pre-development and post-development.  
6
    Copyright (C) 2015  Glenn ten Cate, Riccardo ten Cate
7
8
    This program is free software: you can redistribute it and/or modify
9
    it under the terms of the GNU Affero General Public License as
10
    published by the Free Software Foundation, either version 3 of the
11
    License, or (at your option) any later version.
12
13
    This program is distributed in the hope that it will be useful,
14
    but WITHOUT ANY WARRANTY; without even the implied warranty of
15
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
    GNU Affero General Public License for more details.
17
18
    You should have received a copy of the GNU Affero General Public License
19
    along with this program. If not, see <http://www.gnu.org/licenses/>.
20
"""
21
22
import os, markdown, datetime, string, base64, re, sys, re, requests, mimetypes, smtplib
23
from OpenSSL import SSL, rand
24
from docx import Document
25
from BeautifulSoup import BeautifulSoup
26
from docx.enum.text import WD_ALIGN_PARAGRAPH
27
from docx.shared import Inches
28
from functools import wraps 
29
from sqlite3 import dbapi2 as sqlite3
30
from flask.ext.bcrypt import Bcrypt
31
from flask import Flask, request, session, g, redirect, url_for, abort, \
32
     render_template, flash, Markup, make_response
33
34
from . import version
35
36
# create the application
37
app = Flask(__name__)
38
39
"""Set up bcrypt for passwords encrypting"""
40
bcrypt = Bcrypt(app)
41
42
def add_response_headers(headers={}):
43
    """This decorator adds the headers passed in to the response"""
44
    def decorator(f):
45
        @wraps(f)
46
        def decorated_function(*args, **kwargs):
47
            resp = make_response(f(*args, **kwargs))
48
            h = resp.headers
49
            for header, value in headers.items():
50
                h[header] = value
51
            return resp
52
        return decorated_function
53
    return decorator
54
55
def security(f):
56
    """This decorator passes multiple security headers and checks log file to block users"""
57
    return add_response_headers({'X-Frame-Options': 'deny', 'X-XSS-Protection': '1', 'X-Content-Type-Options': 'nosniff', 'Cache-Control': 'no-store, no-cache','Strict-Transport-Security': 'max-age=16070400; includeSubDomains', 'Server': 'Security Knowledge Framework'})(f)
58
59
def check_token():
60
    """Checks the submitted CSRF token"""
61
    if not session.get('csrf_token') == request.form['csrf_token']:
62
        log("User supplied not valid CSRF token", "FAIL", "HIGH")
63
        session.clear()
64
        return abort(500)(f)
65
66
def generate_pass():
67
    chars = string.letters + string.digits + '+/'
68
    assert 256 % len(chars) == 0  # non-biased later modulo
69
    PWD_LEN = 12
70
    generated_pass = ''.join(chars[ord(c) % len(chars)] for c in os.urandom(PWD_LEN))
71
    return generated_pass
72
73
def random_token(tokenBytes):
74
    #Create random token
75
    rand.cleanup()
76
    Random_token_raw = rand.bytes(int(tokenBytes))
77
    Random_token = base64.b64encode(Random_token_raw)
78
    result = re.sub("==", "", Random_token)
79
    return result
80
81
def log(message, value, threat):
82
    """Create log file and write events triggerd by the user
83
    The variables: message can be everything, value contains FAIL or SUCCESS and threat LOW MEDIUM HIGH"""
84
    now = datetime.datetime.now()
85
    dateLog = now.strftime("%Y-%m")
86
    dateTime = now.strftime("%Y-%m-%d %H:%M") 
87
    ip = request.remote_addr
88
    try:
89
        file = open('logs/'+dateLog+'.txt', 'a+')
90
    except IOError:
91
        # If not exists, create the file
92
        file = open('logs/'+dateLog+'.txt', 'w+')
93
    file.write(dateTime +' '+ message +' ' + ' ' + value + ' ' + threat + ' ' +ip + "\r\n")
94
    file.close()
95
96
def blockUsers():
97
    """Check the log file and based on the FAIL items block a user"""
98
    dateLog  = datetime.datetime.now().strftime("%Y-%m")
99
    count = 0
100
    try:
101
        read = open(os.path.join(app.root_path, 'logs/'+dateLog+'.txt'), 'a+')
102
    except IOError:
103
        # If not exists, create the file
104
        read = open(os.path.join(app.root_path, 'logs/'+dateLog+'.txt'), 'w+')
105
    for line in read:
106
        match = re.search('FAIL', line)
107
        # If-statement after search() tests if it succeeded
108
        if match:                      
109
            count += 1   
110
            str(count) 
111
            if count > 11:
112
                sys.exit('Due to to many FAILED logs in your logging file we have the suspicion your application has been under attack by hackers. Please check your log files to validate and take repercussions. After validation clear your log or simply change the FAIL items to another value.')            
113
                                
114
def valAlphaNum(value, countLevel):
115
    match = re.findall(r"[^ a-zA-Z0-9_.-]", value)
116
    if match:
117
        log("User supplied not an a-zA-Z0-9 value", "FAIL", "MEDIUM")
118
        countAttempts(countLevel)
119
        abort(406)
120
        return False
121
    else:
122
        return True
123
124
def valNum(value, countLevel):
125
    match = re.findall(r'[a-zA-Z_]', str(value))
126
    if match:
127
        log("malicious input found", "FAIL", "MEDIUM")
128
        countAttempts(countLevel)
129
        abort(406)
130
        return False
131
    else:
132
        return True
133
        
134
def encodeInput(html):
135
    """Encode evil chars..."""
136
    result = re.sub('"', "&quot;", html)
137
    result = re.sub("'", "&#39;", result)
138
    result = re.sub("&", "&amp;", result)
139
    result = re.sub("<", "&lt;", result)
140
    result = re.sub(">", "&gt;", result)
141
    log("User supplied input was encoded", "SUCCESS", "NULL")
142
    return result
143
    
144
#not tested yet, made draft did not needed it so far
145
def whiteList(allowed, input, countlevel):
146
    splitted = string.split(allowed, ',')
147
    bool = False
148
    for val in splitted:
149
        if val in input:
150
            bool = True
151
    if bool == False:
152
        log("User is tampering whitelist values", "FAIL", "HIGH")
153
        countAttempts(countLevel)
154
        abort(401)
155
    if bool == True:
156
        return bool
157
158
159
#secret key for flask internal session use
160
rand.cleanup()
161
secret_key = rand.bytes(512)
162
163
mimetypes.add_type('image/svg+xml', '.svg')
164
bindaddr = '127.0.0.1';
165
166
# Load default config and override config from an environment variable
167
# You can also replace password with static password:  PASSWORD='pass!@#example'
168
app.config.update(dict(
169
    DATABASE=os.path.join(app.root_path, 'skf.db'),
170
    DEBUG=True,
171
    SECRET_KEY=secret_key,
172
    SESSION_COOKIE_SECURE=True,
173
    SESSION_COOKIE_HTTPONLY = True
174
))
175
176
@app.context_processor
177
def inject_year():
178
    return dict(year=datetime.datetime.now().strftime("%Y"))
179
180
def connect_db():
181
    """Connects to the specific database."""
182
    rv = sqlite3.connect(app.config['DATABASE'])
183
    rv.row_factory = sqlite3.Row
184
    return rv
185
186
187
def init_db():
188
    """Initializes the database."""
189
    db = get_db()
190
    with app.open_resource('schema.sql') as f:
191
        db.cursor().executescript(f.read())
192
    db.commit()
193
194
195
@app.cli.command('initdb')
196
def initdb_command():
197
    """Creates the database tables."""
198
    init_db()
199
    print('Initialized the database.')
200
201
202
def get_db():
203
    """Opens a new database connection if there is none yet for the
204
    current application context.
205
    """
206
    if not hasattr(g, 'sqlite_db'):
207
        g.sqlite_db = connect_db()
208
    return g.sqlite_db
209
210
def get_filepaths(directory):
211
    """
212
    This function will generate the file names in a directory 
213
    tree by walking the tree either top-down or bottom-up. For each 
214
    directory in the tree rooted at directory top (including top itself), 
215
    it yields a 3-tuple (dirpath, dirnames, filenames).
216
    """
217
    file_paths = [] 
218
    for root, directories, files in os.walk(directory):
219
        for filename in files:
220
            filepath = os.path.join(root, filename)
221
            file_paths.append(filepath)
222
    return file_paths  
223
224
def get_num(x):
225
    """get numbers from a string"""
226
    return int(''.join(ele for ele in x if ele.isdigit()))
227
228
@app.teardown_appcontext
229
def close_db(error):
230
    """Closes the database again at the end of the request."""
231
    if hasattr(g, 'sqlite_db'):
232
        g.sqlite_db.close()
233
234
def check_version():
235
    try:
236
        r = requests.get("http://raw.githubusercontent.com/blabla1337/skf-flask/master/setup.py")
237
        items_remote = r.content.split(",") 
238
        version_remote = items_remote[1]
239
        version_remote = version_remote.replace(version_remote[:14], '')
240
        version_remote = version_remote[:-1]
241
        with open ("version.txt", "r") as myfile:
242
            version_local = myfile.read().replace('\n', '')
243
244
        if version_local == version_remote:
245
            return True
246
        else:
247
            return False
248
    except:
249
        return False
250
251
def get_version():
252
    return version.__version__
253
        
254
def projects_functions_techlist():
255
    """get list of technology used for creating project functions"""
256
    if not session.get('logged_in'):
257
        abort(401)
258
    db = get_db()
259
    cur = db.execute('SELECT techID, techName, vulnID from techhacks ORDER BY techID DESC')
260
    entries = cur.fetchall()
261
    return entries 
262
263
@app.route('/')
264
@security
265
def show_landing():
266
    """show the loging page and set default code language"""
267
    rand.cleanup()
268
    csrf_token_raw = rand.bytes(128)
269
    csrf_token = base64.b64encode(csrf_token_raw)
270
    session['csrf_token'] = csrf_token
271
    session['code_lang'] = "php"
272
273
    return render_template('login.html', csrf_token=session['csrf_token'])
274
275
@app.route('/dashboard', methods=['GET'])
276
@security
277
def dashboard():
278
    """show the landing page"""
279
    if not session.get('logged_in'):
280
        log("User with no valid session tries access to page /dashboard", "FAIL", "HIGH")
281
        abort(401)
282
    permissions("read")
283
    version_check = check_version()
284
    version = get_version()
285
    return render_template('dashboard.html', version=version, version_check=version_check)
286
287
@app.route('/first-login', methods=['GET'])
288
@security
289
def first_login():
290
    version_check = check_version()
291
    version = get_version()
292
    return render_template('first-login.html', version=version, version_check=version_check)
293
294
"""create account for a user"""
295
@app.route('/create-account', methods=['GET', 'POST'])
296
@security
297
def create_account():
298
    """validate the login data for access dashboard page"""
299
    error = None
300
    db = get_db()
301
    db.commit()
302
    if request.method == 'POST':
303
        """Username, password, token, email from form"""
304
        token  = request.form['token']
305
        email  = request.form['email']
306
        password  = request.form['password']
307
        
308
        #hash the password with Bcrypt, does autosalt
309
        hashed = bcrypt.generate_password_hash(password, 12)
310
      
311
        #Do DB query also check for access
312
        cur = db.execute('SELECT accessToken, userID from users where email=? AND accessToken=?',
313
                            [email, token])
314
        check = cur.fetchall()
315
        for verify in check:
316
            userID = verify[1]
317
            if str(verify[0]) == token:
318
                        #update the counter and blocker table with new values 
319
                db.execute('UPDATE users SET access=?, password=?, activated=? WHERE accessToken=? AND userID=?',
320
                           ["true", hashed, "true", token , userID])
321
                db.commit()
322
                #Insert record in counter table for the counting of malicious inputs
323
                db.execute('INSERT INTO counter (userID, countEvil, block) VALUES (?, ?, ?)',
324
                            [userID, 0, 0])
325
                db.commit()
326
                
327
                #Create standard group  for this user to assign himself to
328
                date = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
329
                db.execute('INSERT INTO groups (ownerID, groupName, timestamp) VALUES (?, ?, ?)',
330
                            [userID, "privateGroup", date])
331
                db.commit()
332
                
333
                #Select this groupID so we can assign the user to this group automatically
334
                cur = db.execute('SELECT groupID from groups where ownerID=?',
335
                            [userID])
336
                group = cur.fetchall()
337
                for theID in group:
338
                    groupID = theID[0]
339
                            
340
                #Now we assign the user to the group
341
                date = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
342
                db.execute('INSERT INTO groupMembers (userID, groupID, ownerID) VALUES (?, ?, ?)',
343
                            [userID, groupID, userID])
344
                db.commit()
345
               
346
        if not check:
347
            #if not the right pin, the user account wil be deleted if not exsisting
348
            db.execute('DElETE FROM users where email=? AND activated=?',
349
                        [email, "false"])
350
            db.commit()
351
        
352
        
353
        return render_template('login.html', error=error)
354
355
"""First comes the method for login"""
356
@app.route('/login', methods=['GET', 'POST'])
357
@security
358
def login():
359
    """validate the login data for access dashboard page"""
360
    error = None
361
    db = get_db()
362
    db.commit()
363
    if request.method == 'POST':
364
        """Username and password from form"""
365
        username = request.form['username']
366
        password = request.form['password']
367
        
368
        #Do DB query also check for access
369
        cur = db.execute('SELECT access from users where userName=?',
370
                            [username])
371
        check = cur.fetchall()
372
        for verify in check:
373
            if verify[0] == "false":
374
                return render_template('warning.html', error=error)
375
            
376
        #Do DB query also check for access
377
        cur = db.execute('SELECT u.userID, u.privilegeID, u.userName, u.password, u.access, priv.privilegeID, priv.privilege from users as u JOIN privileges AS priv ON priv.privilegeID = u.privilegeID where username=? AND access="true"',
378
                            [username])
379
        entries = cur.fetchall()
380
        for entry in entries:
381
            passwordHash = entry[3]  
382
            userID 		 = entry[0]         
383
            #Do encryption
384
            if bcrypt.check_password_hash(passwordHash, password):
385
                log("Valid username/password submit", "SUCCESS", "HIGH")  
386
                rand.cleanup()
387
                csrf_token_raw = rand.bytes(128)
388
                csrf_token = base64.b64encode(csrf_token_raw)  
389
                session['logged_in'] = True
390
                session['userID'] = userID
391
                session['csrf_token'] = csrf_token
392
                session['code_lang'] = "php"
393
                session['userName'] = entry[2]
394
                valAlphaNum(session['userName'], 12)
395
                session['permissions'] = entry[6]
396
                version_check = check_version()
397
                version = get_version()
398
                
399
                #Do DB query also check for access
400
                cur = db.execute('SELECT groupID from groups WHERE groupName=? AND ownerID=?',
401
                            ["privateGroup", session['userID']])
402
                groupID = cur.fetchall()
403
                for entry in groupID:
404
                    session['privateGroup'] = entry[0]
405
                return render_template('dashboard.html', version=version, version_check=version_check)
406
            else:    
407
                log("invalid login submit", "FAIL", "HIGH")                   
408
    return render_template('login.html', error=error)
409
410
def countAttempts(counter):
411
    """We count hacking attempts and block the user if structural"""
412
    if not session.get('logged_in'):
413
        abort(401)
414
    db = get_db()
415
    cur = db.execute('SELECT * FROM counter where userID=?',
416
                        [session['userID']])
417
    entries = cur.fetchall()
418
    for entry in entries:
419
        counterDB = entry[2]
420
        blockDB   = entry[3] 
421
    
422
    updateCount = counterDB + counter
423
    updateBlock = blockDB   + counter
424
    redirect = False
425
    
426
    if updateCount >= 3:
427
        countUpdate = 0
428
        redirect = True
429
        
430
    if updateBlock >=12:
431
        redirect = True
432
        db.execute('UPDATE users SET access=? WHERE userID=?',
433
               ["false", session['userID']])
434
    	db.commit()
435
    	renderwhat = "/warning.html"
436
    
437
    #update the counter and blocker table with new values 
438
    db.execute('UPDATE counter SET countEvil=?, block=? WHERE userID=?',
439
        [updateCount, updateBlock, session['userID']])
440
    db.commit()
441
    
442
    if redirect == True:
443
        log( "Authenticated session destroyed by counter class", "SUCCESS", "LOW")
444
        # TO-DO turn on again
445
        #session.pop('logged_in', None)
446
        #session.clear()
447
    if redirect == False:
448
        return True
449
450
"""Here is the method for the database enforced privilege based authentication"""
451
def permissions(fromFunction):
452
    db = get_db()
453
    db.commit()
454
    
455
    """Do DB query to see if username exists"""
456
    cur = db.execute('SELECT a.username, a.userID, a.password, a.privilegeID, b.privilegeID, b.privilege FROM users as a JOIN privileges as b ON a.privilegeID = b.privilegeID WHERE a.userID =? and a.access="true" ',
457
    				       [session['userID']])
458
    entries = cur.fetchall()
459
    for entry in entries:
460
    	permissions = entry[5]
461
    	
462
    permissionsGranted = string.split(permissions, ':')	
463
    permissionsNeeded  = string.split(fromFunction, ':')
464
    
465
    count = len(permissionsNeeded)
466
    counthits = 0
467
	
468
    for val in permissionsGranted:
469
	    if val in fromFunction:
470
	        counthits +=1
471
    if counthits >= count:
472
        return permissions
473
    else:
474
        log( "User tries to reach functions out of bound no restrictions!!", "FAIL", "HIGH")
475
        abort(401)
476
477
@app.route('/logout', methods=['GET', 'POST'])
478
@security
479
def logout():
480
    """logout and destroy session"""
481
    log( "Authenticated session destroyed", "SUCCESS", "LOW")
482
    session.pop('logged_in', None)
483
    session.clear()
484
    return redirect("/")
485
486
@app.route('/code/<code_lang>', methods=['GET'])
487
@security
488
def set_code_lang(code_lang):
489
    """set a code language: php java python perl"""
490
    if not session.get('logged_in'):
491
        log( "User with no valid session tries access to page /code", "FAIL", "HIGH")
492
        abort(401)
493
    permissions("read")
494
    allowed = "php java python asp"
495
    valAlphaNum(code_lang, 12)
496
    safe_code_lang = encodeInput(code_lang)
497
    found = allowed.find(safe_code_lang)
498
    if found != -1:
499
        #to do below security issue... Create white-list of the languages
500
        if safe_code_lang == "asp" or safe_code_lang == "php": 
501
            session['code_lang'] = safe_code_lang
502
    return redirect(url_for('code_examples'))
503
504
@app.route('/code-examples', methods=['GET'])
505
@security
506
def code_examples():
507
    """Shows the knowledge base markdown files."""
508
    if not session.get('logged_in'):
509
        log( "User with no valid session tries access to page /code-examples", "FAIL", "HIGH")
510
        abort(401)
511
    permissions("read")
512
    items = []
513
    id_items = []
514
    full_file_paths = []
515
    allowed = set(string.ascii_lowercase + string.ascii_uppercase + '.')
516
    if set(session['code_lang']) <= allowed:
517
        full_file_paths = get_filepaths(os.path.join(app.root_path, "markdown/code_examples/"+session['code_lang']))
518
        for path in full_file_paths:
519
            id_item = get_num(path)
520
            path = path.split("-")
521
            y = len(path)-3 
522
            kb_name_uri = path[(y)]
523
            kb_name = kb_name_uri.replace("_", " ")
524
            items.append(kb_name)
525
            id_items.append(id_item)
526
    return render_template('code-examples.html', items=items, id_items=id_items)
527
528
@app.route('/code-item', methods=['POST'])
529
@security
530
def show_code_item():
531
    """show the coding examples page"""
532
    if not session.get('logged_in'):
533
        log("User with no valid session tries access to page /code-item", "FAIL", "HIGH")
534
        abort(401)
535
    permissions("read")
536
    valNum(request.form['id'], 12)
537
    id = int(request.form['id'])
538
    items = []
539
    full_file_paths = []
540
    allowed = set(string.ascii_lowercase + string.ascii_uppercase + '.')
541
    if set(session['code_lang']) <= allowed:
542
        full_file_paths = get_filepaths(os.path.join(app.root_path, "markdown/code_examples/"+session['code_lang']))
543
        for path in full_file_paths:
544
            if id == get_num(path):
545
                filemd = open(path, 'r').read()
546
                content = Markup(markdown.markdown(filemd)) 
547
    return render_template('code-examples-item.html', **locals())
548
549
@app.route('/kb-item', methods=['POST'])
550
@security
551
def show_kb_item():
552
    """show the knowledge base search result page"""
553
    if not session.get('logged_in'):
554
        log("User with no valid session tries access to page /kb-item", "FAIL", "HIGH")
555
        abort(401)
556
    permissions("read")
557
    valNum(request.form['id'], 12)
558
    id = int(request.form['id'])
559
    items = []
560
    full_file_paths = []
561
    full_file_paths = get_filepaths(os.path.join(app.root_path, "markdown"))
562
    for path in full_file_paths:
563
        if id == get_num(path):
564
            filemd = open(path, 'r').read()
565
            content = Markup(markdown.markdown(filemd)) 
566
    return render_template('knowledge-base-item.html', **locals())
567
568
569
@app.route('/knowledge-base-api', methods=['GET'])
570
@security
571
def show_kb_api():
572
    """show the knowledge base items page"""
573
    log( "User access page /knowledge-base-api", "SUCCESS", "HIGH")
574
    full_file_paths = []
575
    content = []
576
    kb_name = []
577
    full_file_paths = get_filepaths(os.path.join(app.root_path, "markdown/knowledge_base"))
578
    for path in full_file_paths:
579
        filetmp = open(path, 'r').read()
580
        filetmp2 = filetmp.replace("-------", "")
581
        filetmp3 = filetmp2.replace("**", "")
582
        filetmp4 = filetmp3.replace("\"", "")
583
        filetmp5 = filetmp4.replace("\t", "")
584
        content.append(filetmp5.replace("\n", " "))
585
        path = path.split("-")
586
        y = len(path)-3
587
        kb_name_uri = path[(y)]
588
        kb_name.append(kb_name_uri.replace("_", " "))
589
    return render_template('knowledge-base-api.html', **locals())
590
591
@app.route('/knowledge-base', methods=['GET'])
592
@security
593
def knowledge_base():
594
    """Shows the knowledge base markdown files."""
595
    if not session.get('logged_in'):
596
        log( "User with no valid session tries access to page /knowledge-base", "FAIL", "HIGH")
597
        abort(401)
598
    permissions("read")
599
    items = []
600
    id_items = []
601
    full_file_paths = []
602
    full_file_paths = get_filepaths(os.path.join(app.root_path, "markdown/knowledge_base"))
603
    for path in full_file_paths:
604
        id_item = get_num(path)
605
        path = path.split("-")
606
        y = len(path)-3 
607
        kb_name_uri = path[(y)]
608
        kb_name = kb_name_uri.replace("_", " ")
609
        items.append(kb_name)
610
        id_items.append(id_item)
611
    return render_template('knowledge-base.html', items=items, id_items=id_items)
612
613
@app.route('/users-new', methods=['GET'])
614
@security
615
def user_new():
616
    """show the create new project page"""
617
    if not session.get('logged_in'):
618
        log("User with no valid session tries access to page /user-new", "FAIL", "HIGH")
619
        abort(401)     
620
    permissions("manage")
621
    return render_template('users-new.html', csrf_token=session['csrf_token'])
622
    
623
@app.route('/users-add', methods=['POST'])
624
@security
625
def users_add():
626
    """add a new project to database"""
627
    if not session.get('logged_in'):
628
        log("User with no valid session tries access to page /users-add", "FAIL", "HIGH")
629
        abort(401)
630
    permissions("manage")
631
    check_token()
632
    db = get_db()
633
    valAlphaNum(request.form['username'], 1)
634
    valNum(request.form['privID'], 12)
635
    valNum(request.form['pincode'], 12)
636
    safe_userName = encodeInput(request.form['username'])
637
    safe_email    = encodeInput(request.form['email'])
638
    safe_privID   = encodeInput(request.form['privID'])
639
    pincode       = encodeInput(request.form['pincode'])
640
641
    db.execute('INSERT INTO users (privilegeID, userName, email, password, access, accessToken, activated) VALUES (?, ?, ?, ?, ?, ?, ?)',
642
               [safe_privID, safe_userName, safe_email, "none", "false", pincode, "false"])
643
    db.commit()
644
    
645
    return redirect(url_for('users_manage'))
646
647
@app.route('/users-manage', methods=['GET'])
648
@security
649
def users_manage():
650
    """show the project list page"""
651
    if not session.get('logged_in'):
652
        log("User with no valid session tries access to page /group-manage", "FAIL", "HIGH")
653
        abort(401)
654
    permissions("manage")
655
    db = get_db()
656
    cur = db.execute('SELECT u.userID, u.userName, u.email, u.privilegeID, u.access, p.privilegeID, p.privilege from users as u JOIN privileges as p ON p.privilegeID = u.privilegeID')
657
    users = cur.fetchall()
658
    
659
    return render_template('users-manage.html', users=users, csrf_token=session['csrf_token'])
660
661
@app.route('/user-access', methods=['POST'])
662
@security
663
def user_access():
664
    """add a new project to database"""
665
    if not session.get('logged_in'):
666
        log("User with no valid session tries access to page /assign-group", "FAIL", "HIGH")
667
        abort(401)
668
    permissions("manage")
669
    check_token()
670
    db = get_db()
671
    valNum(request.form['userID'], 12)
672
    whiteList("false,true", request.form['access'], 12)
673
    safe_userID   = encodeInput(request.form['userID'])
674
    safe_access = encodeInput(request.form['access'])
675
    db.execute('UPDATE users SET access=? WHERE userID=?',
676
		   [safe_access, safe_userID])
677
    db.execute('UPDATE counter SET countEvil=? AND block=? WHERE userID=?',
678
		   [0, 0, safe_userID])
679
    db.commit()
680
    
681
    return redirect(url_for('users_manage'))
682
    
683
@app.route('/group-new', methods=['GET'])
684
@security
685
def group_new():
686
    """show the create new project page"""
687
    if not session.get('logged_in'):
688
        log( "User with no valid session tries access to page /group-new", "FAIL", "HIGH")
689
        abort(401)     
690
    permissions("edit")
691
    return render_template('group-new.html', csrf_token=session['csrf_token'])
692
693
@app.route('/group-add', methods=['POST'])
694
@security
695
def group_add():
696
    """add a new project to database"""
697
    if not session.get('logged_in'):
698
        log("User with no valid session tries access to page /group-add", "FAIL", "HIGH")
699
        abort(401)
700
    permissions("edit")
701
    check_token()
702
    db = get_db()
703
    valAlphaNum(request.form['groupName'], 3)
704
    safe_inputName = encodeInput(request.form['groupName'])
705
    date = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
706
    db.execute('INSERT INTO groups (timestamp, groupName, ownerID) VALUES (?, ?, ?)',
707
               [date, safe_inputName, session['userID']])
708
    db.commit()
709
    #than we select the most last group in order to check id
710
    cur2 = db.execute('SELECT groupID from groups WHERE timestamp=? AND ownerID=?',
711
                        [date, session['userID']])
712
    group = cur2.fetchall()
713
    #Do actual loop
714
    for value in group:
715
        groupID = value[0]
716
        
717
    #Than we insert this back into groupMembers table so the user is added to group
718
    db.execute('INSERT INTO groupMembers (userID, groupID, ownerID, timestamp) VALUES (?, ?, ?, ?)',
719
               [session['userID'], groupID, session['userID'], date])
720
    db.commit()
721
    return redirect(url_for('group_manage'))
722
723
@app.route('/group-users', methods=['GET'])
724
@security
725
def group_users():
726
    """show the project list page"""
727
    if not session.get('logged_in'):
728
        log("User with no valid session tries access to page /group-users", "FAIL", "HIGH")
729
        abort(401)
730
    permissions("edit")
731
    db = get_db()
732
    cur = db.execute('SELECT * from groups where ownerID=?',
733
                          [session['userID']])
734
    groups = cur.fetchall()
735
    
736
    """Select all users for adding to group"""
737
    cur2 = db.execute('SELECT username, userID from users')
738
    users = cur2.fetchall()
739
    
740
    """select users by assigned groups for display"""
741
    cur3 = db.execute('SELECT u.username, u.userID, g.groupName, g.groupID, m.groupID, m.userID, m.timestamp, g.ownerID from users as u JOIN groups AS g ON g.groupID = m.groupID JOIN groupMembers as m ON u.userID = m.userID  WHERE g.ownerID=? AND u.userName !=? ORDER BY g.groupName ',
742
    				   [session['userID'], session['userName']])
743
    summary = cur3.fetchall()
744
745
    return render_template('group-users.html', groups=groups, users=users, summary=summary, csrf_token=session['csrf_token'])
746
747
@app.route('/group-add-users', methods=['POST'])
748
@security
749
def group_add_users():
750
    """add a project function"""
751
    if not session.get('logged_in'):
752
        log("User with no valid session tries access to page /project-function-add", "FAIL", "HIGH")
753
        abort(401)
754
    permissions("edit")
755
    check_token()    
756
    valNum(request.form['groupName'], 12)     
757
    safe_groupID = encodeInput(request.form['groupName'])
758
759
    """Check is submitted groupID is owned by user"""
760
    db = get_db()
761
    cur3 = db.execute('SELECT groupID from groups where ownerID=?',
762
    				   [session['userID']])
763
    owner = cur3.fetchall()
764
    for val in owner:
765
	    if int(safe_groupID) == int(val[0]):
766
			f = request.form
767
			for key in f.keys():
768
				for value in f.getlist(key):
769
					found = key.find("test")
770
					if found != -1:
771
						db = get_db()
772
						date = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
773
						items = value.split("-")
774
						userID = items[0]
775
						valNum(userID, 12)
776
						safe_userID = encodeInput(userID)
777
						db.execute('INSERT INTO groupMembers (timestamp, groupID, userID, ownerID) VALUES (?, ?, ?, ?)',
778
							   [date, safe_groupID, safe_userID, session['userID']])
779
						db.commit()
780
    redirect_url = '/group-users'
781
    return redirect(redirect_url)
782
783
@app.route('/user-del', methods=['POST'])
784
@security
785
def user_del():
786
    """delete project from database"""
787
    if not session.get('logged_in'):
788
        log("User with no valid session tries access to page /user-del", "FAIL", "HIGH")
789
        abort(401)
790
    permissions("delete")
791
    check_token()
792
    valNum(request.form['userID'], 12)
793
    
794
    safe_userID  = encodeInput(request.form['userID'])
795
    
796
    db = get_db()
797
    db.execute("DELETE FROM users WHERE userID=?",
798
               [safe_userID])
799
    db.commit()
800
    return redirect("/users-manage")
801
802
@app.route('/group-manage', methods=['GET'])
803
@security
804
def group_manage():
805
    """show the project list page"""
806
    if not session.get('logged_in'):
807
        log("User with no valid session tries access to page /group-manage", "FAIL", "HIGH")
808
        abort(401)
809
    permissions("edit")
810
    db = get_db()
811
    cur = db.execute('SELECT * from groups where ownerID=?',
812
                          [session['userID']])
813
    groups = cur.fetchall()
814
    
815
    return render_template('group-manage.html', groups=groups, csrf_token=session['csrf_token'])
816
    
817
@app.route('/group-del', methods=['POST'])
818
@security
819
def group_del():
820
    """delete project from database"""
821
    if not session.get('logged_in'):
822
        log("User with no valid session tries access to page /group-del", "FAIL", "HIGH")
823
        abort(401)
824
    permissions("manage")
825
    check_token()
826
    valNum(request.form['groupID'], 12)
827
    
828
    safe_groupID = encodeInput(request.form['groupID'])
829
    
830
    db = get_db()
831
    db.execute("DELETE FROM groups WHERE groupID=? AND ownerID=?",
832
               [safe_groupID, session['userID']])
833
    db.commit()
834
    return redirect("/group-manage")
835
836
@app.route('/project-new', methods=['GET'])
837
@security
838
def projects():
839
    """show the create new project page"""
840
    if not session.get('logged_in'):
841
        log("User with no valid session tries access to page /project-new", "FAIL", "HIGH")
842
        abort(401)     
843
    permissions("edit")
844
    return render_template('project-new.html', csrf_token=session['csrf_token'])
845
846
@app.route('/project-add', methods=['POST'])
847
@security
848
def add_entry():
849
    """add a new project to database"""
850
    if not session.get('logged_in'):
851
        log("User with no valid session tries access to page /project-add", "FAIL", "HIGH")
852
        abort(401)
853
    permissions("edit")
854
    check_token()
855
    db = get_db()
856
    valAlphaNum(request.form['inputName'], 1)
857
    valNum(request.form['inputVersion'], 1)
858
    safe_inputName = encodeInput(request.form['inputName'])
859
    safe_inputVersion = encodeInput(request.form['inputVersion'])
860
    safe_inputDesc = encodeInput(request.form['inputDesc'])
861
    date = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
862
    db.execute('INSERT INTO projects (timestamp, projectName, projectVersion, projectDesc, userID, ownerID, groupID) VALUES (?, ?, ?, ?, ?, ?, ?)',
863
               [date, safe_inputName, safe_inputVersion, safe_inputDesc, session['userID'],  session['userID'], session['privateGroup']])
864
    db.commit()
865
    return redirect(url_for('project_list'))
866
867
@app.route('/assign-group', methods=['POST'])
868
@security
869
def assign_group():
870
    """add a new project to database"""
871
    if not session.get('logged_in'):
872
        log("User with no valid session tries access to page /assign-group", "FAIL", "HIGH")
873
        abort(401)
874
    permissions("edit")
875
    check_token()
876
    db = get_db()
877
    valNum(request.form['projectID'], 12)
878
    valNum(request.form['groupID'], 12)
879
    safe_groupID   = encodeInput(request.form['groupID'])
880
    safe_projectID = encodeInput(request.form['projectID'])
881
    """Check is submitted groupID is owned by user"""
882
    cur = db.execute('SELECT groupID from groups where ownerID=?',
883
    				   [session['userID']])
884
    owner = cur.fetchall()
885
    for val in owner:
886
        print(val)
887
        if int(safe_groupID) == int(val[0]):
888
            db.execute('UPDATE projects SET groupID=? WHERE projectID=? AND userID=?',
889
                   [safe_groupID, safe_projectID, session['userID']])
890
            db.commit()
891
    return redirect(url_for('project_list'))
892
893
@app.route('/project-del', methods=['POST'])
894
@security
895
def project_del():
896
    """delete project from database"""
897
    if not session.get('logged_in'):
898
        log("User with no valid session tries access to page /project-del", "FAIL", "HIGH")
899
        abort(401)
900
    permissions("delete")
901
    valNum(request.form['projectID'], 12)
902
    id = request.form['projectID']
903
    check_token()
904
    db = get_db()
905
    db.execute("DELETE FROM projects WHERE projectID=? AND userID=? AND ownerID=?",
906
               [id, session['userID'], session['userID']])
907
    db.commit()
908
    return redirect("/project-list")
909
910
@app.route('/project-list', methods=['GET'])
911
@security
912
def project_list():
913
    """show the project list page"""
914
    if not session.get('logged_in'):
915
        log("User with no valid session tries access to page /project-list", "FAIL", "HIGH")
916
        abort(401)
917
    permissions("read")
918
    db = get_db()  
919
    #First query is for the users own owned projects
920
    cur = db.execute('SELECT p.projectName, p.projectVersion, p.projectDESC, p.projectID, p.timestamp, p.groupID, g.groupName, g.groupID FROM projects as p JOIN groups as g ON g.groupID = p.groupID where p.userID=? ORDER BY projectID DESC',
921
                          [session['userID']])
922
    entries = cur.fetchall()
923
    #select the groups which can be selected by this user    
924
    cur3 = db.execute('SELECT * FROM groups WHERE ownerID=?',
925
                          [session['userID']])
926
    groups = cur3.fetchall()
927
    return render_template('project-list.html', entries=entries, groups=groups, csrf_token=session['csrf_token'])
928
    
929
@app.route('/project-shared', methods=['GET'])
930
@security
931
def project_shared():
932
    """show the project list page"""
933
    if not session.get('logged_in'):
934
        log("User with no valid session tries access to page /project-list", "FAIL", "HIGH")
935
        abort(401)
936
    permissions("read")
937
    db = get_db()
938
    #Here we see what projects this users was assigned to
939
    cur = db.execute('SELECT p.projectName, p.projectVersion, p.projectDESC, p.projectID, p.timestamp, p.groupID, p.ownerID, m.userID, m.groupID, u.userID, u.userName FROM projects as p JOIN groupMembers as m ON m.groupID = p.groupID JOIN users as u ON u.userID=p.ownerID where m.userID=? AND u.userName !=? ORDER BY p.projectID DESC',
940
                          [session['userID'], session['userName']])
941
    entries = cur.fetchall()
942
        
943
    return render_template('project-shared.html', entries=entries, csrf_token=session['csrf_token'])
944
945
@app.route('/project-options/<project_id>', methods=['GET'])
946
@security
947
def projects_options(project_id):
948
    """show the project options landing page"""
949
    if not session.get('logged_in'):
950
        log("User with no valid session tries access to page /project-options", "FAIL", "HIGH")
951
        abort(401)
952
    permissions("read")
953
    valNum(project_id, 12)
954
    safe_project_id = encodeInput(project_id)
955
    return render_template('project-options.html', project_id=safe_project_id, csrf_token=session['csrf_token'])
956
957
@app.route('/project-functions/<project_id>', methods=['GET'])
958
@security
959
def project_functions(project_id):
960
    """show the pproject functions page"""
961
    if not session.get('logged_in'):
962
        log("User with no valid session tries access to page /project-functions", "FAIL", "HIGH")
963
        abort(401)
964
    permissions("read")
965
    techlist = projects_functions_techlist()
966
    valNum(project_id, 12)
967
    safe_project_id = encodeInput(project_id)
968
    db = get_db()
969
    db.commit()
970
    cur = db.execute('SELECT p.paramID, p.functionName, p.functionDesc, p.projectID, p.userID, p.tech, p.techVuln, p.entryDate, t.techName, proj.projectID, proj.groupID, m.userID, m.groupID FROM parameters AS p JOIN techhacks AS t ON p.tech = t.techID JOIN projects as proj ON proj.projectID = p.projectID JOIN groupMembers as m ON m.groupID = proj.groupID WHERE proj.projectID=? AND m.userID=? GROUP BY t.techName',
971
                      [safe_project_id, session['userID']])
972
    entries = cur.fetchall()
973
    return render_template('project-functions.html', project_id=project_id, techlist=projects_functions_techlist(), entries=entries, csrf_token=session['csrf_token'])
974
975
@app.route('/project-function-del', methods=['POST'])
976
@security
977
def function_del():
978
    """delete a project function"""
979
    if not session.get('logged_in'):
980
        log( "User with no valid session tries access to page /project-function-del", "FAIL", "HIGH")
981
        abort(401)
982
    permissions("delete")
983
    check_token()
984
    valNum(request.form['projectID'], 12)
985
    valNum(request.form['paramID'], 12)
986
    id = request.form['projectID']
987
    id_param = int(request.form['paramID'])
988
    db = get_db()
989
    #First check if the user is allowed to delete this parameter
990
    cur = db.execute('SELECT p.projectID, p.groupID, m.groupID, m.userID from projects as p JOIN groupMembers as m ON m.groupID = p.groupID where m.userID=?',
991
    				   [session['userID']])
992
    for val in cur:
993
	    if int(id) == int(val[0]):
994
			db.execute("DELETE FROM parameters WHERE projectID=? AND paramID=?",
995
					   [id, id_param])
996
			db.commit()
997
			redirect_url = "/project-functions/"+str(id)
998
    return redirect(redirect_url)
999
1000
1001
@app.route('/project-function-add', methods=['POST'])
1002
@security
1003
def add_function():
1004
    """add a project function"""
1005
    if not session.get('logged_in'):
1006
        log("User with no valid session tries access to page /project-function-add", "FAIL", "HIGH")
1007
        abort(401)
1008
    permissions("edit")
1009
    check_token()
1010
    valNum(request.form['project_id'], 12)
1011
    id = request.form['project_id']
1012
    valAlphaNum(request.form['functionName'], 1)
1013
    valAlphaNum(request.form['functionDesc'], 1)
1014
    safe_fName = encodeInput(request.form['functionName'])
1015
    safe_fDesc = encodeInput(request.form['functionDesc'])	
1016
    
1017
    #Check is submitted projectID is owned by user
1018
    db = get_db()
1019
    cur3 = db.execute('SELECT p.projectID, p.groupID, m.groupID, m.userID from projects as p JOIN groupMembers as m ON m.groupID = p.groupID where m.userID=?',
1020
    				   [session['userID']])
1021
    owner = cur3.fetchall()
1022
    for val in owner:
1023
        print(val)
1024
        if int(id) == int(val[0]):
1025
			f = request.form
1026
			for key in f.keys():
1027
				for value in f.getlist(key):
1028
						found = key.find("test")
1029
						if found != -1:
1030
							db = get_db()
1031
							date = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
1032
							items = value.split("-")
1033
							techID = items[2]
1034
							vulnID = items[0]
1035
							valAlphaNum(techID, 12)
1036
							valAlphaNum(vulnID, 12)
1037
							safe_techID = encodeInput(techID)
1038
							safe_vulnID = encodeInput(vulnID)
1039
							db.execute('INSERT INTO parameters (entryDate, functionName, functionDesc, techVuln, tech, projectID, userID) VALUES (?, ?, ?, ?, ?, ?, ?)',
1040
								   [date, safe_fName, safe_fDesc, safe_vulnID, safe_techID, id, session['userID']])
1041
							db.commit()
1042
    redirect_url = '/project-functions/'+str(id) 
1043
    return redirect(redirect_url)
1044
1045
@app.route('/project-checklist-add', methods=['POST'])
1046
@security
1047
def add_checklist():
1048
    """add project checklist"""
1049
    if not session.get('logged_in'):
1050
        log("User with no valid session tries access to page /project-checklist-add", "FAIL", "HIGH")
1051
        abort(401)
1052
    permissions("edit")
1053
    check_token()
1054
    i = 1
1055
    #We do valNum for projectID here because we need it in the comparison
1056
    valNum(request.form['projectID'], 12)
1057
    #Check is submitted projectID is owned by user
1058
    db = get_db()
1059
    cur3 = db.execute('SELECT p.projectID, p.groupID, m.groupID, m.userID from projects as p JOIN groupMembers as m ON m.groupID = p.groupID where m.userID=?',
1060
    				   [session['userID']])
1061
    owner = cur3.fetchall()
1062
    for val in owner:
1063
        print(val)
1064
        if int(request.form['projectID']) == int(val[0]):
1065
			f = request.form
1066
			for key in f.keys():
1067
				for value in f.getlist(key):
1068
					found = key.find("vuln")
1069
					if found != -1:
1070
						listID = "listID"+str(i)
1071
						answerID = "answer"+str(i)
1072
						questionID = "questionID"+str(i) 
1073
						vulnID = "vulnID"+str(i)
1074
						valAlphaNum(request.form[answerID], 12)
1075
						valNum(request.form[questionID], 12)
1076
						valNum(request.form[vulnID], 12)
1077
						valAlphaNum(request.form[listID], 12)
1078
						valAlphaNum(request.form['projectName'], 12)
1079
						safe_answerID = encodeInput(request.form[answerID])
1080
						safe_questionID = encodeInput(request.form[questionID])
1081
						safe_vulnID = encodeInput(request.form[vulnID])
1082
						safe_listID = encodeInput(request.form[listID])
1083
						safe_pName = encodeInput(request.form['projectName'])
1084
						safe_id = encodeInput(request.form['projectID'])
1085
						#print '        '+answerID+'="'+str(safe_answerID)+'",'
1086
						#print '        '+questionID+'="'+str(safe_questionID)+'",'
1087
						#print '        '+vulnID+'="'+str(safe_vulnID)+'",'
1088
						#print '        '+listID+'="'+str(safe_listID)+'",'
1089
						date = datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
1090
						db = get_db()
1091
						db.execute('INSERT INTO questionlist (entryDate, answer, projectName, projectID, questionID, vulnID, listName, userID) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
1092
								   [date, safe_answerID, safe_pName, safe_id, safe_questionID, safe_vulnID, safe_listID, session['userID']])
1093
						db.commit()
1094
						i += 1
1095
    redirect_url = "/results-checklists"
1096
    return redirect(redirect_url)
1097
1098
@app.route('/project-checklists/<project_id>', methods=['GET'])
1099
@security
1100
def project_checklists(project_id):
1101
    """show the project checklists page"""
1102
    if not session.get('logged_in'):
1103
        log( "User with no valid session tries access to page /project-checklists", "FAIL", "HIGH")
1104
        abort(401)
1105
    permissions("read")
1106
    valNum(project_id, 12)
1107
    safe_id = int(project_id, 12)
1108
    db = get_db()
1109
    cur = db.execute('SELECT p.projectID, p.userID, p.groupID, p.projectName, p.projectVersion, p.projectDesc, p.ownerID, m.userID, m.groupID FROM projects as p JOIN groupMembers AS m ON m.groupID = p.groupID WHERE p.projectID=? AND m.userID=?',
1110
                        [safe_id, session['userID']])
1111
    row = cur.fetchall()
1112
    prep = row[0]
1113
    projectName = prep[1]
1114
    owasp_items_lvl1 = []
1115
    owasp_items_lvl1_ygb = []
1116
    owasp_ids_lvl1 = []
1117
    owasp_kb_ids_lvl1 = []
1118
    owasp_content_lvl1 = []
1119
    owasp_content_desc_lvl1 = []
1120
    owasp_items_lvl2 = []
1121
    owasp_items_lvl2_ygb = []
1122
    owasp_ids_lvl2 = []
1123
    owasp_kb_ids_lvl2 = []
1124
    owasp_content_lvl2 = []
1125
    owasp_content_desc_lvl2 = []
1126
    owasp_items_lvl3 = []
1127
    owasp_items_lvl3_ygb = []
1128
    owasp_ids_lvl3 = []
1129
    owasp_kb_ids_lvl3 = []
1130
    owasp_content_lvl3 = []
1131
    owasp_content_desc_lvl3 = []
1132
    custom_items = []
1133
    custom_ids = []
1134
    custom_kb_ids = []
1135
    custom_content = []
1136
    basic_items = []
1137
    basic_ids = []
1138
    basic_kb_ids = []
1139
    basic_content = []
1140
    advanced_items = []
1141
    advanced_ids = []
1142
    advanced_kb_ids = []
1143
    advanced_content = []
1144
    full_file_paths = []
1145
    full_file_paths = get_filepaths(os.path.join(app.root_path, "markdown/checklists"))
1146
    full_file_paths.sort()
1147
    for path in full_file_paths:
1148
       found = path.find("ASVS-level-1")
1149
       if found != -1:
1150
            owasp_org_path = path
1151
            owasp_list_lvl1 = "ASVS-level-1"
1152
            owasp_path_lvl1 = path.split("-")
1153
            owasp_kb = owasp_path_lvl1[7]
1154
            owasp_id = get_num(owasp_path_lvl1[1])
1155
            #owasp_items_lvl1.append(owasp_checklist_name)
1156
            owasp_ids_lvl1.append(owasp_id)
1157
            owasp_items_lvl1_ygb.append(owasp_path_lvl1[9])
1158
            owasp_kb_ids_lvl1.append(owasp_kb)
1159
            filemd = open(owasp_org_path, 'r').read()
1160
            owasp_content_lvl1.append(Markup(markdown.markdown(filemd)))
1161
            full_file_paths_kb = get_filepaths(os.path.join(app.root_path, "markdown/knowledge_base"))
1162
            for path in full_file_paths_kb:
1163
                org_path = path
1164
                path_kb = path.split("markdown")
1165
                path_vuln = get_num(path_kb[1])
1166
                if int(owasp_kb) == int(path_vuln):
1167
                    filemd = open(org_path, 'r').read()
1168
                    description = filemd.split("**") 
1169
                    owasp_content_desc_lvl1.append(description[2])
1170
    for path in full_file_paths:
1171
       found = path.find("ASVS-level-2")
1172
       if found != -1:
1173
            owasp_org_path = path
1174
            owasp_list_lvl2 = "ASVS-level-2"
1175
            owasp_path_lvl2 = path.split("-")
1176
            owasp_kb = owasp_path_lvl2[7]
1177
            owasp_id = get_num(owasp_path_lvl2[1])
1178
            #owasp_items_lvl2.append(owasp_checklist_name)
1179
            owasp_ids_lvl2.append(owasp_id)
1180
            owasp_kb_ids_lvl2.append(owasp_kb)
1181
            owasp_items_lvl2_ygb.append(owasp_path_lvl2[9])
1182
            filemd = open(owasp_org_path, 'r').read()
1183
            owasp_content_lvl2.append(Markup(markdown.markdown(filemd)))
1184
            full_file_paths_kb = get_filepaths(os.path.join(app.root_path, "markdown/knowledge_base"))
1185
            for path in full_file_paths_kb:
1186
                org_path = path
1187
                path_kb = path.split("markdown")
1188
                path_vuln = get_num(path_kb[1])
1189
                if int(owasp_kb) == int(path_vuln):
1190
                    filemd = open(org_path, 'r').read()
1191
                    description = filemd.split("**") 
1192
                    owasp_content_desc_lvl2.append(description[2])
1193
    for path in full_file_paths:
1194
       found = path.find("ASVS-level-3")
1195
       if found != -1:
1196
            owasp_org_path = path
1197
            owasp_list_lvl3 = "ASVS-level-3"
1198
            owasp_path_lvl3 = path.split("-")
1199
            owasp_kb = owasp_path_lvl3[7]
1200
            owasp_id = get_num(owasp_path_lvl3[1])
1201
            #owasp_items_lvl3.append(owasp_checklist_name)
1202
            owasp_ids_lvl3.append(owasp_id)
1203
            owasp_kb_ids_lvl3.append(owasp_kb)
1204
            owasp_items_lvl3_ygb.append(owasp_path_lvl3[9])
1205
            filemd = open(owasp_org_path, 'r').read()
1206
            owasp_content_lvl3.append(Markup(markdown.markdown(filemd)))
1207
            full_file_paths_kb = get_filepaths(os.path.join(app.root_path, "markdown/knowledge_base"))
1208
            for path in full_file_paths_kb:
1209
                org_path = path
1210
                path_kb = path.split("markdown")
1211
                path_vuln = get_num(path_kb[1])
1212
                if int(owasp_kb) == int(path_vuln):
1213
                    filemd = open(org_path, 'r').read()
1214
                    description = filemd.split("**") 
1215
                    owasp_content_desc_lvl3.append(description[2])
1216
    for path in full_file_paths:
1217
       found = path.find("CS_basic_audit")
1218
       if found != -1:
1219
            basic_org_path = path
1220
            basic_list = "CS_basic_audit"
1221
            basic_path = path.split("-")
1222
            basic_kb = basic_path[5]
1223
            basic_checklist_name = basic_path[3]
1224
            basic_id = get_num(basic_path[1])
1225
            basic_items.append(basic_checklist_name)
1226
            basic_ids.append(basic_id)
1227
            basic_kb_ids.append(basic_kb)
1228
            filemd = open(basic_org_path, 'r').read()
1229
            basic_content.append(Markup(markdown.markdown(filemd)))
1230
    for path in full_file_paths:
1231
       found = path.find("CS_advanced_audit")
1232
       if found != -1:
1233
            advanced_org_path = path
1234
            advanced_list = "CS_advanced_audit"
1235
            advanced_path = path.split("-")
1236
            advanced_kb = advanced_path[5]
1237
            advanced_name = advanced_path[3]
1238
            advanced_id = get_num(advanced_path[1])
1239
            advanced_items.append(advanced_name)
1240
            advanced_ids.append(advanced_id)
1241
            advanced_kb_ids.append(advanced_kb)
1242
            filemd = open(advanced_org_path, 'r').read()
1243
            advanced_content.append(Markup(markdown.markdown(filemd)))
1244
    for path in full_file_paths:
1245
       found = path.find("custom")
1246
       if found != -1:
1247
            custom_org_path = path
1248
            custom_list = "custom"
1249
            custom_path = path.split("-")
1250
            custom_kb = custom_path[5]
1251
            custom_name = custom_path[3]
1252
            custom_id = get_num(custom_path[1])
1253
            custom_items.append(custom_name)
1254
            custom_ids.append(custom_id)
1255
            custom_kb_ids.append(custom_kb)
1256
            filemd = open(custom_org_path, 'r').read()
1257
            custom_content.append(Markup(markdown.markdown(filemd)))
1258
    return render_template('project-checklists.html', csrf_token=session['csrf_token'],  **locals())
1259
1260
@app.route('/results-checklists', methods=['GET'])
1261
@security
1262
def results_checklists():
1263
    """show the results checklists page"""
1264
    if not session.get('logged_in'):
1265
        log( "User with no valid session tries access to page /results-checklists", "FAIL", "HIGH")
1266
        abort(401)
1267
    permissions("read")
1268
    db = get_db()
1269
    cur = db.execute('SELECT q.answer, q.projectID, q.questionID,  q.vulnID, q.listName, q.entryDate, p.projectName, p.projectVersion, p.projectDesc, p.groupID, m.groupID, m.userID FROM questionlist AS q JOIN projects AS p ON q.projectID = p.projectID JOIN groupMembers as m ON m.groupID = p.groupID WHERE m.userID=? GROUP BY q.listName, q.entryDate ORDER BY p.projectName ASC',
1270
                          [session['userID']])
1271
    entries = cur.fetchall()
1272
    return render_template('results-checklists.html', entries=entries, csrf_token=session['csrf_token'])
1273
1274
@app.route('/results-functions', methods=['GET'])
1275
@security
1276
def results_functions():
1277
    """show the results functions page"""
1278
    if not session.get('logged_in'):
1279
        log( "User with no valid session tries access to page /results-functions", "FAIL", "HIGH")
1280
        abort(401)
1281
    permissions("read")
1282
    db = get_db()
1283
    cur = db.execute('SELECT p.projectName, p.projectID, par.entryDate, p.projectDesc, p.groupID, m.userID, m.groupID, p.projectVersion, par.paramID, par.functionName, par.projectID FROM projects AS p join parameters AS par on p.projectID = par.projectID JOIN groupMembers AS m ON m.groupID = p.groupID WHERE m.userID=? GROUP BY p.projectVersion ',
1284
                         [session['userID']])
1285
    entries = cur.fetchall()
1286
    return render_template('results-functions.html', entries=entries, csrf_token=session['csrf_token'])
1287
1288
@app.route('/results-functions-del', methods=['POST'])
1289
@security
1290
def functions_del():
1291
    """delete functions result items"""
1292
    if not session.get('logged_in'):
1293
        log( "User with no valid session tries access to page /results-functions-del", "FAIL", "HIGH")
1294
        abort(401)
1295
    permissions("delete")
1296
    check_token()
1297
    valNum(request.form['projectID'], 12)
1298
    safe_entryDate = encodeInput(request.form['entryDate'])
1299
    safe_projectID = encodeInput(request.form['projectID'])
1300
    db = get_db()
1301
    
1302
    #Use select in order to see if this user is linked to project
1303
    cur = db.execute("SELECT p.projectID, p.groupID, m.groupID, m.userID FROM projects AS p JOIN groupMembers AS m ON m.groupID = p.groupID WHERE m.userID=?  ",
1304
               		[session['userID']])
1305
    entries = cur.fetchall()
1306
    for entry in entries:
1307
        if int(entry[0]) == int(safe_projectID):
1308
            db.execute("DELETE FROM parameters WHERE entryDate=? AND projectID=?",
1309
               [safe_entryDate, safe_projectID])
1310
            db.commit()
1311
    return redirect("/results-functions")
1312
1313
@app.route('/results-checklists-del', methods=['POST'])
1314
@security
1315
def checklists_del():
1316
    """delete checklist result item"""
1317
    if not session.get('logged_in'):
1318
        log( "User with no valid session tries access to page /results-checklists-del", "FAIL", "HIGH")
1319
        abort(401)
1320
    permissions("delete")
1321
    check_token()
1322
    safe_entryDate = encodeInput(request.form['entryDate'])
1323
    valNum(request.form['projectID'], 12)
1324
    safe_projectID = encodeInput(request.form['projectID'])
1325
    db = get_db()
1326
    #Use select in order to see if this user is linked to project
1327
    cur = db.execute("SELECT p.projectID, p.groupID, m.groupID, m.userID FROM projects AS p JOIN groupMembers AS m ON m.groupID = p.groupID WHERE m.userID=?  ",
1328
               		[session['userID']])
1329
    entries = cur.fetchall()
1330
    for entry in entries:
1331
        if int(entry[0]) == int(safe_projectID):
1332
			db.execute("DELETE FROM questionlist WHERE entryDate=? AND projectID=? ",
1333
				   [safe_entryDate, safe_projectID])
1334
			db.commit()
1335
    return redirect("/results-checklists")
1336
1337
1338
@app.route('/results-checklist-report/<entryDate>', methods=['GET'])
1339
@security
1340
def checklist_results(entryDate):
1341
    """show checklist results report"""
1342
    if not session.get('logged_in'):
1343
        log( "User with no valid session tries access to page /results-checklist-report", "FAIL", "HIGH")
1344
        abort(401)
1345
    permissions("read")
1346
    ygb = []
1347
    id_items = []
1348
    questions = []
1349
    content = []
1350
    full_file_paths = []
1351
    safe_entryDate = encodeInput(entryDate)
1352
    db = get_db()
1353
    cur = db.execute("SELECT l.listID, l.answer, l.projectID, l.projectName, l.questionID, l.vulnID, l.listName, l.entryDate, l.userID, m.userID, m.groupID, p.projectID, p.groupID FROM questionlist AS l JOIN projects AS p ON p.projectID = l.projectID JOIN groupMembers AS m ON m.groupID = p.groupID WHERE l.answer='no' AND l.entryDate=? AND m.userID=?",
1354
               [safe_entryDate, session['userID']])
1355
    entries = cur.fetchall()
1356
    for entry in entries:
1357
        projectName = entry[3]
1358
        questionID = entry[4]
1359
        vulnID = entry[5]
1360
        listName = entry[6]
1361
        entryDate = entry[7]
1362
        full_file_paths = get_filepaths(os.path.join(app.root_path, "markdown/knowledge_base"))
1363
        for path in full_file_paths:
1364
            org_path = path
1365
            path = path.split("markdown")
1366
            path_vuln = get_num(path[1])
1367
            if int(vulnID) == int(path_vuln):
1368
                filemd = open(org_path, 'r').read()
1369
                content.append(Markup(markdown.markdown(filemd)))
1370
                full_file_paths = get_filepaths(os.path.join(app.root_path, "markdown/checklists"))
1371
                for path in full_file_paths:
1372
                    org_path = path
1373
                    custom_path = org_path.split("-")
1374
                    path_questionID = get_num(custom_path[1])
1375
                    if int(questionID) == int(path_questionID):
1376
                        filemd = open(org_path, 'r').read()
1377
                        questions.append(Markup(markdown.markdown(filemd)))
1378
                        custom_paths = org_path.split("-")
1379
                        found = custom_paths[3].find("ASVS")
1380
                        if found != -1:
1381
                            ygb.append(custom_paths[9])
1382
    return render_template('results-checklist-report.html', **locals())
1383
1384
1385
@app.route('/results-checklist-docx/<entryDate>')
1386
def download_file_checklist(entryDate):
1387
    """Download checklist results report in docx"""
1388
    if not session.get('logged_in'):
1389
        log( "User with no valid session tries access to page /results-checklist-docx", "FAIL", "HIGH")
1390
        abort(401)
1391
    permissions("read")
1392
    ygb_docx = []    
1393
    content_raw = []
1394
    content_checklist = []
1395
    content_title = []
1396
    safe_entryDate = encodeInput(entryDate)
1397
    db = get_db()
1398
    cur = db.execute("SELECT l.listID, l.answer, l.projectID, l.projectName, l.questionID, l.vulnID, l.listName, l.entryDate, l.userID, m.userID, m.groupID, p.projectID, p.groupID FROM questionlist AS l JOIN projects AS p ON p.projectID = l.projectID JOIN groupMembers AS m ON m.groupID = p.groupID WHERE l.answer='no' AND l.entryDate=? AND m.userID=?",
1399
               [safe_entryDate, session['userID']])
1400
    entries = cur.fetchall()
1401
    document = Document()
1402
    document.add_picture(os.path.join(app.root_path,'static/img/banner-docx.jpg'), width=Inches(5.125), height=Inches(1.042))
1403
    last_paragraph = document.paragraphs[-1] 
1404
    last_paragraph.alignment = WD_ALIGN_PARAGRAPH.LEFT
1405
    #document.add_heading('Security Knowledge Framework', 0)
1406
    last_paragraph = document.paragraphs[-1] 
1407
    last_paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
1408
    p = document.add_paragraph()
1409
    projectName = entries[0][3]
1410
    listName = entries[0][6]
1411
    ygb = False
1412
    p.add_run('Used Checklist: '+listName)
1413
    p.add_run('\r\n')
1414
    p.add_run('Date: '+datetime.datetime.now().strftime("%Y-%m-%d %H:%M"))
1415
    p.add_run('\r\n')
1416
    p.add_run('Project: '+projectName)
1417
    document.add_page_break()
1418
    p = document.add_heading('Table of contents', level=1)
1419
    p.add_run('\r\n')
1420
    document.add_paragraph('Introduction')
1421
    for entry in entries:
1422
        projectName = entry[3]
1423
        questionID = entry[4]
1424
        vulnID = entry[5]
1425
        listName = entry[6]
1426
        entryDate = entry[7]
1427
        full_file_paths = get_filepaths(os.path.join(app.root_path, "markdown/knowledge_base"))
1428
        for path in full_file_paths:
1429
            org_path = path
1430
            path = path.split("markdown")
1431
            path_vuln = get_num(path[1])
1432
            if int(vulnID) == int(path_vuln):
1433
                filemd = open(org_path, 'r').read()
1434
                content = Markup(markdown.markdown(filemd))
1435
                text = ''.join(BeautifulSoup(content).findAll(text=True))
1436
                text_encode = text.encode('utf-8')
1437
                content_title.append(text_encode.splitlines()[0])
1438
                text_encode = text_encode.replace("Solution", "\nSolution");
1439
                content_raw.append(text_encode)
1440
                full_file_paths = get_filepaths(os.path.join(app.root_path, "markdown/checklists"))
1441
                for path in full_file_paths:
1442
                    org_path = path
1443
                    path = path.split("markdown")
1444
                    tmp_path = path[1].split("-")
1445
                    custom_path = get_num(tmp_path[0])
1446
                    path_questionID = custom_path
1447
                    if int(questionID) == int(path_questionID):
1448
                        filemd = open(org_path, 'r').read()
1449
                        content_checklist.append(Markup(markdown.markdown(filemd)))
1450
                        custom_paths = org_path.split("-")
1451
                        found = custom_paths[3].find("ASVS")
1452
                        if found != -1:
1453
                            ygb = True
1454
                            ygb_docx.append(custom_paths[9])
1455
    for item in content_title:
1456
        p = document.add_paragraph(item)
1457
        p.add_run()
1458
    document.add_page_break()
1459
    document.add_heading('Introduction', level=1)
1460
    p = document.add_paragraph(
1461
        'The security knowledge framework is composed by means of the highest security standards currently available and is designed to maintain the integrity of your application, so you and your costumers sensitive data is protected against hackers. This document is provided with a checklist in which the programmers of your application had to run through in order to provide a secure product.'
1462
    )
1463
    p.add_run('\n')
1464
    p = document.add_paragraph(
1465
        'In the post-development stage of the security knowledge framework the developer double-checks his application against a checklist which consists out of several questions asking the developer about different stages of development and the methodology of implementing different types of functionality the application contains. After filling in this checklist the developer gains feedback on the failed checklist items providing him with solutions about how to solve the additional vulnerability\'s found in the application.'
1466
    )
1467
    document.add_page_break()
1468
    i = 0
1469
    for item in content_raw:
1470
        document.add_heading(content_title[i], level=1)
1471
        result = re.sub("<p>", " ", content_checklist[i])
1472
        result1 = re.sub("</p>", " ", result)
1473
        document.add_heading(result1, level=4)
1474
        p = document.add_paragraph(item.partition("\n")[2])
1475
        if ygb == True:
1476
            if ygb_docx[i] == "b":
1477
                image = document.add_picture(os.path.join(app.root_path,'static/img/blue.png'), width=Inches(0.20))
1478
            elif ygb_docx[i] == "gb":
1479
                image = document.add_picture(os.path.join(app.root_path,'static/img/green.png'), width=Inches(0.20))
1480
                image = document.add_picture(os.path.join(app.root_path,'static/img/blue.png'), width=Inches(0.20))
1481
            elif ygb_docx[i] == "ygb":
1482
                image = document.add_picture(os.path.join(app.root_path,'static/img/yellow.png'), width=Inches(0.20))
1483
                image = document.add_picture(os.path.join(app.root_path,'static/img/green.png'), width=Inches(0.20))            
1484
                image = document.add_picture(os.path.join(app.root_path,'static/img/blue.png'), width=Inches(0.20))
1485
        p.add_run("\n")
1486
        document.add_page_break()
1487
        i += 1
1488
    document.save("checklist-security-report.docx")
1489
    headers = {"Content-Disposition": "attachment; filename=%s" % "checklist-security-report.docx"}
1490
    file_path = os.path.join(app.root_path, "checklist-security-report.docx")
1491
    with open("checklist-security-report.docx", 'rb') as f:
1492
        body = f.read()
1493
    return make_response((body, headers))
1494
    
1495
    
1496
@app.route('/results-function-report/<projectID>', methods=['GET'])
1497
@security
1498
def function_results(projectID):
1499
    """show checklist results report"""
1500
    if not session.get('logged_in'):
1501
        log( "User with no valid session tries access to page /results-function-report", "FAIL", "HIGH")
1502
        abort(401)
1503
    permissions("read")
1504
    id_items = []
1505
    content = []
1506
    full_file_paths = []
1507
    valNum(projectID, 12)
1508
    safe_id = encodeInput(projectID)
1509
    db = get_db()
1510
    cur = db.execute("SELECT projects.projectName, projects.projectID, projects.projectVersion, parameters.functionName, parameters.tech, parameters.functionDesc, parameters.entryDate, parameters.techVuln, techhacks.techName, projects.userID, projects.groupID, m.userID, m.groupID FROM projects JOIN parameters ON parameters.projectID=projects.projectID JOIN techhacks ON techhacks.techID  = parameters.tech JOIN groupMembers AS m ON m.groupID = projects.groupID WHERE parameters.projectID=? AND m.userID=? GROUP BY parameters.tech;",
1511
               [safe_id, session['userID']])
1512
    entries = cur.fetchall()
1513
    for entry in entries:
1514
        projectName = entry[0]
1515
        vulnID = entry[7]
1516
        full_file_paths = get_filepaths(os.path.join(app.root_path, "markdown/knowledge_base"))
1517
        for path in full_file_paths:
1518
            org_path = path
1519
            path = path.split("markdown")
1520
            path_vuln = get_num(path[1])
1521
            if int(vulnID) == int(path_vuln):
1522
                filemd = open(org_path, 'r').read()
1523
                content.append(Markup(markdown.markdown(filemd)))
1524
    return render_template('results-function-report.html', **locals())
1525
1526
@app.route('/results-function-docx/<projectID>')
1527
def download_file_function(projectID):
1528
    """Download checklist results report in docx"""
1529
    if not session.get('logged_in'):
1530
        log( "User with no valid session tries access to page /results-function-docx", "FAIL", "HIGH")
1531
        abort(401)
1532
    permissions("read")
1533
    content_raw = []
1534
    content_title = []
1535
    content_tech = []
1536
    valNum(projectID, 12)
1537
    safe_id = encodeInput(projectID)
1538
    db = get_db()
1539
    cur = db.execute("SELECT projects.projectName, projects.projectID, projects.projectVersion, parameters.functionName, parameters.tech, parameters.functionDesc, parameters.entryDate, parameters.techVuln, techhacks.techName, projects.userID, projects.groupID, m.userID, m.groupID FROM projects JOIN parameters ON parameters.projectID=projects.projectID JOIN techhacks ON techhacks.techID  = parameters.tech JOIN groupMembers AS m ON m.groupID = projects.groupID WHERE parameters.projectID=? AND m.userID=? GROUP BY parameters.tech;",
1540
               [safe_id, session['userID']])
1541
    entries = cur.fetchall()
1542
    document = Document()
1543
    document.add_picture(os.path.join(app.root_path,'static/img/banner-docx.jpg'), width=Inches(5.125), height=Inches(1.042))
1544
    last_paragraph = document.paragraphs[-1] 
1545
    last_paragraph.alignment = WD_ALIGN_PARAGRAPH.LEFT
1546
    #document.add_heading('Security Knowledge Framework', 0)
1547
    last_paragraph = document.paragraphs[-1] 
1548
    last_paragraph.alignment = WD_ALIGN_PARAGRAPH.CENTER
1549
    p = document.add_paragraph()
1550
    projectName = entries[0][0]
1551
    functionName = entries[0][3]
1552
    functionDesc= entries[0][5]
1553
    p.add_run('Date: '+datetime.datetime.now().strftime("%Y-%m-%d %H:%M"))
1554
    p.add_run('\r\n')
1555
    p.add_run('Project: '+projectName)
1556
    document.add_page_break()
1557
    p = document.add_heading('Table of contents', level=1)
1558
    p.add_run('\r\n')
1559
    document.add_paragraph('Introduction')
1560
    for entry in entries:
1561
        entryDate = entry[6]
1562
        vulnID = entry[7]
1563
        full_file_paths = get_filepaths(os.path.join(app.root_path, "markdown/knowledge_base"))
1564
        for path in full_file_paths:
1565
            org_path = path
1566
            path = path.split("markdown")
1567
            path_vuln = get_num(path[1])
1568
            if int(vulnID) == int(path_vuln):
1569
                filemd = open(org_path, 'r').read()
1570
                content = Markup(markdown.markdown(filemd))
1571
                text = ''.join(BeautifulSoup(content).findAll(text=True))
1572
                text_encode = text.encode('utf-8')
1573
                content_title.append(text_encode.splitlines()[0])
1574
                text_encode = text_encode.replace("Solution", "\nSolution");
1575
                content_raw.append(text_encode)
1576
    for item in content_title:
1577
        p = document.add_paragraph(item)
1578
        p.add_run()
1579
    document.add_page_break()
1580
    document.add_heading('Introduction', level=1)
1581
    p = document.add_paragraph(
1582
        'The security knowledge framework is composed by means of the highest security standards currently available and is designed to maintain the integrity of your application, so you and your costumers sensitive data is protected against hackers. This document is provided with a checklist in which the programmers of your application had to run through in order to provide a secure product.'
1583
    )
1584
    p.add_run('\n')
1585
    p = document.add_paragraph(
1586
        'In this part of security knowledge framework, al the parameters and variables are audited by means of the information given by the programmer such as the processing techniques. Each of these techniques contain different types of vulnerabilities when implemented in a improper fashion. This document will raise awareness about these vulnerabilities, as well as presenting solutions for the right implementation.'
1587
    )
1588
    document.add_page_break()
1589
    i = 0
1590
    for item in content_raw:
1591
        document.add_heading("Knowledge-Base: "+content_title[i], level=1)
1592
        document.add_heading("Technology: "+entries[i][8], level=2)
1593
        p = document.add_paragraph(item.partition("\n")[2])
1594
        p.add_run("\n")
1595
        document.add_page_break()
1596
        i += 1
1597
    document.save('function-security-report.docx')
1598
    headers = {"Content-Disposition": "attachment; filename=%s" % "function-security-report.docx"}
1599
    with open("function-security-report.docx", 'rb') as f:
1600
        body = f.read()
1601
    return make_response((body, headers))
1602
1603
if __name__ == "__main__":
1604
    #Command line options to enable debug and/or saas (bind to 0.0.0.0)
1605
    cmdargs = str(sys.argv)
1606
    total = len(sys.argv)
1607
    rand.cleanup()
1608
    csrf_token_raw = rand.bytes(128)
1609
    csrf_token = base64.b64encode(csrf_token_raw)
1610
    for i in xrange(total):
1611
        if (str(sys.argv[i][2:]) == "debug"):
1612
            # Load default config and override config from an environment variable
1613
            app.config.update(dict(
1614
            DEBUG=True
1615
            ))
1616
        if (str(sys.argv[i][2:]) == "saas"):
1617
            bindaddr = '0.0.0.0'
1618
    if os.path.isfile('server.crt') == False: 
1619
       app.run(host=bindaddr, port=5443, ssl_context='adhoc')
1620
    else:
1621
       context = SSL.Context(SSL.TLSv1_METHOD)
1622
       context = ('server.crt', 'server.key')
1623
       app.run(host=bindaddr, port=5443, ssl_context=context)
1624
1625
1626