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:
@@ -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>
|
||||
@@ -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
|
||||
@@ -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()
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
|
||||
@@ -0,0 +1 @@
|
||||
No matches found
|
||||
@@ -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
|
||||
@@ -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>
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -0,0 +1 @@
|
||||
C:/Users/MikeSwanson/Claude/guru-connect/session-logs\2025-12-29-session.md
|
||||
@@ -0,0 +1 @@
|
||||
ALTER TABLE
|
||||
Reference in New Issue
Block a user