mirror of
https://github.com/house-of-vanity/k8s-secrets.git
synced 2026-02-04 01:37:57 +00:00
Added webhook support
This commit is contained in:
169
Cargo.lock
generated
169
Cargo.lock
generated
@@ -45,6 +45,21 @@ version = "0.2.21"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android-tzdata"
|
||||||
|
version = "0.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "android_system_properties"
|
||||||
|
version = "0.1.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.6.20"
|
version = "0.6.20"
|
||||||
@@ -333,6 +348,12 @@ dependencies = [
|
|||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bumpalo"
|
||||||
|
version = "3.19.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bytes"
|
name = "bytes"
|
||||||
version = "1.10.1"
|
version = "1.10.1"
|
||||||
@@ -361,8 +382,13 @@ version = "0.4.41"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
|
checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"android-tzdata",
|
||||||
|
"iana-time-zone",
|
||||||
|
"js-sys",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"serde",
|
"serde",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows-link 0.1.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -943,6 +969,30 @@ dependencies = [
|
|||||||
"tracing",
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone"
|
||||||
|
version = "0.1.64"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb"
|
||||||
|
dependencies = [
|
||||||
|
"android_system_properties",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"iana-time-zone-haiku",
|
||||||
|
"js-sys",
|
||||||
|
"log",
|
||||||
|
"wasm-bindgen",
|
||||||
|
"windows-core",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iana-time-zone-haiku"
|
||||||
|
version = "0.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||||
|
dependencies = [
|
||||||
|
"cc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "icu_collections"
|
name = "icu_collections"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
@@ -1098,6 +1148,16 @@ version = "1.0.15"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "js-sys"
|
||||||
|
version = "0.3.83"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8"
|
||||||
|
dependencies = [
|
||||||
|
"once_cell",
|
||||||
|
"wasm-bindgen",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "json-patch"
|
name = "json-patch"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
@@ -1800,11 +1860,12 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "secret-reader"
|
name = "secret-reader"
|
||||||
version = "0.1.1"
|
version = "0.2.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"askama",
|
"askama",
|
||||||
"axum",
|
"axum",
|
||||||
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
"k8s-openapi",
|
"k8s-openapi",
|
||||||
"kube",
|
"kube",
|
||||||
@@ -2424,12 +2485,116 @@ dependencies = [
|
|||||||
"wit-bindgen",
|
"wit-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen"
|
||||||
|
version = "0.2.106"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"once_cell",
|
||||||
|
"rustversion",
|
||||||
|
"wasm-bindgen-macro",
|
||||||
|
"wasm-bindgen-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro"
|
||||||
|
version = "0.2.106"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"wasm-bindgen-macro-support",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-macro-support"
|
||||||
|
version = "0.2.106"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40"
|
||||||
|
dependencies = [
|
||||||
|
"bumpalo",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.106",
|
||||||
|
"wasm-bindgen-shared",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wasm-bindgen-shared"
|
||||||
|
version = "0.2.106"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-core"
|
||||||
|
version = "0.62.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
|
||||||
|
dependencies = [
|
||||||
|
"windows-implement",
|
||||||
|
"windows-interface",
|
||||||
|
"windows-link 0.2.1",
|
||||||
|
"windows-result",
|
||||||
|
"windows-strings",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-implement"
|
||||||
|
version = "0.60.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.106",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-interface"
|
||||||
|
version = "0.59.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.106",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-link"
|
name = "windows-link"
|
||||||
version = "0.1.3"
|
version = "0.1.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
|
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-link"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-result"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
|
||||||
|
dependencies = [
|
||||||
|
"windows-link 0.2.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "windows-strings"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
|
||||||
|
dependencies = [
|
||||||
|
"windows-link 0.2.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.52.0"
|
version = "0.52.0"
|
||||||
@@ -2479,7 +2644,7 @@ version = "0.53.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
|
checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-link",
|
"windows-link 0.1.3",
|
||||||
"windows_aarch64_gnullvm 0.53.0",
|
"windows_aarch64_gnullvm 0.53.0",
|
||||||
"windows_aarch64_msvc 0.53.0",
|
"windows_aarch64_msvc 0.53.0",
|
||||||
"windows_i686_gnu 0.53.0",
|
"windows_i686_gnu 0.53.0",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "secret-reader"
|
name = "secret-reader"
|
||||||
version = "0.1.1"
|
version = "0.2.0"
|
||||||
edition = "2021"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
axum = "0.7"
|
axum = "0.7"
|
||||||
@@ -16,3 +16,4 @@ tracing = "0.1"
|
|||||||
tracing-subscriber = "0.3"
|
tracing-subscriber = "0.3"
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
totp-rs = { version = "5.6", features = ["otpauth"] }
|
totp-rs = { version = "5.6", features = ["otpauth"] }
|
||||||
|
chrono = "0.4"
|
||||||
|
|||||||
109
src/main.rs
109
src/main.rs
@@ -1,17 +1,19 @@
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
use axum::{
|
use axum::{
|
||||||
extract::{Query, State},
|
extract::{Json, Query, State},
|
||||||
http::StatusCode,
|
http::StatusCode,
|
||||||
response::{Html, IntoResponse, Response},
|
response::{Html, IntoResponse, Response},
|
||||||
routing::get,
|
routing::{get, post},
|
||||||
Router,
|
Router,
|
||||||
};
|
};
|
||||||
|
use chrono;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use k8s_openapi::api::core::v1::Secret;
|
use k8s_openapi::api::core::v1::Secret;
|
||||||
use kube::{Api, Client};
|
use kube::{Api, Client};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::sync::Arc;
|
use std::collections::HashMap;
|
||||||
|
use std::sync::{Arc, RwLock};
|
||||||
use totp_rs::TOTP;
|
use totp_rs::TOTP;
|
||||||
use tracing::{error, info};
|
use tracing::{error, info};
|
||||||
use tracing_subscriber;
|
use tracing_subscriber;
|
||||||
@@ -27,6 +29,9 @@ struct Args {
|
|||||||
|
|
||||||
#[arg(short, long, default_value = "default")]
|
#[arg(short, long, default_value = "default")]
|
||||||
namespace: String,
|
namespace: String,
|
||||||
|
|
||||||
|
#[arg(short = 'w', long, help = "Enable webhook endpoint at /webhook")]
|
||||||
|
webhook: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -34,12 +39,24 @@ struct AppState {
|
|||||||
client: Client,
|
client: Client,
|
||||||
secret_names: Vec<String>,
|
secret_names: Vec<String>,
|
||||||
namespace: String,
|
namespace: String,
|
||||||
|
webhook_secrets: Arc<RwLock<HashMap<String, WebhookSecret>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
struct WebhookSecret {
|
||||||
|
name: String,
|
||||||
|
fields: HashMap<String, String>,
|
||||||
|
#[serde(skip_deserializing)]
|
||||||
|
#[serde(default)]
|
||||||
|
received_at: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
struct SecretData {
|
struct SecretData {
|
||||||
name: String,
|
name: String,
|
||||||
data: Vec<(String, String)>,
|
data: Vec<(String, String)>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
received_at: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Template)]
|
#[derive(Template)]
|
||||||
@@ -80,6 +97,7 @@ async fn read_secrets(state: &AppState) -> Result<Vec<SecretData>> {
|
|||||||
result.push(SecretData {
|
result.push(SecretData {
|
||||||
name: secret_name.clone(),
|
name: secret_name.clone(),
|
||||||
data: data_pairs,
|
data: data_pairs,
|
||||||
|
received_at: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -87,6 +105,7 @@ async fn read_secrets(state: &AppState) -> Result<Vec<SecretData>> {
|
|||||||
result.push(SecretData {
|
result.push(SecretData {
|
||||||
name: secret_name.clone(),
|
name: secret_name.clone(),
|
||||||
data: vec![("error".to_string(), format!("Failed to read: {}", e))],
|
data: vec![("error".to_string(), format!("Failed to read: {}", e))],
|
||||||
|
received_at: None,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,21 +117,8 @@ async fn read_secrets(state: &AppState) -> Result<Vec<SecretData>> {
|
|||||||
async fn index_handler(State(state): State<Arc<AppState>>) -> impl IntoResponse {
|
async fn index_handler(State(state): State<Arc<AppState>>) -> impl IntoResponse {
|
||||||
info!("Handling request, fetching secrets: {:?}", state.secret_names);
|
info!("Handling request, fetching secrets: {:?}", state.secret_names);
|
||||||
|
|
||||||
match read_secrets(&state).await {
|
let mut all_secrets = match read_secrets(&state).await {
|
||||||
Ok(secrets) => {
|
Ok(secrets) => secrets,
|
||||||
let template = IndexTemplate {
|
|
||||||
secrets,
|
|
||||||
error: None,
|
|
||||||
};
|
|
||||||
|
|
||||||
match template.render() {
|
|
||||||
Ok(html) => Html(html).into_response(),
|
|
||||||
Err(e) => {
|
|
||||||
error!("Template render error: {}", e);
|
|
||||||
(StatusCode::INTERNAL_SERVER_ERROR, "Template render error").into_response()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Failed to read secrets: {}", e);
|
error!("Failed to read secrets: {}", e);
|
||||||
let template = IndexTemplate {
|
let template = IndexTemplate {
|
||||||
@@ -120,10 +126,39 @@ async fn index_handler(State(state): State<Arc<AppState>>) -> impl IntoResponse
|
|||||||
error: Some(format!("Failed to read secrets: {}", e)),
|
error: Some(format!("Failed to read secrets: {}", e)),
|
||||||
};
|
};
|
||||||
|
|
||||||
match template.render() {
|
return match template.render() {
|
||||||
Ok(html) => Html(html).into_response(),
|
Ok(html) => Html(html).into_response(),
|
||||||
Err(_) => (StatusCode::INTERNAL_SERVER_ERROR, "Failed to read secrets").into_response(),
|
Err(_) => (StatusCode::INTERNAL_SERVER_ERROR, "Failed to read secrets").into_response(),
|
||||||
}
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add webhook secrets
|
||||||
|
if let Ok(webhook_secrets) = state.webhook_secrets.read() {
|
||||||
|
for (_, webhook_secret) in webhook_secrets.iter() {
|
||||||
|
let mut data_pairs: Vec<(String, String)> = webhook_secret.fields.iter()
|
||||||
|
.map(|(k, v)| (k.clone(), v.clone()))
|
||||||
|
.collect();
|
||||||
|
data_pairs.sort_by(|a, b| a.0.cmp(&b.0));
|
||||||
|
|
||||||
|
all_secrets.push(SecretData {
|
||||||
|
name: webhook_secret.name.clone(),
|
||||||
|
data: data_pairs,
|
||||||
|
received_at: Some(webhook_secret.received_at.clone()),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let template = IndexTemplate {
|
||||||
|
secrets: all_secrets,
|
||||||
|
error: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
match template.render() {
|
||||||
|
Ok(html) => Html(html).into_response(),
|
||||||
|
Err(e) => {
|
||||||
|
error!("Template render error: {}", e);
|
||||||
|
(StatusCode::INTERNAL_SERVER_ERROR, "Template render error").into_response()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,6 +167,27 @@ async fn health_handler() -> impl IntoResponse {
|
|||||||
"OK"
|
"OK"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn webhook_handler(
|
||||||
|
State(state): State<Arc<AppState>>,
|
||||||
|
Json(payload): Json<WebhookSecret>,
|
||||||
|
) -> impl IntoResponse {
|
||||||
|
info!("Received webhook for secret: {}", payload.name);
|
||||||
|
|
||||||
|
let mut webhook_secret = payload;
|
||||||
|
webhook_secret.received_at = chrono::Utc::now().format("%Y-%m-%d %H:%M:%S UTC").to_string();
|
||||||
|
|
||||||
|
match state.webhook_secrets.write() {
|
||||||
|
Ok(mut secrets) => {
|
||||||
|
secrets.insert(webhook_secret.name.clone(), webhook_secret);
|
||||||
|
(StatusCode::OK, "Webhook received")
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
error!("Failed to write webhook secret: {}", e);
|
||||||
|
(StatusCode::INTERNAL_SERVER_ERROR, "Failed to store webhook")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn generate_totp_code(otpauth_url: &str) -> Option<String> {
|
fn generate_totp_code(otpauth_url: &str) -> Option<String> {
|
||||||
// Try to parse the otpauth URL directly using totp-rs
|
// Try to parse the otpauth URL directly using totp-rs
|
||||||
match TOTP::from_url(otpauth_url) {
|
match TOTP::from_url(otpauth_url) {
|
||||||
@@ -220,13 +276,20 @@ async fn main() -> Result<()> {
|
|||||||
client,
|
client,
|
||||||
secret_names: args.secrets,
|
secret_names: args.secrets,
|
||||||
namespace: args.namespace,
|
namespace: args.namespace,
|
||||||
|
webhook_secrets: Arc::new(RwLock::new(HashMap::new())),
|
||||||
});
|
});
|
||||||
|
|
||||||
let app = Router::new()
|
let mut app = Router::new()
|
||||||
.route("/", get(index_handler))
|
.route("/", get(index_handler))
|
||||||
.route("/health", get(health_handler))
|
.route("/health", get(health_handler))
|
||||||
.route("/secret", get(secret_handler))
|
.route("/secret", get(secret_handler));
|
||||||
.with_state(state);
|
|
||||||
|
if args.webhook {
|
||||||
|
info!("Webhook endpoint enabled at /webhook");
|
||||||
|
app = app.route("/webhook", post(webhook_handler));
|
||||||
|
}
|
||||||
|
|
||||||
|
let app = app.with_state(state.clone());
|
||||||
|
|
||||||
let addr = format!("0.0.0.0:{}", args.port);
|
let addr = format!("0.0.0.0:{}", args.port);
|
||||||
info!("Server listening on {}", addr);
|
info!("Server listening on {}", addr);
|
||||||
|
|||||||
@@ -90,6 +90,12 @@
|
|||||||
color: #666;
|
color: #666;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
}
|
}
|
||||||
|
.received-at {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #888;
|
||||||
|
margin-top: 5px;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
.error {
|
.error {
|
||||||
background: #ffdddd;
|
background: #ffdddd;
|
||||||
color: #cc0000;
|
color: #cc0000;
|
||||||
@@ -125,6 +131,9 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% if let Some(received) = secret.received_at %}
|
||||||
|
<div class="received-at">Received: {{ received }}</div>
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
Reference in New Issue
Block a user