Переглянути джерело

dev: sign requests sent to Transloadit (#3517)

* dev: sign requests sent to Transloadit

* Address review comments
Antoine du Hamel 3 роки тому
батько
коміт
a77b039efc

+ 1 - 0
.env.example

@@ -53,5 +53,6 @@ VITE_TUS_ENDPOINT=https://tusd.tusdemo.net/files/
 VITE_XHR_ENDPOINT=https://xhr-server.herokuapp.com/upload
 
 VITE_TRANSLOADIT_KEY=***
+VITE_TRANSLOADIT_SECRET=***
 VITE_TRANSLOADIT_TEMPLATE=***
 VITE_TRANSLOADIT_SERVICE_URL=https://api2.transloadit.com

+ 18 - 9
private/dev/Dashboard.js

@@ -26,6 +26,8 @@ import Audio from '@uppy/audio'
 import Compressor from '@uppy/compressor'
 /* eslint-enable import/no-extraneous-dependencies */
 
+import generateSignatureIfSecret from './generateSignatureIfSecret.js'
+
 // DEV CONFIG: create a .env file in the project root directory to customize those values.
 const {
   VITE_UPLOADER : UPLOADER,
@@ -33,17 +35,30 @@ const {
   VITE_TUS_ENDPOINT : TUS_ENDPOINT,
   VITE_XHR_ENDPOINT : XHR_ENDPOINT,
   VITE_TRANSLOADIT_KEY : TRANSLOADIT_KEY,
+  VITE_TRANSLOADIT_SECRET : TRANSLOADIT_SECRET,
   VITE_TRANSLOADIT_TEMPLATE : TRANSLOADIT_TEMPLATE,
   VITE_TRANSLOADIT_SERVICE_URL : TRANSLOADIT_SERVICE_URL,
 } = import.meta.env
 
-import.meta.env.VITE_TRANSLOADIT_KEY = '***' // to avoid leaking secrets in screenshots.
+import.meta.env.VITE_TRANSLOADIT_KEY &&= '***' // to avoid leaking secrets in screenshots.
+import.meta.env.VITE_TRANSLOADIT_SECRET &&= '***' // to avoid leaking secrets in screenshots.
 console.log(import.meta.env)
 
 // DEV CONFIG: enable or disable Golden Retriever
 
 const RESTORE = false
 
+async function getAssemblyOptions () {
+  return generateSignatureIfSecret(TRANSLOADIT_SECRET, {
+    auth: {
+      key: TRANSLOADIT_KEY,
+    },
+    // It's more secure to use a template_id and enable
+    // Signature Authentication
+    template_id: TRANSLOADIT_TEMPLATE,
+  })
+}
+
 // Rest is implementation! Obviously edit as necessary...
 
 export default () => {
@@ -111,10 +126,7 @@ export default () => {
       uppyDashboard.use(Transloadit, {
         service: TRANSLOADIT_SERVICE_URL,
         waitForEncoding: true,
-        params: {
-          auth: { key: TRANSLOADIT_KEY },
-          template_id: TRANSLOADIT_TEMPLATE,
-        },
+        getAssemblyOptions,
       })
       break
     case 'transloadit-s3':
@@ -122,10 +134,7 @@ export default () => {
       uppyDashboard.use(Transloadit, {
         waitForEncoding: true,
         importFromUploadURLs: true,
-        params: {
-          auth: { key: TRANSLOADIT_KEY },
-          template_id: TRANSLOADIT_TEMPLATE,
-        },
+        getAssemblyOptions,
       })
       break
     case 'transloadit-xhr':

+ 2 - 1
private/dev/DragDrop.js

@@ -11,7 +11,8 @@ const {
   VITE_TUS_ENDPOINT : TUS_ENDPOINT,
 } = import.meta.env
 
-import.meta.env.VITE_TRANSLOADIT_KEY = '***' // to avoid leaking secrets in screenshots.
+import.meta.env.VITE_TRANSLOADIT_KEY &&= '***' // to avoid leaking secrets in screenshots.
+import.meta.env.VITE_TRANSLOADIT_SECRET &&= '***' // to avoid leaking secrets in screenshots.
 console.log(import.meta.env)
 
 export default () => {

+ 34 - 0
private/dev/generateSignatureIfSecret.js

@@ -0,0 +1,34 @@
+const enc = new TextEncoder('utf-8')
+async function sign (secret, body) {
+  const algorithm = { name: 'HMAC', hash: 'SHA-384' }
+
+  const key = await crypto.subtle.importKey('raw', enc.encode(secret), algorithm, false, ['sign', 'verify'])
+  const signature = await crypto.subtle.sign(algorithm.name, key, enc.encode(body))
+  return `sha384:${Array.from(new Uint8Array(signature), x => x.toString(16).padStart(2, '0')).join('')}`
+}
+function getExpiration (future) {
+  return new Date(Date.now() + future)
+    .toISOString()
+    .replace('T', ' ')
+    .replace(/\.\d+Z$/, '+00:00')
+}
+/**
+ * Adds an expiration date and signs the params object if a secret is passed to
+ * it. If no secret is given, it returns the same object.
+ *
+ * @param {string | undefined} secret
+ * @param {object} params
+ * @returns {{ params: string, signature?: string }}
+ */
+export default async function generateSignatureIfSecret (secret, params) {
+  let signature
+  if (secret) {
+    // eslint-disable-next-line no-param-reassign
+    params.auth.expires = getExpiration(5 * 60 * 1000)
+    // eslint-disable-next-line no-param-reassign
+    params = JSON.stringify(params)
+    signature = await sign(secret, params)
+  }
+
+  return { params, signature }
+}