roles modif + argparse
This commit is contained in:
parent
22a59154ba
commit
1c001ba4f8
2 changed files with 158 additions and 73 deletions
|
@ -2,8 +2,8 @@
|
||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
"""cranspasswords-server.py: Serveur pour cranspasswords"""
|
"""cranspasswords-server.py: Serveur pour cranspasswords"""
|
||||||
|
|
||||||
MYDIR = '/home/dstan/crans/cranspasswords/'
|
MYDIR = '/home/dstan/cranspasswords/'
|
||||||
STORE = '/home/dstan/crans/passwords/v2/'
|
STORE = MYDIR+'test/'
|
||||||
|
|
||||||
import glob
|
import glob
|
||||||
import os
|
import os
|
||||||
|
@ -31,7 +31,7 @@ KEYS = {
|
||||||
"becue": ("becue@crans.org", "194974E2"),
|
"becue": ("becue@crans.org", "194974E2"),
|
||||||
"dstan": ("daniel.stan@crans.org", "6E1C820B"),
|
"dstan": ("daniel.stan@crans.org", "6E1C820B"),
|
||||||
"cauderlier": ("cauderlier@crans.org",None), #Méchant pas beau
|
"cauderlier": ("cauderlier@crans.org",None), #Méchant pas beau
|
||||||
"maioli": ("maioli@crans.org","9E5026E8")
|
"maioli": ("maioli@crans.org",None) #Bis (maybe 9E5026E8)
|
||||||
}
|
}
|
||||||
|
|
||||||
RTC=[
|
RTC=[
|
||||||
|
@ -54,15 +54,8 @@ NOUNOUS=RTC+[
|
||||||
]
|
]
|
||||||
|
|
||||||
ROLES = {
|
ROLES = {
|
||||||
"bureau": [
|
"bureau": [],
|
||||||
"aza-vallina",
|
"ca": [],
|
||||||
],
|
|
||||||
"ca": [
|
|
||||||
"aza-vallina",
|
|
||||||
"blockelet",
|
|
||||||
"durand-gasselin",
|
|
||||||
"lagorce",
|
|
||||||
],
|
|
||||||
"rtc": RTC,
|
"rtc": RTC,
|
||||||
"nounous": NOUNOUS,
|
"nounous": NOUNOUS,
|
||||||
"nounous-w": NOUNOUS #Or maybe RTC ?
|
"nounous-w": NOUNOUS #Or maybe RTC ?
|
||||||
|
|
|
@ -8,6 +8,7 @@ import json
|
||||||
import tempfile
|
import tempfile
|
||||||
import os
|
import os
|
||||||
import atexit
|
import atexit
|
||||||
|
import argparse
|
||||||
|
|
||||||
######
|
######
|
||||||
## GPG Definitions
|
## GPG Definitions
|
||||||
|
@ -21,7 +22,10 @@ GPG_ARGS = {
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
|
VERB = False
|
||||||
CLIPBOARD = False # Par défaut, place-t-on le mdp dans le presse-papier ?
|
CLIPBOARD = False # Par défaut, place-t-on le mdp dans le presse-papier ?
|
||||||
|
FORCED = False #Mode interactif qui demande confirmation
|
||||||
|
NROLES = None # Droits à définir sur le fichier en édition
|
||||||
|
|
||||||
def gpg(command, args = None):
|
def gpg(command, args = None):
|
||||||
"""Lance gpg pour la commande donnée avec les arguments
|
"""Lance gpg pour la commande donnée avec les arguments
|
||||||
|
@ -30,7 +34,7 @@ def gpg(command, args = None):
|
||||||
full_command.extend(GPG_ARGS[command])
|
full_command.extend(GPG_ARGS[command])
|
||||||
if args:
|
if args:
|
||||||
full_command.extend(args)
|
full_command.extend(args)
|
||||||
if DEBUG:
|
if VERB:
|
||||||
stderr=sys.stderr
|
stderr=sys.stderr
|
||||||
else:
|
else:
|
||||||
stderr=subprocess.PIPE
|
stderr=subprocess.PIPE
|
||||||
|
@ -41,22 +45,23 @@ def gpg(command, args = None):
|
||||||
stdout = subprocess.PIPE,
|
stdout = subprocess.PIPE,
|
||||||
stderr = stderr,
|
stderr = stderr,
|
||||||
close_fds = True)
|
close_fds = True)
|
||||||
if not DEBUG:
|
if not VERB:
|
||||||
proc.stderr.close()
|
proc.stderr.close()
|
||||||
return proc.stdin, proc.stdout
|
return proc.stdin, proc.stdout
|
||||||
|
|
||||||
######
|
######
|
||||||
## Remote commands
|
## Remote commands
|
||||||
|
|
||||||
SSH = '/usr/bin/ssh'
|
SERVER_CMD_DEBUG = ['/usr/bin/ssh', 'localhost', \
|
||||||
SSH_HOST = 'localhost'
|
'/home/dstan/crans/cranspasswords/cranspasswords-server.py']
|
||||||
REMOTE_COMMAND = ['/home/dstan/crans/cranspasswords/cranspasswords-server.py']
|
SERVER_CMD = ['/usr/bin/ssh', 'vo',\
|
||||||
|
'/home/dstan/cranspasswords/cranspasswords-server']
|
||||||
|
USER = 'dstan'
|
||||||
|
|
||||||
def ssh(command, arg = None):
|
def ssh(command, arg = None):
|
||||||
"""Lance ssh avec les arguments donnés. Renvoie son entrée
|
"""Lance ssh avec les arguments donnés. Renvoie son entrée
|
||||||
standard et sa sortie standard."""
|
standard et sa sortie standard."""
|
||||||
full_command = [SSH, SSH_HOST]
|
full_command = list(SERVER_CMD)
|
||||||
full_command.extend(REMOTE_COMMAND)
|
|
||||||
full_command.append(command)
|
full_command.append(command)
|
||||||
if arg:
|
if arg:
|
||||||
full_command.append(arg)
|
full_command.append(arg)
|
||||||
|
@ -101,6 +106,11 @@ def rm_file(filename):
|
||||||
"""Supprime le fichier sur le serveur distant"""
|
"""Supprime le fichier sur le serveur distant"""
|
||||||
return remote_command("rmfile", filename)
|
return remote_command("rmfile", filename)
|
||||||
|
|
||||||
|
def get_my_roles():
|
||||||
|
"""Retoure la liste des rôles perso"""
|
||||||
|
allr = all_roles()
|
||||||
|
return filter(lambda role: USER in allr[role],allr.keys())
|
||||||
|
|
||||||
######
|
######
|
||||||
## Local commands
|
## Local commands
|
||||||
|
|
||||||
|
@ -120,13 +130,12 @@ def check_keys():
|
||||||
for mail, key in keys.values():
|
for mail, key in keys.values():
|
||||||
if key:
|
if key:
|
||||||
_, stdout = gpg("fingerprint", [key])
|
_, stdout = gpg("fingerprint", [key])
|
||||||
if DEBUG: print "Checking %s" % mail
|
if VERB: print "Checking %s" % mail
|
||||||
if str("<%s>" % mail.lower()) not in stdout.read().lower():
|
if str("<%s>" % mail.lower()) not in stdout.read().lower():
|
||||||
if DEBUG: print "-->Fail on %s" % mail
|
if VERB: print "-->Fail on %s" % mail
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def encrypt(roles, contents):
|
def encrypt(roles, contents):
|
||||||
|
@ -151,7 +160,7 @@ def encrypt(roles, contents):
|
||||||
stdin.close()
|
stdin.close()
|
||||||
out = stdout.read()
|
out = stdout.read()
|
||||||
if out == '':
|
if out == '':
|
||||||
if DEBUG: print "Échec de chiffrement"
|
if VERB: print "Échec de chiffrement"
|
||||||
return None
|
return None
|
||||||
else:
|
else:
|
||||||
return out
|
return out
|
||||||
|
@ -167,6 +176,8 @@ def put_password(name, roles, contents):
|
||||||
"""Dépose le mot de passe après l'avoir chiffré pour les
|
"""Dépose le mot de passe après l'avoir chiffré pour les
|
||||||
destinataires donnés"""
|
destinataires donnés"""
|
||||||
enc_pwd = encrypt(roles, contents)
|
enc_pwd = encrypt(roles, contents)
|
||||||
|
if NROLES != None:
|
||||||
|
roles = NROLES
|
||||||
if enc_pwd <> None:
|
if enc_pwd <> None:
|
||||||
return put_file(name, roles, enc_pwd)
|
return put_file(name, roles, enc_pwd)
|
||||||
else:
|
else:
|
||||||
|
@ -178,26 +189,6 @@ def get_password(name):
|
||||||
return decrypt(remotefile['contents'])
|
return decrypt(remotefile['contents'])
|
||||||
|
|
||||||
## Interface
|
## Interface
|
||||||
def usage():
|
|
||||||
print """Cranspasswords 2 Usage:
|
|
||||||
cranspasswords [options] [<filename>]
|
|
||||||
cranspasswords <filename> Télécharge le fichier
|
|
||||||
cranspasswords Mode interactif
|
|
||||||
|
|
||||||
Options:
|
|
||||||
--view Télécharge le fichier
|
|
||||||
# --upload Upload un nouveau fichier depuis stdin
|
|
||||||
--edit Lance $EDITOR sur le fichier
|
|
||||||
# --roles=<role1>,<role2>… Définit les rôles
|
|
||||||
# --roles+=<role> Ajoute un rôle
|
|
||||||
# --roles-=<role> Supprime un rôle
|
|
||||||
# --edit-roles Lance $EDITOR sur les rôles
|
|
||||||
# --rm Supprime le fichier
|
|
||||||
--update-keys Mets à jour les clés
|
|
||||||
--check-keys Vérifie les clés
|
|
||||||
-l, --list Liste les fichiers disponibles
|
|
||||||
--list-roles Liste des rôles disponibles
|
|
||||||
-c, --clipboard mot de passe en presse papier"""
|
|
||||||
|
|
||||||
def editor(texte):
|
def editor(texte):
|
||||||
""" Lance $EDITOR sur texte"""
|
""" Lance $EDITOR sur texte"""
|
||||||
|
@ -214,8 +205,12 @@ def editor(texte):
|
||||||
|
|
||||||
def show_files():
|
def show_files():
|
||||||
print """Liste des fichiers disponibles"""
|
print """Liste des fichiers disponibles"""
|
||||||
for fname in all_files():
|
my_roles = get_my_roles()
|
||||||
print " * " + fname
|
for (fname,froles) in all_files().iteritems():
|
||||||
|
access = set(my_roles).intersection(froles) != set([])
|
||||||
|
print " %s %s (%s)" % ((access and '+' or '-'),fname,", ".join(froles))
|
||||||
|
print """--Mes roles: %s""" % \
|
||||||
|
", ".join(my_roles)
|
||||||
|
|
||||||
def show_roles():
|
def show_roles():
|
||||||
print """Liste des roles disponibles"""
|
print """Liste des roles disponibles"""
|
||||||
|
@ -254,7 +249,6 @@ def show_file(fname):
|
||||||
print texte
|
print texte
|
||||||
print "-----"
|
print "-----"
|
||||||
print "Visible par: %s" % ','.join(value['roles'])
|
print "Visible par: %s" % ','.join(value['roles'])
|
||||||
# Todo: some clipboard facility
|
|
||||||
|
|
||||||
def edit_file(fname):
|
def edit_file(fname):
|
||||||
value = get_file(fname)
|
value = get_file(fname)
|
||||||
|
@ -273,30 +267,128 @@ def edit_file(fname):
|
||||||
else:
|
else:
|
||||||
print "Erreur lors de l'enregistrement (avez-vous les droits suffisants ?)"
|
print "Erreur lors de l'enregistrement (avez-vous les droits suffisants ?)"
|
||||||
|
|
||||||
|
def confirm(text):
|
||||||
|
if FORCED: return True
|
||||||
|
while True:
|
||||||
|
out = raw_input(text + ' (O/N)').lower()
|
||||||
|
if out == 'o':
|
||||||
|
return True
|
||||||
|
elif out == 'n':
|
||||||
|
return False
|
||||||
|
|
||||||
|
def remove_file(fname):
|
||||||
|
if not confirm('Êtes-vous sûr de vouloir supprimer %s ?' % fname):
|
||||||
|
return
|
||||||
|
if rm_file(fname):
|
||||||
|
print "Suppression achevée"
|
||||||
|
else:
|
||||||
|
print "Erreur de suppression (avez-vous les droits ?)"
|
||||||
|
|
||||||
|
|
||||||
|
def my_check_keys():
|
||||||
|
check_keys() and "Base de clés ok" or "Erreurs dans la base"
|
||||||
|
|
||||||
|
def my_update_keys():
|
||||||
|
print update_keys()
|
||||||
|
|
||||||
|
def update_role(roles=None):
|
||||||
|
""" Reencode les fichiers, si roles est fourni,
|
||||||
|
contient une liste de rôles"""
|
||||||
|
my_roles = get_my_roles()
|
||||||
|
if roles == None:
|
||||||
|
# On ne conserve que les rôles qui finissent par -w
|
||||||
|
roles = [ r[:-2] for r in filter(lambda r: r.endswith('-w'),my_roles)]
|
||||||
|
if type(roles) != list:
|
||||||
|
roles = [roles]
|
||||||
|
|
||||||
|
for (fname,froles) in all_files().iteritems():
|
||||||
|
if set(roles).intersection(froles) == set([]):
|
||||||
|
continue
|
||||||
|
#if VERB:
|
||||||
|
print "Reencodage de %s" % fname
|
||||||
|
put_password(fname,froles,get_password(fname))
|
||||||
|
|
||||||
|
def parse_roles(strroles):
|
||||||
|
if strroles == None: return None
|
||||||
|
roles = all_roles()
|
||||||
|
my_roles = filter(lambda r: USER in roles[r],roles.keys())
|
||||||
|
my_roles_w = [ r[:-2] for r in filter(lambda r: r.endswith('-w'),my_roles) ]
|
||||||
|
ret = set()
|
||||||
|
writable = False
|
||||||
|
for role in strroles.split(','):
|
||||||
|
if role not in roles.keys():
|
||||||
|
print("Le rôle %s n'existe pas !" % role)
|
||||||
|
return False
|
||||||
|
if role.endswith('-w'):
|
||||||
|
print("Le rôle %s ne devrait pas être utilisé ! (utilisez %s)"
|
||||||
|
% (role,role[:-2]))
|
||||||
|
return False
|
||||||
|
writable = writable or role in my_roles_w
|
||||||
|
ret.add(role)
|
||||||
|
|
||||||
|
if not FORCED and not writable:
|
||||||
|
if not confirm("Vous vous apprêtez à perdre vos droits d'écritures (role ne contient pas %s) sur ce fichier, continuer ?" % ", ".join(my_roles_w)):
|
||||||
|
return False
|
||||||
|
return list(ret)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
argv = sys.argv[1:]
|
parser = argparse.ArgumentParser(description="trousseau crans")
|
||||||
if '-c' in argv or '--clipboard' in argv:
|
parser.add_argument('--test',action='store_true',default=False,
|
||||||
CLIPBOARD=True
|
help='Utilisation du serveur de test')
|
||||||
action = show_file
|
parser.add_argument('-v','--verbose',action='store_true',default=False,
|
||||||
if '--edit' in argv:
|
help="Mode verbeux")
|
||||||
action = edit_file
|
parser.add_argument('-c','--clipboard',action='store_true',default=False,
|
||||||
if '-v' in argv: #Verbose !
|
help="Stocker le mot de passe dans le presse papier")
|
||||||
DEBUG = True
|
parser.add_argument('-f','--force',action='store_true',default=False,
|
||||||
for arg in argv:
|
help="Forcer l'action")
|
||||||
if arg in ['--list','-l']:
|
|
||||||
show_files()
|
# Actions possibles
|
||||||
elif not arg.startswith('-'):
|
action_grp = parser.add_mutually_exclusive_group(required=False)
|
||||||
action(arg)
|
action_grp.add_argument('--edit',action='store_const',dest='action',
|
||||||
elif arg == '--check-keys':
|
default=show_file,const=edit_file,
|
||||||
print check_keys() and "Base de clés ok" or "Erreurs dans la base"
|
help="Editer")
|
||||||
elif arg == '--update-keys':
|
action_grp.add_argument('--view',action='store_const',dest='action',
|
||||||
print update_keys()
|
default=show_file,const=show_file,
|
||||||
elif arg == '--list-roles':
|
help="Voir")
|
||||||
show_roles()
|
action_grp.add_argument('--remove',action='store_const',dest='action',
|
||||||
elif arg in ['-c','--clipboard','--view','--edit','-v']:
|
default=show_file,const=remove_file,
|
||||||
pass
|
help="Effacer")
|
||||||
else:
|
action_grp.add_argument('-l','--list',action='store_const',dest='action',
|
||||||
usage()
|
default=show_file,const=show_files,
|
||||||
break
|
help="Lister les fichiers")
|
||||||
|
action_grp.add_argument('--check-keys',action='store_const',dest='action',
|
||||||
|
default=show_file,const=my_check_keys,
|
||||||
|
help="Vérifier les clés")
|
||||||
|
action_grp.add_argument('--update-keys',action='store_const',dest='action',
|
||||||
|
default=show_file,const=my_update_keys,
|
||||||
|
help="Mettre à jour les clés")
|
||||||
|
action_grp.add_argument('--list-roles',action='store_const',dest='action',
|
||||||
|
default=show_file,const=show_roles,
|
||||||
|
help="Lister les rôles des gens")
|
||||||
|
action_grp.add_argument('--recrypt-role',action='store_const',dest='action',
|
||||||
|
default=show_file,const=update_role,
|
||||||
|
help="Met à jour (reencode les roles)")
|
||||||
|
|
||||||
|
parser.add_argument('--roles',nargs='?',default=None,
|
||||||
|
help="liste des roles à affecter au fichier")
|
||||||
|
parser.add_argument('fname',nargs='?',default=None,
|
||||||
|
help="Nom du fichier à afficher")
|
||||||
|
|
||||||
|
parsed = parser.parse_args(sys.argv[1:])
|
||||||
|
DEBUG = parsed.test
|
||||||
|
if DEBUG:
|
||||||
|
SERVER_CMD = SERVER_CMD_DEBUG
|
||||||
|
VERB = parsed.verbose
|
||||||
|
CLIPBOARD = parsed.clipboard
|
||||||
|
FORCED = parsed.force
|
||||||
|
NROLES = parse_roles(parsed.roles)
|
||||||
|
|
||||||
|
if NROLES != False:
|
||||||
|
if parsed.action.func_code.co_argcount == 0:
|
||||||
|
parsed.action()
|
||||||
|
elif parsed.fname == None:
|
||||||
|
print("Vous devez fournir un nom de fichier avec cette commande")
|
||||||
|
parser.print_help()
|
||||||
|
else:
|
||||||
|
parsed.action(parsed.fname)
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue