Passed
Push — master ( baa4d0...50ec1a )
by -
01:35
created

__get_textual_representation_rule()   A

Complexity

Conditions 4

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4
Metric Value
cc 4
dl 0
loc 21
ccs 9
cts 9
cp 1
crap 4
rs 9.0534
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 1
        flash("no rules found, please create one", "error")
31 1
        return redirect("/rules/new")
32
33 1
    return Response(__get_textual_representation_rule(_rule), mimetype='text/plain')
34
35
36 1
@rules.route("/view/<int:sid>", methods=["GET"])
37
def view(sid):
38 1
    _rule = NaxsiRules.query.filter(NaxsiRules.sid == sid).first()
39 1
    if _rule is None:
40 1
        flash("no rules found, please create one", "error")
41 1
        return redirect("/rules/")
42
43 1
    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 1
    terms = request.args.get('s', '')
73
74 1
    if len(terms) < 2:
75 1
        return redirect('/rules')
76
77
    # No fancy injections
78 1
    whitelist = set(string.ascii_letters + string.digits + ':-_ ')
79 1
    filtered = ''.join(filter(whitelist.__contains__, terms))
80
81 1
    if filtered.isdigit():  # get rule by id
82 1
        _rules = db.session.query(NaxsiRules).filter(NaxsiRules.sid == int(filtered)).all()
83
    else:
84 1
        expression = '%' + filtered + '%'
85 1
        _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 1
    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
        sid = 200001
100
    else:
101 1
        sid = latest_sid.sid + 1
102
103 1
    if request.method == "GET":
104 1
        mz = ValueTemplates.query.filter(ValueTemplates.name == "naxsi_mz").all()
105 1
        _rulesets = NaxsiRuleSets.query.all()
106 1
        score = ValueTemplates.query.filter(ValueTemplates.name == "naxsi_score").all()
107 1
        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
def edit(sid):
146 1
    rinfo = NaxsiRules.query.filter(NaxsiRules.sid == sid).first()
147 1
    if not rinfo:
148 1
        return redirect("/rules/")
149
150 1
    mz = ValueTemplates.query.filter(ValueTemplates.name == "naxsi_mz").all()
151 1
    score = ValueTemplates.query.filter(ValueTemplates.name == "naxsi_score").all()
152 1
    _rulesets = NaxsiRuleSets.query.all()
153 1
    rruleset = NaxsiRuleSets.query.filter(NaxsiRuleSets.name == rinfo.ruleset).first()
154 1
    custom_mz = ""
155 1
    mz_check = rinfo.mz
156 1
    if re.search(r"^\$[A-Z]+:(.*)\|[A-Z]+", mz_check):
157
        custom_mz = mz_check
158
        rinfo.mz = "custom"
159 1
    return render_template("rules/edit.html", mz=mz, rulesets=_rulesets, score=score, rules_info=rinfo,
160
                           rule_ruleset=rruleset, custom_mz=custom_mz)
161
162
163 1
@rules.route("/save/<path:sid>", methods=["POST"])
164
def save(sid):  # FIXME this is the exact same method as the `new` one.
165
166
    # create new rule
167
    try:
168
        msg = request.form["msg"]
169
        detect = str(request.form["detection"]).strip()
170
        if not detect.startswith("str:") and not detect.startswith("rx:"):
171
            detect = "str:%s" % detect
172
        mz = "|".join(request.form.getlist("mz"))
173
        try:
174
            if request.form["custom_mz"] == "on":
175
                if len(mz) > 1:
176
                    mz = "%s|%s" % (request.form["custom_mz_val"], mz)
177
                else:
178
                    mz = "%s" % (request.form["custom_mz_val"])
179
        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...
180
            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...
181
        score_raw = request.form["score"].strip()
182
        score_val = request.form["score_%s" % score_raw].strip()
183
        score = "%s:%s" % (score_raw, score_val)
184
        # sid = nr["sid"]
185
        rmks = request.form["rmks"]
186
        ruleset = request.form["ruleset"]
187
        active = request.form["active"]
188
        negative = 'negative' in request.form and request.form['negative'] == 'checked'
189
    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...
190
        flash('ERROR - please select MZ/Score <a href="javascript:alert(history.back)">Go Back</a>', "error")
191
        return redirect("/rules/edit/%s" % sid)
192
193
    nrule = NaxsiRules.query.filter(NaxsiRules.sid == sid).first()
194
    nrule.msg = msg
195
    nrule.detection = detect
196
    nrule.mz = mz
197
    nrule.score = score
198
    nrule.ruleset = ruleset
199
    nrule.rmks = rmks
200
    nrule.active = active
201
    nrule.negative = negative
202
    nrule.timestamp = int(time())
203
    db.session.add(nrule)
204
    try:
205
        db.session.commit()
206
    except SQLAlchemyError:
207
        flash("ERROR while trying to update %s : %s" % (sid, msg), "error")
208
    return redirect("/rules/edit/%s" % sid)
209
210
211 1
@rules.route("/del/<path:sid>", methods=["GET"])
212 1
def del_sid(sid=''):
213 1
    nrule = NaxsiRules.query.filter(NaxsiRules.sid == sid).first()
214 1
    if not nrule:
215 1
        return redirect("/rules/")
216
217 1
    db.session.delete(nrule)
218 1
    try:
219 1
        db.session.commit()
220 1
        flash("OK: deleted %s : %s" % (sid, nrule.msg), "success")
221
    except SQLAlchemyError:
222
        flash("ERROR while trying to update %s : %s" % (sid, nrule.msg), "error")
223
224 1
    return redirect("/rules/")
225
226
227 1
@rules.route("/deact/<int:sid>", methods=["GET"])
228
def deact(sid):
229 1
    nrule = NaxsiRules.query.filter(NaxsiRules.sid == sid).first()
230 1
    if nrule is None:
231 1
        return redirect("/rules/")
232
233 1
    fm = 'deactivate' if nrule.active else 'reactivate'
234 1
    nrule.active = not nrule.active
235
236 1
    db.session.add(nrule)
237 1
    try:
238 1
        db.session.commit()
239 1
        flash("OK: %s %sd : %s" % (fm, sid, nrule.msg), "success")
240
    except SQLAlchemyError:
241
        flash("ERROR while trying to %s %s : %s" % (fm, sid, nrule.msg), "error")
242
243 1
    _mz = ValueTemplates.query.filter(ValueTemplates.name == "naxsi_mz").all()
244 1
    _score = ValueTemplates.query.filter(ValueTemplates.name == "naxsi_score").all()
245 1
    _rulesets = NaxsiRuleSets.query.all()
246 1
    return render_template("rules/edit.html", mz=_mz, rulesets=_rulesets, score=_score, rules_info=nrule)
247
248
249 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...
250 1
    rdate = strftime("%F - %H:%M", localtime(float(str(rule.timestamp))))
251 1
    rmks = "# ".join(rule.rmks.strip().split("\n"))
252 1
    detect = rule.detection.lower() if rule.detection.startswith("str:") else rule.detection
253 1
    negate = 'negative' if rule.negative == 1 else ''
254
255 1
    if full == 1:
256 1
        nout = """
257
#
258
# sid: %s | date: %s
259
#
260
# %s
261
#
262
MainRule %s "%s" "msg:%s" "mz:%s" "s:%s" id:%s ;
263
264
""" % (rule.sid, rdate, rmks, negate, detect, rule.msg, rule.mz, rule.score, rule.sid)
265
    else:
266 1
        nout = """MainRule %s "%s" "msg:%s" "mz:%s" "s:%s" id:%s  ;""" % \
267
               (negate, rule.detection, rule.msg, rule.mz, rule.score, rule.sid)
268
269
    return nout
270