Skip to content

Commit

Permalink
first pass at v2 topics token
Browse files Browse the repository at this point in the history
  • Loading branch information
mwfarb committed Aug 8, 2024
1 parent e48ecbb commit 7bbecaf
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 29 deletions.
164 changes: 136 additions & 28 deletions users/mqtt.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ def generate_arena_token(
ns_scene=None,
ns_device=None,
ids=None,
duration=DEF_JWT_DURATION
duration=DEF_JWT_DURATION,
# TODO(mwfarb): /mqtt_auth/ is versioned now, but need to correct upstream version for all request types
version=API_V1,
):
""" MQTT Token Constructor.
Expand Down Expand Up @@ -101,22 +103,32 @@ def generate_arena_token(
payload["room"] = roomname

# ns_scene, ns_device can/must contain only one '/'
namespace = scene = device = None
namespace = sceneid = deviceid = None
if ns_scene:
parts = ns_scene.split("/")
if len(parts) != 2:
return None
namespace = parts[0]
scene = parts[1]
sceneid = parts[1]
elif ns_device:
parts = ns_device.split("/")
if len(parts) != 2:
return None
namespace = parts[0]
device = parts[1]
deviceid = parts[1]

pubs, subs = pubsub_api_v1(
user, username, realm, namespace, scene, device, ids, perm)
# api-versioned topics
if version == API_V2:
pubs, subs = pubsub_api_v2(
user, username, realm, namespace, sceneid, deviceid, ids, perm)
else:
pubs, subs = pubsub_api_v1(
user, username, realm, namespace, sceneid, deviceid, ids, perm)

# non-api-versioned topics
# network graph
subs.append("$NETWORK")
pubs.append("$NETWORK/latency")

if len(subs) > 0:
payload["subs"] = clean_topics(subs)
Expand All @@ -131,29 +143,30 @@ def pubsub_api_v1(
username,
realm,
namespace,
scene,
device,
sceneid,
deviceid,
ids,
perm,
):
""" V1 Topic Notes:
Does _NOT_ use ./topics.py
/s/: virtual scene objects
/d/: device inter-process
/env/: physical environment detection
"""
pubs = []
subs = []
# everyone should be able to read all public scenes
if not device: # scene token scenario
if not deviceid: # scene token scenario
subs.append(f"{realm}/s/{PUBLIC_NAMESPACE}/#")
# And transmit env data
pubs.append(f"{realm}/env/{PUBLIC_NAMESPACE}/#")
# user presence objects
if user.is_authenticated:
if device: # device token scenario
if deviceid: # device token scenario
# device owners have rights to their device objects only
subs.append(f"{realm}/d/{namespace}/{device}/#")
pubs.append(f"{realm}/d/{namespace}/{device}/#")
subs.append(f"{realm}/d/{namespace}/{deviceid}/#")
pubs.append(f"{realm}/d/{namespace}/{deviceid}/#")
else: # scene token scenario
# scene rights default by namespace
if user.is_staff:
Expand All @@ -164,8 +177,8 @@ def pubsub_api_v1(
subs.append(f"{realm}/env/#")
pubs.append(f"{realm}/env/#")
# vio experiments, staff only
if scene:
pubs.append(f"{realm}/vio/{namespace}/{scene}/#")
if sceneid:
pubs.append(f"{realm}/vio/{namespace}/{sceneid}/#")
else:
# scene owners have rights to their scene objects only
subs.append(f"{realm}/s/{username}/#")
Expand All @@ -176,7 +189,7 @@ def pubsub_api_v1(
# add scenes that have been granted by other owners
u_scenes = Scene.objects.filter(editors=user)
for u_scene in u_scenes:
if not scene or (scene and u_scene.name == f"{namespace}/{scene}"):
if not sceneid or (sceneid and u_scene.name == f"{namespace}/{sceneid}"):
subs.append(f"{realm}/s/{u_scene.name}/#")
pubs.append(f"{realm}/s/{u_scene.name}/#")
subs.append(f"{realm}/env/{u_scene.name}/#")
Expand All @@ -191,24 +204,25 @@ def pubsub_api_v1(
subs.append(f"{realm}/d/{username}/#")
pubs.append(f"{realm}/d/{username}/#")
# anon/non-owners have rights to view scene objects only
if scene and not user.is_staff:
if sceneid and not user.is_staff:
# did the user set specific public read or public write?
if not user.is_authenticated and not perm["anonymous_users"]:
return None # anonymous not permitted
if perm["public_read"]:
subs.append(f"{realm}/s/{namespace}/{scene}/#")
subs.append(f"{realm}/s/{namespace}/{sceneid}/#")
# Interactivity to extent of viewing objects is similar to publishing env
pubs.append(f"{realm}/env/{namespace}/{scene}/#")
pubs.append(f"{realm}/env/{namespace}/{sceneid}/#")
if perm["public_write"]:
pubs.append(f"{realm}/s/{namespace}/{scene}/#")
pubs.append(f"{realm}/s/{namespace}/{sceneid}/#")
# user presence objects
if ids and perm["users"]: # probable web browser write
pubs.append(f"{realm}/s/{namespace}/{scene}/{ids['camid']}")
pubs.append(f"{realm}/s/{namespace}/{scene}/{ids['camid']}/#")
pubs.append(f"{realm}/s/{namespace}/{scene}/{ids['handleftid']}")
pubs.append(f"{realm}/s/{namespace}/{scene}/{ids['handrightid']}")
pubs.append(f"{realm}/s/{namespace}/{sceneid}/{ids['camid']}")
pubs.append(f"{realm}/s/{namespace}/{sceneid}/{ids['camid']}/#")
pubs.append(f"{realm}/s/{namespace}/{sceneid}/{ids['handleftid']}")
pubs.append(
f"{realm}/s/{namespace}/{sceneid}/{ids['handrightid']}")
# chat messages
if scene and ids and perm["users"]:
if sceneid and ids and perm["users"]:
userhandle = ids["userid"] + \
base64.b64encode(ids["userid"].encode()).decode()
# receive private messages: Read
Expand All @@ -220,15 +234,109 @@ def pubsub_api_v1(
# private messages to user: Write
pubs.append(f"{realm}/c/{namespace}/p/+/{userhandle}")
# apriltags
if scene:
if sceneid:
subs.append(f"{realm}/g/a/#")
pubs.append(f"{realm}/g/a/#")
# arts runtime-mngr
subs.append(f"{realm}/proc/#")
pubs.append(f"{realm}/proc/#")
# network graph
subs.append("$NETWORK")
pubs.append("$NETWORK/latency")

return pubs, subs


def pubsub_api_v2(
user,
username,
realm,
namespace,
sceneid,
deviceid,
ids,
perm,
):
""" V2 Topic Notes:
See ./topics.py
"""
# TODO: Reference api v2 version topics from topics.py.
pubs = []
subs = []
# everyone should be able to read all public scenes
if not deviceid: # scene token scenario
subs.append(f"{realm}/s/{PUBLIC_NAMESPACE}/o/#")
# And transmit env data
pubs.append(f"{realm}/e/{PUBLIC_NAMESPACE}/#")
# user presence objects
if user.is_authenticated:
if deviceid: # device token scenario
# device owners have rights to their device objects only
subs.append(f"{realm}/d/{namespace}/{deviceid}/#")
pubs.append(f"{realm}/d/{namespace}/{deviceid}/#")
else: # scene token scenario
# scene rights default by namespace
if user.is_staff:
# staff/admin have rights to all scene objects
subs.append(f"{realm}/s/#")
pubs.append(f"{realm}/s/#")
# env data for all scenes
subs.append(f"{realm}/e/#")
pubs.append(f"{realm}/e/#")
# vio experiments, staff only
if sceneid:
pubs.append(f"{realm}/vio/{namespace}/{sceneid}/#")
else:
# scene owners have rights to their scene objects only
subs.append(f"{realm}/s/{username}/#")
pubs.append(f"{realm}/s/{username}/#")
# scene owners have rights to their scene env only
subs.append(f"{realm}/e/{username}/#")
pubs.append(f"{realm}/e/{username}/#")
# add scenes that have been granted by other owners
u_scenes = Scene.objects.filter(editors=user)
for u_scene in u_scenes:
if not sceneid or (sceneid and u_scene.name == f"{namespace}/{sceneid}"):
subs.append(f"{realm}/s/{u_scene.name}/#")
pubs.append(f"{realm}/s/{u_scene.name}/#")
subs.append(f"{realm}/e/{u_scene.name}/#")
pubs.append(f"{realm}/e/{u_scene.name}/#")
# device rights default by namespace
if user.is_staff:
# staff/admin have rights to all device objects
subs.append(f"{realm}/d/#")
pubs.append(f"{realm}/d/#")
else:
# device owners have rights to their device objects only
subs.append(f"{realm}/d/{username}/#")
pubs.append(f"{realm}/d/{username}/#")
# anon/non-owners have rights to view scene objects only
if sceneid and not user.is_staff:
# did the user set specific public read or public write?
if not user.is_authenticated and not perm["anonymous_users"]:
return None # anonymous not permitted
if perm["public_read"]:
subs.append(f"{realm}/s/{namespace}/{sceneid}/#")
# Interactivity to extent of viewing objects is similar to publishing env
pubs.append(f"{realm}/e/{namespace}/{sceneid}/#")
if perm["public_write"]:
pubs.append(f"{realm}/s/{namespace}/{sceneid}/#")
# user presence objects
if ids and perm["users"]: # probable web browser write
pubs.append(f"{realm}/s/{namespace}/{sceneid}/u/{ids['camid']}")
pubs.append(
f"{realm}/s/{namespace}/{sceneid}/u/{ids['handleftid']}")
pubs.append(
f"{realm}/s/{namespace}/{sceneid}/u/{ids['handrightid']}")
# presence/chat
if sceneid and ids and perm["users"]:
subs.append(f"{realm}/c/{namespace}/x/+")
subs.append(f"{realm}/c/{namespace}/x/+/{ids['userid']}/#")
pubs.append(f"{realm}/c/{namespace}/x/{ids['userid']}/#")
subs.append(f"{realm}/c/{namespace}/c/+")
subs.append(f"{realm}/c/{namespace}/c/+/{ids['userid']}/#")
pubs.append(f"{realm}/c/{namespace}/c/{ids['userid']}/#")
# runtime manager
subs.append(f"{realm}/proc/#")
pubs.append(f"{realm}/proc/#")

return pubs, subs


Expand Down
3 changes: 2 additions & 1 deletion users/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,8 @@ def arena_token(request):
realm=request.POST.get("realm", None),
ns_scene=request.POST.get("scene", None),
ids=ids,
duration=duration
duration=duration,
version=request.version
)
if not token:
return JsonResponse(
Expand Down

0 comments on commit 7bbecaf

Please sign in to comment.