From 04e8a2cd0bc40d26a444e65ae5e02300db6e615e Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sat, 12 Nov 2016 16:54:41 +0100 Subject: [PATCH 001/165] add test translate --- test/test_translate.rb | 31 +++++++++++++++++++++++++++++++ test/tests.rb | 1 + 2 files changed, 32 insertions(+) create mode 100644 test/test_translate.rb diff --git a/test/test_translate.rb b/test/test_translate.rb new file mode 100644 index 0000000..fe9a575 --- /dev/null +++ b/test/test_translate.rb @@ -0,0 +1,31 @@ +#!/usr/bin/ruby + +require 'yaml' +require 'test/unit' + +class TestTranslate < Test::Unit::TestCase + def test_00_check_translate + missing = 0 + + Dir.glob('i18n/*.yml').each do |yaml| + lang = File.basename(yaml, '.yml') + translate = YAML.load_file(yaml) + + `grep -r -o "I18n.t('.*')" bin/ lib/ | cut -d"'" -f2`.each_line do |line| + begin + t = translate[lang] + line.strip.split('.').each do |v| + t = t[v] + end + + assert(!t.to_s.empty?) + rescue + puts "#{lang}.#{line}" + missing = 1 + end + end + end + + assert_equal(0, missing) + end +end diff --git a/test/tests.rb b/test/tests.rb index b85efc0..e4efc5d 100644 --- a/test/tests.rb +++ b/test/tests.rb @@ -3,3 +3,4 @@ require_relative 'test_config.rb' require_relative 'test_item.rb' require_relative 'test_mpw.rb' +require_relative 'test_translate.rb' From d8339b53deb810ff24cdeb455cfd18dc0c240409 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sat, 12 Nov 2016 17:16:57 +0100 Subject: [PATCH 002/165] fix missing translate --- i18n/en.yml | 8 ++++++++ i18n/fr.yml | 8 ++++++++ lib/mpw/cli.rb | 4 ++-- lib/mpw/mpw.rb | 2 +- 4 files changed, 19 insertions(+), 3 deletions(-) diff --git a/i18n/en.yml b/i18n/en.yml index 93955d5..e1ffcf7 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -1,6 +1,7 @@ --- en: error: + bad_class: "The object class isn't valid!" config: write: "Can't write the config file!" load: "Checkconfig failed!" @@ -10,7 +11,9 @@ en: exception: "Can't create the GPG key!" name: "You must define a name for your GPG key!" password: "You must define a password for your GPG key!" + empty: "The class is void" export: "Can't export, unable to write in %{file}!" + export_key: "Can't export the GPG key" gpg_file: decrypt: "Can't decrypt file!" encrypt: "Can't encrypt the GPG file!" @@ -64,6 +67,7 @@ en: import: "Import item since a yaml file" key: "Specify the key name" lang: "Set the software language" + length: "Size of the password" list: "List the wallets" no_sync: "Disable synchronization with the server" numeric: "Use number to generate a password" @@ -72,6 +76,7 @@ en: pattern: "Given search pattern" port: "Specify the connection port" protocol: "Specify the protocol for the connection" + random_password: "Generate a random password" setup: "Create a new configuration file" setup_wallet: "Create a new configuration file for a wallet" special_chars: "Use special char to generate a password" @@ -116,6 +121,8 @@ en: valid: "The item has been removed!" import: ask: "Are you sure you want to import this file %{file} ?" + file_empty: "The import file is empty!" + file_not_exist: "The import file doesn't exist!" valid: "The import is succesfull!" not_valid: "No data to import!" setup_config: @@ -126,6 +133,7 @@ en: wallet_dir: "Enter the wallets's folder path [default=%{home}/wallets]: " valid: "The config file has been created!" setup_wallet: + password: "Sync password: " title: "Wallet setup" sync_type: "Synchronization type (ssh, ftp): " sync_host: "Synchronization server: " diff --git a/i18n/fr.yml b/i18n/fr.yml index 4f8b7ac..82e5af3 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -1,6 +1,7 @@ --- fr: error: + bad_class: "La classe de l'objet n'est pas celle attendue!" config: write: "Impossible d'écrire le fichier de configuration!" load: "Le fichier de configuration est invalide!" @@ -10,7 +11,9 @@ fr: exception: "La création de la clé GPG n'a pas pu aboutir!" name: "Vous devez définir un nom pour votre clé GPG!" password: "Vous devez définir un mot de passe pour votre clé GPG!" + empty: "La classe est vide" export: "Impossible d'exporter les données dans le fichier %{file}!" + export_key: "Impossible d'exporter la clé GPG" gpg_file: decrypt: "Impossible de déchiffrer le fichier GPG!" encrypt: "Impossible de chiffrer le fichier GPG!" @@ -64,6 +67,7 @@ fr: init: "Initialise mpw" key: "Spécifie le nom d'une clé" lang: "Spécifie la langue du logiciel (ex: fr)" + length: "Taille du mot de passe" list: "Liste les portefeuilles" no_sync: "Désactive la synchronisation avec le serveur" numeric: "Utilise des chiffre dans la génération d'un mot de passe" @@ -72,6 +76,7 @@ fr: pattern: "Motif de donnée à chercher" port: "Spécifie le port de connexion" protocol: "Spécifie le protocol utilisé pour la connexion" + random_password: "Génére un mot de passe aléatoire" setup: "Création d'un nouveau fichier de configuration" setup_wallet: "Création d'un nouveau fichier de configuration pour un portefeuille" special_chars: "Utilise des charactères speciaux dans la génération d'un mot de passe" @@ -116,6 +121,8 @@ fr: valid: "L'élément a bien été supprimé!" import: ask: "Êtes vous sûre de vouloir importer le fichier %{file} ?" + file_empty: "Le fichier d'import est vide!" + file_not_exist: "Le fichier d'import n'existe pas" valid: "L'import est un succès!" not_valid: "Aucune donnée à importer!" setup_config: @@ -126,6 +133,7 @@ fr: wallet_dir: "Entrez le chemin du répertoire qui contiendra les porte-feuilles de mot de passe [défaut=%{home}/wallets]: " valid: "Le fichier de configuration a bien été créé!" setup_wallet: + password: "Mot de passe de synchronisation: " title: "Configuration du porte-feuille" sync_type: "Type de synchronisation (ssh, ftp): " sync_host: "Serveur: " diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 722b16d..8cd700a 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -517,8 +517,8 @@ class Cli # Import items from a YAML file # @args: file -> the import file def import(file) - raise I18n.t('import.file_empty') if file.to_s.empty? - raise I18n.t('import.file_not_exist') if not File.exist?(file) + raise I18n.t('form.import.file_empty') if file.to_s.empty? + raise I18n.t('form.import.file_not_exist') if not File.exist?(file) YAML::load_file(file).each_value do |row| diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 533077e..91bd04a 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -228,7 +228,7 @@ class MPW if not item.instance_of?(Item) raise I18n.t('error.bad_class') elsif item.empty? - raise I18n.t('error.add.empty') + raise I18n.t('error.empty') else @data.push(item) end From 36e0f83175e1bc440af907166430ccb095be5ecb Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Mon, 12 Dec 2016 22:15:09 +0100 Subject: [PATCH 003/165] fix gpg key name --- bin/mpw-config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/mpw-config b/bin/mpw-config index 120da5b..fb6b372 100644 --- a/bin/mpw-config +++ b/bin/mpw-config @@ -68,7 +68,7 @@ if not options[:init].nil? cli.setup(values) cli.load_config cli.get_wallet - cli.setup_gpg_key(options[:init]) + cli.setup_gpg_key(values[:gpg_key]) cli.setup_wallet_config else cli.set_config(values) From 3575cd9bd7095c09253492f314acff8f699d3a45 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Mon, 12 Dec 2016 23:09:52 +0100 Subject: [PATCH 004/165] feat change add key --- lib/mpw/cli.rb | 7 +++---- lib/mpw/mpw.rb | 12 ++++++------ 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 8cd700a..43256d1 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -334,10 +334,9 @@ class Cli end # Add a new public key - # args: key -> the key name to add - # file -> gpg public file to import - def add_key(key, file=nil) - @mpw.add_key(key, file) + # args: key -> the key name or key file to add + def add_key(key) + @mpw.add_key(key) @mpw.write_data @mpw.sync(true) if @sync diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 91bd04a..7e50547 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -185,12 +185,12 @@ class MPW end # Add a public key - # args: key -> new public key - # file -> public gpg file to import - def add_key(key, file=nil) - if not file.nil? and File.exists?(file) - data = File.open(file).read - GPGME::Key.import(data, armor: true) + # args: key -> new public key file or name + def add_key(key) + if File.exists?(key) + data = File.open(key).read + key_import = GPGME::Key.import(data, armor: true) + key = GPGME::Key.get(key_import.imports[0].fpr).uids[0].email else data = GPGME::Key.export(key, armor: true).read end From bf356f4d6f9dbcbab6ba150d898f99db0cdfa5fb Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Mon, 12 Dec 2016 23:13:32 +0100 Subject: [PATCH 005/165] add an option for add a share gpg key --- bin/mpw-wallet | 6 ++++++ i18n/en.yml | 1 + i18n/fr.yml | 1 + 3 files changed, 8 insertions(+) diff --git a/bin/mpw-wallet b/bin/mpw-wallet index b81e6b2..f6ea562 100644 --- a/bin/mpw-wallet +++ b/bin/mpw-wallet @@ -31,6 +31,10 @@ values = {} OptionParser.new do |opts| opts.banner = "#{I18n.t('option.usage')}: mpw wallet [options]" + opts.on('-a', '--add-gpg-key NAME', I18n.t('option.add_gpg_key')) do |gpg_key| + options[:gpg_key] = gpg_key + end + opts.on('-c', '--config PATH', I18n.t('option.config')) do |config| options[:config] = config end @@ -84,6 +88,8 @@ cli.load_config if not options[:list].nil? cli.list_wallet +elsif not options[:gpg_key].nil? + cli.add_key(options[:gpg_key]) else cli.get_wallet(options[:wallet]) cli.decrypt diff --git a/i18n/en.yml b/i18n/en.yml index e1ffcf7..eb45c86 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -50,6 +50,7 @@ en: option: add: "Add an item or key" + add_gpg_key: "Share the wallet with an other GPG key (name or file path)" alpha: "Use letter to generate a password" config: "Specify the configuration file to use" clipboard: "Disable the clipboard feature" diff --git a/i18n/fr.yml b/i18n/fr.yml index 82e5af3..5a0ebc0 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -50,6 +50,7 @@ fr: option: add: "Ajoute un élément ou une clé" + add_gpg_key: "Partage le portefeuille avec une autre clé GPG (nom ou fichier)" alpha: "Utilise des lettres dans la génération d'un mot de passe" config: "Spécifie le fichier de configuration à utiliser" clipboard: "Désactive la fonction presse papier" From cb409b1545bb3a2394c071f16a8a4e947c066ce3 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 24 Jan 2017 22:58:03 +0100 Subject: [PATCH 006/165] fix bug when port is > 4 number --- lib/mpw/cli.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 8cd700a..47dfa04 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -153,7 +153,7 @@ class Cli data.each do |k, v| next if k == :id or k == :otp - v[:length] = item.send(k.to_s).length + 3 if item.send(k.to_s).to_s.length >= v[:length] + v[:length] = item.send(k.to_s).to_s.length + 3 if item.send(k.to_s).to_s.length >= v[:length] end end data[:id][:length] = items.length.to_s.length + 2 if items.length.to_s.length > data[:id][:length] From 50aa7713f47fd3cd7765190fe2c30eab843656ed Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Mon, 30 Jan 2017 20:29:42 +0100 Subject: [PATCH 007/165] fix error message when host is empty --- i18n/en.yml | 2 +- i18n/fr.yml | 2 +- lib/mpw/item.rb | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/i18n/en.yml b/i18n/en.yml index e1ffcf7..252efee 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -22,7 +22,7 @@ en: write_data: "Can't to write the MPW file!" import: "Can't import, unable to read %{file}!" update: - name_empty: "You must define a name!" + host_empty: "You must define a host!" sync: general: "An error has appeared during the sync" connection: "Connection fail!" diff --git a/i18n/fr.yml b/i18n/fr.yml index 82e5af3..16160cd 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -22,7 +22,7 @@ fr: write_data: "Impossible d'écrire le fichier MPW!" import: "Impossible d'importer le fichier %{file}, car il n'est pas lisible!" update: - name_empty: "Vous devez définir un nom!" + host_empty: "Vous devez définir un host!" sync: general: "Une erreur est survenue durant la synchronisation" connection: "La connexion n'a pu être établie!" diff --git a/lib/mpw/item.rb b/lib/mpw/item.rb index 4beb49f..d3783b9 100644 --- a/lib/mpw/item.rb +++ b/lib/mpw/item.rb @@ -39,7 +39,7 @@ class Item # raise an error if the hash hasn't the key name def initialize(options={}) if not options.has_key?(:host) or options[:host].to_s.empty? - raise I18n.t('error.update.name_empty') + raise I18n.t('error.update.host_empty') end if not options.has_key?(:id) or options[:id].to_s.empty? or not options.has_key?(:created) or options[:created].to_s.empty? @@ -59,7 +59,7 @@ class Item # @args: options -> a hash of parameter def update(options={}) if options.has_key?(:host) and options[:host].to_s.empty? - raise I18n.t('error.update.name_empty') + raise I18n.t('error.update.host_empty') end @group = options[:group] if options.has_key?(:group) From 8c5be6b795a784f5407e34268a39c15b151daac4 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Mon, 30 Jan 2017 22:10:56 +0100 Subject: [PATCH 008/165] wallet: add remove gpg key option --- bin/mpw-wallet | 18 ++++++++++++++---- i18n/en.yml | 3 ++- i18n/fr.yml | 3 ++- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/bin/mpw-wallet b/bin/mpw-wallet index f6ea562..8bdfb1c 100644 --- a/bin/mpw-wallet +++ b/bin/mpw-wallet @@ -24,9 +24,10 @@ require 'mpw/cli' # Options # --------------------------------------------------------- # -options = {} -options[:sync] = {} -values = {} +options = {} +options[:sync] = {} +options[:delete] = false +values = {} OptionParser.new do |opts| opts.banner = "#{I18n.t('option.usage')}: mpw wallet [options]" @@ -39,6 +40,11 @@ OptionParser.new do |opts| options[:config] = config end + opts.on('-d', '--delete-gpg-key NAME', I18n.t('option.delete_gpg_key')) do |gpg_key| + options[:gpg_key] = gpg_key + options[:delete] = true + end + opts.on('-h', '--help', I18n.t('option.help')) do puts opts exit 0 @@ -89,7 +95,11 @@ cli.load_config if not options[:list].nil? cli.list_wallet elsif not options[:gpg_key].nil? - cli.add_key(options[:gpg_key]) + if options[:delete] + cli.delete_key(options[:gpg_key]) + else + cli.add_key(options[:gpg_key]) + end else cli.get_wallet(options[:wallet]) cli.decrypt diff --git a/i18n/en.yml b/i18n/en.yml index eb45c86..6b1f23f 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -50,10 +50,11 @@ en: option: add: "Add an item or key" - add_gpg_key: "Share the wallet with an other GPG key (name or file path)" + add_gpg_key: "Share the wallet with an other GPG key" alpha: "Use letter to generate a password" config: "Specify the configuration file to use" clipboard: "Disable the clipboard feature" + add_gpg_key: "Delete the wallet's share with an other GPG key" export: "Export a wallet in an yaml file" file_export: "Specify the file where export data" file_import: "Specify the file to import" diff --git a/i18n/fr.yml b/i18n/fr.yml index 5a0ebc0..8dc6d21 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -50,10 +50,11 @@ fr: option: add: "Ajoute un élément ou une clé" - add_gpg_key: "Partage le portefeuille avec une autre clé GPG (nom ou fichier)" + add_gpg_key: "Partage le portefeuille avec une autre clé GPG" alpha: "Utilise des lettres dans la génération d'un mot de passe" config: "Spécifie le fichier de configuration à utiliser" clipboard: "Désactive la fonction presse papier" + delete_gpg_key: "Supprime le partage le portefeuille avec une autre clé GPG" export: "Exporte un portefeuille dans un fichier yaml" file_export: "Spécifie le fichier où exporter les données" file_import: "Spécifie le fichier à importer" From d6d7074341ad199eeca20fe31f6acc5c543adf26 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Mon, 30 Jan 2017 22:20:22 +0100 Subject: [PATCH 009/165] fix error message when there is a bad option --- bin/mpw | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bin/mpw b/bin/mpw index 8e578f8..464980c 100755 --- a/bin/mpw +++ b/bin/mpw @@ -21,6 +21,7 @@ $: << File.expand_path('../../lib', __FILE__) require 'locale' require 'set' require 'i18n' +require 'colorize' # --------------------------------------------------------- # # Set local @@ -45,7 +46,11 @@ bin_dir = File.dirname(__FILE__) command = "#{bin_dir}/mpw-#{ARGV[0]}" if Dir.glob("#{bin_dir}/mpw-*").include?("#{command}") - Kernel.load(command) + begin + Kernel.load(command) + rescue Exception => e + puts "#{I18n.t('display.error')}: #{e}".red + end else puts "#{I18n.t('option.usage')}: mpw COMMAND [options]\n\n" puts 'Commands:' From 06c876861b7d246db798218bcf7ea555c2c96ad4 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Mon, 30 Jan 2017 22:26:18 +0100 Subject: [PATCH 010/165] fix english translation --- i18n/en.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/en.yml b/i18n/en.yml index 6b1f23f..6f3d4c8 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -54,7 +54,7 @@ en: alpha: "Use letter to generate a password" config: "Specify the configuration file to use" clipboard: "Disable the clipboard feature" - add_gpg_key: "Delete the wallet's share with an other GPG key" + delete_gpg_key: "Delete the wallet's share with an other GPG key" export: "Export a wallet in an yaml file" file_export: "Specify the file where export data" file_import: "Specify the file to import" From a1a21f96179f09107770e37e0d72fbc60eb56094 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sat, 11 Feb 2017 11:24:12 +0100 Subject: [PATCH 011/165] mpw: add function list_keys --- lib/mpw/mpw.rb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 7e50547..c5023e6 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -184,6 +184,12 @@ class MPW @passwords[id] = encrypt(password) end + # Return the list of all gpg keys + # rtrn: an array with the gpg keys name + def list_keys + return @keys.keys + end + # Add a public key # args: key -> new public key file or name def add_key(key) From b287b719fee1f3b47d07ced3ef30ffb9d97ff02a Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sat, 11 Feb 2017 11:24:49 +0100 Subject: [PATCH 012/165] add test to check add and delete gpg key --- test/test_mpw.rb | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/test_mpw.rb b/test/test_mpw.rb index 0c6a25b..b1c80c9 100644 --- a/test/test_mpw.rb +++ b/test/test_mpw.rb @@ -118,4 +118,26 @@ class TestMPW < Test::Unit::TestCase assert_equal(1, @mpw.list(pattern: 'existing').length) assert_equal(2, @mpw.list(pattern: 'host_[eu]').length) end + + def test_06_add_gpg_key + @config = MPW::Config.new + @config.setup_gpg_key('password', 'test2@example.com', 2048) + + @mpw.read_data + + @mpw.add_key('test2@example.com') + assert_equal(2, @mpw.keys.length) + + @mpw.write_data + end + + def test07_delete_gpg_key + @mpw.read_data + assert_equal(2, @mpw.keys.length) + + @mpw.delete_key('test2@example.com') + assert_equal(1, @mpw.keys.length) + + @mpw.write_data + end end From 4bd538fa7c4d6768094fb959924d8a33718fa237 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sat, 11 Feb 2017 13:43:29 +0100 Subject: [PATCH 013/165] generate a gpg key for the test --- test/init.rb | 19 +++++++++++++++++++ test/test_mpw.rb | 5 +---- test/tests.rb | 1 + 3 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 test/init.rb diff --git a/test/init.rb b/test/init.rb new file mode 100644 index 0000000..be7a73a --- /dev/null +++ b/test/init.rb @@ -0,0 +1,19 @@ +#!/usr/bin/ruby + +require 'gpgme' + +param = '' +param << '<GnupgKeyParms format="internal">' + "\n" +param << "Key-Type: RSA\n" +param << "Key-Length: 2048\n" +param << "Subkey-Type: ELG-E\n" +param << "Subkey-Length: 2048\n" +param << "Name-Real: test\n" +param << "Name-Comment: test\n" +param << "Name-Email: test2@example.com\n" +param << "Expire-Date: 0\n" +param << "Passphrase: password\n" +param << "</GnupgKeyParms>\n" + +ctx = GPGME::Ctx.new +ctx.genkey(param, nil, nil) diff --git a/test/test_mpw.rb b/test/test_mpw.rb index b1c80c9..d2de795 100644 --- a/test/test_mpw.rb +++ b/test/test_mpw.rb @@ -120,9 +120,6 @@ class TestMPW < Test::Unit::TestCase end def test_06_add_gpg_key - @config = MPW::Config.new - @config.setup_gpg_key('password', 'test2@example.com', 2048) - @mpw.read_data @mpw.add_key('test2@example.com') @@ -131,7 +128,7 @@ class TestMPW < Test::Unit::TestCase @mpw.write_data end - def test07_delete_gpg_key + def test_07_delete_gpg_key @mpw.read_data assert_equal(2, @mpw.keys.length) diff --git a/test/tests.rb b/test/tests.rb index e4efc5d..904f64e 100644 --- a/test/tests.rb +++ b/test/tests.rb @@ -1,5 +1,6 @@ #!/usr/bin/ruby +require_relative 'init.rb' require_relative 'test_config.rb' require_relative 'test_item.rb' require_relative 'test_mpw.rb' From e6238341cd6436cb4f12ed50996b3614f402ebef Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sat, 11 Feb 2017 13:47:22 +0100 Subject: [PATCH 014/165] fix test --- test/test_mpw.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_mpw.rb b/test/test_mpw.rb index d2de795..c4748f6 100644 --- a/test/test_mpw.rb +++ b/test/test_mpw.rb @@ -123,17 +123,17 @@ class TestMPW < Test::Unit::TestCase @mpw.read_data @mpw.add_key('test2@example.com') - assert_equal(2, @mpw.keys.length) + assert_equal(2, @mpw.list_keys.length) @mpw.write_data end def test_07_delete_gpg_key @mpw.read_data - assert_equal(2, @mpw.keys.length) + assert_equal(2, @mpw.list_keys.length) @mpw.delete_key('test2@example.com') - assert_equal(1, @mpw.keys.length) + assert_equal(1, @mpw.list_keys.length) @mpw.write_data end From adf34a006c625d1b772414823819afe498416f56 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sat, 11 Feb 2017 15:09:48 +0100 Subject: [PATCH 015/165] config: generate gpg key with rsa --- lib/mpw/config.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index e8911fa..867ff35 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -97,7 +97,7 @@ class Config param = '' param << '<GnupgKeyParms format="internal">' + "\n" - param << "Key-Type: DSA\n" + param << "Key-Type: RSA\n" param << "Key-Length: #{length}\n" param << "Subkey-Type: ELG-E\n" param << "Subkey-Length: #{length}\n" From 501ae5ab2e243d73720383e89e3afa74bcafb5e1 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sat, 11 Feb 2017 15:11:08 +0100 Subject: [PATCH 016/165] remove unused test files --- test/test.sh | 1 - test/test2.rb | 11 ----------- 2 files changed, 12 deletions(-) delete mode 100644 test/test.sh delete mode 100644 test/test2.rb diff --git a/test/test.sh b/test/test.sh deleted file mode 100644 index ab37885..0000000 --- a/test/test.sh +++ /dev/null @@ -1 +0,0 @@ -echo "test\ntest\n" | ruby ./bin/mpw config --init test@test.com diff --git a/test/test2.rb b/test/test2.rb deleted file mode 100644 index 17af2da..0000000 --- a/test/test2.rb +++ /dev/null @@ -1,11 +0,0 @@ -require 'open3' - -Open3.popen3("./bin/mpw config --init test@test.com") do |stdin, stdout, stderr, thread| - stdin.puts 'test' - stdin.puts 'test' -end - -Open3.popen3("./bin/mpw list") do |stdin, stdout, stderr, thread| - stdin.puts 'test' - puts stdout -end From f251b2ebe098158fa6cad4180039fd2eda4be858 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sat, 11 Feb 2017 19:08:26 +0100 Subject: [PATCH 017/165] test with ruby 2.4 --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 141eab1..1a18023 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,8 @@ language: ruby rvm: - - 2.3.1 - - 2.2.5 + - 2.4.0 + - 2.3.3 + - 2.2.6 - 2.1.10 install: - bundle install From ec3abbe88a006757ab7ef3b9f7fd780b398a0b9f Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 14 Feb 2017 21:30:26 +0100 Subject: [PATCH 018/165] fix bug share key --- bin/mpw-wallet | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/bin/mpw-wallet b/bin/mpw-wallet index 8bdfb1c..5222d81 100644 --- a/bin/mpw-wallet +++ b/bin/mpw-wallet @@ -94,14 +94,17 @@ cli.load_config if not options[:list].nil? cli.list_wallet -elsif not options[:gpg_key].nil? - if options[:delete] - cli.delete_key(options[:gpg_key]) - else - cli.add_key(options[:gpg_key]) - end else cli.get_wallet(options[:wallet]) cli.decrypt - cli.setup_wallet_config(values) + + if not options[:gpg_key].nil? + if options[:delete] + cli.delete_key(options[:gpg_key]) + else + cli.add_key(options[:gpg_key]) + end + else + cli.setup_wallet_config(values) + end end From 362253c63b6f847d54a2627427e0888eaaee9f8e Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Thu, 16 Feb 2017 20:47:39 +0100 Subject: [PATCH 019/165] cli: add list gpg keys in wallet --- bin/mpw-wallet | 10 ++++++++-- i18n/en.yml | 2 ++ i18n/fr.yml | 2 ++ lib/mpw/cli.rb | 24 ++++++++++++++++++++++++ 4 files changed, 36 insertions(+), 2 deletions(-) diff --git a/bin/mpw-wallet b/bin/mpw-wallet index 5222d81..221bb38 100644 --- a/bin/mpw-wallet +++ b/bin/mpw-wallet @@ -54,10 +54,14 @@ OptionParser.new do |opts| values[:host] = host end - opts.on('-l', '--list', I18n.t('option.list')) do |list| + opts.on('-l', '--list', I18n.t('option.list')) do options[:list] = true end + opts.on('-L', '--list-keys', I18n.t('option.list_keys')) do + options[:list_keys] = true + end + opts.on('-n', '--no-sync', I18n.t('option.no_sync')) do options[:sync] = false end @@ -98,7 +102,9 @@ else cli.get_wallet(options[:wallet]) cli.decrypt - if not options[:gpg_key].nil? + if not options[:list_keys].nil? + cli.list_keys + elsif not options[:gpg_key].nil? if options[:delete] cli.delete_key(options[:gpg_key]) else diff --git a/i18n/en.yml b/i18n/en.yml index 16a8c69..abf32bd 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -71,6 +71,7 @@ en: lang: "Set the software language" length: "Size of the password" list: "List the wallets" + list_keys: "List the GPG keys in wallet" no_sync: "Disable synchronization with the server" numeric: "Use number to generate a password" password: "Change the password for the synchronization" @@ -173,6 +174,7 @@ en: display: comment: "Comment" error: "ERROR" + keys: "GPG keys" gpg_password: "GPG passphrase: " group: "Group" login: "Login" diff --git a/i18n/fr.yml b/i18n/fr.yml index 0e4e9f6..9b6a1ea 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -71,6 +71,7 @@ fr: lang: "Spécifie la langue du logiciel (ex: fr)" length: "Taille du mot de passe" list: "Liste les portefeuilles" + list_keys: "Liste les clés GPG dans le portefeuille" no_sync: "Désactive la synchronisation avec le serveur" numeric: "Utilise des chiffre dans la génération d'un mot de passe" password: "Changer le mot de passe de connexion" @@ -173,6 +174,7 @@ fr: display: comment: "Commentaire" error: "ERREUR" + keys: "Clés GPG" gpg_password: "Mot de passe GPG: " group: "Groupe" login: "Identifiant" diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 09e3ebd..15915af 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -112,6 +112,30 @@ class Cli exit 2 end + # List gpg keys in wallet + def list_keys + i = 1 + length = 0 + + @mpw.list_keys.each do |key| + length = key.length if length < key.length + end + length += 7 + + puts "\n#{I18n.t('display.keys')}".red + length.times { print '=' } + print "\n" + + @mpw.list_keys.each do |key| + print " #{i}".cyan + (3 - i.to_s.length).times { print ' ' } + puts "| #{key}" + i += 1 + end + + print "\n" + end + # Load config def load_config @config.load_config From e17219c77210ec2dbd0ba6e9edb9f4a2b1238e31 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Thu, 16 Feb 2017 23:25:54 +0100 Subject: [PATCH 020/165] minor fix in list_keys interface --- lib/mpw/cli.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 15915af..99f79e3 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -123,11 +123,12 @@ class Cli length += 7 puts "\n#{I18n.t('display.keys')}".red + print ' ' length.times { print '=' } print "\n" @mpw.list_keys.each do |key| - print " #{i}".cyan + print " #{i}".cyan (3 - i.to_s.length).times { print ' ' } puts "| #{key}" i += 1 From dbffea6b6e626e7a0778c890f15afab2f38e42ce Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Thu, 16 Feb 2017 23:32:24 +0100 Subject: [PATCH 021/165] upgrade version 4.0.0-beta1 --- README.rst | 2 +- VERSION | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 17725d2..f449383 100644 --- a/README.rst +++ b/README.rst @@ -46,7 +46,7 @@ Output:: 2 | linuxfr.org | example | https | | | Da Linux French Site -.. |Version| image:: https://img.shields.io/badge/latest_version-4.0.0--beta-yellow.svg +.. |Version| image:: https://img.shields.io/badge/latest_version-4.0.0--beta1-yellow.svg :target: https://github.com/nishiki/manage-password/releases .. |License| image:: https://img.shields.io/badge/license-GPL--2.0-blue.svg :target: https://github.com/nishiki/manage-password/blob/master/LICENSE diff --git a/VERSION b/VERSION index c0de572..817c97b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.0.0-beta +4.0.0-beta1 From 795343b66980d4738b7e651730ecf4fd3dfc1ee0 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Thu, 16 Feb 2017 23:39:50 +0100 Subject: [PATCH 022/165] upgrade changelog for version 4.0.0-beta1 --- CHANGELOG | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 261d083..e154a0c 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,10 +1,16 @@ = CHANGELOG = -== v4.0.0 (beta) == +== v4.0.0-beta1 == + +* add manage share key with new interface + +== v4.0.0-beta == * new interface with a table * new command line interface * use text editor for add or update an item +* fix generate gpg key with RSA * several bugs fix +* add unit tests == v3.2.1 == From a3dd83e63c5d23708d78c975bfb6f125319611e5 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Fri, 17 Feb 2017 00:04:25 +0100 Subject: [PATCH 023/165] fix update otp key --- templates/update_form.erb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/update_form.erb b/templates/update_form.erb index f4a380b..b942cf5 100644 --- a/templates/update_form.erb +++ b/templates/update_form.erb @@ -12,6 +12,6 @@ protocol: <%= item.protocol %> # <%= I18n.t('form.update_item.port') %> port: <%= item.port %> # <%= I18n.t('form.update_item.otp_key') %> -opt_key: +otp_key: # <%= I18n.t('form.update_item.comment') %> comment: <%= item.comment %> From afdbb05bc51c4ad2c277e6cfd08e8e7c2ef4d0be Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Mon, 20 Feb 2017 22:26:57 +0100 Subject: [PATCH 024/165] fix nothing item message in copy mode --- lib/mpw/cli.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 99f79e3..331b250 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -247,7 +247,6 @@ class Cli if result.length == 0 puts I18n.t('display.nothing') - else table(result) end @@ -494,7 +493,7 @@ class Cli items = @mpw.list(options) if items.length == 0 - puts "#{I18n.t('display.warning')}: #{I18n.t('warning.select')}".yellow + puts I18n.t('display.nothing') else table(items) From 35a4cd47e4436f9fff27ebbf3d0bf2e92e91c018 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 21 Feb 2017 20:32:26 +0100 Subject: [PATCH 025/165] change readme syntax --- README.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ README.rst | 54 ------------------------------------------------------ 2 files changed, 49 insertions(+), 54 deletions(-) create mode 100644 README.md delete mode 100644 README.rst diff --git a/README.md b/README.md new file mode 100644 index 0000000..563c592 --- /dev/null +++ b/README.md @@ -0,0 +1,49 @@ +# MPW: Manage your passwords! +[](https://github.com/nishiki/manage-password/releases) +[](https://travis-ci.org/nishiki/manage-password) +[](https://github.com/nishiki/manage-password/blob/master/LICENSE) + + +mpw is a little software which stores your passwords in [GnuPG](http://www.gnupg.org/) encrypted files. + +## Features + + * generate OTP code + * synchronize your passwords with SSH or FTP. + * copy your login, password or otp in clipboard + +## Install + +On debian or ubuntu: +``` +apt install ruby ruby-dev xclip +gem install mpw +``` + + +# How to use + +A simple mpw usage: +``` +mpw config --init user@host.com +mpw add +mpw copy +mpw add +mpw list +``` + +Output: +``` +Bank + ============================================================================== + ID | Host | User | Protocol | Port | OTP | Comment + ============================================================================== + 1 | bank.com | 1234456 | https | | X | + +Linux + ============================================================================== + ID | Host | User | Protocol | Port | OTP | Comment + ============================================================================== + 2 | linuxfr.org | example | https | | | Da Linux French Site + +``` diff --git a/README.rst b/README.rst deleted file mode 100644 index f449383..0000000 --- a/README.rst +++ /dev/null @@ -1,54 +0,0 @@ -MPW: Manage your passwords! -******************************************************* -|Version| |Build Status| |License| - -mpw is a little software which stores your passwords in `GnuPG <http://www.gnupg.org/>`_ encrypted files. - -Features -======== - -* generate OTP code -* synchronize your passwords with SSH or FTP. -* copy your login, password or otp in clipboard - -Install -======= - -On debian or ubuntu:: - - apt install ruby ruby-dev xclip - gem install mpw - - -How to use -========== - -A simple mpw usage:: - - mpw config --init user@host.com - mpw add - mpw copy - mpw add - mpw list - -Output:: - - Bank - ============================================================================== - ID | Host | User | Protocol | Port | OTP | Comment - ============================================================================== - 1 | bank.com | 1234456 | https | | X | - - Linux - ============================================================================== - ID | Host | User | Protocol | Port | OTP | Comment - ============================================================================== - 2 | linuxfr.org | example | https | | | Da Linux French Site - - -.. |Version| image:: https://img.shields.io/badge/latest_version-4.0.0--beta1-yellow.svg - :target: https://github.com/nishiki/manage-password/releases -.. |License| image:: https://img.shields.io/badge/license-GPL--2.0-blue.svg - :target: https://github.com/nishiki/manage-password/blob/master/LICENSE -.. |Build Status| image:: https://travis-ci.org/nishiki/manage-password.svg?branch=master - :target: https://travis-ci.org/nishiki/manage-password From 4b6de3575a3643e1f8294eaf47b8c06c75971c73 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 21 Feb 2017 21:05:28 +0100 Subject: [PATCH 026/165] fix interface for wallets list --- i18n/en.yml | 1 + i18n/fr.yml | 1 + lib/mpw/cli.rb | 66 +++++++++++++++++++++++++++----------------------- 3 files changed, 38 insertions(+), 30 deletions(-) diff --git a/i18n/en.yml b/i18n/en.yml index abf32bd..536a5e4 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -186,6 +186,7 @@ en: port: "Port" protocol: "Protocol" server: "Server" + wallets: "Wallets" warning: "Warning" formats: diff --git a/i18n/fr.yml b/i18n/fr.yml index 9b6a1ea..09f060a 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -186,6 +186,7 @@ fr: port: "Port" protocol: "Protocol" server: "Serveur" + wallets: "Porte-feuilles" warning: "Warning" formats: diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 331b250..cf0cc28 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -114,27 +114,7 @@ class Cli # List gpg keys in wallet def list_keys - i = 1 - length = 0 - - @mpw.list_keys.each do |key| - length = key.length if length < key.length - end - length += 7 - - puts "\n#{I18n.t('display.keys')}".red - print ' ' - length.times { print '=' } - print "\n" - - @mpw.list_keys.each do |key| - print " #{i}".cyan - (3 - i.to_s.length).times { print ' ' } - puts "| #{key}" - i += 1 - end - - print "\n" + table_list('keys', @mpw.list_keys) end # Load config @@ -160,8 +140,33 @@ class Cli exit 2 end + # Format list on a table + def table_list(title, list) + i = 1 + length = 0 + + list.each do |item| + length = item.length if length < item.length + end + length += 7 + + puts "\n#{I18n.t("display.#{title}")}".red + print ' ' + length.times { print '=' } + print "\n" + + list.each do |item| + print " #{i}".cyan + (3 - i.to_s.length).times { print ' ' } + puts "| #{item}" + i += 1 + end + + print "\n" + end + # Format items on a table - def table(items=[]) + def table_items(items=[]) group = '.' i = 1 length_total = 10 @@ -248,7 +253,7 @@ class Cli if result.length == 0 puts I18n.t('display.nothing') else - table(result) + table_items(result) end end @@ -334,11 +339,12 @@ class Cli # List all wallets def list_wallet - wallets = Dir.glob("#{@config.wallet_dir}/*.mpw") - - wallets.each do |wallet| - puts File.basename(wallet, '.mpw') + wallets = [] + Dir.glob("#{@config.wallet_dir}/*.mpw").each do |f| + wallets << File.basename(f, '.mpw') end + + table_list('wallets', wallets) end # Display the wallet @@ -442,7 +448,7 @@ class Cli if items.length == 0 puts "#{I18n.t('display.warning')}: #{I18n.t('warning.select')}".yellow else - table(items) if items.length > 1 + table_items(items) if items.length > 1 item = get_item(items) options = text_editor('update_form', item) @@ -467,7 +473,7 @@ class Cli if items.length == 0 puts "#{I18n.t('display.warning')}: #{I18n.t('warning.select')}".yellow else - table(items) + table_items(items) item = get_item(items) confirm = ask("#{I18n.t('form.delete_item.ask')} (y/N) ").to_s @@ -495,7 +501,7 @@ class Cli if items.length == 0 puts I18n.t('display.nothing') else - table(items) + table_items(items) item = get_item(items) clipboard(item, clipboard) From a117e8a6188251580ec5b8e36d8f8c320834b83c Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 21 Feb 2017 21:08:14 +0100 Subject: [PATCH 027/165] nothing to do if no values --- bin/mpw-wallet | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/mpw-wallet b/bin/mpw-wallet index 221bb38..fbf0389 100644 --- a/bin/mpw-wallet +++ b/bin/mpw-wallet @@ -110,7 +110,7 @@ else else cli.add_key(options[:gpg_key]) end - else + elsif not values.empty? cli.setup_wallet_config(values) end end From c63d91faccb2fb2e1a99c15340d464466df6234f Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 21 Feb 2017 22:38:55 +0100 Subject: [PATCH 028/165] fix bug when exit with help message --- bin/mpw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/mpw b/bin/mpw index 464980c..a69b568 100755 --- a/bin/mpw +++ b/bin/mpw @@ -48,7 +48,7 @@ command = "#{bin_dir}/mpw-#{ARGV[0]}" if Dir.glob("#{bin_dir}/mpw-*").include?("#{command}") begin Kernel.load(command) - rescue Exception => e + rescue OptionParser::ParseError => e puts "#{I18n.t('display.error')}: #{e}".red end else From 50d88fc970b207b4f4aebc389d872e244091a0ab Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 22 Feb 2017 19:23:55 +0100 Subject: [PATCH 029/165] fix translation test --- lib/mpw/cli.rb | 2 +- test/test_translate.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index cf0cc28..94fa9c3 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -538,7 +538,7 @@ class Cli File.open(file, 'w') {|f| f << data.to_yaml} - puts "#{I18n.t('export.valid', file)}".green + puts "#{I18n.t('form.export.valid', file)}".green rescue Exception => e puts "#{I18n.t('display.error')} #17: #{e}".red end diff --git a/test/test_translate.rb b/test/test_translate.rb index fe9a575..55f09df 100644 --- a/test/test_translate.rb +++ b/test/test_translate.rb @@ -11,7 +11,7 @@ class TestTranslate < Test::Unit::TestCase lang = File.basename(yaml, '.yml') translate = YAML.load_file(yaml) - `grep -r -o "I18n.t('.*')" bin/ lib/ | cut -d"'" -f2`.each_line do |line| + `grep -r -o "I18n.t('.*)" bin/ lib/ | cut -d"'" -f2`.each_line do |line| begin t = translate[lang] line.strip.split('.').each do |v| From c841123ac0549f0ab6310da55623dd470a48944f Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 22 Feb 2017 21:51:06 +0100 Subject: [PATCH 030/165] feat: add option to set default wallet --- bin/mpw-config | 7 ++++++- i18n/en.yml | 3 +++ i18n/fr.yml | 3 +++ lib/mpw/cli.rb | 19 +++++++++++++------ lib/mpw/config.rb | 41 +++++++++++++++++++---------------------- 5 files changed, 44 insertions(+), 29 deletions(-) diff --git a/bin/mpw-config b/bin/mpw-config index fb6b372..74309ce 100644 --- a/bin/mpw-config +++ b/bin/mpw-config @@ -34,6 +34,10 @@ OptionParser.new do |opts| options[:config] = config end + opts.on('-d', '--default-wallet NAME', I18n.t('option.default_wallet')) do |default_wallet| + values[:default_wallet] = default_wallet + end + opts.on('-g', '--gpg-exe PATH', I18n.t('option.gpg_exe')) do |gpg_exe| values[:gpg_exe] = gpg_exe end @@ -64,12 +68,13 @@ end.parse! config = MPW::Config.new(options[:config]) cli = MPW::Cli.new(config, nil) -if not options[:init].nil? +if options.has_key?(:init) cli.setup(values) cli.load_config cli.get_wallet cli.setup_gpg_key(values[:gpg_key]) cli.setup_wallet_config else + cli.load_config cli.set_config(values) end diff --git a/i18n/en.yml b/i18n/en.yml index 536a5e4..6dafacf 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -54,6 +54,7 @@ en: alpha: "Use letter to generate a password" config: "Specify the configuration file to use" clipboard: "Disable the clipboard feature" + default_wallet: "Specify the default wallet to use" delete_gpg_key: "Delete the wallet's share with an other GPG key" export: "Export a wallet in an yaml file" file_export: "Specify the file where export data" @@ -128,6 +129,8 @@ en: file_not_exist: "The import file doesn't exist!" valid: "The import is succesfull!" not_valid: "No data to import!" + set_config: + valid: "The config file has been edited!" setup_config: title: "Setup a new config file" lang: "Choose your language (en, fr, ...) [default=%{lang}]: " diff --git a/i18n/fr.yml b/i18n/fr.yml index 09f060a..a20e58f 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -54,6 +54,7 @@ fr: alpha: "Utilise des lettres dans la génération d'un mot de passe" config: "Spécifie le fichier de configuration à utiliser" clipboard: "Désactive la fonction presse papier" + default_wallet: "Spécifie le porte-feuille à utiliser par défaut" delete_gpg_key: "Supprime le partage le portefeuille avec une autre clé GPG" export: "Exporte un portefeuille dans un fichier yaml" file_export: "Spécifie le fichier où exporter les données" @@ -128,6 +129,8 @@ fr: file_not_exist: "Le fichier d'import n'existe pas" valid: "L'import est un succès!" not_valid: "Aucune donnée à importer!" + set_config: + valid: "Le fichier de configuration a bien été modifié!" setup_config: title: "Création d'un nouveau fichier de configuration" lang: "Choisissez votre langue (en, fr, ...) [défaut=%{lang}]: " diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 94fa9c3..0a5dcde 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -40,12 +40,15 @@ class Cli # Change a parameter int the config after init # @args: options -> param to change def set_config(options) - gpg_key = options[:gpg_key] || @config.key - lang = options[:lang] || @config.lang - wallet_dir = options[:wallet_dir] || @config.wallet_dir - gpg_exe = options[:gpg_exe] || @config.gpg_exe + gpg_key = options[:gpg_key] || @config.key + lang = options[:lang] || @config.lang + wallet_dir = options[:wallet_dir] || @config.wallet_dir + default_wallet = options[:default_wallet] || @config.default_wallet + gpg_exe = options[:gpg_exe] || @config.gpg_exe - @config.setup(gpg_key, lang, wallet_dir, gpg_exe) + @config.setup(gpg_key, lang, wallet_dir, default_wallet, gpg_exe) + + puts "#{I18n.t('form.set_config.valid')}".green rescue Exception => e puts "#{I18n.t('display.error')} #15: #{e}".red exit 2 @@ -341,7 +344,9 @@ class Cli def list_wallet wallets = [] Dir.glob("#{@config.wallet_dir}/*.mpw").each do |f| - wallets << File.basename(f, '.mpw') + wallet = File.basename(f, '.mpw') + wallet += ' *'.green if wallet == @config.default_wallet + wallets << wallet end table_list('wallets', wallets) @@ -355,6 +360,8 @@ class Cli if wallets.length == 1 @wallet_file = wallets[0] + elsif not @config.default_wallet.to_s.empty? + @wallet_file = "#{@config.wallet_dir}/#{@config.default_wallet}.mpw" else @wallet_file = "#{@config.wallet_dir}/default.mpw" end diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index 867ff35..c1e883c 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -29,6 +29,7 @@ class Config attr_accessor :key attr_accessor :lang attr_accessor :config_dir + attr_accessor :default_wallet attr_accessor :wallet_dir attr_accessor :gpg_exe @@ -45,31 +46,28 @@ class Config @config_dir = "#{Dir.home}/.config/mpw" end - if @config_file.nil? or @config_file.empty? - @config_file = "#{@config_dir}/mpw.cfg" - end + @config_file = "#{@config_dir}/mpw.cfg" if @config_file.nil? or @config_file.empty? end # Create a new config file # @args: key -> the gpg key to encrypt # lang -> the software language - # wallet_dir -> the directory where are the wallets password - # gpg_exe -> the path of gpg executable + # wallet_dir -> the directory where are the wallets password + # default_wallet -> the default wallet + # gpg_exe -> the path of gpg executable # @rtrn: true if le config file is create - def setup(key, lang, wallet_dir, gpg_exe) + def setup(key, lang, wallet_dir, default_wallet, gpg_exe) if not key =~ /[a-zA-Z0-9.-_]+\@[a-zA-Z0-9]+\.[a-zA-Z]+/ raise I18n.t('error.config.key_bad_format') end - if wallet_dir.to_s.empty? - wallet_dir = "#{@config_dir}/wallets" - end - - config = { 'key' => key, - 'lang' => lang, - 'wallet_dir' => wallet_dir, - 'gpg_exe' => gpg_exe, - } + wallet_dir = "#{@config_dir}/wallets" if wallet_dir.to_s.empty? + config = { 'key' => key, + 'lang' => lang, + 'wallet_dir' => wallet_dir, + 'default_wallet' => default_wallet, + 'gpg_exe' => gpg_exe, + } FileUtils.mkdir_p(@config_dir, mode: 0700) FileUtils.mkdir_p(wallet_dir, mode: 0700) @@ -77,7 +75,6 @@ class Config File.open(@config_file, 'w') do |file| file << config.to_yaml end - rescue Exception => e raise "#{I18n.t('error.config.write')}\n#{e}" end @@ -116,16 +113,16 @@ class Config # Load the config file def load_config - config = YAML::load_file(@config_file) - @key = config['key'] - @lang = config['lang'] - @wallet_dir = config['wallet_dir'] - @gpg_exe = config['gpg_exe'] + config = YAML::load_file(@config_file) + @key = config['key'] + @lang = config['lang'] + @wallet_dir = config['wallet_dir'] + @default_wallet = config['default_wallet'] + @gpg_exe = config['gpg_exe'] raise if @key.empty? or @wallet_dir.empty? I18n.locale = @lang.to_sym - rescue Exception => e raise "#{I18n.t('error.config.load')}\n#{e}" end From 31574751ffd58ffb048043b6bcde051f593e51c5 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 22 Feb 2017 21:59:49 +0100 Subject: [PATCH 031/165] fix bug after add default wallet --- lib/mpw/cli.rb | 2 +- test/test_config.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 0a5dcde..12bbe22 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -61,7 +61,7 @@ class Cli I18n.locale = lang.to_sym - @config.setup(options[:gpg_key], lang, options[:wallet_dir], options[:gpg_exe]) + @config.setup(options[:gpg_key], lang, options[:wallet_dir], options[:default_wallet], options[:gpg_exe]) load_config diff --git a/test/test_config.rb b/test/test_config.rb index 3de438c..5e4e721 100644 --- a/test/test_config.rb +++ b/test/test_config.rb @@ -27,7 +27,7 @@ class TestConfig < Test::Unit::TestCase } @config = MPW::Config.new - @config.setup(data[:key], data[:lang], data[:wallet_dir], data[:gpg_exe]) + @config.setup(data[:key], data[:lang], data[:wallet_dir], nil, data[:gpg_exe]) @config.load_config data.each do |k,v| From 000bc3aaa55c807b5e34cf7594491eca10c9e678 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Sat, 25 Feb 2017 18:43:30 +0100 Subject: [PATCH 032/165] add config option for password parameters --- bin/mpw-config | 30 +++++++++++++++++++++++++++++- i18n/en.yml | 3 +++ i18n/fr.yml | 3 +++ lib/mpw/cli.rb | 10 ++-------- lib/mpw/config.rb | 34 ++++++++++++++++++++++++++-------- lib/mpw/mpw.rb | 6 +++--- 6 files changed, 66 insertions(+), 20 deletions(-) diff --git a/bin/mpw-config b/bin/mpw-config index 74309ce..1034f04 100644 --- a/bin/mpw-config +++ b/bin/mpw-config @@ -56,13 +56,41 @@ OptionParser.new do |opts| values[:gpg_key] = gpg_key end - opts.on('-l', '--lang LANG', I18n.t('option.lang')) do |lang| + opts.on('-L', '--lang LANG', I18n.t('option.lang')) do |lang| values[:lang] = lang end opts.on('-w', '--wallet-dir PATH', I18n.t('option.wallet_dir')) do |wallet_dir| values[:wallet_dir] = wallet_dir end + + opts.on('-l', '--length NUMBER', I18n.t('option.length')) do |length| + values[:pwd_length] = length.to_i + end + + opts.on('-n', '--numeric', I18n.t('option.numeric')) do + values[:pwd_numeric] = true + end + + opts.on('-N', '--disable-numeric', I18n.t('option.disable_numeric')) do + values[:pwd_numeric] = false + end + + opts.on('-s', '--special-chars', I18n.t('option.special_chars')) do + values[:pwd_special] = true + end + + opts.on('-S', '--disable_special-chars', I18n.t('option.special_chars')) do + values[:pwd_special] = false + end + + opts.on('-a', '--alpha', I18n.t('option.alpha')) do + values[:pwd_alpha] = true + end + + opts.on('-A', '--disable-alpha', I18n.t('option.disable_alpha')) do + values[:pwd_alpha] = false + end end.parse! config = MPW::Config.new(options[:config]) diff --git a/i18n/en.yml b/i18n/en.yml index 6dafacf..5ee9868 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -56,6 +56,9 @@ en: clipboard: "Disable the clipboard feature" default_wallet: "Specify the default wallet to use" delete_gpg_key: "Delete the wallet's share with an other GPG key" + disable_alpha: "Don't use letter to generate a password" + disable_numeric: "Don't use number to generate a password" + disable_special_chars: "Don't use special char to generate a password" export: "Export a wallet in an yaml file" file_export: "Specify the file where export data" file_import: "Specify the file to import" diff --git a/i18n/fr.yml b/i18n/fr.yml index a20e58f..d9bd279 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -56,6 +56,9 @@ fr: clipboard: "Désactive la fonction presse papier" default_wallet: "Spécifie le porte-feuille à utiliser par défaut" delete_gpg_key: "Supprime le partage le portefeuille avec une autre clé GPG" + disable_alpha: "Désactive l'utilisation des lettres dans la génération d'un mot de passe" + disable_numeric: "Désactive l'utilisation des chiffre dans la génération d'un mot de passe" + disable_special_chars: "Désactive l'utilisation des charactères speciaux dans la génération d'un mot de passe" export: "Exporte un portefeuille dans un fichier yaml" file_export: "Spécifie le fichier où exporter les données" file_import: "Spécifie le fichier à importer" diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 12bbe22..97e7e56 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -40,13 +40,7 @@ class Cli # Change a parameter int the config after init # @args: options -> param to change def set_config(options) - gpg_key = options[:gpg_key] || @config.key - lang = options[:lang] || @config.lang - wallet_dir = options[:wallet_dir] || @config.wallet_dir - default_wallet = options[:default_wallet] || @config.default_wallet - gpg_exe = options[:gpg_exe] || @config.gpg_exe - - @config.setup(gpg_key, lang, wallet_dir, default_wallet, gpg_exe) + @config.setup(options) puts "#{I18n.t('form.set_config.valid')}".green rescue Exception => e @@ -433,7 +427,7 @@ class Cli item = Item.new(options) if password - options[:password] = MPW::password(length: 24) + options[:password] = MPW::password(@config.password) end @mpw.add(item) diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index c1e883c..94b9eb8 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -32,6 +32,7 @@ class Config attr_accessor :default_wallet attr_accessor :wallet_dir attr_accessor :gpg_exe + attr_accessor :password # Constructor # @args: config_file -> the specify config file @@ -50,23 +51,39 @@ class Config end # Create a new config file - # @args: key -> the gpg key to encrypt - # lang -> the software language - # wallet_dir -> the directory where are the wallets password - # default_wallet -> the default wallet - # gpg_exe -> the path of gpg executable + # @args: options -> hash with values # @rtrn: true if le config file is create - def setup(key, lang, wallet_dir, default_wallet, gpg_exe) - if not key =~ /[a-zA-Z0-9.-_]+\@[a-zA-Z0-9]+\.[a-zA-Z]+/ + def setup(options) + gpg_key = options[:gpg_key] || @key + lang = options[:lang] || @lang + wallet_dir = options[:wallet_dir] || @wallet_dir + default_wallet = options[:default_wallet] || @default_wallet + gpg_exe = options[:gpg_exe] || @gpg_exe + password = { numeric: true, + alpha: true, + special: false, + length: 16, + } + + ['numeric', 'special', 'alpha', 'length'].each do |k| + if options.has_key?("pwd_#{k}".to_sym) + password[k.to_sym] = options["pwd_#{k}".to_sym] + elsif not @password.nil? and @password.has_key?(k.to_sym) + password[k.to_sym] = @password[k.to_sym] + end + end + + if not gpg_key =~ /[a-zA-Z0-9.-_]+\@[a-zA-Z0-9]+\.[a-zA-Z]+/ raise I18n.t('error.config.key_bad_format') end wallet_dir = "#{@config_dir}/wallets" if wallet_dir.to_s.empty? - config = { 'key' => key, + config = { 'key' => gpg_key, 'lang' => lang, 'wallet_dir' => wallet_dir, 'default_wallet' => default_wallet, 'gpg_exe' => gpg_exe, + 'password' => password, } FileUtils.mkdir_p(@config_dir, mode: 0700) @@ -119,6 +136,7 @@ class Config @wallet_dir = config['wallet_dir'] @default_wallet = config['default_wallet'] @gpg_exe = config['gpg_exe'] + @password = config['password'] raise if @key.empty? or @wallet_dir.empty? diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index c5023e6..761127c 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -431,9 +431,9 @@ class MPW end chars = [] - chars += [*('!'..'?')] - [*('0'..'9')] if options.include?(:special) - chars += [*('A'..'Z'),*('a'..'z')] if options.include?(:alpha) - chars += [*('0'..'9')] if options.include?(:numeric) + chars += [*('!'..'?')] - [*('0'..'9')] if options[:special] + chars += [*('A'..'Z'),*('a'..'z')] if options[:alpha] + chars += [*('0'..'9')] if options[:numeric] chars = [*('A'..'Z'),*('a'..'z'),*('0'..'9')] if chars.empty? result = '' From cedfe9cef72d94da87e556f1aadf69d46815553a Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Sun, 26 Feb 2017 09:35:46 +0100 Subject: [PATCH 033/165] fix bug encrypt with share key --- lib/mpw/mpw.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index c5023e6..3f9986f 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -206,12 +206,16 @@ class MPW end @keys[key] = data + @password.each_keys { |id| set_password(id, get_password(id)) } + @otp_keys.each_keys { |id| set_otp_key(id, get_otp_key(id)) } end # Delete a public key # args: key -> public key to delete def delete_key(key) @keys.delete(key) + @password.each_keys { |id| set_password(id, get_password(id)) } + @otp_keys.each_keys { |id| set_otp_key(id, get_otp_key(id)) } end # Set config From a737ee94d1b1a1666235ea82628883a6b22e0b93 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Sun, 26 Feb 2017 09:45:19 +0100 Subject: [PATCH 034/165] add unit test --- test/test_config.rb | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/test/test_config.rb b/test/test_config.rb index 5e4e721..9d4b930 100644 --- a/test/test_config.rb +++ b/test/test_config.rb @@ -27,7 +27,7 @@ class TestConfig < Test::Unit::TestCase } @config = MPW::Config.new - @config.setup(data[:key], data[:lang], data[:wallet_dir], nil, data[:gpg_exe]) + @config.setup(data) @config.load_config data.each do |k,v| @@ -37,4 +37,28 @@ class TestConfig < Test::Unit::TestCase @config.setup_gpg_key('password', 'test@example.com', 2048) assert(@config.check_gpg_key?) end + + def test_01_password + data = { password: { alpha: false, + numeric: false, + special: true, + length: 32, + } + } + + @config.load_config + + assert_equal(@config.password[:length], 16) + assert(@config.password[:alpha]) + assert(@config.password[:numeric]) + assert(!@config.password[:special]) + + @config.setup(data) + @config.load_config + + assert_equal(@config.password[:length], 32) + assert(!@config.password[:alpha]) + assert(!@config.password[:numeric]) + assert(@config.password[:special]) + end end From 980adacc2c861cfe8faf298f9aab15783df9d892 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Sun, 26 Feb 2017 21:17:35 +0100 Subject: [PATCH 035/165] fix missing change --- lib/mpw/cli.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 97e7e56..7bce420 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -51,11 +51,11 @@ class Cli # Create a new config file # @args: options -> set param def setup(options) - lang = options[:lang] || Locale::Tag.parse(ENV['LANG']).to_simple.to_s[0..1] + options[:lang] = options[:lang] || Locale::Tag.parse(ENV['LANG']).to_simple.to_s[0..1] I18n.locale = lang.to_sym - @config.setup(options[:gpg_key], lang, options[:wallet_dir], options[:default_wallet], options[:gpg_exe]) + @config.setup(options) load_config From e486be5ba853b90355f91ff080a08172e9034cfb Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Sun, 26 Feb 2017 21:22:25 +0100 Subject: [PATCH 036/165] fix bug --- lib/mpw/cli.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 7bce420..409bf5a 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -53,7 +53,7 @@ class Cli def setup(options) options[:lang] = options[:lang] || Locale::Tag.parse(ENV['LANG']).to_simple.to_s[0..1] - I18n.locale = lang.to_sym + I18n.locale = options[:lang].to_sym @config.setup(options) From d6f7c78eb16345a5ff72d9d2b1aeb5ad90dceaf5 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Sun, 26 Feb 2017 21:26:23 +0100 Subject: [PATCH 037/165] fix test --- test/test_config.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_config.rb b/test/test_config.rb index 9d4b930..3dd0d92 100644 --- a/test/test_config.rb +++ b/test/test_config.rb @@ -20,7 +20,7 @@ class TestConfig < Test::Unit::TestCase end def test_00_config - data = { key: 'test@example.com', + data = { gpg_key: 'test@example.com', lang: 'en', wallet_dir: '/tmp/test', gpg_exe: '', From 5d267a486580ada4ec0da6581deda75e42e8f075 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Sun, 26 Feb 2017 21:34:54 +0100 Subject: [PATCH 038/165] config: rename key to gpg_key --- lib/mpw/cli.rb | 4 ++-- lib/mpw/config.rb | 14 +++++++------- templates/setup_form.erb | 9 --------- 3 files changed, 9 insertions(+), 18 deletions(-) delete mode 100644 templates/setup_form.erb diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 409bf5a..3ad32be 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -98,7 +98,7 @@ class Cli #wallet_file = wallet.nil? ? "#{@config.wallet_dir}/default.mpw" : "#{@config.wallet_dir}/#{wallet}.mpw" - @mpw = MPW.new(@config.key, @wallet_file, @password, @config.gpg_exe) + @mpw = MPW.new(@config.gpg_key, @wallet_file, @password, @config.gpg_exe) @mpw.read_data @mpw.set_config(options) @mpw.write_data @@ -127,7 +127,7 @@ class Cli def decrypt if not defined?(@mpw) @password = ask(I18n.t('display.gpg_password')) {|q| q.echo = false} - @mpw = MPW.new(@config.key, @wallet_file, @password, @config.gpg_exe) + @mpw = MPW.new(@config.gpg_key, @wallet_file, @password, @config.gpg_exe) end @mpw.read_data diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index 94b9eb8..2cf5481 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -26,7 +26,7 @@ class Config attr_accessor :error_msg - attr_accessor :key + attr_accessor :gpg_key attr_accessor :lang attr_accessor :config_dir attr_accessor :default_wallet @@ -54,7 +54,7 @@ class Config # @args: options -> hash with values # @rtrn: true if le config file is create def setup(options) - gpg_key = options[:gpg_key] || @key + gpg_key = options[:gpg_key] || @gpg_key lang = options[:lang] || @lang wallet_dir = options[:wallet_dir] || @wallet_dir default_wallet = options[:default_wallet] || @default_wallet @@ -78,7 +78,7 @@ class Config end wallet_dir = "#{@config_dir}/wallets" if wallet_dir.to_s.empty? - config = { 'key' => gpg_key, + config = { 'gpg_key' => gpg_key, 'lang' => lang, 'wallet_dir' => wallet_dir, 'default_wallet' => default_wallet, @@ -117,7 +117,7 @@ class Config param << "Subkey-Length: #{length}\n" param << "Name-Real: #{name}\n" param << "Name-Comment: #{name}\n" - param << "Name-Email: #{@key}\n" + param << "Name-Email: #{@gpg_key}\n" param << "Expire-Date: #{expire}\n" param << "Passphrase: #{password}\n" param << "</GnupgKeyParms>\n" @@ -131,14 +131,14 @@ class Config # Load the config file def load_config config = YAML::load_file(@config_file) - @key = config['key'] + @gpg_key = config['gpg_key'] @lang = config['lang'] @wallet_dir = config['wallet_dir'] @default_wallet = config['default_wallet'] @gpg_exe = config['gpg_exe'] @password = config['password'] - raise if @key.empty? or @wallet_dir.empty? + raise if @gpg_key.empty? or @wallet_dir.empty? I18n.locale = @lang.to_sym rescue Exception => e @@ -149,7 +149,7 @@ class Config # @rtrn: true if the key exist, else false def check_gpg_key? ctx = GPGME::Ctx.new - ctx.each_key(@key, true) do + ctx.each_key(@gpg_key, true) do return true end diff --git a/templates/setup_form.erb b/templates/setup_form.erb deleted file mode 100644 index f7e6d7b..0000000 --- a/templates/setup_form.erb +++ /dev/null @@ -1,9 +0,0 @@ ---- -# <%= I18n.t('form.setup_config.lang') %> -language: <%= @config.lang %> -# <%= I18n.t('form.setup_config.gpg_key') %> -gpg_key: <%= @config.key %> -# <%= I18n.t('form.setup_config.wallet_dir') %> -wallet_dir: <%= @config.config_dir %> -# <%= I18n.t('form.setup_config.gpg_exe') %> -gpg_exe: <%= @config.gpg_exe %> From 21c3732ad371f70db839bd188b8379c7ab9cb905 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Sun, 26 Feb 2017 21:39:33 +0100 Subject: [PATCH 039/165] fix test --- test/test_config.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_config.rb b/test/test_config.rb index 3dd0d92..4d94fcd 100644 --- a/test/test_config.rb +++ b/test/test_config.rb @@ -46,6 +46,7 @@ class TestConfig < Test::Unit::TestCase } } + @config = MPW::Config.new @config.load_config assert_equal(@config.password[:length], 16) From cced11f6c4247b7779ae5b3126f6fbc823ab82e7 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Sun, 26 Feb 2017 21:45:42 +0100 Subject: [PATCH 040/165] fix test --- test/test_config.rb | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/test/test_config.rb b/test/test_config.rb index 4d94fcd..143b3ed 100644 --- a/test/test_config.rb +++ b/test/test_config.rb @@ -39,11 +39,10 @@ class TestConfig < Test::Unit::TestCase end def test_01_password - data = { password: { alpha: false, - numeric: false, - special: true, - length: 32, - } + data = { pwd_alpha: false, + pwd_numeric: false, + pwd_special: true, + pwd_length: 32, } @config = MPW::Config.new @@ -57,7 +56,7 @@ class TestConfig < Test::Unit::TestCase @config.setup(data) @config.load_config - assert_equal(@config.password[:length], 32) + assert_equal(@config.password[:length], data[:pwd_length]) assert(!@config.password[:alpha]) assert(!@config.password[:numeric]) assert(@config.password[:special]) From e03614fb724481ce34cb72bf7de152973079cc83 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Sun, 26 Feb 2017 09:35:46 +0100 Subject: [PATCH 041/165] fix bug encrypt with share key --- lib/mpw/mpw.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 761127c..f8ab415 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -206,12 +206,16 @@ class MPW end @keys[key] = data + @password.each_keys { |id| set_password(id, get_password(id)) } + @otp_keys.each_keys { |id| set_otp_key(id, get_otp_key(id)) } end # Delete a public key # args: key -> public key to delete def delete_key(key) @keys.delete(key) + @password.each_keys { |id| set_password(id, get_password(id)) } + @otp_keys.each_keys { |id| set_otp_key(id, get_otp_key(id)) } end # Set config From da81f34e07cbe8dad6c9a683f37bb34977f61d11 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Sun, 26 Feb 2017 22:07:18 +0100 Subject: [PATCH 042/165] fix add_key --- lib/mpw/mpw.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index f8ab415..bf03347 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -206,7 +206,7 @@ class MPW end @keys[key] = data - @password.each_keys { |id| set_password(id, get_password(id)) } + @passwords.each_keys { |id| set_password(id, get_password(id)) } @otp_keys.each_keys { |id| set_otp_key(id, get_otp_key(id)) } end From 52577425a6e16c4a60eb1e6662fc0ddb2a79215e Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Sun, 26 Feb 2017 22:11:14 +0100 Subject: [PATCH 043/165] fix each_key --- lib/mpw/mpw.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index bf03347..1e86c08 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -206,16 +206,16 @@ class MPW end @keys[key] = data - @passwords.each_keys { |id| set_password(id, get_password(id)) } - @otp_keys.each_keys { |id| set_otp_key(id, get_otp_key(id)) } + @passwords.each_key { |id| set_password(id, get_password(id)) } + @otp_keys.each_key { |id| set_otp_key(id, get_otp_key(id)) } end # Delete a public key # args: key -> public key to delete def delete_key(key) @keys.delete(key) - @password.each_keys { |id| set_password(id, get_password(id)) } - @otp_keys.each_keys { |id| set_otp_key(id, get_otp_key(id)) } + @passwords.each_key { |id| set_password(id, get_password(id)) } + @otp_keys.each_key { |id| set_otp_key(id, get_otp_key(id)) } end # Set config From e4fb7800163f8643a8e64ec1a76fd79371d027a3 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 26 Feb 2017 23:11:07 +0100 Subject: [PATCH 044/165] fix minor bug when config password is empty --- lib/mpw/config.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index 2cf5481..7fbd778 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -136,7 +136,7 @@ class Config @wallet_dir = config['wallet_dir'] @default_wallet = config['default_wallet'] @gpg_exe = config['gpg_exe'] - @password = config['password'] + @password = config['password'] || {} raise if @gpg_key.empty? or @wallet_dir.empty? From 6b8dce2eff12bc4527fb2b4c2ff3242b947ec145 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 26 Feb 2017 23:12:49 +0100 Subject: [PATCH 045/165] add random password for update --- bin/mpw-update | 6 +++++- lib/mpw/cli.rb | 19 +++++++++---------- templates/update_form.erb | 4 ++-- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/bin/mpw-update b/bin/mpw-update index 301b876..221c632 100644 --- a/bin/mpw-update +++ b/bin/mpw-update @@ -52,6 +52,10 @@ OptionParser.new do |opts| values[:pattern] = pattern end + opts.on('-r', '--random', I18n.t('option.random_password')) do + options[:password] = true + end + opts.on('-w', '--wallet NAME', I18n.t('option.wallet')) do |wallet| options[:wallet] = wallet end @@ -63,4 +67,4 @@ cli = MPW::Cli.new(config, options[:sync]) cli.load_config cli.get_wallet(options[:wallet]) cli.decrypt -cli.update(values) +cli.update(options[:password], values) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 3ad32be..9e8040e 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -423,12 +423,9 @@ class Cli # Form to add a new item # @args: password -> generate a random password def add(password=false) - options = text_editor('add_form', nil, password) - item = Item.new(options) - - if password - options[:password] = MPW::password(@config.password) - end + options = text_editor('add_form', nil, password) + item = Item.new(options) + options[:password] = MPW::password(@config.password) if password @mpw.add(item) @mpw.set_password(item.id, options[:password]) if options.has_key?(:password) @@ -442,8 +439,9 @@ class Cli end # Update an item - # @args: options -> the option to search - def update(options={}) + # @args: password -> generate a random password + # options -> the option to search + def update(password=false, options={}) items = @mpw.list(options) if items.length == 0 @@ -451,8 +449,9 @@ class Cli else table_items(items) if items.length > 1 - item = get_item(items) - options = text_editor('update_form', item) + item = get_item(items) + options = text_editor('update_form', item, password) + options[:password] = MPW::password(@config.password) if password item.update(options) @mpw.set_password(item.id, options[:password]) if options.has_key?(:password) diff --git a/templates/update_form.erb b/templates/update_form.erb index b942cf5..e5363f8 100644 --- a/templates/update_form.erb +++ b/templates/update_form.erb @@ -2,9 +2,9 @@ # <%= I18n.t('form.update_item.host') %> host: <%= item.host %> # <%= I18n.t('form.update_item.login') %> -user: <%= item.user %> +user: <%= item.user %><% if not password %> # <%= I18n.t('form.update_item.password') %> -password: +password: <% end %> # <%= I18n.t('form.update_item.group') %> group: <%= item.group %> # <%= I18n.t('form.update_item.protocol') %> From ba745ccc0c148da7902fb5ed4c4ea74f783bd74b Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Thu, 2 Mar 2017 23:43:19 +0100 Subject: [PATCH 046/165] update README --- README.md | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 67 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 563c592..fa81df6 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,6 @@ [](https://travis-ci.org/nishiki/manage-password) [](https://github.com/nishiki/manage-password/blob/master/LICENSE) - mpw is a little software which stores your passwords in [GnuPG](http://www.gnupg.org/) encrypted files. ## Features @@ -11,6 +10,8 @@ mpw is a little software which stores your passwords in [GnuPG](http://www.gnupg * generate OTP code * synchronize your passwords with SSH or FTP. * copy your login, password or otp in clipboard + * manage many wallets + * share a wallet with others GPG keys ## Install @@ -20,17 +21,28 @@ apt install ruby ruby-dev xclip gem install mpw ``` +## How to use +### First steps -# How to use - -A simple mpw usage: +Initialize your first wallet: ``` mpw config --init user@host.com +``` + +Add your first item: +``` mpw add -mpw copy -mpw add +``` + +And list your items: +``` mpw list ``` +or search an item with +``` +mpw list --pattern Da +mpw list --group bank +``` Output: ``` @@ -47,3 +59,52 @@ Linux 2 | linuxfr.org | example | https | | | Da Linux French Site ``` + +Copy a password, login or OTP code: +``` +mpw copy -p linuxfr +``` + +Update an item: +``` +mpw update -p linuxfr +``` + +Delete an item: +``` +mpw delete -p linuxfr +``` + +### Manage wallets + +List all available wallets: +``` +mpw wallet --list +``` + +Create an other wallet: +``` +mpw config --wallet work --init user@host.com +``` + +List all GPG keys in wallet: +``` +mpw wallet --list-keys [--wallet NAME] +``` + +Share with an other GPG key: +``` +mpw wallet --add-gpg-key test42@localhost.com + or +mpw wallet --add-gpg-key /path/to/file +``` + +Remove a GPG key: +``` +mpw wallet --delete-gpg-key test42@localhost.com +``` + +Add synchronize: +``` +mpw wallet --protocol ssh --host example.com --user test --path /remote/path --password +``` From 55e46e1afadfaca42fad2e39456ed0067a221856 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Thu, 2 Mar 2017 23:47:24 +0100 Subject: [PATCH 047/165] convert changelog to markdown --- CHANGELOG | 49 ------------------------------------------------- CHANGELOG.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 49 deletions(-) delete mode 100644 CHANGELOG create mode 100644 CHANGELOG.md diff --git a/CHANGELOG b/CHANGELOG deleted file mode 100644 index e154a0c..0000000 --- a/CHANGELOG +++ /dev/null @@ -1,49 +0,0 @@ -= CHANGELOG = -== v4.0.0-beta1 == - -* add manage share key with new interface - -== v4.0.0-beta == - -* new interface with a table -* new command line interface -* use text editor for add or update an item -* fix generate gpg key with RSA -* several bugs fix -* add unit tests - -== v3.2.1 == - -* fix bug when add a new item - -== v3.2.0 == - -* add support OTP -* fix bug in synchronize -* improve interface - -== v3.1.0 == - -* add clipboard -* can change gpg version -* minor change in interface -* several bugs fix - -== v3.0.0 == - -* new storage format -* new share system -* remove MPW server - -== v2.0.0 == - -* change format csv to yaml -* easy install with gem -* add sync with ftp and ssh -* many improvement - -== v1.1.0 == - -* Add sync with MPW Server -* Add MPW Server -* Fix minors bugs diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..f00a846 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,49 @@ +# CHANGELOG +## v4.0.0-beta1 + + * add manage share key with new interface + +## v4.0.0-beta + + * new interface with a table + * new command line interface + * use text editor for add or update an item + * fix generate gpg key with RSA + * several bugs fix + * add unit tests + +## v3.2.1 + + * fix bug when add a new item + +## v3.2.0 + + * add support OTP + * fix bug in synchronize + * improve interface + +## v3.1.0 + + * add clipboard + * can change gpg version + * minor change in interface + * several bugs fix + +## v3.0.0 + + * new storage format + * new share system + * remove MPW server + +## v2.0.0 + + * change format csv to yaml + * easy install with gem + * add sync with ftp and ssh + * many improvement + +## v1.1.0 + + * Add sync with MPW Server + * Add MPW Server + * Fix minors bugs From 8fb83bd3910f321ce34cbee6d4ed6e6ac9d59664 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Fri, 3 Mar 2017 21:57:21 +0100 Subject: [PATCH 048/165] fix message in export function --- lib/mpw/cli.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 9e8040e..1eb2b94 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -538,7 +538,7 @@ class Cli File.open(file, 'w') {|f| f << data.to_yaml} - puts "#{I18n.t('form.export.valid', file)}".green + puts "#{I18n.t('form.export.valid', file: file)}".green rescue Exception => e puts "#{I18n.t('display.error')} #17: #{e}".red end From de4beba3dbb2f487c62f98f4a8380d4ad51d04fc Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Fri, 3 Mar 2017 22:00:15 +0100 Subject: [PATCH 049/165] export items with id --- lib/mpw/cli.rb | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 1eb2b94..90fe00d 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -517,23 +517,20 @@ class Cli file = 'export-mpw.yml' if file.to_s.empty? items = @mpw.list(options) data = {} - i = 1 items.each do |item| - data.merge!(i => { 'host' => item.host, - 'user' => item.user, - 'group' => item.group, - 'password' => @mpw.get_password(item.id), - 'protocol' => item.protocol, - 'port' => item.port, - 'otp_key' => @mpw.get_otp_key(item.id), - 'comment' => item.comment, - 'last_edit' => item.last_edit, - 'created' => item.created, - } + data.merge!(item.id => { 'host' => item.host, + 'user' => item.user, + 'group' => item.group, + 'password' => @mpw.get_password(item.id), + 'protocol' => item.protocol, + 'port' => item.port, + 'otp_key' => @mpw.get_otp_key(item.id), + 'comment' => item.comment, + 'last_edit' => item.last_edit, + 'created' => item.created, + } ) - - i += 1 end File.open(file, 'w') {|f| f << data.to_yaml} @@ -550,7 +547,6 @@ class Cli raise I18n.t('form.import.file_not_exist') if not File.exist?(file) YAML::load_file(file).each_value do |row| - item = Item.new(group: row['group'], host: row['host'], protocol: row['protocol'], From 44c1c2b4764c87b6ff3513e47aadf9f59ccdd166 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Fri, 3 Mar 2017 22:42:30 +0100 Subject: [PATCH 050/165] update readme --- README.md | 39 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 38 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index fa81df6..6b32418 100644 --- a/README.md +++ b/README.md @@ -7,10 +7,11 @@ mpw is a little software which stores your passwords in [GnuPG](http://www.gnupg ## Features + * generate random password * generate OTP code - * synchronize your passwords with SSH or FTP. * copy your login, password or otp in clipboard * manage many wallets + * synchronize your passwords with SSH or FTP. * share a wallet with others GPG keys ## Install @@ -108,3 +109,39 @@ Add synchronize: ``` mpw wallet --protocol ssh --host example.com --user test --path /remote/path --password ``` + +### Export and import data + +You can export your data in yaml file with your passwords in clear text: +``` +mpw export --file export.yml +``` + +Import data from an yaml file: +``` +mpw import --file import.yml +``` + +Example yaml file for mpw: + +``` +--- +1: + host: bank.com + user: 123456 + group: Bank + password: secret + protocol: https + port: + otp_key: 1afg34 + comment: +2: + host: linuxfr.org + user: example + group: + password: 'complex %- password' + protocol: https + port: + otp_key: + comment: Da Linux French Site +``` From 58215d4e01ab133e8324c21be9b5d0220e88ddf1 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Fri, 3 Mar 2017 22:57:03 +0100 Subject: [PATCH 051/165] ignore *.gem --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index b844b14..7ae6fcf 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ Gemfile.lock +*.gem From ffedd5b88bae5ecd214d2a1a111cd2f2d7d782e4 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 8 Mar 2017 21:23:15 +0100 Subject: [PATCH 052/165] fix error when delete an item with sync --- lib/mpw/mpw.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 1e86c08..fe46108 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -319,6 +319,8 @@ class MPW if not remote.to_s.empty? @data.each do |item| + next if item.empty? + update = false remote.list.each do |r| From 5a1e0f6aa8a1f07e0c5fb54be8d6d1760cacc190 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Thu, 9 Mar 2017 21:06:05 +0100 Subject: [PATCH 053/165] release version 4.0.0 --- CHANGELOG.md | 7 +++++++ README.md | 2 +- VERSION | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f00a846..452ac98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,11 @@ # CHANGELOG +## v4.0.0 + + * feature: set default wallet + * add option for generate a random password when you update an item + * fix encryption when you share an existing wallet + * several bugs fix + ## v4.0.0-beta1 * add manage share key with new interface diff --git a/README.md b/README.md index 6b32418..7ac7d47 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # MPW: Manage your passwords! -[](https://github.com/nishiki/manage-password/releases) +[](https://github.com/nishiki/manage-password/releases) [](https://travis-ci.org/nishiki/manage-password) [](https://github.com/nishiki/manage-password/blob/master/LICENSE) diff --git a/VERSION b/VERSION index 817c97b..fcdb2e1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.0.0-beta1 +4.0.0 From 2e6d111b69f2153afdf34c39503a15229a91ec30 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Mon, 27 Mar 2017 21:27:50 +0200 Subject: [PATCH 054/165] begind version 4.1.0 --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index fcdb2e1..4aa925d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.0.0 +4.1.0-dev From 871b1dcbed1490d47b8bab40cd22e12aae6eb879 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Mon, 27 Mar 2017 21:47:43 +0200 Subject: [PATCH 055/165] remove all sync --- README.md | 6 --- bin/mpw-add | 9 +--- bin/mpw-copy | 7 +-- bin/mpw-delete | 11 ++--- bin/mpw-export | 11 ++--- bin/mpw-import | 9 +--- bin/mpw-list | 11 ++--- bin/mpw-update | 11 ++--- bin/mpw-wallet | 34 +------------- i18n/en.yml | 26 ----------- i18n/fr.yml | 26 ----------- lib/mpw/cli.rb | 32 +------------ lib/mpw/item.rb | 7 --- lib/mpw/mpw.rb | 106 -------------------------------------------- lib/mpw/sync/ftp.rb | 68 ---------------------------- lib/mpw/sync/ssh.rb | 67 ---------------------------- 16 files changed, 20 insertions(+), 421 deletions(-) delete mode 100644 lib/mpw/sync/ftp.rb delete mode 100644 lib/mpw/sync/ssh.rb diff --git a/README.md b/README.md index 7ac7d47..fd2534a 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,6 @@ mpw is a little software which stores your passwords in [GnuPG](http://www.gnupg * generate OTP code * copy your login, password or otp in clipboard * manage many wallets - * synchronize your passwords with SSH or FTP. * share a wallet with others GPG keys ## Install @@ -105,11 +104,6 @@ Remove a GPG key: mpw wallet --delete-gpg-key test42@localhost.com ``` -Add synchronize: -``` -mpw wallet --protocol ssh --host example.com --user test --path /remote/path --password -``` - ### Export and import data You can export your data in yaml file with your passwords in clear text: diff --git a/bin/mpw-add b/bin/mpw-add index 5322cc1..fc688a4 100644 --- a/bin/mpw-add +++ b/bin/mpw-add @@ -24,8 +24,7 @@ require 'mpw/cli' # Options # --------------------------------------------------------- # -options = {} -options[:sync] = true +options = {} OptionParser.new do |opts| opts.banner = "#{I18n.t('option.usage')}: mpw add [options]" @@ -39,10 +38,6 @@ OptionParser.new do |opts| exit 0 end - opts.on('-n', '--no-sync', I18n.t('option.no_sync')) do - options[:sync] = false - end - opts.on('-r', '--random', I18n.t('option.random_password')) do options[:password] = true end @@ -53,7 +48,7 @@ OptionParser.new do |opts| end.parse! config = MPW::Config.new(options[:config]) -cli = MPW::Cli.new(config, options[:sync]) +cli = MPW::Cli.new(config) cli.load_config cli.get_wallet(options[:wallet]) diff --git a/bin/mpw-copy b/bin/mpw-copy index 0a14ed7..1e5804b 100644 --- a/bin/mpw-copy +++ b/bin/mpw-copy @@ -25,7 +25,6 @@ require 'mpw/cli' # --------------------------------------------------------- # options = {} -options[:sync] = true options[:clipboard] = true values = {} @@ -49,10 +48,6 @@ OptionParser.new do |opts| exit 0 end - opts.on('-n', '--no-sync', I18n.t('option.no_sync')) do - options[:sync] = false - end - opts.on('-p', '--pattern PATTERN', I18n.t('option.pattern')) do |pattern| values[:pattern] = pattern end @@ -63,7 +58,7 @@ OptionParser.new do |opts| end.parse! config = MPW::Config.new(options[:config]) -cli = MPW::Cli.new(config, options[:sync]) +cli = MPW::Cli.new(config) cli.load_config cli.get_wallet(options[:wallet]) diff --git a/bin/mpw-delete b/bin/mpw-delete index 2d79e6a..53c8074 100644 --- a/bin/mpw-delete +++ b/bin/mpw-delete @@ -24,9 +24,8 @@ require 'mpw/cli' # Options # --------------------------------------------------------- # -options = {} -options[:sync] = true -values = {} +options = {} +values = {} OptionParser.new do |opts| opts.banner = "#{I18n.t('option.usage')}: mpw delete [options]" @@ -44,10 +43,6 @@ OptionParser.new do |opts| exit 0 end - opts.on('-n', '--no-sync', I18n.t('option.no_sync')) do - options[:sync] = false - end - opts.on('-p', '--pattern PATTERN', I18n.t('option.pattern')) do |pattern| values[:pattern] = pattern end @@ -58,7 +53,7 @@ OptionParser.new do |opts| end.parse! config = MPW::Config.new(options[:config]) -cli = MPW::Cli.new(config, options[:sync]) +cli = MPW::Cli.new(config) cli.load_config cli.get_wallet(options[:wallet]) diff --git a/bin/mpw-export b/bin/mpw-export index f891873..7913040 100644 --- a/bin/mpw-export +++ b/bin/mpw-export @@ -24,9 +24,8 @@ require 'mpw/cli' # Options # --------------------------------------------------------- # -options = {} -options[:sync] = true -values = {} +options = {} +values = {} OptionParser.new do |opts| opts.banner = "#{I18n.t('option.usage')}: mpw wallet [options]" @@ -48,10 +47,6 @@ OptionParser.new do |opts| exit 0 end - opts.on('-n', '--no-sync', I18n.t('option.no_sync')) do - options[:sync] = false - end - opts.on('-p', '--pattern PATTERN', I18n.t('option.pattern')) do |pattern| values[:pattern] = pattern end @@ -62,7 +57,7 @@ OptionParser.new do |opts| end.parse! config = MPW::Config.new(options[:config]) -cli = MPW::Cli.new(config, options[:sync]) +cli = MPW::Cli.new(config) cli.load_config cli.get_wallet(options[:wallet]) diff --git a/bin/mpw-import b/bin/mpw-import index c740252..a827783 100644 --- a/bin/mpw-import +++ b/bin/mpw-import @@ -24,8 +24,7 @@ require 'mpw/cli' # Options # --------------------------------------------------------- # -options = {} -options[:sync] = true +options = {} OptionParser.new do |opts| opts.banner = "#{I18n.t('option.usage')}: mpw import [options]" @@ -43,17 +42,13 @@ OptionParser.new do |opts| exit 0 end - opts.on('-n', '--no-sync', I18n.t('option.no_sync')) do - options[:sync] = false - end - opts.on('-w', '--wallet NAME', I18n.t('option.wallet')) do |wallet| options[:wallet] = wallet end end.parse! config = MPW::Config.new(options[:config]) -cli = MPW::Cli.new(config, options[:sync]) +cli = MPW::Cli.new(config) cli.load_config cli.get_wallet(options[:wallet]) diff --git a/bin/mpw-list b/bin/mpw-list index 9d18b0d..3ebc2b8 100644 --- a/bin/mpw-list +++ b/bin/mpw-list @@ -24,9 +24,8 @@ require 'mpw/cli' # Options # --------------------------------------------------------- # -options = {} -options[:sync] = true -values = {} +options = {} +values = {} OptionParser.new do |opts| opts.banner = "#{I18n.t('option.usage')}: mpw list [options]" @@ -48,17 +47,13 @@ OptionParser.new do |opts| values[:pattern] = pattern end - opts.on('-n', '--no-sync', I18n.t('option.no_sync')) do - options[:sync] = false - end - opts.on('-w', '--wallet NAME', I18n.t('option.wallet')) do |wallet| options[:wallet] = wallet end end.parse! config = MPW::Config.new(options[:config]) -cli = MPW::Cli.new(config, options[:sync]) +cli = MPW::Cli.new(config) cli.load_config cli.get_wallet(options[:wallet]) diff --git a/bin/mpw-update b/bin/mpw-update index 221c632..fd207c5 100644 --- a/bin/mpw-update +++ b/bin/mpw-update @@ -24,9 +24,8 @@ require 'mpw/cli' # Options # --------------------------------------------------------- # -options = {} -options[:sync] = true -values = {} +options = {} +values = {} OptionParser.new do |opts| opts.banner = "#{I18n.t('option.usage')}: mpw update [options]" @@ -44,10 +43,6 @@ OptionParser.new do |opts| exit 0 end - opts.on('-n', '--no-sync', I18n.t('option.no_sync')) do - options[:sync] = false - end - opts.on('-p', '--pattern PATTERN', I18n.t('option.pattern')) do |pattern| values[:pattern] = pattern end @@ -62,7 +57,7 @@ OptionParser.new do |opts| end.parse! config = MPW::Config.new(options[:config]) -cli = MPW::Cli.new(config, options[:sync]) +cli = MPW::Cli.new(config) cli.load_config cli.get_wallet(options[:wallet]) diff --git a/bin/mpw-wallet b/bin/mpw-wallet index fbf0389..56e96ba 100644 --- a/bin/mpw-wallet +++ b/bin/mpw-wallet @@ -25,9 +25,7 @@ require 'mpw/cli' # --------------------------------------------------------- # options = {} -options[:sync] = {} options[:delete] = false -values = {} OptionParser.new do |opts| opts.banner = "#{I18n.t('option.usage')}: mpw wallet [options]" @@ -50,10 +48,6 @@ OptionParser.new do |opts| exit 0 end - opts.on('--host NAME', I18n.t('option.host')) do |host| - values[:host] = host - end - opts.on('-l', '--list', I18n.t('option.list')) do options[:list] = true end @@ -62,37 +56,13 @@ OptionParser.new do |opts| options[:list_keys] = true end - opts.on('-n', '--no-sync', I18n.t('option.no_sync')) do - options[:sync] = false - end - - opts.on('--password', I18n.t('option.password')) do - values[:password] = true - end - - opts.on('--path PATH', I18n.t('option.path')) do |path| - values[:path] = path - end - - opts.on('--port NUMBER', I18n.t('option.port')) do |port| - values[:port] = port - end - - opts.on('--protocol NAME', I18n.t('option.protocol')) do |protocol| - values[:protocol] = protocol - end - - opts.on('--user NAME', I18n.t('option.user')) do |user| - values[:user] = user - end - opts.on('-w', '--wallet NAME', I18n.t('option.wallet')) do |wallet| options[:wallet] = wallet end end.parse! config = MPW::Config.new(options[:config]) -cli = MPW::Cli.new(config, options[:sync]) +cli = MPW::Cli.new(config) cli.load_config @@ -110,7 +80,5 @@ else else cli.add_key(options[:gpg_key]) end - elsif not values.empty? - cli.setup_wallet_config(values) end end diff --git a/i18n/en.yml b/i18n/en.yml index 5ee9868..162f6b3 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -23,15 +23,6 @@ en: import: "Can't import, unable to read %{file}!" update: host_empty: "You must define a host!" - sync: - general: "An error has appeared during the sync" - connection: "Connection fail!" - communication: "A communication problem with the server is appeared!" - download: "Can't download the file!" - not_authorized: "You haven't the access to remote file!" - upload: "Can't upload the file on the server!" - unknown: "An unknown error is occured!" - unknown_type: "The sync type is unknown" warning: select: 'Your choice is not a valid element!' @@ -68,7 +59,6 @@ en: gpg_key: "Specify a GPG key (ex: user@example.com)" group: "Search the items with specified group" help: "Show this help message" - host: "Specify the server for the synchronization" init: "Initialize mpw" import: "Import item since a yaml file" key: "Specify the key name" @@ -76,13 +66,8 @@ en: length: "Size of the password" list: "List the wallets" list_keys: "List the GPG keys in wallet" - no_sync: "Disable synchronization with the server" numeric: "Use number to generate a password" - password: "Change the password for the synchronization" - path: "Specify the remote path" pattern: "Given search pattern" - port: "Specify the connection port" - protocol: "Specify the protocol for the connection" random_password: "Generate a random password" setup: "Create a new configuration file" setup_wallet: "Create a new configuration file for a wallet" @@ -90,7 +75,6 @@ en: show: "Search and show the items" show_all: "List all items" usage: "Usage" - user: "Specify the user for the connection" wallet: "Specify a wallet to use" wallet_dir: "Set the wallets folder" @@ -141,16 +125,6 @@ en: gpg_exe: "Enter the executable GPG path (optional): " wallet_dir: "Enter the wallets's folder path [default=%{home}/wallets]: " valid: "The config file has been created!" - setup_wallet: - password: "Sync password: " - title: "Wallet setup" - sync_type: "Synchronization type (ssh, ftp): " - sync_host: "Synchronization server: " - sync_port: "Port of the synchronization server: " - sync_user: "Username for the synchronization: " - sync_pwd: "Password for the synchronization: " - sync_path: "File path for the synchronization : " - valid: "The wallet config file has been created!" setup_gpg_key: title: "Setup a GPG key" ask: "Do you want create your GPG key ? (Y/n)" diff --git a/i18n/fr.yml b/i18n/fr.yml index d9bd279..b2e3db4 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -23,15 +23,6 @@ fr: import: "Impossible d'importer le fichier %{file}, car il n'est pas lisible!" update: host_empty: "Vous devez définir un host!" - sync: - general: "Une erreur est survenue durant la synchronisation" - connection: "La connexion n'a pu être établie!" - communication: "Un problème de communication avec le serveur est apparu!" - download: "Impossible de télécharger le fichier!" - not_authorized: "Vous n'avez pas les autorisations d'accès au fichier distant!" - upload: "Impossible d'envoyer le fichier sur le serveur!" - unknown: "Une erreur inconnue est survenue!" - unknown_type: "Le type de synchronisation est inconnu" warning: select: "Votre choix n'est pas un élément valide!" @@ -68,7 +59,6 @@ fr: gpg_key: "Spécifie une clé GPG (ex: user@example.com)" group: "Recherche les éléments appartenant au groupe spécifié" help: "Affiche ce message d'aide" - host: "Spécifie le serveur pour la synchronisation" import: "Importe des éléments depuis un fichier yaml" init: "Initialise mpw" key: "Spécifie le nom d'une clé" @@ -76,13 +66,8 @@ fr: length: "Taille du mot de passe" list: "Liste les portefeuilles" list_keys: "Liste les clés GPG dans le portefeuille" - no_sync: "Désactive la synchronisation avec le serveur" numeric: "Utilise des chiffre dans la génération d'un mot de passe" - password: "Changer le mot de passe de connexion" - path: "Spécifie le chemin distant" pattern: "Motif de donnée à chercher" - port: "Spécifie le port de connexion" - protocol: "Spécifie le protocol utilisé pour la connexion" random_password: "Génére un mot de passe aléatoire" setup: "Création d'un nouveau fichier de configuration" setup_wallet: "Création d'un nouveau fichier de configuration pour un portefeuille" @@ -90,7 +75,6 @@ fr: show: "Recherche et affiche les éléments" show_all: "Liste tous les éléments" usage: "Utilisation" - user: "Spécifie l'identifiant de connection" wallet: "Spécifie le portefeuille à utiliser" wallet_dir: "Spécifie le répertoire des portefeuilles" @@ -141,16 +125,6 @@ fr: gpg_exe: "Entrez le chemin de l'exécutable GPG (optionnel): " wallet_dir: "Entrez le chemin du répertoire qui contiendra les porte-feuilles de mot de passe [défaut=%{home}/wallets]: " valid: "Le fichier de configuration a bien été créé!" - setup_wallet: - password: "Mot de passe de synchronisation: " - title: "Configuration du porte-feuille" - sync_type: "Type de synchronisation (ssh, ftp): " - sync_host: "Serveur: " - sync_port: "Port: " - sync_user: "Utilisateur: " - sync_pwd: "Mot de passe: " - sync_path: "Chemin du fichier: " - valid: "Le fichier de configuration du porte-feuille a bien été créé!" setup_gpg_key: title: "Configuration d'une nouvelle clé GPG" ask: "Voulez vous créer votre clé GPG ? (O/n)" diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 90fe00d..0eb294e 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -31,10 +31,8 @@ class Cli # Constructor # @args: config -> the config - # sync -> boolean for sync or not - def initialize(config, sync=true) - @config = config - @sync = sync + def initialize(config) + @config = config end # Change a parameter int the config after init @@ -89,26 +87,6 @@ class Cli exit 2 end - # Setup wallet config for sync - # @args: options -> value to change - def setup_wallet_config(options={}) - if not options[:password].nil? - options[:password] = ask(I18n.t('form.setup_wallet.password')) {|q| q.echo = false} - end - - #wallet_file = wallet.nil? ? "#{@config.wallet_dir}/default.mpw" : "#{@config.wallet_dir}/#{wallet}.mpw" - - @mpw = MPW.new(@config.gpg_key, @wallet_file, @password, @config.gpg_exe) - @mpw.read_data - @mpw.set_config(options) - @mpw.write_data - - puts "#{I18n.t('form.setup_wallet.valid')}".green - rescue Exception => e - puts "#{I18n.t('display.error')} #10: #{e}".red - exit 2 - end - # List gpg keys in wallet def list_keys table_list('keys', @mpw.list_keys) @@ -131,7 +109,6 @@ class Cli end @mpw.read_data - @mpw.sync if @sync rescue Exception => e puts "#{I18n.t('display.error')} #11: #{e}".red exit 2 @@ -369,7 +346,6 @@ class Cli def add_key(key) @mpw.add_key(key) @mpw.write_data - @mpw.sync(true) if @sync puts "#{I18n.t('form.add_key.valid')}".green rescue Exception => e @@ -381,7 +357,6 @@ class Cli def delete_key(key) @mpw.delete_key(key) @mpw.write_data - @mpw.sync(true) if @sync puts "#{I18n.t('form.delete_key.valid')}".green rescue Exception => e @@ -431,7 +406,6 @@ class Cli @mpw.set_password(item.id, options[:password]) if options.has_key?(:password) @mpw.set_otp_key(item.id, options[:otp_key]) if options.has_key?(:otp_key) @mpw.write_data - @mpw.sync(true) if @sync puts "#{I18n.t('form.add_item.valid')}".green rescue Exception => e @@ -457,7 +431,6 @@ class Cli @mpw.set_password(item.id, options[:password]) if options.has_key?(:password) @mpw.set_otp_key(item.id, options[:otp_key]) if options.has_key?(:otp_key) @mpw.write_data - @mpw.sync(true) if @sync puts "#{I18n.t('form.update_item.valid')}".green end @@ -484,7 +457,6 @@ class Cli item.delete @mpw.write_data - @mpw.sync(true) if @sync puts "#{I18n.t('form.delete_item.valid')}".green end diff --git a/lib/mpw/item.rb b/lib/mpw/item.rb index d3783b9..a4f730b 100644 --- a/lib/mpw/item.rb +++ b/lib/mpw/item.rb @@ -30,7 +30,6 @@ class Item attr_accessor :otp attr_accessor :comment attr_accessor :last_edit - attr_accessor :last_sync attr_accessor :created # Constructor @@ -72,11 +71,6 @@ class Item @last_edit = Time.now.to_i if not options.has_key?(:no_update_last_edit) end - # Update last_sync - def set_last_sync - @last_sync = Time.now.to_i - end - # Delete all data def delete @id = nil @@ -89,7 +83,6 @@ class Item @comment = nil @created = nil @last_edit = nil - @last_sync = nil end def empty? diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index fe46108..8f4b42e 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -229,7 +229,6 @@ class MPW @config['user'] = options[:user] if options.has_key?(:user) @config['password'] = options[:password] if options.has_key?(:password) @config['path'] = options[:path] if options.has_key?(:path) - @config['last_sync'] = @config['last_sync'].nil? ? 0 : @config['last_sync'] end # Add a new item @@ -281,111 +280,6 @@ class MPW return nil end - # Get last sync - def get_last_sync - return @config['last_sync'].to_i - rescue - return 0 - end - - # Sync data with remote file - # @args: force -> force the sync - def sync(force=false) - return if @config.empty? or @config['protocol'].to_s.empty? - return if get_last_sync + 300 > Time.now.to_i and not force - - tmp_file = "#{@wallet_file}.sync" - - case @config['protocol'] - when 'sftp', 'scp', 'ssh' - require "mpw/sync/ssh" - sync = SyncSSH.new(@config) - when 'ftp' - require 'mpw/sync/ftp' - sync = SyncFTP.new(@config) - else - raise I18n.t('error.sync.unknown_type') - end - - sync.connect - sync.get(tmp_file) - - remote = MPW.new(@key, tmp_file, @gpg_pass, @gpg_exe) - remote.read_data - - File.unlink(tmp_file) if File.exist?(tmp_file) - - return if remote.get_last_sync == @config['last_update'] - - if not remote.to_s.empty? - @data.each do |item| - next if item.empty? - - update = false - - remote.list.each do |r| - next if item.id != r.id - - # Update item - if item.last_edit < r.last_edit - item.update(group: r.group, - host: r.host, - protocol: r.protocol, - user: r.user, - port: r.port, - comment: r.comment - ) - set_password(item.id, remote.get_password(item.id)) - end - - r.delete - update = true - - break - end - - # Remove an old item - if not update and item.last_sync.to_i < get_last_sync and item.last_edit < get_last_sync - item.delete - end - end - end - - # Add item - remote.list.each do |r| - next if r.last_edit <= get_last_sync - - item = Item.new(id: r.id, - group: r.group, - host: r.host, - protocol: r.protocol, - user: r.user, - port: r.port, - comment: r.comment, - created: r.created, - last_edit: r.last_edit - ) - - set_password(item.id, remote.get_password(item.id)) - add(item) - end - - remote = nil - - @data.each do |item| - item.set_last_sync - end - - @config['last_sync'] = Time.now.to_i - - write_data - sync.update(@wallet_file) - rescue Exception => e - File.unlink(tmp_file) if File.exist?(tmp_file) - - raise "#{I18n.t('error.sync.general')}\n#{e}" - end - # Set an opt key # args: id -> the item id # key -> the new key diff --git a/lib/mpw/sync/ftp.rb b/lib/mpw/sync/ftp.rb deleted file mode 100644 index d64e629..0000000 --- a/lib/mpw/sync/ftp.rb +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/ruby -# MPW is a software to crypt and manage your passwords -# Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> -# -# 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 2 -# 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, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -require 'i18n' -require 'net/ftp' - -module MPW -class FTP - - # Constructor - # @args: config -> the config - def initialize(config) - @host = config['host'] - @user = config['user'] - @password = config['password'] - @path = config['path'] - @port = config['port'].instance_of?(Integer) ? 22 : config['port'] - end - - - # Connect to server - def connect - Net::FTP.open(@host) do |ftp| - ftp.login(@user, @password) - break - end - rescue Exception => e - raise "#{I18n.t('error.sync.connection')}\n#{e}" - end - - # Get data on server - # @args: file_tmp -> the path where download the file - def get(file_tmp) - Net::FTP.open(@host) do |ftp| - ftp.login(@user, @password) - ftp.gettextfile(@path, file_tmp) - end - rescue Exception => e - raise "#{I18n.t('error.sync.download')}\n#{e}" - end - - # Update the remote data - # @args: file_gpg -> the data to send on server - def update(file_gpg) - Net::FTP.open(@host) do |ftp| - ftp.login(@user, @password) - ftp.puttextfile(file_gpg, @path) - end - rescue Exception => e - raise "#{I18n.t('error.sync.upload')}\n#{e}" - end -end -end diff --git a/lib/mpw/sync/ssh.rb b/lib/mpw/sync/ssh.rb deleted file mode 100644 index 4471949..0000000 --- a/lib/mpw/sync/ssh.rb +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/ruby -# MPW is a software to crypt and manage your passwords -# Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> -# -# 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 2 -# 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, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -require 'i18n' -require 'net/ssh' -require 'net/sftp' - -module MPW -class SyncSSH - - # Constructor - # @args: config -> the config - def initialize(config) - @host = config['host'] - @user = config['user'] - @password = config['password'] - @path = config['path'] - @port = config['port'].instance_of?(Integer) ? 22 : config['port'] - end - - # Connect to server - def connect - Net::SSH.start(@host, @user, password: @password, port: @port) do - break - end - rescue Exception => e - raise "#{I18n.t('error.sync.connection')}\n#{e}" - end - - # Get data on server - # @args: file_tmp -> the path where download the file - def get(file_tmp) - Net::SFTP.start(@host, @user, password: @password, port: @port) do |sftp| - sftp.lstat(@path) do |response| - sftp.download!(@path, file_tmp) if response.ok? - end - end - rescue Exception => e - raise "#{I18n.t('error.sync.download')}\n#{e}" - end - - # Update the remote data - # @args: file_gpg -> the data to send on server - def update(file_gpg) - Net::SFTP.start(@host, @user, password: @password, port: @port) do |sftp| - sftp.upload!(file_gpg, @path) - end - rescue Exception => e - raise "#{I18n.t('error.sync.upload')}\n#{e}" - end -end -end From 7c72b2d90f7322bae290b71e91fb010743269a70 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Mon, 27 Mar 2017 22:18:17 +0200 Subject: [PATCH 056/165] change tab by 2 spaces change tab by 2 spaces --- bin/mpw | 44 +- bin/mpw-add | 34 +- bin/mpw-config | 116 ++--- bin/mpw-copy | 46 +- bin/mpw-delete | 40 +- bin/mpw-export | 46 +- bin/mpw-genpwd | 40 +- bin/mpw-import | 34 +- bin/mpw-list | 40 +- bin/mpw-update | 46 +- bin/mpw-wallet | 78 +-- lib/mpw/cli.rb | 1028 ++++++++++++++++++++-------------------- lib/mpw/config.rb | 240 +++++----- lib/mpw/item.rb | 144 +++--- lib/mpw/mpw.rb | 592 +++++++++++------------ test/test_config.rb | 92 ++-- test/test_item.rb | 280 +++++------ test/test_mpw.rb | 212 ++++----- test/test_translate.rb | 46 +- test/tests.rb | 2 +- 20 files changed, 1600 insertions(+), 1600 deletions(-) diff --git a/bin/mpw b/bin/mpw index a69b568..3eb9fd9 100755 --- a/bin/mpw +++ b/bin/mpw @@ -1,17 +1,17 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> -# +# # 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 2 # 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, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -30,7 +30,7 @@ require 'colorize' lang = Locale::Tag.parse(ENV['LANG']).to_simple.to_s[0..1] if defined?(I18n.enforce_available_locales) - I18n.enforce_available_locales = true + I18n.enforce_available_locales = true end I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) @@ -46,24 +46,24 @@ bin_dir = File.dirname(__FILE__) command = "#{bin_dir}/mpw-#{ARGV[0]}" if Dir.glob("#{bin_dir}/mpw-*").include?("#{command}") - begin - Kernel.load(command) - rescue OptionParser::ParseError => e - puts "#{I18n.t('display.error')}: #{e}".red - end + begin + Kernel.load(command) + rescue OptionParser::ParseError => e + puts "#{I18n.t('display.error')}: #{e}".red + end else - puts "#{I18n.t('option.usage')}: mpw COMMAND [options]\n\n" - puts 'Commands:' - puts " add #{I18n.t('command.add')}" - puts " config #{I18n.t('command.config')}" - puts " copy #{I18n.t('command.copy')}" - puts " delete #{I18n.t('command.delete')}" - puts " export #{I18n.t('command.export')}" - puts " genpwd #{I18n.t('command.genpwd')}" - puts " import #{I18n.t('command.import')}" - puts " list #{I18n.t('command.list')}" - puts " update #{I18n.t('command.update')}" - puts " wallet #{I18n.t('command.wallet')}" + puts "#{I18n.t('option.usage')}: mpw COMMAND [options]\n\n" + puts 'Commands:' + puts " add #{I18n.t('command.add')}" + puts " config #{I18n.t('command.config')}" + puts " copy #{I18n.t('command.copy')}" + puts " delete #{I18n.t('command.delete')}" + puts " export #{I18n.t('command.export')}" + puts " genpwd #{I18n.t('command.genpwd')}" + puts " import #{I18n.t('command.import')}" + puts " list #{I18n.t('command.list')}" + puts " update #{I18n.t('command.update')}" + puts " wallet #{I18n.t('command.wallet')}" - exit 3 + exit 3 end diff --git a/bin/mpw-add b/bin/mpw-add index fc688a4..6376326 100644 --- a/bin/mpw-add +++ b/bin/mpw-add @@ -1,17 +1,17 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> -# +# # 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 2 # 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, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -27,24 +27,24 @@ require 'mpw/cli' options = {} OptionParser.new do |opts| - opts.banner = "#{I18n.t('option.usage')}: mpw add [options]" + opts.banner = "#{I18n.t('option.usage')}: mpw add [options]" - opts.on('-c', '--config PATH', I18n.t('option.config')) do |config| - options[:config] = config - end + opts.on('-c', '--config PATH', I18n.t('option.config')) do |config| + options[:config] = config + end - opts.on('-h', '--help', I18n.t('option.help')) do - puts opts - exit 0 - end + opts.on('-h', '--help', I18n.t('option.help')) do + puts opts + exit 0 + end - opts.on('-r', '--random', I18n.t('option.random_password')) do - options[:password] = true - end + opts.on('-r', '--random', I18n.t('option.random_password')) do + options[:password] = true + end - opts.on('-w', '--wallet NAME', I18n.t('option.wallet')) do |wallet| - options[:wallet] = wallet - end + opts.on('-w', '--wallet NAME', I18n.t('option.wallet')) do |wallet| + options[:wallet] = wallet + end end.parse! config = MPW::Config.new(options[:config]) diff --git a/bin/mpw-config b/bin/mpw-config index 1034f04..14387d9 100644 --- a/bin/mpw-config +++ b/bin/mpw-config @@ -1,17 +1,17 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> -# +# # 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 2 # 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, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -28,81 +28,81 @@ options = {} values = {} OptionParser.new do |opts| - opts.banner = "#{I18n.t('option.usage')}: mpw config [options]" + opts.banner = "#{I18n.t('option.usage')}: mpw config [options]" - opts.on('-c', '--config PATH', I18n.t('option.config')) do |config| - options[:config] = config - end + opts.on('-c', '--config PATH', I18n.t('option.config')) do |config| + options[:config] = config + end - opts.on('-d', '--default-wallet NAME', I18n.t('option.default_wallet')) do |default_wallet| - values[:default_wallet] = default_wallet - end + opts.on('-d', '--default-wallet NAME', I18n.t('option.default_wallet')) do |default_wallet| + values[:default_wallet] = default_wallet + end - opts.on('-g', '--gpg-exe PATH', I18n.t('option.gpg_exe')) do |gpg_exe| - values[:gpg_exe] = gpg_exe - end + opts.on('-g', '--gpg-exe PATH', I18n.t('option.gpg_exe')) do |gpg_exe| + values[:gpg_exe] = gpg_exe + end - opts.on('-h', '--help', I18n.t('option.help')) do - puts opts - exit 0 - end + opts.on('-h', '--help', I18n.t('option.help')) do + puts opts + exit 0 + end - opts.on('-i', '--init GPG_KEY', I18n.t('option.init')) do |gpg_key| - options[:init] = true - values[:gpg_key] = gpg_key - end + opts.on('-i', '--init GPG_KEY', I18n.t('option.init')) do |gpg_key| + options[:init] = true + values[:gpg_key] = gpg_key + end - opts.on('-k', '--key GPG_KEY', I18n.t('option.gpg_key')) do |gpg_key| - values[:gpg_key] = gpg_key - end + opts.on('-k', '--key GPG_KEY', I18n.t('option.gpg_key')) do |gpg_key| + values[:gpg_key] = gpg_key + end - opts.on('-L', '--lang LANG', I18n.t('option.lang')) do |lang| - values[:lang] = lang - end + opts.on('-L', '--lang LANG', I18n.t('option.lang')) do |lang| + values[:lang] = lang + end - opts.on('-w', '--wallet-dir PATH', I18n.t('option.wallet_dir')) do |wallet_dir| - values[:wallet_dir] = wallet_dir - end + opts.on('-w', '--wallet-dir PATH', I18n.t('option.wallet_dir')) do |wallet_dir| + values[:wallet_dir] = wallet_dir + end - opts.on('-l', '--length NUMBER', I18n.t('option.length')) do |length| - values[:pwd_length] = length.to_i - end + opts.on('-l', '--length NUMBER', I18n.t('option.length')) do |length| + values[:pwd_length] = length.to_i + end - opts.on('-n', '--numeric', I18n.t('option.numeric')) do - values[:pwd_numeric] = true - end + opts.on('-n', '--numeric', I18n.t('option.numeric')) do + values[:pwd_numeric] = true + end - opts.on('-N', '--disable-numeric', I18n.t('option.disable_numeric')) do - values[:pwd_numeric] = false - end + opts.on('-N', '--disable-numeric', I18n.t('option.disable_numeric')) do + values[:pwd_numeric] = false + end - opts.on('-s', '--special-chars', I18n.t('option.special_chars')) do - values[:pwd_special] = true - end + opts.on('-s', '--special-chars', I18n.t('option.special_chars')) do + values[:pwd_special] = true + end - opts.on('-S', '--disable_special-chars', I18n.t('option.special_chars')) do - values[:pwd_special] = false - end + opts.on('-S', '--disable_special-chars', I18n.t('option.special_chars')) do + values[:pwd_special] = false + end - opts.on('-a', '--alpha', I18n.t('option.alpha')) do - values[:pwd_alpha] = true - end + opts.on('-a', '--alpha', I18n.t('option.alpha')) do + values[:pwd_alpha] = true + end - opts.on('-A', '--disable-alpha', I18n.t('option.disable_alpha')) do - values[:pwd_alpha] = false - end + opts.on('-A', '--disable-alpha', I18n.t('option.disable_alpha')) do + values[:pwd_alpha] = false + end end.parse! config = MPW::Config.new(options[:config]) cli = MPW::Cli.new(config, nil) if options.has_key?(:init) - cli.setup(values) - cli.load_config - cli.get_wallet - cli.setup_gpg_key(values[:gpg_key]) - cli.setup_wallet_config + cli.setup(values) + cli.load_config + cli.get_wallet + cli.setup_gpg_key(values[:gpg_key]) + cli.setup_wallet_config else - cli.load_config - cli.set_config(values) + cli.load_config + cli.set_config(values) end diff --git a/bin/mpw-copy b/bin/mpw-copy index 1e5804b..9436a10 100644 --- a/bin/mpw-copy +++ b/bin/mpw-copy @@ -1,17 +1,17 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> -# +# # 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 2 # 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, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -29,32 +29,32 @@ options[:clipboard] = true values = {} OptionParser.new do |opts| - opts.banner = "#{I18n.t('option.usage')}: mpw copy [options]" + opts.banner = "#{I18n.t('option.usage')}: mpw copy [options]" - opts.on('-c', '--config PATH', I18n.t('option.config')) do |config| - options[:config] = config - end + opts.on('-c', '--config PATH', I18n.t('option.config')) do |config| + options[:config] = config + end - opts.on('-d', '--disable-clipboard', I18n.t('option.clipboard')) do - options[:clipboard] = false - end + opts.on('-d', '--disable-clipboard', I18n.t('option.clipboard')) do + options[:clipboard] = false + end - opts.on('-g', '--group NAME', I18n.t('option.group')) do |group| - values[:group] = group - end + opts.on('-g', '--group NAME', I18n.t('option.group')) do |group| + values[:group] = group + end - opts.on('-h', '--help', I18n.t('option.help')) do - puts opts - exit 0 - end + opts.on('-h', '--help', I18n.t('option.help')) do + puts opts + exit 0 + end - opts.on('-p', '--pattern PATTERN', I18n.t('option.pattern')) do |pattern| - values[:pattern] = pattern - end + opts.on('-p', '--pattern PATTERN', I18n.t('option.pattern')) do |pattern| + values[:pattern] = pattern + end - opts.on('-w', '--wallet NAME', I18n.t('option.wallet')) do |wallet| - options[:wallet] = wallet - end + opts.on('-w', '--wallet NAME', I18n.t('option.wallet')) do |wallet| + options[:wallet] = wallet + end end.parse! config = MPW::Config.new(options[:config]) diff --git a/bin/mpw-delete b/bin/mpw-delete index 53c8074..f276785 100644 --- a/bin/mpw-delete +++ b/bin/mpw-delete @@ -1,17 +1,17 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> -# +# # 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 2 # 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, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -28,28 +28,28 @@ options = {} values = {} OptionParser.new do |opts| - opts.banner = "#{I18n.t('option.usage')}: mpw delete [options]" + opts.banner = "#{I18n.t('option.usage')}: mpw delete [options]" - opts.on('-c', '--config PATH', I18n.t('option.config')) do |config| - options[:config] = config - end + opts.on('-c', '--config PATH', I18n.t('option.config')) do |config| + options[:config] = config + end - opts.on('-g', '--group NAME', I18n.t('option.group')) do |group| - values[:group] = group - end + opts.on('-g', '--group NAME', I18n.t('option.group')) do |group| + values[:group] = group + end - opts.on('-h', '--help', I18n.t('option.help')) do - puts opts - exit 0 - end + opts.on('-h', '--help', I18n.t('option.help')) do + puts opts + exit 0 + end - opts.on('-p', '--pattern PATTERN', I18n.t('option.pattern')) do |pattern| - values[:pattern] = pattern - end + opts.on('-p', '--pattern PATTERN', I18n.t('option.pattern')) do |pattern| + values[:pattern] = pattern + end - opts.on('-w', '--wallet NAME', I18n.t('option.wallet')) do |wallet| - options[:wallet] = wallet - end + opts.on('-w', '--wallet NAME', I18n.t('option.wallet')) do |wallet| + options[:wallet] = wallet + end end.parse! config = MPW::Config.new(options[:config]) diff --git a/bin/mpw-export b/bin/mpw-export index 7913040..982d1ad 100644 --- a/bin/mpw-export +++ b/bin/mpw-export @@ -1,17 +1,17 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> -# +# # 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 2 # 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, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -28,32 +28,32 @@ options = {} values = {} OptionParser.new do |opts| - opts.banner = "#{I18n.t('option.usage')}: mpw wallet [options]" + opts.banner = "#{I18n.t('option.usage')}: mpw wallet [options]" - opts.on('-c', '--config PATH', I18n.t('option.config')) do |config| - options[:config] = config - end + opts.on('-c', '--config PATH', I18n.t('option.config')) do |config| + options[:config] = config + end - opts.on('-f', '--file PATH', I18n.t('option.file_export')) do |file| - options[:file] = file - end + opts.on('-f', '--file PATH', I18n.t('option.file_export')) do |file| + options[:file] = file + end - opts.on('-g', '--group GROUP', I18n.t('option.group')) do |group| - values[:group] = group - end + opts.on('-g', '--group GROUP', I18n.t('option.group')) do |group| + values[:group] = group + end - opts.on('-h', '--help', I18n.t('option.help')) do - puts opts - exit 0 - end + opts.on('-h', '--help', I18n.t('option.help')) do + puts opts + exit 0 + end - opts.on('-p', '--pattern PATTERN', I18n.t('option.pattern')) do |pattern| - values[:pattern] = pattern - end + opts.on('-p', '--pattern PATTERN', I18n.t('option.pattern')) do |pattern| + values[:pattern] = pattern + end - opts.on('-w', '--wallet NAME', I18n.t('option.wallet')) do |wallet| - options[:wallet] = wallet - end + opts.on('-w', '--wallet NAME', I18n.t('option.wallet')) do |wallet| + options[:wallet] = wallet + end end.parse! config = MPW::Config.new(options[:config]) diff --git a/bin/mpw-genpwd b/bin/mpw-genpwd index 8af4290..0370732 100644 --- a/bin/mpw-genpwd +++ b/bin/mpw-genpwd @@ -1,17 +1,17 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> -# +# # 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 2 # 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, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -22,28 +22,28 @@ require 'mpw/mpw' options = {} OptionParser.new do |opts| - opts.banner = "#{I18n.t('option.usage')}: mpw passwd [options]" + opts.banner = "#{I18n.t('option.usage')}: mpw passwd [options]" - opts.on('-h', '--help', I18n.t('option.help')) do - puts opts - exit 0 - end + opts.on('-h', '--help', I18n.t('option.help')) do + puts opts + exit 0 + end - opts.on('-l', '--length NUMBER', I18n.t('option.length')) do |length| - options[:length] = length.to_i - end + opts.on('-l', '--length NUMBER', I18n.t('option.length')) do |length| + options[:length] = length.to_i + end - opts.on('-n', '--numeric', I18n.t('option.numeric')) do - options[:numeric] = true - end + opts.on('-n', '--numeric', I18n.t('option.numeric')) do + options[:numeric] = true + end - opts.on('-s', '--special-chars', I18n.t('option.special_chars')) do - options[:special] = true - end + opts.on('-s', '--special-chars', I18n.t('option.special_chars')) do + options[:special] = true + end - opts.on('-a', '--alpha', I18n.t('option.alpha')) do - options[:alpha] = true - end + opts.on('-a', '--alpha', I18n.t('option.alpha')) do + options[:alpha] = true + end end.parse! puts MPW::MPW::password(options) diff --git a/bin/mpw-import b/bin/mpw-import index a827783..d9c868d 100644 --- a/bin/mpw-import +++ b/bin/mpw-import @@ -1,17 +1,17 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> -# +# # 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 2 # 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, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -27,24 +27,24 @@ require 'mpw/cli' options = {} OptionParser.new do |opts| - opts.banner = "#{I18n.t('option.usage')}: mpw import [options]" + opts.banner = "#{I18n.t('option.usage')}: mpw import [options]" - opts.on('-c', '--config PATH', I18n.t('option.config')) do |config| - options[:config] = config - end + opts.on('-c', '--config PATH', I18n.t('option.config')) do |config| + options[:config] = config + end - opts.on('-f', '--file PATH', I18n.t('option.file_import')) do |file| - options[:file] = file - end + opts.on('-f', '--file PATH', I18n.t('option.file_import')) do |file| + options[:file] = file + end - opts.on('-h', '--help', I18n.t('option.help')) do - puts opts - exit 0 - end + opts.on('-h', '--help', I18n.t('option.help')) do + puts opts + exit 0 + end - opts.on('-w', '--wallet NAME', I18n.t('option.wallet')) do |wallet| - options[:wallet] = wallet - end + opts.on('-w', '--wallet NAME', I18n.t('option.wallet')) do |wallet| + options[:wallet] = wallet + end end.parse! config = MPW::Config.new(options[:config]) diff --git a/bin/mpw-list b/bin/mpw-list index 3ebc2b8..3571abc 100644 --- a/bin/mpw-list +++ b/bin/mpw-list @@ -1,17 +1,17 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> -# +# # 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 2 # 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, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -28,28 +28,28 @@ options = {} values = {} OptionParser.new do |opts| - opts.banner = "#{I18n.t('option.usage')}: mpw list [options]" + opts.banner = "#{I18n.t('option.usage')}: mpw list [options]" - opts.on('-c', '--config PATH', I18n.t('option.config')) do |config| - options[:config] = config - end + opts.on('-c', '--config PATH', I18n.t('option.config')) do |config| + options[:config] = config + end - opts.on('-g', '--group NAME', I18n.t('option.group')) do |group| - values[:group] = group - end + opts.on('-g', '--group NAME', I18n.t('option.group')) do |group| + values[:group] = group + end - opts.on('-h', '--help', I18n.t('option.help')) do - puts opts - exit 0 - end + opts.on('-h', '--help', I18n.t('option.help')) do + puts opts + exit 0 + end - opts.on('-p', '--pattern PATTERN', I18n.t('option.pattern')) do |pattern| - values[:pattern] = pattern - end + opts.on('-p', '--pattern PATTERN', I18n.t('option.pattern')) do |pattern| + values[:pattern] = pattern + end - opts.on('-w', '--wallet NAME', I18n.t('option.wallet')) do |wallet| - options[:wallet] = wallet - end + opts.on('-w', '--wallet NAME', I18n.t('option.wallet')) do |wallet| + options[:wallet] = wallet + end end.parse! config = MPW::Config.new(options[:config]) diff --git a/bin/mpw-update b/bin/mpw-update index fd207c5..c258330 100644 --- a/bin/mpw-update +++ b/bin/mpw-update @@ -1,17 +1,17 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> -# +# # 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 2 # 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, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -28,32 +28,32 @@ options = {} values = {} OptionParser.new do |opts| - opts.banner = "#{I18n.t('option.usage')}: mpw update [options]" + opts.banner = "#{I18n.t('option.usage')}: mpw update [options]" - opts.on('-c', '--config PATH', I18n.t('option.config')) do |config| - options[:config] = config - end + opts.on('-c', '--config PATH', I18n.t('option.config')) do |config| + options[:config] = config + end - opts.on('-g', '--group NAME', I18n.t('option.group')) do |group| - values[:group] = group - end + opts.on('-g', '--group NAME', I18n.t('option.group')) do |group| + values[:group] = group + end - opts.on('-h', '--help', I18n.t('option.help')) do - puts opts - exit 0 - end + opts.on('-h', '--help', I18n.t('option.help')) do + puts opts + exit 0 + end - opts.on('-p', '--pattern PATTERN', I18n.t('option.pattern')) do |pattern| - values[:pattern] = pattern - end + opts.on('-p', '--pattern PATTERN', I18n.t('option.pattern')) do |pattern| + values[:pattern] = pattern + end - opts.on('-r', '--random', I18n.t('option.random_password')) do - options[:password] = true - end + opts.on('-r', '--random', I18n.t('option.random_password')) do + options[:password] = true + end - opts.on('-w', '--wallet NAME', I18n.t('option.wallet')) do |wallet| - options[:wallet] = wallet - end + opts.on('-w', '--wallet NAME', I18n.t('option.wallet')) do |wallet| + options[:wallet] = wallet + end end.parse! config = MPW::Config.new(options[:config]) diff --git a/bin/mpw-wallet b/bin/mpw-wallet index 56e96ba..e575c0d 100644 --- a/bin/mpw-wallet +++ b/bin/mpw-wallet @@ -1,17 +1,17 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> -# +# # 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 2 # 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, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -28,37 +28,37 @@ options = {} options[:delete] = false OptionParser.new do |opts| - opts.banner = "#{I18n.t('option.usage')}: mpw wallet [options]" + opts.banner = "#{I18n.t('option.usage')}: mpw wallet [options]" - opts.on('-a', '--add-gpg-key NAME', I18n.t('option.add_gpg_key')) do |gpg_key| - options[:gpg_key] = gpg_key - end + opts.on('-a', '--add-gpg-key NAME', I18n.t('option.add_gpg_key')) do |gpg_key| + options[:gpg_key] = gpg_key + end - opts.on('-c', '--config PATH', I18n.t('option.config')) do |config| - options[:config] = config - end + opts.on('-c', '--config PATH', I18n.t('option.config')) do |config| + options[:config] = config + end - opts.on('-d', '--delete-gpg-key NAME', I18n.t('option.delete_gpg_key')) do |gpg_key| - options[:gpg_key] = gpg_key - options[:delete] = true - end + opts.on('-d', '--delete-gpg-key NAME', I18n.t('option.delete_gpg_key')) do |gpg_key| + options[:gpg_key] = gpg_key + options[:delete] = true + end - opts.on('-h', '--help', I18n.t('option.help')) do - puts opts - exit 0 - end + opts.on('-h', '--help', I18n.t('option.help')) do + puts opts + exit 0 + end - opts.on('-l', '--list', I18n.t('option.list')) do - options[:list] = true - end + opts.on('-l', '--list', I18n.t('option.list')) do + options[:list] = true + end - opts.on('-L', '--list-keys', I18n.t('option.list_keys')) do - options[:list_keys] = true - end + opts.on('-L', '--list-keys', I18n.t('option.list_keys')) do + options[:list_keys] = true + end - opts.on('-w', '--wallet NAME', I18n.t('option.wallet')) do |wallet| - options[:wallet] = wallet - end + opts.on('-w', '--wallet NAME', I18n.t('option.wallet')) do |wallet| + options[:wallet] = wallet + end end.parse! config = MPW::Config.new(options[:config]) @@ -67,18 +67,18 @@ cli = MPW::Cli.new(config) cli.load_config if not options[:list].nil? - cli.list_wallet + cli.list_wallet else - cli.get_wallet(options[:wallet]) - cli.decrypt + cli.get_wallet(options[:wallet]) + cli.decrypt - if not options[:list_keys].nil? - cli.list_keys - elsif not options[:gpg_key].nil? - if options[:delete] - cli.delete_key(options[:gpg_key]) - else - cli.add_key(options[:gpg_key]) - end - end + if not options[:list_keys].nil? + cli.list_keys + elsif not options[:gpg_key].nil? + if options[:delete] + cli.delete_key(options[:gpg_key]) + else + cli.add_key(options[:gpg_key]) + end + end end diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 0eb294e..83b9af3 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -1,17 +1,17 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> -# +# # 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 2 # 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, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -29,516 +29,516 @@ require 'mpw/mpw' module MPW class Cli - # Constructor - # @args: config -> the config - def initialize(config) - @config = config - end - - # Change a parameter int the config after init - # @args: options -> param to change - def set_config(options) - @config.setup(options) - - puts "#{I18n.t('form.set_config.valid')}".green - rescue Exception => e - puts "#{I18n.t('display.error')} #15: #{e}".red - exit 2 - end - - # Create a new config file - # @args: options -> set param - def setup(options) - options[:lang] = options[:lang] || Locale::Tag.parse(ENV['LANG']).to_simple.to_s[0..1] - - I18n.locale = options[:lang].to_sym - - @config.setup(options) - - load_config - - puts "#{I18n.t('form.setup_config.valid')}".green - rescue Exception => e - puts "#{I18n.t('display.error')} #8: #{e}".red - exit 2 - end - - # Setup a new GPG key - # @args: gpg_key -> the key name - def setup_gpg_key(gpg_key) - return if @config.check_gpg_key? - - password = ask(I18n.t('form.setup_gpg_key.password')) {|q| q.echo = false} - confirm = ask(I18n.t('form.setup_gpg_key.confirm_password')) {|q| q.echo = false} - - if password != confirm - raise I18n.t('form.setup_gpg_key.error_password') - end - - @password = password.to_s - - puts I18n.t('form.setup_gpg_key.wait') - - @config.setup_gpg_key(@password, gpg_key) - - puts "#{I18n.t('form.setup_gpg_key.valid')}".green - rescue Exception => e - puts "#{I18n.t('display.error')} #8: #{e}".red - exit 2 - end - - # List gpg keys in wallet - def list_keys - table_list('keys', @mpw.list_keys) - end - - # Load config - def load_config - @config.load_config - - rescue Exception => e - puts "#{I18n.t('display.error')} #10: #{e}".red - exit 2 - end - - # Request the GPG password and decrypt the file - def decrypt - if not defined?(@mpw) - @password = ask(I18n.t('display.gpg_password')) {|q| q.echo = false} - @mpw = MPW.new(@config.gpg_key, @wallet_file, @password, @config.gpg_exe) - end - - @mpw.read_data - rescue Exception => e - puts "#{I18n.t('display.error')} #11: #{e}".red - exit 2 - end - - # Format list on a table - def table_list(title, list) - i = 1 - length = 0 - - list.each do |item| - length = item.length if length < item.length - end - length += 7 - - puts "\n#{I18n.t("display.#{title}")}".red - print ' ' - length.times { print '=' } - print "\n" - - list.each do |item| - print " #{i}".cyan - (3 - i.to_s.length).times { print ' ' } - puts "| #{item}" - i += 1 - end - - print "\n" - end - - # Format items on a table - def table_items(items=[]) - group = '.' - i = 1 - length_total = 10 - data = { id: { length: 3, color: 'cyan' }, - host: { length: 9, color: 'yellow' }, - user: { length: 7, color: 'green' }, - protocol: { length: 9, color: 'white' }, - port: { length: 5, color: 'white' }, - otp: { length: 4, color: 'white' }, - comment: { length: 14, color: 'magenta' }, - } - - items.each do |item| - data.each do |k, v| - next if k == :id or k == :otp - - v[:length] = item.send(k.to_s).to_s.length + 3 if item.send(k.to_s).to_s.length >= v[:length] - end - end - data[:id][:length] = items.length.to_s.length + 2 if items.length.to_s.length > data[:id][:length] - - data.each_value { |v| length_total += v[:length] } - items.sort! { |a, b| a.group.to_s.downcase <=> b.group.to_s.downcase } - - items.each do |item| - if group != item.group - group = item.group - - if group.to_s.empty? - puts "\n#{I18n.t('display.no_group')}".red - else - puts "\n#{group}".red - end - - print ' ' - length_total.times { print '=' } - print "\n " - data.each do |k, v| - case k - when :id - print ' ID' - when :otp - print '| OTP' - else - print "| #{k.to_s.capitalize}" - end - - (v[:length] - k.to_s.length).times { print ' ' } - end - print "\n " - length_total.times { print '=' } - print "\n" - end - - print " #{i}".send(data[:id][:color]) - (data[:id][:length] - i.to_s.length).times { print ' ' } - data.each do |k, v| - next if k == :id - - if k == :otp - print '| ' - if item.otp; print ' X ' else 4.times { print ' ' } end - - next - end - - print '| ' - print "#{item.send(k.to_s)}".send(v[:color]) - (v[:length] - item.send(k.to_s).to_s.length).times { print ' ' } - end - print "\n" - - i += 1 - end - - print "\n" - end - - # Display the query's result - # @args: options -> the option to search - def list(options={}) - result = @mpw.list(options) - - if result.length == 0 - puts I18n.t('display.nothing') - else - table_items(result) - end - end - - # Get an item when multiple choice - # @args: items -> array of items - # @rtrn: item - def get_item(items) - return items[0] if items.length == 1 - - items.sort! { |a,b| a.group.to_s.downcase <=> b.group.to_s.downcase } - choice = ask(I18n.t('form.select')).to_i - - if choice >= 1 and choice <= items.length - return items[choice-1] - else - return nil - end - end - - # Copy in clipboard the login and password - # @args: item -> the item - # clipboard -> enable clipboard - def clipboard(item, clipboard=true) - pid = nil - - # Security: force quit after 90s - Thread.new do - sleep 90 - exit - end - - while true - choice = ask(I18n.t('form.clipboard.choice')).to_s - - case choice - when 'q', 'quit' - break - - when 'l', 'login' - if clipboard - Clipboard.copy(item.user) - puts I18n.t('form.clipboard.login').green - else - puts item.user - end - - when 'p', 'password' - if clipboard - Clipboard.copy(@mpw.get_password(item.id)) - puts I18n.t('form.clipboard.password').yellow - - Thread.new do - sleep 30 - - Clipboard.clear - end - else - puts @mpw.get_password(item.id) - end - - when 'o', 'otp' - if clipboard - Clipboard.copy(@mpw.get_otp_code(item.id)) - else - puts @mpw.get_otp_code(item.id) - end - puts I18n.t('form.clipboard.otp', time: @mpw.get_otp_remaining_time).yellow - - else - puts "----- #{I18n.t('form.clipboard.help.name')} -----".cyan - puts I18n.t('form.clipboard.help.login') - puts I18n.t('form.clipboard.help.password') - puts I18n.t('form.clipboard.help.otp_code') - puts I18n.t('form.clipboard.help.quit') - next - end - end - - Clipboard.clear - rescue SystemExit, Interrupt - Clipboard.clear - end - - # List all wallets - def list_wallet - wallets = [] - Dir.glob("#{@config.wallet_dir}/*.mpw").each do |f| - wallet = File.basename(f, '.mpw') - wallet += ' *'.green if wallet == @config.default_wallet - wallets << wallet - end - - table_list('wallets', wallets) - end - - # Display the wallet - # @args: wallet -> the wallet name - def get_wallet(wallet=nil) - if wallet.to_s.empty? - wallets = Dir.glob("#{@config.wallet_dir}/*.mpw") - - if wallets.length == 1 - @wallet_file = wallets[0] - elsif not @config.default_wallet.to_s.empty? - @wallet_file = "#{@config.wallet_dir}/#{@config.default_wallet}.mpw" - else - @wallet_file = "#{@config.wallet_dir}/default.mpw" - end - else - @wallet_file = "#{@config.wallet_dir}/#{wallet}.mpw" - end - end - - # Add a new public key - # args: key -> the key name or key file to add - def add_key(key) - @mpw.add_key(key) - @mpw.write_data - - puts "#{I18n.t('form.add_key.valid')}".green - rescue Exception => e - puts "#{I18n.t('display.error')} #13: #{e}".red - end - - # Add new public key - # args: key -> the key name to delete - def delete_key(key) - @mpw.delete_key(key) - @mpw.write_data - - puts "#{I18n.t('form.delete_key.valid')}".green - rescue Exception => e - puts "#{I18n.t('display.error')} #15: #{e}".red - end - - # Text editor interface - # @args: template -> template name - # item -> the item to edit - # password -> disable field password - def text_editor(template_name, item=nil, password=false) - editor = ENV['EDITOR'] || 'nano' - options = {} - opts = {} - template_file = "#{File.expand_path('../../../templates', __FILE__)}/#{template_name}.erb" - template = ERB.new(IO.read(template_file)) - - Dir.mktmpdir do |dir| - tmp_file = "#{dir}/#{template_name}.yml" - - File.open(tmp_file, 'w') do |f| - f << template.result(binding) - end - - system("#{editor} #{tmp_file}") - - opts = YAML::load_file(tmp_file) - end - - opts.delete_if { |k,v| v.to_s.empty? } - - opts.each do |k,v| - options[k.to_sym] = v - end - - return options - end - - # Form to add a new item - # @args: password -> generate a random password - def add(password=false) - options = text_editor('add_form', nil, password) - item = Item.new(options) - options[:password] = MPW::password(@config.password) if password - - @mpw.add(item) - @mpw.set_password(item.id, options[:password]) if options.has_key?(:password) - @mpw.set_otp_key(item.id, options[:otp_key]) if options.has_key?(:otp_key) - @mpw.write_data - - puts "#{I18n.t('form.add_item.valid')}".green - rescue Exception => e - puts "#{I18n.t('display.error')} #13: #{e}".red - end - - # Update an item - # @args: password -> generate a random password - # options -> the option to search - def update(password=false, options={}) - items = @mpw.list(options) - - if items.length == 0 - puts "#{I18n.t('display.warning')}: #{I18n.t('warning.select')}".yellow - else - table_items(items) if items.length > 1 - - item = get_item(items) - options = text_editor('update_form', item, password) - options[:password] = MPW::password(@config.password) if password - - item.update(options) - @mpw.set_password(item.id, options[:password]) if options.has_key?(:password) - @mpw.set_otp_key(item.id, options[:otp_key]) if options.has_key?(:otp_key) - @mpw.write_data - - puts "#{I18n.t('form.update_item.valid')}".green - end - rescue Exception => e - puts "#{I18n.t('display.error')} #14: #{e}".red - end - - # Remove an item - # @args: options -> the option to search - def delete(options={}) - items = @mpw.list(options) - - if items.length == 0 - puts "#{I18n.t('display.warning')}: #{I18n.t('warning.select')}".yellow - else - table_items(items) - - item = get_item(items) - confirm = ask("#{I18n.t('form.delete_item.ask')} (y/N) ").to_s - - if not confirm =~ /^(y|yes|YES|Yes|Y)$/ - return false - end - - item.delete - @mpw.write_data - - puts "#{I18n.t('form.delete_item.valid')}".green - end - rescue Exception => e - puts "#{I18n.t('display.error')} #16: #{e}".red - end - - # Copy a password, otp, login - # @args: clipboard -> enable clipboard - # options -> the option to search - def copy(clipboard=true, options={}) - items = @mpw.list(options) - - if items.length == 0 - puts I18n.t('display.nothing') - else - table_items(items) - - item = get_item(items) - clipboard(item, clipboard) - end - rescue Exception => e - puts "#{I18n.t('display.error')} #14: #{e}".red - end - - # Export the items in a CSV file - # @args: file -> the destination file - # options -> option to search - def export(file, options) - file = 'export-mpw.yml' if file.to_s.empty? - items = @mpw.list(options) - data = {} - - items.each do |item| - data.merge!(item.id => { 'host' => item.host, - 'user' => item.user, - 'group' => item.group, - 'password' => @mpw.get_password(item.id), - 'protocol' => item.protocol, - 'port' => item.port, - 'otp_key' => @mpw.get_otp_key(item.id), - 'comment' => item.comment, - 'last_edit' => item.last_edit, - 'created' => item.created, - } - ) - end - - File.open(file, 'w') {|f| f << data.to_yaml} - - puts "#{I18n.t('form.export.valid', file: file)}".green - rescue Exception => e - puts "#{I18n.t('display.error')} #17: #{e}".red - end - - # Import items from a YAML file - # @args: file -> the import file - def import(file) - raise I18n.t('form.import.file_empty') if file.to_s.empty? - raise I18n.t('form.import.file_not_exist') if not File.exist?(file) - - YAML::load_file(file).each_value do |row| - item = Item.new(group: row['group'], - host: row['host'], - protocol: row['protocol'], - user: row['user'], - port: row['port'], - comment: row['comment'], - ) - - next if item.empty? - - @mpw.add(item) - @mpw.set_password(item.id, row['password']) if not row['password'].to_s.empty? - @mpw.set_otp_key(item.id, row['otp_key']) if not row['otp_key'].to_s.empty? - end - - @mpw.write_data - - puts "#{I18n.t('form.import.valid')}".green - rescue Exception => e - puts "#{I18n.t('display.error')} #18: #{e}".red - end + # Constructor + # @args: config -> the config + def initialize(config) + @config = config + end + + # Change a parameter int the config after init + # @args: options -> param to change + def set_config(options) + @config.setup(options) + + puts "#{I18n.t('form.set_config.valid')}".green + rescue Exception => e + puts "#{I18n.t('display.error')} #15: #{e}".red + exit 2 + end + + # Create a new config file + # @args: options -> set param + def setup(options) + options[:lang] = options[:lang] || Locale::Tag.parse(ENV['LANG']).to_simple.to_s[0..1] + + I18n.locale = options[:lang].to_sym + + @config.setup(options) + + load_config + + puts "#{I18n.t('form.setup_config.valid')}".green + rescue Exception => e + puts "#{I18n.t('display.error')} #8: #{e}".red + exit 2 + end + + # Setup a new GPG key + # @args: gpg_key -> the key name + def setup_gpg_key(gpg_key) + return if @config.check_gpg_key? + + password = ask(I18n.t('form.setup_gpg_key.password')) {|q| q.echo = false} + confirm = ask(I18n.t('form.setup_gpg_key.confirm_password')) {|q| q.echo = false} + + if password != confirm + raise I18n.t('form.setup_gpg_key.error_password') + end + + @password = password.to_s + + puts I18n.t('form.setup_gpg_key.wait') + + @config.setup_gpg_key(@password, gpg_key) + + puts "#{I18n.t('form.setup_gpg_key.valid')}".green + rescue Exception => e + puts "#{I18n.t('display.error')} #8: #{e}".red + exit 2 + end + + # List gpg keys in wallet + def list_keys + table_list('keys', @mpw.list_keys) + end + + # Load config + def load_config + @config.load_config + + rescue Exception => e + puts "#{I18n.t('display.error')} #10: #{e}".red + exit 2 + end + + # Request the GPG password and decrypt the file + def decrypt + if not defined?(@mpw) + @password = ask(I18n.t('display.gpg_password')) {|q| q.echo = false} + @mpw = MPW.new(@config.gpg_key, @wallet_file, @password, @config.gpg_exe) + end + + @mpw.read_data + rescue Exception => e + puts "#{I18n.t('display.error')} #11: #{e}".red + exit 2 + end + + # Format list on a table + def table_list(title, list) + i = 1 + length = 0 + + list.each do |item| + length = item.length if length < item.length + end + length += 7 + + puts "\n#{I18n.t("display.#{title}")}".red + print ' ' + length.times { print '=' } + print "\n" + + list.each do |item| + print " #{i}".cyan + (3 - i.to_s.length).times { print ' ' } + puts "| #{item}" + i += 1 + end + + print "\n" + end + + # Format items on a table + def table_items(items=[]) + group = '.' + i = 1 + length_total = 10 + data = { id: { length: 3, color: 'cyan' }, + host: { length: 9, color: 'yellow' }, + user: { length: 7, color: 'green' }, + protocol: { length: 9, color: 'white' }, + port: { length: 5, color: 'white' }, + otp: { length: 4, color: 'white' }, + comment: { length: 14, color: 'magenta' }, + } + + items.each do |item| + data.each do |k, v| + next if k == :id or k == :otp + + v[:length] = item.send(k.to_s).to_s.length + 3 if item.send(k.to_s).to_s.length >= v[:length] + end + end + data[:id][:length] = items.length.to_s.length + 2 if items.length.to_s.length > data[:id][:length] + + data.each_value { |v| length_total += v[:length] } + items.sort! { |a, b| a.group.to_s.downcase <=> b.group.to_s.downcase } + + items.each do |item| + if group != item.group + group = item.group + + if group.to_s.empty? + puts "\n#{I18n.t('display.no_group')}".red + else + puts "\n#{group}".red + end + + print ' ' + length_total.times { print '=' } + print "\n " + data.each do |k, v| + case k + when :id + print ' ID' + when :otp + print '| OTP' + else + print "| #{k.to_s.capitalize}" + end + + (v[:length] - k.to_s.length).times { print ' ' } + end + print "\n " + length_total.times { print '=' } + print "\n" + end + + print " #{i}".send(data[:id][:color]) + (data[:id][:length] - i.to_s.length).times { print ' ' } + data.each do |k, v| + next if k == :id + + if k == :otp + print '| ' + if item.otp; print ' X ' else 4.times { print ' ' } end + + next + end + + print '| ' + print "#{item.send(k.to_s)}".send(v[:color]) + (v[:length] - item.send(k.to_s).to_s.length).times { print ' ' } + end + print "\n" + + i += 1 + end + + print "\n" + end + + # Display the query's result + # @args: options -> the option to search + def list(options={}) + result = @mpw.list(options) + + if result.length == 0 + puts I18n.t('display.nothing') + else + table_items(result) + end + end + + # Get an item when multiple choice + # @args: items -> array of items + # @rtrn: item + def get_item(items) + return items[0] if items.length == 1 + + items.sort! { |a,b| a.group.to_s.downcase <=> b.group.to_s.downcase } + choice = ask(I18n.t('form.select')).to_i + + if choice >= 1 and choice <= items.length + return items[choice-1] + else + return nil + end + end + + # Copy in clipboard the login and password + # @args: item -> the item + # clipboard -> enable clipboard + def clipboard(item, clipboard=true) + pid = nil + + # Security: force quit after 90s + Thread.new do + sleep 90 + exit + end + + while true + choice = ask(I18n.t('form.clipboard.choice')).to_s + + case choice + when 'q', 'quit' + break + + when 'l', 'login' + if clipboard + Clipboard.copy(item.user) + puts I18n.t('form.clipboard.login').green + else + puts item.user + end + + when 'p', 'password' + if clipboard + Clipboard.copy(@mpw.get_password(item.id)) + puts I18n.t('form.clipboard.password').yellow + + Thread.new do + sleep 30 + + Clipboard.clear + end + else + puts @mpw.get_password(item.id) + end + + when 'o', 'otp' + if clipboard + Clipboard.copy(@mpw.get_otp_code(item.id)) + else + puts @mpw.get_otp_code(item.id) + end + puts I18n.t('form.clipboard.otp', time: @mpw.get_otp_remaining_time).yellow + + else + puts "----- #{I18n.t('form.clipboard.help.name')} -----".cyan + puts I18n.t('form.clipboard.help.login') + puts I18n.t('form.clipboard.help.password') + puts I18n.t('form.clipboard.help.otp_code') + puts I18n.t('form.clipboard.help.quit') + next + end + end + + Clipboard.clear + rescue SystemExit, Interrupt + Clipboard.clear + end + + # List all wallets + def list_wallet + wallets = [] + Dir.glob("#{@config.wallet_dir}/*.mpw").each do |f| + wallet = File.basename(f, '.mpw') + wallet += ' *'.green if wallet == @config.default_wallet + wallets << wallet + end + + table_list('wallets', wallets) + end + + # Display the wallet + # @args: wallet -> the wallet name + def get_wallet(wallet=nil) + if wallet.to_s.empty? + wallets = Dir.glob("#{@config.wallet_dir}/*.mpw") + + if wallets.length == 1 + @wallet_file = wallets[0] + elsif not @config.default_wallet.to_s.empty? + @wallet_file = "#{@config.wallet_dir}/#{@config.default_wallet}.mpw" + else + @wallet_file = "#{@config.wallet_dir}/default.mpw" + end + else + @wallet_file = "#{@config.wallet_dir}/#{wallet}.mpw" + end + end + + # Add a new public key + # args: key -> the key name or key file to add + def add_key(key) + @mpw.add_key(key) + @mpw.write_data + + puts "#{I18n.t('form.add_key.valid')}".green + rescue Exception => e + puts "#{I18n.t('display.error')} #13: #{e}".red + end + + # Add new public key + # args: key -> the key name to delete + def delete_key(key) + @mpw.delete_key(key) + @mpw.write_data + + puts "#{I18n.t('form.delete_key.valid')}".green + rescue Exception => e + puts "#{I18n.t('display.error')} #15: #{e}".red + end + + # Text editor interface + # @args: template -> template name + # item -> the item to edit + # password -> disable field password + def text_editor(template_name, item=nil, password=false) + editor = ENV['EDITOR'] || 'nano' + options = {} + opts = {} + template_file = "#{File.expand_path('../../../templates', __FILE__)}/#{template_name}.erb" + template = ERB.new(IO.read(template_file)) + + Dir.mktmpdir do |dir| + tmp_file = "#{dir}/#{template_name}.yml" + + File.open(tmp_file, 'w') do |f| + f << template.result(binding) + end + + system("#{editor} #{tmp_file}") + + opts = YAML::load_file(tmp_file) + end + + opts.delete_if { |k,v| v.to_s.empty? } + + opts.each do |k,v| + options[k.to_sym] = v + end + + return options + end + + # Form to add a new item + # @args: password -> generate a random password + def add(password=false) + options = text_editor('add_form', nil, password) + item = Item.new(options) + options[:password] = MPW::password(@config.password) if password + + @mpw.add(item) + @mpw.set_password(item.id, options[:password]) if options.has_key?(:password) + @mpw.set_otp_key(item.id, options[:otp_key]) if options.has_key?(:otp_key) + @mpw.write_data + + puts "#{I18n.t('form.add_item.valid')}".green + rescue Exception => e + puts "#{I18n.t('display.error')} #13: #{e}".red + end + + # Update an item + # @args: password -> generate a random password + # options -> the option to search + def update(password=false, options={}) + items = @mpw.list(options) + + if items.length == 0 + puts "#{I18n.t('display.warning')}: #{I18n.t('warning.select')}".yellow + else + table_items(items) if items.length > 1 + + item = get_item(items) + options = text_editor('update_form', item, password) + options[:password] = MPW::password(@config.password) if password + + item.update(options) + @mpw.set_password(item.id, options[:password]) if options.has_key?(:password) + @mpw.set_otp_key(item.id, options[:otp_key]) if options.has_key?(:otp_key) + @mpw.write_data + + puts "#{I18n.t('form.update_item.valid')}".green + end + rescue Exception => e + puts "#{I18n.t('display.error')} #14: #{e}".red + end + + # Remove an item + # @args: options -> the option to search + def delete(options={}) + items = @mpw.list(options) + + if items.length == 0 + puts "#{I18n.t('display.warning')}: #{I18n.t('warning.select')}".yellow + else + table_items(items) + + item = get_item(items) + confirm = ask("#{I18n.t('form.delete_item.ask')} (y/N) ").to_s + + if not confirm =~ /^(y|yes|YES|Yes|Y)$/ + return false + end + + item.delete + @mpw.write_data + + puts "#{I18n.t('form.delete_item.valid')}".green + end + rescue Exception => e + puts "#{I18n.t('display.error')} #16: #{e}".red + end + + # Copy a password, otp, login + # @args: clipboard -> enable clipboard + # options -> the option to search + def copy(clipboard=true, options={}) + items = @mpw.list(options) + + if items.length == 0 + puts I18n.t('display.nothing') + else + table_items(items) + + item = get_item(items) + clipboard(item, clipboard) + end + rescue Exception => e + puts "#{I18n.t('display.error')} #14: #{e}".red + end + + # Export the items in a CSV file + # @args: file -> the destination file + # options -> option to search + def export(file, options) + file = 'export-mpw.yml' if file.to_s.empty? + items = @mpw.list(options) + data = {} + + items.each do |item| + data.merge!(item.id => { 'host' => item.host, + 'user' => item.user, + 'group' => item.group, + 'password' => @mpw.get_password(item.id), + 'protocol' => item.protocol, + 'port' => item.port, + 'otp_key' => @mpw.get_otp_key(item.id), + 'comment' => item.comment, + 'last_edit' => item.last_edit, + 'created' => item.created, + } + ) + end + + File.open(file, 'w') {|f| f << data.to_yaml} + + puts "#{I18n.t('form.export.valid', file: file)}".green + rescue Exception => e + puts "#{I18n.t('display.error')} #17: #{e}".red + end + + # Import items from a YAML file + # @args: file -> the import file + def import(file) + raise I18n.t('form.import.file_empty') if file.to_s.empty? + raise I18n.t('form.import.file_not_exist') if not File.exist?(file) + + YAML::load_file(file).each_value do |row| + item = Item.new(group: row['group'], + host: row['host'], + protocol: row['protocol'], + user: row['user'], + port: row['port'], + comment: row['comment'], + ) + + next if item.empty? + + @mpw.add(item) + @mpw.set_password(item.id, row['password']) if not row['password'].to_s.empty? + @mpw.set_otp_key(item.id, row['otp_key']) if not row['otp_key'].to_s.empty? + end + + @mpw.write_data + + puts "#{I18n.t('form.import.valid')}".green + rescue Exception => e + puts "#{I18n.t('display.error')} #18: #{e}".red + end end end diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index 7fbd778..298ba61 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -1,17 +1,17 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> -# +# # 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 2 # 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, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -20,140 +20,140 @@ require 'gpgme' require 'yaml' require 'i18n' require 'fileutils' - + module MPW class Config - - attr_accessor :error_msg - attr_accessor :gpg_key - attr_accessor :lang - attr_accessor :config_dir - attr_accessor :default_wallet - attr_accessor :wallet_dir - attr_accessor :gpg_exe - attr_accessor :password + attr_accessor :error_msg - # Constructor - # @args: config_file -> the specify config file - def initialize(config_file=nil) - @config_file = config_file + attr_accessor :gpg_key + attr_accessor :lang + attr_accessor :config_dir + attr_accessor :default_wallet + attr_accessor :wallet_dir + attr_accessor :gpg_exe + attr_accessor :password - if /darwin/ =~ RUBY_PLATFORM - @config_dir = "#{Dir.home}/Library/Preferences/mpw" - elsif /cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM - @config_dir = "#{Dir.home}/AppData/Local/mpw" - else - @config_dir = "#{Dir.home}/.config/mpw" - end - - @config_file = "#{@config_dir}/mpw.cfg" if @config_file.nil? or @config_file.empty? - end + # Constructor + # @args: config_file -> the specify config file + def initialize(config_file=nil) + @config_file = config_file - # Create a new config file - # @args: options -> hash with values - # @rtrn: true if le config file is create - def setup(options) - gpg_key = options[:gpg_key] || @gpg_key - lang = options[:lang] || @lang - wallet_dir = options[:wallet_dir] || @wallet_dir - default_wallet = options[:default_wallet] || @default_wallet - gpg_exe = options[:gpg_exe] || @gpg_exe - password = { numeric: true, - alpha: true, - special: false, - length: 16, - } + if /darwin/ =~ RUBY_PLATFORM + @config_dir = "#{Dir.home}/Library/Preferences/mpw" + elsif /cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM + @config_dir = "#{Dir.home}/AppData/Local/mpw" + else + @config_dir = "#{Dir.home}/.config/mpw" + end - ['numeric', 'special', 'alpha', 'length'].each do |k| - if options.has_key?("pwd_#{k}".to_sym) - password[k.to_sym] = options["pwd_#{k}".to_sym] - elsif not @password.nil? and @password.has_key?(k.to_sym) - password[k.to_sym] = @password[k.to_sym] - end - end + @config_file = "#{@config_dir}/mpw.cfg" if @config_file.nil? or @config_file.empty? + end - if not gpg_key =~ /[a-zA-Z0-9.-_]+\@[a-zA-Z0-9]+\.[a-zA-Z]+/ - raise I18n.t('error.config.key_bad_format') - end + # Create a new config file + # @args: options -> hash with values + # @rtrn: true if le config file is create + def setup(options) + gpg_key = options[:gpg_key] || @gpg_key + lang = options[:lang] || @lang + wallet_dir = options[:wallet_dir] || @wallet_dir + default_wallet = options[:default_wallet] || @default_wallet + gpg_exe = options[:gpg_exe] || @gpg_exe + password = { numeric: true, + alpha: true, + special: false, + length: 16, + } - wallet_dir = "#{@config_dir}/wallets" if wallet_dir.to_s.empty? - config = { 'gpg_key' => gpg_key, - 'lang' => lang, - 'wallet_dir' => wallet_dir, - 'default_wallet' => default_wallet, - 'gpg_exe' => gpg_exe, - 'password' => password, - } + ['numeric', 'special', 'alpha', 'length'].each do |k| + if options.has_key?("pwd_#{k}".to_sym) + password[k.to_sym] = options["pwd_#{k}".to_sym] + elsif not @password.nil? and @password.has_key?(k.to_sym) + password[k.to_sym] = @password[k.to_sym] + end + end - FileUtils.mkdir_p(@config_dir, mode: 0700) - FileUtils.mkdir_p(wallet_dir, mode: 0700) + if not gpg_key =~ /[a-zA-Z0-9.-_]+\@[a-zA-Z0-9]+\.[a-zA-Z]+/ + raise I18n.t('error.config.key_bad_format') + end - File.open(@config_file, 'w') do |file| - file << config.to_yaml - end - rescue Exception => e - raise "#{I18n.t('error.config.write')}\n#{e}" - end + wallet_dir = "#{@config_dir}/wallets" if wallet_dir.to_s.empty? + config = { 'gpg_key' => gpg_key, + 'lang' => lang, + 'wallet_dir' => wallet_dir, + 'default_wallet' => default_wallet, + 'gpg_exe' => gpg_exe, + 'password' => password, + } - # Setup a new gpg key - # @args: password -> the GPG key password - # name -> the name of user - # length -> length of the GPG key - # expire -> the time of expire to GPG key - # @rtrn: true if the GPG key is create, else false - def setup_gpg_key(password, name, length = 4096, expire = 0) - if name.to_s.empty? - raise "#{I18n.t('error.config.genkey_gpg.name')}" - elsif password.to_s.empty? - raise "#{I18n.t('error.config.genkey_gpg.password')}" - end + FileUtils.mkdir_p(@config_dir, mode: 0700) + FileUtils.mkdir_p(wallet_dir, mode: 0700) - param = '' - param << '<GnupgKeyParms format="internal">' + "\n" - param << "Key-Type: RSA\n" - param << "Key-Length: #{length}\n" - param << "Subkey-Type: ELG-E\n" - param << "Subkey-Length: #{length}\n" - param << "Name-Real: #{name}\n" - param << "Name-Comment: #{name}\n" - param << "Name-Email: #{@gpg_key}\n" - param << "Expire-Date: #{expire}\n" - param << "Passphrase: #{password}\n" - param << "</GnupgKeyParms>\n" + File.open(@config_file, 'w') do |file| + file << config.to_yaml + end + rescue Exception => e + raise "#{I18n.t('error.config.write')}\n#{e}" + end - ctx = GPGME::Ctx.new - ctx.genkey(param, nil, nil) - rescue Exception => e - raise "#{I18n.t('error.config.genkey_gpg.exception')}\n#{e}" - end + # Setup a new gpg key + # @args: password -> the GPG key password + # name -> the name of user + # length -> length of the GPG key + # expire -> the time of expire to GPG key + # @rtrn: true if the GPG key is create, else false + def setup_gpg_key(password, name, length = 4096, expire = 0) + if name.to_s.empty? + raise "#{I18n.t('error.config.genkey_gpg.name')}" + elsif password.to_s.empty? + raise "#{I18n.t('error.config.genkey_gpg.password')}" + end - # Load the config file - def load_config - config = YAML::load_file(@config_file) - @gpg_key = config['gpg_key'] - @lang = config['lang'] - @wallet_dir = config['wallet_dir'] - @default_wallet = config['default_wallet'] - @gpg_exe = config['gpg_exe'] - @password = config['password'] || {} + param = '' + param << '<GnupgKeyParms format="internal">' + "\n" + param << "Key-Type: RSA\n" + param << "Key-Length: #{length}\n" + param << "Subkey-Type: ELG-E\n" + param << "Subkey-Length: #{length}\n" + param << "Name-Real: #{name}\n" + param << "Name-Comment: #{name}\n" + param << "Name-Email: #{@gpg_key}\n" + param << "Expire-Date: #{expire}\n" + param << "Passphrase: #{password}\n" + param << "</GnupgKeyParms>\n" - raise if @gpg_key.empty? or @wallet_dir.empty? - - I18n.locale = @lang.to_sym - rescue Exception => e - raise "#{I18n.t('error.config.load')}\n#{e}" - end + ctx = GPGME::Ctx.new + ctx.genkey(param, nil, nil) + rescue Exception => e + raise "#{I18n.t('error.config.genkey_gpg.exception')}\n#{e}" + end - # Check if private key exist - # @rtrn: true if the key exist, else false - def check_gpg_key? - ctx = GPGME::Ctx.new - ctx.each_key(@gpg_key, true) do - return true - end + # Load the config file + def load_config + config = YAML::load_file(@config_file) + @gpg_key = config['gpg_key'] + @lang = config['lang'] + @wallet_dir = config['wallet_dir'] + @default_wallet = config['default_wallet'] + @gpg_exe = config['gpg_exe'] + @password = config['password'] || {} - return false - end + raise if @gpg_key.empty? or @wallet_dir.empty? + + I18n.locale = @lang.to_sym + rescue Exception => e + raise "#{I18n.t('error.config.load')}\n#{e}" + end + + # Check if private key exist + # @rtrn: true if the key exist, else false + def check_gpg_key? + ctx = GPGME::Ctx.new + ctx.each_key(@gpg_key, true) do + return true + end + + return false + end end end diff --git a/lib/mpw/item.rb b/lib/mpw/item.rb index a4f730b..469af15 100644 --- a/lib/mpw/item.rb +++ b/lib/mpw/item.rb @@ -1,102 +1,102 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> -# +# # 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 2 # 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, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. require 'i18n' - + module MPW class Item - attr_accessor :id - attr_accessor :group - attr_accessor :host - attr_accessor :protocol - attr_accessor :user - attr_accessor :port - attr_accessor :otp - attr_accessor :comment - attr_accessor :last_edit - attr_accessor :created + attr_accessor :id + attr_accessor :group + attr_accessor :host + attr_accessor :protocol + attr_accessor :user + attr_accessor :port + attr_accessor :otp + attr_accessor :comment + attr_accessor :last_edit + attr_accessor :created - # Constructor - # Create a new item - # @args: options -> a hash of parameter - # raise an error if the hash hasn't the key name - def initialize(options={}) - if not options.has_key?(:host) or options[:host].to_s.empty? - raise I18n.t('error.update.host_empty') - end + # Constructor + # Create a new item + # @args: options -> a hash of parameter + # raise an error if the hash hasn't the key name + def initialize(options={}) + if not options.has_key?(:host) or options[:host].to_s.empty? + raise I18n.t('error.update.host_empty') + end - if not options.has_key?(:id) or options[:id].to_s.empty? or not options.has_key?(:created) or options[:created].to_s.empty? - @id = generate_id - @created = Time.now.to_i - else - @id = options[:id] - @created = options[:created] - @last_edit = options[:last_edit] - options[:no_update_last_edit] = true - end + if not options.has_key?(:id) or options[:id].to_s.empty? or not options.has_key?(:created) or options[:created].to_s.empty? + @id = generate_id + @created = Time.now.to_i + else + @id = options[:id] + @created = options[:created] + @last_edit = options[:last_edit] + options[:no_update_last_edit] = true + end - update(options) - end + update(options) + end - # Update the item - # @args: options -> a hash of parameter - def update(options={}) - if options.has_key?(:host) and options[:host].to_s.empty? - raise I18n.t('error.update.host_empty') - end + # Update the item + # @args: options -> a hash of parameter + def update(options={}) + if options.has_key?(:host) and options[:host].to_s.empty? + raise I18n.t('error.update.host_empty') + end - @group = options[:group] if options.has_key?(:group) - @host = options[:host] if options.has_key?(:host) - @protocol = options[:protocol] if options.has_key?(:protocol) - @user = options[:user] if options.has_key?(:user) - @port = options[:port].to_i if options.has_key?(:port) and not options[:port].to_s.empty? - @otp = options[:otp] if options.has_key?(:otp) - @comment = options[:comment] if options.has_key?(:comment) - @last_edit = Time.now.to_i if not options.has_key?(:no_update_last_edit) - end + @group = options[:group] if options.has_key?(:group) + @host = options[:host] if options.has_key?(:host) + @protocol = options[:protocol] if options.has_key?(:protocol) + @user = options[:user] if options.has_key?(:user) + @port = options[:port].to_i if options.has_key?(:port) and not options[:port].to_s.empty? + @otp = options[:otp] if options.has_key?(:otp) + @comment = options[:comment] if options.has_key?(:comment) + @last_edit = Time.now.to_i if not options.has_key?(:no_update_last_edit) + end - # Delete all data - def delete - @id = nil - @group = nil - @host = nil - @protocol = nil - @user = nil - @port = nil - @otp = nil - @comment = nil - @created = nil - @last_edit = nil - end + # Delete all data + def delete + @id = nil + @group = nil + @host = nil + @protocol = nil + @user = nil + @port = nil + @otp = nil + @comment = nil + @created = nil + @last_edit = nil + end - def empty? - return @id.to_s.empty? - end + def empty? + return @id.to_s.empty? + end - def nil? - return false - end + def nil? + return false + end - # Generate an random id - private - def generate_id - return ([*('A'..'Z'),*('a'..'z'),*('0'..'9')]).sample(16).join - end + # Generate an random id + private + def generate_id + return ([*('A'..'Z'),*('a'..'z'),*('0'..'9')]).sample(16).join + end end end diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 8f4b42e..9147648 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -1,17 +1,17 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> -# +# # 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 2 # 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, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. @@ -22,360 +22,360 @@ require 'i18n' require 'yaml' require 'rotp' require 'mpw/item' - + module MPW class MPW - # Constructor - def initialize(key, wallet_file, gpg_pass=nil, gpg_exe=nil) - @key = key - @gpg_pass = gpg_pass - @gpg_exe = gpg_exe - @wallet_file = wallet_file + # Constructor + def initialize(key, wallet_file, gpg_pass=nil, gpg_exe=nil) + @key = key + @gpg_pass = gpg_pass + @gpg_exe = gpg_exe + @wallet_file = wallet_file - if not @gpg_exe.to_s.empty? - GPGME::Engine.set_info(GPGME::PROTOCOL_OpenPGP, @gpg_exe, "#{Dir.home}/.gnupg") - end - end + if not @gpg_exe.to_s.empty? + GPGME::Engine.set_info(GPGME::PROTOCOL_OpenPGP, @gpg_exe, "#{Dir.home}/.gnupg") + end + end - # Read mpw file - def read_data - @config = {} - @data = [] - @keys = {} - @passwords = {} - @otp_keys = {} + # Read mpw file + def read_data + @config = {} + @data = [] + @keys = {} + @passwords = {} + @otp_keys = {} - data = nil + data = nil - return if not File.exists?(@wallet_file) + return if not File.exists?(@wallet_file) - Gem::Package::TarReader.new(File.open(@wallet_file)) do |tar| - tar.each do |f| - case f.full_name - when 'wallet/config.gpg' - @config = YAML.load(decrypt(f.read)) + Gem::Package::TarReader.new(File.open(@wallet_file)) do |tar| + tar.each do |f| + case f.full_name + when 'wallet/config.gpg' + @config = YAML.load(decrypt(f.read)) - when 'wallet/meta.gpg' - data = decrypt(f.read) + when 'wallet/meta.gpg' + data = decrypt(f.read) - when /^wallet\/keys\/(?<key>.+)\.pub$/ - key = Regexp.last_match('key') + when /^wallet\/keys\/(?<key>.+)\.pub$/ + key = Regexp.last_match('key') - if GPGME::Key.find(:public, key).length == 0 - GPGME::Key.import(f.read, armor: true) - end + if GPGME::Key.find(:public, key).length == 0 + GPGME::Key.import(f.read, armor: true) + end - @keys[key] = f.read + @keys[key] = f.read - when /^wallet\/passwords\/(?<id>[a-zA-Z0-9]+)\.gpg$/ - @passwords[Regexp.last_match('id')] = f.read + when /^wallet\/passwords\/(?<id>[a-zA-Z0-9]+)\.gpg$/ + @passwords[Regexp.last_match('id')] = f.read - when /^wallet\/otp_keys\/(?<id>[a-zA-Z0-9]+)\.gpg$/ - @otp_keys[Regexp.last_match('id')] = f.read + when /^wallet\/otp_keys\/(?<id>[a-zA-Z0-9]+)\.gpg$/ + @otp_keys[Regexp.last_match('id')] = f.read - else - next - end - end - end + else + next + end + end + end - if not data.nil? and not data.empty? - YAML.load(data).each_value do |d| - @data.push(Item.new(id: d['id'], - group: d['group'], - host: d['host'], - protocol: d['protocol'], - user: d['user'], - port: d['port'], - otp: @otp_keys.has_key?(d['id']), - comment: d['comment'], - last_edit: d['last_edit'], - created: d['created'], - ) - ) - end - end + if not data.nil? and not data.empty? + YAML.load(data).each_value do |d| + @data.push(Item.new(id: d['id'], + group: d['group'], + host: d['host'], + protocol: d['protocol'], + user: d['user'], + port: d['port'], + otp: @otp_keys.has_key?(d['id']), + comment: d['comment'], + last_edit: d['last_edit'], + created: d['created'], + ) + ) + end + end - add_key(@key) if @keys[@key].nil? - rescue Exception => e - raise "#{I18n.t('error.mpw_file.read_data')}\n#{e}" - end + add_key(@key) if @keys[@key].nil? + rescue Exception => e + raise "#{I18n.t('error.mpw_file.read_data')}\n#{e}" + end - # Encrypt a file - def write_data - data = {} - tmp_file = "#{@wallet_file}.tmp" + # Encrypt a file + def write_data + data = {} + tmp_file = "#{@wallet_file}.tmp" - @data.each do |item| - next if item.empty? + @data.each do |item| + next if item.empty? - data.merge!(item.id => { 'id' => item.id, - 'group' => item.group, - 'host' => item.host, - 'protocol' => item.protocol, - 'user' => item.user, - 'port' => item.port, - 'comment' => item.comment, - 'last_edit' => item.last_edit, - 'created' => item.created, - } - ) - end + data.merge!(item.id => { 'id' => item.id, + 'group' => item.group, + 'host' => item.host, + 'protocol' => item.protocol, + 'user' => item.user, + 'port' => item.port, + 'comment' => item.comment, + 'last_edit' => item.last_edit, + 'created' => item.created, + } + ) + end - @config['last_update'] = Time.now.to_i + @config['last_update'] = Time.now.to_i - Gem::Package::TarWriter.new(File.open(tmp_file, 'w+')) do |tar| - data_encrypt = encrypt(data.to_yaml) - tar.add_file_simple('wallet/meta.gpg', 0400, data_encrypt.length) do |io| - io.write(data_encrypt) - end + Gem::Package::TarWriter.new(File.open(tmp_file, 'w+')) do |tar| + data_encrypt = encrypt(data.to_yaml) + tar.add_file_simple('wallet/meta.gpg', 0400, data_encrypt.length) do |io| + io.write(data_encrypt) + end - config = encrypt(@config.to_yaml) - tar.add_file_simple('wallet/config.gpg', 0400, config.length) do |io| - io.write(config) - end + config = encrypt(@config.to_yaml) + tar.add_file_simple('wallet/config.gpg', 0400, config.length) do |io| + io.write(config) + end - @passwords.each do |id, password| - tar.add_file_simple("wallet/passwords/#{id}.gpg", 0400, password.length) do |io| - io.write(password) - end - end + @passwords.each do |id, password| + tar.add_file_simple("wallet/passwords/#{id}.gpg", 0400, password.length) do |io| + io.write(password) + end + end - @otp_keys.each do |id, key| - tar.add_file_simple("wallet/otp_keys/#{id}.gpg", 0400, key.length) do |io| - io.write(key) - end - end + @otp_keys.each do |id, key| + tar.add_file_simple("wallet/otp_keys/#{id}.gpg", 0400, key.length) do |io| + io.write(key) + end + end - @keys.each do |id, key| - tar.add_file_simple("wallet/keys/#{id}.pub", 0400, key.length) do |io| - io.write(key) - end - end - end + @keys.each do |id, key| + tar.add_file_simple("wallet/keys/#{id}.pub", 0400, key.length) do |io| + io.write(key) + end + end + end - File.rename(tmp_file, @wallet_file) - rescue Exception => e - File.unlink(tmp_file) if File.exist?(tmp_file) + File.rename(tmp_file, @wallet_file) + rescue Exception => e + File.unlink(tmp_file) if File.exist?(tmp_file) - raise "#{I18n.t('error.mpw_file.write_data')}\n#{e}" - end + raise "#{I18n.t('error.mpw_file.write_data')}\n#{e}" + end - # Get a password - # args: id -> the item id - def get_password(id) - password = decrypt(@passwords[id]) - - if /^\$[a-zA-Z0-9]{4,9}::(?<password>.+)$/ =~ password - return Regexp.last_match('password') - else - return password - end - end + # Get a password + # args: id -> the item id + def get_password(id) + password = decrypt(@passwords[id]) - # Set a password - # args: id -> the item id - # password -> the new password - def set_password(id, password) - salt = MPW::password(length: Random.rand(4..9)) - password = "$#{salt}::#{password}" + if /^\$[a-zA-Z0-9]{4,9}::(?<password>.+)$/ =~ password + return Regexp.last_match('password') + else + return password + end + end - @passwords[id] = encrypt(password) - end + # Set a password + # args: id -> the item id + # password -> the new password + def set_password(id, password) + salt = MPW::password(length: Random.rand(4..9)) + password = "$#{salt}::#{password}" - # Return the list of all gpg keys - # rtrn: an array with the gpg keys name - def list_keys - return @keys.keys - end + @passwords[id] = encrypt(password) + end - # Add a public key - # args: key -> new public key file or name - def add_key(key) - if File.exists?(key) - data = File.open(key).read - key_import = GPGME::Key.import(data, armor: true) - key = GPGME::Key.get(key_import.imports[0].fpr).uids[0].email - else - data = GPGME::Key.export(key, armor: true).read - end + # Return the list of all gpg keys + # rtrn: an array with the gpg keys name + def list_keys + return @keys.keys + end - if data.to_s.empty? - raise I18n.t('error.export_key') - end + # Add a public key + # args: key -> new public key file or name + def add_key(key) + if File.exists?(key) + data = File.open(key).read + key_import = GPGME::Key.import(data, armor: true) + key = GPGME::Key.get(key_import.imports[0].fpr).uids[0].email + else + data = GPGME::Key.export(key, armor: true).read + end - @keys[key] = data - @passwords.each_key { |id| set_password(id, get_password(id)) } - @otp_keys.each_key { |id| set_otp_key(id, get_otp_key(id)) } - end + if data.to_s.empty? + raise I18n.t('error.export_key') + end - # Delete a public key - # args: key -> public key to delete - def delete_key(key) - @keys.delete(key) - @passwords.each_key { |id| set_password(id, get_password(id)) } - @otp_keys.each_key { |id| set_otp_key(id, get_otp_key(id)) } - end + @keys[key] = data + @passwords.each_key { |id| set_password(id, get_password(id)) } + @otp_keys.each_key { |id| set_otp_key(id, get_otp_key(id)) } + end - # Set config - # args: config -> a hash with config options - def set_config(options={}) - @config = {} if @config.nil? + # Delete a public key + # args: key -> public key to delete + def delete_key(key) + @keys.delete(key) + @passwords.each_key { |id| set_password(id, get_password(id)) } + @otp_keys.each_key { |id| set_otp_key(id, get_otp_key(id)) } + end - @config['protocol'] = options[:protocol] if options.has_key?(:protocol) - @config['host'] = options[:host] if options.has_key?(:host) - @config['port'] = options[:port] if options.has_key?(:port) - @config['user'] = options[:user] if options.has_key?(:user) - @config['password'] = options[:password] if options.has_key?(:password) - @config['path'] = options[:path] if options.has_key?(:path) - end + # Set config + # args: config -> a hash with config options + def set_config(options={}) + @config = {} if @config.nil? - # Add a new item - # @args: item -> Object MPW::Item - def add(item) - if not item.instance_of?(Item) - raise I18n.t('error.bad_class') - elsif item.empty? - raise I18n.t('error.empty') - else - @data.push(item) - end - end + @config['protocol'] = options[:protocol] if options.has_key?(:protocol) + @config['host'] = options[:host] if options.has_key?(:host) + @config['port'] = options[:port] if options.has_key?(:port) + @config['user'] = options[:user] if options.has_key?(:user) + @config['password'] = options[:password] if options.has_key?(:password) + @config['path'] = options[:path] if options.has_key?(:path) + end - # Search in some csv data - # @args: options -> a hash with paramaters - # @rtrn: a list with the resultat of the search - def list(options={}) - result = [] + # Add a new item + # @args: item -> Object MPW::Item + def add(item) + if not item.instance_of?(Item) + raise I18n.t('error.bad_class') + elsif item.empty? + raise I18n.t('error.empty') + else + @data.push(item) + end + end - search = options[:pattern].to_s.downcase - group = options[:group].to_s.downcase + # Search in some csv data + # @args: options -> a hash with paramaters + # @rtrn: a list with the resultat of the search + def list(options={}) + result = [] - @data.each do |item| - next if item.empty? - next if not group.empty? and not group.eql?(item.group.to_s.downcase) - - host = item.host.to_s.downcase - comment = item.comment.to_s.downcase + search = options[:pattern].to_s.downcase + group = options[:group].to_s.downcase - if not host =~ /^.*#{search}.*$/ and not comment =~ /^.*#{search}.*$/ - next - end + @data.each do |item| + next if item.empty? + next if not group.empty? and not group.eql?(item.group.to_s.downcase) - result.push(item) - end + host = item.host.to_s.downcase + comment = item.comment.to_s.downcase - return result - end + if not host =~ /^.*#{search}.*$/ and not comment =~ /^.*#{search}.*$/ + next + end - # Search in some csv data - # @args: id -> the id item - # @rtrn: a row with the result of the search - def search_by_id(id) - @data.each do |item| - return item if item.id == id - end + result.push(item) + end - return nil - end + return result + end - # Set an opt key - # args: id -> the item id - # key -> the new key - def set_otp_key(id, key) - if not key.to_s.empty? - @otp_keys[id] = encrypt(key.to_s) - end - end + # Search in some csv data + # @args: id -> the id item + # @rtrn: a row with the result of the search + def search_by_id(id) + @data.each do |item| + return item if item.id == id + end - # Get an opt key - # args: id -> the item id - # key -> the new key - def get_otp_key(id) - if @otp_keys.has_key?(id) - return decrypt(@otp_keys[id]) - else - return nil - end - end + return nil + end + + # Set an opt key + # args: id -> the item id + # key -> the new key + def set_otp_key(id, key) + if not key.to_s.empty? + @otp_keys[id] = encrypt(key.to_s) + end + end + + # Get an opt key + # args: id -> the item id + # key -> the new key + def get_otp_key(id) + if @otp_keys.has_key?(id) + return decrypt(@otp_keys[id]) + else + return nil + end + end - # Get an otp code - # @args: id -> the item id - # @rtrn: an otp code - def get_otp_code(id) - if not @otp_keys.has_key?(id) - return 0 - else - return ROTP::TOTP.new(decrypt(@otp_keys[id])).now - end - end + # Get an otp code + # @args: id -> the item id + # @rtrn: an otp code + def get_otp_code(id) + if not @otp_keys.has_key?(id) + return 0 + else + return ROTP::TOTP.new(decrypt(@otp_keys[id])).now + end + end - # Get remaining time before expire otp code - # @rtrn: return time in seconde - def get_otp_remaining_time - return (Time.now.utc.to_i / 30 + 1) * 30 - Time.now.utc.to_i - end + # Get remaining time before expire otp code + # @rtrn: return time in seconde + def get_otp_remaining_time + return (Time.now.utc.to_i / 30 + 1) * 30 - Time.now.utc.to_i + end - # Generate a random password - # @args: options -> :length, :special, :alpha, :numeric - # @rtrn: a random string - def self.password(options={}) - if not options.include?(:length) or options[:length].to_i <= 0 - length = 8 - elsif options[:length].to_i >= 32768 - length = 32768 - else - length = options[:length].to_i - end + # Generate a random password + # @args: options -> :length, :special, :alpha, :numeric + # @rtrn: a random string + def self.password(options={}) + if not options.include?(:length) or options[:length].to_i <= 0 + length = 8 + elsif options[:length].to_i >= 32768 + length = 32768 + else + length = options[:length].to_i + end - chars = [] - chars += [*('!'..'?')] - [*('0'..'9')] if options[:special] - chars += [*('A'..'Z'),*('a'..'z')] if options[:alpha] - chars += [*('0'..'9')] if options[:numeric] - chars = [*('A'..'Z'),*('a'..'z'),*('0'..'9')] if chars.empty? + chars = [] + chars += [*('!'..'?')] - [*('0'..'9')] if options[:special] + chars += [*('A'..'Z'),*('a'..'z')] if options[:alpha] + chars += [*('0'..'9')] if options[:numeric] + chars = [*('A'..'Z'),*('a'..'z'),*('0'..'9')] if chars.empty? - result = '' - while length > 62 do - result << chars.sample(62).join - length -= 62 - end - result << chars.sample(length).join + result = '' + while length > 62 do + result << chars.sample(62).join + length -= 62 + end + result << chars.sample(length).join - return result - end + return result + end - # Decrypt a gpg file - # @args: data -> string to decrypt - private - def decrypt(data) - return nil if data.to_s.empty? + # Decrypt a gpg file + # @args: data -> string to decrypt + private + def decrypt(data) + return nil if data.to_s.empty? - crypto = GPGME::Crypto.new(armor: true) - - return crypto.decrypt(data, password: @gpg_pass).read.force_encoding('utf-8') - rescue Exception => e - raise "#{I18n.t('error.gpg_file.decrypt')}\n#{e}" - end + crypto = GPGME::Crypto.new(armor: true) - # Encrypt a file - # args: data -> string to encrypt - private - def encrypt(data) - recipients = [] - crypto = GPGME::Crypto.new(armor: true, always_trust: true) + return crypto.decrypt(data, password: @gpg_pass).read.force_encoding('utf-8') + rescue Exception => e + raise "#{I18n.t('error.gpg_file.decrypt')}\n#{e}" + end - recipients.push(@key) - @keys.each_key do |key| - next if key == @key - recipients.push(key) - end + # Encrypt a file + # args: data -> string to encrypt + private + def encrypt(data) + recipients = [] + crypto = GPGME::Crypto.new(armor: true, always_trust: true) - return crypto.encrypt(data, recipients: recipients).read - rescue Exception => e - raise "#{I18n.t('error.gpg_file.encrypt')}\n#{e}" - end + recipients.push(@key) + @keys.each_key do |key| + next if key == @key + recipients.push(key) + end + + return crypto.encrypt(data, recipients: recipients).read + rescue Exception => e + raise "#{I18n.t('error.gpg_file.encrypt')}\n#{e}" + end end end diff --git a/test/test_config.rb b/test/test_config.rb index 143b3ed..2d1a51b 100644 --- a/test/test_config.rb +++ b/test/test_config.rb @@ -6,59 +6,59 @@ require 'locale' require 'i18n' class TestConfig < Test::Unit::TestCase - def setup - lang = Locale::Tag.parse(ENV['LANG']).to_simple.to_s[0..1] - - if defined?(I18n.enforce_available_locales) - I18n.enforce_available_locales = true - end - - I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) - I18n.load_path = Dir["#{File.expand_path('../../i18n', __FILE__)}/*.yml"] - I18n.default_locale = :en - I18n.locale = lang.to_sym - end + def setup + lang = Locale::Tag.parse(ENV['LANG']).to_simple.to_s[0..1] - def test_00_config - data = { gpg_key: 'test@example.com', - lang: 'en', - wallet_dir: '/tmp/test', - gpg_exe: '', - } + if defined?(I18n.enforce_available_locales) + I18n.enforce_available_locales = true + end - @config = MPW::Config.new - @config.setup(data) - @config.load_config + I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) + I18n.load_path = Dir["#{File.expand_path('../../i18n', __FILE__)}/*.yml"] + I18n.default_locale = :en + I18n.locale = lang.to_sym + end - data.each do |k,v| - assert_equal(v, @config.send(k)) - end + def test_00_config + data = { gpg_key: 'test@example.com', + lang: 'en', + wallet_dir: '/tmp/test', + gpg_exe: '', + } - @config.setup_gpg_key('password', 'test@example.com', 2048) - assert(@config.check_gpg_key?) - end + @config = MPW::Config.new + @config.setup(data) + @config.load_config - def test_01_password - data = { pwd_alpha: false, - pwd_numeric: false, - pwd_special: true, - pwd_length: 32, - } + data.each do |k,v| + assert_equal(v, @config.send(k)) + end - @config = MPW::Config.new - @config.load_config + @config.setup_gpg_key('password', 'test@example.com', 2048) + assert(@config.check_gpg_key?) + end - assert_equal(@config.password[:length], 16) - assert(@config.password[:alpha]) - assert(@config.password[:numeric]) - assert(!@config.password[:special]) + def test_01_password + data = { pwd_alpha: false, + pwd_numeric: false, + pwd_special: true, + pwd_length: 32, + } - @config.setup(data) - @config.load_config + @config = MPW::Config.new + @config.load_config - assert_equal(@config.password[:length], data[:pwd_length]) - assert(!@config.password[:alpha]) - assert(!@config.password[:numeric]) - assert(@config.password[:special]) - end + assert_equal(@config.password[:length], 16) + assert(@config.password[:alpha]) + assert(@config.password[:numeric]) + assert(!@config.password[:special]) + + @config.setup(data) + @config.load_config + + assert_equal(@config.password[:length], data[:pwd_length]) + assert(!@config.password[:alpha]) + assert(!@config.password[:numeric]) + assert(@config.password[:special]) + end end diff --git a/test/test_item.rb b/test/test_item.rb index b9f5961..751e1b0 100644 --- a/test/test_item.rb +++ b/test/test_item.rb @@ -1,172 +1,172 @@ #!/usr/bin/ruby - + require 'mpw/item' require 'test/unit' require 'yaml' - + class TestItem < Test::Unit::TestCase - def setup - @fixture_file = 'test/files/fixtures.yml' - @fixtures = YAML.load_file(@fixture_file) - - if defined?(I18n.enforce_available_locales) - I18n.enforce_available_locales = false - end + def setup + @fixture_file = 'test/files/fixtures.yml' + @fixtures = YAML.load_file(@fixture_file) - I18n.load_path = Dir['./i18n/cli/*.yml'] - I18n.default_locale = :en + if defined?(I18n.enforce_available_locales) + I18n.enforce_available_locales = false + end + + I18n.load_path = Dir['./i18n/cli/*.yml'] + I18n.default_locale = :en - puts - end + puts + end - def test_00_add_without_name - assert_raise(RuntimeError){MPW::Item.new} - end + def test_00_add_without_name + assert_raise(RuntimeError){MPW::Item.new} + end - def test_01_add_new - data = { group: @fixtures['add_new']['group'], - host: @fixtures['add_new']['host'], - protocol: @fixtures['add_new']['protocol'], - user: @fixtures['add_new']['user'], - port: @fixtures['add_new']['port'], - comment: @fixtures['add_new']['comment'], - } - - item = MPW::Item.new(data) + def test_01_add_new + data = { group: @fixtures['add_new']['group'], + host: @fixtures['add_new']['host'], + protocol: @fixtures['add_new']['protocol'], + user: @fixtures['add_new']['user'], + port: @fixtures['add_new']['port'], + comment: @fixtures['add_new']['comment'], + } - assert(!item.nil?) - assert(!item.empty?) + item = MPW::Item.new(data) - assert_equal(@fixtures['add_new']['group'], item.group) - assert_equal(@fixtures['add_new']['host'], item.host) - assert_equal(@fixtures['add_new']['protocol'], item.protocol) - assert_equal(@fixtures['add_new']['user'], item.user) - assert_equal(@fixtures['add_new']['port'].to_i, item.port) - assert_equal(@fixtures['add_new']['comment'], item.comment) - end + assert(!item.nil?) + assert(!item.empty?) - def test_02_add_existing - data = { id: @fixtures['add_existing']['id'], - group: @fixtures['add_existing']['group'], - host: @fixtures['add_existing']['host'], - protocol: @fixtures['add_existing']['protocol'], - user: @fixtures['add_existing']['user'], - port: @fixtures['add_existing']['port'], - comment: @fixtures['add_existing']['comment'], - created: @fixtures['add_existing']['created'], - } + assert_equal(@fixtures['add_new']['group'], item.group) + assert_equal(@fixtures['add_new']['host'], item.host) + assert_equal(@fixtures['add_new']['protocol'], item.protocol) + assert_equal(@fixtures['add_new']['user'], item.user) + assert_equal(@fixtures['add_new']['port'].to_i, item.port) + assert_equal(@fixtures['add_new']['comment'], item.comment) + end - item = MPW::Item.new(data) + def test_02_add_existing + data = { id: @fixtures['add_existing']['id'], + group: @fixtures['add_existing']['group'], + host: @fixtures['add_existing']['host'], + protocol: @fixtures['add_existing']['protocol'], + user: @fixtures['add_existing']['user'], + port: @fixtures['add_existing']['port'], + comment: @fixtures['add_existing']['comment'], + created: @fixtures['add_existing']['created'], + } - assert(!item.nil?) - assert(!item.empty?) + item = MPW::Item.new(data) - assert_equal(@fixtures['add_existing']['id'], item.id) - assert_equal(@fixtures['add_existing']['group'], item.group) - assert_equal(@fixtures['add_existing']['host'], item.host) - assert_equal(@fixtures['add_existing']['protocol'], item.protocol) - assert_equal(@fixtures['add_existing']['user'], item.user) - assert_equal(@fixtures['add_existing']['port'].to_i, item.port) - assert_equal(@fixtures['add_existing']['comment'], item.comment) - assert_equal(@fixtures['add_existing']['created'], item.created) - end + assert(!item.nil?) + assert(!item.empty?) - def test_03_update - data = { group: @fixtures['add_new']['group'], - host: @fixtures['add_new']['host'], - protocol: @fixtures['add_new']['protocol'], - user: @fixtures['add_new']['user'], - port: @fixtures['add_new']['port'], - comment: @fixtures['add_new']['comment'], - } - - item = MPW::Item.new(data) + assert_equal(@fixtures['add_existing']['id'], item.id) + assert_equal(@fixtures['add_existing']['group'], item.group) + assert_equal(@fixtures['add_existing']['host'], item.host) + assert_equal(@fixtures['add_existing']['protocol'], item.protocol) + assert_equal(@fixtures['add_existing']['user'], item.user) + assert_equal(@fixtures['add_existing']['port'].to_i, item.port) + assert_equal(@fixtures['add_existing']['comment'], item.comment) + assert_equal(@fixtures['add_existing']['created'], item.created) + end - assert(!item.nil?) - assert(!item.empty?) + def test_03_update + data = { group: @fixtures['add_new']['group'], + host: @fixtures['add_new']['host'], + protocol: @fixtures['add_new']['protocol'], + user: @fixtures['add_new']['user'], + port: @fixtures['add_new']['port'], + comment: @fixtures['add_new']['comment'], + } - created = item.created - last_edit = item.last_edit + item = MPW::Item.new(data) - data = { group: @fixtures['update']['group'], - host: @fixtures['update']['host'], - protocol: @fixtures['update']['protocol'], - user: @fixtures['update']['user'], - port: @fixtures['update']['port'], - comment: @fixtures['update']['comment'], - } - - sleep(1) - assert(item.update(data)) + assert(!item.nil?) + assert(!item.empty?) - assert(!item.empty?) + created = item.created + last_edit = item.last_edit - assert_equal(@fixtures['update']['group'], item.group) - assert_equal(@fixtures['update']['host'], item.host) - assert_equal(@fixtures['update']['protocol'], item.protocol) - assert_equal(@fixtures['update']['user'], item.user) - assert_equal(@fixtures['update']['port'].to_i, item.port) - assert_equal(@fixtures['update']['comment'], item.comment) + data = { group: @fixtures['update']['group'], + host: @fixtures['update']['host'], + protocol: @fixtures['update']['protocol'], + user: @fixtures['update']['user'], + port: @fixtures['update']['port'], + comment: @fixtures['update']['comment'], + } - assert_equal(created, item.created) - assert_not_equal(last_edit, item.last_edit) - end + sleep(1) + assert(item.update(data)) - def test_05_update_one_element - data = { group: @fixtures['add_new']['group'], - host: @fixtures['add_new']['host'], - protocol: @fixtures['add_new']['protocol'], - user: @fixtures['add_new']['user'], - port: @fixtures['add_new']['port'], - comment: @fixtures['add_new']['comment'], - } - - item = MPW::Item.new(data) + assert(!item.empty?) - assert(!item.nil?) - assert(!item.empty?) + assert_equal(@fixtures['update']['group'], item.group) + assert_equal(@fixtures['update']['host'], item.host) + assert_equal(@fixtures['update']['protocol'], item.protocol) + assert_equal(@fixtures['update']['user'], item.user) + assert_equal(@fixtures['update']['port'].to_i, item.port) + assert_equal(@fixtures['update']['comment'], item.comment) - last_edit = item.last_edit + assert_equal(created, item.created) + assert_not_equal(last_edit, item.last_edit) + end - sleep(1) - assert(item.update({comment: @fixtures['update']['comment']})) + def test_05_update_one_element + data = { group: @fixtures['add_new']['group'], + host: @fixtures['add_new']['host'], + protocol: @fixtures['add_new']['protocol'], + user: @fixtures['add_new']['user'], + port: @fixtures['add_new']['port'], + comment: @fixtures['add_new']['comment'], + } - assert_equal(@fixtures['add_new']['group'], item.group) - assert_equal(@fixtures['add_new']['host'], item.host) - assert_equal(@fixtures['add_new']['protocol'], item.protocol) - assert_equal(@fixtures['add_new']['user'], item.user) - assert_equal(@fixtures['add_new']['port'].to_i, item.port) - assert_equal(@fixtures['update']['comment'], item.comment) - - assert_not_equal(last_edit, item.last_edit) - end + item = MPW::Item.new(data) - def test_05_delete - data = { group: @fixtures['add_new']['group'], - host: @fixtures['add_new']['host'], - protocol: @fixtures['add_new']['protocol'], - user: @fixtures['add_new']['user'], - port: @fixtures['add_new']['port'], - comment: @fixtures['add_new']['comment'], - } - - item = MPW::Item.new(data) + assert(!item.nil?) + assert(!item.empty?) - assert(!item.nil?) - assert(!item.empty?) + last_edit = item.last_edit - item.delete - assert(!item.nil?) - assert(item.empty?) + sleep(1) + assert(item.update({comment: @fixtures['update']['comment']})) - assert_equal(nil, item.id) - assert_equal(nil, item.group) - assert_equal(nil, item.host) - assert_equal(nil, item.protocol) - assert_equal(nil, item.user) - assert_equal(nil, item.port) - assert_equal(nil, item.comment) - assert_equal(nil, item.created) - end -end + assert_equal(@fixtures['add_new']['group'], item.group) + assert_equal(@fixtures['add_new']['host'], item.host) + assert_equal(@fixtures['add_new']['protocol'], item.protocol) + assert_equal(@fixtures['add_new']['user'], item.user) + assert_equal(@fixtures['add_new']['port'].to_i, item.port) + assert_equal(@fixtures['update']['comment'], item.comment) + + assert_not_equal(last_edit, item.last_edit) + end + + def test_05_delete + data = { group: @fixtures['add_new']['group'], + host: @fixtures['add_new']['host'], + protocol: @fixtures['add_new']['protocol'], + user: @fixtures['add_new']['user'], + port: @fixtures['add_new']['port'], + comment: @fixtures['add_new']['comment'], + } + + item = MPW::Item.new(data) + + assert(!item.nil?) + assert(!item.empty?) + + item.delete + assert(!item.nil?) + assert(item.empty?) + + assert_equal(nil, item.id) + assert_equal(nil, item.group) + assert_equal(nil, item.host) + assert_equal(nil, item.protocol) + assert_equal(nil, item.user) + assert_equal(nil, item.port) + assert_equal(nil, item.comment) + assert_equal(nil, item.created) + end +end diff --git a/test/test_mpw.rb b/test/test_mpw.rb index c4748f6..30c9028 100644 --- a/test/test_mpw.rb +++ b/test/test_mpw.rb @@ -1,140 +1,140 @@ #!/usr/bin/ruby - + require 'mpw/mpw' require 'mpw/item' require 'test/unit' require 'yaml' require 'csv' - + class TestMPW < Test::Unit::TestCase - def setup - fixture_file = './test/files/fixtures.yml' + def setup + fixture_file = './test/files/fixtures.yml' - wallet_file = 'default.gpg' - key = 'test@example.com' - password = 'password' + wallet_file = 'default.gpg' + key = 'test@example.com' + password = 'password' - if defined?(I18n.enforce_available_locales) - I18n.enforce_available_locales = false - end + if defined?(I18n.enforce_available_locales) + I18n.enforce_available_locales = false + end - @mpw = MPW::MPW.new(key, wallet_file, password) - @fixtures = YAML.load_file(fixture_file) - end - - def test_00_decrypt_empty_file - @mpw.read_data - assert_equal(0, @mpw.list.length) - end + @mpw = MPW::MPW.new(key, wallet_file, password) + @fixtures = YAML.load_file(fixture_file) + end - def test_01_encrypt_empty_file - @mpw.read_data - @mpw.write_data - end + def test_00_decrypt_empty_file + @mpw.read_data + assert_equal(0, @mpw.list.length) + end - def test_02_add_item - data = { group: @fixtures['add_new']['group'], - host: @fixtures['add_new']['host'], - protocol: @fixtures['add_new']['protocol'], - user: @fixtures['add_new']['user'], - port: @fixtures['add_new']['port'], - comment: @fixtures['add_new']['comment'], - } - - item = MPW::Item.new(data) + def test_01_encrypt_empty_file + @mpw.read_data + @mpw.write_data + end - assert(!item.nil?) - assert(!item.empty?) + def test_02_add_item + data = { group: @fixtures['add_new']['group'], + host: @fixtures['add_new']['host'], + protocol: @fixtures['add_new']['protocol'], + user: @fixtures['add_new']['user'], + port: @fixtures['add_new']['port'], + comment: @fixtures['add_new']['comment'], + } - @mpw.read_data - @mpw.add(item) - @mpw.set_password(item.id, @fixtures['add_new']['password']) + item = MPW::Item.new(data) - assert_equal(1, @mpw.list.length) + assert(!item.nil?) + assert(!item.empty?) - item = @mpw.list[0] - @fixtures['add_new'].each do |k,v| - if k == 'password' - assert_equal(v, @mpw.get_password(item.id)) - else - assert_equal(v, item.send(k).to_s) - end - end + @mpw.read_data + @mpw.add(item) + @mpw.set_password(item.id, @fixtures['add_new']['password']) - @mpw.write_data - end + assert_equal(1, @mpw.list.length) - def test_03_decrypt_file - @mpw.read_data - assert_equal(1, @mpw.list.length) + item = @mpw.list[0] + @fixtures['add_new'].each do |k,v| + if k == 'password' + assert_equal(v, @mpw.get_password(item.id)) + else + assert_equal(v, item.send(k).to_s) + end + end - item = @mpw.list[0] - @fixtures['add_new'].each do |k,v| - if k == 'password' - assert_equal(v, @mpw.get_password(item.id)) - else - assert_equal(v, item.send(k).to_s) - end - end - end + @mpw.write_data + end - def test_04_delete_item - @mpw.read_data + def test_03_decrypt_file + @mpw.read_data + assert_equal(1, @mpw.list.length) - assert_equal(1, @mpw.list.length) + item = @mpw.list[0] + @fixtures['add_new'].each do |k,v| + if k == 'password' + assert_equal(v, @mpw.get_password(item.id)) + else + assert_equal(v, item.send(k).to_s) + end + end + end - @mpw.list.each do |item| - item.delete - end + def test_04_delete_item + @mpw.read_data - assert_equal(0, @mpw.list.length) + assert_equal(1, @mpw.list.length) - @mpw.write_data - end + @mpw.list.each do |item| + item.delete + end - def test_05_search - @mpw.read_data + assert_equal(0, @mpw.list.length) - @fixtures.each_value do |v| - data = { group: v['group'], - host: v['host'], - protocol: v['protocol'], - user: v['user'], - port: v['port'], - comment: v['comment'], - } - - item = MPW::Item.new(data) - - assert(!item.nil?) - assert(!item.empty?) - - @mpw.add(item) - @mpw.set_password(item.id, v['password']) - end + @mpw.write_data + end - assert_equal(3, @mpw.list.length) - assert_equal(1, @mpw.list(group: @fixtures['add_new']['group']).length) - assert_equal(1, @mpw.list(pattern: 'existing').length) - assert_equal(2, @mpw.list(pattern: 'host_[eu]').length) - end + def test_05_search + @mpw.read_data - def test_06_add_gpg_key - @mpw.read_data + @fixtures.each_value do |v| + data = { group: v['group'], + host: v['host'], + protocol: v['protocol'], + user: v['user'], + port: v['port'], + comment: v['comment'], + } - @mpw.add_key('test2@example.com') - assert_equal(2, @mpw.list_keys.length) + item = MPW::Item.new(data) - @mpw.write_data - end + assert(!item.nil?) + assert(!item.empty?) - def test_07_delete_gpg_key - @mpw.read_data - assert_equal(2, @mpw.list_keys.length) + @mpw.add(item) + @mpw.set_password(item.id, v['password']) + end - @mpw.delete_key('test2@example.com') - assert_equal(1, @mpw.list_keys.length) + assert_equal(3, @mpw.list.length) + assert_equal(1, @mpw.list(group: @fixtures['add_new']['group']).length) + assert_equal(1, @mpw.list(pattern: 'existing').length) + assert_equal(2, @mpw.list(pattern: 'host_[eu]').length) + end - @mpw.write_data - end + def test_06_add_gpg_key + @mpw.read_data + + @mpw.add_key('test2@example.com') + assert_equal(2, @mpw.list_keys.length) + + @mpw.write_data + end + + def test_07_delete_gpg_key + @mpw.read_data + assert_equal(2, @mpw.list_keys.length) + + @mpw.delete_key('test2@example.com') + assert_equal(1, @mpw.list_keys.length) + + @mpw.write_data + end end diff --git a/test/test_translate.rb b/test/test_translate.rb index 55f09df..6334a78 100644 --- a/test/test_translate.rb +++ b/test/test_translate.rb @@ -4,28 +4,28 @@ require 'yaml' require 'test/unit' class TestTranslate < Test::Unit::TestCase - def test_00_check_translate - missing = 0 - - Dir.glob('i18n/*.yml').each do |yaml| - lang = File.basename(yaml, '.yml') - translate = YAML.load_file(yaml) - - `grep -r -o "I18n.t('.*)" bin/ lib/ | cut -d"'" -f2`.each_line do |line| - begin - t = translate[lang] - line.strip.split('.').each do |v| - t = t[v] - end + def test_00_check_translate + missing = 0 - assert(!t.to_s.empty?) - rescue - puts "#{lang}.#{line}" - missing = 1 - end - end - end - - assert_equal(0, missing) - end + Dir.glob('i18n/*.yml').each do |yaml| + lang = File.basename(yaml, '.yml') + translate = YAML.load_file(yaml) + + `grep -r -o "I18n.t('.*)" bin/ lib/ | cut -d"'" -f2`.each_line do |line| + begin + t = translate[lang] + line.strip.split('.').each do |v| + t = t[v] + end + + assert(!t.to_s.empty?) + rescue + puts "#{lang}.#{line}" + missing = 1 + end + end + end + + assert_equal(0, missing) + end end diff --git a/test/tests.rb b/test/tests.rb index 904f64e..7f3fc7d 100644 --- a/test/tests.rb +++ b/test/tests.rb @@ -1,5 +1,5 @@ #!/usr/bin/ruby - + require_relative 'init.rb' require_relative 'test_config.rb' require_relative 'test_item.rb' From 178d0e6d1d3d32ad765fc4203cf1ee2e5575024f Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Mon, 27 Mar 2017 22:31:05 +0200 Subject: [PATCH 057/165] replace if not by unless --- bin/mpw-wallet | 2 +- lib/mpw/cli.rb | 12 +++++------- lib/mpw/config.rb | 2 +- lib/mpw/item.rb | 2 +- lib/mpw/mpw.rb | 18 +++++++----------- templates/add_form.erb | 2 +- templates/update_form.erb | 2 +- 7 files changed, 17 insertions(+), 23 deletions(-) diff --git a/bin/mpw-wallet b/bin/mpw-wallet index e575c0d..bcc3fc2 100644 --- a/bin/mpw-wallet +++ b/bin/mpw-wallet @@ -66,7 +66,7 @@ cli = MPW::Cli.new(config) cli.load_config -if not options[:list].nil? +if !options[:list].nil? cli.list_wallet else cli.get_wallet(options[:wallet]) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 83b9af3..9571fec 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -103,7 +103,7 @@ class Cli # Request the GPG password and decrypt the file def decrypt - if not defined?(@mpw) + unless defined?(@mpw) @password = ask(I18n.t('display.gpg_password')) {|q| q.echo = false} @mpw = MPW.new(@config.gpg_key, @wallet_file, @password, @config.gpg_exe) end @@ -451,9 +451,7 @@ class Cli item = get_item(items) confirm = ask("#{I18n.t('form.delete_item.ask')} (y/N) ").to_s - if not confirm =~ /^(y|yes|YES|Yes|Y)$/ - return false - end + return false unless confirm =~ /^(y|yes|YES|Yes|Y)$/ item.delete @mpw.write_data @@ -516,7 +514,7 @@ class Cli # @args: file -> the import file def import(file) raise I18n.t('form.import.file_empty') if file.to_s.empty? - raise I18n.t('form.import.file_not_exist') if not File.exist?(file) + raise I18n.t('form.import.file_not_exist') unless File.exist?(file) YAML::load_file(file).each_value do |row| item = Item.new(group: row['group'], @@ -530,8 +528,8 @@ class Cli next if item.empty? @mpw.add(item) - @mpw.set_password(item.id, row['password']) if not row['password'].to_s.empty? - @mpw.set_otp_key(item.id, row['otp_key']) if not row['otp_key'].to_s.empty? + @mpw.set_password(item.id, row['password']) unless row['password'].to_s.empty? + @mpw.set_otp_key(item.id, row['otp_key']) unless row['otp_key'].to_s.empty? end @mpw.write_data diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index 298ba61..8ec8e3a 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -73,7 +73,7 @@ class Config end end - if not gpg_key =~ /[a-zA-Z0-9.-_]+\@[a-zA-Z0-9]+\.[a-zA-Z]+/ + unless gpg_key =~ /[a-zA-Z0-9.-_]+\@[a-zA-Z0-9]+\.[a-zA-Z]+/ raise I18n.t('error.config.key_bad_format') end diff --git a/lib/mpw/item.rb b/lib/mpw/item.rb index 469af15..7c2547e 100644 --- a/lib/mpw/item.rb +++ b/lib/mpw/item.rb @@ -68,7 +68,7 @@ class Item @port = options[:port].to_i if options.has_key?(:port) and not options[:port].to_s.empty? @otp = options[:otp] if options.has_key?(:otp) @comment = options[:comment] if options.has_key?(:comment) - @last_edit = Time.now.to_i if not options.has_key?(:no_update_last_edit) + @last_edit = Time.now.to_i unless options.has_key?(:no_update_last_edit) end # Delete all data diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 9147648..bb4e38b 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -33,7 +33,7 @@ class MPW @gpg_exe = gpg_exe @wallet_file = wallet_file - if not @gpg_exe.to_s.empty? + unless @gpg_exe.to_s.empty? GPGME::Engine.set_info(GPGME::PROTOCOL_OpenPGP, @gpg_exe, "#{Dir.home}/.gnupg") end end @@ -48,7 +48,7 @@ class MPW data = nil - return if not File.exists?(@wallet_file) + return unless File.exists?(@wallet_file) Gem::Package::TarReader.new(File.open(@wallet_file)) do |tar| tar.each do |f| @@ -80,7 +80,7 @@ class MPW end end - if not data.nil? and not data.empty? + unless data.to_s.empty? YAML.load(data).each_value do |d| @data.push(Item.new(id: d['id'], group: d['group'], @@ -254,14 +254,12 @@ class MPW @data.each do |item| next if item.empty? - next if not group.empty? and not group.eql?(item.group.to_s.downcase) + next unless group.empty? or group.eql?(item.group.to_s.downcase) host = item.host.to_s.downcase comment = item.comment.to_s.downcase - if not host =~ /^.*#{search}.*$/ and not comment =~ /^.*#{search}.*$/ - next - end + next unless host =~ /^.*#{search}.*$/ or comment =~ /^.*#{search}.*$/ result.push(item) end @@ -284,9 +282,7 @@ class MPW # args: id -> the item id # key -> the new key def set_otp_key(id, key) - if not key.to_s.empty? - @otp_keys[id] = encrypt(key.to_s) - end + @otp_keys[id] = encrypt(key.to_s) unless key.to_s.empty? end # Get an opt key @@ -305,7 +301,7 @@ class MPW # @args: id -> the item id # @rtrn: an otp code def get_otp_code(id) - if not @otp_keys.has_key?(id) + unless @otp_keys.has_key?(id) return 0 else return ROTP::TOTP.new(decrypt(@otp_keys[id])).now diff --git a/templates/add_form.erb b/templates/add_form.erb index c2d6d73..bb81787 100644 --- a/templates/add_form.erb +++ b/templates/add_form.erb @@ -2,7 +2,7 @@ host: # <%= I18n.t('form.add_item.host') %> user: # <%= I18n.t('form.add_item.login') %> group: # <%= I18n.t('form.add_item.group') %> -protocol: # <%= I18n.t('form.add_item.protocol') %><% if not password %> +protocol: # <%= I18n.t('form.add_item.protocol') %><% unless password %> password: # <%= I18n.t('form.add_item.password') %><% end %> port: # <%= I18n.t('form.add_item.port') %> comment: # <%= I18n.t('form.add_item.comment') %> diff --git a/templates/update_form.erb b/templates/update_form.erb index e5363f8..f27da0b 100644 --- a/templates/update_form.erb +++ b/templates/update_form.erb @@ -2,7 +2,7 @@ # <%= I18n.t('form.update_item.host') %> host: <%= item.host %> # <%= I18n.t('form.update_item.login') %> -user: <%= item.user %><% if not password %> +user: <%= item.user %><% unless password %> # <%= I18n.t('form.update_item.password') %> password: <% end %> # <%= I18n.t('form.update_item.group') %> From e71f8e2acf36e74c81ba624405fd29ab94da06e2 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 29 Mar 2017 22:49:46 +0200 Subject: [PATCH 058/165] replace if not by unless --- lib/mpw/mpw.rb | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index bb4e38b..724dcaf 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -234,13 +234,10 @@ class MPW # Add a new item # @args: item -> Object MPW::Item def add(item) - if not item.instance_of?(Item) - raise I18n.t('error.bad_class') - elsif item.empty? - raise I18n.t('error.empty') - else - @data.push(item) - end + raise I18n.t('error.bad_class') unless item.instance_of?(Item) + raise I18n.t('error.empty') if item.empty? + + return @data.push(item) end # Search in some csv data From 8ed90c2ddc7de2eac70d36c528869edd8cb846d5 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 29 Mar 2017 22:50:47 +0200 Subject: [PATCH 059/165] fix --- bin/mpw-wallet | 4 ++-- lib/mpw/cli.rb | 6 +++--- lib/mpw/config.rb | 6 +++--- lib/mpw/item.rb | 8 ++++---- lib/mpw/mpw.rb | 8 ++++---- 5 files changed, 16 insertions(+), 16 deletions(-) diff --git a/bin/mpw-wallet b/bin/mpw-wallet index bcc3fc2..fffeaac 100644 --- a/bin/mpw-wallet +++ b/bin/mpw-wallet @@ -72,9 +72,9 @@ else cli.get_wallet(options[:wallet]) cli.decrypt - if not options[:list_keys].nil? + if !options[:list_keys].nil? cli.list_keys - elsif not options[:gpg_key].nil? + elsif !options[:gpg_key].nil? if options[:delete] cli.delete_key(options[:gpg_key]) else diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 9571fec..6b56c63 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -155,7 +155,7 @@ class Cli items.each do |item| data.each do |k, v| - next if k == :id or k == :otp + next if k == :id || k == :otp v[:length] = item.send(k.to_s).to_s.length + 3 if item.send(k.to_s).to_s.length >= v[:length] end @@ -240,7 +240,7 @@ class Cli items.sort! { |a,b| a.group.to_s.downcase <=> b.group.to_s.downcase } choice = ask(I18n.t('form.select')).to_i - if choice >= 1 and choice <= items.length + if choice >= 1 && choice <= items.length return items[choice-1] else return nil @@ -331,7 +331,7 @@ class Cli if wallets.length == 1 @wallet_file = wallets[0] - elsif not @config.default_wallet.to_s.empty? + elsif !@config.default_wallet.to_s.empty? @wallet_file = "#{@config.wallet_dir}/#{@config.default_wallet}.mpw" else @wallet_file = "#{@config.wallet_dir}/default.mpw" diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index 8ec8e3a..cd584b1 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -47,7 +47,7 @@ class Config @config_dir = "#{Dir.home}/.config/mpw" end - @config_file = "#{@config_dir}/mpw.cfg" if @config_file.nil? or @config_file.empty? + @config_file = "#{@config_dir}/mpw.cfg" if @config_file.nil? || @config_file.empty? end # Create a new config file @@ -68,7 +68,7 @@ class Config ['numeric', 'special', 'alpha', 'length'].each do |k| if options.has_key?("pwd_#{k}".to_sym) password[k.to_sym] = options["pwd_#{k}".to_sym] - elsif not @password.nil? and @password.has_key?(k.to_sym) + elsif !@password.nil? && @password.has_key?(k.to_sym) password[k.to_sym] = @password[k.to_sym] end end @@ -138,7 +138,7 @@ class Config @gpg_exe = config['gpg_exe'] @password = config['password'] || {} - raise if @gpg_key.empty? or @wallet_dir.empty? + raise if @gpg_key.empty? || @wallet_dir.empty? I18n.locale = @lang.to_sym rescue Exception => e diff --git a/lib/mpw/item.rb b/lib/mpw/item.rb index 7c2547e..c0ca11e 100644 --- a/lib/mpw/item.rb +++ b/lib/mpw/item.rb @@ -37,11 +37,11 @@ class Item # @args: options -> a hash of parameter # raise an error if the hash hasn't the key name def initialize(options={}) - if not options.has_key?(:host) or options[:host].to_s.empty? + if !options.has_key?(:host) || options[:host].to_s.empty? raise I18n.t('error.update.host_empty') end - if not options.has_key?(:id) or options[:id].to_s.empty? or not options.has_key?(:created) or options[:created].to_s.empty? + if !options.has_key?(:id) || options[:id].to_s.empty? || !options.has_key?(:created) || options[:created].to_s.empty? @id = generate_id @created = Time.now.to_i else @@ -57,7 +57,7 @@ class Item # Update the item # @args: options -> a hash of parameter def update(options={}) - if options.has_key?(:host) and options[:host].to_s.empty? + if options.has_key?(:host) && options[:host].to_s.empty? raise I18n.t('error.update.host_empty') end @@ -65,7 +65,7 @@ class Item @host = options[:host] if options.has_key?(:host) @protocol = options[:protocol] if options.has_key?(:protocol) @user = options[:user] if options.has_key?(:user) - @port = options[:port].to_i if options.has_key?(:port) and not options[:port].to_s.empty? + @port = options[:port].to_i if options.has_key?(:port) && !options[:port].to_s.empty? @otp = options[:otp] if options.has_key?(:otp) @comment = options[:comment] if options.has_key?(:comment) @last_edit = Time.now.to_i unless options.has_key?(:no_update_last_edit) diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 724dcaf..183b888 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -237,7 +237,7 @@ class MPW raise I18n.t('error.bad_class') unless item.instance_of?(Item) raise I18n.t('error.empty') if item.empty? - return @data.push(item) + @data.push(item) end # Search in some csv data @@ -251,12 +251,12 @@ class MPW @data.each do |item| next if item.empty? - next unless group.empty? or group.eql?(item.group.to_s.downcase) + next unless group.empty? || group.eql?(item.group.to_s.downcase) host = item.host.to_s.downcase comment = item.comment.to_s.downcase - next unless host =~ /^.*#{search}.*$/ or comment =~ /^.*#{search}.*$/ + next unless host =~ /^.*#{search}.*$/ || comment =~ /^.*#{search}.*$/ result.push(item) end @@ -315,7 +315,7 @@ class MPW # @args: options -> :length, :special, :alpha, :numeric # @rtrn: a random string def self.password(options={}) - if not options.include?(:length) or options[:length].to_i <= 0 + if !options.include?(:length) || options[:length].to_i <= 0 length = 8 elsif options[:length].to_i >= 32768 length = 32768 From e7fff4bb87aa97ffac32d9ee5eac50aec813bc7b Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 28 Mar 2017 22:17:52 +0200 Subject: [PATCH 060/165] remove return if useless --- lib/mpw/cli.rb | 10 +++------- lib/mpw/config.rb | 2 +- lib/mpw/item.rb | 6 +++--- lib/mpw/mpw.rb | 32 +++++++++++--------------------- 4 files changed, 18 insertions(+), 32 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 6b56c63..ecd98e3 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -240,11 +240,7 @@ class Cli items.sort! { |a,b| a.group.to_s.downcase <=> b.group.to_s.downcase } choice = ask(I18n.t('form.select')).to_i - if choice >= 1 && choice <= items.length - return items[choice-1] - else - return nil - end + choice >= 1 && choice <= items.length ? items[choice-1] : nil end # Copy in clipboard the login and password @@ -392,7 +388,7 @@ class Cli options[k.to_sym] = v end - return options + options end # Form to add a new item @@ -451,7 +447,7 @@ class Cli item = get_item(items) confirm = ask("#{I18n.t('form.delete_item.ask')} (y/N) ").to_s - return false unless confirm =~ /^(y|yes|YES|Yes|Y)$/ + return unless confirm =~ /^(y|yes|YES|Yes|Y)$/ item.delete @mpw.write_data diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index cd584b1..b23842e 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -153,7 +153,7 @@ class Config return true end - return false + false end end end diff --git a/lib/mpw/item.rb b/lib/mpw/item.rb index c0ca11e..bd1445b 100644 --- a/lib/mpw/item.rb +++ b/lib/mpw/item.rb @@ -86,17 +86,17 @@ class Item end def empty? - return @id.to_s.empty? + @id.to_s.empty? end def nil? - return false + false end # Generate an random id private def generate_id - return ([*('A'..'Z'),*('a'..'z'),*('0'..'9')]).sample(16).join + ([*('A'..'Z'),*('a'..'z'),*('0'..'9')]).sample(16).join end end end diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 183b888..de99440 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -168,9 +168,9 @@ class MPW password = decrypt(@passwords[id]) if /^\$[a-zA-Z0-9]{4,9}::(?<password>.+)$/ =~ password - return Regexp.last_match('password') + Regexp.last_match('password') else - return password + password end end @@ -187,7 +187,7 @@ class MPW # Return the list of all gpg keys # rtrn: an array with the gpg keys name def list_keys - return @keys.keys + @keys.keys end # Add a public key @@ -261,7 +261,7 @@ class MPW result.push(item) end - return result + result end # Search in some csv data @@ -272,7 +272,7 @@ class MPW return item if item.id == id end - return nil + nil end # Set an opt key @@ -286,29 +286,20 @@ class MPW # args: id -> the item id # key -> the new key def get_otp_key(id) - if @otp_keys.has_key?(id) - return decrypt(@otp_keys[id]) - else - return nil - end + @otp_keys.has_key?(id) ? decrypt(@otp_keys[id]) : nil end - # Get an otp code # @args: id -> the item id # @rtrn: an otp code def get_otp_code(id) - unless @otp_keys.has_key?(id) - return 0 - else - return ROTP::TOTP.new(decrypt(@otp_keys[id])).now - end + @otp_keys.has_key?(id) ? 0 : ROTP::TOTP.new(decrypt(@otp_keys[id])).now end # Get remaining time before expire otp code # @rtrn: return time in seconde def get_otp_remaining_time - return (Time.now.utc.to_i / 30 + 1) * 30 - Time.now.utc.to_i + (Time.now.utc.to_i / 30 + 1) * 30 - Time.now.utc.to_i end # Generate a random password @@ -336,7 +327,7 @@ class MPW end result << chars.sample(length).join - return result + result end # Decrypt a gpg file @@ -347,7 +338,7 @@ class MPW crypto = GPGME::Crypto.new(armor: true) - return crypto.decrypt(data, password: @gpg_pass).read.force_encoding('utf-8') + crypto.decrypt(data, password: @gpg_pass).read.force_encoding('utf-8') rescue Exception => e raise "#{I18n.t('error.gpg_file.decrypt')}\n#{e}" end @@ -365,10 +356,9 @@ class MPW recipients.push(key) end - return crypto.encrypt(data, recipients: recipients).read + crypto.encrypt(data, recipients: recipients).read rescue Exception => e raise "#{I18n.t('error.gpg_file.encrypt')}\n#{e}" end - end end From 31aba3b13c4a9d87cbfad1fee8aa16abdec4c0d9 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 28 Mar 2017 22:22:09 +0200 Subject: [PATCH 061/165] replace hash method has_key? by key? --- bin/mpw-config | 2 +- lib/mpw/cli.rb | 8 ++++---- lib/mpw/config.rb | 4 ++-- lib/mpw/item.rb | 22 +++++++++++----------- lib/mpw/mpw.rb | 18 +++++++++--------- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/bin/mpw-config b/bin/mpw-config index 14387d9..4740ed1 100644 --- a/bin/mpw-config +++ b/bin/mpw-config @@ -96,7 +96,7 @@ end.parse! config = MPW::Config.new(options[:config]) cli = MPW::Cli.new(config, nil) -if options.has_key?(:init) +if options.key?(:init) cli.setup(values) cli.load_config cli.get_wallet diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index ecd98e3..90f7665 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -399,8 +399,8 @@ class Cli options[:password] = MPW::password(@config.password) if password @mpw.add(item) - @mpw.set_password(item.id, options[:password]) if options.has_key?(:password) - @mpw.set_otp_key(item.id, options[:otp_key]) if options.has_key?(:otp_key) + @mpw.set_password(item.id, options[:password]) if options.key?(:password) + @mpw.set_otp_key(item.id, options[:otp_key]) if options.key?(:otp_key) @mpw.write_data puts "#{I18n.t('form.add_item.valid')}".green @@ -424,8 +424,8 @@ class Cli options[:password] = MPW::password(@config.password) if password item.update(options) - @mpw.set_password(item.id, options[:password]) if options.has_key?(:password) - @mpw.set_otp_key(item.id, options[:otp_key]) if options.has_key?(:otp_key) + @mpw.set_password(item.id, options[:password]) if options.key?(:password) + @mpw.set_otp_key(item.id, options[:otp_key]) if options.key?(:otp_key) @mpw.write_data puts "#{I18n.t('form.update_item.valid')}".green diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index b23842e..b7cf5e8 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -66,9 +66,9 @@ class Config } ['numeric', 'special', 'alpha', 'length'].each do |k| - if options.has_key?("pwd_#{k}".to_sym) + if options.key?("pwd_#{k}".to_sym) password[k.to_sym] = options["pwd_#{k}".to_sym] - elsif !@password.nil? && @password.has_key?(k.to_sym) + elsif !@password.nil? && @password.key?(k.to_sym) password[k.to_sym] = @password[k.to_sym] end end diff --git a/lib/mpw/item.rb b/lib/mpw/item.rb index bd1445b..6e99f6a 100644 --- a/lib/mpw/item.rb +++ b/lib/mpw/item.rb @@ -37,11 +37,11 @@ class Item # @args: options -> a hash of parameter # raise an error if the hash hasn't the key name def initialize(options={}) - if !options.has_key?(:host) || options[:host].to_s.empty? + if !options.key?(:host) || options[:host].to_s.empty? raise I18n.t('error.update.host_empty') end - if !options.has_key?(:id) || options[:id].to_s.empty? || !options.has_key?(:created) || options[:created].to_s.empty? + if !options.key?(:id) || options[:id].to_s.empty? || !options.key?(:created) || options[:created].to_s.empty? @id = generate_id @created = Time.now.to_i else @@ -57,18 +57,18 @@ class Item # Update the item # @args: options -> a hash of parameter def update(options={}) - if options.has_key?(:host) && options[:host].to_s.empty? + if options.key?(:host) && options[:host].to_s.empty? raise I18n.t('error.update.host_empty') end - @group = options[:group] if options.has_key?(:group) - @host = options[:host] if options.has_key?(:host) - @protocol = options[:protocol] if options.has_key?(:protocol) - @user = options[:user] if options.has_key?(:user) - @port = options[:port].to_i if options.has_key?(:port) && !options[:port].to_s.empty? - @otp = options[:otp] if options.has_key?(:otp) - @comment = options[:comment] if options.has_key?(:comment) - @last_edit = Time.now.to_i unless options.has_key?(:no_update_last_edit) + @group = options[:group] if options.key?(:group) + @host = options[:host] if options.key?(:host) + @protocol = options[:protocol] if options.key?(:protocol) + @user = options[:user] if options.key?(:user) + @port = options[:port].to_i if options.key?(:port) && !options[:port].to_s.empty? + @otp = options[:otp] if options.key?(:otp) + @comment = options[:comment] if options.key?(:comment) + @last_edit = Time.now.to_i unless options.key?(:no_update_last_edit) end # Delete all data diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index de99440..a957ef0 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -88,7 +88,7 @@ class MPW protocol: d['protocol'], user: d['user'], port: d['port'], - otp: @otp_keys.has_key?(d['id']), + otp: @otp_keys.key?(d['id']), comment: d['comment'], last_edit: d['last_edit'], created: d['created'], @@ -223,12 +223,12 @@ class MPW def set_config(options={}) @config = {} if @config.nil? - @config['protocol'] = options[:protocol] if options.has_key?(:protocol) - @config['host'] = options[:host] if options.has_key?(:host) - @config['port'] = options[:port] if options.has_key?(:port) - @config['user'] = options[:user] if options.has_key?(:user) - @config['password'] = options[:password] if options.has_key?(:password) - @config['path'] = options[:path] if options.has_key?(:path) + @config['protocol'] = options[:protocol] if options.key?(:protocol) + @config['host'] = options[:host] if options.key?(:host) + @config['port'] = options[:port] if options.key?(:port) + @config['user'] = options[:user] if options.key?(:user) + @config['password'] = options[:password] if options.key?(:password) + @config['path'] = options[:path] if options.key?(:path) end # Add a new item @@ -286,14 +286,14 @@ class MPW # args: id -> the item id # key -> the new key def get_otp_key(id) - @otp_keys.has_key?(id) ? decrypt(@otp_keys[id]) : nil + @otp_keys.key?(id) ? decrypt(@otp_keys[id]) : nil end # Get an otp code # @args: id -> the item id # @rtrn: an otp code def get_otp_code(id) - @otp_keys.has_key?(id) ? 0 : ROTP::TOTP.new(decrypt(@otp_keys[id])).now + @otp_keys.key?(id) ? 0 : ROTP::TOTP.new(decrypt(@otp_keys[id])).now end # Get remaining time before expire otp code From 351499aef6c76b99f75f6789c2440b5c387bc39c Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 28 Mar 2017 22:56:23 +0200 Subject: [PATCH 062/165] replace MPW::password to MPW.password replace YAML::load_file to YAML.load_file replace YAML::load to YAML.safe_load --- bin/mpw-genpwd | 2 +- lib/mpw/cli.rb | 8 ++++---- lib/mpw/config.rb | 2 +- lib/mpw/mpw.rb | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/bin/mpw-genpwd b/bin/mpw-genpwd index 0370732..1c09489 100644 --- a/bin/mpw-genpwd +++ b/bin/mpw-genpwd @@ -46,5 +46,5 @@ OptionParser.new do |opts| end end.parse! -puts MPW::MPW::password(options) +puts MPW::MPW.password(options) exit 0 diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 90f7665..7f406b7 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -379,7 +379,7 @@ class Cli system("#{editor} #{tmp_file}") - opts = YAML::load_file(tmp_file) + opts = YAML.load_file(tmp_file) end opts.delete_if { |k,v| v.to_s.empty? } @@ -396,7 +396,7 @@ class Cli def add(password=false) options = text_editor('add_form', nil, password) item = Item.new(options) - options[:password] = MPW::password(@config.password) if password + options[:password] = MPW.password(@config.password) if password @mpw.add(item) @mpw.set_password(item.id, options[:password]) if options.key?(:password) @@ -421,7 +421,7 @@ class Cli item = get_item(items) options = text_editor('update_form', item, password) - options[:password] = MPW::password(@config.password) if password + options[:password] = MPW.password(@config.password) if password item.update(options) @mpw.set_password(item.id, options[:password]) if options.key?(:password) @@ -512,7 +512,7 @@ class Cli raise I18n.t('form.import.file_empty') if file.to_s.empty? raise I18n.t('form.import.file_not_exist') unless File.exist?(file) - YAML::load_file(file).each_value do |row| + YAML.load_file(file).each_value do |row| item = Item.new(group: row['group'], host: row['host'], protocol: row['protocol'], diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index b7cf5e8..6f3632c 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -130,7 +130,7 @@ class Config # Load the config file def load_config - config = YAML::load_file(@config_file) + config = YAML.load_file(@config_file) @gpg_key = config['gpg_key'] @lang = config['lang'] @wallet_dir = config['wallet_dir'] diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index a957ef0..70f3847 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -54,7 +54,7 @@ class MPW tar.each do |f| case f.full_name when 'wallet/config.gpg' - @config = YAML.load(decrypt(f.read)) + @config = YAML.safe_load(decrypt(f.read)) when 'wallet/meta.gpg' data = decrypt(f.read) @@ -81,7 +81,7 @@ class MPW end unless data.to_s.empty? - YAML.load(data).each_value do |d| + YAML.safe_load(data).each_value do |d| @data.push(Item.new(id: d['id'], group: d['group'], host: d['host'], @@ -178,7 +178,7 @@ class MPW # args: id -> the item id # password -> the new password def set_password(id, password) - salt = MPW::password(length: Random.rand(4..9)) + salt = MPW.password(length: Random.rand(4..9)) password = "$#{salt}::#{password}" @passwords[id] = encrypt(password) From db6bb2b0f6fef4cd97b0223b8bea07b552e5c84d Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 28 Mar 2017 23:04:54 +0200 Subject: [PATCH 063/165] replace "#{var}" by var.to_s --- lib/mpw/cli.rb | 22 +++++++++++----------- lib/mpw/config.rb | 4 ++-- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 7f406b7..1807f75 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -40,7 +40,7 @@ class Cli def set_config(options) @config.setup(options) - puts "#{I18n.t('form.set_config.valid')}".green + puts I18n.t('form.set_config.valid').to_s.green rescue Exception => e puts "#{I18n.t('display.error')} #15: #{e}".red exit 2 @@ -57,7 +57,7 @@ class Cli load_config - puts "#{I18n.t('form.setup_config.valid')}".green + puts I18n.t('form.setup_config.valid').to_s.green rescue Exception => e puts "#{I18n.t('display.error')} #8: #{e}".red exit 2 @@ -81,7 +81,7 @@ class Cli @config.setup_gpg_key(@password, gpg_key) - puts "#{I18n.t('form.setup_gpg_key.valid')}".green + puts I18n.t('form.setup_gpg_key.valid').to_s.green rescue Exception => e puts "#{I18n.t('display.error')} #8: #{e}".red exit 2 @@ -208,7 +208,7 @@ class Cli end print '| ' - print "#{item.send(k.to_s)}".send(v[:color]) + print item.send(k.to_s).to_s.send(v[:color]) (v[:length] - item.send(k.to_s).to_s.length).times { print ' ' } end print "\n" @@ -343,7 +343,7 @@ class Cli @mpw.add_key(key) @mpw.write_data - puts "#{I18n.t('form.add_key.valid')}".green + puts I18n.t('form.add_key.valid').to_s.green rescue Exception => e puts "#{I18n.t('display.error')} #13: #{e}".red end @@ -354,7 +354,7 @@ class Cli @mpw.delete_key(key) @mpw.write_data - puts "#{I18n.t('form.delete_key.valid')}".green + puts I18n.t('form.delete_key.valid').to_s.green rescue Exception => e puts "#{I18n.t('display.error')} #15: #{e}".red end @@ -403,7 +403,7 @@ class Cli @mpw.set_otp_key(item.id, options[:otp_key]) if options.key?(:otp_key) @mpw.write_data - puts "#{I18n.t('form.add_item.valid')}".green + puts I18n.t('form.add_item.valid').to_s.green rescue Exception => e puts "#{I18n.t('display.error')} #13: #{e}".red end @@ -428,7 +428,7 @@ class Cli @mpw.set_otp_key(item.id, options[:otp_key]) if options.key?(:otp_key) @mpw.write_data - puts "#{I18n.t('form.update_item.valid')}".green + puts I18n.t('form.update_item.valid').to_s.green end rescue Exception => e puts "#{I18n.t('display.error')} #14: #{e}".red @@ -452,7 +452,7 @@ class Cli item.delete @mpw.write_data - puts "#{I18n.t('form.delete_item.valid')}".green + puts I18n.t('form.delete_item.valid').to_s.green end rescue Exception => e puts "#{I18n.t('display.error')} #16: #{e}".red @@ -501,7 +501,7 @@ class Cli File.open(file, 'w') {|f| f << data.to_yaml} - puts "#{I18n.t('form.export.valid', file: file)}".green + puts I18n.t('form.export.valid', file: file).to_s.green rescue Exception => e puts "#{I18n.t('display.error')} #17: #{e}".red end @@ -530,7 +530,7 @@ class Cli @mpw.write_data - puts "#{I18n.t('form.import.valid')}".green + puts I18n.t('form.import.valid').to_s.green rescue Exception => e puts "#{I18n.t('display.error')} #18: #{e}".red end diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index 6f3632c..be99f31 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -104,9 +104,9 @@ class Config # @rtrn: true if the GPG key is create, else false def setup_gpg_key(password, name, length = 4096, expire = 0) if name.to_s.empty? - raise "#{I18n.t('error.config.genkey_gpg.name')}" + raise I18n.t('error.config.genkey_gpg.name') elsif password.to_s.empty? - raise "#{I18n.t('error.config.genkey_gpg.password')}" + raise I18n.t('error.config.genkey_gpg.password') end param = '' From e99b18519db246afeccb990959f602e4e6b5b79b Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 28 Mar 2017 23:13:45 +0200 Subject: [PATCH 064/165] replace var.length == 0 by var.empty? --- lib/mpw/cli.rb | 8 ++++---- lib/mpw/mpw.rb | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 1807f75..991388c 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -224,7 +224,7 @@ class Cli def list(options={}) result = @mpw.list(options) - if result.length == 0 + if result.empty? puts I18n.t('display.nothing') else table_items(result) @@ -414,7 +414,7 @@ class Cli def update(password=false, options={}) items = @mpw.list(options) - if items.length == 0 + if items.empty? puts "#{I18n.t('display.warning')}: #{I18n.t('warning.select')}".yellow else table_items(items) if items.length > 1 @@ -439,7 +439,7 @@ class Cli def delete(options={}) items = @mpw.list(options) - if items.length == 0 + if items.empty? puts "#{I18n.t('display.warning')}: #{I18n.t('warning.select')}".yellow else table_items(items) @@ -464,7 +464,7 @@ class Cli def copy(clipboard=true, options={}) items = @mpw.list(options) - if items.length == 0 + if items.empty? puts I18n.t('display.nothing') else table_items(items) diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 70f3847..811a7a1 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -62,7 +62,7 @@ class MPW when /^wallet\/keys\/(?<key>.+)\.pub$/ key = Regexp.last_match('key') - if GPGME::Key.find(:public, key).length == 0 + if GPGME::Key.find(:public, key).empty? GPGME::Key.import(f.read, armor: true) end From 6a6120ca1448363f0fd21264c05ff2ad9fa9e44a Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 28 Mar 2017 23:24:22 +0200 Subject: [PATCH 065/165] use %w for words array --- lib/mpw/config.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index be99f31..915e603 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -65,7 +65,7 @@ class Config length: 16, } - ['numeric', 'special', 'alpha', 'length'].each do |k| + %w(numeric special alpha length).each do |k| if options.key?("pwd_#{k}".to_sym) password[k.to_sym] = options["pwd_#{k}".to_sym] elsif !@password.nil? && @password.key?(k.to_sym) From 7a831555f49fe0a2dbdb0d25edb6e64a4d36ed42 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 28 Mar 2017 23:29:33 +0200 Subject: [PATCH 066/165] fix spacing --- lib/mpw/cli.rb | 38 ++++++++++++++++++------------------- lib/mpw/config.rb | 2 +- lib/mpw/item.rb | 6 +++--- lib/mpw/mpw.rb | 48 +++++++++++++++++++++++------------------------ 4 files changed, 47 insertions(+), 47 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 991388c..300318a 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -68,8 +68,8 @@ class Cli def setup_gpg_key(gpg_key) return if @config.check_gpg_key? - password = ask(I18n.t('form.setup_gpg_key.password')) {|q| q.echo = false} - confirm = ask(I18n.t('form.setup_gpg_key.confirm_password')) {|q| q.echo = false} + password = ask(I18n.t('form.setup_gpg_key.password')) { |q| q.echo = false } + confirm = ask(I18n.t('form.setup_gpg_key.confirm_password')) { |q| q.echo = false } if password != confirm raise I18n.t('form.setup_gpg_key.error_password') @@ -104,7 +104,7 @@ class Cli # Request the GPG password and decrypt the file def decrypt unless defined?(@mpw) - @password = ask(I18n.t('display.gpg_password')) {|q| q.echo = false} + @password = ask(I18n.t('display.gpg_password')) { |q| q.echo = false } @mpw = MPW.new(@config.gpg_key, @wallet_file, @password, @config.gpg_exe) end @@ -140,7 +140,7 @@ class Cli end # Format items on a table - def table_items(items=[]) + def table_items(items = []) group = '.' i = 1 length_total = 10 @@ -160,7 +160,7 @@ class Cli v[:length] = item.send(k.to_s).to_s.length + 3 if item.send(k.to_s).to_s.length >= v[:length] end end - data[:id][:length] = items.length.to_s.length + 2 if items.length.to_s.length > data[:id][:length] + data[:id][:length] = items.length.to_s.length + 2 if items.length.to_s.length > data[:id][:length] data.each_value { |v| length_total += v[:length] } items.sort! { |a, b| a.group.to_s.downcase <=> b.group.to_s.downcase } @@ -221,7 +221,7 @@ class Cli # Display the query's result # @args: options -> the option to search - def list(options={}) + def list(options = {}) result = @mpw.list(options) if result.empty? @@ -237,16 +237,16 @@ class Cli def get_item(items) return items[0] if items.length == 1 - items.sort! { |a,b| a.group.to_s.downcase <=> b.group.to_s.downcase } + items.sort! { |a, b| a.group.to_s.downcase <=> b.group.to_s.downcase } choice = ask(I18n.t('form.select')).to_i - choice >= 1 && choice <= items.length ? items[choice-1] : nil + choice >= 1 && choice <= items.length ? items[choice - 1] : nil end # Copy in clipboard the login and password # @args: item -> the item # clipboard -> enable clipboard - def clipboard(item, clipboard=true) + def clipboard(item, clipboard = true) pid = nil # Security: force quit after 90s @@ -321,7 +321,7 @@ class Cli # Display the wallet # @args: wallet -> the wallet name - def get_wallet(wallet=nil) + def get_wallet(wallet = nil) if wallet.to_s.empty? wallets = Dir.glob("#{@config.wallet_dir}/*.mpw") @@ -363,7 +363,7 @@ class Cli # @args: template -> template name # item -> the item to edit # password -> disable field password - def text_editor(template_name, item=nil, password=false) + def text_editor(template_name, item = nil, password = false) editor = ENV['EDITOR'] || 'nano' options = {} opts = {} @@ -382,9 +382,9 @@ class Cli opts = YAML.load_file(tmp_file) end - opts.delete_if { |k,v| v.to_s.empty? } + opts.delete_if { |k, v| v.to_s.empty? } - opts.each do |k,v| + opts.each do |k, v| options[k.to_sym] = v end @@ -393,7 +393,7 @@ class Cli # Form to add a new item # @args: password -> generate a random password - def add(password=false) + def add(password = false) options = text_editor('add_form', nil, password) item = Item.new(options) options[:password] = MPW.password(@config.password) if password @@ -411,7 +411,7 @@ class Cli # Update an item # @args: password -> generate a random password # options -> the option to search - def update(password=false, options={}) + def update(password = false, options = {}) items = @mpw.list(options) if items.empty? @@ -421,7 +421,7 @@ class Cli item = get_item(items) options = text_editor('update_form', item, password) - options[:password] = MPW.password(@config.password) if password + options[:password] = MPW.password(@config.password) if password item.update(options) @mpw.set_password(item.id, options[:password]) if options.key?(:password) @@ -436,7 +436,7 @@ class Cli # Remove an item # @args: options -> the option to search - def delete(options={}) + def delete(options = {}) items = @mpw.list(options) if items.empty? @@ -461,7 +461,7 @@ class Cli # Copy a password, otp, login # @args: clipboard -> enable clipboard # options -> the option to search - def copy(clipboard=true, options={}) + def copy(clipboard = true, options = {}) items = @mpw.list(options) if items.empty? @@ -499,7 +499,7 @@ class Cli ) end - File.open(file, 'w') {|f| f << data.to_yaml} + File.open(file, 'w') { |f| f << data.to_yaml } puts I18n.t('form.export.valid', file: file).to_s.green rescue Exception => e diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index 915e603..c722c39 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -36,7 +36,7 @@ class Config # Constructor # @args: config_file -> the specify config file - def initialize(config_file=nil) + def initialize(config_file = nil) @config_file = config_file if /darwin/ =~ RUBY_PLATFORM diff --git a/lib/mpw/item.rb b/lib/mpw/item.rb index 6e99f6a..55e0061 100644 --- a/lib/mpw/item.rb +++ b/lib/mpw/item.rb @@ -36,7 +36,7 @@ class Item # Create a new item # @args: options -> a hash of parameter # raise an error if the hash hasn't the key name - def initialize(options={}) + def initialize(options = {}) if !options.key?(:host) || options[:host].to_s.empty? raise I18n.t('error.update.host_empty') end @@ -56,7 +56,7 @@ class Item # Update the item # @args: options -> a hash of parameter - def update(options={}) + def update(options = {}) if options.key?(:host) && options[:host].to_s.empty? raise I18n.t('error.update.host_empty') end @@ -96,7 +96,7 @@ class Item # Generate an random id private def generate_id - ([*('A'..'Z'),*('a'..'z'),*('0'..'9')]).sample(16).join + ([*('A'..'Z'), *('a'..'z'), *('0'..'9')]).sample(16).join end end end diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 811a7a1..678987e 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -27,7 +27,7 @@ module MPW class MPW # Constructor - def initialize(key, wallet_file, gpg_pass=nil, gpg_exe=nil) + def initialize(key, wallet_file, gpg_pass = nil, gpg_exe = nil) @key = key @gpg_pass = gpg_pass @gpg_exe = gpg_exe @@ -53,29 +53,29 @@ class MPW Gem::Package::TarReader.new(File.open(@wallet_file)) do |tar| tar.each do |f| case f.full_name - when 'wallet/config.gpg' - @config = YAML.safe_load(decrypt(f.read)) + when 'wallet/config.gpg' + @config = YAML.safe_load(decrypt(f.read)) - when 'wallet/meta.gpg' - data = decrypt(f.read) + when 'wallet/meta.gpg' + data = decrypt(f.read) - when /^wallet\/keys\/(?<key>.+)\.pub$/ - key = Regexp.last_match('key') + when /^wallet\/keys\/(?<key>.+)\.pub$/ + key = Regexp.last_match('key') - if GPGME::Key.find(:public, key).empty? - GPGME::Key.import(f.read, armor: true) - end + if GPGME::Key.find(:public, key).empty? + GPGME::Key.import(f.read, armor: true) + end - @keys[key] = f.read + @keys[key] = f.read - when /^wallet\/passwords\/(?<id>[a-zA-Z0-9]+)\.gpg$/ - @passwords[Regexp.last_match('id')] = f.read + when /^wallet\/passwords\/(?<id>[a-zA-Z0-9]+)\.gpg$/ + @passwords[Regexp.last_match('id')] = f.read - when /^wallet\/otp_keys\/(?<id>[a-zA-Z0-9]+)\.gpg$/ - @otp_keys[Regexp.last_match('id')] = f.read + when /^wallet\/otp_keys\/(?<id>[a-zA-Z0-9]+)\.gpg$/ + @otp_keys[Regexp.last_match('id')] = f.read - else - next + else + next end end end @@ -220,7 +220,7 @@ class MPW # Set config # args: config -> a hash with config options - def set_config(options={}) + def set_config(options = {}) @config = {} if @config.nil? @config['protocol'] = options[:protocol] if options.key?(:protocol) @@ -243,7 +243,7 @@ class MPW # Search in some csv data # @args: options -> a hash with paramaters # @rtrn: a list with the resultat of the search - def list(options={}) + def list(options = {}) result = [] search = options[:pattern].to_s.downcase @@ -305,7 +305,7 @@ class MPW # Generate a random password # @args: options -> :length, :special, :alpha, :numeric # @rtrn: a random string - def self.password(options={}) + def self.password(options = {}) if !options.include?(:length) || options[:length].to_i <= 0 length = 8 elsif options[:length].to_i >= 32768 @@ -315,10 +315,10 @@ class MPW end chars = [] - chars += [*('!'..'?')] - [*('0'..'9')] if options[:special] - chars += [*('A'..'Z'),*('a'..'z')] if options[:alpha] - chars += [*('0'..'9')] if options[:numeric] - chars = [*('A'..'Z'),*('a'..'z'),*('0'..'9')] if chars.empty? + chars += [*('!'..'?')] - [*('0'..'9')] if options[:special] + chars += [*('A'..'Z'), *('a'..'z')] if options[:alpha] + chars += [*('0'..'9')] if options[:numeric] + chars = [*('A'..'Z'), *('a'..'z'), *('0'..'9')] if chars.empty? result = '' while length > 62 do From 043e378eab897e63cb0488ebcb1093ca5a23ff86 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 28 Mar 2017 23:34:24 +0200 Subject: [PATCH 067/165] replace File.exists? by File.exist? --- lib/mpw/mpw.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 678987e..13c864f 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -48,7 +48,7 @@ class MPW data = nil - return unless File.exists?(@wallet_file) + return unless File.exist?(@wallet_file) Gem::Package::TarReader.new(File.open(@wallet_file)) do |tar| tar.each do |f| @@ -193,7 +193,7 @@ class MPW # Add a public key # args: key -> new public key file or name def add_key(key) - if File.exists?(key) + if File.exist?(key) data = File.open(key).read key_import = GPGME::Key.import(data, armor: true) key = GPGME::Key.get(key_import.imports[0].fpr).uids[0].email From 05c30200c3b2a2efa6373aa4d0cf72131e699b6f Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 29 Mar 2017 08:12:57 +0200 Subject: [PATCH 068/165] add rubocop file --- .rubocop.yml | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 .rubocop.yml diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..8685f88 --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,122 @@ + +AllCops: + Exclude: + - db/**/* + - config/**/* + - test/* + - Vagrantfile + TargetRubyVersion: 2.3 + +Style/AccessorMethodName: + Enabled: false +Style/NumericLiteralPrefix: + Enabled: false +Style/TrailingCommaInArguments: + Enabled: false +Style/TrailingCommaInLiteral: + Enabled: false +Style/FrozenStringLiteralComment: + Enabled: false +Metrics/ParameterLists: + Max: 5 + CountKeywordArgs: false +Style/MutableConstant: + Enabled: false +Metrics/LineLength: + Max: 120 +Metrics/AbcSize: + Enabled: false +Metrics/MethodLength: + Enabled: false +Metrics/BlockLength: + Enabled: false +Metrics/CyclomaticComplexity: + Enabled: false +Metrics/PerceivedComplexity: + Enabled: false +Metrics/ClassLength: + Enabled: false +Style/SpaceInsideHashLiteralBraces: + Enabled: false +Style/AsciiComments: + Enabled: true +Style/Documentation: + Enabled: false +Style/SignalException: + Enabled: false +Style/OptionHash: + Enabled: true +Style/SymbolArray: + Enabled: true +Performance/Casecmp: + Enabled: false +Style/DoubleNegation: + Enabled: false +Style/Alias: + EnforcedStyle: prefer_alias_method +Style/MultilineMethodCallIndentation: + EnforcedStyle: indented +Style/RaiseArgs: + EnforcedStyle: exploded +Style/SpaceInLambdaLiteral: + Enabled: false +Lint/UnneededSplatExpansion: + Enabled: false + + +# Generated configuration +Style/HashSyntax: + Enabled: true + EnforcedStyle: ruby19 + UseHashRocketsWithSymbolValues: false +Style/MethodDefParentheses: + Enabled: true + EnforcedStyle: require_parentheses +Style/MultilineAssignmentLayout: + Enabled: true + EnforcedStyle: new_line +Style/IndentationConsistency: + Enabled: true + EnforcedStyle: normal +Style/AlignParameters: + Enabled: true + EnforcedStyle: with_fixed_indentation +Style/BlockDelimiters: + Enabled: true + EnforcedStyle: line_count_based +Style/AndOr: + Enabled: true +Style/DotPosition: + Enabled: true + EnforcedStyle: leading +Style/EmptyLinesAroundClassBody: + Enabled: true + EnforcedStyle: no_empty_lines +Style/EmptyLinesAroundModuleBody: + Enabled: true + EnforcedStyle: no_empty_lines +Style/NumericPredicate: + Enabled: true + EnforcedStyle: comparison +Style/EvenOdd: + Enabled: false +Style/CollectionMethods: + Enabled: true + PreferredMethods: + collect: map + collect!: map! + inject: reduce + detect: find + find_all: select +Style/EmptyLinesAroundAccessModifier: + Enabled: true +Style/CommandLiteral: + Enabled: true + EnforcedStyle: percent_x +Style/StringLiterals: + Enabled: true + EnforcedStyle: single_quotes +Style/SpaceInsideBlockBraces: + EnforcedStyle: space +Style/VariableNumber: + EnforcedStyle: snake_case From c1baf3e1d4f18e5dee5c93530905281d16624417 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 29 Mar 2017 22:00:21 +0200 Subject: [PATCH 069/165] remove unused variable --- lib/mpw/cli.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 300318a..8faab03 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -247,8 +247,6 @@ class Cli # @args: item -> the item # clipboard -> enable clipboard def clipboard(item, clipboard = true) - pid = nil - # Security: force quit after 90s Thread.new do sleep 90 From b32846ea5edb61842464f798b4b60b78cdab9583 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 29 Mar 2017 22:12:11 +0200 Subject: [PATCH 070/165] replace while true by Kernel.loop --- lib/mpw/cli.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 8faab03..a334e61 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -253,7 +253,7 @@ class Cli exit end - while true + Kernel.loop do choice = ask(I18n.t('form.clipboard.choice')).to_s case choice From c29d2e92d23ea103c66e0107a237d73b60315f6e Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 29 Mar 2017 22:13:53 +0200 Subject: [PATCH 071/165] replace :? to --- bin/mpw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/mpw b/bin/mpw index 3eb9fd9..8ee1305 100755 --- a/bin/mpw +++ b/bin/mpw @@ -16,7 +16,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -$: << File.expand_path('../../lib', __FILE__) +$LOAD_PATH << File.expand_path('../../lib', __FILE__) require 'locale' require 'set' From 74d08a7d5b9706561ab52b597eb999c3d3fa8ad1 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 29 Mar 2017 22:24:50 +0200 Subject: [PATCH 072/165] add to_s --- bin/mpw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/mpw b/bin/mpw index 8ee1305..1bdf835 100755 --- a/bin/mpw +++ b/bin/mpw @@ -45,7 +45,7 @@ I18n.locale = lang.to_sym bin_dir = File.dirname(__FILE__) command = "#{bin_dir}/mpw-#{ARGV[0]}" -if Dir.glob("#{bin_dir}/mpw-*").include?("#{command}") +if Dir.glob("#{bin_dir}/mpw-*").include?(command.to_s) begin Kernel.load(command) rescue OptionParser::ParseError => e From da248460da2fe8d674ea4979a33facc249b07ae9 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 29 Mar 2017 22:31:04 +0200 Subject: [PATCH 073/165] use %r{} for regex --- lib/mpw/mpw.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 13c864f..b3a733c 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -59,7 +59,7 @@ class MPW when 'wallet/meta.gpg' data = decrypt(f.read) - when /^wallet\/keys\/(?<key>.+)\.pub$/ + when %r{^wallet/keys/(?<key>.+)\.pub$} key = Regexp.last_match('key') if GPGME::Key.find(:public, key).empty? @@ -68,10 +68,10 @@ class MPW @keys[key] = f.read - when /^wallet\/passwords\/(?<id>[a-zA-Z0-9]+)\.gpg$/ + when %r{^wallet/passwords/(?<id>[a-zA-Z0-9]+)\.gpg$} @passwords[Regexp.last_match('id')] = f.read - when /^wallet\/otp_keys\/(?<id>[a-zA-Z0-9]+)\.gpg$/ + when %r{^wallet/otp_keys/(?<id>[a-zA-Z0-9]+)\.gpg$} @otp_keys[Regexp.last_match('id')] = f.read else From 8cd7b6e583fef8d355b559eeab5c19f2e631cfc0 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 29 Mar 2017 22:31:48 +0200 Subject: [PATCH 074/165] use iter form --- lib/mpw/cli.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index a334e61..7f1c2da 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -202,7 +202,7 @@ class Cli if k == :otp print '| ' - if item.otp; print ' X ' else 4.times { print ' ' } end + item.otp ? (print ' X ') : 4.times { print ' ' } next end From 18ba72e91bd9fc52381c2a27c42d12444617b121 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 29 Mar 2017 22:36:46 +0200 Subject: [PATCH 075/165] fix private style --- lib/mpw/item.rb | 3 ++- lib/mpw/mpw.rb | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/mpw/item.rb b/lib/mpw/item.rb index 55e0061..225a3d7 100644 --- a/lib/mpw/item.rb +++ b/lib/mpw/item.rb @@ -93,8 +93,9 @@ class Item false end - # Generate an random id private + + # Generate an random id def generate_id ([*('A'..'Z'), *('a'..'z'), *('0'..'9')]).sample(16).join end diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index b3a733c..d09e9bd 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -330,9 +330,10 @@ class MPW result end + private + # Decrypt a gpg file # @args: data -> string to decrypt - private def decrypt(data) return nil if data.to_s.empty? @@ -345,7 +346,6 @@ class MPW # Encrypt a file # args: data -> string to encrypt - private def encrypt(data) recipients = [] crypto = GPGME::Crypto.new(armor: true, always_trust: true) From 5db52db1a39c7c6c4ccfc2bd7d9e707c3cd53118 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 29 Mar 2017 22:38:16 +0200 Subject: [PATCH 076/165] remove do in while line --- lib/mpw/mpw.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index d09e9bd..ffdccff 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -321,7 +321,7 @@ class MPW chars = [*('A'..'Z'), *('a'..'z'), *('0'..'9')] if chars.empty? result = '' - while length > 62 do + while length > 62 result << chars.sample(62).join length -= 62 end From e04d00d3f477a08c1e69b76bfb27df883a0ec4e2 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 29 Mar 2017 22:45:39 +0200 Subject: [PATCH 077/165] use new form for module --- lib/mpw/cli.rb | 4 +--- lib/mpw/config.rb | 4 +--- lib/mpw/item.rb | 4 +--- lib/mpw/mpw.rb | 4 +--- 4 files changed, 4 insertions(+), 12 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 7f1c2da..d2dcd0b 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -26,8 +26,7 @@ require 'tmpdir' require 'mpw/item' require 'mpw/mpw' -module MPW -class Cli +class MPW::Cli # Constructor # @args: config -> the config @@ -533,4 +532,3 @@ class Cli puts "#{I18n.t('display.error')} #18: #{e}".red end end -end diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index c722c39..4c4e259 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -21,8 +21,7 @@ require 'yaml' require 'i18n' require 'fileutils' -module MPW -class Config +class MPW::Config attr_accessor :error_msg @@ -156,4 +155,3 @@ class Config false end end -end diff --git a/lib/mpw/item.rb b/lib/mpw/item.rb index 225a3d7..a5528a6 100644 --- a/lib/mpw/item.rb +++ b/lib/mpw/item.rb @@ -18,8 +18,7 @@ require 'i18n' -module MPW -class Item +class MPW::Item attr_accessor :id attr_accessor :group @@ -100,4 +99,3 @@ class Item ([*('A'..'Z'), *('a'..'z'), *('0'..'9')]).sample(16).join end end -end diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index ffdccff..0eac01c 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -23,8 +23,7 @@ require 'yaml' require 'rotp' require 'mpw/item' -module MPW -class MPW +class MPW::MPW # Constructor def initialize(key, wallet_file, gpg_pass = nil, gpg_exe = nil) @@ -361,4 +360,3 @@ class MPW raise "#{I18n.t('error.gpg_file.encrypt')}\n#{e}" end end -end From 782f3d8b5f88cc7acd16311157406a236c031352 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 29 Mar 2017 23:01:12 +0200 Subject: [PATCH 078/165] remove useless line --- lib/mpw/cli.rb | 1 - lib/mpw/config.rb | 1 - lib/mpw/item.rb | 1 - lib/mpw/mpw.rb | 1 - 4 files changed, 4 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index d2dcd0b..3488b5a 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -27,7 +27,6 @@ require 'mpw/item' require 'mpw/mpw' class MPW::Cli - # Constructor # @args: config -> the config def initialize(config) diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index 4c4e259..4818104 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -22,7 +22,6 @@ require 'i18n' require 'fileutils' class MPW::Config - attr_accessor :error_msg attr_accessor :gpg_key diff --git a/lib/mpw/item.rb b/lib/mpw/item.rb index a5528a6..8c0db4c 100644 --- a/lib/mpw/item.rb +++ b/lib/mpw/item.rb @@ -19,7 +19,6 @@ require 'i18n' class MPW::Item - attr_accessor :id attr_accessor :group attr_accessor :host diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 0eac01c..0aa9aea 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -24,7 +24,6 @@ require 'rotp' require 'mpw/item' class MPW::MPW - # Constructor def initialize(key, wallet_file, gpg_pass = nil, gpg_exe = nil) @key = key From b1fd013d921f12f71b93bc1db0a532bd6562f44b Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 29 Mar 2017 23:15:45 +0200 Subject: [PATCH 079/165] fix indentation for multiline method and hash --- lib/mpw/cli.rb | 32 +++++++++++++++--------------- lib/mpw/config.rb | 6 ++---- lib/mpw/mpw.rb | 50 +++++++++++++++++++++++++---------------------- 3 files changed, 45 insertions(+), 43 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 3488b5a..12f18af 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -148,8 +148,7 @@ class MPW::Cli protocol: { length: 9, color: 'white' }, port: { length: 5, color: 'white' }, otp: { length: 4, color: 'white' }, - comment: { length: 14, color: 'magenta' }, - } + comment: { length: 14, color: 'magenta' } } items.each do |item| data.each do |k, v| @@ -481,18 +480,20 @@ class MPW::Cli data = {} items.each do |item| - data.merge!(item.id => { 'host' => item.host, - 'user' => item.user, - 'group' => item.group, - 'password' => @mpw.get_password(item.id), - 'protocol' => item.protocol, - 'port' => item.port, - 'otp_key' => @mpw.get_otp_key(item.id), - 'comment' => item.comment, - 'last_edit' => item.last_edit, - 'created' => item.created, - } - ) + data.merge!( + item.id => { + 'host' => item.host, + 'user' => item.user, + 'group' => item.group, + 'password' => @mpw.get_password(item.id), + 'protocol' => item.protocol, + 'port' => item.port, + 'otp_key' => @mpw.get_otp_key(item.id), + 'comment' => item.comment, + 'last_edit' => item.last_edit, + 'created' => item.created, + } + ) end File.open(file, 'w') { |f| f << data.to_yaml } @@ -514,8 +515,7 @@ class MPW::Cli protocol: row['protocol'], user: row['user'], port: row['port'], - comment: row['comment'], - ) + comment: row['comment']) next if item.empty? diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index 4818104..f82fadb 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -60,8 +60,7 @@ class MPW::Config password = { numeric: true, alpha: true, special: false, - length: 16, - } + length: 16 } %w(numeric special alpha length).each do |k| if options.key?("pwd_#{k}".to_sym) @@ -81,8 +80,7 @@ class MPW::Config 'wallet_dir' => wallet_dir, 'default_wallet' => default_wallet, 'gpg_exe' => gpg_exe, - 'password' => password, - } + 'password' => password } FileUtils.mkdir_p(@config_dir, mode: 0700) FileUtils.mkdir_p(wallet_dir, mode: 0700) diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 0aa9aea..1e385cb 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -80,18 +80,20 @@ class MPW::MPW unless data.to_s.empty? YAML.safe_load(data).each_value do |d| - @data.push(Item.new(id: d['id'], - group: d['group'], - host: d['host'], - protocol: d['protocol'], - user: d['user'], - port: d['port'], - otp: @otp_keys.key?(d['id']), - comment: d['comment'], - last_edit: d['last_edit'], - created: d['created'], - ) - ) + @data.push( + Item.new( + id: d['id'], + group: d['group'], + host: d['host'], + protocol: d['protocol'], + user: d['user'], + port: d['port'], + otp: @otp_keys.key?(d['id']), + comment: d['comment'], + last_edit: d['last_edit'], + created: d['created'], + ) + ) end end @@ -108,17 +110,19 @@ class MPW::MPW @data.each do |item| next if item.empty? - data.merge!(item.id => { 'id' => item.id, - 'group' => item.group, - 'host' => item.host, - 'protocol' => item.protocol, - 'user' => item.user, - 'port' => item.port, - 'comment' => item.comment, - 'last_edit' => item.last_edit, - 'created' => item.created, - } - ) + data.merge!( + item.id => { + 'id' => item.id, + 'group' => item.group, + 'host' => item.host, + 'protocol' => item.protocol, + 'user' => item.user, + 'port' => item.port, + 'comment' => item.comment, + 'last_edit' => item.last_edit, + 'created' => item.created, + } + ) end @config['last_update'] = Time.now.to_i From ac2732d116e56c68fa60873ac70b570bda122156 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 29 Mar 2017 23:24:54 +0200 Subject: [PATCH 080/165] revert new module form --- lib/mpw/cli.rb | 4 +++- lib/mpw/config.rb | 4 +++- lib/mpw/item.rb | 4 +++- lib/mpw/mpw.rb | 4 +++- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 12f18af..b44d770 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -26,7 +26,8 @@ require 'tmpdir' require 'mpw/item' require 'mpw/mpw' -class MPW::Cli +module MPW +class Cli # Constructor # @args: config -> the config def initialize(config) @@ -531,3 +532,4 @@ class MPW::Cli puts "#{I18n.t('display.error')} #18: #{e}".red end end +end diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index f82fadb..8e2cb6e 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -21,7 +21,8 @@ require 'yaml' require 'i18n' require 'fileutils' -class MPW::Config +module MPW +class Config attr_accessor :error_msg attr_accessor :gpg_key @@ -152,3 +153,4 @@ class MPW::Config false end end +end diff --git a/lib/mpw/item.rb b/lib/mpw/item.rb index 8c0db4c..f6d90ef 100644 --- a/lib/mpw/item.rb +++ b/lib/mpw/item.rb @@ -18,7 +18,8 @@ require 'i18n' -class MPW::Item +module MPW +class Item attr_accessor :id attr_accessor :group attr_accessor :host @@ -98,3 +99,4 @@ class MPW::Item ([*('A'..'Z'), *('a'..'z'), *('0'..'9')]).sample(16).join end end +end diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 1e385cb..0c65435 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -23,7 +23,8 @@ require 'yaml' require 'rotp' require 'mpw/item' -class MPW::MPW +module MPW +class MPW # Constructor def initialize(key, wallet_file, gpg_pass = nil, gpg_exe = nil) @key = key @@ -363,3 +364,4 @@ class MPW::MPW raise "#{I18n.t('error.gpg_file.encrypt')}\n#{e}" end end +end From 002ec2175b427ba148dbf803d3fa34f39ca402bd Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Thu, 30 Mar 2017 19:35:50 +0200 Subject: [PATCH 081/165] fix rescue --- lib/mpw/cli.rb | 27 +++++++++++++-------------- lib/mpw/config.rb | 6 +++--- lib/mpw/mpw.rb | 8 ++++---- 3 files changed, 20 insertions(+), 21 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index b44d770..a1533b5 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -40,7 +40,7 @@ class Cli @config.setup(options) puts I18n.t('form.set_config.valid').to_s.green - rescue Exception => e + rescue => e puts "#{I18n.t('display.error')} #15: #{e}".red exit 2 end @@ -57,7 +57,7 @@ class Cli load_config puts I18n.t('form.setup_config.valid').to_s.green - rescue Exception => e + rescue => e puts "#{I18n.t('display.error')} #8: #{e}".red exit 2 end @@ -81,7 +81,7 @@ class Cli @config.setup_gpg_key(@password, gpg_key) puts I18n.t('form.setup_gpg_key.valid').to_s.green - rescue Exception => e + rescue => e puts "#{I18n.t('display.error')} #8: #{e}".red exit 2 end @@ -94,8 +94,7 @@ class Cli # Load config def load_config @config.load_config - - rescue Exception => e + rescue => e puts "#{I18n.t('display.error')} #10: #{e}".red exit 2 end @@ -108,7 +107,7 @@ class Cli end @mpw.read_data - rescue Exception => e + rescue => e puts "#{I18n.t('display.error')} #11: #{e}".red exit 2 end @@ -340,7 +339,7 @@ class Cli @mpw.write_data puts I18n.t('form.add_key.valid').to_s.green - rescue Exception => e + rescue => e puts "#{I18n.t('display.error')} #13: #{e}".red end @@ -351,7 +350,7 @@ class Cli @mpw.write_data puts I18n.t('form.delete_key.valid').to_s.green - rescue Exception => e + rescue => e puts "#{I18n.t('display.error')} #15: #{e}".red end @@ -400,7 +399,7 @@ class Cli @mpw.write_data puts I18n.t('form.add_item.valid').to_s.green - rescue Exception => e + rescue => e puts "#{I18n.t('display.error')} #13: #{e}".red end @@ -426,7 +425,7 @@ class Cli puts I18n.t('form.update_item.valid').to_s.green end - rescue Exception => e + rescue => e puts "#{I18n.t('display.error')} #14: #{e}".red end @@ -450,7 +449,7 @@ class Cli puts I18n.t('form.delete_item.valid').to_s.green end - rescue Exception => e + rescue => e puts "#{I18n.t('display.error')} #16: #{e}".red end @@ -468,7 +467,7 @@ class Cli item = get_item(items) clipboard(item, clipboard) end - rescue Exception => e + rescue => e puts "#{I18n.t('display.error')} #14: #{e}".red end @@ -500,7 +499,7 @@ class Cli File.open(file, 'w') { |f| f << data.to_yaml } puts I18n.t('form.export.valid', file: file).to_s.green - rescue Exception => e + rescue => e puts "#{I18n.t('display.error')} #17: #{e}".red end @@ -528,7 +527,7 @@ class Cli @mpw.write_data puts I18n.t('form.import.valid').to_s.green - rescue Exception => e + rescue => e puts "#{I18n.t('display.error')} #18: #{e}".red end end diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index 8e2cb6e..af746a2 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -89,7 +89,7 @@ class Config File.open(@config_file, 'w') do |file| file << config.to_yaml end - rescue Exception => e + rescue => e raise "#{I18n.t('error.config.write')}\n#{e}" end @@ -121,7 +121,7 @@ class Config ctx = GPGME::Ctx.new ctx.genkey(param, nil, nil) - rescue Exception => e + rescue => e raise "#{I18n.t('error.config.genkey_gpg.exception')}\n#{e}" end @@ -138,7 +138,7 @@ class Config raise if @gpg_key.empty? || @wallet_dir.empty? I18n.locale = @lang.to_sym - rescue Exception => e + rescue => e raise "#{I18n.t('error.config.load')}\n#{e}" end diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 0c65435..069a123 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -99,7 +99,7 @@ class MPW end add_key(@key) if @keys[@key].nil? - rescue Exception => e + rescue => e raise "#{I18n.t('error.mpw_file.read_data')}\n#{e}" end @@ -159,7 +159,7 @@ class MPW end File.rename(tmp_file, @wallet_file) - rescue Exception => e + rescue => e File.unlink(tmp_file) if File.exist?(tmp_file) raise "#{I18n.t('error.mpw_file.write_data')}\n#{e}" @@ -343,7 +343,7 @@ class MPW crypto = GPGME::Crypto.new(armor: true) crypto.decrypt(data, password: @gpg_pass).read.force_encoding('utf-8') - rescue Exception => e + rescue => e raise "#{I18n.t('error.gpg_file.decrypt')}\n#{e}" end @@ -360,7 +360,7 @@ class MPW end crypto.encrypt(data, recipients: recipients).read - rescue Exception => e + rescue => e raise "#{I18n.t('error.gpg_file.encrypt')}\n#{e}" end end From 3c787371b36d0760a0a19645a657807047a084a7 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Thu, 30 Mar 2017 19:40:04 +0200 Subject: [PATCH 082/165] fix syntax for options in method --- lib/mpw/cli.rb | 8 ++++---- lib/mpw/item.rb | 4 ++-- lib/mpw/mpw.rb | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index a1533b5..3f4d43d 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -218,7 +218,7 @@ class Cli # Display the query's result # @args: options -> the option to search - def list(options = {}) + def list(**options) result = @mpw.list(options) if result.empty? @@ -406,7 +406,7 @@ class Cli # Update an item # @args: password -> generate a random password # options -> the option to search - def update(password = false, options = {}) + def update(password = false, **options) items = @mpw.list(options) if items.empty? @@ -431,7 +431,7 @@ class Cli # Remove an item # @args: options -> the option to search - def delete(options = {}) + def delete(**options) items = @mpw.list(options) if items.empty? @@ -456,7 +456,7 @@ class Cli # Copy a password, otp, login # @args: clipboard -> enable clipboard # options -> the option to search - def copy(clipboard = true, options = {}) + def copy(clipboard = true, **options) items = @mpw.list(options) if items.empty? diff --git a/lib/mpw/item.rb b/lib/mpw/item.rb index f6d90ef..1534cc4 100644 --- a/lib/mpw/item.rb +++ b/lib/mpw/item.rb @@ -35,7 +35,7 @@ class Item # Create a new item # @args: options -> a hash of parameter # raise an error if the hash hasn't the key name - def initialize(options = {}) + def initialize(**options) if !options.key?(:host) || options[:host].to_s.empty? raise I18n.t('error.update.host_empty') end @@ -55,7 +55,7 @@ class Item # Update the item # @args: options -> a hash of parameter - def update(options = {}) + def update(**options) if options.key?(:host) && options[:host].to_s.empty? raise I18n.t('error.update.host_empty') end diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 069a123..46355ec 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -223,7 +223,7 @@ class MPW # Set config # args: config -> a hash with config options - def set_config(options = {}) + def set_config(**options) @config = {} if @config.nil? @config['protocol'] = options[:protocol] if options.key?(:protocol) @@ -246,7 +246,7 @@ class MPW # Search in some csv data # @args: options -> a hash with paramaters # @rtrn: a list with the resultat of the search - def list(options = {}) + def list(**options) result = [] search = options[:pattern].to_s.downcase From 755df6c3425663e7bcfd3e07b6a8976e349c703d Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Thu, 30 Mar 2017 19:41:00 +0200 Subject: [PATCH 083/165] fix syntax for variable with multiple conditional --- lib/mpw/cli.rb | 21 +++++++++++---------- lib/mpw/config.rb | 15 ++++++++------- lib/mpw/mpw.rb | 17 +++++++++-------- 3 files changed, 28 insertions(+), 25 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 3f4d43d..0536108 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -317,19 +317,20 @@ class Cli # Display the wallet # @args: wallet -> the wallet name def get_wallet(wallet = nil) - if wallet.to_s.empty? - wallets = Dir.glob("#{@config.wallet_dir}/*.mpw") + @wallet_file = + if wallet.to_s.empty? + wallets = Dir.glob("#{@config.wallet_dir}/*.mpw") - if wallets.length == 1 - @wallet_file = wallets[0] - elsif !@config.default_wallet.to_s.empty? - @wallet_file = "#{@config.wallet_dir}/#{@config.default_wallet}.mpw" + if wallets.length == 1 + wallets[0] + elsif !@config.default_wallet.to_s.empty? + "#{@config.wallet_dir}/#{@config.default_wallet}.mpw" + else + "#{@config.wallet_dir}/default.mpw" + end else - @wallet_file = "#{@config.wallet_dir}/default.mpw" + "#{@config.wallet_dir}/#{wallet}.mpw" end - else - @wallet_file = "#{@config.wallet_dir}/#{wallet}.mpw" - end end # Add a new public key diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index af746a2..a6c102e 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -38,13 +38,14 @@ class Config def initialize(config_file = nil) @config_file = config_file - if /darwin/ =~ RUBY_PLATFORM - @config_dir = "#{Dir.home}/Library/Preferences/mpw" - elsif /cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM - @config_dir = "#{Dir.home}/AppData/Local/mpw" - else - @config_dir = "#{Dir.home}/.config/mpw" - end + @config_dir = + if /darwin/ =~ RUBY_PLATFORM + "#{Dir.home}/Library/Preferences/mpw" + elsif /cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM + "#{Dir.home}/AppData/Local/mpw" + else + "#{Dir.home}/.config/mpw" + end @config_file = "#{@config_dir}/mpw.cfg" if @config_file.nil? || @config_file.empty? end diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 46355ec..557d572 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -308,14 +308,15 @@ class MPW # Generate a random password # @args: options -> :length, :special, :alpha, :numeric # @rtrn: a random string - def self.password(options = {}) - if !options.include?(:length) || options[:length].to_i <= 0 - length = 8 - elsif options[:length].to_i >= 32768 - length = 32768 - else - length = options[:length].to_i - end + def self.password(**options) + length = + if !options.include?(:length) || options[:length].to_i <= 0 + 8 + elsif options[:length].to_i >= 32_768 + 32_768 + else + options[:length].to_i + end chars = [] chars += [*('!'..'?')] - [*('0'..'9')] if options[:special] From 0f7510b6e6b61dfb898328eb6c161b2583dbff83 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Thu, 30 Mar 2017 19:44:32 +0200 Subject: [PATCH 084/165] multiple fix on syntax --- lib/mpw/cli.rb | 6 ++---- lib/mpw/config.rb | 7 ++----- lib/mpw/item.rb | 2 +- lib/mpw/mpw.rb | 8 ++------ 4 files changed, 7 insertions(+), 16 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 0536108..cc452cf 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -70,9 +70,7 @@ class Cli password = ask(I18n.t('form.setup_gpg_key.password')) { |q| q.echo = false } confirm = ask(I18n.t('form.setup_gpg_key.confirm_password')) { |q| q.echo = false } - if password != confirm - raise I18n.t('form.setup_gpg_key.error_password') - end + raise I18n.t('form.setup_gpg_key.error_password') if password != confirm @password = password.to_s @@ -378,7 +376,7 @@ class Cli opts = YAML.load_file(tmp_file) end - opts.delete_if { |k, v| v.to_s.empty? } + opts.delete_if { |_, v| v.to_s.empty? } opts.each do |k, v| options[k.to_sym] = v diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index a6c102e..d691559 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -101,11 +101,8 @@ class Config # expire -> the time of expire to GPG key # @rtrn: true if the GPG key is create, else false def setup_gpg_key(password, name, length = 4096, expire = 0) - if name.to_s.empty? - raise I18n.t('error.config.genkey_gpg.name') - elsif password.to_s.empty? - raise I18n.t('error.config.genkey_gpg.password') - end + raise I18n.t('error.config.genkey_gpg.name') if name.to_s.empty? + raise I18n.t('error.config.genkey_gpg.password') if password.to_s.empty? param = '' param << '<GnupgKeyParms format="internal">' + "\n" diff --git a/lib/mpw/item.rb b/lib/mpw/item.rb index 1534cc4..cd24168 100644 --- a/lib/mpw/item.rb +++ b/lib/mpw/item.rb @@ -96,7 +96,7 @@ class Item # Generate an random id def generate_id - ([*('A'..'Z'), *('a'..'z'), *('0'..'9')]).sample(16).join + [*('A'..'Z'), *('a'..'z'), *('0'..'9')].sample(16).join end end end diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 557d572..daf04ff 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -32,9 +32,7 @@ class MPW @gpg_exe = gpg_exe @wallet_file = wallet_file - unless @gpg_exe.to_s.empty? - GPGME::Engine.set_info(GPGME::PROTOCOL_OpenPGP, @gpg_exe, "#{Dir.home}/.gnupg") - end + GPGME::Engine.set_info(GPGME::PROTOCOL_OpenPGP, @gpg_exe, "#{Dir.home}/.gnupg") unless @gpg_exe.to_s.empty? end # Read mpw file @@ -204,9 +202,7 @@ class MPW data = GPGME::Key.export(key, armor: true).read end - if data.to_s.empty? - raise I18n.t('error.export_key') - end + raise I18n.t('error.export_key') if data.to_s.empty? @keys[key] = data @passwords.each_key { |id| set_password(id, get_password(id)) } From 01745cac2d5ced7a5237b16087b9525974876634 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Thu, 30 Mar 2017 20:04:20 +0200 Subject: [PATCH 085/165] indent class --- lib/mpw/cli.rb | 886 +++++++++++++++++++++++----------------------- lib/mpw/config.rb | 228 ++++++------ lib/mpw/item.rb | 138 ++++---- lib/mpw/mpw.rb | 622 ++++++++++++++++---------------- 4 files changed, 937 insertions(+), 937 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index cc452cf..d4d4027 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -27,507 +27,507 @@ require 'mpw/item' require 'mpw/mpw' module MPW -class Cli - # Constructor - # @args: config -> the config - def initialize(config) - @config = config - end - - # Change a parameter int the config after init - # @args: options -> param to change - def set_config(options) - @config.setup(options) - - puts I18n.t('form.set_config.valid').to_s.green - rescue => e - puts "#{I18n.t('display.error')} #15: #{e}".red - exit 2 - end - - # Create a new config file - # @args: options -> set param - def setup(options) - options[:lang] = options[:lang] || Locale::Tag.parse(ENV['LANG']).to_simple.to_s[0..1] - - I18n.locale = options[:lang].to_sym - - @config.setup(options) - - load_config - - puts I18n.t('form.setup_config.valid').to_s.green - rescue => e - puts "#{I18n.t('display.error')} #8: #{e}".red - exit 2 - end - - # Setup a new GPG key - # @args: gpg_key -> the key name - def setup_gpg_key(gpg_key) - return if @config.check_gpg_key? - - password = ask(I18n.t('form.setup_gpg_key.password')) { |q| q.echo = false } - confirm = ask(I18n.t('form.setup_gpg_key.confirm_password')) { |q| q.echo = false } - - raise I18n.t('form.setup_gpg_key.error_password') if password != confirm - - @password = password.to_s - - puts I18n.t('form.setup_gpg_key.wait') - - @config.setup_gpg_key(@password, gpg_key) - - puts I18n.t('form.setup_gpg_key.valid').to_s.green - rescue => e - puts "#{I18n.t('display.error')} #8: #{e}".red - exit 2 - end - - # List gpg keys in wallet - def list_keys - table_list('keys', @mpw.list_keys) - end - - # Load config - def load_config - @config.load_config - rescue => e - puts "#{I18n.t('display.error')} #10: #{e}".red - exit 2 - end - - # Request the GPG password and decrypt the file - def decrypt - unless defined?(@mpw) - @password = ask(I18n.t('display.gpg_password')) { |q| q.echo = false } - @mpw = MPW.new(@config.gpg_key, @wallet_file, @password, @config.gpg_exe) + class Cli + # Constructor + # @args: config -> the config + def initialize(config) + @config = config end - @mpw.read_data - rescue => e - puts "#{I18n.t('display.error')} #11: #{e}".red - exit 2 - end + # Change a parameter int the config after init + # @args: options -> param to change + def set_config(options) + @config.setup(options) - # Format list on a table - def table_list(title, list) - i = 1 - length = 0 - - list.each do |item| - length = item.length if length < item.length - end - length += 7 - - puts "\n#{I18n.t("display.#{title}")}".red - print ' ' - length.times { print '=' } - print "\n" - - list.each do |item| - print " #{i}".cyan - (3 - i.to_s.length).times { print ' ' } - puts "| #{item}" - i += 1 + puts I18n.t('form.set_config.valid').to_s.green + rescue => e + puts "#{I18n.t('display.error')} #15: #{e}".red + exit 2 end - print "\n" - end + # Create a new config file + # @args: options -> set param + def setup(options) + options[:lang] = options[:lang] || Locale::Tag.parse(ENV['LANG']).to_simple.to_s[0..1] - # Format items on a table - def table_items(items = []) - group = '.' - i = 1 - length_total = 10 - data = { id: { length: 3, color: 'cyan' }, - host: { length: 9, color: 'yellow' }, - user: { length: 7, color: 'green' }, - protocol: { length: 9, color: 'white' }, - port: { length: 5, color: 'white' }, - otp: { length: 4, color: 'white' }, - comment: { length: 14, color: 'magenta' } } + I18n.locale = options[:lang].to_sym - items.each do |item| - data.each do |k, v| - next if k == :id || k == :otp + @config.setup(options) - v[:length] = item.send(k.to_s).to_s.length + 3 if item.send(k.to_s).to_s.length >= v[:length] - end + load_config + + puts I18n.t('form.setup_config.valid').to_s.green + rescue => e + puts "#{I18n.t('display.error')} #8: #{e}".red + exit 2 end - data[:id][:length] = items.length.to_s.length + 2 if items.length.to_s.length > data[:id][:length] - data.each_value { |v| length_total += v[:length] } - items.sort! { |a, b| a.group.to_s.downcase <=> b.group.to_s.downcase } + # Setup a new GPG key + # @args: gpg_key -> the key name + def setup_gpg_key(gpg_key) + return if @config.check_gpg_key? - items.each do |item| - if group != item.group - group = item.group + password = ask(I18n.t('form.setup_gpg_key.password')) { |q| q.echo = false } + confirm = ask(I18n.t('form.setup_gpg_key.confirm_password')) { |q| q.echo = false } - if group.to_s.empty? - puts "\n#{I18n.t('display.no_group')}".red - else - puts "\n#{group}".red - end + raise I18n.t('form.setup_gpg_key.error_password') if password != confirm - print ' ' - length_total.times { print '=' } - print "\n " - data.each do |k, v| - case k - when :id - print ' ID' - when :otp - print '| OTP' - else - print "| #{k.to_s.capitalize}" - end + @password = password.to_s - (v[:length] - k.to_s.length).times { print ' ' } - end - print "\n " - length_total.times { print '=' } - print "\n" + puts I18n.t('form.setup_gpg_key.wait') + + @config.setup_gpg_key(@password, gpg_key) + + puts I18n.t('form.setup_gpg_key.valid').to_s.green + rescue => e + puts "#{I18n.t('display.error')} #8: #{e}".red + exit 2 + end + + # List gpg keys in wallet + def list_keys + table_list('keys', @mpw.list_keys) + end + + # Load config + def load_config + @config.load_config + rescue => e + puts "#{I18n.t('display.error')} #10: #{e}".red + exit 2 + end + + # Request the GPG password and decrypt the file + def decrypt + unless defined?(@mpw) + @password = ask(I18n.t('display.gpg_password')) { |q| q.echo = false } + @mpw = MPW.new(@config.gpg_key, @wallet_file, @password, @config.gpg_exe) end - print " #{i}".send(data[:id][:color]) - (data[:id][:length] - i.to_s.length).times { print ' ' } - data.each do |k, v| - next if k == :id + @mpw.read_data + rescue => e + puts "#{I18n.t('display.error')} #11: #{e}".red + exit 2 + end - if k == :otp - print '| ' - item.otp ? (print ' X ') : 4.times { print ' ' } + # Format list on a table + def table_list(title, list) + i = 1 + length = 0 - next - end - - print '| ' - print item.send(k.to_s).to_s.send(v[:color]) - (v[:length] - item.send(k.to_s).to_s.length).times { print ' ' } + list.each do |item| + length = item.length if length < item.length end + length += 7 + + puts "\n#{I18n.t("display.#{title}")}".red + print ' ' + length.times { print '=' } print "\n" - i += 1 + list.each do |item| + print " #{i}".cyan + (3 - i.to_s.length).times { print ' ' } + puts "| #{item}" + i += 1 + end + + print "\n" end - print "\n" - end + # Format items on a table + def table_items(items = []) + group = '.' + i = 1 + length_total = 10 + data = { id: { length: 3, color: 'cyan' }, + host: { length: 9, color: 'yellow' }, + user: { length: 7, color: 'green' }, + protocol: { length: 9, color: 'white' }, + port: { length: 5, color: 'white' }, + otp: { length: 4, color: 'white' }, + comment: { length: 14, color: 'magenta' } } - # Display the query's result - # @args: options -> the option to search - def list(**options) - result = @mpw.list(options) + items.each do |item| + data.each do |k, v| + next if k == :id || k == :otp - if result.empty? - puts I18n.t('display.nothing') - else - table_items(result) - end - end + v[:length] = item.send(k.to_s).to_s.length + 3 if item.send(k.to_s).to_s.length >= v[:length] + end + end + data[:id][:length] = items.length.to_s.length + 2 if items.length.to_s.length > data[:id][:length] - # Get an item when multiple choice - # @args: items -> array of items - # @rtrn: item - def get_item(items) - return items[0] if items.length == 1 + data.each_value { |v| length_total += v[:length] } + items.sort! { |a, b| a.group.to_s.downcase <=> b.group.to_s.downcase } - items.sort! { |a, b| a.group.to_s.downcase <=> b.group.to_s.downcase } - choice = ask(I18n.t('form.select')).to_i + items.each do |item| + if group != item.group + group = item.group - choice >= 1 && choice <= items.length ? items[choice - 1] : nil - end + if group.to_s.empty? + puts "\n#{I18n.t('display.no_group')}".red + else + puts "\n#{group}".red + end - # Copy in clipboard the login and password - # @args: item -> the item - # clipboard -> enable clipboard - def clipboard(item, clipboard = true) - # Security: force quit after 90s - Thread.new do - sleep 90 - exit - end + print ' ' + length_total.times { print '=' } + print "\n " + data.each do |k, v| + case k + when :id + print ' ID' + when :otp + print '| OTP' + else + print "| #{k.to_s.capitalize}" + end - Kernel.loop do - choice = ask(I18n.t('form.clipboard.choice')).to_s - - case choice - when 'q', 'quit' - break - - when 'l', 'login' - if clipboard - Clipboard.copy(item.user) - puts I18n.t('form.clipboard.login').green - else - puts item.user + (v[:length] - k.to_s.length).times { print ' ' } + end + print "\n " + length_total.times { print '=' } + print "\n" end - when 'p', 'password' - if clipboard - Clipboard.copy(@mpw.get_password(item.id)) - puts I18n.t('form.clipboard.password').yellow + print " #{i}".send(data[:id][:color]) + (data[:id][:length] - i.to_s.length).times { print ' ' } + data.each do |k, v| + next if k == :id - Thread.new do - sleep 30 + if k == :otp + print '| ' + item.otp ? (print ' X ') : 4.times { print ' ' } - Clipboard.clear + next + end + + print '| ' + print item.send(k.to_s).to_s.send(v[:color]) + (v[:length] - item.send(k.to_s).to_s.length).times { print ' ' } + end + print "\n" + + i += 1 + end + + print "\n" + end + + # Display the query's result + # @args: options -> the option to search + def list(**options) + result = @mpw.list(options) + + if result.empty? + puts I18n.t('display.nothing') + else + table_items(result) + end + end + + # Get an item when multiple choice + # @args: items -> array of items + # @rtrn: item + def get_item(items) + return items[0] if items.length == 1 + + items.sort! { |a, b| a.group.to_s.downcase <=> b.group.to_s.downcase } + choice = ask(I18n.t('form.select')).to_i + + choice >= 1 && choice <= items.length ? items[choice - 1] : nil + end + + # Copy in clipboard the login and password + # @args: item -> the item + # clipboard -> enable clipboard + def clipboard(item, clipboard = true) + # Security: force quit after 90s + Thread.new do + sleep 90 + exit + end + + Kernel.loop do + choice = ask(I18n.t('form.clipboard.choice')).to_s + + case choice + when 'q', 'quit' + break + + when 'l', 'login' + if clipboard + Clipboard.copy(item.user) + puts I18n.t('form.clipboard.login').green + else + puts item.user + end + + when 'p', 'password' + if clipboard + Clipboard.copy(@mpw.get_password(item.id)) + puts I18n.t('form.clipboard.password').yellow + + Thread.new do + sleep 30 + + Clipboard.clear + end + else + puts @mpw.get_password(item.id) + end + + when 'o', 'otp' + if clipboard + Clipboard.copy(@mpw.get_otp_code(item.id)) + else + puts @mpw.get_otp_code(item.id) + end + puts I18n.t('form.clipboard.otp', time: @mpw.get_otp_remaining_time).yellow + + else + puts "----- #{I18n.t('form.clipboard.help.name')} -----".cyan + puts I18n.t('form.clipboard.help.login') + puts I18n.t('form.clipboard.help.password') + puts I18n.t('form.clipboard.help.otp_code') + puts I18n.t('form.clipboard.help.quit') + next + end + end + + Clipboard.clear + rescue SystemExit, Interrupt + Clipboard.clear + end + + # List all wallets + def list_wallet + wallets = [] + Dir.glob("#{@config.wallet_dir}/*.mpw").each do |f| + wallet = File.basename(f, '.mpw') + wallet += ' *'.green if wallet == @config.default_wallet + wallets << wallet + end + + table_list('wallets', wallets) + end + + # Display the wallet + # @args: wallet -> the wallet name + def get_wallet(wallet = nil) + @wallet_file = + if wallet.to_s.empty? + wallets = Dir.glob("#{@config.wallet_dir}/*.mpw") + + if wallets.length == 1 + wallets[0] + elsif !@config.default_wallet.to_s.empty? + "#{@config.wallet_dir}/#{@config.default_wallet}.mpw" + else + "#{@config.wallet_dir}/default.mpw" end else - puts @mpw.get_password(item.id) + "#{@config.wallet_dir}/#{wallet}.mpw" + end + end + + # Add a new public key + # args: key -> the key name or key file to add + def add_key(key) + @mpw.add_key(key) + @mpw.write_data + + puts I18n.t('form.add_key.valid').to_s.green + rescue => e + puts "#{I18n.t('display.error')} #13: #{e}".red + end + + # Add new public key + # args: key -> the key name to delete + def delete_key(key) + @mpw.delete_key(key) + @mpw.write_data + + puts I18n.t('form.delete_key.valid').to_s.green + rescue => e + puts "#{I18n.t('display.error')} #15: #{e}".red + end + + # Text editor interface + # @args: template -> template name + # item -> the item to edit + # password -> disable field password + def text_editor(template_name, item = nil, password = false) + editor = ENV['EDITOR'] || 'nano' + options = {} + opts = {} + template_file = "#{File.expand_path('../../../templates', __FILE__)}/#{template_name}.erb" + template = ERB.new(IO.read(template_file)) + + Dir.mktmpdir do |dir| + tmp_file = "#{dir}/#{template_name}.yml" + + File.open(tmp_file, 'w') do |f| + f << template.result(binding) end - when 'o', 'otp' - if clipboard - Clipboard.copy(@mpw.get_otp_code(item.id)) - else - puts @mpw.get_otp_code(item.id) - end - puts I18n.t('form.clipboard.otp', time: @mpw.get_otp_remaining_time).yellow + system("#{editor} #{tmp_file}") - else - puts "----- #{I18n.t('form.clipboard.help.name')} -----".cyan - puts I18n.t('form.clipboard.help.login') - puts I18n.t('form.clipboard.help.password') - puts I18n.t('form.clipboard.help.otp_code') - puts I18n.t('form.clipboard.help.quit') - next - end - end - - Clipboard.clear - rescue SystemExit, Interrupt - Clipboard.clear - end - - # List all wallets - def list_wallet - wallets = [] - Dir.glob("#{@config.wallet_dir}/*.mpw").each do |f| - wallet = File.basename(f, '.mpw') - wallet += ' *'.green if wallet == @config.default_wallet - wallets << wallet - end - - table_list('wallets', wallets) - end - - # Display the wallet - # @args: wallet -> the wallet name - def get_wallet(wallet = nil) - @wallet_file = - if wallet.to_s.empty? - wallets = Dir.glob("#{@config.wallet_dir}/*.mpw") - - if wallets.length == 1 - wallets[0] - elsif !@config.default_wallet.to_s.empty? - "#{@config.wallet_dir}/#{@config.default_wallet}.mpw" - else - "#{@config.wallet_dir}/default.mpw" - end - else - "#{@config.wallet_dir}/#{wallet}.mpw" - end - end - - # Add a new public key - # args: key -> the key name or key file to add - def add_key(key) - @mpw.add_key(key) - @mpw.write_data - - puts I18n.t('form.add_key.valid').to_s.green - rescue => e - puts "#{I18n.t('display.error')} #13: #{e}".red - end - - # Add new public key - # args: key -> the key name to delete - def delete_key(key) - @mpw.delete_key(key) - @mpw.write_data - - puts I18n.t('form.delete_key.valid').to_s.green - rescue => e - puts "#{I18n.t('display.error')} #15: #{e}".red - end - - # Text editor interface - # @args: template -> template name - # item -> the item to edit - # password -> disable field password - def text_editor(template_name, item = nil, password = false) - editor = ENV['EDITOR'] || 'nano' - options = {} - opts = {} - template_file = "#{File.expand_path('../../../templates', __FILE__)}/#{template_name}.erb" - template = ERB.new(IO.read(template_file)) - - Dir.mktmpdir do |dir| - tmp_file = "#{dir}/#{template_name}.yml" - - File.open(tmp_file, 'w') do |f| - f << template.result(binding) + opts = YAML.load_file(tmp_file) end - system("#{editor} #{tmp_file}") + opts.delete_if { |_, v| v.to_s.empty? } - opts = YAML.load_file(tmp_file) + opts.each do |k, v| + options[k.to_sym] = v + end + + options end - opts.delete_if { |_, v| v.to_s.empty? } - - opts.each do |k, v| - options[k.to_sym] = v - end - - options - end - - # Form to add a new item - # @args: password -> generate a random password - def add(password = false) - options = text_editor('add_form', nil, password) - item = Item.new(options) - options[:password] = MPW.password(@config.password) if password - - @mpw.add(item) - @mpw.set_password(item.id, options[:password]) if options.key?(:password) - @mpw.set_otp_key(item.id, options[:otp_key]) if options.key?(:otp_key) - @mpw.write_data - - puts I18n.t('form.add_item.valid').to_s.green - rescue => e - puts "#{I18n.t('display.error')} #13: #{e}".red - end - - # Update an item - # @args: password -> generate a random password - # options -> the option to search - def update(password = false, **options) - items = @mpw.list(options) - - if items.empty? - puts "#{I18n.t('display.warning')}: #{I18n.t('warning.select')}".yellow - else - table_items(items) if items.length > 1 - - item = get_item(items) - options = text_editor('update_form', item, password) + # Form to add a new item + # @args: password -> generate a random password + def add(password = false) + options = text_editor('add_form', nil, password) + item = Item.new(options) options[:password] = MPW.password(@config.password) if password - item.update(options) + @mpw.add(item) @mpw.set_password(item.id, options[:password]) if options.key?(:password) @mpw.set_otp_key(item.id, options[:otp_key]) if options.key?(:otp_key) @mpw.write_data - puts I18n.t('form.update_item.valid').to_s.green + puts I18n.t('form.add_item.valid').to_s.green + rescue => e + puts "#{I18n.t('display.error')} #13: #{e}".red end - rescue => e - puts "#{I18n.t('display.error')} #14: #{e}".red - end - # Remove an item - # @args: options -> the option to search - def delete(**options) - items = @mpw.list(options) + # Update an item + # @args: password -> generate a random password + # options -> the option to search + def update(password = false, **options) + items = @mpw.list(options) - if items.empty? - puts "#{I18n.t('display.warning')}: #{I18n.t('warning.select')}".yellow - else - table_items(items) + if items.empty? + puts "#{I18n.t('display.warning')}: #{I18n.t('warning.select')}".yellow + else + table_items(items) if items.length > 1 - item = get_item(items) - confirm = ask("#{I18n.t('form.delete_item.ask')} (y/N) ").to_s + item = get_item(items) + options = text_editor('update_form', item, password) + options[:password] = MPW.password(@config.password) if password - return unless confirm =~ /^(y|yes|YES|Yes|Y)$/ + item.update(options) + @mpw.set_password(item.id, options[:password]) if options.key?(:password) + @mpw.set_otp_key(item.id, options[:otp_key]) if options.key?(:otp_key) + @mpw.write_data + + puts I18n.t('form.update_item.valid').to_s.green + end + rescue => e + puts "#{I18n.t('display.error')} #14: #{e}".red + end + + # Remove an item + # @args: options -> the option to search + def delete(**options) + items = @mpw.list(options) + + if items.empty? + puts "#{I18n.t('display.warning')}: #{I18n.t('warning.select')}".yellow + else + table_items(items) + + item = get_item(items) + confirm = ask("#{I18n.t('form.delete_item.ask')} (y/N) ").to_s + + return unless confirm =~ /^(y|yes|YES|Yes|Y)$/ + + item.delete + @mpw.write_data + + puts I18n.t('form.delete_item.valid').to_s.green + end + rescue => e + puts "#{I18n.t('display.error')} #16: #{e}".red + end + + # Copy a password, otp, login + # @args: clipboard -> enable clipboard + # options -> the option to search + def copy(clipboard = true, **options) + items = @mpw.list(options) + + if items.empty? + puts I18n.t('display.nothing') + else + table_items(items) + + item = get_item(items) + clipboard(item, clipboard) + end + rescue => e + puts "#{I18n.t('display.error')} #14: #{e}".red + end + + # Export the items in a CSV file + # @args: file -> the destination file + # options -> option to search + def export(file, options) + file = 'export-mpw.yml' if file.to_s.empty? + items = @mpw.list(options) + data = {} + + items.each do |item| + data.merge!( + item.id => { + 'host' => item.host, + 'user' => item.user, + 'group' => item.group, + 'password' => @mpw.get_password(item.id), + 'protocol' => item.protocol, + 'port' => item.port, + 'otp_key' => @mpw.get_otp_key(item.id), + 'comment' => item.comment, + 'last_edit' => item.last_edit, + 'created' => item.created, + } + ) + end + + File.open(file, 'w') { |f| f << data.to_yaml } + + puts I18n.t('form.export.valid', file: file).to_s.green + rescue => e + puts "#{I18n.t('display.error')} #17: #{e}".red + end + + # Import items from a YAML file + # @args: file -> the import file + def import(file) + raise I18n.t('form.import.file_empty') if file.to_s.empty? + raise I18n.t('form.import.file_not_exist') unless File.exist?(file) + + YAML.load_file(file).each_value do |row| + item = Item.new(group: row['group'], + host: row['host'], + protocol: row['protocol'], + user: row['user'], + port: row['port'], + comment: row['comment']) + + next if item.empty? + + @mpw.add(item) + @mpw.set_password(item.id, row['password']) unless row['password'].to_s.empty? + @mpw.set_otp_key(item.id, row['otp_key']) unless row['otp_key'].to_s.empty? + end - item.delete @mpw.write_data - puts I18n.t('form.delete_item.valid').to_s.green + puts I18n.t('form.import.valid').to_s.green + rescue => e + puts "#{I18n.t('display.error')} #18: #{e}".red end - rescue => e - puts "#{I18n.t('display.error')} #16: #{e}".red - end - - # Copy a password, otp, login - # @args: clipboard -> enable clipboard - # options -> the option to search - def copy(clipboard = true, **options) - items = @mpw.list(options) - - if items.empty? - puts I18n.t('display.nothing') - else - table_items(items) - - item = get_item(items) - clipboard(item, clipboard) - end - rescue => e - puts "#{I18n.t('display.error')} #14: #{e}".red - end - - # Export the items in a CSV file - # @args: file -> the destination file - # options -> option to search - def export(file, options) - file = 'export-mpw.yml' if file.to_s.empty? - items = @mpw.list(options) - data = {} - - items.each do |item| - data.merge!( - item.id => { - 'host' => item.host, - 'user' => item.user, - 'group' => item.group, - 'password' => @mpw.get_password(item.id), - 'protocol' => item.protocol, - 'port' => item.port, - 'otp_key' => @mpw.get_otp_key(item.id), - 'comment' => item.comment, - 'last_edit' => item.last_edit, - 'created' => item.created, - } - ) - end - - File.open(file, 'w') { |f| f << data.to_yaml } - - puts I18n.t('form.export.valid', file: file).to_s.green - rescue => e - puts "#{I18n.t('display.error')} #17: #{e}".red - end - - # Import items from a YAML file - # @args: file -> the import file - def import(file) - raise I18n.t('form.import.file_empty') if file.to_s.empty? - raise I18n.t('form.import.file_not_exist') unless File.exist?(file) - - YAML.load_file(file).each_value do |row| - item = Item.new(group: row['group'], - host: row['host'], - protocol: row['protocol'], - user: row['user'], - port: row['port'], - comment: row['comment']) - - next if item.empty? - - @mpw.add(item) - @mpw.set_password(item.id, row['password']) unless row['password'].to_s.empty? - @mpw.set_otp_key(item.id, row['otp_key']) unless row['otp_key'].to_s.empty? - end - - @mpw.write_data - - puts I18n.t('form.import.valid').to_s.green - rescue => e - puts "#{I18n.t('display.error')} #18: #{e}".red end end -end diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index d691559..3b88b0a 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -22,133 +22,133 @@ require 'i18n' require 'fileutils' module MPW -class Config - attr_accessor :error_msg + class Config + attr_accessor :error_msg - attr_accessor :gpg_key - attr_accessor :lang - attr_accessor :config_dir - attr_accessor :default_wallet - attr_accessor :wallet_dir - attr_accessor :gpg_exe - attr_accessor :password + attr_accessor :gpg_key + attr_accessor :lang + attr_accessor :config_dir + attr_accessor :default_wallet + attr_accessor :wallet_dir + attr_accessor :gpg_exe + attr_accessor :password - # Constructor - # @args: config_file -> the specify config file - def initialize(config_file = nil) - @config_file = config_file + # Constructor + # @args: config_file -> the specify config file + def initialize(config_file = nil) + @config_file = config_file - @config_dir = - if /darwin/ =~ RUBY_PLATFORM - "#{Dir.home}/Library/Preferences/mpw" - elsif /cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM - "#{Dir.home}/AppData/Local/mpw" - else - "#{Dir.home}/.config/mpw" + @config_dir = + if /darwin/ =~ RUBY_PLATFORM + "#{Dir.home}/Library/Preferences/mpw" + elsif /cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM + "#{Dir.home}/AppData/Local/mpw" + else + "#{Dir.home}/.config/mpw" + end + + @config_file = "#{@config_dir}/mpw.cfg" if @config_file.nil? || @config_file.empty? + end + + # Create a new config file + # @args: options -> hash with values + # @rtrn: true if le config file is create + def setup(options) + gpg_key = options[:gpg_key] || @gpg_key + lang = options[:lang] || @lang + wallet_dir = options[:wallet_dir] || @wallet_dir + default_wallet = options[:default_wallet] || @default_wallet + gpg_exe = options[:gpg_exe] || @gpg_exe + password = { numeric: true, + alpha: true, + special: false, + length: 16 } + + %w(numeric special alpha length).each do |k| + if options.key?("pwd_#{k}".to_sym) + password[k.to_sym] = options["pwd_#{k}".to_sym] + elsif !@password.nil? && @password.key?(k.to_sym) + password[k.to_sym] = @password[k.to_sym] + end end - @config_file = "#{@config_dir}/mpw.cfg" if @config_file.nil? || @config_file.empty? - end - - # Create a new config file - # @args: options -> hash with values - # @rtrn: true if le config file is create - def setup(options) - gpg_key = options[:gpg_key] || @gpg_key - lang = options[:lang] || @lang - wallet_dir = options[:wallet_dir] || @wallet_dir - default_wallet = options[:default_wallet] || @default_wallet - gpg_exe = options[:gpg_exe] || @gpg_exe - password = { numeric: true, - alpha: true, - special: false, - length: 16 } - - %w(numeric special alpha length).each do |k| - if options.key?("pwd_#{k}".to_sym) - password[k.to_sym] = options["pwd_#{k}".to_sym] - elsif !@password.nil? && @password.key?(k.to_sym) - password[k.to_sym] = @password[k.to_sym] + unless gpg_key =~ /[a-zA-Z0-9.-_]+\@[a-zA-Z0-9]+\.[a-zA-Z]+/ + raise I18n.t('error.config.key_bad_format') end + + wallet_dir = "#{@config_dir}/wallets" if wallet_dir.to_s.empty? + config = { 'gpg_key' => gpg_key, + 'lang' => lang, + 'wallet_dir' => wallet_dir, + 'default_wallet' => default_wallet, + 'gpg_exe' => gpg_exe, + 'password' => password } + + FileUtils.mkdir_p(@config_dir, mode: 0700) + FileUtils.mkdir_p(wallet_dir, mode: 0700) + + File.open(@config_file, 'w') do |file| + file << config.to_yaml + end + rescue => e + raise "#{I18n.t('error.config.write')}\n#{e}" end - unless gpg_key =~ /[a-zA-Z0-9.-_]+\@[a-zA-Z0-9]+\.[a-zA-Z]+/ - raise I18n.t('error.config.key_bad_format') + # Setup a new gpg key + # @args: password -> the GPG key password + # name -> the name of user + # length -> length of the GPG key + # expire -> the time of expire to GPG key + # @rtrn: true if the GPG key is create, else false + def setup_gpg_key(password, name, length = 4096, expire = 0) + raise I18n.t('error.config.genkey_gpg.name') if name.to_s.empty? + raise I18n.t('error.config.genkey_gpg.password') if password.to_s.empty? + + param = '' + param << '<GnupgKeyParms format="internal">' + "\n" + param << "Key-Type: RSA\n" + param << "Key-Length: #{length}\n" + param << "Subkey-Type: ELG-E\n" + param << "Subkey-Length: #{length}\n" + param << "Name-Real: #{name}\n" + param << "Name-Comment: #{name}\n" + param << "Name-Email: #{@gpg_key}\n" + param << "Expire-Date: #{expire}\n" + param << "Passphrase: #{password}\n" + param << "</GnupgKeyParms>\n" + + ctx = GPGME::Ctx.new + ctx.genkey(param, nil, nil) + rescue => e + raise "#{I18n.t('error.config.genkey_gpg.exception')}\n#{e}" end - wallet_dir = "#{@config_dir}/wallets" if wallet_dir.to_s.empty? - config = { 'gpg_key' => gpg_key, - 'lang' => lang, - 'wallet_dir' => wallet_dir, - 'default_wallet' => default_wallet, - 'gpg_exe' => gpg_exe, - 'password' => password } + # Load the config file + def load_config + config = YAML.load_file(@config_file) + @gpg_key = config['gpg_key'] + @lang = config['lang'] + @wallet_dir = config['wallet_dir'] + @default_wallet = config['default_wallet'] + @gpg_exe = config['gpg_exe'] + @password = config['password'] || {} - FileUtils.mkdir_p(@config_dir, mode: 0700) - FileUtils.mkdir_p(wallet_dir, mode: 0700) + raise if @gpg_key.empty? || @wallet_dir.empty? - File.open(@config_file, 'w') do |file| - file << config.to_yaml - end - rescue => e - raise "#{I18n.t('error.config.write')}\n#{e}" - end - - # Setup a new gpg key - # @args: password -> the GPG key password - # name -> the name of user - # length -> length of the GPG key - # expire -> the time of expire to GPG key - # @rtrn: true if the GPG key is create, else false - def setup_gpg_key(password, name, length = 4096, expire = 0) - raise I18n.t('error.config.genkey_gpg.name') if name.to_s.empty? - raise I18n.t('error.config.genkey_gpg.password') if password.to_s.empty? - - param = '' - param << '<GnupgKeyParms format="internal">' + "\n" - param << "Key-Type: RSA\n" - param << "Key-Length: #{length}\n" - param << "Subkey-Type: ELG-E\n" - param << "Subkey-Length: #{length}\n" - param << "Name-Real: #{name}\n" - param << "Name-Comment: #{name}\n" - param << "Name-Email: #{@gpg_key}\n" - param << "Expire-Date: #{expire}\n" - param << "Passphrase: #{password}\n" - param << "</GnupgKeyParms>\n" - - ctx = GPGME::Ctx.new - ctx.genkey(param, nil, nil) - rescue => e - raise "#{I18n.t('error.config.genkey_gpg.exception')}\n#{e}" - end - - # Load the config file - def load_config - config = YAML.load_file(@config_file) - @gpg_key = config['gpg_key'] - @lang = config['lang'] - @wallet_dir = config['wallet_dir'] - @default_wallet = config['default_wallet'] - @gpg_exe = config['gpg_exe'] - @password = config['password'] || {} - - raise if @gpg_key.empty? || @wallet_dir.empty? - - I18n.locale = @lang.to_sym - rescue => e - raise "#{I18n.t('error.config.load')}\n#{e}" - end - - # Check if private key exist - # @rtrn: true if the key exist, else false - def check_gpg_key? - ctx = GPGME::Ctx.new - ctx.each_key(@gpg_key, true) do - return true + I18n.locale = @lang.to_sym + rescue => e + raise "#{I18n.t('error.config.load')}\n#{e}" end - false + # Check if private key exist + # @rtrn: true if the key exist, else false + def check_gpg_key? + ctx = GPGME::Ctx.new + ctx.each_key(@gpg_key, true) do + return true + end + + false + end end end -end diff --git a/lib/mpw/item.rb b/lib/mpw/item.rb index cd24168..8b4b867 100644 --- a/lib/mpw/item.rb +++ b/lib/mpw/item.rb @@ -19,84 +19,84 @@ require 'i18n' module MPW -class Item - attr_accessor :id - attr_accessor :group - attr_accessor :host - attr_accessor :protocol - attr_accessor :user - attr_accessor :port - attr_accessor :otp - attr_accessor :comment - attr_accessor :last_edit - attr_accessor :created + class Item + attr_accessor :id + attr_accessor :group + attr_accessor :host + attr_accessor :protocol + attr_accessor :user + attr_accessor :port + attr_accessor :otp + attr_accessor :comment + attr_accessor :last_edit + attr_accessor :created - # Constructor - # Create a new item - # @args: options -> a hash of parameter - # raise an error if the hash hasn't the key name - def initialize(**options) - if !options.key?(:host) || options[:host].to_s.empty? - raise I18n.t('error.update.host_empty') + # Constructor + # Create a new item + # @args: options -> a hash of parameter + # raise an error if the hash hasn't the key name + def initialize(**options) + if !options.key?(:host) || options[:host].to_s.empty? + raise I18n.t('error.update.host_empty') + end + + if !options.key?(:id) || options[:id].to_s.empty? || !options.key?(:created) || options[:created].to_s.empty? + @id = generate_id + @created = Time.now.to_i + else + @id = options[:id] + @created = options[:created] + @last_edit = options[:last_edit] + options[:no_update_last_edit] = true + end + + update(options) end - if !options.key?(:id) || options[:id].to_s.empty? || !options.key?(:created) || options[:created].to_s.empty? - @id = generate_id - @created = Time.now.to_i - else - @id = options[:id] - @created = options[:created] - @last_edit = options[:last_edit] - options[:no_update_last_edit] = true + # Update the item + # @args: options -> a hash of parameter + def update(**options) + if options.key?(:host) && options[:host].to_s.empty? + raise I18n.t('error.update.host_empty') + end + + @group = options[:group] if options.key?(:group) + @host = options[:host] if options.key?(:host) + @protocol = options[:protocol] if options.key?(:protocol) + @user = options[:user] if options.key?(:user) + @port = options[:port].to_i if options.key?(:port) && !options[:port].to_s.empty? + @otp = options[:otp] if options.key?(:otp) + @comment = options[:comment] if options.key?(:comment) + @last_edit = Time.now.to_i unless options.key?(:no_update_last_edit) end - update(options) - end - - # Update the item - # @args: options -> a hash of parameter - def update(**options) - if options.key?(:host) && options[:host].to_s.empty? - raise I18n.t('error.update.host_empty') + # Delete all data + def delete + @id = nil + @group = nil + @host = nil + @protocol = nil + @user = nil + @port = nil + @otp = nil + @comment = nil + @created = nil + @last_edit = nil end - @group = options[:group] if options.key?(:group) - @host = options[:host] if options.key?(:host) - @protocol = options[:protocol] if options.key?(:protocol) - @user = options[:user] if options.key?(:user) - @port = options[:port].to_i if options.key?(:port) && !options[:port].to_s.empty? - @otp = options[:otp] if options.key?(:otp) - @comment = options[:comment] if options.key?(:comment) - @last_edit = Time.now.to_i unless options.key?(:no_update_last_edit) - end + def empty? + @id.to_s.empty? + end - # Delete all data - def delete - @id = nil - @group = nil - @host = nil - @protocol = nil - @user = nil - @port = nil - @otp = nil - @comment = nil - @created = nil - @last_edit = nil - end + def nil? + false + end - def empty? - @id.to_s.empty? - end + private - def nil? - false - end - - private - - # Generate an random id - def generate_id - [*('A'..'Z'), *('a'..'z'), *('0'..'9')].sample(16).join + # Generate an random id + def generate_id + [*('A'..'Z'), *('a'..'z'), *('0'..'9')].sample(16).join + end end end -end diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index daf04ff..8389be9 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -24,341 +24,341 @@ require 'rotp' require 'mpw/item' module MPW -class MPW - # Constructor - def initialize(key, wallet_file, gpg_pass = nil, gpg_exe = nil) - @key = key - @gpg_pass = gpg_pass - @gpg_exe = gpg_exe - @wallet_file = wallet_file + class MPW + # Constructor + def initialize(key, wallet_file, gpg_pass = nil, gpg_exe = nil) + @key = key + @gpg_pass = gpg_pass + @gpg_exe = gpg_exe + @wallet_file = wallet_file - GPGME::Engine.set_info(GPGME::PROTOCOL_OpenPGP, @gpg_exe, "#{Dir.home}/.gnupg") unless @gpg_exe.to_s.empty? - end - - # Read mpw file - def read_data - @config = {} - @data = [] - @keys = {} - @passwords = {} - @otp_keys = {} - - data = nil - - return unless File.exist?(@wallet_file) - - Gem::Package::TarReader.new(File.open(@wallet_file)) do |tar| - tar.each do |f| - case f.full_name - when 'wallet/config.gpg' - @config = YAML.safe_load(decrypt(f.read)) - - when 'wallet/meta.gpg' - data = decrypt(f.read) - - when %r{^wallet/keys/(?<key>.+)\.pub$} - key = Regexp.last_match('key') - - if GPGME::Key.find(:public, key).empty? - GPGME::Key.import(f.read, armor: true) - end - - @keys[key] = f.read - - when %r{^wallet/passwords/(?<id>[a-zA-Z0-9]+)\.gpg$} - @passwords[Regexp.last_match('id')] = f.read - - when %r{^wallet/otp_keys/(?<id>[a-zA-Z0-9]+)\.gpg$} - @otp_keys[Regexp.last_match('id')] = f.read - - else - next - end - end + GPGME::Engine.set_info(GPGME::PROTOCOL_OpenPGP, @gpg_exe, "#{Dir.home}/.gnupg") unless @gpg_exe.to_s.empty? end - unless data.to_s.empty? - YAML.safe_load(data).each_value do |d| - @data.push( - Item.new( - id: d['id'], - group: d['group'], - host: d['host'], - protocol: d['protocol'], - user: d['user'], - port: d['port'], - otp: @otp_keys.key?(d['id']), - comment: d['comment'], - last_edit: d['last_edit'], - created: d['created'], + # Read mpw file + def read_data + @config = {} + @data = [] + @keys = {} + @passwords = {} + @otp_keys = {} + + data = nil + + return unless File.exist?(@wallet_file) + + Gem::Package::TarReader.new(File.open(@wallet_file)) do |tar| + tar.each do |f| + case f.full_name + when 'wallet/config.gpg' + @config = YAML.safe_load(decrypt(f.read)) + + when 'wallet/meta.gpg' + data = decrypt(f.read) + + when %r{^wallet/keys/(?<key>.+)\.pub$} + key = Regexp.last_match('key') + + if GPGME::Key.find(:public, key).empty? + GPGME::Key.import(f.read, armor: true) + end + + @keys[key] = f.read + + when %r{^wallet/passwords/(?<id>[a-zA-Z0-9]+)\.gpg$} + @passwords[Regexp.last_match('id')] = f.read + + when %r{^wallet/otp_keys/(?<id>[a-zA-Z0-9]+)\.gpg$} + @otp_keys[Regexp.last_match('id')] = f.read + + else + next + end + end + end + + unless data.to_s.empty? + YAML.safe_load(data).each_value do |d| + @data.push( + Item.new( + id: d['id'], + group: d['group'], + host: d['host'], + protocol: d['protocol'], + user: d['user'], + port: d['port'], + otp: @otp_keys.key?(d['id']), + comment: d['comment'], + last_edit: d['last_edit'], + created: d['created'], + ) ) + end + end + + add_key(@key) if @keys[@key].nil? + rescue => e + raise "#{I18n.t('error.mpw_file.read_data')}\n#{e}" + end + + # Encrypt a file + def write_data + data = {} + tmp_file = "#{@wallet_file}.tmp" + + @data.each do |item| + next if item.empty? + + data.merge!( + item.id => { + 'id' => item.id, + 'group' => item.group, + 'host' => item.host, + 'protocol' => item.protocol, + 'user' => item.user, + 'port' => item.port, + 'comment' => item.comment, + 'last_edit' => item.last_edit, + 'created' => item.created, + } ) end - end - add_key(@key) if @keys[@key].nil? - rescue => e - raise "#{I18n.t('error.mpw_file.read_data')}\n#{e}" - end + @config['last_update'] = Time.now.to_i - # Encrypt a file - def write_data - data = {} - tmp_file = "#{@wallet_file}.tmp" + Gem::Package::TarWriter.new(File.open(tmp_file, 'w+')) do |tar| + data_encrypt = encrypt(data.to_yaml) + tar.add_file_simple('wallet/meta.gpg', 0400, data_encrypt.length) do |io| + io.write(data_encrypt) + end - @data.each do |item| - next if item.empty? + config = encrypt(@config.to_yaml) + tar.add_file_simple('wallet/config.gpg', 0400, config.length) do |io| + io.write(config) + end - data.merge!( - item.id => { - 'id' => item.id, - 'group' => item.group, - 'host' => item.host, - 'protocol' => item.protocol, - 'user' => item.user, - 'port' => item.port, - 'comment' => item.comment, - 'last_edit' => item.last_edit, - 'created' => item.created, - } - ) - end + @passwords.each do |id, password| + tar.add_file_simple("wallet/passwords/#{id}.gpg", 0400, password.length) do |io| + io.write(password) + end + end - @config['last_update'] = Time.now.to_i + @otp_keys.each do |id, key| + tar.add_file_simple("wallet/otp_keys/#{id}.gpg", 0400, key.length) do |io| + io.write(key) + end + end - Gem::Package::TarWriter.new(File.open(tmp_file, 'w+')) do |tar| - data_encrypt = encrypt(data.to_yaml) - tar.add_file_simple('wallet/meta.gpg', 0400, data_encrypt.length) do |io| - io.write(data_encrypt) - end - - config = encrypt(@config.to_yaml) - tar.add_file_simple('wallet/config.gpg', 0400, config.length) do |io| - io.write(config) - end - - @passwords.each do |id, password| - tar.add_file_simple("wallet/passwords/#{id}.gpg", 0400, password.length) do |io| - io.write(password) + @keys.each do |id, key| + tar.add_file_simple("wallet/keys/#{id}.pub", 0400, key.length) do |io| + io.write(key) + end end end - @otp_keys.each do |id, key| - tar.add_file_simple("wallet/otp_keys/#{id}.gpg", 0400, key.length) do |io| - io.write(key) - end - end + File.rename(tmp_file, @wallet_file) + rescue => e + File.unlink(tmp_file) if File.exist?(tmp_file) - @keys.each do |id, key| - tar.add_file_simple("wallet/keys/#{id}.pub", 0400, key.length) do |io| - io.write(key) - end - end + raise "#{I18n.t('error.mpw_file.write_data')}\n#{e}" end - File.rename(tmp_file, @wallet_file) - rescue => e - File.unlink(tmp_file) if File.exist?(tmp_file) + # Get a password + # args: id -> the item id + def get_password(id) + password = decrypt(@passwords[id]) - raise "#{I18n.t('error.mpw_file.write_data')}\n#{e}" - end - - # Get a password - # args: id -> the item id - def get_password(id) - password = decrypt(@passwords[id]) - - if /^\$[a-zA-Z0-9]{4,9}::(?<password>.+)$/ =~ password - Regexp.last_match('password') - else - password - end - end - - # Set a password - # args: id -> the item id - # password -> the new password - def set_password(id, password) - salt = MPW.password(length: Random.rand(4..9)) - password = "$#{salt}::#{password}" - - @passwords[id] = encrypt(password) - end - - # Return the list of all gpg keys - # rtrn: an array with the gpg keys name - def list_keys - @keys.keys - end - - # Add a public key - # args: key -> new public key file or name - def add_key(key) - if File.exist?(key) - data = File.open(key).read - key_import = GPGME::Key.import(data, armor: true) - key = GPGME::Key.get(key_import.imports[0].fpr).uids[0].email - else - data = GPGME::Key.export(key, armor: true).read - end - - raise I18n.t('error.export_key') if data.to_s.empty? - - @keys[key] = data - @passwords.each_key { |id| set_password(id, get_password(id)) } - @otp_keys.each_key { |id| set_otp_key(id, get_otp_key(id)) } - end - - # Delete a public key - # args: key -> public key to delete - def delete_key(key) - @keys.delete(key) - @passwords.each_key { |id| set_password(id, get_password(id)) } - @otp_keys.each_key { |id| set_otp_key(id, get_otp_key(id)) } - end - - # Set config - # args: config -> a hash with config options - def set_config(**options) - @config = {} if @config.nil? - - @config['protocol'] = options[:protocol] if options.key?(:protocol) - @config['host'] = options[:host] if options.key?(:host) - @config['port'] = options[:port] if options.key?(:port) - @config['user'] = options[:user] if options.key?(:user) - @config['password'] = options[:password] if options.key?(:password) - @config['path'] = options[:path] if options.key?(:path) - end - - # Add a new item - # @args: item -> Object MPW::Item - def add(item) - raise I18n.t('error.bad_class') unless item.instance_of?(Item) - raise I18n.t('error.empty') if item.empty? - - @data.push(item) - end - - # Search in some csv data - # @args: options -> a hash with paramaters - # @rtrn: a list with the resultat of the search - def list(**options) - result = [] - - search = options[:pattern].to_s.downcase - group = options[:group].to_s.downcase - - @data.each do |item| - next if item.empty? - next unless group.empty? || group.eql?(item.group.to_s.downcase) - - host = item.host.to_s.downcase - comment = item.comment.to_s.downcase - - next unless host =~ /^.*#{search}.*$/ || comment =~ /^.*#{search}.*$/ - - result.push(item) - end - - result - end - - # Search in some csv data - # @args: id -> the id item - # @rtrn: a row with the result of the search - def search_by_id(id) - @data.each do |item| - return item if item.id == id - end - - nil - end - - # Set an opt key - # args: id -> the item id - # key -> the new key - def set_otp_key(id, key) - @otp_keys[id] = encrypt(key.to_s) unless key.to_s.empty? - end - - # Get an opt key - # args: id -> the item id - # key -> the new key - def get_otp_key(id) - @otp_keys.key?(id) ? decrypt(@otp_keys[id]) : nil - end - - # Get an otp code - # @args: id -> the item id - # @rtrn: an otp code - def get_otp_code(id) - @otp_keys.key?(id) ? 0 : ROTP::TOTP.new(decrypt(@otp_keys[id])).now - end - - # Get remaining time before expire otp code - # @rtrn: return time in seconde - def get_otp_remaining_time - (Time.now.utc.to_i / 30 + 1) * 30 - Time.now.utc.to_i - end - - # Generate a random password - # @args: options -> :length, :special, :alpha, :numeric - # @rtrn: a random string - def self.password(**options) - length = - if !options.include?(:length) || options[:length].to_i <= 0 - 8 - elsif options[:length].to_i >= 32_768 - 32_768 + if /^\$[a-zA-Z0-9]{4,9}::(?<password>.+)$/ =~ password + Regexp.last_match('password') else - options[:length].to_i + password + end + end + + # Set a password + # args: id -> the item id + # password -> the new password + def set_password(id, password) + salt = MPW.password(length: Random.rand(4..9)) + password = "$#{salt}::#{password}" + + @passwords[id] = encrypt(password) + end + + # Return the list of all gpg keys + # rtrn: an array with the gpg keys name + def list_keys + @keys.keys + end + + # Add a public key + # args: key -> new public key file or name + def add_key(key) + if File.exist?(key) + data = File.open(key).read + key_import = GPGME::Key.import(data, armor: true) + key = GPGME::Key.get(key_import.imports[0].fpr).uids[0].email + else + data = GPGME::Key.export(key, armor: true).read end - chars = [] - chars += [*('!'..'?')] - [*('0'..'9')] if options[:special] - chars += [*('A'..'Z'), *('a'..'z')] if options[:alpha] - chars += [*('0'..'9')] if options[:numeric] - chars = [*('A'..'Z'), *('a'..'z'), *('0'..'9')] if chars.empty? + raise I18n.t('error.export_key') if data.to_s.empty? - result = '' - while length > 62 - result << chars.sample(62).join - length -= 62 - end - result << chars.sample(length).join - - result - end - - private - - # Decrypt a gpg file - # @args: data -> string to decrypt - def decrypt(data) - return nil if data.to_s.empty? - - crypto = GPGME::Crypto.new(armor: true) - - crypto.decrypt(data, password: @gpg_pass).read.force_encoding('utf-8') - rescue => e - raise "#{I18n.t('error.gpg_file.decrypt')}\n#{e}" - end - - # Encrypt a file - # args: data -> string to encrypt - def encrypt(data) - recipients = [] - crypto = GPGME::Crypto.new(armor: true, always_trust: true) - - recipients.push(@key) - @keys.each_key do |key| - next if key == @key - recipients.push(key) + @keys[key] = data + @passwords.each_key { |id| set_password(id, get_password(id)) } + @otp_keys.each_key { |id| set_otp_key(id, get_otp_key(id)) } end - crypto.encrypt(data, recipients: recipients).read - rescue => e - raise "#{I18n.t('error.gpg_file.encrypt')}\n#{e}" + # Delete a public key + # args: key -> public key to delete + def delete_key(key) + @keys.delete(key) + @passwords.each_key { |id| set_password(id, get_password(id)) } + @otp_keys.each_key { |id| set_otp_key(id, get_otp_key(id)) } + end + + # Set config + # args: config -> a hash with config options + def set_config(**options) + @config = {} if @config.nil? + + @config['protocol'] = options[:protocol] if options.key?(:protocol) + @config['host'] = options[:host] if options.key?(:host) + @config['port'] = options[:port] if options.key?(:port) + @config['user'] = options[:user] if options.key?(:user) + @config['password'] = options[:password] if options.key?(:password) + @config['path'] = options[:path] if options.key?(:path) + end + + # Add a new item + # @args: item -> Object MPW::Item + def add(item) + raise I18n.t('error.bad_class') unless item.instance_of?(Item) + raise I18n.t('error.empty') if item.empty? + + @data.push(item) + end + + # Search in some csv data + # @args: options -> a hash with paramaters + # @rtrn: a list with the resultat of the search + def list(**options) + result = [] + + search = options[:pattern].to_s.downcase + group = options[:group].to_s.downcase + + @data.each do |item| + next if item.empty? + next unless group.empty? || group.eql?(item.group.to_s.downcase) + + host = item.host.to_s.downcase + comment = item.comment.to_s.downcase + + next unless host =~ /^.*#{search}.*$/ || comment =~ /^.*#{search}.*$/ + + result.push(item) + end + + result + end + + # Search in some csv data + # @args: id -> the id item + # @rtrn: a row with the result of the search + def search_by_id(id) + @data.each do |item| + return item if item.id == id + end + + nil + end + + # Set an opt key + # args: id -> the item id + # key -> the new key + def set_otp_key(id, key) + @otp_keys[id] = encrypt(key.to_s) unless key.to_s.empty? + end + + # Get an opt key + # args: id -> the item id + # key -> the new key + def get_otp_key(id) + @otp_keys.key?(id) ? decrypt(@otp_keys[id]) : nil + end + + # Get an otp code + # @args: id -> the item id + # @rtrn: an otp code + def get_otp_code(id) + @otp_keys.key?(id) ? 0 : ROTP::TOTP.new(decrypt(@otp_keys[id])).now + end + + # Get remaining time before expire otp code + # @rtrn: return time in seconde + def get_otp_remaining_time + (Time.now.utc.to_i / 30 + 1) * 30 - Time.now.utc.to_i + end + + # Generate a random password + # @args: options -> :length, :special, :alpha, :numeric + # @rtrn: a random string + def self.password(**options) + length = + if !options.include?(:length) || options[:length].to_i <= 0 + 8 + elsif options[:length].to_i >= 32_768 + 32_768 + else + options[:length].to_i + end + + chars = [] + chars += [*('!'..'?')] - [*('0'..'9')] if options[:special] + chars += [*('A'..'Z'), *('a'..'z')] if options[:alpha] + chars += [*('0'..'9')] if options[:numeric] + chars = [*('A'..'Z'), *('a'..'z'), *('0'..'9')] if chars.empty? + + result = '' + while length > 62 + result << chars.sample(62).join + length -= 62 + end + result << chars.sample(length).join + + result + end + + private + + # Decrypt a gpg file + # @args: data -> string to decrypt + def decrypt(data) + return nil if data.to_s.empty? + + crypto = GPGME::Crypto.new(armor: true) + + crypto.decrypt(data, password: @gpg_pass).read.force_encoding('utf-8') + rescue => e + raise "#{I18n.t('error.gpg_file.decrypt')}\n#{e}" + end + + # Encrypt a file + # args: data -> string to encrypt + def encrypt(data) + recipients = [] + crypto = GPGME::Crypto.new(armor: true, always_trust: true) + + recipients.push(@key) + @keys.each_key do |key| + next if key == @key + recipients.push(key) + end + + crypto.encrypt(data, recipients: recipients).read + rescue => e + raise "#{I18n.t('error.gpg_file.encrypt')}\n#{e}" + end end end -end From 7eb585726faf69eb02367f236ed524e903adf39c Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Thu, 30 Mar 2017 20:07:47 +0200 Subject: [PATCH 086/165] fix syntax on Genfile and mpw.gemspec --- Gemfile | 18 +++++++++--------- mpw.gemspec | 21 +++++++++++---------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/Gemfile b/Gemfile index a588d17..7e2d83c 100644 --- a/Gemfile +++ b/Gemfile @@ -1,10 +1,10 @@ source 'https://rubygems.org' -gem "i18n", "~> 0.7", ">= 0.7.0" -gem "gpgme", "~> 2.0", ">= 2.0.12" -gem "highline", "~> 1.7", ">= 1.7.8" -gem "locale", "~> 2.1", ">= 2.1.2" -gem "colorize", "~> 0.8", ">= 0.8.1" -gem "net-ssh", "~> 3.2", ">= 3.2.0" -gem "net-sftp", "~> 2.1", ">= 2.1.2" -gem "clipboard", "~> 1.1", ">= 1.1.1" -gem "rotp", "~> 3.1", ">= 3.1.0" +gem 'clipboard', '~> 1.1', '>= 1.1.1' +gem 'colorize', '~> 0.8', '>= 0.8.1' +gem 'gpgme', '~> 2.0', '>= 2.0.12' +gem 'highline', '~> 1.7', '>= 1.7.8' +gem 'i18n', '~> 0.7', '>= 0.7.0' +gem 'locale', '~> 2.1', '>= 2.1.2' +gem 'net-sftp', '~> 2.1', '>= 2.1.2' +gem 'net-ssh', '~> 3.2', '>= 3.2.0' +gem 'rotp', '~> 3.1', '>= 3.1.0' diff --git a/mpw.gemspec b/mpw.gemspec index 80d9344..7f687ab 100644 --- a/mpw.gemspec +++ b/mpw.gemspec @@ -1,4 +1,5 @@ # coding: utf-8 + lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) @@ -12,18 +13,18 @@ Gem::Specification.new do |spec| spec.homepage = 'https://github.com/nishiki/manage-password' spec.license = 'GPL-2.0' - spec.files = `git ls-files -z`.split("\x0") + spec.files = %x(git ls-files -z).split("\x0") spec.executables = ['mpw'] spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ['lib'] - spec.add_dependency "i18n", "~> 0.7", ">= 0.7.0" - spec.add_dependency "gpgme", "~> 2.0", ">= 2.0.12" - spec.add_dependency "highline", "~> 1.7", ">= 1.7.8" - spec.add_dependency "locale", "~> 2.1", ">= 2.1.2" - spec.add_dependency "colorize", "~> 0.8", ">= 0.8.1" - spec.add_dependency "net-ssh", "~> 3.2", ">= 3.2.0" - spec.add_dependency "net-sftp", "~> 2.1", ">= 2.1.2" - spec.add_dependency "clipboard", "~> 1.1", ">= 1.1.1" - spec.add_dependency "rotp", "~> 3.1", ">= 3.1.0" + spec.add_dependency 'i18n', '~> 0.7', '>= 0.7.0' + spec.add_dependency 'gpgme', '~> 2.0', '>= 2.0.12' + spec.add_dependency 'highline', '~> 1.7', '>= 1.7.8' + spec.add_dependency 'locale', '~> 2.1', '>= 2.1.2' + spec.add_dependency 'colorize', '~> 0.8', '>= 0.8.1' + spec.add_dependency 'net-ssh', '~> 3.2', '>= 3.2.0' + spec.add_dependency 'net-sftp', '~> 2.1', '>= 2.1.2' + spec.add_dependency 'clipboard', '~> 1.1', '>= 1.1.1' + spec.add_dependency 'rotp', '~> 3.1', '>= 3.1.0' end From 2cb8ad4dbe4806bedb64b257cd1bc45d65d85c7a Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Thu, 30 Mar 2017 20:18:49 +0200 Subject: [PATCH 087/165] add rubocop test in travis --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 1a18023..faa5c04 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,8 +7,10 @@ rvm: install: - bundle install - gem install 'test-unit' + - gem install rubocop - echo 9999 > VERSION - gem build mpw.gemspec - gem install mpw-9999.gem script: + - rubocop - ruby ./test/tests.rb From 1e688d191cd9c45e748ecaa3c7fd51f848dca727 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Thu, 30 Mar 2017 22:41:12 +0200 Subject: [PATCH 088/165] remove unused dependancies --- Gemfile | 2 -- mpw.gemspec | 2 -- 2 files changed, 4 deletions(-) diff --git a/Gemfile b/Gemfile index 7e2d83c..71d84d4 100644 --- a/Gemfile +++ b/Gemfile @@ -5,6 +5,4 @@ gem 'gpgme', '~> 2.0', '>= 2.0.12' gem 'highline', '~> 1.7', '>= 1.7.8' gem 'i18n', '~> 0.7', '>= 0.7.0' gem 'locale', '~> 2.1', '>= 2.1.2' -gem 'net-sftp', '~> 2.1', '>= 2.1.2' -gem 'net-ssh', '~> 3.2', '>= 3.2.0' gem 'rotp', '~> 3.1', '>= 3.1.0' diff --git a/mpw.gemspec b/mpw.gemspec index 7f687ab..9f27023 100644 --- a/mpw.gemspec +++ b/mpw.gemspec @@ -23,8 +23,6 @@ Gem::Specification.new do |spec| spec.add_dependency 'highline', '~> 1.7', '>= 1.7.8' spec.add_dependency 'locale', '~> 2.1', '>= 2.1.2' spec.add_dependency 'colorize', '~> 0.8', '>= 0.8.1' - spec.add_dependency 'net-ssh', '~> 3.2', '>= 3.2.0' - spec.add_dependency 'net-sftp', '~> 2.1', '>= 2.1.2' spec.add_dependency 'clipboard', '~> 1.1', '>= 1.1.1' spec.add_dependency 'rotp', '~> 3.1', '>= 3.1.0' end From 92cb89ad33083a917710cafe057d4303c8bc91eb Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Sun, 2 Apr 2017 12:14:27 +0200 Subject: [PATCH 089/165] fix gpg password with pinentry --- lib/mpw/mpw.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 8389be9..2444f12 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -339,7 +339,7 @@ module MPW crypto = GPGME::Crypto.new(armor: true) - crypto.decrypt(data, password: @gpg_pass).read.force_encoding('utf-8') + crypto.decrypt(data, password: @gpg_pass, pinentry_mode: GPGME::PINENTRY_MODE_LOOPBACK).read.force_encoding('utf-8') rescue => e raise "#{I18n.t('error.gpg_file.decrypt')}\n#{e}" end From 3543b0cf05cfc4fc177dc54a0407a21951747aac Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 2 Apr 2017 22:39:31 +0200 Subject: [PATCH 090/165] remove unused wallet config --- lib/mpw/mpw.rb | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 8389be9..c52f8db 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -37,7 +37,6 @@ module MPW # Read mpw file def read_data - @config = {} @data = [] @keys = {} @passwords = {} @@ -50,9 +49,6 @@ module MPW Gem::Package::TarReader.new(File.open(@wallet_file)) do |tar| tar.each do |f| case f.full_name - when 'wallet/config.gpg' - @config = YAML.safe_load(decrypt(f.read)) - when 'wallet/meta.gpg' data = decrypt(f.read) @@ -124,19 +120,12 @@ module MPW ) end - @config['last_update'] = Time.now.to_i - Gem::Package::TarWriter.new(File.open(tmp_file, 'w+')) do |tar| data_encrypt = encrypt(data.to_yaml) tar.add_file_simple('wallet/meta.gpg', 0400, data_encrypt.length) do |io| io.write(data_encrypt) end - config = encrypt(@config.to_yaml) - tar.add_file_simple('wallet/config.gpg', 0400, config.length) do |io| - io.write(config) - end - @passwords.each do |id, password| tar.add_file_simple("wallet/passwords/#{id}.gpg", 0400, password.length) do |io| io.write(password) @@ -217,19 +206,6 @@ module MPW @otp_keys.each_key { |id| set_otp_key(id, get_otp_key(id)) } end - # Set config - # args: config -> a hash with config options - def set_config(**options) - @config = {} if @config.nil? - - @config['protocol'] = options[:protocol] if options.key?(:protocol) - @config['host'] = options[:host] if options.key?(:host) - @config['port'] = options[:port] if options.key?(:port) - @config['user'] = options[:user] if options.key?(:user) - @config['password'] = options[:password] if options.key?(:password) - @config['path'] = options[:path] if options.key?(:path) - end - # Add a new item # @args: item -> Object MPW::Item def add(item) From d1adfd24c10ab9a4fd80cb3c08ebbfbc069bc585 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 2 Apr 2017 23:44:36 +0200 Subject: [PATCH 091/165] fix pinentry mode with gpg 1.4 --- lib/mpw/mpw.rb | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 2444f12..88cab5c 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -337,9 +337,18 @@ module MPW def decrypt(data) return nil if data.to_s.empty? - crypto = GPGME::Crypto.new(armor: true) + password = + if /^1\.[0-9.]+$/ =~ GPGME::Engine.info.first.version + { password: @gpg_pass } + else + { password: @gpg_pass, + pinentry_mode: GPGME::PINENTRY_MODE_LOOPBACK } + end - crypto.decrypt(data, password: @gpg_pass, pinentry_mode: GPGME::PINENTRY_MODE_LOOPBACK).read.force_encoding('utf-8') + crypto = GPGME::Crypto.new(armor: true) + crypto + .decrypt(data, password) + .read.force_encoding('utf-8') rescue => e raise "#{I18n.t('error.gpg_file.decrypt')}\n#{e}" end From 7ce4ba721bb039f30af6882dca9c55e748b58944 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 4 Apr 2017 23:45:03 +0200 Subject: [PATCH 092/165] add option to enable pinmode with gpg >= 2.1 --- bin/mpw-config | 6 +++++- lib/mpw/cli.rb | 2 +- lib/mpw/config.rb | 6 +++++- lib/mpw/mpw.rb | 5 +++-- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/bin/mpw-config b/bin/mpw-config index 4740ed1..1e3480d 100644 --- a/bin/mpw-config +++ b/bin/mpw-config @@ -60,6 +60,10 @@ OptionParser.new do |opts| values[:lang] = lang end + opts.on('-P', '--pinmode', I18n.t('option.pinmode')) do + values[:pinmode] = true + end + opts.on('-w', '--wallet-dir PATH', I18n.t('option.wallet_dir')) do |wallet_dir| values[:wallet_dir] = wallet_dir end @@ -94,7 +98,7 @@ OptionParser.new do |opts| end.parse! config = MPW::Config.new(options[:config]) -cli = MPW::Cli.new(config, nil) +cli = MPW::Cli.new(config) if options.key?(:init) cli.setup(values) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index d4d4027..56e77a1 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -101,7 +101,7 @@ module MPW def decrypt unless defined?(@mpw) @password = ask(I18n.t('display.gpg_password')) { |q| q.echo = false } - @mpw = MPW.new(@config.gpg_key, @wallet_file, @password, @config.gpg_exe) + @mpw = MPW.new(@config.gpg_key, @wallet_file, @password, @config.gpg_exe, @config.pinmode) end @mpw.read_data diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index 3b88b0a..829abc2 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -32,6 +32,7 @@ module MPW attr_accessor :wallet_dir attr_accessor :gpg_exe attr_accessor :password + attr_accessor :pinmode # Constructor # @args: config_file -> the specify config file @@ -59,6 +60,7 @@ module MPW wallet_dir = options[:wallet_dir] || @wallet_dir default_wallet = options[:default_wallet] || @default_wallet gpg_exe = options[:gpg_exe] || @gpg_exe + pinmode = options[:pinmode] || @pinmode password = { numeric: true, alpha: true, special: false, @@ -82,7 +84,8 @@ module MPW 'wallet_dir' => wallet_dir, 'default_wallet' => default_wallet, 'gpg_exe' => gpg_exe, - 'password' => password } + 'password' => password, + 'pinmode' => pinmode } FileUtils.mkdir_p(@config_dir, mode: 0700) FileUtils.mkdir_p(wallet_dir, mode: 0700) @@ -132,6 +135,7 @@ module MPW @default_wallet = config['default_wallet'] @gpg_exe = config['gpg_exe'] @password = config['password'] || {} + @pinmode = config['pinmode'] raise if @gpg_key.empty? || @wallet_dir.empty? diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 88cab5c..7d15b52 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -26,11 +26,12 @@ require 'mpw/item' module MPW class MPW # Constructor - def initialize(key, wallet_file, gpg_pass = nil, gpg_exe = nil) + def initialize(key, wallet_file, gpg_pass = nil, gpg_exe = nil, pinmode = false) @key = key @gpg_pass = gpg_pass @gpg_exe = gpg_exe @wallet_file = wallet_file + @pinmode = pinmode GPGME::Engine.set_info(GPGME::PROTOCOL_OpenPGP, @gpg_exe, "#{Dir.home}/.gnupg") unless @gpg_exe.to_s.empty? end @@ -338,7 +339,7 @@ module MPW return nil if data.to_s.empty? password = - if /^1\.[0-9.]+$/ =~ GPGME::Engine.info.first.version + if /^1\.[0-9.]+$/ =~ GPGME::Engine.info.first.version || @pinmode { password: @gpg_pass } else { password: @gpg_pass, From d8df357993212cc6d43148eaeb3f907f7479fa5c Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 4 Apr 2017 23:50:38 +0200 Subject: [PATCH 093/165] not use pinmode if gpg version < 2.1 --- lib/mpw/mpw.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 7d15b52..dd12ef6 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -339,7 +339,7 @@ module MPW return nil if data.to_s.empty? password = - if /^1\.[0-9.]+$/ =~ GPGME::Engine.info.first.version || @pinmode + if /^(1\.[0-9.]+|2\.0)(\.[0-9]+)?/ =~ GPGME::Engine.info.first.version || @pinmode { password: @gpg_pass } else { password: @gpg_pass, From 45ead1e24e13fda0161dab564198980ae2b57abd Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 4 Apr 2017 23:52:00 +0200 Subject: [PATCH 094/165] fix syntax for rubocop 0.48.1 --- lib/mpw/config.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index 829abc2..591b991 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -66,7 +66,7 @@ module MPW special: false, length: 16 } - %w(numeric special alpha length).each do |k| + %w[numeric special alpha length].each do |k| if options.key?("pwd_#{k}".to_sym) password[k.to_sym] = options["pwd_#{k}".to_sym] elsif !@password.nil? && @password.key?(k.to_sym) From 621819203f4025c9632f79971383c76b8c0415bf Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 5 Apr 2017 00:03:53 +0200 Subject: [PATCH 095/165] add option to disable pinmode --- bin/mpw-config | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bin/mpw-config b/bin/mpw-config index 1e3480d..67ffc50 100644 --- a/bin/mpw-config +++ b/bin/mpw-config @@ -60,10 +60,14 @@ OptionParser.new do |opts| values[:lang] = lang end - opts.on('-P', '--pinmode', I18n.t('option.pinmode')) do + opts.on('-P', '--enable-pinmode', I18n.t('option.pinmode')) do values[:pinmode] = true end + opts.on('-p', '--disable-pinmode', I18n.t('option.disable_pinmode')) do + values[:pinmode] = false + end + opts.on('-w', '--wallet-dir PATH', I18n.t('option.wallet_dir')) do |wallet_dir| values[:wallet_dir] = wallet_dir end From 3b5bb48e6ba6cdcc9ae60783a62a85440e406761 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 5 Apr 2017 00:04:15 +0200 Subject: [PATCH 096/165] add translate for pinmode options --- i18n/en.yml | 2 ++ i18n/fr.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/i18n/en.yml b/i18n/en.yml index 162f6b3..97f1928 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -49,6 +49,7 @@ en: delete_gpg_key: "Delete the wallet's share with an other GPG key" disable_alpha: "Don't use letter to generate a password" disable_numeric: "Don't use number to generate a password" + disable_pinmode: "Disable the pinentry mode" disable_special_chars: "Don't use special char to generate a password" export: "Export a wallet in an yaml file" file_export: "Specify the file where export data" @@ -68,6 +69,7 @@ en: list_keys: "List the GPG keys in wallet" numeric: "Use number to generate a password" pattern: "Given search pattern" + pinmode: "Enable pinentry mode (available with gpg >= 2.1)" random_password: "Generate a random password" setup: "Create a new configuration file" setup_wallet: "Create a new configuration file for a wallet" diff --git a/i18n/fr.yml b/i18n/fr.yml index b2e3db4..0c7319c 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -49,6 +49,7 @@ fr: delete_gpg_key: "Supprime le partage le portefeuille avec une autre clé GPG" disable_alpha: "Désactive l'utilisation des lettres dans la génération d'un mot de passe" disable_numeric: "Désactive l'utilisation des chiffre dans la génération d'un mot de passe" + disable_pinmode: "Désactive le mode pinentry" disable_special_chars: "Désactive l'utilisation des charactères speciaux dans la génération d'un mot de passe" export: "Exporte un portefeuille dans un fichier yaml" file_export: "Spécifie le fichier où exporter les données" @@ -68,6 +69,7 @@ fr: list_keys: "Liste les clés GPG dans le portefeuille" numeric: "Utilise des chiffre dans la génération d'un mot de passe" pattern: "Motif de donnée à chercher" + pinmode: "Active le mode pinentry (valable avec gpg >= 2.1)" random_password: "Génére un mot de passe aléatoire" setup: "Création d'un nouveau fichier de configuration" setup_wallet: "Création d'un nouveau fichier de configuration pour un portefeuille" From 55c07b90af363055bc2131f04030e500e2c56f72 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sat, 8 Apr 2017 10:04:43 +0200 Subject: [PATCH 097/165] minor refacto --- bin/mpw-wallet | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/bin/mpw-wallet b/bin/mpw-wallet index fffeaac..8bbffcf 100644 --- a/bin/mpw-wallet +++ b/bin/mpw-wallet @@ -66,19 +66,15 @@ cli = MPW::Cli.new(config) cli.load_config -if !options[:list].nil? +if options.key?(:list) cli.list_wallet else cli.get_wallet(options[:wallet]) cli.decrypt - if !options[:list_keys].nil? + if options.key?(:list_keys) cli.list_keys - elsif !options[:gpg_key].nil? - if options[:delete] - cli.delete_key(options[:gpg_key]) - else - cli.add_key(options[:gpg_key]) - end + elsif options.key?(:gpg_key) + options[:delete] ? cli.delete_key(options[:gpg_key]) : cli.add_key(options[:gpg_key]) end end From 25baa260e33756fc0efeb17c525e2563470c75fa Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sat, 8 Apr 2017 17:15:05 +0200 Subject: [PATCH 098/165] feat: add option to set a specific path for a wallet --- bin/mpw-wallet | 11 +++++++++++ i18n/en.yml | 4 ++++ i18n/fr.yml | 4 ++++ lib/mpw/cli.rb | 29 +++++++++++++++++++++++------ lib/mpw/config.rb | 38 ++++++++++++++++++++++++++++++++++---- 5 files changed, 76 insertions(+), 10 deletions(-) diff --git a/bin/mpw-wallet b/bin/mpw-wallet index 8bbffcf..5b3b7f9 100644 --- a/bin/mpw-wallet +++ b/bin/mpw-wallet @@ -56,6 +56,14 @@ OptionParser.new do |opts| options[:list_keys] = true end + opts.on('-p', '--path PATH', I18n.t('option.path')) do |path| + options[:path] = path + end + + opts.on('-P', '--default-path', I18n.t('option.default_path')) do + options[:path] = 'default' + end + opts.on('-w', '--wallet NAME', I18n.t('option.wallet')) do |wallet| options[:wallet] = wallet end @@ -68,6 +76,9 @@ cli.load_config if options.key?(:list) cli.list_wallet +elsif options.key?(:path) + cli.get_wallet(options[:wallet]) + cli.set_wallet_path(options[:path]) else cli.get_wallet(options[:wallet]) cli.decrypt diff --git a/i18n/en.yml b/i18n/en.yml index 97f1928..1fa2618 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -45,6 +45,7 @@ en: alpha: "Use letter to generate a password" config: "Specify the configuration file to use" clipboard: "Disable the clipboard feature" + default_path: "Move the wallet in default directory" default_wallet: "Specify the default wallet to use" delete_gpg_key: "Delete the wallet's share with an other GPG key" disable_alpha: "Don't use letter to generate a password" @@ -68,6 +69,7 @@ en: list: "List the wallets" list_keys: "List the GPG keys in wallet" numeric: "Use number to generate a password" + path: "Move the wallet in new specify directory" pattern: "Given search pattern" pinmode: "Enable pinentry mode (available with gpg >= 2.1)" random_password: "Generate a random password" @@ -120,6 +122,8 @@ en: not_valid: "No data to import!" set_config: valid: "The config file has been edited!" + set_wallet_path: + valid: "The wallet has well moved!" setup_config: title: "Setup a new config file" lang: "Choose your language (en, fr, ...) [default=%{lang}]: " diff --git a/i18n/fr.yml b/i18n/fr.yml index 0c7319c..76b07ef 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -45,6 +45,7 @@ fr: alpha: "Utilise des lettres dans la génération d'un mot de passe" config: "Spécifie le fichier de configuration à utiliser" clipboard: "Désactive la fonction presse papier" + default_path: "Déplace le portefeuille dans le dossier par défaut" default_wallet: "Spécifie le porte-feuille à utiliser par défaut" delete_gpg_key: "Supprime le partage le portefeuille avec une autre clé GPG" disable_alpha: "Désactive l'utilisation des lettres dans la génération d'un mot de passe" @@ -68,6 +69,7 @@ fr: list: "Liste les portefeuilles" list_keys: "Liste les clés GPG dans le portefeuille" numeric: "Utilise des chiffre dans la génération d'un mot de passe" + path: "Déplace le portefeuille dans un nouveau dossier" pattern: "Motif de donnée à chercher" pinmode: "Active le mode pinentry (valable avec gpg >= 2.1)" random_password: "Génére un mot de passe aléatoire" @@ -120,6 +122,8 @@ fr: not_valid: "Aucune donnée à importer!" set_config: valid: "Le fichier de configuration a bien été modifié!" + set_wallet_path: + valid: "Le portefeuille a bien été déplacé!" setup_config: title: "Création d'un nouveau fichier de configuration" lang: "Choisissez votre langue (en, fr, ...) [défaut=%{lang}]: " diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 56e77a1..23114d1 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -45,6 +45,17 @@ module MPW exit 2 end + # Change the wallet path + # @args: path -> the new path + def set_wallet_path(path) + @config.set_wallet_path(path, @wallet) + + puts I18n.t('form.set_wallet_path.valid').to_s.green + rescue => e + puts "#{I18n.t('display.error')} #19: #{e}".red + exit 2 + end + # Create a new config file # @args: options -> set param def setup(options) @@ -315,19 +326,25 @@ module MPW # Display the wallet # @args: wallet -> the wallet name def get_wallet(wallet = nil) - @wallet_file = + @wallet = if wallet.to_s.empty? wallets = Dir.glob("#{@config.wallet_dir}/*.mpw") - if wallets.length == 1 - wallets[0] + File.basename(wallets[0], '.mpw') elsif !@config.default_wallet.to_s.empty? - "#{@config.wallet_dir}/#{@config.default_wallet}.mpw" + @config.default_wallet else - "#{@config.wallet_dir}/default.mpw" + 'default' end else - "#{@config.wallet_dir}/#{wallet}.mpw" + wallet + end + + @wallet_file = + if @config.wallet_paths.key?(@wallet) + "#{@config.wallet_paths[@wallet]}/#{@wallet}.mpw" + else + "#{@config.wallet_dir}/#{@wallet}.mpw" end end diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index 591b991..fd78cf8 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -30,6 +30,7 @@ module MPW attr_accessor :config_dir attr_accessor :default_wallet attr_accessor :wallet_dir + attr_accessor :wallet_paths attr_accessor :gpg_exe attr_accessor :password attr_accessor :pinmode @@ -38,8 +39,7 @@ module MPW # @args: config_file -> the specify config file def initialize(config_file = nil) @config_file = config_file - - @config_dir = + @config_dir = if /darwin/ =~ RUBY_PLATFORM "#{Dir.home}/Library/Preferences/mpw" elsif /cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM @@ -48,7 +48,7 @@ module MPW "#{Dir.home}/.config/mpw" end - @config_file = "#{@config_dir}/mpw.cfg" if @config_file.nil? || @config_file.empty? + @config_file = "#{@config_dir}/mpw.cfg" if @config_file.to_s.empty? end # Create a new config file @@ -85,7 +85,8 @@ module MPW 'default_wallet' => default_wallet, 'gpg_exe' => gpg_exe, 'password' => password, - 'pinmode' => pinmode } + 'pinmode' => pinmode, + 'wallet_paths' => @wallet_paths } FileUtils.mkdir_p(@config_dir, mode: 0700) FileUtils.mkdir_p(wallet_dir, mode: 0700) @@ -132,6 +133,7 @@ module MPW @gpg_key = config['gpg_key'] @lang = config['lang'] @wallet_dir = config['wallet_dir'] + @wallet_paths = config['wallet_paths'] || {} @default_wallet = config['default_wallet'] @gpg_exe = config['gpg_exe'] @password = config['password'] || {} @@ -154,5 +156,33 @@ module MPW false end + + # Change the path of one wallet + # @args: path -> the new directory path + # wallet -> the wallet name + def set_wallet_path(path, wallet) + path = @wallet_dir if path == 'default' + + return if path == @wallet_dir && File.exist?("#{@wallet_dir}/#{wallet}.mpw") + return if path == @wallet_paths[wallet] + + old_wallet_file = + if @wallet_paths.key?(wallet) + "#{@wallet_paths[wallet]}/#{wallet}.mpw" + else + "#{@wallet_dir}/#{wallet}.mpw" + end + + FileUtils.mkdir_p(path) unless Dir.exist?(path) + FileUtils.mv(old_wallet_file, "#{path}/#{wallet}.mpw") if File.exist?(old_wallet_file) + + if path == @wallet_dir + @wallet_paths.delete(wallet) + else + @wallet_paths[wallet] = path + end + + setup + end end end From 18ba8967d9b634eeb8cb5f65df6e9f3f92949df0 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sat, 8 Apr 2017 17:27:56 +0200 Subject: [PATCH 099/165] add test for wallet_paths --- test/test_config.rb | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/test_config.rb b/test/test_config.rb index 2d1a51b..49af82c 100644 --- a/test/test_config.rb +++ b/test/test_config.rb @@ -61,4 +61,19 @@ class TestConfig < Test::Unit::TestCase assert(!@config.password[:numeric]) assert(@config.password[:special]) end + + def test_02_wallet_paths + new_path = '/tmp/mpw-test' + + @config = MPW::Config.new + @config.load_config + + assert(!@config.wallet_paths['default']) + + @config.set_wallet_path(new_path, 'default') + assert_equal(@config.wallet_paths['default'], new_path) + + @config.set_wallet_path('default', 'default') + assert(!@config.wallet_paths['default']) + end end From 388dc439b6baf9bfff10645a5dfad0191e5c36b5 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sat, 8 Apr 2017 17:39:51 +0200 Subject: [PATCH 100/165] fix argument in config setup --- lib/mpw/config.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index fd78cf8..fa1a825 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -54,7 +54,7 @@ module MPW # Create a new config file # @args: options -> hash with values # @rtrn: true if le config file is create - def setup(options) + def setup(**options) gpg_key = options[:gpg_key] || @gpg_key lang = options[:lang] || @lang wallet_dir = options[:wallet_dir] || @wallet_dir From b65595d0b7eea175bf20a5bce731fb9732e35d9a Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 9 Apr 2017 08:47:07 +0200 Subject: [PATCH 101/165] minor refacto --- lib/mpw/mpw.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index c6a5cf0..896339c 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -93,7 +93,7 @@ module MPW end end - add_key(@key) if @keys[@key].nil? + add_key(@key) unless @keys.key?(@key) rescue => e raise "#{I18n.t('error.mpw_file.read_data')}\n#{e}" end From 3f9d7eff3368b2042311fe54b38f8e07d18ec2d8 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 9 Apr 2017 10:08:25 +0200 Subject: [PATCH 102/165] feat: add print configuration --- bin/mpw-config | 6 +++++- i18n/en.yml | 1 + i18n/fr.yml | 1 + lib/mpw/cli.rb | 46 +++++++++++++++++++++++++++++++++++----------- 4 files changed, 42 insertions(+), 12 deletions(-) diff --git a/bin/mpw-config b/bin/mpw-config index 67ffc50..04f960b 100644 --- a/bin/mpw-config +++ b/bin/mpw-config @@ -112,5 +112,9 @@ if options.key?(:init) cli.setup_wallet_config else cli.load_config - cli.set_config(values) + if values.empty? + cli.list_config + else + cli.set_config(values) + end end diff --git a/i18n/en.yml b/i18n/en.yml index 1fa2618..5ed50c7 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -159,6 +159,7 @@ en: display: comment: "Comment" + config: "Configuration" error: "ERROR" keys: "GPG keys" gpg_password: "GPG passphrase: " diff --git a/i18n/fr.yml b/i18n/fr.yml index 76b07ef..13829a2 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -159,6 +159,7 @@ fr: display: comment: "Commentaire" + config: "Configuration" error: "ERREUR" keys: "Clés GPG" gpg_password: "Mot de passe GPG: " diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 23114d1..22b24cb 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -100,6 +100,21 @@ module MPW table_list('keys', @mpw.list_keys) end + # List config + def list_config + config = { + 'lang' => @config.lang, + 'gpg_key' => @config.gpg_key, + 'config_dir' => @config.config_dir, + 'pinmode' => @config.pinmode, + 'gpg_exe' => @config.gpg_exe + } + + @config.password.each { |k, v| config["password_#{k}"] = v } + + table_list('config', config) + end + # Load config def load_config @config.load_config @@ -122,31 +137,40 @@ module MPW end # Format list on a table + # @args: title -> the name of table + # list -> array or hash def table_list(title, list) - i = 1 - length = 0 + length = { k: 0, v: 0 } - list.each do |item| - length = item.length if length < item.length + if list.is_a?(Array) + i = 0 + list = list.map do |item| + i += 1 + [i, item] + end.to_h + end + + list.each do |k, v| + length[:k] = k.to_s.length if length[:k] < k.to_s.length + length[:v] = v.to_s.length if length[:v] < v.to_s.length end - length += 7 puts "\n#{I18n.t("display.#{title}")}".red print ' ' - length.times { print '=' } + (length[:k] + length[:v] + 5).times { print '=' } print "\n" - list.each do |item| - print " #{i}".cyan - (3 - i.to_s.length).times { print ' ' } - puts "| #{item}" - i += 1 + list.each do |k, v| + print " #{k}".cyan + (length[:k] - k.to_s.length + 1).times { print ' ' } + puts "| #{v}" end print "\n" end # Format items on a table + # @args: items -> an aray items def table_items(items = []) group = '.' i = 1 From 77bca426bca26c81dff1ccdaec9c51f247017a52 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 9 Apr 2017 11:02:07 +0200 Subject: [PATCH 103/165] add information in print config --- lib/mpw/cli.rb | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 22b24cb..6fd257f 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -103,14 +103,16 @@ module MPW # List config def list_config config = { - 'lang' => @config.lang, - 'gpg_key' => @config.gpg_key, - 'config_dir' => @config.config_dir, - 'pinmode' => @config.pinmode, - 'gpg_exe' => @config.gpg_exe + 'lang' => @config.lang, + 'gpg_key' => @config.gpg_key, + 'default_wallet' => @config.default_wallet, + 'config_dir' => @config.config_dir, + 'pinmode' => @config.pinmode, + 'gpg_exe' => @config.gpg_exe } - @config.password.each { |k, v| config["password_#{k}"] = v } + @config.wallet_paths.each { |k, v| config["path_wallet_#{k}"] = "#{v}/#{k}.mpw" } + @config.password.each { |k, v| config["password_#{k}"] = v } table_list('config', config) end From 0fdefdf4332d33e88bcfc1027addd159e70e4c45 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Thu, 13 Apr 2017 22:35:57 +0200 Subject: [PATCH 104/165] feat: add options to edit or update an item --- bin/mpw-add | 38 +++++++++++++++++++++++++++++++++-- bin/mpw-update | 42 +++++++++++++++++++++++++++++++++++---- i18n/en.yml | 8 ++++++++ i18n/fr.yml | 8 ++++++++ lib/mpw/cli.rb | 26 ++++++++++++++---------- templates/add_form.erb | 16 +++++++-------- templates/update_form.erb | 14 ++++++------- 7 files changed, 120 insertions(+), 32 deletions(-) diff --git a/bin/mpw-add b/bin/mpw-add index 6376326..20eaf7b 100644 --- a/bin/mpw-add +++ b/bin/mpw-add @@ -24,7 +24,9 @@ require 'mpw/cli' # Options # --------------------------------------------------------- # -options = {} +values = {} +options = {} +options[:text_editor] = true OptionParser.new do |opts| opts.banner = "#{I18n.t('option.usage')}: mpw add [options]" @@ -33,15 +35,47 @@ OptionParser.new do |opts| options[:config] = config end + opts.on('-C', '--comment COMMENT', I18n.t('option.comment')) do |comment| + values[:comment] = comment + end + + opts.on('-G', '--group NAME', I18n.t('option.new_group')) do |group| + values[:group] = group + end + opts.on('-h', '--help', I18n.t('option.help')) do puts opts exit 0 end + opts.on('-H', '--host HOST', I18n.t('option.host')) do |host| + values[:host] = host + end + + opts.on('-o', '--otp-code CODE', I18n.t('option.otp_code')) do |otp| + values[:otp_key] = otp + end + + opts.on('-O', '--protocol PROTOCOL', I18n.t('option.protocol')) do |protocol| + values[:protocol] = protocol + end + + opts.on('-P', '--port NUMBER', I18n.t('option.port')) do |port| + values[:port] = port + end + opts.on('-r', '--random', I18n.t('option.random_password')) do options[:password] = true end + opts.on('-t', '--text-editor', I18n.t('option.text_editor')) do + options[:text_editor] = true + end + + opts.on('-u', '--user USER', I18n.t('option.user')) do |user| + values[:user] = user + end + opts.on('-w', '--wallet NAME', I18n.t('option.wallet')) do |wallet| options[:wallet] = wallet end @@ -53,4 +87,4 @@ cli = MPW::Cli.new(config) cli.load_config cli.get_wallet(options[:wallet]) cli.decrypt -cli.add(options[:password]) +cli.add(options[:password], options[:text_editor], values) diff --git a/bin/mpw-update b/bin/mpw-update index c258330..d887ce3 100644 --- a/bin/mpw-update +++ b/bin/mpw-update @@ -24,8 +24,10 @@ require 'mpw/cli' # Options # --------------------------------------------------------- # -options = {} -values = {} +values = {} +search = {} +options = {} +options[:text_editor] = false OptionParser.new do |opts| opts.banner = "#{I18n.t('option.usage')}: mpw update [options]" @@ -34,7 +36,15 @@ OptionParser.new do |opts| options[:config] = config end + opts.on('-C', '--comment COMMENT', I18n.t('option.comment')) do |comment| + values[:comment] = comment + end + opts.on('-g', '--group NAME', I18n.t('option.group')) do |group| + search[:group] = group + end + + opts.on('-G', '--new-group NAME', I18n.t('option.new_group')) do |group| values[:group] = group end @@ -43,14 +53,38 @@ OptionParser.new do |opts| exit 0 end + opts.on('-H', '--host HOST', I18n.t('option.host')) do |host| + values[:host] = host + end + + opts.on('-o', '--otp-code CODE', I18n.t('option.otp_code')) do |otp| + values[:otp_key] = otp + end + + opts.on('-O', '--protocol PROTOCOL', I18n.t('option.protocol')) do |protocol| + values[:protocol] = protocol + end + opts.on('-p', '--pattern PATTERN', I18n.t('option.pattern')) do |pattern| - values[:pattern] = pattern + search[:pattern] = pattern + end + + opts.on('-P', '--port NUMBER', I18n.t('option.port')) do |port| + values[:port] = port end opts.on('-r', '--random', I18n.t('option.random_password')) do options[:password] = true end + opts.on('-t', '--text-editor', I18n.t('option.text_editor')) do + options[:text_editor] = true + end + + opts.on('-u', '--user USER', I18n.t('option.user')) do |user| + values[:user] = user + end + opts.on('-w', '--wallet NAME', I18n.t('option.wallet')) do |wallet| options[:wallet] = wallet end @@ -62,4 +96,4 @@ cli = MPW::Cli.new(config) cli.load_config cli.get_wallet(options[:wallet]) cli.decrypt -cli.update(options[:password], values) +cli.update(options[:password], options[:text_editor], search, values) diff --git a/i18n/en.yml b/i18n/en.yml index 5ed50c7..402facd 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -43,6 +43,7 @@ en: add: "Add an item or key" add_gpg_key: "Share the wallet with an other GPG key" alpha: "Use letter to generate a password" + comment: "Specify a comment" config: "Specify the configuration file to use" clipboard: "Disable the clipboard feature" default_path: "Move the wallet in default directory" @@ -61,6 +62,7 @@ en: gpg_key: "Specify a GPG key (ex: user@example.com)" group: "Search the items with specified group" help: "Show this help message" + host: "Specify a host or ip" init: "Initialize mpw" import: "Import item since a yaml file" key: "Specify the key name" @@ -68,17 +70,23 @@ en: length: "Size of the password" list: "List the wallets" list_keys: "List the GPG keys in wallet" + new_group: "Specify the group for the item" numeric: "Use number to generate a password" + otp_code: "Set an otp key" path: "Move the wallet in new specify directory" pattern: "Given search pattern" pinmode: "Enable pinentry mode (available with gpg >= 2.1)" + port: "Set a port of connexion" + protocol: "Set a protocol of connexion" random_password: "Generate a random password" setup: "Create a new configuration file" setup_wallet: "Create a new configuration file for a wallet" special_chars: "Use special char to generate a password" show: "Search and show the items" show_all: "List all items" + text_editor: "Use text editor to edit the item" usage: "Usage" + user: "Set an user" wallet: "Specify a wallet to use" wallet_dir: "Set the wallets folder" diff --git a/i18n/fr.yml b/i18n/fr.yml index 13829a2..b1b4ecc 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -44,6 +44,7 @@ fr: add_gpg_key: "Partage le portefeuille avec une autre clé GPG" alpha: "Utilise des lettres dans la génération d'un mot de passe" config: "Spécifie le fichier de configuration à utiliser" + comment: "Spécifie un commentaire" clipboard: "Désactive la fonction presse papier" default_path: "Déplace le portefeuille dans le dossier par défaut" default_wallet: "Spécifie le porte-feuille à utiliser par défaut" @@ -61,6 +62,7 @@ fr: gpg_key: "Spécifie une clé GPG (ex: user@example.com)" group: "Recherche les éléments appartenant au groupe spécifié" help: "Affiche ce message d'aide" + host: "Spécifie le nom du serveur ou l'ip" import: "Importe des éléments depuis un fichier yaml" init: "Initialise mpw" key: "Spécifie le nom d'une clé" @@ -68,17 +70,23 @@ fr: length: "Taille du mot de passe" list: "Liste les portefeuilles" list_keys: "Liste les clés GPG dans le portefeuille" + new_group: "Spécifie le groupe de l'item" numeric: "Utilise des chiffre dans la génération d'un mot de passe" + otp_code: "Spécifie un code OTP" path: "Déplace le portefeuille dans un nouveau dossier" pattern: "Motif de donnée à chercher" pinmode: "Active le mode pinentry (valable avec gpg >= 2.1)" + port: "Spécifie un port de connexion" + protocol: "Spécifie un protocol de connexion" random_password: "Génére un mot de passe aléatoire" setup: "Création d'un nouveau fichier de configuration" setup_wallet: "Création d'un nouveau fichier de configuration pour un portefeuille" special_chars: "Utilise des charactères speciaux dans la génération d'un mot de passe" show: "Recherche et affiche les éléments" show_all: "Liste tous les éléments" + text_editor: "Active l'édition avec un éditeur de texte" usage: "Utilisation" + user: "Spécifie un utilisateur" wallet: "Spécifie le portefeuille à utiliser" wallet_dir: "Spécifie le répertoire des portefeuilles" diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 6fd257f..7aad7f0 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -400,9 +400,9 @@ module MPW # @args: template -> template name # item -> the item to edit # password -> disable field password - def text_editor(template_name, item = nil, password = false) + # @rtrn: a hash with the value for an item + def text_editor(template_name, password = false, item = nil, **options) editor = ENV['EDITOR'] || 'nano' - options = {} opts = {} template_file = "#{File.expand_path('../../../templates', __FILE__)}/#{template_name}.erb" template = ERB.new(IO.read(template_file)) @@ -430,8 +430,10 @@ module MPW # Form to add a new item # @args: password -> generate a random password - def add(password = false) - options = text_editor('add_form', nil, password) + # text_editor -> enable text editor mode + # values -> hash with multiples value to set the item + def add(password = false, text_editor = false, **values) + options = text_editor('add_form', password, nil, values) if text_editor item = Item.new(options) options[:password] = MPW.password(@config.password) if password @@ -447,8 +449,10 @@ module MPW # Update an item # @args: password -> generate a random password + # text_editor -> enable text editor mode # options -> the option to search - def update(password = false, **options) + # values -> hash with multiples value to set the item + def update(password = false, text_editor = false, options = {}, **values) items = @mpw.list(options) if items.empty? @@ -456,13 +460,13 @@ module MPW else table_items(items) if items.length > 1 - item = get_item(items) - options = text_editor('update_form', item, password) - options[:password] = MPW.password(@config.password) if password + item = get_item(items) + values = text_editor('update_form', password, item, values) if text_editor + values[:password] = MPW.password(@config.password) if password - item.update(options) - @mpw.set_password(item.id, options[:password]) if options.key?(:password) - @mpw.set_otp_key(item.id, options[:otp_key]) if options.key?(:otp_key) + item.update(values) + @mpw.set_password(item.id, values[:password]) if values.key?(:password) + @mpw.set_otp_key(item.id, values[:otp_key]) if values.key?(:otp_key) @mpw.write_data puts I18n.t('form.update_item.valid').to_s.green diff --git a/templates/add_form.erb b/templates/add_form.erb index bb81787..d88874e 100644 --- a/templates/add_form.erb +++ b/templates/add_form.erb @@ -1,9 +1,9 @@ --- -host: # <%= I18n.t('form.add_item.host') %> -user: # <%= I18n.t('form.add_item.login') %> -group: # <%= I18n.t('form.add_item.group') %> -protocol: # <%= I18n.t('form.add_item.protocol') %><% unless password %> -password: # <%= I18n.t('form.add_item.password') %><% end %> -port: # <%= I18n.t('form.add_item.port') %> -comment: # <%= I18n.t('form.add_item.comment') %> -otp_key: # <%= I18n.t('form.add_item.otp_key') %> +host: <%= options[:host] %> # <%= I18n.t('form.add_item.host') %> +user: <%= options[:user] %> # <%= I18n.t('form.add_item.login') %> +group: <%= options[:group] %> # <%= I18n.t('form.add_item.group') %> +protocol: <%= options[:protocol] %> # <%= I18n.t('form.add_item.protocol') %><% unless password %> +password: # <%= I18n.t('form.add_item.password') %><% end %> +port: <%= options[:port] %> # <%= I18n.t('form.add_item.port') %> +comment: <%= options[:comment] %> # <%= I18n.t('form.add_item.comment') %> +otp_key: <%= options[:otp] %> # <%= I18n.t('form.add_item.otp_key') %> diff --git a/templates/update_form.erb b/templates/update_form.erb index f27da0b..5037568 100644 --- a/templates/update_form.erb +++ b/templates/update_form.erb @@ -1,17 +1,17 @@ --- # <%= I18n.t('form.update_item.host') %> -host: <%= item.host %> +host: <% if options[:host] %><%= options[:host] %><% else %><%= item.host %><% end %> # <%= I18n.t('form.update_item.login') %> -user: <%= item.user %><% unless password %> +user: <% if options[:user] %><%= options[:user] %><% else %><%= item.user %><% end %><% unless password %> # <%= I18n.t('form.update_item.password') %> password: <% end %> # <%= I18n.t('form.update_item.group') %> -group: <%= item.group %> +group: <% if options[:group] %><%= options[:group] %><% else %><%= item.group %><% end %> # <%= I18n.t('form.update_item.protocol') %> -protocol: <%= item.protocol %> +protocol: <% if options[:protocol] %><%= options[:protocol] %><% else %><%= item.protocol %><% end %> # <%= I18n.t('form.update_item.port') %> -port: <%= item.port %> +port: <% if options[:port] %><%= options[:port] %><% else %><%= item.port %><% end %> # <%= I18n.t('form.update_item.otp_key') %> -otp_key: +otp_key: <% if options[:otp_key] %><%= options[:otp_key] %><% end %> # <%= I18n.t('form.update_item.comment') %> -comment: <%= item.comment %> +comment: <% if options[:comment] %><%= options[:comment] %><% else %><%= item.comment %><% end %> From b2b94374312f570a79c2971a5361803171b579d9 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Thu, 20 Apr 2017 23:22:56 +0200 Subject: [PATCH 105/165] change copyright year --- bin/mpw | 2 +- bin/mpw-add | 2 +- bin/mpw-config | 2 +- bin/mpw-copy | 2 +- bin/mpw-delete | 2 +- bin/mpw-export | 2 +- bin/mpw-genpwd | 2 +- bin/mpw-import | 2 +- bin/mpw-list | 2 +- bin/mpw-update | 2 +- bin/mpw-wallet | 2 +- lib/mpw/cli.rb | 2 +- lib/mpw/config.rb | 2 +- lib/mpw/item.rb | 2 +- lib/mpw/mpw.rb | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) diff --git a/bin/mpw b/bin/mpw index 1bdf835..811322e 100755 --- a/bin/mpw +++ b/bin/mpw @@ -1,6 +1,6 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords -# Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> +# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/bin/mpw-add b/bin/mpw-add index 20eaf7b..2c2e996 100644 --- a/bin/mpw-add +++ b/bin/mpw-add @@ -1,6 +1,6 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords -# Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> +# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/bin/mpw-config b/bin/mpw-config index 04f960b..3f049fa 100644 --- a/bin/mpw-config +++ b/bin/mpw-config @@ -1,6 +1,6 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords -# Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> +# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/bin/mpw-copy b/bin/mpw-copy index 9436a10..95c01d6 100644 --- a/bin/mpw-copy +++ b/bin/mpw-copy @@ -1,6 +1,6 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords -# Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> +# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/bin/mpw-delete b/bin/mpw-delete index f276785..ea352c4 100644 --- a/bin/mpw-delete +++ b/bin/mpw-delete @@ -1,6 +1,6 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords -# Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> +# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/bin/mpw-export b/bin/mpw-export index 982d1ad..83d35ae 100644 --- a/bin/mpw-export +++ b/bin/mpw-export @@ -1,6 +1,6 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords -# Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> +# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/bin/mpw-genpwd b/bin/mpw-genpwd index 1c09489..051c5c4 100644 --- a/bin/mpw-genpwd +++ b/bin/mpw-genpwd @@ -1,6 +1,6 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords -# Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> +# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/bin/mpw-import b/bin/mpw-import index d9c868d..0502b2b 100644 --- a/bin/mpw-import +++ b/bin/mpw-import @@ -1,6 +1,6 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords -# Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> +# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/bin/mpw-list b/bin/mpw-list index 3571abc..434ea11 100644 --- a/bin/mpw-list +++ b/bin/mpw-list @@ -1,6 +1,6 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords -# Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> +# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/bin/mpw-update b/bin/mpw-update index d887ce3..5e2c62d 100644 --- a/bin/mpw-update +++ b/bin/mpw-update @@ -1,6 +1,6 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords -# Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> +# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/bin/mpw-wallet b/bin/mpw-wallet index 5b3b7f9..c23e1e2 100644 --- a/bin/mpw-wallet +++ b/bin/mpw-wallet @@ -1,6 +1,6 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords -# Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> +# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 7aad7f0..d622bff 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -1,6 +1,6 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords -# Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> +# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index fa1a825..72b732d 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -1,6 +1,6 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords -# Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> +# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/lib/mpw/item.rb b/lib/mpw/item.rb index 8b4b867..b338998 100644 --- a/lib/mpw/item.rb +++ b/lib/mpw/item.rb @@ -1,6 +1,6 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords -# Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> +# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 896339c..71676c7 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -1,6 +1,6 @@ #!/usr/bin/ruby # MPW is a software to crypt and manage your passwords -# Copyright (C) 2016 Adrien Waksberg <mpw@yae.im> +# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License From 02996b590419aa81e84fc5ff3ea0a3b24e46bfbd Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Thu, 20 Apr 2017 23:26:40 +0200 Subject: [PATCH 106/165] gemspec: add minimal ruby version --- mpw.gemspec | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mpw.gemspec b/mpw.gemspec index 9f27023..4afbe3b 100644 --- a/mpw.gemspec +++ b/mpw.gemspec @@ -18,6 +18,8 @@ Gem::Specification.new do |spec| spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) spec.require_paths = ['lib'] + spec.required_ruby_version = '>= 2.1' + spec.add_dependency 'i18n', '~> 0.7', '>= 0.7.0' spec.add_dependency 'gpgme', '~> 2.0', '>= 2.0.12' spec.add_dependency 'highline', '~> 1.7', '>= 1.7.8' From 83fe41921c4c4ab55af4e9ef88d21f2b05f820de Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sat, 22 Apr 2017 10:25:19 +0200 Subject: [PATCH 107/165] update version 4.1 --- CHANGELOG.md | 9 +++++++++ README.md | 33 +++++++++++++++++++++++++++------ VERSION | 2 +- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 452ac98..7f52b5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,13 @@ # CHANGELOG +## v4.1.0 + + * feat: add options to update or add an item in command line + * feat: print config + * feat: add a specific path for a wallet + * feat: add rubocop to fix syntax + * fix: pinentry mode with gpg >= 2.1 + * remove SSH and FTP synchronization + ## v4.0.0 * feature: set default wallet diff --git a/README.md b/README.md index fd2534a..60a69d8 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # MPW: Manage your passwords! -[](https://github.com/nishiki/manage-password/releases) +[](https://github.com/nishiki/manage-password/releases) [](https://travis-ci.org/nishiki/manage-password) [](https://github.com/nishiki/manage-password/blob/master/LICENSE) @@ -82,11 +82,6 @@ List all available wallets: mpw wallet --list ``` -Create an other wallet: -``` -mpw config --wallet work --init user@host.com -``` - List all GPG keys in wallet: ``` mpw wallet --list-keys [--wallet NAME] @@ -139,3 +134,29 @@ Example yaml file for mpw: otp_key: comment: Da Linux French Site ``` + +### Config + +Print the current config +``` +mpw config +``` + +Output: + +``` +Configuration + ============================================== + lang | fr + gpg_key | mpw@yae.im + default_wallet | + config_dir | /home/mpw/.config/mpw + pinmode | true + gpg_exe | + path_wallet_test | /tmp/test.mpw + password_numeric | true + password_alpha | true + password_special | false + password_length | 16 + +``` diff --git a/VERSION b/VERSION index 4aa925d..ee74734 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.1.0-dev +4.1.0 From 9ad8eba901c97637d0cb0e1d2eb3a6c067f04b96 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 3 May 2017 19:54:21 +0200 Subject: [PATCH 108/165] fix: remove unused method --- bin/mpw-config | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/mpw-config b/bin/mpw-config index 3f049fa..bec687d 100644 --- a/bin/mpw-config +++ b/bin/mpw-config @@ -109,7 +109,6 @@ if options.key?(:init) cli.load_config cli.get_wallet cli.setup_gpg_key(values[:gpg_key]) - cli.setup_wallet_config else cli.load_config if values.empty? From 96380d3d934eba25747713c2bbbbf068b060ed76 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 3 May 2017 20:39:32 +0200 Subject: [PATCH 109/165] update version 4.1.1 --- CHANGELOG.md | 4 ++++ README.md | 2 +- VERSION | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f52b5f..1fb8d79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ # CHANGELOG +## v4.1.1 + + * fix bug in init + ## v4.1.0 * feat: add options to update or add an item in command line diff --git a/README.md b/README.md index 60a69d8..afb4ade 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # MPW: Manage your passwords! -[](https://github.com/nishiki/manage-password/releases) +[](https://github.com/nishiki/manage-password/releases) [](https://travis-ci.org/nishiki/manage-password) [](https://github.com/nishiki/manage-password/blob/master/LICENSE) diff --git a/VERSION b/VERSION index ee74734..627a3f4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.1.0 +4.1.1 From a7a165bca9e401845fbc7d18b6349f2f423fdd88 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 3 May 2017 22:53:56 +0200 Subject: [PATCH 110/165] feat: comment the code with yard --- .gitignore | 2 ++ lib/mpw/cli.rb | 71 +++++++++++++++++++++++------------------------ lib/mpw/config.rb | 21 ++++++-------- lib/mpw/item.rb | 8 ++---- lib/mpw/mpw.rb | 59 +++++++++++++++++++++------------------ 5 files changed, 81 insertions(+), 80 deletions(-) diff --git a/.gitignore b/.gitignore index 7ae6fcf..afd83c3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ Gemfile.lock *.gem +.yardoc +doc diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index d622bff..e3cb85e 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -28,14 +28,13 @@ require 'mpw/mpw' module MPW class Cli - # Constructor - # @args: config -> the config + # @param config [Config] def initialize(config) @config = config end # Change a parameter int the config after init - # @args: options -> param to change + # @param options [Hash] param to change def set_config(options) @config.setup(options) @@ -46,7 +45,7 @@ module MPW end # Change the wallet path - # @args: path -> the new path + # @param path [String] new path def set_wallet_path(path) @config.set_wallet_path(path, @wallet) @@ -57,7 +56,7 @@ module MPW end # Create a new config file - # @args: options -> set param + # @param options [Hash] def setup(options) options[:lang] = options[:lang] || Locale::Tag.parse(ENV['LANG']).to_simple.to_s[0..1] @@ -74,7 +73,7 @@ module MPW end # Setup a new GPG key - # @args: gpg_key -> the key name + # @param gpg_key [String] gpg key name def setup_gpg_key(gpg_key) return if @config.check_gpg_key? @@ -139,8 +138,8 @@ module MPW end # Format list on a table - # @args: title -> the name of table - # list -> array or hash + # @param title [String] name of table + # @param list an array or hash def table_list(title, list) length = { k: 0, v: 0 } @@ -172,7 +171,7 @@ module MPW end # Format items on a table - # @args: items -> an aray items + # @param items [Array] def table_items(items = []) group = '.' i = 1 @@ -252,7 +251,7 @@ module MPW end # Display the query's result - # @args: options -> the option to search + # @param options [Hash] the options to search def list(**options) result = @mpw.list(options) @@ -264,8 +263,8 @@ module MPW end # Get an item when multiple choice - # @args: items -> array of items - # @rtrn: item + # @param items [Array] list of items + # @return item [Item] def get_item(items) return items[0] if items.length == 1 @@ -276,8 +275,8 @@ module MPW end # Copy in clipboard the login and password - # @args: item -> the item - # clipboard -> enable clipboard + # @param item [Item] + # @param clipboard [Boolean] enable clipboard def clipboard(item, clipboard = true) # Security: force quit after 90s Thread.new do @@ -350,7 +349,7 @@ module MPW end # Display the wallet - # @args: wallet -> the wallet name + # @param wallet [String] wallet name def get_wallet(wallet = nil) @wallet = if wallet.to_s.empty? @@ -375,7 +374,7 @@ module MPW end # Add a new public key - # args: key -> the key name or key file to add + # @param key [String] key name or key file to add def add_key(key) @mpw.add_key(key) @mpw.write_data @@ -386,7 +385,7 @@ module MPW end # Add new public key - # args: key -> the key name to delete + # @param key [String] key name to delete def delete_key(key) @mpw.delete_key(key) @mpw.write_data @@ -397,10 +396,10 @@ module MPW end # Text editor interface - # @args: template -> template name - # item -> the item to edit - # password -> disable field password - # @rtrn: a hash with the value for an item + # @param template [String] template name + # @param item [Item] the item to edit + # @param password [Boolean] disable field password + # @return [Hash] the values for an item def text_editor(template_name, password = false, item = nil, **options) editor = ENV['EDITOR'] || 'nano' opts = {} @@ -429,9 +428,9 @@ module MPW end # Form to add a new item - # @args: password -> generate a random password - # text_editor -> enable text editor mode - # values -> hash with multiples value to set the item + # @param password [Boolean] generate a random password + # @param text_editor [Boolean] enable text editor mode + # @param values [Hash] multiples value to set the item def add(password = false, text_editor = false, **values) options = text_editor('add_form', password, nil, values) if text_editor item = Item.new(options) @@ -448,10 +447,10 @@ module MPW end # Update an item - # @args: password -> generate a random password - # text_editor -> enable text editor mode - # options -> the option to search - # values -> hash with multiples value to set the item + # @param password [Boolean] generate a random password + # @param text_editor [Boolean] enable text editor mode + # @param options [Hash] the options to search + # @param values [Hash] multiples value to set the item def update(password = false, text_editor = false, options = {}, **values) items = @mpw.list(options) @@ -476,7 +475,7 @@ module MPW end # Remove an item - # @args: options -> the option to search + # @param options [Hash] the options to search def delete(**options) items = @mpw.list(options) @@ -500,8 +499,8 @@ module MPW end # Copy a password, otp, login - # @args: clipboard -> enable clipboard - # options -> the option to search + # @param clipboard [Boolean] enable clipboard + # @param options [Hash] the options to search def copy(clipboard = true, **options) items = @mpw.list(options) @@ -517,9 +516,9 @@ module MPW puts "#{I18n.t('display.error')} #14: #{e}".red end - # Export the items in a CSV file - # @args: file -> the destination file - # options -> option to search + # Export the items in an yaml file + # @param file [String] the path of destination file + # @param options [Hash] options to search def export(file, options) file = 'export-mpw.yml' if file.to_s.empty? items = @mpw.list(options) @@ -549,8 +548,8 @@ module MPW puts "#{I18n.t('display.error')} #17: #{e}".red end - # Import items from a YAML file - # @args: file -> the import file + # Import items from an yaml file + # @param file [String] path of import file def import(file) raise I18n.t('form.import.file_empty') if file.to_s.empty? raise I18n.t('form.import.file_not_exist') unless File.exist?(file) diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index 72b732d..bdcf394 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -35,8 +35,7 @@ module MPW attr_accessor :password attr_accessor :pinmode - # Constructor - # @args: config_file -> the specify config file + # @param config_file [String] path of config file def initialize(config_file = nil) @config_file = config_file @config_dir = @@ -52,8 +51,7 @@ module MPW end # Create a new config file - # @args: options -> hash with values - # @rtrn: true if le config file is create + # @param options [Hash] the value to set the config file def setup(**options) gpg_key = options[:gpg_key] || @gpg_key lang = options[:lang] || @lang @@ -99,11 +97,10 @@ module MPW end # Setup a new gpg key - # @args: password -> the GPG key password - # name -> the name of user - # length -> length of the GPG key - # expire -> the time of expire to GPG key - # @rtrn: true if the GPG key is create, else false + # @param password [String] gpg key password + # @param name [String] the name of user + # @param length [Integer] length of the gpg key + # @param expire [Integer] time of expire to gpg key def setup_gpg_key(password, name, length = 4096, expire = 0) raise I18n.t('error.config.genkey_gpg.name') if name.to_s.empty? raise I18n.t('error.config.genkey_gpg.password') if password.to_s.empty? @@ -147,7 +144,7 @@ module MPW end # Check if private key exist - # @rtrn: true if the key exist, else false + # @return [Boolean] true if the key exist, else false def check_gpg_key? ctx = GPGME::Ctx.new ctx.each_key(@gpg_key, true) do @@ -158,8 +155,8 @@ module MPW end # Change the path of one wallet - # @args: path -> the new directory path - # wallet -> the wallet name + # @param path [String]new directory path + # @param wallet [String] wallet name def set_wallet_path(path, wallet) path = @wallet_dir if path == 'default' diff --git a/lib/mpw/item.rb b/lib/mpw/item.rb index b338998..ba86b96 100644 --- a/lib/mpw/item.rb +++ b/lib/mpw/item.rb @@ -31,10 +31,7 @@ module MPW attr_accessor :last_edit attr_accessor :created - # Constructor - # Create a new item - # @args: options -> a hash of parameter - # raise an error if the hash hasn't the key name + # @param options [Hash] the option :host is required def initialize(**options) if !options.key?(:host) || options[:host].to_s.empty? raise I18n.t('error.update.host_empty') @@ -54,7 +51,7 @@ module MPW end # Update the item - # @args: options -> a hash of parameter + # @param options [Hash] def update(**options) if options.key?(:host) && options[:host].to_s.empty? raise I18n.t('error.update.host_empty') @@ -95,6 +92,7 @@ module MPW private # Generate an random id + # @return [String] random string def generate_id [*('A'..'Z'), *('a'..'z'), *('0'..'9')].sample(16).join end diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 71676c7..fbca576 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -25,7 +25,11 @@ require 'mpw/item' module MPW class MPW - # Constructor + # @param key [String] gpg key name + # @param wallet_file [String] path of the wallet file + # @param gpg_pass [String] password of the gpg key + # @param gpg_exe [String] path of the gpg executable + # @param pinmode [Boolean] enable the gpg pinmode def initialize(key, wallet_file, gpg_pass = nil, gpg_exe = nil, pinmode = false) @key = key @gpg_pass = gpg_pass @@ -98,7 +102,7 @@ module MPW raise "#{I18n.t('error.mpw_file.read_data')}\n#{e}" end - # Encrypt a file + # Encrypt all data in tarball def write_data data = {} tmp_file = "#{@wallet_file}.tmp" @@ -154,7 +158,7 @@ module MPW end # Get a password - # args: id -> the item id + # @param id [String] the item id def get_password(id) password = decrypt(@passwords[id]) @@ -165,9 +169,9 @@ module MPW end end - # Set a password - # args: id -> the item id - # password -> the new password + # Set a new password for an item + # @param id [String] the item id + # @param password [String] the new password def set_password(id, password) salt = MPW.password(length: Random.rand(4..9)) password = "$#{salt}::#{password}" @@ -176,13 +180,13 @@ module MPW end # Return the list of all gpg keys - # rtrn: an array with the gpg keys name + # @return [Array] the gpg keys name def list_keys @keys.keys end # Add a public key - # args: key -> new public key file or name + # @param key [String] new public key file or name def add_key(key) if File.exist?(key) data = File.open(key).read @@ -200,7 +204,7 @@ module MPW end # Delete a public key - # args: key -> public key to delete + # @param key [String] public key to delete def delete_key(key) @keys.delete(key) @passwords.each_key { |id| set_password(id, get_password(id)) } @@ -208,7 +212,7 @@ module MPW end # Add a new item - # @args: item -> Object MPW::Item + # @param item [Item] def add(item) raise I18n.t('error.bad_class') unless item.instance_of?(Item) raise I18n.t('error.empty') if item.empty? @@ -217,8 +221,8 @@ module MPW end # Search in some csv data - # @args: options -> a hash with paramaters - # @rtrn: a list with the resultat of the search + # @params options [Hash] + # @return [Array] a list with the resultat of the search def list(**options) result = [] @@ -240,9 +244,9 @@ module MPW result end - # Search in some csv data - # @args: id -> the id item - # @rtrn: a row with the result of the search + # Search an item with an id + # @param id [String]the id item + # @return [Item] an item or nil def search_by_id(id) @data.each do |item| return item if item.id == id @@ -251,36 +255,35 @@ module MPW nil end - # Set an opt key - # args: id -> the item id - # key -> the new key + # Set a new opt key + # @param id [String] the item id + # @param key [String] the new key def set_otp_key(id, key) @otp_keys[id] = encrypt(key.to_s) unless key.to_s.empty? end # Get an opt key - # args: id -> the item id - # key -> the new key + # @param id [String] the item id def get_otp_key(id) @otp_keys.key?(id) ? decrypt(@otp_keys[id]) : nil end # Get an otp code - # @args: id -> the item id - # @rtrn: an otp code + # @param id [String] the item id + # @return [String] an otp code def get_otp_code(id) @otp_keys.key?(id) ? 0 : ROTP::TOTP.new(decrypt(@otp_keys[id])).now end # Get remaining time before expire otp code - # @rtrn: return time in seconde + # @return [Integer] time in seconde def get_otp_remaining_time (Time.now.utc.to_i / 30 + 1) * 30 - Time.now.utc.to_i end # Generate a random password - # @args: options -> :length, :special, :alpha, :numeric - # @rtrn: a random string + # @param options [Hash] :length, :special, :alpha, :numeric + # @return [String] a random string def self.password(**options) length = if !options.include?(:length) || options[:length].to_i <= 0 @@ -310,7 +313,8 @@ module MPW private # Decrypt a gpg file - # @args: data -> string to decrypt + # @param data [String] data to decrypt + # @return [String] data decrypted def decrypt(data) return nil if data.to_s.empty? @@ -331,7 +335,8 @@ module MPW end # Encrypt a file - # args: data -> string to encrypt + # @param data [String] data to encrypt + # @return [String] data encrypted def encrypt(data) recipients = [] crypto = GPGME::Crypto.new(armor: true, always_trust: true) From f91531b856e7b1299851331ec204c08c0da92200 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sat, 6 May 2017 09:09:17 +0200 Subject: [PATCH 111/165] feat: replace host by url in table --- lib/mpw/cli.rb | 33 +++++++++++++++++++++------------ lib/mpw/item.rb | 11 +++++++++++ 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index e3cb85e..023b9b2 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -179,16 +179,19 @@ module MPW data = { id: { length: 3, color: 'cyan' }, host: { length: 9, color: 'yellow' }, user: { length: 7, color: 'green' }, - protocol: { length: 9, color: 'white' }, - port: { length: 5, color: 'white' }, otp: { length: 4, color: 'white' }, comment: { length: 14, color: 'magenta' } } items.each do |item| data.each do |k, v| - next if k == :id || k == :otp - - v[:length] = item.send(k.to_s).to_s.length + 3 if item.send(k.to_s).to_s.length >= v[:length] + case k + when :id, :otp + next + when :host + v[:length] = item.url.length + 3 if item.url.length >= v[:length] + else + v[:length] = item.send(k.to_s).to_s.length + 3 if item.send(k.to_s).to_s.length >= v[:length] + end end end data[:id][:length] = items.length.to_s.length + 2 if items.length.to_s.length > data[:id][:length] @@ -231,16 +234,22 @@ module MPW data.each do |k, v| next if k == :id - if k == :otp - print '| ' + print '| ' + + case k + when :otp item.otp ? (print ' X ') : 4.times { print ' ' } - next - end + when :host + print "#{item.protocol}://" if item.protocol + print item.host.send(v[:color]) + print ":#{item.port}" if item.port + (v[:length] - item.url.to_s.length).times { print ' ' } - print '| ' - print item.send(k.to_s).to_s.send(v[:color]) - (v[:length] - item.send(k.to_s).to_s.length).times { print ' ' } + else + print item.send(k.to_s).to_s.send(v[:color]) + (v[:length] - item.send(k.to_s).to_s.length).times { print ' ' } + end end print "\n" diff --git a/lib/mpw/item.rb b/lib/mpw/item.rb index ba86b96..be03dba 100644 --- a/lib/mpw/item.rb +++ b/lib/mpw/item.rb @@ -81,6 +81,17 @@ module MPW @last_edit = nil end + # Return data on url format + # @return [String] an url + def url + url = '' + url += "#{@protocol}://" if @protocol + url += @host + url += ":#{@port}" if @port + + url + end + def empty? @id.to_s.empty? end From 6a3f2ca007823190e755154c5e0df48f6a38cae7 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 7 May 2017 17:11:42 +0200 Subject: [PATCH 112/165] add first tests for cli --- .travis.yml | 7 ++++++- test/test_cli.rb | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ test/tests.rb | 7 ------- 3 files changed, 56 insertions(+), 8 deletions(-) create mode 100644 test/test_cli.rb delete mode 100644 test/tests.rb diff --git a/.travis.yml b/.travis.yml index faa5c04..89d29f0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,4 +13,9 @@ install: - gem install mpw-9999.gem script: - rubocop - - ruby ./test/tests.rb + - ruby ./test/init.rb + - ruby ./test/test_config.rb + - ruby ./test/test_item.rb + - ruby ./test/test_mpw.rb + - ruby ./test/test_translate.rb + - ruby ./test/test_cli.rb diff --git a/test/test_cli.rb b/test/test_cli.rb new file mode 100644 index 0000000..0db3ffa --- /dev/null +++ b/test/test_cli.rb @@ -0,0 +1,50 @@ +#!/usr/bin/ruby + +require 'fileutils' +require 'test/unit' + +class TestConfig < Test::Unit::TestCase + def setup + @password = 'password' + end + + def test_00_init_config + FileUtils.rm_rf("#{Dir.home}/.config/mpw") + FileUtils.rm_rf("#{Dir.home}/.gnupg") + + output = `echo "#{@password}\n#{@password}" | mpw config --init test@example.com` + assert_match('The config file has been created', output) + assert_match('Your GPG key has been created ;-)', output) + end + + def test_01_add_item + host = 'example.com' + + output = `echo #{@password} | mpw add --host #{host} -r` + assert_match('Item has been added!', output) + + output = `echo #{@password} | mpw list` + assert_match(host, output) + end + + def test_02_update_item + host_old = 'example.com' + host_new = 'example2.com' + + output = `echo #{@password} | mpw update -p #{host_old} --host #{host_new}` + assert_match('Item has been updated!', output) + + output = `echo #{@password} | mpw list` + assert_match(host_new, output) + end + + def test_03_delete_item + host = 'example2.com' + + output = `echo "#{@password}\ny" | mpw delete -p #{host}` + assert_match('The item has been removed!', output) + + output = `echo #{@password} | mpw list` + assert_no_match(/#{host}/, output) + end +end diff --git a/test/tests.rb b/test/tests.rb deleted file mode 100644 index 7f3fc7d..0000000 --- a/test/tests.rb +++ /dev/null @@ -1,7 +0,0 @@ -#!/usr/bin/ruby - -require_relative 'init.rb' -require_relative 'test_config.rb' -require_relative 'test_item.rb' -require_relative 'test_mpw.rb' -require_relative 'test_translate.rb' From 646f096aac6f6efd9db6b4464b7d6a9b1de908f7 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 7 May 2017 19:29:22 +0200 Subject: [PATCH 113/165] update ruby version for test --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 89d29f0..f9db456 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ language: ruby rvm: - - 2.4.0 - - 2.3.3 - - 2.2.6 + - 2.4.1 + - 2.3.4 + - 2.2.7 - 2.1.10 install: - bundle install From a13fcd147fb53d05bb3df493111e155926dabc85 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sat, 6 May 2017 09:09:17 +0200 Subject: [PATCH 114/165] feat: replace host by url in table --- lib/mpw/cli.rb | 33 +++++++++++++++++++++------------ lib/mpw/item.rb | 11 +++++++++++ 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index e3cb85e..023b9b2 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -179,16 +179,19 @@ module MPW data = { id: { length: 3, color: 'cyan' }, host: { length: 9, color: 'yellow' }, user: { length: 7, color: 'green' }, - protocol: { length: 9, color: 'white' }, - port: { length: 5, color: 'white' }, otp: { length: 4, color: 'white' }, comment: { length: 14, color: 'magenta' } } items.each do |item| data.each do |k, v| - next if k == :id || k == :otp - - v[:length] = item.send(k.to_s).to_s.length + 3 if item.send(k.to_s).to_s.length >= v[:length] + case k + when :id, :otp + next + when :host + v[:length] = item.url.length + 3 if item.url.length >= v[:length] + else + v[:length] = item.send(k.to_s).to_s.length + 3 if item.send(k.to_s).to_s.length >= v[:length] + end end end data[:id][:length] = items.length.to_s.length + 2 if items.length.to_s.length > data[:id][:length] @@ -231,16 +234,22 @@ module MPW data.each do |k, v| next if k == :id - if k == :otp - print '| ' + print '| ' + + case k + when :otp item.otp ? (print ' X ') : 4.times { print ' ' } - next - end + when :host + print "#{item.protocol}://" if item.protocol + print item.host.send(v[:color]) + print ":#{item.port}" if item.port + (v[:length] - item.url.to_s.length).times { print ' ' } - print '| ' - print item.send(k.to_s).to_s.send(v[:color]) - (v[:length] - item.send(k.to_s).to_s.length).times { print ' ' } + else + print item.send(k.to_s).to_s.send(v[:color]) + (v[:length] - item.send(k.to_s).to_s.length).times { print ' ' } + end end print "\n" diff --git a/lib/mpw/item.rb b/lib/mpw/item.rb index ba86b96..be03dba 100644 --- a/lib/mpw/item.rb +++ b/lib/mpw/item.rb @@ -81,6 +81,17 @@ module MPW @last_edit = nil end + # Return data on url format + # @return [String] an url + def url + url = '' + url += "#{@protocol}://" if @protocol + url += @host + url += ":#{@port}" if @port + + url + end + def empty? @id.to_s.empty? end From 09e451bf3be5ac589fdaebf85c4768eec97b13a0 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Tue, 9 May 2017 13:56:52 +0200 Subject: [PATCH 115/165] use ligth_black for port and protocol --- lib/mpw/cli.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 023b9b2..4e2f240 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -241,9 +241,9 @@ module MPW item.otp ? (print ' X ') : 4.times { print ' ' } when :host - print "#{item.protocol}://" if item.protocol + print "#{item.protocol}://".light_black if item.protocol print item.host.send(v[:color]) - print ":#{item.port}" if item.port + print ":#{item.port}".light_black if item.port (v[:length] - item.url.to_s.length).times { print ' ' } else From 977266def846ec5794494e697d8dc8174c305391 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Wed, 10 May 2017 22:38:35 +0200 Subject: [PATCH 116/165] add new test --- test/test_cli.rb | 69 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 54 insertions(+), 15 deletions(-) diff --git a/test/test_cli.rb b/test/test_cli.rb index 0db3ffa..c3466e8 100644 --- a/test/test_cli.rb +++ b/test/test_cli.rb @@ -12,39 +12,78 @@ class TestConfig < Test::Unit::TestCase FileUtils.rm_rf("#{Dir.home}/.config/mpw") FileUtils.rm_rf("#{Dir.home}/.gnupg") - output = `echo "#{@password}\n#{@password}" | mpw config --init test@example.com` + output = %x(echo "#{@password}\n#{@password}" | mpw config --init test@example.com) assert_match('The config file has been created', output) assert_match('Your GPG key has been created ;-)', output) end def test_01_add_item - host = 'example.com' + host = 'example.com' + port = 1234 + proto = 'http' + user = 'root' + comment = 'the super website' + group = 'Bank' - output = `echo #{@password} | mpw add --host #{host} -r` + output = %x( + echo #{@password} | mpw add \ + --host #{host} \ + --port #{port} \ + --protocol #{proto} \ + --user #{user} \ + --comment '#{comment}' \ + --group #{group} \ + --random) + puts output assert_match('Item has been added!', output) - - output = `echo #{@password} | mpw list` - assert_match(host, output) + + output = %x(echo #{@password} | mpw list) + puts output + assert_match(%r{#{proto}://.+#{host}.+:#{port}}, output) + assert_match(user, output) + assert_match(comment, output) + assert_match(group, output) end def test_02_update_item - host_old = 'example.com' - host_new = 'example2.com' + host_old = 'example.com' + host_new = 'example2.com' + port_new = 4321 + proto_new = 'ssh' + user_new = 'tortue' + comment_new = 'my account' + group_new = 'Assurance' - output = `echo #{@password} | mpw update -p #{host_old} --host #{host_new}` + output = %x( + echo #{@password} | mpw update \ + -p #{host_old} \ + --host #{host_new} \ + --port #{port_new} \ + --protocol #{proto_new} \ + --user #{user_new} \ + --comment '#{comment_new}' \ + --new-group #{group_new} + ) + puts output assert_match('Item has been updated!', output) - - output = `echo #{@password} | mpw list` - assert_match(host_new, output) + + output = %x(echo #{@password} | mpw list) + puts output + assert_match(%r{#{proto_new}://.+#{host_new}.+:#{port_new}}, output) + assert_match(user_new, output) + assert_match(comment_new, output) + assert_match(group_new, output) end def test_03_delete_item host = 'example2.com' - output = `echo "#{@password}\ny" | mpw delete -p #{host}` + output = %x(echo "#{@password}\ny" | mpw delete -p #{host}) + puts output assert_match('The item has been removed!', output) - - output = `echo #{@password} | mpw list` + + output = %x(echo #{@password} | mpw list) + puts output assert_no_match(/#{host}/, output) end end From f150feec10240ec8b007283da5bc9ae900789b4e Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Thu, 11 May 2017 22:24:05 +0200 Subject: [PATCH 117/165] fix syntax for all tests --- .rubocop.yml | 1 - test/test_config.rb | 24 +++++----- test/test_item.rb | 99 ++++++++++++++++++++++-------------------- test/test_mpw.rb | 40 ++++++++--------- test/test_translate.rb | 2 +- 5 files changed, 85 insertions(+), 81 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index 8685f88..ce1de33 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -3,7 +3,6 @@ AllCops: Exclude: - db/**/* - config/**/* - - test/* - Vagrantfile TargetRubyVersion: 2.3 diff --git a/test/test_config.rb b/test/test_config.rb index 49af82c..8ad7369 100644 --- a/test/test_config.rb +++ b/test/test_config.rb @@ -20,17 +20,18 @@ class TestConfig < Test::Unit::TestCase end def test_00_config - data = { gpg_key: 'test@example.com', - lang: 'en', - wallet_dir: '/tmp/test', - gpg_exe: '', - } + data = { + gpg_key: 'test@example.com', + lang: 'en', + wallet_dir: '/tmp/test', + gpg_exe: '' + } @config = MPW::Config.new @config.setup(data) @config.load_config - data.each do |k,v| + data.each do |k, v| assert_equal(v, @config.send(k)) end @@ -39,11 +40,12 @@ class TestConfig < Test::Unit::TestCase end def test_01_password - data = { pwd_alpha: false, - pwd_numeric: false, - pwd_special: true, - pwd_length: 32, - } + data = { + pwd_alpha: false, + pwd_numeric: false, + pwd_special: true, + pwd_length: 32 + } @config = MPW::Config.new @config.load_config diff --git a/test/test_item.rb b/test/test_item.rb index 751e1b0..961834e 100644 --- a/test/test_item.rb +++ b/test/test_item.rb @@ -16,22 +16,22 @@ class TestItem < Test::Unit::TestCase I18n.load_path = Dir['./i18n/cli/*.yml'] I18n.default_locale = :en - puts end def test_00_add_without_name - assert_raise(RuntimeError){MPW::Item.new} + assert_raise(RuntimeError) { MPW::Item.new } end def test_01_add_new - data = { group: @fixtures['add_new']['group'], - host: @fixtures['add_new']['host'], - protocol: @fixtures['add_new']['protocol'], - user: @fixtures['add_new']['user'], - port: @fixtures['add_new']['port'], - comment: @fixtures['add_new']['comment'], - } + data = { + group: @fixtures['add_new']['group'], + host: @fixtures['add_new']['host'], + protocol: @fixtures['add_new']['protocol'], + user: @fixtures['add_new']['user'], + port: @fixtures['add_new']['port'], + comment: @fixtures['add_new']['comment'] + } item = MPW::Item.new(data) @@ -47,15 +47,16 @@ class TestItem < Test::Unit::TestCase end def test_02_add_existing - data = { id: @fixtures['add_existing']['id'], - group: @fixtures['add_existing']['group'], - host: @fixtures['add_existing']['host'], - protocol: @fixtures['add_existing']['protocol'], - user: @fixtures['add_existing']['user'], - port: @fixtures['add_existing']['port'], - comment: @fixtures['add_existing']['comment'], - created: @fixtures['add_existing']['created'], - } + data = { + id: @fixtures['add_existing']['id'], + group: @fixtures['add_existing']['group'], + host: @fixtures['add_existing']['host'], + protocol: @fixtures['add_existing']['protocol'], + user: @fixtures['add_existing']['user'], + port: @fixtures['add_existing']['port'], + comment: @fixtures['add_existing']['comment'], + created: @fixtures['add_existing']['created'] + } item = MPW::Item.new(data) @@ -73,13 +74,14 @@ class TestItem < Test::Unit::TestCase end def test_03_update - data = { group: @fixtures['add_new']['group'], - host: @fixtures['add_new']['host'], - protocol: @fixtures['add_new']['protocol'], - user: @fixtures['add_new']['user'], - port: @fixtures['add_new']['port'], - comment: @fixtures['add_new']['comment'], - } + data = { + group: @fixtures['add_new']['group'], + host: @fixtures['add_new']['host'], + protocol: @fixtures['add_new']['protocol'], + user: @fixtures['add_new']['user'], + port: @fixtures['add_new']['port'], + comment: @fixtures['add_new']['comment'] + } item = MPW::Item.new(data) @@ -89,13 +91,14 @@ class TestItem < Test::Unit::TestCase created = item.created last_edit = item.last_edit - data = { group: @fixtures['update']['group'], - host: @fixtures['update']['host'], - protocol: @fixtures['update']['protocol'], - user: @fixtures['update']['user'], - port: @fixtures['update']['port'], - comment: @fixtures['update']['comment'], - } + data = { + group: @fixtures['update']['group'], + host: @fixtures['update']['host'], + protocol: @fixtures['update']['protocol'], + user: @fixtures['update']['user'], + port: @fixtures['update']['port'], + comment: @fixtures['update']['comment'] + } sleep(1) assert(item.update(data)) @@ -114,13 +117,14 @@ class TestItem < Test::Unit::TestCase end def test_05_update_one_element - data = { group: @fixtures['add_new']['group'], - host: @fixtures['add_new']['host'], - protocol: @fixtures['add_new']['protocol'], - user: @fixtures['add_new']['user'], - port: @fixtures['add_new']['port'], - comment: @fixtures['add_new']['comment'], - } + data = { + group: @fixtures['add_new']['group'], + host: @fixtures['add_new']['host'], + protocol: @fixtures['add_new']['protocol'], + user: @fixtures['add_new']['user'], + port: @fixtures['add_new']['port'], + comment: @fixtures['add_new']['comment'] + } item = MPW::Item.new(data) @@ -130,7 +134,7 @@ class TestItem < Test::Unit::TestCase last_edit = item.last_edit sleep(1) - assert(item.update({comment: @fixtures['update']['comment']})) + assert(item.update(comment: @fixtures['update']['comment'])) assert_equal(@fixtures['add_new']['group'], item.group) assert_equal(@fixtures['add_new']['host'], item.host) @@ -143,13 +147,14 @@ class TestItem < Test::Unit::TestCase end def test_05_delete - data = { group: @fixtures['add_new']['group'], - host: @fixtures['add_new']['host'], - protocol: @fixtures['add_new']['protocol'], - user: @fixtures['add_new']['user'], - port: @fixtures['add_new']['port'], - comment: @fixtures['add_new']['comment'], - } + data = { + group: @fixtures['add_new']['group'], + host: @fixtures['add_new']['host'], + protocol: @fixtures['add_new']['protocol'], + user: @fixtures['add_new']['user'], + port: @fixtures['add_new']['port'], + comment: @fixtures['add_new']['comment'] + } item = MPW::Item.new(data) diff --git a/test/test_mpw.rb b/test/test_mpw.rb index 30c9028..dd005ca 100644 --- a/test/test_mpw.rb +++ b/test/test_mpw.rb @@ -33,13 +33,14 @@ class TestMPW < Test::Unit::TestCase end def test_02_add_item - data = { group: @fixtures['add_new']['group'], - host: @fixtures['add_new']['host'], - protocol: @fixtures['add_new']['protocol'], - user: @fixtures['add_new']['user'], - port: @fixtures['add_new']['port'], - comment: @fixtures['add_new']['comment'], - } + data = { + group: @fixtures['add_new']['group'], + host: @fixtures['add_new']['host'], + protocol: @fixtures['add_new']['protocol'], + user: @fixtures['add_new']['user'], + port: @fixtures['add_new']['port'], + comment: @fixtures['add_new']['comment'] + } item = MPW::Item.new(data) @@ -53,7 +54,7 @@ class TestMPW < Test::Unit::TestCase assert_equal(1, @mpw.list.length) item = @mpw.list[0] - @fixtures['add_new'].each do |k,v| + @fixtures['add_new'].each do |k, v| if k == 'password' assert_equal(v, @mpw.get_password(item.id)) else @@ -69,7 +70,7 @@ class TestMPW < Test::Unit::TestCase assert_equal(1, @mpw.list.length) item = @mpw.list[0] - @fixtures['add_new'].each do |k,v| + @fixtures['add_new'].each do |k, v| if k == 'password' assert_equal(v, @mpw.get_password(item.id)) else @@ -80,13 +81,9 @@ class TestMPW < Test::Unit::TestCase def test_04_delete_item @mpw.read_data - assert_equal(1, @mpw.list.length) - @mpw.list.each do |item| - item.delete - end - + @mpw.list.each(&:delete) assert_equal(0, @mpw.list.length) @mpw.write_data @@ -96,13 +93,14 @@ class TestMPW < Test::Unit::TestCase @mpw.read_data @fixtures.each_value do |v| - data = { group: v['group'], - host: v['host'], - protocol: v['protocol'], - user: v['user'], - port: v['port'], - comment: v['comment'], - } + data = { + group: v['group'], + host: v['host'], + protocol: v['protocol'], + user: v['user'], + port: v['port'], + comment: v['comment'] + } item = MPW::Item.new(data) diff --git a/test/test_translate.rb b/test/test_translate.rb index 6334a78..d4bb002 100644 --- a/test/test_translate.rb +++ b/test/test_translate.rb @@ -11,7 +11,7 @@ class TestTranslate < Test::Unit::TestCase lang = File.basename(yaml, '.yml') translate = YAML.load_file(yaml) - `grep -r -o "I18n.t('.*)" bin/ lib/ | cut -d"'" -f2`.each_line do |line| + %x(grep -r -o "I18n.t('.*)" bin/ lib/ | cut -d"'" -f2).each_line do |line| begin t = translate[lang] line.strip.split('.').each do |v| From 72c213b7b7112727642fced0e04fe6964c8e96a8 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Sat, 13 May 2017 01:04:56 +0200 Subject: [PATCH 118/165] test: use dynamic translation --- test/test_cli.rb | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/test/test_cli.rb b/test/test_cli.rb index c3466e8..375de4e 100644 --- a/test/test_cli.rb +++ b/test/test_cli.rb @@ -1,10 +1,19 @@ #!/usr/bin/ruby require 'fileutils' +require 'i18n' require 'test/unit' class TestConfig < Test::Unit::TestCase def setup + if defined?(I18n.enforce_available_locales) + I18n.enforce_available_locales = true + end + + I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) + I18n.load_path = ["#{File.expand_path('../../i18n', __FILE__)}/en.yml"] + I18n.locale = :en + @password = 'password' end @@ -13,8 +22,8 @@ class TestConfig < Test::Unit::TestCase FileUtils.rm_rf("#{Dir.home}/.gnupg") output = %x(echo "#{@password}\n#{@password}" | mpw config --init test@example.com) - assert_match('The config file has been created', output) - assert_match('Your GPG key has been created ;-)', output) + assert_match(I18n.t('form.setup_config.valid'), output) + assert_match(I18n.t('form.setup_gpg_key.valid'), output) end def test_01_add_item @@ -35,7 +44,7 @@ class TestConfig < Test::Unit::TestCase --group #{group} \ --random) puts output - assert_match('Item has been added!', output) + assert_match(I18n.t('form.add_item.valid'), output) output = %x(echo #{@password} | mpw list) puts output @@ -65,7 +74,7 @@ class TestConfig < Test::Unit::TestCase --new-group #{group_new} ) puts output - assert_match('Item has been updated!', output) + assert_match(I18n.t('form.update_item.valid'), output) output = %x(echo #{@password} | mpw list) puts output @@ -80,7 +89,7 @@ class TestConfig < Test::Unit::TestCase output = %x(echo "#{@password}\ny" | mpw delete -p #{host}) puts output - assert_match('The item has been removed!', output) + assert_match(I18n.t('form.delete_item.valid'), output) output = %x(echo #{@password} | mpw list) puts output From f41a9e68d32f9ec3651a9690310a3552da679512 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Thu, 11 May 2017 22:24:05 +0200 Subject: [PATCH 119/165] fix syntax for all tests --- test/test_item.rb | 5 +---- test/test_mpw.rb | 4 +--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/test/test_item.rb b/test/test_item.rb index 961834e..4b0cf1b 100644 --- a/test/test_item.rb +++ b/test/test_item.rb @@ -6,9 +6,6 @@ require 'yaml' class TestItem < Test::Unit::TestCase def setup - @fixture_file = 'test/files/fixtures.yml' - @fixtures = YAML.load_file(@fixture_file) - if defined?(I18n.enforce_available_locales) I18n.enforce_available_locales = false end @@ -16,7 +13,7 @@ class TestItem < Test::Unit::TestCase I18n.load_path = Dir['./i18n/cli/*.yml'] I18n.default_locale = :en - puts + @fixtures = YAML.load_file('./test/files/fixtures.yml') end def test_00_add_without_name diff --git a/test/test_mpw.rb b/test/test_mpw.rb index dd005ca..2877d19 100644 --- a/test/test_mpw.rb +++ b/test/test_mpw.rb @@ -8,8 +8,6 @@ require 'csv' class TestMPW < Test::Unit::TestCase def setup - fixture_file = './test/files/fixtures.yml' - wallet_file = 'default.gpg' key = 'test@example.com' password = 'password' @@ -19,7 +17,7 @@ class TestMPW < Test::Unit::TestCase end @mpw = MPW::MPW.new(key, wallet_file, password) - @fixtures = YAML.load_file(fixture_file) + @fixtures = YAML.load_file('./test/files/fixtures.yml') end def test_00_decrypt_empty_file From ca2e0d9e479cd21cc6139428bb7c3076bce02655 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Sat, 13 May 2017 12:28:42 +0200 Subject: [PATCH 120/165] test: update fixture --- test/files/fixtures.yml | 46 ++++++++--------- test/test_cli.rb | 60 ++++++++++------------ test/test_item.rb | 108 ++++++++++++++++++++-------------------- test/test_mpw.rb | 24 ++++----- 4 files changed, 114 insertions(+), 124 deletions(-) diff --git a/test/files/fixtures.yml b/test/files/fixtures.yml index 5651911..765314e 100644 --- a/test/files/fixtures.yml +++ b/test/files/fixtures.yml @@ -1,28 +1,28 @@ -add_new: - group: 'test_group' - host: 'test_host' - protocol: 'test_protocol' - user: 'test_user' - password: 'test_password' - port: '42' - comment: 'test_comment' +add: + group: 'Bank' + host: 'example.com' + protocol: 'https' + user: 'admin' + password: 'VmfnCN6pPIqgRIbc' + port: '8080' + comment: 'the website' -add_existing: +import: id: 'TEST-ID-XXXXX' - group: 'test_group_existing' - host: 'test_host_existing' - protocol: 'test_protocol_existing' - user: 'test_user_existing' - password: 'test_password_existing' - port: '44' - comment: 'test_comment_existing' + group: 'Cloud' + host: 'gogole.com' + protocol: 'https' + user: 'gg-2304' + password: 'TITl0kV9CDDa9sVK' + port: '8081' + comment: 'My little servers' created: 1386752948 update: - group: 'test_group_update' - host: 'test_host_update' - protocol: 'test_protocol_update' - user: 'test_user_update' - password: 'test_password_update' - port: '43' - comment: 'test_comment_update' + group: 'Assurance' + host: 'example2.com' + protocol: 'ssh' + user: 'root' + password: 'kbSrbv4WlMaVxaZ7' + port: '2222' + comment: 'i love ssh' diff --git a/test/test_cli.rb b/test/test_cli.rb index 375de4e..d92e175 100644 --- a/test/test_cli.rb +++ b/test/test_cli.rb @@ -15,6 +15,7 @@ class TestConfig < Test::Unit::TestCase I18n.locale = :en @password = 'password' + @fixtures = YAML.load_file(fixture_file) end def test_00_init_config @@ -27,65 +28,54 @@ class TestConfig < Test::Unit::TestCase end def test_01_add_item - host = 'example.com' - port = 1234 - proto = 'http' - user = 'root' - comment = 'the super website' - group = 'Bank' + data = @fixtures['add'] output = %x( echo #{@password} | mpw add \ - --host #{host} \ - --port #{port} \ - --protocol #{proto} \ - --user #{user} \ - --comment '#{comment}' \ - --group #{group} \ + --host #{data['host']} \ + --port #{data['port']} \ + --protocol #{data['protocol']} \ + --user #{data['user']} \ + --comment '#{data['comment']}' \ + --group #{data['group']} \ --random) puts output assert_match(I18n.t('form.add_item.valid'), output) output = %x(echo #{@password} | mpw list) puts output - assert_match(%r{#{proto}://.+#{host}.+:#{port}}, output) - assert_match(user, output) - assert_match(comment, output) - assert_match(group, output) + assert_match(%r{#{data['protocol']}://.+#{data['host']}.+:#{data['port']}}, output) + assert_match(data['user'], output) + assert_match(data['comment'], output) + assert_match(data['group'], output) end def test_02_update_item - host_old = 'example.com' - host_new = 'example2.com' - port_new = 4321 - proto_new = 'ssh' - user_new = 'tortue' - comment_new = 'my account' - group_new = 'Assurance' + data = @fixtures['update'] output = %x( echo #{@password} | mpw update \ - -p #{host_old} \ - --host #{host_new} \ - --port #{port_new} \ - --protocol #{proto_new} \ - --user #{user_new} \ - --comment '#{comment_new}' \ - --new-group #{group_new} + -p #{@fixtures['add']['host']} \ + --host #{data['host']} \ + --port #{data['port']} \ + --protocol #{data['protocol']} \ + --user #{data['user']} \ + --comment '#{data['comment']}' \ + --new-group #{data['group']} ) puts output assert_match(I18n.t('form.update_item.valid'), output) output = %x(echo #{@password} | mpw list) puts output - assert_match(%r{#{proto_new}://.+#{host_new}.+:#{port_new}}, output) - assert_match(user_new, output) - assert_match(comment_new, output) - assert_match(group_new, output) + assert_match(%r{#{data['protocol']}://.+#{data['host']}.+:#{data['port']}}, output) + assert_match(data['user'], output) + assert_match(data['comment'], output) + assert_match(data['group'], output) end def test_03_delete_item - host = 'example2.com' + host = @fixtures['update']['host'] output = %x(echo "#{@password}\ny" | mpw delete -p #{host}) puts output diff --git a/test/test_item.rb b/test/test_item.rb index 4b0cf1b..c83cbc3 100644 --- a/test/test_item.rb +++ b/test/test_item.rb @@ -20,14 +20,14 @@ class TestItem < Test::Unit::TestCase assert_raise(RuntimeError) { MPW::Item.new } end - def test_01_add_new + def test_01_add data = { - group: @fixtures['add_new']['group'], - host: @fixtures['add_new']['host'], - protocol: @fixtures['add_new']['protocol'], - user: @fixtures['add_new']['user'], - port: @fixtures['add_new']['port'], - comment: @fixtures['add_new']['comment'] + group: @fixtures['add']['group'], + host: @fixtures['add']['host'], + protocol: @fixtures['add']['protocol'], + user: @fixtures['add']['user'], + port: @fixtures['add']['port'], + comment: @fixtures['add']['comment'] } item = MPW::Item.new(data) @@ -35,24 +35,24 @@ class TestItem < Test::Unit::TestCase assert(!item.nil?) assert(!item.empty?) - assert_equal(@fixtures['add_new']['group'], item.group) - assert_equal(@fixtures['add_new']['host'], item.host) - assert_equal(@fixtures['add_new']['protocol'], item.protocol) - assert_equal(@fixtures['add_new']['user'], item.user) - assert_equal(@fixtures['add_new']['port'].to_i, item.port) - assert_equal(@fixtures['add_new']['comment'], item.comment) + assert_equal(@fixtures['add']['group'], item.group) + assert_equal(@fixtures['add']['host'], item.host) + assert_equal(@fixtures['add']['protocol'], item.protocol) + assert_equal(@fixtures['add']['user'], item.user) + assert_equal(@fixtures['add']['port'].to_i, item.port) + assert_equal(@fixtures['add']['comment'], item.comment) end - def test_02_add_existing + def test_02_import data = { - id: @fixtures['add_existing']['id'], - group: @fixtures['add_existing']['group'], - host: @fixtures['add_existing']['host'], - protocol: @fixtures['add_existing']['protocol'], - user: @fixtures['add_existing']['user'], - port: @fixtures['add_existing']['port'], - comment: @fixtures['add_existing']['comment'], - created: @fixtures['add_existing']['created'] + id: @fixtures['import']['id'], + group: @fixtures['import']['group'], + host: @fixtures['import']['host'], + protocol: @fixtures['import']['protocol'], + user: @fixtures['import']['user'], + port: @fixtures['import']['port'], + comment: @fixtures['import']['comment'], + created: @fixtures['import']['created'] } item = MPW::Item.new(data) @@ -60,24 +60,24 @@ class TestItem < Test::Unit::TestCase assert(!item.nil?) assert(!item.empty?) - assert_equal(@fixtures['add_existing']['id'], item.id) - assert_equal(@fixtures['add_existing']['group'], item.group) - assert_equal(@fixtures['add_existing']['host'], item.host) - assert_equal(@fixtures['add_existing']['protocol'], item.protocol) - assert_equal(@fixtures['add_existing']['user'], item.user) - assert_equal(@fixtures['add_existing']['port'].to_i, item.port) - assert_equal(@fixtures['add_existing']['comment'], item.comment) - assert_equal(@fixtures['add_existing']['created'], item.created) + assert_equal(@fixtures['import']['id'], item.id) + assert_equal(@fixtures['import']['group'], item.group) + assert_equal(@fixtures['import']['host'], item.host) + assert_equal(@fixtures['import']['protocol'], item.protocol) + assert_equal(@fixtures['import']['user'], item.user) + assert_equal(@fixtures['import']['port'].to_i, item.port) + assert_equal(@fixtures['import']['comment'], item.comment) + assert_equal(@fixtures['import']['created'], item.created) end def test_03_update data = { - group: @fixtures['add_new']['group'], - host: @fixtures['add_new']['host'], - protocol: @fixtures['add_new']['protocol'], - user: @fixtures['add_new']['user'], - port: @fixtures['add_new']['port'], - comment: @fixtures['add_new']['comment'] + group: @fixtures['add']['group'], + host: @fixtures['add']['host'], + protocol: @fixtures['add']['protocol'], + user: @fixtures['add']['user'], + port: @fixtures['add']['port'], + comment: @fixtures['add']['comment'] } item = MPW::Item.new(data) @@ -115,12 +115,12 @@ class TestItem < Test::Unit::TestCase def test_05_update_one_element data = { - group: @fixtures['add_new']['group'], - host: @fixtures['add_new']['host'], - protocol: @fixtures['add_new']['protocol'], - user: @fixtures['add_new']['user'], - port: @fixtures['add_new']['port'], - comment: @fixtures['add_new']['comment'] + group: @fixtures['add']['group'], + host: @fixtures['add']['host'], + protocol: @fixtures['add']['protocol'], + user: @fixtures['add']['user'], + port: @fixtures['add']['port'], + comment: @fixtures['add']['comment'] } item = MPW::Item.new(data) @@ -133,24 +133,24 @@ class TestItem < Test::Unit::TestCase sleep(1) assert(item.update(comment: @fixtures['update']['comment'])) - assert_equal(@fixtures['add_new']['group'], item.group) - assert_equal(@fixtures['add_new']['host'], item.host) - assert_equal(@fixtures['add_new']['protocol'], item.protocol) - assert_equal(@fixtures['add_new']['user'], item.user) - assert_equal(@fixtures['add_new']['port'].to_i, item.port) - assert_equal(@fixtures['update']['comment'], item.comment) + assert_equal(@fixtures['add']['group'], item.group) + assert_equal(@fixtures['add']['host'], item.host) + assert_equal(@fixtures['add']['protocol'], item.protocol) + assert_equal(@fixtures['add']['user'], item.user) + assert_equal(@fixtures['add']['port'].to_i, item.port) + assert_equal(@fixtures['update']['comment'], item.comment) assert_not_equal(last_edit, item.last_edit) end def test_05_delete data = { - group: @fixtures['add_new']['group'], - host: @fixtures['add_new']['host'], - protocol: @fixtures['add_new']['protocol'], - user: @fixtures['add_new']['user'], - port: @fixtures['add_new']['port'], - comment: @fixtures['add_new']['comment'] + group: @fixtures['add']['group'], + host: @fixtures['add']['host'], + protocol: @fixtures['add']['protocol'], + user: @fixtures['add']['user'], + port: @fixtures['add']['port'], + comment: @fixtures['add']['comment'] } item = MPW::Item.new(data) diff --git a/test/test_mpw.rb b/test/test_mpw.rb index 2877d19..a783225 100644 --- a/test/test_mpw.rb +++ b/test/test_mpw.rb @@ -32,12 +32,12 @@ class TestMPW < Test::Unit::TestCase def test_02_add_item data = { - group: @fixtures['add_new']['group'], - host: @fixtures['add_new']['host'], - protocol: @fixtures['add_new']['protocol'], - user: @fixtures['add_new']['user'], - port: @fixtures['add_new']['port'], - comment: @fixtures['add_new']['comment'] + group: @fixtures['add']['group'], + host: @fixtures['add']['host'], + protocol: @fixtures['add']['protocol'], + user: @fixtures['add']['user'], + port: @fixtures['add']['port'], + comment: @fixtures['add']['comment'] } item = MPW::Item.new(data) @@ -47,12 +47,12 @@ class TestMPW < Test::Unit::TestCase @mpw.read_data @mpw.add(item) - @mpw.set_password(item.id, @fixtures['add_new']['password']) + @mpw.set_password(item.id, @fixtures['add']['password']) assert_equal(1, @mpw.list.length) item = @mpw.list[0] - @fixtures['add_new'].each do |k, v| + @fixtures['add'].each do |k, v| if k == 'password' assert_equal(v, @mpw.get_password(item.id)) else @@ -68,7 +68,7 @@ class TestMPW < Test::Unit::TestCase assert_equal(1, @mpw.list.length) item = @mpw.list[0] - @fixtures['add_new'].each do |k, v| + @fixtures['add'].each do |k, v| if k == 'password' assert_equal(v, @mpw.get_password(item.id)) else @@ -110,9 +110,9 @@ class TestMPW < Test::Unit::TestCase end assert_equal(3, @mpw.list.length) - assert_equal(1, @mpw.list(group: @fixtures['add_new']['group']).length) - assert_equal(1, @mpw.list(pattern: 'existing').length) - assert_equal(2, @mpw.list(pattern: 'host_[eu]').length) + assert_equal(1, @mpw.list(group: @fixtures['add']['group']).length) + assert_equal(1, @mpw.list(pattern: 'gogole').length) + assert_equal(2, @mpw.list(pattern: 'example[2\.]').length) end def test_06_add_gpg_key From 5f7cb6e0cc40b61c1eeaaf392bbf5b54ad733781 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <adrien.waksberg@doctolib.fr> Date: Sat, 13 May 2017 19:30:23 +0200 Subject: [PATCH 121/165] add search test in cli --- lib/mpw/cli.rb | 4 ++-- test/test_cli.rb | 31 ++++++++++++++++++++++++------- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 4e2f240..cc0ebf0 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -464,7 +464,7 @@ module MPW items = @mpw.list(options) if items.empty? - puts "#{I18n.t('display.warning')}: #{I18n.t('warning.select')}".yellow + puts I18n.t('display.nothing') else table_items(items) if items.length > 1 @@ -489,7 +489,7 @@ module MPW items = @mpw.list(options) if items.empty? - puts "#{I18n.t('display.warning')}: #{I18n.t('warning.select')}".yellow + puts I18n.t('display.nothing') else table_items(items) diff --git a/test/test_cli.rb b/test/test_cli.rb index d92e175..8944ce2 100644 --- a/test/test_cli.rb +++ b/test/test_cli.rb @@ -15,7 +15,7 @@ class TestConfig < Test::Unit::TestCase I18n.locale = :en @password = 'password' - @fixtures = YAML.load_file(fixture_file) + @fixtures = YAML.load_file('./test/files/fixtures.yml') end def test_00_init_config @@ -50,7 +50,26 @@ class TestConfig < Test::Unit::TestCase assert_match(data['group'], output) end - def test_02_update_item + def test_02_search + data = @fixtures['add'] + + output = %x(echo #{@password} | mpw list --group #{data['group']}) + assert_match(%r{#{data['protocol']}://.+#{data['host']}.+:#{data['port']}}, output) + + output = %x(echo #{@password} | mpw list --pattern #{data['host']}) + assert_match(%r{#{data['protocol']}://.+#{data['host']}.+:#{data['port']}}, output) + + output = %x(echo #{@password} | mpw list --pattern #{data['comment']}) + assert_match(%r{#{data['protocol']}://.+#{data['host']}.+:#{data['port']}}, output) + + output = %x(echo #{@password} | mpw list --group R1Pmfbp626TFpjlr) + assert_match(I18n.t('display.nothing'), output) + + output = %x(echo #{@password} | mpw list --pattern h1IfnKqamaGM9oEX) + assert_match(I18n.t('display.nothing'), output) + end + + def test_03_update_item data = @fixtures['update'] output = %x( @@ -74,15 +93,13 @@ class TestConfig < Test::Unit::TestCase assert_match(data['group'], output) end - def test_03_delete_item - host = @fixtures['update']['host'] - - output = %x(echo "#{@password}\ny" | mpw delete -p #{host}) + def test_04_delete_item + output = %x(echo "#{@password}\ny" | mpw delete -p #{@fixtures['update']['host']}) puts output assert_match(I18n.t('form.delete_item.valid'), output) output = %x(echo #{@password} | mpw list) puts output - assert_no_match(/#{host}/, output) + assert_match(I18n.t('display.nothing'), output) end end From 62318fe0778e8c1f17d74ddbcf57e5585330fd1e Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Thu, 18 May 2017 23:03:30 +0200 Subject: [PATCH 122/165] add test cli for config --- bin/mpw-config | 2 +- test/test_cli.rb | 59 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/bin/mpw-config b/bin/mpw-config index bec687d..0af88bd 100644 --- a/bin/mpw-config +++ b/bin/mpw-config @@ -88,7 +88,7 @@ OptionParser.new do |opts| values[:pwd_special] = true end - opts.on('-S', '--disable_special-chars', I18n.t('option.special_chars')) do + opts.on('-S', '--disable-special-chars', I18n.t('option.special_chars')) do values[:pwd_special] = false end diff --git a/test/test_cli.rb b/test/test_cli.rb index 8944ce2..56326c2 100644 --- a/test/test_cli.rb +++ b/test/test_cli.rb @@ -16,13 +16,14 @@ class TestConfig < Test::Unit::TestCase @password = 'password' @fixtures = YAML.load_file('./test/files/fixtures.yml') + @gpg_key = 'test@example.com' end def test_00_init_config FileUtils.rm_rf("#{Dir.home}/.config/mpw") FileUtils.rm_rf("#{Dir.home}/.gnupg") - output = %x(echo "#{@password}\n#{@password}" | mpw config --init test@example.com) + output = %x(echo "#{@password}\n#{@password}" | mpw config --init #{@gpg_key}) assert_match(I18n.t('form.setup_config.valid'), output) assert_match(I18n.t('form.setup_gpg_key.valid'), output) end @@ -38,7 +39,8 @@ class TestConfig < Test::Unit::TestCase --user #{data['user']} \ --comment '#{data['comment']}' \ --group #{data['group']} \ - --random) + --random + ) puts output assert_match(I18n.t('form.add_item.valid'), output) @@ -102,4 +104,57 @@ class TestConfig < Test::Unit::TestCase puts output assert_match(I18n.t('display.nothing'), output) end + + def test_05_setup_config + gpg_key = 'user@example2.com' + gpg_exe = '/usr/bin/gpg2' + wallet_dir = '/tmp/mpw' + length = 24 + wallet = 'work' + + output = %x( + mpw config \ + --gpg-exe #{gpg_exe} \ + --enable-pinmode \ + --disable-alpha \ + --disable-special-chars \ + --disable-numeric \ + --length #{length} \ + --wallet-dir #{wallet_dir} \ + --default-wallet #{wallet} + ) + puts output + assert_match(I18n.t('form.set_config.valid'), output) + + output = %x(mpw config) + puts output + assert_match(/gpg_key.+\| #{@gpg_key}/, output) + assert_match(/gpg_exe.+\| #{gpg_exe}/, output) + assert_match(/pinmode.+\| true/, output) + assert_match(/default_wallet.+\| #{wallet}/, output) + assert_match(/wallet_dir.+\| #{wallet_dir}/, output) + assert_match(/password_length.+\| #{length}/, output) + %w[numeric alpha special].each do |k| + assert_match(/password_#{k}.+\| false/, output) + end + + output = %x( + mpw config \ + --key #{gpg_key} \ + --alpha \ + --special-chars \ + --numeric \ + --disable-pinmode + ) + puts output + assert_match(I18n.t('form.set_config.valid'), output) + + output = %x(mpw config) + puts output + assert_match(/gpg_key.+\| #{gpg_key}/, output) + assert_match(/pinmode.+\| false/, output) + %w[numeric alpha special].each do |k| + assert_match(/password_#{k}.+\| true/, output) + end + end end From 8e4fb1c91bf2701d8ded1a9ff9db36d0003d763a Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Thu, 18 May 2017 23:30:54 +0200 Subject: [PATCH 123/165] fix show config --- lib/mpw/cli.rb | 2 +- lib/mpw/config.rb | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index cc0ebf0..d794434 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -105,7 +105,7 @@ module MPW 'lang' => @config.lang, 'gpg_key' => @config.gpg_key, 'default_wallet' => @config.default_wallet, - 'config_dir' => @config.config_dir, + 'wallet_dir' => @config.wallet_dir, 'pinmode' => @config.pinmode, 'gpg_exe' => @config.gpg_exe } diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index bdcf394..016c690 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -58,11 +58,13 @@ module MPW wallet_dir = options[:wallet_dir] || @wallet_dir default_wallet = options[:default_wallet] || @default_wallet gpg_exe = options[:gpg_exe] || @gpg_exe - pinmode = options[:pinmode] || @pinmode - password = { numeric: true, - alpha: true, - special: false, - length: 16 } + pinmode = options.key?(:pinmode) ? options[:pinmode] : @pinmode + password = { + numeric: true, + alpha: true, + special: false, + length: 16 + } %w[numeric special alpha length].each do |k| if options.key?("pwd_#{k}".to_sym) @@ -134,7 +136,7 @@ module MPW @default_wallet = config['default_wallet'] @gpg_exe = config['gpg_exe'] @password = config['password'] || {} - @pinmode = config['pinmode'] + @pinmode = config['pinmode'] || false raise if @gpg_key.empty? || @wallet_dir.empty? From 7c369861418c0b0f5a262476ceef7d515a2562ae Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Fri, 19 May 2017 22:28:15 +0200 Subject: [PATCH 124/165] feat: show wallet list by default --- bin/mpw-wallet | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/mpw-wallet b/bin/mpw-wallet index c23e1e2..caee35d 100644 --- a/bin/mpw-wallet +++ b/bin/mpw-wallet @@ -74,12 +74,10 @@ cli = MPW::Cli.new(config) cli.load_config -if options.key?(:list) - cli.list_wallet -elsif options.key?(:path) +if options.key?(:path) cli.get_wallet(options[:wallet]) cli.set_wallet_path(options[:path]) -else +elsif options.key?(:list_keys) || options.key?(:gpg_key) cli.get_wallet(options[:wallet]) cli.decrypt @@ -88,4 +86,6 @@ else elsif options.key?(:gpg_key) options[:delete] ? cli.delete_key(options[:gpg_key]) : cli.add_key(options[:gpg_key]) end +else + cli.list_wallet end From 3b9ff8c15cb2bd0229fa31407da4e6a909b4ebb9 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sat, 20 May 2017 08:06:50 +0200 Subject: [PATCH 125/165] add test cli for wallet options --- .travis.yml | 1 + test/init.rb | 8 ++++++-- test/test_cli.rb | 50 +++++++++++++++++++++++++++++++++++++++++++----- 3 files changed, 52 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index f9db456..b640d4d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,4 +18,5 @@ script: - ruby ./test/test_item.rb - ruby ./test/test_mpw.rb - ruby ./test/test_translate.rb + - ruby ./test/init.rb - ruby ./test/test_cli.rb diff --git a/test/init.rb b/test/init.rb index be7a73a..6da9ecb 100644 --- a/test/init.rb +++ b/test/init.rb @@ -1,13 +1,17 @@ #!/usr/bin/ruby +require 'fileutils' require 'gpgme' +FileUtils.rm_rf("#{Dir.home}/.config/mpw") +FileUtils.rm_rf("#{Dir.home}/.gnupg") + param = '' param << '<GnupgKeyParms format="internal">' + "\n" param << "Key-Type: RSA\n" -param << "Key-Length: 2048\n" +param << "Key-Length: 512\n" param << "Subkey-Type: ELG-E\n" -param << "Subkey-Length: 2048\n" +param << "Subkey-Length: 512\n" param << "Name-Real: test\n" param << "Name-Comment: test\n" param << "Name-Email: test2@example.com\n" diff --git a/test/test_cli.rb b/test/test_cli.rb index 56326c2..3e97308 100644 --- a/test/test_cli.rb +++ b/test/test_cli.rb @@ -1,6 +1,5 @@ #!/usr/bin/ruby -require 'fileutils' require 'i18n' require 'test/unit' @@ -20,9 +19,6 @@ class TestConfig < Test::Unit::TestCase end def test_00_init_config - FileUtils.rm_rf("#{Dir.home}/.config/mpw") - FileUtils.rm_rf("#{Dir.home}/.gnupg") - output = %x(echo "#{@password}\n#{@password}" | mpw config --init #{@gpg_key}) assert_match(I18n.t('form.setup_config.valid'), output) assert_match(I18n.t('form.setup_gpg_key.valid'), output) @@ -105,7 +101,51 @@ class TestConfig < Test::Unit::TestCase assert_match(I18n.t('display.nothing'), output) end - def test_05_setup_config + def test_05_setup_wallet + path = '/tmp/' + gpg_key = 'test2@example.com' + + output = %x(echo #{@password} | mpw wallet --add-gpg-key #{gpg_key}) + puts output + assert_match(I18n.t('form.add_key.valid'), output) + + output = %x(echo #{@password} | mpw wallet --list-keys) + puts output + assert_match("| #{@gpg_key}", output) + assert_match("| #{gpg_key}", output) + + output = %x(echo #{@password} | mpw wallet --delete-gpg-key #{gpg_key}) + puts output + assert_match(I18n.t('form.delete_key.valid'), output) + + output = %x(echo #{@password} | mpw wallet --list-keys) + puts output + assert_match("| #{@gpg_key}", output) + assert_no_match(/\| #{gpg_key}/, output) + + output = %x(mpw wallet) + puts output + assert_match('| default', output) + + output = %x(mpw wallet --path #{path}) + puts output + assert_match(I18n.t('form.set_wallet_path.valid'), output) + + output = %x(mpw config) + puts output + assert_match(%r{path_wallet_default.+\| #{path}/default.mpw}, output) + assert(File.exist?("#{path}/default.mpw")) + + output = %x(mpw wallet --default-path) + puts output + assert_match(I18n.t('form.set_wallet_path.valid'), output) + + output = %x(mpw config) + puts output + assert_no_match(/path_wallet_default/, output) + end + + def test_06_setup_config gpg_key = 'user@example2.com' gpg_exe = '/usr/bin/gpg2' wallet_dir = '/tmp/mpw' From 01831c1f2b703bc2e99f84e9328f7b52874e52cd Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sat, 20 May 2017 11:31:37 +0200 Subject: [PATCH 126/165] add test cli for genpwd --- test/test_cli.rb | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/test/test_cli.rb b/test/test_cli.rb index 3e97308..85d5a5a 100644 --- a/test/test_cli.rb +++ b/test/test_cli.rb @@ -197,4 +197,29 @@ class TestConfig < Test::Unit::TestCase assert_match(/password_#{k}.+\| true/, output) end end + + def test_07_generate_password + length = 24 + + output = %x( + mpw genpwd \ + --length #{length} \ + --alpha + ) + assert_match(/[a-zA-Z]{#{length}}/, output) + + output = %x( + mpw genpwd \ + --length #{length} \ + --numeric + ) + assert_match(/[0-9]{#{length}}/, output) + + output = %x( + mpw genpwd \ + --length #{length} \ + --special-chars + ) + assert_no_match(/[a-zA-Z0-9]/, output) + end end From 811c576aae1866978dfb62b9c04f8d1f53898f0b Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sat, 20 May 2017 12:03:57 +0200 Subject: [PATCH 127/165] fix password generator --- lib/mpw/mpw.rb | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index fbca576..9917801 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -301,11 +301,9 @@ module MPW chars = [*('A'..'Z'), *('a'..'z'), *('0'..'9')] if chars.empty? result = '' - while length > 62 - result << chars.sample(62).join - length -= 62 + length.times do + result << chars.sample end - result << chars.sample(length).join result end From efff66b12e8c52bdb374cdac9b39c5c69d888cef Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sat, 20 May 2017 13:26:12 +0200 Subject: [PATCH 128/165] add test cli for export and import --- test/files/fixtures-import.yml | 19 +++++++++++++++++++ test/test_cli.rb | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 test/files/fixtures-import.yml diff --git a/test/files/fixtures-import.yml b/test/files/fixtures-import.yml new file mode 100644 index 0000000..f79ab0a --- /dev/null +++ b/test/files/fixtures-import.yml @@ -0,0 +1,19 @@ +--- +1: + host: fric.com + user: 230403 + group: Bank + password: 5XdiTQOubRDw9B0aJoMlcEyL + protocol: https + port: + otp_key: 330223432 + comment: I love my bank +2: + host: assurance.com + user: user_2132 + group: Assurance + password: DMyK6B3v4bWO52VzU7aTHIem + protocol: https + port: 443 + otp_key: + comment: diff --git a/test/test_cli.rb b/test/test_cli.rb index 85d5a5a..2dd411f 100644 --- a/test/test_cli.rb +++ b/test/test_cli.rb @@ -101,7 +101,35 @@ class TestConfig < Test::Unit::TestCase assert_match(I18n.t('display.nothing'), output) end - def test_05_setup_wallet + def test_05_import_export + file_import = './test/files/fixtures-import.yml' + file_export = '/tmp/test-mpw.yml' + + output = %x(echo #{@password} | mpw import --file #{file_import}) + assert_match(I18n.t('form.import.valid', file: file_import), output) + + output = %x(echo #{@password} | mpw export --file #{file_export}) + assert_match(I18n.t('form.export.valid', file: file_export), output) + assert(File.exist?(file_export)) + assert_equal(YAML.load_file(file_export).length, 2) + + YAML.load_file(file_import).each_value do |import| + error = true + + YAML.load_file(file_export).each_value do |export| + next if import['host'] != export['host'] + + %w[user group password protocol port otp_key comment].each do |key| + assert_equal(import[key].to_s, export[key].to_s) + end + + error = false + end + assert(!error) + end + end + + def test_06_setup_wallet path = '/tmp/' gpg_key = 'test2@example.com' @@ -145,7 +173,7 @@ class TestConfig < Test::Unit::TestCase assert_no_match(/path_wallet_default/, output) end - def test_06_setup_config + def test_07_setup_config gpg_key = 'user@example2.com' gpg_exe = '/usr/bin/gpg2' wallet_dir = '/tmp/mpw' @@ -198,7 +226,7 @@ class TestConfig < Test::Unit::TestCase end end - def test_07_generate_password + def test_08_generate_password length = 24 output = %x( From 6541931b792431fbe5181e145a76403ffb9ed4a4 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sat, 20 May 2017 15:30:19 +0200 Subject: [PATCH 129/165] enable text editor if threre isn't nothing value who has been set --- bin/mpw-update | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/mpw-update b/bin/mpw-update index 5e2c62d..143e187 100644 --- a/bin/mpw-update +++ b/bin/mpw-update @@ -93,6 +93,8 @@ end.parse! config = MPW::Config.new(options[:config]) cli = MPW::Cli.new(config) +options[:text_editor] = true if values.empty? + cli.load_config cli.get_wallet(options[:wallet]) cli.decrypt From 90486d1e9338f57801f029622fde5b0d0cd4e96c Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sat, 20 May 2017 15:42:28 +0200 Subject: [PATCH 130/165] update README --- README.md | 61 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index afb4ade..c1abef6 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,9 @@ mpw config --init user@host.com Add your first item: ``` -mpw add +mpw add --host assurance.com --port 443 --user user_2132 --protocol https --random +mpw add --host fric.com --user 230403 --otp-code 23434113 --protocol https --comment 'I love my bank' --random + ``` And list your items: @@ -40,46 +42,45 @@ mpw list ``` or search an item with ``` -mpw list --pattern Da +mpw list --pattern love mpw list --group bank ``` Output: ``` +Assurance + ========================================================================== + ID | Host | User | OTP | Comment + ========================================================================== + 1 | https://assurance.com:443 | user_2132 | | + Bank - ============================================================================== - ID | Host | User | Protocol | Port | OTP | Comment - ============================================================================== - 1 | bank.com | 1234456 | https | | X | - -Linux - ============================================================================== - ID | Host | User | Protocol | Port | OTP | Comment - ============================================================================== - 2 | linuxfr.org | example | https | | | Da Linux French Site - + ========================================================================== + ID | Host | User | OTP | Comment + ========================================================================== + 3 | https://fric.com | 230403 | X | I love my bank ``` Copy a password, login or OTP code: ``` -mpw copy -p linuxfr +mpw copy -p assurance.com ``` Update an item: ``` -mpw update -p linuxfr +mpw update -p assurance.com ``` Delete an item: ``` -mpw delete -p linuxfr +mpw delete -p assurance.com ``` ### Manage wallets List all available wallets: ``` -mpw wallet --list +mpw wallet ``` List all GPG keys in wallet: @@ -116,23 +117,23 @@ Example yaml file for mpw: ``` --- 1: - host: bank.com - user: 123456 + host: fric.com + user: 230403 group: Bank - password: secret + password: 5XdiTQOubRDw9B0aJoMlcEyL protocol: https - port: - otp_key: 1afg34 - comment: + port: + otp_key: 330223432 + comment: I love my bank 2: - host: linuxfr.org - user: example - group: - password: 'complex %- password' + host: assurance.com + user: user_2132 + group: Assurance + password: DMyK6B3v4bWO52VzU7aTHIem protocol: https - port: - otp_key: - comment: Da Linux French Site + port: 443 + otp_key: + comment: ``` ### Config From 5f29f7b6e826c104dbd074650cc58d9342d9ee3b Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 21 May 2017 17:19:46 +0200 Subject: [PATCH 131/165] add test cli for copy mode --- test/test_cli.rb | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/test/test_cli.rb b/test/test_cli.rb index 2dd411f..8fb91ee 100644 --- a/test/test_cli.rb +++ b/test/test_cli.rb @@ -129,7 +129,19 @@ class TestConfig < Test::Unit::TestCase end end - def test_06_setup_wallet + def test_06_copy + data = YAML.load_file('./test/files/fixtures-import.yml')[1] + + output = %x( + echo "#{@password}\np\nq" | mpw copy \ + --disable-clipboard \ + -p #{data['host']} + ) + puts output + assert_match(data['password'], output) + end + + def test_07_setup_wallet path = '/tmp/' gpg_key = 'test2@example.com' @@ -173,7 +185,7 @@ class TestConfig < Test::Unit::TestCase assert_no_match(/path_wallet_default/, output) end - def test_07_setup_config + def test_08_setup_config gpg_key = 'user@example2.com' gpg_exe = '/usr/bin/gpg2' wallet_dir = '/tmp/mpw' @@ -226,7 +238,7 @@ class TestConfig < Test::Unit::TestCase end end - def test_08_generate_password + def test_09_generate_password length = 24 output = %x( From ab459f954d0867a69582783acd7f33e338a7b401 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 21 May 2017 18:00:43 +0200 Subject: [PATCH 132/165] feat: add copy url --- i18n/en.yml | 2 ++ i18n/fr.yml | 2 ++ lib/mpw/cli.rb | 9 +++++++++ 3 files changed, 13 insertions(+) diff --git a/i18n/en.yml b/i18n/en.yml index 402facd..cd78280 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -111,8 +111,10 @@ en: login: "The login has been copied in clipboard." password: "The password has been copied in clipboard for 30s!" otp: "The OTP code has been copied for %{time}s!" + url: "The URL has been copied in clipboard." help: name: "Help" + url: "Press <u> to copy URL" login: "Press <l> to copy the login" password: "Press <p> to copy the password" otp_code: "Press <o> to copy the otp code" diff --git a/i18n/fr.yml b/i18n/fr.yml index b1b4ecc..d529ee4 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -111,8 +111,10 @@ fr: login: "L'identifiant a été copié dans le presse papier" password: "Le mot de passe a été copié dans le presse papier pour 30s!" otp: "Le code OTP a été copié dans le presse papier il est valable %{time}s!" + url: "L'URL a été copié dans le presse papier" help: name: "Aide" + url: "Pressez <u> pour copier l'URL" login: "Pressez <l> pour copier l'identifiant" password: "Pressez <p> pour copier le mot de passe" otp_code: "Pressez <o> pour copier le code OTP" diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index d794434..ccf212c 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -300,6 +300,14 @@ module MPW when 'q', 'quit' break + when 'u', 'url' + if clipboard + Clipboard.copy(item.url) + puts I18n.t('form.clipboard.url').green + else + puts item.url + end + when 'l', 'login' if clipboard Clipboard.copy(item.user) @@ -332,6 +340,7 @@ module MPW else puts "----- #{I18n.t('form.clipboard.help.name')} -----".cyan + puts I18n.t('form.clipboard.help.url') puts I18n.t('form.clipboard.help.login') puts I18n.t('form.clipboard.help.password') puts I18n.t('form.clipboard.help.otp_code') From dcb286ec09b56588df5e959459fc3f60f358c678 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Mon, 22 May 2017 20:32:06 +0200 Subject: [PATCH 133/165] add gem for development --- Gemfile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Gemfile b/Gemfile index 71d84d4..1fdac16 100644 --- a/Gemfile +++ b/Gemfile @@ -6,3 +6,8 @@ gem 'highline', '~> 1.7', '>= 1.7.8' gem 'i18n', '~> 0.7', '>= 0.7.0' gem 'locale', '~> 2.1', '>= 2.1.2' gem 'rotp', '~> 3.1', '>= 3.1.0' + +group :development do + gem 'rubocop' + gem 'yard' +end From 1fcac965e975ba9b11f47cebb3be3d106c165c1d Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Mon, 22 May 2017 20:32:27 +0200 Subject: [PATCH 134/165] fix comments --- lib/mpw/cli.rb | 4 ++-- lib/mpw/mpw.rb | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index ccf212c..02ede97 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -273,7 +273,7 @@ module MPW # Get an item when multiple choice # @param items [Array] list of items - # @return item [Item] + # @return [Item] an item def get_item(items) return items[0] if items.length == 1 @@ -414,7 +414,7 @@ module MPW end # Text editor interface - # @param template [String] template name + # @param template_name [String] template name # @param item [Item] the item to edit # @param password [Boolean] disable field password # @return [Hash] the values for an item diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 9917801..5905492 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -221,7 +221,7 @@ module MPW end # Search in some csv data - # @params options [Hash] + # @param options [Hash] # @return [Array] a list with the resultat of the search def list(**options) result = [] From b83b27832e5d44e5c8cb726279b234529dcfa3ed Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Mon, 22 May 2017 21:25:56 +0200 Subject: [PATCH 135/165] feat: no ask password if not necessary --- lib/mpw/cli.rb | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 02ede97..d92e4e4 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -126,12 +126,20 @@ module MPW # Request the GPG password and decrypt the file def decrypt - unless defined?(@mpw) - @password = ask(I18n.t('display.gpg_password')) { |q| q.echo = false } - @mpw = MPW.new(@config.gpg_key, @wallet_file, @password, @config.gpg_exe, @config.pinmode) - end + if defined?(@mpw) + @mpw.read_data + else + begin + @mpw = MPW.new(@config.gpg_key, @wallet_file, nil, @config.gpg_exe, @config.pinmode) - @mpw.read_data + @mpw.read_data + rescue + @password = ask(I18n.t('display.gpg_password')) { |q| q.echo = false } + @mpw = MPW.new(@config.gpg_key, @wallet_file, @password, @config.gpg_exe, @config.pinmode) + + @mpw.read_data + end + end rescue => e puts "#{I18n.t('display.error')} #11: #{e}".red exit 2 From a2c2711ddc1f5a60dc5fd4b62172e6f5b66a6d11 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 23 May 2017 19:33:05 +0200 Subject: [PATCH 136/165] add gem test-unit for development --- .travis.yml | 2 -- Gemfile | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b640d4d..525a9d0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,8 +6,6 @@ rvm: - 2.1.10 install: - bundle install - - gem install 'test-unit' - - gem install rubocop - echo 9999 > VERSION - gem build mpw.gemspec - gem install mpw-9999.gem diff --git a/Gemfile b/Gemfile index 1fdac16..56b6638 100644 --- a/Gemfile +++ b/Gemfile @@ -9,5 +9,6 @@ gem 'rotp', '~> 3.1', '>= 3.1.0' group :development do gem 'rubocop' + gem 'test-unit' gem 'yard' end From 6ea40e542025d9b186b0edce061da89423627533 Mon Sep 17 00:00:00 2001 From: fbonely <fanny.bonely@arte.tv> Date: Tue, 23 May 2017 19:49:20 +0200 Subject: [PATCH 137/165] Update translations EN --- i18n/en.yml | 96 ++++++++++++++++++++++++++--------------------------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/i18n/en.yml b/i18n/en.yml index cd78280..b50fd63 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -5,27 +5,27 @@ en: config: write: "Can't write the config file!" load: "Checkconfig failed!" - key_bad_format: "The key string isn't in good format!" - no_key_public: "You haven't the public key of %{key}!" + key_bad_format: "The key string isn't in the right format!" + no_key_public: "You haven't entered the public key of %{key}!" genkey_gpg: exception: "Can't create the GPG key!" name: "You must define a name for your GPG key!" password: "You must define a password for your GPG key!" - empty: "The class is void" + empty: "The class is empty" export: "Can't export, unable to write in %{file}!" export_key: "Can't export the GPG key" gpg_file: decrypt: "Can't decrypt file!" encrypt: "Can't encrypt the GPG file!" mpw_file: - read_data: "Can't to read the MPW file!" - write_data: "Can't to write the MPW file!" + read_data: "Can't read the MPW file!" + write_data: "Can't write the MPW file!" import: "Can't import, unable to read %{file}!" update: host_empty: "You must define a host!" warning: - select: 'Your choice is not a valid element!' + select: 'Your choice is not a valid item!' command: add: "Add a new item" @@ -41,37 +41,37 @@ en: option: add: "Add an item or key" - add_gpg_key: "Share the wallet with an other GPG key" - alpha: "Use letter to generate a password" + add_gpg_key: "Share the wallet with another GPG key" + alpha: "Use letter to create a password" comment: "Specify a comment" config: "Specify the configuration file to use" clipboard: "Disable the clipboard feature" - default_path: "Move the wallet in default directory" + default_path: "Move the wallet to the default directory" default_wallet: "Specify the default wallet to use" - delete_gpg_key: "Delete the wallet's share with an other GPG key" - disable_alpha: "Don't use letter to generate a password" - disable_numeric: "Don't use number to generate a password" + delete_gpg_key: "Delete wallet sharing with an other GPG key" + disable_alpha: "Don't use letters to create a password" + disable_numeric: "Don't use numbers to generate a password" disable_pinmode: "Disable the pinentry mode" - disable_special_chars: "Don't use special char to generate a password" + disable_special_chars: "Don't use special char to create a password" export: "Export a wallet in an yaml file" - file_export: "Specify the file where export data" + file_export: "Specify the file to export data" file_import: "Specify the file to import" - force: "No ask to confirm when you delete an item" - generate_password: "Generate a random password (default 8 characters)" + force: "Do not ask confirmation when deleting an item" + generate_password: "Create a random password (default 8 characters)" gpg_exe: "Set the gpg binary path to use" gpg_key: "Specify a GPG key (ex: user@example.com)" group: "Search the items with specified group" help: "Show this help message" host: "Specify a host or ip" init: "Initialize mpw" - import: "Import item since a yaml file" - key: "Specify the key name" + import: "Import item from an yaml file" + key: "Define the key name" lang: "Set the software language" length: "Size of the password" list: "List the wallets" list_keys: "List the GPG keys in wallet" - new_group: "Specify the group for the item" - numeric: "Use number to generate a password" + new_group: "Define a group for the item" + numeric: "Use number to create a password" otp_code: "Set an otp key" path: "Move the wallet in new specify directory" pattern: "Given search pattern" @@ -81,11 +81,11 @@ en: random_password: "Generate a random password" setup: "Create a new configuration file" setup_wallet: "Create a new configuration file for a wallet" - special_chars: "Use special char to generate a password" - show: "Search and show the items" - show_all: "List all items" + special_chars: "Use special char to create a password" + show: "Search and display the items" + show_all: "Listing all items" text_editor: "Use text editor to edit the item" - usage: "Usage" + usage: "Use" user: "Set an user" wallet: "Specify a wallet to use" wallet_dir: "Set the wallets folder" @@ -95,13 +95,13 @@ en: add_key: valid: "Key has been added!" add_item: - name: "The item's name (mandatory" - group: "The group's name" - host: "The hostname or ip" - protocol: "The protocol of the connection (ssh, http, ...)" - login: "The login of connection" - password: "The password" - port: "The connection port" + name: "Item name (mandatory)" + group: "Group name" + host: "Hostname or ip" + protocol: "Connection protocol (ssh, http, ...)" + login: "Connection ID" + password: "Password" + port: "Connection port" comment: "A comment" otp_key: "The OTP secret" valid: "Item has been added!" @@ -110,7 +110,7 @@ en: clean: "The clipboard has been cleaned." login: "The login has been copied in clipboard." password: "The password has been copied in clipboard for 30s!" - otp: "The OTP code has been copied for %{time}s!" + otp: "The OTP code has been copied %{time}s!" url: "The URL has been copied in clipboard." help: name: "Help" @@ -122,18 +122,18 @@ en: delete_key: valid: "Key has been deleted!" delete_item: - ask: "Are you sure you want to remove the item ?" + ask: "Are you sure you want to remove this item ?" valid: "The item has been removed!" import: ask: "Are you sure you want to import this file %{file} ?" file_empty: "The import file is empty!" file_not_exist: "The import file doesn't exist!" - valid: "The import is succesfull!" + valid: "The import is successful!" not_valid: "No data to import!" set_config: valid: "The config file has been edited!" set_wallet_path: - valid: "The wallet has well moved!" + valid: "The wallet has been moved!" setup_config: title: "Setup a new config file" lang: "Choose your language (en, fr, ...) [default=%{lang}]: " @@ -143,36 +143,36 @@ en: valid: "The config file has been created!" setup_gpg_key: title: "Setup a GPG key" - ask: "Do you want create your GPG key ? (Y/n)" - no_create: "You must create manually your GPG key or relaunch the software." + ask: "Do you want to create your GPG key ? (Y/n)" + no_create: "You must to create manually your GPG key or relaunch the software." name: "Your name and lastname: " password: "A password for the GPG key: " confirm_password: "Confirm your password: " error_password: "Your passwords aren't identical!" length: "Size of the GPG key [default=2048]: " expire: "Expire time of the GPG key [default=0 (unlimited)]: " - wait: "Please waiting during the GPG key generate, this process can take few minutes." + wait: "Please wait until GPG key is created, this process can take a few minutes." valid: "Your GPG key has been created ;-)" update_item: - name: "The item's name (mandatory" - group: "The group's name" - host: "The hostname or ip" - protocol: "The protocol of the connection (ssh, http, ...)" - login: "The login of connection" - password: "The password (leave empty if you don't want change)" - port: "The connection port" + name: "Item name (mandatory)" + group: "Group name" + host: "Hostname or ip" + protocol: "Connection protocol (ssh, http, ...)" + login: "Login id" + password: "Password (leave empty if you don't want to update it)" + port: "Connection port" comment: "A comment" - otp_key: "The OTP secret (leave empty if you don't want change" + otp_key: "Secret OTP (leave empty if you don't want to update it" valid: "Item has been updated!" export: - valid: "The export in %{file} is succesfull!" + valid: "The export in %{file} is successful!" display: comment: "Comment" config: "Configuration" error: "ERROR" keys: "GPG keys" - gpg_password: "GPG passphrase: " + gpg_password: "GPG password: " group: "Group" login: "Login" name: "Name" From 767343e36879dee6f9bed415119be93906b66329 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 6 Jun 2017 22:56:23 +0200 Subject: [PATCH 138/165] update version 4.2.0 --- CHANGELOG.md | 43 ++++++++++++++++++++++++++++++++----------- README.md | 2 +- VERSION | 2 +- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fb8d79..2430516 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,9 +1,18 @@ # CHANGELOG -## v4.1.1 +## v4.2.0 (2017-06-06) + + * feat: improve the interface + * feat: add copy url + * feat: add unit tests for cli + * feat: comment the code with yarn syntax + * fix several bugs + * fix translations + +## v4.1.1 (2017-05-03) * fix bug in init -## v4.1.0 +## v4.1.0 (2017-04-22) * feat: add options to update or add an item in command line * feat: print config @@ -12,18 +21,18 @@ * fix: pinentry mode with gpg >= 2.1 * remove SSH and FTP synchronization -## v4.0.0 +## v4.0.0 (2017-03-09) * feature: set default wallet * add option for generate a random password when you update an item * fix encryption when you share an existing wallet * several bugs fix -## v4.0.0-beta1 +## v4.0.0-beta1 (2017-02-16) * add manage share key with new interface -## v4.0.0-beta +## v4.0.0-beta (2016-11-11) * new interface with a table * new command line interface @@ -32,38 +41,50 @@ * several bugs fix * add unit tests -## v3.2.1 +## v3.2.1 (2016-08-06) * fix bug when add a new item -## v3.2.0 +## v3.2.0 (2016-08-03) * add support OTP * fix bug in synchronize * improve interface -## v3.1.0 +## v3.1.0 (2016-07-09) * add clipboard * can change gpg version * minor change in interface * several bugs fix -## v3.0.0 +## v3.0.0 (2016-07-05) * new storage format * new share system * remove MPW server -## v2.0.0 +## v2.0.3 (2015-09-27) + + * add no-sync option + +## v2.0.1 (2015-06-23) + + * fix mpw-ssh + +## v2.0.0 (2015-06-22) * change format csv to yaml * easy install with gem * add sync with ftp and ssh * many improvement -## v1.1.0 +## v1.1.0 (2014-01-28) * Add sync with MPW Server * Add MPW Server * Fix minors bugs + +## v1.0.0 (2014-01-15) + + * first release diff --git a/README.md b/README.md index c1abef6..8a39d81 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # MPW: Manage your passwords! -[](https://github.com/nishiki/manage-password/releases) +[](https://github.com/nishiki/manage-password/releases) [](https://travis-ci.org/nishiki/manage-password) [](https://github.com/nishiki/manage-password/blob/master/LICENSE) diff --git a/VERSION b/VERSION index 627a3f4..6aba2b2 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.1.1 +4.2.0 From 11de55ccb76f6899071130a61ca7ebe0187ad9b9 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 6 Jun 2017 23:06:25 +0200 Subject: [PATCH 139/165] update Gemfile to fix rubocop version --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 56b6638..de2741f 100644 --- a/Gemfile +++ b/Gemfile @@ -8,7 +8,7 @@ gem 'locale', '~> 2.1', '>= 2.1.2' gem 'rotp', '~> 3.1', '>= 3.1.0' group :development do - gem 'rubocop' + gem 'rubocop', '0.48.1' gem 'test-unit' gem 'yard' end From d185509113bc11503d7fcdb788f597df7b81efe5 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 30 Jul 2017 22:30:15 +0200 Subject: [PATCH 140/165] fix bug in otp generator --- CHANGELOG.md | 4 ++++ README.md | 2 +- VERSION | 2 +- lib/mpw/mpw.rb | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2430516..9367be4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ # CHANGELOG +## v4.2.1 (2017-07-30) + + * fix bug in otp generator + ## v4.2.0 (2017-06-06) * feat: improve the interface diff --git a/README.md b/README.md index 8a39d81..e6a119f 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # MPW: Manage your passwords! -[](https://github.com/nishiki/manage-password/releases) +[](https://github.com/nishiki/manage-password/releases) [](https://travis-ci.org/nishiki/manage-password) [](https://github.com/nishiki/manage-password/blob/master/LICENSE) diff --git a/VERSION b/VERSION index 6aba2b2..fae6e3d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.2.0 +4.2.1 diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 5905492..81a0231 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -272,7 +272,7 @@ module MPW # @param id [String] the item id # @return [String] an otp code def get_otp_code(id) - @otp_keys.key?(id) ? 0 : ROTP::TOTP.new(decrypt(@otp_keys[id])).now + @otp_keys.key?(id) ? ROTP::TOTP.new(decrypt(@otp_keys[id])).now : 0 end # Get remaining time before expire otp code From 948db2e905e8801dfd8b7acf4545317865f3c5d9 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Thu, 10 Aug 2017 22:45:03 +0200 Subject: [PATCH 141/165] feat: minor improve clipboard interface --- lib/mpw/cli.rb | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index d92e4e4..33d4151 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -291,6 +291,17 @@ module MPW choice >= 1 && choice <= items.length ? items[choice - 1] : nil end + # Print help message for clipboard mode + # @param item [Item] + def clipboard_help(item) + puts "----- #{I18n.t('form.clipboard.help.name')} -----".cyan + puts I18n.t('form.clipboard.help.url') + puts I18n.t('form.clipboard.help.login') + puts I18n.t('form.clipboard.help.password') + puts I18n.t('form.clipboard.help.otp_code') if item.otp + puts I18n.t('form.clipboard.help.quit') + end + # Copy in clipboard the login and password # @param item [Item] # @param clipboard [Boolean] enable clipboard @@ -339,7 +350,10 @@ module MPW end when 'o', 'otp' - if clipboard + if !item.otp + clipboard_help(item) + next + elsif clipboard Clipboard.copy(@mpw.get_otp_code(item.id)) else puts @mpw.get_otp_code(item.id) @@ -347,13 +361,7 @@ module MPW puts I18n.t('form.clipboard.otp', time: @mpw.get_otp_remaining_time).yellow else - puts "----- #{I18n.t('form.clipboard.help.name')} -----".cyan - puts I18n.t('form.clipboard.help.url') - puts I18n.t('form.clipboard.help.login') - puts I18n.t('form.clipboard.help.password') - puts I18n.t('form.clipboard.help.otp_code') - puts I18n.t('form.clipboard.help.quit') - next + clipboard_help(item) end end From 65db261c00224f8d35f883e703d7a736d79d9f83 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Thu, 10 Aug 2017 23:23:06 +0200 Subject: [PATCH 142/165] feat: minor improve get_item interface --- i18n/en.yml | 4 +++- i18n/fr.yml | 4 +++- lib/mpw/cli.rb | 6 ++++-- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/i18n/en.yml b/i18n/en.yml index b50fd63..962b6ef 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -91,7 +91,9 @@ en: wallet_dir: "Set the wallets folder" form: - select: "Select the item: " + select: + choice: "Select the item: " + error: "No item selected" add_key: valid: "Key has been added!" add_item: diff --git a/i18n/fr.yml b/i18n/fr.yml index d529ee4..e117c1f 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -91,7 +91,9 @@ fr: wallet_dir: "Spécifie le répertoire des portefeuilles" form: - select: "Sélectionner l'élément: " + select: + choice: "Sélectionner l'élément: " + error: "Aucun élément sélectionné" add_key: valid: "La clé a bien été ajoutée!" add_item: diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 33d4151..02d6eb9 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -286,9 +286,11 @@ module MPW return items[0] if items.length == 1 items.sort! { |a, b| a.group.to_s.downcase <=> b.group.to_s.downcase } - choice = ask(I18n.t('form.select')).to_i + choice = ask(I18n.t('form.select.choice')).to_i - choice >= 1 && choice <= items.length ? items[choice - 1] : nil + raise I18n.t('form.select.error') unless choice >= 1 && choice <= items.length + + items[choice - 1] end # Print help message for clipboard mode From 0195771c76a15b83b407c3ca420cd7b0a02530a9 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Thu, 10 Aug 2017 23:41:20 +0200 Subject: [PATCH 143/165] feat: minor improvement add_form interface --- templates/add_form.erb | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/templates/add_form.erb b/templates/add_form.erb index d88874e..89b750e 100644 --- a/templates/add_form.erb +++ b/templates/add_form.erb @@ -1,9 +1,17 @@ --- -host: <%= options[:host] %> # <%= I18n.t('form.add_item.host') %> -user: <%= options[:user] %> # <%= I18n.t('form.add_item.login') %> -group: <%= options[:group] %> # <%= I18n.t('form.add_item.group') %> -protocol: <%= options[:protocol] %> # <%= I18n.t('form.add_item.protocol') %><% unless password %> -password: # <%= I18n.t('form.add_item.password') %><% end %> -port: <%= options[:port] %> # <%= I18n.t('form.add_item.port') %> -comment: <%= options[:comment] %> # <%= I18n.t('form.add_item.comment') %> -otp_key: <%= options[:otp] %> # <%= I18n.t('form.add_item.otp_key') %> +# <%= I18n.t('form.add_item.host') %> +host: <%= options[:host] %> +# <%= I18n.t('form.add_item.login') %> +user: <%= options[:user] %> +# <%= I18n.t('form.add_item.group') %> +group: <%= options[:group] %> +# <%= I18n.t('form.add_item.protocol') %> +protocol: <%= options[:protocol] %><% unless password %> +# <%= I18n.t('form.add_item.password') %> +password:<% end %> +# <%= I18n.t('form.add_item.port') %> +port: <%= options[:port] %> +# <%= I18n.t('form.add_item.comment') %> +comment: <%= options[:comment] %> +# <%= I18n.t('form.add_item.otp_key') %> +otp_key: <%= options[:otp] %> From 8aeb7f5224ad165d657b4fe879c180a65021c0b6 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sat, 12 Aug 2017 01:19:52 +0200 Subject: [PATCH 144/165] feat: alway use absolute path for wallet path --- lib/mpw/config.rb | 1 + test/test_cli.rb | 7 +++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index 016c690..95390a4 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -161,6 +161,7 @@ module MPW # @param wallet [String] wallet name def set_wallet_path(path, wallet) path = @wallet_dir if path == 'default' + path = File.absolute_path(path) return if path == @wallet_dir && File.exist?("#{@wallet_dir}/#{wallet}.mpw") return if path == @wallet_paths[wallet] diff --git a/test/test_cli.rb b/test/test_cli.rb index 8fb91ee..8f5d546 100644 --- a/test/test_cli.rb +++ b/test/test_cli.rb @@ -142,7 +142,6 @@ class TestConfig < Test::Unit::TestCase end def test_07_setup_wallet - path = '/tmp/' gpg_key = 'test2@example.com' output = %x(echo #{@password} | mpw wallet --add-gpg-key #{gpg_key}) @@ -167,14 +166,14 @@ class TestConfig < Test::Unit::TestCase puts output assert_match('| default', output) - output = %x(mpw wallet --path #{path}) + output = %x(mpw wallet --path '.') puts output assert_match(I18n.t('form.set_wallet_path.valid'), output) output = %x(mpw config) puts output - assert_match(%r{path_wallet_default.+\| #{path}/default.mpw}, output) - assert(File.exist?("#{path}/default.mpw")) + assert_match(%r{path_wallet_default.+\| #{Dir.pwd}/default.mpw}, output) + assert(File.exist?("#{Dir.pwd}/default.mpw")) output = %x(mpw wallet --default-path) puts output From b2a38ccd4eeeef088fe0d6bd690b778bd1e2b589 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 15 Aug 2017 21:13:34 +0200 Subject: [PATCH 145/165] update version to 4.2.2 --- CHANGELOG.md | 4 ++++ README.md | 2 +- VERSION | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9367be4..199b863 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ # CHANGELOG +## v4.2.2 (2017-08-15) + + * minor improvements in the interface + ## v4.2.1 (2017-07-30) * fix bug in otp generator diff --git a/README.md b/README.md index e6a119f..9c2c5d6 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # MPW: Manage your passwords! -[](https://github.com/nishiki/manage-password/releases) +[](https://github.com/nishiki/manage-password/releases) [](https://travis-ci.org/nishiki/manage-password) [](https://github.com/nishiki/manage-password/blob/master/LICENSE) diff --git a/VERSION b/VERSION index fae6e3d..af8c8ec 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -4.2.1 +4.2.2 From e2b455798128c0bb58c5ff423491660cbaaf54cc Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 3 Sep 2017 02:37:17 +0200 Subject: [PATCH 146/165] feat: add import gorilla file --- bin/mpw-import | 14 ++++++++-- i18n/en.yml | 4 ++- i18n/fr.yml | 4 ++- lib/mpw/cli.rb | 25 +++++++++++------ lib/mpw/import/gorilla.rb | 57 +++++++++++++++++++++++++++++++++++++++ lib/mpw/import/mpw.rb | 29 ++++++++++++++++++++ lib/mpw/item.rb | 12 ++++----- 7 files changed, 126 insertions(+), 19 deletions(-) create mode 100644 lib/mpw/import/gorilla.rb create mode 100644 lib/mpw/import/mpw.rb diff --git a/bin/mpw-import b/bin/mpw-import index 0502b2b..76e163e 100644 --- a/bin/mpw-import +++ b/bin/mpw-import @@ -24,7 +24,13 @@ require 'mpw/cli' # Options # --------------------------------------------------------- # -options = {} +formats = + Dir["#{File.expand_path('../../lib/mpw/import', __FILE__)}/*.rb"] + .map { |v| File.basename(v, '.rb') } + .join(', ') +options = { + format: 'mpw' +} OptionParser.new do |opts| opts.banner = "#{I18n.t('option.usage')}: mpw import [options]" @@ -37,6 +43,10 @@ OptionParser.new do |opts| options[:file] = file end + opts.on('-F', '--format STRING', I18n.t('option.file_format', formats: formats)) do |format| + options[:format] = format + end + opts.on('-h', '--help', I18n.t('option.help')) do puts opts exit 0 @@ -53,4 +63,4 @@ cli = MPW::Cli.new(config) cli.load_config cli.get_wallet(options[:wallet]) cli.decrypt -cli.import(options[:file]) +cli.import(options[:file], options[:format]) diff --git a/i18n/en.yml b/i18n/en.yml index 962b6ef..2375084 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -22,7 +22,7 @@ en: write_data: "Can't write the MPW file!" import: "Can't import, unable to read %{file}!" update: - host_empty: "You must define a host!" + host_and_comment_empty: "You must define a host or a comment!" warning: select: 'Your choice is not a valid item!' @@ -55,6 +55,7 @@ en: disable_special_chars: "Don't use special char to create a password" export: "Export a wallet in an yaml file" file_export: "Specify the file to export data" + file_format: "Format of import file (default: mpw; available: %{formats})" file_import: "Specify the file to import" force: "Do not ask confirmation when deleting an item" generate_password: "Create a random password (default 8 characters)" @@ -130,6 +131,7 @@ en: ask: "Are you sure you want to import this file %{file} ?" file_empty: "The import file is empty!" file_not_exist: "The import file doesn't exist!" + format_unknown: "The import format '%{file_format} is unknown!" valid: "The import is successful!" not_valid: "No data to import!" set_config: diff --git a/i18n/fr.yml b/i18n/fr.yml index e117c1f..9ab2e58 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -22,7 +22,7 @@ fr: write_data: "Impossible d'écrire le fichier MPW!" import: "Impossible d'importer le fichier %{file}, car il n'est pas lisible!" update: - host_empty: "Vous devez définir un host!" + host_and_comment_empty: "Vous devez définir un host ou un commentaire!" warning: select: "Votre choix n'est pas un élément valide!" @@ -55,6 +55,7 @@ fr: disable_special_chars: "Désactive l'utilisation des charactères speciaux dans la génération d'un mot de passe" export: "Exporte un portefeuille dans un fichier yaml" file_export: "Spécifie le fichier où exporter les données" + file_format: "Format du fichier d'import (défault: mpw; disponible: %{formats})" file_import: "Spécifie le fichier à importer" force: "Ne demande pas de confirmation pour la suppression d'un élément" generate_password: "Génére un mot de passe aléatoire (défaut 8 caractères)" @@ -130,6 +131,7 @@ fr: ask: "Êtes vous sûre de vouloir importer le fichier %{file} ?" file_empty: "Le fichier d'import est vide!" file_not_exist: "Le fichier d'import n'existe pas" + format_unknown: "Le format d'import '%{file_format}' est inconnu!" valid: "L'import est un succès!" not_valid: "Aucune donnée à importer!" set_config: diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 02d6eb9..17701b6 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -586,17 +586,26 @@ module MPW # Import items from an yaml file # @param file [String] path of import file - def import(file) + # @param format [String] the software import file format + def import(file, format = 'mpw') raise I18n.t('form.import.file_empty') if file.to_s.empty? raise I18n.t('form.import.file_not_exist') unless File.exist?(file) - YAML.load_file(file).each_value do |row| - item = Item.new(group: row['group'], - host: row['host'], - protocol: row['protocol'], - user: row['user'], - port: row['port'], - comment: row['comment']) + begin + require "mpw/import/#{format}" + rescue LoadError + raise I18n.t('form.import.format_unknown', file_format: format) + end + + Import.send(format, file).each_value do |row| + item = Item.new( + group: row['group'], + host: row['host'], + protocol: row['protocol'], + user: row['user'], + port: row['port'], + comment: row['comment'] + ) next if item.empty? diff --git a/lib/mpw/import/gorilla.rb b/lib/mpw/import/gorilla.rb new file mode 100644 index 0000000..0ab5dc3 --- /dev/null +++ b/lib/mpw/import/gorilla.rb @@ -0,0 +1,57 @@ +#!/usr/bin/ruby +# MPW is a software to crypt and manage your passwords +# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> +# +# 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 2 +# 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'csv' + +module MPW + module Import + # Import an export mpw file + # @param file [String] the file path to import + def self.gorilla(file) + data = {} + + CSV.foreach(file, headers: true) do |row| + id = row['uuid'] + comment = + if row['title'] && row['notes'] + "#{row['title']} #{row['notes']}" + elsif row['title'] + row['title'] + elsif row['notes'] + row['notes'] + end + + data[id] = { + 'group' => row['group'], + 'host' => row['url'], + 'user' => row['user'], + 'password' => row['password'], + 'comment' => comment + } + + if row['url'] =~ %r{^((?<protocol>[a-z]+)://)?(?<host>[a-zA-Z0-9_.-]+)(:(?<port>[0-9]{1,5}))?$} + data[id]['protocol'] = Regexp.last_match(:protocol) + data[id]['port'] = Regexp.last_match(:port) + data[id]['host'] = Regexp.last_match(:host) + end + end + + data + end + end +end diff --git a/lib/mpw/import/mpw.rb b/lib/mpw/import/mpw.rb new file mode 100644 index 0000000..8d6b1c4 --- /dev/null +++ b/lib/mpw/import/mpw.rb @@ -0,0 +1,29 @@ +#!/usr/bin/ruby +# MPW is a software to crypt and manage your passwords +# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> +# +# 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 2 +# 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'yaml' + +module MPW + module Import + # Import an export mpw file + # @param file [String] the file path to import + def self.mpw(file) + YAML.load_file(file) + end + end +end diff --git a/lib/mpw/item.rb b/lib/mpw/item.rb index be03dba..4e17912 100644 --- a/lib/mpw/item.rb +++ b/lib/mpw/item.rb @@ -33,9 +33,7 @@ module MPW # @param options [Hash] the option :host is required def initialize(**options) - if !options.key?(:host) || options[:host].to_s.empty? - raise I18n.t('error.update.host_empty') - end + @host = '' if !options.key?(:id) || options[:id].to_s.empty? || !options.key?(:created) || options[:created].to_s.empty? @id = generate_id @@ -53,12 +51,12 @@ module MPW # Update the item # @param options [Hash] def update(**options) - if options.key?(:host) && options[:host].to_s.empty? - raise I18n.t('error.update.host_empty') + unless options[:host] || options[:comment] + raise I18n.t('error.update.host_and_comment_empty') end @group = options[:group] if options.key?(:group) - @host = options[:host] if options.key?(:host) + @host = options[:host] if options.key?(:host) && !options[:host].nil? @protocol = options[:protocol] if options.key?(:protocol) @user = options[:user] if options.key?(:user) @port = options[:port].to_i if options.key?(:port) && !options[:port].to_s.empty? @@ -86,7 +84,7 @@ module MPW def url url = '' url += "#{@protocol}://" if @protocol - url += @host + url += @host if @host url += ":#{@port}" if @port url From 2a647afb10c205a1d62b75b91b6ca9a53133cae5 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 3 Sep 2017 10:23:44 +0200 Subject: [PATCH 147/165] fix: force system on travis --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 525a9d0..57c6924 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ language: ruby +dist: precise rvm: - 2.4.1 - 2.3.4 From 42629c61b35da7bf7eb22e78e1f56839bcf35ecf Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 3 Sep 2017 15:10:01 +0200 Subject: [PATCH 148/165] feat: add test for import --- .travis.yml | 1 + test/files/import-gorilla.txt | 4 +++ test/test_cli.rb | 12 +++++---- test/test_import.rb | 46 +++++++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 5 deletions(-) create mode 100644 test/files/import-gorilla.txt create mode 100644 test/test_import.rb diff --git a/.travis.yml b/.travis.yml index 57c6924..e289bcf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,3 +19,4 @@ script: - ruby ./test/test_translate.rb - ruby ./test/init.rb - ruby ./test/test_cli.rb + - ruby ./test/test_import.rb diff --git a/test/files/import-gorilla.txt b/test/files/import-gorilla.txt new file mode 100644 index 0000000..a5fc604 --- /dev/null +++ b/test/files/import-gorilla.txt @@ -0,0 +1,4 @@ +uuid,group,title,url,user,password,notes +49627979-e393-48c4-49ca-1cf66603238e,Bank,Fric,http://fric.com,12345,secret,money money +49627979-e393-48c4-49ca-1cf66603238f,,My little server,server.com,secret2, +49627979-e393-48c4-49ca-1cf66603238g,Cloud,,ssh://fric.com:4333,username,secret,bastion diff --git a/test/test_cli.rb b/test/test_cli.rb index 8f5d546..f4cf356 100644 --- a/test/test_cli.rb +++ b/test/test_cli.rb @@ -185,15 +185,16 @@ class TestConfig < Test::Unit::TestCase end def test_08_setup_config - gpg_key = 'user@example2.com' + gpg_key = 'test2@example.com' gpg_exe = '/usr/bin/gpg2' - wallet_dir = '/tmp/mpw' + wallet_dir = '/tmp' length = 24 wallet = 'work' output = %x( mpw config \ --gpg-exe #{gpg_exe} \ + --key #{gpg_key} \ --enable-pinmode \ --disable-alpha \ --disable-special-chars \ @@ -207,7 +208,7 @@ class TestConfig < Test::Unit::TestCase output = %x(mpw config) puts output - assert_match(/gpg_key.+\| #{@gpg_key}/, output) + assert_match(/gpg_key.+\| #{gpg_key}/, output) assert_match(/gpg_exe.+\| #{gpg_exe}/, output) assert_match(/pinmode.+\| true/, output) assert_match(/default_wallet.+\| #{wallet}/, output) @@ -219,7 +220,8 @@ class TestConfig < Test::Unit::TestCase output = %x( mpw config \ - --key #{gpg_key} \ + --gpg-exe '' \ + --key #{@gpg_key} \ --alpha \ --special-chars \ --numeric \ @@ -230,7 +232,7 @@ class TestConfig < Test::Unit::TestCase output = %x(mpw config) puts output - assert_match(/gpg_key.+\| #{gpg_key}/, output) + assert_match(/gpg_key.+\| #{@gpg_key}/, output) assert_match(/pinmode.+\| false/, output) %w[numeric alpha special].each do |k| assert_match(/password_#{k}.+\| true/, output) diff --git a/test/test_import.rb b/test/test_import.rb new file mode 100644 index 0000000..c27b58f --- /dev/null +++ b/test/test_import.rb @@ -0,0 +1,46 @@ +#!/usr/bin/ruby + +require 'i18n' +require 'test/unit' + +class TestImport < Test::Unit::TestCase + def setup + if defined?(I18n.enforce_available_locales) + I18n.enforce_available_locales = true + end + + I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks) + I18n.load_path = ["#{File.expand_path('../../i18n', __FILE__)}/en.yml"] + I18n.locale = :en + + @password = 'password' + end + + def test_00_import + Dir['./test/files/import-*.txt'].each do |file| + format = File.basename(file, '.txt').partition('-').last + + puts format + + output = %x( + mpw import \ + --file #{file} \ + --format #{format} \ + --wallet #{format} + ) + assert_match(I18n.t('form.import.valid'), output) + + output = %x(echo #{@password} | mpw list --group Bank --wallet #{format}) + puts output + assert_match(%r{http://.*fric\.com.*12345.*Fric money money}, output) + + output = %x(echo #{@password} | mpw list --group Cloud --wallet #{format}) + puts output + assert_match(%r{ssh://.*fric\.com.*:4333.*username.*bastion}, output) + + output = %x(echo #{@password} | mpw list --wallet #{format}) + puts output + assert_match(/server\.com.*My little server/, output) + end + end +end From cf5b7e014213d592ceb9bf975b137a4c57f03810 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 17 Sep 2017 16:25:05 +0200 Subject: [PATCH 149/165] fix travis tests --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index e289bcf..7f524d4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,8 @@ rvm: - 2.2.7 - 2.1.10 install: + - sudo cp -a /dev/urandom /dev/random + - sudo apt-get purge -y gnupg-agent gnupg2 - bundle install - echo 9999 > VERSION - gem build mpw.gemspec From 8b5c7ae581e391b3c81b079816adb993217d43ec Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 5 Sep 2017 22:16:37 +0200 Subject: [PATCH 150/165] feat: major change the url storage --- bin/mpw-add | 18 +++------- bin/mpw-update | 18 +++------- i18n/en.yml | 4 +-- i18n/fr.yml | 4 +-- lib/mpw/cli.rb | 22 +++++------- lib/mpw/import/gorilla.rb | 12 ++----- lib/mpw/item.rb | 63 ++++++++++++++++------------------ lib/mpw/mpw.rb | 8 ++--- templates/add_form.erb | 10 ++---- templates/update_form.erb | 8 ++--- test/files/fixtures-import.yml | 9 ++--- test/files/fixtures.yml | 3 ++ test/test_cli.rb | 14 ++++---- test/test_item.rb | 31 +++++++---------- test/test_mpw.rb | 8 ++--- 15 files changed, 87 insertions(+), 145 deletions(-) diff --git a/bin/mpw-add b/bin/mpw-add index 2c2e996..1d0581a 100644 --- a/bin/mpw-add +++ b/bin/mpw-add @@ -48,22 +48,10 @@ OptionParser.new do |opts| exit 0 end - opts.on('-H', '--host HOST', I18n.t('option.host')) do |host| - values[:host] = host - end - opts.on('-o', '--otp-code CODE', I18n.t('option.otp_code')) do |otp| values[:otp_key] = otp end - opts.on('-O', '--protocol PROTOCOL', I18n.t('option.protocol')) do |protocol| - values[:protocol] = protocol - end - - opts.on('-P', '--port NUMBER', I18n.t('option.port')) do |port| - values[:port] = port - end - opts.on('-r', '--random', I18n.t('option.random_password')) do options[:password] = true end @@ -72,7 +60,11 @@ OptionParser.new do |opts| options[:text_editor] = true end - opts.on('-u', '--user USER', I18n.t('option.user')) do |user| + opts.on('-u', '--url URL', I18n.t('option.url')) do |url| + values[:url] = url + end + + opts.on('-U', '--user USER', I18n.t('option.user')) do |user| values[:user] = user end diff --git a/bin/mpw-update b/bin/mpw-update index 143e187..d15b8e7 100644 --- a/bin/mpw-update +++ b/bin/mpw-update @@ -53,26 +53,14 @@ OptionParser.new do |opts| exit 0 end - opts.on('-H', '--host HOST', I18n.t('option.host')) do |host| - values[:host] = host - end - opts.on('-o', '--otp-code CODE', I18n.t('option.otp_code')) do |otp| values[:otp_key] = otp end - opts.on('-O', '--protocol PROTOCOL', I18n.t('option.protocol')) do |protocol| - values[:protocol] = protocol - end - opts.on('-p', '--pattern PATTERN', I18n.t('option.pattern')) do |pattern| search[:pattern] = pattern end - opts.on('-P', '--port NUMBER', I18n.t('option.port')) do |port| - values[:port] = port - end - opts.on('-r', '--random', I18n.t('option.random_password')) do options[:password] = true end @@ -81,7 +69,11 @@ OptionParser.new do |opts| options[:text_editor] = true end - opts.on('-u', '--user USER', I18n.t('option.user')) do |user| + opts.on('-u', '--url URL', I18n.t('option.url')) do |url| + values[:url] = url + end + + opts.on('-U', '--user USER', I18n.t('option.user')) do |user| values[:user] = user end diff --git a/i18n/en.yml b/i18n/en.yml index 2375084..9df7bda 100644 --- a/i18n/en.yml +++ b/i18n/en.yml @@ -63,7 +63,6 @@ en: gpg_key: "Specify a GPG key (ex: user@example.com)" group: "Search the items with specified group" help: "Show this help message" - host: "Specify a host or ip" init: "Initialize mpw" import: "Import item from an yaml file" key: "Define the key name" @@ -77,8 +76,6 @@ en: path: "Move the wallet in new specify directory" pattern: "Given search pattern" pinmode: "Enable pinentry mode (available with gpg >= 2.1)" - port: "Set a port of connexion" - protocol: "Set a protocol of connexion" random_password: "Generate a random password" setup: "Create a new configuration file" setup_wallet: "Create a new configuration file for a wallet" @@ -87,6 +84,7 @@ en: show_all: "Listing all items" text_editor: "Use text editor to edit the item" usage: "Use" + url: "Set an url (ex: https://example.com/path)" user: "Set an user" wallet: "Specify a wallet to use" wallet_dir: "Set the wallets folder" diff --git a/i18n/fr.yml b/i18n/fr.yml index 9ab2e58..04583ad 100644 --- a/i18n/fr.yml +++ b/i18n/fr.yml @@ -63,7 +63,6 @@ fr: gpg_key: "Spécifie une clé GPG (ex: user@example.com)" group: "Recherche les éléments appartenant au groupe spécifié" help: "Affiche ce message d'aide" - host: "Spécifie le nom du serveur ou l'ip" import: "Importe des éléments depuis un fichier yaml" init: "Initialise mpw" key: "Spécifie le nom d'une clé" @@ -77,8 +76,6 @@ fr: path: "Déplace le portefeuille dans un nouveau dossier" pattern: "Motif de donnée à chercher" pinmode: "Active le mode pinentry (valable avec gpg >= 2.1)" - port: "Spécifie un port de connexion" - protocol: "Spécifie un protocol de connexion" random_password: "Génére un mot de passe aléatoire" setup: "Création d'un nouveau fichier de configuration" setup_wallet: "Création d'un nouveau fichier de configuration pour un portefeuille" @@ -87,6 +84,7 @@ fr: show_all: "Liste tous les éléments" text_editor: "Active l'édition avec un éditeur de texte" usage: "Utilisation" + url: "Spécifie l'url (ex: http://example.com/path)" user: "Spécifie un utilisateur" wallet: "Spécifie le portefeuille à utiliser" wallet_dir: "Spécifie le répertoire des portefeuilles" diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 17701b6..d54b314 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -563,16 +563,14 @@ module MPW items.each do |item| data.merge!( item.id => { - 'host' => item.host, - 'user' => item.user, - 'group' => item.group, - 'password' => @mpw.get_password(item.id), - 'protocol' => item.protocol, - 'port' => item.port, - 'otp_key' => @mpw.get_otp_key(item.id), 'comment' => item.comment, - 'last_edit' => item.last_edit, 'created' => item.created, + 'group' => item.group, + 'last_edit' => item.last_edit, + 'otp_key' => @mpw.get_otp_key(item.id), + 'password' => @mpw.get_password(item.id), + 'url' => item.url, + 'user' => item.user } ) end @@ -599,12 +597,10 @@ module MPW Import.send(format, file).each_value do |row| item = Item.new( + comment: row['comment'], group: row['group'], - host: row['host'], - protocol: row['protocol'], - user: row['user'], - port: row['port'], - comment: row['comment'] + url: row['url'], + user: row['user'] ) next if item.empty? diff --git a/lib/mpw/import/gorilla.rb b/lib/mpw/import/gorilla.rb index 0ab5dc3..fd5d9f1 100644 --- a/lib/mpw/import/gorilla.rb +++ b/lib/mpw/import/gorilla.rb @@ -37,18 +37,12 @@ module MPW end data[id] = { + 'comment' => comment, 'group' => row['group'], - 'host' => row['url'], - 'user' => row['user'], 'password' => row['password'], - 'comment' => comment + 'url' => row['url'], + 'user' => row['user'] } - - if row['url'] =~ %r{^((?<protocol>[a-z]+)://)?(?<host>[a-zA-Z0-9_.-]+)(:(?<port>[0-9]{1,5}))?$} - data[id]['protocol'] = Regexp.last_match(:protocol) - data[id]['port'] = Regexp.last_match(:port) - data[id]['host'] = Regexp.last_match(:host) - end end data diff --git a/lib/mpw/item.rb b/lib/mpw/item.rb index 4e17912..ec8ab0e 100644 --- a/lib/mpw/item.rb +++ b/lib/mpw/item.rb @@ -17,25 +17,27 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. require 'i18n' +require 'uri' module MPW class Item - attr_accessor :id + attr_accessor :created + attr_accessor :comment attr_accessor :group attr_accessor :host - attr_accessor :protocol - attr_accessor :user - attr_accessor :port + attr_accessor :id attr_accessor :otp - attr_accessor :comment + attr_accessor :port + attr_accessor :protocol attr_accessor :last_edit - attr_accessor :created + attr_accessor :url + attr_accessor :user # @param options [Hash] the option :host is required def initialize(**options) @host = '' - if !options.key?(:id) || options[:id].to_s.empty? || !options.key?(:created) || options[:created].to_s.empty? + if !options[:id] || !options[:created] @id = generate_id @created = Time.now.to_i else @@ -51,43 +53,38 @@ module MPW # Update the item # @param options [Hash] def update(**options) - unless options[:host] || options[:comment] + unless options[:url] || options[:comment] raise I18n.t('error.update.host_and_comment_empty') end - @group = options[:group] if options.key?(:group) - @host = options[:host] if options.key?(:host) && !options[:host].nil? - @protocol = options[:protocol] if options.key?(:protocol) - @user = options[:user] if options.key?(:user) - @port = options[:port].to_i if options.key?(:port) && !options[:port].to_s.empty? - @otp = options[:otp] if options.key?(:otp) - @comment = options[:comment] if options.key?(:comment) - @last_edit = Time.now.to_i unless options.key?(:no_update_last_edit) + if options[:url] + uri = URI(options[:url]) + @host = uri.host || options[:url] + @port = uri.port || nil + @protocol = uri.scheme || nil + @url = options[:url] + end + + @comment = options[:comment] if options.key?(:comment) + @group = options[:group] if options.key?(:group) + @last_edit = Time.now.to_i unless options.key?(:no_update_last_edit) + @otp = options[:otp] if options.key?(:otp) + @user = options[:user] if options.key?(:user) end # Delete all data def delete @id = nil - @group = nil - @host = nil - @protocol = nil - @user = nil - @port = nil - @otp = nil @comment = nil @created = nil + @group = nil + @host = nil @last_edit = nil - end - - # Return data on url format - # @return [String] an url - def url - url = '' - url += "#{@protocol}://" if @protocol - url += @host if @host - url += ":#{@port}" if @port - - url + @otp = nil + @port = nil + @protocol = nil + @url = nil + @user = nil end def empty? diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 81a0231..a5fc0ae 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -84,10 +84,8 @@ module MPW Item.new( id: d['id'], group: d['group'], - host: d['host'], - protocol: d['protocol'], user: d['user'], - port: d['port'], + url: d['url'], otp: @otp_keys.key?(d['id']), comment: d['comment'], last_edit: d['last_edit'], @@ -114,10 +112,8 @@ module MPW item.id => { 'id' => item.id, 'group' => item.group, - 'host' => item.host, - 'protocol' => item.protocol, 'user' => item.user, - 'port' => item.port, + 'url' => item.url, 'comment' => item.comment, 'last_edit' => item.last_edit, 'created' => item.created, diff --git a/templates/add_form.erb b/templates/add_form.erb index 89b750e..e2aea20 100644 --- a/templates/add_form.erb +++ b/templates/add_form.erb @@ -1,16 +1,12 @@ --- -# <%= I18n.t('form.add_item.host') %> -host: <%= options[:host] %> +# <%= I18n.t('form.add_item.url') %> +url: <%= options[:url] %> # <%= I18n.t('form.add_item.login') %> user: <%= options[:user] %> # <%= I18n.t('form.add_item.group') %> -group: <%= options[:group] %> -# <%= I18n.t('form.add_item.protocol') %> -protocol: <%= options[:protocol] %><% unless password %> +group: <%= options[:group] %><% unless password %> # <%= I18n.t('form.add_item.password') %> password:<% end %> -# <%= I18n.t('form.add_item.port') %> -port: <%= options[:port] %> # <%= I18n.t('form.add_item.comment') %> comment: <%= options[:comment] %> # <%= I18n.t('form.add_item.otp_key') %> diff --git a/templates/update_form.erb b/templates/update_form.erb index 5037568..eafeb1b 100644 --- a/templates/update_form.erb +++ b/templates/update_form.erb @@ -1,16 +1,12 @@ --- -# <%= I18n.t('form.update_item.host') %> -host: <% if options[:host] %><%= options[:host] %><% else %><%= item.host %><% end %> +# <%= I18n.t('form.update_item.url') %> +host: <% if options[:url] %><%= options[:url] %><% else %><%= item.url %><% end %> # <%= I18n.t('form.update_item.login') %> user: <% if options[:user] %><%= options[:user] %><% else %><%= item.user %><% end %><% unless password %> # <%= I18n.t('form.update_item.password') %> password: <% end %> # <%= I18n.t('form.update_item.group') %> group: <% if options[:group] %><%= options[:group] %><% else %><%= item.group %><% end %> -# <%= I18n.t('form.update_item.protocol') %> -protocol: <% if options[:protocol] %><%= options[:protocol] %><% else %><%= item.protocol %><% end %> -# <%= I18n.t('form.update_item.port') %> -port: <% if options[:port] %><%= options[:port] %><% else %><%= item.port %><% end %> # <%= I18n.t('form.update_item.otp_key') %> otp_key: <% if options[:otp_key] %><%= options[:otp_key] %><% end %> # <%= I18n.t('form.update_item.comment') %> diff --git a/test/files/fixtures-import.yml b/test/files/fixtures-import.yml index f79ab0a..8cb1ff4 100644 --- a/test/files/fixtures-import.yml +++ b/test/files/fixtures-import.yml @@ -1,19 +1,16 @@ --- 1: - host: fric.com + url: https://fric.com user: 230403 group: Bank password: 5XdiTQOubRDw9B0aJoMlcEyL - protocol: https - port: otp_key: 330223432 comment: I love my bank 2: - host: assurance.com + url: https://assurance.com:443 user: user_2132 + host: assurance.com group: Assurance password: DMyK6B3v4bWO52VzU7aTHIem - protocol: https - port: 443 otp_key: comment: diff --git a/test/files/fixtures.yml b/test/files/fixtures.yml index 765314e..d8927cb 100644 --- a/test/files/fixtures.yml +++ b/test/files/fixtures.yml @@ -1,4 +1,5 @@ add: + url: 'https://example.com:8080' group: 'Bank' host: 'example.com' protocol: 'https' @@ -9,6 +10,7 @@ add: import: id: 'TEST-ID-XXXXX' + url: 'https://gogole.com:8081/toto' group: 'Cloud' host: 'gogole.com' protocol: 'https' @@ -19,6 +21,7 @@ import: created: 1386752948 update: + url: 'ssh://example2.com:2222' group: 'Assurance' host: 'example2.com' protocol: 'ssh' diff --git a/test/test_cli.rb b/test/test_cli.rb index f4cf356..07c4273 100644 --- a/test/test_cli.rb +++ b/test/test_cli.rb @@ -29,9 +29,7 @@ class TestConfig < Test::Unit::TestCase output = %x( echo #{@password} | mpw add \ - --host #{data['host']} \ - --port #{data['port']} \ - --protocol #{data['protocol']} \ + --url #{data['url']} \ --user #{data['user']} \ --comment '#{data['comment']}' \ --group #{data['group']} \ @@ -73,9 +71,7 @@ class TestConfig < Test::Unit::TestCase output = %x( echo #{@password} | mpw update \ -p #{@fixtures['add']['host']} \ - --host #{data['host']} \ - --port #{data['port']} \ - --protocol #{data['protocol']} \ + --url #{data['url']} \ --user #{data['user']} \ --comment '#{data['comment']}' \ --new-group #{data['group']} @@ -117,20 +113,22 @@ class TestConfig < Test::Unit::TestCase error = true YAML.load_file(file_export).each_value do |export| - next if import['host'] != export['host'] + next if import['url'] != export['url'] %w[user group password protocol port otp_key comment].each do |key| assert_equal(import[key].to_s, export[key].to_s) end error = false + break end + assert(!error) end end def test_06_copy - data = YAML.load_file('./test/files/fixtures-import.yml')[1] + data = YAML.load_file('./test/files/fixtures-import.yml')[2] output = %x( echo "#{@password}\np\nq" | mpw copy \ diff --git a/test/test_item.rb b/test/test_item.rb index c83cbc3..80e39ff 100644 --- a/test/test_item.rb +++ b/test/test_item.rb @@ -23,10 +23,8 @@ class TestItem < Test::Unit::TestCase def test_01_add data = { group: @fixtures['add']['group'], - host: @fixtures['add']['host'], - protocol: @fixtures['add']['protocol'], user: @fixtures['add']['user'], - port: @fixtures['add']['port'], + url: @fixtures['add']['url'], comment: @fixtures['add']['comment'] } @@ -35,6 +33,7 @@ class TestItem < Test::Unit::TestCase assert(!item.nil?) assert(!item.empty?) + assert_equal(@fixtures['add']['url'], item.url) assert_equal(@fixtures['add']['group'], item.group) assert_equal(@fixtures['add']['host'], item.host) assert_equal(@fixtures['add']['protocol'], item.protocol) @@ -47,10 +46,8 @@ class TestItem < Test::Unit::TestCase data = { id: @fixtures['import']['id'], group: @fixtures['import']['group'], - host: @fixtures['import']['host'], - protocol: @fixtures['import']['protocol'], user: @fixtures['import']['user'], - port: @fixtures['import']['port'], + url: @fixtures['import']['url'], comment: @fixtures['import']['comment'], created: @fixtures['import']['created'] } @@ -61,6 +58,7 @@ class TestItem < Test::Unit::TestCase assert(!item.empty?) assert_equal(@fixtures['import']['id'], item.id) + assert_equal(@fixtures['import']['url'], item.url) assert_equal(@fixtures['import']['group'], item.group) assert_equal(@fixtures['import']['host'], item.host) assert_equal(@fixtures['import']['protocol'], item.protocol) @@ -73,10 +71,8 @@ class TestItem < Test::Unit::TestCase def test_03_update data = { group: @fixtures['add']['group'], - host: @fixtures['add']['host'], - protocol: @fixtures['add']['protocol'], user: @fixtures['add']['user'], - port: @fixtures['add']['port'], + url: @fixtures['add']['url'], comment: @fixtures['add']['comment'] } @@ -90,10 +86,8 @@ class TestItem < Test::Unit::TestCase data = { group: @fixtures['update']['group'], - host: @fixtures['update']['host'], - protocol: @fixtures['update']['protocol'], user: @fixtures['update']['user'], - port: @fixtures['update']['port'], + url: @fixtures['update']['url'], comment: @fixtures['update']['comment'] } @@ -102,6 +96,7 @@ class TestItem < Test::Unit::TestCase assert(!item.empty?) + assert_equal(@fixtures['update']['url'], item.url) assert_equal(@fixtures['update']['group'], item.group) assert_equal(@fixtures['update']['host'], item.host) assert_equal(@fixtures['update']['protocol'], item.protocol) @@ -116,10 +111,8 @@ class TestItem < Test::Unit::TestCase def test_05_update_one_element data = { group: @fixtures['add']['group'], - host: @fixtures['add']['host'], - protocol: @fixtures['add']['protocol'], user: @fixtures['add']['user'], - port: @fixtures['add']['port'], + url: @fixtures['add']['url'], comment: @fixtures['add']['comment'] } @@ -131,8 +124,9 @@ class TestItem < Test::Unit::TestCase last_edit = item.last_edit sleep(1) - assert(item.update(comment: @fixtures['update']['comment'])) + item.update(comment: @fixtures['update']['comment']) + assert_equal(@fixtures['add']['url'], item.url) assert_equal(@fixtures['add']['group'], item.group) assert_equal(@fixtures['add']['host'], item.host) assert_equal(@fixtures['add']['protocol'], item.protocol) @@ -146,10 +140,8 @@ class TestItem < Test::Unit::TestCase def test_05_delete data = { group: @fixtures['add']['group'], - host: @fixtures['add']['host'], - protocol: @fixtures['add']['protocol'], user: @fixtures['add']['user'], - port: @fixtures['add']['port'], + url: @fixtures['add']['url'], comment: @fixtures['add']['comment'] } @@ -163,6 +155,7 @@ class TestItem < Test::Unit::TestCase assert(item.empty?) assert_equal(nil, item.id) + assert_equal(nil, item.url) assert_equal(nil, item.group) assert_equal(nil, item.host) assert_equal(nil, item.protocol) diff --git a/test/test_mpw.rb b/test/test_mpw.rb index a783225..a1633ef 100644 --- a/test/test_mpw.rb +++ b/test/test_mpw.rb @@ -33,10 +33,8 @@ class TestMPW < Test::Unit::TestCase def test_02_add_item data = { group: @fixtures['add']['group'], - host: @fixtures['add']['host'], - protocol: @fixtures['add']['protocol'], user: @fixtures['add']['user'], - port: @fixtures['add']['port'], + url: @fixtures['add']['url'], comment: @fixtures['add']['comment'] } @@ -93,10 +91,8 @@ class TestMPW < Test::Unit::TestCase @fixtures.each_value do |v| data = { group: v['group'], - host: v['host'], - protocol: v['protocol'], user: v['user'], - port: v['port'], + url: v['url'], comment: v['comment'] } From dd02776baa297adca47dc344984723ab842ee1dd Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 17 Sep 2017 22:47:59 +0200 Subject: [PATCH 151/165] feat: add import old version of mpw --- lib/mpw/import/mpw_old.rb | 46 +++++++++++++++++++++++++++++++++++ test/files/import-mpw_old.txt | 35 ++++++++++++++++++++++++++ 2 files changed, 81 insertions(+) create mode 100644 lib/mpw/import/mpw_old.rb create mode 100644 test/files/import-mpw_old.txt diff --git a/lib/mpw/import/mpw_old.rb b/lib/mpw/import/mpw_old.rb new file mode 100644 index 0000000..f6957fe --- /dev/null +++ b/lib/mpw/import/mpw_old.rb @@ -0,0 +1,46 @@ +#!/usr/bin/ruby +# MPW is a software to crypt and manage your passwords +# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> +# +# 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 2 +# 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'yaml' + +module MPW + module Import + # Import an export mpw file + # @param file [String] the file path to import + def self.mpw_old(file) + data = {} + YAML.load_file(file).each do |id, item| + url = '' + url += "#{item['protocol']}://" if item['protocol'] + url += item['host'] + url += ":#{item['port']}" if item['port'] + + data[id] = { + 'comment' => item['comment'], + 'group' => item['group'], + 'otp' => item['otp'], + 'password' => item['password'], + 'url' => url, + 'user' => item['user'] + } + end + + data + end + end +end diff --git a/test/files/import-mpw_old.txt b/test/files/import-mpw_old.txt new file mode 100644 index 0000000..fd162aa --- /dev/null +++ b/test/files/import-mpw_old.txt @@ -0,0 +1,35 @@ +--- +1: + host: fric.com + user: 12345 + group: Bank + password: secret + protocol: http + port: + otp_key: + comment: Fric money money + last_edit: 1487623641 + created: 1485729356 +2: + host: server.com + user: sercret2 + group: + password: + protocol: + port: 4222 + otp_key: + comment: My little server + last_edit: 1487623641 + created: 1485729356 +3: + host: fric.com + user: username + group: Cloud + password: + protocol: ssh + port: 4333 + otp_key: + comment: bastion + last_edit: 1487623641 + created: 1485729356 + From ce02022ac758b8a4bf20a7a3e28827715df82c5d Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 24 Sep 2017 12:38:14 +0200 Subject: [PATCH 152/165] feat: update rubocop to 0.50.0 --- .rubocop.yml | 109 +++++--------------------------------- Gemfile | 2 +- bin/mpw-add | 1 - bin/mpw-config | 1 - bin/mpw-copy | 1 - bin/mpw-delete | 1 - bin/mpw-export | 1 - bin/mpw-genpwd | 1 - bin/mpw-import | 1 - bin/mpw-list | 1 - bin/mpw-update | 1 - bin/mpw-wallet | 1 - lib/mpw/cli.rb | 29 +++++----- lib/mpw/config.rb | 11 ++-- lib/mpw/import/gorilla.rb | 1 - lib/mpw/import/mpw.rb | 1 - lib/mpw/import/mpw_old.rb | 1 - lib/mpw/item.rb | 1 - lib/mpw/mpw.rb | 13 +++-- mpw.gemspec | 2 - test/init.rb | 2 - test/test_cli.rb | 2 - test/test_config.rb | 2 - test/test_import.rb | 2 - test/test_item.rb | 2 - test/test_mpw.rb | 2 - test/test_translate.rb | 2 - 27 files changed, 39 insertions(+), 155 deletions(-) diff --git a/.rubocop.yml b/.rubocop.yml index ce1de33..56d1540 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -6,116 +6,33 @@ AllCops: - Vagrantfile TargetRubyVersion: 2.3 -Style/AccessorMethodName: +Naming/AccessorMethodName: Enabled: false -Style/NumericLiteralPrefix: - Enabled: false -Style/TrailingCommaInArguments: - Enabled: false -Style/TrailingCommaInLiteral: - Enabled: false -Style/FrozenStringLiteralComment: - Enabled: false -Metrics/ParameterLists: - Max: 5 - CountKeywordArgs: false -Style/MutableConstant: + +Lint/RescueWithoutErrorClass: Enabled: false + Metrics/LineLength: Max: 120 -Metrics/AbcSize: +Metrics/CyclomaticComplexity: + Enabled: false +Metrics/PerceivedComplexity: Enabled: false Metrics/MethodLength: Enabled: false Metrics/BlockLength: Enabled: false -Metrics/CyclomaticComplexity: - Enabled: false -Metrics/PerceivedComplexity: - Enabled: false Metrics/ClassLength: Enabled: false -Style/SpaceInsideHashLiteralBraces: - Enabled: false -Style/AsciiComments: - Enabled: true -Style/Documentation: - Enabled: false -Style/SignalException: - Enabled: false -Style/OptionHash: - Enabled: true -Style/SymbolArray: - Enabled: true -Performance/Casecmp: - Enabled: false -Style/DoubleNegation: - Enabled: false -Style/Alias: - EnforcedStyle: prefer_alias_method -Style/MultilineMethodCallIndentation: - EnforcedStyle: indented -Style/RaiseArgs: - EnforcedStyle: exploded -Style/SpaceInLambdaLiteral: - Enabled: false -Lint/UnneededSplatExpansion: +Metrics/AbcSize: Enabled: false - -# Generated configuration -Style/HashSyntax: - Enabled: true - EnforcedStyle: ruby19 - UseHashRocketsWithSymbolValues: false -Style/MethodDefParentheses: - Enabled: true - EnforcedStyle: require_parentheses -Style/MultilineAssignmentLayout: - Enabled: true - EnforcedStyle: new_line -Style/IndentationConsistency: - Enabled: true - EnforcedStyle: normal -Style/AlignParameters: - Enabled: true - EnforcedStyle: with_fixed_indentation -Style/BlockDelimiters: - Enabled: true - EnforcedStyle: line_count_based -Style/AndOr: - Enabled: true -Style/DotPosition: - Enabled: true - EnforcedStyle: leading -Style/EmptyLinesAroundClassBody: - Enabled: true - EnforcedStyle: no_empty_lines -Style/EmptyLinesAroundModuleBody: - Enabled: true - EnforcedStyle: no_empty_lines -Style/NumericPredicate: - Enabled: true - EnforcedStyle: comparison -Style/EvenOdd: +Style/NumericLiteralPrefix: + Enabled: false +Style/FrozenStringLiteralComment: Enabled: false -Style/CollectionMethods: - Enabled: true - PreferredMethods: - collect: map - collect!: map! - inject: reduce - detect: find - find_all: select -Style/EmptyLinesAroundAccessModifier: - Enabled: true Style/CommandLiteral: Enabled: true EnforcedStyle: percent_x -Style/StringLiterals: - Enabled: true - EnforcedStyle: single_quotes -Style/SpaceInsideBlockBraces: - EnforcedStyle: space -Style/VariableNumber: - EnforcedStyle: snake_case +Style/Documentation: + Enabled: false diff --git a/Gemfile b/Gemfile index de2741f..405c4df 100644 --- a/Gemfile +++ b/Gemfile @@ -8,7 +8,7 @@ gem 'locale', '~> 2.1', '>= 2.1.2' gem 'rotp', '~> 3.1', '>= 3.1.0' group :development do - gem 'rubocop', '0.48.1' + gem 'rubocop', '0.50.0' gem 'test-unit' gem 'yard' end diff --git a/bin/mpw-add b/bin/mpw-add index 1d0581a..cdc23b0 100644 --- a/bin/mpw-add +++ b/bin/mpw-add @@ -1,4 +1,3 @@ -#!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # diff --git a/bin/mpw-config b/bin/mpw-config index 0af88bd..e36d2f8 100644 --- a/bin/mpw-config +++ b/bin/mpw-config @@ -1,4 +1,3 @@ -#!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # diff --git a/bin/mpw-copy b/bin/mpw-copy index 95c01d6..01b75aa 100644 --- a/bin/mpw-copy +++ b/bin/mpw-copy @@ -1,4 +1,3 @@ -#!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # diff --git a/bin/mpw-delete b/bin/mpw-delete index ea352c4..78dc340 100644 --- a/bin/mpw-delete +++ b/bin/mpw-delete @@ -1,4 +1,3 @@ -#!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # diff --git a/bin/mpw-export b/bin/mpw-export index 83d35ae..3ab0945 100644 --- a/bin/mpw-export +++ b/bin/mpw-export @@ -1,4 +1,3 @@ -#!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # diff --git a/bin/mpw-genpwd b/bin/mpw-genpwd index 051c5c4..de5628f 100644 --- a/bin/mpw-genpwd +++ b/bin/mpw-genpwd @@ -1,4 +1,3 @@ -#!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # diff --git a/bin/mpw-import b/bin/mpw-import index 76e163e..8213eb3 100644 --- a/bin/mpw-import +++ b/bin/mpw-import @@ -1,4 +1,3 @@ -#!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # diff --git a/bin/mpw-list b/bin/mpw-list index 434ea11..71e7b5a 100644 --- a/bin/mpw-list +++ b/bin/mpw-list @@ -1,4 +1,3 @@ -#!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # diff --git a/bin/mpw-update b/bin/mpw-update index d15b8e7..53ce5f8 100644 --- a/bin/mpw-update +++ b/bin/mpw-update @@ -1,4 +1,3 @@ -#!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # diff --git a/bin/mpw-wallet b/bin/mpw-wallet index caee35d..6f84afd 100644 --- a/bin/mpw-wallet +++ b/bin/mpw-wallet @@ -1,4 +1,3 @@ -#!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index d54b314..7309024 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -1,4 +1,3 @@ -#!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # @@ -39,7 +38,7 @@ module MPW @config.setup(options) puts I18n.t('form.set_config.valid').to_s.green - rescue => e + rescue e puts "#{I18n.t('display.error')} #15: #{e}".red exit 2 end @@ -50,7 +49,7 @@ module MPW @config.set_wallet_path(path, @wallet) puts I18n.t('form.set_wallet_path.valid').to_s.green - rescue => e + rescue e puts "#{I18n.t('display.error')} #19: #{e}".red exit 2 end @@ -67,7 +66,7 @@ module MPW load_config puts I18n.t('form.setup_config.valid').to_s.green - rescue => e + rescue e puts "#{I18n.t('display.error')} #8: #{e}".red exit 2 end @@ -89,7 +88,7 @@ module MPW @config.setup_gpg_key(@password, gpg_key) puts I18n.t('form.setup_gpg_key.valid').to_s.green - rescue => e + rescue e puts "#{I18n.t('display.error')} #8: #{e}".red exit 2 end @@ -119,7 +118,7 @@ module MPW # Load config def load_config @config.load_config - rescue => e + rescue e puts "#{I18n.t('display.error')} #10: #{e}".red exit 2 end @@ -140,7 +139,7 @@ module MPW @mpw.read_data end end - rescue => e + rescue e puts "#{I18n.t('display.error')} #11: #{e}".red exit 2 end @@ -416,7 +415,7 @@ module MPW @mpw.write_data puts I18n.t('form.add_key.valid').to_s.green - rescue => e + rescue e puts "#{I18n.t('display.error')} #13: #{e}".red end @@ -427,7 +426,7 @@ module MPW @mpw.write_data puts I18n.t('form.delete_key.valid').to_s.green - rescue => e + rescue e puts "#{I18n.t('display.error')} #15: #{e}".red end @@ -478,7 +477,7 @@ module MPW @mpw.write_data puts I18n.t('form.add_item.valid').to_s.green - rescue => e + rescue e puts "#{I18n.t('display.error')} #13: #{e}".red end @@ -506,7 +505,7 @@ module MPW puts I18n.t('form.update_item.valid').to_s.green end - rescue => e + rescue e puts "#{I18n.t('display.error')} #14: #{e}".red end @@ -530,7 +529,7 @@ module MPW puts I18n.t('form.delete_item.valid').to_s.green end - rescue => e + rescue e puts "#{I18n.t('display.error')} #16: #{e}".red end @@ -548,7 +547,7 @@ module MPW item = get_item(items) clipboard(item, clipboard) end - rescue => e + rescue e puts "#{I18n.t('display.error')} #14: #{e}".red end @@ -578,7 +577,7 @@ module MPW File.open(file, 'w') { |f| f << data.to_yaml } puts I18n.t('form.export.valid', file: file).to_s.green - rescue => e + rescue e puts "#{I18n.t('display.error')} #17: #{e}".red end @@ -613,7 +612,7 @@ module MPW @mpw.write_data puts I18n.t('form.import.valid').to_s.green - rescue => e + rescue e puts "#{I18n.t('display.error')} #18: #{e}".red end end diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index 95390a4..47440ab 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -1,4 +1,3 @@ -#!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # @@ -39,9 +38,9 @@ module MPW def initialize(config_file = nil) @config_file = config_file @config_dir = - if /darwin/ =~ RUBY_PLATFORM + if RUBY_PLATFORM =~ /darwin/ "#{Dir.home}/Library/Preferences/mpw" - elsif /cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM + elsif RUBY_PLATFORM =~ /cygwin|mswin|mingw|bccwin|wince|emx/ "#{Dir.home}/AppData/Local/mpw" else "#{Dir.home}/.config/mpw" @@ -94,7 +93,7 @@ module MPW File.open(@config_file, 'w') do |file| file << config.to_yaml end - rescue => e + rescue e raise "#{I18n.t('error.config.write')}\n#{e}" end @@ -122,7 +121,7 @@ module MPW ctx = GPGME::Ctx.new ctx.genkey(param, nil, nil) - rescue => e + rescue e raise "#{I18n.t('error.config.genkey_gpg.exception')}\n#{e}" end @@ -141,7 +140,7 @@ module MPW raise if @gpg_key.empty? || @wallet_dir.empty? I18n.locale = @lang.to_sym - rescue => e + rescue e raise "#{I18n.t('error.config.load')}\n#{e}" end diff --git a/lib/mpw/import/gorilla.rb b/lib/mpw/import/gorilla.rb index fd5d9f1..a5a8fbe 100644 --- a/lib/mpw/import/gorilla.rb +++ b/lib/mpw/import/gorilla.rb @@ -1,4 +1,3 @@ -#!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # diff --git a/lib/mpw/import/mpw.rb b/lib/mpw/import/mpw.rb index 8d6b1c4..aca88aa 100644 --- a/lib/mpw/import/mpw.rb +++ b/lib/mpw/import/mpw.rb @@ -1,4 +1,3 @@ -#!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # diff --git a/lib/mpw/import/mpw_old.rb b/lib/mpw/import/mpw_old.rb index f6957fe..7f8c33e 100644 --- a/lib/mpw/import/mpw_old.rb +++ b/lib/mpw/import/mpw_old.rb @@ -1,4 +1,3 @@ -#!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # diff --git a/lib/mpw/item.rb b/lib/mpw/item.rb index ec8ab0e..ec4c50e 100644 --- a/lib/mpw/item.rb +++ b/lib/mpw/item.rb @@ -1,4 +1,3 @@ -#!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index a5fc0ae..257d3bf 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -1,4 +1,3 @@ -#!/usr/bin/ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # @@ -89,14 +88,14 @@ module MPW otp: @otp_keys.key?(d['id']), comment: d['comment'], last_edit: d['last_edit'], - created: d['created'], + created: d['created'] ) ) end end add_key(@key) unless @keys.key?(@key) - rescue => e + rescue e raise "#{I18n.t('error.mpw_file.read_data')}\n#{e}" end @@ -116,7 +115,7 @@ module MPW 'url' => item.url, 'comment' => item.comment, 'last_edit' => item.last_edit, - 'created' => item.created, + 'created' => item.created } ) end @@ -147,7 +146,7 @@ module MPW end File.rename(tmp_file, @wallet_file) - rescue => e + rescue e File.unlink(tmp_file) if File.exist?(tmp_file) raise "#{I18n.t('error.mpw_file.write_data')}\n#{e}" @@ -324,7 +323,7 @@ module MPW crypto .decrypt(data, password) .read.force_encoding('utf-8') - rescue => e + rescue e raise "#{I18n.t('error.gpg_file.decrypt')}\n#{e}" end @@ -342,7 +341,7 @@ module MPW end crypto.encrypt(data, recipients: recipients).read - rescue => e + rescue e raise "#{I18n.t('error.gpg_file.encrypt')}\n#{e}" end end diff --git a/mpw.gemspec b/mpw.gemspec index 4afbe3b..dfb4825 100644 --- a/mpw.gemspec +++ b/mpw.gemspec @@ -1,5 +1,3 @@ -# coding: utf-8 - lib = File.expand_path('../lib', __FILE__) $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) diff --git a/test/init.rb b/test/init.rb index 6da9ecb..08ebbb8 100644 --- a/test/init.rb +++ b/test/init.rb @@ -1,5 +1,3 @@ -#!/usr/bin/ruby - require 'fileutils' require 'gpgme' diff --git a/test/test_cli.rb b/test/test_cli.rb index 07c4273..9cfe215 100644 --- a/test/test_cli.rb +++ b/test/test_cli.rb @@ -1,5 +1,3 @@ -#!/usr/bin/ruby - require 'i18n' require 'test/unit' diff --git a/test/test_config.rb b/test/test_config.rb index 8ad7369..2b88b54 100644 --- a/test/test_config.rb +++ b/test/test_config.rb @@ -1,5 +1,3 @@ -#!/usr/bin/ruby - require 'mpw/config' require 'test/unit' require 'locale' diff --git a/test/test_import.rb b/test/test_import.rb index c27b58f..101fd1a 100644 --- a/test/test_import.rb +++ b/test/test_import.rb @@ -1,5 +1,3 @@ -#!/usr/bin/ruby - require 'i18n' require 'test/unit' diff --git a/test/test_item.rb b/test/test_item.rb index 80e39ff..97503c0 100644 --- a/test/test_item.rb +++ b/test/test_item.rb @@ -1,5 +1,3 @@ -#!/usr/bin/ruby - require 'mpw/item' require 'test/unit' require 'yaml' diff --git a/test/test_mpw.rb b/test/test_mpw.rb index a1633ef..8fc544e 100644 --- a/test/test_mpw.rb +++ b/test/test_mpw.rb @@ -1,5 +1,3 @@ -#!/usr/bin/ruby - require 'mpw/mpw' require 'mpw/item' require 'test/unit' diff --git a/test/test_translate.rb b/test/test_translate.rb index d4bb002..d7cbceb 100644 --- a/test/test_translate.rb +++ b/test/test_translate.rb @@ -1,5 +1,3 @@ -#!/usr/bin/ruby - require 'yaml' require 'test/unit' From ef0a9081449d0b0fd65859bdca84c53179189485 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Mon, 18 Sep 2017 07:58:21 +0200 Subject: [PATCH 153/165] feat: add docker for local tests --- .docker-test | 32 ++++++++++++++++++++++++++++++++ Dockerfile | 20 ++++++++++++++++++++ README.md | 17 +++++++++++++++++ 3 files changed, 69 insertions(+) create mode 100644 .docker-test create mode 100644 Dockerfile diff --git a/.docker-test b/.docker-test new file mode 100644 index 0000000..d36fad8 --- /dev/null +++ b/.docker-test @@ -0,0 +1,32 @@ +#!/bin/bash + +ruby_version=${1:-2.4.2} + +if ! rvm use ruby-${ruby_version} &>/dev/null ; then + echo "The ruby version '${ruby_version}' doesn't exist!" + echo "Available versions are:" + rvm list rubies strings | cut -d '-' -f2 + exit 2 +fi + +echo '# ---------------------------------' +echo "# Use ruby version: ${ruby_version}" +echo '# ---------------------------------' + +cp -r /mpw ~/mpw +cd ~/mpw +gem install bundler --no-ri --no-rdoc +bundle install +gem build mpw.gemspec +gem install mpw-$(cat VERSION).gem +cp -a /dev/urandom /dev/random + +rubocop +ruby ./test/init.rb +ruby ./test/test_config.rb +ruby ./test/test_item.rb +ruby ./test/test_mpw.rb +ruby ./test/test_translate.rb +ruby ./test/init.rb +ruby ./test/test_cli.rb +ruby ./test/test_import.rb diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..d8995d0 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,20 @@ +FROM debian:stretch +MAINTAINER Adrien Waksberg "mpw@yae.im" + +RUN apt update +RUN apt dist-upgrade -y + +RUN apt install -y procps gnupg1 curl git +RUN ln -snvf /usr/bin/gpg1 /usr/bin/gpg +RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB +RUN curl -sSL https://get.rvm.io | bash -s stable +RUN echo 'source "/usr/local/rvm/scripts/rvm"' >> /etc/bash.bashrc + +run apt install -y patch bzip2 gawk g++ gcc make libc6-dev patch zlib1g-dev libyaml-dev libsqlite3-dev \ + sqlite3 autoconf libgmp-dev libgdbm-dev libncurses5-dev automake libtool bison \ + pkg-config libffi-dev libgmp-dev libreadline-dev libssl-dev + +RUN /bin/bash -l -c "rvm install 2.4.2" +RUN /bin/bash -l -c "rvm install 2.3.5" +RUN /bin/bash -l -c "rvm install 2.2.8" +RUN /bin/bash -l -c "rvm install 2.1.10" diff --git a/README.md b/README.md index 9c2c5d6..162be49 100644 --- a/README.md +++ b/README.md @@ -161,3 +161,20 @@ Configuration password_length | 16 ``` + +## Development + +Don't run the tests on your local machine, you risk to lost your datas. + +### Test on local machine with docker + + * install [docker](https://docs.docker.com/engine/installation/) + * build the container +``` +docker build -t mpw/debian:stretch -f Dockerfile . +``` + * run the tests + +``` +docker run -v $(pwd):/mpw:ro -it mpw/debian:stretch /bin/bash -l /mpw/.docker-test +``` From 2abad3695f2883488f6b1f9796542ac262763c4a Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 1 Oct 2017 20:01:35 +0200 Subject: [PATCH 154/165] fix no show wallet in other folder --- lib/mpw/cli.rb | 3 ++- test/test_cli.rb | 4 ++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 7309024..711e91c 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -373,7 +373,8 @@ module MPW # List all wallets def list_wallet - wallets = [] + wallets = @config.wallet_paths.keys + Dir.glob("#{@config.wallet_dir}/*.mpw").each do |f| wallet = File.basename(f, '.mpw') wallet += ' *'.green if wallet == @config.default_wallet diff --git a/test/test_cli.rb b/test/test_cli.rb index 9cfe215..766aebd 100644 --- a/test/test_cli.rb +++ b/test/test_cli.rb @@ -171,6 +171,10 @@ class TestConfig < Test::Unit::TestCase assert_match(%r{path_wallet_default.+\| #{Dir.pwd}/default.mpw}, output) assert(File.exist?("#{Dir.pwd}/default.mpw")) + output = %x(mpw wallet) + puts output + assert_match('default', output) + output = %x(mpw wallet --default-path) puts output assert_match(I18n.t('form.set_wallet_path.valid'), output) From afd6585acc4fac66133a8264460a4751f1bcdd37 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 1 Oct 2017 20:31:43 +0200 Subject: [PATCH 155/165] fix: remove outputs in tests --- test/test_cli.rb | 70 +++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 40 deletions(-) diff --git a/test/test_cli.rb b/test/test_cli.rb index 766aebd..8bae4cc 100644 --- a/test/test_cli.rb +++ b/test/test_cli.rb @@ -17,7 +17,11 @@ class TestConfig < Test::Unit::TestCase end def test_00_init_config - output = %x(echo "#{@password}\n#{@password}" | mpw config --init #{@gpg_key}) + output = %x( + echo "#{@password}\n#{@password}" | mpw config \ + --init #{@gpg_key} \ + 2>/dev/null + ) assert_match(I18n.t('form.setup_config.valid'), output) assert_match(I18n.t('form.setup_gpg_key.valid'), output) end @@ -31,13 +35,12 @@ class TestConfig < Test::Unit::TestCase --user #{data['user']} \ --comment '#{data['comment']}' \ --group #{data['group']} \ - --random + --random \ + 2>/dev/null ) - puts output assert_match(I18n.t('form.add_item.valid'), output) - output = %x(echo #{@password} | mpw list) - puts output + output = %x(echo #{@password} | mpw list 2>/dev/null) assert_match(%r{#{data['protocol']}://.+#{data['host']}.+:#{data['port']}}, output) assert_match(data['user'], output) assert_match(data['comment'], output) @@ -47,19 +50,19 @@ class TestConfig < Test::Unit::TestCase def test_02_search data = @fixtures['add'] - output = %x(echo #{@password} | mpw list --group #{data['group']}) + output = %x(echo #{@password} | mpw list --group #{data['group']} 2>/dev/null) assert_match(%r{#{data['protocol']}://.+#{data['host']}.+:#{data['port']}}, output) - output = %x(echo #{@password} | mpw list --pattern #{data['host']}) + output = %x(echo #{@password} | mpw list --pattern #{data['host']} 2>/dev/null) assert_match(%r{#{data['protocol']}://.+#{data['host']}.+:#{data['port']}}, output) - output = %x(echo #{@password} | mpw list --pattern #{data['comment']}) + output = %x(echo #{@password} | mpw list --pattern #{data['comment']} 2>/dev/null) assert_match(%r{#{data['protocol']}://.+#{data['host']}.+:#{data['port']}}, output) - output = %x(echo #{@password} | mpw list --group R1Pmfbp626TFpjlr) + output = %x(echo #{@password} | mpw list --group R1Pmfbp626TFpjlr 2>/dev/null) assert_match(I18n.t('display.nothing'), output) - output = %x(echo #{@password} | mpw list --pattern h1IfnKqamaGM9oEX) + output = %x(echo #{@password} | mpw list --pattern h1IfnKqamaGM9oEX 2>/dev/null) assert_match(I18n.t('display.nothing'), output) end @@ -72,13 +75,12 @@ class TestConfig < Test::Unit::TestCase --url #{data['url']} \ --user #{data['user']} \ --comment '#{data['comment']}' \ - --new-group #{data['group']} + --new-group #{data['group']} \ + 2>/dev/null ) - puts output assert_match(I18n.t('form.update_item.valid'), output) - output = %x(echo #{@password} | mpw list) - puts output + output = %x(echo #{@password} | mpw list 2>/dev/null) assert_match(%r{#{data['protocol']}://.+#{data['host']}.+:#{data['port']}}, output) assert_match(data['user'], output) assert_match(data['comment'], output) @@ -86,12 +88,14 @@ class TestConfig < Test::Unit::TestCase end def test_04_delete_item - output = %x(echo "#{@password}\ny" | mpw delete -p #{@fixtures['update']['host']}) - puts output + output = %x( + echo "#{@password}\ny" | mpw delete \ + -p #{@fixtures['update']['host']} \ + 2>/dev/null + ) assert_match(I18n.t('form.delete_item.valid'), output) - output = %x(echo #{@password} | mpw list) - puts output + output = %x(echo #{@password} | mpw list 2>/dev/null) assert_match(I18n.t('display.nothing'), output) end @@ -99,10 +103,10 @@ class TestConfig < Test::Unit::TestCase file_import = './test/files/fixtures-import.yml' file_export = '/tmp/test-mpw.yml' - output = %x(echo #{@password} | mpw import --file #{file_import}) + output = %x(echo #{@password} | mpw import --file #{file_import} 2>/dev/null) assert_match(I18n.t('form.import.valid', file: file_import), output) - output = %x(echo #{@password} | mpw export --file #{file_export}) + output = %x(echo #{@password} | mpw export --file #{file_export} 2>/dev/null) assert_match(I18n.t('form.export.valid', file: file_export), output) assert(File.exist?(file_export)) assert_equal(YAML.load_file(file_export).length, 2) @@ -131,56 +135,46 @@ class TestConfig < Test::Unit::TestCase output = %x( echo "#{@password}\np\nq" | mpw copy \ --disable-clipboard \ - -p #{data['host']} + -p #{data['host']} \ + 2>/dev/null ) - puts output assert_match(data['password'], output) end def test_07_setup_wallet gpg_key = 'test2@example.com' - output = %x(echo #{@password} | mpw wallet --add-gpg-key #{gpg_key}) - puts output + output = %x(echo #{@password} | mpw wallet --add-gpg-key #{gpg_key} 2>/dev/null) assert_match(I18n.t('form.add_key.valid'), output) - output = %x(echo #{@password} | mpw wallet --list-keys) - puts output + output = %x(echo #{@password} | mpw wallet --list-keys 2>/dev/null) assert_match("| #{@gpg_key}", output) assert_match("| #{gpg_key}", output) - output = %x(echo #{@password} | mpw wallet --delete-gpg-key #{gpg_key}) - puts output + output = %x(echo #{@password} | mpw wallet --delete-gpg-key #{gpg_key} 2>/dev/null) assert_match(I18n.t('form.delete_key.valid'), output) - output = %x(echo #{@password} | mpw wallet --list-keys) - puts output + output = %x(echo #{@password} | mpw wallet --list-keys 2>/dev/null) assert_match("| #{@gpg_key}", output) assert_no_match(/\| #{gpg_key}/, output) output = %x(mpw wallet) - puts output assert_match('| default', output) output = %x(mpw wallet --path '.') - puts output assert_match(I18n.t('form.set_wallet_path.valid'), output) output = %x(mpw config) - puts output assert_match(%r{path_wallet_default.+\| #{Dir.pwd}/default.mpw}, output) assert(File.exist?("#{Dir.pwd}/default.mpw")) output = %x(mpw wallet) - puts output assert_match('default', output) output = %x(mpw wallet --default-path) - puts output assert_match(I18n.t('form.set_wallet_path.valid'), output) output = %x(mpw config) - puts output assert_no_match(/path_wallet_default/, output) end @@ -203,11 +197,9 @@ class TestConfig < Test::Unit::TestCase --wallet-dir #{wallet_dir} \ --default-wallet #{wallet} ) - puts output assert_match(I18n.t('form.set_config.valid'), output) output = %x(mpw config) - puts output assert_match(/gpg_key.+\| #{gpg_key}/, output) assert_match(/gpg_exe.+\| #{gpg_exe}/, output) assert_match(/pinmode.+\| true/, output) @@ -227,11 +219,9 @@ class TestConfig < Test::Unit::TestCase --numeric \ --disable-pinmode ) - puts output assert_match(I18n.t('form.set_config.valid'), output) output = %x(mpw config) - puts output assert_match(/gpg_key.+\| #{@gpg_key}/, output) assert_match(/pinmode.+\| false/, output) %w[numeric alpha special].each do |k| From 348db7cfd0ce14b8374c0573fc581289030cbb01 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 1 Oct 2017 20:32:56 +0200 Subject: [PATCH 156/165] feat: update travis.yml --- .travis.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7f524d4..14d696a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,17 +1,16 @@ language: ruby dist: precise rvm: - - 2.4.1 - - 2.3.4 - - 2.2.7 + - 2.4.2 + - 2.3.5 + - 2.2.8 - 2.1.10 install: - sudo cp -a /dev/urandom /dev/random - sudo apt-get purge -y gnupg-agent gnupg2 - bundle install - - echo 9999 > VERSION - gem build mpw.gemspec - - gem install mpw-9999.gem + - gem install mpw-$(cat VERSION).gem script: - rubocop - ruby ./test/init.rb From 8fddbd01be1e5a10b24b1ba8ab49536b6f9145de Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 3 Oct 2017 13:07:53 +0200 Subject: [PATCH 157/165] fix: minor change in dockerfile --- Dockerfile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index d8995d0..6654780 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,10 +10,6 @@ RUN gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A170311380 RUN curl -sSL https://get.rvm.io | bash -s stable RUN echo 'source "/usr/local/rvm/scripts/rvm"' >> /etc/bash.bashrc -run apt install -y patch bzip2 gawk g++ gcc make libc6-dev patch zlib1g-dev libyaml-dev libsqlite3-dev \ - sqlite3 autoconf libgmp-dev libgdbm-dev libncurses5-dev automake libtool bison \ - pkg-config libffi-dev libgmp-dev libreadline-dev libssl-dev - RUN /bin/bash -l -c "rvm install 2.4.2" RUN /bin/bash -l -c "rvm install 2.3.5" RUN /bin/bash -l -c "rvm install 2.2.8" From b0905f18f1f4d14d5b9f08f4379809cacc3cf27d Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Tue, 3 Oct 2017 13:09:27 +0200 Subject: [PATCH 158/165] fix: remove output for test_import --- test/test_import.rb | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/test_import.rb b/test/test_import.rb index 101fd1a..ae53eef 100644 --- a/test/test_import.rb +++ b/test/test_import.rb @@ -29,15 +29,12 @@ class TestImport < Test::Unit::TestCase assert_match(I18n.t('form.import.valid'), output) output = %x(echo #{@password} | mpw list --group Bank --wallet #{format}) - puts output assert_match(%r{http://.*fric\.com.*12345.*Fric money money}, output) output = %x(echo #{@password} | mpw list --group Cloud --wallet #{format}) - puts output assert_match(%r{ssh://.*fric\.com.*:4333.*username.*bastion}, output) output = %x(echo #{@password} | mpw list --wallet #{format}) - puts output assert_match(/server\.com.*My little server/, output) end end From 2de66a4eaf9c4b6b7c8c4f7d8766039609f89aba Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 19 Nov 2017 13:49:42 +0100 Subject: [PATCH 159/165] fix syntax for all rescue --- lib/mpw/cli.rb | 28 ++++++++++++++-------------- lib/mpw/config.rb | 6 +++--- lib/mpw/mpw.rb | 8 ++++---- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index 711e91c..db703a8 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -38,7 +38,7 @@ module MPW @config.setup(options) puts I18n.t('form.set_config.valid').to_s.green - rescue e + rescue => e puts "#{I18n.t('display.error')} #15: #{e}".red exit 2 end @@ -49,7 +49,7 @@ module MPW @config.set_wallet_path(path, @wallet) puts I18n.t('form.set_wallet_path.valid').to_s.green - rescue e + rescue => e puts "#{I18n.t('display.error')} #19: #{e}".red exit 2 end @@ -66,7 +66,7 @@ module MPW load_config puts I18n.t('form.setup_config.valid').to_s.green - rescue e + rescue => e puts "#{I18n.t('display.error')} #8: #{e}".red exit 2 end @@ -88,7 +88,7 @@ module MPW @config.setup_gpg_key(@password, gpg_key) puts I18n.t('form.setup_gpg_key.valid').to_s.green - rescue e + rescue => e puts "#{I18n.t('display.error')} #8: #{e}".red exit 2 end @@ -118,7 +118,7 @@ module MPW # Load config def load_config @config.load_config - rescue e + rescue => e puts "#{I18n.t('display.error')} #10: #{e}".red exit 2 end @@ -139,7 +139,7 @@ module MPW @mpw.read_data end end - rescue e + rescue => e puts "#{I18n.t('display.error')} #11: #{e}".red exit 2 end @@ -416,7 +416,7 @@ module MPW @mpw.write_data puts I18n.t('form.add_key.valid').to_s.green - rescue e + rescue => e puts "#{I18n.t('display.error')} #13: #{e}".red end @@ -427,7 +427,7 @@ module MPW @mpw.write_data puts I18n.t('form.delete_key.valid').to_s.green - rescue e + rescue => e puts "#{I18n.t('display.error')} #15: #{e}".red end @@ -478,7 +478,7 @@ module MPW @mpw.write_data puts I18n.t('form.add_item.valid').to_s.green - rescue e + rescue => e puts "#{I18n.t('display.error')} #13: #{e}".red end @@ -506,7 +506,7 @@ module MPW puts I18n.t('form.update_item.valid').to_s.green end - rescue e + rescue => e puts "#{I18n.t('display.error')} #14: #{e}".red end @@ -530,7 +530,7 @@ module MPW puts I18n.t('form.delete_item.valid').to_s.green end - rescue e + rescue => e puts "#{I18n.t('display.error')} #16: #{e}".red end @@ -548,7 +548,7 @@ module MPW item = get_item(items) clipboard(item, clipboard) end - rescue e + rescue => e puts "#{I18n.t('display.error')} #14: #{e}".red end @@ -578,7 +578,7 @@ module MPW File.open(file, 'w') { |f| f << data.to_yaml } puts I18n.t('form.export.valid', file: file).to_s.green - rescue e + rescue => e puts "#{I18n.t('display.error')} #17: #{e}".red end @@ -613,7 +613,7 @@ module MPW @mpw.write_data puts I18n.t('form.import.valid').to_s.green - rescue e + rescue => e puts "#{I18n.t('display.error')} #18: #{e}".red end end diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index 47440ab..a4d2142 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -93,7 +93,7 @@ module MPW File.open(@config_file, 'w') do |file| file << config.to_yaml end - rescue e + rescue => e raise "#{I18n.t('error.config.write')}\n#{e}" end @@ -121,7 +121,7 @@ module MPW ctx = GPGME::Ctx.new ctx.genkey(param, nil, nil) - rescue e + rescue => e raise "#{I18n.t('error.config.genkey_gpg.exception')}\n#{e}" end @@ -140,7 +140,7 @@ module MPW raise if @gpg_key.empty? || @wallet_dir.empty? I18n.locale = @lang.to_sym - rescue e + rescue => e raise "#{I18n.t('error.config.load')}\n#{e}" end diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index 257d3bf..a67f09d 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -95,7 +95,7 @@ module MPW end add_key(@key) unless @keys.key?(@key) - rescue e + rescue => e raise "#{I18n.t('error.mpw_file.read_data')}\n#{e}" end @@ -146,7 +146,7 @@ module MPW end File.rename(tmp_file, @wallet_file) - rescue e + rescue => e File.unlink(tmp_file) if File.exist?(tmp_file) raise "#{I18n.t('error.mpw_file.write_data')}\n#{e}" @@ -323,7 +323,7 @@ module MPW crypto .decrypt(data, password) .read.force_encoding('utf-8') - rescue e + rescue => e raise "#{I18n.t('error.gpg_file.decrypt')}\n#{e}" end @@ -341,7 +341,7 @@ module MPW end crypto.encrypt(data, recipients: recipients).read - rescue e + rescue => e raise "#{I18n.t('error.gpg_file.encrypt')}\n#{e}" end end From ed09f55ce282bd4b170b8ebc9abf615be633098a Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 19 Nov 2017 13:54:17 +0100 Subject: [PATCH 160/165] chore: update README --- README.md | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/README.md b/README.md index 162be49..4b0c0b0 100644 --- a/README.md +++ b/README.md @@ -169,12 +169,8 @@ Don't run the tests on your local machine, you risk to lost your datas. ### Test on local machine with docker * install [docker](https://docs.docker.com/engine/installation/) - * build the container -``` -docker build -t mpw/debian:stretch -f Dockerfile . -``` * run the tests ``` -docker run -v $(pwd):/mpw:ro -it mpw/debian:stretch /bin/bash -l /mpw/.docker-test +docker run -v $(pwd):/mpw:ro -it nishiki/ruby:stretch /bin/bash -l /mpw/.docker-test ``` From 30ca80f6db7b67bfd74c1a8b57e6eebaa859c1b6 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 19 Nov 2017 18:27:48 +0100 Subject: [PATCH 161/165] fix shebang --- bin/mpw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/mpw b/bin/mpw index 811322e..384374a 100755 --- a/bin/mpw +++ b/bin/mpw @@ -1,4 +1,4 @@ -#!/usr/bin/ruby +#!/usr/bin/env ruby # MPW is a software to crypt and manage your passwords # Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # From 6a2d5da9fbf022ba90fc3ed594eae87616339001 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 19 Nov 2017 20:11:39 +0100 Subject: [PATCH 162/165] feat: update gem dependencies --- Gemfile | 6 +++--- mpw.gemspec | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Gemfile b/Gemfile index 405c4df..a76b2c1 100644 --- a/Gemfile +++ b/Gemfile @@ -1,11 +1,11 @@ source 'https://rubygems.org' gem 'clipboard', '~> 1.1', '>= 1.1.1' gem 'colorize', '~> 0.8', '>= 0.8.1' -gem 'gpgme', '~> 2.0', '>= 2.0.12' +gem 'gpgme', '~> 2.0', '>= 2.0.14' gem 'highline', '~> 1.7', '>= 1.7.8' -gem 'i18n', '~> 0.7', '>= 0.7.0' +gem 'i18n', '~> 0.9', '>= 0.9.1' gem 'locale', '~> 2.1', '>= 2.1.2' -gem 'rotp', '~> 3.1', '>= 3.1.0' +gem 'rotp', '~> 3.3', '>= 3.3.0' group :development do gem 'rubocop', '0.50.0' diff --git a/mpw.gemspec b/mpw.gemspec index dfb4825..abcb375 100644 --- a/mpw.gemspec +++ b/mpw.gemspec @@ -18,11 +18,11 @@ Gem::Specification.new do |spec| spec.required_ruby_version = '>= 2.1' - spec.add_dependency 'i18n', '~> 0.7', '>= 0.7.0' - spec.add_dependency 'gpgme', '~> 2.0', '>= 2.0.12' + spec.add_dependency 'i18n', '~> 0.9', '>= 0.9.1' + spec.add_dependency 'gpgme', '~> 2.0', '>= 2.0.14' spec.add_dependency 'highline', '~> 1.7', '>= 1.7.8' spec.add_dependency 'locale', '~> 2.1', '>= 2.1.2' spec.add_dependency 'colorize', '~> 0.8', '>= 0.8.1' spec.add_dependency 'clipboard', '~> 1.1', '>= 1.1.1' - spec.add_dependency 'rotp', '~> 3.1', '>= 3.1.0' + spec.add_dependency 'rotp', '~> 3.3', '>= 3.3.0' end From a11777cadead7dab24775538be9f171c50d6dbb6 Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 19 Nov 2017 21:25:42 +0100 Subject: [PATCH 163/165] feat: add keepass --- lib/mpw/import/keepass.rb | 50 +++++++++++++++++++++++ test/files/import-keepass.txt | 3 ++ test/test_import.rb | 74 ++++++++++++++++++++++++++--------- 3 files changed, 109 insertions(+), 18 deletions(-) create mode 100644 lib/mpw/import/keepass.rb create mode 100644 test/files/import-keepass.txt diff --git a/lib/mpw/import/keepass.rb b/lib/mpw/import/keepass.rb new file mode 100644 index 0000000..b9d7852 --- /dev/null +++ b/lib/mpw/import/keepass.rb @@ -0,0 +1,50 @@ +# MPW is a software to crypt and manage your passwords +# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> +# +# 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 2 +# 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, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'csv' + +module MPW + module Import + # Import an keepass2 export csv file + # @param file [String] the file path to import + def self.keepass(file) + data = {} + + CSV.foreach(file, headers: true) do |row| + id = "#{row['Group']} #{row['Title']}" + comment = + if row['Title'] && row['Notes'] + "#{row['Title']} #{row['Notes']}" + elsif row['Title'] + row['Title'] + elsif row['Notes'] + row['Notes'] + end + + data[id] = { + 'comment' => comment, + 'group' => row['Group'], + 'password' => row['Password'], + 'url' => row['URL'], + 'user' => row['Username'] + } + end + + data + end + end +end diff --git a/test/files/import-keepass.txt b/test/files/import-keepass.txt new file mode 100644 index 0000000..61ce7ad --- /dev/null +++ b/test/files/import-keepass.txt @@ -0,0 +1,3 @@ +"Group","Title","Username","Password","URL","Notes" +"Racine","Bank","123456","ywcExJW8qmBVTSyi","http://bank.com/login","My little bank" +"Racine/Cloud","GAFAM","wesh","superpassword","localhost.local","" diff --git a/test/test_import.rb b/test/test_import.rb index ae53eef..f1a8727 100644 --- a/test/test_import.rb +++ b/test/test_import.rb @@ -14,28 +14,66 @@ class TestImport < Test::Unit::TestCase @password = 'password' end - def test_00_import - Dir['./test/files/import-*.txt'].each do |file| - format = File.basename(file, '.txt').partition('-').last + def test_00_import_mpw_old + file = './test/files/import-mpw_old.txt' + format = 'mpw_old' - puts format + output = %x( + mpw import \ + --file #{file} \ + --format #{format} \ + --wallet #{format} + ) + assert_match(I18n.t('form.import.valid'), output) - output = %x( - mpw import \ - --file #{file} \ - --format #{format} \ - --wallet #{format} - ) - assert_match(I18n.t('form.import.valid'), output) + output = %x(echo #{@password} | mpw list --group Bank --wallet #{format}) + assert_match(%r{http://.*fric\.com.*12345.*Fric money money}, output) - output = %x(echo #{@password} | mpw list --group Bank --wallet #{format}) - assert_match(%r{http://.*fric\.com.*12345.*Fric money money}, output) + output = %x(echo #{@password} | mpw list --group Cloud --wallet #{format}) + assert_match(%r{ssh://.*fric\.com.*:4333.*username.*bastion}, output) - output = %x(echo #{@password} | mpw list --group Cloud --wallet #{format}) - assert_match(%r{ssh://.*fric\.com.*:4333.*username.*bastion}, output) + output = %x(echo #{@password} | mpw list --wallet #{format}) + assert_match(/server\.com.*My little server/, output) + end - output = %x(echo #{@password} | mpw list --wallet #{format}) - assert_match(/server\.com.*My little server/, output) - end + def test_01_import_gorilla + file = './test/files/import-gorilla.txt' + format = 'gorilla' + + output = %x( + mpw import \ + --file #{file} \ + --format #{format} \ + --wallet #{format} + ) + assert_match(I18n.t('form.import.valid'), output) + + output = %x(echo #{@password} | mpw list --group Bank --wallet #{format}) + assert_match(%r{http://.*fric\.com.*12345.*Fric money money}, output) + + output = %x(echo #{@password} | mpw list --group Cloud --wallet #{format}) + assert_match(%r{ssh://.*fric\.com.*:4333.*username.*bastion}, output) + + output = %x(echo #{@password} | mpw list --wallet #{format}) + assert_match(/server\.com.*My little server/, output) + end + + def test_02_import_keepass + file = './test/files/import-keepass.txt' + format = 'keepass' + + output = %x( + mpw import \ + --file #{file} \ + --format #{format} \ + --wallet #{format} + ) + assert_match(I18n.t('form.import.valid'), output) + + output = %x(echo #{@password} | mpw list --group 'Racine/Cloud' --wallet #{format}) + assert_match(/localhost\.local.*wesh.*GAFAM/, output) + + output = %x(echo #{@password} | mpw list --wallet #{format}) + assert_match(%r{http://.*bank\.com.*123456.*Bank My little bank}, output) end end From fe7a03ba52e5b7a2ef0f3786cbdc474a53a83c4a Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Sun, 19 Nov 2017 23:03:16 +0100 Subject: [PATCH 164/165] feat: change license GPL2.0 to Apache2.0 --- LICENSE | 476 ++++++++++++++------------------------ README.md | 23 +- bin/mpw | 29 +-- bin/mpw-add | 29 +-- bin/mpw-config | 29 +-- bin/mpw-copy | 29 +-- bin/mpw-delete | 29 +-- bin/mpw-export | 28 +-- bin/mpw-genpwd | 28 +-- bin/mpw-import | 28 +-- bin/mpw-list | 28 +-- bin/mpw-update | 28 +-- bin/mpw-wallet | 28 +-- lib/mpw/cli.rb | 29 +-- lib/mpw/config.rb | 29 +-- lib/mpw/import/gorilla.rb | 29 +-- lib/mpw/import/keepass.rb | 29 +-- lib/mpw/import/mpw.rb | 29 +-- lib/mpw/import/mpw_old.rb | 29 +-- lib/mpw/item.rb | 29 +-- lib/mpw/mpw.rb | 29 +-- 21 files changed, 482 insertions(+), 562 deletions(-) diff --git a/LICENSE b/LICENSE index d159169..8dada3e 100644 --- a/LICENSE +++ b/LICENSE @@ -1,339 +1,201 @@ - GNU GENERAL PUBLIC LICENSE - Version 2, June 1991 + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ - Copyright (C) 1989, 1991 Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - Preamble + 1. Definitions. - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -License is intended to guarantee your freedom to share and change free -software--to make sure the software is free for all its users. This -General Public License applies to most of the Free Software -Foundation's software and to any other program whose authors commit to -using it. (Some other Free Software Foundation software is covered by -the GNU Lesser General Public License instead.) You can apply it to -your programs, too. + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -this service if you wish), that you receive source code or can get it -if you want it, that you can change the software or use pieces of it -in new free programs; and that you know you can do these things. + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. - To protect your rights, we need to make restrictions that forbid -anyone to deny you these rights or to ask you to surrender the rights. -These restrictions translate to certain responsibilities for you if you -distribute copies of the software, or if you modify it. + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must give the recipients all the rights that -you have. You must make sure that they, too, receive or can get the -source code. And you must show them these terms so they know their -rights. + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. - We protect your rights with two steps: (1) copyright the software, and -(2) offer you this license which gives you legal permission to copy, -distribute and/or modify the software. + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. - Also, for each author's protection and ours, we want to make certain -that everyone understands that there is no warranty for this free -software. If the software is modified by someone else and passed on, we -want its recipients to know that what they have is not the original, so -that any problems introduced by others will not reflect on the original -authors' reputations. + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. - Finally, any free program is threatened constantly by software -patents. We wish to avoid the danger that redistributors of a free -program will individually obtain patent licenses, in effect making the -program proprietary. To prevent this, we have made it clear that any -patent must be licensed for everyone's free use or not licensed at all. + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). - The precise terms and conditions for copying, distribution and -modification follow. + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. - GNU GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." - 0. This License applies to any program or other work which contains -a notice placed by the copyright holder saying it may be distributed -under the terms of this General Public License. The "Program", below, -refers to any such program or work, and a "work based on the Program" -means either the Program or any derivative work under copyright law: -that is to say, a work containing the Program or a portion of it, -either verbatim or with modifications and/or translated into another -language. (Hereinafter, translation is included without limitation in -the term "modification".) Each licensee is addressed as "you". + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. -Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running the Program is not restricted, and the output from the Program -is covered only if its contents constitute a work based on the -Program (independent of having been made by running the Program). -Whether that is true depends on what the Program does. + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. - 1. You may copy and distribute verbatim copies of the Program's -source code as you receive it, in any medium, provided that you -conspicuously and appropriately publish on each copy an appropriate -copyright notice and disclaimer of warranty; keep intact all the -notices that refer to this License and to the absence of any warranty; -and give any other recipients of the Program a copy of this License -along with the Program. + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. -You may charge a fee for the physical act of transferring a copy, and -you may at your option offer warranty protection in exchange for a fee. + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: - 2. You may modify your copy or copies of the Program or any portion -of it, thus forming a work based on the Program, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and - a) You must cause the modified files to carry prominent notices - stating that you changed the files and the date of any change. + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and - b) You must cause any work that you distribute or publish, that in - whole or in part contains or is derived from the Program or any - part thereof, to be licensed as a whole at no charge to all third - parties under the terms of this License. + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and - c) If the modified program normally reads commands interactively - when run, you must cause it, when started running for such - interactive use in the most ordinary way, to print or display an - announcement including an appropriate copyright notice and a - notice that there is no warranty (or else, saying that you provide - a warranty) and that users may redistribute the program under - these conditions, and telling the user how to view a copy of this - License. (Exception: if the Program itself is interactive but - does not normally print such an announcement, your work based on - the Program is not required to print an announcement.) + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Program, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Program, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote it. + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Program. + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. -In addition, mere aggregation of another work not based on the Program -with the Program (or with a work based on the Program) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. - 3. You may copy and distribute the Program (or a work based on it, -under Section 2) in object code or executable form under the terms of -Sections 1 and 2 above provided that you also do one of the following: + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. - a) Accompany it with the complete corresponding machine-readable - source code, which must be distributed under the terms of Sections - 1 and 2 above on a medium customarily used for software interchange; or, + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. - b) Accompany it with a written offer, valid for at least three - years, to give any third party, for a charge no more than your - cost of physically performing source distribution, a complete - machine-readable copy of the corresponding source code, to be - distributed under the terms of Sections 1 and 2 above on a medium - customarily used for software interchange; or, + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. - c) Accompany it with the information you received as to the offer - to distribute corresponding source code. (This alternative is - allowed only for noncommercial distribution and only if you - received the program in object code or executable form with such - an offer, in accord with Subsection b above.) + END OF TERMS AND CONDITIONS -The source code for a work means the preferred form of the work for -making modifications to it. For an executable work, complete source -code means all the source code for all modules it contains, plus any -associated interface definition files, plus the scripts used to -control compilation and installation of the executable. However, as a -special exception, the source code distributed need not include -anything that is normally distributed (in either source or binary -form) with the major components (compiler, kernel, and so on) of the -operating system on which the executable runs, unless that component -itself accompanies the executable. + APPENDIX: How to apply the Apache License to your work. -If distribution of executable or object code is made by offering -access to copy from a designated place, then offering equivalent -access to copy the source code from the same place counts as -distribution of the source code, even though third parties are not -compelled to copy the source along with the object code. + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. - 4. You may not copy, modify, sublicense, or distribute the Program -except as expressly provided under this License. Any attempt -otherwise to copy, modify, sublicense or distribute the Program is -void, and will automatically terminate your rights under this License. -However, parties who have received copies, or rights, from you under -this License will not have their licenses terminated so long as such -parties remain in full compliance. + Copyright {yyyy} {name of copyright owner} - 5. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Program or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Program (or any work based on the -Program), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Program or works based on it. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at - 6. Each time you redistribute the Program (or any work based on the -Program), the recipient automatically receives a license from the -original licensor to copy, distribute or modify the Program subject to -these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties to -this License. + http://www.apache.org/licenses/LICENSE-2.0 - 7. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Program at all. For example, if a patent -license would not permit royalty-free redistribution of the Program by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Program. - -If any portion of this section is held invalid or unenforceable under -any particular circumstance, the balance of the section is intended to -apply and the section as a whole is intended to apply in other -circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system, which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 8. If the distribution and/or use of the Program is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Program under this License -may add an explicit geographical distribution limitation excluding -those countries, so that distribution is permitted only in or among -countries not thus excluded. In such case, this License incorporates -the limitation as if written in the body of this License. - - 9. The Free Software Foundation may publish revised and/or new versions -of the General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - -Each version is given a distinguishing version number. If the Program -specifies a version number of this License which applies to it and "any -later version", you have the option of following the terms and conditions -either of that version or of any later version published by the Free -Software Foundation. If the Program does not specify a version number of -this License, you may choose any version ever published by the Free Software -Foundation. - - 10. If you wish to incorporate parts of the Program into other free -programs whose distribution conditions are different, write to the author -to ask for permission. For software which is copyrighted by the Free -Software Foundation, write to the Free Software Foundation; we sometimes -make exceptions for this. Our decision will be guided by the two goals -of preserving the free status of all derivatives of our free software and -of promoting the sharing and reuse of software generally. - - NO WARRANTY - - 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY -FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN -OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES -PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED -OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS -TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE -PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, -REPAIR OR CORRECTION. - - 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR -REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, -INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING -OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED -TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY -YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER -PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE -POSSIBILITY OF SUCH DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - <one line to give the program's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - 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 2 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, write to the Free Software Foundation, Inc., - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - -Also add information on how to contact you by electronic and paper mail. - -If the program is interactive, make it output a short notice like this -when it starts in an interactive mode: - - Gnomovision version 69, Copyright (C) year name of author - Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, the commands you use may -be called something other than `show w' and `show c'; they could even be -mouse-clicks or menu items--whatever suits your program. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the program, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the program - `Gnomovision' (which makes passes at compilers) written by James Hacker. - - <signature of Ty Coon>, 1 April 1989 - Ty Coon, President of Vice - -This General Public License does not permit incorporating your program into -proprietary programs. If your program is a subroutine library, you may -consider it more useful to permit linking proprietary applications with the -library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 4b0c0b0..be9e7cb 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # MPW: Manage your passwords! [](https://github.com/nishiki/manage-password/releases) [](https://travis-ci.org/nishiki/manage-password) -[](https://github.com/nishiki/manage-password/blob/master/LICENSE) +[](https://github.com/nishiki/manage-password/blob/master/LICENSE) mpw is a little software which stores your passwords in [GnuPG](http://www.gnupg.org/) encrypted files. @@ -33,7 +33,6 @@ Add your first item: ``` mpw add --host assurance.com --port 443 --user user_2132 --protocol https --random mpw add --host fric.com --user 230403 --otp-code 23434113 --protocol https --comment 'I love my bank' --random - ``` And list your items: @@ -174,3 +173,23 @@ Don't run the tests on your local machine, you risk to lost your datas. ``` docker run -v $(pwd):/mpw:ro -it nishiki/ruby:stretch /bin/bash -l /mpw/.docker-test ``` + +## License + +``` +* Author:: Adrien Waksberg <mpw@yae.im> + +Copyright (c) 2013-2017 Adrien Waksberg + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +``` diff --git a/bin/mpw b/bin/mpw index 384374a..11bc726 100755 --- a/bin/mpw +++ b/bin/mpw @@ -1,20 +1,23 @@ #!/usr/bin/env ruby -# MPW is a software to crypt and manage your passwords -# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # -# 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 2 -# of the License, or (at your option) any later version. +# Copyright:: 2013, Adrien Waksberg # -# 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. +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. $LOAD_PATH << File.expand_path('../../lib', __FILE__) diff --git a/bin/mpw-add b/bin/mpw-add index cdc23b0..e08caae 100644 --- a/bin/mpw-add +++ b/bin/mpw-add @@ -1,19 +1,22 @@ -# MPW is a software to crypt and manage your passwords -# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # -# 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 2 -# of the License, or (at your option) any later version. +# Copyright:: 2013, Adrien Waksberg # -# 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. +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. require 'optparse' require 'mpw/config' diff --git a/bin/mpw-config b/bin/mpw-config index e36d2f8..2ac0f77 100644 --- a/bin/mpw-config +++ b/bin/mpw-config @@ -1,19 +1,22 @@ -# MPW is a software to crypt and manage your passwords -# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # -# 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 2 -# of the License, or (at your option) any later version. +# Copyright:: 2013, Adrien Waksberg # -# 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. +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. require 'optparse' require 'mpw/config' diff --git a/bin/mpw-copy b/bin/mpw-copy index 01b75aa..fc3b6e0 100644 --- a/bin/mpw-copy +++ b/bin/mpw-copy @@ -1,19 +1,22 @@ -# MPW is a software to crypt and manage your passwords -# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # -# 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 2 -# of the License, or (at your option) any later version. +# Copyright:: 2013, Adrien Waksberg # -# 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. +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. require 'optparse' require 'mpw/config' diff --git a/bin/mpw-delete b/bin/mpw-delete index 78dc340..48eb792 100644 --- a/bin/mpw-delete +++ b/bin/mpw-delete @@ -1,19 +1,22 @@ -# MPW is a software to crypt and manage your passwords -# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # -# 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 2 -# of the License, or (at your option) any later version. +# Copyright:: 2013, Adrien Waksberg # -# 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. +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. require 'optparse' require 'mpw/config' diff --git a/bin/mpw-export b/bin/mpw-export index 3ab0945..92eb7bd 100644 --- a/bin/mpw-export +++ b/bin/mpw-export @@ -1,19 +1,19 @@ -# MPW is a software to crypt and manage your passwords -# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at # -# 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 2 -# of the License, or (at your option) any later version. +# http://www.apache.org/licenses/LICENSE-2.0 # -# 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, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. require 'optparse' require 'mpw/config' diff --git a/bin/mpw-genpwd b/bin/mpw-genpwd index de5628f..f6ca795 100644 --- a/bin/mpw-genpwd +++ b/bin/mpw-genpwd @@ -1,19 +1,19 @@ -# MPW is a software to crypt and manage your passwords -# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at # -# 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 2 -# of the License, or (at your option) any later version. +# http://www.apache.org/licenses/LICENSE-2.0 # -# 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, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. require 'optparse' require 'mpw/mpw' diff --git a/bin/mpw-import b/bin/mpw-import index 8213eb3..d0deae9 100644 --- a/bin/mpw-import +++ b/bin/mpw-import @@ -1,19 +1,19 @@ -# MPW is a software to crypt and manage your passwords -# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at # -# 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 2 -# of the License, or (at your option) any later version. +# http://www.apache.org/licenses/LICENSE-2.0 # -# 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, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. require 'optparse' require 'mpw/config' diff --git a/bin/mpw-list b/bin/mpw-list index 71e7b5a..fb7899c 100644 --- a/bin/mpw-list +++ b/bin/mpw-list @@ -1,19 +1,19 @@ -# MPW is a software to crypt and manage your passwords -# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at # -# 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 2 -# of the License, or (at your option) any later version. +# http://www.apache.org/licenses/LICENSE-2.0 # -# 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, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. require 'optparse' require 'mpw/config' diff --git a/bin/mpw-update b/bin/mpw-update index 53ce5f8..26a55c9 100644 --- a/bin/mpw-update +++ b/bin/mpw-update @@ -1,19 +1,19 @@ -# MPW is a software to crypt and manage your passwords -# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at # -# 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 2 -# of the License, or (at your option) any later version. +# http://www.apache.org/licenses/LICENSE-2.0 # -# 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, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. require 'optparse' require 'mpw/config' diff --git a/bin/mpw-wallet b/bin/mpw-wallet index 6f84afd..6518283 100644 --- a/bin/mpw-wallet +++ b/bin/mpw-wallet @@ -1,19 +1,19 @@ -# MPW is a software to crypt and manage your passwords -# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at # -# 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 2 -# of the License, or (at your option) any later version. +# http://www.apache.org/licenses/LICENSE-2.0 # -# 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, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. require 'optparse' require 'mpw/config' diff --git a/lib/mpw/cli.rb b/lib/mpw/cli.rb index db703a8..e64d27c 100644 --- a/lib/mpw/cli.rb +++ b/lib/mpw/cli.rb @@ -1,19 +1,22 @@ -# MPW is a software to crypt and manage your passwords -# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # -# 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 2 -# of the License, or (at your option) any later version. +# Copyright:: 2013, Adrien Waksberg # -# 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. +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. require 'readline' require 'locale' diff --git a/lib/mpw/config.rb b/lib/mpw/config.rb index a4d2142..f3974b5 100644 --- a/lib/mpw/config.rb +++ b/lib/mpw/config.rb @@ -1,19 +1,22 @@ -# MPW is a software to crypt and manage your passwords -# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # -# 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 2 -# of the License, or (at your option) any later version. +# Copyright:: 2013, Adrien Waksberg # -# 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. +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. require 'gpgme' require 'yaml' diff --git a/lib/mpw/import/gorilla.rb b/lib/mpw/import/gorilla.rb index a5a8fbe..feffce6 100644 --- a/lib/mpw/import/gorilla.rb +++ b/lib/mpw/import/gorilla.rb @@ -1,19 +1,22 @@ -# MPW is a software to crypt and manage your passwords -# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # -# 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 2 -# of the License, or (at your option) any later version. +# Copyright:: 2013, Adrien Waksberg # -# 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. +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. require 'csv' diff --git a/lib/mpw/import/keepass.rb b/lib/mpw/import/keepass.rb index b9d7852..0b961d4 100644 --- a/lib/mpw/import/keepass.rb +++ b/lib/mpw/import/keepass.rb @@ -1,19 +1,22 @@ -# MPW is a software to crypt and manage your passwords -# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # -# 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 2 -# of the License, or (at your option) any later version. +# Copyright:: 2013, Adrien Waksberg # -# 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. +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. require 'csv' diff --git a/lib/mpw/import/mpw.rb b/lib/mpw/import/mpw.rb index aca88aa..a287357 100644 --- a/lib/mpw/import/mpw.rb +++ b/lib/mpw/import/mpw.rb @@ -1,19 +1,22 @@ -# MPW is a software to crypt and manage your passwords -# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # -# 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 2 -# of the License, or (at your option) any later version. +# Copyright:: 2013, Adrien Waksberg # -# 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. +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. require 'yaml' diff --git a/lib/mpw/import/mpw_old.rb b/lib/mpw/import/mpw_old.rb index 7f8c33e..923bf16 100644 --- a/lib/mpw/import/mpw_old.rb +++ b/lib/mpw/import/mpw_old.rb @@ -1,19 +1,22 @@ -# MPW is a software to crypt and manage your passwords -# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # -# 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 2 -# of the License, or (at your option) any later version. +# Copyright:: 2013, Adrien Waksberg # -# 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. +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. require 'yaml' diff --git a/lib/mpw/item.rb b/lib/mpw/item.rb index ec4c50e..9da60b1 100644 --- a/lib/mpw/item.rb +++ b/lib/mpw/item.rb @@ -1,19 +1,22 @@ -# MPW is a software to crypt and manage your passwords -# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # -# 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 2 -# of the License, or (at your option) any later version. +# Copyright:: 2013, Adrien Waksberg # -# 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. +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. require 'i18n' require 'uri' diff --git a/lib/mpw/mpw.rb b/lib/mpw/mpw.rb index a67f09d..191caae 100644 --- a/lib/mpw/mpw.rb +++ b/lib/mpw/mpw.rb @@ -1,19 +1,22 @@ -# MPW is a software to crypt and manage your passwords -# Copyright (C) 2017 Adrien Waksberg <mpw@yae.im> # -# 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 2 -# of the License, or (at your option) any later version. +# Copyright:: 2013, Adrien Waksberg # -# 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. +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at # -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. require 'rubygems/package' require 'gpgme' From be526c297f09b68f312a1653898c6e6653cdd08e Mon Sep 17 00:00:00 2001 From: Adrien Waksberg <git@yae.im> Date: Thu, 7 Dec 2017 14:15:51 +0100 Subject: [PATCH 165/165] fix: update LICENSE with good copyright --- LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE b/LICENSE index 8dada3e..0c5ea8e 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright {yyyy} {name of copyright owner} + Copyright 2017 Adrien Waksberg Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License.