use crate::core::ConfigProvider;
use base64::Engine;
pub const API_TOKEN: &str = "api_token";
pub const APP_PASSWORD: &str = "app_password";
pub const OAUTH: &str = "oauth";
#[must_use]
pub fn basic_header(username: &str, secret: &str) -> String {
let encoded = base64::engine::general_purpose::STANDARD.encode(format!("{username}:{secret}"));
format!("Basic {encoded}")
}
#[must_use]
pub fn bearer_header(token: &str) -> String {
format!("Bearer {token}")
}
#[must_use]
pub fn header_for(config: &dyn ConfigProvider, host: &str) -> Option<String> {
let token = config.auth_token(host)?;
let auth_type = config
.get(host, "auth_type")
.unwrap_or_else(|| APP_PASSWORD.to_owned());
if auth_type == OAUTH {
Some(bearer_header(&token))
} else {
let username = config.get(host, "username").unwrap_or_default();
Some(basic_header(&username, &token))
}
}
pub const TOKEN_URL: &str = "https://bitbucket.org/site/oauth2/access_token";
#[derive(serde::Deserialize)]
pub struct TokenResponse {
pub access_token: String,
#[serde(default)]
pub refresh_token: Option<String>,
}
pub fn post_form<T: serde::de::DeserializeOwned>(
transport: &dyn crate::core::Transport,
url: &str,
body: &str,
basic_auth: &str,
) -> anyhow::Result<T> {
use crate::core::{ApiError, HttpRequest, Method};
let req = HttpRequest::new(Method::Post, url)
.header("Accept", "application/json")
.header("Content-Type", "application/x-www-form-urlencoded")
.header("Authorization", basic_auth.to_owned())
.body(body.as_bytes().to_vec());
let resp = transport.execute(req)?;
if !resp.is_success() {
let detail = String::from_utf8_lossy(&resp.body);
let detail = detail.trim();
let message = if detail.is_empty() {
format!("token request failed with status {}", resp.status)
} else {
format!("token request failed with status {}: {detail}", resp.status)
};
return Err(ApiError::Http {
status: resp.status,
url: url.to_owned(),
message,
errors: Vec::new(),
}
.into());
}
serde_json::from_slice(&resp.body).map_err(|e| ApiError::Decode(e.to_string()).into())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn basic_header_encodes() {
assert_eq!(basic_header("user", "pass"), "Basic dXNlcjpwYXNz");
}
#[test]
fn bearer_header_formats() {
assert_eq!(bearer_header("abc"), "Bearer abc");
}
}