Last active
November 12, 2022 23:03
-
-
Save zerg000000/40978e85a971286e926dfcde0af7188a to your computer and use it in GitHub Desktop.
S3 presign (post) example aws-api
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(require '[buddy.core.codecs.base64 :as base64] | |
'[cognitect.aws.util :as util] | |
'[clojure.string :as str] | |
'[jsonista.core :as json] | |
'[cognitect.aws.credentials :as creds] | |
'[cognitect.aws.http :as http]) | |
(import '[java.util Date]) | |
(defn host-style-bucket-uri [bucket] | |
(str "http://" bucket ".s3.amazonaws.com/")) | |
(defn new-x-amz-date | |
([] (new-x-amz-date (Date.))) | |
([d] (->> (util/format-date util/x-amz-date-format d) | |
(util/parse-date util/x-amz-date-format)))) | |
(defn credential-scope | |
[{:keys [region service] :as auth-info} x-amz-date] | |
(str/join "/" [(get-in auth-info [:aws/access-key-id]) | |
(->> x-amz-date | |
(util/format-date util/x-amz-date-only-format)) | |
region | |
service | |
"aws4_request"])) | |
(defn signature | |
[{:keys [region service] :as auth-info} string x-amz-date] | |
(util/hex-encode | |
(util/hmac-sha-256 (-> (.getBytes (str "AWS4" (get-in auth-info [:aws/secret-access-key])) "UTF-8") | |
(util/hmac-sha-256 (util/format-date util/x-amz-date-only-format x-amz-date)) | |
(util/hmac-sha-256 region) | |
(util/hmac-sha-256 service) | |
(util/hmac-sha-256 "aws4_request")) | |
string))) | |
(defn new-policy | |
"Create Policy for S3 Presign POST upload" | |
[{:keys [bucket] :as auth-info} key expiration conditions] | |
(let [x-amz-date (new-x-amz-date)] | |
{"conditions" (cond-> [{"bucket" bucket} | |
{"key" key} | |
{"x-amz-credential" (credential-scope auth-info x-amz-date)} | |
{"x-amz-algorithm" "AWS4-HMAC-SHA256"} | |
{"x-amz-date" (util/format-date util/x-amz-date-format x-amz-date)}] | |
conditions | |
(into conditions) | |
(:aws/session-token auth-info) | |
(conj {"x-amz-security-token" (:aws/session-token auth-info)})) | |
"expiration" (util/format-date util/iso8601-msecs-date-format expiration)})) | |
(defn get-cred-from-env [] | |
(creds/fetch (creds/default-credentials-provider (http/resolve-http-client nil)))) | |
(defn presign | |
"Create a browser based Image Upload payload as mentioned in | |
https://docs.aws.amazon.com/AmazonS3/latest/API/sigv4-post-example.html" | |
[s3 key content-type expiration conditions] | |
(let [auth-info (merge (get-cred-from-env) | |
s3) | |
now (new-x-amz-date) | |
policy-string (-> (new-policy auth-info key expiration conditions) | |
(json/write-value-as-bytes) | |
(base64/encode) | |
(String.))] | |
(cond-> {:key key | |
:Content-Type content-type | |
:X-Amz-Credential (credential-scope auth-info now) | |
:X-Amz-Algorithm "AWS4-HMAC-SHA256" | |
:X-Amz-Date (util/format-date util/x-amz-date-format now) | |
:Policy policy-string | |
:X-Amz-Signature (signature auth-info policy-string now)} | |
(:aws/session-token auth-info) | |
(assoc :X-Amz-Security-Token (:aws/session-token auth-info))))) | |
;;;; Usage | |
(let [_id "my-file-name" | |
bucket {:bucket "my-s3-bucket" | |
:folder "my-private-folder" | |
:aws-region "ap-eastnorth-1" ; assume inside ecs container, aws-region need to provided by ourselves, since aws-api cannot fetch it from env correctly | |
:conditions [["starts-with" "$Content-Type" "image/"] | |
; limit size to 1byte - 10M | |
["content-length-range" 1 10485760]] | |
:service "s3"}] | |
{:uri (host-style-bucket-uri (:bucket bucket)) | |
:form-data (presign bucket | |
(str (:folder bucket) "/" (.toString _id)) | |
"image/jpeg" | |
expire | |
(:conditions bucket)) | |
:expires-on expire | |
:_id _id}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment