update
This commit is contained in:
+51
-11
@@ -4,7 +4,7 @@ export
|
||||
LifecycleExpiration, build_lifecycle_xml,
|
||||
GarageStorage, put_file, get_file, list_files, delete_file,
|
||||
set_lifecycle_expiration, get_lifecycle, delete_lifecycle,
|
||||
s3_sign_url
|
||||
s3_sign_url, s3_sign_url_web
|
||||
|
||||
using AWS
|
||||
@service S3
|
||||
@@ -24,7 +24,7 @@ storage1 = GeneralUtils.GarageStorage(
|
||||
"https://s3-api.yiem.cc",
|
||||
"GKb080154a2e5b19100b1b2c6e", # key ID (create at garage-ui.yiem.cc)
|
||||
"a2c6b1379c2f731d3e6e5a408dd4d6cffca7511717675f55114ff94828febca1", # key ID's secret key
|
||||
"testbucket"
|
||||
"sommpanion"
|
||||
)
|
||||
|
||||
# Safe to run inside concurrent HTTP handlers (e.g., Oxygen.jl, HTTP.jl)
|
||||
@@ -347,6 +347,9 @@ function s3_sign_url(
|
||||
scope = "$date_stamp/$region/$service/$terminator"
|
||||
|
||||
headers = OrderedDict{String,String}("Host" => URIs.URI(endpoint).host)
|
||||
if verb == "PUT"
|
||||
headers["Content-Type"] = content_type
|
||||
end
|
||||
sort!(headers; by=name -> lowercase(name))
|
||||
canonical_header_names = join(map(name -> lowercase(name), collect(keys(headers))), ";")
|
||||
|
||||
@@ -355,11 +358,11 @@ function s3_sign_url(
|
||||
"X-Amz-Algorithm" => "$scheme-$algorithm",
|
||||
"X-Amz-Credential" => "$(creds.access_key_id)/$scope",
|
||||
"X-Amz-Date" => datetime_stamp,
|
||||
"X-Amz-Security-Token" => isempty(creds.token) ? "" : creds.token,
|
||||
"X-Amz-SignedHeaders" => canonical_header_names,
|
||||
)
|
||||
|
||||
sort!(query; by=name -> lowercase(name))
|
||||
if !isempty(creds.token)
|
||||
query["X-Amz-Security-Token"] = creds.token
|
||||
end
|
||||
|
||||
canonical_headers = join(
|
||||
map(
|
||||
@@ -370,12 +373,24 @@ function s3_sign_url(
|
||||
|
||||
resource_path = "/$bucket/$key"
|
||||
|
||||
# Build canonical query string: sort by key=value pair lexicographically,
|
||||
# URL-encoding each key and value (matching Garage's uri_encode)
|
||||
sorted_q = sort(
|
||||
[URIs.escapeuri(k) * "=" * URIs.escapeuri(v) for (k, v) in pairs(query)],
|
||||
by=lowercase,
|
||||
)
|
||||
canonical_query = join(sorted_q, "&")
|
||||
|
||||
canonical_request = string(
|
||||
"$verb\n",
|
||||
"$(URIs.escapeuri(resource_path))\n",
|
||||
"$(URIs.escapeuri(query))\n",
|
||||
"$canonical_headers\n",
|
||||
"$canonical_header_names\n",
|
||||
resource_path,
|
||||
"\n",
|
||||
canonical_query,
|
||||
"\n",
|
||||
canonical_headers,
|
||||
"\n",
|
||||
canonical_header_names,
|
||||
"\n",
|
||||
"UNSIGNED-PAYLOAD",
|
||||
)
|
||||
|
||||
@@ -386,8 +401,8 @@ function s3_sign_url(
|
||||
bytes2hex(digest(MD_SHA256, canonical_request)),
|
||||
)
|
||||
|
||||
key_secret = string(scheme, creds.secret_key)
|
||||
key_date = digest(MD_SHA256, date_stamp, key_secret)
|
||||
key_secret_bytes = Vector{UInt8}(string(scheme, creds.secret_key))
|
||||
key_date = digest(MD_SHA256, date_stamp, key_secret_bytes)
|
||||
key_region = digest(MD_SHA256, region, key_date)
|
||||
key_service = digest(MD_SHA256, service, key_region)
|
||||
key_signing = digest(MD_SHA256, terminator, key_service)
|
||||
@@ -399,6 +414,31 @@ function s3_sign_url(
|
||||
return "$(endpoint)/$bucket/$key?$query_string"
|
||||
end
|
||||
|
||||
""" Generate a pre-signed URL using the Garage S3 web endpoint (s3-web).
|
||||
|
||||
Useful for direct browser access — URLs look like
|
||||
`https://s3-web.yiem.cc/bucket/key?X-Amz-Signature=...`
|
||||
|
||||
Arguments and keyword arguments are the same as `s3_sign_url`.
|
||||
"""
|
||||
function s3_sign_url_web(
|
||||
storage::GarageStorage,
|
||||
key::String,
|
||||
seconds::Int=3600;
|
||||
verb::String="GET",
|
||||
content_type::String="application/octet-stream",
|
||||
signature_version::String="v4",
|
||||
)::String
|
||||
web_endpoint = replace(storage.config.endpoint, "s3-api" => "s3-web")
|
||||
web_creds = SimpleCredentials(
|
||||
storage.config.credentials.access_key_id,
|
||||
storage.config.credentials.secret_key,
|
||||
storage.config.credentials.token,
|
||||
)
|
||||
web_config = GarageConfig(web_endpoint, storage.config.region, web_creds)
|
||||
web_storage = GarageStorage(web_config, storage.bucket)
|
||||
return s3_sign_url(web_storage, key, seconds; verb, content_type, signature_version)
|
||||
end
|
||||
|
||||
# ===================================================================
|
||||
# 3. Bucket Lifecycle Configuration
|
||||
|
||||
Reference in New Issue
Block a user