fix(macos): support password auth mode for gateway connections

GatewayChannel now sends both 'token' and 'password' fields in the auth
payload to support both authentication modes. Gateway checks the field
matching its auth.mode configuration ('token' or 'password').

Also adds config file password fallback for remote mode, allowing
gateway password to be configured in ~/.clawdis/clawdis.json without
requiring environment variables.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
jeffersonwarrior
2026-01-01 21:26:37 -06:00
parent 35582cfe8a
commit 9387ecf043
4 changed files with 25 additions and 4 deletions

View File

@@ -97,4 +97,13 @@ enum ClawdisConfigFile {
self.logger.debug("agent workspace updated set=\(!trimmed.isEmpty)")
}
static func gatewayPassword() -> String? {
let root = self.loadDict()
guard let gateway = root["gateway"] as? [String: Any],
let remote = gateway["remote"] as? [String: Any] else {
return nil
}
return remote["password"] as? String
}
}

View File

@@ -213,7 +213,13 @@ actor GatewayChannelActor {
"userAgent": ProtoAnyCodable(ProcessInfo.processInfo.operatingSystemVersionString),
]
if let token = self.token {
params["auth"] = ProtoAnyCodable(["token": ProtoAnyCodable(token)])
// Send both 'token' and 'password' to support both auth modes.
// Gateway checks the field matching its auth.mode configuration.
let authDict: [String: ProtoAnyCodable] = [
"token": ProtoAnyCodable(token),
"password": ProtoAnyCodable(token),
]
params["auth"] = ProtoAnyCodable(authDict)
}
let frame = RequestFrame(

View File

@@ -23,7 +23,13 @@ actor GatewayEndpointStore {
static let live = Deps(
mode: { await MainActor.run { AppStateStore.shared.connectionMode } },
token: { ProcessInfo.processInfo.environment["CLAWDIS_GATEWAY_TOKEN"] },
token: {
// First check env var, fallback to config file
if let envToken = ProcessInfo.processInfo.environment["CLAWDIS_GATEWAY_TOKEN"], !envToken.isEmpty {
return envToken
}
return ClawdisConfigFile.gatewayPassword()
},
localPort: { GatewayEnvironment.gatewayPort() },
remotePortIfRunning: { await RemoteTunnelManager.shared.controlTunnelPortIfRunning() },
ensureRemoteTunnel: { try await RemoteTunnelManager.shared.ensureControlTunnel() })

View File

@@ -18,7 +18,7 @@ export type HookMappingResolved = {
messageTemplate?: string;
textTemplate?: string;
deliver?: boolean;
channel?: "last" | "whatsapp" | "telegram" | "discord";
channel?: "last" | "whatsapp" | "telegram" | "discord" | "signal" | "imessage";
to?: string;
thinking?: string;
timeoutSeconds?: number;
@@ -50,7 +50,7 @@ export type HookAction =
wakeMode: "now" | "next-heartbeat";
sessionKey?: string;
deliver?: boolean;
channel?: "last" | "whatsapp" | "telegram" | "discord";
channel?: "last" | "whatsapp" | "telegram" | "discord" | "signal" | "imessage";
to?: string;
thinking?: string;
timeoutSeconds?: number;