2025-03-01 03:32:41 +08:00
|
|
|
use anyhow::{anyhow, Result};
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
use serde_json::Value;
|
|
|
|
use uuid::Uuid;
|
|
|
|
|
2025-03-01 03:45:53 +08:00
|
|
|
use database::{enums::DataSourceType, vault::read_secret};
|
2025-03-01 03:32:41 +08:00
|
|
|
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
|
|
#[serde(tag = "type")]
|
|
|
|
#[serde(rename_all = "lowercase")]
|
|
|
|
pub enum Credential {
|
|
|
|
Postgres(PostgresCredentials),
|
2025-03-01 03:55:28 +08:00
|
|
|
MySql(MySqlCredentials),
|
2025-03-01 03:32:41 +08:00
|
|
|
Bigquery(BigqueryCredentials),
|
|
|
|
SqlServer(SqlServerCredentials),
|
|
|
|
Redshift(RedshiftCredentials),
|
|
|
|
Databricks(DatabricksCredentials),
|
|
|
|
Snowflake(SnowflakeCredentials),
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
|
|
pub struct BigqueryCredentials {
|
|
|
|
pub credentials_json: Value,
|
|
|
|
pub project_id: String,
|
|
|
|
pub dataset_ids: Option<Vec<String>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
|
|
pub struct DatabricksCredentials {
|
|
|
|
pub host: String,
|
|
|
|
pub api_key: String,
|
|
|
|
pub warehouse_id: String,
|
|
|
|
pub catalog_name: String,
|
|
|
|
pub schemas: Option<Vec<String>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
|
|
pub struct MariadbCredentials {
|
|
|
|
pub host: String,
|
|
|
|
pub port: u16,
|
|
|
|
pub username: String,
|
|
|
|
pub password: String,
|
|
|
|
pub jump_host: Option<String>,
|
|
|
|
pub ssh_username: Option<String>,
|
|
|
|
pub ssh_private_key: Option<String>,
|
|
|
|
#[serde(rename = "schemas")]
|
|
|
|
pub databases: Option<Vec<String>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
|
|
pub struct MySqlCredentials {
|
|
|
|
pub host: String,
|
|
|
|
pub port: u16,
|
|
|
|
pub username: String,
|
|
|
|
pub password: String,
|
|
|
|
pub jump_host: Option<String>,
|
|
|
|
pub ssh_username: Option<String>,
|
|
|
|
pub ssh_private_key: Option<String>,
|
|
|
|
#[serde(rename = "schemas")]
|
|
|
|
pub databases: Option<Vec<String>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
|
|
pub struct PostgresCredentials {
|
|
|
|
pub host: String,
|
|
|
|
pub port: u16,
|
|
|
|
pub username: String,
|
|
|
|
pub password: String,
|
|
|
|
#[serde(alias = "dbname")]
|
|
|
|
pub database: String,
|
|
|
|
pub schema: Option<String>,
|
|
|
|
pub jump_host: Option<String>,
|
|
|
|
pub ssh_username: Option<String>,
|
|
|
|
pub ssh_private_key: Option<String>,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Deprecated: REDSHIFT just uses postgres credentials
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
|
|
pub struct RedshiftCredentials {
|
|
|
|
pub host: String,
|
|
|
|
pub port: u16,
|
|
|
|
pub username: String,
|
|
|
|
pub password: String,
|
|
|
|
pub database: String,
|
|
|
|
pub schemas: Option<Vec<String>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
|
|
pub struct SnowflakeCredentials {
|
|
|
|
pub account_id: String,
|
|
|
|
pub warehouse_id: String,
|
|
|
|
pub database_id: Option<String>,
|
|
|
|
pub username: String,
|
|
|
|
pub password: String,
|
|
|
|
pub role: Option<String>,
|
|
|
|
pub schemas: Option<Vec<String>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
|
|
|
pub struct SqlServerCredentials {
|
|
|
|
pub host: String,
|
|
|
|
pub port: u16,
|
|
|
|
pub username: String,
|
|
|
|
pub password: String,
|
|
|
|
pub database: String,
|
|
|
|
pub jump_host: Option<String>,
|
|
|
|
pub ssh_username: Option<String>,
|
|
|
|
pub ssh_private_key: Option<String>,
|
|
|
|
pub schemas: Option<Vec<String>>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Credential {
|
|
|
|
pub fn get_type_string(&self) -> String {
|
|
|
|
match self {
|
|
|
|
Credential::Postgres(_) => "postgres".to_string(),
|
2025-03-01 03:55:28 +08:00
|
|
|
Credential::MySql(_) => "mysql".to_string(),
|
2025-03-01 03:32:41 +08:00
|
|
|
Credential::Bigquery(_) => "bigquery".to_string(),
|
|
|
|
Credential::SqlServer(_) => "sqlserver".to_string(),
|
|
|
|
Credential::Redshift(_) => "redshift".to_string(),
|
|
|
|
Credential::Databricks(_) => "databricks".to_string(),
|
|
|
|
Credential::Snowflake(_) => "snowflake".to_string(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn get_type(&self) -> DataSourceType {
|
|
|
|
match self {
|
|
|
|
Credential::Postgres(_) => DataSourceType::Postgres,
|
2025-03-01 03:55:28 +08:00
|
|
|
Credential::MySql(_) => DataSourceType::MySql,
|
2025-03-01 03:32:41 +08:00
|
|
|
Credential::Bigquery(_) => DataSourceType::BigQuery,
|
|
|
|
Credential::SqlServer(_) => DataSourceType::SqlServer,
|
|
|
|
Credential::Redshift(_) => DataSourceType::Redshift,
|
|
|
|
Credential::Databricks(_) => DataSourceType::Databricks,
|
|
|
|
Credential::Snowflake(_) => DataSourceType::Snowflake,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn get_data_source_credentials(
|
|
|
|
secret_id: &Uuid,
|
|
|
|
data_source_type: &DataSourceType,
|
|
|
|
redact_secret: bool,
|
|
|
|
) -> Result<Credential> {
|
|
|
|
let secret_string = match read_secret(&secret_id).await {
|
|
|
|
Ok(secret) => secret,
|
|
|
|
Err(e) => return Err(anyhow!("Error reading secret: {:?}", e)),
|
|
|
|
};
|
|
|
|
|
|
|
|
let credential: Credential = match data_source_type {
|
|
|
|
DataSourceType::BigQuery => {
|
|
|
|
match serde_json::from_str::<BigqueryCredentials>(&secret_string) {
|
|
|
|
Ok(mut credential) => {
|
|
|
|
println!("credential: {:?}", credential);
|
|
|
|
|
|
|
|
if redact_secret {
|
|
|
|
credential.credentials_json = Value::Null;
|
|
|
|
}
|
|
|
|
Credential::Bigquery(credential)
|
|
|
|
}
|
|
|
|
Err(e) => return Err(anyhow!("Error deserializing BigQuery secret: {:?}", e)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DataSourceType::Databricks => {
|
|
|
|
match serde_json::from_str::<DatabricksCredentials>(&secret_string) {
|
|
|
|
Ok(mut credential) => {
|
|
|
|
if redact_secret {
|
|
|
|
credential.api_key = "[REDACTED]".to_string();
|
|
|
|
}
|
|
|
|
Credential::Databricks(credential)
|
|
|
|
}
|
|
|
|
Err(e) => return Err(anyhow!("Error deserializing Databricks secret: {:?}", e)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DataSourceType::MySql => match serde_json::from_str::<MySqlCredentials>(&secret_string) {
|
|
|
|
Ok(mut credential) => {
|
|
|
|
if redact_secret {
|
|
|
|
credential.password = "[REDACTED]".to_string();
|
|
|
|
credential.ssh_private_key =
|
|
|
|
credential.ssh_private_key.map(|_| "[REDACTED]".to_string());
|
|
|
|
}
|
2025-03-01 03:55:28 +08:00
|
|
|
Credential::MySql(credential)
|
2025-03-01 03:32:41 +08:00
|
|
|
}
|
|
|
|
Err(e) => return Err(anyhow!("Error deserializing MySQL secret: {:?}", e)),
|
|
|
|
},
|
|
|
|
DataSourceType::Mariadb => match serde_json::from_str::<MySqlCredentials>(&secret_string) {
|
|
|
|
Ok(mut credential) => {
|
|
|
|
if redact_secret {
|
|
|
|
credential.password = "[REDACTED]".to_string();
|
|
|
|
credential.ssh_private_key =
|
|
|
|
credential.ssh_private_key.map(|_| "[REDACTED]".to_string());
|
|
|
|
}
|
2025-03-01 03:55:28 +08:00
|
|
|
Credential::MySql(credential)
|
2025-03-01 03:32:41 +08:00
|
|
|
}
|
|
|
|
Err(e) => return Err(anyhow!("Error deserializing MariaDB secret: {:?}", e)),
|
|
|
|
},
|
|
|
|
DataSourceType::Postgres => {
|
|
|
|
match serde_json::from_str::<PostgresCredentials>(&secret_string) {
|
|
|
|
Ok(mut credential) => {
|
|
|
|
if redact_secret {
|
|
|
|
credential.password = "[REDACTED]".to_string();
|
|
|
|
credential.ssh_private_key =
|
|
|
|
credential.ssh_private_key.map(|_| "[REDACTED]".to_string());
|
|
|
|
}
|
|
|
|
Credential::Postgres(credential)
|
|
|
|
}
|
|
|
|
Err(e) => return Err(anyhow!("Error deserializing Postgres secret: {:?}", e)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DataSourceType::Redshift => {
|
|
|
|
match serde_json::from_str::<PostgresCredentials>(&secret_string) {
|
|
|
|
Ok(mut credential) => {
|
|
|
|
if redact_secret {
|
|
|
|
credential.password = "[REDACTED]".to_string();
|
|
|
|
}
|
|
|
|
Credential::Postgres(credential)
|
|
|
|
}
|
|
|
|
Err(e) => return Err(anyhow!("Error deserializing Redshift secret: {:?}", e)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DataSourceType::Snowflake => {
|
|
|
|
match serde_json::from_str::<SnowflakeCredentials>(&secret_string) {
|
|
|
|
Ok(mut credential) => {
|
|
|
|
if redact_secret {
|
|
|
|
credential.password = "[REDACTED]".to_string();
|
|
|
|
}
|
|
|
|
Credential::Snowflake(credential)
|
|
|
|
}
|
|
|
|
Err(e) => return Err(anyhow!("Error deserializing Snowflake secret: {:?}", e)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DataSourceType::SqlServer => {
|
|
|
|
match serde_json::from_str::<SqlServerCredentials>(&secret_string) {
|
|
|
|
Ok(mut credential) => {
|
|
|
|
if redact_secret {
|
|
|
|
credential.password = "[REDACTED]".to_string();
|
|
|
|
credential.ssh_private_key =
|
|
|
|
credential.ssh_private_key.map(|_| "[REDACTED]".to_string());
|
|
|
|
}
|
|
|
|
Credential::SqlServer(credential)
|
|
|
|
}
|
|
|
|
Err(e) => return Err(anyhow!("Error deserializing SQL Server secret: {:?}", e)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DataSourceType::Supabase => {
|
|
|
|
match serde_json::from_str::<PostgresCredentials>(&secret_string) {
|
|
|
|
Ok(mut credential) => {
|
|
|
|
if redact_secret {
|
|
|
|
credential.password = "[REDACTED]".to_string();
|
|
|
|
credential.ssh_private_key =
|
|
|
|
credential.ssh_private_key.map(|_| "[REDACTED]".to_string());
|
|
|
|
}
|
|
|
|
Credential::Postgres(credential)
|
|
|
|
}
|
|
|
|
Err(e) => return Err(anyhow!("Error deserializing Supabase secret: {:?}", e)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
Ok(credential)
|
|
|
|
}
|