diff --git a/kallithea/controllers/admin/gists.py b/kallithea/controllers/admin/gists.py --- a/kallithea/controllers/admin/gists.py +++ b/kallithea/controllers/admin/gists.py @@ -40,9 +40,8 @@ from kallithea.model.gist import GistMod from kallithea.model.meta import Session from kallithea.model.db import Gist, User from kallithea.lib import helpers as h -from kallithea.lib.base import BaseController, render +from kallithea.lib.base import BaseController, render, jsonify from kallithea.lib.auth import LoginRequired, NotAnonymous -from kallithea.lib.utils import jsonify from kallithea.lib.utils2 import safe_int, safe_unicode, time_to_datetime from kallithea.lib.page import Page from sqlalchemy.sql.expression import or_ diff --git a/kallithea/controllers/admin/repos.py b/kallithea/controllers/admin/repos.py --- a/kallithea/controllers/admin/repos.py +++ b/kallithea/controllers/admin/repos.py @@ -38,8 +38,8 @@ from kallithea.config.routing import url from kallithea.lib import helpers as h from kallithea.lib.auth import LoginRequired, \ HasRepoPermissionAnyDecorator, NotAnonymous, HasPermissionAny -from kallithea.lib.base import BaseRepoController, render -from kallithea.lib.utils import action_logger, jsonify +from kallithea.lib.base import BaseRepoController, render, jsonify +from kallithea.lib.utils import action_logger from kallithea.lib.vcs import RepositoryError from kallithea.model.meta import Session from kallithea.model.db import User, Repository, UserFollowing, RepoGroup, \ diff --git a/kallithea/controllers/changeset.py b/kallithea/controllers/changeset.py --- a/kallithea/controllers/changeset.py +++ b/kallithea/controllers/changeset.py @@ -33,7 +33,6 @@ from pylons import tmpl_context as c, re from pylons.i18n.translation import _ from webob.exc import HTTPFound, HTTPForbidden, HTTPBadRequest, HTTPNotFound -from kallithea.lib.utils import jsonify from kallithea.lib.vcs.exceptions import RepositoryError, \ ChangesetDoesNotExistError, EmptyRepositoryError @@ -41,7 +40,7 @@ from kallithea.lib.compat import json import kallithea.lib.helpers as h from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator, \ NotAnonymous -from kallithea.lib.base import BaseRepoController, render +from kallithea.lib.base import BaseRepoController, render, jsonify from kallithea.lib.utils import action_logger from kallithea.lib.compat import OrderedDict from kallithea.lib import diffs diff --git a/kallithea/controllers/files.py b/kallithea/controllers/files.py --- a/kallithea/controllers/files.py +++ b/kallithea/controllers/files.py @@ -37,7 +37,7 @@ from pylons.i18n.translation import _ from webob.exc import HTTPFound from kallithea.config.routing import url -from kallithea.lib.utils import jsonify, action_logger +from kallithea.lib.utils import action_logger from kallithea.lib import diffs from kallithea.lib import helpers as h @@ -45,7 +45,7 @@ from kallithea.lib.compat import Ordered from kallithea.lib.utils2 import convert_line_endings, detect_mode, safe_str, \ str2bool, safe_int from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator -from kallithea.lib.base import BaseRepoController, render +from kallithea.lib.base import BaseRepoController, render, jsonify from kallithea.lib.vcs.backends.base import EmptyChangeset from kallithea.lib.vcs.conf import settings from kallithea.lib.vcs.exceptions import RepositoryError, \ diff --git a/kallithea/controllers/home.py b/kallithea/controllers/home.py --- a/kallithea/controllers/home.py +++ b/kallithea/controllers/home.py @@ -33,10 +33,10 @@ from pylons.i18n.translation import _ from webob.exc import HTTPBadRequest from sqlalchemy.sql.expression import func -from kallithea.lib.utils import jsonify, conditional_cache +from kallithea.lib.utils import conditional_cache from kallithea.lib.compat import json from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator -from kallithea.lib.base import BaseController, render +from kallithea.lib.base import BaseController, render, jsonify from kallithea.model.db import Repository, RepoGroup from kallithea.model.repo import RepoModel diff --git a/kallithea/controllers/pullrequests.py b/kallithea/controllers/pullrequests.py --- a/kallithea/controllers/pullrequests.py +++ b/kallithea/controllers/pullrequests.py @@ -39,12 +39,12 @@ from kallithea.lib import helpers as h from kallithea.lib import diffs from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator, \ NotAnonymous -from kallithea.lib.base import BaseRepoController, render +from kallithea.lib.base import BaseRepoController, render, jsonify from kallithea.lib.compat import json, OrderedDict from kallithea.lib.diffs import LimitedDiffContainer from kallithea.lib.exceptions import UserInvalidException from kallithea.lib.page import Page -from kallithea.lib.utils import action_logger, jsonify +from kallithea.lib.utils import action_logger from kallithea.lib.vcs.exceptions import EmptyRepositoryError, ChangesetDoesNotExistError from kallithea.lib.vcs.utils import safe_str from kallithea.lib.vcs.utils.hgcompat import unionrepo diff --git a/kallithea/controllers/summary.py b/kallithea/controllers/summary.py --- a/kallithea/controllers/summary.py +++ b/kallithea/controllers/summary.py @@ -42,11 +42,10 @@ from kallithea.lib.vcs.exceptions import NodeDoesNotExistError from kallithea.config.conf import ALL_READMES, ALL_EXTS, LANGUAGES_EXTENSIONS_MAP from kallithea.model.db import Statistics, CacheInvalidation, User -from kallithea.lib.utils import jsonify from kallithea.lib.utils2 import safe_str from kallithea.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator, \ NotAnonymous -from kallithea.lib.base import BaseRepoController, render +from kallithea.lib.base import BaseRepoController, render, jsonify from kallithea.lib.vcs.backends.base import EmptyChangeset from kallithea.lib.markup_renderer import MarkupRenderer from kallithea.lib.celerylib.tasks import get_commits_stats diff --git a/kallithea/lib/base.py b/kallithea/lib/base.py --- a/kallithea/lib/base.py +++ b/kallithea/lib/base.py @@ -29,9 +29,11 @@ Original author and date, and relevant c """ import datetime +import decorator import logging import time import traceback +import warnings import webob.exc import paste.httpexceptions @@ -39,7 +41,7 @@ import paste.auth.basic import paste.httpheaders from webhelpers.pylonslib import secure_form -from pylons import config, tmpl_context as c, request, session +from pylons import config, tmpl_context as c, request, response, session from pylons.controllers import WSGIController from pylons.templating import render_mako as render # don't remove this import from pylons.i18n.translation import _ @@ -51,6 +53,7 @@ from kallithea.lib.utils2 import str2boo safe_str, safe_int from kallithea.lib import auth_modules from kallithea.lib.auth import AuthUser, HasPermissionAnyMiddleware +from kallithea.lib.compat import json from kallithea.lib.utils import get_repo_slug from kallithea.lib.exceptions import UserCreationError from kallithea.lib.vcs.exceptions import RepositoryError, EmptyRepositoryError, ChangesetDoesNotExistError @@ -581,3 +584,28 @@ class WSGIResultCloseCallback(object): if hasattr(self._result, 'close'): self._result.close() self._close() + + +@decorator.decorator +def jsonify(func, *args, **kwargs): + """Action decorator that formats output for JSON + + Given a function that will return content, this decorator will turn + the result into JSON, with a content-type of 'application/json' and + output it. + """ + response.headers['Content-Type'] = 'application/json; charset=utf-8' + data = func(*args, **kwargs) + if isinstance(data, (list, tuple)): + # A JSON list response is syntactically valid JavaScript and can be + # loaded and executed as JavaScript by a malicious third-party site + # using