1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2025-12-11 07:52:50 -05:00

rename backend to core

This commit is contained in:
bbedward
2025-11-12 23:12:31 -05:00
parent 0fdc0748cf
commit db584b7897
280 changed files with 265 additions and 265 deletions

View File

@@ -0,0 +1,552 @@
# NetworkManager API Documentation
## Overview
The network manager API provides methods for managing WiFi connections, monitoring network state, and handling credential prompts through NetworkManager. Communication occurs over a message-based protocol (websocket, IPC, etc.) with event subscriptions for state updates.
## API Methods
### network.wifi.connect
Initiate a WiFi connection.
**Request:**
```json
{
"method": "network.wifi.connect",
"params": {
"ssid": "NetworkName",
"password": "optional-password",
"interactive": true
}
}
```
**Parameters:**
- `ssid` (string, required): Network SSID
- `password` (string, optional): Pre-shared key for WPA/WPA2/WPA3 networks
- `interactive` (boolean, optional): Enable credential prompting if authentication fails or password is missing. Automatically set to `true` when connecting to secured networks without providing a password.
**Response:**
```json
{
"success": true,
"message": "connecting"
}
```
**Behavior:**
- Returns immediately; connection happens asynchronously
- State updates delivered via `network` service subscription
- Credential prompts delivered via `network.credentials` service subscription
### network.credentials.submit
Submit credentials in response to a prompt.
**Request:**
```json
{
"method": "network.credentials.submit",
"params": {
"token": "correlation-token",
"secrets": {
"psk": "password"
},
"save": true
}
}
```
**Parameters:**
- `token` (string, required): Token from credential prompt
- `secrets` (object, required): Key-value map of credential fields
- `save` (boolean, optional): Whether to persist credentials (default: false)
**Common secret fields:**
- `psk`: Pre-shared key for WPA2/WPA3 personal networks
- `identity`: Username for 802.1X enterprise networks
- `password`: Password for 802.1X enterprise networks
### network.credentials.cancel
Cancel a credential prompt.
**Request:**
```json
{
"method": "network.credentials.cancel",
"params": {
"token": "correlation-token"
}
}
```
## Event Subscriptions
### Subscribing to Events
Subscribe to receive network state updates and credential prompts:
```json
{
"method": "subscribe",
"params": {
"services": ["network", "network.credentials"]
}
}
```
Both services are required for full connection handling. Missing `network.credentials` means credential prompts won't be received.
### network Service Events
State updates are sent whenever network configuration changes:
```json
{
"service": "network",
"data": {
"networkStatus": "wifi",
"isConnecting": false,
"connectingSSID": "",
"wifiConnected": true,
"wifiSSID": "MyNetwork",
"wifiIP": "192.168.1.100",
"lastError": ""
}
}
```
**State fields:**
- `networkStatus`: Current connection type (`wifi`, `ethernet`, `disconnected`)
- `isConnecting`: Whether a connection attempt is in progress
- `connectingSSID`: SSID being connected to (empty when idle)
- `wifiConnected`: Whether associated with an access point
- `wifiSSID`: Currently connected network name
- `wifiIP`: Assigned IP address (empty until DHCP completes)
- `lastError`: Error message from last failed connection attempt
### network.credentials Service Events
Credential prompts are sent when authentication is required:
```json
{
"service": "network.credentials",
"data": {
"token": "unique-prompt-id",
"ssid": "NetworkName",
"setting": "802-11-wireless-security",
"fields": ["psk"],
"hints": ["wpa3", "sae"],
"reason": "Credentials required"
}
}
```
**Prompt fields:**
- `token`: Unique identifier for this prompt (use in submit/cancel)
- `ssid`: Network requesting credentials
- `setting`: Authentication type (`802-11-wireless-security` for personal WiFi, `802-1x` for enterprise)
- `fields`: Array of required credential field names
- `hints`: Additional context about the network type
- `reason`: Human-readable explanation (e.g., "Previous password was incorrect")
## Connection Flow
### Typical Timeline
```
T+0ms Call network.wifi.connect
T+10ms Receive {"success": true, "message": "connecting"}
T+100ms State update: isConnecting=true, connectingSSID="Network"
T+500ms Credential prompt (if needed)
T+1000ms Submit credentials
T+3000ms State update: wifiConnected=true, wifiIP="192.168.x.x"
```
### State Machine
```
IDLE
|
| network.wifi.connect
v
CONNECTING (isConnecting=true, connectingSSID set)
|
+-- Needs credentials
| |
| v
| PROMPTING (credential prompt event)
| |
| | network.credentials.submit
| v
| back to CONNECTING
|
+-- Success
| |
| v
| CONNECTED (wifiConnected=true, wifiIP set, isConnecting=false)
|
+-- Failure
|
v
ERROR (isConnecting=false, !wifiConnected, lastError set)
```
## Connection Success Detection
A connection is successful when all of the following are true:
1. `wifiConnected` is `true`
2. `wifiIP` is set and non-empty
3. `wifiSSID` matches the target network
4. `isConnecting` is `false`
Do not rely on `wifiConnected` alone - the device may be associated with an access point but not have an IP address yet.
**Example:**
```javascript
function isConnectionComplete(state, targetSSID) {
return state.wifiConnected &&
state.wifiIP &&
state.wifiIP !== "" &&
state.wifiSSID === targetSSID &&
!state.isConnecting;
}
```
## Error Handling
### Error Detection
Errors occur when a connection attempt stops without success:
```javascript
function checkForFailure(state, wasConnecting, targetSSID) {
// Was connecting, now idle, but not connected
if (wasConnecting &&
!state.isConnecting &&
state.connectingSSID === "" &&
!state.wifiConnected) {
return state.lastError || "Connection failed";
}
return null;
}
```
### Common Error Scenarios
#### Wrong Password
**Detection methods:**
1. Quick failure (< 3 seconds from start)
2. `lastError` contains "password", "auth", or "secrets"
3. Second credential prompt with `reason: "Previous password was incorrect"`
**Handling:**
```javascript
if (prompt.reason === "Previous password was incorrect") {
// Show error, clear password field, re-focus input
}
```
#### Network Out of Range
**Detection:**
- `lastError` contains "not-found" or "connection-attempt-failed"
#### Connection Timeout
**Detection:**
- `isConnecting` remains true for > 30 seconds
**Implementation:**
```javascript
let timeout = setTimeout(() => {
if (currentState.isConnecting) {
handleTimeout();
}
}, 30000);
```
#### DHCP Failure
**Detection:**
- `wifiConnected` is true
- `wifiIP` is empty after 15+ seconds
### Error Message Translation
Map technical errors to user-friendly messages:
| lastError value | Meaning | User message |
|----------------|---------|--------------|
| `secrets-required` | Password needed | "Please enter password" |
| `authentication-failed` | Wrong password | "Incorrect password" |
| `connection-removed` | Profile deleted | "Network configuration removed" |
| `connection-attempt-failed` | Generic failure | "Failed to connect" |
| `network-not-found` | Out of range | "Network not found" |
| `(timeout)` | Timeout | "Connection timed out" |
## Credential Handling
### Secret Agent Architecture
The credential system uses a broker pattern:
```
NetworkManager -> SecretAgent -> PromptBroker -> UI -> User
^
|
User Response
|
NetworkManager <- SecretAgent <- PromptBroker <- UI
```
### Implementing a Broker
```go
type CustomBroker struct {
ui UIInterface
pending map[string]chan network.PromptReply
}
func (b *CustomBroker) Ask(ctx context.Context, req network.PromptRequest) (string, error) {
token := generateToken()
b.pending[token] = make(chan network.PromptReply, 1)
// Send to UI
b.ui.ShowCredentialPrompt(token, req)
return token, nil
}
func (b *CustomBroker) Wait(ctx context.Context, token string) (network.PromptReply, error) {
select {
case <-ctx.Done():
return network.PromptReply{}, errors.New("timeout")
case reply := <-b.pending[token]:
return reply, nil
}
}
func (b *CustomBroker) Resolve(token string, reply network.PromptReply) error {
if ch, ok := b.pending[token]; ok {
ch <- reply
close(ch)
delete(b.pending, token)
}
return nil
}
```
### Credential Field Types
**Personal WiFi (802-11-wireless-security):**
- Fields: `["psk"]`
- UI: Single password input
**Enterprise WiFi (802-1x):**
- Fields: `["identity", "password"]`
- UI: Username and password inputs
### Building Secrets Object
```javascript
function buildSecrets(setting, fields, formData) {
let secrets = {};
if (setting === "802-11-wireless-security") {
secrets.psk = formData.password;
} else if (setting === "802-1x") {
secrets.identity = formData.username;
secrets.password = formData.password;
}
return secrets;
}
```
## Best Practices
### Track Target Network
Always store which network you're connecting to:
```javascript
let targetSSID = null;
function connect(ssid) {
targetSSID = ssid;
// send request
}
function onStateUpdate(state) {
if (!targetSSID) return;
if (state.wifiSSID === targetSSID && state.wifiConnected && state.wifiIP) {
// Success for the network we care about
targetSSID = null;
}
}
```
### Implement Timeouts
Never wait indefinitely for a connection:
```javascript
const CONNECTION_TIMEOUT = 30000; // 30 seconds
const DHCP_TIMEOUT = 15000; // 15 seconds
let timer = setTimeout(() => {
if (stillConnecting) {
handleTimeout();
}
}, CONNECTION_TIMEOUT);
```
### Handle Credential Re-prompts
Wrong passwords trigger a second prompt:
```javascript
function onCredentialPrompt(prompt) {
if (prompt.reason.includes("incorrect")) {
// Show error, but keep dialog open
showError("Wrong password");
clearPasswordField();
} else {
// First time prompt
showDialog(prompt);
}
}
```
### Clean Up State
Reset tracking variables on success, failure, or cancellation:
```javascript
function cleanup() {
clearTimeout(timer);
targetSSID = null;
closeDialogs();
}
```
### Subscribe to Both Services
Missing `network.credentials` means prompts won't arrive:
```javascript
// Correct
services: ["network", "network.credentials"]
// Wrong - will miss credential prompts
services: ["network"]
```
## Testing
### Connection Test Checklist
- [ ] Connect to open network
- [ ] Connect to WPA2 network with password provided
- [ ] Connect to WPA2 network without password (triggers prompt)
- [ ] Enter wrong password (verify error and re-prompt)
- [ ] Cancel credential prompt
- [ ] Connection timeout after 30 seconds
- [ ] DHCP timeout detection
- [ ] Network out of range
- [ ] Reconnect to already-configured network
### Verifying Secret Agent Setup
Check connection profile flags:
```bash
nmcli connection show "NetworkName" | grep flags
# Should show: 802-11-wireless-security.psk-flags: 1 (agent-owned)
```
Check agent registration in logs:
```
INFO: Registered with NetworkManager as secret agent
```
## Security
- Never log credential values (passwords, PSKs)
- Clear password fields when dialogs close
- Implement prompt timeouts (default: 2 minutes)
- Validate user input before submission
- Use secure channels for credential transmission
## Troubleshooting
### Credential prompt doesn't appear
**Check:**
- Subscribed to both `network` and `network.credentials`
- Connection has `interactive: true`
- Secret flags set to AGENT_OWNED (value: 1)
- Broker registered successfully
### Connection succeeds without prompting
**Cause:** NetworkManager found saved credentials
**Solution:** Delete existing connection first, or use different credentials
### State updates seem delayed
**Expected behavior:** State changes occur in rapid succession during connection
**Solution:** Debounce UI updates; only act on final state
### Multiple rapid credential prompts
**Cause:** Connection profile has incorrect flags or conflicting agents
**Solution:**
- Check only one agent is running
- Verify psk-flags value
- Check NetworkManager logs for agent conflicts
## Data Structures Reference
### PromptRequest
```go
type PromptRequest struct {
SSID string `json:"ssid"`
SettingName string `json:"setting"`
Fields []string `json:"fields"`
Hints []string `json:"hints"`
Reason string `json:"reason"`
}
```
### PromptReply
```go
type PromptReply struct {
Secrets map[string]string `json:"secrets"`
Save bool `json:"save"`
Cancel bool `json:"cancel"`
}
```
### NetworkState
```go
type NetworkState struct {
NetworkStatus string `json:"networkStatus"`
IsConnecting bool `json:"isConnecting"`
ConnectingSSID string `json:"connectingSSID"`
WifiConnected bool `json:"wifiConnected"`
WifiSSID string `json:"wifiSSID"`
WifiIP string `json:"wifiIP"`
LastError string `json:"lastError"`
}
```