7
7
8
8
import os
9
9
import json
10
+ from slugify import slugify
10
11
from datetime import datetime
11
12
from google .protobuf .json_format import MessageToJson , Parse
12
13
14
+ DefaultRulesPath = "/etc/opensnitchd/rules"
15
+
16
+ # date format displayed on the GUI (created column)
17
+ DBDateFieldFormat = "%Y-%m-%d %H:%M:%S"
18
+
13
19
class Rule ():
14
20
def __init__ (self ):
15
21
pass
@@ -41,7 +47,7 @@ def new_from_records(records):
41
47
created = int (datetime .now ().timestamp ())
42
48
if records .value (RuleFields .Created ) != "" :
43
49
created = int (datetime .strptime (
44
- records .value (RuleFields .Created ), "%Y-%m-%d %H:%M:%S"
50
+ records .value (RuleFields .Created ), DBDateFieldFormat
45
51
).timestamp ())
46
52
rule .created = created
47
53
@@ -77,14 +83,14 @@ def add(self, time, node, name, description, enabled, precedence, nolog, action,
77
83
def add_rules (self , addr , rules ):
78
84
try :
79
85
for _ ,r in enumerate (rules ):
80
- self .add (datetime .now ().strftime ("%Y-%m-%d %H:%M:%S" ),
86
+ self .add (datetime .now ().strftime (DBDateFieldFormat ),
81
87
addr ,
82
88
r .name , r .description , str (r .enabled ),
83
89
str (r .precedence ), str (r .nolog ), r .action , r .duration ,
84
90
r .operator .type ,
85
91
str (r .operator .sensitive ),
86
92
r .operator .operand , r .operator .data ,
87
- str (datetime .fromtimestamp (r .created ).strftime ("%Y-%m-%d %H:%M:%S" )))
93
+ str (datetime .fromtimestamp (r .created ).strftime (DBDateFieldFormat )))
88
94
89
95
return True
90
96
except Exception as e :
@@ -135,6 +141,12 @@ def update_time(self, time, name, addr):
135
141
action_on_conflict = "OR REPLACE"
136
142
)
137
143
144
+ def _timestamp_to_rfc3339 (self , time ):
145
+ """converts timestamp to rfc3339 format"""
146
+ return "{0}Z" .format (
147
+ datetime .fromtimestamp (time ).isoformat (timespec = 'microseconds' )
148
+ )
149
+
138
150
def rule_to_json (self , node , rule_name ):
139
151
try :
140
152
records = self ._db .get_rule (rule_name , node )
@@ -146,16 +158,33 @@ def rule_to_json(self, node, rule_name):
146
158
# exclude this field when exporting to json
147
159
tempRule = MessageToJson (rule )
148
160
jRule = json .loads (tempRule )
149
- jRule ['created' ] = "{0}Z" .format (
150
- datetime .fromtimestamp (rule .created ).isoformat (timespec = 'microseconds' )
151
- )
161
+ jRule ['created' ] = self ._timestamp_to_rfc3339 (rule .created )
152
162
return json .dumps (jRule , indent = " " )
153
163
except Exception as e :
154
164
print ("rule_to_json() exception:" , e )
155
165
return None
156
166
167
+ def _export_rule_common (self , node , records , outdir ):
168
+ try :
169
+ rule = Rule .new_from_records (records )
170
+ rulename = rule .name
171
+ if ".json" not in rulename :
172
+ rulename = rulename + ".json"
173
+ with open (outdir + "/" + rulename , 'w' ) as jsfile :
174
+ actual_json_text = MessageToJson (rule )
175
+ jRule = json .loads (actual_json_text )
176
+ jRule ['created' ] = self ._timestamp_to_rfc3339 (rule .created )
177
+ actual_json_text = json .dumps (jRule , indent = " " )
178
+ jsfile .write ( actual_json_text )
179
+
180
+ return True
181
+ except Exception as e :
182
+ print (self .LOG_TAG , "export_rules(" , node , outdir , ") exception:" , e )
183
+
184
+ return False
185
+
157
186
def export_rule (self , node , rule_name , outdir ):
158
- """Gets the the rule from the DB and writes it out to a directory.
187
+ """Gets the rule from the DB and writes it out to a directory.
159
188
A new directory per node will be created.
160
189
"""
161
190
try :
@@ -164,51 +193,38 @@ def export_rule(self, node, rule_name, outdir):
164
193
print ("export_rule() get_error 2:" , records )
165
194
return False
166
195
167
- rule = Rule .new_from_records (records )
168
- rulesdir = outdir + "/" + node
196
+ rulesdir = outdir + "/" + slugify (node )
169
197
try :
170
198
os .makedirs (rulesdir , 0o700 )
171
199
except Exception as e :
172
200
print ("exception creating dirs:" , e )
173
- rulename = rule .name
174
- if ".json" not in rulename :
175
- rulename = rulename + ".json"
176
- with open (rulesdir + "/" + rulename , 'w' ) as jsfile :
177
- actual_json_text = MessageToJson (rule )
178
- jsfile .write ( actual_json_text )
179
201
180
- return True
202
+ return self ._export_rule_common (node , records , rulesdir )
203
+
181
204
except Exception as e :
182
- print (self .LOG_TAG , "export_rules(" , node , outdir , ") exception:" , e )
205
+ print (self .LOG_TAG , "export_rules(" , node , rulesdir , ") exception:" , e )
183
206
184
207
return False
185
208
186
209
def export_rules (self , node , outdir ):
187
- """Gets the the rules from the DB and writes them out to a directory.
210
+ """Gets the rules from the DB and writes them out to a directory.
188
211
A new directory per node will be created.
189
212
"""
190
213
records = self ._db .get_rules (node )
191
214
if records == None :
192
215
return False
193
216
217
+ rulesdir = outdir + "/" + slugify (node )
218
+ try :
219
+ os .makedirs (rulesdir , 0o700 )
220
+ except Exception as e :
221
+ print ("exception creating dirs:" , e )
194
222
try :
195
223
while records .next () != False :
196
- rule = Rule .new_from_records (records )
197
-
198
- rulesdir = outdir + "/" + node
199
- try :
200
- os .makedirs (rulesdir , 0o700 )
201
- except :
202
- pass
203
- rulename = rule .name
204
- if ".json" not in rulename :
205
- rulename = rulename + ".json"
206
- with open (rulesdir + "/" + rulename , 'w' ) as jsfile :
207
- actual_json_text = MessageToJson (rule )
208
- jsfile .write ( actual_json_text )
224
+ self ._export_rule_common (node , records , rulesdir )
209
225
210
226
except Exception as e :
211
- print (self .LOG_TAG , "export_rules(" , node , outdir , ") exception:" , e )
227
+ print (self .LOG_TAG , "export_rules(" , node , rulesdir , ") exception:" , e )
212
228
return False
213
229
214
230
return True
@@ -222,7 +238,20 @@ def import_rules(self, rulesdir):
222
238
for rulename in os .listdir (rulesdir ):
223
239
with open (rulesdir + "/" + rulename , 'r' ) as f :
224
240
jsrule = f .read ()
225
- pb_rule = Parse (text = jsrule , message = ui_pb2 .Rule (), ignore_unknown_fields = True )
241
+ # up until v1.6.5/v1.7.0, 'created' field was exported as timestamp.
242
+ # since > v1.6.5 it's exported in rfc3339 format, so if we fail to
243
+ # parse the rule, we'll try to convert the 'created' value from
244
+ # timestamp to rfc3339.
245
+ try :
246
+ pb_rule = Parse (text = jsrule , message = ui_pb2 .Rule (), ignore_unknown_fields = True )
247
+ except :
248
+ jRule = json .loads (jsrule )
249
+ created = int (datetime .strptime (
250
+ jRule ['created' ], "%Y-%m-%dT%H:%M:%S.%fZ"
251
+ ).timestamp ())
252
+ jRule ['created' ] = created
253
+ jsrule = json .dumps (jRule )
254
+ pb_rule = Parse (text = jsrule , message = ui_pb2 .Rule (), ignore_unknown_fields = True )
226
255
rules .append (pb_rule )
227
256
228
257
return rules
0 commit comments