@@ -131,6 +131,15 @@ def __init__(
131
131
CONF_UPDATE_INTERVAL , DEFAULT_UPDATE_INTERVAL
132
132
)
133
133
134
+ # match/replacement pairs for redacting addresses
135
+ self .redactions : dict [str , str ] = {}
136
+ # Any remaining MAC addresses will be replaced with this. We define it here
137
+ # so we can compile it once.
138
+ self ._redact_generic_re = re .compile (
139
+ r"(?P<start>[0-9A-Fa-f]{2}):([0-9A-Fa-f]{2}:){4}(?P<end>[0-9A-Fa-f]{2})"
140
+ )
141
+ self ._redact_generic_sub = r"\g<start>:xx:xx:xx:xx:\g<end>"
142
+
134
143
self .stamp_last_prune : float = 0 # When we last pruned device list
135
144
136
145
super ().__init__ (
@@ -1182,71 +1191,84 @@ async def service_dump_devices(
1182
1191
# lowercase all the addresses for matching
1183
1192
addresses = list (map (str .lower , addresses ))
1184
1193
1185
- # set up redaction lookups. To make troubleshooting easier, we assign
1186
- # labels and identifiers to each unique MAC/address.
1187
- redactions = {}
1188
- if redact :
1189
- i = 0
1190
- for address in self .scanner_list :
1191
- i += 1
1192
- redactions [address .upper ()] = (
1193
- f"{ address [:2 ]} ::SCANNER_{ i } ::{ address [- 2 :]} "
1194
- )
1195
- i = 0
1196
- for address in self .options .get (CONF_DEVICES , []):
1197
- if address .upper () not in redactions :
1198
- i += 1
1199
- if address .count ("_" ) == 2 :
1200
- redactions [address ] = (
1201
- f"{ address [:4 ]} ::CFG_iBea_{ i } ::{ address [32 :]} "
1202
- )
1203
- elif len (address ) == 17 :
1204
- redactions [address ] = (
1205
- f"{ address [:2 ]} ::CFG_MAC_{ i } ::{ address [- 2 :]} "
1206
- )
1207
- else :
1208
- # Don't know what it is, but not a mac.
1209
- redactions [address ] = f"CFG_OTHER_{ 1 } _{ address } "
1210
-
1211
- # don't reset i, just continue on for all the other devices.
1212
- for address , device in self .devices .items ():
1213
- if address .upper () not in redactions :
1214
- # Only add if they are not already there.
1215
- i += 1
1216
- if device .address_type == ADDR_TYPE_PRIVATE_BLE_DEVICE :
1217
- redactions [address ] = f"{ address [:2 ]} ::IRK_DEV_{ i } "
1218
- elif address .count ("_" ) == 2 :
1219
- redactions [address ] = (
1220
- f"{ address [:4 ]} ::OTHER_iBea_{ i } ::{ address [32 :]} "
1221
- )
1222
- elif len (address ) == 17 : # a MAC
1223
- redactions [address ] = (
1224
- f"{ address [:2 ]} ::OTHER_MAC_{ i } ::{ address [- 2 :]} "
1225
- )
1226
- else :
1227
- # Don't know what it is.
1228
- redactions [address ] = f"OTHER_{ 1 } _{ address } "
1229
-
1230
1194
# Build the dict of devices
1231
1195
for address , device in self .devices .items ():
1232
1196
if len (addresses ) == 0 or address .lower () in addresses :
1233
1197
out [address ] = device .to_dict ()
1234
1198
1235
- def redact_data (data , redactions ):
1236
- if isinstance (data , str ):
1237
- for find , fix in redactions .items ():
1238
- data = re .sub (find , fix , data , flags = re .I )
1239
- return data
1240
- elif isinstance (data , dict ):
1241
- return {
1242
- redact_data (k , redactions ): redact_data (v , redactions )
1243
- for k , v in data .items ()
1244
- }
1245
- elif isinstance (data , list ):
1246
- return [redact_data (v , redactions ) for v in data ]
1247
- else :
1248
- return data
1249
-
1250
1199
if redact :
1251
- out = cast (ServiceResponse , redact_data (out , redactions ))
1200
+ self .redaction_list_update ()
1201
+ out = cast (ServiceResponse , self .redact_data (out ))
1252
1202
return out
1203
+
1204
+ def redaction_list_update (self ):
1205
+ """Freshen or create the list of match/replace pairs that we use to
1206
+ redact MAC addresses. This gives a set of helpful address replacements
1207
+ that still allows identifying device entries without disclosing MAC
1208
+ addresses."""
1209
+ i = len (self .redactions ) # not entirely accurate but we don't care.
1210
+
1211
+ # SCANNERS
1212
+ for address in self .scanner_list :
1213
+ if address .upper () not in self .redactions :
1214
+ i += 1
1215
+ self .redactions [address .upper ()] = (
1216
+ f"{ address [:2 ]} ::SCANNER_{ i } ::{ address [- 2 :]} "
1217
+ )
1218
+ # CONFIGURED DEVICES
1219
+ for address in self .options .get (CONF_DEVICES , []):
1220
+ if address .upper () not in self .redactions :
1221
+ i += 1
1222
+ if address .count ("_" ) == 2 :
1223
+ self .redactions [address ] = (
1224
+ f"{ address [:4 ]} ::CFG_iBea_{ i } ::{ address [32 :]} "
1225
+ )
1226
+ elif len (address ) == 17 :
1227
+ self .redactions [address ] = (
1228
+ f"{ address [:2 ]} ::CFG_MAC_{ i } ::{ address [- 2 :]} "
1229
+ )
1230
+ else :
1231
+ # Don't know what it is, but not a mac.
1232
+ self .redactions [address ] = f"CFG_OTHER_{ 1 } _{ address } "
1233
+ # EVERYTHING ELSE
1234
+ for address , device in self .devices .items ():
1235
+ if address .upper () not in self .redactions :
1236
+ # Only add if they are not already there.
1237
+ i += 1
1238
+ if device .address_type == ADDR_TYPE_PRIVATE_BLE_DEVICE :
1239
+ self .redactions [address ] = f"{ address [:2 ]} ::IRK_DEV_{ i } "
1240
+ elif address .count ("_" ) == 2 :
1241
+ self .redactions [address ] = (
1242
+ f"{ address [:4 ]} ::OTHER_iBea_{ i } ::{ address [32 :]} "
1243
+ )
1244
+ elif len (address ) == 17 : # a MAC
1245
+ self .redactions [address ] = (
1246
+ f"{ address [:2 ]} ::OTHER_MAC_{ i } ::{ address [- 2 :]} "
1247
+ )
1248
+ else :
1249
+ # Don't know what it is.
1250
+ self .redactions [address ] = f"OTHER_{ 1 } _{ address } "
1251
+
1252
+ def redact_data (self , data ):
1253
+ """Wash any collection of data of any MAC addresses.
1254
+
1255
+ Uses the redaction list of substitutions if already created, then
1256
+ washes any remaining mac-like addresses. This routine is recursive,
1257
+ so if you're changing it bear that in mind!"""
1258
+ if len (self .redactions ) == 0 :
1259
+ # Initialise the list of addresses if not already done.
1260
+ self .redaction_list_update ()
1261
+ if isinstance (data , str ):
1262
+ # the end of the recursive wormhole, do the actual work:
1263
+ for find , fix in self .redactions .items ():
1264
+ data = re .sub (find , fix , data , flags = re .I )
1265
+ # redactions done, now replace any remaining MAC addresses
1266
+ # We are only looking for xx:xx:xx... format.
1267
+ data = self ._redact_generic_re .sub (self ._redact_generic_sub , data )
1268
+ return data
1269
+ elif isinstance (data , dict ):
1270
+ return {self .redact_data (k ): self .redact_data (v ) for k , v in data .items ()}
1271
+ elif isinstance (data , list ):
1272
+ return [self .redact_data (v ) for v in data ]
1273
+ else :
1274
+ return data
0 commit comments