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('"', """, html) |
137
|
|
|
result = re.sub("'", "'", result) |
138
|
|
|
result = re.sub("&", "&", result) |
139
|
|
|
result = re.sub("<", "<", result) |
140
|
|
|
result = re.sub(">", ">", 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
|
|
|
|