Merge branch 'release/0.2.0'

This commit is contained in:
Rostislav Raykov 2019-09-23 12:01:42 +02:00
commit 1658a432cf
7 changed files with 103 additions and 40 deletions

View file

@ -60,8 +60,8 @@ jobs:
name: cloudflare-ddns v${{ steps.get_version.outputs.VERSION }} name: cloudflare-ddns v${{ steps.get_version.outputs.VERSION }}
files: | files: |
LICENSE LICENSE
cloudflare-ddns-macOS-${{ steps.get_version.outputs.VERSION }} cloudflare-ddns-macOS-${{ steps.get_version.outputs.VERSION }}.tar.xz
cloudflare-ddns-ubuntu-${{ steps.get_version.outputs.VERSION }} cloudflare-ddns-ubuntu-${{ steps.get_version.outputs.VERSION }}.tar.xz
env: env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
publish_crate: publish_crate:

12
Cargo.lock generated
View file

@ -153,7 +153,7 @@ dependencies = [
[[package]] [[package]]
name = "cloudflare-ddns" name = "cloudflare-ddns"
version = "0.1.8" version = "0.2.0"
dependencies = [ dependencies = [
"exitcode 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "exitcode 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
@ -163,6 +163,7 @@ dependencies = [
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]] [[package]]
@ -1551,6 +1552,14 @@ dependencies = [
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "toml"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "try-lock" name = "try-lock"
version = "0.2.2" version = "0.2.2"
@ -1926,6 +1935,7 @@ dependencies = [
"checksum tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "90ca01319dea1e376a001e8dc192d42ebde6dd532532a5bad988ac37db365b19" "checksum tokio-threadpool 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "90ca01319dea1e376a001e8dc192d42ebde6dd532532a5bad988ac37db365b19"
"checksum tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f2106812d500ed25a4f38235b9cae8f78a09edf43203e16e59c3b769a342a60e" "checksum tokio-timer 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "f2106812d500ed25a4f38235b9cae8f78a09edf43203e16e59c3b769a342a60e"
"checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f" "checksum toml 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "758664fc71a3a69038656bee8b6be6477d2a6c315a6b81f7081f591bffa4111f"
"checksum toml 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c7aabe75941d914b72bf3e5d3932ed92ce0664d49d8432305a8b547c37227724"
"checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382" "checksum try-lock 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e604eb7b43c06650e854be16a2a03155743d3752dd1c943f6829e26b7a36e382"
"checksum try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "283d3b89e1368717881a9d51dad843cc435380d8109c9e47d38780a324698d8b" "checksum try_from 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "283d3b89e1368717881a9d51dad843cc435380d8109c9e47d38780a324698d8b"
"checksum unicase 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2e2e6bd1e59e56598518beb94fd6db628ded570326f0a98c679a304bd9f00150" "checksum unicase 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2e2e6bd1e59e56598518beb94fd6db628ded570326f0a98c679a304bd9f00150"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "cloudflare-ddns" name = "cloudflare-ddns"
version = "0.1.8" version = "0.2.0"
authors = ["Rostislav Raykov <z@zbrox.org>"] authors = ["Rostislav Raykov <z@zbrox.org>"]
edition = "2018" edition = "2018"
description = "A simple CLI tool to use Cloudflare's free DDNS service" description = "A simple CLI tool to use Cloudflare's free DDNS service"
@ -12,8 +12,6 @@ license = "MIT"
documentation = "https://github.com/zbrox/cloudflare-ddns" documentation = "https://github.com/zbrox/cloudflare-ddns"
readme = "README.md" readme = "README.md"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
quicli = "0.4" quicli = "0.4"
structopt = "0.3.1" structopt = "0.3.1"
@ -22,4 +20,5 @@ serde = "1.0.101"
serde_json = "1.0.40" serde_json = "1.0.40"
exitcode = "1.1.2" exitcode = "1.1.2"
human-panic = "1.0.1" human-panic = "1.0.1"
failure = "0.1.5" failure = "0.1.5"
toml = "0.5.3"

View file

@ -8,12 +8,26 @@ This is a simple CLI you can use to continuously update an A DNS record for a do
``` ```
-k, --key <auth-key> The auth key you need to generate in your Cloudflare profile -k, --key <auth-key> The auth key you need to generate in your Cloudflare profile
-c, --cache <cache> Cache file for previously reported IP address (if skipped the IP will be reported on every execution) -c, --cache <cache> Cache file for previously reported IP address (if skipped the IP will be reported on every
execution)
-f, --config <config> 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
-d, --domain <domain> The domain for which you want to report the current IP address -d, --domain <domain> The domain for which you want to report the current IP address
-e, --email <email> Your Cloudflare login email -e, --email <email> Your Cloudflare login email
-z, --zone <zone> The zone in which your domain is (usually that is your base domain name) -z, --zone <zone> The zone in which your domain is (usually that is your base domain name)
``` ```
### Config
You Can pass a path to a configuration file (`-f` or `--config`) instead of each option as a command line argument. The configuration should be a [TOML](https://github.com/toml-lang/toml) file and hold the same options. Here's a sample:
```TOML
email = "example@example.com"
auth_key = "secretkey"
domain = "example.example.com"
zone = "example.com"
```
## Cloudflare Setup ## Cloudflare Setup
You need to do some preparatory work in Cloudflare. Firstly this assumes you're using Cloudflare already to manage the DNS records for your domain. You need to do some preparatory work in Cloudflare. Firstly this assumes you're using Cloudflare already to manage the DNS records for your domain.

View file

@ -1,19 +1,12 @@
use failure::Error; use failure::Error;
use std::fs::File; use quicli::fs::{write_to_file, read_file};
use std::io::prelude::*;
use std::path::PathBuf; use std::path::PathBuf;
pub fn read_cache_file(path: &PathBuf) -> Result<String, Error> { pub fn read_cache_file(path: &PathBuf) -> Result<String, Error> {
let mut file = File::open(&path)?; Ok(read_file(path)?)
let mut s = String::new();
file.read_to_string(&mut s)?;
Ok(s.clone())
} }
pub fn write_cache_file(path: &PathBuf, ip: &str) -> Result<(), Error> { pub fn write_cache_file(path: &PathBuf, ip: &str) -> Result<(), Error> {
let mut file = File::create(&path)?; write_to_file(path, ip)?;
file.write_all(ip.as_bytes())?;
Ok(()) Ok(())
} }

View file

@ -4,28 +4,41 @@ mod network;
use file::{read_cache_file, write_cache_file}; use file::{read_cache_file, write_cache_file};
use human_panic::setup_panic; use human_panic::setup_panic;
use network::{get_current_ip, get_dns_record_id, get_zone_identifier, update_ddns}; use network::{get_current_ip, get_dns_record_id, get_zone_identifier, update_ddns};
use quicli::fs::read_file;
use quicli::prelude::*; use quicli::prelude::*;
use std::path::PathBuf; use std::path::PathBuf;
use structopt::StructOpt; use structopt::StructOpt;
#[derive(Deserialize)]
struct Config {
email: String,
auth_key: String,
zone: String,
domain: String,
}
#[derive(Debug, StructOpt)] #[derive(Debug, StructOpt)]
/// Inform Cloudflare's DDNS service of the current IP address for your domain /// Inform Cloudflare's DDNS service of the current IP address for your domain
struct Cli { 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
#[structopt(long = "config", short = "f")]
config: Option<PathBuf>,
/// Your Cloudflare login email /// Your Cloudflare login email
#[structopt(long = "email", short = "e")] #[structopt(long = "email", short = "e", required_unless = "config")]
email: String, email: Option<String>,
/// The auth key you need to generate in your Cloudflare profile /// The auth key you need to generate in your Cloudflare profile
#[structopt(long = "key", short = "k")] #[structopt(long = "key", short = "k", required_unless = "config")]
auth_key: String, auth_key: Option<String>,
/// The zone in which your domain is (usually that is your base domain name) /// The zone in which your domain is (usually that is your base domain name)
#[structopt(long = "zone", short = "z")] #[structopt(long = "zone", short = "z", required_unless = "config")]
zone: String, zone: Option<String>,
/// The domain for which you want to report the current IP address /// The domain for which you want to report the current IP address
#[structopt(long = "domain", short = "d")] #[structopt(long = "domain", short = "d", required_unless = "config")]
domain: String, domain: Option<String>,
/// Cache file for previously reported IP address (if skipped the IP will be reported on every execution) /// Cache file for previously reported IP address (if skipped the IP will be reported on every execution)
#[structopt(long = "cache", short = "c")] #[structopt(long = "cache", short = "c")]
@ -34,10 +47,9 @@ struct Cli {
fn main() -> CliResult { fn main() -> CliResult {
setup_panic!(); setup_panic!();
let args = Cli::from_args(); let args = Cli::from_args();
let should_use_cache = args.cache.is_some();
let should_use_cache = args.cache.is_some();
let cached_ip: Option<String> = match args.cache.clone() { let cached_ip: Option<String> = match args.cache.clone() {
Some(v) => { Some(v) => {
if v.exists() { if v.exists() {
@ -64,22 +76,48 @@ fn main() -> CliResult {
write_cache_file(&args.cache.unwrap(), &current_ip)?; write_cache_file(&args.cache.unwrap(), &current_ip)?;
} }
let zone_id = get_zone_identifier(&args.zone, &args.email, &args.auth_key)?; let (email, auth_key, zone, domain) = match args.config {
let record_id = get_dns_record_id(&zone_id, &args.domain, &args.email, &args.auth_key)?; 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)
}
None => (
args.email.expect("Email is not set"),
args.auth_key.expect("Auth key is not set"),
args.zone.expect("Zone is not set"),
args.domain.expect("Domain is not set"),
),
};
update_ddns( update(&current_ip, &email, &auth_key, &zone, &domain)?;
&current_ip,
&args.domain,
&zone_id,
&record_id,
&args.email,
&args.auth_key,
)?;
println!( println!(
"Successfully updated the A record for {} to {}", "Successfully updated the A record for {} to {}",
&args.domain, &current_ip &domain, &current_ip
); );
Ok(()) Ok(())
} }
fn update(
current_ip: &str,
email: &str,
auth_key: &str,
zone: &str,
domain: &str,
) -> Result<(), Error> {
let zone_id = get_zone_identifier(&zone, &email, &auth_key)?;
let record_id = get_dns_record_id(&zone_id, &domain, &email, &auth_key)?;
update_ddns(
&current_ip,
&domain,
&zone_id,
&record_id,
&email,
&auth_key,
)?;
Ok(())
}

View file

@ -77,7 +77,16 @@ pub fn get_dns_record_id(
return Err(format_err!("API Error: {}", err)); return Err(format_err!("API Error: {}", err));
} }
Ok(response.result[0].id.clone()) let id = match response.result.first() {
Some(v) => v.id.clone(),
None => {
return Err(format_err!(
"Unexpected API result for DNS record. Check if you passed the right options."
))
}
};
Ok(id)
} }
pub fn get_current_ip() -> Result<String, Error> { pub fn get_current_ip() -> Result<String, Error> {