buildSecurityPolicyError extracts challenge_url and the hint from a Lark API response's data block, so the typed SecurityPolicyError carries the same browser-challenge information that internal/auth/transport.go surfaces at the HTTP layer. Data shapes accepted (whichever the upstream sends): {"co
(p errs.Problem, resp map[string]any)
| 179 | // Hint is read from `data.hint` first and falls back to `data.cli_hint` so |
| 180 | // either spelling surfaces, matching the transport layer. |
| 181 | func buildSecurityPolicyError(p errs.Problem, resp map[string]any) *errs.SecurityPolicyError { |
| 182 | dataMap, _ := resp["data"].(map[string]any) |
| 183 | if dataMap == nil { |
| 184 | if errBlock, ok := resp["error"].(map[string]any); ok { |
| 185 | dataMap, _ = errBlock["data"].(map[string]any) |
| 186 | } |
| 187 | } |
| 188 | if dataMap == nil { |
| 189 | return &errs.SecurityPolicyError{Problem: p} |
| 190 | } |
| 191 | |
| 192 | challengeURL := strings.Trim(stringFromAny(dataMap["challenge_url"]), " `") |
| 193 | if challengeURL != "" && !isHTTPSURL(challengeURL) { |
| 194 | challengeURL = "" |
| 195 | } |
| 196 | |
| 197 | hint := stringFromAny(dataMap["hint"]) |
| 198 | if hint == "" { |
| 199 | hint = stringFromAny(dataMap["cli_hint"]) |
| 200 | } |
| 201 | if hint != "" { |
| 202 | p.Hint = hint |
| 203 | } |
| 204 | |
| 205 | return &errs.SecurityPolicyError{ |
| 206 | Problem: p, |
| 207 | ChallengeURL: challengeURL, |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | // isHTTPSURL is the local-to-errclass duplicate of internal/auth/transport.go's |
| 212 | // isValidChallengeURL. Kept local to avoid coupling errclass to internal/auth; |
no test coverage detected