Skip to content

Commit 7f5e7c4

Browse files
webjunkie01dill0wn
authored andcommitted
[#8595] add new function to hide/redact email addresses and also shorten the acces tokens that appear printed in the logs
1 parent 3379bfd commit 7f5e7c4

File tree

3 files changed

+60
-6
lines changed

3 files changed

+60
-6
lines changed

Allura/allura/controllers/rest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ def save_request_token(self, token: dict, request: oauthlib.common.Request) -> N
158158
callback=request.oauth_params.get('oauth_callback', 'oob'),
159159
)
160160
session(req_token).flush()
161-
log.info('Saving new request token with key: %s', req_token.api_key)
161+
log.info('Saving new request token with key: %s', req_token.api_key[:(len(req_token.api_key) // 2)])
162162

163163
def verify_request_token(self, token: str, request: oauthlib.common.Request) -> bool:
164164
return M.OAuthRequestToken.query.get(api_key=token) is not None
@@ -477,7 +477,7 @@ def authorize(self, **kwargs):
477477

478478
rtok = M.OAuthRequestToken.query.get(api_key=oauth_token)
479479
if rtok is None:
480-
log.error('Invalid token %s', oauth_token)
480+
log.error('Invalid token %s', oauth_token[:(len(oauth_token) // 2)])
481481
raise exc.HTTPUnauthorized
482482
# store what user this is, so later use of the token can act as them
483483
rtok.user_id = c.user._id

Allura/allura/lib/utils.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -882,3 +882,57 @@ def join_paths_no_traversal(base: str | Path, *paths: str | Path) -> str:
882882

883883
def pkg_file(pkg_name: str, *paths: str) -> str:
884884
return join_paths_no_traversal(importlib.resources.files(pkg_name), *paths)
885+
886+
887+
def hide_email(email_or_match: str | re.Match | Iterable[str] | None) -> str:
888+
hide_name_re = re.compile(r'(\w{2,}.\s+)')
889+
hide_email_re = re.compile(r'<?([_a-zA-Z0-9+.=-]+)@([a-zA-Z0-9-]{2}).*>?')
890+
hide_email_cleanup_re = re.compile(r'"|=\?.+\?=')
891+
"""
892+
Emails passed to this method may or may not include brackets, but it
893+
can't be inferred from just that whether or not they *should* have brackets
894+
in the place where it'll be displayed. So, use the optional kwarg to make that explicit.
895+
Possible places include the mailman heading table and the body of individual messages.
896+
"""
897+
def erepl(m):
898+
uname = m.group(1)
899+
truncate = 2 if len(uname) <= 7 else 3
900+
res = '{}...@{}...'.format(m.group(1)[:truncate], m.group(2))
901+
if ensure_brackets and not res.startswith('<'):
902+
res = f"<{res}>"
903+
return res
904+
905+
def hide(email_address):
906+
email = hide_email_re.sub(erepl, email_address)
907+
email = hide_email_cleanup_re.sub('', email)
908+
return email
909+
910+
def name_tpl(m):
911+
return f'{m.group(1)[:1]}. '
912+
913+
def hide_name(email_address):
914+
str_pieces = email_address.split(' ')
915+
if len(str_pieces) == 1:
916+
return email_address
917+
first_name = str_pieces[0]
918+
email_address = email_address.replace(first_name, '', 1)
919+
result = hide_name_re.sub(name_tpl, email_address)
920+
return f'{first_name}{result}'
921+
922+
if not email_or_match:
923+
return ''
924+
925+
ensure_brackets = False
926+
if isinstance(email_or_match, re.Match):
927+
email = email_or_match.group(0)
928+
elif isinstance(email_or_match, str):
929+
ensure_brackets = True
930+
email = email_or_match
931+
else:
932+
emails = []
933+
for address in email_or_match:
934+
email = hide(address)
935+
emails.append(email)
936+
return ', '.join(emails)
937+
email = hide_name(email)
938+
email = hide(email)

Allura/allura/model/auth.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ def set_nonce_hash(self):
171171

172172
def send_verification_link(self):
173173
self.set_nonce_hash()
174-
log.info('Sending verification link to %s', self.email)
174+
log.info('Sending verification link to %s', utils.hide_email(self.email))
175175
text = '''
176176
To verify the email address {} belongs to the user {},
177177
please visit the following URL:
@@ -181,7 +181,7 @@ def send_verification_link(self):
181181
self.claimed_by_user(include_pending=True).username,
182182
h.absurl(f'/auth/verify_addr?a={h.urlquote(self.nonce)}'),
183183
)
184-
log.info('Verification email:\n%s', text)
184+
log.info('Verification email:\n%s', utils.hide_email(self.email))
185185
allura.tasks.mail_tasks.sendsimplemail.post(
186186
fromaddr=g.noreply,
187187
reply_to=g.noreply,
@@ -452,7 +452,7 @@ def send_password_reset_email(self, email_address=None, subject_tmpl='{site_name
452452
email_address = self.get_pref('email_address')
453453
reset_url = self.make_password_reset_url()
454454

455-
log.info('Sending password recovery link to %s', email_address)
455+
log.info('Sending password recovery link to %s', utils.hide_email(email_address))
456456
subject = subject_tmpl.format(site_name=config['site_name'])
457457
text = g.jinja2_env.get_template('allura:templates/mail/forgot_password.txt').render(dict(
458458
user=self,
@@ -733,7 +733,7 @@ def by_email_address(cls, addr, only_confirmed=True):
733733
users = [u for u in users if u is not None]
734734
if len(users) > 1:
735735
log.warning('Multiple active users matching confirmed email: %s %s. '
736-
'Using first one', [u.username for u in users], addr)
736+
'Using first one', [u.username for u in users], utils.hide_email(addr))
737737
return users[0] if len(users) > 0 else None
738738

739739
@classmethod

0 commit comments

Comments
 (0)