New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

ringcentral-softphone

Package Overview
Dependencies
Maintainers
1
Versions
64
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ringcentral-softphone - npm Package Compare versions

Comparing version 0.2.0 to 0.3.0

demos/browser/index.html

169

dist/index.js

@@ -20,10 +20,12 @@ "use strict";

var _RequestSipMessage = _interopRequireDefault(require("./SipMessage/outbound/RequestSipMessage"));
var _requestSipMessage = _interopRequireDefault(require("./sip-message/outbound/request-sip-message"));
var _InboundSipMessage = _interopRequireDefault(require("./SipMessage/inbound/InboundSipMessage"));
var _inboundSipMessage = _interopRequireDefault(require("./sip-message/inbound/inbound-sip-message"));
var _ResponseSipMessage = _interopRequireDefault(require("./SipMessage/outbound/ResponseSipMessage"));
var _responseSipMessage = _interopRequireDefault(require("./sip-message/outbound/response-sip-message"));
var _utils = require("./utils");
var _rcMessage = _interopRequireDefault(require("./rc-message/rc-message"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -37,27 +39,50 @@

this.fakeEmail = (0, _v.default)() + '@' + this.fakeDomain;
this.branch = () => 'z9hG4bK' + (0, _v.default)();
this.fromTag = (0, _v.default)();
this.callerId = (0, _v.default)();
this.callId = (0, _v.default)();
}
newCallId() {
this.callId = (0, _v.default)();
}
async handleSipMessage(inboundSipMessage) {
if (inboundSipMessage.subject.startsWith('INVITE sip:')) {
// invite
await this.send(new _ResponseSipMessage.default(inboundSipMessage, 100, 'Trying'));
await this.send(new _ResponseSipMessage.default(inboundSipMessage, 180, 'Ringing', {
await this.response(inboundSipMessage, 180, {
Contact: `<sip:${this.fakeDomain};transport=ws>`
}));
this.inviteSipMessage = inboundSipMessage;
this.emit('INVITE', this.inviteSipMessage);
});
await this.sendRcMessage(inboundSipMessage, 17);
this.emit('INVITE', inboundSipMessage);
} else if (inboundSipMessage.subject.startsWith('BYE ')) {
// bye
await this.response(inboundSipMessage, 200);
this.emit('BYE', inboundSipMessage);
} else if (inboundSipMessage.subject.startsWith('MESSAGE ') && inboundSipMessage.body.includes(' Cmd="7"')) {
// take over
await this.send(new _ResponseSipMessage.default(inboundSipMessage, 200, 'OK'));
// server side: already processed
await this.response(inboundSipMessage, 200);
}
}
async sendRcMessage(inboundSipMessage, reqid) {
const rcMessage = _rcMessage.default.fromXml(inboundSipMessage.headers['P-rc']);
const newRcMessage = new _rcMessage.default({
SID: rcMessage.Hdr.SID,
Req: rcMessage.Hdr.Req,
From: rcMessage.Hdr.To,
To: rcMessage.Hdr.From,
Cmd: reqid
}, {
Cln: this.sipInfo.authorizationId
});
const requestSipMessage = new _requestSipMessage.default(`MESSAGE sip:${newRcMessage.Hdr.To} SIP/2.0`, {
Via: `SIP/2.0/WSS ${this.fakeDomain};branch=${(0, _utils.branch)()}`,
To: `<sip:${newRcMessage.Hdr.To}>`,
From: `<sip:${this.sipInfo.username}@${this.sipInfo.domain}>;tag=${this.fromTag}`,
'Call-ID': this.callId,
'Content-Type': 'x-rc/agent'
}, newRcMessage.toXml());
await this.send(requestSipMessage);
}
async send(sipMessage) {

@@ -77,3 +102,3 @@ return new Promise((resolve, reject) => {

if (inboundSipMessage.subject === 'SIP/2.0 100 Trying') {
if (inboundSipMessage.subject === 'SIP/2.0 100 Trying' || inboundSipMessage.subject === 'SIP/2.0 183 Session Progress') {
return; // ignore

@@ -84,3 +109,3 @@ }

if (inboundSipMessage.subject.startsWith('SIP/2.0 603 ')) {
if (inboundSipMessage.subject.startsWith('SIP/2.0 5') || inboundSipMessage.subject.startsWith('SIP/2.0 6') || inboundSipMessage.subject.startsWith('SIP/2.0 403')) {
reject(inboundSipMessage);

@@ -98,2 +123,6 @@ return;

async response(inboundSipMessage, responseCode, headers = {}, body = '') {
await this.send(new _responseSipMessage.default(inboundSipMessage, responseCode, headers, body));
}
async register() {

@@ -130,3 +159,3 @@ const r = await this.rc.post('/restapi/v1.0/client-info/sip-provision', {

this.ws.addEventListener('message', e => {
const sipMessage = _InboundSipMessage.default.fromString(e.data);
const sipMessage = _inboundSipMessage.default.fromString(e.data);

@@ -139,8 +168,10 @@ this.emit('sipMessage', sipMessage);

this.ws.removeEventListener('open', openHandler);
const requestSipMessage = new _RequestSipMessage.default(`REGISTER sip:${this.sipInfo.domain} SIP/2.0`, {
'Call-ID': this.callerId,
const requestSipMessage = new _requestSipMessage.default(`REGISTER sip:${this.sipInfo.domain} SIP/2.0`, {
'Call-ID': this.callId,
Contact: `<sip:${this.fakeEmail};transport=ws>;expires=600`,
From: `<sip:${this.sipInfo.username}@${this.sipInfo.domain}>;tag=${this.fromTag}`,
To: `<sip:${this.sipInfo.username}@${this.sipInfo.domain}>`,
Via: `SIP/2.0/WSS ${this.fakeDomain};branch=${this.branch()}`
Via: `SIP/2.0/WSS ${this.fakeDomain};branch=${(0, _utils.branch)()}`,
Allow: 'ACK,CANCEL,INVITE,MESSAGE,BYE,OPTIONS,INFO,NOTIFY,REFER',
Supported: 'path, gruu, outbound'
});

@@ -153,4 +184,9 @@ let inboundSipMessage = await this.send(requestSipMessage);

const nonce = wwwAuth.match(/, nonce="(.+?)"/)[1];
requestSipMessage.headers.Authorization = (0, _utils.generateAuthorization)(this.sipInfo, 'REGISTER', nonce);
inboundSipMessage = await this.send(requestSipMessage);
const newRequestSipMessage = requestSipMessage.fork();
newRequestSipMessage.headers.Authorization = (0, _utils.generateAuthorization)(this.sipInfo, 'REGISTER', nonce);
inboundSipMessage = await this.send(newRequestSipMessage);
if (inboundSipMessage.subject === 'SIP/2.0 200 OK') {
this.emit('registered');
}
}

@@ -162,4 +198,4 @@ };

async answer(inputAudioStream = undefined) {
const sdp = this.inviteSipMessage.body;
async answer(inviteSipMessage, inputAudioStream = undefined) {
const sdp = inviteSipMessage.body;
const remoteRtcSd = new _isomorphicWebrtc.RTCSessionDescription({

@@ -186,10 +222,89 @@ type: 'offer',

peerConnection.setLocalDescription(localRtcSd);
await this.send(new _ResponseSipMessage.default(this.inviteSipMessage, 200, 'OK', {
await this.response(inviteSipMessage, 200, {
Contact: `<sip:${this.fakeEmail};transport=ws>`,
'Content-Type': 'application/sdp'
}, localRtcSd.sdp));
}, localRtcSd.sdp);
}
async reject() {}
async toVoicemail(inviteSipMessage) {
await this.sendRcMessage(inviteSipMessage, 11);
}
async ignore(inviteSipMessage) {
await this.response(inviteSipMessage, 480);
}
async invite(callee, inputAudioStream = undefined) {
this.newCallId();
const peerConnection = new _isomorphicWebrtc.RTCPeerConnection({
iceServers: [{
urls: 'stun:74.125.194.127:19302'
}]
});
/* this is for debugging - start */
// const eventNames = [
// 'addstream', 'connectionstatechange', 'datachannel', 'icecandidate',
// 'iceconnectionstatechange', 'icegatheringstatechange', 'identityresult',
// 'negotiationneeded', 'removestream', 'signalingstatechange', 'track'
// ]
// for (const eventName of eventNames) {
// peerConnection.addEventListener(eventName, e => {
// console.log(`\n****** RTCPeerConnection ${eventName} event - start *****`)
// console.log(e)
// console.log(`****** RTCPeerConnection ${eventName} event - end *****\n`)
// })
// }
/* this is for debugging - end */
if (inputAudioStream) {
const track = inputAudioStream.getAudioTracks()[0];
peerConnection.addTrack(track, inputAudioStream);
}
const localRtcSd = await peerConnection.createOffer();
peerConnection.setLocalDescription(localRtcSd);
const requestSipMessage = new _requestSipMessage.default(`INVITE sip:${callee}@${this.sipInfo.domain} SIP/2.0`, {
Via: `SIP/2.0/WSS ${this.fakeDomain};branch=${(0, _utils.branch)()}`,
To: `<sip:${callee}@${this.sipInfo.domain}>`,
From: `<sip:${this.sipInfo.username}@${this.sipInfo.domain}>;tag=${this.fromTag}`,
'Call-ID': this.callId,
Contact: `<sip:${this.fakeEmail};transport=ws;ob>`,
'Content-Type': 'application/sdp',
// 'P-rc-country-id': 1,
// 'P-rc-endpoint-id': uuid(),
// 'Client-id': process.env.RINGCENTRAL_CLIENT_ID,
// 'P-Asserted-Identity': 'sip:+16504223279@sip.ringcentral.com',
Allow: 'ACK,CANCEL,INVITE,MESSAGE,BYE,OPTIONS,INFO,NOTIFY,REFER',
Supported: 'outbound'
}, localRtcSd.sdp);
let inboundSipMessage = await this.send(requestSipMessage);
const wwwAuth = inboundSipMessage.headers['Proxy-Authenticate'];
if (wwwAuth && wwwAuth.includes(', nonce="')) {
// authorization required
const ackMessage = new _requestSipMessage.default(`ACK ${inboundSipMessage.headers.Contact.match(/<(.+?)>/)[1]} SIP/2.0`, {
Via: `SIP/2.0/WSS ${this.fakeDomain};branch=${(0, _utils.branch)()}`,
To: inboundSipMessage.headers.To,
From: inboundSipMessage.headers.From,
'Call-ID': this.callId,
Supported: 'outbound'
});
ackMessage.reuseCseq();
this.send(ackMessage);
const nonce = wwwAuth.match(/, nonce="(.+?)"/)[1];
const newRequestSipMessage = requestSipMessage.fork();
newRequestSipMessage.headers['Proxy-Authorization'] = (0, _utils.generateProxyAuthorization)(this.sipInfo, 'INVITE', callee, nonce);
inboundSipMessage = await this.send(newRequestSipMessage);
const remoteRtcSd = new _isomorphicWebrtc.RTCSessionDescription({
type: 'answer',
sdp: inboundSipMessage.body
});
peerConnection.addEventListener('track', e => {
this.emit('track', e);
});
peerConnection.setRemoteDescription(remoteRtcSd);
}
}
}

@@ -196,0 +311,0 @@

@@ -6,6 +6,8 @@ "use strict";

});
exports.generateProxyAuthorization = exports.generateAuthorization = void 0;
exports.branch = exports.generateProxyAuthorization = exports.generateAuthorization = void 0;
var _blueimpMd = _interopRequireDefault(require("blueimp-md5"));
var _v = _interopRequireDefault(require("uuid/v4"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -54,2 +56,6 @@

exports.generateProxyAuthorization = generateProxyAuthorization;
const branch = () => 'z9hG4bK' + (0, _v.default)();
exports.branch = branch;
//# sourceMappingURL=utils.js.map

20

package.json
{
"name": "ringcentral-softphone",
"version": "0.2.0",
"version": "0.3.0",
"license": "MIT",
"main": "dist/index.js",
"scripts": {
"server": "node -r dotenv-override-true/config -r @babel/register demos/node.js",
"server": "node -r dotenv-override-true/config -r @babel/register demos/node/answer-and-talk.js",
"browser": "webpack-dev-server --progress --colors --open",
"test": "standard && jest",
"release": "babel src --out-dir dist --source-maps",
"prepush": "yarn test",
"prepublishOnly": "yarn release"

@@ -22,6 +21,6 @@ },

"devDependencies": {
"@babel/cli": "^7.6.0",
"@babel/core": "^7.6.0",
"@babel/preset-env": "^7.6.0",
"@babel/register": "^7.6.0",
"@babel/cli": "^7.6.2",
"@babel/core": "^7.6.2",
"@babel/preset-env": "^7.6.2",
"@babel/register": "^7.6.2",
"@ringcentral/sdk": "^4.0.0-alpha.7",

@@ -37,3 +36,3 @@ "core-js": "^3.2.1",

"standard": "^14.3.1",
"webpack": "^4.40.2",
"webpack": "^4.41.0",
"webpack-cli": "^3.3.9",

@@ -47,3 +46,8 @@ "webpack-dev-server": "^3.8.1",

"@ringcentral/sdk": "^4.0.0-alpha.7"
},
"husky": {
"hooks": {
"pre-push": "yarn test"
}
}
}

@@ -7,5 +7,27 @@ # RingCentral Softphone SDK for JavaScript

This project was originally designed for server and desktop. It works both with and without browsers.
This project was originally designed for server and desktop. It doesn't require a browser to run. It could run in browser too.
## Supported features:
- Answer inbound call
- Make outbound call
- Speak and listen, two way communication
- Call control features
- Redirect inbound call to voicemail
- Ignore inbound call
## Demos
- [browser demo](./demos/browser)
- node.js
- [answer inbound call](./demos/node/answer-and-talk.js)
- [make outbound call](./demos/node/outbound-call.js)
- [redirect inbound call to voicemail](./demos/node/to-voicemail.js)
- [ignore inbound call](./demos/node/ignore.js)
- [call supervise](https://github.com/tylerlong/ringcentral-call-supervise-demo)
- supervise an existing phone call and get real time audio stream
## Install

@@ -23,12 +45,10 @@

because node.js by default doesn't support WebSocket & WebRTC.
## Usage
- for node.js, check [this demo](./demos/node.js)
- for browser, check [this demo](./demos/browser.js)
- for node.js, check [here](./demos/node)
- for browser, check [here](./demos/browser)
## Demos
## Official demos

@@ -44,3 +64,5 @@ ### Setup

- `CALLEE_FOR_TESTING` is a phone number to receive testing phone calls. You don't need to specify it if you do not make outbound calls.
### Run

@@ -54,8 +76,5 @@

Make a phone call to the phone number you configured in `.env` file.
Make a phone call to the phone number you configured in `.env` file. The demo app will answer the call and you can speak and listen.
- for node.js, the app will auto pick up the call and redirect your voice to speaker.
- for browser, the app will auto pick up the call and redirect your voice to an `<audio/>` HTML5 element.
## Interesting Usage cases

@@ -81,4 +100,11 @@

## Play recorded audio
You can create a program to make a phone cal or answer a phone call and play recorded audio. This is good for announcement purpose. This is also good for quick voicemail drop.
## Todo
- make outbound call
- stay alive
- How to create a publish message
- How to forward a call

@@ -6,6 +6,7 @@ import uuid from 'uuid/v4'

import RequestSipMessage from './SipMessage/outbound/RequestSipMessage'
import InboundSipMessage from './SipMessage/inbound/InboundSipMessage'
import ResponseSipMessage from './SipMessage/outbound/ResponseSipMessage'
import { generateAuthorization } from './utils'
import RequestSipMessage from './sip-message/outbound/request-sip-message'
import InboundSipMessage from './sip-message/inbound/inbound-sip-message'
import ResponseSipMessage from './sip-message/outbound/response-sip-message'
import { generateAuthorization, generateProxyAuthorization, branch } from './utils'
import RcMessage from './rc-message/rc-message'

@@ -18,22 +19,49 @@ class Softphone extends EventEmitter {

this.fakeEmail = uuid() + '@' + this.fakeDomain
this.branch = () => 'z9hG4bK' + uuid()
this.fromTag = uuid()
this.callerId = uuid()
this.callId = uuid()
}
newCallId () {
this.callId = uuid()
}
async handleSipMessage (inboundSipMessage) {
if (inboundSipMessage.subject.startsWith('INVITE sip:')) { // invite
await this.send(new ResponseSipMessage(inboundSipMessage, 100, 'Trying'))
await this.send(new ResponseSipMessage(inboundSipMessage, 180, 'Ringing', {
await this.response(inboundSipMessage, 180, {
Contact: `<sip:${this.fakeDomain};transport=ws>`
}))
this.inviteSipMessage = inboundSipMessage
this.emit('INVITE', this.inviteSipMessage)
})
await this.sendRcMessage(inboundSipMessage, 17)
this.emit('INVITE', inboundSipMessage)
} else if (inboundSipMessage.subject.startsWith('BYE ')) { // bye
await this.response(inboundSipMessage, 200)
this.emit('BYE', inboundSipMessage)
} else if (inboundSipMessage.subject.startsWith('MESSAGE ') && inboundSipMessage.body.includes(' Cmd="7"')) { // take over
await this.send(new ResponseSipMessage(inboundSipMessage, 200, 'OK'))
} else if (inboundSipMessage.subject.startsWith('MESSAGE ') && inboundSipMessage.body.includes(' Cmd="7"')) { // server side: already processed
await this.response(inboundSipMessage, 200)
}
}
async sendRcMessage (inboundSipMessage, reqid) {
const rcMessage = RcMessage.fromXml(inboundSipMessage.headers['P-rc'])
const newRcMessage = new RcMessage(
{
SID: rcMessage.Hdr.SID,
Req: rcMessage.Hdr.Req,
From: rcMessage.Hdr.To,
To: rcMessage.Hdr.From,
Cmd: reqid
},
{
Cln: this.sipInfo.authorizationId
}
)
const requestSipMessage = new RequestSipMessage(`MESSAGE sip:${newRcMessage.Hdr.To} SIP/2.0`, {
Via: `SIP/2.0/WSS ${this.fakeDomain};branch=${branch()}`,
To: `<sip:${newRcMessage.Hdr.To}>`,
From: `<sip:${this.sipInfo.username}@${this.sipInfo.domain}>;tag=${this.fromTag}`,
'Call-ID': this.callId,
'Content-Type': 'x-rc/agent'
}, newRcMessage.toXml())
await this.send(requestSipMessage)
}
async send (sipMessage) {

@@ -50,7 +78,10 @@ return new Promise((resolve, reject) => {

}
if (inboundSipMessage.subject === 'SIP/2.0 100 Trying') {
if (inboundSipMessage.subject === 'SIP/2.0 100 Trying' || inboundSipMessage.subject === 'SIP/2.0 183 Session Progress') {
return // ignore
}
this.off('sipMessage', responseHandler)
if (inboundSipMessage.subject.startsWith('SIP/2.0 603 ')) {
if (inboundSipMessage.subject.startsWith('SIP/2.0 5') ||
inboundSipMessage.subject.startsWith('SIP/2.0 6') ||
inboundSipMessage.subject.startsWith('SIP/2.0 403')
) {
reject(inboundSipMessage)

@@ -66,2 +97,6 @@ return

async response (inboundSipMessage, responseCode, headers = {}, body = '') {
await this.send(new ResponseSipMessage(inboundSipMessage, responseCode, headers, body))
}
async register () {

@@ -97,7 +132,9 @@ const r = await this.rc.post('/restapi/v1.0/client-info/sip-provision', {

const requestSipMessage = new RequestSipMessage(`REGISTER sip:${this.sipInfo.domain} SIP/2.0`, {
'Call-ID': this.callerId,
'Call-ID': this.callId,
Contact: `<sip:${this.fakeEmail};transport=ws>;expires=600`,
From: `<sip:${this.sipInfo.username}@${this.sipInfo.domain}>;tag=${this.fromTag}`,
To: `<sip:${this.sipInfo.username}@${this.sipInfo.domain}>`,
Via: `SIP/2.0/WSS ${this.fakeDomain};branch=${this.branch()}`
Via: `SIP/2.0/WSS ${this.fakeDomain};branch=${branch()}`,
Allow: 'ACK,CANCEL,INVITE,MESSAGE,BYE,OPTIONS,INFO,NOTIFY,REFER',
Supported: 'path, gruu, outbound'
})

@@ -108,4 +145,8 @@ let inboundSipMessage = await this.send(requestSipMessage)

const nonce = wwwAuth.match(/, nonce="(.+?)"/)[1]
requestSipMessage.headers.Authorization = generateAuthorization(this.sipInfo, 'REGISTER', nonce)
inboundSipMessage = await this.send(requestSipMessage)
const newRequestSipMessage = requestSipMessage.fork()
newRequestSipMessage.headers.Authorization = generateAuthorization(this.sipInfo, 'REGISTER', nonce)
inboundSipMessage = await this.send(newRequestSipMessage)
if (inboundSipMessage.subject === 'SIP/2.0 200 OK') {
this.emit('registered')
}
}

@@ -116,4 +157,4 @@ }

async answer (inputAudioStream = undefined) {
const sdp = this.inviteSipMessage.body
async answer (inviteSipMessage, inputAudioStream = undefined) {
const sdp = inviteSipMessage.body
const remoteRtcSd = new RTCSessionDescription({ type: 'offer', sdp })

@@ -131,13 +172,80 @@ const peerConnection = new RTCPeerConnection({ iceServers: [{ urls: 'stun:74.125.194.127:19302' }] })

peerConnection.setLocalDescription(localRtcSd)
await this.send(new ResponseSipMessage(this.inviteSipMessage, 200, 'OK', {
await this.response(inviteSipMessage, 200, {
Contact: `<sip:${this.fakeEmail};transport=ws>`,
'Content-Type': 'application/sdp'
}, localRtcSd.sdp))
}, localRtcSd.sdp)
}
async reject () {
async toVoicemail (inviteSipMessage) {
await this.sendRcMessage(inviteSipMessage, 11)
}
async ignore (inviteSipMessage) {
await this.response(inviteSipMessage, 480)
}
async invite (callee, inputAudioStream = undefined) {
this.newCallId()
const peerConnection = new RTCPeerConnection({
iceServers: [{ urls: 'stun:74.125.194.127:19302' }]
})
/* this is for debugging - start */
// const eventNames = [
// 'addstream', 'connectionstatechange', 'datachannel', 'icecandidate',
// 'iceconnectionstatechange', 'icegatheringstatechange', 'identityresult',
// 'negotiationneeded', 'removestream', 'signalingstatechange', 'track'
// ]
// for (const eventName of eventNames) {
// peerConnection.addEventListener(eventName, e => {
// console.log(`\n****** RTCPeerConnection ${eventName} event - start *****`)
// console.log(e)
// console.log(`****** RTCPeerConnection ${eventName} event - end *****\n`)
// })
// }
/* this is for debugging - end */
if (inputAudioStream) {
const track = inputAudioStream.getAudioTracks()[0]
peerConnection.addTrack(track, inputAudioStream)
}
const localRtcSd = await peerConnection.createOffer()
peerConnection.setLocalDescription(localRtcSd)
const requestSipMessage = new RequestSipMessage(`INVITE sip:${callee}@${this.sipInfo.domain} SIP/2.0`, {
Via: `SIP/2.0/WSS ${this.fakeDomain};branch=${branch()}`,
To: `<sip:${callee}@${this.sipInfo.domain}>`,
From: `<sip:${this.sipInfo.username}@${this.sipInfo.domain}>;tag=${this.fromTag}`,
'Call-ID': this.callId,
Contact: `<sip:${this.fakeEmail};transport=ws;ob>`,
'Content-Type': 'application/sdp',
// 'P-rc-country-id': 1,
// 'P-rc-endpoint-id': uuid(),
// 'Client-id': process.env.RINGCENTRAL_CLIENT_ID,
// 'P-Asserted-Identity': 'sip:+16504223279@sip.ringcentral.com',
Allow: 'ACK,CANCEL,INVITE,MESSAGE,BYE,OPTIONS,INFO,NOTIFY,REFER',
Supported: 'outbound'
}, localRtcSd.sdp)
let inboundSipMessage = await this.send(requestSipMessage)
const wwwAuth = inboundSipMessage.headers['Proxy-Authenticate']
if (wwwAuth && wwwAuth.includes(', nonce="')) { // authorization required
const ackMessage = new RequestSipMessage(`ACK ${inboundSipMessage.headers.Contact.match(/<(.+?)>/)[1]} SIP/2.0`, {
Via: `SIP/2.0/WSS ${this.fakeDomain};branch=${branch()}`,
To: inboundSipMessage.headers.To,
From: inboundSipMessage.headers.From,
'Call-ID': this.callId,
Supported: 'outbound'
})
ackMessage.reuseCseq()
this.send(ackMessage)
const nonce = wwwAuth.match(/, nonce="(.+?)"/)[1]
const newRequestSipMessage = requestSipMessage.fork()
newRequestSipMessage.headers['Proxy-Authorization'] = generateProxyAuthorization(this.sipInfo, 'INVITE', callee, nonce)
inboundSipMessage = await this.send(newRequestSipMessage)
const remoteRtcSd = new RTCSessionDescription({ type: 'answer', sdp: inboundSipMessage.body })
peerConnection.addEventListener('track', e => {
this.emit('track', e)
})
peerConnection.setRemoteDescription(remoteRtcSd)
}
}
}
export default Softphone
import md5 from 'blueimp-md5'
import uuid from 'uuid/v4'

@@ -30,1 +31,3 @@ const generateResponse = (username, password, realm, method, uri, nonce) => {

}
export const branch = () => 'z9hG4bK' + uuid()

@@ -7,7 +7,7 @@ import HtmlWebpackPlugin from 'html-webpack-plugin'

entry: {
index: './demos/browser.js'
index: './demos/browser/index.js'
},
plugins: [
new HtmlWebpackPlugin({
template: 'demos/index.html'
template: 'demos/browser/index.html'
}),

@@ -14,0 +14,0 @@ new HotModuleReplacementPlugin(),

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc