Files
zoneminder/web/js/Server.js
Isaac Connor 40129a5564 refactor: replace the auth_hash/auth_relay globals with one ZMAuth credential
The page kept two copies of the same secret: auth_relay, the query fragment
every AJAX call is authenticated with, and auth_hash, the bare hash stamped
into stream <img> URLs. Different responses updated different copies, so
they could drift, and a drifted auth_hash produced stream URLs that zms
rejects.

ZMAuth stores only the relay and derives the hash from it, so the two cannot
disagree. Its helpers cover the four shapes the call sites used:

  zmAuth.hash          derived, '' under the plain/none relay forms
  zmAuth.update(data)  absorb the auth fields of any response
  zmAuth.appendTo(url) authenticate a url, no-op when auth is off
  zmAuth.applyTo(src)  point a stream url at the current credential

appendTo also removes the `x ? '&'+x : ''` guard repeated at every call
site, some of which had omitted it and emitted a dangling '?'.

Migrates all call sites across web/js and the classic skin, and drops both
globals from skin.js.php.

Tests: tests/js/auth-helpers.test.js, 44 passing.
2026-08-09 10:29:46 -04:00

75 lines
3.1 KiB
JavaScript

'use strict';
var _createClass = function() {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor);
}
} return function(Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor;
};
}();
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
var Server = function() {
function Server(json) {
_classCallCheck(this, Server);
for (var k in json) {
this[k] = json[k];
}
}
_createClass(Server, [
{
key: 'url',
value: function url() {
const port = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
return location.protocol + '//' + this.Hostname + (port ? ':' + port : (this.Port ? ':' + this.Port : (location.port ? ':' + location.port : ''))) + (this.PathPrefix && this.PathPrefix != 'null' ? this.PathPrefix : '');
}
},
{
key: 'urlToZMS',
value: function urlToZMS() {
const port = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
return this.Protocol + '://' + this.Hostname + (port ? ':' + port : (this.Port ? ':' + this.Port : (location.port ? ':' + location.port : ''))) + (this.PathToZMS && this.PathToZMS != 'null' ? this.PathToZMS : '');
}
},
{
key: 'urlToApi',
value: function urlToApi() {
const port = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
const protocol = (location.protocol == 'https:' ? 'https:' : this.Protocol + ':');
const path = (this.PathToApi && (this.PathToApi != 'null')) ? this.PathToApi : '';
// Single-server: match browser's host:port (this.Hostname/Port may be wrong behind a proxy).
if (!this.Id) {
return protocol + '//' + (port ? location.hostname + ':' + port : location.host) + path;
}
return protocol + '//' + this.Hostname + (port ? ':' + port : (this.Port ? ':' + this.Port : (location.port ? ':' + location.port : ''))) + path;
}
},
{
key: 'getFromApi',
value: function getFromApi() {
const url = this.urlToApi() + (arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '');
return fetch(appendQuery(zmAuth.appendTo(url), arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''));
}
},
{
key: 'urlToJanus',
value: function urlToJanus() {
const port = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
return (location.protocol=='https:'? 'https:' : this.Protocol+':') + '//' + this.Hostname + (port ? ':' + port : (this.Port ? ':' + this.Port : (location.port ? ':' + location.port : ''))) + '/janus';
}
}
]);
return Server;
}();