rebroadcast: Fix rtsp client auth bugs

This commit is contained in:
Koushik Dutta
2022-04-20 09:33:29 -07:00
parent bfed0527e7
commit 34d5efd7ef
3 changed files with 41 additions and 34 deletions

View File

@@ -178,7 +178,7 @@ const quote = (str: string): string => `"${str.replace(/"/g, '\\"')}"`;
export class RtspClient extends RtspBase {
cseq = 0;
session: string;
authorization: string;
wwwAuthenticate: string;
requestTimeout: number;
rfc4571 = new PassThrough();
needKeepAlive = false;
@@ -224,9 +224,10 @@ export class RtspClient extends RtspBase {
const line = `${method} ${fullUrl} RTSP/1.0`;
const cseq = this.cseq++;
headers['CSeq'] = cseq.toString();
headers['User-Agent'] = 'Scrypted';
if (this.authorization)
headers['Authorization'] = this.authorization;
if (this.wwwAuthenticate)
headers['Authorization'] = this.createAuthorizationHeader(method);
if (this.session)
headers['Session'] = this.session;
@@ -285,6 +286,39 @@ export class RtspClient extends RtspBase {
}
}
createAuthorizationHeader(method: string) {
if (!this.wwwAuthenticate)
throw new Error('no WWW-Authenticate found');
const parsedUrl = new URL(this.url);
if (this.wwwAuthenticate.includes('Basic')) {
const hash = BASIC.computeHash(parsedUrl);
return `Basic ${hash}`;
}
const wwwAuth = DIGEST.parseWWWAuthenticateRest(this.wwwAuthenticate);
const username = decodeURIComponent(parsedUrl.username);
const password = decodeURIComponent(parsedUrl.password);
const ha1 = crypto.createHash('md5').update(`${username}:${wwwAuth.realm}:${password}`).digest('hex');
const ha2 = crypto.createHash('md5').update(`${method}:${parsedUrl.pathname}`).digest('hex');
const hash = crypto.createHash('md5').update(`${ha1}:${wwwAuth.nonce}:${ha2}`).digest('hex');
const params = {
username,
realm: wwwAuth.realm,
nonce: wwwAuth.nonce,
uri: parsedUrl.pathname,
algorithm: 'MD5',
response: hash,
};
const paramsString = Object.entries(params).map(([key, value]) => `${key}=${value && quote(value)}`).join(', ');
return `Digest ${paramsString}`;
}
async request(method: string, headers?: Headers, path?: string, body?: Buffer, authenticating?: boolean): Promise<{
headers: Headers,
body: Buffer
@@ -302,34 +336,7 @@ export class RtspClient extends RtspBase {
if (authenticating)
throw new Error('auth failed');
const parsedUrl = new URL(this.url);
if (wwwAuthenticate.includes('Basic')) {
const hash = BASIC.computeHash(parsedUrl);
this.authorization = `Basic ${hash}`;
}
else {
const wwwAuth = DIGEST.parseWWWAuthenticateRest(wwwAuthenticate);
const username = decodeURIComponent(parsedUrl.username);
const password = decodeURIComponent(parsedUrl.password);
const ha1 = crypto.createHash('md5').update(`${username}:${wwwAuth.realm}:${password}`).digest('hex');
const ha2 = crypto.createHash('md5').update(`${method}:${parsedUrl.pathname}`).digest('hex');
const hash = crypto.createHash('md5').update(`${ha1}:${wwwAuth.nonce}:${ha2}`).digest('hex');
const params = {
username,
realm: wwwAuth.realm,
nonce: wwwAuth.nonce,
uri: parsedUrl.pathname,
algorithm: 'MD5',
response: hash,
};
const paramsString = Object.entries(params).map(([key, value]) => `${key}=${value && quote(value)}`).join(', ');
this.authorization = `Digest ${paramsString}`;
}
this.wwwAuthenticate = wwwAuthenticate;
return this.request(method, headers, path, body, true);
}

View File

@@ -1,12 +1,12 @@
{
"name": "@scrypted/prebuffer-mixin",
"version": "0.1.237",
"version": "0.1.238",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@scrypted/prebuffer-mixin",
"version": "0.1.237",
"version": "0.1.238",
"license": "Apache-2.0",
"dependencies": {
"@scrypted/common": "file:../../common",

View File

@@ -1,6 +1,6 @@
{
"name": "@scrypted/prebuffer-mixin",
"version": "0.1.237",
"version": "0.1.238",
"description": "Rebroadcast and Prebuffer for VideoCameras.",
"author": "Scrypted",
"license": "Apache-2.0",