Passed
Branch master (e2d0e9)
by jvo
02:56 queued 01:31
created

plain()   A

Complexity

Conditions 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2.1481
Metric Value
cc 2
dl 0
loc 8
ccs 4
cts 6
cp 0.6667
crap 2.1481
rs 9.4285
1 1
import logging
2 1
import re
3 1
import string
4 1
from time import time, localtime, strftime
5
6 1
from flask import Blueprint, render_template, request, redirect, flash, Response
1 ignored issue
show
Configuration introduced by
The import flask could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
7 1
from sqlalchemy.exc import SQLAlchemyError
0 ignored issues
show
Configuration introduced by
The import sqlalchemy.exc could not be resolved.

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
8
9 1
from spike.model import db
10 1
from spike.model.naxsi_rules import NaxsiRules
11 1
from spike.model.value_templates import ValueTemplates
12 1
from spike.model.naxsi_rulesets import NaxsiRuleSets
13
14 1
rules = Blueprint('rules', __name__)
15
16
17 1
@rules.route("/")
18
def index():
19 1
    _rules = NaxsiRules.query.order_by(NaxsiRules.sid.desc()).all()
20 1
    if not _rules:
21
        flash("no rules found, please create one", "success")
22
        return redirect("/rules/new")
23 1
    return render_template("rules/index.html", rules=_rules)
24
25
26 1
@rules.route("/plain/<int:sid>", methods=["GET"])
27
def plain(sid):
28 1
    _rule = NaxsiRules.query.filter(NaxsiRules.sid == sid).first()
29 1
    if not _rule:
30
        flash("no rules found, please create one", "error")
31
        return redirect("/rules/new")
32
33 1
    return Response(__get_textual_representation_rule(_rule), mimetype='text/plain')
34
35
36 1
@rules.route("/view/<path:sid>", methods=["GET"])
37 1
def view(sid=''):
38
    _rule = NaxsiRules.query.filter(NaxsiRules.sid == sid).first()
39
    if not _rule:
40
        flash("no rules found, please create one", "error")
41
        return redirect("/rules/")
42
43
    return render_template("rules/view.html", rule=_rule, rtext=__get_textual_representation_rule(_rule, full=0))
44
45
46 1
@rules.route("/select/<path:selector>", methods=["GET"])
47 1
def select(selector=''):
48
    if not selector:
49
        return redirect("/rules/")
50
51
    sel = str(selector)
52
    logging.info("sel: %s ", sel)
53
    try:
54
        rs_val = sel.split(":")[1]
55
    except SQLAlchemyError:
56
        return redirect("/rules/")
57
58
    if sel.startswith('r:'):
59
        _rules = NaxsiRules.query.filter(NaxsiRules.ruleset == rs_val).order_by(NaxsiRules.sid.desc()).all()
60
        selection = "Search ruleset: %s " % rs_val
61
    elif sel.startswith('id:'):
62
        _rules = NaxsiRules.query.filter(NaxsiRules.sid == rs_val).order_by(NaxsiRules.sid.desc()).all()
63
        selection = "Search sid: %s " % rs_val
64
    else:
65
        return redirect("/rules/")
66
67
    return render_template("rules/index.html", rules=_rules, selection=selection)
68
69
70 1
@rules.route("/search/", methods=["GET"])
71
def search():
72
    terms = request.args.get('s', '')
73
74
    if len(terms) < 2:
75
        return redirect('/rules')
76
77
    # No fancy injections
78
    whitelist = set(string.ascii_letters + string.digits + ':-_ ')
79
    filtered = ''.join(filter(whitelist.__contains__, terms))
80
81
    if filtered.isdigit():  # get rule by id
82
        _rules = db.session.query(NaxsiRules).filter(NaxsiRules.sid == int(filtered)).all()
83
    else:
84
        expression = '%' + filtered + '%'
85
        _rules = db.session.query(NaxsiRules).filter(
86
            db.or_(
87
                NaxsiRules.msg.like(expression),
88
                NaxsiRules.rmks.like(expression),
89
                NaxsiRules.detection.like(expression)
90
            )
91
        ).order_by(NaxsiRules.sid.desc()).all()
92
    return render_template("rules/index.html", rules=_rules, selection="Search: %s" % filtered, lsearch=terms)
93
94
95 1
@rules.route("/new", methods=["GET", "POST"])
96
def new():
97 1
    latest_sid = NaxsiRules.query.order_by(NaxsiRules.sid.desc()).first()
98 1
    if latest_sid is None:
99 1
        sid = 200001
100
    else:
101
        sid = latest_sid.sid + 1
102
103 1
    if request.method == "GET":
104
        mz = ValueTemplates.query.filter(ValueTemplates.name == "naxsi_mz").all()
105
        _rulesets = NaxsiRuleSets.query.all()
106
        score = ValueTemplates.query.filter(ValueTemplates.name == "naxsi_score").all()
107
        return render_template("rules/new.html", mz=mz, rulesets=_rulesets, score=score, latestn=sid)
108
109
    # create new rule
110 1
    logging.debug('Posted new request: %s', request.form)
111
112 1
    detect = str(request.form["detection"]).strip()
113 1
    if not detect.startswith("str:") and not detect.startswith("rx:"):
114 1
        detect = "str:%s" % detect
115
116 1
    mz = "|".join(request.form.getlist("mz"))
117
118 1
    try:
119 1
        if request.form["custom_mz"] == "on":
120
            mz = "%s|%s" % (mz, request.form["custom_mz_val"])
121 1
    except:
0 ignored issues
show
Coding Style Best Practice introduced by
General except handlers without types should be used sparingly.

Typically, you would use general except handlers when you intend to specifically handle all types of errors, f.e. when logging. Otherwise, such general error handlers can mask errors in your application that you want to know of.

Loading history...
122 1
        pass
0 ignored issues
show
Unused Code introduced by
This except handler seems to be unused and could be removed.

Except handlers which only contain pass and do not have an else clause can usually simply be removed:

try:
    raises_exception()
except:  # Could be removed
    pass
Loading history...
123
124 1
    score_raw = request.form["score"].strip()
125 1
    score_val = request.form["score_%s" % score_raw].strip()
126 1
    score = "%s:%s" % (score_raw, score_val)
127 1
    rmks = request.form["rmks"]
128 1
    ruleset = request.form["ruleset"]
129 1
    negative = 'negative' in request.form and request.form['negative'] == 'checked'
130
131 1
    nrule = NaxsiRules(request.form["msg"], detect, mz, score, sid, ruleset, rmks, "1", negative, int(time()))
132 1
    db.session.add(nrule)
133
134 1
    try:
135 1
        db.session.commit()
136 1
        flash("OK: created %s : %s" % (sid, request.form["msg"]), "success")
137 1
        return redirect("/rules/edit/%s" % sid)
138
    except SQLAlchemyError:
139
        flash("ERROR while trying to create %s : %s" % (sid, request.form["msg"]), "error")
140
141
    return redirect("/rules/new")
142
143
144 1
@rules.route("/edit/<path:sid>", methods=["GET", "POST"])
145 1
def edit(sid=''):
146 1
    if not sid:
147
        return redirect("/rules/")
148
149 1
    rinfo = NaxsiRules.query.filter(NaxsiRules.sid == sid).first()
150 1
    if not rinfo:
151
        return redirect("/rules/")
152
153 1
    mz = ValueTemplates.query.filter(ValueTemplates.name == "naxsi_mz").all()
154 1
    score = ValueTemplates.query.filter(ValueTemplates.name == "naxsi_score").all()
155 1
    _rulesets = NaxsiRuleSets.query.all()
156 1
    rruleset = NaxsiRuleSets.query.filter(NaxsiRuleSets.name == rinfo.ruleset).first()
157 1
    custom_mz = ""
158 1
    mz_check = rinfo.mz
159 1
    if re.search(r"^\$[A-Z]+:(.*)\|[A-Z]+", mz_check):
160
        custom_mz = mz_check
161
        rinfo.mz = "custom"
162 1
    return render_template("rules/edit.html", mz=mz, rulesets=_rulesets, score=score, rules_info=rinfo,
163
                           rule_ruleset=rruleset, custom_mz=custom_mz)
164
165
166 1
@rules.route("/save/<path:sid>", methods=["POST"])
167 1
def save(sid=''):  # FIXME this is the exact same method as the `new` one.
168
    if not sid:
169
        return redirect("/rules/")
170
171
    # create new rule
172
    try:
173
        msg = request.form["msg"]
174
        detect = str(request.form["detection"]).strip()
175
        if not detect.startswith("str:") and not detect.startswith("rx:"):
176
            detect = "str:%s" % detect
177
        mz = "|".join(request.form.getlist("mz"))
178
        try:
179
            if request.form["custom_mz"] == "on":
180
                if len(mz) > 1:
181
                    mz = "%s|%s" % (request.form["custom_mz_val"], mz)
182
                else:
183
                    mz = "%s" % (request.form["custom_mz_val"])
184
        except:
0 ignored issues
show
Coding Style Best Practice introduced by
General except handlers without types should be used sparingly.

Typically, you would use general except handlers when you intend to specifically handle all types of errors, f.e. when logging. Otherwise, such general error handlers can mask errors in your application that you want to know of.

Loading history...
185
            pass
0 ignored issues
show
Unused Code introduced by
This except handler seems to be unused and could be removed.

Except handlers which only contain pass and do not have an else clause can usually simply be removed:

try:
    raises_exception()
except:  # Could be removed
    pass
Loading history...
186
        score_raw = request.form["score"].strip()
187
        score_val = request.form["score_%s" % score_raw].strip()
188
        score = "%s:%s" % (score_raw, score_val)
189
        # sid = nr["sid"]
190
        rmks = request.form["rmks"]
191
        ruleset = request.form["ruleset"]
192
        active = request.form["active"]
193
        negative = 'negative' in request.form and request.form['negative'] == 'checked'
194
    except:
0 ignored issues
show
Coding Style Best Practice introduced by
General except handlers without types should be used sparingly.

Typically, you would use general except handlers when you intend to specifically handle all types of errors, f.e. when logging. Otherwise, such general error handlers can mask errors in your application that you want to know of.

Loading history...
195
        flash('ERROR - please select MZ/Score <a href="javascript:alert(history.back)">Go Back</a>', "error")
196
        return redirect("/rules/edit/%s" % sid)
197
198
    nrule = NaxsiRules.query.filter(NaxsiRules.sid == sid).first()
199
    nrule.msg = msg
200
    nrule.detection = detect
201
    nrule.mz = mz
202
    nrule.score = score
203
    nrule.ruleset = ruleset
204
    nrule.rmks = rmks
205
    nrule.active = active
206
    nrule.negative = negative
207
    nrule.timestamp = int(time())
208
    db.session.add(nrule)
209
    try:
210
        db.session.commit()
211
    except SQLAlchemyError:
212
        flash("ERROR while trying to update %s : %s" % (sid, msg), "error")
213
    return redirect("/rules/edit/%s" % sid)
214
215
216 1
@rules.route("/del/<path:sid>", methods=["GET"])
217 1
def del_sid(sid=''):
218 1
    if not sid:
219
        return redirect("/rules/")
220
221 1
    nrule = NaxsiRules.query.filter(NaxsiRules.sid == sid).first()
222 1
    if not nrule:
223
        return redirect("/rules/")
224
225 1
    db.session.delete(nrule)
226 1
    try:
227 1
        db.session.commit()
228 1
        flash("OK: deleted %s : %s" % (sid, nrule.msg), "success")
229
    except SQLAlchemyError:
230
        flash("ERROR while trying to update %s : %s" % (sid, nrule.msg), "error")
231
232 1
    return redirect("/rules/")
233
234
235 1
@rules.route("/deact/<path:sid>", methods=["GET"])
236 1
def deact(sid=''):
237
    if not sid:
238
        return redirect("/rules/")
239
240
    nrule = NaxsiRules.query.filter(NaxsiRules.sid == sid).first()
241
    if not nrule:
242
        return redirect("/rules/")
243
244
    if nrule.active == 0:
245
        nrule.active = 1
246
        fm = "reactivate"
247
    else:
248
        nrule.active = 0
249
        fm = "deactivate"
250
251
    db.session.add(nrule)
252
    try:
253
        db.session.commit()
254
        flash("OK: %s %sd : %s" % (fm, sid, nrule.msg), "success")
255
    except SQLAlchemyError:
256
        flash("ERROR while trying to %s %s : %s" % (fm, sid, nrule.msg), "error")
257
258
    rinfo = NaxsiRules.query.filter(NaxsiRules.sid == sid).first()
259
    if not rinfo:
260
        return redirect("/rules/")
261
262
    mz = ValueTemplates.query.filter(ValueTemplates.name == "naxsi_mz").all()
263
    score = ValueTemplates.query.filter(ValueTemplates.name == "naxsi_score").all()
264
    _rulesets = NaxsiRuleSets.query.all()
265
    return render_template("rules/edit.html", mz=mz, rulesets=_rulesets, score=score, rules_info=rinfo)
266
267
268 1
def __get_textual_representation_rule(rule, full=1):
0 ignored issues
show
Coding Style Naming introduced by
The name __get_textual_representation_rule does not conform to the function naming conventions ([a-z_][a-z0-9_]{1,30}$).

This check looks for invalid names for a range of different identifiers.

You can set regular expressions to which the identifiers must conform if the defaults do not match your requirements.

If your project includes a Pylint configuration file, the settings contained in that file take precedence.

To find out more about Pylint, please refer to their site.

Loading history...
269 1
    rdate = strftime("%F - %H:%M", localtime(float(str(rule.timestamp))))
270 1
    rmks = "# ".join(rule.rmks.strip().split("\n"))
271 1
    detect = rule.detection.lower() if rule.detection.startswith("str:") else rule.detection
272 1
    negate = 'negative' if rule.negative == 1 else ''
273
274 1
    if full == 1:
275 1
        nout = """
276
#
277
# sid: %s | date: %s
278
#
279
# %s
280
#
281
MainRule %s "%s" "msg:%s" "mz:%s" "s:%s" id:%s ;
282
283
""" % (rule.sid, rdate, rmks, negate, detect, rule.msg, rule.mz, rule.score, rule.sid)
284
    else:
285
        nout = """MainRule %s "%s" "msg:%s" "mz:%s" "s:%s" id:%s  ;""" % \
286
               (negate, rule.detection, rule.msg, rule.mz, rule.score, rule.sid)
287
288
    return nout
289