Skip to main content

pray_core/
push_auth.rs

1use crate::ssh_publishers::authorize_ssh_push;
2use crate::{PrayError, PrayResult};
3use std::path::Path;
4
5pub fn authorize_distribution_push(
6    root: &Path,
7    bind_host: &str,
8    allow_open_push: bool,
9    stdio_mode: bool,
10) -> PrayResult<()> {
11    let stdio_mode = stdio_mode || std::env::var_os("PRAY_SERVE_STDIO").is_some();
12    if stdio_mode {
13        return authorize_ssh_push(root);
14    }
15
16    match authorize_ssh_push(root) {
17        Ok(()) => {
18            if publishers_configured(root)? {
19                return Ok(());
20            }
21        }
22        Err(error) => return Err(error),
23    }
24
25    if allow_open_push || is_loopback_bind_host(bind_host) {
26        return Ok(());
27    }
28
29    Err(PrayError::Resolution(
30        "HTTP push requires configured ssh publishers, loopback bind, or --allow-open-push"
31            .to_string(),
32    ))
33}
34
35fn publishers_configured(root: &Path) -> PrayResult<bool> {
36    match crate::ssh_publishers::read_ssh_publishers(root)? {
37        Some(config) => Ok(!config.publishers.is_empty()),
38        None => Ok(false),
39    }
40}
41
42pub fn is_loopback_bind_host(host: &str) -> bool {
43    matches!(host, "127.0.0.1" | "localhost" | "::1" | "0:0:0:0:0:0:0:1")
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49    use std::fs;
50
51    #[test]
52    fn loopback_allows_open_push_without_publishers() {
53        let root =
54            std::env::temp_dir().join(format!("pray-push-auth-loopback-{}", std::process::id()));
55        let _ = fs::remove_dir_all(&root);
56        fs::create_dir_all(&root).expect("temp root");
57        authorize_distribution_push(&root, "127.0.0.1", false, false).expect("loopback open push");
58        let _ = fs::remove_dir_all(&root);
59    }
60
61    #[test]
62    fn non_loopback_requires_flag_without_publishers() {
63        let root =
64            std::env::temp_dir().join(format!("pray-push-auth-public-{}", std::process::id()));
65        let _ = fs::remove_dir_all(&root);
66        fs::create_dir_all(&root).expect("temp root");
67        let error =
68            authorize_distribution_push(&root, "0.0.0.0", false, false).expect_err("public bind");
69        assert!(error.to_string().contains("--allow-open-push"));
70        authorize_distribution_push(&root, "0.0.0.0", true, false).expect("flag allows");
71        let _ = fs::remove_dir_all(&root);
72    }
73}