Expose all device params to config expressions
This commit is contained in:
1 parent
75ff56f3ae
commit
add4c84132
9 files changed
+254
-137
No files matched your search
+77
-54
@@ -31,57 +31,77 @@ import {
|
|||||||
udpConnectionRequest
|
udpConnectionRequest
|
||||||
} from "./connection-request";
|
} from "./connection-request";
|
||||||
import { Expression, Task } from "./types";
|
import { Expression, Task } from "./types";
|
||||||
|
import { flattenDevice } from "./mongodb-functions";
|
||||||
|
import { evaluate } from "./common/expression";
|
||||||
|
|
||||||
export async function connectionRequest(deviceId): Promise<void> {
|
export async function connectionRequest(
|
||||||
const options = {
|
deviceId: string,
|
||||||
projection: {
|
device?: {}
|
||||||
_deviceId: 1,
|
): Promise<void> {
|
||||||
"Device.ManagementServer.ConnectionRequestURL._value": 1,
|
if (!device) {
|
||||||
"Device.ManagementServer.UDPConnectionRequestAddress._value": 1,
|
const res = await db.devicesCollection.findOne({ _id: deviceId });
|
||||||
"Device.ManagementServer.ConnectionRequestUsername._value": 1,
|
if (!res) throw new Error("No such device");
|
||||||
"Device.ManagementServer.ConnectionRequestPassword._value": 1,
|
device = flattenDevice(res);
|
||||||
"InternetGatewayDevice.ManagementServer.ConnectionRequestURL._value": 1,
|
|
||||||
"InternetGatewayDevice.ManagementServer.UDPConnectionRequestAddress._value": 1,
|
|
||||||
"InternetGatewayDevice.ManagementServer.ConnectionRequestUsername._value": 1,
|
|
||||||
"InternetGatewayDevice.ManagementServer.ConnectionRequestPassword._value": 1
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
const device = await db.devicesCollection.findOne({ _id: deviceId }, options);
|
let connectionRequestUrl, udpConnectionRequestAddress, username, password;
|
||||||
if (!device) throw new Error("No such device");
|
|
||||||
|
|
||||||
let managementServer,
|
if (device["InternetGatewayDevice.ManagementServer.ConnectionRequestURL"]) {
|
||||||
connectionRequestUrl,
|
connectionRequestUrl = (device[
|
||||||
udpConnectionRequestAddress,
|
"InternetGatewayDevice.ManagementServer.ConnectionRequestURL"
|
||||||
username,
|
].value || [""])[0];
|
||||||
password;
|
udpConnectionRequestAddress = ((
|
||||||
if (device.Device)
|
device[
|
||||||
// TR-181 data model
|
"InternetGatewayDevice.ManagementServer.UDPConnectionRequestAddress"
|
||||||
managementServer = device.Device.ManagementServer;
|
] || {}
|
||||||
// TR-098 data model
|
).value || [""])[0];
|
||||||
else managementServer = device.InternetGatewayDevice.ManagementServer;
|
username = ((
|
||||||
|
device[
|
||||||
if (managementServer.ConnectionRequestURL)
|
"InternetGatewayDevice.ManagementServer.ConnectionRequestUsername"
|
||||||
connectionRequestUrl = managementServer.ConnectionRequestURL._value;
|
] || {}
|
||||||
if (managementServer.UDPConnectionRequestAddress) {
|
).value || [""])[0];
|
||||||
udpConnectionRequestAddress =
|
password = ((
|
||||||
managementServer.UDPConnectionRequestAddress._value;
|
device[
|
||||||
|
"InternetGatewayDevice.ManagementServer.ConnectionRequestPassword"
|
||||||
|
] || {}
|
||||||
|
).value || [""])[0];
|
||||||
|
} else {
|
||||||
|
connectionRequestUrl = (device[
|
||||||
|
"Device.ManagementServer.ConnectionRequestURL"
|
||||||
|
].value || [""])[0];
|
||||||
|
udpConnectionRequestAddress = ((
|
||||||
|
device["Device.ManagementServer.UDPConnectionRequestAddress"] || {}
|
||||||
|
).value || [""])[0];
|
||||||
|
udpConnectionRequestAddress = ((
|
||||||
|
device["Device.ManagementServer.ConnectionRequestUsername"] || {}
|
||||||
|
).value || [""])[0];
|
||||||
|
password = ((
|
||||||
|
device["Device.ManagementServer.ConnectionRequestPassword"] || {}
|
||||||
|
).value || [""])[0];
|
||||||
}
|
}
|
||||||
if (managementServer.ConnectionRequestUsername)
|
|
||||||
username = managementServer.ConnectionRequestUsername._value;
|
|
||||||
if (managementServer.ConnectionRequestPassword)
|
|
||||||
password = managementServer.ConnectionRequestPassword._value;
|
|
||||||
|
|
||||||
const context = {
|
const remoteAddress = parse(connectionRequestUrl).host;
|
||||||
id: device["_id"],
|
|
||||||
serialNumber: device["_deviceId"]["SerialNumber"],
|
const evalCallback = (exp): Expression => {
|
||||||
productClass: device["_deviceId"]["ProductClass"],
|
if (!Array.isArray(exp)) return exp;
|
||||||
oui: device["_deviceId"]["OUI"],
|
if (exp[0] === "PARAM") {
|
||||||
remoteAddress: connectionRequestUrl
|
let name = exp[1];
|
||||||
? parse(connectionRequestUrl).host
|
if (name === "id") name = "DeviceID.ID";
|
||||||
: null,
|
else if (name === "serialNumber") name = "DeviceID.SerialNumber";
|
||||||
username: username || "",
|
else if (name === "productClass") name = "DeviceID.ProductClass";
|
||||||
password: password || ""
|
else if (name === "oui") name = "DeviceID.OUI";
|
||||||
|
else if (name === "remoteAddress") return remoteAddress;
|
||||||
|
else if (name === "username") return username;
|
||||||
|
else if (name === "password") return password;
|
||||||
|
|
||||||
|
const p = device[name];
|
||||||
|
if (p && p.value) return p.value[0];
|
||||||
|
} else if (exp[0] === "FUNC") {
|
||||||
|
if (exp[1] === "REMOTE_ADDRESS") return remoteAddress;
|
||||||
|
else if (exp[1] === "USERNAME") return username;
|
||||||
|
else if (exp[1] === "PASSWORD") return password;
|
||||||
|
}
|
||||||
|
return exp;
|
||||||
};
|
};
|
||||||
|
|
||||||
const snapshot = await getCurrentSnapshot();
|
const snapshot = await getCurrentSnapshot();
|
||||||
@@ -89,20 +109,23 @@ export async function connectionRequest(deviceId): Promise<void> {
|
|||||||
const UDP_CONNECTION_REQUEST_PORT = +getConfig(
|
const UDP_CONNECTION_REQUEST_PORT = +getConfig(
|
||||||
snapshot,
|
snapshot,
|
||||||
"cwmp.udpConnectionRequestPort",
|
"cwmp.udpConnectionRequestPort",
|
||||||
context,
|
{},
|
||||||
now
|
now,
|
||||||
|
evalCallback
|
||||||
);
|
);
|
||||||
const CONNECTION_REQUEST_TIMEOUT = +getConfig(
|
const CONNECTION_REQUEST_TIMEOUT = +getConfig(
|
||||||
snapshot,
|
snapshot,
|
||||||
"cwmp.connectionRequestTimeout",
|
"cwmp.connectionRequestTimeout",
|
||||||
context,
|
{},
|
||||||
now
|
now,
|
||||||
|
evalCallback
|
||||||
);
|
);
|
||||||
const CONNECTION_REQUEST_ALLOW_BASIC_AUTH = !!getConfig(
|
const CONNECTION_REQUEST_ALLOW_BASIC_AUTH = !!getConfig(
|
||||||
snapshot,
|
snapshot,
|
||||||
"cwmp.connectionRequestAllowBasicAuth",
|
"cwmp.connectionRequestAllowBasicAuth",
|
||||||
context,
|
{},
|
||||||
now
|
now,
|
||||||
|
evalCallback
|
||||||
);
|
);
|
||||||
let authExp: Expression = getConfigExpression(
|
let authExp: Expression = getConfigExpression(
|
||||||
snapshot,
|
snapshot,
|
||||||
@@ -118,14 +141,15 @@ export async function connectionRequest(deviceId): Promise<void> {
|
|||||||
] as Expression;
|
] as Expression;
|
||||||
}
|
}
|
||||||
|
|
||||||
const debug = !!getConfig(snapshot, "cwmp.debug", context, now);
|
authExp = evaluate(authExp, {}, now, evalCallback);
|
||||||
|
|
||||||
|
const debug = !!getConfig(snapshot, "cwmp.debug", {}, now, evalCallback);
|
||||||
|
|
||||||
let udpProm;
|
let udpProm;
|
||||||
if (udpConnectionRequestAddress) {
|
if (udpConnectionRequestAddress) {
|
||||||
udpProm = udpConnectionRequest(
|
udpProm = udpConnectionRequest(
|
||||||
udpConnectionRequestAddress,
|
udpConnectionRequestAddress,
|
||||||
authExp,
|
authExp,
|
||||||
context,
|
|
||||||
UDP_CONNECTION_REQUEST_PORT,
|
UDP_CONNECTION_REQUEST_PORT,
|
||||||
debug,
|
debug,
|
||||||
deviceId
|
deviceId
|
||||||
@@ -136,7 +160,6 @@ export async function connectionRequest(deviceId): Promise<void> {
|
|||||||
await httpConnectionRequest(
|
await httpConnectionRequest(
|
||||||
connectionRequestUrl,
|
connectionRequestUrl,
|
||||||
authExp,
|
authExp,
|
||||||
context,
|
|
||||||
CONNECTION_REQUEST_ALLOW_BASIC_AUTH,
|
CONNECTION_REQUEST_ALLOW_BASIC_AUTH,
|
||||||
CONNECTION_REQUEST_TIMEOUT,
|
CONNECTION_REQUEST_TIMEOUT,
|
||||||
debug,
|
debug,
|
||||||
|
|||||||
+3
-1
@@ -26,8 +26,10 @@ function parseHeaderFeilds(str: string): {} {
|
|||||||
let part;
|
let part;
|
||||||
while ((part = parts.shift()) != null) {
|
while ((part = parts.shift()) != null) {
|
||||||
const name = part.split("=", 1)[0];
|
const name = part.split("=", 1)[0];
|
||||||
if (name.length === part.length)
|
if (name.length === part.length) {
|
||||||
|
if (!part.trim()) continue;
|
||||||
throw new Error("Unable to parse auth header");
|
throw new Error("Unable to parse auth header");
|
||||||
|
}
|
||||||
|
|
||||||
let value = part.slice(name.length + 1);
|
let value = part.slice(name.length + 1);
|
||||||
if (!/^\s*"/.test(value)) {
|
if (!/^\s*"/.test(value)) {
|
||||||
|
|||||||
@@ -29,15 +29,13 @@ import * as debug from "./debug";
|
|||||||
|
|
||||||
async function extractAuth(
|
async function extractAuth(
|
||||||
exp: Expression,
|
exp: Expression,
|
||||||
context: {},
|
|
||||||
now: number,
|
|
||||||
dflt: any
|
dflt: any
|
||||||
): Promise<[string, string, Expression]> {
|
): Promise<[string, string, Expression]> {
|
||||||
let username, password;
|
let username, password;
|
||||||
const _exp = await evaluateAsync(
|
const _exp = await evaluateAsync(
|
||||||
exp,
|
exp,
|
||||||
context,
|
{},
|
||||||
now,
|
0,
|
||||||
async (e: Expression): Promise<Expression> => {
|
async (e: Expression): Promise<Expression> => {
|
||||||
if (!username && Array.isArray(e) && e[0] === "FUNC") {
|
if (!username && Array.isArray(e) && e[0] === "FUNC") {
|
||||||
if (e[1] === "EXT") {
|
if (e[1] === "EXT") {
|
||||||
@@ -50,8 +48,8 @@ async function extractAuth(
|
|||||||
return fault ? null : value;
|
return fault ? null : value;
|
||||||
} else if (e[1] === "AUTH") {
|
} else if (e[1] === "AUTH") {
|
||||||
if (!Array.isArray(e[2]) && !Array.isArray(e[3])) {
|
if (!Array.isArray(e[2]) && !Array.isArray(e[3])) {
|
||||||
username = e[2];
|
username = e[2] || "";
|
||||||
password = e[3];
|
password = e[3] || "";
|
||||||
}
|
}
|
||||||
return dflt;
|
return dflt;
|
||||||
}
|
}
|
||||||
@@ -95,13 +93,11 @@ function httpGet(
|
|||||||
export async function httpConnectionRequest(
|
export async function httpConnectionRequest(
|
||||||
address: string,
|
address: string,
|
||||||
authExp: Expression,
|
authExp: Expression,
|
||||||
context: {},
|
|
||||||
allowBasicAuth: boolean,
|
allowBasicAuth: boolean,
|
||||||
timeout: number,
|
timeout: number,
|
||||||
_debug: boolean,
|
_debug: boolean,
|
||||||
deviceId: string
|
deviceId: string
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const now = Date.now();
|
|
||||||
const options: http.RequestOptions = parse(address);
|
const options: http.RequestOptions = parse(address);
|
||||||
if (options.protocol !== "http:")
|
if (options.protocol !== "http:")
|
||||||
throw new Error("Invalid connection request URL or protocol");
|
throw new Error("Invalid connection request URL or protocol");
|
||||||
@@ -163,12 +159,7 @@ export async function httpConnectionRequest(
|
|||||||
authHeader = auth.parseWwwAuthenticateHeader(
|
authHeader = auth.parseWwwAuthenticateHeader(
|
||||||
res.headers["www-authenticate"]
|
res.headers["www-authenticate"]
|
||||||
);
|
);
|
||||||
[username, password, authExp] = await extractAuth(
|
[username, password, authExp] = await extractAuth(authExp, false);
|
||||||
authExp,
|
|
||||||
context,
|
|
||||||
now,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
`Unexpected response code from device: ${res.statusCode}`
|
`Unexpected response code from device: ${res.statusCode}`
|
||||||
@@ -181,7 +172,6 @@ export async function httpConnectionRequest(
|
|||||||
export async function udpConnectionRequest(
|
export async function udpConnectionRequest(
|
||||||
address: string,
|
address: string,
|
||||||
authExp: Expression,
|
authExp: Expression,
|
||||||
context: {},
|
|
||||||
sourcePort: number = 0,
|
sourcePort: number = 0,
|
||||||
_debug: boolean,
|
_debug: boolean,
|
||||||
deviceId: string
|
deviceId: string
|
||||||
@@ -202,12 +192,7 @@ export async function udpConnectionRequest(
|
|||||||
let username: string;
|
let username: string;
|
||||||
let password: string;
|
let password: string;
|
||||||
|
|
||||||
[username, password, authExp] = await extractAuth(
|
[username, password, authExp] = await extractAuth(authExp, null);
|
||||||
authExp,
|
|
||||||
context,
|
|
||||||
now,
|
|
||||||
null
|
|
||||||
);
|
|
||||||
|
|
||||||
if (username == null) username = "";
|
if (username == null) username = "";
|
||||||
if (password == null) password = "";
|
if (password == null) password = "";
|
||||||
@@ -233,12 +218,7 @@ export async function udpConnectionRequest(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
[username, password, authExp] = await extractAuth(
|
[username, password, authExp] = await extractAuth(authExp, null);
|
||||||
authExp,
|
|
||||||
context,
|
|
||||||
now,
|
|
||||||
null
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
client.close();
|
client.close();
|
||||||
}
|
}
|
||||||
+64
-30
@@ -103,12 +103,12 @@ async function authenticate(
|
|||||||
authentication["body"] = body;
|
authentication["body"] = body;
|
||||||
}
|
}
|
||||||
|
|
||||||
const now = Date.now();
|
|
||||||
const res = await evaluateAsync(
|
const res = await evaluateAsync(
|
||||||
authExpression,
|
authExpression,
|
||||||
sessionContext.configContext,
|
{},
|
||||||
now,
|
sessionContext.timestamp,
|
||||||
async (e: Expression): Promise<Expression> => {
|
async (e: Expression): Promise<Expression> => {
|
||||||
|
e = session.configContextCallback(sessionContext, e);
|
||||||
if (Array.isArray(e) && e[0] === "FUNC") {
|
if (Array.isArray(e) && e[0] === "FUNC") {
|
||||||
if (e[1] === "EXT") {
|
if (e[1] === "EXT") {
|
||||||
if (typeof e[2] !== "string" || typeof e[3] !== "string") return null;
|
if (typeof e[2] !== "string" || typeof e[3] !== "string") return null;
|
||||||
@@ -294,7 +294,9 @@ async function inform(sessionContext: SessionContext, rpc): Promise<void> {
|
|||||||
const cookiesPath = localCache.getConfig(
|
const cookiesPath = localCache.getConfig(
|
||||||
sessionContext.cacheSnapshot,
|
sessionContext.cacheSnapshot,
|
||||||
"cwmp.cookiesPath",
|
"cwmp.cookiesPath",
|
||||||
sessionContext.configContext
|
{},
|
||||||
|
sessionContext.timestamp,
|
||||||
|
e => session.configContextCallback(sessionContext, e)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (cookiesPath) {
|
if (cookiesPath) {
|
||||||
@@ -384,7 +386,9 @@ async function applyPresets(sessionContext: SessionContext): Promise<void> {
|
|||||||
const RETRY_DELAY = +localCache.getConfig(
|
const RETRY_DELAY = +localCache.getConfig(
|
||||||
sessionContext.cacheSnapshot,
|
sessionContext.cacheSnapshot,
|
||||||
"cwmp.retryDelay",
|
"cwmp.retryDelay",
|
||||||
sessionContext.configContext
|
{},
|
||||||
|
sessionContext.timestamp,
|
||||||
|
e => session.configContextCallback(sessionContext, e)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (sessionContext.faults) {
|
if (sessionContext.faults) {
|
||||||
@@ -1263,9 +1267,19 @@ async function listenerAsync(
|
|||||||
debug.outgoingHttpResponse(httpResponse, sessionContext.deviceId, msg);
|
debug.outgoingHttpResponse(httpResponse, sessionContext.deviceId, msg);
|
||||||
} else {
|
} else {
|
||||||
const cacheSnapshot = await localCache.getCurrentSnapshot();
|
const cacheSnapshot = await localCache.getCurrentSnapshot();
|
||||||
const d = !!localCache.getConfig(cacheSnapshot, "cwmp.debug", {
|
const d = !!localCache.getConfig(
|
||||||
|
cacheSnapshot,
|
||||||
|
"cwmp.debug",
|
||||||
|
{
|
||||||
remoteAddress: httpResponse.connection.remoteAddress
|
remoteAddress: httpResponse.connection.remoteAddress
|
||||||
});
|
},
|
||||||
|
Date.now(),
|
||||||
|
e => {
|
||||||
|
if (Array.isArray(e) && e[0] === "FUNC" && e[1] === "REMOTE_ADDRESS")
|
||||||
|
return httpResponse.connection.remoteAddress;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
);
|
||||||
if (d) debug.outgoingHttpResponse(httpResponse, null, msg);
|
if (d) debug.outgoingHttpResponse(httpResponse, null, msg);
|
||||||
}
|
}
|
||||||
httpResponse.end(msg);
|
httpResponse.end(msg);
|
||||||
@@ -1314,9 +1328,19 @@ async function listenerAsync(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const cacheSnapshot = await localCache.getCurrentSnapshot();
|
const cacheSnapshot = await localCache.getCurrentSnapshot();
|
||||||
const d = !!localCache.getConfig(cacheSnapshot, "cwmp.debug", {
|
const d = !!localCache.getConfig(
|
||||||
|
cacheSnapshot,
|
||||||
|
"cwmp.debug",
|
||||||
|
{
|
||||||
remoteAddress: httpResponse.connection.remoteAddress
|
remoteAddress: httpResponse.connection.remoteAddress
|
||||||
});
|
},
|
||||||
|
Date.now(),
|
||||||
|
e => {
|
||||||
|
if (Array.isArray(e) && e[0] === "FUNC" && e[1] === "REMOTE_ADDRESS")
|
||||||
|
return httpResponse.connection.remoteAddress;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
);
|
||||||
if (d) debug.outgoingHttpResponse(httpResponse, null, error.message);
|
if (d) debug.outgoingHttpResponse(httpResponse, null, error.message);
|
||||||
}
|
}
|
||||||
httpResponse.end(error.message);
|
httpResponse.end(error.message);
|
||||||
@@ -1347,9 +1371,19 @@ async function listenerAsync(
|
|||||||
httpResponse.setHeader("Content-Length", Buffer.byteLength(_body));
|
httpResponse.setHeader("Content-Length", Buffer.byteLength(_body));
|
||||||
httpResponse.writeHead(400, { Connection: "close" });
|
httpResponse.writeHead(400, { Connection: "close" });
|
||||||
const cacheSnapshot = await localCache.getCurrentSnapshot();
|
const cacheSnapshot = await localCache.getCurrentSnapshot();
|
||||||
const d = !!localCache.getConfig(cacheSnapshot, "cwmp.debug", {
|
const d = !!localCache.getConfig(
|
||||||
|
cacheSnapshot,
|
||||||
|
"cwmp.debug",
|
||||||
|
{
|
||||||
remoteAddress: httpResponse.connection.remoteAddress
|
remoteAddress: httpResponse.connection.remoteAddress
|
||||||
});
|
},
|
||||||
|
Date.now(),
|
||||||
|
e => {
|
||||||
|
if (Array.isArray(e) && e[0] === "FUNC" && e[1] === "REMOTE_ADDRESS")
|
||||||
|
return httpResponse.connection.remoteAddress;
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
);
|
||||||
if (d)
|
if (d)
|
||||||
debug.outgoingHttpResponse(httpResponse, sessionContext.deviceId, _body);
|
debug.outgoingHttpResponse(httpResponse, sessionContext.deviceId, _body);
|
||||||
httpResponse.end(_body);
|
httpResponse.end(_body);
|
||||||
@@ -1361,31 +1395,13 @@ async function listenerAsync(
|
|||||||
|
|
||||||
const cacheSnapshot = await localCache.getCurrentSnapshot();
|
const cacheSnapshot = await localCache.getCurrentSnapshot();
|
||||||
|
|
||||||
const configContext = {
|
|
||||||
id: deviceId,
|
|
||||||
serialNumber: rpc.cpeRequest.deviceId["SerialNumber"],
|
|
||||||
productClass: rpc.cpeRequest.deviceId["ProductClass"],
|
|
||||||
oui: rpc.cpeRequest.deviceId["OUI"],
|
|
||||||
remoteAddress: httpRequest.connection.remoteAddress
|
|
||||||
};
|
|
||||||
|
|
||||||
const sessionTimeout =
|
|
||||||
rpc.sessionTimeout ||
|
|
||||||
localCache.getConfig(cacheSnapshot, "cwmp.sessionTimeout", configContext);
|
|
||||||
|
|
||||||
const _sessionContext = session.init(
|
const _sessionContext = session.init(
|
||||||
deviceId,
|
deviceId,
|
||||||
rpc.cwmpVersion,
|
rpc.cwmpVersion,
|
||||||
sessionTimeout
|
rpc.sessionTimeout
|
||||||
);
|
);
|
||||||
|
|
||||||
_sessionContext.cacheSnapshot = cacheSnapshot;
|
_sessionContext.cacheSnapshot = cacheSnapshot;
|
||||||
_sessionContext.configContext = configContext;
|
|
||||||
_sessionContext.debug = !!localCache.getConfig(
|
|
||||||
cacheSnapshot,
|
|
||||||
"cwmp.debug",
|
|
||||||
configContext
|
|
||||||
);
|
|
||||||
|
|
||||||
_sessionContext.httpRequest = httpRequest;
|
_sessionContext.httpRequest = httpRequest;
|
||||||
_sessionContext.httpResponse = httpResponse;
|
_sessionContext.httpResponse = httpResponse;
|
||||||
@@ -1434,6 +1450,24 @@ async function listenerAsync(
|
|||||||
_sessionContext.new = true;
|
_sessionContext.new = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!_sessionContext.timeout) {
|
||||||
|
_sessionContext.timeout = +localCache.getConfig(
|
||||||
|
cacheSnapshot,
|
||||||
|
"cwmp.sessionTimeout",
|
||||||
|
{},
|
||||||
|
_sessionContext.timestamp,
|
||||||
|
e => session.configContextCallback(_sessionContext, e)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_sessionContext.debug = !!localCache.getConfig(
|
||||||
|
cacheSnapshot,
|
||||||
|
"cwmp.debug",
|
||||||
|
{},
|
||||||
|
_sessionContext.timestamp,
|
||||||
|
e => session.configContextCallback(_sessionContext, e)
|
||||||
|
);
|
||||||
|
|
||||||
const authenticated = await authenticate(_sessionContext, bodyStr);
|
const authenticated = await authenticate(_sessionContext, bodyStr);
|
||||||
if (!authenticated) return responseUnauthorized(_sessionContext);
|
if (!authenticated) return responseUnauthorized(_sessionContext);
|
||||||
|
|
||||||
|
|||||||
+19
-8
@@ -461,10 +461,11 @@ export function getFiles(
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getConfig(
|
export function getConfig(
|
||||||
snapshotKey,
|
snapshotKey: string,
|
||||||
key,
|
key: string,
|
||||||
context?,
|
context: {},
|
||||||
now?
|
now: number,
|
||||||
|
cb?: (Expression) => Expression
|
||||||
): string | number | boolean | null {
|
): string | number | boolean | null {
|
||||||
const snapshot = snapshots.get(snapshotKey);
|
const snapshot = snapshots.get(snapshotKey);
|
||||||
if (!snapshot) throw new Error("Cache snapshot does not exist");
|
if (!snapshot) throw new Error("Cache snapshot does not exist");
|
||||||
@@ -488,11 +489,21 @@ export function getConfig(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (!(key in snapshot.config)) {
|
if (!(key in snapshot.config)) {
|
||||||
if (key in oldOpts)
|
if (key in oldOpts) {
|
||||||
return config.get(oldOpts[key], context ? context.id : null);
|
let id;
|
||||||
else return null;
|
if (context && context["id"]) {
|
||||||
|
id = context["id"];
|
||||||
|
} else if (cb) {
|
||||||
|
id = cb(["PARAM", "DeviceID.ID"]);
|
||||||
|
if (Array.isArray(id)) id = null;
|
||||||
}
|
}
|
||||||
return expression.evaluate(snapshot.config[key], context, now || Date.now());
|
return config.get(oldOpts[key], id);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const v = expression.evaluate(snapshot.config[key], context, now, cb);
|
||||||
|
return Array.isArray(v) ? null : v;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getConfigExpression(snapshotKey, key): Expression {
|
export function getConfigExpression(snapshotKey, key): Expression {
|
||||||
|
|||||||
+57
-10
@@ -47,7 +47,8 @@ import {
|
|||||||
InformRequest,
|
InformRequest,
|
||||||
TransferCompleteRequest,
|
TransferCompleteRequest,
|
||||||
Operation,
|
Operation,
|
||||||
ScriptResult
|
ScriptResult,
|
||||||
|
Expression
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
|
||||||
const VALID_PARAM_TYPES = new Set([
|
const VALID_PARAM_TYPES = new Set([
|
||||||
@@ -105,6 +106,34 @@ function generateRpcId(sessionContext: SessionContext): string {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function configContextCallback(
|
||||||
|
sessionContext: SessionContext,
|
||||||
|
exp: Expression
|
||||||
|
): Expression {
|
||||||
|
if (!Array.isArray(exp)) return exp;
|
||||||
|
if (exp[0] === "PARAM") {
|
||||||
|
let name = exp[1];
|
||||||
|
if (name === "id") name = "DeviceID.ID";
|
||||||
|
else if (name === "serialNumber") name = "DeviceID.SerialNumber";
|
||||||
|
else if (name === "productClass") name = "DeviceID.ProductClass";
|
||||||
|
else if (name === "oui") name = "DeviceID.OUI";
|
||||||
|
else if (name === "remoteAddress")
|
||||||
|
return sessionContext.httpRequest.connection.remoteAddress;
|
||||||
|
|
||||||
|
const deviceData = sessionContext.deviceData;
|
||||||
|
const paths = deviceData.paths;
|
||||||
|
const path = paths.get(Path.parse(name));
|
||||||
|
if (path) {
|
||||||
|
const attrs = deviceData.attributes.get(path, 1);
|
||||||
|
if (attrs && attrs.value && attrs.value[1]) return attrs.value[1][0];
|
||||||
|
}
|
||||||
|
} else if (exp[0] === "FUNC") {
|
||||||
|
if (exp[1] === "REMOTE_ADDRESS")
|
||||||
|
return sessionContext.httpRequest.connection.remoteAddress;
|
||||||
|
}
|
||||||
|
return exp;
|
||||||
|
}
|
||||||
|
|
||||||
export async function inform(
|
export async function inform(
|
||||||
sessionContext: SessionContext,
|
sessionContext: SessionContext,
|
||||||
rpcReq: InformRequest
|
rpcReq: InformRequest
|
||||||
@@ -413,7 +442,9 @@ export async function timeoutOperations(
|
|||||||
+localCache.getConfig(
|
+localCache.getConfig(
|
||||||
sessionContext.cacheSnapshot,
|
sessionContext.cacheSnapshot,
|
||||||
"cwmp.downloadTimeout",
|
"cwmp.downloadTimeout",
|
||||||
sessionContext.configContext
|
{},
|
||||||
|
sessionContext.timestamp,
|
||||||
|
e => configContextCallback(sessionContext, e)
|
||||||
) * 1000;
|
) * 1000;
|
||||||
|
|
||||||
if (sessionContext.timestamp > operation.timestamp + DOWNLOAD_TIMEOUT) {
|
if (sessionContext.timestamp > operation.timestamp + DOWNLOAD_TIMEOUT) {
|
||||||
@@ -448,7 +479,9 @@ export function addProvisions(
|
|||||||
+localCache.getConfig(
|
+localCache.getConfig(
|
||||||
sessionContext.cacheSnapshot,
|
sessionContext.cacheSnapshot,
|
||||||
"cwmp.maxCommitIterations",
|
"cwmp.maxCommitIterations",
|
||||||
sessionContext.configContext
|
{},
|
||||||
|
sessionContext.timestamp,
|
||||||
|
e => configContextCallback(sessionContext, e)
|
||||||
) * 2;
|
) * 2;
|
||||||
|
|
||||||
delete sessionContext.syncState;
|
delete sessionContext.syncState;
|
||||||
@@ -501,7 +534,9 @@ export function clearProvisions(sessionContext: SessionContext): void {
|
|||||||
+localCache.getConfig(
|
+localCache.getConfig(
|
||||||
sessionContext.cacheSnapshot,
|
sessionContext.cacheSnapshot,
|
||||||
"cwmp.maxCommitIterations",
|
"cwmp.maxCommitIterations",
|
||||||
sessionContext.configContext
|
{},
|
||||||
|
sessionContext.timestamp,
|
||||||
|
e => configContextCallback(sessionContext, e)
|
||||||
) * 2;
|
) * 2;
|
||||||
|
|
||||||
if (sessionContext.revisions[sessionContext.revisions.length - 1] > 0) {
|
if (sessionContext.revisions[sessionContext.revisions.length - 1] > 0) {
|
||||||
@@ -1080,7 +1115,9 @@ export async function rpcRequest(
|
|||||||
+localCache.getConfig(
|
+localCache.getConfig(
|
||||||
sessionContext.cacheSnapshot,
|
sessionContext.cacheSnapshot,
|
||||||
"cwmp.maxCommitIterations",
|
"cwmp.maxCommitIterations",
|
||||||
sessionContext.configContext
|
{},
|
||||||
|
sessionContext.timestamp,
|
||||||
|
e => configContextCallback(sessionContext, e)
|
||||||
) * 2;
|
) * 2;
|
||||||
|
|
||||||
if (sessionContext.iteration >= MAX_ITERATIONS * (sessionContext.cycle + 1)) {
|
if (sessionContext.iteration >= MAX_ITERATIONS * (sessionContext.cycle + 1)) {
|
||||||
@@ -1523,7 +1560,9 @@ function generateGetRpcRequest(sessionContext: SessionContext): GetAcsRequest {
|
|||||||
const GPN_NEXT_LEVEL = localCache.getConfig(
|
const GPN_NEXT_LEVEL = localCache.getConfig(
|
||||||
sessionContext.cacheSnapshot,
|
sessionContext.cacheSnapshot,
|
||||||
"cwmp.gpnNextLevel",
|
"cwmp.gpnNextLevel",
|
||||||
sessionContext.configContext
|
{},
|
||||||
|
sessionContext.timestamp,
|
||||||
|
e => configContextCallback(sessionContext, e)
|
||||||
);
|
);
|
||||||
|
|
||||||
const paths = Array.from(syncState.gpn.keys()).sort(
|
const paths = Array.from(syncState.gpn.keys()).sort(
|
||||||
@@ -1582,7 +1621,9 @@ function generateGetRpcRequest(sessionContext: SessionContext): GetAcsRequest {
|
|||||||
const GPV_BATCH_SIZE = localCache.getConfig(
|
const GPV_BATCH_SIZE = localCache.getConfig(
|
||||||
sessionContext.cacheSnapshot,
|
sessionContext.cacheSnapshot,
|
||||||
"cwmp.gpvBatchSize",
|
"cwmp.gpvBatchSize",
|
||||||
sessionContext.configContext
|
{},
|
||||||
|
sessionContext.timestamp,
|
||||||
|
e => configContextCallback(sessionContext, e)
|
||||||
);
|
);
|
||||||
|
|
||||||
const parameterNames: string[] = [];
|
const parameterNames: string[] = [];
|
||||||
@@ -1643,19 +1684,25 @@ function generateSetRpcRequest(sessionContext: SessionContext): SetAcsRequest {
|
|||||||
const GPV_BATCH_SIZE = localCache.getConfig(
|
const GPV_BATCH_SIZE = localCache.getConfig(
|
||||||
sessionContext.cacheSnapshot,
|
sessionContext.cacheSnapshot,
|
||||||
"cwmp.gpvBatchSize",
|
"cwmp.gpvBatchSize",
|
||||||
sessionContext.configContext
|
{},
|
||||||
|
sessionContext.timestamp,
|
||||||
|
e => configContextCallback(sessionContext, e)
|
||||||
);
|
);
|
||||||
|
|
||||||
const DATETIME_MILLISECONDS = !!localCache.getConfig(
|
const DATETIME_MILLISECONDS = !!localCache.getConfig(
|
||||||
sessionContext.cacheSnapshot,
|
sessionContext.cacheSnapshot,
|
||||||
"cwmp.datetimeMilliseconds",
|
"cwmp.datetimeMilliseconds",
|
||||||
sessionContext.configContext
|
{},
|
||||||
|
sessionContext.timestamp,
|
||||||
|
e => configContextCallback(sessionContext, e)
|
||||||
);
|
);
|
||||||
|
|
||||||
const BOOLEAN_LITERAL = !!localCache.getConfig(
|
const BOOLEAN_LITERAL = !!localCache.getConfig(
|
||||||
sessionContext.cacheSnapshot,
|
sessionContext.cacheSnapshot,
|
||||||
"cwmp.booleanLiteral",
|
"cwmp.booleanLiteral",
|
||||||
sessionContext.configContext
|
{},
|
||||||
|
sessionContext.timestamp,
|
||||||
|
e => configContextCallback(sessionContext, e)
|
||||||
);
|
);
|
||||||
|
|
||||||
const parameterValues: [Path, string | number | boolean, string][] = [];
|
const parameterValues: [Path, string | number | boolean, string][] = [];
|
||||||
|
|||||||
@@ -131,7 +131,6 @@ export interface SessionContext {
|
|||||||
faults?: { [channel: string]: SessionFault };
|
faults?: { [channel: string]: SessionFault };
|
||||||
retries?: { [channel: string]: number };
|
retries?: { [channel: string]: number };
|
||||||
cacheSnapshot?: string;
|
cacheSnapshot?: string;
|
||||||
configContext?: { [name: string]: any };
|
|
||||||
httpResponse?: ServerResponse;
|
httpResponse?: ServerResponse;
|
||||||
httpRequest?: IncomingMessage;
|
httpRequest?: IncomingMessage;
|
||||||
faultsTouched?: { [channel: string]: boolean };
|
faultsTouched?: { [channel: string]: boolean };
|
||||||
|
|||||||
@@ -88,7 +88,8 @@ export async function deleteResource(resource, id): Promise<void> {
|
|||||||
export async function postTasks(
|
export async function postTasks(
|
||||||
deviceId,
|
deviceId,
|
||||||
tasks,
|
tasks,
|
||||||
timeout
|
timeout,
|
||||||
|
device
|
||||||
): Promise<{ connectionRequest: string; tasks: any[] }> {
|
): Promise<{ connectionRequest: string; tasks: any[] }> {
|
||||||
for (const task of tasks) {
|
for (const task of tasks) {
|
||||||
delete task._id;
|
delete task._id;
|
||||||
@@ -103,7 +104,7 @@ export async function postTasks(
|
|||||||
await del(`${deviceId}_tasks_faults_operations`);
|
await del(`${deviceId}_tasks_faults_operations`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await connectionRequest(deviceId);
|
await connectionRequest(deviceId, device);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return {
|
return {
|
||||||
connectionRequest: err.message,
|
connectionRequest: err.message,
|
||||||
|
|||||||
+24
-4
@@ -30,6 +30,7 @@ import { generateSalt, hashPassword } from "../auth";
|
|||||||
import { del } from "../cache";
|
import { del } from "../cache";
|
||||||
import Authorizer from "../common/authorizer";
|
import Authorizer from "../common/authorizer";
|
||||||
import { ping } from "../ping";
|
import { ping } from "../ping";
|
||||||
|
import * as url from "url";
|
||||||
|
|
||||||
const router = new Router();
|
const router = new Router();
|
||||||
export default router;
|
export default router;
|
||||||
@@ -481,8 +482,9 @@ router.post("/devices/:id/tasks", async (ctx, next) => {
|
|||||||
}
|
}
|
||||||
const devices = await db.query("devices", filter);
|
const devices = await db.query("devices", filter);
|
||||||
if (!devices.length) return void next();
|
if (!devices.length) return void next();
|
||||||
|
const device = devices[0];
|
||||||
|
|
||||||
const validate = authorizer.getValidator("devices", devices[0]);
|
const validate = authorizer.getValidator("devices", device);
|
||||||
for (const t of ctx.request.body) {
|
for (const t of ctx.request.body) {
|
||||||
if (!validate("task", t)) {
|
if (!validate("task", t)) {
|
||||||
logUnauthorizedWarning(log);
|
logUnauthorizedWarning(log);
|
||||||
@@ -490,16 +492,34 @@ router.post("/devices/:id/tasks", async (ctx, next) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Pass context and timestamp
|
|
||||||
const onlineThreshold = getConfig(
|
const onlineThreshold = getConfig(
|
||||||
ctx.state.configSnapshot,
|
ctx.state.configSnapshot,
|
||||||
"cwmp.deviceOnlineThreshold"
|
"cwmp.deviceOnlineThreshold",
|
||||||
|
{},
|
||||||
|
Date.now(),
|
||||||
|
exp => {
|
||||||
|
if (!Array.isArray(exp)) return exp;
|
||||||
|
if (exp[0] === "PARAM") {
|
||||||
|
const p = device[exp[1]];
|
||||||
|
if (p && p.value) return p.value[0];
|
||||||
|
} else if (exp[0] === "FUNC") {
|
||||||
|
if (exp[1] === "REMOTE_ADDRESS") {
|
||||||
|
for (const root of ["InternetGatewayDevice", "Device"]) {
|
||||||
|
const p = device[`${root}.ManagementServer.ConnectionRequestURL`];
|
||||||
|
if (p && p.value) return url.parse(p.value[0]).host;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return exp;
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
const res = await apiFunctions.postTasks(
|
const res = await apiFunctions.postTasks(
|
||||||
ctx.params.id,
|
ctx.params.id,
|
||||||
ctx.request.body,
|
ctx.request.body,
|
||||||
onlineThreshold
|
onlineThreshold,
|
||||||
|
device
|
||||||
);
|
);
|
||||||
|
|
||||||
log.tasks = res.tasks.map(t => t._id).join(",");
|
log.tasks = res.tasks.map(t => t._id).join(",");
|
||||||
|
|||||||
Reference in new issue
Block a user