(ns creator.handler | |
(:require [compojure.core :refer :all] | |
[compojure.handler :as handler] | |
[compojure.route :as route] | |
[ring.middleware.params :refer [wrap-params]] | |
[hiccup.page :refer [html5 include-css include-js]] | |
[clojure.data.json :as json] | |
[ring.util.codec :refer [base64-encode]]) | |
(:import (javax.crypto Mac) | |
(javax.crypto.spec SecretKeySpec) | |
(java.text SimpleDateFormat) | |
(java.util Date TimeZone))) | |
(def s3-bucket "your-bucket") | |
(def aws-access-key "key") | |
(def aws-secret-key "secret") | |
(defn now-plus [n] | |
"Returns current time plus `n` minutes as string" | |
(let [f (SimpleDateFormat. "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") | |
_ (.setTimeZone f (TimeZone/getTimeZone "UTC" ))] | |
(.format f (Date. (+ (System/currentTimeMillis) (* n 60 1000)))))) | |
(defn policy | |
"Generate policy for upload of `key` with `mime-type` to be uploaded | |
within optional `expiration-window` (defaults to 60)." | |
([key mime-type] | |
(policy key mime-type 60)) | |
([key mime-type expiration-window] | |
(ring.util.codec/base64-encode | |
(.getBytes (json/write-str { "expiration" (now-plus expiration-window) | |
"conditions" [{"bucket" s3-bucket} | |
{"acl" "public-read"} | |
["starts-with" "$Content-Type" mime-type] | |
["starts-with" "$key" key] | |
{"success_action_status" "201"}]}) | |
"UTF-8")))) | |
(defn hmac-sha1 [key string] | |
"Returns signature of `string` with a given `key` using SHA-1 HMAC." | |
(ring.util.codec/base64-encode | |
(.doFinal (doto (javax.crypto.Mac/getInstance "HmacSHA1") | |
(.init (javax.crypto.spec.SecretKeySpec. (.getBytes key) "HmacSHA1"))) | |
(.getBytes string "UTF-8")))) | |
(defn sign-upload [{:keys [file-name mime-type]}] | |
(let [p (policy file-name mime-type)] | |
{:action (str "https://" s3-bucket ".s3-eu-west-1.amazonaws.com/") | |
:key file-name | |
:Content-Type mime-type | |
:policy p | |
:acl "public-read" | |
:success_action_status "201" | |
:AWSAccessKeyId aws-access-key | |
:signature (hmac-sha1 aws-secret-key p)})) | |
(defroutes app-routes | |
(GET "/" [] app-template) | |
(GET "/sign" {params :params} {:status 200 :body (pr-str (sign-upload params))}) | |
(route/resources "/") | |
(route/not-found "Not Found")) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment