diff --git a/source/code/models.py b/source/code/models.py index 70705d7..e068050 100644 --- a/source/code/models.py +++ b/source/code/models.py @@ -17,6 +17,7 @@ from source.tags.models import TechnologyTaggedItem, ConceptTaggedItem from source.utils.caching import expire_page_cache from taggit.managers import TaggableManager +from urllib.parse import urlparse GITHUB_CLIENT_ID=settings.GITHUB_CLIENT_ID GITHUB_CLIENT_SECRET=settings.GITHUB_CLIENT_SECRET @@ -63,7 +64,11 @@ def __str__(self): def save(self, *args, **kwargs): # GitHub API does not like trailing slashes on repo links, # so clean things up just in case - if self.url and 'github.com' in self.url: + #if self.url and 'github.com' in self.url: + if self.url: + parsed_url = urlparse(self.url) + if parsed_url.hostname and (parsed_url.hostname == "github.com" or parsed_url.hostname.endswith(".github.com")): + self.url = self.url.rstrip('/') self.url = self.url.rstrip('/') # update GitHub stats @@ -128,32 +133,36 @@ def update_github_stats(self): does _not_ save those stats. That is left to the function that calls the method to avoid unnecessary db hits (e.g. the save() method above). ''' - if self.url and '//github.com/' in self.url.lower(): - # create our connection to the GitHub API - _github_location = self.url.split('github.com/')[1] - _github_user, _github_repo = _github_location.split('/') - _github_api_url = 'https://api.github.com/repos/%s/%s?client_id=%s&client_secret=%s' % ( - _github_user.lower(), _github_repo.lower(), - GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET - ) - - # get the data for this repo - r = requests.get(_github_api_url) - _data = r.json - - try: - # handle GitHub API's ISO8601 timestamps - last_push = _data['pushed_at'].strip('Z') - last_push = dateutil.parser.parse(last_push, fuzzy=True) - self.repo_last_push = last_push - # the rest of the API data - self.repo_forks = _data['forks'] - self.repo_watchers = _data['watchers'] - self.repo_description = _data['description'] - self.repo_master_branch = _data['master_branch'] - return True - except: - return False + if self.url: + parsed_url = urlparse(self.url) + # enforce URL substring sanitization + if parsed_url.hostname and parsed_url.hostname.lower() == 'github.com': + # create our connection to the GitHub API + _github_location = parsed_url.path.lstrip('/') + _github_location = self.url.split('github.com/')[1] + _github_user, _github_repo = _github_location.split('/') + _github_api_url = 'https://api.github.com/repos/%s/%s?client_id=%s&client_secret=%s' % ( + _github_user.lower(), _github_repo.lower(), + GITHUB_CLIENT_ID, GITHUB_CLIENT_SECRET + ) + + # get the data for this repo + r = requests.get(_github_api_url) + _data = r.json + + try: + # handle GitHub API's ISO8601 timestamps + last_push = _data['pushed_at'].strip('Z') + last_push = dateutil.parser.parse(last_push, fuzzy=True) + self.repo_last_push = last_push + # the rest of the API data + self.repo_forks = _data['forks'] + self.repo_watchers = _data['watchers'] + self.repo_description = _data['description'] + self.repo_master_branch = _data['master_branch'] + return True + except: + return False return False diff --git a/source/code/static/code/js/repo.js b/source/code/static/code/js/repo.js index 32a7301..8c7837a 100755 --- a/source/code/static/code/js/repo.js +++ b/source/code/static/code/js/repo.js @@ -16,6 +16,20 @@ * Dual licensed under the MIT and GPL licenses. * http://darcyclarke.me/ */ + +function escapeHtml(str) { + return str.replace(/[&<>"']/g, function(match) { + const escapeMap = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' + }; + return escapeMap[match]; + }); +} + (function($){ // Github repo @@ -246,7 +260,7 @@ .find('.active') .removeClass('active') .end() - .append('' + link.text() + ''); + .append('' + escapeHtml(link.text()) + ''); transition(el, 'left'); // Is link a back link