Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
a31b581
Add offline mode prompt when zone check fails due to no internet
MrAlders0n Feb 17, 2026
65e81d3
Added option to disable carpeater RSSI filter under settings
MrAlders0n Feb 17, 2026
dd61de8
Multi-hop CARpeater packets now strip the CARpeater hop and report co…
MrAlders0n Feb 17, 2026
af64adc
Added Code of Conduct & Security
MrAlders0n Feb 18, 2026
8936f89
Update links
MrAlders0n Feb 18, 2026
bbd723b
Exclude .vscode/ from version control
MrAlders0n Feb 18, 2026
ce4e538
Bug fixes:
MrAlders0n Feb 18, 2026
a47b49c
Anonymous Mode — New privacy option in Settings that renames your de…
MrAlders0n Feb 18, 2026
861c09d
Update repeater endpoint from /repeaters.json to /get_repeaters.php
MrAlders0n Feb 18, 2026
4001583
### New Features
MrAlders0n Feb 19, 2026
9fe6acf
Regional Flood Scoping: TX pings(Active Mode) are now scoped to your …
MrAlders0n Feb 20, 2026
fa17d59
New Features
MrAlders0n Feb 21, 2026
4824072
### Improvements
MrAlders0n Feb 21, 2026
e399a21
## Bug Fixes
MrAlders0n Feb 21, 2026
8c9f7c9
Debug logging is now enabled by default on all builds (not just dev b…
MrAlders0n Feb 27, 2026
22334a4
The API returns "scopes":["#*"] for zones with no regional scope. The…
MrAlders0n Feb 27, 2026
d7ccdb0
Added dialog to upload logs window
MrAlders0n Feb 27, 2026
18e2c46
Add Discovery Drop feature — failed discovery requests can now be r…
MrAlders0n Mar 7, 2026
c5d0947
New Feature
MrAlders0n Mar 8, 2026
18226d6
Add hopBytes support and update repeater display logic
MrAlders0n Mar 8, 2026
a62539c
Refactor settings screen theme and unit toggles to use SwitchListTile…
MrAlders0n Mar 8, 2026
25739ed
Repeater markers now rotate with the map and stay upright
MrAlders0n Mar 8, 2026
8f061dd
Prevent duplicate GPS stream subscriptions on restart (#6)
robekl Mar 8, 2026
c8f0d71
Own and dispose app-level stream subscriptions (#7)
robekl Mar 8, 2026
4d41d43
Fix mobile BLE scan stream completion and cleanup (#8)
robekl Mar 8, 2026
18330b5
Bump version to 1.2.0 and enhance authentication flow with staged pub…
MrAlders0n Mar 9, 2026
fb59aca
- **Hive corruption fallback for ping queue:** When the `api_queue` H…
MrAlders0n Mar 9, 2026
ae7fb03
Add heartbeat retry, local session expiry tracking, and offline queue…
MrAlders0n Mar 12, 2026
40b3da9
Cancel stale auto-ping restore timers (#10)
robekl Mar 15, 2026
8d53b49
Recheck location permission after disclosure (#11)
robekl Mar 15, 2026
bfb9a85
- Discovery pings now extract repeater IDs using the region's hop byt…
MrAlders0n Mar 15, 2026
e3d9074
fixed overflow in disc request byte count fix
MrAlders0n Mar 15, 2026
35e28e9
- Added option to keep the #wardriving channel after exiting a sessio…
MrAlders0n Mar 15, 2026
2645d73
- Minimum ping distance is now configurable for TX and discovery ping…
MrAlders0n Mar 15, 2026
d451bee
- GPS-related zone check errors (inaccurate/stale) no longer retry ev…
MrAlders0n Mar 15, 2026
fb2d4c3
lib/screens/settings_screen.dart — Replaced the radio button dialog…
MrAlders0n Mar 15, 2026
d2fddb5
- Hybrid mode now defaults to enabled for new users and existing user…
MrAlders0n Mar 15, 2026
ee06b4f
Implmented Trace Mode
MrAlders0n Mar 15, 2026
60f41ea
- Fixed a regression where device firmware version was no longer bein…
MrAlders0n Mar 15, 2026
3021691
- Redesigned the Connection tab for clarity. The previous layout was …
MrAlders0n Mar 15, 2026
d5243a1
### Bug Fixes
MrAlders0n Mar 15, 2026
5d58025
Bug 1 — Trace Mode fails after path byte mode switch:
MrAlders0n Mar 15, 2026
dc52c76
### Improvements
MrAlders0n Mar 15, 2026
8261c02
### New Features
MrAlders0n Mar 16, 2026
980d1fb
fix trace bytes
MrAlders0n Mar 16, 2026
9e301b5
Added Repeater Picker dropdown for traces
MrAlders0n Mar 16, 2026
904c1dd
Final fixes for trace mode
MrAlders0n Mar 17, 2026
8f71d52
Log tab redesign
MrAlders0n Mar 17, 2026
6a670d6
Resigned log & settings screen
MrAlders0n Mar 17, 2026
914b688
**New Features**
MrAlders0n Mar 17, 2026
0a5ad31
### Bug Fixes
MrAlders0n Mar 17, 2026
7735ef5
- Updated landscape controls to match the new portrait layout and add…
MrAlders0n Mar 17, 2026
23c5849
- Added text scale clamping for device accessibility settings. Previo…
MrAlders0n Mar 17, 2026
6cc9d41
Fixing some font sizing and layouts
MrAlders0n Mar 18, 2026
eccc88d
Fixed trace mode chip and trace icon
MrAlders0n Mar 18, 2026
e4e9fae
### New Features
MrAlders0n Mar 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .build_version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.0.1
1.2.0
6 changes: 2 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@ migrate_working_dir/
*.iws
.idea/

# The .vscode folder contains launch configuration and tasks you configure in
# VS Code which you may wish to be included in version control, so this line
# is commented out by default.
#.vscode/
.vscode/

# Flutter/Dart/Pub related
**/doc/api/
Expand Down Expand Up @@ -75,6 +72,7 @@ ios/Flutter/flutter_export_environment.sh
*.g.dart

# Debug logs
debug/
debuglog/
meshmapper-debug-*.txt

Expand Down
21 changes: 0 additions & 21 deletions .vscode/tasks.json

This file was deleted.

104 changes: 104 additions & 0 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Contributor Covenant Code of Conduct

## Our Pledge

We as members, contributors, and leaders pledge to make participation in our
community a welcoming experience for everyone, regardless of background or
identity.

We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.

## Our Standards

Examples of behavior that contributes to a positive environment:

- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members

Examples of unacceptable behavior:

- Trolling, insulting or derogatory comments, and personal attacks
- Public or private harassment of any kind
- Publishing others' private information without explicit permission
- Other conduct which could reasonably be considered inappropriate in a
professional setting

## Enforcement Responsibilities

Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, or harmful.

Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.

## Scope

This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.

## Enforcement

Instances of unacceptable behavior may be reported to the project maintainers at
the [MeshMapper Project issue tracker](https://github.com/MeshMapper/MeshMapper_Project/issues).

All complaints will be reviewed and investigated promptly and fairly. All
community leaders are obligated to respect the privacy and security of the
reporter of any incident.

## Enforcement Guidelines

Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:

### 1. Correction

**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.

**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.

### 2. Warning

**Community Impact**: A violation through a single incident or series of
actions.

**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels.
Violating these terms may lead to a temporary or permanent ban.

### 3. Temporary Ban

**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.

**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.

### 4. Permanent Ban

**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, or targeted conduct
against an individual or group.

**Consequence**: A permanent ban from any sort of public interaction within
the community.

## Attribution

This Code of Conduct is adapted from the [Contributor Covenant](https://www.contributor-covenant.org/),
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
13 changes: 12 additions & 1 deletion DEVELOPMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -295,10 +295,21 @@ Keeps the screen on during auto-ping to prevent device sleep during wardriving s

### Packet Structure
- Custom binary protocol with header byte (0x11 = GROUP_TEXT, 0x21 = ADVERT)
- Path encoding: hop count + repeater IDs (4 bytes each)
- Path encoding: `pathLen` byte encodes hash size (top 2 bits) + hop count (bottom 6 bits), followed by `hopCount * hashSize` path bytes
- `pathHashSize = (pathLen >> 6) + 1` → 1, 2, 3, or 4 bytes per hop
- `pathHashCount = pathLen & 63` → 0-63 hops
- SNR/RSSI metadata in BLE event payload
- Encrypted message payload (AES-ECB with channel key)

### Multi-Byte Path Support (v1.14.0+)
- **Purpose**: Expands repeater ID space from 256 (1-byte) to 65K (2-byte) or 16M (3-byte) unique IDs
- **TX mode**: Configured via `CMD_SET_PATH_HASH_MODE = 61 (0x3D)` — `[0x3D][0x00][mode]` where mode=0→1-byte, 1→2-byte, 2→3-byte
- **RX auto-detect**: Each received packet's `pathLen` byte is decoded to determine hash size, regardless of the user's TX setting
- **DeviceInfo**: v10+ firmware includes `path_hash_mode` byte after manufacturer + firmware version fields
- **API enforcement**: Auth response may include `hop_bytes` (1/2/3) to enforce regional path byte size
- **Lifecycle**: Radio mode is set during connection and restored to original on clean disconnect. Unclean disconnect leaves radio in configured mode.
- **Discovery pings**: NOT affected — multi-byte paths apply only to TX/RX channel messages

## Platform-Specific Notes

### Web (Chrome/Edge only)
Expand Down
62 changes: 62 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Security Policy

## Supported Versions

| Version | Supported |
| ------- | --------- |
| Latest | Yes |

Only the latest release on the `main` branch receives security updates.

## Reporting a Vulnerability

If you discover a security vulnerability in MeshMapper Flutter App, please report it responsibly. **Do not open a public GitHub issue for security vulnerabilities.**

### How to Report

1. Open a **private security advisory** at:
https://github.com/MeshMapper/MeshMapper_Project/security/advisories/new

2. Include the following information:
- Description of the vulnerability
- Steps to reproduce
- Potential impact
- Suggested fix (if any)

### What to Expect

- **Acknowledgment**: We will acknowledge receipt of your report within 72 hours.
- **Assessment**: We will assess the severity and impact of the vulnerability.
- **Fix timeline**: Critical issues will be addressed as quickly as possible. We aim to release a fix within 30 days of confirmation.
- **Disclosure**: We will coordinate with you on public disclosure timing after a fix is available.

## Security Considerations

### API Key Handling

- API keys are injected at build time via `--dart-define=API_KEY=...` and are **never** hardcoded in source code.

### Bluetooth Security

- The app communicates with MeshCore devices over Bluetooth Low Energy (BLE) using the MeshCore companion protocol.
- Channel messages are encrypted using AES-ECB with SHA-256 derived channel keys (encryption mode is dictated by the MeshCore protocol).

### Data Privacy

- GPS location data is sent to the MeshMapper API for community mesh coverage mapping.
- Users must be within a valid geographic zone (server-side validation) to submit data.
- No personal information beyond device name/public key and location data is transmitted.

## Scope

The following are **in scope** for security reports:

- Vulnerabilities in the Flutter application code
- API key or secret exposure
- Authentication or session management issues
- Data leakage or privacy concerns

The following are **out of scope**:

- Vulnerabilities in third-party dependencies (report to the upstream project)
- Issues with the MeshCore firmware or radio protocol (report to the MeshCore project)
13 changes: 10 additions & 3 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,14 @@ import 'services/bluetooth/mobile_bluetooth.dart';
import 'services/bluetooth/web_bluetooth.dart';
import 'services/background_service.dart';
import 'services/debug_file_logger.dart';
import 'utils/constants.dart';
import 'utils/debug_logger_io.dart';

void main() async {
WidgetsFlutterBinding.ensureInitialized();

// Enable debug file logging FIRST on mobile for dev builds
// Enable debug file logging FIRST on mobile to capture early logs
// This must happen before DebugLogger.initialize() to capture early logs
if (!kIsWeb && AppConstants.isDevelopmentBuild) {
if (!kIsWeb) {
await DebugFileLogger.enable();
}

Expand Down Expand Up @@ -248,6 +247,14 @@ class _ThemedAppState extends State<_ThemedApp> {

return MaterialApp(
title: 'MeshMapper',
builder: (context, child) {
return MediaQuery(
data: MediaQuery.of(context).copyWith(
textScaler: TextScaler.noScaling,
),
child: child!,
);
},
theme: ThemeData(
colorScheme: lightColorScheme,
scaffoldBackgroundColor: const Color(0xFFF1F5F9), // slate-100
Expand Down
81 changes: 79 additions & 2 deletions lib/models/api_queue_item.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class ApiQueueItem extends HiveObject {
final String heardRepeats;

/// Earliest time this item can be uploaded (milliseconds since epoch)
/// TX items have 5-second delay; RX/DISC are immediate
/// All items are immediate; upload timing is controlled by flush timers
@HiveField(13)
final int canUploadAfter;

Expand Down Expand Up @@ -81,7 +81,7 @@ class ApiQueueItem extends HiveObject {
longitude: longitude,
timestamp: DateTime.fromMillisecondsSinceEpoch(timestamp * 1000),
heardRepeats: heardRepeats,
canUploadAfter: DateTime.now().millisecondsSinceEpoch + 5000, // 5 seconds from now
canUploadAfter: DateTime.now().millisecondsSinceEpoch, // Immediate — flush timer controls upload timing
externalAntenna: externalAntenna,
noiseFloor: noiseFloor,
);
Expand Down Expand Up @@ -138,10 +138,87 @@ class ApiQueueItem extends HiveObject {
);
}

/// Create from a successful TRACE ping (targeted zero-hop trace)
/// heardRepeats format: "repeaterId:localSnr:localRssi:remoteSnr"
factory ApiQueueItem.fromTrace({
required double latitude,
required double longitude,
required String repeaterId,
required double localSnr,
required int localRssi,
required double remoteSnr,
required int timestamp,
required bool externalAntenna,
int? noiseFloor,
}) {
final heardRepeats = '$repeaterId:${localSnr.toStringAsFixed(2)}:$localRssi:${remoteSnr.toStringAsFixed(2)}';
return ApiQueueItem(
type: 'TRACE',
latitude: latitude,
longitude: longitude,
timestamp: DateTime.fromMillisecondsSinceEpoch(timestamp * 1000),
heardRepeats: heardRepeats,
canUploadAfter: DateTime.now().millisecondsSinceEpoch, // Immediate
externalAntenna: externalAntenna,
noiseFloor: noiseFloor,
);
}

/// Create from a failed DISC discovery (no nodes responded)
factory ApiQueueItem.fromDiscDrop({
required double latitude,
required double longitude,
required int timestamp,
required bool externalAntenna,
int? noiseFloor,
}) {
return ApiQueueItem(
type: 'DISC',
latitude: latitude,
longitude: longitude,
timestamp: DateTime.fromMillisecondsSinceEpoch(timestamp * 1000),
heardRepeats: 'None',
canUploadAfter: DateTime.now().millisecondsSinceEpoch, // Immediate
externalAntenna: externalAntenna,
noiseFloor: noiseFloor,
);
}

/// Convert to API JSON format (matches WebClient exactly)
Map<String, dynamic> toApiJson() {
// For TRACE type, parse the heardRepeats field to extract individual values
if (type == 'TRACE') {
// Format: "repeaterId:localSnr:localRssi:remoteSnr"
final parts = heardRepeats.split(':');
return {
'type': type,
'lat': latitude,
'lon': longitude,
'noisefloor': noiseFloor,
'repeater_id': parts.isNotEmpty ? parts[0] : '',
'local_snr': parts.length > 1 ? double.tryParse(parts[1]) : null,
'local_rssi': parts.length > 2 ? int.tryParse(parts[2]) : null,
'remote_snr': parts.length > 3 ? double.tryParse(parts[3]) : null,
'timestamp': timestamp.millisecondsSinceEpoch ~/ 1000,
'external_antenna': externalAntenna,
};
}

// For DISC type, parse the heardRepeats field to extract individual values
if (type == 'DISC') {
// Failed discovery (no nodes responded)
if (heardRepeats == 'None') {
return {
'type': type,
'lat': latitude,
'lon': longitude,
'noisefloor': noiseFloor,
'repeater_id': 'None',
'timestamp': timestamp.millisecondsSinceEpoch ~/ 1000,
'external_antenna': externalAntenna,
};
}

// Format: "repeaterId:nodeType:localSnr:localRssi:remoteSnr:pubkeyFull"
final parts = heardRepeats.split(':');
return {
Expand Down
Loading
Loading