diff --git a/.hgtags b/.hgtags
--- a/.hgtags
+++ b/.hgtags
@@ -74,3 +74,4 @@ a18445b85d407294da0b7f1d8be3bedef5ffdea6
19086c5de05f4984d7a90cd31624c45dd893f6bb 0.4.0
da65398a62fff50f3d241796cbf17acdea2092ef 0.4.1
bfa0b0a814644f0af3f492d17a9ed169cc3b89fe 0.5.0
+d01a8e92936dbd62c76505432f60efba432e9397 0.5.1
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -1,11 +1,12 @@
List of contributors to Kallithea project:
+ Thomas De Schampheleire 2014-2020
+ Mads Kiilerich 2016-2020
Andrej Shadura 2012 2014-2017 2019
- Thomas De Schampheleire 2014-2019
Étienne Gilli 2015-2017 2019
- Mads Kiilerich 2016-2019
Allan Nordhøy 2017-2019
ssantos 2018-2019
+ Adi Kriegisch 2019
Danni Randeris 2019
Edmund Wong 2019
Elizabeth Sherrock 2019
@@ -15,6 +16,7 @@ List of contributors to Kallithea projec
Mateusz Mendel 2019
Nathan 2019
Oleksandr Shtalinberg 2019
+ Private 2019
THANOS SIOURDAKIS 2019
Wolfgang Scherer 2019
Христо Станев 2019
diff --git a/development.ini b/development.ini
--- a/development.ini
+++ b/development.ini
@@ -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
diff --git a/docs/conf.py b/docs/conf.py
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -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
diff --git a/docs/setup.rst b/docs/setup.rst
--- a/docs/setup.rst
+++ b/docs/setup.rst
@@ -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)
diff --git a/kallithea/alembic/env.py b/kallithea/alembic/env.py
--- a/kallithea/alembic/env.py
+++ b/kallithea/alembic/env.py
@@ -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):
diff --git a/kallithea/alembic/versions/4851d15bc437_db_migration_step_after_95c01895c006_.py b/kallithea/alembic/versions/4851d15bc437_db_migration_step_after_95c01895c006_.py
--- a/kallithea/alembic/versions/4851d15bc437_db_migration_step_after_95c01895c006_.py
+++ b/kallithea/alembic/versions/4851d15bc437_db_migration_step_after_95c01895c006_.py
@@ -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():
- with op.batch_alter_table('user_ssh_keys', schema=None) as batch_op:
- batch_op.drop_index('usk_public_key_idx')
+ 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')
diff --git a/kallithea/alembic/versions/d7ec25b66e47_ssh_drop_usk_public_key_idx_again.py b/kallithea/alembic/versions/d7ec25b66e47_ssh_drop_usk_public_key_idx_again.py
new file mode 100644
--- /dev/null
+++ b/kallithea/alembic/versions/d7ec25b66e47_ssh_drop_usk_public_key_idx_again.py
@@ -0,0 +1,43 @@
+# 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 .
+
+"""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
diff --git a/kallithea/bin/kallithea_cli_base.py b/kallithea/bin/kallithea_cli_base.py
--- a/kallithea/bin/kallithea_cli_base.py
+++ b/kallithea/bin/kallithea_cli_base.py
@@ -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)
diff --git a/kallithea/bin/kallithea_cli_iis.py b/kallithea/bin/kallithea_cli_iis.py
--- a/kallithea/bin/kallithea_cli_iis.py
+++ b/kallithea/bin/kallithea_cli_iis.py
@@ -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,
})
diff --git a/kallithea/bin/kallithea_cli_ssh.py b/kallithea/bin/kallithea_cli_ssh.py
--- a/kallithea/bin/kallithea_cli_ssh.py
+++ b/kallithea/bin/kallithea_cli_ssh.py
@@ -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.
"""
-
- SshKeyModel().write_authorized_keys()
+ try:
+ SshKeyModel().write_authorized_keys()
+ except SshKeyModelException as e:
+ sys.stderr.write("%s\n" % e)
+ sys.exit(1)
diff --git a/kallithea/config/app_cfg.py b/kallithea/config/app_cfg.py
--- a/kallithea/config/app_cfg.py
+++ b/kallithea/config/app_cfg.py
@@ -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()
diff --git a/kallithea/config/middleware.py b/kallithea/config/middleware.py
--- a/kallithea/config/middleware.py
+++ b/kallithea/config/middleware.py
@@ -13,8 +13,6 @@
# along with this program. If not, see .
"""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)
diff --git a/kallithea/controllers/admin/my_account.py b/kallithea/controllers/admin/my_account.py
--- a/kallithea/controllers/admin/my_account.py
+++ b/kallithea/controllers/admin/my_account.py
@@ -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')
diff --git a/kallithea/controllers/admin/users.py b/kallithea/controllers/admin/users.py
--- a/kallithea/controllers/admin/users.py
+++ b/kallithea/controllers/admin/users.py
@@ -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')
diff --git a/kallithea/controllers/login.py b/kallithea/controllers/login.py
--- a/kallithea/controllers/login.py
+++ b/kallithea/controllers/login.py
@@ -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:
diff --git a/kallithea/i18n/en/LC_MESSAGES/kallithea.mo b/kallithea/i18n/en/LC_MESSAGES/kallithea.mo
new file mode 100644
index 0000000000000000000000000000000000000000..babcfcd322ba8631ee98ce633dbe7dd029faea32
GIT binary patch
literal 20
Oc$}NcB6N=d4FCWf1_6oy
diff --git a/kallithea/lib/auth.py b/kallithea/lib/auth.py
--- a/kallithea/lib/auth.py
+++ b/kallithea/lib/auth.py
@@ -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
diff --git a/kallithea/lib/hooks.py b/kallithea/lib/hooks.py
--- a/kallithea/lib/hooks.py
+++ b/kallithea/lib/hooks.py
@@ -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"""
- baseui, repo = _hook_environment(repo_path)
+ 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()
diff --git a/kallithea/lib/paster_commands/template.ini.mako b/kallithea/lib/paster_commands/template.ini.mako
--- a/kallithea/lib/paster_commands/template.ini.mako
+++ b/kallithea/lib/paster_commands/template.ini.mako
@@ -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
diff --git a/kallithea/lib/ssh.py b/kallithea/lib/ssh.py
--- a/kallithea/lib/ssh.py
+++ b/kallithea/lib/ssh.py
@@ -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,
diff --git a/kallithea/lib/utils2.py b/kallithea/lib/utils2.py
--- a/kallithea/lib/utils2.py
+++ b/kallithea/lib/utils2.py
@@ -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)
diff --git a/kallithea/model/db.py b/kallithea/model/db.py
--- a/kallithea/model/db.py
+++ b/kallithea/model/db.py
@@ -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
diff --git a/kallithea/model/ssh_key.py b/kallithea/model/ssh_key.py
--- a/kallithea/model/ssh_key.py
+++ b/kallithea/model/ssh_key.py
@@ -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)
+ 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)
diff --git a/kallithea/templates/about.html b/kallithea/templates/about.html
--- a/kallithea/templates/about.html
+++ b/kallithea/templates/about.html
@@ -24,12 +24,13 @@
necessarily limited to the following: