@routr/connect 2.0.8-alpha.0 → 2.0.8-alpha.10
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.
- package/dist/access.d.ts +28 -0
- package/dist/access.js +126 -0
- package/dist/errors.d.ts +3 -3
- package/dist/errors.js +3 -3
- package/dist/handlers.d.ts +2 -2
- package/dist/handlers.js +41 -14
- package/dist/router.d.ts +2 -3
- package/dist/router.js +92 -28
- package/dist/service.js +1 -1
- package/dist/tailor.js +2 -4
- package/dist/types.d.ts +1 -1
- package/dist/types.js +11 -10
- package/dist/utils.d.ts +10 -5
- package/dist/utils.js +68 -41
- package/package.json +5 -5
package/dist/access.d.ts
ADDED
@@ -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 checkAgentOrPeerAccess: (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.checkAgentOrPeerAccess = 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.PEER_TO_PSTN:
|
40
|
+
case types_1.RoutingDirection.AGENT_TO_AGENT:
|
41
|
+
case types_1.RoutingDirection.AGENT_TO_PSTN:
|
42
|
+
return (0, exports.checkAgentOrPeerAccess)(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 checkAgentOrPeerAccess = (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.checkAgentOrPeerAccess = checkAgentOrPeerAccess;
|
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.spec.credentials.username,
|
115
|
+
secret: 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
@@ -1,4 +1,4 @@
|
|
1
|
-
import {
|
1
|
+
import { RoutingDirection } from "./types";
|
2
2
|
/**
|
3
3
|
* Throw when the API server is unavailable.
|
4
4
|
*/
|
@@ -19,7 +19,7 @@ export declare class UnsuportedRoutingError extends Error {
|
|
19
19
|
/**
|
20
20
|
* Create a new ServiceUnavailableError.
|
21
21
|
*
|
22
|
-
* @param {
|
22
|
+
* @param {RoutingDirection} routingDirection - The routing direction
|
23
23
|
*/
|
24
|
-
constructor(
|
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 {
|
70
|
+
* @param {RoutingDirection} routingDirection - The routing direction
|
71
71
|
*/
|
72
|
-
constructor(
|
73
|
-
super("unsupported routing direction: " +
|
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);
|
package/dist/handlers.d.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import { MessageRequest, Response } from "@routr/processor";
|
2
|
-
import { ILocationService } from "@routr/location
|
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,21 +34,44 @@ 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
|
37
|
+
const utils_1 = require("./utils");
|
38
|
+
const handleRegister = (dataAPI, location) => {
|
38
39
|
return (request, res) => __awaiter(void 0, void 0, void 0, function* () {
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
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 peerOrAgent = yield (0, utils_1.findResource)(dataAPI, fromURI.host, fromURI.user);
|
46
|
+
if (!peerOrAgent) {
|
47
|
+
return res.send(common_1.Auth.createForbideenResponse());
|
48
|
+
}
|
49
|
+
const credentials = yield dataAPI.get(peerOrAgent.spec.credentialsRef);
|
50
|
+
// Calculate response and compare with the one send by the endpoint
|
51
|
+
const calcRes = common_1.Auth.calculateAuthResponse(auth, {
|
52
|
+
username: credentials === null || credentials === void 0 ? void 0 : credentials.spec.credentials.username,
|
53
|
+
secret: credentials === null || credentials === void 0 ? void 0 : credentials.spec.credentials.password
|
54
|
+
});
|
55
|
+
if (calcRes !== auth.response) {
|
56
|
+
return res.send(common_1.Auth.createUnauthorizedResponse(request.message.requestUri.host));
|
57
|
+
}
|
58
|
+
// TODO: Needs test
|
59
|
+
yield location.addRoute({
|
60
|
+
aor: peerOrAgent.spec.aor || processor_1.Target.getTargetAOR(request),
|
61
|
+
route: location_1.Helper.createRoute(request)
|
62
|
+
});
|
63
|
+
res.sendOk();
|
64
|
+
}
|
65
|
+
else {
|
66
|
+
return res.send(common_1.Auth.createUnauthorizedResponse(request.message.requestUri.host));
|
67
|
+
}
|
44
68
|
});
|
45
69
|
};
|
46
70
|
exports.handleRegister = handleRegister;
|
47
71
|
// TODO: Needs test
|
48
72
|
const handleRegistry = (req, res) => {
|
49
73
|
const route = processor_1.Helper.createRouteFromLastMessage(req);
|
50
|
-
|
51
|
-
res.send(newReq);
|
74
|
+
res.send((0, function_1.pipe)(req, processor_1.Alterations.addSelfVia(route), processor_1.Alterations.decreaseMaxForwards, processor_1.Alterations.removeAuthorization, processor_1.Alterations.removeRoutes, processor_1.Alterations.removeXEdgePortRef));
|
52
75
|
};
|
53
76
|
exports.handleRegistry = handleRegistry;
|
54
77
|
// TODO: If request has X-Connect-Token then validate the JWT value and continue
|
@@ -59,13 +82,17 @@ const handleRequest = (location, dataAPI) => (req, res) => __awaiter(void 0, voi
|
|
59
82
|
: yield (0, router_1.router)(location, dataAPI)(req);
|
60
83
|
if (!route)
|
61
84
|
return res.sendNotFound();
|
62
|
-
//
|
63
|
-
if (
|
64
|
-
return
|
65
|
-
|
66
|
-
|
85
|
+
// If route is not type Route then return
|
86
|
+
if (!("user" in route)) {
|
87
|
+
return res.send(route);
|
88
|
+
}
|
89
|
+
else {
|
90
|
+
// Forward request to peer edgeport
|
91
|
+
if (req.edgePortRef !== route.edgePortRef) {
|
92
|
+
return (0, function_1.pipe)(req, processor_1.Alterations.addSelfVia(route), processor_1.Alterations.addRouteToPeerEdgePort(route), processor_1.Alterations.addXEdgePortRef, processor_1.Alterations.decreaseMaxForwards);
|
93
|
+
}
|
94
|
+
res.send((0, tailor_1.tailor)(route, req));
|
67
95
|
}
|
68
|
-
res.send((0, tailor_1.tailor)(route, req));
|
69
96
|
}
|
70
97
|
catch (err) {
|
71
98
|
res.sendError(err);
|
package/dist/router.d.ts
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
import { Route } from "@routr/common";
|
1
|
+
import { CommonConnect as CC, Route } from "@routr/common";
|
2
2
|
import { MessageRequest } from "@routr/processor";
|
3
3
|
import { ILocationService } from "@routr/location";
|
4
|
-
|
5
|
-
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
@@ -29,35 +29,49 @@ exports.router = void 0;
|
|
29
29
|
* limitations under the License.
|
30
30
|
*/
|
31
31
|
const types_1 = require("./types");
|
32
|
+
const common_1 = require("@routr/common");
|
32
33
|
const utils_1 = require("./utils");
|
33
34
|
const processor_1 = require("@routr/processor");
|
34
|
-
const errors_1 = require("./errors");
|
35
35
|
const location_1 = require("@routr/location");
|
36
|
+
const errors_1 = require("./errors");
|
36
37
|
const logger_1 = require("@fonoster/logger");
|
37
|
-
const
|
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 (
|
43
|
-
const fromURI =
|
44
|
-
const 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
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
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) {
|
65
|
+
case types_1.RoutingDirection.AGENT_TO_AGENT:
|
66
|
+
return agentToAgent(location, request);
|
67
|
+
case types_1.RoutingDirection.AGENT_TO_PSTN:
|
68
|
+
return yield agentToPSTN(dataAPI, request, caller, requestURI.user);
|
69
|
+
case types_1.RoutingDirection.FROM_PSTN:
|
70
|
+
return yield fromPSTN(location, callee);
|
71
|
+
case types_1.RoutingDirection.PEER_TO_PSTN:
|
72
|
+
return yield peerToPSTN(dataAPI, request);
|
59
73
|
default:
|
60
|
-
throw new errors_1.UnsuportedRoutingError(
|
74
|
+
throw new errors_1.UnsuportedRoutingError(routingDirection);
|
61
75
|
}
|
62
76
|
});
|
63
77
|
}
|
@@ -72,11 +86,10 @@ function agentToAgent(location, req) {
|
|
72
86
|
* From PSTN routing.
|
73
87
|
*
|
74
88
|
* @param {ILocationService} location - Location service
|
75
|
-
* @param {uknown} _
|
76
89
|
* @param {Resource} callee - The callee
|
77
90
|
* @return {Promise<Route>}
|
78
91
|
*/
|
79
|
-
function fromPSTN(location,
|
92
|
+
function fromPSTN(location, callee) {
|
80
93
|
var _a;
|
81
94
|
return __awaiter(this, void 0, void 0, function* () {
|
82
95
|
const route = (yield location.findRoutes({
|
@@ -99,24 +112,68 @@ function fromPSTN(location, _, callee) {
|
|
99
112
|
});
|
100
113
|
}
|
101
114
|
// eslint-disable-next-line require-jsdoc
|
102
|
-
function
|
103
|
-
var _a
|
115
|
+
function agentToPSTN(dataAPI, req, caller, calleeNumber) {
|
116
|
+
var _a;
|
104
117
|
return __awaiter(this, void 0, void 0, function* () {
|
105
118
|
const domain = yield dataAPI.get(caller.spec.domainRef);
|
119
|
+
if (!domain.spec.context.egressPolicies) {
|
120
|
+
// TODO: Create custom error
|
121
|
+
throw new Error(`no egress policy found for Domain ref: ${domain.ref}`);
|
122
|
+
}
|
106
123
|
// Look for Number in domain that matches regex callee
|
107
|
-
const policy =
|
124
|
+
const policy = domain.spec.context.egressPolicies.find((policy) => {
|
108
125
|
const regex = new RegExp(policy.rule);
|
109
126
|
return regex.test(calleeNumber);
|
110
127
|
});
|
111
128
|
const number = yield dataAPI.get(policy === null || policy === void 0 ? void 0 : policy.numberRef);
|
112
129
|
const trunk = yield dataAPI.get(number === null || number === void 0 ? void 0 : number.spec.trunkRef);
|
113
|
-
if (!
|
114
|
-
//
|
115
|
-
throw new Error(`no
|
130
|
+
if (!trunk) {
|
131
|
+
// This should never happen
|
132
|
+
throw new Error(`no trunk associated with Number ref: ${number.ref}`);
|
116
133
|
}
|
134
|
+
const uri = (0, utils_1.getTrunkURI)(trunk);
|
135
|
+
return {
|
136
|
+
user: uri.user,
|
137
|
+
host: uri.host,
|
138
|
+
port: uri.port,
|
139
|
+
transport: uri.transport,
|
140
|
+
edgePortRef: req.edgePortRef,
|
141
|
+
listeningPoints: req.listeningPoints,
|
142
|
+
localnets: req.localnets,
|
143
|
+
externalAddrs: req.externalAddrs,
|
144
|
+
headers: [
|
145
|
+
// TODO: Find a more deterministic way to re-add the Privacy header
|
146
|
+
{
|
147
|
+
name: "Privacy",
|
148
|
+
action: common_1.CommonTypes.HeaderModifierAction.REMOVE
|
149
|
+
},
|
150
|
+
{
|
151
|
+
name: "Privacy",
|
152
|
+
value: ((_a = caller.spec.privacy) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === common_1.CommonTypes.Privacy.PRIVATE
|
153
|
+
? common_1.CommonTypes.Privacy.PRIVATE
|
154
|
+
: common_1.CommonTypes.Privacy.NONE,
|
155
|
+
action: common_1.CommonTypes.HeaderModifierAction.ADD
|
156
|
+
},
|
157
|
+
(0, utils_1.createRemotePartyId)(trunk, number),
|
158
|
+
(0, utils_1.createPAssertedIdentity)(req, trunk, number),
|
159
|
+
yield (0, utils_1.createTrunkAuthentication)(dataAPI, trunk)
|
160
|
+
]
|
161
|
+
};
|
162
|
+
});
|
163
|
+
}
|
164
|
+
// eslint-disable-next-line require-jsdoc
|
165
|
+
function peerToPSTN(dataAPI, req) {
|
166
|
+
return __awaiter(this, void 0, void 0, function* () {
|
167
|
+
const numberTel = processor_1.Extensions.getHeaderValue(req, common_1.CommonTypes.ExtraHeader.DOD_NUMBER);
|
168
|
+
const privacy = processor_1.Extensions.getHeaderValue(req, common_1.CommonTypes.ExtraHeader.DOD_PRIVACY);
|
169
|
+
const number = yield (0, utils_1.findNumberByTelUrl)(dataAPI, `tel:${numberTel}`);
|
170
|
+
if (!number) {
|
171
|
+
throw new Error(`no Number found for tel: ${numberTel}`);
|
172
|
+
}
|
173
|
+
const trunk = yield dataAPI.get(number === null || number === void 0 ? void 0 : number.spec.trunkRef);
|
117
174
|
if (!trunk) {
|
118
175
|
// TODO: Create custom error
|
119
|
-
throw new Error(`no trunk associated with Number ref: ${number
|
176
|
+
throw new Error(`no trunk associated with Number ref: ${number.ref}`);
|
120
177
|
}
|
121
178
|
const uri = (0, utils_1.getTrunkURI)(trunk);
|
122
179
|
return {
|
@@ -125,11 +182,18 @@ function toPSTN(dataAPI, req, caller, calleeNumber) {
|
|
125
182
|
port: uri.port,
|
126
183
|
transport: uri.transport,
|
127
184
|
edgePortRef: req.edgePortRef,
|
128
|
-
|
185
|
+
listeningPoints: req.listeningPoints,
|
186
|
+
localnets: req.localnets,
|
187
|
+
externalAddrs: req.externalAddrs,
|
129
188
|
headers: [
|
189
|
+
// TODO: Find a more deterministic way to re-add the Privacy header
|
190
|
+
{
|
191
|
+
name: "Privacy",
|
192
|
+
action: common_1.CommonTypes.HeaderModifierAction.REMOVE
|
193
|
+
},
|
130
194
|
{
|
131
195
|
name: "Privacy",
|
132
|
-
value: (
|
196
|
+
value: (privacy === null || privacy === void 0 ? void 0 : privacy.toLocaleLowerCase()) === common_1.CommonTypes.Privacy.PRIVATE
|
133
197
|
? common_1.CommonTypes.Privacy.PRIVATE
|
134
198
|
: common_1.CommonTypes.Privacy.NONE,
|
135
199
|
action: common_1.CommonTypes.HeaderModifierAction.ADD
|
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/tailor.js
CHANGED
@@ -21,10 +21,8 @@ exports.tailor = void 0;
|
|
21
21
|
*/
|
22
22
|
const processor_1 = require("@routr/processor");
|
23
23
|
const function_1 = require("fp-ts/function");
|
24
|
-
// Q:
|
25
|
-
const tailor = (route, req) => (0, function_1.pipe)(
|
26
|
-
// TODO: Fix this hardcode
|
27
|
-
processor_1.Extensions.removeHeader(req, "Privacy"), processor_1.Alterations.addSelfVia(route), processor_1.Alterations.applyXHeaders(route), processor_1.Alterations.addRoute(route), processor_1.Alterations.addSelfRecordRoute, processor_1.Alterations.decreaseMaxForwards, processor_1.Alterations.removeAuthorization, processor_1.Alterations.removeRoutes, processor_1.Alterations.removeXEdgePortRef
|
24
|
+
// Q: Should we add support for strict routing?
|
25
|
+
const tailor = (route, req) => (0, function_1.pipe)(req, processor_1.Alterations.addSelfVia(route), processor_1.Alterations.applyXHeaders(route), processor_1.Alterations.addRoute(route), processor_1.Alterations.addSelfRecordRoute(route), processor_1.Alterations.decreaseMaxForwards, processor_1.Alterations.removeAuthorization, processor_1.Alterations.removeRoutes, processor_1.Alterations.removeXEdgePortRef
|
28
26
|
// Add updateContact for SIP.js support
|
29
27
|
);
|
30
28
|
exports.tailor = tailor;
|
package/dist/types.d.ts
CHANGED
package/dist/types.js
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.
|
4
|
-
var
|
5
|
-
(function (
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
3
|
+
exports.RoutingDirection = void 0;
|
4
|
+
var RoutingDirection;
|
5
|
+
(function (RoutingDirection) {
|
6
|
+
RoutingDirection["FROM_PSTN"] = "from-pstn";
|
7
|
+
RoutingDirection["AGENT_TO_AGENT"] = "agent-to-agent";
|
8
|
+
RoutingDirection["AGENT_TO_PSTN"] = "agent-to-pstn";
|
9
|
+
// WARNING: This is not supported yet
|
10
|
+
RoutingDirection["PEER_TO_AGENT"] = "peer-to-agent";
|
11
|
+
RoutingDirection["PEER_TO_PSTN"] = "peer-to-pstn";
|
12
|
+
RoutingDirection["UNKNOWN"] = "unknown";
|
13
|
+
})(RoutingDirection = exports.RoutingDirection || (exports.RoutingDirection = {}));
|
package/dist/utils.d.ts
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
-
import { HeaderModifier, MessageRequest, Transport } from "@routr/common";
|
2
|
-
import {
|
3
|
-
|
4
|
-
export declare const isKind: (res: CC.Resource, kind: CC.KIND) => boolean;
|
1
|
+
import { HeaderModifier, MessageRequest, Transport, CommonConnect as CC } from "@routr/common";
|
2
|
+
import { RoutingDirection } from "./types";
|
3
|
+
export declare const isKind: (res: CC.Resource, kind: CC.Kind) => boolean;
|
5
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>;
|
6
7
|
export declare const findResource: (dataAPI: CC.DataAPI, domainUri: string, userpart: string) => Promise<CC.Resource>;
|
7
|
-
export declare const getRoutingDirection: (caller: CC.Resource, callee: CC.Resource) =>
|
8
|
+
export declare const getRoutingDirection: (caller: CC.Resource, callee: CC.Resource) => RoutingDirection;
|
8
9
|
export declare const createPAssertedIdentity: (req: MessageRequest, trunk: CC.Resource, number: CC.Resource) => HeaderModifier;
|
9
10
|
export declare const createRemotePartyId: (trunk: CC.Resource, number: CC.Resource) => HeaderModifier;
|
10
11
|
export declare const createTrunkAuthentication: (dataAPI: CC.DataAPI, trunk: CC.Resource) => Promise<HeaderModifier>;
|
@@ -14,3 +15,7 @@ export declare const getTrunkURI: (trunk: CC.Resource) => {
|
|
14
15
|
user: string;
|
15
16
|
transport: Transport;
|
16
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
|
@@ -29,10 +29,9 @@ exports.getTrunkURI = exports.createTrunkAuthentication = exports.createRemotePa
|
|
29
29
|
* limitations under the License.
|
30
30
|
*/
|
31
31
|
const common_1 = require("@routr/common");
|
32
|
-
const common_2 = require("@routr/common");
|
33
32
|
const types_1 = require("./types");
|
34
33
|
const isKind = (res, kind) => {
|
35
|
-
if (res == null && kind ===
|
34
|
+
if (res == null && kind === common_1.CommonConnect.Kind.UNKNOWN) {
|
36
35
|
return true;
|
37
36
|
}
|
38
37
|
return (res === null || res === void 0 ? void 0 : res.kind.toLowerCase()) === kind;
|
@@ -40,35 +39,59 @@ const isKind = (res, kind) => {
|
|
40
39
|
exports.isKind = isKind;
|
41
40
|
const findDomain = (dataAPI, domainUri) => __awaiter(void 0, void 0, void 0, function* () {
|
42
41
|
return (yield dataAPI.findBy({
|
43
|
-
kind:
|
44
|
-
criteria:
|
42
|
+
kind: common_1.CommonConnect.Kind.DOMAIN,
|
43
|
+
criteria: common_1.CommonConnect.FindCriteria.FIND_DOMAIN_BY_DOMAINURI,
|
45
44
|
parameters: {
|
46
45
|
domainUri
|
47
46
|
}
|
48
47
|
}))[0];
|
49
48
|
});
|
50
49
|
exports.findDomain = findDomain;
|
51
|
-
const
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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({
|
62
|
+
kind: common_1.CommonConnect.Kind.NUMBER,
|
63
|
+
criteria: common_1.CommonConnect.FindCriteria.FIND_NUMBER_BY_TELURL,
|
57
64
|
parameters: {
|
58
|
-
telUrl
|
65
|
+
telUrl
|
59
66
|
}
|
60
67
|
}))[0];
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
:
|
71
|
-
|
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}`);
|
74
|
+
// Next, try to find an agent
|
75
|
+
if (res == null) {
|
76
|
+
res = (yield dataAPI.findBy({
|
77
|
+
kind: common_1.CommonConnect.Kind.AGENT,
|
78
|
+
criteria: common_1.CommonConnect.FindCriteria.FIND_AGENT_BY_USERNAME,
|
79
|
+
parameters: {
|
80
|
+
username: userpart
|
81
|
+
}
|
82
|
+
}))[0];
|
83
|
+
}
|
84
|
+
// Next, try to find a peer
|
85
|
+
if (res == null) {
|
86
|
+
res = (yield dataAPI.findBy({
|
87
|
+
kind: common_1.CommonConnect.Kind.PEER,
|
88
|
+
criteria: common_1.CommonConnect.FindCriteria.FIND_PEER_BY_USERNAME,
|
89
|
+
parameters: {
|
90
|
+
username: userpart
|
91
|
+
}
|
92
|
+
}))[0];
|
93
|
+
}
|
94
|
+
if ((0, exports.isKind)(res, common_1.CommonConnect.Kind.AGENT) && res.spec.domainRef != (domain === null || domain === void 0 ? void 0 : domain.ref)) {
|
72
95
|
// Not in the same domain
|
73
96
|
return null;
|
74
97
|
}
|
@@ -76,23 +99,23 @@ const findResource = (dataAPI, domainUri, userpart) => __awaiter(void 0, void 0,
|
|
76
99
|
});
|
77
100
|
exports.findResource = findResource;
|
78
101
|
const getRoutingDirection = (caller, callee) => {
|
79
|
-
if ((0, exports.isKind)(caller,
|
80
|
-
return types_1.
|
102
|
+
if ((0, exports.isKind)(caller, common_1.CommonConnect.Kind.AGENT) && (0, exports.isKind)(callee, common_1.CommonConnect.Kind.AGENT)) {
|
103
|
+
return types_1.RoutingDirection.AGENT_TO_AGENT;
|
81
104
|
}
|
82
|
-
if ((0, exports.isKind)(caller,
|
83
|
-
return types_1.
|
105
|
+
if ((0, exports.isKind)(caller, common_1.CommonConnect.Kind.AGENT) && (0, exports.isKind)(callee, common_1.CommonConnect.Kind.UNKNOWN)) {
|
106
|
+
return types_1.RoutingDirection.AGENT_TO_PSTN;
|
84
107
|
}
|
85
|
-
if ((0, exports.isKind)(caller,
|
86
|
-
return types_1.
|
108
|
+
if ((0, exports.isKind)(caller, common_1.CommonConnect.Kind.PEER) && (0, exports.isKind)(callee, common_1.CommonConnect.Kind.AGENT)) {
|
109
|
+
return types_1.RoutingDirection.PEER_TO_AGENT;
|
87
110
|
}
|
88
111
|
// All we know is that the Number is managed by this instance of Routr
|
89
|
-
if ((0, exports.isKind)(callee,
|
90
|
-
return types_1.
|
112
|
+
if ((0, exports.isKind)(callee, common_1.CommonConnect.Kind.NUMBER)) {
|
113
|
+
return types_1.RoutingDirection.FROM_PSTN;
|
91
114
|
}
|
92
|
-
if ((0, exports.isKind)(caller,
|
93
|
-
return types_1.
|
115
|
+
if ((0, exports.isKind)(caller, common_1.CommonConnect.Kind.PEER) && (0, exports.isKind)(callee, common_1.CommonConnect.Kind.UNKNOWN)) {
|
116
|
+
return types_1.RoutingDirection.PEER_TO_PSTN;
|
94
117
|
}
|
95
|
-
return types_1.
|
118
|
+
return types_1.RoutingDirection.UNKNOWN;
|
96
119
|
};
|
97
120
|
exports.getRoutingDirection = getRoutingDirection;
|
98
121
|
const createPAssertedIdentity = (req, trunk, number) => {
|
@@ -104,7 +127,7 @@ const createPAssertedIdentity = (req, trunk, number) => {
|
|
104
127
|
value: displayName
|
105
128
|
? `"${displayName}" <sip:${remoteNumber}@${trunkHost};user=phone>`
|
106
129
|
: `<sip:${remoteNumber}@${trunkHost};user=phone>`,
|
107
|
-
action:
|
130
|
+
action: common_1.CommonTypes.HeaderModifierAction.ADD
|
108
131
|
};
|
109
132
|
};
|
110
133
|
exports.createPAssertedIdentity = createPAssertedIdentity;
|
@@ -114,7 +137,7 @@ const createRemotePartyId = (trunk, number) => {
|
|
114
137
|
return {
|
115
138
|
name: "Remote-Party-ID",
|
116
139
|
value: `<sip:${remoteNumber}@${trunkHost}>;screen=yes;party=calling`,
|
117
|
-
action:
|
140
|
+
action: common_1.CommonTypes.HeaderModifierAction.ADD
|
118
141
|
};
|
119
142
|
};
|
120
143
|
exports.createRemotePartyId = createRemotePartyId;
|
@@ -122,18 +145,20 @@ const createTrunkAuthentication = (dataAPI, trunk) => __awaiter(void 0, void 0,
|
|
122
145
|
var _a, _b;
|
123
146
|
const credentials = yield dataAPI.get(trunk.spec.outbound.credentialsRef);
|
124
147
|
return {
|
125
|
-
name:
|
148
|
+
name: common_1.CommonTypes.ExtraHeader.GATEWAY_AUTH,
|
126
149
|
value: Buffer.from(`${(_a = credentials.spec.credentials) === null || _a === void 0 ? void 0 : _a.username}:${(_b = credentials.spec.credentials) === null || _b === void 0 ? void 0 : _b.password}`).toString("base64"),
|
127
|
-
action:
|
150
|
+
action: common_1.CommonTypes.HeaderModifierAction.ADD
|
128
151
|
};
|
129
152
|
});
|
130
153
|
exports.createTrunkAuthentication = createTrunkAuthentication;
|
131
154
|
const getTrunkURI = (trunk) => {
|
132
|
-
|
133
|
-
|
155
|
+
if (!trunk.spec.outbound) {
|
156
|
+
throw new Error(`trunk ${trunk.ref} has no outbound settings`);
|
157
|
+
}
|
158
|
+
const { user, host, port, transport } = trunk.spec.outbound.uris[0].uri;
|
134
159
|
const t = !transport
|
135
160
|
? common_1.Transport.UDP
|
136
|
-
: Object.
|
161
|
+
: Object.values(common_1.Transport)[Object.values(common_1.Transport).indexOf(transport.toLowerCase())];
|
137
162
|
return {
|
138
163
|
user,
|
139
164
|
host,
|
@@ -142,3 +167,5 @@ const getTrunkURI = (trunk) => {
|
|
142
167
|
};
|
143
168
|
};
|
144
169
|
exports.getTrunkURI = getTrunkURI;
|
170
|
+
const getSIPURI = (uri) => uri.user ? `sip:${uri.user}@${uri.host}` : `sip:${uri.host}`;
|
171
|
+
exports.getSIPURI = getSIPURI;
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@routr/connect",
|
3
|
-
"version": "2.0.8-alpha.
|
3
|
+
"version": "2.0.8-alpha.10",
|
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.
|
32
|
-
"@routr/location": "^2.0.8-alpha.
|
33
|
-
"@routr/processor": "^2.0.8-alpha.
|
31
|
+
"@routr/common": "^2.0.8-alpha.10",
|
32
|
+
"@routr/location": "^2.0.8-alpha.10",
|
33
|
+
"@routr/processor": "^2.0.8-alpha.10"
|
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": "
|
48
|
+
"gitHead": "5082233fb155ddb8535f934550fa4013da87468e"
|
49
49
|
}
|