@routr/connect 2.0.8-alpha.5 → 2.0.8-alpha.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,28 @@
1
+ import { MessageRequest, CommonConnect as CC } from "@routr/common";
2
+ import { RoutingDirection } from "./types";
3
+ export declare const checkAccess: (accessRequest: {
4
+ dataAPI: CC.DataAPI;
5
+ request: MessageRequest;
6
+ caller: CC.Resource;
7
+ callee: CC.Resource;
8
+ routingDirection: RoutingDirection;
9
+ }) => Promise<Record<string, unknown>>;
10
+ export declare const checkAgentAccess: (dataAPI: CC.DataAPI, request: MessageRequest, caller: CC.Resource) => Promise<{
11
+ message: {
12
+ responseType: number;
13
+ wwwAuthenticate: {
14
+ scheme: string;
15
+ realm: string;
16
+ qop: string;
17
+ opaque: string;
18
+ stale: boolean;
19
+ nonce: string;
20
+ algorithm: string;
21
+ };
22
+ };
23
+ }>;
24
+ export declare const checkAccessFromPSTN: (dataAPI: CC.DataAPI, request: MessageRequest, callee: CC.Resource) => Promise<{
25
+ message: {
26
+ responseType: number;
27
+ };
28
+ }>;
package/dist/access.js ADDED
@@ -0,0 +1,126 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.checkAccessFromPSTN = exports.checkAgentAccess = exports.checkAccess = void 0;
13
+ /*
14
+ * Copyright (C) 2022 by Fonoster Inc (https://fonoster.com)
15
+ * http://github.com/fonoster
16
+ *
17
+ * This file is part of Routr.
18
+ *
19
+ * Licensed under the MIT License (the "License");
20
+ * you may not use this file except in compliance with
21
+ * the License. You may obtain a copy of the License at
22
+ *
23
+ * https://opensource.org/licenses/MIT
24
+ *
25
+ * Unless required by applicable law or agreed to in writing, software
26
+ * distributed under the License is distributed on an "AS IS" BASIS,
27
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28
+ * See the License for the specific language governing permissions and
29
+ * limitations under the License.
30
+ */
31
+ const logger_1 = require("@fonoster/logger");
32
+ const common_1 = require("@routr/common");
33
+ const types_1 = require("./types");
34
+ const utils_1 = require("./utils");
35
+ const logger = (0, logger_1.getLogger)({ service: "connect", filePath: __filename });
36
+ const checkAccess = (accessRequest) => __awaiter(void 0, void 0, void 0, function* () {
37
+ const { dataAPI, request, caller, callee, routingDirection } = accessRequest;
38
+ switch (routingDirection) {
39
+ case types_1.RoutingDirection.AGENT_TO_AGENT:
40
+ return (0, exports.checkAgentAccess)(dataAPI, request, caller);
41
+ case types_1.RoutingDirection.AGENT_TO_PSTN:
42
+ return (0, exports.checkAgentAccess)(dataAPI, request, caller);
43
+ case types_1.RoutingDirection.FROM_PSTN:
44
+ return (0, exports.checkAccessFromPSTN)(dataAPI, request, callee);
45
+ case types_1.RoutingDirection.UNKNOWN:
46
+ return common_1.Auth.createForbideenResponse();
47
+ }
48
+ });
49
+ exports.checkAccess = checkAccess;
50
+ const checkAgentAccess = (dataAPI, request, caller) => __awaiter(void 0, void 0, void 0, function* () {
51
+ // Calculate and return challenge
52
+ if (request.message.authorization) {
53
+ const auth = Object.assign({}, request.message.authorization);
54
+ auth.method = request.method;
55
+ const credentials = yield dataAPI.get(caller.spec.credentialsRef);
56
+ // Calculate response and compare with the one send by the endpoint
57
+ const calcRes = common_1.Auth.calculateAuthResponse(auth, {
58
+ username: credentials === null || credentials === void 0 ? void 0 : credentials.spec.credentials.username,
59
+ secret: credentials === null || credentials === void 0 ? void 0 : credentials.spec.credentials.password
60
+ });
61
+ if (calcRes !== auth.response) {
62
+ return common_1.Auth.createUnauthorizedResponse(request.message.requestUri.host);
63
+ }
64
+ }
65
+ else {
66
+ return common_1.Auth.createUnauthorizedResponse(request.message.requestUri.host);
67
+ }
68
+ });
69
+ exports.checkAgentAccess = checkAgentAccess;
70
+ const checkAccessFromPSTN = (dataAPI, request, callee) => __awaiter(void 0, void 0, void 0, function* () {
71
+ var _a, _b;
72
+ // Get the Trunk associated with the SIP URI
73
+ const trunk = yield (0, utils_1.findTrunkByRequestURI)(dataAPI, request.message.requestUri.host);
74
+ // If the Trunk or Number doesn't exist reject the call
75
+ if (!callee || !trunk) {
76
+ return common_1.Auth.createForbideenResponse();
77
+ }
78
+ if (callee.spec.trunkRef !== trunk.ref) {
79
+ return common_1.Auth.createForbideenResponse();
80
+ }
81
+ // Verify that the IP is whitelisted which means getting the access control list for the trunk
82
+ if ((_a = trunk.spec.inbound) === null || _a === void 0 ? void 0 : _a.accessControlListRef) {
83
+ try {
84
+ const acl = yield dataAPI.get(trunk.spec.inbound.accessControlListRef);
85
+ if (!acl) {
86
+ // Should never happen since the ACL is required
87
+ return common_1.Auth.createServerInternalErrorResponse();
88
+ }
89
+ const allow = acl.spec.accessControlList.allow.filter((net) => {
90
+ return common_1.IpUtils.hasIp(net, request.sender.host);
91
+ })[0];
92
+ if (!allow) {
93
+ // TODO: Replace with Unauthorized
94
+ return common_1.Auth.createUnauthorizedResponseWithoutChallenge();
95
+ }
96
+ }
97
+ catch (e) {
98
+ logger.error(e);
99
+ }
100
+ }
101
+ // If the Trunk has a User/Password we must verify that the User/Password are valid
102
+ if ((_b = trunk.spec.inbound) === null || _b === void 0 ? void 0 : _b.credentialsRef) {
103
+ const credentials = yield dataAPI.get(trunk.spec.inbound.credentialsRef);
104
+ if (!credentials) {
105
+ // Should never happen since the Credentials is required
106
+ return common_1.Auth.createServerInternalErrorResponse();
107
+ }
108
+ // Calculate and return challenge
109
+ if (request.message.authorization) {
110
+ const auth = Object.assign({}, request.message.authorization);
111
+ auth.method = request.method;
112
+ // Calculate response and compare with the one send by the endpoint
113
+ const calcRes = common_1.Auth.calculateAuthResponse(auth, {
114
+ username: credentials === null || credentials === void 0 ? void 0 : credentials.spec.credentials.username,
115
+ secret: credentials === null || credentials === void 0 ? void 0 : credentials.spec.credentials.password
116
+ });
117
+ if (calcRes !== auth.response) {
118
+ return common_1.Auth.createUnauthorizedResponse(request.message.requestUri.host);
119
+ }
120
+ }
121
+ else {
122
+ return common_1.Auth.createUnauthorizedResponse(request.message.requestUri.host);
123
+ }
124
+ }
125
+ });
126
+ exports.checkAccessFromPSTN = checkAccessFromPSTN;
package/dist/errors.d.ts CHANGED
@@ -19,7 +19,7 @@ export declare class UnsuportedRoutingError extends Error {
19
19
  /**
20
20
  * Create a new ServiceUnavailableError.
21
21
  *
22
- * @param {string} routingDir - The routing direction
22
+ * @param {RoutingDirection} routingDirection - The routing direction
23
23
  */
24
- constructor(routingDir: RoutingDirection);
24
+ constructor(routingDirection: RoutingDirection);
25
25
  }
package/dist/errors.js CHANGED
@@ -67,10 +67,10 @@ class UnsuportedRoutingError extends Error {
67
67
  /**
68
68
  * Create a new ServiceUnavailableError.
69
69
  *
70
- * @param {string} routingDir - The routing direction
70
+ * @param {RoutingDirection} routingDirection - The routing direction
71
71
  */
72
- constructor(routingDir) {
73
- super("unsupported routing direction: " + routingDir);
72
+ constructor(routingDirection) {
73
+ super("unsupported routing direction: " + routingDirection);
74
74
  this.code = grpc.status.UNKNOWN;
75
75
  // Set the prototype explicitly.
76
76
  Object.setPrototypeOf(this, ServiceUnavailableError.prototype);
@@ -1,6 +1,6 @@
1
1
  import { MessageRequest, Response } from "@routr/processor";
2
- import { ILocationService } from "@routr/location/src/types";
2
+ import { ILocationService } from "@routr/location";
3
3
  import { CommonConnect as CC } from "@routr/common";
4
- export declare const handleRegister: (location: ILocationService) => (request: MessageRequest, res: Response) => Promise<void>;
4
+ export declare const handleRegister: (dataAPI: CC.DataAPI, location: ILocationService) => (request: MessageRequest, res: Response) => Promise<void>;
5
5
  export declare const handleRegistry: (req: MessageRequest, res: Response) => void;
6
6
  export declare const handleRequest: (location: ILocationService, dataAPI?: CC.DataAPI) => (req: MessageRequest, res: Response) => Promise<void | MessageRequest>;
package/dist/handlers.js CHANGED
@@ -34,8 +34,28 @@ const processor_1 = require("@routr/processor");
34
34
  const function_1 = require("fp-ts/function");
35
35
  const router_1 = require("./router");
36
36
  const common_1 = require("@routr/common");
37
- const handleRegister = (location) => {
37
+ const utils_1 = require("./utils");
38
+ const handleRegister = (dataAPI, location) => {
38
39
  return (request, res) => __awaiter(void 0, void 0, void 0, function* () {
40
+ // Calculate and return challenge
41
+ if (request.message.authorization) {
42
+ const auth = Object.assign({}, request.message.authorization);
43
+ auth.method = request.method;
44
+ const fromURI = request.message.from.address.uri;
45
+ const agent = yield (0, utils_1.findResource)(dataAPI, fromURI.host, fromURI.user);
46
+ const credentials = yield dataAPI.get(agent === null || agent === void 0 ? void 0 : agent.spec.credentialsRef);
47
+ // Calculate response and compare with the one send by the endpoint
48
+ const calcRes = common_1.Auth.calculateAuthResponse(auth, {
49
+ username: credentials === null || credentials === void 0 ? void 0 : credentials.spec.credentials.username,
50
+ secret: credentials === null || credentials === void 0 ? void 0 : credentials.spec.credentials.password
51
+ });
52
+ if (calcRes !== auth.response) {
53
+ return res.send(common_1.Auth.createUnauthorizedResponse(request.message.requestUri.host));
54
+ }
55
+ }
56
+ else {
57
+ return res.send(common_1.Auth.createUnauthorizedResponse(request.message.requestUri.host));
58
+ }
39
59
  yield location.addRoute({
40
60
  aor: processor_1.Target.getTargetAOR(request),
41
61
  route: location_1.Helper.createRoute(request)
@@ -58,13 +78,17 @@ const handleRequest = (location, dataAPI) => (req, res) => __awaiter(void 0, voi
58
78
  : yield (0, router_1.router)(location, dataAPI)(req);
59
79
  if (!route)
60
80
  return res.sendNotFound();
61
- // Forward request to peer edgeport
62
- if (req.edgePortRef !== route.edgePortRef) {
63
- return (0, function_1.pipe)(req, processor_1.Alterations.addSelfVia(route),
64
- // The LP address belongs to another edgeport
65
- processor_1.Alterations.addRouteToListeningPoint(route), processor_1.Alterations.addXEdgePortRef, processor_1.Alterations.decreaseMaxForwards);
81
+ // If route is not type Route then return
82
+ if (!("user" in route)) {
83
+ return res.send(route);
84
+ }
85
+ else {
86
+ // Forward request to peer edgeport
87
+ if (req.edgePortRef !== route.edgePortRef) {
88
+ return (0, function_1.pipe)(req, processor_1.Alterations.addSelfVia(route), processor_1.Alterations.addRouteToPeerEdgePort(route), processor_1.Alterations.addXEdgePortRef, processor_1.Alterations.decreaseMaxForwards);
89
+ }
90
+ res.send((0, tailor_1.tailor)(route, req));
66
91
  }
67
- res.send((0, tailor_1.tailor)(route, req));
68
92
  }
69
93
  catch (err) {
70
94
  res.sendError(err);
package/dist/router.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import { CommonConnect as CC, Route } from "@routr/common";
2
2
  import { MessageRequest } from "@routr/processor";
3
3
  import { ILocationService } from "@routr/location";
4
- export declare function router(location: ILocationService, dataAPI: CC.DataAPI): (req: MessageRequest) => Promise<Route>;
4
+ export declare function router(location: ILocationService, dataAPI: CC.DataAPI): (request: MessageRequest) => Promise<Route | Record<string, unknown>>;
package/dist/router.js CHANGED
@@ -35,29 +35,41 @@ const processor_1 = require("@routr/processor");
35
35
  const location_1 = require("@routr/location");
36
36
  const errors_1 = require("./errors");
37
37
  const logger_1 = require("@fonoster/logger");
38
+ const access_1 = require("./access");
38
39
  const logger = (0, logger_1.getLogger)({ service: "connect", filePath: __filename });
39
- const getSIPURI = (uri) => `sip:${uri.user}@${uri.host}`;
40
40
  // eslint-disable-next-line require-jsdoc
41
41
  function router(location, dataAPI) {
42
- return (req) => __awaiter(this, void 0, void 0, function* () {
43
- const fromURI = req.message.from.address.uri;
44
- const requestURI = req.message.requestUri;
42
+ return (request) => __awaiter(this, void 0, void 0, function* () {
43
+ const fromURI = request.message.from.address.uri;
44
+ const requestURI = request.message.requestUri;
45
45
  logger.verbose("routing request from: " +
46
- getSIPURI(fromURI) +
46
+ (0, utils_1.getSIPURI)(fromURI) +
47
47
  ", to: " +
48
- getSIPURI(requestURI), { fromURI: getSIPURI(fromURI), requestURI: getSIPURI(requestURI) });
48
+ (0, utils_1.getSIPURI)(requestURI), { fromURI: (0, utils_1.getSIPURI)(fromURI), requestURI: (0, utils_1.getSIPURI)(requestURI) });
49
49
  const caller = yield (0, utils_1.findResource)(dataAPI, fromURI.host, fromURI.user);
50
50
  const callee = yield (0, utils_1.findResource)(dataAPI, requestURI.host, requestURI.user);
51
- const routingDir = (0, utils_1.getRoutingDirection)(caller, callee);
52
- switch (routingDir) {
53
- case types_1.RoutingDirection.AGENT_TO_PSTN:
54
- return yield toPSTN(dataAPI, req, caller, requestURI.user);
51
+ const routingDirection = (0, utils_1.getRoutingDirection)(caller, callee);
52
+ if (request.method === common_1.CommonTypes.Method.INVITE) {
53
+ const failedCheck = yield (0, access_1.checkAccess)({
54
+ dataAPI,
55
+ request,
56
+ caller,
57
+ callee,
58
+ routingDirection
59
+ });
60
+ if (failedCheck) {
61
+ return failedCheck;
62
+ }
63
+ }
64
+ switch (routingDirection) {
55
65
  case types_1.RoutingDirection.AGENT_TO_AGENT:
56
- return agentToAgent(location, req);
66
+ return agentToAgent(location, request);
67
+ case types_1.RoutingDirection.AGENT_TO_PSTN:
68
+ return yield toPSTN(dataAPI, request, caller, requestURI.user);
57
69
  case types_1.RoutingDirection.FROM_PSTN:
58
70
  return yield fromPSTN(location, dataAPI, callee);
59
71
  default:
60
- throw new errors_1.UnsuportedRoutingError(routingDir);
72
+ throw new errors_1.UnsuportedRoutingError(routingDirection);
61
73
  }
62
74
  });
63
75
  }
@@ -119,14 +131,15 @@ function toPSTN(dataAPI, req, caller, calleeNumber) {
119
131
  throw new Error(`no trunk associated with Number ref: ${number === null || number === void 0 ? void 0 : number.ref}`);
120
132
  }
121
133
  const uri = (0, utils_1.getTrunkURI)(trunk);
122
- const egressListeningPoint = common_1.Helper.getListeningPoint(req, uri.transport);
123
134
  return {
124
135
  user: uri.user,
125
136
  host: uri.host,
126
137
  port: uri.port,
127
138
  transport: uri.transport,
128
139
  edgePortRef: req.edgePortRef,
129
- egressListeningPoint,
140
+ listeningPoints: req.listeningPoints,
141
+ localnets: req.localnets,
142
+ externalAddrs: req.externalAddrs,
130
143
  headers: [
131
144
  // TODO: Find a more deterministic way to re-add the Privacy header
132
145
  {
package/dist/service.js CHANGED
@@ -70,7 +70,7 @@ function ConnectProcessor(config) {
70
70
  (0, handlers_1.handleRegistry)(req, res);
71
71
  }
72
72
  else {
73
- (0, handlers_1.handleRegister)(location)(req, res);
73
+ (0, handlers_1.handleRegister)(common_2.CommonConnect.dataAPI(config.apiAddr), location)(req, res);
74
74
  }
75
75
  break;
76
76
  case common_1.Method.BYE:
package/dist/utils.d.ts CHANGED
@@ -2,6 +2,8 @@ import { HeaderModifier, MessageRequest, Transport, CommonConnect as CC } from "
2
2
  import { RoutingDirection } from "./types";
3
3
  export declare const isKind: (res: CC.Resource, kind: CC.Kind) => boolean;
4
4
  export declare const findDomain: (dataAPI: CC.DataAPI, domainUri: string) => Promise<CC.Resource>;
5
+ export declare const findTrunkByRequestURI: (dataAPI: CC.DataAPI, requestUri: string) => Promise<CC.Resource>;
6
+ export declare const findNumberByTelUrl: (dataAPI: CC.DataAPI, telUrl: string) => Promise<CC.Resource>;
5
7
  export declare const findResource: (dataAPI: CC.DataAPI, domainUri: string, userpart: string) => Promise<CC.Resource>;
6
8
  export declare const getRoutingDirection: (caller: CC.Resource, callee: CC.Resource) => RoutingDirection;
7
9
  export declare const createPAssertedIdentity: (req: MessageRequest, trunk: CC.Resource, number: CC.Resource) => HeaderModifier;
@@ -13,3 +15,7 @@ export declare const getTrunkURI: (trunk: CC.Resource) => {
13
15
  user: string;
14
16
  transport: Transport;
15
17
  };
18
+ export declare const getSIPURI: (uri: {
19
+ user?: string;
20
+ host: string;
21
+ }) => string;
package/dist/utils.js CHANGED
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
- exports.getTrunkURI = exports.createTrunkAuthentication = exports.createRemotePartyId = exports.createPAssertedIdentity = exports.getRoutingDirection = exports.findResource = exports.findDomain = exports.isKind = void 0;
12
+ exports.getSIPURI = exports.getTrunkURI = exports.createTrunkAuthentication = exports.createRemotePartyId = exports.createPAssertedIdentity = exports.getRoutingDirection = exports.findResource = exports.findNumberByTelUrl = exports.findTrunkByRequestURI = exports.findDomain = exports.isKind = void 0;
13
13
  /*
14
14
  * Copyright (C) 2022 by Fonoster Inc (https://fonoster.com)
15
15
  * http://github.com/fonoster/routr
@@ -47,16 +47,30 @@ const findDomain = (dataAPI, domainUri) => __awaiter(void 0, void 0, void 0, fun
47
47
  }))[0];
48
48
  });
49
49
  exports.findDomain = findDomain;
50
- const findResource = (dataAPI, domainUri, userpart) => __awaiter(void 0, void 0, void 0, function* () {
51
- const domain = yield (0, exports.findDomain)(dataAPI, domainUri);
52
- // TODO: Fix jsonpath not working for logical AND and OR
53
- let res = (yield dataAPI.findBy({
50
+ const findTrunkByRequestURI = (dataAPI, requestUri) => __awaiter(void 0, void 0, void 0, function* () {
51
+ return (yield dataAPI.findBy({
52
+ kind: common_1.CommonConnect.Kind.TRUNK,
53
+ criteria: common_1.CommonConnect.FindCriteria.FIND_TRUNK_BY_REQUEST_URI,
54
+ parameters: {
55
+ requestUri
56
+ }
57
+ }))[0];
58
+ });
59
+ exports.findTrunkByRequestURI = findTrunkByRequestURI;
60
+ const findNumberByTelUrl = (dataAPI, telUrl) => __awaiter(void 0, void 0, void 0, function* () {
61
+ return (yield dataAPI.findBy({
54
62
  kind: common_1.CommonConnect.Kind.NUMBER,
55
63
  criteria: common_1.CommonConnect.FindCriteria.FIND_NUMBER_BY_TELURL,
56
64
  parameters: {
57
- telUrl: `tel:${userpart}`
65
+ telUrl
58
66
  }
59
67
  }))[0];
68
+ });
69
+ exports.findNumberByTelUrl = findNumberByTelUrl;
70
+ const findResource = (dataAPI, domainUri, userpart) => __awaiter(void 0, void 0, void 0, function* () {
71
+ const domain = yield (0, exports.findDomain)(dataAPI, domainUri);
72
+ // TODO: Fix jsonpath not working for logical AND and OR
73
+ let res = yield (0, exports.findNumberByTelUrl)(dataAPI, `tel:${userpart}`);
60
74
  res =
61
75
  res == null
62
76
  ? (yield dataAPI.findBy({
@@ -141,3 +155,5 @@ const getTrunkURI = (trunk) => {
141
155
  };
142
156
  };
143
157
  exports.getTrunkURI = getTrunkURI;
158
+ const getSIPURI = (uri) => uri.user ? `sip:${uri.user}@${uri.host}` : `sip:${uri.host}`;
159
+ exports.getSIPURI = getSIPURI;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@routr/connect",
3
- "version": "2.0.8-alpha.5",
3
+ "version": "2.0.8-alpha.7",
4
4
  "description": "Default processor",
5
5
  "author": "Pedro Sanders <psanders@fonoster.com>",
6
6
  "homepage": "https://github.com/fonoster/routr#readme",
@@ -28,9 +28,9 @@
28
28
  "@opentelemetry/sdk-trace-base": "^1.0.4",
29
29
  "@opentelemetry/sdk-trace-node": "^1.0.4",
30
30
  "@opentelemetry/semantic-conventions": "^1.0.4",
31
- "@routr/common": "^2.0.8-alpha.5",
32
- "@routr/location": "^2.0.8-alpha.5",
33
- "@routr/processor": "^2.0.8-alpha.5"
31
+ "@routr/common": "^2.0.8-alpha.7",
32
+ "@routr/location": "^2.0.8-alpha.7",
33
+ "@routr/processor": "^2.0.8-alpha.7"
34
34
  },
35
35
  "files": [
36
36
  "dist"
@@ -45,5 +45,5 @@
45
45
  "bugs": {
46
46
  "url": "https://github.com/fonoster/routr/issues"
47
47
  },
48
- "gitHead": "215638b9d7b56b2db2c2f0bc1bada3b6accbde58"
48
+ "gitHead": "d2e012d926e02e319646ea0f5419962f8b712362"
49
49
  }