309 lines
12 KiB
Rust
309 lines
12 KiB
Rust
use md5;
|
|
use serde;
|
|
use std::env;
|
|
use worker::*;
|
|
|
|
pub async fn main(req: Request, env: Env, _ctx: worker::Context) -> Result<Response> {
|
|
// Create an instance of the Router, which can use parameters (/user/:name) or wildcard values
|
|
// (/file/*pathname). Alternatively, use `Router::with_data(D)` and pass in arbitrary data for
|
|
// routes to access and share using the `ctx.data()` method.
|
|
let router = Router::new();
|
|
|
|
#[derive(serde::Serialize, serde::Deserialize)]
|
|
struct UserInfo {
|
|
ext: String,
|
|
passwd: String,
|
|
comment: String,
|
|
created_at: String,
|
|
}
|
|
|
|
router
|
|
.get_async("/asterisk/:hostname/:code", |_req, ctx| async move {
|
|
let http = reqwest::Client::new();
|
|
|
|
auth!(http,ctx);
|
|
|
|
if let Some(hostname) = ctx.param("hostname") {
|
|
let kv = ctx.kv("GONK_NODES")?;
|
|
|
|
return match kv.get("base_asterisk").cache_ttl(300).text().await? {
|
|
Some(a) => Response::ok(&a),
|
|
None => Response::error(
|
|
format!("Could not find asterisk.conf for {}", hostname),
|
|
404,
|
|
),
|
|
};
|
|
}
|
|
Response::error("Bad Request", 400)
|
|
})
|
|
.get_async("/asterisk/pjsip/:hostname/:code", |_req, ctx| async move {
|
|
let http = reqwest::Client::new();
|
|
|
|
auth!(http,ctx);
|
|
|
|
if let Some(hostname) = ctx.param("hostname") {
|
|
let kv = ctx.kv("GONK_NODES")?;
|
|
|
|
return match kv.get("base_asterisk_pjsip").cache_ttl(300).text().await? {
|
|
Some(base) => {
|
|
let mut conf = base + "";
|
|
// let remote_ip =
|
|
// match _req.headers().get("CF-Connecting-IP").unwrap_or_default() {
|
|
// Some(ip) => ip,
|
|
// None => return Response::error("Could not find remote IP", 500),
|
|
// };
|
|
|
|
// conf = conf.replace("##EXTERNAL_IP##", &remote_ip) + "\n";
|
|
|
|
match kv.get("users").cache_ttl(300).text().await? {
|
|
Some(users) => {
|
|
let users = users.split(",");
|
|
let base_user =
|
|
match kv.get("base_asterisk_pjsip_user").cache_ttl(300).text().await? {
|
|
Some(base) => base,
|
|
None => {
|
|
return Response::error("Could not find user_base", 500)
|
|
}
|
|
};
|
|
|
|
for u in users {
|
|
let mut user = base_user.clone();
|
|
let info: UserInfo =
|
|
match kv.get(u).cache_ttl(300).json().await? {
|
|
Some(info) => info,
|
|
None => {
|
|
return Response::error(
|
|
format!("Could not find user {}", u),
|
|
500,
|
|
)
|
|
}
|
|
};
|
|
|
|
user = user.replace("##CALL##", u);
|
|
user = user.replace("##EXT##", &info.ext);
|
|
user = user.replace(
|
|
"##MD5_CRED##",
|
|
&format!(
|
|
"{:x}",
|
|
md5::compute(format!("{}:gonk:{}", u, &info.passwd))
|
|
),
|
|
);
|
|
|
|
// user = user.replace("##PASSWD##", &info.passwd);
|
|
|
|
conf = conf + &user;
|
|
}
|
|
}
|
|
None => {
|
|
return Response::error(format!("Could not find gonk users"), 404);
|
|
}
|
|
}
|
|
Response::ok(&conf)
|
|
}
|
|
None => {
|
|
Response::error(format!("Could not find pjsip.conf for {}", hostname), 404)
|
|
}
|
|
};
|
|
}
|
|
Response::error("Bad Request", 400)
|
|
})
|
|
.get_async("/asterisk/modules/:hostname/:code", |_req, ctx| async move {
|
|
let http = reqwest::Client::new();
|
|
|
|
auth!(http,ctx);
|
|
|
|
if let Some(hostname) = ctx.param("hostname") {
|
|
let kv = ctx.kv("GONK_NODES")?;
|
|
|
|
return match kv.get("base_asterisk_modules").cache_ttl(300).text().await? {
|
|
Some(base) => Response::ok(&base),
|
|
None => Response::error(
|
|
format!("Could not find modules.conf for {}", hostname),
|
|
404,
|
|
),
|
|
};
|
|
}
|
|
Response::error("Bad Request", 400)
|
|
})
|
|
.get_async("/asterisk/logger/:hostname/:code", |_req, ctx| async move {
|
|
let http = reqwest::Client::new();
|
|
|
|
auth!(http,ctx);
|
|
|
|
if let Some(hostname) = ctx.param("hostname") {
|
|
let kv = ctx.kv("GONK_NODES")?;
|
|
|
|
return match kv.get("base_asterisk_logger").cache_ttl(300).text().await? {
|
|
Some(base) => Response::ok(&base),
|
|
None => {
|
|
Response::error(format!("Could not find logger.conf for {}", hostname), 404)
|
|
}
|
|
};
|
|
}
|
|
Response::error("Bad Request", 400)
|
|
})
|
|
.get_async("/f2b/asterisk/:hostname/:code", |_req, ctx| async move {
|
|
let http = reqwest::Client::new();
|
|
|
|
auth!(http,ctx);
|
|
|
|
if let Some(hostname) = ctx.param("hostname") {
|
|
let kv = ctx.kv("GONK_NODES")?;
|
|
|
|
return match kv.get("base_f2b_asterisk").cache_ttl(300).text().await? {
|
|
Some(base) => Response::ok(&base),
|
|
None => Response::error(
|
|
format!("Could not find fail2ban asterisk.conf for {}", hostname),
|
|
404,
|
|
),
|
|
};
|
|
}
|
|
Response::error("Bad Request", 400)
|
|
})
|
|
.get_async("/f2b/voipbl/:hostname/:code", |_req, ctx| async move {
|
|
let http = reqwest::Client::new();
|
|
|
|
auth!(http,ctx);
|
|
|
|
if let Some(hostname) = ctx.param("hostname") {
|
|
let kv = ctx.kv("GONK_NODES")?;
|
|
|
|
return match kv.get("base_f2b_voipbl").cache_ttl(300).text().await? {
|
|
Some(base) => Response::ok(&base),
|
|
None => Response::error(
|
|
format!("Could not find fail2ban voipbl.conf for {}", hostname),
|
|
404,
|
|
),
|
|
};
|
|
}
|
|
Response::error("Bad Request", 400)
|
|
})
|
|
.get_async(
|
|
"/asterisk/extensions/:hostname/:code",
|
|
|_req, ctx| async move {
|
|
let http = reqwest::Client::new();
|
|
|
|
auth!(http,ctx);
|
|
|
|
|
|
if let Some(hostname) = ctx.param("hostname") {
|
|
let kv = ctx.kv("GONK_NODES")?;
|
|
|
|
return match kv.get("base_asterisk_extensions").cache_ttl(300).text().await? {
|
|
Some(base) => {
|
|
let mut conf = base + "\n";
|
|
|
|
match kv.get("users").cache_ttl(300).text().await? {
|
|
Some(users) => {
|
|
let users = users.split(",");
|
|
let base_user =
|
|
match kv.get("base_asterisk_extensions_user").cache_ttl(300).text().await? {
|
|
Some(base) => base,
|
|
None => {
|
|
return Response::error(
|
|
"Could not find the per user configuration for extensions",
|
|
500,
|
|
)
|
|
}
|
|
};
|
|
|
|
for u in users {
|
|
let mut user = base_user.clone();
|
|
let info: UserInfo =
|
|
match kv.get(u).cache_ttl(300).json().await? {
|
|
Some(info) => info,
|
|
None => {
|
|
return Response::error(
|
|
format!("Could not find user {}", u),
|
|
500,
|
|
)
|
|
}
|
|
};
|
|
|
|
user = user.replace("##CALL##", u);
|
|
user = user.replace("##EXT##", &info.ext);
|
|
|
|
conf = conf + &user;
|
|
}
|
|
}
|
|
None => {
|
|
return Response::error(
|
|
format!("Could not find gonk users"),
|
|
404,
|
|
);
|
|
}
|
|
}
|
|
Response::ok(&conf)
|
|
}
|
|
None => Response::error(
|
|
format!("Could not find extensions.conf for {}", hostname),
|
|
404,
|
|
),
|
|
};
|
|
}
|
|
Response::error("Bad Request", 400)
|
|
},
|
|
)
|
|
.run(req, env)
|
|
.await
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! auth {
|
|
($http:expr, $ctx:expr) => {{
|
|
let code = match $ctx.param("code") {
|
|
Some(code) => code,
|
|
None => return Response::error("Bad Request", 400),
|
|
};
|
|
|
|
let hostname = match $ctx.param("hostname") {
|
|
Some(hostname) => hostname,
|
|
None => return Response::error("Bad Request", 400),
|
|
};
|
|
|
|
let token = match $http
|
|
.post("https://vault.gonknet.org/auth/approle/login")
|
|
.header("CF-Access-Client-Id", env::var("ACCESS_ID").unwrap())
|
|
.header(
|
|
"CF-Access-Client-Secret",
|
|
env::var("ACCESS_SECRET").unwrap(),
|
|
)
|
|
.header("Content-Type", "application/json")
|
|
.body(
|
|
serde_json::json!({
|
|
"role_id": env::var("ROLE_ID").unwrap(),
|
|
"secret_id": env::var("SECRET_ID").unwrap(),
|
|
})
|
|
.to_string(),
|
|
)
|
|
.send()
|
|
.await
|
|
{
|
|
Ok(r) => {
|
|
let d =
|
|
serde_json::from_str::<serde_json::Value>(&r.text().await.unwrap()).unwrap();
|
|
d["auth"]["client_token"].to_string()
|
|
}
|
|
Err(_) => return Response::error("Bad Request", 400),
|
|
};
|
|
|
|
let validation: bool = match $http
|
|
.post(format!(
|
|
"https://vault.gonknet.org/totp/code/{}",
|
|
hostname
|
|
))
|
|
.header("CF-Access-Client-Id", env::var("ACCESS_ID").unwrap())
|
|
.header(
|
|
"CF-Access-Client-Secret",
|
|
env::var("ACCESS_SECRET").unwrap(),
|
|
)
|
|
.header("X-Vault-Token", token)
|
|
.send()
|
|
.await
|
|
{
|
|
Ok(_) => true,
|
|
Err(_) => return Response::error("Bad Request", 400),
|
|
};
|
|
}};
|
|
}
|