Skip to content

Commit

Permalink
Merge pull request #736 from readthedocs/davidfischer/publisher-allow…
Browse files Browse the repository at this point in the history
…ed-domains

Publisher allowed domains
  • Loading branch information
davidfischer committed Apr 28, 2023
2 parents 70e158d + fe57f89 commit b512e87
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 0 deletions.
23 changes: 23 additions & 0 deletions adserver/migrations/0082_publisher_allowed_domains.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 3.2.18 on 2023-04-18 16:54
from django.db import migrations
from django.db import models


class Migration(migrations.Migration):

dependencies = [
('adserver', '0081_rollout_ad_prioritization_pacing'),
]

operations = [
migrations.AddField(
model_name='historicalpublisher',
name='allowed_domains',
field=models.CharField(blank=True, default='', help_text="A space separated list of domains where the publisher's ads can appear", max_length=1024, verbose_name='Allowed domains'),
),
migrations.AddField(
model_name='publisher',
name='allowed_domains',
field=models.CharField(blank=True, default='', help_text="A space separated list of domains where the publisher's ads can appear", max_length=1024, verbose_name='Allowed domains'),
),
]
11 changes: 11 additions & 0 deletions adserver/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,17 @@ class Publisher(TimeStampedModel, IndestructibleModel):
blank=True,
)

# If this is blank, all domains are allowed
allowed_domains = models.CharField(
_("Allowed domains"),
max_length=1024,
help_text=_(
"A space separated list of domains where the publisher's ads can appear"
),
default="",
blank=True,
)

unauthed_ad_decisions = models.BooleanField(
default=True,
help_text=_(
Expand Down
24 changes: 24 additions & 0 deletions adserver/tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from ..utils import get_client_user_agent
from ..utils import get_geoipdb_geolocation
from ..utils import get_geolocation
from ..utils import is_allowed_domain
from ..utils import is_blocklisted_ip
from ..utils import is_blocklisted_referrer
from ..utils import is_blocklisted_user_agent
Expand Down Expand Up @@ -194,3 +195,26 @@ def test_parse_date_string(self):
parse_date_string("2020-01-01"),
datetime.datetime(year=2020, month=1, day=1, tzinfo=pytz.utc),
)

def test_is_allowed_domain(self):
# Check some nulls
self.assertTrue(is_allowed_domain("", None))
self.assertTrue(is_allowed_domain("http://example.com", None))
self.assertTrue(is_allowed_domain(None, ("not-example.com",)))

self.assertTrue(
is_allowed_domain("http://example.com", ("not-example.com", "example.com"))
)
self.assertTrue(
is_allowed_domain(
"https://example.com/path.html", ("not-example.com", "example.com")
)
)

self.assertFalse(is_allowed_domain("http://example.com", ("not-example.com",)))
self.assertFalse(
is_allowed_domain("https://example.com/path.html", ("not-example.com",))
)

# Subdomains aren't included by default
self.assertFalse(is_allowed_domain("http://www.example.com", ("example.com",)))
14 changes: 14 additions & 0 deletions adserver/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,20 @@ def is_proxy_ip(ip):
return False


def is_allowed_domain(url, allowed_domains):
"""Check if a domain is in the domain allowed list."""
url_domain = get_domain_from_url(url)

# If there's no domain restrictions, all URLs are allowed
if not allowed_domains or not url_domain:
return True

if url_domain in allowed_domains:
return True

return False


def get_geolocation(request, force=False):
"""Gets the geolocation for this IP address."""
if force:
Expand Down
11 changes: 11 additions & 0 deletions adserver/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@
from .utils import get_client_ip
from .utils import get_client_user_agent
from .utils import get_geolocation
from .utils import is_allowed_domain
from .utils import is_blocklisted_ip
from .utils import is_blocklisted_referrer
from .utils import is_blocklisted_user_agent
Expand Down Expand Up @@ -785,6 +786,16 @@ def ignore_tracking_reason(self, request, advertisement, offer):
user_agent,
)
reason = "Mismatched browser"
elif offer.publisher.allowed_domains and not is_allowed_domain(
offer.url, offer.publisher.allowed_domains.split()
):
log.log(
self.log_security_level,
"Offer URL is not on the allowed domain list. Publisher: [%s], Offer URL: [%s]",
offer.publisher,
offer.url,
)
# Note: this does not set a reason so it only logs mismatches

# This is out of the elif block and will be run everytime
if offer and offer.ip != anonymize_ip_address(ip_address):
Expand Down

0 comments on commit b512e87

Please sign in to comment.