Changeset - 8f468d08f463
[Not reviewed]
Merge default
0 34 2
Mads Kiilerich - 6 years ago 2020-01-22 23:46:12
mads@kiilerich.com
Merge stable
35 files changed with 194 insertions and 83 deletions:
0 comments (0 inline, 0 general)
.hgtags
Show inline comments
 
@@ -74,3 +74,4 @@ a18445b85d407294da0b7f1d8be3bedef5ffdea6
 
19086c5de05f4984d7a90cd31624c45dd893f6bb 0.4.0
 
da65398a62fff50f3d241796cbf17acdea2092ef 0.4.1
 
bfa0b0a814644f0af3f492d17a9ed169cc3b89fe 0.5.0
 
d01a8e92936dbd62c76505432f60efba432e9397 0.5.1
CONTRIBUTORS
Show inline comments
 
List of contributors to Kallithea project:
 

	
 
    Thomas De Schampheleire <thomas.de_schampheleire@nokia.com> 2014-2020
 
    Mads Kiilerich <mads@kiilerich.com> 2016-2020
 
    Andrej Shadura <andrew@shadura.me> 2012 2014-2017 2019
 
    Thomas De Schampheleire <thomas.de_schampheleire@nokia.com> 2014-2019
 
    Étienne Gilli <etienne.gilli@gmail.com> 2015-2017 2019
 
    Mads Kiilerich <mads@kiilerich.com> 2016-2019
 
    Allan Nordhøy <epost@anotheragency.no> 2017-2019
 
    ssantos <ssantos@web.de> 2018-2019
 
    Adi Kriegisch <adi@cg.tuwien.ac.at> 2019
 
    Danni Randeris <danniranderis@gmail.com> 2019
 
    Edmund Wong <ewong@crazy-cat.org> 2019
 
    Elizabeth Sherrock <lizzyd710@gmail.com> 2019
 
@@ -15,6 +16,7 @@ List of contributors to Kallithea projec
 
    Mateusz Mendel <mendelm9@gmail.com> 2019
 
    Nathan <bonnemainsnathan@gmail.com> 2019
 
    Oleksandr Shtalinberg <o.shtalinberg@gmail.com> 2019
 
    Private <adamantine.sword@gmail.com> 2019
 
    THANOS SIOURDAKIS <siourdakisthanos@gmail.com> 2019
 
    Wolfgang Scherer <wolfgang.scherer@gmx.de> 2019
 
    Христо Станев <hstanev@gmail.com> 2019
development.ini
Show inline comments
 
@@ -90,10 +90,12 @@ full_stack = true
 
static_files = true
 

	
 
## Internationalization (see setup documentation for details)
 
## By default, the language requested by the browser is used if available.
 
#i18n.enabled = false
 
## Fallback language, empty for English (valid values are the names of subdirectories in kallithea/i18n):
 
i18n.lang =
 
## By default, the languages requested by the browser are used if available, with English as default.
 
## Set i18n.enabled=false to disable automatic language choice.
 
#i18n.enabled = true
 
## To Force a language, set i18n.enabled=false and specify the language in i18n.lang.
 
## Valid values are the names of subdirectories in kallithea/i18n with a LC_MESSAGES/kallithea.mo
 
#i18n.lang = en
 

	
 
cache_dir = %(here)s/data
 
index_dir = %(here)s/data/index
docs/conf.py
Show inline comments
 
@@ -47,7 +47,7 @@ master_doc = 'index'
 

	
 
# General information about the project.
 
project = u'Kallithea'
 
copyright = u'2010-2019 by various authors, licensed as GPLv3.'
 
copyright = u'2010-2020 by various authors, licensed as GPLv3.'
 

	
 
# The version info for the project you're documenting, acts as replacement for
 
# |version| and |release|, also used in various other places throughout the
docs/setup.rst
Show inline comments
 
@@ -80,13 +80,12 @@ The Kallithea web interface is automatic
 
language, as indicated by the browser. Thus, different users may see the
 
application in different languages. If the requested language is not available
 
(because the translation file for that language does not yet exist or is
 
incomplete), the language specified in setting ``i18n.lang`` in the Kallithea
 
configuration file is used as fallback. If no fallback language is explicitly
 
specified, English is used.
 
incomplete), English is used.
 

	
 
If you want to disable automatic language detection and instead configure a
 
fixed language regardless of user preference, set ``i18n.enabled = false`` and
 
set ``i18n.lang`` to the desired language (or leave empty for English).
 
specify another language by setting ``i18n.lang`` in the Kallithea
 
configuration file.
 

	
 

	
 
Using Kallithea with SSH
 
@@ -562,7 +561,7 @@ that, you'll need to:
 

	
 
      ini = '/srv/kallithea/my.ini'
 
      from logging.config import fileConfig
 
      fileConfig(ini)
 
      fileConfig(ini, {'__file__': ini, 'here': '/srv/kallithea'})
 
      from paste.deploy import loadapp
 
      application = loadapp('config:' + ini)
 

	
 
@@ -578,7 +577,7 @@ that, you'll need to:
 

	
 
      ini = '/srv/kallithea/kallithea.ini'
 
      from logging.config import fileConfig
 
      fileConfig(ini)
 
      fileConfig(ini, {'__file__': ini, 'here': '/srv/kallithea'})
 
      from paste.deploy import loadapp
 
      application = loadapp('config:' + ini)
 

	
kallithea/alembic/env.py
Show inline comments
 
@@ -15,6 +15,7 @@
 
# Alembic migration environment (configuration).
 

	
 
import logging
 
import os
 
from logging.config import fileConfig
 

	
 
from alembic import context
 
@@ -43,7 +44,9 @@ logging.getLogger('alembic').setLevel(lo
 
# stamping during "kallithea-cli db-create"), config_file_name is not available,
 
# and loggers are assumed to already have been configured.
 
if config.config_file_name:
 
    fileConfig(config.config_file_name, disable_existing_loggers=False)
 
    fileConfig(config.config_file_name,
 
        {'__file__': config.config_file_name, 'here': os.path.dirname(config.config_file_name)},
 
        disable_existing_loggers=False)
 

	
 

	
 
def include_in_autogeneration(object, name, type, reflected, compare_to):
kallithea/alembic/versions/4851d15bc437_db_migration_step_after_95c01895c006_.py
Show inline comments
 
@@ -31,14 +31,20 @@ from alembic import op
 

	
 

	
 
def upgrade():
 
    meta = sa.MetaData()
 
    meta.reflect(bind=op.get_bind())
 
    pass
 
    # The following upgrade step turned out to be a bad idea. A later step
 
    # "d7ec25b66e47_ssh_drop_usk_public_key_idx_again" will remove the index
 
    # again if it exists ... but we shouldn't even try to create it.
 

	
 
    if not any(i.name == 'usk_public_key_idx' for i in meta.tables['user_ssh_keys'].indexes):
 
        with op.batch_alter_table('user_ssh_keys', schema=None) as batch_op:
 
            batch_op.create_index('usk_public_key_idx', ['public_key'], unique=False)
 
    #meta = sa.MetaData()
 
    #meta.reflect(bind=op.get_bind())
 

	
 
    #if not any(i.name == 'usk_public_key_idx' for i in meta.tables['user_ssh_keys'].indexes):
 
    #    with op.batch_alter_table('user_ssh_keys', schema=None) as batch_op:
 
    #        batch_op.create_index('usk_public_key_idx', ['public_key'], unique=False)
 

	
 

	
 
def downgrade():
 
    if any(i.name == 'usk_public_key_idx' for i in meta.tables['user_ssh_keys'].indexes):
 
    with op.batch_alter_table('user_ssh_keys', schema=None) as batch_op:
 
        batch_op.drop_index('usk_public_key_idx')
kallithea/alembic/versions/d7ec25b66e47_ssh_drop_usk_public_key_idx_again.py
Show inline comments
 
new file 100644
 
# This program is free software: you can redistribute it and/or modify
 
# it under the terms of the GNU General Public License as published by
 
# the Free Software Foundation, either version 3 of the License, or
 
# (at your option) any later version.
 
#
 
# This program is distributed in the hope that it will be useful,
 
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
# GNU General Public License for more details.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
"""ssh: drop usk_public_key_idx again
 

	
 
Revision ID: d7ec25b66e47
 
Revises: 4851d15bc437
 
Create Date: 2019-12-29 15:33:10.982003
 

	
 
"""
 

	
 
# The following opaque hexadecimal identifiers ("revisions") are used
 
# by Alembic to track this migration script and its relations to others.
 
revision = 'd7ec25b66e47'
 
down_revision = '4851d15bc437'
 
branch_labels = None
 
depends_on = None
 

	
 
import sqlalchemy as sa
 
from alembic import op
 

	
 

	
 
def upgrade():
 
    meta = sa.MetaData()
 
    meta.reflect(bind=op.get_bind())
 

	
 
    if any(i.name == 'usk_public_key_idx' for i in meta.tables['user_ssh_keys'].indexes):
 
        with op.batch_alter_table('user_ssh_keys', schema=None) as batch_op:
 
            batch_op.drop_index('usk_public_key_idx')
 

	
 

	
 
def downgrade():
 
    pass
kallithea/bin/kallithea_cli_base.py
Show inline comments
 
@@ -72,7 +72,8 @@ def register_command(config_file=False, 
 
                path_to_ini_file = os.path.realpath(config_file)
 
                kallithea.CONFIG = paste.deploy.appconfig('config:' + path_to_ini_file)
 
                config_string = read_config(path_to_ini_file, strip_section_prefix=annotated.__name__)
 
                logging.config.fileConfig(io.StringIO(config_string))
 
                logging.config.fileConfig(io.StringIO(config_string),
 
                    {'__file__': path_to_ini_file, 'here': os.path.dirname(path_to_ini_file)})
 
                if config_file_initialize_app:
 
                    kallithea.config.middleware.make_app_without_logging(kallithea.CONFIG.global_conf, **kallithea.CONFIG.local_conf)
 
                return annotated(*args, **kwargs)
kallithea/bin/kallithea_cli_iis.py
Show inline comments
 
@@ -33,7 +33,8 @@ import os
 
def __ExtensionFactory__():
 
    from paste.deploy import loadapp
 
    from logging.config import fileConfig
 
    fileConfig('%(inifile)s')
 
    fileConfig('%(inifile)s', {'__file__': '%(inifile)s', 'here': '%(inifiledir)s'})
 

	
 
    application = loadapp('config:%(inifile)s')
 

	
 
    def app(environ, start_response):
 
@@ -75,6 +76,7 @@ def iis_install(virtualdir):
 
    with open(dispatchfile, 'w') as f:
 
        f.write(dispath_py_template % {
 
            'inifile': config_file_abs.replace('\\', '\\\\'),
 
            'inifiledir': os.path.dirname(config_file_abs).replace('\\', '\\\\'),
 
            'virtualdir': virtualdir,
 
            })
 

	
kallithea/bin/kallithea_cli_ssh.py
Show inline comments
 
@@ -24,7 +24,7 @@ import kallithea.bin.kallithea_cli_base 
 
from kallithea.lib.utils2 import str2bool
 
from kallithea.lib.vcs.backends.git.ssh import GitSshHandler
 
from kallithea.lib.vcs.backends.hg.ssh import MercurialSshHandler
 
from kallithea.model.ssh_key import SshKeyModel
 
from kallithea.model.ssh_key import SshKeyModel, SshKeyModelException
 

	
 

	
 
log = logging.getLogger(__name__)
 
@@ -82,5 +82,8 @@ def ssh_update_authorized_keys():
 

	
 
    The file is usually maintained automatically, but this command will also re-write it.
 
    """
 

	
 
    try:
 
    SshKeyModel().write_authorized_keys()
 
    except SshKeyModelException as e:
 
        sys.stderr.write("%s\n" % e)
 
        sys.exit(1)
kallithea/config/app_cfg.py
Show inline comments
 
@@ -98,6 +98,11 @@ class KallitheaAppConfig(AppConfig):
 
        # Disable transaction manager -- currently Kallithea takes care of transactions itself
 
        self['tm.enabled'] = False
 

	
 
        # Set the i18n source language so TG doesn't search beyond 'en' in Accept-Language.
 
        # Don't force the default here if configuration force something else.
 
        if not self.get('i18n.lang'):
 
            self['i18n.lang'] = 'en'
 

	
 

	
 
base_config = KallitheaAppConfig()
 

	
kallithea/config/middleware.py
Show inline comments
 
@@ -13,8 +13,6 @@
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
"""WSGI middleware initialization for the Kallithea application."""
 

	
 
import logging.config
 

	
 
from kallithea.config.app_cfg import base_config
 
from kallithea.config.environment import load_environment
 

	
 
@@ -49,5 +47,4 @@ def make_app(global_conf, full_stack=Tru
 
    ``app_conf`` contains all the application-specific settings (those defined
 
    under ``[app:main]``.
 
    """
 
    logging.config.fileConfig(global_conf['__file__'])
 
    return make_app_without_logging(global_conf, full_stack=full_stack, **app_conf)
kallithea/controllers/admin/my_account.py
Show inline comments
 
@@ -285,9 +285,9 @@ class MyAccountController(BaseController
 

	
 
    @IfSshEnabled
 
    def my_account_ssh_keys_delete(self):
 
        public_key = request.POST.get('del_public_key')
 
        fingerprint = request.POST.get('del_public_key_fingerprint')
 
        try:
 
            SshKeyModel().delete(public_key, request.authuser.user_id)
 
            SshKeyModel().delete(fingerprint, request.authuser.user_id)
 
            Session().commit()
 
            SshKeyModel().write_authorized_keys()
 
            h.flash(_("SSH key successfully deleted"), category='success')
kallithea/controllers/admin/users.py
Show inline comments
 
@@ -460,9 +460,9 @@ class UsersController(BaseController):
 
    def ssh_keys_delete(self, id):
 
        c.user = self._get_user_or_raise_if_default(id)
 

	
 
        public_key = request.POST.get('del_public_key')
 
        fingerprint = request.POST.get('del_public_key_fingerprint')
 
        try:
 
            SshKeyModel().delete(public_key, c.user.user_id)
 
            SshKeyModel().delete(fingerprint, c.user.user_id)
 
            Session().commit()
 
            SshKeyModel().write_authorized_keys()
 
            h.flash(_("SSH key successfully deleted"), category='success')
kallithea/controllers/login.py
Show inline comments
 
@@ -210,12 +210,10 @@ class LoginController(BaseController):
 

	
 
        # The template needs the email address outside of the form.
 
        c.email = request.params.get('email')
 

	
 
        c.timestamp = request.params.get('timestamp') or ''
 
        c.token = request.params.get('token') or ''
 
        if not request.POST:
 
            return htmlfill.render(
 
                render('/password_reset_confirmation.html'),
 
                defaults=dict(request.params),
 
                encoding='UTF-8')
 
            return render('/password_reset_confirmation.html')
 

	
 
        form = PasswordResetConfirmationForm()()
 
        try:
kallithea/i18n/en/LC_MESSAGES/kallithea.mo
Show inline comments
 
new file 100644
 
binary diff not shown
kallithea/lib/auth.py
Show inline comments
 
@@ -28,6 +28,7 @@ import hashlib
 
import itertools
 
import logging
 
import os
 
import string
 

	
 
import ipaddr
 
from decorator import decorator
 
@@ -109,8 +110,9 @@ def check_password(password, hashed):
 
    :param password: password
 
    :param hashed: password in hashed form
 
    """
 

	
 
    if is_windows:
 
    # sha256 hashes will always be 64 hex chars
 
    # bcrypt hashes will always contain $ (and be shorter)
 
    if is_windows or len(hashed) == 64 and all(x in string.hexdigits for x in hashed):
 
        return hashlib.sha256(safe_bytes(password)).hexdigest() == hashed
 
    elif is_unix:
 
        import bcrypt
kallithea/lib/hooks.py
Show inline comments
 
@@ -26,6 +26,7 @@ Original author and date, and relevant c
 
"""
 

	
 
import os
 
import sys
 
import time
 

	
 
import mercurial.scmutil
 
@@ -33,7 +34,7 @@ import mercurial.scmutil
 
from kallithea.lib import helpers as h
 
from kallithea.lib.exceptions import UserCreationError
 
from kallithea.lib.utils import action_logger, make_ui
 
from kallithea.lib.utils2 import ascii_str, get_hook_environment, safe_bytes, safe_str, safe_unicode
 
from kallithea.lib.utils2 import HookEnvironmentError, ascii_str, get_hook_environment, safe_bytes, safe_str, safe_unicode
 
from kallithea.lib.vcs.backends.base import EmptyChangeset
 
from kallithea.model.db import Repository, User
 

	
 
@@ -333,7 +334,11 @@ def handle_git_pre_receive(repo_path, gi
 

	
 
def handle_git_post_receive(repo_path, git_stdin_lines):
 
    """Called from Git post-receive hook"""
 
    try:
 
    baseui, repo = _hook_environment(repo_path)
 
    except HookEnvironmentError as e:
 
        sys.stderr.write("Skipping Kallithea Git post-recieve hook %r.\nGit was apparently not invoked by Kallithea: %s\n" % (sys.argv[0], e))
 
        return 0
 

	
 
    # the post push hook should never use the cached instance
 
    scm_repo = repo.scm_instance_no_cache()
kallithea/lib/paster_commands/template.ini.mako
Show inline comments
 
@@ -185,10 +185,12 @@ full_stack = true
 
static_files = true
 

	
 
<%text>## Internationalization (see setup documentation for details)</%text>
 
<%text>## By default, the language requested by the browser is used if available.</%text>
 
#i18n.enabled = false
 
<%text>## Fallback language, empty for English (valid values are the names of subdirectories in kallithea/i18n):</%text>
 
i18n.lang =
 
<%text>## By default, the languages requested by the browser are used if available, with English as default.</%text>
 
<%text>## Set i18n.enabled=false to disable automatic language choice.</%text>
 
#i18n.enabled = true
 
<%text>## To Force a language, set i18n.enabled=false and specify the language in i18n.lang.</%text>
 
<%text>## Valid values are the names of subdirectories in kallithea/i18n with a LC_MESSAGES/kallithea.mo</%text>
 
#i18n.lang = en
 

	
 
cache_dir = %(here)s/data
 
index_dir = %(here)s/data/index
kallithea/lib/ssh.py
Show inline comments
 
@@ -48,7 +48,7 @@ def parse_pub_key(ssh_key):
 
    >>> parse_pub_key('''AAAAB3NzaC1yc2EAAAALVGhpcyBpcyBmYWtlIQ''')
 
    Traceback (most recent call last):
 
    ...
 
    SshKeyParseError: Incorrect SSH key - it must have both a key type and a base64 part
 
    SshKeyParseError: Incorrect SSH key - it must have both a key type and a base64 part, like 'ssh-rsa ASRNeaZu4FA...xlJp='
 
    >>> parse_pub_key('''abc AAAAB3NzaC1yc2EAAAALVGhpcyBpcyBmYWtlIQ''')
 
    Traceback (most recent call last):
 
    ...
 
@@ -76,7 +76,7 @@ def parse_pub_key(ssh_key):
 

	
 
    parts = ssh_key.split(None, 2)
 
    if len(parts) < 2:
 
        raise SshKeyParseError(_("Incorrect SSH key - it must have both a key type and a base64 part"))
 
        raise SshKeyParseError(_("Incorrect SSH key - it must have both a key type and a base64 part, like 'ssh-rsa ASRNeaZu4FA...xlJp='"))
 

	
 
    keytype, keyvalue, comment = (parts + [''])[:3]
 
    if keytype not in ('ssh-rsa', 'ssh-dss', 'ssh-ed25519'):
 
@@ -99,6 +99,18 @@ def parse_pub_key(ssh_key):
 
SSH_OPTIONS = 'no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding'
 

	
 

	
 
def _safe_check(s, rec = re.compile('^[a-zA-Z0-9+/]+={0,2}$')):
 
    """Return true if s really has the right content for base64 encoding and only contains safe characters
 
    >>> _safe_check('asdf')
 
    True
 
    >>> _safe_check('as df')
 
    False
 
    >>> _safe_check('AAAAB3NzaC1yc2EAAAALVGhpcyBpcyBmYWtlIQ==')
 
    True
 
    """
 
    return rec.match(s) is not None
 

	
 

	
 
def authorized_keys_line(kallithea_cli_path, config_file, key):
 
    """
 
    Return a line as it would appear in .authorized_keys
 
@@ -116,6 +128,8 @@ def authorized_keys_line(kallithea_cli_p
 
        return '# Invalid Kallithea SSH key: %s %s\n' % (key.user.user_id, key.user_ssh_key_id)
 
    base64_key = ascii_str(base64.b64encode(key_bytes))
 
    assert '\n' not in base64_key
 
    if not _safe_check(base64_key):
 
        return '# Invalid Kallithea SSH key - bad base64 encoding: %s %s\n' % (key.user.user_id, key.user_ssh_key_id)
 
    return '%s,command="%s ssh-serve -c %s %s %s" %s %s\n' % (
 
        SSH_OPTIONS, kallithea_cli_path, config_file,
 
        key.user.user_id, key.user_ssh_key_id,
kallithea/lib/utils2.py
Show inline comments
 
@@ -430,6 +430,9 @@ def obfuscate_url_pw(engine):
 
    return str(_url)
 

	
 

	
 
class HookEnvironmentError(Exception): pass
 

	
 

	
 
def get_hook_environment():
 
    """
 
    Get hook context by deserializing the global KALLITHEA_EXTRAS environment
 
@@ -441,15 +444,16 @@ def get_hook_environment():
 
    """
 

	
 
    try:
 
        extras = json.loads(os.environ['KALLITHEA_EXTRAS'])
 
        kallithea_extras = os.environ['KALLITHEA_EXTRAS']
 
    except KeyError:
 
        raise Exception("Environment variable KALLITHEA_EXTRAS not found")
 
        raise HookEnvironmentError("Environment variable KALLITHEA_EXTRAS not found")
 

	
 
    extras = json.loads(kallithea_extras)
 
    try:
 
        for k in ['username', 'repository', 'scm', 'action', 'ip']:
 
        for k in ['username', 'repository', 'scm', 'action', 'ip', 'config']:
 
            extras[k]
 
    except KeyError:
 
        raise Exception('Missing key %s in KALLITHEA_EXTRAS %s' % (k, extras))
 
        raise HookEnvironmentError('Missing key %s in KALLITHEA_EXTRAS %s' % (k, extras))
 

	
 
    return AttributeDict(extras)
 

	
kallithea/model/db.py
Show inline comments
 
@@ -2523,7 +2523,6 @@ class Gist(Base, BaseDbModel):
 
class UserSshKeys(Base, BaseDbModel):
 
    __tablename__ = 'user_ssh_keys'
 
    __table_args__ = (
 
        Index('usk_public_key_idx', 'public_key'),
 
        Index('usk_fingerprint_idx', 'fingerprint'),
 
        UniqueConstraint('fingerprint'),
 
        _table_args_default_dict
kallithea/model/ssh_key.py
Show inline comments
 
@@ -30,6 +30,7 @@ from tg.i18n import ugettext as _
 

	
 
from kallithea.lib import ssh
 
from kallithea.lib.utils2 import str2bool
 
from kallithea.lib.vcs.exceptions import RepositoryError
 
from kallithea.model.db import User, UserSshKeys
 
from kallithea.model.meta import Session
 

	
 
@@ -37,7 +38,7 @@ from kallithea.model.meta import Session
 
log = logging.getLogger(__name__)
 

	
 

	
 
class SshKeyModelException(Exception):
 
class SshKeyModelException(RepositoryError):
 
    """Exception raised by SshKeyModel methods to report errors"""
 

	
 

	
 
@@ -72,21 +73,19 @@ class SshKeyModel(object):
 

	
 
        return new_ssh_key
 

	
 
    def delete(self, public_key, user=None):
 
    def delete(self, fingerprint, user):
 
        """
 
        Deletes given public_key, if user is set it also filters the object for
 
        deletion by given user.
 
        Deletes ssh key with given fingerprint for the given user.
 
        Will raise SshKeyModelException on errors
 
        """
 
        ssh_key = UserSshKeys.query().filter(UserSshKeys._public_key == public_key)
 
        ssh_key = UserSshKeys.query().filter(UserSshKeys.fingerprint == fingerprint)
 

	
 
        if user:
 
            user = User.guess_instance(user)
 
            ssh_key = ssh_key.filter(UserSshKeys.user_id == user.user_id)
 

	
 
        ssh_key = ssh_key.scalar()
 
        if ssh_key is None:
 
            raise SshKeyModelException(_('SSH key %r not found') % public_key)
 
            raise SshKeyModelException(_('SSH key with fingerprint %r found') % fingerprint)
 
        Session().delete(ssh_key)
 

	
 
    def get_ssh_keys(self, user):
 
@@ -116,7 +115,7 @@ class SshKeyModel(object):
 
        # Now, test that the directory is or was created in a readable way by previous.
 
        if not (os.path.isdir(authorized_keys_dir) and
 
                os.access(authorized_keys_dir, os.W_OK)):
 
            raise Exception("Directory of authorized_keys cannot be written to so authorized_keys file %s cannot be written" % (authorized_keys))
 
            raise SshKeyModelException("Directory of authorized_keys cannot be written to so authorized_keys file %s cannot be written" % (authorized_keys))
 

	
 
        # Make sure we don't overwrite a key file with important content
 
        if os.path.exists(authorized_keys):
 
@@ -127,10 +126,11 @@ class SshKeyModel(object):
 
                    elif ssh.SSH_OPTIONS in l and ' ssh-serve ' in l:
 
                        pass # Kallithea entries are ok to overwrite
 
                    else:
 
                        raise Exception("Safety check failed, found %r in %s - please review and remove it" % (l.strip(), authorized_keys))
 
                        raise SshKeyModelException("Safety check failed, found %r line in %s - please remove it if Kallithea should manage the file" % (l.strip(), authorized_keys))
 

	
 
        fh, tmp_authorized_keys = tempfile.mkstemp('.authorized_keys', dir=os.path.dirname(authorized_keys))
 
        with os.fdopen(fh, 'w') as f:
 
            f.write("# WARNING: This .ssh/authorized_keys file is managed by Kallithea. Manual editing or adding new entries will make Kallithea back off.\n")
 
            for key in UserSshKeys.query().join(UserSshKeys.user).filter(User.active == True):
 
                f.write(ssh.authorized_keys_line(kallithea_cli_path, config['__file__'], key))
 
        os.chmod(tmp_authorized_keys, stat.S_IRUSR | stat.S_IWUSR)
kallithea/templates/about.html
Show inline comments
 
@@ -24,12 +24,13 @@
 
  necessarily limited to the following:</p>
 
  <ul>
 

	
 
  <li>Copyright &copy; 2012&ndash;2019, Mads Kiilerich</li>
 
  <li>Copyright &copy; 2012&ndash;2020, Mads Kiilerich</li>
 
  <li>Copyright &copy; 2014&ndash;2020, Thomas De Schampheleire</li>
 
  <li>Copyright &copy; 2012, 2014&ndash;2017, 2019, Andrej Shadura</li>
 
  <li>Copyright &copy; 2014&ndash;2019, Thomas De Schampheleire</li>
 
  <li>Copyright &copy; 2015&ndash;2017, 2019, Étienne Gilli</li>
 
  <li>Copyright &copy; 2017&ndash;2019, Allan Nordhøy</li>
 
  <li>Copyright &copy; 2018&ndash;2019, ssantos</li>
 
  <li>Copyright &copy; 2019, Adi Kriegisch</li>
 
  <li>Copyright &copy; 2019, Danni Randeris</li>
 
  <li>Copyright &copy; 2019, Edmund Wong</li>
 
  <li>Copyright &copy; 2019, Elizabeth Sherrock</li>
 
@@ -39,6 +40,7 @@
 
  <li>Copyright &copy; 2019, Mateusz Mendel</li>
 
  <li>Copyright &copy; 2019, Nathan</li>
 
  <li>Copyright &copy; 2019, Oleksandr Shtalinberg</li>
 
  <li>Copyright &copy; 2019, Private</li>
 
  <li>Copyright &copy; 2019, THANOS SIOURDAKIS</li>
 
  <li>Copyright &copy; 2019, Wolfgang Scherer</li>
 
  <li>Copyright &copy; 2019, Христо Станев</li>
kallithea/templates/admin/my_account/my_account_ssh_keys.html
Show inline comments
 
@@ -23,7 +23,7 @@
 
            </td>
 
            <td>
 
                ${h.form(url('my_account_ssh_keys_delete'))}
 
                    ${h.hidden('del_public_key', ssh_key.public_key)}
 
                    ${h.hidden('del_public_key_fingerprint', ssh_key.fingerprint)}
 
                    <button class="btn btn-danger btn-xs" type="submit"
 
                            onclick="return confirm('${_('Confirm to remove this SSH key: %s') % ssh_key.fingerprint}');">
 
                        <i class="icon-trashcan"></i>
kallithea/templates/admin/users/user_edit_ssh_keys.html
Show inline comments
 
@@ -23,7 +23,7 @@
 
            </td>
 
            <td>
 
                ${h.form(url('edit_user_ssh_keys_delete', id=c.user.user_id))}
 
                    ${h.hidden('del_public_key', ssh_key.public_key)}
 
                    ${h.hidden('del_public_key_fingerprint', ssh_key.fingerprint)}
 
                    <button class="btn btn-danger btn-xs" type="submit"
 
                            onclick="return confirm('${_('Confirm to remove this SSH key: %s') % ssh_key.fingerprint}');">
 
                        <i class="icon-trashcan"></i>
kallithea/templates/base/base.html
Show inline comments
 
@@ -23,7 +23,7 @@
 
            <a class="navbar-link" href="${h.url('kallithea_project_url')}" target="_blank">Kallithea</a>,
 
        %endif
 
        which is
 
        <a class="navbar-link" href="${h.canonical_url('about')}#copyright">&copy; 2010&ndash;2019 by various authors &amp; licensed under GPLv3</a>.
 
        <a class="navbar-link" href="${h.canonical_url('about')}#copyright">&copy; 2010&ndash;2020 by various authors &amp; licensed under GPLv3</a>.
 
        %if c.issues_url:
 
            &ndash; <a class="navbar-link" href="${c.issues_url}" target="_blank">${_('Support')}</a>
 
        %endif
kallithea/templates/password_reset_confirmation.html
Show inline comments
 
@@ -22,13 +22,13 @@
 
        ${h.form(h.url('reset_password_confirmation'), method='post')}
 
        <p>${_('You are about to set a new password for the email address %s.') % c.email}</p>
 
        <p>${_('Note that you must use the same browser session for this as the one used to request the password reset.')}</p>
 
        ${h.hidden('email')}
 
        ${h.hidden('timestamp')}
 
        ${h.hidden('email', value=c.email)}
 
        ${h.hidden('timestamp', value=c.timestamp)}
 
        <div class="form">
 
                <div class="form-group">
 
                    <label class="control-label" for="token">${_('Code you received in the email')}:</label>
 
                    <div>
 
                        ${h.text('token', class_='form-control')}
 
                        ${h.text('token', value=c.token, class_='form-control')}
 
                    </div>
 
                </div>
 

	
kallithea/tests/functional/test_admin_users.py
Show inline comments
 
@@ -556,7 +556,7 @@ class TestAdminUsersController(base.Test
 
        assert ssh_key.description == u'me@localhost'
 

	
 
        response = self.app.post(base.url('edit_user_ssh_keys_delete', id=user_id),
 
                                 {'del_public_key': ssh_key.public_key,
 
                                 {'del_public_key_fingerprint': ssh_key.fingerprint,
 
                                  '_session_csrf_secret_token': self.session_csrf_secret_token()})
 
        self.checkSessionFlash(response, 'SSH key successfully deleted')
 
        keys = UserSshKeys.query().all()
kallithea/tests/functional/test_login.py
Show inline comments
 
@@ -3,8 +3,10 @@ import re
 
import time
 
import urlparse
 

	
 
import mock
 
from tg.util.webtest import test_context
 

	
 
import kallithea.lib.celerylib.tasks
 
from kallithea.lib import helpers as h
 
from kallithea.lib.auth import check_password
 
from kallithea.lib.utils2 import generate_api_key
 
@@ -404,6 +406,14 @@ class TestLoginController(base.TestContr
 
        Session().add(new)
 
        Session().commit()
 

	
 
        token = UserModel().get_reset_password_token(
 
            User.get_by_username(username), timestamp, self.session_csrf_secret_token())
 

	
 
        collected = []
 
        def mock_send_email(recipients, subject, body='', html_body='', headers=None, author=None):
 
            collected.append((recipients, subject, body, html_body))
 

	
 
        with mock.patch.object(kallithea.lib.celerylib.tasks, 'send_email', mock_send_email):
 
        response = self.app.post(base.url(controller='login',
 
                                     action='password_reset'),
 
                                 {'email': email,
 
@@ -411,11 +421,23 @@ class TestLoginController(base.TestContr
 

	
 
        self.checkSessionFlash(response, 'A password reset confirmation code has been sent')
 

	
 
        ((recipients, subject, body, html_body),) = collected
 
        assert recipients == ['username@example.com']
 
        assert subject == 'Password reset link'
 
        assert '\n%s\n' % token in body
 
        (confirmation_url,) = (line for line in body.splitlines() if line.startswith('http://'))
 
        assert ' href="%s"' % confirmation_url.replace('&', '&amp;').replace('@', '%40') in html_body
 

	
 
        d = urlparse.parse_qs(urlparse.urlparse(confirmation_url).query)
 
        assert d['token'] == [token]
 
        assert d['timestamp'] == [str(timestamp)]
 
        assert d['email'] == [email]
 

	
 
        response = response.follow()
 

	
 
        # BAD TOKEN
 

	
 
        token = "bad"
 
        bad_token = "bad"
 

	
 
        response = self.app.post(base.url(controller='login',
 
                                     action='password_reset_confirmation'),
 
@@ -423,7 +445,7 @@ class TestLoginController(base.TestContr
 
                                  'timestamp': timestamp,
 
                                  'password': "p@ssw0rd",
 
                                  'password_confirm': "p@ssw0rd",
 
                                  'token': token,
 
                                  'token': bad_token,
 
                                  '_session_csrf_secret_token': self.session_csrf_secret_token(),
 
                                 })
 
        assert response.status == '200 OK'
 
@@ -431,20 +453,16 @@ class TestLoginController(base.TestContr
 

	
 
        # GOOD TOKEN
 

	
 
        # TODO: The token should ideally be taken from the mail sent
 
        # above, instead of being recalculated.
 

	
 
        token = UserModel().get_reset_password_token(
 
            User.get_by_username(username), timestamp, self.session_csrf_secret_token())
 

	
 
        response = self.app.get(base.url(controller='login',
 
                                    action='password_reset_confirmation',
 
                                    email=email,
 
                                    timestamp=timestamp,
 
                                    token=token))
 
        response = self.app.get(confirmation_url)
 
        assert response.status == '200 OK'
 
        response.mustcontain("You are about to set a new password for the email address %s" % email)
 
        response.mustcontain('<form action="%s" method="post">' % base.url(controller='login', action='password_reset_confirmation'))
 
        response.mustcontain('value="%s"' % self.session_csrf_secret_token())
 
        response.mustcontain('value="%s"' % token)
 
        response.mustcontain('value="%s"' % timestamp)
 
        response.mustcontain('value="username@example.com"')
 

	
 
        # fake a submit of that form
 
        response = self.app.post(base.url(controller='login',
 
                                     action='password_reset_confirmation'),
 
                                 {'email': email,
kallithea/tests/functional/test_my_account.py
Show inline comments
 
@@ -289,7 +289,7 @@ class TestMyAccountController(base.TestC
 
        assert ssh_key.description == u'me@localhost'
 

	
 
        response = self.app.post(base.url('my_account_ssh_keys_delete'),
 
                                 {'del_public_key': ssh_key.public_key,
 
                                 {'del_public_key_fingerprint': ssh_key.fingerprint,
 
                                  '_session_csrf_secret_token': self.session_csrf_secret_token()})
 
        self.checkSessionFlash(response, 'SSH key successfully deleted')
 
        keys = UserSshKeys.query().all()
scripts/make-release
Show inline comments
 
@@ -46,7 +46,7 @@ ls -l $(pwd)/dist/$namerel.tar.gz
 
echo "Releasing Kallithea $version in directory $namerel"
 

	
 
echo "Verify dist file content"
 
diff -u <((hg mani | grep -v '^\.hg') | LANG=C sort) <(tar tf dist/Kallithea-$version.tar.gz | sed "s|^$namerel/||" | grep . | grep -v '^kallithea/i18n/.*/LC_MESSAGES/kallithea.mo$\|^Kallithea.egg-info/\|^PKG-INFO$\|/$' | LANG=C sort)
 
diff -u <((hg mani | grep -v '^\.hg\|^kallithea/i18n/en/LC_MESSAGES/kallithea.mo$') | LANG=C sort) <(tar tf dist/Kallithea-$version.tar.gz | sed "s|^$namerel/||" | grep . | grep -v '^kallithea/i18n/.*/LC_MESSAGES/kallithea.mo$\|^Kallithea.egg-info/\|^PKG-INFO$\|/$' | LANG=C sort)
 

	
 
echo "Verify docs build"
 
python2 setup.py build_sphinx # the results are not actually used, but we want to make sure it builds
scripts/update-copyrights.py
Show inline comments
 
@@ -100,6 +100,9 @@ def insert_entries(
 
    for year, name in all_entries:
 
        if name in no_entries or (name, year) in no_entries:
 
            continue
 
        parts = name.split(' <', 1)
 
        if len(parts) == 2:
 
            name = parts[0] + ' <' + parts[1].lower()
 
        domain = name.split('@', 1)[-1].rstrip('>')
 
        if domain in domain_extra:
 
            name_years[domain_extra[domain]].add(year)
scripts/validate-minimum-dependency-versions
Show inline comments
 
@@ -34,7 +34,7 @@ pip install --upgrade pip setuptools
 
pip install -e . -r "$min_requirements" python-ldap python-pam 2> >(tee "$log" >&2)
 

	
 
# Strip out the known Python 2.7 deprecation message.
 
sed -i '/DEPRECATION: Python 2\.7 will reach the end of its life/d' "$log"
 
sed -i '/DEPRECATION: Python 2\.7 /d' "$log"
 

	
 
# Treat any message on stderr as a problem, for the caller to interpret.
 
if [ -s "$log" ]; then
0 comments (0 inline, 0 general)