src/mercurialserver/refreshauth.py
author Paul Crowley <paul@lshift.net>
Mon, 09 Nov 2009 17:36:33 +0000
branchdebian
changeset 183 6569a18b8a52
parent 165 3606d60b07e5
child 211 0cd59649772c
permissions -rw-r--r--
Added tag debian_0.7 for changeset 95c9ab8e4bfc

# Copyright 2008-2009 LShift Ltd

# WARNING
# This hook completely destroys your ~/.ssh/authorized_keys
# file every time it is run
# WARNING

import re
import base64
import os
import os.path
import subprocess
from mercurialserver import paths

goodkey = re.compile("[/A-Za-z0-9._-]+$")

def refreshAuth():
    akeyfile = os.path.expanduser("~/.ssh/authorized_keys")
    wrappercommand = paths.getExePath() + "/hg-ssh"
    prefix='no-pty,no-port-forwarding,no-X11-forwarding,no-agent-forwarding,command='

    if os.path.exists(akeyfile):
        f = open(akeyfile)
        try:
            for l in f:
                if not l.startswith(prefix):
                    raise Exception("Safety check failed, delete %s to continue" % akeyfile)
        finally:
            f.close()

    akeys = open(akeyfile + "_new", "w")
    for keyroot in paths.getKeysPaths():
        kr = keyroot + "/"
        #print "Processing keyroot", keyroot
        for root, dirs, files in os.walk(keyroot):
            for fn in files:
                ffn = os.path.join(root, fn)
                if not ffn.startswith(kr):
                    raise Exception("Inconsistent behaviour in os.walk, bailing")
                #print "Processing file", ffn
                keyname = ffn[len(kr):]
                if not goodkey.match(keyname):
                    # Encode it for safe quoting
                    keyname = "--base64 " + base64.b64encode(keyname)
                p = subprocess.Popen(("ssh-keygen", "-i", "-f", ffn), 
                    stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                newkey = p.communicate()[0]
                if p.wait() == 0:
                    klines = [l.strip() for l in newkey.split("\n")]
                else:
                    # Conversion failed, read it directly.
                    kf = open(ffn)
                    try:
                        klines = [l.strip() for l in kf]
                    finally:
                        kf.close()
                for l in klines:
                    if len(l):
                        akeys.write('%s"%s %s" %s\n' % (prefix, wrappercommand, keyname, l))
    akeys.close()
    os.rename(akeyfile + "_new", akeyfile)
    
def hook(ui, repo, hooktype, node=None, source=None, **kwargs):
    refreshAuth()