2022-03-27 23:45:31 +05:30
|
|
|
/*
|
2022-03-30 10:10:14 +05:30
|
|
|
* ForgeFlux StarChart - A federated software forge spider
|
2022-03-27 23:45:31 +05:30
|
|
|
* Copyright © 2022 Aravinth Manivannan <realaravinth@batsense.net>
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU Affero General Public License as
|
|
|
|
* published by the Free Software Foundation, either version 3 of the
|
|
|
|
* License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU Affero General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
2022-05-19 17:35:22 +05:30
|
|
|
use serde::{Deserialize, Serialize};
|
2022-03-27 23:45:31 +05:30
|
|
|
use trust_dns_resolver::{
|
|
|
|
config::{ResolverConfig, ResolverOpts},
|
|
|
|
AsyncResolver,
|
|
|
|
};
|
2022-07-14 23:47:37 +05:30
|
|
|
use url::Url;
|
2022-03-27 23:45:31 +05:30
|
|
|
|
2022-05-19 16:24:18 +05:30
|
|
|
use crate::ArcCtx;
|
2022-03-27 23:45:31 +05:30
|
|
|
|
2023-02-22 12:05:49 +05:30
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
|
|
|
/// represents a DNS challenge
|
|
|
|
pub struct Challenge {
|
|
|
|
/// url of the forge instance
|
|
|
|
pub url: String,
|
|
|
|
/// key of TXT record
|
|
|
|
pub key: String,
|
|
|
|
/// value of TXT record
|
|
|
|
pub value: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
|
2022-03-27 23:45:31 +05:30
|
|
|
pub struct TXTChallenge {
|
2022-05-19 17:35:22 +05:30
|
|
|
pub key: String,
|
|
|
|
pub value: String,
|
2022-03-27 23:45:31 +05:30
|
|
|
}
|
|
|
|
|
|
|
|
const VALUES_LEN: usize = 30;
|
|
|
|
|
|
|
|
impl TXTChallenge {
|
2022-05-19 16:24:18 +05:30
|
|
|
pub fn get_challenge_txt_key_prefix(ctx: &ArcCtx) -> String {
|
|
|
|
// starchart-{{ starchart instance's hostname}}.{{ forge instance's hostname }}
|
|
|
|
format!("starchart-{}", &ctx.settings.server.domain)
|
|
|
|
}
|
|
|
|
|
2022-07-14 23:47:37 +05:30
|
|
|
pub fn get_challenge_txt_key(ctx: &ArcCtx, hostname: &Url) -> String {
|
|
|
|
format!(
|
|
|
|
"{}.{}",
|
|
|
|
Self::get_challenge_txt_key_prefix(ctx),
|
|
|
|
hostname.host_str().unwrap()
|
|
|
|
)
|
2022-05-19 16:24:18 +05:30
|
|
|
}
|
|
|
|
|
2022-07-14 23:47:37 +05:30
|
|
|
pub fn new(ctx: &ArcCtx, hostname: &Url) -> Self {
|
2022-05-19 16:24:18 +05:30
|
|
|
let key = Self::get_challenge_txt_key(ctx, hostname);
|
2023-02-22 12:05:49 +05:30
|
|
|
let value = ctx.settings.server.domain.clone();
|
2022-05-19 17:35:22 +05:30
|
|
|
Self { key, value }
|
2022-03-27 23:45:31 +05:30
|
|
|
}
|
|
|
|
|
2022-05-19 16:24:18 +05:30
|
|
|
pub async fn verify_txt(&self) -> Result<bool, Box<dyn std::error::Error>> {
|
2022-03-27 23:45:31 +05:30
|
|
|
let conf = ResolverConfig::cloudflare_tls();
|
|
|
|
let opts = ResolverOpts::default();
|
2022-05-19 16:24:18 +05:30
|
|
|
let resolver = AsyncResolver::tokio(conf, opts)?;
|
|
|
|
let res = resolver.txt_lookup(&self.key).await?;
|
|
|
|
Ok(res.iter().any(|r| r.to_string() == self.value))
|
2022-03-27 23:45:31 +05:30
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
2022-05-19 17:35:22 +05:30
|
|
|
pub mod tests {
|
2022-03-27 23:45:31 +05:30
|
|
|
use super::*;
|
2022-05-19 16:24:18 +05:30
|
|
|
use crate::tests::sqlx_sqlite;
|
2022-07-14 23:47:37 +05:30
|
|
|
pub const BASE_DOMAIN: &str = "https://forge.forgeflux.org";
|
2022-05-19 17:35:22 +05:30
|
|
|
pub const VALUE: &str = "ifthisvalueisretrievedbyforgefluxstarchartthenthetestshouldpass";
|
2022-03-27 23:45:31 +05:30
|
|
|
|
|
|
|
#[actix_rt::test]
|
|
|
|
async fn verify_txt_works() {
|
|
|
|
// please note that this DNS record is in prod
|
2022-05-19 16:24:18 +05:30
|
|
|
|
|
|
|
let (_db, ctx, _federate, _tmp_dir) = sqlx_sqlite::get_ctx().await;
|
|
|
|
|
2022-07-14 23:47:37 +05:30
|
|
|
let base_hostname = Url::parse(BASE_DOMAIN).unwrap();
|
|
|
|
|
|
|
|
let key = TXTChallenge::get_challenge_txt_key(&ctx, &base_hostname);
|
2022-03-27 23:45:31 +05:30
|
|
|
let mut txt_challenge = TXTChallenge {
|
|
|
|
value: VALUE.to_string(),
|
2022-05-19 16:24:18 +05:30
|
|
|
key: key.clone(),
|
2022-03-27 23:45:31 +05:30
|
|
|
};
|
2022-07-14 23:47:37 +05:30
|
|
|
assert_eq!(
|
|
|
|
TXTChallenge::get_challenge_txt_key(&ctx, &base_hostname),
|
|
|
|
key,
|
|
|
|
);
|
2022-03-27 23:45:31 +05:30
|
|
|
|
|
|
|
assert!(
|
2022-05-19 16:24:18 +05:30
|
|
|
txt_challenge.verify_txt().await.unwrap(),
|
2022-03-27 23:45:31 +05:30
|
|
|
"TXT Challenge verification test"
|
|
|
|
);
|
2022-05-19 16:24:18 +05:30
|
|
|
txt_challenge.value = key;
|
|
|
|
assert!(!txt_challenge.verify_txt().await.unwrap());
|
2022-03-27 23:45:31 +05:30
|
|
|
}
|
|
|
|
}
|