mirror of
https://github.com/zulip/zulip.git
synced 2025-11-16 11:52:01 +00:00
Show user-uploaded avatars on the website.
Show user-uploaded avatars on the website for users who have UserProfile.avatar_source == 'U'. (Continue to show gravatars for other users.) This includes the home page, the visible-phone div, and the settings page. This fix does NOT address a few things: * There is no GUI to actually upload user images yet on the website. * The !gravatar syntax in bugdown will continue to show gravatar images only. * We are not changing identicon behavior. (imported from commit 9f5ac0bbe21ba56528048233aab2430e4dd431aa)
This commit is contained in:
@@ -99,6 +99,12 @@ SECRET_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
|
|||||||
# username generation.
|
# username generation.
|
||||||
HASH_SALT = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
|
HASH_SALT = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
|
||||||
|
|
||||||
|
# Use this salt to hash a user's email into a filename for their user-uploaded
|
||||||
|
# avatar. If this salt is discovered, attackers will only be able to determine
|
||||||
|
# that the owner of an email account has uploaded an avatar to Humbug, which isn't
|
||||||
|
# the end of the world. Don't use the salt where there is more security exposure.
|
||||||
|
AVATAR_SALT = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
|
||||||
|
|
||||||
# Tell the browser to never send our cookies without encryption, e.g.
|
# Tell the browser to never send our cookies without encryption, e.g.
|
||||||
# when executing the initial http -> https redirect.
|
# when executing the initial http -> https redirect.
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
<div class="upper_sidebar">
|
<div class="upper_sidebar">
|
||||||
<div class="brand">
|
<div class="brand">
|
||||||
<img class="img-rounded gravatar-profile"
|
<img class="img-rounded gravatar-profile"
|
||||||
src="https://secure.gravatar.com/avatar/{{ email_hash }}?d=identicon&s=60" />
|
src="{{ avatar_url }}&s=60" />
|
||||||
<span id="my_information">
|
<span id="my_information">
|
||||||
<span class="my_fullname">{{ user_profile.full_name }}</span><br />
|
<span class="my_fullname">{{ user_profile.full_name }}</span><br />
|
||||||
<span class="my_email">{{ user_profile.email }}</span>
|
<span class="my_email">{{ user_profile.email }}</span>
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<a class="brand skinny-user-gravatar visible-phone" href="#"
|
<a class="brand skinny-user-gravatar visible-phone" href="#"
|
||||||
title="{{user_profile.full_name}} - {{user_profile.email}}">
|
title="{{user_profile.full_name}} - {{user_profile.email}}">
|
||||||
<img class="img-rounded gravatar-profile"
|
<img class="img-rounded gravatar-profile"
|
||||||
src="https://secure.gravatar.com/avatar/{{ email_hash }}?d=identicon&s=30" />
|
src="{{ avatar_url }}&s=30" />
|
||||||
</a>
|
</a>
|
||||||
<div id="searchbox">
|
<div id="searchbox">
|
||||||
<form id="searchbox_form" class="form-search navbar-search">
|
<form id="searchbox_form" class="form-search navbar-search">
|
||||||
|
|||||||
@@ -68,8 +68,8 @@
|
|||||||
<label class="control-label">Your picture</label>
|
<label class="control-label">Your picture</label>
|
||||||
<div class="controls">
|
<div class="controls">
|
||||||
<a href="https://en.gravatar.com/emails" target="_blank" class="change_gravatar_button">
|
<a href="https://en.gravatar.com/emails" target="_blank" class="change_gravatar_button">
|
||||||
<p><img class="img-rounded gravatar-profile"
|
<p><img class="img-rounded gravatar-profile user-image-settings"
|
||||||
src="https://secure.gravatar.com/avatar/{{ email_hash }}?d=identicon&s=60" /></p>
|
src="{{ avatar_url }}&s=60" /></p>
|
||||||
<p>Change at Gravatar.com</p>
|
<p>Change at Gravatar.com</p>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
from django.conf import settings
|
||||||
|
|
||||||
import hashlib
|
import hashlib
|
||||||
from zephyr.lib.utils import make_safe_digest
|
from zephyr.lib.utils import make_safe_digest
|
||||||
@@ -11,3 +12,21 @@ def gravatar_hash(email):
|
|||||||
# typo an address or someone manages to give us a non-ASCII address, let's
|
# typo an address or someone manages to give us a non-ASCII address, let's
|
||||||
# not error out on it.
|
# not error out on it.
|
||||||
return make_safe_digest(email.lower(), hashlib.md5)
|
return make_safe_digest(email.lower(), hashlib.md5)
|
||||||
|
|
||||||
|
def user_avatar_hash(email):
|
||||||
|
# Salting the user_key may be overkill, but it prevents us from
|
||||||
|
# basically mimicking Gravatar's hashing scheme, which could lead
|
||||||
|
# to some abuse scenarios like folks using us as a free Gravatar
|
||||||
|
# replacement.
|
||||||
|
user_key = email.lower() + settings.AVATAR_SALT
|
||||||
|
return make_safe_digest(user_key, hashlib.sha1)
|
||||||
|
|
||||||
|
def avatar_url(user_profile):
|
||||||
|
if user_profile.avatar_source == 'U':
|
||||||
|
bucket = settings.S3_AVATAR_BUCKET
|
||||||
|
hash_key = user_avatar_hash(user_profile.email)
|
||||||
|
# ?x=x allows templates to append additional parameters with &s
|
||||||
|
return "https://%s.s3.amazonaws.com/%s?x=x" % (bucket, hash_key)
|
||||||
|
else:
|
||||||
|
hash_key = gravatar_hash(user_profile.email)
|
||||||
|
return "https://secure.gravatar.com/avatar/%s?d=identicon" % (hash_key,)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ from zephyr.lib.utils import make_safe_digest
|
|||||||
import os
|
import os
|
||||||
from django.db import transaction, IntegrityError
|
from django.db import transaction, IntegrityError
|
||||||
from zephyr.lib import bugdown
|
from zephyr.lib import bugdown
|
||||||
from zephyr.lib.avatar import gravatar_hash
|
from zephyr.lib.avatar import gravatar_hash, avatar_url
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.contrib.sessions.models import Session
|
from django.contrib.sessions.models import Session
|
||||||
from django.utils.html import escape
|
from django.utils.html import escape
|
||||||
@@ -333,7 +333,8 @@ class Message(models.Model):
|
|||||||
recipient_id = self.recipient.id,
|
recipient_id = self.recipient.id,
|
||||||
subject = self.subject,
|
subject = self.subject,
|
||||||
timestamp = datetime_to_timestamp(self.pub_date),
|
timestamp = datetime_to_timestamp(self.pub_date),
|
||||||
gravatar_hash = gravatar_hash(self.sender.email),
|
gravatar_hash = gravatar_hash(self.sender.email), # Deprecated June 2013
|
||||||
|
avatar_url = avatar_url(self.sender),
|
||||||
client = self.sending_client.name)
|
client = self.sending_client.name)
|
||||||
|
|
||||||
if self.last_edit_time != None:
|
if self.last_edit_time != None:
|
||||||
|
|||||||
@@ -59,7 +59,7 @@
|
|||||||
{{#include_sender}}
|
{{#include_sender}}
|
||||||
<span class="message_sender actions_hover">
|
<span class="message_sender actions_hover">
|
||||||
<div class="inline_profile_picture"
|
<div class="inline_profile_picture"
|
||||||
style="background-image: url('https://secure.gravatar.com/avatar/{{gravatar_hash}}?d=identicon&s=30?stamp={{stamp}}');"/>
|
style="background-image: url('{{avatar_url}}&s=30&stamp={{stamp}}');"/>
|
||||||
<span class="sender_name">{{sender_full_name}}</span>
|
<span class="sender_name">{{sender_full_name}}</span>
|
||||||
</span>
|
</span>
|
||||||
{{/include_sender}}
|
{{/include_sender}}
|
||||||
|
|||||||
@@ -1046,9 +1046,11 @@ class GetOldMessagesTest(AuthedTestCase):
|
|||||||
self.assertIsInstance(result["messages"], list)
|
self.assertIsInstance(result["messages"], list)
|
||||||
for message in result["messages"]:
|
for message in result["messages"]:
|
||||||
for field in ("content", "content_type", "display_recipient",
|
for field in ("content", "content_type", "display_recipient",
|
||||||
"gravatar_hash", "recipient_id", "sender_full_name",
|
"avatar_url", "recipient_id", "sender_full_name",
|
||||||
"sender_short_name", "timestamp"):
|
"sender_short_name", "timestamp"):
|
||||||
self.assertIn(field, message)
|
self.assertIn(field, message)
|
||||||
|
# TODO: deprecate soon in favor of avatar_url
|
||||||
|
self.assertIn('gravatar_hash', message)
|
||||||
|
|
||||||
def test_successful_get_old_messages(self):
|
def test_successful_get_old_messages(self):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ from zephyr.decorator import require_post, \
|
|||||||
JsonableError, RequestVariableMissingError, get_user_profile_by_email, \
|
JsonableError, RequestVariableMissingError, get_user_profile_by_email, \
|
||||||
authenticated_rest_api_view, process_as_post, REQ, rate_limit, rate_limit_user
|
authenticated_rest_api_view, process_as_post, REQ, rate_limit, rate_limit_user
|
||||||
from zephyr.lib.query import last_n
|
from zephyr.lib.query import last_n
|
||||||
from zephyr.lib.avatar import gravatar_hash
|
from zephyr.lib.avatar import avatar_url
|
||||||
from zephyr.lib.response import json_success, json_error, json_response, json_method_not_allowed, \
|
from zephyr.lib.response import json_success, json_error, json_response, json_method_not_allowed, \
|
||||||
render_to_response
|
render_to_response
|
||||||
from zephyr.lib.timestamp import datetime_to_timestamp
|
from zephyr.lib.timestamp import datetime_to_timestamp
|
||||||
@@ -580,7 +580,7 @@ def home(request):
|
|||||||
return render_to_response('zephyr/index.html',
|
return render_to_response('zephyr/index.html',
|
||||||
{'user_profile': user_profile,
|
{'user_profile': user_profile,
|
||||||
'page_params' : page_params,
|
'page_params' : page_params,
|
||||||
'email_hash' : gravatar_hash(user_profile.email),
|
'avatar_url': avatar_url(user_profile),
|
||||||
'show_debug':
|
'show_debug':
|
||||||
settings.DEBUG and ('show_debug' in request.GET),
|
settings.DEBUG and ('show_debug' in request.GET),
|
||||||
'show_invites': show_invites
|
'show_invites': show_invites
|
||||||
|
|||||||
Reference in New Issue
Block a user