瀏覽代碼

Adds functionality for authentication with external system.

j8
paweldomas 10 年之前
父節點
當前提交
f4004656a3
共有 11 個文件被更改,包括 253 次插入56 次删除
  1. 88
    4
      app.js
  2. 3
    0
      css/font.css
  3. 6
    0
      index.html
  4. 26
    0
      message_handler.js
  5. 3
    3
      moderatemuc.js
  6. 56
    15
      moderator.js
  7. 6
    0
      muc.js
  8. 2
    2
      recording.js
  9. 3
    3
      rtp_sts.js
  10. 13
    0
      toolbar.js
  11. 47
    29
      videolayout.js

+ 88
- 4
app.js 查看文件

@@ -2,11 +2,12 @@
2 2
 /* application specific logic */
3 3
 var connection = null;
4 4
 var authenticatedUser = false;
5
+var authenticationWindow = null;
5 6
 var activecall = null;
6 7
 var RTC = null;
7 8
 var nickname = null;
8 9
 var sharedKey = '';
9
-var focusJid = null;
10
+var focusMucJid = null;
10 11
 var roomUrl = null;
11 12
 var roomName = null;
12 13
 var ssrc2jid = {};
@@ -164,6 +165,8 @@ function connect(jid, password) {
164 165
             }
165 166
             document.getElementById('connect').disabled = true;
166 167
 
168
+            console.info("My Jabber ID: " + connection.jid);
169
+
167 170
             if(password)
168 171
                 authenticatedUser = true;
169 172
             maybeDoJoin();
@@ -755,6 +758,10 @@ $(document).bind('joined.muc', function (event, jid, info) {
755 758
     // Once we've joined the muc show the toolbar
756 759
     ToolbarToggler.showToolbar();
757 760
 
761
+    // Show authenticate button if needed
762
+    Toolbar.showAuthenticateButton(
763
+        Moderator.isExternalAuthEnabled() && !Moderator.isModerator());
764
+
758 765
     var displayName = !config.displayJids
759 766
         ? info.displayName : Strophe.getResourceFromJid(jid);
760 767
 
@@ -767,10 +774,8 @@ $(document).bind('entered.muc', function (event, jid, info, pres) {
767 774
     console.log('entered', jid, info);
768 775
     if (info.isFocus)
769 776
     {
770
-        focusJid = jid;
777
+        focusMucJid = jid;
771 778
         console.info("Ignore focus: " + jid +", real JID: " + info.jid);
772
-        // We don't want this notification for the focus.
773
-        // messageHandler.notify('Focus', 'connected', 'connected');
774 779
         return;
775 780
     }
776 781
 
@@ -944,6 +949,44 @@ $(document).bind('kicked.muc', function (event, jid) {
944 949
     }
945 950
 });
946 951
 
952
+$(document).bind('role.changed.muc', function (event, jid, member, pres) {
953
+        console.info("Role changed for " + jid + ", new role: " + member.role);
954
+
955
+        VideoLayout.showModeratorIndicator();
956
+
957
+        if (member.role === 'moderator') {
958
+            var displayName = member.displayName;
959
+            if (!displayName) {
960
+                displayName = 'Somebody';
961
+            }
962
+            messageHandler.notify(
963
+                displayName,
964
+                'connected',
965
+                'Moderator rights granted to ' + displayName + '!');
966
+        }
967
+    }
968
+);
969
+
970
+$(document).bind('local.role.changed.muc', function (event, jid, info, pres) {
971
+
972
+        console.info("My role changed, new role: " + info.role);
973
+        var isModerator = Moderator.isModerator();
974
+
975
+        VideoLayout.showModeratorIndicator();
976
+        Toolbar.showAuthenticateButton(
977
+            Moderator.isExternalAuthEnabled() && !isModerator);
978
+
979
+        if (isModerator) {
980
+            if (authenticationWindow) {
981
+                authenticationWindow.close();
982
+                authenticationWindow = null;
983
+            }
984
+            messageHandler.notify(
985
+                'Me', 'connected', 'Moderator rights granted !');
986
+        }
987
+    }
988
+);
989
+
947 990
 $(document).bind('passwordrequired.muc', function (event, jid) {
948 991
     console.log('on password required', jid);
949 992
 
@@ -996,6 +1039,44 @@ $(document).bind('passwordrequired.main', function (event) {
996 1039
     );
997 1040
 });
998 1041
 
1042
+$(document).bind('auth_required.moderator', function () {
1043
+    // extract room name from 'room@muc.server.net'
1044
+    var room = roomName.substr(0, roomName.indexOf('@'));
1045
+
1046
+    messageHandler.openDialog(
1047
+        'Stop',
1048
+        'Authentication is required to create room:<br/>' + room,
1049
+        true,
1050
+        {
1051
+            Authenticate: 'authNow',
1052
+            Close: 'close'
1053
+        },
1054
+        function (onSubmitEvent, submitValue) {
1055
+            console.info('On submit: ' + submitValue, submitValue);
1056
+            if (submitValue === 'authNow') {
1057
+                authenticateClicked();
1058
+            } else {
1059
+                Toolbar.showAuthenticateButton(true);
1060
+            }
1061
+        }
1062
+    );
1063
+});
1064
+
1065
+function authenticateClicked() {
1066
+    // Get authentication URL
1067
+    Moderator.getAuthUrl(function (url) {
1068
+        // Open popup with authentication URL
1069
+        authenticationWindow = messageHandler.openCenteredPopup(
1070
+            url, 500, 400,
1071
+            function () {
1072
+                // On popup closed - retry room allocation
1073
+                Moderator.allocateConferenceFocus(
1074
+                    roomName, doJoinAfterFocus);
1075
+                authenticationWindow = null;
1076
+            });
1077
+    });
1078
+};
1079
+
999 1080
 /**
1000 1081
  * Checks if video identified by given src is desktop stream.
1001 1082
  * @param videoSrc eg.
@@ -1474,6 +1555,9 @@ $(window).bind('beforeunload', function () {
1474 1555
 });
1475 1556
 
1476 1557
 function disposeConference(onUnload) {
1558
+
1559
+    Toolbar.showAuthenticateButton(false);
1560
+
1477 1561
     var handler = getConferenceHandler();
1478 1562
     if (handler && handler.peerconnection) {
1479 1563
         // FIXME: probably removing streams is not required and close() should

+ 3
- 0
css/font.css 查看文件

@@ -42,6 +42,9 @@
42 42
 .icon-recEnable:before {
43 43
     content: "\e614";
44 44
 }
45
+.icon-authenticate:before {
46
+    content: "\e1ae";
47
+}
45 48
 .icon-kick1:before {
46 49
     content: "\e60f";
47 50
 }

+ 6
- 0
index.html 查看文件

@@ -184,6 +184,12 @@
184 184
                     <a class="button" data-container="body" data-toggle="popover" data-placement="bottom" shortcut="toggleVideoPopover" content="Start / stop camera" onclick='toggleVideo();'>
185 185
                         <i id="video" class="icon-camera"></i>
186 186
                     </a>
187
+                    <span id="authentication" style="display: none">
188
+                        <div class="header_button_separator"></div>
189
+                        <a class="button" data-container="body" data-toggle="popover" data-placement="bottom" content="Authenticate" onclick='authenticateClicked();'>
190
+                            <i id="authButton" class="icon-avatar"></i>
191
+                        </a>
192
+                    </span>
187 193
                     <span id="recording" style="display: none">
188 194
                         <div class="header_button_separator"></div>
189 195
                         <a class="button" data-container="body" data-toggle="popover" data-placement="bottom" content="Record" onclick='toggleRecording();'>

+ 26
- 0
message_handler.js 查看文件

@@ -80,6 +80,32 @@ var messageHandler = (function(my) {
80 80
         myPrompt.on('impromptu:statechanged', stateChangedFunction);
81 81
     };
82 82
 
83
+    /**
84
+     * Opens new popup window for given <tt>url</tt> centered over current
85
+     * window.
86
+     *
87
+     * @param url the URL to be displayed in the popup window
88
+     * @param w the width of the popup window
89
+     * @param h the height of the popup window
90
+     * @param onPopupClosed optional callback function called when popup window
91
+     *        has been closed.
92
+     */
93
+    my.openCenteredPopup = function (url, w, h, onPopupClosed) {
94
+        var l = window.screenX + (window.innerWidth / 2) - (w / 2);
95
+        var t = window.screenY + (window.innerHeight / 2) - (h / 2);
96
+        var popup = window.open(
97
+            url, '_blank',
98
+            'top=' + t + ', left=' + l + ', width=' + w + ', height=' + h + '');
99
+        if (onPopupClosed) {
100
+            var pollTimer = window.setInterval(function () {
101
+                if (popup.closed !== false) {
102
+                    window.clearInterval(pollTimer);
103
+                    onPopupClosed();
104
+                }
105
+            }, 200);
106
+        }
107
+    };
108
+
83 109
     /**
84 110
      * Shows a dialog prompting the user to send an error report.
85 111
      *

+ 3
- 3
moderatemuc.js 查看文件

@@ -1,4 +1,4 @@
1
-/* global $, $iq, config, connection, focusJid, forceMuted, messageHandler,
1
+/* global $, $iq, config, connection, focusMucJid, forceMuted, messageHandler,
2 2
    setAudioMuted, Strophe, toggleAudio */
3 3
 /**
4 4
  * Moderate connection plugin.
@@ -17,7 +17,7 @@ Strophe.addConnectionPlugin('moderate', {
17 17
     },
18 18
     setMute: function (jid, mute) {
19 19
         console.info("set mute", mute);
20
-        var iqToFocus = $iq({to: focusJid, type: 'set'})
20
+        var iqToFocus = $iq({to: focusMucJid, type: 'set'})
21 21
             .c('mute', {
22 22
                 xmlns: 'http://jitsi.org/jitmeet/audio',
23 23
                 jid: jid
@@ -40,7 +40,7 @@ Strophe.addConnectionPlugin('moderate', {
40 40
     },
41 41
     onMute: function (iq) {
42 42
         var from = iq.getAttribute('from');
43
-        if (from !== focusJid) {
43
+        if (from !== focusMucJid) {
44 44
             console.warn("Ignored mute from non focus peer");
45 45
             return false;
46 46
         }

+ 56
- 15
moderator.js 查看文件

@@ -9,11 +9,21 @@ var Moderator = (function (my) {
9 9
     var focusUserJid;
10 10
     var getNextTimeout = Util.createExpBackoffTimer(1000);
11 11
     var getNextErrorTimeout = Util.createExpBackoffTimer(1000);
12
+    // External authentication stuff
13
+    var externalAuthEnabled = false;
12 14
 
13 15
     my.isModerator = function () {
14 16
         return connection.emuc.isModerator();
15 17
     };
16 18
 
19
+    my.isPeerModerator = function (peerJid) {
20
+        return connection.emuc.getMemberRole(peerJid) === 'moderator';
21
+    };
22
+
23
+    my.isExternalAuthEnabled = function () {
24
+        return externalAuthEnabled;
25
+    };
26
+
17 27
     my.onModeratorStatusChanged = function (isModerator) {
18 28
 
19 29
         Toolbar.showSipCallButton(isModerator);
@@ -27,25 +37,12 @@ var Moderator = (function (my) {
27 37
         if (isModerator && config.etherpad_base) {
28 38
             Etherpad.init();
29 39
         }
30
-
31
-        $(document).trigger('local.role.moderator', [isModerator]);
32 40
     };
33 41
 
34 42
     my.init = function () {
35
-        $(document).bind(
36
-            'role.changed.muc',
37
-            function (event, jid, info, pres) {
38
-                console.info(
39
-                    "Role changed for " + jid + ", new role: " + info.role);
40
-                VideoLayout.showModeratorIndicator();
41
-            }
42
-        );
43
-
44 43
         $(document).bind(
45 44
             'local.role.changed.muc',
46 45
             function (event, jid, info, pres) {
47
-                console.info("My role changed, new role: " + info.role);
48
-                VideoLayout.showModeratorIndicator();
49 46
                 Moderator.onModeratorStatusChanged(Moderator.isModerator());
50 47
             }
51 48
         );
@@ -141,6 +138,19 @@ var Moderator = (function (my) {
141 138
         return elem;
142 139
     };
143 140
 
141
+    my.parseConfigOptions = function (resultIq) {
142
+
143
+        Moderator.setFocusUserJid(
144
+            $(resultIq).find('conference').attr('focusjid'));
145
+
146
+        var extAuthParam
147
+            = $(resultIq).find('>conference>property[name=\'externalAuth\']');
148
+        if (extAuthParam.length) {
149
+            externalAuthEnabled = extAuthParam.attr('value') === 'true';
150
+        }
151
+        console.info("External authentication enabled: " + externalAuthEnabled);
152
+    };
153
+
144 154
     // FIXME: we need to show the fact that we're waiting for the focus
145 155
     // to the user(or that focus is not available)
146 156
     my.allocateConferenceFocus = function (roomName, callback) {
@@ -155,8 +165,9 @@ var Moderator = (function (my) {
155 165
                     // Reset both timers
156 166
                     getNextTimeout(true);
157 167
                     getNextErrorTimeout(true);
158
-                    Moderator.setFocusUserJid(
159
-                        $(result).find('conference').attr('focusjid'));
168
+                    // Setup config options
169
+                    Moderator.parseConfigOptions(result);
170
+                    // Exec callback
160 171
                     callback();
161 172
                 } else {
162 173
                     var waitMs = getNextTimeout();
@@ -171,6 +182,12 @@ var Moderator = (function (my) {
171 182
                 }
172 183
             },
173 184
             function (error) {
185
+                // Not authorized to create new room
186
+                if ($(error).find('>error>not-authorized').length) {
187
+                    console.warn("Unauthorized to start the conference");
188
+                    $(document).trigger('auth_required.moderator');
189
+                    return;
190
+                }
174 191
                 var waitMs = getNextErrorTimeout();
175 192
                 console.error("Focus error, retry after " + waitMs, error);
176 193
                 // Show message
@@ -188,6 +205,30 @@ var Moderator = (function (my) {
188 205
         );
189 206
     };
190 207
 
208
+    my.getAuthUrl = function (urlCallback) {
209
+        var iq = $iq({to: Moderator.getFocusComponent(), type: 'get'});
210
+        iq.c('auth-url', {
211
+            xmlns: 'http://jitsi.org/protocol/focus',
212
+            room: roomName
213
+        });
214
+        connection.sendIQ(
215
+            iq,
216
+            function (result) {
217
+                var url = $(result).find('auth-url').attr('url');
218
+                if (url) {
219
+                    console.info("Got auth url: " + url);
220
+                    urlCallback(url);
221
+                } else {
222
+                    console.error(
223
+                        "Failed to get auth url fro mthe focus", result);
224
+                }
225
+            },
226
+            function (error) {
227
+                console.error("Get auth url error", error);
228
+            }
229
+        );
230
+    };
231
+
191 232
     return my;
192 233
 }(Moderator || {}));
193 234
 

+ 6
- 0
muc.js 查看文件

@@ -503,5 +503,11 @@ Strophe.addConnectionPlugin('emuc', {
503 503
     },
504 504
     isModerator: function() {
505 505
         return this.role === 'moderator';
506
+    },
507
+    getMemberRole: function(peerJid) {
508
+        if (this.members[peerJid]) {
509
+            return this.members[peerJid].role;
510
+        }
511
+        return null;
506 512
     }
507 513
 });

+ 2
- 2
recording.js 查看文件

@@ -1,4 +1,4 @@
1
-/* global $, $iq, config, connection, focusJid, messageHandler, Moderator,
1
+/* global $, $iq, config, connection, focusMucJid, messageHandler, Moderator,
2 2
    Toolbar, Util */
3 3
 var Recording = (function (my) {
4 4
     var recordingToken = null;
@@ -13,7 +13,7 @@ var Recording = (function (my) {
13 13
     // with the new recording state, according to the IQ.
14 14
     my.setRecording = function (state, token, callback) {
15 15
         var self = this;
16
-        var elem = $iq({to: focusJid, type: 'set'});
16
+        var elem = $iq({to: focusMucJid, type: 'set'});
17 17
         elem.c('conference', {
18 18
             xmlns: 'http://jitsi.org/protocol/colibri'
19 19
         });

+ 3
- 3
rtp_sts.js 查看文件

@@ -1,4 +1,4 @@
1
-/* global ssrc2jid */
1
+/* global focusMucJid, ssrc2jid */
2 2
 /* jshint -W117 */
3 3
 /**
4 4
  * Calculates packet lost percent using the number of lost packets and the
@@ -324,7 +324,7 @@ StatsCollector.prototype.addStatsToBeLogged = function (reports) {
324 324
 };
325 325
 
326 326
 StatsCollector.prototype.logStats = function () {
327
-    if (!focusJid) {
327
+    if (!focusMucJid) {
328 328
         return;
329 329
     }
330 330
 
@@ -337,7 +337,7 @@ StatsCollector.prototype.logStats = function () {
337 337
     content = Base64.encode(content);
338 338
 
339 339
     // XEP-0337-ish
340
-    var message = $msg({to: focusJid, type: 'normal'});
340
+    var message = $msg({to: focusMucJid, type: 'normal'});
341 341
     message.c('log', { xmlns: 'urn:xmpp:eventlog',
342 342
                        id: 'PeerConnectionStats'});
343 343
     message.c('message').t(content).up();

+ 13
- 0
toolbar.js 查看文件

@@ -221,6 +221,19 @@ var Toolbar = (function (my) {
221 221
             buttonClick("#lockIcon", "icon-security icon-security-locked");
222 222
     };
223 223
 
224
+    /**
225
+     * Shows or hides authentication button
226
+     * @param show <tt>true</tt> to show or <tt>false</tt> to hide
227
+     */
228
+    my.showAuthenticateButton = function (show) {
229
+        if (show) {
230
+            $('#authentication').css({display: "inline"});
231
+        }
232
+        else {
233
+            $('#authentication').css({display: "none"});
234
+        }
235
+    };
236
+
224 237
     // Shows or hides the 'recording' button.
225 238
     my.showRecordingButton = function (show) {
226 239
         if (!config.enableRecording) {

+ 47
- 29
videolayout.js 查看文件

@@ -485,7 +485,8 @@ var VideoLayout = (function (my) {
485 485
         if ($('#' + videoSpanId).length > 0) {
486 486
             // If there's been a focus change, make sure we add focus related
487 487
             // interface!!
488
-            if (Moderator.isModerator() && $('#remote_popupmenu_' + resourceJid).length <= 0) {
488
+            if (Moderator.isModerator() && !Moderator.isPeerModerator(peerJid)
489
+                && $('#remote_popupmenu_' + resourceJid).length <= 0) {
489 490
                 addRemoteVideoMenu(peerJid,
490 491
                     document.getElementById(videoSpanId));
491 492
             }
@@ -905,38 +906,42 @@ var VideoLayout = (function (my) {
905 906
             {
906 907
                 createModeratorIndicatorElement(indicatorSpan[0]);
907 908
             }
908
-        } else {
909
-            Object.keys(connection.emuc.members).forEach(function (jid) {
910
-                var member = connection.emuc.members[jid];
911
-                if (member.role === 'moderator') {
912
-                    var moderatorId
913
-                        = 'participant_' + Strophe.getResourceFromJid(jid);
914
-
915
-                    var moderatorContainer
916
-                        = document.getElementById(moderatorId);
917
-
918
-                    if (Strophe.getResourceFromJid(jid) === 'focus') {
919
-                        // Skip server side focus
920
-                        return;
921
-                    }
922
-                    if (!moderatorContainer) {
923
-                        console.error("No moderator container for " + jid);
924
-                        return;
925
-                    }
926
-                    var indicatorSpan
927
-                        = $('#' + moderatorId + ' .focusindicator');
909
+        }
910
+        Object.keys(connection.emuc.members).forEach(function (jid) {
911
+            var member = connection.emuc.members[jid];
912
+            if (member.role === 'moderator') {
913
+                var moderatorId
914
+                    = 'participant_' + Strophe.getResourceFromJid(jid);
915
+
916
+                var moderatorContainer
917
+                    = document.getElementById(moderatorId);
928 918
 
929
-                    if (!indicatorSpan || indicatorSpan.length === 0) {
930
-                        indicatorSpan = document.createElement('span');
931
-                        indicatorSpan.className = 'focusindicator';
919
+                if (Strophe.getResourceFromJid(jid) === 'focus') {
920
+                    // Skip server side focus
921
+                    return;
922
+                }
923
+                if (!moderatorContainer) {
924
+                    console.error("No moderator container for " + jid);
925
+                    return;
926
+                }
927
+                var menuSpan = $('#' + moderatorId + '>span.remotevideomenu');
928
+                if (menuSpan.length) {
929
+                    removeRemoteVideoMenu(moderatorId);
930
+                }
932 931
 
933
-                        moderatorContainer.appendChild(indicatorSpan);
932
+                var indicatorSpan
933
+                    = $('#' + moderatorId + ' .focusindicator');
934 934
 
935
-                        createModeratorIndicatorElement(indicatorSpan);
936
-                    }
935
+                if (!indicatorSpan || indicatorSpan.length === 0) {
936
+                    indicatorSpan = document.createElement('span');
937
+                    indicatorSpan.className = 'focusindicator';
938
+
939
+                    moderatorContainer.appendChild(indicatorSpan);
940
+
941
+                    createModeratorIndicatorElement(indicatorSpan);
937 942
                 }
938
-            });
939
-        }
943
+            }
944
+        });
940 945
     };
941 946
 
942 947
     /**
@@ -1399,6 +1404,19 @@ var VideoLayout = (function (my) {
1399 1404
         popupmenuElement.appendChild(paddingSpan);
1400 1405
     }
1401 1406
 
1407
+    /**
1408
+     * Removes remote video menu element from video element identified by
1409
+     * given <tt>videoElementId</tt>.
1410
+     *
1411
+     * @param videoElementId the id of local or remote video element.
1412
+     */
1413
+    function removeRemoteVideoMenu(videoElementId) {
1414
+        var menuSpan = $('#' + videoElementId + '>span.remotevideomenu');
1415
+        if (menuSpan.length) {
1416
+            menuSpan.remove();
1417
+        }
1418
+    }
1419
+
1402 1420
     /**
1403 1421
      * On contact list item clicked.
1404 1422
      */

Loading…
取消
儲存