{"record":{"id":"7060388665ebea9c","repo":"jlcodes99/cockpit-tools","slug":"auth-url","errorCode":null,"errorMessage":"无效的 Auth URL","messagePattern":"无效的 Auth URL","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/cockpit-core/src/modules/oauth.rs","lineNumber":101,"sourceCode":"        \"https://www.googleapis.com/auth/cclog\",\n        \"https://www.googleapis.com/auth/experimentsandconfigs\",\n    ]\n    .join(\" \");\n\n    let mut params = vec![\n        (\"client_id\", client_id),\n        (\"redirect_uri\", redirect_uri),\n        (\"response_type\", \"code\"),\n        (\"scope\", &scopes),\n        (\"access_type\", \"offline\"),\n        (\"prompt\", \"consent\"),\n    ];\n\n    if let Some(state) = state.filter(|value| !value.trim().is_empty()) {\n        params.push((\"state\", state));\n    }\n\n    let url = url::Url::parse_with_params(AUTH_URL, &params).expect(\"无效的 Auth URL\");\n    url.to_string()\n}\n\n/// 使用 Authorization Code 交换 Token\npub async fn exchange_code(code: &str, redirect_uri: &str) -> Result<TokenResponse, String> {\n    crate::modules::logger::log_info(&format!(\"开始 Token 交换, redirect_uri: {}\", redirect_uri));\n    let client = crate::utils::http::create_client(15);\n    let (client_id, client_secret, client_key) = oauth_client_config(None)?;\n\n    let params = [\n        (\"client_id\", client_id),\n        (\"client_secret\", client_secret),\n        (\"code\", code),\n        (\"redirect_uri\", redirect_uri),\n        (\"grant_type\", \"authorization_code\"),\n    ];\n\n    let response = client","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/jlcodes99/cockpit-tools/blob/1ed8b77992d62ca81fabf744deb0839ad361d5bf/crates/cockpit-core/src/modules/oauth.rs#L83-L119","documentation":"At the end of get_auth_url (crates/cockpit-core/src/modules/oauth.rs:101) the code parses the hardcoded constant AUTH_URL with url::Url::parse_with_params(...).expect(\"无效的 Auth URL\"). This panics only if the compile-time constant AUTH_URL is not a valid absolute URL. With the shipped Google OAuth endpoint constant this can never fail; the expect is a static-configuration assertion.","triggerScenarios":"Panics only when the AUTH_URL constant is edited/typoed to an invalid URL (e.g. missing scheme, illegal characters) or the query parameters contain characters that break URL encoding — none of which occur with the bundled constant.","commonSituations":"A developer forks the app and points AUTH_URL at a self-hosted or alternate endpoint and mistypes it (missing https://, stray whitespace, invalid IDN), then the panic fires on the first login attempt.","solutions":["Fix the AUTH_URL constant to a valid absolute URL including scheme (e.g. \"https://accounts.google.com/o/oauth2/v2/auth\").","Trim and sanitize the constant; verify state/parameter values contain no raw control characters.","Refactor to return Result<String, String> and map the parse error instead of .expect so misconfiguration surfaces as a normal error."],"exampleFix":"// before\nlet url = url::Url::parse_with_params(AUTH_URL, &params).expect(\"无效的 Auth URL\");\n// after\nlet url = url::Url::parse_with_params(AUTH_URL, &params)\n    .map_err(|e| format!(\"无效的 Auth URL: {e}\"))?;","handlingStrategy":"validation","validationCode":"// Validate AUTH_URL statically before use:\nlet parsed = url::Url::parse(AUTH_URL);\nassert!(parsed.is_ok(), \"AUTH_URL must be a valid absolute URL: {:?}\", parsed.err());","typeGuard":"fn is_valid_url(s: &str) -> bool { url::Url::parse(s).map(|u| u.scheme().starts_with(\"http\")).unwrap_or(false) }","tryCatchPattern":"let url = url::Url::parse_with_params(AUTH_URL, &params)\n    .map_err(|e| format!(\"无效的 Auth URL: {e}\"))?;","preventionTips":["Keep AUTH_URL as a compile-time constant and add a unit test parsing it at build/test time.","Always include the scheme (https://) when changing the endpoint.","Avoid hand-editing URL constants without running the test suite."],"tags":["rust","oauth","url-parsing","panic"],"backgroundTag":"invalid-url-parse","analyzedSha":"1ed8b77992d62ca81fabf744deb0839ad361d5bf","analyzedAt":"2026-09-05T09:51:41.178Z","contentChangedAt":"2026-09-05T09:51:41.178Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}