Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

mod_muc_jigasi_invite.lua 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. -- A http endpoint to invite jigasi to a meeting via http endpoint
  2. -- jwt is used to validate access
  3. -- Copyright (C) 2023-present 8x8, Inc.
  4. local jid_split = require "util.jid".split;
  5. local hashes = require "util.hashes";
  6. local random = require "util.random";
  7. local st = require("util.stanza");
  8. local json = require 'cjson.safe';
  9. local util = module:require "util";
  10. local async_handler_wrapper = util.async_handler_wrapper;
  11. local process_host_module = util.process_host_module;
  12. local muc_domain_base = module:get_option_string("muc_mapper_domain_base");
  13. -- This module chooses jigasi from the brewery room, so it needs information for the configured brewery
  14. local muc_domain = module:get_option_string("muc_internal_domain_base", 'internal.auth.' .. muc_domain_base);
  15. local jigasi_brewery_room_jid = module:get_option_string("muc_jigasi_brewery_jid", 'jigasibrewery@' .. muc_domain);
  16. local jigasi_bare_jid = module:get_option_string("muc_jigasi_jid", "jigasi@auth." .. muc_domain_base);
  17. local focus_jid = module:get_option_string("muc_jicofo_brewery_jid", jigasi_brewery_room_jid .. "/focus");
  18. local main_muc_service;
  19. local JSON_CONTENT_TYPE = "application/json";
  20. local event_count = module:measure("muc_invite_jigasi_rate", "rate")
  21. local event_count_success = module:measure("muc_invite_jigasi_success", "rate")
  22. local ASAP_KEY_SERVER = module:get_option_string("prosody_password_public_key_repo_url", "");
  23. local token_util = module:require "token/util".new(module);
  24. if ASAP_KEY_SERVER then
  25. -- init token util with our asap keyserver
  26. token_util:set_asap_key_server(ASAP_KEY_SERVER)
  27. end
  28. local function invite_jigasi(conference, phone_no)
  29. local jigasi_brewery_room = main_muc_service.get_room_from_jid(jigasi_brewery_room_jid);
  30. if not jigasi_brewery_room then
  31. module:log("error", "Jigasi brewery room not found")
  32. return 404, 'Brewery room was not found'
  33. end
  34. module:log("info", "Invite jigasi from %s to join conference %s and outbound phone_no %s", jigasi_brewery_room.jid, conference, phone_no)
  35. --select least stressed Jigasi
  36. local least_stressed_value = math.huge;
  37. local least_stressed_jigasi_jid;
  38. for occupant_jid, occupant in jigasi_brewery_room:each_occupant() do
  39. local _, _, resource = jid_split(occupant_jid);
  40. if resource ~= 'focus' then
  41. local occ = occupant:get_presence();
  42. local stats_child = occ:get_child("stats", "http://jitsi.org/protocol/colibri")
  43. local is_sip_jigasi = true;
  44. for stats_tag in stats_child:children() do
  45. if stats_tag.attr.name == 'supports_sip' and stats_tag.attr.value == 'false' then
  46. is_sip_jigasi = false;
  47. end
  48. end
  49. if is_sip_jigasi then
  50. for stats_tag in stats_child:children() do
  51. if stats_tag.attr.name == 'stress_level' then
  52. local stress_level = tonumber(stats_tag.attr.value);
  53. module:log("debug", "Stressed level %s %s ", stress_level, occupant_jid)
  54. if stress_level < least_stressed_value then
  55. least_stressed_jigasi_jid = occupant_jid
  56. least_stressed_value = stress_level
  57. end
  58. end
  59. end
  60. end
  61. end
  62. end
  63. module:log("debug", "Least stressed jigasi selected jid %s value %s", least_stressed_jigasi_jid, least_stressed_value)
  64. if not least_stressed_jigasi_jid then
  65. module:log("error", "Cannot invite jigasi from room %s", jigasi_brewery_room.jid)
  66. return 404, 'Jigasi not found'
  67. end
  68. -- invite Jigasi to join the conference
  69. local _, _, jigasi_res = jid_split(least_stressed_jigasi_jid)
  70. local jigasi_full_jid = jigasi_bare_jid .. "/" .. jigasi_res;
  71. local stanza_id = hashes.sha256(random.bytes(8), true);
  72. local invite_jigasi_stanza = st.iq({ xmlns = "jabber:client", type = "set", to = jigasi_full_jid, from = focus_jid, id = stanza_id })
  73. :tag("dial", { xmlns = "urn:xmpp:rayo:1", from = "fromnumber", to = phone_no })
  74. :tag("header", { xmlns = "urn:xmpp:rayo:1", name = "JvbRoomName", value = conference })
  75. module:log("debug", "Invite jigasi stanza %s", invite_jigasi_stanza)
  76. jigasi_brewery_room:route_stanza(invite_jigasi_stanza);
  77. return 200
  78. end
  79. local function is_token_valid(token)
  80. if token == nil then
  81. module:log("warn", "no token provided");
  82. return false;
  83. end
  84. local session = {};
  85. session.auth_token = token;
  86. local verified, reason, msg = token_util:process_and_verify_token(session);
  87. if not verified then
  88. module:log("warn", "not a valid token %s %s", tostring(reason), tostring(msg));
  89. return false;
  90. end
  91. return true;
  92. end
  93. local function handle_jigasi_invite(event)
  94. module:log("debug", "Request for invite jigasi received: reqId %s", event.request.headers["request_id"])
  95. event_count()
  96. local request = event.request;
  97. -- verify access
  98. local token = event.request.headers["authorization"]
  99. if not token then
  100. module:log("error", "Authorization header was not provided for conference %s", conference)
  101. return { status_code = 401 };
  102. end
  103. if util.starts_with(token, 'Bearer ') then
  104. token = token:sub(8, #token)
  105. else
  106. module:log("error", "Authorization header is invalid")
  107. return { status_code = 401 };
  108. end
  109. if not is_token_valid(token) then
  110. return { status_code = 401 };
  111. end
  112. -- verify payload
  113. if request.headers.content_type ~= JSON_CONTENT_TYPE
  114. or (not request.body or #request.body == 0) then
  115. module:log("warn", "Wrong content type: %s or missing payload", request.headers.content_type);
  116. return { status_code = 400; }
  117. end
  118. local payload, error = json.decode(request.body);
  119. if not payload then
  120. module:log('error', 'Cannot decode json error:%s', error);
  121. return { status_code = 400; }
  122. end
  123. local conference = payload["conference"];
  124. local phone_no = payload["phoneNo"];
  125. if not conference then
  126. module:log("warn", "Missing conference param")
  127. return { status_code = 400; }
  128. end
  129. if not phone_no then
  130. module:log("warn", "Missing phone no param")
  131. return { status_code = 400; }
  132. end
  133. --invite jigasi
  134. local status_code, error_msg = invite_jigasi(conference, phone_no)
  135. if not error_msg then
  136. event_count_success()
  137. return { status_code = 200 }
  138. else
  139. return { status_code = status_code, body = json.encode({ error = error_msg }) }
  140. end
  141. end
  142. module:log("info", "Adding http handler for /invite-jigasi on %s", module.host);
  143. module:depends("http");
  144. module:provides("http", {
  145. default_path = "/";
  146. route = {
  147. ["POST invite-jigasi"] = function(event)
  148. return async_handler_wrapper(event, handle_jigasi_invite)
  149. end;
  150. };
  151. });
  152. process_host_module(muc_domain, function(_, host)
  153. local muc_module = prosody.hosts[host].modules.muc;
  154. if muc_module then
  155. main_muc_service = muc_module;
  156. module:log('info', 'Found main_muc_service: %s', main_muc_service);
  157. else
  158. module:log('info', 'Will wait for muc to be available');
  159. prosody.hosts[host].events.add_handler('module-loaded', function(event)
  160. if (event.module == 'muc') then
  161. main_muc_service = prosody.hosts[host].modules.muc;
  162. module:log('info', 'Found(on loaded) main_muc_service: %s', main_muc_service);
  163. end
  164. end);
  165. end
  166. end);