Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow embedding by list of trusted referers when GLOBAL_LOGIN is enabled. #1093

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions cms/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,8 @@

# Comma separated list of domains: ["organization.com", "private.organization.com", "org2.com"]
# Empty list disables.
ALLOWED_DOMAINS_FOR_USER_REGISTRATION = []
ALLOWED_DOMAINS_FOR_USER_REGISTRATION = []


# django rest settings
REST_FRAMEWORK = {
Expand Down Expand Up @@ -459,6 +460,12 @@
# it is placed here so it can be overrided on local_settings.py
GLOBAL_LOGIN_REQUIRED = False

# When GLOBAL_LOGIN_REQUIRED is True, allow certain domains to embed the content.
# This is useful when you want to serve content on your servers but not allow general public access.
# You also must properly configure CORS origins for this to work.
# Should be a comma-separated list of domains.
GLOBAL_LOGIN_ALLOW_EMBED_DOMAINS = [] # ['my-refering-domain.com', 'cdn.my-site.com']

# TODO: separate settings on production/development more properly, for now
# this should be ok
CELERY_TASK_ALWAYS_EAGER = False
Expand Down Expand Up @@ -497,6 +504,11 @@
r'/accounts/confirm-email/.*/$',
r'/api/v[0-9]+/',
]
if (GLOBAL_LOGIN_ALLOW_EMBED_DOMAINS):
LOGIN_REQUIRED_IGNORE_PATHS += [
r'^/embed.*', # r'/embed\?m=.*$',
r'^/media/.*'
]

# if True, only show original, don't perform any action on videos
DO_NOT_TRANSCODE_VIDEO = False
Expand Down Expand Up @@ -538,4 +550,4 @@
SPRITE_NUM_SECS = 10
# number of seconds for sprite image.
# If you plan to change this, you must also follow the instructions on admin_docs.md
# to change the equivalent value in ./frontend/src/static/js/components/media-viewer/VideoViewer/index.js and then re-build frontend
# to change the equivalent value in ./frontend/src/static/js/components/media-viewer/VideoViewer/index.js and then re-build frontend
1 change: 1 addition & 0 deletions docs/admins_docs.md
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,7 @@ ADMINS_NOTIFICATIONS = {

- Make the portal workflow public, but at the same time set `GLOBAL_LOGIN_REQUIRED = True` so that only logged in users can see content.
- You can either set `REGISTER_ALLOWED = False` if you want to add members yourself or checkout options on "django-allauth settings" that affects registration in `cms/settings.py`. Eg set the portal invite only, or set email confirmation as mandatory, so that you control who registers.
- If you wish to have private media management, but allow trusted referers to embed the media for viewing, you can over-ride the global login requirement for embedded media on some sites by setting `GLOBAL_LOGIN_ALLOW_EMBED_DOMAINS = ['your-approved-domain.com', ...]`. This has the effect of checking the HTTP_REFERER domain in the request against the list of approved referers, and allowing the video to stream if there is a match. The videos you wish to embed must be set to unlisted or public in the media management, and the referring site or proxy must properly set the HTTP_REFERER header to an approved domain. You may also need to properly set or update CORS_ALLOWED_ORIGINS headers depending on your specific configuration and cross-site requirements. Depending on your use-case, you may need to patch the default player auto-play and share links to get a suitable plain-jane video feed.

### 5.24 Enable the sitemap

Expand Down
1 change: 0 additions & 1 deletion files/frontend_translations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ def check_language_code(language_code):
replacement_strings[language_code] = tr_module.replacement_strings



def get_translation(language_code):
# get list of translations per language
if not check_language_code(language_code):
Expand Down
4 changes: 2 additions & 2 deletions files/management/commands/process_translations.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ def process_translation_files(self, translations_dir):
with open(file_path, 'w') as f:
f.write("translation_strings = {\n")
for key, value in translation_strings_wip.items():
f.write(f' "{key}": "{value}",\n')
f.write(f' "{key}": "{value}", \n')
f.write("}\n\n")

f.write("replacement_strings = {\n")
for key, value in replacement_strings_wip.items():
f.write(f' "{key}": "{value}",\n')
f.write(f' "{key}": "{value}", \n')
f.write("}\n")

self.stdout.write(self.style.SUCCESS(f'Processed {file}'))
13 changes: 13 additions & 0 deletions files/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
)
from .stop_words import STOP_WORDS
from .tasks import save_user_action
from urllib.parse import urlparse

VALID_USER_ACTIONS = [action for action, name in USER_MEDIA_ACTIONS]

Expand Down Expand Up @@ -207,6 +208,18 @@ def embed_media(request):
if not media:
return HttpResponseRedirect("/")

try:
if (settings.GLOBAL_LOGIN_REQUIRED and hasattr(settings, 'GLOBAL_LOGIN_ALLOW_EMBED_DOMAINS') and settings.GLOBAL_LOGIN_ALLOW_EMBED_DOMAINS):
if request.META.get('HTTP_REFERER'):
referring_domain = urlparse(request.META['HTTP_REFERER']).hostname
if (not referring_domain) or (referring_domain not in settings.GLOBAL_LOGIN_ALLOW_EMBED_DOMAINS):
raise PermissionDenied("HTTP referer not permitted.")
else:
raise PermissionDenied("HTTP referer not set.")

except PermissionDenied:
return render(request, "cms/embed-403.html")

context = {}
context["media"] = friendly_token
return render(request, "cms/embed.html", context)
Expand Down
39 changes: 39 additions & 0 deletions templates/cms/embed-403.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<body>
<style>
.fakePlayer {
background-color: #242424;
position: absolute;
top: 0px;
left: 0px;
right: 0px;
bottom: 0px;
padding: 0px;
color: white;
width: auto;
height: auto;
text-align: center;
}
.center {
margin: 0;
position: absolute;
top: 50%;
left: 0px;
right: 0px;
-ms-transform: translate(0,-50%);
transform: translate(0,-50%);
text-align: center;
}
</style>
<div class="fakePlayer">
<div class="center">
<p> 403 - Forbidden </p>
<p>
<svg xmlns="http://www.w3.org/2000/svg" width="85" height="85" fill="currentColor" class="bi bi-x" viewBox="0 0 16 16">
<path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708"/>
</svg>
</p>
<p>Embedded media is not permitted from this referer.</p>
<p> If this is a preview, please save your content to see the video.</p>
</div>
</div>
</body>
4 changes: 2 additions & 2 deletions users/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ def get_email_confirmation_url_stub(self, request, emailconfirmation):
return settings.SSL_FRONTEND_HOST + url

def clean_email(self, email):
if hasattr(settings,"ALLOWED_DOMAINS_FOR_USER_REGISTRATION") and settings.ALLOWED_DOMAINS_FOR_USER_REGISTRATION:
if hasattr(settings, "ALLOWED_DOMAINS_FOR_USER_REGISTRATION") and settings.ALLOWED_DOMAINS_FOR_USER_REGISTRATION:
if email.split("@")[1] not in settings.ALLOWED_DOMAINS_FOR_USER_REGISTRATION:
raise ValidationError("Domain is not in the permitted list")

if email.split("@")[1] in settings.RESTRICTED_DOMAINS_FOR_USER_REGISTRATION:
raise ValidationError("Domain is restricted from registering")
return email
Expand Down
Loading