示例#1
0
def gravatar_url(email_address, size=30, ssl_enabled=True):
    from pylons import url  # doh, we need to re-import url to mock it later
    from rhodecode import CONFIG

    _def = '*****@*****.**'  # default gravatar
    use_gravatar = str2bool(CONFIG.get('use_gravatar'))
    alternative_gravatar_url = CONFIG.get('alternative_gravatar_url', '')
    email_address = email_address or _def
    if not use_gravatar or not email_address or email_address == _def:
        f = lambda a, l: min(l, key=lambda x: abs(x - a))
        return url("/images/user%s.png" % f(size, [14, 16, 20, 24, 30]))

    if use_gravatar and alternative_gravatar_url:
        tmpl = alternative_gravatar_url
        parsed_url = urlparse.urlparse(url.current(qualified=True))
        tmpl = tmpl.replace('{email}', email_address)\
                   .replace('{md5email}', hashlib.md5(email_address.lower()).hexdigest()) \
                   .replace('{netloc}', parsed_url.netloc)\
                   .replace('{scheme}', parsed_url.scheme)\
                   .replace('{size}', str(size))
        return tmpl

    default = 'identicon'
    baseurl_nossl = "http://www.gravatar.com/avatar/"
    baseurl_ssl = "https://secure.gravatar.com/avatar/"
    baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl

    if isinstance(email_address, unicode):
        #hashlib crashes on unicode items
        email_address = safe_str(email_address)
    # construct the url
    gravatar_url = baseurl + hashlib.md5(email_address.lower()).hexdigest() + "?"
    gravatar_url += urllib.urlencode({'d': default, 's': str(size)})

    return gravatar_url
示例#2
0
def show_id(cs):
    """
    Configurable function that shows ID
    by default it's r123:fffeeefffeee

    :param cs: changeset instance
    """
    from rhodecode import CONFIG
    def_len = safe_int(CONFIG.get('show_sha_length', 12))
    show_rev = str2bool(CONFIG.get('show_revision_number', True))

    raw_id = cs.raw_id[:def_len]
    if show_rev:
        return 'r%s:%s' % (cs.revision, raw_id)
    else:
        return '%s' % (raw_id)
示例#3
0
def show_id(cs):
    """
    Configurable function that shows ID
    by default it's r123:fffeeefffeee

    :param cs: changeset instance
    """
    from rhodecode import CONFIG
    def_len = safe_int(CONFIG.get('show_sha_length', 12))
    show_rev = str2bool(CONFIG.get('show_revision_number', True))

    raw_id = cs.raw_id[:def_len]
    if show_rev:
        return 'r%s:%s' % (cs.revision, raw_id)
    else:
        return '%s' % (raw_id)
示例#4
0
 def __init__(self, message, *args, **kwargs):
     from rhodecode import CONFIG
     from rhodecode.lib.utils2 import safe_int
     _code = CONFIG.get('lock_ret_code')
     self.code = safe_int(_code, self.code)
     self.title = self.explanation = message
     super(HTTPLockedRC, self).__init__(*args, **kwargs)
     self.args = (message, )
示例#5
0
 def __init__(self, reponame, username, *args, **kwargs):
     from rhodecode import CONFIG
     from rhodecode.lib.utils2 import safe_int
     _code = CONFIG.get('lock_ret_code')
     self.code = safe_int(_code, self.code)
     self.title = self.explanation = ('Repository `%s` locked by '
                                      'user `%s`' % (reponame, username))
     super(HTTPLockedRC, self).__init__(*args, **kwargs)
示例#6
0
def gravatar_url(email_address, size=30, ssl_enabled=True):
    from pylons import url  # doh, we need to re-import url to mock it later
    from rhodecode import CONFIG

    _def = '*****@*****.**'  # default gravatar
    use_gravatar = str2bool(CONFIG.get('use_gravatar'))
    alternative_gravatar_url = CONFIG.get('alternative_gravatar_url', '')
    email_address = email_address or _def
    if not use_gravatar or not email_address or email_address == _def:
        f = lambda a, l: min(l, key=lambda x: abs(x - a))
        return url("/images/user%s.png" % f(size, [14, 16, 20, 24, 30]))

    if use_gravatar and alternative_gravatar_url:
        tmpl = alternative_gravatar_url
        parsed_url = urlparse.urlparse(url.current(qualified=True))
        tmpl = tmpl.replace('{email}', email_address)\
                   .replace('{md5email}', hashlib.md5(email_address.lower()).hexdigest()) \
                   .replace('{netloc}', parsed_url.netloc)\
                   .replace('{scheme}', parsed_url.scheme)\
                   .replace('{size}', str(size))
        return tmpl

    default = 'identicon'
    baseurl_nossl = "http://www.gravatar.com/avatar/"
    baseurl_ssl = "https://secure.gravatar.com/avatar/"
    baseurl = baseurl_ssl if ssl_enabled else baseurl_nossl

    if isinstance(email_address, unicode):
        #hashlib crashes on unicode items
        email_address = safe_str(email_address)
    # construct the url
    gravatar_url = baseurl + hashlib.md5(
        email_address.lower()).hexdigest() + "?"
    gravatar_url += urllib.urlencode({'d': default, 's': str(size)})

    return gravatar_url
示例#7
0
    def archivefile(self, repo_name, fname):

        fileformat = None
        revision = None
        ext = None
        subrepos = request.GET.get('subrepos') == 'true'

        for a_type, ext_data in settings.ARCHIVE_SPECS.items():
            archive_spec = fname.split(ext_data[1])
            if len(archive_spec) == 2 and archive_spec[1] == '':
                fileformat = a_type or ext_data[1]
                revision = archive_spec[0]
                ext = ext_data[1]

        try:
            dbrepo = RepoModel().get_by_repo_name(repo_name)
            if not dbrepo.enable_downloads:
                return _('Downloads disabled')

            if c.rhodecode_repo.alias == 'hg':
                # patch and reset hooks section of UI config to not run any
                # hooks on fetching archives with subrepos
                for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
                    c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)

            cs = c.rhodecode_repo.get_changeset(revision)
            content_type = settings.ARCHIVE_SPECS[fileformat][0]
        except ChangesetDoesNotExistError:
            return _('Unknown revision %s') % revision
        except EmptyRepositoryError:
            return _('Empty repository')
        except (ImproperArchiveTypeError, KeyError):
            return _('Unknown archive type')
        # archive cache
        from rhodecode import CONFIG
        rev_name = cs.raw_id[:12]
        archive_name = '%s-%s%s' % (safe_str(repo_name.replace('/', '_')),
                                    safe_str(rev_name), ext)

        use_cached_archive = False  # defines if we use cached version of archive
        archive_cache_enabled = CONFIG.get('archive_cache_dir')
        if not subrepos and archive_cache_enabled:
            #check if we it's ok to write
            if not os.path.isdir(CONFIG['archive_cache_dir']):
                os.makedirs(CONFIG['archive_cache_dir'])
            cached_archive_path = os.path.join(CONFIG['archive_cache_dir'], archive_name)
            if os.path.isfile(cached_archive_path):
                log.debug('Found cached archive in %s' % cached_archive_path)
                fd, archive = None, cached_archive_path
                use_cached_archive = True
            else:
                log.debug('Archive %s is not yet cached' % (archive_name))

        if not use_cached_archive:
            #generate new archive
            try:
                fd, archive = tempfile.mkstemp()
                t = open(archive, 'wb')
                log.debug('Creating new temp archive in %s' % archive)
                cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
                if archive_cache_enabled:
                    #if we generated the archive and use cache rename that
                    log.debug('Storing new archive in %s' % cached_archive_path)
                    shutil.move(archive, cached_archive_path)
                    archive = cached_archive_path
            finally:
                t.close()

        def get_chunked_archive(archive):
            stream = open(archive, 'rb')
            while True:
                data = stream.read(16 * 1024)
                if not data:
                    stream.close()
                    if fd:  # fd means we used temporary file
                        os.close(fd)
                    if not archive_cache_enabled:
                        log.debug('Destroing temp archive %s' % archive)
                        os.remove(archive)
                    break
                yield data

        response.content_disposition = str('attachment; filename=%s' % (archive_name))
        response.content_type = str(content_type)
        return get_chunked_archive(archive)
示例#8
0
class SimpleHg(BaseVCSController):
    def _handle_request(self, environ, start_response):
        if not is_mercurial(environ):
            return self.application(environ, start_response)
        if not self._check_ssl(environ, start_response):
            return HTTPNotAcceptable('SSL REQUIRED !')(environ, start_response)

        ip_addr = self._get_ip_addr(environ)
        username = None
        # skip passing error to error controller
        environ['pylons.status_code_redirect'] = True

        #======================================================================
        # EXTRACT REPOSITORY NAME FROM ENV
        #======================================================================
        try:
            repo_name = environ['REPO_NAME'] = self.__get_repository(environ)
            log.debug('Extracted repo name is %s' % repo_name)
        except Exception:
            return HTTPInternalServerError()(environ, start_response)

        # quick check if that dir exists...
        if not is_valid_repo(repo_name, self.basepath, 'hg'):
            return HTTPNotFound()(environ, start_response)

        #======================================================================
        # GET ACTION PULL or PUSH
        #======================================================================
        action = self.__get_action(environ)

        #======================================================================
        # CHECK ANONYMOUS PERMISSION
        #======================================================================
        if action in ['pull', 'push']:
            anonymous_user = self.__get_user('default')
            username = anonymous_user.username
            anonymous_perm = self._check_permission(action, anonymous_user,
                                                    repo_name, ip_addr)

            if not anonymous_perm or not anonymous_user.active:
                if not anonymous_perm:
                    log.debug('Not enough credentials to access this '
                              'repository as anonymous user')
                if not anonymous_user.active:
                    log.debug('Anonymous access is disabled, running '
                              'authentication')
                #==============================================================
                # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
                # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
                #==============================================================

                # Attempting to retrieve username from the container
                username = get_container_username(environ, self.config)

                # If not authenticated by the container, running basic auth
                if not username:
                    self.authenticate.realm = \
                        safe_str(self.config['rhodecode_realm'])
                    result = self.authenticate(environ)
                    if isinstance(result, str):
                        AUTH_TYPE.update(environ, 'basic')
                        REMOTE_USER.update(environ, result)
                        username = result
                    else:
                        return result.wsgi_application(environ, start_response)

                #==============================================================
                # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
                #==============================================================
                try:
                    user = self.__get_user(username)
                    if user is None or not user.active:
                        return HTTPForbidden()(environ, start_response)
                    username = user.username
                except Exception:
                    log.error(traceback.format_exc())
                    return HTTPInternalServerError()(environ, start_response)

                #check permissions for this repository
                perm = self._check_permission(action, user, repo_name, ip_addr)
                if not perm:
                    return HTTPForbidden()(environ, start_response)

        # extras are injected into mercurial UI object and later available
        # in hg hooks executed by rhodecode
        from rhodecode import CONFIG
        server_url = get_server_url(environ)
        extras = {
            'ip': ip_addr,
            'username': username,
            'action': action,
            'repository': repo_name,
            'scm': 'hg',
            'config': CONFIG['__file__'],
            'server_url': server_url,
            'make_lock': None,
            'locked_by': [None, None]
        }
        #======================================================================
        # MERCURIAL REQUEST HANDLING
        #======================================================================
        str_repo_name = safe_str(repo_name)
        repo_path = os.path.join(safe_str(self.basepath), str_repo_name)
        log.debug('Repository path is %s' % repo_path)

        # CHECK LOCKING only if it's not ANONYMOUS USER
        if username != User.DEFAULT_USER:
            log.debug('Checking locking on repository')
            (make_lock, locked,
             locked_by) = self._check_locking_state(environ=environ,
                                                    action=action,
                                                    repo=repo_name,
                                                    user_id=user.user_id)
            # store the make_lock for later evaluation in hooks
            extras.update({'make_lock': make_lock, 'locked_by': locked_by})

        fix_PATH()
        log.debug('HOOKS extras is %s' % extras)
        baseui = make_ui('db')
        self.__inject_extras(repo_path, baseui, extras)

        try:
            log.info('%s action on HG repo "%s" by "%s" from %s' %
                     (action, str_repo_name, safe_str(username), ip_addr))
            app = self.__make_app(repo_path, baseui, extras)
            return app(environ, start_response)
        except RepoError, e:
            if str(e).find('not found') != -1:
                return HTTPNotFound()(environ, start_response)
        except HTTPLockedRC, e:
            _code = CONFIG.get('lock_ret_code')
            log.debug('Repository LOCKED ret code %s!' % (_code))
            return e(environ, start_response)
示例#9
0
    def archivefile(self, repo_name, fname):

        fileformat = None
        revision = None
        ext = None
        subrepos = request.GET.get('subrepos') == 'true'

        for a_type, ext_data in settings.ARCHIVE_SPECS.items():
            archive_spec = fname.split(ext_data[1])
            if len(archive_spec) == 2 and archive_spec[1] == '':
                fileformat = a_type or ext_data[1]
                revision = archive_spec[0]
                ext = ext_data[1]

        try:
            dbrepo = RepoModel().get_by_repo_name(repo_name)
            if not dbrepo.enable_downloads:
                return _('Downloads disabled')

            if c.rhodecode_repo.alias == 'hg':
                # patch and reset hooks section of UI config to not run any
                # hooks on fetching archives with subrepos
                for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
                    c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)

            cs = c.rhodecode_repo.get_changeset(revision)
            content_type = settings.ARCHIVE_SPECS[fileformat][0]
        except ChangesetDoesNotExistError:
            return _('Unknown revision %s') % revision
        except EmptyRepositoryError:
            return _('Empty repository')
        except (ImproperArchiveTypeError, KeyError):
            return _('Unknown archive type')
        # archive cache
        from rhodecode import CONFIG
        rev_name = cs.raw_id[:12]
        archive_name = '%s-%s%s' % (safe_str(repo_name.replace('/', '_')),
                                    safe_str(rev_name), ext)

        use_cached_archive = False  # defines if we use cached version of archive
        archive_cache_enabled = CONFIG.get('archive_cache_dir')
        if not subrepos and archive_cache_enabled:
            #check if we it's ok to write
            if not os.path.isdir(CONFIG['archive_cache_dir']):
                os.makedirs(CONFIG['archive_cache_dir'])
            cached_archive_path = os.path.join(CONFIG['archive_cache_dir'], archive_name)
            if os.path.isfile(cached_archive_path):
                log.debug('Found cached archive in %s' % cached_archive_path)
                fd, archive = None, cached_archive_path
                use_cached_archive = True
            else:
                log.debug('Archive %s is not yet cached' % (archive_name))

        if not use_cached_archive:
            #generate new archive
            try:
                fd, archive = tempfile.mkstemp()
                t = open(archive, 'wb')
                log.debug('Creating new temp archive in %s' % archive)
                cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
                if archive_cache_enabled:
                    #if we generated the archive and use cache rename that
                    log.debug('Storing new archive in %s' % cached_archive_path)
                    shutil.move(archive, cached_archive_path)
                    archive = cached_archive_path
            finally:
                t.close()

        def get_chunked_archive(archive):
            stream = open(archive, 'rb')
            while True:
                data = stream.read(16 * 1024)
                if not data:
                    stream.close()
                    if fd:  # fd means we used temporary file
                        os.close(fd)
                    if not archive_cache_enabled:
                        log.debug('Destroing temp archive %s' % archive)
                        os.remove(archive)
                    break
                yield data
        # store download action
        action_logger(user=c.rhodecode_user,
                      action='user_downloaded_archive:%s' % (archive_name),
                      repo=repo_name, ipaddr=self.ip_addr, commit=True)
        response.content_disposition = str('attachment; filename=%s' % (archive_name))
        response.content_type = str(content_type)
        return get_chunked_archive(archive)
示例#10
0
    def _handle_request(self, environ, start_response):
        if not is_git(environ):
            return self.application(environ, start_response)
        if not self._check_ssl(environ, start_response):
            return HTTPNotAcceptable('SSL REQUIRED !')(environ, start_response)

        ip_addr = self._get_ip_addr(environ)
        username = None
        self._git_first_op = False
        # skip passing error to error controller
        environ['pylons.status_code_redirect'] = True

        #======================================================================
        # EXTRACT REPOSITORY NAME FROM ENV
        #======================================================================
        try:
            repo_name = self.__get_repository(environ)
            log.debug('Extracted repo name is %s' % repo_name)
        except Exception:
            return HTTPInternalServerError()(environ, start_response)

        # quick check if that dir exists...
        if not is_valid_repo(repo_name, self.basepath, 'git'):
            return HTTPNotFound()(environ, start_response)

        #======================================================================
        # GET ACTION PULL or PUSH
        #======================================================================
        action = self.__get_action(environ)

        #======================================================================
        # CHECK ANONYMOUS PERMISSION
        #======================================================================
        if action in ['pull', 'push']:
            anonymous_user = self.__get_user('default')
            username = anonymous_user.username
            anonymous_perm = self._check_permission(action, anonymous_user,
                                                    repo_name, ip_addr)

            if not anonymous_perm or not anonymous_user.active:
                if not anonymous_perm:
                    log.debug('Not enough credentials to access this '
                              'repository as anonymous user')
                if not anonymous_user.active:
                    log.debug('Anonymous access is disabled, running '
                              'authentication')
                #==============================================================
                # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
                # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
                #==============================================================

                # Attempting to retrieve username from the container
                username = get_container_username(environ, self.config)

                # If not authenticated by the container, running basic auth
                if not username:
                    self.authenticate.realm = \
                        safe_str(self.config['rhodecode_realm'])
                    result = self.authenticate(environ)
                    if isinstance(result, str):
                        AUTH_TYPE.update(environ, 'basic')
                        REMOTE_USER.update(environ, result)
                        username = result
                    else:
                        return result.wsgi_application(environ, start_response)

                #==============================================================
                # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
                #==============================================================
                try:
                    user = self.__get_user(username)
                    if user is None or not user.active:
                        return HTTPForbidden()(environ, start_response)
                    username = user.username
                except Exception:
                    log.error(traceback.format_exc())
                    return HTTPInternalServerError()(environ, start_response)

                #check permissions for this repository
                perm = self._check_permission(action, user, repo_name, ip_addr)
                if not perm:
                    return HTTPForbidden()(environ, start_response)

        # extras are injected into UI object and later available
        # in hooks executed by rhodecode
        from rhodecode import CONFIG
        server_url = get_server_url(environ)
        extras = {
            'ip': ip_addr,
            'username': username,
            'action': action,
            'repository': repo_name,
            'scm': 'git',
            'config': CONFIG['__file__'],
            'server_url': server_url,
            'make_lock': None,
            'locked_by': [None, None]
        }

        #===================================================================
        # GIT REQUEST HANDLING
        #===================================================================
        str_repo_name = safe_str(repo_name)
        repo_path = os.path.join(safe_str(self.basepath),str_repo_name)
        log.debug('Repository path is %s' % repo_path)

        # CHECK LOCKING only if it's not ANONYMOUS USER
        if username != User.DEFAULT_USER:
            log.debug('Checking locking on repository')
            (make_lock,
             locked,
             locked_by) = self._check_locking_state(
                            environ=environ, action=action,
                            repo=repo_name, user_id=user.user_id
                       )
            # store the make_lock for later evaluation in hooks
            extras.update({'make_lock': make_lock,
                           'locked_by': locked_by})

        fix_PATH()
        log.debug('HOOKS extras is %s' % extras)
        baseui = make_ui('db')
        self.__inject_extras(repo_path, baseui, extras)

        try:
            self._handle_githooks(repo_name, action, baseui, environ)
            log.info('%s action on GIT repo "%s" by "%s" from %s' %
                     (action, str_repo_name, safe_str(username), ip_addr))
            app = self.__make_app(repo_name, repo_path, extras)
            return app(environ, start_response)
        except HTTPLockedRC, e:
            _code = CONFIG.get('lock_ret_code')
            log.debug('Repository LOCKED ret code %s!' % (_code))
            return e(environ, start_response)
示例#11
0
    def archivefile(self, repo_name, fname):

        fileformat = None
        revision = None
        ext = None
        subrepos = request.GET.get("subrepos") == "true"

        for a_type, ext_data in settings.ARCHIVE_SPECS.items():
            archive_spec = fname.split(ext_data[1])
            if len(archive_spec) == 2 and archive_spec[1] == "":
                fileformat = a_type or ext_data[1]
                revision = archive_spec[0]
                ext = ext_data[1]

        try:
            dbrepo = RepoModel().get_by_repo_name(repo_name)
            if not dbrepo.enable_downloads:
                return _("Downloads disabled")

            if c.rhodecode_repo.alias == "hg":
                # patch and reset hooks section of UI config to not run any
                # hooks on fetching archives with subrepos
                for k, v in c.rhodecode_repo._repo.ui.configitems("hooks"):
                    c.rhodecode_repo._repo.ui.setconfig("hooks", k, None)

            cs = c.rhodecode_repo.get_changeset(revision)
            content_type = settings.ARCHIVE_SPECS[fileformat][0]
        except ChangesetDoesNotExistError:
            return _("Unknown revision %s") % revision
        except EmptyRepositoryError:
            return _("Empty repository")
        except (ImproperArchiveTypeError, KeyError):
            return _("Unknown archive type")
        # archive cache
        from rhodecode import CONFIG

        rev_name = cs.raw_id[:12]
        archive_name = "%s-%s%s" % (safe_str(repo_name.replace("/", "_")), safe_str(rev_name), ext)

        use_cached_archive = False  # defines if we use cached version of archive
        archive_cache_enabled = CONFIG.get("archive_cache_dir")
        if not subrepos and archive_cache_enabled:
            # check if we it's ok to write
            if not os.path.isdir(CONFIG["archive_cache_dir"]):
                os.makedirs(CONFIG["archive_cache_dir"])
            cached_archive_path = os.path.join(CONFIG["archive_cache_dir"], archive_name)
            if os.path.isfile(cached_archive_path):
                log.debug("Found cached archive in %s" % cached_archive_path)
                fd, archive = None, cached_archive_path
                use_cached_archive = True
            else:
                log.debug("Archive %s is not yet cached" % (archive_name))

        if not use_cached_archive:
            # generate new archive
            try:
                fd, archive = tempfile.mkstemp()
                t = open(archive, "wb")
                log.debug("Creating new temp archive in %s" % archive)
                cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
                if archive_cache_enabled:
                    # if we generated the archive and use cache rename that
                    log.debug("Storing new archive in %s" % cached_archive_path)
                    shutil.move(archive, cached_archive_path)
                    archive = cached_archive_path
            finally:
                t.close()

        def get_chunked_archive(archive):
            stream = open(archive, "rb")
            while True:
                data = stream.read(16 * 1024)
                if not data:
                    stream.close()
                    if fd:  # fd means we used temporary file
                        os.close(fd)
                    if not archive_cache_enabled:
                        log.debug("Destroing temp archive %s" % archive)
                        os.remove(archive)
                    break
                yield data

        response.content_disposition = str("attachment; filename=%s" % (archive_name))
        response.content_type = str(content_type)
        return get_chunked_archive(archive)
示例#12
0
    def archivefile(self, repo_name, fname):
        fileformat = None
        commit_id = None
        ext = None
        subrepos = request.GET.get('subrepos') == 'true'

        for a_type, ext_data in settings.ARCHIVE_SPECS.items():
            archive_spec = fname.split(ext_data[1])
            if len(archive_spec) == 2 and archive_spec[1] == '':
                fileformat = a_type or ext_data[1]
                commit_id = archive_spec[0]
                ext = ext_data[1]

        dbrepo = RepoModel().get_by_repo_name(repo_name)
        if not dbrepo.enable_downloads:
            return _('Downloads disabled')

        try:
            commit = c.rhodecode_repo.get_commit(commit_id)
            content_type = settings.ARCHIVE_SPECS[fileformat][0]
        except CommitDoesNotExistError:
            return _('Unknown revision %s') % commit_id
        except EmptyRepositoryError:
            return _('Empty repository')
        except KeyError:
            return _('Unknown archive type')

        # archive cache
        from rhodecode import CONFIG

        archive_name = '%s-%s%s%s' % (safe_str(repo_name.replace(
            '/', '_')), '-sub' if subrepos else '', safe_str(
                commit.short_id), ext)

        use_cached_archive = False
        archive_cache_enabled = CONFIG.get(
            'archive_cache_dir') and not request.GET.get('no_cache')

        if archive_cache_enabled:
            # check if we it's ok to write
            if not os.path.isdir(CONFIG['archive_cache_dir']):
                os.makedirs(CONFIG['archive_cache_dir'])
            cached_archive_path = os.path.join(CONFIG['archive_cache_dir'],
                                               archive_name)
            if os.path.isfile(cached_archive_path):
                log.debug('Found cached archive in %s', cached_archive_path)
                fd, archive = None, cached_archive_path
                use_cached_archive = True
            else:
                log.debug('Archive %s is not yet cached', archive_name)

        if not use_cached_archive:
            # generate new archive
            fd, archive = tempfile.mkstemp()
            log.debug('Creating new temp archive in %s' % (archive, ))
            try:
                commit.archive_repo(archive,
                                    kind=fileformat,
                                    subrepos=subrepos)
            except ImproperArchiveTypeError:
                return _('Unknown archive type')
            if archive_cache_enabled:
                # if we generated the archive and we have cache enabled
                # let's use this for future
                log.debug('Storing new archive in %s' %
                          (cached_archive_path, ))
                shutil.move(archive, cached_archive_path)
                archive = cached_archive_path

        def get_chunked_archive(archive):
            with open(archive, 'rb') as stream:
                while True:
                    data = stream.read(16 * 1024)
                    if not data:
                        if fd:  # fd means we used temporary file
                            os.close(fd)
                        if not archive_cache_enabled:
                            log.debug('Destroying temp archive %s', archive)
                            os.remove(archive)
                        break
                    yield data

        # store download action
        action_logger(user=c.rhodecode_user,
                      action='user_downloaded_archive:%s' % archive_name,
                      repo=repo_name,
                      ipaddr=self.ip_addr,
                      commit=True)
        response.content_disposition = str('attachment; filename=%s' %
                                           archive_name)
        response.content_type = str(content_type)

        return get_chunked_archive(archive)
示例#13
0
    def _handle_request(self, environ, start_response):
        if not is_git(environ):
            return self.application(environ, start_response)
        if not self._check_ssl(environ, start_response):
            return HTTPNotAcceptable("SSL REQUIRED !")(environ, start_response)

        ip_addr = self._get_ip_addr(environ)
        username = None
        self._git_first_op = False
        # skip passing error to error controller
        environ["pylons.status_code_redirect"] = True

        # ======================================================================
        # EXTRACT REPOSITORY NAME FROM ENV
        # ======================================================================
        try:
            repo_name = self.__get_repository(environ)
            log.debug("Extracted repo name is %s" % repo_name)
        except Exception:
            return HTTPInternalServerError()(environ, start_response)

        # quick check if that dir exists...
        if not is_valid_repo(repo_name, self.basepath, "git"):
            return HTTPNotFound()(environ, start_response)

        # ======================================================================
        # GET ACTION PULL or PUSH
        # ======================================================================
        action = self.__get_action(environ)

        # ======================================================================
        # CHECK ANONYMOUS PERMISSION
        # ======================================================================
        if action in ["pull", "push"]:
            anonymous_user = self.__get_user("default")
            username = anonymous_user.username
            anonymous_perm = self._check_permission(action, anonymous_user, repo_name, ip_addr)

            if not anonymous_perm or not anonymous_user.active:
                if not anonymous_perm:
                    log.debug("Not enough credentials to access this " "repository as anonymous user")
                if not anonymous_user.active:
                    log.debug("Anonymous access is disabled, running " "authentication")
                # ==============================================================
                # DEFAULT PERM FAILED OR ANONYMOUS ACCESS IS DISABLED SO WE
                # NEED TO AUTHENTICATE AND ASK FOR AUTH USER PERMISSIONS
                # ==============================================================

                # Attempting to retrieve username from the container
                username = get_container_username(environ, self.config)

                # If not authenticated by the container, running basic auth
                if not username:
                    self.authenticate.realm = safe_str(self.config["rhodecode_realm"])
                    result = self.authenticate(environ)
                    if isinstance(result, str):
                        AUTH_TYPE.update(environ, "basic")
                        REMOTE_USER.update(environ, result)
                        username = result
                    else:
                        return result.wsgi_application(environ, start_response)

                # ==============================================================
                # CHECK PERMISSIONS FOR THIS REQUEST USING GIVEN USERNAME
                # ==============================================================
                try:
                    user = self.__get_user(username)
                    if user is None or not user.active:
                        return HTTPForbidden()(environ, start_response)
                    username = user.username
                except Exception:
                    log.error(traceback.format_exc())
                    return HTTPInternalServerError()(environ, start_response)

                # check permissions for this repository
                perm = self._check_permission(action, user, repo_name, ip_addr)
                if not perm:
                    return HTTPForbidden()(environ, start_response)

        # extras are injected into UI object and later available
        # in hooks executed by rhodecode
        from rhodecode import CONFIG

        server_url = get_server_url(environ)
        extras = {
            "ip": ip_addr,
            "username": username,
            "action": action,
            "repository": repo_name,
            "scm": "git",
            "config": CONFIG["__file__"],
            "server_url": server_url,
            "make_lock": None,
            "locked_by": [None, None],
        }

        # ===================================================================
        # GIT REQUEST HANDLING
        # ===================================================================
        str_repo_name = safe_str(repo_name)
        repo_path = os.path.join(safe_str(self.basepath), str_repo_name)
        log.debug("Repository path is %s" % repo_path)

        # CHECK LOCKING only if it's not ANONYMOUS USER
        if username != User.DEFAULT_USER:
            log.debug("Checking locking on repository")
            (make_lock, locked, locked_by) = self._check_locking_state(
                environ=environ, action=action, repo=repo_name, user_id=user.user_id
            )
            # store the make_lock for later evaluation in hooks
            extras.update({"make_lock": make_lock, "locked_by": locked_by})
        # set the environ variables for this request
        os.environ["RC_SCM_DATA"] = json.dumps(extras)
        fix_PATH()
        log.debug("HOOKS extras is %s" % extras)
        baseui = make_ui("db")
        self.__inject_extras(repo_path, baseui, extras)

        try:
            self._handle_githooks(repo_name, action, baseui, environ)
            log.info(
                '%s action on GIT repo "%s" by "%s" from %s' % (action, str_repo_name, safe_str(username), ip_addr)
            )
            app = self.__make_app(repo_name, repo_path, extras)
            return app(environ, start_response)
        except HTTPLockedRC, e:
            _code = CONFIG.get("lock_ret_code")
            log.debug("Repository LOCKED ret code %s!" % (_code))
            return e(environ, start_response)