Skip to content

Add to the hubBlob().serve() method options object with the property onlyStream to prevent downloading videos #444

Closed as not planned
@serhii-chernenko

Description

@serhii-chernenko

Is your feature request related to a problem? Please describe.
I have a simple component with an HTML5 video tag:

<ClientOnly>
  <video
    controls
    playsinline
    preload="preload"
    controlsList="noplaybackrate"
    src="/api/v1/videos/stream/custom-name.mp4"
  />
</ClientOnly>

I prepared an API endpoint to stream video blobs by name:

server/api/v1/videos/stream/[pathname].get.ts
import { z } from 'zod'

const rules = z.object({
  pathname: z.string().nonempty().max(255),
})

export default defineEventHandler(async (event) => {
  const params = await getValidatedRouterParams(
    event,
    rules.safeParse,
  )

  if (params.error) {
    throw createError({
      statusCode: 400,
      statusMessage: 'Invalid URL parameters',
      data: params.error,
    })
  }

  const { pathname } = params.data

  setHeader(event, 'Content-Security-Policy', 'default-src \'none\';')

  return hubBlob().serve(event, pathname)
})

When the video is loaded, I can download it:
Image
Image

Describe the solution you'd like
I decided to create a middleware

server/middleware/stream.ts

And check range and referrer headers in the request. If they are missed, throw an Unauthorized 403 error:

export default defineEventHandler((event) => {
  const url = getRequestURL(event).toString()

  if (url.includes('videos/stream')) {
    const referrer = getHeader(event, 'referer')
    const range = getHeader(event, 'range')

    if (!referrer || !range) {
      throw createError({
        statusCode: 403,
        statusMessage: 'Unauthorized',
      })
    }
  }
})

The issue has solved for me:
Image

I expect similar behavior for the serve function when the onlyStream option is provided:

return hubBlob().serve(event, pathname, {
  onlyStream: true,
})

Additional context
Please don't suggest adding nodownload to the controlsList of the video tag because it could be simply “hacked” by any user who knows how to open DevTools.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions