drachtio-srf 5.0.0 → 5.0.2
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/lib/@types/index.d.ts +171 -143
- package/lib/digest-client.js +3 -0
- package/lib/srf.js +4 -6
- package/package.json +3 -3
- package/test/docker-compose-testbed.yaml +11 -0
- package/test/scenarios/uas-407-no-auth-header.xml +142 -0
- package/test/uac.js +26 -0
package/lib/@types/index.d.ts
CHANGED
|
@@ -1,156 +1,184 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { EventEmitter } from 'events';
|
|
1
|
+
import { Socket } from 'net';
|
|
2
|
+
import { EventEmitter } from 'events';
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
declare namespace Srf {
|
|
5
|
+
type SipMethod = 'ACK' | 'BYE' | 'CANCEL' | 'INFO' | 'INVITE' | 'MESSAGE' | 'NOTIFY' | 'OPTIONS' | 'PRACK' | 'PUBLISH' | 'REFER' | 'REGISTER' | 'SUBSCRIBE' | 'UPDATE';
|
|
6
|
+
type SipMessageHeaders = Record<string, string>;
|
|
7
|
+
type AOR = { name: string; uri: string; params?: Record<string, any>; };
|
|
8
|
+
type Via = { version: string; protocol: string; host: string; port: string; };
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
export interface SrfConfig {
|
|
11
|
+
apiSecret?: string;
|
|
12
|
+
host?: string;
|
|
13
|
+
port?: number;
|
|
14
|
+
secret?: string;
|
|
15
|
+
}
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
interface ParseUriResult {
|
|
18
|
+
family?: 'ipv6' | 'ipv4';
|
|
19
|
+
scheme: 'sip' | 'sips' | 'tel';
|
|
20
|
+
user?: string;
|
|
21
|
+
password?: string;
|
|
22
|
+
host?: string;
|
|
23
|
+
port?: string;
|
|
24
|
+
params: Record<string, string | null>;
|
|
25
|
+
headers: Record<string, string>;
|
|
26
|
+
context?: string;
|
|
27
|
+
}
|
|
19
28
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
body: string;
|
|
23
|
-
payload: object[];
|
|
24
|
-
source: "network" | "application";
|
|
25
|
-
source_address: string;
|
|
26
|
-
source_port: string;
|
|
27
|
-
protocol: string;
|
|
28
|
-
stackTime: string;
|
|
29
|
-
calledNumber: string;
|
|
30
|
-
callingNumber: string;
|
|
31
|
-
raw: string;
|
|
32
|
-
get(name: string): string;
|
|
33
|
-
has(name: string): boolean;
|
|
34
|
-
set(name: string, value: string);
|
|
35
|
-
getParsedHeader(name: "contact" | "Contact"): Array<AOR>;
|
|
36
|
-
getParsedHeader(name: "via" | "Via"): Array<Via>;
|
|
37
|
-
getParsedHeader(name: "To" | "to" | "From" | "from" | "refer-to" | "referred-by" | "p-asserted-identity" | "remote-party-id"): AOR;
|
|
38
|
-
getParsedHeader(name: string): string;
|
|
39
|
-
}
|
|
29
|
+
export function parseUri(uri: string): ParseUriResult;
|
|
30
|
+
export function stringifyUri(uri: object): string;
|
|
40
31
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
32
|
+
export interface SipMessage {
|
|
33
|
+
type: "request" | "response";
|
|
34
|
+
body: string;
|
|
35
|
+
payload: object[];
|
|
36
|
+
source: "network" | "application";
|
|
37
|
+
source_address: string;
|
|
38
|
+
source_port: string;
|
|
39
|
+
protocol: string;
|
|
40
|
+
stackTime: string;
|
|
41
|
+
calledNumber: string;
|
|
42
|
+
callingNumber: string;
|
|
43
|
+
raw: string;
|
|
44
|
+
get(name: string): string;
|
|
45
|
+
has(name: string): boolean;
|
|
46
|
+
set(name: string, value: string): void;
|
|
47
|
+
getParsedHeader(name: "contact" | "Contact"): Array<AOR>;
|
|
48
|
+
getParsedHeader(name: "via" | "Via"): Array<Via>;
|
|
49
|
+
getParsedHeader(name: "To" | "to" | "From" | "from" | "refer-to" | "referred-by" | "p-asserted-identity" | "remote-party-id"): AOR;
|
|
50
|
+
getParsedHeader(name: string): string;
|
|
51
|
+
}
|
|
61
52
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
53
|
+
export interface SrfRequest extends SipMessage {
|
|
54
|
+
method: SipMethod;
|
|
55
|
+
get isNewInvite(): boolean
|
|
56
|
+
cancel(callback: (err: any, req: SrfRequest) => void): void;
|
|
57
|
+
on(event: 'response', callback: (res?: SrfResponse, ack?: (opts?: { sdp: string }) => void) => void): void;
|
|
58
|
+
on(event: 'cancel', callback: (res: SipMessage) => void): void;
|
|
59
|
+
branch: string;
|
|
60
|
+
callId: string;
|
|
61
|
+
from: string;
|
|
62
|
+
headers: Record<string, string>;
|
|
63
|
+
msg: any;
|
|
64
|
+
sdp: string;
|
|
65
|
+
srf: any;
|
|
66
|
+
to: string;
|
|
67
|
+
uri: string;
|
|
68
|
+
registration?: {
|
|
69
|
+
type: "unregister" | "register";
|
|
70
|
+
expires: number;
|
|
71
|
+
contact: Array<AOR>;
|
|
72
|
+
aor: string;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
73
75
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
destroy(opts?: { headers: Record<string, string>; }, callback?: (err, msg) => {}): void;
|
|
83
|
-
modify(sdp, callback?: (err: any, msg: SrfResponse) => void): void;
|
|
84
|
-
modify({ noAck: boolean }, callback?: (err: any, resp: any, resAck: any) => void): void;
|
|
85
|
-
on(messageType: "ack", callback: (msg: SrfRequest) => void): void;
|
|
86
|
-
on(messageType: "destroy", callback: (msg: SrfRequest) => void): void;
|
|
87
|
-
on(messageType: "info", callback: (req: SrfRequest, res: SrfResponse) => void): void;
|
|
88
|
-
on(messageType: "message", callback: (req: SrfRequest, res: SrfResponse) => void): void;
|
|
89
|
-
on(messageType: "modify", callback: (req: SrfRequest, res: SrfResponse) => void): void;
|
|
90
|
-
on(messageType: "notify", callback: (req: SrfRequest, res: SrfResponse) => void): void;
|
|
91
|
-
on(messageType: "options", callback: (req: SrfRequest, res: SrfResponse) => void): void;
|
|
92
|
-
on(messageType: "refer", callback: (req: SrfRequest, res: SrfResponse) => void): void;
|
|
93
|
-
on(messageType: "refresh", callback: (msg: SrfRequest) => void): void;
|
|
94
|
-
on(messageType: "update", callback: (req: SrfRequest, res: SrfResponse) => void): void;
|
|
95
|
-
on(messageType: "modify", callback: (req: SrfRequest, res: SrfResponse) => void): void;
|
|
96
|
-
once(messageType: string, callback: (msg: SrfResponse) => void): void;
|
|
97
|
-
listeners(messageType: string): any[];
|
|
98
|
-
request(opts?: { method: SipMethod; headers?: Record<string, string | number>; body?: string; }, callback?: (err, msg) => {});
|
|
99
|
-
}
|
|
76
|
+
export interface ProxyRequestOptions {
|
|
77
|
+
forking?: 'sequential' | 'simultaneous';
|
|
78
|
+
remainInDialog?: boolean;
|
|
79
|
+
recordRoute?: boolean;
|
|
80
|
+
provisionalTimeout?: string;
|
|
81
|
+
finalTimeout?: string;
|
|
82
|
+
followRedirects?: boolean
|
|
83
|
+
}
|
|
100
84
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
85
|
+
export interface SrfResponse extends SipMessage {
|
|
86
|
+
status: number;
|
|
87
|
+
statusCode: number;
|
|
88
|
+
reason: string;
|
|
89
|
+
finalResponseSent: boolean;
|
|
90
|
+
send(status: number, opts?: object): void;
|
|
91
|
+
send(status: number, reason: string, opts: object): void;
|
|
92
|
+
send(status: number, reason: string, opts: object, callback: (err: any, msg: SipMessage) => void): void;
|
|
93
|
+
end(): void;
|
|
94
|
+
}
|
|
105
95
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
96
|
+
export interface Dialog {
|
|
97
|
+
sip: { callId: string; localTag: string; remoteTag: string; };
|
|
98
|
+
onHold: boolean;
|
|
99
|
+
other: Dialog;
|
|
100
|
+
type: "uac" | "uas";
|
|
101
|
+
local: { uri: string; sdp: string; };
|
|
102
|
+
remote: { uri: string; sdp: string; };
|
|
103
|
+
req: SrfRequest;
|
|
104
|
+
destroy(opts?: { headers: Record<string, string>; }, callback?: (err: any, msg: SrfRequest) => void): void;
|
|
105
|
+
modify(sdp: string, opts?: { noAck: boolean }): Promise<string>;
|
|
106
|
+
modify(opts: { noAck: boolean }): Promise<string>;
|
|
107
|
+
modify(sdp: string, opts?: { noAck: boolean }, callback?: (err: any, msg: SrfResponse) => void): void;
|
|
108
|
+
modify(opts: { noAck: boolean }, callback?: (err: any, resp?: string, resAck?: (sdp: string) => void) => void): void;
|
|
109
|
+
on(messageType: "ack", callback: (msg: SrfRequest) => void): void;
|
|
110
|
+
on(messageType: "destroy", callback: (msg: SrfRequest) => void): void;
|
|
111
|
+
on(messageType: "info", callback: (req: SrfRequest, res: SrfResponse) => void): void;
|
|
112
|
+
on(messageType: "message", callback: (req: SrfRequest, res: SrfResponse) => void): void;
|
|
113
|
+
on(messageType: "modify", callback: (req: SrfRequest, res: SrfResponse) => void): void;
|
|
114
|
+
on(messageType: "notify", callback: (req: SrfRequest, res: SrfResponse) => void): void;
|
|
115
|
+
on(messageType: "options", callback: (req: SrfRequest, res: SrfResponse) => void): void;
|
|
116
|
+
on(messageType: "refer", callback: (req: SrfRequest, res: SrfResponse) => void): void;
|
|
117
|
+
on(messageType: "refresh", callback: (msg: SrfRequest) => void): void;
|
|
118
|
+
on(messageType: "update", callback: (req: SrfRequest, res: SrfResponse) => void): void;
|
|
119
|
+
on(messageType: "modify", callback: (req: SrfRequest, res: SrfResponse) => void): void;
|
|
120
|
+
once(messageType: string, callback: (msg: SrfResponse) => void): void;
|
|
121
|
+
listeners(messageType: string): any[];
|
|
122
|
+
request(opts?: SrfRequest): Promise<SrfResponse>;
|
|
123
|
+
request(opts: SrfRequest, callback?: (err: any, msg: SrfResponse) => void): void;
|
|
124
|
+
}
|
|
114
125
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
localSdpB?: string | ((sdp: string) => string | Promise<string>);
|
|
120
|
-
proxyRequestHeaders?: string[];
|
|
121
|
-
proxyResponseHeaders?: string[];
|
|
122
|
-
passFailure?: boolean;
|
|
123
|
-
passProvisionalResponses?: boolean;
|
|
124
|
-
proxy?: string;
|
|
125
|
-
auth?: { username: string; password: string; };
|
|
126
|
-
}
|
|
126
|
+
export interface CreateUASOptions {
|
|
127
|
+
localSdp: string;
|
|
128
|
+
headers?: SipMessageHeaders;
|
|
129
|
+
}
|
|
127
130
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
request(uri: string, opts, method, [body], callback?: (err, requestSent: SrfRequest) => void);
|
|
137
|
-
proxyRequest(req: SrfRequest, destination: string | string[], [opts], callback?: (err, results) => {}): void;
|
|
138
|
-
createUAS(req: SrfRequest, res: SrfResponse, opts: CreateUASOptions, callback?: (err, dialog: Dialog) => void): Promise<Dialog>;
|
|
139
|
-
createUAC(uri: string | CreateUACOptions, opts?: CreateUACOptions, progressCallbacks?: { cbRequest?: (req: SrfRequest) => void; cbProvisional?: (provisionalRes: SrfResponse) => void; }, callback?: (err, dialog: Dialog) => void): Promise<Dialog>;
|
|
140
|
-
createB2BUA(req: SrfRequest, res: SrfResponse, uri: string, opts: CreateB2BUAOptions, progressCallbacks?: { cbRequest?: (req: SrfRequest) => void; cbProvisional?: (provisionalRes: Response) => void; cbFinalizedUac?: (uac: Dialog) => void; }, callback?: (err, dialog: Dialog) => {}): Promise<{ uas: Dialog; uac: Dialog }>;
|
|
141
|
-
on(event: 'connect', listener: (err: Error, hostPort: string) => void): this;
|
|
142
|
-
on(event: 'error', listener: (err: Error) => void): this;
|
|
143
|
-
on(event: 'disconnect', listener: () => void): this;
|
|
144
|
-
on(event: 'message', listener: (req: SrfRequest, res: SrfResponse) => void): this;
|
|
145
|
-
on(event: 'request', listener: (req: SrfRequest, res: SrfResponse) => void): this;
|
|
146
|
-
on(event: 'register' | 'invite' | 'bye' | 'cancel' | 'ack' | 'info' | 'notify' | 'options' | 'prack' | 'publish' | 'refer' | 'subscribe' | 'update', listener: (req: SrfRequest, res: SrfResponse) => void): this;
|
|
147
|
-
on(event: 'cdr:attempt', listener: (source: string, time: string, msg: SipMessage) => void): this;
|
|
148
|
-
on(event: 'cdr:start', listener: (source: string, time: string, role: string, msg: SipMessage) => void): this;
|
|
149
|
-
on(event: 'cdr:stop', listener: (source: string, time: string, reason: string, msg: SipMessage) => void): this;
|
|
150
|
-
locals: {[name: string]: any};
|
|
151
|
-
socket: Socket;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
131
|
+
export interface CreateUACOptions {
|
|
132
|
+
headers?: SipMessageHeaders;
|
|
133
|
+
uri?: string;
|
|
134
|
+
noAck?: boolean;
|
|
135
|
+
localSdp?: string;
|
|
136
|
+
proxy?: string;
|
|
137
|
+
auth?: { username: string; password: string; };
|
|
138
|
+
}
|
|
154
139
|
|
|
155
|
-
|
|
140
|
+
export interface CreateB2BUAOptions {
|
|
141
|
+
headers?: SipMessageHeaders;
|
|
142
|
+
responseHeaders?: SipMessageHeaders | ((uacRes: SipMessageHeaders, headers: SipMessageHeaders) => SipMessageHeaders | null);
|
|
143
|
+
localSdpA?: string | ((sdp: string, res: SrfResponse) => string | Promise<string>);
|
|
144
|
+
localSdpB?: string | ((sdp: string) => string | Promise<string>);
|
|
145
|
+
proxyRequestHeaders?: string[];
|
|
146
|
+
proxyResponseHeaders?: string[];
|
|
147
|
+
passFailure?: boolean;
|
|
148
|
+
passProvisionalResponses?: boolean;
|
|
149
|
+
proxy?: string;
|
|
150
|
+
auth?: { username: string; password: string; };
|
|
151
|
+
}
|
|
156
152
|
}
|
|
153
|
+
|
|
154
|
+
declare class Srf extends EventEmitter {
|
|
155
|
+
constructor();
|
|
156
|
+
constructor(tags: string | string[]);
|
|
157
|
+
connect(config?: Srf.SrfConfig): Promise<void>;
|
|
158
|
+
disconnect(): void;
|
|
159
|
+
use(callback: (req: Srf.SrfRequest, res: Srf.SrfResponse, next: Function) => void): void;
|
|
160
|
+
use(messageType: string, callback: (req: Srf.SrfRequest, res: Srf.SrfResponse, next: Function) => void): void;
|
|
161
|
+
invite(callback: (req: Srf.SrfRequest, res: Srf.SrfResponse) => void): void;
|
|
162
|
+
request(uri: string, opts: Srf.SrfRequest, method: Srf.SipMethod, [body]: string[]): Promise<Srf.SrfRequest>;
|
|
163
|
+
request(uri: string, opts: Srf.SrfRequest, method: Srf.SipMethod, [body]: string[], callback?: (err: any, requestSent: Srf.SrfRequest) => void): void;
|
|
164
|
+
proxyRequest(req: Srf.SrfRequest, destination: string | string[], opts?: Srf.ProxyRequestOptions, callback?: (err: any, results: string) => void): void;
|
|
165
|
+
createUAS(req: Srf.SrfRequest, res: Srf.SrfResponse, opts: Srf.CreateUASOptions): Promise<Srf.Dialog>;
|
|
166
|
+
createUAS(req: Srf.SrfRequest, res: Srf.SrfResponse, opts: Srf.CreateUASOptions, callback?: (err: any, dialog: Srf.Dialog) => void): this;
|
|
167
|
+
createUAC(uri: string | Srf.CreateUACOptions, opts?: Srf.CreateUACOptions, progressCallbacks?: { cbRequest?: (req: Srf.SrfRequest) => void; cbProvisional?: (provisionalRes: Srf.SrfResponse) => void; }): Promise<Srf.Dialog>;
|
|
168
|
+
createUAC(uri: string | Srf.CreateUACOptions, opts?: Srf.CreateUACOptions, progressCallbacks?: { cbRequest?: (req: Srf.SrfRequest) => void; cbProvisional?: (provisionalRes: Srf.SrfResponse) => void; }, callback?: (err: any, dialog: Srf.Dialog) => void): this;
|
|
169
|
+
createB2BUA(req: Srf.SrfRequest, res: Srf.SrfResponse, uri: string, opts: Srf.CreateB2BUAOptions, progressCallbacks?: { cbRequest?: (req: Srf.SrfRequest) => void; cbProvisional?: (provisionalRes: Response) => void; cbFinalizedUac?: (uac: Srf.Dialog) => void; }): Promise<{ uas: Srf.Dialog; uac: Srf.Dialog }>;
|
|
170
|
+
createB2BUA(req: Srf.SrfRequest, res: Srf.SrfResponse, uri: string, opts: Srf.CreateB2BUAOptions, progressCallbacks?: { cbRequest?: (req: Srf.SrfRequest) => void; cbProvisional?: (provisionalRes: Response) => void; cbFinalizedUac?: (uac: Srf.Dialog) => void; }, callback?: (err: any, dialog: Srf.Dialog) => void): this;
|
|
171
|
+
on(event: 'connect', listener: (err: Error, hostPort: string) => void): this;
|
|
172
|
+
on(event: 'error', listener: (err: Error) => void): this;
|
|
173
|
+
on(event: 'disconnect', listener: () => void): this;
|
|
174
|
+
on(event: 'message', listener: (req: Srf.SrfRequest, res: Srf.SrfResponse) => void): this;
|
|
175
|
+
on(event: 'request', listener: (req: Srf.SrfRequest, res: Srf.SrfResponse) => void): this;
|
|
176
|
+
on(event: 'register' | 'invite' | 'bye' | 'cancel' | 'ack' | 'info' | 'notify' | 'options' | 'prack' | 'publish' | 'refer' | 'subscribe' | 'update', listener: (req: Srf.SrfRequest, res: Srf.SrfResponse) => void): this;
|
|
177
|
+
on(event: 'cdr:attempt', listener: (source: string, time: string, msg: Srf.SipMessage) => void): this;
|
|
178
|
+
on(event: 'cdr:start', listener: (source: string, time: string, role: string, msg: Srf.SipMessage) => void): this;
|
|
179
|
+
on(event: 'cdr:stop', listener: (source: string, time: string, reason: string, msg: Srf.SipMessage) => void): this;
|
|
180
|
+
locals: { [name: string]: any };
|
|
181
|
+
socket: Socket;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export = Srf;
|
package/lib/digest-client.js
CHANGED
|
@@ -39,6 +39,9 @@ module.exports = class DigestClient {
|
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
const header = this.res.statusCode === 407 ? 'proxy-authenticate' : 'www-authenticate' ;
|
|
42
|
+
if (!this.res.has(header)) {
|
|
43
|
+
return callback(new Error(`missing ${header} in ${this.res.statusCode} response`));
|
|
44
|
+
}
|
|
42
45
|
const challenge = this._parseChallenge(this.res.get(header));
|
|
43
46
|
|
|
44
47
|
const ha1 = crypto.createHash('md5');
|
package/lib/srf.js
CHANGED
|
@@ -10,6 +10,7 @@ const debug = require('debug')('drachtio:srf') ;
|
|
|
10
10
|
const Socket = require('net').Socket;
|
|
11
11
|
const noop = () => {};
|
|
12
12
|
const idgen = require('short-uuid')();
|
|
13
|
+
const sdpTransform = require('sdp-transform');
|
|
13
14
|
|
|
14
15
|
class DialogState {}
|
|
15
16
|
class DialogDirection {}
|
|
@@ -560,12 +561,9 @@ class Srf extends Emitter {
|
|
|
560
561
|
res
|
|
561
562
|
});
|
|
562
563
|
}
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
bhSdp = bhSdp.replace(/(o=[a-zA-Z0-9]+\s+\d+\s+\d+\s+IN\s+IP4\s+)(\d+\.\d+\.\d+\.\d+)/,
|
|
567
|
-
(match, p1) => { return p1 + '0.0.0.0' ;}
|
|
568
|
-
) ;
|
|
564
|
+
const parsed = sdpTransform.parse(res.body);
|
|
565
|
+
parsed.direction = 'recvonly';
|
|
566
|
+
const bhSdp = sdpTransform.write(parsed);
|
|
569
567
|
ack({
|
|
570
568
|
body: bhSdp
|
|
571
569
|
}) ;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "drachtio-srf",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.2",
|
|
4
4
|
"description": "drachtio signaling resource framework",
|
|
5
5
|
"main": "lib/srf.js",
|
|
6
6
|
"types": "lib/@types/index.d.ts",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"delegates": "^0.1.0",
|
|
29
29
|
"node-noop": "^0.0.1",
|
|
30
30
|
"only": "^0.0.2",
|
|
31
|
-
"sdp-transform": "^2.
|
|
31
|
+
"sdp-transform": "^2.15.0",
|
|
32
32
|
"short-uuid": "^4.2.2",
|
|
33
33
|
"sip-methods": "^0.3.0",
|
|
34
34
|
"sip-status": "^0.1.0",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"nyc": "^15.1.0",
|
|
45
45
|
"should": "^13.2.3",
|
|
46
46
|
"sip-message-examples": "^0.0.6",
|
|
47
|
-
"tape": "^5.
|
|
47
|
+
"tape": "^5.7.3",
|
|
48
48
|
"typescript": "^4.3.2"
|
|
49
49
|
}
|
|
50
50
|
}
|
|
@@ -183,3 +183,14 @@ services:
|
|
|
183
183
|
networks:
|
|
184
184
|
testbed:
|
|
185
185
|
ipv4_address: 172.29.0.26
|
|
186
|
+
|
|
187
|
+
sipp-uas-407-no-auth-header:
|
|
188
|
+
image: drachtio/sipp:latest
|
|
189
|
+
command: sipp -sf /tmp/uas-407-no-auth-header.xml
|
|
190
|
+
container_name: sipp-uas-407-no-auth-header
|
|
191
|
+
volumes:
|
|
192
|
+
- ./scenarios:/tmp
|
|
193
|
+
tty: true
|
|
194
|
+
networks:
|
|
195
|
+
testbed:
|
|
196
|
+
ipv4_address: 172.29.0.27
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
|
2
|
+
<!DOCTYPE scenario SYSTEM "sipp.dtd">
|
|
3
|
+
|
|
4
|
+
<!-- This program is free software; you can redistribute it and/or -->
|
|
5
|
+
<!-- modify it under the terms of the GNU General Public License as -->
|
|
6
|
+
<!-- published by the Free Software Foundation; either version 2 of the -->
|
|
7
|
+
<!-- License, or (at your option) any later version. -->
|
|
8
|
+
<!-- -->
|
|
9
|
+
<!-- This program is distributed in the hope that it will be useful, -->
|
|
10
|
+
<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
|
|
11
|
+
<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
|
|
12
|
+
<!-- GNU General Public License for more details. -->
|
|
13
|
+
<!-- -->
|
|
14
|
+
<!-- You should have received a copy of the GNU General Public License -->
|
|
15
|
+
<!-- along with this program; if not, write to the -->
|
|
16
|
+
<!-- Free Software Foundation, Inc., -->
|
|
17
|
+
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
|
|
18
|
+
<!-- -->
|
|
19
|
+
<!-- Sipp default 'uas' scenario. -->
|
|
20
|
+
<!-- -->
|
|
21
|
+
|
|
22
|
+
<scenario name="Basic UAS responder">
|
|
23
|
+
<!-- By adding rrs="true" (Record Route Sets), the route sets -->
|
|
24
|
+
<!-- are saved and used for following messages sent. Useful to test -->
|
|
25
|
+
<!-- against stateful SIP proxies/B2BUAs. -->
|
|
26
|
+
<recv request="INVITE" crlf="true">
|
|
27
|
+
</recv>
|
|
28
|
+
|
|
29
|
+
<send>
|
|
30
|
+
<![CDATA[
|
|
31
|
+
|
|
32
|
+
SIP/2.0 100 Trying
|
|
33
|
+
[last_Via:]
|
|
34
|
+
[last_From:]
|
|
35
|
+
[last_To:]
|
|
36
|
+
[last_Call-ID:]
|
|
37
|
+
[last_CSeq:]
|
|
38
|
+
Content-Length: 0
|
|
39
|
+
|
|
40
|
+
]]>
|
|
41
|
+
</send>
|
|
42
|
+
|
|
43
|
+
<send retrans="500">
|
|
44
|
+
<![CDATA[
|
|
45
|
+
|
|
46
|
+
SIP/2.0 407 Proxy Authentication Required
|
|
47
|
+
[last_Via:]
|
|
48
|
+
[last_From:]
|
|
49
|
+
[last_To:];tag=[pid]SIPpTag01[call_number]
|
|
50
|
+
[last_Call-ID:]
|
|
51
|
+
[last_CSeq:]
|
|
52
|
+
Content-Length: 0
|
|
53
|
+
|
|
54
|
+
]]>
|
|
55
|
+
</send>
|
|
56
|
+
|
|
57
|
+
<recv request="ACK"
|
|
58
|
+
rtd="true"
|
|
59
|
+
crlf="true">
|
|
60
|
+
</recv>
|
|
61
|
+
|
|
62
|
+
<recv request="INVITE" crlf="true">
|
|
63
|
+
<action>
|
|
64
|
+
<ereg regexp=".*" search_in="hdr" header="Proxy-Authorization:" assign_to="1" />
|
|
65
|
+
</action>
|
|
66
|
+
</recv>
|
|
67
|
+
|
|
68
|
+
<send>
|
|
69
|
+
<![CDATA[
|
|
70
|
+
|
|
71
|
+
SIP/2.0 180 Ringing
|
|
72
|
+
[last_Via:]
|
|
73
|
+
[last_From:]
|
|
74
|
+
[last_To:];tag=[pid]SIPpTag01[call_number]
|
|
75
|
+
[last_Call-ID:]
|
|
76
|
+
[last_CSeq:]
|
|
77
|
+
Subject:[$1]
|
|
78
|
+
Content-Length: 0
|
|
79
|
+
|
|
80
|
+
]]>
|
|
81
|
+
</send>
|
|
82
|
+
|
|
83
|
+
<send retrans="500">
|
|
84
|
+
<![CDATA[
|
|
85
|
+
|
|
86
|
+
SIP/2.0 200 OK
|
|
87
|
+
[last_Via:]
|
|
88
|
+
[last_From:]
|
|
89
|
+
[last_To:];tag=[pid]SIPpTag01[call_number]
|
|
90
|
+
[last_Call-ID:]
|
|
91
|
+
[last_CSeq:]
|
|
92
|
+
Contact: <sip:[local_ip]:[local_port];transport=[transport]>
|
|
93
|
+
Content-Type: application/sdp
|
|
94
|
+
Content-Length: [len]
|
|
95
|
+
|
|
96
|
+
v=0
|
|
97
|
+
o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
|
|
98
|
+
s=-
|
|
99
|
+
c=IN IP[media_ip_type] [media_ip]
|
|
100
|
+
t=0 0
|
|
101
|
+
m=audio [media_port] RTP/AVP 0
|
|
102
|
+
a=rtpmap:0 PCMU/8000
|
|
103
|
+
|
|
104
|
+
]]>
|
|
105
|
+
</send>
|
|
106
|
+
|
|
107
|
+
<recv request="ACK"
|
|
108
|
+
optional="true"
|
|
109
|
+
rtd="true"
|
|
110
|
+
crlf="true">
|
|
111
|
+
</recv>
|
|
112
|
+
<recv request="BYE">
|
|
113
|
+
</recv>
|
|
114
|
+
|
|
115
|
+
<send>
|
|
116
|
+
<![CDATA[
|
|
117
|
+
|
|
118
|
+
SIP/2.0 200 OK
|
|
119
|
+
[last_Via:]
|
|
120
|
+
[last_From:]
|
|
121
|
+
[last_To:]
|
|
122
|
+
[last_Call-ID:]
|
|
123
|
+
[last_CSeq:]
|
|
124
|
+
Contact: <sip:[local_ip]:[local_port];transport=[transport]>
|
|
125
|
+
Content-Length: 0
|
|
126
|
+
|
|
127
|
+
]]>
|
|
128
|
+
</send>
|
|
129
|
+
|
|
130
|
+
<!-- Keep the call open for a while in case the 200 is lost to be -->
|
|
131
|
+
<!-- able to retransmit it if we receive the BYE again. -->
|
|
132
|
+
<timewait milliseconds="4000"/>
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
<!-- definition of the response time repartition table (unit is ms) -->
|
|
136
|
+
<ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
|
|
137
|
+
|
|
138
|
+
<!-- definition of the call length repartition table (unit is ms) -->
|
|
139
|
+
<CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
|
|
140
|
+
|
|
141
|
+
</scenario>
|
|
142
|
+
|
package/test/uac.js
CHANGED
|
@@ -220,6 +220,32 @@ test('UAC', (t) => {
|
|
|
220
220
|
return t.pass('Srf#createUAC can handle digest authentication, sending to same server');
|
|
221
221
|
})
|
|
222
222
|
|
|
223
|
+
.then(() => {
|
|
224
|
+
srf = new Srf();
|
|
225
|
+
return connect(srf);
|
|
226
|
+
})
|
|
227
|
+
.then(() => {
|
|
228
|
+
return srf.createUAC('sip:sipp-uas-407-no-auth-header', {
|
|
229
|
+
method: 'INVITE',
|
|
230
|
+
headers: {
|
|
231
|
+
To: 'sip:dhorton@sip.drachtio.org',
|
|
232
|
+
From: 'sip:dhorton@sip.drachtio.org'
|
|
233
|
+
},
|
|
234
|
+
auth: {
|
|
235
|
+
username: 'foo',
|
|
236
|
+
password: 'bar'
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
})
|
|
240
|
+
.then((uac, err) => {
|
|
241
|
+
srf.disconnect();
|
|
242
|
+
return t.fail('Srf#createUAC should not handle digest without authentication');
|
|
243
|
+
})
|
|
244
|
+
.catch((err) => {
|
|
245
|
+
srf.disconnect();
|
|
246
|
+
return t.pass('Srf#createUAC cannot handle digest without authentication');
|
|
247
|
+
})
|
|
248
|
+
|
|
223
249
|
.then(() => {
|
|
224
250
|
srf = new Srf();
|
|
225
251
|
return connect(srf);
|