mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-26 08:01:38 +00:00
feat: configurable expiry for presigned s3 public url signatures (#10835)
* feat: configurable expiry for presigned s3 public url signatures Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015JdZFeMXLGfeFNiQgx9QvA * fix: describe expiry_secs clamping in the spec and pin the bounds in a test Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015JdZFeMXLGfeFNiQgx9QvA * fix: omit null expiry_secs from the python sdk sign request Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015JdZFeMXLGfeFNiQgx9QvA --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -17,7 +17,11 @@
|
||||
//! so two test functions sharing the one fixture workspace serve each other's stale — by then
|
||||
//! deleted — filesystem root.
|
||||
//!
|
||||
//! Advanced S3 permissions are an enterprise feature, so this test requires the
|
||||
//! A second test pins the `expiry_secs` bounds: the signature's `exp` follows the caller's
|
||||
//! request, defaults to 12h, and is clamped to [60s, 7d]. It only mints signatures and never
|
||||
//! fetches through the proxy, so it never populates or reads that cache.
|
||||
//!
|
||||
//! Advanced S3 permissions are an enterprise feature, so these tests require the
|
||||
//! `enterprise` + `private` + `parquet` features.
|
||||
#![cfg(all(feature = "enterprise", feature = "private", feature = "parquet"))]
|
||||
|
||||
@@ -175,3 +179,88 @@ async fn test_sign_s3_objects_enforces_read_authz(db: Pool<Postgres>) -> anyhow:
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// `exp` is signed into the HMAC message, so the only way a caller can influence
|
||||
/// it is through `expiry_secs` — pin the default and both clamp bounds.
|
||||
#[sqlx::test(fixtures("base"))]
|
||||
async fn test_sign_s3_objects_expiry_secs(db: Pool<Postgres>) -> anyhow::Result<()> {
|
||||
initialize_tracing().await;
|
||||
|
||||
let server = ApiServer::start(db.clone()).await?;
|
||||
let port = server.addr.port();
|
||||
let base = format!("http://localhost:{port}/api/w/test-workspace");
|
||||
|
||||
let storage_dir = tempfile::tempdir()?;
|
||||
configure_lfs(&db, &storage_dir.path().to_string_lossy()).await?;
|
||||
|
||||
async fn signed_exp(base: &str, body: serde_json::Value) -> anyhow::Result<i64> {
|
||||
let resp = authed(
|
||||
client().post(format!("{base}/apps/sign_s3_objects")),
|
||||
"SECRET_TOKEN",
|
||||
)
|
||||
.json(&body)
|
||||
.send()
|
||||
.await?;
|
||||
let status = resp.status();
|
||||
let signed: serde_json::Value = resp.json().await?;
|
||||
assert!(status.is_success(), "sign must succeed: {status} {signed}");
|
||||
let presigned = signed[0]["presigned"]
|
||||
.as_str()
|
||||
.expect("sign must return a presigned string");
|
||||
let exp = presigned
|
||||
.split('&')
|
||||
.find_map(|kv| kv.strip_prefix("exp="))
|
||||
.expect("presigned string must carry exp");
|
||||
Ok(exp.parse::<i64>()?)
|
||||
}
|
||||
|
||||
let key = json!([{ "s3": "allowed/file.txt" }]);
|
||||
// The handler stamps `now` itself, so assert on a window rather than an exact value.
|
||||
// Keep the window well under the 60s lower bound, or an unclamped 1s would pass.
|
||||
let ttl_around = |exp: i64| exp - chrono::Utc::now().timestamp();
|
||||
let tolerance = 30;
|
||||
|
||||
let default_ttl = ttl_around(signed_exp(&base, json!({ "s3_objects": key.clone() })).await?);
|
||||
assert!(
|
||||
(43200 - tolerance..=43200).contains(&default_ttl),
|
||||
"omitting expiry_secs must keep the 12h default, got {default_ttl}s"
|
||||
);
|
||||
|
||||
let honored = ttl_around(
|
||||
signed_exp(
|
||||
&base,
|
||||
json!({ "s3_objects": key.clone(), "expiry_secs": 300 }),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
assert!(
|
||||
(300 - tolerance..=300).contains(&honored),
|
||||
"expiry_secs must be honored verbatim inside the bounds, got {honored}s"
|
||||
);
|
||||
|
||||
let clamped_low = ttl_around(
|
||||
signed_exp(
|
||||
&base,
|
||||
json!({ "s3_objects": key.clone(), "expiry_secs": 1 }),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
assert!(
|
||||
(60 - tolerance..=60).contains(&clamped_low),
|
||||
"expiry_secs below 60s must clamp up to 60s, got {clamped_low}s"
|
||||
);
|
||||
|
||||
let clamped_high = ttl_around(
|
||||
signed_exp(
|
||||
&base,
|
||||
json!({ "s3_objects": key.clone(), "expiry_secs": 99_999_999 }),
|
||||
)
|
||||
.await?,
|
||||
);
|
||||
assert!(
|
||||
(604800 - tolerance..=604800).contains(&clamped_high),
|
||||
"expiry_secs above 7d must clamp down to 7d, got {clamped_high}s"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -13468,6 +13468,10 @@ paths:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/S3Object"
|
||||
expiry_secs:
|
||||
type: integer
|
||||
format: int64
|
||||
description: how long the signature stays valid, in seconds. Defaults to 43200 (12h) and is clamped server-side to [60, 604800] (1 minute to 7 days).
|
||||
required:
|
||||
- s3_objects
|
||||
responses:
|
||||
|
||||
@@ -4112,10 +4112,18 @@ struct S3DeleteTokenClaims {
|
||||
pub exp: usize,
|
||||
}
|
||||
|
||||
#[cfg(feature = "parquet")]
|
||||
const SIGN_S3_DEFAULT_EXPIRY_SECS: i64 = 12 * 60 * 60;
|
||||
#[cfg(feature = "parquet")]
|
||||
const SIGN_S3_MIN_EXPIRY_SECS: i64 = 60;
|
||||
#[cfg(feature = "parquet")]
|
||||
const SIGN_S3_MAX_EXPIRY_SECS: i64 = 7 * 24 * 60 * 60;
|
||||
|
||||
#[cfg(feature = "parquet")]
|
||||
#[derive(Deserialize)]
|
||||
struct S3TokenRequestBody {
|
||||
s3_objects: Vec<S3Object>,
|
||||
expiry_secs: Option<i64>,
|
||||
}
|
||||
#[cfg(feature = "parquet")]
|
||||
async fn sign_s3_objects(
|
||||
@@ -4126,6 +4134,12 @@ async fn sign_s3_objects(
|
||||
) -> Result<Json<Vec<S3Object>>> {
|
||||
let workspace_key = get_workspace_key(&w_id, &db).await?;
|
||||
|
||||
let expiry_secs = body
|
||||
.expiry_secs
|
||||
.unwrap_or(SIGN_S3_DEFAULT_EXPIRY_SECS)
|
||||
.clamp(SIGN_S3_MIN_EXPIRY_SECS, SIGN_S3_MAX_EXPIRY_SECS);
|
||||
let exp = (chrono::Utc::now() + chrono::Duration::seconds(expiry_secs)).timestamp();
|
||||
|
||||
let futures = body.s3_objects.into_iter().map(|s3_object| async {
|
||||
// The signature this mints is a transferable bearer capability: `validate_s3_signature`
|
||||
// only checks the HMAC and expiry, so anyone who obtains the string can read this key.
|
||||
@@ -4156,7 +4170,6 @@ async fn sign_s3_objects(
|
||||
)
|
||||
.await?;
|
||||
|
||||
let exp = (chrono::Utc::now() + chrono::Duration::hours(12)).timestamp();
|
||||
let message = format!(
|
||||
"file_key={}&exp={}{}",
|
||||
s3_object.s3.clone(),
|
||||
|
||||
Generated
+36
-16
@@ -848,31 +848,35 @@ async deleteS3File(s3object: S3Object, workspace: string | undefined = undefined
|
||||
/**
|
||||
* Sign S3 objects to be used by anonymous users in public apps
|
||||
* @param s3objects s3 objects to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed s3 objects
|
||||
*/
|
||||
async signS3Objects(s3objects: S3Object[]): Promise<S3Object[]>
|
||||
async signS3Objects(s3objects: S3Object[], { expirySecs }: { expirySecs?: number } = {}): Promise<S3Object[]>
|
||||
|
||||
/**
|
||||
* Sign S3 object to be used by anonymous users in public apps
|
||||
* @param s3object s3 object to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed s3 object
|
||||
*/
|
||||
async signS3Object(s3object: S3Object): Promise<S3Object>
|
||||
async signS3Object(s3object: S3Object, { expirySecs }: { expirySecs?: number } = {}): Promise<S3Object>
|
||||
|
||||
/**
|
||||
* Generate a presigned public URL for an array of S3 objects.
|
||||
* If an S3 object is not signed yet, it will be signed first.
|
||||
* @param s3Objects s3 objects to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns list of signed public URLs
|
||||
*/
|
||||
async getPresignedS3PublicUrls(s3Objects: S3Object[], { baseUrl }: { baseUrl?: string } = {}): Promise<string[]>
|
||||
async getPresignedS3PublicUrls(s3Objects: S3Object[], { baseUrl, expirySecs }: { baseUrl?: string; expirySecs?: number } = {}): Promise<string[]>
|
||||
|
||||
/**
|
||||
* Generate a presigned public URL for an S3 object. If the S3 object is not signed yet, it will be signed first.
|
||||
* @param s3Object s3 object to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed public URL
|
||||
*/
|
||||
async getPresignedS3PublicUrl(s3Objects: S3Object, { baseUrl }: { baseUrl?: string } = {}): Promise<string>
|
||||
async getPresignedS3PublicUrl(s3Objects: S3Object, { baseUrl, expirySecs }: { baseUrl?: string; expirySecs?: number } = {}): Promise<string>
|
||||
|
||||
/**
|
||||
* Get URLs needed for resuming a flow after this step
|
||||
@@ -1631,31 +1635,35 @@ async deleteS3File(s3object: S3Object, workspace: string | undefined = undefined
|
||||
/**
|
||||
* Sign S3 objects to be used by anonymous users in public apps
|
||||
* @param s3objects s3 objects to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed s3 objects
|
||||
*/
|
||||
async signS3Objects(s3objects: S3Object[]): Promise<S3Object[]>
|
||||
async signS3Objects(s3objects: S3Object[], { expirySecs }: { expirySecs?: number } = {}): Promise<S3Object[]>
|
||||
|
||||
/**
|
||||
* Sign S3 object to be used by anonymous users in public apps
|
||||
* @param s3object s3 object to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed s3 object
|
||||
*/
|
||||
async signS3Object(s3object: S3Object): Promise<S3Object>
|
||||
async signS3Object(s3object: S3Object, { expirySecs }: { expirySecs?: number } = {}): Promise<S3Object>
|
||||
|
||||
/**
|
||||
* Generate a presigned public URL for an array of S3 objects.
|
||||
* If an S3 object is not signed yet, it will be signed first.
|
||||
* @param s3Objects s3 objects to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns list of signed public URLs
|
||||
*/
|
||||
async getPresignedS3PublicUrls(s3Objects: S3Object[], { baseUrl }: { baseUrl?: string } = {}): Promise<string[]>
|
||||
async getPresignedS3PublicUrls(s3Objects: S3Object[], { baseUrl, expirySecs }: { baseUrl?: string; expirySecs?: number } = {}): Promise<string[]>
|
||||
|
||||
/**
|
||||
* Generate a presigned public URL for an S3 object. If the S3 object is not signed yet, it will be signed first.
|
||||
* @param s3Object s3 object to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed public URL
|
||||
*/
|
||||
async getPresignedS3PublicUrl(s3Objects: S3Object, { baseUrl }: { baseUrl?: string } = {}): Promise<string>
|
||||
async getPresignedS3PublicUrl(s3Objects: S3Object, { baseUrl, expirySecs }: { baseUrl?: string; expirySecs?: number } = {}): Promise<string>
|
||||
|
||||
/**
|
||||
* Get URLs needed for resuming a flow after this step
|
||||
@@ -2508,31 +2516,35 @@ async deleteS3File(s3object: S3Object, workspace: string | undefined = undefined
|
||||
/**
|
||||
* Sign S3 objects to be used by anonymous users in public apps
|
||||
* @param s3objects s3 objects to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed s3 objects
|
||||
*/
|
||||
async signS3Objects(s3objects: S3Object[]): Promise<S3Object[]>
|
||||
async signS3Objects(s3objects: S3Object[], { expirySecs }: { expirySecs?: number } = {}): Promise<S3Object[]>
|
||||
|
||||
/**
|
||||
* Sign S3 object to be used by anonymous users in public apps
|
||||
* @param s3object s3 object to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed s3 object
|
||||
*/
|
||||
async signS3Object(s3object: S3Object): Promise<S3Object>
|
||||
async signS3Object(s3object: S3Object, { expirySecs }: { expirySecs?: number } = {}): Promise<S3Object>
|
||||
|
||||
/**
|
||||
* Generate a presigned public URL for an array of S3 objects.
|
||||
* If an S3 object is not signed yet, it will be signed first.
|
||||
* @param s3Objects s3 objects to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns list of signed public URLs
|
||||
*/
|
||||
async getPresignedS3PublicUrls(s3Objects: S3Object[], { baseUrl }: { baseUrl?: string } = {}): Promise<string[]>
|
||||
async getPresignedS3PublicUrls(s3Objects: S3Object[], { baseUrl, expirySecs }: { baseUrl?: string; expirySecs?: number } = {}): Promise<string[]>
|
||||
|
||||
/**
|
||||
* Generate a presigned public URL for an S3 object. If the S3 object is not signed yet, it will be signed first.
|
||||
* @param s3Object s3 object to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed public URL
|
||||
*/
|
||||
async getPresignedS3PublicUrl(s3Objects: S3Object, { baseUrl }: { baseUrl?: string } = {}): Promise<string>
|
||||
async getPresignedS3PublicUrl(s3Objects: S3Object, { baseUrl, expirySecs }: { baseUrl?: string; expirySecs?: number } = {}): Promise<string>
|
||||
|
||||
/**
|
||||
* Get URLs needed for resuming a flow after this step
|
||||
@@ -4225,19 +4237,23 @@ def delete_s3_object(s3object: S3Object | str, s3_resource_path: str | None = No
|
||||
#
|
||||
# Args:
|
||||
# s3_objects: List of S3 objects to sign
|
||||
# expiry_secs: How long the signature stays valid, in seconds
|
||||
# (defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
#
|
||||
# Returns:
|
||||
# List of signed S3 objects
|
||||
def sign_s3_objects(s3_objects: list[S3Object | str]) -> list[S3Object]
|
||||
def sign_s3_objects(s3_objects: list[S3Object | str], expiry_secs: int | None = None) -> list[S3Object]
|
||||
|
||||
# Sign a single S3 object for use by anonymous users in public apps.
|
||||
#
|
||||
# Args:
|
||||
# s3_object: S3 object to sign
|
||||
# expiry_secs: How long the signature stays valid, in seconds
|
||||
# (defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
#
|
||||
# Returns:
|
||||
# Signed S3 object
|
||||
def sign_s3_object(s3_object: S3Object | str) -> S3Object
|
||||
def sign_s3_object(s3_object: S3Object | str, expiry_secs: int | None = None) -> S3Object
|
||||
|
||||
# Generate presigned public URLs for an array of S3 objects.
|
||||
# If an S3 object is not signed yet, it will be signed first.
|
||||
@@ -4245,6 +4261,8 @@ def sign_s3_object(s3_object: S3Object | str) -> S3Object
|
||||
# Args:
|
||||
# s3_objects: List of S3 objects to sign
|
||||
# base_url: Optional base URL for the presigned URLs (defaults to WM_BASE_URL)
|
||||
# expiry_secs: How long the signatures stay valid, in seconds
|
||||
# (defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
#
|
||||
# Returns:
|
||||
# List of signed public URLs
|
||||
@@ -4252,7 +4270,7 @@ def sign_s3_object(s3_object: S3Object | str) -> S3Object
|
||||
# Example:
|
||||
# >>> s3_objs = [S3Object(s3="/path/to/file1.txt"), S3Object(s3="/path/to/file2.txt")]
|
||||
# >>> urls = client.get_presigned_s3_public_urls(s3_objs)
|
||||
def get_presigned_s3_public_urls(s3_objects: list[S3Object | str], base_url: str | None = None) -> list[str]
|
||||
def get_presigned_s3_public_urls(s3_objects: list[S3Object | str], base_url: str | None = None, expiry_secs: int | None = None) -> list[str]
|
||||
|
||||
# Generate a presigned public URL for an S3 object.
|
||||
# If the S3 object is not signed yet, it will be signed first.
|
||||
@@ -4260,6 +4278,8 @@ def get_presigned_s3_public_urls(s3_objects: list[S3Object | str], base_url: str
|
||||
# Args:
|
||||
# s3_object: S3 object to sign
|
||||
# base_url: Optional base URL for the presigned URL (defaults to WM_BASE_URL)
|
||||
# expiry_secs: How long the signature stays valid, in seconds
|
||||
# (defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
#
|
||||
# Returns:
|
||||
# Signed public URL
|
||||
@@ -4267,7 +4287,7 @@ def get_presigned_s3_public_urls(s3_objects: list[S3Object | str], base_url: str
|
||||
# Example:
|
||||
# >>> s3_obj = S3Object(s3="/path/to/file.txt")
|
||||
# >>> url = client.get_presigned_s3_public_url(s3_obj)
|
||||
def get_presigned_s3_public_url(s3_object: S3Object | str, base_url: str | None = None) -> str
|
||||
def get_presigned_s3_public_url(s3_object: S3Object | str, base_url: str | None = None, expiry_secs: int | None = None) -> str
|
||||
|
||||
# Get the current user information.
|
||||
#
|
||||
|
||||
@@ -31,6 +31,15 @@ logger = logging.getLogger("windmill_client")
|
||||
JobStatus = Literal["RUNNING", "WAITING", "COMPLETED"]
|
||||
|
||||
|
||||
def _sign_s3_objects_body(s3_objects: list, expiry_secs: int | None) -> dict:
|
||||
# `expiry_secs` is optional but not nullable in the spec, so omit it rather than
|
||||
# sending an explicit null a validating gateway would reject.
|
||||
body: dict = {"s3_objects": s3_objects}
|
||||
if expiry_secs is not None:
|
||||
body["expiry_secs"] = expiry_secs
|
||||
return body
|
||||
|
||||
|
||||
class Windmill:
|
||||
"""Windmill client for interacting with the Windmill API."""
|
||||
|
||||
@@ -1044,37 +1053,45 @@ class Windmill:
|
||||
except Exception as e:
|
||||
raise Exception("Could not delete file from S3") from e
|
||||
|
||||
def sign_s3_objects(self, s3_objects: list[S3Object | str]) -> list[S3Object]:
|
||||
def sign_s3_objects(
|
||||
self, s3_objects: list[S3Object | str], expiry_secs: int | None = None
|
||||
) -> list[S3Object]:
|
||||
"""Sign S3 objects for use by anonymous users in public apps.
|
||||
|
||||
Args:
|
||||
s3_objects: List of S3 objects to sign
|
||||
expiry_secs: How long the signature stays valid, in seconds
|
||||
(defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
|
||||
Returns:
|
||||
List of signed S3 objects
|
||||
"""
|
||||
return self.post(
|
||||
f"/w/{self.workspace}/apps/sign_s3_objects", json={"s3_objects": list(map(parse_s3_object, s3_objects))}
|
||||
f"/w/{self.workspace}/apps/sign_s3_objects",
|
||||
json=_sign_s3_objects_body(list(map(parse_s3_object, s3_objects)), expiry_secs),
|
||||
).json()
|
||||
|
||||
def sign_s3_object(self, s3_object: S3Object | str) -> S3Object:
|
||||
def sign_s3_object(self, s3_object: S3Object | str, expiry_secs: int | None = None) -> S3Object:
|
||||
"""Sign a single S3 object for use by anonymous users in public apps.
|
||||
|
||||
Args:
|
||||
s3_object: S3 object to sign
|
||||
expiry_secs: How long the signature stays valid, in seconds
|
||||
(defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
|
||||
Returns:
|
||||
Signed S3 object
|
||||
"""
|
||||
return self.post(
|
||||
f"/w/{self.workspace}/apps/sign_s3_objects",
|
||||
json={"s3_objects": [s3_object]},
|
||||
json=_sign_s3_objects_body([s3_object], expiry_secs),
|
||||
).json()[0]
|
||||
|
||||
def get_presigned_s3_public_urls(
|
||||
self,
|
||||
s3_objects: list[S3Object | str],
|
||||
base_url: str | None = None,
|
||||
expiry_secs: int | None = None,
|
||||
) -> list[str]:
|
||||
"""
|
||||
Generate presigned public URLs for an array of S3 objects.
|
||||
@@ -1083,6 +1100,8 @@ class Windmill:
|
||||
Args:
|
||||
s3_objects: List of S3 objects to sign
|
||||
base_url: Optional base URL for the presigned URLs (defaults to WM_BASE_URL)
|
||||
expiry_secs: How long the signatures stay valid, in seconds
|
||||
(defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
|
||||
Returns:
|
||||
List of signed public URLs
|
||||
@@ -1104,7 +1123,7 @@ class Windmill:
|
||||
|
||||
if s3_objs_to_sign:
|
||||
signed_s3_objs = self.sign_s3_objects(
|
||||
[s3_obj for s3_obj, _ in s3_objs_to_sign]
|
||||
[s3_obj for s3_obj, _ in s3_objs_to_sign], expiry_secs
|
||||
)
|
||||
for i, (_, original_index) in enumerate(s3_objs_to_sign):
|
||||
s3_objs[original_index] = parse_s3_object(signed_s3_objs[i])
|
||||
@@ -1123,6 +1142,7 @@ class Windmill:
|
||||
self,
|
||||
s3_object: S3Object | str,
|
||||
base_url: str | None = None,
|
||||
expiry_secs: int | None = None,
|
||||
) -> str:
|
||||
"""
|
||||
Generate a presigned public URL for an S3 object.
|
||||
@@ -1131,6 +1151,8 @@ class Windmill:
|
||||
Args:
|
||||
s3_object: S3 object to sign
|
||||
base_url: Optional base URL for the presigned URL (defaults to WM_BASE_URL)
|
||||
expiry_secs: How long the signature stays valid, in seconds
|
||||
(defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
|
||||
Returns:
|
||||
Signed public URL
|
||||
@@ -1139,7 +1161,7 @@ class Windmill:
|
||||
>>> s3_obj = S3Object(s3="/path/to/file.txt")
|
||||
>>> url = client.get_presigned_s3_public_url(s3_obj)
|
||||
"""
|
||||
urls = self.get_presigned_s3_public_urls([s3_object], base_url)
|
||||
urls = self.get_presigned_s3_public_urls([s3_object], base_url, expiry_secs)
|
||||
return urls[0]
|
||||
|
||||
def _get_public_base_url(self) -> str:
|
||||
@@ -1814,27 +1836,38 @@ def delete_s3_object(
|
||||
|
||||
|
||||
@init_global_client
|
||||
def sign_s3_objects(s3_objects: list[S3Object | str]) -> list[S3Object]:
|
||||
def sign_s3_objects(s3_objects: list[S3Object | str], expiry_secs: int | None = None) -> list[S3Object]:
|
||||
"""
|
||||
Sign S3 objects to be used by anonymous users in public apps
|
||||
Returns a list of signed s3 tokens
|
||||
|
||||
Args:
|
||||
s3_objects: List of S3 objects to sign
|
||||
expiry_secs: How long the signatures stay valid, in seconds
|
||||
(defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
"""
|
||||
return _client.sign_s3_objects(s3_objects)
|
||||
return _client.sign_s3_objects(s3_objects, expiry_secs)
|
||||
|
||||
|
||||
@init_global_client
|
||||
def sign_s3_object(s3_object: S3Object| str) -> S3Object:
|
||||
def sign_s3_object(s3_object: S3Object| str, expiry_secs: int | None = None) -> S3Object:
|
||||
"""
|
||||
Sign S3 object to be used by anonymous users in public apps
|
||||
Returns a signed s3 object
|
||||
|
||||
Args:
|
||||
s3_object: S3 object to sign
|
||||
expiry_secs: How long the signature stays valid, in seconds
|
||||
(defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
"""
|
||||
return _client.sign_s3_object(s3_object)
|
||||
return _client.sign_s3_object(s3_object, expiry_secs)
|
||||
|
||||
|
||||
@init_global_client
|
||||
def get_presigned_s3_public_urls(
|
||||
s3_objects: list[S3Object | str],
|
||||
base_url: str | None = None,
|
||||
expiry_secs: int | None = None,
|
||||
) -> list[str]:
|
||||
"""
|
||||
Generate presigned public URLs for an array of S3 objects.
|
||||
@@ -1843,6 +1876,8 @@ def get_presigned_s3_public_urls(
|
||||
Args:
|
||||
s3_objects: List of S3 objects to sign
|
||||
base_url: Optional base URL for the presigned URLs (defaults to WM_BASE_URL)
|
||||
expiry_secs: How long the signatures stay valid, in seconds
|
||||
(defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
|
||||
Returns:
|
||||
List of signed public URLs
|
||||
@@ -1853,13 +1888,14 @@ def get_presigned_s3_public_urls(
|
||||
>>> s3_objs = [S3Object(s3="/path/to/file1.txt"), S3Object(s3="/path/to/file2.txt")]
|
||||
>>> urls = wmill.get_presigned_s3_public_urls(s3_objs)
|
||||
"""
|
||||
return _client.get_presigned_s3_public_urls(s3_objects, base_url)
|
||||
return _client.get_presigned_s3_public_urls(s3_objects, base_url, expiry_secs)
|
||||
|
||||
|
||||
@init_global_client
|
||||
def get_presigned_s3_public_url(
|
||||
s3_object: S3Object | str,
|
||||
base_url: str | None = None,
|
||||
expiry_secs: int | None = None,
|
||||
) -> str:
|
||||
"""
|
||||
Generate a presigned public URL for an S3 object.
|
||||
@@ -1868,6 +1904,8 @@ def get_presigned_s3_public_url(
|
||||
Args:
|
||||
s3_object: S3 object to sign
|
||||
base_url: Optional base URL for the presigned URL (defaults to WM_BASE_URL)
|
||||
expiry_secs: How long the signature stays valid, in seconds
|
||||
(defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
|
||||
Returns:
|
||||
Signed public URL
|
||||
@@ -1878,7 +1916,7 @@ def get_presigned_s3_public_url(
|
||||
>>> s3_obj = S3Object(s3="/path/to/file.txt")
|
||||
>>> url = wmill.get_presigned_s3_public_url(s3_obj)
|
||||
"""
|
||||
return _client.get_presigned_s3_public_url(s3_object, base_url)
|
||||
return _client.get_presigned_s3_public_url(s3_object, base_url, expiry_secs)
|
||||
|
||||
|
||||
@init_global_client
|
||||
|
||||
@@ -1546,31 +1546,35 @@ async deleteS3File(s3object: S3Object, workspace: string | undefined = undefined
|
||||
/**
|
||||
* Sign S3 objects to be used by anonymous users in public apps
|
||||
* @param s3objects s3 objects to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed s3 objects
|
||||
*/
|
||||
async signS3Objects(s3objects: S3Object[]): Promise<S3Object[]>
|
||||
async signS3Objects(s3objects: S3Object[], { expirySecs }: { expirySecs?: number } = {}): Promise<S3Object[]>
|
||||
|
||||
/**
|
||||
* Sign S3 object to be used by anonymous users in public apps
|
||||
* @param s3object s3 object to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed s3 object
|
||||
*/
|
||||
async signS3Object(s3object: S3Object): Promise<S3Object>
|
||||
async signS3Object(s3object: S3Object, { expirySecs }: { expirySecs?: number } = {}): Promise<S3Object>
|
||||
|
||||
/**
|
||||
* Generate a presigned public URL for an array of S3 objects.
|
||||
* If an S3 object is not signed yet, it will be signed first.
|
||||
* @param s3Objects s3 objects to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns list of signed public URLs
|
||||
*/
|
||||
async getPresignedS3PublicUrls(s3Objects: S3Object[], { baseUrl }: { baseUrl?: string } = {}): Promise<string[]>
|
||||
async getPresignedS3PublicUrls(s3Objects: S3Object[], { baseUrl, expirySecs }: { baseUrl?: string; expirySecs?: number } = {}): Promise<string[]>
|
||||
|
||||
/**
|
||||
* Generate a presigned public URL for an S3 object. If the S3 object is not signed yet, it will be signed first.
|
||||
* @param s3Object s3 object to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed public URL
|
||||
*/
|
||||
async getPresignedS3PublicUrl(s3Objects: S3Object, { baseUrl }: { baseUrl?: string } = {}): Promise<string>
|
||||
async getPresignedS3PublicUrl(s3Objects: S3Object, { baseUrl, expirySecs }: { baseUrl?: string; expirySecs?: number } = {}): Promise<string>
|
||||
|
||||
/**
|
||||
* Get URLs needed for resuming a flow after this step
|
||||
@@ -2169,19 +2173,23 @@ def delete_s3_object(s3object: S3Object | str, s3_resource_path: str | None = No
|
||||
#
|
||||
# Args:
|
||||
# s3_objects: List of S3 objects to sign
|
||||
# expiry_secs: How long the signature stays valid, in seconds
|
||||
# (defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
#
|
||||
# Returns:
|
||||
# List of signed S3 objects
|
||||
def sign_s3_objects(s3_objects: list[S3Object | str]) -> list[S3Object]
|
||||
def sign_s3_objects(s3_objects: list[S3Object | str], expiry_secs: int | None = None) -> list[S3Object]
|
||||
|
||||
# Sign a single S3 object for use by anonymous users in public apps.
|
||||
#
|
||||
# Args:
|
||||
# s3_object: S3 object to sign
|
||||
# expiry_secs: How long the signature stays valid, in seconds
|
||||
# (defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
#
|
||||
# Returns:
|
||||
# Signed S3 object
|
||||
def sign_s3_object(s3_object: S3Object | str) -> S3Object
|
||||
def sign_s3_object(s3_object: S3Object | str, expiry_secs: int | None = None) -> S3Object
|
||||
|
||||
# Generate presigned public URLs for an array of S3 objects.
|
||||
# If an S3 object is not signed yet, it will be signed first.
|
||||
@@ -2189,6 +2197,8 @@ def sign_s3_object(s3_object: S3Object | str) -> S3Object
|
||||
# Args:
|
||||
# s3_objects: List of S3 objects to sign
|
||||
# base_url: Optional base URL for the presigned URLs (defaults to WM_BASE_URL)
|
||||
# expiry_secs: How long the signatures stay valid, in seconds
|
||||
# (defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
#
|
||||
# Returns:
|
||||
# List of signed public URLs
|
||||
@@ -2196,7 +2206,7 @@ def sign_s3_object(s3_object: S3Object | str) -> S3Object
|
||||
# Example:
|
||||
# >>> s3_objs = [S3Object(s3="/path/to/file1.txt"), S3Object(s3="/path/to/file2.txt")]
|
||||
# >>> urls = client.get_presigned_s3_public_urls(s3_objs)
|
||||
def get_presigned_s3_public_urls(s3_objects: list[S3Object | str], base_url: str | None = None) -> list[str]
|
||||
def get_presigned_s3_public_urls(s3_objects: list[S3Object | str], base_url: str | None = None, expiry_secs: int | None = None) -> list[str]
|
||||
|
||||
# Generate a presigned public URL for an S3 object.
|
||||
# If the S3 object is not signed yet, it will be signed first.
|
||||
@@ -2204,6 +2214,8 @@ def get_presigned_s3_public_urls(s3_objects: list[S3Object | str], base_url: str
|
||||
# Args:
|
||||
# s3_object: S3 object to sign
|
||||
# base_url: Optional base URL for the presigned URL (defaults to WM_BASE_URL)
|
||||
# expiry_secs: How long the signature stays valid, in seconds
|
||||
# (defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
#
|
||||
# Returns:
|
||||
# Signed public URL
|
||||
@@ -2211,7 +2223,7 @@ def get_presigned_s3_public_urls(s3_objects: list[S3Object | str], base_url: str
|
||||
# Example:
|
||||
# >>> s3_obj = S3Object(s3="/path/to/file.txt")
|
||||
# >>> url = client.get_presigned_s3_public_url(s3_obj)
|
||||
def get_presigned_s3_public_url(s3_object: S3Object | str, base_url: str | None = None) -> str
|
||||
def get_presigned_s3_public_url(s3_object: S3Object | str, base_url: str | None = None, expiry_secs: int | None = None) -> str
|
||||
|
||||
# Get the current user information.
|
||||
#
|
||||
|
||||
@@ -1738,31 +1738,35 @@ async deleteS3File(s3object: S3Object, workspace: string | undefined = undefined
|
||||
/**
|
||||
* Sign S3 objects to be used by anonymous users in public apps
|
||||
* @param s3objects s3 objects to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed s3 objects
|
||||
*/
|
||||
async signS3Objects(s3objects: S3Object[]): Promise<S3Object[]>
|
||||
async signS3Objects(s3objects: S3Object[], { expirySecs }: { expirySecs?: number } = {}): Promise<S3Object[]>
|
||||
|
||||
/**
|
||||
* Sign S3 object to be used by anonymous users in public apps
|
||||
* @param s3object s3 object to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed s3 object
|
||||
*/
|
||||
async signS3Object(s3object: S3Object): Promise<S3Object>
|
||||
async signS3Object(s3object: S3Object, { expirySecs }: { expirySecs?: number } = {}): Promise<S3Object>
|
||||
|
||||
/**
|
||||
* Generate a presigned public URL for an array of S3 objects.
|
||||
* If an S3 object is not signed yet, it will be signed first.
|
||||
* @param s3Objects s3 objects to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns list of signed public URLs
|
||||
*/
|
||||
async getPresignedS3PublicUrls(s3Objects: S3Object[], { baseUrl }: { baseUrl?: string } = {}): Promise<string[]>
|
||||
async getPresignedS3PublicUrls(s3Objects: S3Object[], { baseUrl, expirySecs }: { baseUrl?: string; expirySecs?: number } = {}): Promise<string[]>
|
||||
|
||||
/**
|
||||
* Generate a presigned public URL for an S3 object. If the S3 object is not signed yet, it will be signed first.
|
||||
* @param s3Object s3 object to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed public URL
|
||||
*/
|
||||
async getPresignedS3PublicUrl(s3Objects: S3Object, { baseUrl }: { baseUrl?: string } = {}): Promise<string>
|
||||
async getPresignedS3PublicUrl(s3Objects: S3Object, { baseUrl, expirySecs }: { baseUrl?: string; expirySecs?: number } = {}): Promise<string>
|
||||
|
||||
/**
|
||||
* Get URLs needed for resuming a flow after this step
|
||||
@@ -2361,19 +2365,23 @@ def delete_s3_object(s3object: S3Object | str, s3_resource_path: str | None = No
|
||||
#
|
||||
# Args:
|
||||
# s3_objects: List of S3 objects to sign
|
||||
# expiry_secs: How long the signature stays valid, in seconds
|
||||
# (defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
#
|
||||
# Returns:
|
||||
# List of signed S3 objects
|
||||
def sign_s3_objects(s3_objects: list[S3Object | str]) -> list[S3Object]
|
||||
def sign_s3_objects(s3_objects: list[S3Object | str], expiry_secs: int | None = None) -> list[S3Object]
|
||||
|
||||
# Sign a single S3 object for use by anonymous users in public apps.
|
||||
#
|
||||
# Args:
|
||||
# s3_object: S3 object to sign
|
||||
# expiry_secs: How long the signature stays valid, in seconds
|
||||
# (defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
#
|
||||
# Returns:
|
||||
# Signed S3 object
|
||||
def sign_s3_object(s3_object: S3Object | str) -> S3Object
|
||||
def sign_s3_object(s3_object: S3Object | str, expiry_secs: int | None = None) -> S3Object
|
||||
|
||||
# Generate presigned public URLs for an array of S3 objects.
|
||||
# If an S3 object is not signed yet, it will be signed first.
|
||||
@@ -2381,6 +2389,8 @@ def sign_s3_object(s3_object: S3Object | str) -> S3Object
|
||||
# Args:
|
||||
# s3_objects: List of S3 objects to sign
|
||||
# base_url: Optional base URL for the presigned URLs (defaults to WM_BASE_URL)
|
||||
# expiry_secs: How long the signatures stay valid, in seconds
|
||||
# (defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
#
|
||||
# Returns:
|
||||
# List of signed public URLs
|
||||
@@ -2388,7 +2398,7 @@ def sign_s3_object(s3_object: S3Object | str) -> S3Object
|
||||
# Example:
|
||||
# >>> s3_objs = [S3Object(s3="/path/to/file1.txt"), S3Object(s3="/path/to/file2.txt")]
|
||||
# >>> urls = client.get_presigned_s3_public_urls(s3_objs)
|
||||
def get_presigned_s3_public_urls(s3_objects: list[S3Object | str], base_url: str | None = None) -> list[str]
|
||||
def get_presigned_s3_public_urls(s3_objects: list[S3Object | str], base_url: str | None = None, expiry_secs: int | None = None) -> list[str]
|
||||
|
||||
# Generate a presigned public URL for an S3 object.
|
||||
# If the S3 object is not signed yet, it will be signed first.
|
||||
@@ -2396,6 +2406,8 @@ def get_presigned_s3_public_urls(s3_objects: list[S3Object | str], base_url: str
|
||||
# Args:
|
||||
# s3_object: S3 object to sign
|
||||
# base_url: Optional base URL for the presigned URL (defaults to WM_BASE_URL)
|
||||
# expiry_secs: How long the signature stays valid, in seconds
|
||||
# (defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
#
|
||||
# Returns:
|
||||
# Signed public URL
|
||||
@@ -2403,7 +2415,7 @@ def get_presigned_s3_public_urls(s3_objects: list[S3Object | str], base_url: str
|
||||
# Example:
|
||||
# >>> s3_obj = S3Object(s3="/path/to/file.txt")
|
||||
# >>> url = client.get_presigned_s3_public_url(s3_obj)
|
||||
def get_presigned_s3_public_url(s3_object: S3Object | str, base_url: str | None = None) -> str
|
||||
def get_presigned_s3_public_url(s3_object: S3Object | str, base_url: str | None = None, expiry_secs: int | None = None) -> str
|
||||
|
||||
# Get the current user information.
|
||||
#
|
||||
|
||||
@@ -313,19 +313,23 @@ def delete_s3_object(s3object: S3Object | str, s3_resource_path: str | None = No
|
||||
#
|
||||
# Args:
|
||||
# s3_objects: List of S3 objects to sign
|
||||
# expiry_secs: How long the signature stays valid, in seconds
|
||||
# (defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
#
|
||||
# Returns:
|
||||
# List of signed S3 objects
|
||||
def sign_s3_objects(s3_objects: list[S3Object | str]) -> list[S3Object]
|
||||
def sign_s3_objects(s3_objects: list[S3Object | str], expiry_secs: int | None = None) -> list[S3Object]
|
||||
|
||||
# Sign a single S3 object for use by anonymous users in public apps.
|
||||
#
|
||||
# Args:
|
||||
# s3_object: S3 object to sign
|
||||
# expiry_secs: How long the signature stays valid, in seconds
|
||||
# (defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
#
|
||||
# Returns:
|
||||
# Signed S3 object
|
||||
def sign_s3_object(s3_object: S3Object | str) -> S3Object
|
||||
def sign_s3_object(s3_object: S3Object | str, expiry_secs: int | None = None) -> S3Object
|
||||
|
||||
# Generate presigned public URLs for an array of S3 objects.
|
||||
# If an S3 object is not signed yet, it will be signed first.
|
||||
@@ -333,6 +337,8 @@ def sign_s3_object(s3_object: S3Object | str) -> S3Object
|
||||
# Args:
|
||||
# s3_objects: List of S3 objects to sign
|
||||
# base_url: Optional base URL for the presigned URLs (defaults to WM_BASE_URL)
|
||||
# expiry_secs: How long the signatures stay valid, in seconds
|
||||
# (defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
#
|
||||
# Returns:
|
||||
# List of signed public URLs
|
||||
@@ -340,7 +346,7 @@ def sign_s3_object(s3_object: S3Object | str) -> S3Object
|
||||
# Example:
|
||||
# >>> s3_objs = [S3Object(s3="/path/to/file1.txt"), S3Object(s3="/path/to/file2.txt")]
|
||||
# >>> urls = client.get_presigned_s3_public_urls(s3_objs)
|
||||
def get_presigned_s3_public_urls(s3_objects: list[S3Object | str], base_url: str | None = None) -> list[str]
|
||||
def get_presigned_s3_public_urls(s3_objects: list[S3Object | str], base_url: str | None = None, expiry_secs: int | None = None) -> list[str]
|
||||
|
||||
# Generate a presigned public URL for an S3 object.
|
||||
# If the S3 object is not signed yet, it will be signed first.
|
||||
@@ -348,6 +354,8 @@ def get_presigned_s3_public_urls(s3_objects: list[S3Object | str], base_url: str
|
||||
# Args:
|
||||
# s3_object: S3 object to sign
|
||||
# base_url: Optional base URL for the presigned URL (defaults to WM_BASE_URL)
|
||||
# expiry_secs: How long the signature stays valid, in seconds
|
||||
# (defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
#
|
||||
# Returns:
|
||||
# Signed public URL
|
||||
@@ -355,7 +363,7 @@ def get_presigned_s3_public_urls(s3_objects: list[S3Object | str], base_url: str
|
||||
# Example:
|
||||
# >>> s3_obj = S3Object(s3="/path/to/file.txt")
|
||||
# >>> url = client.get_presigned_s3_public_url(s3_obj)
|
||||
def get_presigned_s3_public_url(s3_object: S3Object | str, base_url: str | None = None) -> str
|
||||
def get_presigned_s3_public_url(s3_object: S3Object | str, base_url: str | None = None, expiry_secs: int | None = None) -> str
|
||||
|
||||
# Get the current user information.
|
||||
#
|
||||
|
||||
@@ -303,31 +303,35 @@ async deleteS3File(s3object: S3Object, workspace: string | undefined = undefined
|
||||
/**
|
||||
* Sign S3 objects to be used by anonymous users in public apps
|
||||
* @param s3objects s3 objects to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed s3 objects
|
||||
*/
|
||||
async signS3Objects(s3objects: S3Object[]): Promise<S3Object[]>
|
||||
async signS3Objects(s3objects: S3Object[], { expirySecs }: { expirySecs?: number } = {}): Promise<S3Object[]>
|
||||
|
||||
/**
|
||||
* Sign S3 object to be used by anonymous users in public apps
|
||||
* @param s3object s3 object to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed s3 object
|
||||
*/
|
||||
async signS3Object(s3object: S3Object): Promise<S3Object>
|
||||
async signS3Object(s3object: S3Object, { expirySecs }: { expirySecs?: number } = {}): Promise<S3Object>
|
||||
|
||||
/**
|
||||
* Generate a presigned public URL for an array of S3 objects.
|
||||
* If an S3 object is not signed yet, it will be signed first.
|
||||
* @param s3Objects s3 objects to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns list of signed public URLs
|
||||
*/
|
||||
async getPresignedS3PublicUrls(s3Objects: S3Object[], { baseUrl }: { baseUrl?: string } = {}): Promise<string[]>
|
||||
async getPresignedS3PublicUrls(s3Objects: S3Object[], { baseUrl, expirySecs }: { baseUrl?: string; expirySecs?: number } = {}): Promise<string[]>
|
||||
|
||||
/**
|
||||
* Generate a presigned public URL for an S3 object. If the S3 object is not signed yet, it will be signed first.
|
||||
* @param s3Object s3 object to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed public URL
|
||||
*/
|
||||
async getPresignedS3PublicUrl(s3Objects: S3Object, { baseUrl }: { baseUrl?: string } = {}): Promise<string>
|
||||
async getPresignedS3PublicUrl(s3Objects: S3Object, { baseUrl, expirySecs }: { baseUrl?: string; expirySecs?: number } = {}): Promise<string>
|
||||
|
||||
/**
|
||||
* Get URLs needed for resuming a flow after this step
|
||||
|
||||
@@ -474,31 +474,35 @@ async deleteS3File(s3object: S3Object, workspace: string | undefined = undefined
|
||||
/**
|
||||
* Sign S3 objects to be used by anonymous users in public apps
|
||||
* @param s3objects s3 objects to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed s3 objects
|
||||
*/
|
||||
async signS3Objects(s3objects: S3Object[]): Promise<S3Object[]>
|
||||
async signS3Objects(s3objects: S3Object[], { expirySecs }: { expirySecs?: number } = {}): Promise<S3Object[]>
|
||||
|
||||
/**
|
||||
* Sign S3 object to be used by anonymous users in public apps
|
||||
* @param s3object s3 object to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed s3 object
|
||||
*/
|
||||
async signS3Object(s3object: S3Object): Promise<S3Object>
|
||||
async signS3Object(s3object: S3Object, { expirySecs }: { expirySecs?: number } = {}): Promise<S3Object>
|
||||
|
||||
/**
|
||||
* Generate a presigned public URL for an array of S3 objects.
|
||||
* If an S3 object is not signed yet, it will be signed first.
|
||||
* @param s3Objects s3 objects to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns list of signed public URLs
|
||||
*/
|
||||
async getPresignedS3PublicUrls(s3Objects: S3Object[], { baseUrl }: { baseUrl?: string } = {}): Promise<string[]>
|
||||
async getPresignedS3PublicUrls(s3Objects: S3Object[], { baseUrl, expirySecs }: { baseUrl?: string; expirySecs?: number } = {}): Promise<string[]>
|
||||
|
||||
/**
|
||||
* Generate a presigned public URL for an S3 object. If the S3 object is not signed yet, it will be signed first.
|
||||
* @param s3Object s3 object to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed public URL
|
||||
*/
|
||||
async getPresignedS3PublicUrl(s3Objects: S3Object, { baseUrl }: { baseUrl?: string } = {}): Promise<string>
|
||||
async getPresignedS3PublicUrl(s3Objects: S3Object, { baseUrl, expirySecs }: { baseUrl?: string; expirySecs?: number } = {}): Promise<string>
|
||||
|
||||
/**
|
||||
* Get URLs needed for resuming a flow after this step
|
||||
|
||||
@@ -474,31 +474,35 @@ async deleteS3File(s3object: S3Object, workspace: string | undefined = undefined
|
||||
/**
|
||||
* Sign S3 objects to be used by anonymous users in public apps
|
||||
* @param s3objects s3 objects to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed s3 objects
|
||||
*/
|
||||
async signS3Objects(s3objects: S3Object[]): Promise<S3Object[]>
|
||||
async signS3Objects(s3objects: S3Object[], { expirySecs }: { expirySecs?: number } = {}): Promise<S3Object[]>
|
||||
|
||||
/**
|
||||
* Sign S3 object to be used by anonymous users in public apps
|
||||
* @param s3object s3 object to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed s3 object
|
||||
*/
|
||||
async signS3Object(s3object: S3Object): Promise<S3Object>
|
||||
async signS3Object(s3object: S3Object, { expirySecs }: { expirySecs?: number } = {}): Promise<S3Object>
|
||||
|
||||
/**
|
||||
* Generate a presigned public URL for an array of S3 objects.
|
||||
* If an S3 object is not signed yet, it will be signed first.
|
||||
* @param s3Objects s3 objects to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns list of signed public URLs
|
||||
*/
|
||||
async getPresignedS3PublicUrls(s3Objects: S3Object[], { baseUrl }: { baseUrl?: string } = {}): Promise<string[]>
|
||||
async getPresignedS3PublicUrls(s3Objects: S3Object[], { baseUrl, expirySecs }: { baseUrl?: string; expirySecs?: number } = {}): Promise<string[]>
|
||||
|
||||
/**
|
||||
* Generate a presigned public URL for an S3 object. If the S3 object is not signed yet, it will be signed first.
|
||||
* @param s3Object s3 object to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed public URL
|
||||
*/
|
||||
async getPresignedS3PublicUrl(s3Objects: S3Object, { baseUrl }: { baseUrl?: string } = {}): Promise<string>
|
||||
async getPresignedS3PublicUrl(s3Objects: S3Object, { baseUrl, expirySecs }: { baseUrl?: string; expirySecs?: number } = {}): Promise<string>
|
||||
|
||||
/**
|
||||
* Get URLs needed for resuming a flow after this step
|
||||
|
||||
@@ -476,31 +476,35 @@ async deleteS3File(s3object: S3Object, workspace: string | undefined = undefined
|
||||
/**
|
||||
* Sign S3 objects to be used by anonymous users in public apps
|
||||
* @param s3objects s3 objects to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed s3 objects
|
||||
*/
|
||||
async signS3Objects(s3objects: S3Object[]): Promise<S3Object[]>
|
||||
async signS3Objects(s3objects: S3Object[], { expirySecs }: { expirySecs?: number } = {}): Promise<S3Object[]>
|
||||
|
||||
/**
|
||||
* Sign S3 object to be used by anonymous users in public apps
|
||||
* @param s3object s3 object to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed s3 object
|
||||
*/
|
||||
async signS3Object(s3object: S3Object): Promise<S3Object>
|
||||
async signS3Object(s3object: S3Object, { expirySecs }: { expirySecs?: number } = {}): Promise<S3Object>
|
||||
|
||||
/**
|
||||
* Generate a presigned public URL for an array of S3 objects.
|
||||
* If an S3 object is not signed yet, it will be signed first.
|
||||
* @param s3Objects s3 objects to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns list of signed public URLs
|
||||
*/
|
||||
async getPresignedS3PublicUrls(s3Objects: S3Object[], { baseUrl }: { baseUrl?: string } = {}): Promise<string[]>
|
||||
async getPresignedS3PublicUrls(s3Objects: S3Object[], { baseUrl, expirySecs }: { baseUrl?: string; expirySecs?: number } = {}): Promise<string[]>
|
||||
|
||||
/**
|
||||
* Generate a presigned public URL for an S3 object. If the S3 object is not signed yet, it will be signed first.
|
||||
* @param s3Object s3 object to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed public URL
|
||||
*/
|
||||
async getPresignedS3PublicUrl(s3Objects: S3Object, { baseUrl }: { baseUrl?: string } = {}): Promise<string>
|
||||
async getPresignedS3PublicUrl(s3Objects: S3Object, { baseUrl, expirySecs }: { baseUrl?: string; expirySecs?: number } = {}): Promise<string>
|
||||
|
||||
/**
|
||||
* Get URLs needed for resuming a flow after this step
|
||||
|
||||
@@ -498,19 +498,23 @@ def delete_s3_object(s3object: S3Object | str, s3_resource_path: str | None = No
|
||||
#
|
||||
# Args:
|
||||
# s3_objects: List of S3 objects to sign
|
||||
# expiry_secs: How long the signature stays valid, in seconds
|
||||
# (defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
#
|
||||
# Returns:
|
||||
# List of signed S3 objects
|
||||
def sign_s3_objects(s3_objects: list[S3Object | str]) -> list[S3Object]
|
||||
def sign_s3_objects(s3_objects: list[S3Object | str], expiry_secs: int | None = None) -> list[S3Object]
|
||||
|
||||
# Sign a single S3 object for use by anonymous users in public apps.
|
||||
#
|
||||
# Args:
|
||||
# s3_object: S3 object to sign
|
||||
# expiry_secs: How long the signature stays valid, in seconds
|
||||
# (defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
#
|
||||
# Returns:
|
||||
# Signed S3 object
|
||||
def sign_s3_object(s3_object: S3Object | str) -> S3Object
|
||||
def sign_s3_object(s3_object: S3Object | str, expiry_secs: int | None = None) -> S3Object
|
||||
|
||||
# Generate presigned public URLs for an array of S3 objects.
|
||||
# If an S3 object is not signed yet, it will be signed first.
|
||||
@@ -518,6 +522,8 @@ def sign_s3_object(s3_object: S3Object | str) -> S3Object
|
||||
# Args:
|
||||
# s3_objects: List of S3 objects to sign
|
||||
# base_url: Optional base URL for the presigned URLs (defaults to WM_BASE_URL)
|
||||
# expiry_secs: How long the signatures stay valid, in seconds
|
||||
# (defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
#
|
||||
# Returns:
|
||||
# List of signed public URLs
|
||||
@@ -525,7 +531,7 @@ def sign_s3_object(s3_object: S3Object | str) -> S3Object
|
||||
# Example:
|
||||
# >>> s3_objs = [S3Object(s3="/path/to/file1.txt"), S3Object(s3="/path/to/file2.txt")]
|
||||
# >>> urls = client.get_presigned_s3_public_urls(s3_objs)
|
||||
def get_presigned_s3_public_urls(s3_objects: list[S3Object | str], base_url: str | None = None) -> list[str]
|
||||
def get_presigned_s3_public_urls(s3_objects: list[S3Object | str], base_url: str | None = None, expiry_secs: int | None = None) -> list[str]
|
||||
|
||||
# Generate a presigned public URL for an S3 object.
|
||||
# If the S3 object is not signed yet, it will be signed first.
|
||||
@@ -533,6 +539,8 @@ def get_presigned_s3_public_urls(s3_objects: list[S3Object | str], base_url: str
|
||||
# Args:
|
||||
# s3_object: S3 object to sign
|
||||
# base_url: Optional base URL for the presigned URL (defaults to WM_BASE_URL)
|
||||
# expiry_secs: How long the signature stays valid, in seconds
|
||||
# (defaults to 43200 = 12h, clamped to [60, 604800])
|
||||
#
|
||||
# Returns:
|
||||
# Signed public URL
|
||||
@@ -540,7 +548,7 @@ def get_presigned_s3_public_urls(s3_objects: list[S3Object | str], base_url: str
|
||||
# Example:
|
||||
# >>> s3_obj = S3Object(s3="/path/to/file.txt")
|
||||
# >>> url = client.get_presigned_s3_public_url(s3_obj)
|
||||
def get_presigned_s3_public_url(s3_object: S3Object | str, base_url: str | None = None) -> str
|
||||
def get_presigned_s3_public_url(s3_object: S3Object | str, base_url: str | None = None, expiry_secs: int | None = None) -> str
|
||||
|
||||
# Get the current user information.
|
||||
#
|
||||
|
||||
Vendored
+12
-4
@@ -200,37 +200,45 @@ export declare function writeS3File(
|
||||
/**
|
||||
* Sign S3 objects to be used by anonymous users in public apps
|
||||
* @param s3objects s3 objects to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed s3 objects
|
||||
*/
|
||||
export declare function signS3Objects(
|
||||
s3objects: S3Object[]
|
||||
s3objects: S3Object[],
|
||||
{ expirySecs }?: { expirySecs?: number }
|
||||
): Promise<S3Object[]>;
|
||||
/**
|
||||
* Sign S3 object to be used by anonymous users in public apps
|
||||
* @param s3object s3 object to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed s3 object
|
||||
*/
|
||||
export declare function signS3Object(s3object: S3Object): Promise<S3Object>;
|
||||
export declare function signS3Object(
|
||||
s3object: S3Object,
|
||||
{ expirySecs }?: { expirySecs?: number }
|
||||
): Promise<S3Object>;
|
||||
|
||||
/**
|
||||
* Generate a presigned public URL for an array of S3 objects.
|
||||
* If an S3 object is not signed yet, it will be signed first.
|
||||
* @param s3Objects s3 objects to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns list of signed public URLs
|
||||
*/
|
||||
export declare function getPresignedS3PublicUrls(
|
||||
s3Objects: S3Object[],
|
||||
{ baseUrl }: { baseUrl?: string }
|
||||
{ baseUrl, expirySecs }: { baseUrl?: string; expirySecs?: number }
|
||||
): Promise<string[]>;
|
||||
|
||||
/**
|
||||
* Generate a presigned public URL for an S3 object. If the S3 object is not signed yet, it will be signed first.
|
||||
* @param s3Object s3 object to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed public URL
|
||||
*/
|
||||
export declare function getPresignedS3PublicUrl(
|
||||
s3Objects: S3Object,
|
||||
{ baseUrl }: { baseUrl?: string }
|
||||
{ baseUrl, expirySecs }: { baseUrl?: string; expirySecs?: number }
|
||||
): Promise<string>;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1057,15 +1057,18 @@ export async function deleteS3File(
|
||||
/**
|
||||
* Sign S3 objects to be used by anonymous users in public apps
|
||||
* @param s3objects s3 objects to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed s3 objects
|
||||
*/
|
||||
export async function signS3Objects(
|
||||
s3objects: S3Object[]
|
||||
s3objects: S3Object[],
|
||||
{ expirySecs }: { expirySecs?: number } = {}
|
||||
): Promise<S3Object[]> {
|
||||
const signedKeys = await AppService.signS3Objects({
|
||||
workspace: getWorkspace(),
|
||||
requestBody: {
|
||||
s3_objects: s3objects.map(parseS3Object),
|
||||
expiry_secs: expirySecs,
|
||||
},
|
||||
});
|
||||
return signedKeys;
|
||||
@@ -1073,10 +1076,14 @@ export async function signS3Objects(
|
||||
/**
|
||||
* Sign S3 object to be used by anonymous users in public apps
|
||||
* @param s3object s3 object to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed s3 object
|
||||
*/
|
||||
export async function signS3Object(s3object: S3Object): Promise<S3Object> {
|
||||
const [signedObject] = await signS3Objects([s3object]);
|
||||
export async function signS3Object(
|
||||
s3object: S3Object,
|
||||
{ expirySecs }: { expirySecs?: number } = {}
|
||||
): Promise<S3Object> {
|
||||
const [signedObject] = await signS3Objects([s3object], { expirySecs });
|
||||
return signedObject;
|
||||
}
|
||||
|
||||
@@ -1084,11 +1091,12 @@ export async function signS3Object(s3object: S3Object): Promise<S3Object> {
|
||||
* Generate a presigned public URL for an array of S3 objects.
|
||||
* If an S3 object is not signed yet, it will be signed first.
|
||||
* @param s3Objects s3 objects to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns list of signed public URLs
|
||||
*/
|
||||
export async function getPresignedS3PublicUrls(
|
||||
s3Objects: S3Object[],
|
||||
{ baseUrl }: { baseUrl?: string } = {}
|
||||
{ baseUrl, expirySecs }: { baseUrl?: string; expirySecs?: number } = {}
|
||||
): Promise<string[]> {
|
||||
baseUrl ??= getPublicBaseUrl();
|
||||
|
||||
@@ -1100,7 +1108,8 @@ export async function getPresignedS3PublicUrls(
|
||||
.filter(([s3Obj, _]) => s3Obj.presigned === undefined);
|
||||
if (s3ObjsToSign.length > 0) {
|
||||
const signedS3Objs = await signS3Objects(
|
||||
s3ObjsToSign.map(([s3Obj, _]) => s3Obj)
|
||||
s3ObjsToSign.map(([s3Obj, _]) => s3Obj),
|
||||
{ expirySecs }
|
||||
);
|
||||
for (let i = 0; i < s3ObjsToSign.length; i++) {
|
||||
const [_, originalIndex] = s3ObjsToSign[i];
|
||||
@@ -1120,13 +1129,17 @@ export async function getPresignedS3PublicUrls(
|
||||
/**
|
||||
* Generate a presigned public URL for an S3 object. If the S3 object is not signed yet, it will be signed first.
|
||||
* @param s3Object s3 object to sign
|
||||
* @param expirySecs how long the signature stays valid, in seconds (default 43200 = 12h, clamped to [60, 604800])
|
||||
* @returns signed public URL
|
||||
*/
|
||||
export async function getPresignedS3PublicUrl(
|
||||
s3Objects: S3Object,
|
||||
{ baseUrl }: { baseUrl?: string } = {}
|
||||
{ baseUrl, expirySecs }: { baseUrl?: string; expirySecs?: number } = {}
|
||||
): Promise<string> {
|
||||
const [s3Object] = await getPresignedS3PublicUrls([s3Objects], { baseUrl });
|
||||
const [s3Object] = await getPresignedS3PublicUrls([s3Objects], {
|
||||
baseUrl,
|
||||
expirySecs,
|
||||
});
|
||||
return s3Object;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user