Files
hmac-file-server/xmpp_client_upload_diagnosis.ipynb

482 lines
18 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "markdown",
"id": "050a107f",
"metadata": {},
"source": [
"# 🔍 XMPP Client Upload Authentication Diagnosis\n",
"\n",
"**Problem Analysis:** Dino and Gajim can't upload after restart, Android works after reconnection\n",
"\n",
"**Network Setup:**\n",
"- Desktop: WLAN + Ethernet → Router → HMAC File Server\n",
"- Mobile: Android XMPP client → Router → HMAC File Server\n",
"\n",
"**Date:** August 26, 2025"
]
},
{
"cell_type": "markdown",
"id": "b6a2684e",
"metadata": {},
"source": [
"## 🎯 Problem Identification\n",
"\n",
"### Symptoms:\n",
"- ❌ **Dino (Desktop):** Upload fails after restart\n",
"- ❌ **Gajim (Desktop):** Upload fails after restart \n",
"- ✅ **Android:** Upload works after disconnect/reconnect\n",
"\n",
"### Network Context:\n",
"- Notebook with WLAN + Ethernet (dual interface)\n",
"- Router provides access to HMAC File Server\n",
"- Fixed connections vs mobile reconnection behavior"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b04688cd",
"metadata": {},
"outputs": [],
"source": [
"# Check current server status and configuration\n",
"import subprocess\n",
"import json\n",
"from datetime import datetime\n",
"\n",
"print(\"🔍 HMAC File Server Status Check\")\n",
"print(\"=\" * 40)\n",
"\n",
"# Check if server is running\n",
"try:\n",
" result = subprocess.run(['ps', 'aux'], capture_output=True, text=True)\n",
" if 'hmac-file-server' in result.stdout:\n",
" print(\"✅ HMAC File Server is running\")\n",
" \n",
" # Extract server process info\n",
" for line in result.stdout.split('\\n'):\n",
" if 'hmac-file-server' in line and 'grep' not in line:\n",
" print(f\"📊 Process: {line.split()[1]} {' '.join(line.split()[10:])}\")\n",
" else:\n",
" print(\"❌ HMAC File Server not running\")\n",
"except Exception as e:\n",
" print(f\"⚠️ Could not check server status: {e}\")\n",
"\n",
"print(f\"\\n🕐 Check time: {datetime.now()}\")"
]
},
{
"cell_type": "markdown",
"id": "86dc3450",
"metadata": {},
"source": [
"## 🔍 Root Cause Analysis\n",
"\n",
"### Likely Issues:\n",
"\n",
"#### 1. **Token Expiration vs Session Management**\n",
"- Desktop clients (Dino/Gajim) may cache expired tokens after restart\n",
"- Android reconnection triggers fresh token generation\n",
"- Grace periods may not apply to cached tokens\n",
"\n",
"#### 2. **Network Interface Detection**\n",
"- Dual interface (WLAN + Ethernet) may confuse IP detection\n",
"- Desktop clients may use different IP after restart\n",
"- Router NAT may assign different internal IPs\n",
"\n",
"#### 3. **Client Behavior Differences**\n",
"- Desktop clients: Restore session from disk cache\n",
"- Mobile clients: Fresh authentication after reconnect\n",
"- Token validation may be stricter for cached sessions"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "1bcfae8c",
"metadata": {},
"outputs": [],
"source": [
"# Check network configuration and IP detection\n",
"print(\"🌐 Network Configuration Analysis\")\n",
"print(\"=\" * 40)\n",
"\n",
"# Check network interfaces\n",
"try:\n",
" result = subprocess.run(['ip', 'addr', 'show'], capture_output=True, text=True)\n",
" interfaces = []\n",
" current_interface = None\n",
" \n",
" for line in result.stdout.split('\\n'):\n",
" if ': ' in line and ('wlan' in line or 'eth' in line or 'eno' in line or 'wlp' in line):\n",
" current_interface = line.split(':')[1].strip().split('@')[0]\n",
" interfaces.append(current_interface)\n",
" elif current_interface and 'inet ' in line and '127.0.0.1' not in line:\n",
" ip = line.strip().split()[1].split('/')[0]\n",
" print(f\"📡 Interface {current_interface}: {ip}\")\n",
" \n",
" print(f\"\\n🔌 Total network interfaces found: {len(interfaces)}\")\n",
" if len(interfaces) > 1:\n",
" print(\"⚠️ Multiple interfaces detected - potential IP confusion for clients\")\n",
" \n",
"except Exception as e:\n",
" print(f\"⚠️ Could not analyze network interfaces: {e}\")\n",
"\n",
"# Check routing table\n",
"try:\n",
" result = subprocess.run(['ip', 'route', 'show'], capture_output=True, text=True)\n",
" print(\"\\n🛣 Default routes:\")\n",
" for line in result.stdout.split('\\n'):\n",
" if 'default' in line:\n",
" print(f\" {line}\")\n",
"except Exception as e:\n",
" print(f\"⚠️ Could not check routing: {e}\")"
]
},
{
"cell_type": "markdown",
"id": "44dabca1",
"metadata": {},
"source": [
"## 📊 Bearer Token Analysis\n",
"\n",
"Let's examine how the HMAC File Server handles different client scenarios:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bbfe7fe4",
"metadata": {},
"outputs": [],
"source": [
"# Analyze Bearer token validation logic\n",
"print(\"🔐 Bearer Token Validation Analysis\")\n",
"print(\"=\" * 40)\n",
"\n",
"# Check if the enhanced validation function exists\n",
"try:\n",
" with open('/root/hmac-file-server/cmd/server/main.go', 'r') as f:\n",
" content = f.read()\n",
" \n",
" # Look for mobile client detection\n",
" if 'isMobileXMPP' in content:\n",
" print(\"✅ Mobile XMPP client detection enabled\")\n",
" \n",
" # Extract mobile detection logic\n",
" lines = content.split('\\n')\n",
" in_mobile_section = False\n",
" for i, line in enumerate(lines):\n",
" if 'isMobileXMPP.*:=' in line or 'isMobileXMPP =' in line:\n",
" in_mobile_section = True\n",
" print(\"\\n📱 Mobile client detection logic:\")\n",
" elif in_mobile_section and 'conversations' in line.lower():\n",
" print(f\" - Conversations: {'✅' if 'conversations' in line else '❌'}\")\n",
" elif in_mobile_section and 'dino' in line.lower():\n",
" print(f\" - Dino: {'✅' if 'dino' in line else '❌'}\")\n",
" elif in_mobile_section and 'gajim' in line.lower():\n",
" print(f\" - Gajim: {'✅' if 'gajim' in line else '❌'}\")\n",
" elif in_mobile_section and 'android' in line.lower():\n",
" print(f\" - Android: {'✅' if 'android' in line else '❌'}\")\n",
" elif in_mobile_section and ('}' in line or 'if ' in line):\n",
" in_mobile_section = False\n",
" \n",
" # Check grace period configuration\n",
" if 'gracePeriod' in content:\n",
" print(\"\\n⏰ Grace period configuration:\")\n",
" for line in content.split('\\n'):\n",
" if 'gracePeriod.*=' in line and ('28800' in line or '43200' in line or '86400' in line or '259200' in line):\n",
" if '28800' in line:\n",
" print(\" - Base grace: 8 hours (28800s)\")\n",
" elif '43200' in line:\n",
" print(\" - Mobile grace: 12 hours (43200s)\")\n",
" elif '86400' in line:\n",
" print(\" - Network resilience: 24 hours (86400s)\")\n",
" elif '259200' in line:\n",
" print(\" - Ultra grace: 72 hours (259200s)\")\n",
" \n",
"except Exception as e:\n",
" print(f\"⚠️ Could not analyze Bearer token validation: {e}\")"
]
},
{
"cell_type": "markdown",
"id": "5527fdcc",
"metadata": {},
"source": [
"## 🎯 Specific Problem: Desktop vs Mobile Client Behavior\n",
"\n",
"### The Issue:\n",
"1. **Desktop clients (Dino/Gajim)** restore sessions from cache after restart\n",
"2. **Cached tokens may be expired** or tied to old IP addresses\n",
"3. **Mobile clients get fresh tokens** when reconnecting\n",
"4. **Grace periods may not apply** to restored cached sessions"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "dcfb3356",
"metadata": {},
"outputs": [],
"source": [
"# Check server logs for authentication failures\n",
"print(\"📋 Recent Authentication Activity\")\n",
"print(\"=\" * 40)\n",
"\n",
"log_files = [\n",
" '/var/log/hmac-file-server-mobile.log',\n",
" '/var/log/hmac-file-server.log',\n",
" '/tmp/server.log'\n",
"]\n",
"\n",
"for log_file in log_files:\n",
" try:\n",
" result = subprocess.run(['tail', '-20', log_file], capture_output=True, text=True)\n",
" if result.returncode == 0 and result.stdout.strip():\n",
" print(f\"\\n📝 Last 20 lines from {log_file}:\")\n",
" lines = result.stdout.strip().split('\\n')\n",
" for line in lines[-10:]: # Show last 10 lines\n",
" if any(keyword in line.lower() for keyword in ['error', 'fail', 'invalid', 'expired', 'bearer', 'auth']):\n",
" print(f\"🔍 {line}\")\n",
" break\n",
" except:\n",
" continue\n",
" \n",
"print(\"\\n💡 Look for patterns like:\")\n",
"print(\" - 'Invalid Bearer token' (expired cached tokens)\")\n",
"print(\" - 'expired beyond grace period' (old sessions)\")\n",
"print(\" - User-Agent differences between clients\")"
]
},
{
"cell_type": "markdown",
"id": "41f66318",
"metadata": {},
"source": [
"## 🔧 Solution Strategy\n",
"\n",
"### Immediate Fixes:\n",
"\n",
"#### 1. **Clear Client Caches**\n",
"- Dino: `~/.local/share/dino/` \n",
"- Gajim: `~/.local/share/gajim/`\n",
"\n",
"#### 2. **Extend Grace Periods for Desktop Clients**\n",
"- Treat Dino/Gajim as mobile clients for grace period calculation\n",
"- Add specific detection for desktop XMPP clients\n",
"\n",
"#### 3. **Enhanced Session Recovery**\n",
"- Implement session recovery for cached tokens\n",
"- Allow IP changes for restored sessions"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c3054967",
"metadata": {},
"outputs": [],
"source": [
"# Generate client cache clearing commands\n",
"print(\"🧹 Client Cache Clearing Commands\")\n",
"print(\"=\" * 40)\n",
"\n",
"import os\n",
"home_dir = os.path.expanduser('~')\n",
"\n",
"cache_locations = {\n",
" 'Dino': [\n",
" f'{home_dir}/.local/share/dino/',\n",
" f'{home_dir}/.cache/dino/',\n",
" f'{home_dir}/.config/dino/'\n",
" ],\n",
" 'Gajim': [\n",
" f'{home_dir}/.local/share/gajim/',\n",
" f'{home_dir}/.cache/gajim/',\n",
" f'{home_dir}/.config/gajim/'\n",
" ]\n",
"}\n",
"\n",
"print(\"🔍 Check these locations for cached data:\")\n",
"for client, locations in cache_locations.items():\n",
" print(f\"\\n📱 {client}:\")\n",
" for location in locations:\n",
" if os.path.exists(location):\n",
" print(f\" ✅ {location} (exists)\")\n",
" # List important files\n",
" try:\n",
" for root, dirs, files in os.walk(location):\n",
" for file in files:\n",
" if any(keyword in file.lower() for keyword in ['token', 'session', 'cache', 'upload']):\n",
" print(f\" 🔍 {os.path.join(root, file)}\")\n",
" except:\n",
" pass\n",
" else:\n",
" print(f\" ❌ {location} (not found)\")\n",
"\n",
"print(\"\\n🚨 MANUAL STEPS TO TRY:\")\n",
"print(\"1. Close Dino and Gajim completely\")\n",
"print(\"2. Clear application caches (backup first!)\")\n",
"print(\"3. Restart clients and test upload\")\n",
"print(\"4. If still failing, check server logs for specific errors\")"
]
},
{
"cell_type": "markdown",
"id": "6dcc992f",
"metadata": {},
"source": [
"## 🛠️ Enhanced Server Configuration\n",
"\n",
"Let's create an enhanced configuration that treats desktop XMPP clients with the same grace as mobile clients:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6efe0490",
"metadata": {},
"outputs": [],
"source": [
"# Check current mobile client detection and suggest improvements\n",
"print(\"🔧 Desktop Client Enhancement Strategy\")\n",
"print(\"=\" * 40)\n",
"\n",
"# Read current configuration\n",
"try:\n",
" with open('/root/hmac-file-server/config-mobile-resilient.toml', 'r') as f:\n",
" config = f.read()\n",
" \n",
" print(\"📄 Current grace period settings:\")\n",
" for line in config.split('\\n'):\n",
" if 'grace' in line.lower() and '=' in line:\n",
" print(f\" {line.strip()}\")\n",
" \n",
" print(\"\\n💡 Recommended enhancement:\")\n",
" print(\" - Treat Dino and Gajim as 'mobile' clients for grace periods\")\n",
" print(\" - Add 'desktop_xmpp_grace_period = 24h' for cached session recovery\")\n",
" print(\" - Enable session_restoration = true for desktop clients\")\n",
" \n",
"except Exception as e:\n",
" print(f\"⚠️ Could not read config: {e}\")\n",
"\n",
"# Show the enhanced mobile detection logic needed\n",
"print(\"\\n🔍 Enhanced Client Detection Logic Needed:\")\n",
"print(\"```go\")\n",
"print(\"// Enhanced XMPP client detection (both mobile and desktop)\")\n",
"print(\"isXMPPClient := strings.Contains(strings.ToLower(userAgent), \\\"conversations\\\") ||\")\n",
"print(\" strings.Contains(strings.ToLower(userAgent), \\\"dino\\\") ||\")\n",
"print(\" strings.Contains(strings.ToLower(userAgent), \\\"gajim\\\") ||\")\n",
"print(\" strings.Contains(strings.ToLower(userAgent), \\\"android\\\") ||\")\n",
"print(\" strings.Contains(strings.ToLower(userAgent), \\\"xmpp\\\")\")\n",
"print(\"\")\n",
"print(\"// Desktop XMPP clients need same grace as mobile for session restoration\")\n",
"print(\"if isXMPPClient {\")\n",
"print(\" gracePeriod = int64(86400) // 24 hours for all XMPP clients\")\n",
"print(\"}\")\n",
"print(\"```\")"
]
},
{
"cell_type": "markdown",
"id": "6cdcf458",
"metadata": {},
"source": [
"## 🎯 Immediate Action Plan\n",
"\n",
"### Step 1: Quick Client Fix\n",
"1. **Close Dino and Gajim completely**\n",
"2. **Clear their caches/sessions** (backup first)\n",
"3. **Restart clients** - they should get fresh tokens\n",
"\n",
"### Step 2: Server Enhancement \n",
"1. **Modify mobile client detection** to include desktop XMPP clients\n",
"2. **Extend grace periods** for all XMPP clients (not just mobile)\n",
"3. **Add session restoration** logic for cached tokens\n",
"\n",
"### Step 3: Network Optimization\n",
"1. **Check for IP conflicts** between WLAN/Ethernet\n",
"2. **Verify router configuration** for consistent NAT\n",
"3. **Monitor upload endpoints** for client-specific issues"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "d1f7580d",
"metadata": {},
"outputs": [],
"source": [
"# Generate immediate fix commands\n",
"print(\"⚡ IMMEDIATE FIX COMMANDS\")\n",
"print(\"=\" * 40)\n",
"\n",
"print(\"1⃣ STOP XMPP CLIENTS:\")\n",
"print(\" pkill -f dino\")\n",
"print(\" pkill -f gajim\")\n",
"print(\" # Wait 5 seconds\")\n",
"\n",
"print(\"\\n2⃣ BACKUP AND CLEAR CACHES:\")\n",
"print(\" # Backup first (optional)\")\n",
"print(\" cp -r ~/.local/share/dino ~/.local/share/dino.backup\")\n",
"print(\" cp -r ~/.local/share/gajim ~/.local/share/gajim.backup\")\n",
"print(\" \")\n",
"print(\" # Clear session caches\")\n",
"print(\" rm -rf ~/.cache/dino/\")\n",
"print(\" rm -rf ~/.cache/gajim/\")\n",
"print(\" \")\n",
"print(\" # Clear specific upload-related files (if they exist)\")\n",
"print(\" find ~/.local/share/dino -name '*upload*' -delete 2>/dev/null || true\")\n",
"print(\" find ~/.local/share/gajim -name '*upload*' -delete 2>/dev/null || true\")\n",
"\n",
"print(\"\\n3⃣ RESTART CLIENTS:\")\n",
"print(\" # Start Dino\")\n",
"print(\" dino &\")\n",
"print(\" \")\n",
"print(\" # Start Gajim\")\n",
"print(\" gajim &\")\n",
"\n",
"print(\"\\n4⃣ TEST UPLOAD:\")\n",
"print(\" # Try uploading a small file in both clients\")\n",
"print(\" # Check server logs for any authentication issues\")\n",
"print(\" tail -f /var/log/hmac-file-server-mobile.log\")\n",
"\n",
"print(\"\\n🔍 If this doesn't work, the issue is in the server's client detection logic.\")\n",
"print(\"The server may not be treating Dino/Gajim with sufficient grace periods.\")"
]
},
{
"cell_type": "markdown",
"id": "75e3eac8",
"metadata": {},
"source": [
"## 📋 Diagnosis Summary\n",
"\n",
"### 🎯 **Root Cause**: Session Cache vs Fresh Authentication\n",
"\n",
"- **Desktop clients (Dino/Gajim)**: Restore cached sessions with potentially expired tokens\n",
"- **Mobile clients**: Get fresh authentication after reconnection\n",
"- **Server**: May not apply sufficient grace periods to cached/restored sessions\n",
"\n",
"### ✅ **Solution Priority**:\n",
"1. **Immediate**: Clear client caches to force fresh authentication\n",
"2. **Short-term**: Enhance server to treat desktop XMPP clients with mobile-level grace\n",
"3. **Long-term**: Implement proper session restoration for all XMPP clients\n",
"\n",
"### 🔧 **Next Steps**:\n",
"Execute the immediate fix commands above, then monitor server logs for authentication patterns."
]
}
],
"metadata": {
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 5
}