From b701e8c68c1122bf138575804af41260ec1c436d Mon Sep 17 00:00:00 2001 From: Samuel Newman Date: Wed, 7 Aug 2024 16:56:12 +0100 Subject: [PATCH] [Video] Authed video upload (#4885) * add service auth call * update API package --------- Co-authored-by: Samuel Newman <10959775+mozzius@users.noreply.github.com> --- package.json | 2 +- src/state/queries/video/video-upload.ts | 26 +++++++++++++++------ src/state/queries/video/video-upload.web.ts | 22 +++++++++++++---- yarn.lock | 8 +++---- 4 files changed, 42 insertions(+), 16 deletions(-) diff --git a/package.json b/package.json index 3d053bc8..faeee448 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "open-analyzer": "EXPO_PUBLIC_OPEN_ANALYZER=1 yarn build-web" }, "dependencies": { - "@atproto/api": "^0.12.26", + "@atproto/api": "0.12.29", "@bam.tech/react-native-image-resizer": "^3.0.4", "@braintree/sanitize-url": "^6.0.2", "@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet", diff --git a/src/state/queries/video/video-upload.ts b/src/state/queries/video/video-upload.ts index 4d7f7995..cf741b25 100644 --- a/src/state/queries/video/video-upload.ts +++ b/src/state/queries/video/video-upload.ts @@ -2,10 +2,11 @@ import {createUploadTask, FileSystemUploadType} from 'expo-file-system' import {useMutation} from '@tanstack/react-query' import {nanoid} from 'nanoid/non-secure' -import {CompressedVideo} from 'lib/media/video/compress' -import {UploadVideoResponse} from 'lib/media/video/types' -import {createVideoEndpointUrl} from 'state/queries/video/util' -import {useSession} from 'state/session' +import {CompressedVideo} from '#/lib/media/video/compress' +import {UploadVideoResponse} from '#/lib/media/video/types' +import {createVideoEndpointUrl} from '#/state/queries/video/util' +import {useAgent, useSession} from '#/state/session' + const UPLOAD_HEADER = process.env.EXPO_PUBLIC_VIDEO_HEADER ?? '' export const useUploadVideoMutation = ({ @@ -18,6 +19,7 @@ export const useUploadVideoMutation = ({ setProgress: (progress: number) => void }) => { const {currentAccount} = useSession() + const agent = useAgent() return useMutation({ mutationFn: async (video: CompressedVideo) => { @@ -26,6 +28,17 @@ export const useUploadVideoMutation = ({ name: `${nanoid(12)}.mp4`, // @TODO what are we limiting this to? }) + // a logged-in agent should have this set, but we'll check just in case + if (!agent.pdsUrl) { + throw new Error('Agent does not have a PDS URL') + } + + const {data: serviceAuth} = + await agent.api.com.atproto.server.getServiceAuth({ + aud: `did:web:${agent.pdsUrl.hostname}`, + lxm: 'com.atproto.repo.uploadBlob', + }) + const uploadTask = createUploadTask( uri, video.uri, @@ -33,13 +46,12 @@ export const useUploadVideoMutation = ({ headers: { 'dev-key': UPLOAD_HEADER, 'content-type': 'video/mp4', // @TODO same question here. does the compression step always output mp4? + Authorization: `Bearer ${serviceAuth.token}`, }, httpMethod: 'POST', uploadType: FileSystemUploadType.BINARY_CONTENT, }, - p => { - setProgress(p.totalBytesSent / p.totalBytesExpectedToSend) - }, + p => setProgress(p.totalBytesSent / p.totalBytesExpectedToSend), ) const res = await uploadTask.uploadAsync() diff --git a/src/state/queries/video/video-upload.web.ts b/src/state/queries/video/video-upload.web.ts index b5b9e93b..b9b0bacf 100644 --- a/src/state/queries/video/video-upload.web.ts +++ b/src/state/queries/video/video-upload.web.ts @@ -1,10 +1,11 @@ import {useMutation} from '@tanstack/react-query' import {nanoid} from 'nanoid/non-secure' -import {CompressedVideo} from 'lib/media/video/compress' -import {UploadVideoResponse} from 'lib/media/video/types' -import {createVideoEndpointUrl} from 'state/queries/video/util' -import {useSession} from 'state/session' +import {CompressedVideo} from '#/lib/media/video/compress' +import {UploadVideoResponse} from '#/lib/media/video/types' +import {createVideoEndpointUrl} from '#/state/queries/video/util' +import {useAgent, useSession} from '#/state/session' + const UPLOAD_HEADER = process.env.EXPO_PUBLIC_VIDEO_HEADER ?? '' export const useUploadVideoMutation = ({ @@ -17,6 +18,7 @@ export const useUploadVideoMutation = ({ setProgress: (progress: number) => void }) => { const {currentAccount} = useSession() + const agent = useAgent() return useMutation({ mutationFn: async (video: CompressedVideo) => { @@ -25,6 +27,17 @@ export const useUploadVideoMutation = ({ name: `${nanoid(12)}.mp4`, // @TODO what are we limiting this to? }) + // a logged-in agent should have this set, but we'll check just in case + if (!agent.pdsUrl) { + throw new Error('Agent does not have a PDS URL') + } + + const {data: serviceAuth} = + await agent.api.com.atproto.server.getServiceAuth({ + aud: `did:web:${agent.pdsUrl.hostname}`, + lxm: 'com.atproto.repo.uploadBlob', + }) + const bytes = await fetch(video.uri).then(res => res.arrayBuffer()) const xhr = new XMLHttpRequest() @@ -53,6 +66,7 @@ export const useUploadVideoMutation = ({ xhr.setRequestHeader('Content-Type', 'video/mp4') // @TODO how we we set the proper content type? // @TODO remove this header for prod xhr.setRequestHeader('dev-key', UPLOAD_HEADER) + xhr.setRequestHeader('Authorization', `Bearer ${serviceAuth.token}`) xhr.send(bytes) })) as UploadVideoResponse diff --git a/yarn.lock b/yarn.lock index 6fa88051..16547aa3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -34,10 +34,10 @@ jsonpointer "^5.0.0" leven "^3.1.0" -"@atproto/api@^0.12.26": - version "0.12.26" - resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.12.26.tgz#940888466522cc9ff8c03d8164dc39221b29d9ca" - integrity sha512-RH0ymOGbDfT8IL8eNzzY+hwtyTgknHfkzUVqRd0sstNblvTf8WGpDR2FSTveiiMR3OpVO6zG8fRYVzBfmY1+pA== +"@atproto/api@0.12.29": + version "0.12.29" + resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.12.29.tgz#95a19202c2f0eec4c955909685be11009ba9b9a1" + integrity sha512-PyzPLjGWR0qNOMrmj3Nt3N5NuuANSgOk/33Bu3j+rFjjPrHvk9CI6iQPU6zuDaDCoyOTRJRafw8X/aMQw+ilgw== dependencies: "@atproto/common-web" "^0.3.0" "@atproto/lexicon" "^0.4.0"