Switch MQTT to TLS, fix last_heard fallback, downgrade CDN to HTTP

This commit is contained in:
Will Bradley
2026-04-14 09:08:49 -07:00
parent 74f41c5044
commit 150c61fe65
5 changed files with 27 additions and 29 deletions
+3 -3
View File
@@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Meshtastic MQTT Dashboard</title>
<link rel="stylesheet" href="css/style.css">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
<link rel="stylesheet" href="http://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
</head>
<body>
<!-- Login Screen -->
@@ -190,8 +190,8 @@
</div>
<!-- Scripts -->
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://unpkg.com/d3@7/dist/d3.min.js"></script>
<script src="http://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="http://unpkg.com/d3@7/dist/d3.min.js"></script>
<script src="js/app.js"></script>
</body>
</html>
+3 -3
View File
@@ -701,7 +701,7 @@ function displayNodes(nodes) {
</div>
<div style="display: flex; gap: 8px; align-items: center;">
${node.latitude && node.longitude ? `
<a href="https://www.openstreetmap.org/?mlat=${node.latitude}&mlon=${node.longitude}&zoom=11"
<a href="http://www.openstreetmap.org/?mlat=${node.latitude}&mlon=${node.longitude}&zoom=11"
target="_blank"
rel="noopener noreferrer"
onclick="event.stopPropagation()"
@@ -779,7 +779,7 @@ window.showNodeDetail = async function(nodeId) {
<span class="detail-label">Location</span>
<span class="detail-value">
${node.latitude.toFixed(6)}, ${node.longitude.toFixed(6)}
<a href="https://www.openstreetmap.org/?mlat=${node.latitude}&mlon=${node.longitude}&zoom=11"
<a href="http://www.openstreetmap.org/?mlat=${node.latitude}&mlon=${node.longitude}&zoom=11"
target="_blank"
rel="noopener noreferrer"
style="background: #4CAF50; color: white; padding: 4px 8px; border-radius: 4px; text-decoration: none; font-size: 14px; line-height: 1; margin-left: 8px; display: inline-block;">🌍</a>
@@ -948,7 +948,7 @@ function displayPositions(positions) {
<a href="#"
onclick="event.preventDefault(); window.showNodeDetail('${pos.node_id}'); return false;"
style="background: #2196F3; color: white; padding: 4px 12px; border-radius: 4px; text-decoration: none; font-size: 14px; line-height: 1; flex: 1; text-align: center;">View Details</a>
<a href="https://www.openstreetmap.org/?mlat=${pos.latitude}&mlon=${pos.longitude}&zoom=11"
<a href="http://www.openstreetmap.org/?mlat=${pos.latitude}&mlon=${pos.longitude}&zoom=11"
target="_blank"
rel="noopener noreferrer"
style="background: #4CAF50; color: white; padding: 4px 8px; border-radius: 4px; text-decoration: none; font-size: 16px; line-height: 1;">🌍</a>
+2 -2
View File
@@ -21,8 +21,8 @@ module.exports = {
// MQTT configuration
mqtt: {
broker: process.env.MQTT_BROKER || 'mqtt://mqtt.meshtastic.org',
port: parseInt(process.env.MQTT_PORT) || 1883,
broker: process.env.MQTT_BROKER || 'mqtts://mqtt.meshtastic.org:8883',
port: 8883,
username: process.env.MQTT_USERNAME || 'meshdev',
password: process.env.MQTT_PASSWORD || 'large4cats',
topic: process.env.MQTT_TOPIC || 'msh/US/#',
+13 -17
View File
@@ -27,7 +27,7 @@ const nodeQueries = {
node_id, short_name, long_name, hardware_model, role,
firmware_version, last_heard, battery_level, voltage,
channel_utilization, air_util_tx, uptime_seconds, updated_at
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
) VALUES (?, ?, ?, ?, ?, ?, COALESCE(?, CURRENT_TIMESTAMP), ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
ON CONFLICT(node_id) DO UPDATE SET
short_name = COALESCE(excluded.short_name, short_name),
long_name = COALESCE(excluded.long_name, long_name),
@@ -72,24 +72,20 @@ const nodeQueries = {
updateNullLastHeard: db.prepare(`
UPDATE nodes
SET last_heard = (
SELECT MAX(latest_time)
FROM (
SELECT MAX(created_at) as latest_time FROM messages WHERE from_node = nodes.node_id
UNION ALL
SELECT MAX(timestamp) as latest_time FROM positions WHERE node_id = nodes.node_id
UNION ALL
SELECT MAX(timestamp) as latest_time FROM telemetry WHERE node_id = nodes.node_id
)
SET last_heard = COALESCE(
(
SELECT MAX(latest_time)
FROM (
SELECT MAX(created_at) as latest_time FROM messages WHERE from_node = nodes.node_id
UNION ALL
SELECT MAX(timestamp) as latest_time FROM positions WHERE node_id = nodes.node_id
UNION ALL
SELECT MAX(timestamp) as latest_time FROM telemetry WHERE node_id = nodes.node_id
)
),
created_at
)
WHERE last_heard IS NULL
AND EXISTS (
SELECT 1 FROM messages WHERE from_node = nodes.node_id
UNION
SELECT 1 FROM positions WHERE node_id = nodes.node_id
UNION
SELECT 1 FROM telemetry WHERE node_id = nodes.node_id
)
`),
getOldNodesWithData: db.prepare(`
+6 -4
View File
@@ -19,12 +19,14 @@ app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'", "https://unpkg.com"],
scriptSrc: ["'self'", "'unsafe-inline'", "https://unpkg.com"],
styleSrc: ["'self'", "'unsafe-inline'", "http://unpkg.com"],
scriptSrc: ["'self'", "'unsafe-inline'", "http://unpkg.com"],
imgSrc: ["'self'", "data:", "https:", "http:"],
connectSrc: ["'self'"]
connectSrc: ["'self'"],
upgradeInsecureRequests: null
}
}
},
hsts: false
}));
// CORS configuration