Merge branch 'release/0.2.0'
This commit is contained in:
commit
1658a432cf
4
.github/workflows/publish_release.yml
vendored
4
.github/workflows/publish_release.yml
vendored
|
@ -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
12
Cargo.lock
generated
|
@ -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"
|
||||||
|
|
|
@ -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"
|
||||||
|
|
16
README.md
16
README.md
|
@ -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.
|
||||||
|
|
13
src/file.rs
13
src/file.rs
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
80
src/main.rs
80
src/main.rs
|
@ -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(), ¤t_ip)?;
|
write_cache_file(&args.cache.unwrap(), ¤t_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(¤t_ip, &email, &auth_key, &zone, &domain)?;
|
||||||
¤t_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, ¤t_ip
|
&domain, ¤t_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(
|
||||||
|
¤t_ip,
|
||||||
|
&domain,
|
||||||
|
&zone_id,
|
||||||
|
&record_id,
|
||||||
|
&email,
|
||||||
|
&auth_key,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
@ -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> {
|
||||||
|
|
Loading…
Reference in a new issue