Bluesky app fork with some witchin' additions 💫

[Video] Authed video upload (#4885)

* add service auth call

* update API package

---------

Co-authored-by: Samuel Newman <10959775+mozzius@users.noreply.github.com>

authored by samuel.fm

Samuel Newman and committed by
GitHub
b701e8c6 753a2334

+42 -16
+1 -1
package.json
··· 52 52 "open-analyzer": "EXPO_PUBLIC_OPEN_ANALYZER=1 yarn build-web" 53 53 }, 54 54 "dependencies": { 55 - "@atproto/api": "^0.12.26", 55 + "@atproto/api": "0.12.29", 56 56 "@bam.tech/react-native-image-resizer": "^3.0.4", 57 57 "@braintree/sanitize-url": "^6.0.2", 58 58 "@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet",
+19 -7
src/state/queries/video/video-upload.ts
··· 2 2 import {useMutation} from '@tanstack/react-query' 3 3 import {nanoid} from 'nanoid/non-secure' 4 4 5 - import {CompressedVideo} from 'lib/media/video/compress' 6 - import {UploadVideoResponse} from 'lib/media/video/types' 7 - import {createVideoEndpointUrl} from 'state/queries/video/util' 8 - import {useSession} from 'state/session' 5 + import {CompressedVideo} from '#/lib/media/video/compress' 6 + import {UploadVideoResponse} from '#/lib/media/video/types' 7 + import {createVideoEndpointUrl} from '#/state/queries/video/util' 8 + import {useAgent, useSession} from '#/state/session' 9 + 9 10 const UPLOAD_HEADER = process.env.EXPO_PUBLIC_VIDEO_HEADER ?? '' 10 11 11 12 export const useUploadVideoMutation = ({ ··· 18 19 setProgress: (progress: number) => void 19 20 }) => { 20 21 const {currentAccount} = useSession() 22 + const agent = useAgent() 21 23 22 24 return useMutation({ 23 25 mutationFn: async (video: CompressedVideo) => { ··· 26 28 name: `${nanoid(12)}.mp4`, // @TODO what are we limiting this to? 27 29 }) 28 30 31 + // a logged-in agent should have this set, but we'll check just in case 32 + if (!agent.pdsUrl) { 33 + throw new Error('Agent does not have a PDS URL') 34 + } 35 + 36 + const {data: serviceAuth} = 37 + await agent.api.com.atproto.server.getServiceAuth({ 38 + aud: `did:web:${agent.pdsUrl.hostname}`, 39 + lxm: 'com.atproto.repo.uploadBlob', 40 + }) 41 + 29 42 const uploadTask = createUploadTask( 30 43 uri, 31 44 video.uri, ··· 33 46 headers: { 34 47 'dev-key': UPLOAD_HEADER, 35 48 'content-type': 'video/mp4', // @TODO same question here. does the compression step always output mp4? 49 + Authorization: `Bearer ${serviceAuth.token}`, 36 50 }, 37 51 httpMethod: 'POST', 38 52 uploadType: FileSystemUploadType.BINARY_CONTENT, 39 53 }, 40 - p => { 41 - setProgress(p.totalBytesSent / p.totalBytesExpectedToSend) 42 - }, 54 + p => setProgress(p.totalBytesSent / p.totalBytesExpectedToSend), 43 55 ) 44 56 const res = await uploadTask.uploadAsync() 45 57
+18 -4
src/state/queries/video/video-upload.web.ts
··· 1 1 import {useMutation} from '@tanstack/react-query' 2 2 import {nanoid} from 'nanoid/non-secure' 3 3 4 - import {CompressedVideo} from 'lib/media/video/compress' 5 - import {UploadVideoResponse} from 'lib/media/video/types' 6 - import {createVideoEndpointUrl} from 'state/queries/video/util' 7 - import {useSession} from 'state/session' 4 + import {CompressedVideo} from '#/lib/media/video/compress' 5 + import {UploadVideoResponse} from '#/lib/media/video/types' 6 + import {createVideoEndpointUrl} from '#/state/queries/video/util' 7 + import {useAgent, useSession} from '#/state/session' 8 + 8 9 const UPLOAD_HEADER = process.env.EXPO_PUBLIC_VIDEO_HEADER ?? '' 9 10 10 11 export const useUploadVideoMutation = ({ ··· 17 18 setProgress: (progress: number) => void 18 19 }) => { 19 20 const {currentAccount} = useSession() 21 + const agent = useAgent() 20 22 21 23 return useMutation({ 22 24 mutationFn: async (video: CompressedVideo) => { ··· 25 27 name: `${nanoid(12)}.mp4`, // @TODO what are we limiting this to? 26 28 }) 27 29 30 + // a logged-in agent should have this set, but we'll check just in case 31 + if (!agent.pdsUrl) { 32 + throw new Error('Agent does not have a PDS URL') 33 + } 34 + 35 + const {data: serviceAuth} = 36 + await agent.api.com.atproto.server.getServiceAuth({ 37 + aud: `did:web:${agent.pdsUrl.hostname}`, 38 + lxm: 'com.atproto.repo.uploadBlob', 39 + }) 40 + 28 41 const bytes = await fetch(video.uri).then(res => res.arrayBuffer()) 29 42 30 43 const xhr = new XMLHttpRequest() ··· 53 66 xhr.setRequestHeader('Content-Type', 'video/mp4') // @TODO how we we set the proper content type? 54 67 // @TODO remove this header for prod 55 68 xhr.setRequestHeader('dev-key', UPLOAD_HEADER) 69 + xhr.setRequestHeader('Authorization', `Bearer ${serviceAuth.token}`) 56 70 xhr.send(bytes) 57 71 })) as UploadVideoResponse 58 72
+4 -4
yarn.lock
··· 34 34 jsonpointer "^5.0.0" 35 35 leven "^3.1.0" 36 36 37 - "@atproto/api@^0.12.26": 38 - version "0.12.26" 39 - resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.12.26.tgz#940888466522cc9ff8c03d8164dc39221b29d9ca" 40 - integrity sha512-RH0ymOGbDfT8IL8eNzzY+hwtyTgknHfkzUVqRd0sstNblvTf8WGpDR2FSTveiiMR3OpVO6zG8fRYVzBfmY1+pA== 37 + "@atproto/api@0.12.29": 38 + version "0.12.29" 39 + resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.12.29.tgz#95a19202c2f0eec4c955909685be11009ba9b9a1" 40 + integrity sha512-PyzPLjGWR0qNOMrmj3Nt3N5NuuANSgOk/33Bu3j+rFjjPrHvk9CI6iQPU6zuDaDCoyOTRJRafw8X/aMQw+ilgw== 41 41 dependencies: 42 42 "@atproto/common-web" "^0.3.0" 43 43 "@atproto/lexicon" "^0.4.0"