Multibyte: some path fixes

- Validate encoded path hop counts before saving or sending custom paths
- Fix multi-byte path reversal by reversing hops instead of raw bytes
- Decode raw log path lengths using packed path_len format
- Localize path hash mode options and optimize map anchor lookup
This commit is contained in:
HDDen
2026-05-28 03:17:08 +03:00
parent 9e18b99e9d
commit 61fb39b9f8
4 changed files with 104 additions and 36 deletions
+23 -14
View File
@@ -700,6 +700,16 @@ class _MapScreenState extends State<MapScreen> {
int pathHashByteWidth,
) {
final result = <_GuessedLocation>[];
final hopWidth = pathHashByteWidth.clamp(1, 4).toInt();
final anchorsByPrefix = <String, List<Contact>>{};
for (final repeater in withLocation) {
if (repeater.type != advTypeRepeater) continue;
if (repeater.publicKey.length < hopWidth) continue;
final prefix = PathHelper.formatHopHex(
repeater.publicKey.sublist(0, hopWidth),
);
anchorsByPrefix.putIfAbsent(prefix, () => []).add(repeater);
}
for (final contact in allContacts) {
if (contact.hasLocation) continue;
@@ -722,21 +732,13 @@ class _MapScreenState extends State<MapScreen> {
];
for (final pathBytes in pathSets) {
if (pathBytes.isEmpty) continue;
final hopWidth = pathHashByteWidth.clamp(1, 4);
final lastHop = pathBytes.sublist(max(0, pathBytes.length - hopWidth));
if (lastHop.isEmpty) continue;
for (final repeater in withLocation) {
if (repeater.type != advTypeRepeater) continue;
if (repeater.publicKey.length < lastHop.length) continue;
if (!listEquals(
repeater.publicKey.sublist(0, lastHop.length),
lastHop,
)) {
continue;
}
final repeaters = anchorsByPrefix[PathHelper.formatHopHex(lastHop)];
if (repeaters != null && repeaters.isNotEmpty) {
final repeater = repeaters.first;
anchorSet.add(LatLng(repeater.latitude!, repeater.longitude!));
break;
}
}
@@ -2304,10 +2306,17 @@ class _MapScreenState extends State<MapScreen> {
connector.pathHashByteWidth.clamp(1, pubKeySize),
contact.publicKey.length,
).toInt();
final hopPrefix = contact.publicKey.sublist(0, hopWidth);
for (final existingHop in PathHelper.splitPathBytes(
_pathTrace,
connector.pathHashByteWidth,
)) {
if (listEquals(existingHop, hopPrefix)) {
return;
}
}
setState(() {
_pathTrace.addAll(
contact.publicKey.sublist(0, hopWidth),
); // Add the hop-width prefix of the public key to the trace
_pathTrace.addAll(hopPrefix); // Add the hop-width pubkey prefix.
_pathTraceHopWidths.add(hopWidth);
_pathTraceContacts.add(
contact.copyWith(
+17 -5
View File
@@ -580,11 +580,23 @@ class _SettingsScreenState extends State<SettingsScreen> {
labelText: l10n.repeater_pathHashMode,
border: const OutlineInputBorder(),
),
items: const [
DropdownMenuItem(value: 0, child: Text('0 - 1 byte')),
DropdownMenuItem(value: 1, child: Text('1 - 2 bytes')),
DropdownMenuItem(value: 2, child: Text('2 - 3 bytes')),
DropdownMenuItem(value: 3, child: Text('3 - 4 bytes')),
items: [
DropdownMenuItem(
value: 0,
child: Text(l10n.repeater_pathHashModeOption0),
),
DropdownMenuItem(
value: 1,
child: Text(l10n.repeater_pathHashModeOption1),
),
DropdownMenuItem(
value: 2,
child: Text(l10n.repeater_pathHashModeOption2),
),
DropdownMenuItem(
value: 3,
child: Text(l10n.repeater_pathHashModeOption3),
),
],
onChanged: (value) {
if (value == null) return;