diff --git a/client.py b/client.py index 8eaa5cfa95f152ddba1a83115ffaed7833b8e7d5..091ac19c976103def355b2e861c4c533e753441d 100755 --- a/client.py +++ b/client.py @@ -65,7 +65,7 @@ GPG_TRUSTLEVELS = { VERB = False #: Par défaut, place-t-on le mdp dans le presse-papier ? CLIPBOARD = bool(os.getenv('DISPLAY')) and os.path.exists('/usr/bin/xclip') -#: Mode «ne pas demaner confirmation» +#: Mode «ne pas demander confirmation» FORCED = False #: Droits à définir sur le fichier en édition NROLES = None @@ -255,11 +255,9 @@ def encrypt(roles, contents): stdin.close() out = stdout.read().decode("utf-8") if out == '': - if not QUIET: - print(u"Échec de chiffrement".encode("utf-8")) - return None + return [False, u"Échec de chiffrement"] else: - return out + return [True, out] def decrypt(contents): """Déchiffre le contenu""" @@ -271,20 +269,24 @@ def decrypt(contents): def put_password(name, roles, contents): """Dépose le mot de passe après l'avoir chiffré pour les destinataires donnés""" - enc_pwd = encrypt(roles, contents) + success, enc_pwd_or_error = encrypt(roles, contents) if NROLES != None: roles = NROLES if VERB: print(u"Pas de nouveaux rôles".encode("utf-8")) - if enc_pwd <> None: + if success: + enc_pwd = enc_pwd_or_error return put_file(name, roles, enc_pwd) else: - return False + error = enc_pwd_or_error + return [False, error] def get_password(name): """Récupère le mot de passe donné par name""" - remotefile = get_file(name) - return decrypt(remotefile['contents']) + gotit, remotefile = get_file(name) + if gotit: + remotefile = decrypt(remotefile['contents']) + return [gotit, remotefile] ###### ## Interface @@ -308,9 +310,7 @@ def editor(texte, annotations=u""): ntexte = f.read().decode("utf-8") f.close() ntexte = u'\n'.join(filter(lambda l: not l.startswith('#'), ntexte.split('\n'))) - if texte != ntexte: - return ntexte - return None + return ntexte def show_files(): """Affiche la liste des fichiers disponibles sur le serveur distant""" @@ -328,9 +328,9 @@ def show_files(): def show_roles(): """Affiche la liste des roles existants""" print(u"Liste des roles disponibles".encode("utf-8")) - for role in all_roles().keys(): + for (role, usernames) in all_roles().iteritems(): if not role.endswith('-w'): - print((u" * " + role ).encode("utf-8")) + print((u" * %s : %s" % (role, ", ".join(usernames))).encode("utf-8")) def show_servers(): """Affiche la liste des serveurs disponibles""" @@ -367,9 +367,9 @@ def clipboard(texte): def show_file(fname): """Affiche le contenu d'un fichier""" - value = get_file(fname) - if value == False: - print(u"Fichier introuvable".encode("utf-8")) + gotit, value = get_file(fname) + if not gotit: + print(value.encode("utf-8")) # value contient le message d'erreur return (sin, sout) = gpg('decrypt') sin.write(value['contents'].encode("utf-8")) @@ -395,10 +395,10 @@ def show_file(fname): def edit_file(fname): """Modifie/Crée un fichier""" - value = get_file(fname) + gotit, value = get_file(fname) nfile = False annotations = u"" - if value == False: + if not gotit and not "pas les droits" in value: nfile = True print(u"Fichier introuvable".encode("utf-8")) if not confirm(u"Créer fichier ?"): @@ -415,13 +415,16 @@ Enregistrez le fichier vide pour annuler.\n""" print(u"Vous ne possédez aucun rôle en écriture ! Abandon.".encode("utf-8")) return value = {'roles' : roles} + elif not gotit: + print(value.encode("utf-8")) # value contient le message d'erreur + return else: (sin, sout) = gpg('decrypt') sin.write(value['contents'].encode("utf-8")) sin.close() texte = sout.read().decode("utf-8") value['roles'] = NROLES or value['roles'] - + annotations += u"""Ce fichier sera chiffré pour les rôles suivants :\n%s\n C'est-à -dire pour les utilisateurs suivants :\n%s""" % ( ', '.join(value['roles']), @@ -429,15 +432,14 @@ C'est-à -dire pour les utilisateurs suivants :\n%s""" % ( ) ntexte = editor(texte, annotations) - - if ntexte == None and not nfile and NROLES == None: - print(u"Pas de modifications effectuées".encode("utf-8")) + + if ((not nfile and ntexte in [u'', texte] and NROLES == None) or # Fichier existant vidé ou inchangé + (nfile and ntexte == u'')): # Nouveau fichier créé vide + print(u"Pas de modification effectuée".encode("utf-8")) else: ntexte = texte if ntexte == None else ntexte - if put_password(fname, value['roles'], ntexte): - print(u"Modifications enregistrées".encode("utf-8")) - else: - print(u"Erreur lors de l'enregistrement (avez-vous les droits suffisants ?)".encode("utf-8")) + success, message = put_password(fname, value['roles'], ntexte) + print(message.encode("utf-8")) def confirm(text): """Demande confirmation, sauf si on est mode ``FORCED``""" @@ -451,12 +453,10 @@ def confirm(text): def remove_file(fname): """Supprime un fichier""" - if not confirm((u'Êtes-vous sûr de vouloir supprimer %s ?' % fname).encode("utf-8")): + if not confirm(u'Êtes-vous sûr de vouloir supprimer %s ?' % fname): return - if rm_file(fname): - print(u"Suppression effectuée".encode("utf-8")) - else: - print(u"Erreur de suppression (avez-vous les droits ?)".encode("utf-8")) + message = rm_file(fname) + print(message.encode("utf-8")) def my_check_keys(): @@ -482,7 +482,8 @@ def recrypt_files(): if set(roles).intersection(froles) == set([]): continue print((u"Rechiffrement de %s" % fname).encode("utf-8")) - put_password(fname, froles, get_password(fname)) + _, password = get_password(fname) + put_password(fname, froles, password) def parse_roles(strroles): """Interprête une liste de rôles fournie par l'utilisateur""" diff --git a/server.py b/server.py index 941866a23b9a7827b4392ae366c9bde8cf608fe4..5d7d4fc70bd1c8603c5db65c25525e59f34591f0 100755 --- a/server.py +++ b/server.py @@ -72,10 +72,10 @@ def getfile(filename): try: obj = json.loads(open(filepath).read()) if not validate(obj['roles']): - return False - return obj + return [False, u"Vous n'avez pas les droits de lecture sur le fichier %s." % filename] + return [True, obj] except IOError: - return False + return [False, u"Le fichier %s n'existe pas." % filename] def putfile(filename): @@ -87,41 +87,38 @@ def putfile(filename): roles = parsed_stdin['roles'] contents = parsed_stdin['contents'] except KeyError: - return False + return [False, u"Entrée invalide"] - try: - old = getfile(filename) - oldroles = old['roles'] - except TypeError: + gotit, old = getfile(filename) + if not gotit: old = u"[Création du fichier]" pass else: - if not validate(oldroles,'w'): - return False - - corps = u"Le fichier %s a été modifié par %s." % (filename, MYUID) - backup(corps, filename, old) - notification(u"Modification de %s" % filename, corps, filename, old) + oldroles = old['roles'] + if not validate(oldroles, 'w'): + return [False, u"Vous n'avez pas le droit d'écriture sur %s." % filename] + + corps = u"Le fichier %s a été modifié par %s." % (filename, MYUID) + backup(corps, filename, old) + notification(u"Modification de %s" % filename, corps, filename, old) writefile(filepath, json.dumps({'roles': roles, 'contents': contents})) - return True + return [True, u"Modification effectuée."] def rmfile(filename): """Supprime le fichier filename après avoir vérifié les droits sur le fichier""" - try: - old = getfile(filename) - roles = old['roles'] - except TypeError: - return True + gotit, old = getfile(filename) + if not gotit: + return old # contient le message d'erreur + roles = old['roles'] + if validate(roles, 'w'): + corps = u"Le fichier %s a été supprimé par %s." % (filename, MYUID) + backup(corps, filename, old) + notification(u"Suppression de %s" % filename, corps, filename, old) + os.remove(getpath(filename)) else: - if validate(roles,'w'): - corps = u"Le fichier %s a été supprimé par %s." % (filename, MYUID) - backup(corps, filename, old) - notification(u"Suppression de %s" % filename, corps, filename, old) - os.remove(getpath(filename)) - else: - return False - return True + return u"Vous n'avez pas les droits d'écriture sur le fichier %s." % filename + return u"Suppression effectuée" def backup(corps, fname, old): """Backupe l'ancienne version du fichier""" @@ -164,20 +161,23 @@ if __name__ == "__main__": except IndexError: pass + answer = None if command == "listroles": - print(json.dumps(listroles())) + answer = listroles() elif command == "listkeys": - print(json.dumps(listkeys())) + answer = listkeys() elif command == "listfiles": - print(json.dumps(listfiles())) + answer = listfiles() else: if not filename: sys.exit(1) if command == "getfile": - print(json.dumps(getfile(filename))) + answer = getfile(filename) elif command == "putfile": - print(json.dumps(putfile(filename))) + answer = putfile(filename) elif command == "rmfile": - print(json.dumps(rmfile(filename))) + answer = rmfile(filename) else: sys.exit(1) + if not answer is None: + print(json.dumps(answer))