diff --git a/alliance_auth/settings.py.example b/alliance_auth/settings.py.example index bfa42806..d2bde0f5 100755 --- a/alliance_auth/settings.py.example +++ b/alliance_auth/settings.py.example @@ -124,6 +124,15 @@ DATABASES = { 'PASSWORD': os.environ.get('AA_DB_MARKET_PASSWORD', 'password'), 'HOST': os.environ.get('AA_DB_MARKET_HOST', '127.0.0.1'), 'PORT': os.environ.get('AA_DB_MARKET_PORT', '3306'), + }, + + 'pathfinder': { + 'ENGINE': 'django.db.backends.mysql', + 'NAME': 'alliance_pathfinder', + 'USER': os.environ.get('AA_DB_PATHFINDER_USER', 'allianceserver'), + 'PASSWORD': os.environ.get('AA_DB_PATHFINDER_PASSWORD', 'password'), + 'HOST': os.environ.get('AA_DB_PATHFINDER_HOST', '127.0.0.1'), + 'PORT': os.environ.get('AA_DB_PATHFINDER_PORT', '3306'), } } @@ -253,6 +262,7 @@ BLUE_ALLIANCE_GROUPS = 'True' == os.environ.get('AA_BLUE_ALLIANCE_GROUPS', 'Fals # ENABLE_AUTH_IPS4 - Enable IPS4 support in the auth for auth'd members # ENABLE_AUTH_SMF - Enable SMF forum support in the auth for auth'd members # ENABLE_AUTH_MARKET = Enable Alliance Market support in auth for auth'd members +# ENABLE_AUTH_PATHFINDER = Enable Alliance Pathfinder suppor in auth for auth'd members ######################### ENABLE_AUTH_FORUM = 'True' == os.environ.get('AA_ENABLE_AUTH_FORUM', 'False') ENABLE_AUTH_JABBER = 'True' == os.environ.get('AA_ENABLE_AUTH_JABBER', 'False') @@ -264,7 +274,7 @@ ENABLE_AUTH_DISCOURSE = 'True' == os.environ.get('AA_ENABLE_AUTH_DISCOURSE', 'Fa ENABLE_AUTH_IPS4 = 'True' == os.environ.get('AA_ENABLE_AUTH_IPS4', 'False') ENABLE_AUTH_SMF = 'True' == os.environ.get('AA_ENABLE_AUTH_SMF', 'False') ENABLE_AUTH_MARKET = 'True' == os.environ.get('AA_ENABLE_AUTH_MARKET', 'False') - +ENABLE_AUTH_PATHFINDER = 'True' == os.environ.get('AA_ENABLE_AUTH_PATHFINDER', 'False') ##################### # Blue service Setup @@ -279,6 +289,7 @@ ENABLE_AUTH_MARKET = 'True' == os.environ.get('AA_ENABLE_AUTH_MARKET', 'False') # ENABLE_BLUE_IPS4 - Enable IPS4 forum support in the auth for blues # ENABLE_BLUE_SMF - Enable SMF forum support in the auth for blues # ENABLE_BLUE_MARKET - Enable Alliance Market in the auth for blues +# ENABLE_BLUE_PATHFINDER = Enable Pathfinder support in the auth for blues ##################### BLUE_STANDING = float(os.environ.get('AA_BLUE_STANDING', '5.0')) ENABLE_BLUE_FORUM = 'True' == os.environ.get('AA_ENABLE_BLUE_FORUM', 'False') @@ -291,6 +302,7 @@ ENABLE_BLUE_DISCOURSE = 'True' == os.environ.get('AA_ENABLE_BLUE_DISCOURSE', 'Fa ENABLE_BLUE_IPS4 = 'True' == os.environ.get('AA_ENABLE_BLUE_IPS4', 'False') ENABLE_BLUE_SMF = 'True' == os.environ.get('AA_ENABLE_BLUE_SMF', 'False') ENABLE_BLUE_MARKET = 'True' == os.environ.get('AA_ENABLE_BLUE_MARKET', 'False') +ENABLE_BLUE_PATHFINDER = 'True' == os.environ.get('AA_ENABLE_BLUE_PATHFINDER', 'False') ######################### # Corp Configuration @@ -328,6 +340,11 @@ MEMBER_API_ACCOUNT = 'True' == os.environ.get('AA_MEMBER_API_ACCOUNT', 'True') BLUE_API_MASK = os.environ.get('AA_BLUE_API_MASK', 8388608) BLUE_API_ACCOUNT = 'True' == os.environ.get('AA_BLUE_API_ACCOUNT', 'False') +########################## +# Pathfinder Configuration +########################## +PATHFINDER_URL = os.environ.get('AA_PATHFINDER_URL', 'http://pathfinder.yourdomain.com') + ##################### # Alliance Market ##################### @@ -422,6 +439,7 @@ DISCOURSE_URL = os.environ.get('AA_DISCOURSE_URL', '') DISCOURSE_API_USERNAME = os.environ.get('AA_DISCOURSE_API_USERNAME', '') DISCOURSE_API_KEY = os.environ.get('AA_DISCOURSE_API_KEY', '') + ##################################### # IPS4 Configuration ##################################### diff --git a/alliance_auth/urls.py b/alliance_auth/urls.py index ca15a232..7bb36e8d 100755 --- a/alliance_auth/urls.py +++ b/alliance_auth/urls.py @@ -136,7 +136,7 @@ urlpatterns = patterns('', url(r'^activate_discord/$', 'services.views.activate_discord', name='auth_activate_discord'), url(r'^deactivate_discord/$', 'services.views.deactivate_discord', name='auth_deactivate_discord'), url(r'^reset_discord/$', 'services.views.reset_discord', name='auth_reset_discord'), - + # Discourse Service Control url(r'^activate_discourse/$', 'services.views.activate_discourse', name='auth_activate_discourse'), url(r'^deactivate_discourse/$', 'services.views.deactivate_discourse', name='auth_deactivate_discourse'), @@ -164,6 +164,13 @@ urlpatterns = patterns('', name='auth_reset_market_password'), url(r'^set_market_password/$', 'services.views.set_market_password', name='auth_set_market_password'), + # Pathfinder Control + url(r'^activate_pathfinder/$', 'services.views.activate_pathfinder', name='auth_activate_pathfinder'), + url(r'^deactivate_pathfinder/$', 'services.views.deactivate_pathfinder', name='auth_deactivate_pathfinder'), + url(r'^reset_pathfinder_password/$', 'services.views.reset_pathfinder_password', + name='auth_reset_pathfinder_password'), + url(r'^set_pathfinder_password/$', 'services.views.set_pathfinder_password', name='auth_set_pathfinder_password'), + # Tools url(r'^tool/fleet_formatter_tool/$', 'services.views.fleet_formatter_view', name='auth_fleet_format_tool_view'), diff --git a/authentication/managers.py b/authentication/managers.py index 926b6ca1..84f867bf 100755 --- a/authentication/managers.py +++ b/authentication/managers.py @@ -121,7 +121,7 @@ class AuthServicesInfoManager: logger.info("Updated user %s discord info in authservicesinfo model." % user) else: logger.error("Failed to update user %s discord info: user does not exist." % user) - + @staticmethod def update_user_discourse_info(username, password, user): if User.objects.filter(username=user.username).exists(): @@ -170,3 +170,15 @@ class AuthServicesInfoManager: logger.info("Updated user %s market info in authservicesinfo model." % user) else: logger.error("Failed to update user %s market info: user does not exist." % user) + + @staticmethod + def update_user_pathfinder_info(username, password, user): + if User.objects.filter(username=user.username).exists(): + logger.debug("Updating user %s market info: username %s" % (user, username)) + authserviceinfo = AuthServicesInfoManager.__get_or_create(user) + authserviceinfo.pathfinder_username = username + authserviceinfo.pathfinder_password = password + authserviceinfo.save(update_fields=['pathfinder_username', 'pathfinder_password']) + logger.info("Updated user %s pathfinder info in authservicesinfo model." % user) + else: + logger.error("Failed to update user %s pathfinder info: user does not exist." % user) diff --git a/authentication/models.py b/authentication/models.py index 713f658f..11b51097 100755 --- a/authentication/models.py +++ b/authentication/models.py @@ -23,6 +23,8 @@ class AuthServicesInfo(models.Model): smf_password = models.CharField(max_length=254, blank=True, default="") market_username = models.CharField(max_length=254, blank=True, default="") market_password = models.CharField(max_length=254, blank=True, default="") + pathfinder_username = models.CharField(max_length=254, blank=True, default="") + pathfinder_password = models.CharField(max_length=254, blank=True, default="") main_char_id = models.CharField(max_length=64, blank=True, default="") is_blue = models.BooleanField(default=False) user = models.ForeignKey(User) diff --git a/cache/.gitignore b/cache/.gitignore deleted file mode 100644 index bbd659de..00000000 --- a/cache/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -* - -!README.md -!.gitignore diff --git a/cache/README.md b/cache/README.md deleted file mode 100644 index dd8a0213..00000000 --- a/cache/README.md +++ /dev/null @@ -1 +0,0 @@ -Make sure to make this folder writeable to the web server diff --git a/services/managers/pathfinder_manager.py b/services/managers/pathfinder_manager.py new file mode 100644 index 00000000..dedc7b4a --- /dev/null +++ b/services/managers/pathfinder_manager.py @@ -0,0 +1,196 @@ +import logging +from django.conf import settings +import requests +import os +from django.db import connections +from passlib.hash import bcrypt +from eveonline.managers import EveManager +from authentication.managers import AuthServicesInfo +from eveonline.models import EveCharacter +from eveonline.models import EveApiKeyPair + +logger = logging.getLogger(__name__) + +class pathfinderManager: + + SQL_ADD_USER = r"INSERT INTO user (name, email, password, active) VALUES (%s, %s, %s, %s)" + SQL_ADD_API = r"INSERT INTO user_api (userid, keyid, vCode, active) VALUES (%s, %s, %s, %s)" + SQL_ADD_CHARACTER = r"INSERT INTO user_character (userid, apiId, characterId, isMain) VALUES (%s, %s, %s, %s)" + SQL_GET_APIID = r"SELECT id, keyId FROM user_api WHERE userId = %s" + SQL_GET_USERID = r"SELECT id FROM user WHERE name = %s" + SQL_DISABLE_USER = r"UPDATE user SET active = '0' WHERE name = %s" + SQL_UPDATE_USER = r"UPDATE user SET active = '1', password = %s WHERE name = %s" + SQL_CHECK_USER = r"SELECT name FROM user WHERE name = %s" + SQL_CHECK_EMAIL = r"SELECT email from user WHERE email = %s" + SQL_SET_MAIN = r"UPDATE user_character SET isMain = 1 WHERE characterId = %s" + + + @staticmethod + def __santatize_username(username): + sanatized = username.replace(" ", "_") + return sanatized.lower() + + @staticmethod + def __generate_random_pass(): + return os.urandom(8).encode('hex') + + @staticmethod + def check_username(username): + logger.debug("Checking for pathfinder username %s" % username) + cursor = connections['pathfinder'].cursor() + cursor.execute(pathfinderManager.SQL_CHECK_USER, [pathfinderManager.__santatize_username(username)]) + row = cursor.fetchone() + if row: + logger.debug("Found user %s on pathfinder" % username) + return True + logger.debug("User %s not found on pathfinder" % username) + return False + + @staticmethod + def update_user_info(username): + logger.debug("Updating pathfinder user %s" % username) + try: + username_clean = pathfinderManager.__santatize_username(username) + plain_password = pathfinderManager.__generate_random_pass() + passwd = bcrypt.encrypt(plain_password, rounds=10) + cursor = connections['pathfinder'].cursor() + cursor.execute(pathfinderManager.SQL_UPDATE_USER, [passwd, username_clean]) + return username_clean, plain_password + except: + logger.debug("Pathfinder update user failed for %s" % username) + return "", "" + + @staticmethod + def update_custom_password(username, plain_password): + logger.debug("Updating pathfinder user id %s password" % username) + if pathfinderManager.check_username(username): + username_clean = pathfinderManager.__santatize_username(username) + passwd = bcrypt.encrypt(plain_password, rounds=10) + cursor = connections['pathfinder'].cursor() + cursor.execute(pathfinderManager.SQL_UPDATE_USER, [passwd, username_clean]) + return plain_password + else: + logger.error("Unable to update ips4 user %s password" % username) + return "" + + @staticmethod + def disable_user(username): + logger.debug("Disabling user %s" % username) + if pathfinderManager.check_username(username) == True: + try: + cursor = connections['pathfinder'].cursor() + cursor.execute(pathfinderManager.SQL_DISABLE_USER, [pathfinderManager.__santatize_username(username)]) + return True + except: + logger.debug("User %s not found cannot disable" % username) + + + + @staticmethod + def add_user(username, email, charactername): + logger.debug("Adding new pathfinder user %s" % username) + plain_password = pathfinderManager.__generate_random_pass() + passwd = bcrypt.encrypt(plain_password, rounds=10) + username_clean = pathfinderManager.__santatize_username(username) + auth_id = pathfinderManager.get_authid_by_username(charactername) + + if pathfinderManager.check_username(username)== False: + if pathfinderManager.check_email(username, email) == False: + try: + logger.debug("Adding user %s to pathfinder" % username) + cursor = connections['pathfinder'].cursor() + cursor.execute(pathfinderManager.SQL_ADD_USER, [username_clean,email, passwd, '1']) + path_id = pathfinderManager.get_pathfinder_user_id(username_clean) + api_keys = pathfinderManager.get_api_key_pairs(auth_id) + main_character = AuthServicesInfo.objects.get(user=auth_id).main_char_id + + for keyId, key in api_keys.items(): + cursor.execute(pathfinderManager.SQL_ADD_API, [path_id, keyId, key, '1']) + + char_apis = pathfinderManager.get_char_id(auth_id) + + for c,a in char_apis.items(): + cursor.execute(pathfinderManager.SQL_ADD_CHARACTER, [path_id, (pathfinderManager.get_pathfinder_api_id(username, path_id)), c, '0']) + + pathfinderManager.set_main_char(username, main_character) + return username_clean, plain_password + + except: + logger.debug("Unsuccessful attempt at adding user %s to pathfinder on add_user" % username) + return "","" + else: + logger.debug("pathfinder username %s already exists Updating instead" % username) + username_clean, password = pathfinderManager.update_user_info(username) + return username_clean, password + else: + logger.debug("pathfinder username %s already exists Updating instead" % username) + username_clean, password = pathfinderManager.update_user_info(username) + return username_clean, password + + @staticmethod + def set_main_char (username, main_character): + try: + cursor = connections['pathfinder'].cursor() + cursor.execute(pathfinderManager.SQL_SET_MAIN, [main_character]) + except: + logger.debug("Failed setting main character for user %s"% username) + return "" + + @staticmethod + def get_api_key_pairs(user_id): + char = EveCharacter.objects.all().filter(user_id=user_id) + api_list = dict() + for c in char: + api_pair = EveApiKeyPair.objects.get(api_id=c.api_id) + api_list[api_pair.api_id] = api_pair.api_key + return api_list + + @staticmethod + def get_char_id(auth_id): + char = EveCharacter.objects.all().filter(user_id=auth_id) + char_list = dict() + for c in char: + char_list[c.character_id] = c.api_id + logger.debug("printing char list %s" % char_list) + return char_list + + @staticmethod + def get_authid_by_username(username): + authid = EveCharacter.objects.get(character_name=username).user_id + return authid + + @staticmethod + def get_pathfinder_user_id(username): + cursor = connections['pathfinder'].cursor() + cursor.execute(pathfinderManager.SQL_GET_USERID, [username]) + row = cursor.fetchone() + if row: + logger.debug("Pathfinder ID for user %s is %s" % (username, row[0])) + return int(row[0]) + else: + logger.debug("failed to get pathfinder ID for user %s" % username) + return "" + + @staticmethod + def get_pathfinder_api_id(username, path_id): + cursor = connections['pathfinder'].cursor() + cursor.execute(pathfinderManager.SQL_GET_APIID, [path_id]) + row = cursor.fetchone() + if row: + logger.debug("Pathfinder API ID for user %s is %s" % (username, row[0])) + return int(row[0]) + else: + logger.debug("failed to get pathfinder API ID for user %s" % username) + return "" + + @staticmethod + def check_email(username, email): + logger.debug("Checking if email %s exists for username %s" % (email,username)) + cursor = connections['pathfinder'].cursor() + cursor.execute(pathfinderManager.SQL_CHECK_EMAIL, [email]) + row = cursor.fetchone() + if row: + logger.debug("Found user %s email on pathfinder" % username) + return True + logger.debug("User %s email not found on pathfinder" % username) + return False \ No newline at end of file diff --git a/services/views.py b/services/views.py index fd8534a6..7edc6129 100755 --- a/services/views.py +++ b/services/views.py @@ -18,6 +18,7 @@ from managers.discourse_manager import DiscourseManager from managers.ips4_manager import Ips4Manager from managers.smf_manager import smfManager from managers.market_manager import marketManager +from managers.pathfinder_manager import pathfinderManager from authentication.managers import AuthServicesInfoManager from eveonline.managers import EveManager from celerytask.tasks import update_jabber_groups @@ -609,7 +610,7 @@ def set_ipboard_password(request): logger.debug("Rendering form for user %s" % request.user) context = {'form': form, 'service': 'IPBoard', 'error': error} return render_to_response('registered/service_password.html', context, context_instance=RequestContext(request)) - + @login_required @user_passes_test(service_blue_alliance_test) def activate_discourse(request): @@ -640,9 +641,9 @@ def deactivate_discourse(request): return HttpResponseRedirect("/services/") logger.error("Unsuccessful attempt to activate discourse for user %s" % request.user) return HttpResponseRedirect("/dashboard") - + @login_required -@user_passes_test(service_blue_alliance_test) +user_passes_test(service_blue_alliance_test) def activate_ips4(request): logger.debug("activate_ips4 called by user %s" % request.user) authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) @@ -754,6 +755,7 @@ def deactivate_smf(request): logger.error("Unsuccesful attempt to activate smf for user %s" % request.user) return HttpResponseRedirect("/dashboard") + @login_required @user_passes_test(service_blue_alliance_test) def reset_smf_password(request): @@ -877,3 +879,82 @@ def set_market_password(request): logger.debug("Rendering form for user %s" % request.user) context = {'form': form, 'service': 'Market'} return render_to_response('registered/service_password.html', context, context_instance=RequestContext(request)) + +@login_required +@user_passes_test(service_blue_alliance_test) +def activate_pathfinder(request): + logger.debug("activate_pathfinder called by user %s" % request.user) + authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + # Valid now we get the main characters + character = EveManager.get_character_by_id(authinfo.main_char_id) + logger.debug("Adding pathfinder for user %s with main character %s" % (request.user, character)) + result = pathfinderManager.add_user(character.character_name, request.user.email, character.character_name) + # if empty we failed + if result[0] != "": + AuthServicesInfoManager.update_user_pathfinder_info(result[0], result[1], request.user) + logger.debug("Updated authserviceinfo for user %s with pathfinder credentials." % request.user) + logger.info("Succesfully activated pathfinder for user %s" % request.user) + return HttpResponseRedirect("/services/") + logger.error("Unsuccesful attempt to activate pathfinder for user %s" % request.user) + return HttpResponseRedirect("/dashboard") + + +@login_required +@user_passes_test(service_blue_alliance_test) +def deactivate_pathfinder(request): + logger.debug("deactivate_pathfinder called by user %s" % request.user) + authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + result = pathfinderManager.disable_user(authinfo.pathfinder_username) + # false we failed + if result: + AuthServicesInfoManager.update_user_pathfinder_info("", "", request.user) + logger.info("Succesfully deactivated pathfinder for user %s" % request.user) + return HttpResponseRedirect("/services/") + logger.error("Unsuccesful attempt to activate pathfinder for user %s" % request.user) + return HttpResponseRedirect("/dashboard") + + +@login_required +@user_passes_test(service_blue_alliance_test) +def reset_pathfinder_password(request): + logger.debug("reset_pathfinder_password called by user %s" % request.user) + authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + result = pathfinderManager.update_user_info(authinfo.pathfinder_username) + # false we failed + if result != "": + AuthServicesInfoManager.update_user_pathfinder_info(authinfo.pathfinder_username, result[1], request.user) + logger.info("Succesfully reset pathfinder password for user %s" % request.user) + return HttpResponseRedirect("/services/") + logger.error("Unsuccessful attempt to reset pathfinder password for user %s" % request.user) + return HttpResponseRedirect("/dashboard") + +@login_required +@user_passes_test(service_blue_alliance_test) +def set_pathfinder_password(request): + logger.debug("set_pathfinder_password called by user %s" % request.user) + error = None + if request.method == 'POST': + logger.debug("Received POST request with form.") + form = ServicePasswordForm(request.POST) + logger.debug("Form is valid: %s" % form.is_valid()) + if form.is_valid(): + password = form.cleaned_data['password'] + logger.debug("Form contains password of length %s" % len(password)) + authinfo = AuthServicesInfoManager.get_auth_service_info(request.user) + result = pathfinderManager.update_custom_password(authinfo.pathfinder_username, password) + if result != "": + AuthServicesInfoManager.update_user_pathfinder_info(authinfo.pathfinder_username, result, request.user) + logger.info("Succesfully reset pathfinder password for user %s" % request.user) + return HttpResponseRedirect("/services/") + else: + logger.error("Failed to install custom pathfinder password for user %s" % request.user) + error = "Failed to install custom password." + else: + error = "Invalid password provided" + else: + logger.debug("Request is not type POST - providing empty form.") + form = ServicePasswordForm() + + logger.debug("Rendering form for user %s" % request.user) + context = {'form': form, 'service': 'Pathfinder'} + return render_to_response('registered/service_password.html', context, context_instance=RequestContext(request)) diff --git a/stock/templates/registered/services.html b/stock/templates/registered/services.html index 1e7cac52..34a07fea 100755 --- a/stock/templates/registered/services.html +++ b/stock/templates/registered/services.html @@ -126,6 +126,33 @@ {% endifequal %} {% endif %} + {% if ENABLE_BLUE_PATHFINDER %} + Pathfinder + {{ authinfo.pathfinder_username }} + {{ authinfo.pathfinder_password }} + {{ PATHFINDER_URL }} + + {% ifequal authinfo.pathfinder_username "" %} + + + + {% else %} + + + + + + + + + + {% endifequal %} + + {% endif %} {% if ENABLE_BLUE_JABBER %} Jabber @@ -416,6 +443,33 @@ {% endifequal %} {% endif %} + {% if ENABLE_AUTH_PATHFINDER %} + Pathfinder + {{ authinfo.pathfinder_username }} + {{ authinfo.pathfinder_password }} + {{ PATHFINDER_URL }} + + {% ifequal authinfo.pathfinder_username "" %} + + + + {% else %} + + + + + + + + + + {% endifequal %} + + {% endif %} {% if ENABLE_AUTH_JABBER %} Jabber diff --git a/util/context_processors.py b/util/context_processors.py index 524217ad..83b52eb4 100755 --- a/util/context_processors.py +++ b/util/context_processors.py @@ -41,6 +41,7 @@ def domain_url(request): 'ENABLE_AUTH_IPS4': settings.ENABLE_AUTH_IPS4, 'ENABLE_AUTH_SMF': settings.ENABLE_AUTH_SMF, 'ENABLE_AUTH_MARKET': settings.ENABLE_AUTH_MARKET, + 'ENABLE_AUTH_PATHFINDER': settings.ENABLE_AUTH_PATHFINDER, 'ENABLE_BLUE_JABBER': settings.ENABLE_BLUE_JABBER, 'ENABLE_BLUE_FORUM': settings.ENABLE_BLUE_FORUM, 'ENABLE_BLUE_MUMBLE': settings.ENABLE_BLUE_MUMBLE, @@ -51,6 +52,7 @@ def domain_url(request): 'ENABLE_BLUE_IPS4': settings.ENABLE_BLUE_IPS4, 'ENABLE_BLUE_SMF': settings.ENABLE_BLUE_SMF, 'ENABLE_BLUE_MARKET': settings.ENABLE_BLUE_MARKET, + 'ENABLE_BLUE_PATHFINDER': settings.ENABLE_BLUE_PATHFINDER, 'TEAMSPEAK3_PUBLIC_URL': settings.TEAMSPEAK3_PUBLIC_URL, 'JACK_KNIFE_URL': settings.JACK_KNIFE_URL, 'DISCORD_SERVER_ID': settings.DISCORD_SERVER_ID, @@ -59,5 +61,6 @@ def domain_url(request): 'IPS4_URL': settings.IPS4_URL, 'SMF_URL': settings.SMF_URL, 'MARKET_URL': settings.MARKET_URL, + 'PATHFINDER_URL': settings.PATHFINDER_URL, 'EXTERNAL_MEDIA_URL': settings.EXTERNAL_MEDIA_URL, 'CURRENT_UTC_TIME': timezone.now()}