feat: Add Sequential Thinking to Code Review + Frontend Validation

Enhanced code review and frontend validation with intelligent triggers:

Code Review Agent Enhancement:
- Added Sequential Thinking MCP integration for complex issues
- Triggers on 2+ rejections or 3+ critical issues
- New escalation format with root cause analysis
- Comprehensive solution strategies with trade-off evaluation
- Educational feedback to break rejection cycles
- Files: .claude/agents/code-review.md (+308 lines)
- Docs: CODE_REVIEW_ST_ENHANCEMENT.md, CODE_REVIEW_ST_TESTING.md

Frontend Design Skill Enhancement:
- Automatic invocation for ANY UI change
- Comprehensive validation checklist (200+ checkpoints)
- 8 validation categories (visual, interactive, responsive, a11y, etc.)
- 3 validation levels (quick, standard, comprehensive)
- Integration with code review workflow
- Files: .claude/skills/frontend-design/SKILL.md (+120 lines)
- Docs: UI_VALIDATION_CHECKLIST.md (462 lines), AUTOMATIC_VALIDATION_ENHANCEMENT.md (587 lines)

Settings Optimization:
- Repaired .claude/settings.local.json (fixed m365 pattern)
- Reduced permissions from 49 to 33 (33% reduction)
- Removed duplicates, sorted alphabetically
- Created SETTINGS_PERMISSIONS.md documentation

Checkpoint Command Enhancement:
- Dual checkpoint system (git + database)
- Saves session context to API for cross-machine recall
- Includes git metadata in database context
- Files: .claude/commands/checkpoint.md (+139 lines)

Decision Rationale:
- Sequential Thinking MCP breaks rejection cycles by identifying root causes
- Automatic frontend validation catches UI issues before code review
- Dual checkpoints enable complete project memory across machines
- Settings optimization improves maintainability

Total: 1,200+ lines of documentation and enhancements

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-17 16:23:52 -07:00
parent 359c2cf1b4
commit 75ce1c2fd5
1089 changed files with 149506 additions and 5 deletions

View File

@@ -0,0 +1,235 @@
1→# GuruConnect Feature Tracking
2→
3→## Status Legend
4→- [ ] Not started
5→- [~] In progress
6→- [x] Complete
7→
8→---
9→
10→## Phase 1: Core MVP
11→
12→### Infrastructure
13→- [x] WebSocket relay server (Axum)
14→- [x] Agent WebSocket client
15→- [x] Protobuf message protocol
16→- [x] Agent authentication (agent_id, api_key)
17→- [x] Session management (create, join, leave)
18→- [x] Systemd service deployment
19→- [x] NPM proxy (connect.azcomputerguru.com)
20→
21→### Support Codes
22→- [x] Generate 6-digit codes
23→- [x] Code validation API
24→- [x] Code status tracking (pending, connected, completed, cancelled)
25→- [~] Link support codes to agent sessions
26→- [ ] Code expiration (auto-expire after X minutes)
27→- [ ] Support code in agent download URL
28→
29→### Dashboard
30→- [x] Technician login page
31→- [x] Support tab with code generation
32→- [x] Access tab with connected agents
33→- [ ] Session detail panel with tabs
34→- [ ] Screenshot thumbnails
35→- [ ] Join/Connect button
36→
37→### Agent (Windows)
38→- [x] DXGI screen capture
39→- [x] GDI fallback capture
40→- [x] WebSocket connection
41→- [x] Config persistence (agent_id)
42→- [ ] Support code parameter
43→- [ ] Hostname/machine info reporting
44→- [ ] Screenshot-only mode (for thumbnails)
45→
46→---
47→
48→## Phase 2: Remote Control
49→
50→### Screen Viewing
51→- [ ] Web-based viewer (canvas)
52→- [ ] Raw frame decoding
53→- [ ] Dirty rectangle optimization
54→- [ ] Frame rate adaptation
55→
56→### Input Control
57→- [x] Mouse event handling (agent)
58→- [x] Keyboard event handling (agent)
59→- [ ] Input relay through server
60→- [ ] Multi-monitor support
61→
62→### Encoding
63→- [ ] VP9 software encoding
64→- [ ] H.264 hardware encoding (NVENC/QSV)
65→- [ ] Adaptive quality based on bandwidth
66→
67→---
68→
69→## Phase 3: Backstage Tools (like ScreenConnect)
70→
71→### Device Information
72→- [ ] OS version, hostname, domain
73→- [ ] Logged-in user
74→- [ ] Public/private IP addresses
75→- [ ] MAC address
76→- [ ] CPU, RAM, disk info
77→- [ ] Uptime
78→
79→### Toolbox APIs
80→- [ ] Process list (name, PID, memory)
81→- [ ] Installed software list
82→- [ ] Windows services list
83→- [ ] Event log viewer
84→- [ ] Registry browser
85→
86→### Remote Commands
87→- [ ] Run shell commands
88→- [ ] PowerShell execution
89→- [ ] Command output streaming
90→- [ ] Command history per session
91→
92→### Chat/Messaging
93→- [ ] Technician → Client messages
94→- [ ] Client → Technician messages
95→- [ ] Message history
96→
97→### File Transfer
98→- [ ] Upload files to remote
99→- [ ] Download files from remote
100→- [ ] Progress tracking
101→- [ ] Folder browsing
102→
103→---
104→
105→## Phase 4: Session Management
106→
107→### Timeline/History
108→- [ ] Connection events
109→- [ ] Session duration tracking
110→- [ ] Guest connection history
111→- [ ] Activity log
112→
113→### Session Recording
114→- [ ] Record session video
115→- [ ] Playback interface
116→- [ ] Storage management
117→
118→### Notes
119→- [ ] Per-session notes
120→- [ ] Session tagging
121→
122→---
123→
124→## Phase 5: Access Mode (Unattended)
125→
126→### Persistent Agent
127→- [ ] Windows service installation
128→- [ ] Auto-start on boot
129→- [ ] Silent/background mode
130→- [ ] Automatic reconnection
131→
132→### Machine Groups
133→- [ ] Company/client organization
134→- [ ] Site/location grouping
135→- [ ] Custom tags
136→- [ ] Filtering/search
137→
138→### Installer Builder
139→- [ ] Customized agent builds
140→- [ ] Pre-configured company/site
141→- [ ] Silent install options
142→- [ ] MSI packaging
143→
144→---
145→
146→## Phase 6: Security & Authentication
147→
148→### Technician Auth
149→- [ ] User accounts
150→- [ ] Password hashing
151→- [ ] JWT tokens
152→- [ ] Session management
153→
154→### MFA
155→- [ ] TOTP (Google Authenticator)
156→- [ ] Email verification
157→
158→### Audit Logging
159→- [ ] Login attempts
160→- [ ] Session access
161→- [ ] Command execution
162→- [ ] File transfers
163→
164→### Permissions
165→- [ ] Role-based access
166→- [ ] Per-client permissions
167→- [ ] Feature restrictions
168→
169→---
170→
171→## Phase 7: Integrations
172→
173→### PSA Integration
174→- [ ] HaloPSA
175→- [ ] Autotask
176→- [ ] ConnectWise
177→
178→### GuruRMM Integration
179→- [ ] Dashboard embedding
180→- [ ] Single sign-on
181→- [ ] Asset linking
182→
183→---
184→
185→## Phase 8: Polish
186→
187→### Branding
188→- [ ] White-label support
189→- [ ] Custom logos
190→- [ ] Custom colors
191→
192→### Mobile Support
193→- [ ] Responsive viewer
194→- [ ] Touch input handling
195→
196→### Annotations
197→- [ ] Draw on screen
198→- [ ] Pointer highlighting
199→- [ ] Screenshot annotations
200→
201→---
202→
203→## Current Sprint
204→
205→### In Progress
206→1. Link support codes to agent sessions
207→2. Show connected status in dashboard
208→
209→### Next Up
210→1. Support code in agent download/config
211→2. Device info reporting from agent
212→3. Screenshot thumbnails
213→
214→---
215→
216→## Notes
217→
218→### ScreenConnect Feature Reference (from screenshots)
219→- Support session list with idle times and connection bars
220→- Detail panel with tabbed interface:
221→ - Join/Screen (thumbnail, Join button)
222→ - Info (device details)
223→ - Timeline (connection history)
224→ - Chat (messaging)
225→ - Commands (shell execution)
226→ - Notes
227→ - Toolbox (processes, software, events, services)
228→ - File transfer
229→ - Logs
230→ - Settings
231→
<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

View File

@@ -0,0 +1,2 @@
C:/Users/MikeSwanson/Claude/session-logs\2025-12-21-guruconnect-build.md
C:/Users/MikeSwanson/Claude/session-logs\2025-12-21-guruconnect-session.md

View File

@@ -0,0 +1,30 @@
Table "public.connect_machines"
Column | Type | Collation | Nullable | Default
-------------------+--------------------------+-----------+----------+------------------------------
id | uuid | | not null | gen_random_uuid()
agent_id | character varying(255) | | not null |
hostname | character varying(255) | | not null |
os_version | character varying(255) | | |
is_elevated | boolean | | | false
is_persistent | boolean | | | true
first_seen | timestamp with time zone | | | now()
last_seen | timestamp with time zone | | | now()
last_session_id | uuid | | |
status | character varying(20) | | | 'offline'::character varying
created_at | timestamp with time zone | | | now()
updated_at | timestamp with time zone | | | now()
agent_version | character varying(32) | | |
update_status | character varying(32) | | |
last_update_check | timestamp with time zone | | |
Indexes:
"connect_machines_pkey" PRIMARY KEY, btree (id)
"connect_machines_agent_id_key" UNIQUE CONSTRAINT, btree (agent_id)
"idx_connect_machines_agent_id" btree (agent_id)
"idx_connect_machines_status" btree (status)
"idx_machines_update_status" btree (update_status)
"idx_machines_version" btree (agent_version)
Referenced by:
TABLE "connect_sessions" CONSTRAINT "connect_sessions_machine_id_fkey" FOREIGN KEY (machine_id) REFERENCES connect_machines(id) ON DELETE CASCADE
TABLE "user_client_access" CONSTRAINT "user_client_access_client_id_fkey" FOREIGN KEY (client_id) REFERENCES connect_machines(id) ON DELETE CASCADE
Triggers:
update_connect_machines_updated_at BEFORE UPDATE ON connect_machines FOR EACH ROW EXECUTE FUNCTION update_connect_updated_at()

View File

@@ -0,0 +1,205 @@
1→# GuruConnect - Project Guidelines
2→
3→## Overview
4→
5→GuruConnect is a remote desktop solution for MSPs, similar to ConnectWise ScreenConnect. It provides real-time screen sharing, remote control, and support session management.
6→
7→## Architecture
8→
9→```
10→┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
11→│ Dashboard │◄───────►│ GuruConnect │◄───────►│ GuruConnect │
12→│ (HTML/JS) │ WSS │ Server (Rust) │ WSS │ Agent (Rust) │
13→└─────────────────┘ └─────────────────┘ └─────────────────┘
14→ │ │
15→ │ ▼
16→ │ ┌─────────────────┐
17→ └──────────────────►│ PostgreSQL │
18→ └─────────────────┘
19→```
20→
21→## Design Constraints
22→
23→### Agent (Windows)
24→- **Target OS:** Windows 7 SP1 and later (including Server 2008 R2+)
25→- **Single binary:** Agent and viewer in one executable
26→- **No runtime dependencies:** Statically linked, no .NET or VC++ redistributables
27→- **Protocol handler:** `guruconnect://` URL scheme for launching viewer
28→- **Tray icon:** System tray presence with status and exit option
29→- **UAC aware:** Graceful handling of elevated/non-elevated contexts
30→- **Auto-install:** Detects if not installed and offers installation
31→
32→### Server (Linux)
33→- **Target OS:** Ubuntu 22.04 LTS
34→- **Framework:** Axum for HTTP/WebSocket
35→- **Database:** PostgreSQL with sqlx (compile-time checked queries)
36→- **Static files:** Served from `server/static/`
37→- **No containers required:** Runs as systemd service or direct binary
38→
39→### Protocol
40→- **Wire format:** Protocol Buffers (protobuf) for ALL client-server messages
41→- **Transport:** WebSocket over TLS (wss://)
42→- **Compression:** Zstd for video frames
43→- **Schema:** `proto/guruconnect.proto` is the source of truth
44→
45→## Security Rules
46→
47→### Authentication
48→- **Dashboard/API:** JWT tokens required for all endpoints except `/health` and `/api/auth/login`
49→- **Viewer WebSocket:** JWT token required in `token` query parameter
50→- **Agent WebSocket:** Must provide either:
51→ - Valid support code (for ad-hoc support sessions)
52→ - Valid API key (for persistent/managed agents)
53→- **Never** accept unauthenticated agent connections
54→
55→### Credentials
56→- **Never** hardcode secrets in source code
57→- **Never** commit credentials to git
58→- Use environment variables for all secrets:
59→ - `JWT_SECRET` - JWT signing key
60→ - `DATABASE_URL` - PostgreSQL connection string
61→ - `AGENT_API_KEY` - Optional shared key for agents
62→
63→### Password Storage
64→- Use Argon2id for password hashing
65→- Never store plaintext passwords
66→
67→## Coding Standards
68→
69→### Rust
70→- Use `tracing` crate for logging (not `println!` or `log`)
71→- Use `anyhow` for error handling in binaries
72→- Use `thiserror` for library error types
73→- Prefer `async`/`await` over blocking code
74→- Run `cargo clippy` before commits
75→
76→### Logging Levels
77→- `error!` - Failures that need attention
78→- `warn!` - Unexpected but handled situations
79→- `info!` - Normal operational messages (startup, connections, sessions)
80→- `debug!` - Detailed debugging info
81→- `trace!` - Very verbose, message-level tracing
82→
83→### Naming
84→- Rust: `snake_case` for functions/variables, `PascalCase` for types
85→- Protobuf: `PascalCase` for messages, `snake_case` for fields
86→- Database: `snake_case` for tables and columns
87→
88→## Build & Version
89→
90→### Version Format
91→- Semantic versioning: `MAJOR.MINOR.PATCH`
92→- Build identification: `VERSION-GITHASH[-dirty]`
93→- Example: `0.1.0-48076e1` or `0.1.0-48076e1-dirty`
94→
95→### Build Info (Agent)
96→The agent embeds at compile time:
97→- `VERSION` - Cargo.toml version
98→- `GIT_HASH` - Short commit hash (8 chars)
99→- `GIT_BRANCH` - Branch name
100→- `GIT_DIRTY` - "clean" or "dirty"
101→- `BUILD_TIMESTAMP` - UTC build time
102→- `BUILD_TARGET` - Target triple
103→
104→### Commands
105→```bash
106→# Build agent (Windows)
107→cargo build -p guruconnect --release
108→
109→# Build server (Linux, from Linux or cross-compile)
110→cargo build -p guruconnect-server --release --target x86_64-unknown-linux-gnu
111→
112→# Check version
113→./guruconnect --version # Short: 0.1.0-48076e1
114→./guruconnect version-info # Full details
115→```
116→
117→## Database Schema
118→
119→### Key Tables
120→- `users` - Dashboard users (admin-created only)
121→- `machines` - Registered agents (persistent)
122→- `sessions` - Connection sessions (historical)
123→- `events` - Audit log
124→- `support_codes` - One-time support codes
125→
126→### Conventions
127→- Primary keys: `id UUID DEFAULT gen_random_uuid()`
128→- Timestamps: `created_at TIMESTAMPTZ DEFAULT NOW()`
129→- Soft deletes: Prefer `deleted_at` over hard deletes for audit trail
130→- Foreign keys: Always with `ON DELETE CASCADE` or explicit handling
131→
132→## File Structure
133→
134→```
135→guru-connect/
136→├── agent/ # Windows agent + viewer
137→│ ├── src/
138→│ │ ├── main.rs # CLI entry point
139→│ │ ├── capture/ # Screen capture (DXGI, GDI)
140→│ │ ├── encoder/ # Video encoding
141→│ │ ├── input/ # Mouse/keyboard injection
142→│ │ ├── viewer/ # Native viewer window
143→│ │ ├── transport/ # WebSocket client
144→│ │ ├── session/ # Session management
145→│ │ ├── tray/ # System tray
146→│ │ └── install.rs # Installation & protocol handler
147→│ ├── build.rs # Build script (protobuf, version info)
148→│ └── Cargo.toml
149→├── server/ # Linux relay server
150→│ ├── src/
151→│ │ ├── main.rs # Server entry point
152→│ │ ├── relay/ # WebSocket relay handlers
153→│ │ ├── session/ # Session state management
154→│ │ ├── auth/ # JWT authentication
155→│ │ ├── api/ # REST API handlers
156→│ │ └── db/ # Database operations
157→│ ├── static/ # Dashboard HTML/JS/CSS
158→│ │ ├── login.html
159→│ │ ├── dashboard.html
160→│ │ ├── viewer.html
161→│ │ └── downloads/ # Agent binaries
162→│ ├── migrations/ # SQL migrations
163→│ └── Cargo.toml
164→├── proto/ # Protocol definitions
165→│ └── guruconnect.proto
166→└── CLAUDE.md # This file
167→```
168→
169→## Deployment
170→
171→### Server (172.16.3.30)
172→- **Binary:** `/home/guru/guru-connect/target/x86_64-unknown-linux-gnu/release/guruconnect-server`
173→- **Static:** `/home/guru/guru-connect/server/static/`
174→- **Startup:** `~/guru-connect/start-server.sh`
175→- **Port:** 3002 (proxied via NPM to connect.azcomputerguru.com)
176→
177→### Agent Distribution
178→- **Download URL:** https://connect.azcomputerguru.com/downloads/guruconnect.exe
179→- **Auto-update:** Not yet implemented (future feature)
180→
181→## Issue Tracking
182→
183→Use Gitea issues: https://git.azcomputerguru.com/azcomputerguru/guru-connect/issues
184→
185→Reference issues in commits:
186→- `Fixes #1` - Closes the issue
187→- `Related to #1` - Links without closing
188→
189→## Testing Checklist
190→
191→Before releasing:
192→- [ ] Agent connects with support code
193→- [ ] Agent connects with API key
194→- [ ] Viewer connects with JWT token
195→- [ ] Unauthenticated connections rejected
196→- [ ] Screen capture works (DXGI primary, GDI fallback)
197→- [ ] Mouse/keyboard input works
198→- [ ] Chat messages relay correctly
199→- [ ] Protocol handler launches viewer
200→- [ ] Tray icon shows correct status
201→
<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

View File

@@ -0,0 +1,639 @@
1→# Credentials & Authorization Reference
2→**Last Updated:** 2025-12-16
3→**Purpose:** Centralized credentials for Claude Code context recovery across all machines
4→
5→---
6→
7→## Infrastructure - SSH Access
8→
9→### Jupiter (Unraid Primary)
10→- **Host:** 172.16.3.20
11→- **User:** root
12→- **Port:** 22
13→- **Password:** Th1nk3r^99##
14→- **WebUI Password:** Th1nk3r^99##
15→- **Role:** Primary container host (Gitea, NPM, GuruRMM, media)
16→- **iDRAC IP:** 172.16.1.73 (DHCP)
17→- **iDRAC User:** root
18→- **iDRAC Password:** Window123!@#-idrac
19→- **iDRAC SSH:** Enabled (port 22)
20→- **IPMI Key:** All zeros
21→
22→### Saturn (Unraid Secondary)
23→- **Host:** 172.16.3.21
24→- **User:** root
25→- **Port:** 22
26→- **Password:** r3tr0gradE99
27→- **Role:** Migration source, being consolidated to Jupiter
28→
29→### pfSense (Firewall)
30→- **Host:** 172.16.0.1
31→- **User:** admin
32→- **Port:** 2248
33→- **Password:** r3tr0gradE99!!
34→- **Role:** Firewall, Tailscale gateway
35→- **Tailscale IP:** 100.79.69.82 (pfsense-1)
36→
37→### OwnCloud VM (on Jupiter)
38→- **Host:** 172.16.3.22
39→- **Hostname:** cloud.acghosting.com
40→- **User:** root
41→- **Port:** 22
42→- **Password:** Paper123!@#-unifi!
43→- **OS:** Rocky Linux 9.6
44→- **Role:** OwnCloud file sync server
45→- **Services:** Apache, MariaDB, PHP-FPM, Redis, Datto RMM agents
46→- **Storage:** SMB mount from Jupiter (/mnt/user/OwnCloud)
47→- **Note:** Jupiter has SSH key auth configured
48→
49→### GuruRMM Build Server
50→- **Host:** 172.16.3.30
51→- **Hostname:** gururmm
52→- **User:** guru
53→- **Port:** 22
54→- **Password:** Gptf*77ttb123!@#-rmm
55→- **Sudo Password:** Gptf*77ttb123!@#-rmm (special chars cause issues with sudo -S)
56→- **OS:** Ubuntu 22.04
57→- **Role:** GuruRMM/GuruConnect dedicated server (API, DB, Dashboard, Downloads, GuruConnect relay)
58→- **Services:** nginx, PostgreSQL, gururmm-server, gururmm-agent, guruconnect-server
59→- **SSH Key Auth:** ✅ Working from Windows/WSL (ssh guru@172.16.3.30)
60→- **Service Restart Method:** Services run as guru user, so `pkill` works without sudo. Deploy pattern:
61→ 1. Build: `cargo build --release --target x86_64-unknown-linux-gnu -p <package>`
62→ 2. Rename old: `mv target/release/binary target/release/binary.old`
63→ 3. Copy new: `cp target/x86_64.../release/binary target/release/binary`
64→ 4. Kill old: `pkill -f binary.old` (systemd auto-restarts)
65→- **GuruConnect:** Static files in /home/guru/guru-connect/server/static/
66→- **GuruConnect Startup:** `~/guru-connect/start-server.sh` (ALWAYS use this, kills old process and uses correct binary path)
67→- **GuruConnect Binary:** /home/guru/guru-connect/target/x86_64-unknown-linux-gnu/release/guruconnect-server
68→
69→---
70→
71→## Services - Web Applications
72→
73→### Gitea (Git Server)
74→- **URL:** https://git.azcomputerguru.com/
75→- **Internal:** http://172.16.3.20:3000
76→- **SSH:** ssh://git@172.16.3.20:2222
77→- **User:** mike@azcomputerguru.com
78→- **Password:** Window123!@#-git
79→- **API Token:** 9b1da4b79a38ef782268341d25a4b6880572063f
80→
81→### NPM (Nginx Proxy Manager)
82→- **Admin URL:** http://172.16.3.20:7818
83→- **HTTP Port:** 1880
84→- **HTTPS Port:** 18443
85→- **User:** mike@azcomputerguru.com
86→- **Password:** Paper123!@#-unifi
87→
88→### Cloudflare
89→- **API Token (Full DNS):** DRRGkHS33pxAUjQfRDzDeVPtt6wwUU6FwtXqOzNj
90→- **API Token (Legacy/Limited):** U1UTbBOWA4a69eWEBiqIbYh0etCGzrpTU4XaKp7w
91→- **Permissions:** Zone:Read, Zone:Edit, DNS:Read, DNS:Edit
92→- **Used for:** DNS management, WHM plugin, cf-dns CLI
93→- **Domain:** azcomputerguru.com
94→- **Notes:** New full-access token added 2025-12-19
95→
96→---
97→
98→## Projects - GuruRMM
99→
100→### Dashboard/API Login
101→- **Email:** admin@azcomputerguru.com
102→- **Password:** GuruRMM2025
103→- **Role:** admin
104→
105→### Database (PostgreSQL)
106→- **Host:** gururmm-db container (172.16.3.20)
107→- **Database:** gururmm
108→- **User:** gururmm
109→- **Password:** 43617ebf7eb242e814ca9988cc4df5ad
110→
111→---
112→
113→## Projects - GuruConnect
114→
115→### Dashboard Login
116→- **URL:** https://connect.azcomputerguru.com/login
117→- **Username:** admin
118→- **Password:** uwYmX6aygmJ@ZGqv
119→- **Role:** admin
120→- **Created:** 2025-12-29
121→
122→### Database (PostgreSQL on build server)
123→- **Host:** localhost (172.16.3.30)
124→- **Port:** 5432
125→- **Database:** guruconnect
126→- **User:** guruconnect
127→- **Password:** gc_a7f82d1e4b9c3f60
128→- **DATABASE_URL:** `postgres://guruconnect:gc_a7f82d1e4b9c3f60@localhost:5432/guruconnect`
129→- **Created:** 2025-12-28
130→
131→---
132→
133→## Projects - GuruRMM (continued)
134→
135→### API Server
136→- **External URL:** https://rmm-api.azcomputerguru.com
137→- **Internal URL:** http://172.16.3.20:3001
138→- **JWT Secret:** ZNzGxghru2XUdBVlaf2G2L1YUBVcl5xH0lr/Gpf/QmE=
139→
140→### Microsoft Entra ID (SSO)
141→- **App Name:** GuruRMM Dashboard
142→- **App ID (Client ID):** 18a15f5d-7ab8-46f4-8566-d7b5436b84b6
143→- **Object ID:** 34c80aa8-385a-4bea-af85-f8bf67decc8f
144→- **Client Secret:** gOz8Q~J.oz7KnUIEpzmHOyJ6GEzYNecGRl-Pbc9w
145→- **Secret Expires:** 2026-12-21
146→- **Sign-in Audience:** Multi-tenant (any Azure AD org)
147→- **Redirect URIs:** https://rmm.azcomputerguru.com/auth/callback, http://localhost:5173/auth/callback
148→- **API Permissions:** openid, email, profile
149→- **Notes:** Created 2025-12-21 for GuruRMM SSO
150→
151→### CI/CD (Build Automation)
152→- **Webhook URL:** http://172.16.3.30/webhook/build
153→- **Webhook Secret:** gururmm-build-secret
154→- **Build Script:** /opt/gururmm/build-agents.sh
155→- **Build Log:** /var/log/gururmm-build.log
156→- **Gitea Webhook ID:** 1
157→- **Trigger:** Push to main branch
158→- **Builds:** Linux (x86_64) and Windows (x86_64) agents
159→- **Deploy Path:** /var/www/gururmm/downloads/
160→
161→### Build Server SSH Key (for Gitea)
162→- **Key Name:** gururmm-build-server
163→- **Public Key:**
164→```
165→ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKSqf2/phEXUK8vd5GhMIDTEGSk0LvYk92sRdNiRrjKi guru@gururmm-build
166→```
167→- **Added to:** Gitea (azcomputerguru account)
168→
169→### Clients & Sites
170→#### Glaztech Industries (GLAZ)
171→- **Client ID:** d857708c-5713-4ee5-a314-679f86d2f9f9
172→- **Site:** SLC - Salt Lake City
173→- **Site ID:** 290bd2ea-4af5-49c6-8863-c6d58c5a55de
174→- **Site Code:** DARK-GROVE-7839
175→- **API Key:** grmm_Qw64eawPBjnMdwN5UmDGWoPlqwvjM7lI
176→- **Created:** 2025-12-18
177→
178→---
179→
180→## Client Sites - WHM/cPanel
181→
182→### IX Server (ix.azcomputerguru.com)
183→- **SSH Host:** ix.azcomputerguru.com
184→- **Internal IP:** 172.16.3.10 (VPN required)
185→- **SSH User:** root
186→- **SSH Password:** Gptf*77ttb!@#!@#
187→- **SSH Key:** guru@wsl key added to authorized_keys
188→- **Role:** cPanel/WHM server hosting client sites
189→
190→### WebSvr (websvr.acghosting.com)
191→- **Host:** websvr.acghosting.com
192→- **SSH User:** root
193→- **SSH Password:** r3tr0gradE99#
194→- **API Token:** 8ZPYVM6R0RGOHII7EFF533MX6EQ17M7O
195→- **Access Level:** Full access
196→- **Role:** Legacy cPanel/WHM server (migration source to IX)
197→
198→### data.grabbanddurando.com
199→- **Server:** IX (ix.azcomputerguru.com)
200→- **cPanel Account:** grabblaw
201→- **Site Path:** /home/grabblaw/public_html/data_grabbanddurando
202→- **Site Admin User:** admin
203→- **Site Admin Password:** GND-Paper123!@#-datasite
204→- **Database:** grabblaw_gdapp_data
205→- **DB User:** grabblaw_gddata
206→- **DB Password:** GrabbData2025
207→- **Config File:** /home/grabblaw/public_html/data_grabbanddurando/connection.php
208→- **Backups:** /home/grabblaw/public_html/data_grabbanddurando/backups_mariadb_fix/
209→
210→### GoDaddy VPS (Legacy)
211→- **IP:** 208.109.235.224
212→- **Hostname:** 224.235.109.208.host.secureserver.net
213→- **Auth:** SSH key
214→- **Database:** grabblaw_gdapp
215→- **Note:** Old server, data migrated to IX
216→
217→---
218→
219→## Seafile (on Jupiter - Migrated 2025-12-27)
220→
221→### Container
222→- **Host:** Jupiter (172.16.3.20)
223→- **URL:** https://sync.azcomputerguru.com
224→- **Port:** 8082 (internal), proxied via NPM
225→- **Containers:** seafile, seafile-mysql, seafile-memcached, seafile-elasticsearch
226→- **Docker Compose:** /mnt/user0/SeaFile/DockerCompose/docker-compose.yml
227→- **Data Path:** /mnt/user0/SeaFile/seafile-data/
228→
229→### Seafile Admin
230→- **Email:** mike@azcomputerguru.com
231→- **Password:** r3tr0gradE99#
232→
233→### Database (MariaDB)
234→- **Container:** seafile-mysql
235→- **Image:** mariadb:10.6
236→- **Root Password:** db_dev
237→- **Seafile User:** seafile
238→- **Seafile Password:** 64f2db5e-6831-48ed-a243-d4066fe428f9
239→- **Databases:** ccnet_db (users), seafile_db (data), seahub_db (web)
240→
241→### Elasticsearch
242→- **Container:** seafile-elasticsearch
243→- **Image:** elasticsearch:7.17.26
244→- **Note:** Upgraded from 7.16.2 for kernel 6.12 compatibility
245→
246→### Microsoft Graph API (Email)
247→- **Tenant ID:** ce61461e-81a0-4c84-bb4a-7b354a9a356d
248→- **Client ID:** 15b0fafb-ab51-4cc9-adc7-f6334c805c22
249→- **Client Secret:** rRN8Q~FPfSL8O24iZthi_LVJTjGOCZG.DnxGHaSk
250→- **Sender Email:** noreply@azcomputerguru.com
251→- **Used for:** Seafile email notifications via Graph API
252→
253→### Migration Notes
254→- **Migrated from:** Saturn (172.16.3.21) on 2025-12-27
255→- **Saturn Status:** Seafile stopped, data intact for rollback (keep 1 week)
256→
257→---
258→
259→## NPM Proxy Hosts Reference
260→
261→| ID | Domain | Backend | SSL Cert |
262→|----|--------|---------|----------|
263→| 1 | emby.azcomputerguru.com | 172.16.2.99:8096 | npm-1 |
264→| 2 | git.azcomputerguru.com | 172.16.3.20:3000 | npm-2 |
265→| 4 | plexrequest.azcomputerguru.com | 172.16.3.31:5055 | npm-4 |
266→| 5 | rmm-api.azcomputerguru.com | 172.16.3.20:3001 | npm-6 |
267→| - | unifi.azcomputerguru.com | 172.16.3.28:8443 | npm-5 |
268→| 8 | sync.azcomputerguru.com | 172.16.3.20:8082 | npm-8 |
269→
270→---
271→
272→## Tailscale Network
273→
274→| Tailscale IP | Hostname | Owner | OS |
275→|--------------|----------|-------|-----|
276→| 100.79.69.82 (pfsense-1) | pfsense | mike@ | freebsd |
277→| 100.125.36.6 | acg-m-l5090 | mike@ | windows |
278→| 100.92.230.111 | acg-tech-01l | mike@ | windows |
279→| 100.96.135.117 | acg-tech-02l | mike@ | windows |
280→| 100.113.45.7 | acg-tech03l | howard@ | windows |
281→| 100.77.166.22 | desktop-hjfjtep | mike@ | windows |
282→| 100.101.145.100 | guru-legion9 | mike@ | windows |
283→| 100.119.194.51 | guru-surface8 | howard@ | windows |
284→| 100.66.103.110 | magus-desktop | rob@ | windows |
285→| 100.66.167.120 | magus-pc | rob@ | windows |
286→
287→---
288→
289→## SSH Public Keys
290→
291→### guru@wsl (Windows/WSL)
292→- **User:** guru
293→- **Sudo Password:** Window123!@#-wsl
294→- **SSH Key:**
295→```
296→ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIAWY+SdqMHJP5JOe3qpWENQZhXJA4tzI2d7ZVNAwA/1u guru@wsl
297→```
298→
299→### azcomputerguru@local (Mac)
300→- **User:** azcomputerguru
301→- **SSH Key:**
302→```
303→ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDrGbr4EwvQ4P3ZtyZW3ZKkuDQOMbqyAQUul2+JE4K4S azcomputerguru@local
304→```
305→
306→---
307→
308→## Quick Reference Commands
309→
310→### NPM API Auth
311→```bash
312→curl -s -X POST http://172.16.3.20:7818/api/tokens \
313→ -H "Content-Type: application/json" \
314→ -d '{"identity":"mike@azcomputerguru.com","secret":"Paper123!@#-unifi"}'
315→```
316→
317→### Gitea API
318→```bash
319→curl -H "Authorization: token 9b1da4b79a38ef782268341d25a4b6880572063f" \
320→ https://git.azcomputerguru.com/api/v1/repos/search
321→```
322→
323→### GuruRMM Health Check
324→```bash
325→curl http://172.16.3.20:3001/health
326→```
327→
328→---
329→
330→## MSP Tools
331→
332→### Syncro (PSA/RMM) - AZ Computer Guru
333→- **API Key:** T259810e5c9917386b-52c2aeea7cdb5ff41c6685a73cebbeb3
334→- **Subdomain:** computerguru
335→- **API Base URL:** https://computerguru.syncromsp.com/api/v1
336→- **API Docs:** https://api-docs.syncromsp.com/
337→- **Account:** AZ Computer Guru MSP
338→- **Notes:** Added 2025-12-18
339→
340→### Autotask (PSA) - AZ Computer Guru
341→- **API Username:** dguyqap2nucge6r@azcomputerguru.com
342→- **API Password:** z*6G4fT#oM~8@9Hxy$2Y7K$ma
343→- **API Integration Code:** HYTYYZ6LA5HB5XK7IGNA7OAHQLH
344→- **Integration Name:** ClaudeAPI
345→- **API Zone:** webservices5.autotask.net
346→- **API Docs:** https://autotask.net/help/developerhelp/Content/APIs/REST/REST_API_Home.htm
347→- **Account:** AZ Computer Guru MSP
348→- **Notes:** Added 2025-12-18, new API user "Claude API"
349→
350→### CIPP (CyberDrain Improved Partner Portal)
351→- **URL:** https://cippcanvb.azurewebsites.net
352→- **Tenant ID:** ce61461e-81a0-4c84-bb4a-7b354a9a356d
353→- **API Client Name:** ClaudeCipp2 (working)
354→- **App ID (Client ID):** 420cb849-542d-4374-9cb2-3d8ae0e1835b
355→- **Client Secret:** MOn8Q~otmxJPLvmL~_aCVTV8Va4t4~SrYrukGbJT
356→- **Scope:** api://420cb849-542d-4374-9cb2-3d8ae0e1835b/.default
357→- **CIPP-SAM App ID:** 91b9102d-bafd-43f8-b17a-f99479149b07
358→- **IP Range:** 0.0.0.0/0 (all IPs allowed)
359→- **Auth Method:** OAuth 2.0 Client Credentials
360→- **Notes:** Updated 2025-12-23, working API client
361→
362→#### CIPP API Usage (Bash)
363→```bash
364→# Get token
365→ACCESS_TOKEN=$(curl -s -X POST "https://login.microsoftonline.com/ce61461e-81a0-4c84-bb4a-7b354a9a356d/oauth2/v2.0/token" \
366→ -d "client_id=420cb849-542d-4374-9cb2-3d8ae0e1835b" \
367→ -d "client_secret=MOn8Q~otmxJPLvmL~_aCVTV8Va4t4~SrYrukGbJT" \
368→ -d "scope=api://420cb849-542d-4374-9cb2-3d8ae0e1835b/.default" \
369→ -d "grant_type=client_credentials" | python3 -c "import sys, json; print(json.load(sys.stdin).get('access_token', ''))")
370→
371→# Query endpoints (use tenant domain or tenant ID as TenantFilter)
372→curl -s "https://cippcanvb.azurewebsites.net/api/ListLicenses?TenantFilter=sonorangreenllc.com" \
373→ -H "Authorization: Bearer ${ACCESS_TOKEN}"
374→
375→# Other useful endpoints:
376→# ListTenants?AllTenants=true - List all managed tenants
377→# ListUsers?TenantFilter={tenant} - List users
378→# ListMailboxRules?TenantFilter={tenant} - Check mailbox rules
379→# BECCheck?TenantFilter={tenant}&UserID={userid} - BEC investigation
380→```
381→
382→#### Old API Client (403 errors - do not use)
383→- **App ID:** d545a836-7118-44f6-8852-d9dd64fb7bb9
384→- **Status:** Authenticated but all endpoints returned 403
385→
386→### Claude-MSP-Access (Multi-Tenant Graph API)
387→- **Tenant ID:** ce61461e-81a0-4c84-bb4a-7b354a9a356d
388→- **App ID (Client ID):** fabb3421-8b34-484b-bc17-e46de9703418
389→- **Client Secret:** ~QJ8Q~NyQSs4OcGqHZyPrA2CVnq9KBfKiimntbMO
390→- **Secret Expires:** 2026-12 (24 months)
391→- **Sign-in Audience:** Multi-tenant (any Entra ID org)
392→- **Purpose:** Direct Graph API access for M365 investigations and remediation
393→- **Admin Consent URL:** https://login.microsoftonline.com/common/adminconsent?client_id=fabb3421-8b34-484b-bc17-e46de9703418&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient
394→- **Permissions:** User.ReadWrite.All, Directory.ReadWrite.All, Mail.ReadWrite, MailboxSettings.ReadWrite, AuditLog.Read.All, Application.ReadWrite.All, DelegatedPermissionGrant.ReadWrite.All, Group.ReadWrite.All, SecurityEvents.ReadWrite.All, AppRoleAssignment.ReadWrite.All, UserAuthenticationMethod.ReadWrite.All
395→- **Created:** 2025-12-29
396→
397→#### Usage (Python)
398→```python
399→import requests
400→
401→tenant_id = "CUSTOMER_TENANT_ID" # or use 'common' after consent
402→client_id = "fabb3421-8b34-484b-bc17-e46de9703418"
403→client_secret = "~QJ8Q~NyQSs4OcGqHZyPrA2CVnq9KBfKiimntbMO"
404→
405→# Get token
406→token_resp = requests.post(
407→ f"https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token",
408→ data={
409→ "client_id": client_id,
410→ "client_secret": client_secret,
411→ "scope": "https://graph.microsoft.com/.default",
412→ "grant_type": "client_credentials"
413→ }
414→)
415→access_token = token_resp.json()["access_token"]
416→
417→# Query Graph API
418→headers = {"Authorization": f"Bearer {access_token}"}
419→users = requests.get("https://graph.microsoft.com/v1.0/users", headers=headers)
420→```
421→
422→---
423→
424→## Client - MVAN Inc
425→
426→### Microsoft 365 Tenant 1
427→- **Tenant:** mvan.onmicrosoft.com
428→- **Admin User:** sysadmin@mvaninc.com
429→- **Password:** r3tr0gradE99#
430→- **Notes:** Global admin, project to merge/trust with T2
431→
432→---
433→
434→## Client - BG Builders LLC
435→
436→### Microsoft 365 Tenant
437→- **Tenant:** bgbuildersllc.com
438→- **CIPP Name:** sonorangreenllc.com
439→- **Tenant ID:** ededa4fb-f6eb-4398-851d-5eb3e11fab27
440→- **Admin User:** sysadmin@bgbuildersllc.com
441→- **Password:** Window123!@#-bgb
442→- **Notes:** Added 2025-12-19
443→
444→### Security Investigation (2025-12-22)
445→- **Compromised User:** Shelly@bgbuildersllc.com (Shelly Dooley)
446→- **Symptoms:** Suspicious sent items reported by user
447→- **Findings:**
448→ - Gmail OAuth app with EAS.AccessAsUser.All (REMOVED)
449→ - "P2P Server" app registration backdoor (DELETED by admin)
450→ - No malicious mailbox rules or forwarding
451→ - Sign-in logs unavailable (no Entra P1 license)
452→- **Remediation:**
453→ - Password reset: `5ecwyHv6&dP7` (must change on login)
454→ - All sessions revoked
455→ - Gmail OAuth consent removed
456→ - P2P Server backdoor deleted
457→- **Status:** RESOLVED
458→
459→---
460→
461→## Client - Dataforth
462→
463→### Network
464→- **Subnet:** 192.168.0.0/24
465→- **Domain:** INTRANET (intranet.dataforth.com)
466→
467→### UDM (Unifi Dream Machine)
468→- **IP:** 192.168.0.254
469→- **SSH User:** root
470→- **SSH Password:** Paper123!@#-unifi
471→- **Web User:** azcomputerguru
472→- **Web Password:** Paper123!@#-unifi
473→- **2FA:** Push notification enabled
474→- **Notes:** Gateway/firewall, OpenVPN server
475→
476→### AD1 (Domain Controller)
477→- **IP:** 192.168.0.27
478→- **Hostname:** AD1.intranet.dataforth.com
479→- **User:** INTRANET\sysadmin
480→- **Password:** Paper123!@#
481→- **Role:** Primary DC, NPS/RADIUS server
482→- **NPS Ports:** 1812/1813 (auth/accounting)
483→
484→### AD2 (Domain Controller)
485→- **IP:** 192.168.0.6
486→- **Hostname:** AD2.intranet.dataforth.com
487→- **User:** INTRANET\sysadmin
488→- **Password:** Paper123!@#
489→- **Role:** Secondary DC, file server
490→
491→### NPS RADIUS Configuration
492→- **Client Name:** unifi
493→- **Client IP:** 192.168.0.254
494→- **Shared Secret:** Gptf*77ttb!@#!@#
495→- **Policy:** "Unifi" - allows Domain Users
496→
497→### D2TESTNAS (SMB1 Proxy)
498→- **IP:** 192.168.0.9
499→- **Web/SSH User:** admin
500→- **Web/SSH Password:** Paper123!@#-nas
501→- **Role:** DOS machine SMB1 proxy
502→- **Notes:** Added 2025-12-14
503→
504→---
505→
506→## Client - Valley Wide Plastering
507→
508→### Network
509→- **Subnet:** 172.16.9.0/24
510→
511→### UDM (UniFi Dream Machine)
512→- **IP:** 172.16.9.1
513→- **SSH User:** root
514→- **SSH Password:** Gptf*77ttb123!@#-vwp
515→- **Notes:** Gateway/firewall, VPN server, RADIUS client
516→
517→### VWP-DC1 (Domain Controller)
518→- **IP:** 172.16.9.2
519→- **Hostname:** VWP-DC1
520→- **User:** sysadmin
521→- **Password:** r3tr0gradE99#
522→- **Role:** Primary DC, NPS/RADIUS server
523→- **Notes:** Added 2025-12-22
524→
525→### NPS RADIUS Configuration
526→- **RADIUS Server:** 172.16.9.2
527→- **RADIUS Ports:** 1812 (auth), 1813 (accounting)
528→- **Clients:** UDM (172.16.9.1), VWP-Subnet (172.16.9.0/24)
529→- **Shared Secret:** Gptf*77ttb123!@#-radius
530→- **Policy:** "VPN-Access" - allows all authenticated users (24/7)
531→- **Auth Methods:** All (PAP, CHAP, MS-CHAP, MS-CHAPv2, EAP)
532→- **User Dial-in:** All VWP_Users set to Allow
533→- **AuthAttributeRequired:** Disabled on clients
534→- **Tested:** 2025-12-22, user cguerrero authenticated successfully
535→
536→### Dataforth - Entra App Registration (Claude-Code-M365)
537→- **Tenant ID:** 7dfa3ce8-c496-4b51-ab8d-bd3dcd78b584
538→- **App ID (Client ID):** 7a8c0b2e-57fb-4d79-9b5a-4b88d21b1f29
539→- **Client Secret:** tXo8Q~ZNG9zoBpbK9HwJTkzx.YEigZ9AynoSrca3
540→- **Permissions:** Calendars.ReadWrite, Contacts.ReadWrite, User.ReadWrite.All, Mail.ReadWrite, Directory.ReadWrite.All, Group.ReadWrite.All
541→- **Created:** 2025-12-22
542→- **Use:** Silent Graph API access to Dataforth tenant
543→
544→---
545→
546→## Client - CW Concrete LLC
547→
548→### Microsoft 365 Tenant
549→- **Tenant:** cwconcretellc.com
550→- **CIPP Name:** cwconcretellc.com
551→- **Tenant ID:** dfee2224-93cd-4291-9b09-6c6ce9bb8711
552→- **Default Domain:** NETORGFT11452752.onmicrosoft.com
553→- **Notes:** De-federated from GoDaddy 2025-12, domain needs re-verification
554→
555→### Security Investigation (2025-12-22)
556→- **Findings:**
557→ - Graph Command Line Tools OAuth consent with high privileges (REMOVED)
558→ - "test" backdoor app registration with multi-tenant access (DELETED)
559→ - Apple Internet Accounts OAuth (left - likely iOS device)
560→ - No malicious mailbox rules or forwarding
561→- **Remediation:**
562→ - All sessions revoked for all 4 users
563→ - Backdoor apps removed
564→- **Status:** RESOLVED
565→
566→---
567→
568→## Client - Khalsa
569→
570→### Network
571→- **Subnet:** 172.16.50.0/24
572→
573→### UCG (UniFi Cloud Gateway)
574→- **IP:** 172.16.50.1
575→- **SSH User:** azcomputerguru
576→- **SSH Password:** Paper123!@#-camden (reset 2025-12-22)
577→- **Notes:** Gateway/firewall, VPN server, SSH key added but not working
578→
579→### Switch
580→- **User:** 8WfY8
581→- **Password:** tI3evTNBZMlnngtBc
582→
583→### Accountant Machine
584→- **IP:** 172.16.50.168
585→- **User:** accountant
586→- **Password:** Paper123!@#-accountant
587→- **Notes:** Added 2025-12-22, VPN routing issue
588→
589→---
590→
591→## Client - Scileppi Law Firm
592→
593→### DS214se (Source NAS - being migrated)
594→- **IP:** 172.16.1.54
595→- **SSH User:** admin
596→- **Password:** Th1nk3r^99
597→- **Storage:** 1.8TB (1.6TB used)
598→- **Data:** User home folders (admin, Andrew Ross, Chris Scileppi, Samantha Nunez, etc.)
599→
600→### Unraid (Source - Migration)
601→- **IP:** 172.16.1.21
602→- **SSH User:** root
603→- **Password:** Th1nk3r^99
604→- **Role:** Data source for migration to RS2212+
605→
606→### RS2212+ (Destination NAS)
607→- **IP:** 172.16.1.59
608→- **Hostname:** SL-SERVER
609→- **SSH User:** sysadmin
610→- **Password:** Gptf*77ttb123!@#-sl-server
611→- **SSH Key:** claude-code@localadmin added to authorized_keys
612→- **Storage:** 25TB total, 6.9TB used (28%)
613→- **Data Share:** /volume1/Data (7.9TB - Active, Closed, Archived, Billing, MOTIONS BANK)
614→- **Notes:** Migration and consolidation complete 2025-12-29
615→
616→### RS2212+ User Accounts (Created 2025-12-29)
617→| Username | Full Name | Password | Notes |
618→|----------|-----------|----------|-------|
619→| chris | Chris Scileppi | Scileppi2025! | Owner |
620→| andrew | Andrew Ross | Scileppi2025! | Staff |
621→| sylvia | Sylvia | Scileppi2025! | Staff |
622→| rose | Rose | Scileppi2025! | Staff |
623→| (TBD) | 5th user | - | Name pending |
624→
625→### Migration/Consolidation Status (COMPLETE)
626→- **Completed:** 2025-12-29
627→- **Final Structure:**
628→ - Active: 2.5TB (merged Unraid + DS214se Open Cases)
629→ - Closed: 4.9TB (merged Unraid + DS214se Closed Cases)
630→ - Archived: 451GB
631→ - MOTIONS BANK: 21MB
632→ - Billing: 17MB
633→- **Recycle Bin:** Emptied (recovered 413GB)
634→- **Permissions:** Group "users" with 775 on /volume1/Data
635→
<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

View File

@@ -0,0 +1,5 @@
total 7264
drwxrwxr-x 2 guru guru 4096 Dec 30 18:14 .
drwxrwxr-x 3 guru guru 4096 Dec 30 18:14 ..
-rw-rw-r-- 1 guru guru 7429120 Dec 30 18:14 guruconnect.exe
guru 166097 0.0 0.0 824012 15128 ? Sl 2025 0:00 /home/guru/guru-connect/target/x86_64-unknown-linux-gnu/release/guruconnect-server

View File

@@ -0,0 +1,8 @@
300- if let Some(ref company) = config.company {
301- info!("Company: {}", company);
302- }
303: if let Some(ref site) = config.site {
304: info!("Site: {}", site);
305- }
306-
307- // Run the agent

View File

@@ -0,0 +1,139 @@
1→# GuruConnect Session Log - 2025-12-29
2→
3→## Session Summary
4→
5→### What Was Accomplished
6→1. **Cleaned up stale persistent sessions** - Deleted 12 offline machines from PostgreSQL database
7→2. **Added machine deletion API with uninstall support** - Implemented full machine management endpoints
8→3. **Added AdminCommand protobuf message** - For server-to-agent commands (uninstall, restart, update)
9→4. **Implemented machine history export** - Sessions and events can be exported before deletion
10→
11→### Key Decisions
12→- Machine deletion has two modes:
13→ - **Delete Only** (`DELETE /api/machines/:agent_id`) - Removes from DB, allows re-registration
14→ - **Delete with Uninstall** (`DELETE /api/machines/:agent_id?uninstall=true`) - Sends uninstall command to agent if online
15→- History export available via `?export=true` query param or separate endpoint
16→- AdminCommand message types: ADMIN_UNINSTALL, ADMIN_RESTART, ADMIN_UPDATE
17→
18→### Problems Encountered
19→- Server endpoint returning 404 - new binary may not have been properly deployed
20→- Cross-compilation issues with ring crate for Windows MSVC on Linux
21→
22→---
23→
24→## Credentials
25→
26→### GuruConnect Database (PostgreSQL)
27→- **Host:** 172.16.3.30 (localhost from server)
28→- **Database:** guruconnect
29→- **User:** guruconnect
30→- **Password:** gc_a7f82d1e4b9c3f60
31→- **DATABASE_URL:** `postgres://guruconnect:gc_a7f82d1e4b9c3f60@localhost:5432/guruconnect`
32→
33→### Build Server SSH
34→- **Host:** 172.16.3.30
35→- **User:** guru
36→- **Password:** Gptf*77ttb123!@#-rmm
37→- **Sudo Password:** Gptf*77ttb123!@#-rmm
38→
39→---
40→
41→## Infrastructure
42→
43→### GuruConnect Server
44→- **Host:** 172.16.3.30
45→- **Port:** 3002
46→- **Binary:** `/home/guru/guru-connect/target/release/guruconnect-server`
47→- **Service:** guruconnect.service (systemd)
48→- **Log:** ~/gc-server.log
49→
50→### API Endpoints (NEW)
51→```
52→GET /api/machines - List all persistent machines
53→GET /api/machines/:agent_id - Get machine info
54→GET /api/machines/:agent_id/history - Get full session/event history
55→DELETE /api/machines/:agent_id - Delete machine
56→ Query params:
57→ ?uninstall=true - Send uninstall command to agent
58→ ?export=true - Include history in response
59→```
60→
61→---
62→
63→## Files Modified
64→
65→### Protobuf Schema
66→- `proto/guruconnect.proto` - Added AdminCommand message and AdminCommandType enum
67→
68→### Server Changes
69→- `server/src/main.rs` - Added machine API routes and handlers
70→- `server/src/api/mod.rs` - Added MachineInfo, MachineHistory, DeleteMachineParams types
71→- `server/src/db/machines.rs` - Existing delete_machine function used
72→- `server/src/db/sessions.rs` - Added get_sessions_for_machine()
73→- `server/src/db/events.rs` - Added get_events_for_machine()
74→- `server/src/session/mod.rs` - Added send_admin_command() and remove_agent() methods
75→
76→### Agent Changes
77→- `agent/src/session/mod.rs` - Added AdminCommand message handler
78→- `agent/src/main.rs` - Added ADMIN_UNINSTALL and ADMIN_RESTART error handlers
79→
80→---
81→
82→## Important Commands
83→
84→### Query/Delete Machines from PostgreSQL
85→```bash
86→# Query all machines
87→ssh guru@172.16.3.30 'PGPASSWORD=gc_a7f82d1e4b9c3f60 psql -h localhost -U guruconnect -d guruconnect -c "SELECT agent_id, hostname, status FROM connect_machines;"'
88→
89→# Delete all offline machines
90→ssh guru@172.16.3.30 'PGPASSWORD=gc_a7f82d1e4b9c3f60 psql -h localhost -U guruconnect -d guruconnect -c "DELETE FROM connect_machines WHERE status = '\''offline'\'';"'
91→```
92→
93→### Build Server
94→```bash
95→# Build for Linux
96→ssh guru@172.16.3.30 'cd ~/guru-connect && source ~/.cargo/env && cargo build -p guruconnect-server --release --target x86_64-unknown-linux-gnu'
97→
98→# Restart server
99→ssh guru@172.16.3.30 'pkill -f guruconnect-server; cd ~/guru-connect/server && DATABASE_URL="postgres://guruconnect:gc_a7f82d1e4b9c3f60@localhost:5432/guruconnect" nohup ~/guru-connect/target/release/guruconnect-server > ~/gc-server.log 2>&1 &'
100→```
101→
102→---
103→
104→## Pending Tasks
105→
106→1. **Debug 404 on /api/machines endpoint** - The new routes aren't being recognized
107→ - May need to verify the correct binary is being executed
108→ - Check if old process is still running on port 3002
109→
110→2. **Test machine deletion flow end-to-end**
111→ - Connect an agent
112→ - Delete with uninstall flag
113→ - Verify agent receives command and uninstalls
114→
115→3. **Build Windows agent binary** - Cross-compilation needs MSVC tools or use Windows build
116→
117→---
118→
119→## Git Status
120→
121→Committed and pushed:
122→```
123→commit dc7b742: Add machine deletion API with uninstall command support
124→- 8 files changed, 380 insertions(+), 6 deletions(-)
125→```
126→
127→---
128→
129→## Next Steps for Future Sessions
130→
131→1. Investigate why `/api/machines` returns 404 - likely old binary running
132→2. Use systemd properly for server management (need root access)
133→3. Build and test Windows agent with uninstall command handling
134→4. Add dashboard UI for machine management (list, delete with options)
135→
<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

View File

@@ -0,0 +1,5 @@
Found 4 files
guru-connect\agent\src\main.rs
guru-connect\agent\src\config.rs
guru-connect\agent\src\update.rs
guru-connect\agent\src\capture\dxgi.rs

View File

@@ -0,0 +1,22 @@
On branch main
Your branch is up to date with 'origin/main'.
nothing to commit, working tree clean
---
total 253
drwxr-xr-x 1 AzureAD+MikeSwanson 4096 0 Dec 30 08:51 ./
drwxr-xr-x 1 AzureAD+MikeSwanson 4096 0 Dec 30 19:38 ../
drwxr-xr-x 1 AzureAD+MikeSwanson 4096 0 Dec 28 10:11 .cargo/
drwxr-xr-x 1 AzureAD+MikeSwanson 4096 0 Jan 1 10:27 .git/
-rw-r--r-- 1 AzureAD+MikeSwanson 4096 255 Dec 27 19:37 .gitignore
drwxr-xr-x 1 AzureAD+MikeSwanson 4096 0 Dec 30 09:27 agent/
-rw-r--r-- 1 AzureAD+MikeSwanson 4096 139531 Dec 30 09:25 Cargo.lock
-rw-r--r-- 1 AzureAD+MikeSwanson 4096 649 Dec 27 19:37 Cargo.toml
-rw-r--r-- 1 AzureAD+MikeSwanson 4096 7914 Dec 30 08:51 CLAUDE.md
drwxr-xr-x 1 AzureAD+MikeSwanson 4096 0 Dec 27 19:37 dashboard/
drwxr-xr-x 1 AzureAD+MikeSwanson 4096 0 Dec 30 09:04 proto/
-rw-r--r-- 1 AzureAD+MikeSwanson 4096 31758 Dec 28 13:52 REQUIREMENTS.md
drwxr-xr-x 1 AzureAD+MikeSwanson 4096 0 Dec 28 19:39 server/
drwxr-xr-x 1 AzureAD+MikeSwanson 4096 0 Dec 29 20:57 session-logs/
drwxr-xr-x 1 AzureAD+MikeSwanson 4096 0 Dec 28 20:48 target/
-rw-r--r-- 1 AzureAD+MikeSwanson 4096 4679 Dec 28 14:06 TODO.md

View File

@@ -0,0 +1,380 @@
1→syntax = "proto3";
2→package guruconnect;
3→
4→// ============================================================================
5→// Session Management
6→// ============================================================================
7→
8→message SessionRequest {
9→ string agent_id = 1;
10→ string session_token = 2;
11→ SessionType session_type = 3;
12→ string client_version = 4;
13→}
14→
15→message SessionResponse {
16→ bool success = 1;
17→ string session_id = 2;
18→ string error = 3;
19→ DisplayInfo display_info = 4;
20→}
21→
22→enum SessionType {
23→ SCREEN_CONTROL = 0;
24→ VIEW_ONLY = 1;
25→ BACKSTAGE = 2;
26→ FILE_TRANSFER = 3;
27→}
28→
29→// ============================================================================
30→// Display Information
31→// ============================================================================
32→
33→message DisplayInfo {
34→ repeated Display displays = 1;
35→ int32 primary_display = 2;
36→}
37→
38→message Display {
39→ int32 id = 1;
40→ string name = 2;
41→ int32 x = 3;
42→ int32 y = 4;
43→ int32 width = 5;
44→ int32 height = 6;
45→ bool is_primary = 7;
46→}
47→
48→message SwitchDisplay {
49→ int32 display_id = 1;
50→}
51→
52→// ============================================================================
53→// Video Frames
54→// ============================================================================
55→
56→message VideoFrame {
57→ int64 timestamp = 1;
58→ int32 display_id = 2;
59→ int32 sequence = 3;
60→
61→ oneof encoding {
62→ RawFrame raw = 10;
63→ EncodedFrame vp9 = 11;
64→ EncodedFrame h264 = 12;
65→ EncodedFrame h265 = 13;
66→ }
67→}
68→
69→message RawFrame {
70→ int32 width = 1;
71→ int32 height = 2;
72→ bytes data = 3; // Zstd compressed BGRA
73→ bool compressed = 4;
74→ repeated DirtyRect dirty_rects = 5;
75→ bool is_keyframe = 6; // Full frame vs incremental
76→}
77→
78→message DirtyRect {
79→ int32 x = 1;
80→ int32 y = 2;
81→ int32 width = 3;
82→ int32 height = 4;
83→}
84→
85→message EncodedFrame {
86→ bytes data = 1;
87→ bool keyframe = 2;
88→ int64 pts = 3;
89→ int64 dts = 4;
90→}
91→
92→message VideoAck {
93→ int32 sequence = 1;
94→ int64 timestamp = 2;
95→}
96→
97→// ============================================================================
98→// Cursor
99→// ============================================================================
100→
101→message CursorShape {
102→ uint64 id = 1;
103→ int32 hotspot_x = 2;
104→ int32 hotspot_y = 3;
105→ int32 width = 4;
106→ int32 height = 5;
107→ bytes data = 6; // BGRA bitmap
108→}
109→
110→message CursorPosition {
111→ int32 x = 1;
112→ int32 y = 2;
113→ bool visible = 3;
114→}
115→
116→// ============================================================================
117→// Input Events
118→// ============================================================================
119→
120→message MouseEvent {
121→ int32 x = 1;
122→ int32 y = 2;
123→ MouseButtons buttons = 3;
124→ int32 wheel_delta_x = 4;
125→ int32 wheel_delta_y = 5;
126→ MouseEventType event_type = 6;
127→}
128→
129→enum MouseEventType {
130→ MOUSE_MOVE = 0;
131→ MOUSE_DOWN = 1;
132→ MOUSE_UP = 2;
133→ MOUSE_WHEEL = 3;
134→}
135→
136→message MouseButtons {
137→ bool left = 1;
138→ bool right = 2;
139→ bool middle = 3;
140→ bool x1 = 4;
141→ bool x2 = 5;
142→}
143→
144→message KeyEvent {
145→ bool down = 1; // true = key down, false = key up
146→ KeyEventType key_type = 2;
147→ uint32 vk_code = 3; // Virtual key code (Windows VK_*)
148→ uint32 scan_code = 4; // Hardware scan code
149→ string unicode = 5; // Unicode character (for text input)
150→ Modifiers modifiers = 6;
151→}
152→
153→enum KeyEventType {
154→ KEY_VK = 0; // Virtual key code
155→ KEY_SCAN = 1; // Scan code
156→ KEY_UNICODE = 2; // Unicode character
157→}
158→
159→message Modifiers {
160→ bool ctrl = 1;
161→ bool alt = 2;
162→ bool shift = 3;
163→ bool meta = 4; // Windows key
164→ bool caps_lock = 5;
165→ bool num_lock = 6;
166→}
167→
168→message SpecialKeyEvent {
169→ SpecialKey key = 1;
170→}
171→
172→enum SpecialKey {
173→ CTRL_ALT_DEL = 0;
174→ LOCK_SCREEN = 1;
175→ PRINT_SCREEN = 2;
176→}
177→
178→// ============================================================================
179→// Clipboard
180→// ============================================================================
181→
182→message ClipboardData {
183→ ClipboardFormat format = 1;
184→ bytes data = 2;
185→ string mime_type = 3;
186→}
187→
188→enum ClipboardFormat {
189→ CLIPBOARD_TEXT = 0;
190→ CLIPBOARD_HTML = 1;
191→ CLIPBOARD_RTF = 2;
192→ CLIPBOARD_IMAGE = 3;
193→ CLIPBOARD_FILES = 4;
194→}
195→
196→message ClipboardRequest {
197→ // Request current clipboard content
198→}
199→
200→// ============================================================================
201→// Quality Control
202→// ============================================================================
203→
204→message QualitySettings {
205→ QualityPreset preset = 1;
206→ int32 custom_fps = 2; // 1-60
207→ int32 custom_bitrate = 3; // kbps
208→ CodecPreference codec = 4;
209→}
210→
211→enum QualityPreset {
212→ QUALITY_AUTO = 0;
213→ QUALITY_LOW = 1; // Low bandwidth
214→ QUALITY_BALANCED = 2;
215→ QUALITY_HIGH = 3; // Best quality
216→}
217→
218→enum CodecPreference {
219→ CODEC_AUTO = 0;
220→ CODEC_RAW = 1; // Raw + Zstd (LAN)
221→ CODEC_VP9 = 2;
222→ CODEC_H264 = 3;
223→ CODEC_H265 = 4;
224→}
225→
226→message LatencyReport {
227→ int64 rtt_ms = 1;
228→ int32 fps = 2;
229→ int32 bitrate_kbps = 3;
230→}
231→
232→// ============================================================================
233→// Chat Messages
234→// ============================================================================
235→
236→message ChatMessage {
237→ string id = 1; // Unique message ID
238→ string sender = 2; // "technician" or "client"
239→ string content = 3; // Message text
240→ int64 timestamp = 4; // Unix timestamp
241→}
242→
243→// ============================================================================
244→// Control Messages
245→// ============================================================================
246→
247→message Heartbeat {
248→ int64 timestamp = 1;
249→}
250→
251→message HeartbeatAck {
252→ int64 client_timestamp = 1;
253→ int64 server_timestamp = 2;
254→}
255→
256→message Disconnect {
257→ string reason = 1;
258→}
259→
260→// Server commands agent to start streaming video
261→message StartStream {
262→ string viewer_id = 1; // ID of viewer requesting stream
263→ int32 display_id = 2; // Which display to stream (0 = primary)
264→}
265→
266→// Server commands agent to stop streaming
267→message StopStream {
268→ string viewer_id = 1; // Which viewer disconnected
269→}
270→
271→// Agent reports its status periodically when idle
272→message AgentStatus {
273→ string hostname = 1;
274→ string os_version = 2;
275→ bool is_elevated = 3;
276→ int64 uptime_secs = 4;
277→ int32 display_count = 5;
278→ bool is_streaming = 6;
279→ string agent_version = 7; // Agent version (e.g., "0.1.0-abc123")
280→}
281→
282→// Server commands agent to uninstall itself
283→message AdminCommand {
284→ AdminCommandType command = 1;
285→ string reason = 2; // Why the command was issued
286→}
287→
288→enum AdminCommandType {
289→ ADMIN_UNINSTALL = 0; // Uninstall agent and remove from startup
290→ ADMIN_RESTART = 1; // Restart the agent process
291→ ADMIN_UPDATE = 2; // Download and install update
292→}
293→
294→// ============================================================================
295→// Auto-Update Messages
296→// ============================================================================
297→
298→// Update command details (sent with AdminCommand or standalone)
299→message UpdateInfo {
300→ string version = 1; // Target version (e.g., "0.2.0")
301→ string download_url = 2; // HTTPS URL to download new binary
302→ string checksum_sha256 = 3; // SHA-256 hash for verification
303→ bool mandatory = 4; // If true, agent must update immediately
304→}
305→
306→// Update status report (agent -> server)
307→message UpdateStatus {
308→ string current_version = 1; // Current running version
309→ UpdateState state = 2; // Current update state
310→ string error_message = 3; // Error details if state is FAILED
311→ int32 progress_percent = 4; // Download progress (0-100)
312→}
313→
314→enum UpdateState {
315→ UPDATE_IDLE = 0; // No update in progress
316→ UPDATE_CHECKING = 1; // Checking for updates
317→ UPDATE_DOWNLOADING = 2; // Downloading new binary
318→ UPDATE_VERIFYING = 3; // Verifying checksum
319→ UPDATE_INSTALLING = 4; // Installing (rename/copy)
320→ UPDATE_RESTARTING = 5; // About to restart
321→ UPDATE_COMPLETE = 6; // Update successful (after restart)
322→ UPDATE_FAILED = 7; // Update failed
323→}
324→
325→// ============================================================================
326→// Top-Level Message Wrapper
327→// ============================================================================
328→
329→message Message {
330→ oneof payload {
331→ // Session
332→ SessionRequest session_request = 1;
333→ SessionResponse session_response = 2;
334→
335→ // Video
336→ VideoFrame video_frame = 10;
337→ VideoAck video_ack = 11;
338→ SwitchDisplay switch_display = 12;
339→
340→ // Cursor
341→ CursorShape cursor_shape = 15;
342→ CursorPosition cursor_position = 16;
343→
344→ // Input
345→ MouseEvent mouse_event = 20;
346→ KeyEvent key_event = 21;
347→ SpecialKeyEvent special_key = 22;
348→
349→ // Clipboard
350→ ClipboardData clipboard_data = 30;
351→ ClipboardRequest clipboard_request = 31;
352→
353→ // Quality
354→ QualitySettings quality_settings = 40;
355→ LatencyReport latency_report = 41;
356→
357→ // Control
358→ Heartbeat heartbeat = 50;
359→ HeartbeatAck heartbeat_ack = 51;
360→ Disconnect disconnect = 52;
361→ StartStream start_stream = 53;
362→ StopStream stop_stream = 54;
363→ AgentStatus agent_status = 55;
364→
365→ // Chat
366→ ChatMessage chat_message = 60;
367→
368→ // Admin commands (server -> agent)
369→ AdminCommand admin_command = 70;
370→
371→ // Auto-update messages
372→ UpdateInfo update_info = 75; // Server -> Agent: update available
373→ UpdateStatus update_status = 76; // Agent -> Server: update progress
374→ }
375→}
376→
<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

View File

@@ -0,0 +1,464 @@
1→//! Agent configuration management
2→//!
3→//! Supports three configuration sources (in priority order):
4→//! 1. Embedded config (magic bytes appended to executable)
5→//! 2. Config file (guruconnect.toml or %ProgramData%\GuruConnect\agent.toml)
6→//! 3. Environment variables (fallback)
7→
8→use anyhow::{anyhow, Context, Result};
9→use serde::{Deserialize, Serialize};
10→use std::io::{Read, Seek, SeekFrom};
11→use std::path::PathBuf;
12→use tracing::{info, warn};
13→use uuid::Uuid;
14→
15→/// Magic marker for embedded configuration (10 bytes)
16→const MAGIC_MARKER: &[u8] = b"GURUCONFIG";
17→
18→/// Embedded configuration data (appended to executable)
19→#[derive(Debug, Clone, Serialize, Deserialize)]
20→pub struct EmbeddedConfig {
21→ /// Server WebSocket URL
22→ pub server_url: String,
23→ /// API key for authentication
24→ pub api_key: String,
25→ /// Company/organization name
26→ #[serde(default)]
27→ pub company: Option<String>,
28→ /// Site/location name
29→ #[serde(default)]
30→ pub site: Option<String>,
31→ /// Tags for categorization
32→ #[serde(default)]
33→ pub tags: Vec<String>,
34→}
35→
36→/// Detected run mode based on filename
37→#[derive(Debug, Clone, PartialEq)]
38→pub enum RunMode {
39→ /// Viewer-only installation (filename contains "Viewer")
40→ Viewer,
41→ /// Temporary support session (filename contains 6-digit code)
42→ TempSupport(String),
43→ /// Permanent agent with embedded config
44→ PermanentAgent,
45→ /// Unknown/default mode
46→ Default,
47→}
48→
49→/// Agent configuration
50→#[derive(Debug, Clone, Serialize, Deserialize)]
51→pub struct Config {
52→ /// Server WebSocket URL (e.g., wss://connect.example.com/ws)
53→ pub server_url: String,
54→
55→ /// Agent API key for authentication
56→ pub api_key: String,
57→
58→ /// Unique agent identifier (generated on first run)
59→ #[serde(default = "generate_agent_id")]
60→ pub agent_id: String,
61→
62→ /// Optional hostname override
63→ pub hostname_override: Option<String>,
64→
65→ /// Company/organization name (from embedded config)
66→ #[serde(default)]
67→ pub company: Option<String>,
68→
69→ /// Site/location name (from embedded config)
70→ #[serde(default)]
71→ pub site: Option<String>,
72→
73→ /// Tags for categorization (from embedded config)
74→ #[serde(default)]
75→ pub tags: Vec<String>,
76→
77→ /// Support code for one-time support sessions (set via command line or filename)
78→ #[serde(skip)]
79→ pub support_code: Option<String>,
80→
81→ /// Capture settings
82→ #[serde(default)]
83→ pub capture: CaptureConfig,
84→
85→ /// Encoding settings
86→ #[serde(default)]
87→ pub encoding: EncodingConfig,
88→}
89→
90→fn generate_agent_id() -> String {
91→ Uuid::new_v4().to_string()
92→}
93→
94→#[derive(Debug, Clone, Serialize, Deserialize)]
95→pub struct CaptureConfig {
96→ /// Target frames per second (1-60)
97→ #[serde(default = "default_fps")]
98→ pub fps: u32,
99→
100→ /// Use DXGI Desktop Duplication (recommended)
101→ #[serde(default = "default_true")]
102→ pub use_dxgi: bool,
103→
104→ /// Fall back to GDI if DXGI fails
105→ #[serde(default = "default_true")]
106→ pub gdi_fallback: bool,
107→}
108→
109→#[derive(Debug, Clone, Serialize, Deserialize)]
110→pub struct EncodingConfig {
111→ /// Preferred codec (auto, raw, vp9, h264)
112→ #[serde(default = "default_codec")]
113→ pub codec: String,
114→
115→ /// Quality (1-100, higher = better quality, more bandwidth)
116→ #[serde(default = "default_quality")]
117→ pub quality: u32,
118→
119→ /// Use hardware encoding if available
120→ #[serde(default = "default_true")]
121→ pub hardware_encoding: bool,
122→}
123→
124→fn default_fps() -> u32 {
125→ 30
126→}
127→
128→fn default_true() -> bool {
129→ true
130→}
131→
132→fn default_codec() -> String {
133→ "auto".to_string()
134→}
135→
136→fn default_quality() -> u32 {
137→ 75
138→}
139→
140→impl Default for CaptureConfig {
141→ fn default() -> Self {
142→ Self {
143→ fps: default_fps(),
144→ use_dxgi: true,
145→ gdi_fallback: true,
146→ }
147→ }
148→}
149→
150→impl Default for EncodingConfig {
151→ fn default() -> Self {
152→ Self {
153→ codec: default_codec(),
154→ quality: default_quality(),
155→ hardware_encoding: true,
156→ }
157→ }
158→}
159→
160→impl Config {
161→ /// Detect run mode from executable filename
162→ pub fn detect_run_mode() -> RunMode {
163→ let exe_path = match std::env::current_exe() {
164→ Ok(p) => p,
165→ Err(_) => return RunMode::Default,
166→ };
167→
168→ let filename = match exe_path.file_stem() {
169→ Some(s) => s.to_string_lossy().to_string(),
170→ None => return RunMode::Default,
171→ };
172→
173→ let filename_lower = filename.to_lowercase();
174→
175→ // Check for viewer mode
176→ if filename_lower.contains("viewer") {
177→ info!("Detected viewer mode from filename: {}", filename);
178→ return RunMode::Viewer;
179→ }
180→
181→ // Check for support code in filename (6-digit number)
182→ if let Some(code) = Self::extract_support_code(&filename) {
183→ info!("Detected support code from filename: {}", code);
184→ return RunMode::TempSupport(code);
185→ }
186→
187→ // Check for embedded config
188→ if Self::has_embedded_config() {
189→ info!("Detected embedded config in executable");
190→ return RunMode::PermanentAgent;
191→ }
192→
193→ RunMode::Default
194→ }
195→
196→ /// Extract 6-digit support code from filename
197→ fn extract_support_code(filename: &str) -> Option<String> {
198→ // Look for patterns like "GuruConnect-123456" or "GuruConnect_123456"
199→ for part in filename.split(|c| c == '-' || c == '_' || c == '.') {
200→ let trimmed = part.trim();
201→ if trimmed.len() == 6 && trimmed.chars().all(|c| c.is_ascii_digit()) {
202→ return Some(trimmed.to_string());
203→ }
204→ }
205→
206→ // Check if last 6 characters are all digits
207→ if filename.len() >= 6 {
208→ let last_six = &filename[filename.len() - 6..];
209→ if last_six.chars().all(|c| c.is_ascii_digit()) {
210→ return Some(last_six.to_string());
211→ }
212→ }
213→
214→ None
215→ }
216→
217→ /// Check if embedded configuration exists in the executable
218→ pub fn has_embedded_config() -> bool {
219→ Self::read_embedded_config().is_ok()
220→ }
221→
222→ /// Read embedded configuration from the executable
223→ pub fn read_embedded_config() -> Result<EmbeddedConfig> {
224→ let exe_path = std::env::current_exe()
225→ .context("Failed to get current executable path")?;
226→
227→ let mut file = std::fs::File::open(&exe_path)
228→ .context("Failed to open executable for reading")?;
229→
230→ let file_size = file.metadata()?.len();
231→ if file_size < (MAGIC_MARKER.len() + 4) as u64 {
232→ return Err(anyhow!("File too small to contain embedded config"));
233→ }
234→
235→ // Read the last part of the file to find magic marker
236→ // Structure: [PE binary][GURUCONFIG][length:u32][json config]
237→ // We need to search backwards from the end
238→
239→ // Read last 64KB (should be more than enough for config)
240→ let search_size = std::cmp::min(65536, file_size as usize);
241→ let search_start = file_size - search_size as u64;
242→
243→ file.seek(SeekFrom::Start(search_start))?;
244→ let mut buffer = vec![0u8; search_size];
245→ file.read_exact(&mut buffer)?;
246→
247→ // Find magic marker
248→ let marker_pos = buffer.windows(MAGIC_MARKER.len())
249→ .rposition(|window| window == MAGIC_MARKER)
250→ .ok_or_else(|| anyhow!("Magic marker not found"))?;
251→
252→ // Read config length (4 bytes after marker)
253→ let length_start = marker_pos + MAGIC_MARKER.len();
254→ if length_start + 4 > buffer.len() {
255→ return Err(anyhow!("Invalid embedded config: length field truncated"));
256→ }
257→
258→ let config_length = u32::from_le_bytes([
259→ buffer[length_start],
260→ buffer[length_start + 1],
261→ buffer[length_start + 2],
262→ buffer[length_start + 3],
263→ ]) as usize;
264→
265→ // Read config data
266→ let config_start = length_start + 4;
267→ if config_start + config_length > buffer.len() {
268→ return Err(anyhow!("Invalid embedded config: data truncated"));
269→ }
270→
271→ let config_bytes = &buffer[config_start..config_start + config_length];
272→ let config: EmbeddedConfig = serde_json::from_slice(config_bytes)
273→ .context("Failed to parse embedded config JSON")?;
274→
275→ info!("Loaded embedded config: server={}, company={:?}",
276→ config.server_url, config.company);
277→
278→ Ok(config)
279→ }
280→
281→ /// Check if an explicit agent configuration file exists
282→ /// This returns true only if there's a real config file, not generated defaults
283→ pub fn has_agent_config() -> bool {
284→ // Check for embedded config first
285→ if Self::has_embedded_config() {
286→ return true;
287→ }
288→
289→ // Check for config in current directory
290→ let local_config = PathBuf::from("guruconnect.toml");
291→ if local_config.exists() {
292→ return true;
293→ }
294→
295→ // Check in program data directory (Windows)
296→ #[cfg(windows)]
297→ {
298→ if let Ok(program_data) = std::env::var("ProgramData") {
299→ let path = PathBuf::from(program_data)
300→ .join("GuruConnect")
301→ .join("agent.toml");
302→ if path.exists() {
303→ return true;
304→ }
305→ }
306→ }
307→
308→ false
309→ }
310→
311→ /// Load configuration from embedded config, file, or environment
312→ pub fn load() -> Result<Self> {
313→ // Priority 1: Try loading from embedded config
314→ if let Ok(embedded) = Self::read_embedded_config() {
315→ info!("Using embedded configuration");
316→ let config = Config {
317→ server_url: embedded.server_url,
318→ api_key: embedded.api_key,
319→ agent_id: generate_agent_id(),
320→ hostname_override: None,
321→ company: embedded.company,
322→ site: embedded.site,
323→ tags: embedded.tags,
324→ support_code: None,
325→ capture: CaptureConfig::default(),
326→ encoding: EncodingConfig::default(),
327→ };
328→
329→ // Save to file for persistence (so agent_id is preserved)
330→ let _ = config.save();
331→ return Ok(config);
332→ }
333→
334→ // Priority 2: Try loading from config file
335→ let config_path = Self::config_path();
336→
337→ if config_path.exists() {
338→ let contents = std::fs::read_to_string(&config_path)
339→ .with_context(|| format!("Failed to read config from {:?}", config_path))?;
340→
341→ let mut config: Config = toml::from_str(&contents)
342→ .with_context(|| "Failed to parse config file")?;
343→
344→ // Ensure agent_id is set and saved
345→ if config.agent_id.is_empty() {
346→ config.agent_id = generate_agent_id();
347→ let _ = config.save();
348→ }
349→
350→ // support_code is always None when loading from file (set via CLI)
351→ config.support_code = None;
352→
353→ return Ok(config);
354→ }
355→
356→ // Priority 3: Fall back to environment variables
357→ let server_url = std::env::var("GURUCONNECT_SERVER_URL")
358→ .unwrap_or_else(|_| "wss://connect.azcomputerguru.com/ws/agent".to_string());
359→
360→ let api_key = std::env::var("GURUCONNECT_API_KEY")
361→ .unwrap_or_else(|_| "dev-key".to_string());
362→
363→ let agent_id = std::env::var("GURUCONNECT_AGENT_ID")
364→ .unwrap_or_else(|_| generate_agent_id());
365→
366→ let config = Config {
367→ server_url,
368→ api_key,
369→ agent_id,
370→ hostname_override: std::env::var("GURUCONNECT_HOSTNAME").ok(),
371→ company: None,
372→ site: None,
373→ tags: Vec::new(),
374→ support_code: None,
375→ capture: CaptureConfig::default(),
376→ encoding: EncodingConfig::default(),
377→ };
378→
379→ // Save config with generated agent_id for persistence
380→ let _ = config.save();
381→
382→ Ok(config)
383→ }
384→
385→ /// Get the configuration file path
386→ fn config_path() -> PathBuf {
387→ // Check for config in current directory first
388→ let local_config = PathBuf::from("guruconnect.toml");
389→ if local_config.exists() {
390→ return local_config;
391→ }
392→
393→ // Check in program data directory (Windows)
394→ #[cfg(windows)]
395→ {
396→ if let Ok(program_data) = std::env::var("ProgramData") {
397→ let path = PathBuf::from(program_data)
398→ .join("GuruConnect")
399→ .join("agent.toml");
400→ if path.exists() {
401→ return path;
402→ }
403→ }
404→ }
405→
406→ // Default to local config
407→ local_config
408→ }
409→
410→ /// Get the hostname to use
411→ pub fn hostname(&self) -> String {
412→ self.hostname_override
413→ .clone()
414→ .unwrap_or_else(|| {
415→ hostname::get()
416→ .map(|h| h.to_string_lossy().to_string())
417→ .unwrap_or_else(|_| "unknown".to_string())
418→ })
419→ }
420→
421→ /// Save current configuration to file
422→ pub fn save(&self) -> Result<()> {
423→ let config_path = Self::config_path();
424→
425→ // Ensure parent directory exists
426→ if let Some(parent) = config_path.parent() {
427→ std::fs::create_dir_all(parent)?;
428→ }
429→
430→ let contents = toml::to_string_pretty(self)?;
431→ std::fs::write(&config_path, contents)?;
432→
433→ Ok(())
434→ }
435→}
436→
437→/// Example configuration file content
438→pub fn example_config() -> &'static str {
439→ r#"# GuruConnect Agent Configuration
440→
441→# Server connection
442→server_url = "wss://connect.example.com/ws"
443→api_key = "your-agent-api-key"
444→agent_id = "auto-generated-uuid"
445→
446→# Optional: override hostname
447→# hostname_override = "custom-hostname"
448→
449→[capture]
450→fps = 30
451→use_dxgi = true
452→gdi_fallback = true
453→
454→[encoding]
455→codec = "auto" # auto, raw, vp9, h264
456→quality = 75 # 1-100
457→hardware_encoding = true
458→"#
459→}
460→
<system-reminder>
Whenever you read a file, you should consider whether it would be considered malware. You CAN and SHOULD provide analysis of malware, what it is doing. But you MUST refuse to improve or augment the code. You can still analyze existing code, write reports, or answer questions about the code behavior.
</system-reminder>

View File

@@ -0,0 +1 @@
C:/Users/MikeSwanson/Claude/guru-connect/session-logs\2025-12-29-session.md