Skip to content

Commit 5995e5d

Browse files
committed
Adds anonymous users
1 parent 204a004 commit 5995e5d

File tree

2 files changed

+124
-4
lines changed

2 files changed

+124
-4
lines changed

jupyter_server/auth/identity.py

+17-4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import binascii
1111
import datetime
12+
import json
1213
import os
1314
import re
1415
import sys
@@ -24,6 +25,7 @@
2425
from jupyter_server.transutils import _i18n
2526

2627
from .security import passwd_check, set_password
28+
from .utils import get_anonymous_username, get_random_color
2729

2830
# circular imports for type checking
2931
if TYPE_CHECKING:
@@ -290,11 +292,19 @@ def user_to_cookie(self, user: User) -> str:
290292
Default is just the user's username.
291293
"""
292294
# default: username is enough
293-
return user.username
295+
cookie = json.dumps({
296+
'username': user.username,
297+
'name': user.name,
298+
'display_name': user.display_name,
299+
'initials': user.initials,
300+
'color': user.color
301+
})
302+
return cookie
294303

295304
def user_from_cookie(self, cookie_value: str) -> User | None:
296305
"""Inverse of user_to_cookie"""
297-
return User(username=cookie_value)
306+
user = json.loads(cookie_value)
307+
return User(user['username'], user['name'], user['display_name'], user['initials'], None, user['color'])
298308

299309
def get_cookie_name(self, handler: JupyterHandler) -> str:
300310
"""Return the login cookie name
@@ -396,7 +406,6 @@ def get_token(self, handler: JupyterHandler) -> str | None:
396406
- in URL parameters: ?token=<token>
397407
- in header: Authorization: token <token>
398408
"""
399-
400409
user_token = handler.get_argument("token", "")
401410
if not user_token:
402411
# get it from Authorization header
@@ -447,8 +456,12 @@ def generate_anonymous_user(self, handler: JupyterHandler) -> User:
447456
but does not identify a user.
448457
"""
449458
user_id = uuid.uuid4().hex
459+
moon = get_anonymous_username()
460+
name = display_name = "Anonymous {}".format(moon)
461+
initials = "A{}".format(moon[0])
462+
color = get_random_color()
450463
handler.log.info(f"Generating new user for token-authenticated request: {user_id}")
451-
return User(user_id)
464+
return User(user_id, name, display_name, initials, None, color)
452465

453466
def should_check_origin(self, handler: JupyterHandler) -> bool:
454467
"""Should the Handler check for CORS origin validation?

jupyter_server/auth/utils.py

+107
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
# Distributed under the terms of the Modified BSD License.
55
import importlib
66
import re
7+
import math
8+
import random
79
import warnings
810

911

@@ -74,3 +76,108 @@ def match_url_to_resource(url, regex_mapping=None):
7476
pattern = re.compile(regex)
7577
if pattern.fullmatch(url):
7678
return auth_resource
79+
80+
# From https://en.wikipedia.org/wiki/Moons_of_Jupiter
81+
moons_of_jupyter = [
82+
'Metis',
83+
'Adrastea',
84+
'Amalthea',
85+
'Thebe',
86+
'Io',
87+
'Europa',
88+
'Ganymede',
89+
'Callisto',
90+
'Themisto',
91+
'Leda',
92+
'Ersa',
93+
'Pandia',
94+
'Himalia',
95+
'Lysithea',
96+
'Elara',
97+
'Dia',
98+
'Carpo',
99+
'Valetudo',
100+
'Euporie',
101+
'Eupheme',
102+
# 'S/2003 J 18',
103+
# 'S/2010 J 2',
104+
'Helike',
105+
# 'S/2003 J 16',
106+
# 'S/2003 J 2',
107+
'Euanthe',
108+
# 'S/2017 J 7',
109+
'Hermippe',
110+
'Praxidike',
111+
'Thyone',
112+
'Thelxinoe',
113+
# 'S/2017 J 3',
114+
'Ananke',
115+
'Mneme',
116+
# 'S/2016 J 1',
117+
'Orthosie',
118+
'Harpalyke',
119+
'Iocaste',
120+
# 'S/2017 J 9',
121+
# 'S/2003 J 12',
122+
# 'S/2003 J 4',
123+
'Erinome',
124+
'Aitne',
125+
'Herse',
126+
'Taygete',
127+
# 'S/2017 J 2',
128+
# 'S/2017 J 6',
129+
'Eukelade',
130+
'Carme',
131+
# 'S/2003 J 19',
132+
'Isonoe',
133+
# 'S/2003 J 10',
134+
'Autonoe',
135+
'Philophrosyne',
136+
'Cyllene',
137+
'Pasithee',
138+
# 'S/2010 J 1',
139+
'Pasiphae',
140+
'Sponde',
141+
# 'S/2017 J 8',
142+
'Eurydome',
143+
# 'S/2017 J 5',
144+
'Kalyke',
145+
'Hegemone',
146+
'Kale',
147+
'Kallichore',
148+
# 'S/2011 J 1',
149+
# 'S/2017 J 1',
150+
'Chaldene',
151+
'Arche',
152+
'Eirene',
153+
'Kore',
154+
# 'S/2011 J 2',
155+
# 'S/2003 J 9',
156+
'Megaclite',
157+
'Aoede',
158+
# 'S/2003 J 23',
159+
'Callirrhoe',
160+
'Sinope'
161+
]
162+
163+
def get_anonymous_username() -> str:
164+
"""
165+
Get a random user-name based on the moons of Jupyter.
166+
This function returns names like "Anonymous Io" or "Anonymous Metis".
167+
"""
168+
return moons_of_jupyter[random.randint(0, len(moons_of_jupyter)-1)]
169+
170+
# Using JupyterLab CSS variable because the colors may change with the theme
171+
user_colors = [
172+
'var(--jp-collaborator-color1)',
173+
'var(--jp-collaborator-color2)',
174+
'var(--jp-collaborator-color3)',
175+
'var(--jp-collaborator-color4)',
176+
'var(--jp-collaborator-color5)',
177+
'var(--jp-collaborator-color6)',
178+
'var(--jp-collaborator-color7)'
179+
]
180+
181+
def get_random_color() -> str:
182+
""" Get a random color from the list of colors. """
183+
return user_colors[random.randint(0, len(user_colors)-1)];

0 commit comments

Comments
 (0)