bbbctl 0.1.0__tar.gz → 0.3.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bbbctl
3
- Version: 0.1.0
3
+ Version: 0.3.0
4
4
  Summary: BigBlueButton API command-line client
5
5
  Home-page: https://github.com/defnull/bbbctl
6
6
  Author: Marcel Hellkamp
@@ -1,6 +1,6 @@
1
1
  [metadata]
2
2
  name = bbbctl
3
- version = 0.1.0
3
+ version = 0.3.0
4
4
  author = Marcel Hellkamp
5
5
  author_email = marc@gsites.de
6
6
  description = BigBlueButton API command-line client
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: bbbctl
3
- Version: 0.1.0
3
+ Version: 0.3.0
4
4
  Summary: BigBlueButton API command-line client
5
5
  Home-page: https://github.com/defnull/bbbctl
6
6
  Author: Marcel Hellkamp
@@ -6,10 +6,9 @@ import urllib.parse
6
6
  import hashlib
7
7
  import sys, os
8
8
  import xml.etree.ElementTree as ET
9
- from xml.dom import minidom
10
9
  import json
11
10
  import datetime
12
- import re
11
+ import ssl
13
12
 
14
13
  __all__ = ["BBBApiClient", "ApiError"]
15
14
 
@@ -23,9 +22,10 @@ class ApiError(RuntimeError):
23
22
 
24
23
 
25
24
  class BBBApiClient:
26
- def __init__(self, api, secret):
25
+ def __init__(self, api, secret, ssl_context=None):
27
26
  self.api = api.rstrip("/")
28
27
  self.secret = secret
28
+ self.ssl = ssl_context or ssl.create_default_context()
29
29
 
30
30
  def makeurl(self, command, **query):
31
31
  query = urllib.parse.urlencode(query)
@@ -39,7 +39,7 @@ class BBBApiClient:
39
39
 
40
40
  def call(self, command, **query):
41
41
  url = self.makeurl(command, **query)
42
- with urllib.request.urlopen(url) as f:
42
+ with urllib.request.urlopen(url, context=self.ssl) as f:
43
43
  xml = f.read().decode("utf8")
44
44
  root = ET.fromstring(xml)
45
45
  if root.find("./returncode").text != "SUCCESS":
@@ -84,6 +84,10 @@ def build_parser():
84
84
  "--secret",
85
85
  help="API secretd (default: BBBCTL_SECRET or local config)",
86
86
  )
87
+ parser.add_argument(
88
+ "--insecure",
89
+ help="Skip TLS verification and accept self-signed or invalid SSL certificates as if they were valid",
90
+ )
87
91
 
88
92
  parser.add_argument(
89
93
  "--format",
@@ -125,7 +129,7 @@ def build_parser():
125
129
 
126
130
  cmd = meet_sub.add_parser("list", help="List meetings")
127
131
  cmd.add_argument("--sort", help="Sort by a specific key")
128
- cmd.add_argument("--no-user", action="store_true", help="Do not show participatns")
132
+ cmd.add_argument("--no-user", action="store_true", help="Do not show participants")
129
133
  cmd.set_defaults(cmd=cmd_meet_list)
130
134
 
131
135
  cmd = meet_sub.add_parser("info", help="Show meeting details")
@@ -135,10 +139,10 @@ def build_parser():
135
139
  cmd = meet_sub.add_parser("create", help="Create meeting")
136
140
  cmd.add_argument("id", help="Meeting ID")
137
141
  cmd.add_argument("name", help="Meeting name")
138
- cmd.add_argument("--record", help="Allow recodring?", action="store_true")
142
+ cmd.add_argument("--record", help="Allow recording?", action="store_true")
139
143
  cmd.add_argument(
140
144
  "--mod",
141
- help="Directly create and print a join link for this username. Can be repeated.",
145
+ help="Directly create and print a moderator join link for this username. Can be repeated.",
142
146
  action="append",
143
147
  )
144
148
  cmd.set_defaults(cmd=cmd_meet_create)
@@ -161,7 +165,8 @@ def build_parser():
161
165
  cmd.set_defaults(cmd=cmd_meet_end)
162
166
 
163
167
  cmd = meet_sub.add_parser("nuke", help="End ALL meeting")
164
- cmd.add_argument("--doit", help="Really end all meetings?", action="store_true")
168
+ cmd.add_argument("--doit", help="Disable dry-run mode and actually end meetings?", action="store_true")
169
+ cmd.add_argument("--ask", help="Ask for every meeting?", action="store_true")
165
170
  cmd.set_defaults(cmd=cmd_meet_nuke)
166
171
 
167
172
  return parser
@@ -176,6 +181,7 @@ config_paths = [
176
181
  "/etc/bigbluebutton/bbb-web.properties",
177
182
  "/usr/share/bbb-web/WEB-INF/classes/bigbluebutton.properties",
178
183
  "/var/lib/tomcat7/webapps/bigbluebutton/WEB-INF/classes/bigbluebutton.properties",
184
+ "./bbbctl.conf",
179
185
  ]
180
186
 
181
187
 
@@ -213,12 +219,17 @@ def main():
213
219
  )
214
220
 
215
221
  server = server.rstrip("/")
216
- if '://' not in server:
222
+ if "://" not in server:
217
223
  server = "https://" + server
218
224
  if not server.endswith("/bigbluebutton/api"):
219
225
  server += "/bigbluebutton/api"
220
226
 
221
- client = BBBApiClient(server, secret)
227
+ ctx = ssl.create_default_context()
228
+ if args.insecure:
229
+ ctx.check_hostname = False
230
+ ctx.verify_mode = ssl.CERT_NONE
231
+
232
+ client = BBBApiClient(server, secret, ssl_context=ctx)
222
233
 
223
234
  try:
224
235
  args.cmd(client, args)
@@ -249,7 +260,7 @@ def format_human(e, indent=""):
249
260
  result = indent + e.tag + ":"
250
261
  if e.tag.lower() in ("starttime", "endtime"):
251
262
  value = "%s (%s)" % (
252
- datetime.datetime.utcfromtimestamp(float(value) / 1000),
263
+ datetime.datetime.fromtimestamp(float(value) / 1000, datetime.timezone.utc),
253
264
  value,
254
265
  )
255
266
  if value:
@@ -278,7 +289,19 @@ def format_json(e, *a, **ka):
278
289
 
279
290
 
280
291
  _should_be_list = ["attendees"]
281
- _should_be_number = ["createTime", "duration", "startTime", "endTime", "participantCount", "listenerCount", "voiceParticipantCount", "videoCount", "maxUsers", "moderatorCount"]
292
+ _should_be_number = [
293
+ "createTime",
294
+ "duration",
295
+ "startTime",
296
+ "endTime",
297
+ "participantCount",
298
+ "listenerCount",
299
+ "voiceParticipantCount",
300
+ "videoCount",
301
+ "maxUsers",
302
+ "moderatorCount",
303
+ ]
304
+
282
305
 
283
306
  def _unpack_xml(e):
284
307
  if e.tag in _should_be_list:
@@ -290,8 +313,8 @@ def _unpack_xml(e):
290
313
  return int(value)
291
314
  if not value:
292
315
  return None
293
- if value in ('true', 'false'):
294
- return value == 'true'
316
+ if value in ("true", "false"):
317
+ return value == "true"
295
318
  return value
296
319
 
297
320
 
@@ -351,7 +374,8 @@ def cmd_meet_create(api, args):
351
374
  link = api.getJoinLink(
352
375
  meetingID=args.id,
353
376
  fullName=name,
354
- password=created.find("moderatorPW").text,
377
+ createTime=created.find("createTime").text,
378
+ role="MODERATOR",
355
379
  )
356
380
  print(name + ":", link)
357
381
 
@@ -365,6 +389,7 @@ def cmd_meet_join(api, args):
365
389
 
366
390
  if args.open:
367
391
  import webbrowser
392
+
368
393
  webbrowser.open_new_tab(link)
369
394
  else:
370
395
  print(link)
@@ -378,11 +403,6 @@ def cmd_meet_end(api, args):
378
403
  def cmd_meet_nuke(api, args):
379
404
  meetings = list(api.getMeetings())
380
405
  for meeting in meetings:
381
- if args.doit:
382
- api.end(
383
- meetingID=meeting.find("meetingID").text,
384
- password=meeting.find("moderatorPW").text,
385
- )
386
406
  print(
387
407
  "{dryrun}id={id} user={users} name={name!r}".format(
388
408
  dryrun="" if args.doit else "(dry run) ",
@@ -391,6 +411,16 @@ def cmd_meet_nuke(api, args):
391
411
  name=meeting.find("meetingName").text,
392
412
  )
393
413
  )
414
+ if args.doit:
415
+ if args.ask:
416
+ answer = input("End this meeting? [Yna] ").strip().lower()
417
+ if answer == "a":
418
+ args.ask = False
419
+ elif answer in ("", "y"):
420
+ pass
421
+ else:
422
+ continue
423
+ api.end(meetingID=meeting.find("meetingID").text)
394
424
 
395
425
 
396
426
  if __name__ == "__main__":
File without changes
File without changes
File without changes