diff --git a/package.json b/package.json index f772f89..cfdd949 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,6 @@ "type": "module", "scripts": { "build": "aegir build", - "clean": "rm -rfv node_modules dist *.lock *-lock.json ", "test": "aegir test", "format": "prettier --write src/*.ts" }, @@ -27,6 +26,7 @@ "@libp2p/interfaces": "^3.0.3", "@libp2p/logger": "^2.0.0", "@libp2p/peer-id": "^1.1.15", + "@multiformats/multiaddr": "../js-multiaddr/", "abortable-iterator": "^4.0.2", "it-merge": "^1.0.4", "p-defer": "^4.0.0", diff --git a/src/error.ts b/src/error.ts new file mode 100644 index 0000000..c973d34 --- /dev/null +++ b/src/error.ts @@ -0,0 +1,13 @@ +export class WebRTCTransportError extends Error { + constructor(msg: string) { + super(msg); + this.name = 'WebRTCTransportError'; + } +} + +export class InvalidArgumentError extends WebRTCTransportError { + constructor(msg: string) { + super(msg); + this.name = 'WebRTC/InvalidArgumentError'; + } +} \ No newline at end of file diff --git a/src/sdp.ts b/src/sdp.ts index b8c3189..65f131d 100644 --- a/src/sdp.ts +++ b/src/sdp.ts @@ -1,9 +1,10 @@ +import { InvalidArgumentError } from './error.js' import { logger } from '@libp2p/logger'; import { Multiaddr } from '@multiformats/multiaddr'; const log = logger('libp2p:webrtc:sdp'); -const P_XWEBRTC: number = 0x115; +const CERTHASH_CODE: number = 466; const ANSWER_SDP_FORMAT: string = ` v=0 o=- 0 0 IN %s %s @@ -37,38 +38,44 @@ function port(ma: Multiaddr): number { return ma.toOptions().port; } function certhash(ma: Multiaddr): string { - let webrtc_value = ma - .stringTuples() - .filter((tup) => tup[0] == P_XWEBRTC) + let tups = ma.stringTuples(); + let certhash_value = tups + .filter((tup) => tup[0] == CERTHASH_CODE) .map((tup) => tup[1])[0]; - if (webrtc_value) { - return webrtc_value.split('/')[1]; + if (certhash_value) { + return certhash_value; } else { - throw new Error("Couldn't find a webrtc component of multiaddr:" + ma.toString()); + throw new Error("Couldn't find a certhash component of multiaddr:" + ma.toString()); } } function ma2sdp(ma: Multiaddr, ufrag: string): string { - return ANSWER_SDP_FORMAT.replace('/%s/', ipv(ma)) - .replace('/%s/', ip(ma)) - .replace('/%s/', ipv(ma)) - .replace('/%s/', ip(ma)) - .replace('/%s/', port(ma).toString()) - .replace('/%s/', ufrag) - .replace('/%s/', ufrag) - .replace('/%s/', certhash(ma)); + return ANSWER_SDP_FORMAT + .replace('%s', ipv(ma)) + .replace('%s', ip(ma)) + .replace('%s', ipv(ma)) + .replace('%s', ip(ma)) + .replace('%d', port(ma).toString()) + .replace('%s', ufrag) + .replace('%s', ufrag) + .replace('%s', certhash(ma)); } export function fromMultiAddr(ma: Multiaddr, ufrag: string): RTCSessionDescriptionInit { return { - type: 'offer', + type: 'answer', sdp: ma2sdp(ma, ufrag), }; } export function munge(desc: RTCSessionDescriptionInit, ufrag: string): RTCSessionDescriptionInit { - //TODO - // desc.sdp.replaceAll(/^a=ice-ufrag=(.*)/, 'a=ice-ufrag=' + ufrag); - // desc.sdp.replaceAll(/^a=ice-pwd=(.*)/, 'a=ice-pwd=' + ufrag); - return desc; + if (desc.sdp) { + desc.sdp = desc.sdp + .replace(/\na=ice-ufrag:[^\n]*\n/, '\na=ice-ufrag:' + ufrag + '\n') + .replace(/\na=ice-pwd:[^\n]*\n/, '\na=ice-pwd:' + ufrag + '\n') + ; + return desc; + } else { + throw new InvalidArgumentError("Can't munge a missing SDP"); + } } diff --git a/test/node.js b/test/node.js deleted file mode 100644 index 5c78a05..0000000 --- a/test/node.js +++ /dev/null @@ -1,6 +0,0 @@ -/* eslint-env mocha */ - -export {} - -describe('noop', () => { -}) diff --git a/test/sdp.spec.ts b/test/sdp.spec.ts new file mode 100644 index 0000000..f576a9e --- /dev/null +++ b/test/sdp.spec.ts @@ -0,0 +1,51 @@ +import { Multiaddr } from '@multiformats/multiaddr'; +import { expect } from 'chai'; +import * as underTest from '../src/sdp.js'; + +const an_sdp = ` +v=0 +o=- 0 0 IN IP4 192.168.0.152 +s=- +c=IN IP4 192.168.0.152 +t=0 0 +m=application 2345 UDP/DTLS/SCTP webrtc-datachannel +a=mid:0 +a=ice-options:ice2 +a=ice-ufrag:MyUserFragment +a=ice-pwd:MyUserFragment +a=fingerprint:mTXVsdGliYXNlIGlzIGF3ZXNvbWUhIFxvLw +a=setup:actpass +a=sctp-port:5000 +a=max-message-size:100000 +`; + +describe('SDP creation', () => { + it('handles simple blue sky easily enough', async () => { + let ma = new Multiaddr('/ip4/192.168.0.152/udp/2345/webrtc/certhash/zYAjKoNbau5KiqmHPmSxYCvn66dA1vLmwbt'); + let ufrag = 'MyUserFragment'; + let sdp = underTest.fromMultiAddr(ma, ufrag); + expect(sdp.sdp).to.equal(an_sdp); + }); +}); + +describe('SDP munging', () => { + it('does a simple replacement', () => { + let result = underTest.munge({type:'answer',sdp: an_sdp},'someotheruserfragmentstring'); + expect(result.sdp).to.equal(` +v=0 +o=- 0 0 IN IP4 192.168.0.152 +s=- +c=IN IP4 192.168.0.152 +t=0 0 +m=application 2345 UDP/DTLS/SCTP webrtc-datachannel +a=mid:0 +a=ice-options:ice2 +a=ice-ufrag:someotheruserfragmentstring +a=ice-pwd:someotheruserfragmentstring +a=fingerprint:mTXVsdGliYXNlIGlzIGF3ZXNvbWUhIFxvLw +a=setup:actpass +a=sctp-port:5000 +a=max-message-size:100000 +`); + }); +});