From b08261ab3307d43f4aa35f7df6bd3a418d3b0de5 Mon Sep 17 00:00:00 2001 From: Bo Lu Date: Mon, 26 Aug 2024 17:35:03 +1000 Subject: [PATCH 1/4] feat: add get_vault_secret_by_name() function --- supabase-wrappers/src/utils.rs | 28 +++++++++++++++++++---- wrappers/src/fdw/stripe_fdw/stripe_fdw.rs | 15 ++++++++---- 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/supabase-wrappers/src/utils.rs b/supabase-wrappers/src/utils.rs index 1f1b7f4c..612d0713 100644 --- a/supabase-wrappers/src/utils.rs +++ b/supabase-wrappers/src/utils.rs @@ -154,9 +154,9 @@ pub fn create_async_runtime() -> Result { Ok(Builder::new_current_thread().enable_all().build()?) } -/// Get decrypted secret from Vault +/// Get decrypted secret from Vault by secret ID /// -/// Get decrypted secret as string from Vault. Vault is an extension for storing +/// Get decrypted secret as string from Vault by secret ID. Vault is an extension for storing /// encrypted secrets, [see more details](https://github.com/supabase/vault). pub fn get_vault_secret(secret_id: &str) -> Option { match Uuid::try_parse(secret_id) { @@ -169,11 +169,11 @@ pub fn get_vault_secret(secret_id: &str) -> Option { pgrx::Uuid::from_bytes(sid).into_datum(), )], ) { - Ok(sid) => sid, + Ok(decrypted) => decrypted, Err(err) => { report_error( PgSqlErrorCode::ERRCODE_FDW_ERROR, - &format!("invalid secret id \"{}\": {}", secret_id, err), + &format!("query vault failed \"{}\": {}", secret_id, err), ); None } @@ -189,6 +189,26 @@ pub fn get_vault_secret(secret_id: &str) -> Option { } } +/// Get decrypted secret from Vault by secret name +/// +/// Get decrypted secret as string from Vault by secret name. Vault is an extension for storing +/// encrypted secrets, [see more details](https://github.com/supabase/vault). +pub fn get_vault_secret_by_name(secret_name: &str) -> Option { + match Spi::get_one_with_args::( + "select decrypted_secret from vault.decrypted_secrets where name = $1", + vec![(PgBuiltInOids::TEXTOID.oid(), secret_name.into_datum())], + ) { + Ok(decrypted) => decrypted, + Err(err) => { + report_error( + PgSqlErrorCode::ERRCODE_FDW_ERROR, + &format!("query vault failed \"{}\": {}", secret_name, err), + ); + None + } + } +} + pub(super) unsafe fn tuple_table_slot_to_row(slot: *mut pg_sys::TupleTableSlot) -> Row { let tup_desc = PgTupleDesc::from_pg_copy((*slot).tts_tupleDescriptor); diff --git a/wrappers/src/fdw/stripe_fdw/stripe_fdw.rs b/wrappers/src/fdw/stripe_fdw/stripe_fdw.rs index f02b5be0..bf7f28c5 100644 --- a/wrappers/src/fdw/stripe_fdw/stripe_fdw.rs +++ b/wrappers/src/fdw/stripe_fdw/stripe_fdw.rs @@ -638,10 +638,17 @@ impl ForeignDataWrapper for StripeFdw { let api_version = server.options.get("api_version").map(|t| t.as_str()); let client = match server.options.get("api_key") { Some(api_key) => Some(create_client(api_key, api_version)), - None => { - let key_id = require_option("api_key_id", &server.options)?; - get_vault_secret(key_id).map(|api_key| create_client(&api_key, api_version)) - } + None => server + .options + .get("api_key_id") + .and_then(|key_id| get_vault_secret(key_id)) + .or_else(|| { + server + .options + .get("api_key_name") + .and_then(|key_name| get_vault_secret_by_name(key_name)) + }) + .map(|api_key| create_client(&api_key, api_version)), } .transpose()?; From fb561b584f5a1fc6c93a7b249c64f8ad09fa77c6 Mon Sep 17 00:00:00 2001 From: Bo Lu Date: Mon, 26 Aug 2024 17:48:46 +1000 Subject: [PATCH 2/4] update docs --- docs/catalog/stripe.md | 29 ++++++++++++++------------- wrappers/src/fdw/stripe_fdw/README.md | 1 + 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/docs/catalog/stripe.md b/docs/catalog/stripe.md index 31bd47c1..afa51e94 100644 --- a/docs/catalog/stripe.md +++ b/docs/catalog/stripe.md @@ -41,18 +41,6 @@ create foreign data wrapper stripe_wrapper We need to provide Postgres with the credentials to connect to Stripe, and any additional options. We can do this using the `create server` command: -=== "Without Vault" - - ```sql - create server stripe_server - foreign data wrapper stripe_wrapper - options ( - api_key '', -- Stripe API key, required - api_url 'https://api.stripe.com/v1/', -- Stripe API base URL, optional. Default is 'https://api.stripe.com/v1/' - api_version '2024-06-20' -- Stripe API version, optional. Default is your Stripe account’s default API version. - ); - ``` - === "With Vault" By default, Postgres stores FDW credentials inside `pg_catalog.pg_foreign_server` in plain text. Anyone with access to this table will be able to view these credentials. @@ -68,13 +56,26 @@ We need to provide Postgres with the credentials to connect to Stripe, and any a ) returning key_id; ``` - Reference the credentials using the Key ID: + Reference the credentials using the Key ID or Key Name: ```sql create server stripe_server foreign data wrapper stripe_wrapper options ( - api_key_id '', -- The Key ID from above, required. + api_key_id '', -- The Key ID from above, required if api_key_name is not specified. + api_key_name '', -- The Key Name from above, required if api_key_id is not specified. + api_url 'https://api.stripe.com/v1/', -- Stripe API base URL, optional. Default is 'https://api.stripe.com/v1/' + api_version '2024-06-20' -- Stripe API version, optional. Default is your Stripe account’s default API version. + ); + ``` + +=== "Without Vault" + + ```sql + create server stripe_server + foreign data wrapper stripe_wrapper + options ( + api_key '', -- Stripe API key, required api_url 'https://api.stripe.com/v1/', -- Stripe API base URL, optional. Default is 'https://api.stripe.com/v1/' api_version '2024-06-20' -- Stripe API version, optional. Default is your Stripe account’s default API version. ); diff --git a/wrappers/src/fdw/stripe_fdw/README.md b/wrappers/src/fdw/stripe_fdw/README.md index 598b1684..8cb1704c 100644 --- a/wrappers/src/fdw/stripe_fdw/README.md +++ b/wrappers/src/fdw/stripe_fdw/README.md @@ -10,6 +10,7 @@ This is a foreign data wrapper for [Stripe](https://stripe.com/) developed using | Version | Date | Notes | | ------- | ---------- | ---------------------------------------------------- | +| 0.1.10 | 2024-08-26 | Added 'api_key_name' server option | | 0.1.9 | 2024-07-01 | Added 'api_version' server option | | 0.1.7 | 2023-07-13 | Added fdw stats collection | | 0.1.6 | 2023-05-30 | Added Checkout Session object | From e9a122364488176c523cb07b1a5fecc02650e78d Mon Sep 17 00:00:00 2001 From: Bo Lu Date: Tue, 27 Aug 2024 11:47:42 +1000 Subject: [PATCH 3/4] pump stripe fdw version number --- wrappers/src/fdw/stripe_fdw/stripe_fdw.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wrappers/src/fdw/stripe_fdw/stripe_fdw.rs b/wrappers/src/fdw/stripe_fdw/stripe_fdw.rs index bf7f28c5..5613b6cc 100644 --- a/wrappers/src/fdw/stripe_fdw/stripe_fdw.rs +++ b/wrappers/src/fdw/stripe_fdw/stripe_fdw.rs @@ -255,7 +255,7 @@ fn inc_stats_request_cnt(stats_metadata: &mut JsonB) -> StripeFdwResult<()> { } #[wrappers_fdw( - version = "0.1.9", + version = "0.1.10", author = "Supabase", website = "https://github.com/supabase/wrappers/tree/main/wrappers/src/fdw/stripe_fdw", error_type = "StripeFdwError" From a84196ac49da658e857277161e10b487ebea7494 Mon Sep 17 00:00:00 2001 From: Bo Lu Date: Tue, 27 Aug 2024 13:50:28 +1000 Subject: [PATCH 4/4] add error report for missing options --- wrappers/src/fdw/stripe_fdw/stripe_fdw.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/wrappers/src/fdw/stripe_fdw/stripe_fdw.rs b/wrappers/src/fdw/stripe_fdw/stripe_fdw.rs index 5613b6cc..a279c874 100644 --- a/wrappers/src/fdw/stripe_fdw/stripe_fdw.rs +++ b/wrappers/src/fdw/stripe_fdw/stripe_fdw.rs @@ -648,7 +648,14 @@ impl ForeignDataWrapper for StripeFdw { .get("api_key_name") .and_then(|key_name| get_vault_secret_by_name(key_name)) }) - .map(|api_key| create_client(&api_key, api_version)), + .map(|api_key| create_client(&api_key, api_version)) + .or_else(|| { + report_error( + pgrx::PgSqlErrorCode::ERRCODE_FDW_ERROR, + "either api_key_id or api_key_name option is required", + ); + None + }), } .transpose()?;