M1/F1: Kimi Code OAuth device-code flow
Replace the xAI OAuth stack with the Kimi device authorization grant:
- kimi_oauth.rs wire layer (device_authorization + token poll + refresh
against kigi_env::oauth_host(); client_id per PRD; retryable statuses
429/5xx with backoff; expired_token restarts authorization)
- X-Msh-Device-{Name,Model,Id} headers; device_id minted uuid4-hex at
~/.kigi/device_id (0600)
- Storage: system keyring service `kigi`, entry `oauth/kimi-code`
(macOS/Windows native backends), atomic-file fallback under ~/.kigi;
official client's keyring/~/.kimi never touched
- Refresh manager: 60s tick, threshold max(300, expires_in*0.5),
401-tombstone keyed by rejected refresh token with 300s cooldown and
rotation auto-clear, cross-process lock with sibling-adoption
triple-check, sleep/wake forced refresh
- Deleted xAI machinery: enterprise OIDC (PKCE/JWKS/teams), devbox login,
external auth provider, JWT tier gating + subscription paywall stack,
X-XAI-Token-Auth marker headers, ZDR gates, /user enrichment
- kigi login / TUI /login both drive the device flow; login-host display
now derives from kigi_env::oauth_host()
- 264 auth unit/wiremock tests; live contract probe of
auth.kimi.com/api/oauth/device_authorization matches the wire shapes
Gates: check/clippy --all-targets clean, fmt, deny ok, kigi-shell lib
5131 tests green.
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Access gate from `grok_build_access_gate`.
|
||||
/// Access-gate copy resolved from remote settings (message + optional CTA).
|
||||
/// Auth no longer produces gates (tier gating was an xAI concept); the pager
|
||||
/// still renders one when remote settings carry a gate message.
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct GateInfo {
|
||||
pub message: String,
|
||||
@@ -17,24 +19,6 @@ pub struct AuthMeta {
|
||||
pub email: Option<String>,
|
||||
#[serde(default)]
|
||||
pub auth_mode: Option<String>,
|
||||
/// Team principal UUID when the session is a team login (`None` for personal).
|
||||
#[serde(default)]
|
||||
pub team_id: Option<String>,
|
||||
#[serde(default)]
|
||||
pub team_name: Option<String>,
|
||||
#[serde(default)]
|
||||
pub is_zdr: bool,
|
||||
#[serde(default)]
|
||||
pub team_role: Option<String>,
|
||||
#[serde(default)]
|
||||
pub coding_data_retention_opt_out: bool,
|
||||
#[serde(default)]
|
||||
pub show_resolved_model: Option<bool>,
|
||||
/// `Some` = user is blocked; `None` = user has access.
|
||||
#[serde(default)]
|
||||
pub gate: Option<GateInfo>,
|
||||
/// User-friendly display name for the current subscription tier
|
||||
/// (e.g. "SuperGrok Heavy", "X Premium", "Free"). From CCP `/settings`.
|
||||
#[serde(default)]
|
||||
pub subscription_tier: Option<String>,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user