diff --git a/bin/genieacs-ui b/bin/genieacs-ui index c3f9b85..02cb42c 100755 --- a/bin/genieacs-ui +++ b/bin/genieacs-ui @@ -9,6 +9,7 @@ import * as logger from "../lib/logger"; import * as cluster from "../lib/cluster"; import * as server from "../lib/server"; import { listener } from "../lib/ui"; +import * as extensions from "../lib/extensions"; import * as db from "../lib/ui/db"; import * as db2 from "../lib/db"; import * as cache from "../lib/cache"; @@ -23,11 +24,14 @@ function exitWorkerGracefully(): void { db.disconnect(); db2.disconnect(); cache.disconnect(); + extensions.killAll(); cluster.worker.disconnect(); } function exitWorkerUngracefully(): void { - process.exit(1); + extensions.killAll().then(() => { + process.exit(1); + }); } if (!cluster.worker) { diff --git a/lib/api-functions.ts b/lib/api-functions.ts index 882a93a..08387a7 100644 --- a/lib/api-functions.ts +++ b/lib/api-functions.ts @@ -119,7 +119,7 @@ export async function connectionRequest(deviceId): Promise { udpProm = udpConnectionRequest( udpConnectionRequestAddress, authExp, - db.configCollection, + context, UDP_CONNECTION_REQUEST_PORT ); } diff --git a/lib/connection-request.ts b/lib/connection-request.ts index 265b367..3ad2d5a 100644 --- a/lib/connection-request.ts +++ b/lib/connection-request.ts @@ -21,29 +21,44 @@ import * as crypto from "crypto"; import * as dgram from "dgram"; import { parse } from "url"; import * as http from "http"; -import { evaluate } from "./common/expression"; +import { evaluateAsync } from "./common/expression"; import { Expression } from "./types"; import * as auth from "./auth"; +import * as extensions from "./extensions"; -function extractAuth( +async function extractAuth( exp: Expression, context: {}, now: number, dflt: any -): [string, string, Expression] { +): Promise<[string, string, Expression]> { let username, password; - exp = evaluate(exp, context, now, e => { - if (!username && Array.isArray(e) && e[0] === "FUNC" && e[1] === "AUTH") { - if (!Array.isArray(e[2]) && !Array.isArray(e[3])) { - username = e[2]; - password = e[3]; - } - return dflt; - } - return e; - }); + const _exp = await evaluateAsync( + exp, + context, + now, + async (e: Expression): Promise => { + if (!username && Array.isArray(e) && e[0] === "FUNC") { + if (e[1] === "EXT") { + if (typeof e[2] !== "string" || typeof e[3] !== "string") return null; - return [username, password, exp]; + for (let i = 4; i < e.length; i++) + if (Array.isArray(e[i])) return null; + + const { fault, value } = await extensions.run(e.slice(2)); + return fault ? null : value; + } else if (e[1] === "AUTH") { + if (!Array.isArray(e[2]) && !Array.isArray(e[3])) { + username = e[2]; + password = e[3]; + } + return dflt; + } + } + return e; + } + ); + return [username, password, _exp]; } function httpGet( @@ -137,7 +152,12 @@ export async function httpConnectionRequest( authHeader = auth.parseWwwAuthenticateHeader( res.headers["www-authenticate"] ); - [username, password, authExp] = extractAuth(authExp, context, now, false); + [username, password, authExp] = await extractAuth( + authExp, + context, + now, + false + ); } else { throw new Error( `Unexpected response code from device: ${res.statusCode}` @@ -169,7 +189,13 @@ export async function udpConnectionRequest( let username: string; let password: string; - [username, password, authExp] = extractAuth(authExp, context, now, null); + [username, password, authExp] = await extractAuth( + authExp, + context, + now, + null + ); + if (username == null) username = ""; if (password == null) password = ""; while (username != null && password != null) { @@ -194,7 +220,12 @@ export async function udpConnectionRequest( }); } - [username, password, authExp] = extractAuth(authExp, context, now, null); + [username, password, authExp] = await extractAuth( + authExp, + context, + now, + null + ); } client.close(); } diff --git a/lib/cwmp.ts b/lib/cwmp.ts index 6ff3fa2..e015a71 100644 --- a/lib/cwmp.ts +++ b/lib/cwmp.ts @@ -26,7 +26,7 @@ import * as config from "./config"; import * as common from "./common"; import * as soap from "./soap"; import * as session from "./session"; -import { evaluate, extractParams } from "./common/expression"; +import { evaluateAsync, evaluate, extractParams } from "./common/expression"; import * as device from "./device"; import * as cache from "./cache"; import * as localCache from "./local-cache"; @@ -34,6 +34,7 @@ import * as db from "./db"; import * as logger from "./logger"; import * as scheduling from "./scheduling"; import Path from "./common/path"; +import * as extensions from "./extensions"; import { SessionContext, AcsRequest, @@ -64,7 +65,7 @@ const stats = { initiatedSessions: 0 }; -function authenticate(sessionContext: SessionContext): boolean { +async function authenticate(sessionContext: SessionContext): Promise { const authExpression: Expression = localCache.getConfigExpression( sessionContext.cacheSnapshot, "cwmp.auth" @@ -80,19 +81,29 @@ function authenticate(sessionContext: SessionContext): boolean { } const now = Date.now(); - const res = evaluate( + const res = await evaluateAsync( authExpression, sessionContext.configContext, now, - (e: Expression): Expression => { - if (Array.isArray(e) && e[0] === "FUNC" && e[1] === "AUTH") { - if (authentication && authentication["method"] === "Basic") { - return ( - authentication["username"] === e[2] && - authentication["password"] === e[3] - ); - } else { - return false; + async (e: Expression): Promise => { + if (Array.isArray(e) && e[0] === "FUNC") { + if (e[1] === "EXT") { + if (typeof e[2] !== "string" || typeof e[3] !== "string") return null; + + for (let i = 4; i < e.length; i++) + if (Array.isArray(e[i])) return null; + + const { fault, value } = await extensions.run(e.slice(2)); + return fault ? null : value; + } else if (e[1] === "AUTH") { + if (authentication && authentication["method"] === "Basic") { + return ( + authentication["username"] === e[2] && + authentication["password"] === e[3] + ); + } else { + return false; + } } } return e; @@ -1160,7 +1171,10 @@ async function listenerAsync( } if (sessionContext) { - if (sessionContext.state === 0 && !authenticate(sessionContext)) { + const authenticated = + sessionContext.state === 0 ? await authenticate(sessionContext) : true; + + if (!authenticated) { logger.accessError({ message: "Authentication failure", sessionContext: sessionContext @@ -1248,7 +1262,8 @@ async function listenerAsync( } } - if (!authenticate(_sessionContext)) { + const authenticated = await authenticate(_sessionContext); + if (!authenticated) { logger.accessError({ message: "Authentication failure", sessionContext: _sessionContext