Commit a9d38c6c authored by Benoit Lavenier's avatar Benoit Lavenier

Fix WIF and EWIF keychain file generation

parent 5850a26b
......@@ -518,6 +518,9 @@
"BTN_RESET" : "Reset",
"DOWNLOAD_REVOKE": "Save a revocation file",
"DOWNLOAD_REVOKE_HELP" : "Having a revocation file is important, for example in case of loss of identifiers. It allows you to <b>get this account out of the Web Of Trust</b>, thus becoming a simple wallet.",
"GENERATE_KEYFILE": "Generate my keychain file ...",
"GENERATE_KEYFILE_HELP": "Generate a file allowing you to authenticate without entering your identifiers.<br/><b>Warning:</b> this file will contain your secret key; It is therefore very important to put it in a safe place!",
"KEYFILE_FILENAME": "keychain-{{pubkey|formatPubkey}}-{{currency}}-{{format}}.dunikey",
"MEMBERSHIP_IN": "Register as member...",
"MEMBERSHIP_IN_HELP": "Allows you to <b>transform </b> a simple wallet account <b>into a member account</b>, by sending a membership request. Useful only if you do not already have another member account.",
"SEND_IDENTITY": "Publish identity...",
......@@ -556,7 +559,23 @@
"SAVE_ID": "Save my credentials...",
"SAVE_ID_HELP": "Creating a backup file, to <b>retrieve your password</b> (and the secret identifier) <b> in case of forgetting</b>. The file is <b>secured</ b> (encrypted) using personal questions.",
"STRONG_LEVEL": "Strong <span class=\"hidden-xs \">(6 questions minimum)</span>",
"TITLE": "Account and security"
"TITLE": "Account and security",
"KEYFILE": {
"PUBSEC_FORMAT": "PubSec format.",
"PUBSEC_FORMAT_HELP": "This file format is compatible in particular with Cesium and Gannonce. Your keychain is stored <b>without encryption</b>: anyone with a copy of this file will be able to empty your account.",
"WIF_FORMAT": "Wallet Import Format (WIF)",
"WIF_FORMAT_HELP": "This format is used in particular by paper wallets. Your keychain is stored <b>without encryption</b>: anyone with a copy of this file will be able to empty your account.",
"EWIF_FORMAT": "Encrypted Wallet Import Format (WIF)",
"EWIF_FORMAT_HELP": "This format is used in particular by paper wallets. However, <b>the keychain is encrypted</b> from a passphrase of your choice.",
"PASSWORD_POPUP": {
"TITLE": "Keychain file encrypted",
"HELP": "Please enter the passphrase:",
"PASSWORD_HELP": "Passphrase"
},
"ERROR": {
"BAD_PASSWORD": "Bad passphrase"
}
}
},
"FILE_NAME": "{{currency}} - Account statement {{pubkey|formatPubkey}} to {{currentTime|formatDateForFile}}.csv",
"HEADERS": {
......@@ -582,9 +601,12 @@
}
},
"ERROR": {
"UNKNOWN_URI_FORMAT": "Unknown URI format",
"PUBKEY_INVALID_CHECKSUM": "Invalid public key (bad checksum).",
"POPUP_TITLE": "Error",
"UNKNOWN_ERROR": "Unknown error",
"CRYPTO_UNKNOWN_ERROR": "Your browser is not compatible with cryptographic features.",
"DOWNLOAD_KEYFILE_FAILED": "Failed to generate the keychain file.",
"EQUALS_TO_PSEUDO": "Must be different from pseudonym",
"EQUALS_TO_SALT": "Must be different from secret identifier",
"FIELD_REQUIRED": "This field is required.",
......@@ -634,6 +656,7 @@
"INVALID_USER_ID": "Field 'pseudonym' must not contains spaces or special characters.",
"INVALID_COMMENT": "Field 'reference' has a bad format.",
"INVALID_PUBKEY": "Public key has a bad format.",
"INVALID_PUBKEY_CHECKSUM": "Invalid checksum.",
"IDENTITY_REVOKED": "This identity <b>has been revoked {{revocationTime|formatFromNow}}</b> ({{revocationTime|formatDate}}). It can no longer become a member.",
"IDENTITY_PENDING_REVOCATION": "The <b>revocation of this identity</b> has been requested and is awaiting processing. Certification is therefore disabled.",
"IDENTITY_INVALID_BLOCK_HASH": "This membership application is no longer valid (because it references a block that network peers are cancelled): the person must renew its application for membership <b>before</b> being certified.",
......
......@@ -518,6 +518,9 @@
"BTN_RESET" : "Reset",
"DOWNLOAD_REVOKE": "Save a revocation file",
"DOWNLOAD_REVOKE_HELP" : "Having a revocation file is important, for example in case of loss of identifiers. It allows you to <b>get this account out of the Web Of Trust</b>, thus becoming a simple wallet.",
"GENERATE_KEYFILE": "Generate my keychain file ...",
"GENERATE_KEYFILE_HELP": "Generate a file allowing you to authenticate without entering your identifiers.<br/><b>Warning:</b> this file will contain your secret key; It is therefore very important to put it in a safe place!",
"KEYFILE_FILENAME": "keychain-{{pubkey|formatPubkey}}-{{currency}}-{{format}}.dunikey",
"MEMBERSHIP_IN": "Register as member...",
"MEMBERSHIP_IN_HELP": "Allows you to <b>transform </b> a simple wallet account <b>into a member account</b>, by sending a membership request. Useful only if you do not already have another member account.",
"SEND_IDENTITY": "Publish identity...",
......@@ -556,7 +559,23 @@
"SAVE_ID": "Save my credentials...",
"SAVE_ID_HELP": "Creating a backup file, to <b>retrieve your password</b> (and the secret identifier) <b> in case of forgetting</b>. The file is <b>secured</ b> (encrypted) using personal questions.",
"STRONG_LEVEL": "Strong <span class=\"hidden-xs \">(6 questions minimum)</span>",
"TITLE": "Account and security"
"TITLE": "Account and security",
"KEYFILE": {
"PUBSEC_FORMAT": "PubSec format.",
"PUBSEC_FORMAT_HELP": "This file format is compatible in particular with Cesium and Gannonce. Your keychain is stored <b>without encryption</b>: anyone with a copy of this file will be able to empty your account.",
"WIF_FORMAT": "Wallet Import Format (WIF)",
"WIF_FORMAT_HELP": "This format is used in particular by paper wallets. Your keychain is stored <b>without encryption</b>: anyone with a copy of this file will be able to empty your account.",
"EWIF_FORMAT": "Encrypted Wallet Import Format (WIF)",
"EWIF_FORMAT_HELP": "This format is used in particular by paper wallets. However, <b>the keychain is encrypted</b> from a passphrase of your choice.",
"PASSWORD_POPUP": {
"TITLE": "Keychain file encrypted",
"HELP": "Please enter the passphrase:",
"PASSWORD_HELP": "Passphrase"
},
"ERROR": {
"BAD_PASSWORD": "Bad passphrase"
}
}
},
"FILE_NAME": "{{currency}} - Account statement {{pubkey|formatPubkey}} to {{currentTime|formatDateForFile}}.csv",
"HEADERS": {
......@@ -582,9 +601,12 @@
}
},
"ERROR": {
"UNKNOWN_URI_FORMAT": "Unknown URI format",
"PUBKEY_INVALID_CHECKSUM": "Invalid public key (bad checksum).",
"POPUP_TITLE": "Error",
"UNKNOWN_ERROR": "Unknown error",
"CRYPTO_UNKNOWN_ERROR": "Your browser is not compatible with cryptographic features.",
"DOWNLOAD_KEYFILE_FAILED": "Failed to generate the keychain file.",
"EQUALS_TO_PSEUDO": "Must be different from pseudonym",
"EQUALS_TO_SALT": "Must be different from secret identifier",
"FIELD_REQUIRED": "This field is required.",
......@@ -634,6 +656,7 @@
"INVALID_USER_ID": "Field 'pseudonym' must not contains spaces or special characters.",
"INVALID_COMMENT": "Field 'reference' has a bad format.",
"INVALID_PUBKEY": "Public key has a bad format.",
"INVALID_PUBKEY_CHECKSUM": "Invalid checksum.",
"IDENTITY_REVOKED": "This identity <b>has been revoked {{revocationTime|formatFromNow}}</b> ({{revocationTime|formatDate}}). It can no longer become a member.",
"IDENTITY_PENDING_REVOCATION": "The <b>revocation of this identity</b> has been requested and is awaiting processing. Certification is therefore disabled.",
"IDENTITY_INVALID_BLOCK_HASH": "This membership application is no longer valid (because it references a block that network peers are cancelled): the person must renew its application for membership <b>before</b> being certified.",
......
......@@ -423,7 +423,7 @@
"TYPE" : "Type :",
"SIZE": "Taille :",
"VALIDATING": "Validation en cours...",
"HELP": "Format de fichier attendu : <b>.dunikey</b> (type PubSec). D'autres formats sont en cours de développement (EWIF, WIF)."
"HELP": "Format de fichier attendu : <b>.yml</b> ou <b>.dunikey</b> (type PubSec, WIF ou EWIF)."
}
},
"AUTH": {
......@@ -519,7 +519,7 @@
"DOWNLOAD_REVOKE": "Sauvegarder mon fichier de révocation",
"DOWNLOAD_REVOKE_HELP": "Disposer d'un fichier de révocation est important, par exemple en cas de perte de vos identifiants. Il vous permet de <b>sortir ce compte de la toile de confiance</b>, en redevenant ainsi un simple portefeuille.",
"GENERATE_KEYFILE": "Générer mon fichier de trousseau...",
"GENERATE_KEYFILE_HELP": "Génère un fichier permettant de vous authentifier sans saisir vos identifiants.<br/><b>Attention :</b> ce fichier contiendra votre clef secrète : il est donc très important de le mettre en lieu sûr !",
"GENERATE_KEYFILE_HELP": "Génère un fichier permettant de vous authentifier sans saisir vos identifiants.<br/><b>Attention :</b> ce fichier contiendra votre trousseau de compte (clefs publique et secrète) ; Il est donc très important de le mettre en lieu sûr !",
"KEYFILE_FILENAME": "trousseau-{{pubkey|formatPubkey}}-{{currency}}-{{format}}.dunikey",
"MEMBERSHIP_IN": "Transformer en compte membre...",
"MEMBERSHIP_IN_HELP": "Permet de <b>transformer</b> un compte simple portefeuille <b>en compte membre</b>, en envoyant une demande d'adhésion. Utile uniquement si vous n'avez pas déjà une autre compte membre.",
......@@ -562,15 +562,18 @@
"TITLE": "Compte et sécurité",
"KEYFILE": {
"PUBSEC_FORMAT": "Format PubSec.",
"PUBSEC_FORMAT_HELP": "Ce format de fichier est compatible notamment avec Cesium et gannonce.",
"WIF_FORMAT": "Format WIF",
"WIF_FORMAT_HELP": "Ce format permet notamment la génération de portefeuilles papier (Paper Wallet).",
"EWIF_FORMAT": "Format EWIF",
"EWIF_FORMAT_HELP": "Ce format protège le trousseau par un mot de passe. Il permet notamment la génération de portefeuilles papier (Paper Wallet).",
"PUBSEC_FORMAT_HELP": "Ce format votre stocke votre trousseau de manière très simple. Il est compatible notamment avec Cesium, ğannonce et Duniter.<br/><b>Attention:</b>Le fichier <b>n'est pas chiffré</b> (la clef secrète y apparait en clair); Veuillez donc le stocker en lieu sûr !",
"WIF_FORMAT": "Format WIF (Wallet Import Format) - v1",
"WIF_FORMAT_HELP": "Ce format stocke votre votre trousseau, en y intégrant une somme de contrôle pour vérifier l'intégrité du fichier. Il est compatible notamment avec les portefeuilles papier (Duniter paper wallet).<br/><b>Attention:</b>Le fichier <b>n'est pas chiffré</b> (la clef secrète y apparait en clair); Veuillez donc le stocker en lieu sûr !",
"EWIF_FORMAT": "Format EWIF (Encrypted Wallet Import Format) - v1",
"EWIF_FORMAT_HELP": "Ce format stocke votre trouseau <b>de manière chiffré</b> à partir d'une phrase secrète de votre choix. Il intègre aussi une somme de contrôle pour vérifier l'intégrité du fichier.<br/><b>Attention:</b> Veuillez à toujours vous rappeller de votre phrase secrète !",
"PASSWORD_POPUP": {
"TITLE": "Fichier de trousseau chiffré",
"HELP": "Veuillez indiquer le mot de passe:",
"PASSWORD_HELP": "Mot de passe"
"HELP": "Veuillez indiquer la phrase secrète:",
"PASSWORD_HELP": "Phrase secrète"
},
"ERROR": {
"BAD_PASSWORD": "Phrase secrète incorrecte"
}
}
},
......
......@@ -86,37 +86,44 @@ function AppController($scope, $rootScope, $state, $ionicSideMenuDelegate, $q, $
// Device Methods
////////////////////////////////////////
function parseWif(data) {
return CryptoUtils.readWif(data, {
password: function() {
return Modals.showPassword({
function parseWIF(data, options) {
options = options || {};
options.withSecret = angular.isDefined(options.withSecret) && options.withSecret || true;
options.password = function() {
return Modals.showPassword({
title: 'ACCOUNT.SECURITY.KEYFILE.PASSWORD_POPUP.TITLE',
subTitle: 'ACCOUNT.SECURITY.KEYFILE.PASSWORD_POPUP.HELP'
subTitle: 'ACCOUNT.SECURITY.KEYFILE.PASSWORD_POPUP.HELP',
error: options.error
})
.then(function(password) {
UIUtils.loading.show();
if (password) UIUtils.loading.show();
return password;
});
}
})
};
return CryptoUtils.parseWIF_or_EWIF(data, options)
.catch(function(err) {
if (err && err == 'CANCELLED') return;
if (err && err == 'BAD_PASSWORD') return parseWif(); // recursive call
if (err && err.ucode == CryptoUtils.errorCodes.BAD_PASSWORD) {
// recursive call
return parseWIF(data, {withSecret: options.withSecret, error: 'ACCOUNT.SECURITY.KEYFILE.ERROR.BAD_PASSWORD'});
}
console.error("[app] Unable to parse as WIF or EWIF format: " + (err && err.message || err));
throw err; // rethrow
});
}
$scope.scanQrCodeAndGo = function() {
if (!Device.barcode.enable) {
return;
}
Device.barcode.scan()
if (!Device.barcode.enable) return;
// Run scan cordova plugin, on device
return Device.barcode.scan()
.then(function(data) {
if (!data) return;
// Parse as an URI
BMA.uri.parse(data)
// Try to parse as an URI
return BMA.uri.parse(data)
.then(function(res){
if (!res || res.pubkey) throw {message: 'ERROR.SCAN_UNKNOWN_FORMAT'};
// If pubkey: open the identity
......@@ -131,15 +138,14 @@ function AppController($scope, $rootScope, $state, $ionicSideMenuDelegate, $q, $
console.debug(err && err.message || err);
// Try to read as WIF format
return parseWif(data)
return parseWIF(data)
.then(function(keypair) {
if (!keypair || !keypair.signPk || !keypair.signSk) throw {message: 'ERROR.SCAN_UNKNOWN_FORMAT'};
var pubkey = CryptoUtils.base58.encode(keypair.signPk);
if (!keypair || !keypair.signPk || !keypair.signSk) throw err; // rethrow the first error
return csWallet.login({
forceAuth: true,
minData: false,
authData: {
pubkey: pubkey,
pubkey: CryptoUtils.base58.encode(keypair.signPk),
keypair: keypair
}
})
......
......@@ -325,10 +325,11 @@ function LoginModalController($scope, $timeout, $q, $ionicPopover, CryptoUtils,
options = options || {};
options.password = options.password || $scope.formData.file.password || function() {
$scope.formData.file.password = undefined;
$scope.formData.file.password = undefined;
return Modals.showPassword({
title: 'ACCOUNT.SECURITY.KEYFILE.PASSWORD_POPUP.TITLE',
subTitle: 'ACCOUNT.SECURITY.KEYFILE.PASSWORD_POPUP.HELP'
subTitle: 'ACCOUNT.SECURITY.KEYFILE.PASSWORD_POPUP.HELP',
error: options.error
})
.then(function (password) {
// Remember password (for validation)
......@@ -339,9 +340,10 @@ function LoginModalController($scope, $timeout, $q, $ionicPopover, CryptoUtils,
return CryptoUtils.readKeyFile($scope.formData.file, options)
.catch(function(err) {
if (err && err == 'CANCELLED') return;
if (err && err == 'BAD_PASSWORD') {
return $scope.readKeyFile($scope.formData.file, options); // Loop (ask the password again)
$scope.formData.file.password = undefined;
if (err && err.ucode == CryptoUtils.errorCodes.BAD_PASSWORD) {
// Recursive call
return $scope.readKeyFile($scope.formData.file, {withSecret: options.withSecret, error: 'ACCOUNT.SECURITY.KEYFILE.ERROR.BAD_PASSWORD'});
}
throw err;
});
......
This diff is collapsed.
......@@ -146,7 +146,7 @@ angular.module('cesium.modal.services', [])
};
})
.factory('Modals', function($rootScope, $translate, $ionicPopup, ModalUtils, UIUtils) {
.factory('Modals', function($rootScope, $translate, $ionicPopup, $timeout, ModalUtils, UIUtils) {
'ngInject';
function showTransfer(parameters) {
......@@ -235,14 +235,14 @@ angular.module('cesium.modal.services', [])
};
scope.submit = function(e) {
scope.form.$submitted=true;
if(!scope.form.$valid || !scope.formData.password) {
//don't allow the user to close unless he enters a uid
if (e && e.preventDefault) e.preventDefault();
} else {
if (e && e.preventDefault) e.preventDefault();
if(scope.form.$valid && scope.formData.password) {
options.popup.close(scope.formData.password);
}
};
scope.error = options.error || undefined;
// Choose password popup
return $translate([options.title, options.subTitle, 'COMMON.BTN_OK', 'COMMON.BTN_CANCEL'])
.then(function (translations) {
......
......@@ -1409,41 +1409,30 @@ angular.module('cesium.wallet.services', ['ngApi', 'ngFileSaver', 'cesium.bma.se
},
getKeyFileDocument =function(format) {
var document;
switch(format) {
case "PubSec" :
document = "Type: PubSec\n" +
"Version: 1\n" +
"pub: " + data.pubkey + "\n" +
"sec: " + CryptoUtils.base58.encode(data.keypair.signSk) + "\n";
break;
case "WIF" :
document = "Type: WIF\n" +
"Version: 1\n" +
"Data: " + CryptoUtils.wif_v1_from_keypair(data.keypair)+ "\n";
break;
case "EWIF" :
document = "Type: EWIF\n" +
"Version: 1\n" +
"Data: " + CryptoUtils.ewif_v1_from_keypair(data.keypair, "bonjour") + "\n";
break;
default:
return $q.reject("Unknown keyfile format: " + format);
}
if (document) {
return $q.resolve(document);
}
},
downloadKeyFile = function(format){
if (!isAuth()) return $q.reject('user not authenticated');
return $q.all([
csCurrency.get(),
getKeyFileDocument(format)
CryptoUtils.generateKeyFileContent(data.keypair,
{
type: format,
password: function() {
UIUtils.loading.hide();
return Modals.showPassword({
title: 'ACCOUNT.SECURITY.KEYFILE.PASSWORD_POPUP.TITLE',
subTitle: 'ACCOUNT.SECURITY.KEYFILE.PASSWORD_POPUP.HELP'
})
.then(function(password) {
return UIUtils.loading.show(10)
.then(function(){
return password;
});
});
}
})
])
.then(function(res) {
var currency = res[0];
......
......@@ -17,5 +17,8 @@
<span translate="ERROR.FIELD_TOO_SHORT"></span>
</div>
</div>
<div class="form-errors" ng-if="error">
<div class="form-error" >{{error|translate}}</div>
</div>
</div>
</form>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment