|
@@ -10,6 +10,13 @@ if token_util == nil then
|
10
|
10
|
return;
|
11
|
11
|
end
|
12
|
12
|
|
|
13
|
+-- configuration to limit number of outgoing calls
|
|
14
|
+local LIMIT_OUTGOING_CALLS = module:get_option_number("max_number_outgoing_calls", -1);
|
|
15
|
+
|
|
16
|
+-- Header names to use to push extra data extracted from token, if any
|
|
17
|
+local OUT_INITIATOR_USER_ATTR_NAME = "X-outbound-call-initiator-user";
|
|
18
|
+local OUT_INITIATOR_GROUP_ATTR_NAME = "X-outbound-call-initiator-group";
|
|
19
|
+
|
13
|
20
|
-- filters rayo iq in case of requested from not jwt authenticated sessions
|
14
|
21
|
-- or if the session has features in user context and it doesn't mention
|
15
|
22
|
-- feature "outbound-call" to be enabled
|
|
@@ -39,11 +46,120 @@ module:hook("pre-iq/full", function(event)
|
39
|
46
|
(dial.attr.to == 'jitsi_meet_transcribe' and 'transcription'
|
40
|
47
|
or 'outbound-call'))
|
41
|
48
|
then
|
42
|
|
- module:log("info",
|
|
49
|
+ module:log("warn",
|
43
|
50
|
"Filtering stanza dial, stanza:%s", tostring(stanza));
|
44
|
51
|
session.send(st.error_reply(stanza, "auth", "forbidden"));
|
45
|
52
|
return true;
|
46
|
53
|
end
|
|
54
|
+
|
|
55
|
+ -- now lets check any limits if configured
|
|
56
|
+ if LIMIT_OUTGOING_CALLS > 0
|
|
57
|
+ and get_concurrent_outgoing_count(
|
|
58
|
+ session.jitsi_meet_context_user["id"],
|
|
59
|
+ session.jitsi_meet_context_group) >= LIMIT_OUTGOING_CALLS
|
|
60
|
+ then
|
|
61
|
+ module:log("warn",
|
|
62
|
+ "Filtering stanza dial, stanza:%s, outgoing calls limit reached", tostring(stanza));
|
|
63
|
+ session.send(st.error_reply(stanza, "cancel", "resource-constraint"));
|
|
64
|
+ return true;
|
|
65
|
+ end
|
|
66
|
+
|
|
67
|
+ -- now lets insert token information if any
|
|
68
|
+ if session and session.jitsi_meet_context_user then
|
|
69
|
+ -- First remove any 'header' element if it already
|
|
70
|
+ -- exists, so it cannot be spoofed by a client
|
|
71
|
+ stanza:maptags(
|
|
72
|
+ function(tag)
|
|
73
|
+ if tag.name == "header"
|
|
74
|
+ and (tag.attr.name == OUT_INITIATOR_USER_ATTR_NAME
|
|
75
|
+ or tag.attr.name == OUT_INITIATOR_GROUP_ATTR_NAME) then
|
|
76
|
+ return nil
|
|
77
|
+ end
|
|
78
|
+ return tag
|
|
79
|
+ end
|
|
80
|
+ )
|
|
81
|
+
|
|
82
|
+ local dial = stanza:get_child('dial', 'urn:xmpp:rayo:1');
|
|
83
|
+ -- adds initiator user id from token
|
|
84
|
+ dial:tag("header", {
|
|
85
|
+ xmlns = "urn:xmpp:rayo:1",
|
|
86
|
+ name = OUT_INITIATOR_USER_ATTR_NAME,
|
|
87
|
+ value = session.jitsi_meet_context_user["id"] });
|
|
88
|
+ dial:up();
|
|
89
|
+
|
|
90
|
+ -- Add the initiator group information if it is present
|
|
91
|
+ if session.jitsi_meet_context_group then
|
|
92
|
+ dial:tag("header", {
|
|
93
|
+ xmlns = "urn:xmpp:rayo:1",
|
|
94
|
+ name = OUT_INITIATOR_GROUP_ATTR_NAME,
|
|
95
|
+ value = session.jitsi_meet_context_group });
|
|
96
|
+ dial:up();
|
|
97
|
+ end
|
|
98
|
+ end
|
47
|
99
|
end
|
48
|
100
|
end
|
49
|
101
|
end);
|
|
102
|
+
|
|
103
|
+--- Finds and returns the number of concurrent outgoing calls for a user
|
|
104
|
+-- @param context_user the user id extracted from the token
|
|
105
|
+-- @param context_group the group id extracted from the token
|
|
106
|
+-- @return returns the count of concurrent calls
|
|
107
|
+function get_concurrent_outgoing_count(context_user, context_group)
|
|
108
|
+ local count = 0;
|
|
109
|
+ for _, host in pairs(hosts) do
|
|
110
|
+ local component = host;
|
|
111
|
+ if component then
|
|
112
|
+ local muc = component.modules.muc
|
|
113
|
+ local rooms = nil;
|
|
114
|
+ if muc and rawget(muc,"rooms") then
|
|
115
|
+ -- We're running 0.9.x or 0.10 (old MUC API)
|
|
116
|
+ return muc.rooms;
|
|
117
|
+ elseif muc and rawget(muc,"live_rooms") then
|
|
118
|
+ -- We're running >=0.11 (new MUC API)
|
|
119
|
+ rooms = muc.live_rooms();
|
|
120
|
+ elseif muc and rawget(muc,"each_room") then
|
|
121
|
+ -- We're running trunk<0.11 (each_room is later [DEPRECATED])
|
|
122
|
+ rooms = muc.each_room(true);
|
|
123
|
+ end
|
|
124
|
+
|
|
125
|
+ -- now lets iterate over rooms and occupants and search for
|
|
126
|
+ -- call initiated by the user
|
|
127
|
+ if rooms then
|
|
128
|
+ for room in rooms do
|
|
129
|
+ for _, occupant in room:each_occupant() do
|
|
130
|
+ for _, presence in occupant:each_session() do
|
|
131
|
+
|
|
132
|
+ local initiator = presence:get_child('initiator', 'http://jitsi.org/protocol/jigasi');
|
|
133
|
+
|
|
134
|
+ local found_user = false;
|
|
135
|
+ local found_group = false;
|
|
136
|
+
|
|
137
|
+ if initiator then
|
|
138
|
+ initiator:maptags(function (tag)
|
|
139
|
+ if tag.name == "header"
|
|
140
|
+ and tag.attr.name == OUT_INITIATOR_USER_ATTR_NAME then
|
|
141
|
+ found_user = tag.attr.value == context_user;
|
|
142
|
+ elseif tag.name == "header"
|
|
143
|
+ and tag.attr.name == OUT_INITIATOR_GROUP_ATTR_NAME then
|
|
144
|
+ found_group = tag.attr.value == context_group;
|
|
145
|
+ end
|
|
146
|
+
|
|
147
|
+ return tag;
|
|
148
|
+ end );
|
|
149
|
+ -- if found a jigasi participant initiated by the concurrent
|
|
150
|
+ -- participant, count it
|
|
151
|
+ if found_user
|
|
152
|
+ and (context_group == nil or found_group) then
|
|
153
|
+ count = count + 1;
|
|
154
|
+ end
|
|
155
|
+ end
|
|
156
|
+ end
|
|
157
|
+ end
|
|
158
|
+ end
|
|
159
|
+ end
|
|
160
|
+ end
|
|
161
|
+ end
|
|
162
|
+
|
|
163
|
+ return count;
|
|
164
|
+end
|
|
165
|
+
|