feat: migrate to api tokens

Cloudflare's v4 API provides three ways of authenticating,
with the API tokens being the new, standard conform, recommended
way. This patch removes the use of the old auth_key + email combo
and replaces it with API tokens.

BREAKING CHANGE: auth keys can't be used anymore, switch to api tokens
This commit is contained in:
Jan Christian Grünhage 2020-04-20 23:04:31 +02:00
parent 2920328093
commit ec8b893f6a
2 changed files with 19 additions and 32 deletions

View file

@ -11,8 +11,7 @@ use anyhow::{Context, Result};
#[derive(Deserialize)]
struct Config {
email: String,
auth_key: String,
api_token: String,
zone: String,
domain: String,
}
@ -20,17 +19,13 @@ struct Config {
#[derive(Debug, StructOpt)]
/// Inform Cloudflare's DDNS service of the current IP address for your domain
struct Cli {
/// Your TOML config file containing all the required options (email, auth_key, zone, domain) which you can use instead of passing the arguments to the command line
/// Your TOML config file containing all the required options (api_token, zone, domain) which you can use instead of passing the arguments to the command line
#[structopt(long = "config", short = "f")]
config: Option<PathBuf>,
/// Your Cloudflare login email
#[structopt(long = "email", short = "e", required_unless = "config")]
email: Option<String>,
/// The auth key you need to generate in your Cloudflare profile
#[structopt(long = "key", short = "k", required_unless = "config")]
auth_key: Option<String>,
/// The api token you need to generate in your Cloudflare profile
#[structopt(long = "token", short = "t", required_unless = "config")]
api_token: Option<String>,
/// The zone in which your domain is (usually that is your base domain name)
#[structopt(long = "zone", short = "z", required_unless = "config")]
@ -76,21 +71,20 @@ fn main() -> Result<()> {
write_file(&args.cache.unwrap(), &current_ip)?;
}
let (email, auth_key, zone, domain) = match args.config {
let (api_token, zone, domain) = match args.config {
Some(c) => {
let config_str = read_file(&c)?;
let config: Config = toml::from_str(&config_str)?;
(config.email, config.auth_key, config.zone, config.domain)
(config.api_token, config.zone, config.domain)
}
None => (
args.email.expect("Email is not set"),
args.auth_key.expect("Auth key is not set"),
args.api_token.expect("API token is not set"),
args.zone.expect("Zone is not set"),
args.domain.expect("Domain is not set"),
),
};
update(&current_ip, &email, &auth_key, &zone, &domain)?;
update(&current_ip, &api_token, &zone, &domain)?;
println!(
"Successfully updated the A record for {} to {}",
@ -102,21 +96,19 @@ fn main() -> Result<()> {
fn update(
current_ip: &str,
email: &str,
auth_key: &str,
api_token: &str,
zone: &str,
domain: &str,
) -> Result<()> {
let zone_id = get_zone_identifier(&zone, &email, &auth_key).context("Error getting the zone identifier")?;
let record_id = get_dns_record_id(&zone_id, &domain, &email, &auth_key).context("Error getting the DNS record ID")?;
let zone_id = get_zone_identifier(&zone, &api_token).context("Error getting the zone identifier")?;
let record_id = get_dns_record_id(&zone_id, &domain, &api_token).context("Error getting the DNS record ID")?;
update_ddns(
&current_ip,
&domain,
&zone_id,
&record_id,
&email,
&auth_key,
&api_token,
).context("Error updating the DNS record")?;
Ok(())

View file

@ -28,14 +28,13 @@ struct UpdateIpData {
content: String,
}
pub fn get_zone_identifier(zone: &str, email: &str, key: &str) -> anyhow::Result<String> {
pub fn get_zone_identifier(zone: &str, api_token: &str) -> anyhow::Result<String> {
let client = reqwest::blocking::Client::new();
let url = format!("https://api.cloudflare.com/client/v4/zones?name={}", zone);
let response = client
.get(&url)
.header("X-Auth-Email", email)
.header("X-Auth-Key", key)
.header("Authorization", format!("Bearer {}", api_token))
.header("Content-Type", "application/json")
.send()?;
@ -68,8 +67,7 @@ pub fn get_zone_identifier(zone: &str, email: &str, key: &str) -> anyhow::Result
pub fn get_dns_record_id(
zone_id: &str,
domain: &str,
email: &str,
key: &str,
api_token: &str,
) -> anyhow::Result<String> {
let client = reqwest::blocking::Client::new();
let url = format!(
@ -79,8 +77,7 @@ pub fn get_dns_record_id(
let response = client
.get(&url)
.header("X-Auth-Email", email)
.header("X-Auth-Key", key)
.header("Authorization", format!("Bearer {}", api_token))
.header("Content-Type", "application/json")
.send()?;
@ -132,8 +129,7 @@ pub fn update_ddns(
domain: &str,
zone_id: &str,
record_id: &str,
email: &str,
key: &str,
api_token: &str,
) -> anyhow::Result<()> {
let client = reqwest::blocking::Client::new();
let url = format!(
@ -150,8 +146,7 @@ pub fn update_ddns(
let response = client
.put(&url)
.header("X-Auth-Email", email)
.header("X-Auth-Key", key)
.header("Authorization", format!("Bearer {}", api_token))
.header("Content-Type", "application/json")
.json(&update_data)
.send()?;