Skip to content

Commit

Permalink
ui: fixed exporting/importing rules
Browse files Browse the repository at this point in the history
When exporting rules, use rfc3339 format for the Created field.
We were exporting it as timestamp, which caused issues when
importing the rules.

Related:
 58aa979
 issue #1140
(cherry picked from commit 552aed5)
  • Loading branch information
gustavo-iniguez-goya committed Jun 19, 2024
1 parent 7519db7 commit 1ec8a02
Showing 1 changed file with 62 additions and 33 deletions.
95 changes: 62 additions & 33 deletions ui/opensnitch/rules.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,15 @@

import os
import json
from slugify import slugify
from datetime import datetime
from google.protobuf.json_format import MessageToJson, Parse

DefaultRulesPath = "/etc/opensnitchd/rules"

# date format displayed on the GUI (created column)
DBDateFieldFormat = "%Y-%m-%d %H:%M:%S"

class Rule():
def __init__(self):
pass
Expand Down Expand Up @@ -41,7 +47,7 @@ def new_from_records(records):
created = int(datetime.now().timestamp())
if records.value(RuleFields.Created) != "":
created = int(datetime.strptime(
records.value(RuleFields.Created), "%Y-%m-%d %H:%M:%S"
records.value(RuleFields.Created), DBDateFieldFormat
).timestamp())
rule.created = created

Expand Down Expand Up @@ -77,14 +83,14 @@ def add(self, time, node, name, description, enabled, precedence, nolog, action,
def add_rules(self, addr, rules):
try:
for _,r in enumerate(rules):
self.add(datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
self.add(datetime.now().strftime(DBDateFieldFormat),
addr,
r.name, r.description, str(r.enabled),
str(r.precedence), str(r.nolog), r.action, r.duration,
r.operator.type,
str(r.operator.sensitive),
r.operator.operand, r.operator.data,
str(datetime.fromtimestamp(r.created).strftime("%Y-%m-%d %H:%M:%S")))
str(datetime.fromtimestamp(r.created).strftime(DBDateFieldFormat)))

return True
except Exception as e:
Expand Down Expand Up @@ -135,6 +141,12 @@ def update_time(self, time, name, addr):
action_on_conflict="OR REPLACE"
)

def _timestamp_to_rfc3339(self, time):
"""converts timestamp to rfc3339 format"""
return "{0}Z".format(
datetime.fromtimestamp(time).isoformat(timespec='microseconds')
)

def rule_to_json(self, node, rule_name):
try:
records = self._db.get_rule(rule_name, node)
Expand All @@ -146,16 +158,33 @@ def rule_to_json(self, node, rule_name):
# exclude this field when exporting to json
tempRule = MessageToJson(rule)
jRule = json.loads(tempRule)
jRule['created'] = "{0}Z".format(
datetime.fromtimestamp(rule.created).isoformat(timespec='microseconds')
)
jRule['created'] = self._timestamp_to_rfc3339(rule.created)
return json.dumps(jRule, indent=" ")
except Exception as e:
print("rule_to_json() exception:", e)
return None

def _export_rule_common(self, node, records, outdir):
try:
rule = Rule.new_from_records(records)
rulename = rule.name
if ".json" not in rulename:
rulename = rulename + ".json"
with open(outdir + "/" + rulename, 'w') as jsfile:
actual_json_text = MessageToJson(rule)
jRule = json.loads(actual_json_text)
jRule['created'] = self._timestamp_to_rfc3339(rule.created)
actual_json_text = json.dumps(jRule, indent=" ")
jsfile.write( actual_json_text )

return True
except Exception as e:
print(self.LOG_TAG, "export_rules(", node, outdir, ") exception:", e)

return False

def export_rule(self, node, rule_name, outdir):
"""Gets the the rule from the DB and writes it out to a directory.
"""Gets the rule from the DB and writes it out to a directory.
A new directory per node will be created.
"""
try:
Expand All @@ -164,51 +193,38 @@ def export_rule(self, node, rule_name, outdir):
print("export_rule() get_error 2:", records)
return False

rule = Rule.new_from_records(records)
rulesdir = outdir + "/" + node
rulesdir = outdir + "/" + slugify(node)
try:
os.makedirs(rulesdir, 0o700)
except Exception as e:
print("exception creating dirs:", e)
rulename = rule.name
if ".json" not in rulename:
rulename = rulename + ".json"
with open(rulesdir + "/" + rulename, 'w') as jsfile:
actual_json_text = MessageToJson(rule)
jsfile.write( actual_json_text )

return True
return self._export_rule_common(node, records, rulesdir)

except Exception as e:
print(self.LOG_TAG, "export_rules(", node, outdir, ") exception:", e)
print(self.LOG_TAG, "export_rules(", node, rulesdir, ") exception:", e)

return False

def export_rules(self, node, outdir):
"""Gets the the rules from the DB and writes them out to a directory.
"""Gets the rules from the DB and writes them out to a directory.
A new directory per node will be created.
"""
records = self._db.get_rules(node)
if records == None:
return False

rulesdir = outdir + "/" + slugify(node)
try:
os.makedirs(rulesdir, 0o700)
except Exception as e:
print("exception creating dirs:", e)
try:
while records.next() != False:
rule = Rule.new_from_records(records)

rulesdir = outdir + "/" + node
try:
os.makedirs(rulesdir, 0o700)
except:
pass
rulename = rule.name
if ".json" not in rulename:
rulename = rulename + ".json"
with open(rulesdir + "/" + rulename, 'w') as jsfile:
actual_json_text = MessageToJson(rule)
jsfile.write( actual_json_text )
self._export_rule_common(node, records, rulesdir)

except Exception as e:
print(self.LOG_TAG, "export_rules(", node, outdir, ") exception:", e)
print(self.LOG_TAG, "export_rules(", node, rulesdir, ") exception:", e)
return False

return True
Expand All @@ -222,7 +238,20 @@ def import_rules(self, rulesdir):
for rulename in os.listdir(rulesdir):
with open(rulesdir + "/" + rulename, 'r') as f:
jsrule = f.read()
pb_rule = Parse(text=jsrule, message=ui_pb2.Rule(), ignore_unknown_fields=True)
# up until v1.6.5/v1.7.0, 'created' field was exported as timestamp.
# since > v1.6.5 it's exported in rfc3339 format, so if we fail to
# parse the rule, we'll try to convert the 'created' value from
# timestamp to rfc3339.
try:
pb_rule = Parse(text=jsrule, message=ui_pb2.Rule(), ignore_unknown_fields=True)
except:
jRule = json.loads(jsrule)
created = int(datetime.strptime(
jRule['created'], "%Y-%m-%dT%H:%M:%S.%fZ"
).timestamp())
jRule['created'] = created
jsrule = json.dumps(jRule)
pb_rule = Parse(text=jsrule, message=ui_pb2.Rule(), ignore_unknown_fields=True)
rules.append(pb_rule)

return rules
Expand Down

0 comments on commit 1ec8a02

Please sign in to comment.