Explorar o código

Conditional TLS for TURN

Disable TLS TURN server on Firefox <53 to save allocations.
Danilo Bargen %!s(int64=8) %!d(string=hai) anos
pai
achega
0b541ce2f6

+ 1 - 0
karma.conf.js

@@ -9,6 +9,7 @@ module.exports = function(config) {
             'tests/filters.js',
             'tests/service/qrcode.js',
             'tests/service/message.js',
+            'tests/service/webclient.js',
             'tests/helpers.js',
         ],
         customLaunchers: {

+ 2 - 1
src/services/peerconnection.ts

@@ -49,7 +49,8 @@ export class PeerConnectionHelper {
                 webrtcTask: saltyrtc.tasks.webrtc.WebRTCTask,
                 iceServers: RTCIceServer[]) {
         this.$log = $log;
-        this.$log.info('Initialize WebRTC PeerConnection');
+        this.$log.info(this.logTag, 'Initialize WebRTC PeerConnection');
+        this.$log.debug(this.logTag, 'ICE servers used:', [].concat(...iceServers.map((c) => c.urls)).join(', '));
         this.$q = $q;
         this.$timeout = $timeout;
         this.$rootScope = $rootScope;

+ 25 - 0
src/services/webclient.ts

@@ -242,6 +242,7 @@ export class WebClientService implements threema.WebClientService {
         // Get default class
         this.defaults = new WebClientDefault();
 
+        // Initialize drafts
         this.drafts = this.container.createDrafts();
 
         // Setup fields
@@ -366,6 +367,12 @@ export class WebClientService implements threema.WebClientService {
         // Once the connection is established, initiate the peer connection
         // and start the handover.
         this.salty.once('state-change:task', () => {
+            // Firefox <53 does not yet support TLS. Skip it, to save allocations.
+            const browser = this.browserService.getBrowser();
+            if (browser.firefox && parseFloat(browser.version) < 53) {
+                this.skipIceTls();
+            }
+
             this.pcHelper = new PeerConnectionHelper(this.$log, this.$q, this.$timeout,
                                                      this.$rootScope, this.webrtcTask,
                                                      this.config.ICE_SERVERS);
@@ -568,6 +575,24 @@ export class WebClientService implements threema.WebClientService {
         }
     }
 
+    /**
+     * Remove "turns:" servers from the ICE_SERVERS configuration
+     * if at least one "turn:" server with tcp transport is in the list.
+     */
+    public skipIceTls(): void {
+        this.$log.debug(this.logTag, 'Requested to remove TURNS server from ICE configuration');
+        const allUrls = [].concat(...this.config.ICE_SERVERS.map((conf) => conf.urls));
+        if (allUrls.some((url) => url.startsWith('turn:') && url.endsWith('=tcp'))) {
+            // There's at least one TURN server with TCP transport in the list
+            for (let server of this.config.ICE_SERVERS) {
+                // Remove TLS entries
+                server.urls = server.urls.filter((url) => !url.startsWith('turns:'));
+            }
+        } else {
+            this.$log.debug(this.logTag, 'No fallback TURN TCP server present, keeping TURNS server');
+        }
+    }
+
     // Mark a component as initialized
     public registerInitializationStep(name: threema.InitializationStep) {
         if (this.initialized.has(name) ) {

+ 90 - 0
tests/service/webclient.js

@@ -0,0 +1,90 @@
+describe('WebClientService', function() {
+
+    let $service;
+
+    beforeEach(function() {
+
+        module(($provide) => {
+            // Provide configuration
+            $provide.constant('CONFIG', {
+                ICE_SERVERS: [
+                    {
+                        urls: [
+                            'turn:turn.threema.ch:443?transport=tcp',
+                            'turn:turn.threema.ch:443?transport=udp',
+                            'turns:turn.threema.ch:443?transport=tcp',
+                        ],
+                        username: 'user',
+                        credential: 'credential',
+                    },
+                ],
+            });
+
+            // Mock some dependencies that we don't really need
+            $provide.constant('PROTOCOL_VERSION', 1337);
+            $provide.constant('$state', null);
+            $provide.constant('$translate', null);
+        });
+
+        // Load modules
+        module('3ema.services');
+        module('3ema.container');
+
+        // Inject the service to be tested
+        inject(function(WebClientService) {
+            $service = WebClientService;
+        });
+
+    });
+
+    it('can skip ICE TLS hosts if a non-TLS TCP server is available', () => {
+        const allUrlsBefore = [].concat(...$service.config.ICE_SERVERS.map((conf) => conf.urls));
+        expect(allUrlsBefore.indexOf('turns:turn.threema.ch:443?transport=tcp')).not.toEqual(-1);
+
+        $service.skipIceTls();
+
+        const allUrlsAfter = [].concat(...$service.config.ICE_SERVERS.map((conf) => conf.urls));
+        expect(allUrlsAfter.length).toEqual(allUrlsBefore.length - 1);
+        expect(allUrlsAfter.indexOf('turns:turn.threema.ch:443?transport=tcp')).toEqual(-1);
+    });
+
+    it('can skip ICE TLS hosts if a non-TLS TCP server is available in another server object', () => {
+        $service.config.ICE_SERVERS = [
+            {
+                urls: ['turn:turn.threema.ch:443?transport=udp', 'turns:turn.threema.ch:443?transport=tcp'],
+                username: 'user', credential: 'credential',
+            },
+            {
+                urls: ['turn:turn.threema.ch:443?transport=tcp'],
+                username: 'user', credential: 'credential',
+            }
+        ];
+        const allUrlsBefore = [].concat(...$service.config.ICE_SERVERS.map((conf) => conf.urls));
+        expect(allUrlsBefore.indexOf('turns:turn.threema.ch:443?transport=tcp')).not.toEqual(-1);
+
+        $service.skipIceTls();
+
+        const allUrlsAfter = [].concat(...$service.config.ICE_SERVERS.map((conf) => conf.urls));
+        expect(allUrlsAfter.length).toEqual(allUrlsBefore.length - 1);
+        expect(allUrlsAfter.indexOf('turns:turn.threema.ch:443?transport=tcp')).toEqual(-1);
+    });
+
+    it('does not skip ICE TLS hosts if no non-TLS TCP server is available', () => {
+        $service.config.ICE_SERVERS = [
+            {
+                urls: ['turn:turn.threema.ch:443?transport=udp', 'turns:turn.threema.ch:443?transport=tcp'],
+                username: 'user',
+                credential: 'credential',
+            }
+        ];
+        const allUrlsBefore = [].concat(...$service.config.ICE_SERVERS.map((conf) => conf.urls));
+        expect(allUrlsBefore.indexOf('turns:turn.threema.ch:443?transport=tcp')).not.toEqual(-1);
+
+        $service.skipIceTls();
+
+        const allUrlsAfter = [].concat(...$service.config.ICE_SERVERS.map((conf) => conf.urls));
+        expect(allUrlsAfter.length).toEqual(allUrlsBefore.length);
+        expect(allUrlsAfter.indexOf('turns:turn.threema.ch:443?transport=tcp')).not.toEqual(-1);
+    });
+
+});

+ 1 - 0
tests/testsuite.html

@@ -19,6 +19,7 @@
         <script src="filters.js"></script>
         <script src="service/qrcode.js"></script>
         <script src="service/message.js"></script>
+        <script src="service/webclient.js"></script>
         <script src="helpers.js"></script>
     </head>
     <body>