I have a web based remote management portal, which can only connect to the internal network of the managed system, through port 80, which runs the remote management backend server.
On the local network of the system are some AXIS IP cameras which provide MJPEG streams over HTTP. In order to show their image in the web interface, I've made a proxy endpoint on the backend, so a local URL like http://192.168.1.72:8080/streams/example.mjpeg
will be accessed from outside using http://sytem-remote- url.com/proxy/http%3A%2F%2F192.168.1.72%3A8080%2Fstreams%2Fexample.mjpeg
Right now I have this code, made with express
and http-proxy
, which works pretty well.
const generalProxy = httpProxy.createProxyServer()
app.use('/proxy/:url', (req, res) => {
const { url } = req.params
if (!url || typeof url !== 'string') {
res.status(406).send('Missing URL')
return
}
generalProxy.web(req, res, { target: url })
})
BUT - now the IP cameras needs to disable anonymous access, which means that I have to authenticate with a user, in order to access the streams. The AXIS cameras require HTTP Digest Auth, so it's not enough to just to do like http://user:password@...
in the URL, since the Digest Auth makes some ping/pong during the auth when the connection is initialized.
Also, it's a little complicated since the browser showing the web interface is not aware of the different IP camera hosts behind the proxy URL, as they look like they are from the same domain/host to the browser. Therefore, even though the user is prompted for the username/password, the digest auth won't work.
I'm a little lost here. In the above code that proxies the traffic, how can I then make a digest auth on the server side (using credentials stored on the server), while the proxy connection is being established, so that the client will just experience the same as if no HTTP auth was required, but the AXIS IP camera will experience a client that authenticates using HTTP Digest Auth?
I went with this solution:
import { request } from 'urllib'
app.use('/proxy/:url', async (req, res) => {
const { url } = req.params
if (!url || typeof url !== 'string') {
res.status(406).send('Missing URL')
return
}
const { res: targetResult } = await request(url, { digestAuth: 'viewer:viewer', dataType: 'stream' })
res.writeHead(targetResult.statusCode, targetResult.statusText, targetResult.headers)
targetResult.pipe(res, { end: true })
console.log('Starting proxy to', url)
res.on('close', () => console.log('Ended proxy to', url))
})