From b1fa2bdae628d7b8195e4069282f3ee76e12136f Mon Sep 17 00:00:00 2001 From: Kyle McCormick Date: Fri, 16 Apr 2021 14:00:04 -0400 Subject: [PATCH] refactor: make embargo app go through geoinfo API (#27350) Consolidates all usage of geoip database within geoinfo app. --- openedx/core/djangoapps/embargo/api.py | 28 ++---------------- openedx/core/djangoapps/geoinfo/api.py | 29 +++++++++++++++++++ openedx/core/djangoapps/geoinfo/middleware.py | 13 ++------- 3 files changed, 34 insertions(+), 36 deletions(-) create mode 100644 openedx/core/djangoapps/geoinfo/api.py diff --git a/openedx/core/djangoapps/embargo/api.py b/openedx/core/djangoapps/embargo/api.py index e2b9066c2f..ba101f9b79 100644 --- a/openedx/core/djangoapps/embargo/api.py +++ b/openedx/core/djangoapps/embargo/api.py @@ -14,8 +14,8 @@ from ipware.ip import get_client_ip from rest_framework import status from rest_framework.response import Response -import geoip2.database from common.djangoapps.student.auth import has_course_author_access +from openedx.core.djangoapps.geoinfo.api import country_code_from_ip from .models import CountryAccessRule, RestrictedCourse @@ -79,7 +79,7 @@ def check_course_access(course_key, user=None, ip_address=None, url=None): if ip_address is not None: # Retrieve the country code from the IP address # and check it against the allowed countries list for a course - user_country_from_ip = _country_code_from_ip(ip_address) + user_country_from_ip = country_code_from_ip(ip_address) if not CountryAccessRule.check_country_access(course_key, user_country_from_ip): log.info( @@ -159,30 +159,6 @@ def _get_user_country_from_profile(user): return profile_country -def _country_code_from_ip(ip_addr): - """ - Return the country code associated with an IP address. - Handles both IPv4 and IPv6 addresses. - - Args: - ip_addr (str): The IP address to look up. - - Returns: - str: A 2-letter country code. - - """ - reader = geoip2.database.Reader(settings.GEOIP_PATH) - - try: - response = reader.country(ip_addr) - # pylint: disable=no-member - country_code = response.country.iso_code - except geoip2.errors.AddressNotFoundError: - country_code = "" - reader.close() - return country_code - - def get_embargo_response(request, course_id, user): """ Check whether any country access rules block the user from enrollment. diff --git a/openedx/core/djangoapps/geoinfo/api.py b/openedx/core/djangoapps/geoinfo/api.py new file mode 100644 index 0000000000..9445b56fb9 --- /dev/null +++ b/openedx/core/djangoapps/geoinfo/api.py @@ -0,0 +1,29 @@ +""" +Simple Python API to identify the country of origin of page requests. +""" + +import geoip2.database +from django.conf import settings + + +def country_code_from_ip(ip_addr: str) -> str: + """ + Return the country code associated with an IP address. + Handles both IPv4 and IPv6 addresses. + + Args: + ip_addr: The IP address to look up. + + Returns: + A 2-letter country code, + or an empty string if lookup failed. + """ + reader = geoip2.database.Reader(settings.GEOIP_PATH) + try: + response = reader.country(ip_addr) + # pylint: disable=no-member + country_code = response.country.iso_code + except geoip2.errors.AddressNotFoundError: + country_code = "" + reader.close() + return country_code diff --git a/openedx/core/djangoapps/geoinfo/middleware.py b/openedx/core/djangoapps/geoinfo/middleware.py index 1bd556bfba..9b9df817e2 100644 --- a/openedx/core/djangoapps/geoinfo/middleware.py +++ b/openedx/core/djangoapps/geoinfo/middleware.py @@ -10,13 +10,13 @@ decorator `django.utils.decorators.decorator_from_middleware(middleware_class)` """ import logging -import geoip2.database -from django.conf import settings from django.utils.deprecation import MiddlewareMixin from ipware.ip import get_client_ip from ipware.utils import is_public_ip +from .api import country_code_from_ip + log = logging.getLogger(__name__) @@ -37,14 +37,7 @@ class CountryMiddleware(MiddlewareMixin): del request.session['ip_address'] del request.session['country_code'] elif new_ip_address != old_ip_address and is_public_ip(new_ip_address): - reader = geoip2.database.Reader(settings.GEOIP_PATH) - try: - response = reader.country(new_ip_address) - country_code = response.country.iso_code - except geoip2.errors.AddressNotFoundError: - country_code = "" - + country_code = country_code_from_ip(new_ip_address) request.session['country_code'] = country_code request.session['ip_address'] = new_ip_address log.debug('Country code for IP: %s is set to %s', new_ip_address, country_code) - reader.close()