fix(desktop): send the connection extra gateway headers on remote media streams
createMediaProtocolHandler() set only the session token / bearer on the /api/files/stream request. The descriptor it resolves now carries the connection's extra gateway headers, but the handler never read them, so attachments in session history from a header-gated remote still bounced off the access proxy even though every fetchJsonForBackend() call got through. Merge connection.headers into the media request before auth, letting the forwarded range/cache negotiation headers win, and pin it on both the token and the OAuth cookie-session legs. Part of #112072
This commit is contained in:
@@ -164,6 +164,44 @@ describe('createMediaProtocolHandler', () => {
|
||||
expect(headers.get('range')).toBe('bytes=0-1023')
|
||||
})
|
||||
|
||||
it('sends the connection extra gateway headers on remote media without clobbering range negotiation', async () => {
|
||||
const deps = dependencies({
|
||||
resolveRemoteConnection: vi.fn(async () => ({
|
||||
authMode: 'token' as const,
|
||||
baseUrl: 'https://gateway.test',
|
||||
headers: { 'CF-Access-Client-Id': 'client-id', Range: 'bytes=9-9' },
|
||||
mode: 'remote' as const,
|
||||
token: 'secret'
|
||||
}))
|
||||
})
|
||||
|
||||
await createMediaProtocolHandler(deps)(
|
||||
request('hermes-media://remote/%2Ftmp%2Fclip.mp4', { Range: 'bytes=0-1023' })
|
||||
)
|
||||
|
||||
const [, headers] = vi.mocked(deps.fetchRemote).mock.calls[0]
|
||||
expect(headers.get('cf-access-client-id')).toBe('client-id')
|
||||
expect(headers.get('range')).toBe('bytes=0-1023')
|
||||
expect(headers.get('x-hermes-session-token')).toBe('secret')
|
||||
})
|
||||
|
||||
it('sends the connection extra gateway headers on OAuth cookie-session remote media', async () => {
|
||||
const deps = dependencies({
|
||||
resolveRemoteConnection: vi.fn(async () => ({
|
||||
authMode: 'oauth' as const,
|
||||
baseUrl: 'https://gateway.test',
|
||||
headers: { 'CF-Access-Client-Id': 'client-id' },
|
||||
mode: 'remote' as const,
|
||||
token: null
|
||||
}))
|
||||
})
|
||||
|
||||
await createMediaProtocolHandler(deps)(request('hermes-media://remote/%2Ftmp%2Fclip.mp4'))
|
||||
|
||||
const [, headers] = vi.mocked(deps.fetchRemoteWithCookies).mock.calls[0]
|
||||
expect(headers.get('cf-access-client-id')).toBe('client-id')
|
||||
})
|
||||
|
||||
it('adds profile scope when one registry backend serves multiple profiles', async () => {
|
||||
const deps = dependencies({
|
||||
resolveRemoteConnection: vi.fn(async () => ({
|
||||
|
||||
@@ -36,6 +36,7 @@ export interface MediaRemoteScope {
|
||||
export interface MediaRemoteConnection {
|
||||
authMode?: 'oauth' | 'token'
|
||||
baseUrl: string
|
||||
headers?: Record<string, string>
|
||||
mode?: 'local' | 'remote'
|
||||
token?: null | string
|
||||
sharedRemote?: boolean
|
||||
@@ -163,6 +164,14 @@ export function createMediaProtocolHandler(dependencies: MediaProtocolDependenci
|
||||
connection.sharedRemote ? target.profile : undefined
|
||||
)
|
||||
|
||||
// The gateway's configured extra headers (access-proxy gates) travel on
|
||||
// every remote request; forwarded range/cache negotiation headers win.
|
||||
for (const [name, value] of Object.entries(connection.headers ?? {})) {
|
||||
if (!headers.has(name)) {
|
||||
headers.set(name, value)
|
||||
}
|
||||
}
|
||||
|
||||
if (connection.authMode === 'oauth') {
|
||||
return await requestWithOauthFallback(connection.baseUrl, {
|
||||
ensureNativeAccessToken: dependencies.ensureRemoteBearer,
|
||||
|
||||
Reference in New Issue
Block a user