Verified Commit c5b7d575 authored by Didier WECKMANN's avatar Didier WECKMANN
Browse files

feat(io): add a "retry/cancel" dialog when the password is wrong

parent 0aae7ba1
......@@ -43,7 +43,7 @@ public:
NEVER = 0, /// Never use a password
ONCE = 1, /// Ask for password once and reuse it later
ALWAYS = 2, /// Always ask for a password
DEFAULT = NEVER, /// Default behavior is nothing is set
DEFAULT = NEVER, /// Default behavior if nothing is set
INVALID = 255 /// Used for error management
};
......@@ -53,7 +53,7 @@ public:
PASSWORD = 0, /// Use the given password for encryption
SALTED = 1, /// Use the given password with salt for encryption
FORCED = 2, /// Force encryption with a pseudo random hidden password
DEFAULT = PASSWORD, /// Default behavior is nothing is set
DEFAULT = PASSWORD, /// Default behavior if nothing is set
INVALID = 255 /// Used for error management
};
......
......@@ -47,7 +47,7 @@ public:
inline SessionReaderImpl(SessionReader* const sessionReader) :
m_SessionReader(sessionReader),
m_password(std::make_unique<PasswordKeeper>()),
m_EncryptionPolicy(PasswordKeeper::EncryptionPolicy::DEFAULT)
m_encryptionPolicy(PasswordKeeper::EncryptionPolicy::DEFAULT)
{
}
......@@ -59,7 +59,7 @@ public:
{
// Create the session and deserialize the root object
detail::SessionDeserializer session;
m_object = session.deserialize(m_SessionReader->getFile(), m_password->getPassword(), m_EncryptionPolicy);
m_object = session.deserialize(m_SessionReader->getFile(), m_password->getPassword(), m_encryptionPolicy);
}
/// Use a shared_ptr to keep the object alive as it is the read() return value
......@@ -72,7 +72,7 @@ public:
const std::unique_ptr<PasswordKeeper> m_password;
/// The encryption policy
PasswordKeeper::EncryptionPolicy m_EncryptionPolicy;
PasswordKeeper::EncryptionPolicy m_encryptionPolicy;
};
SessionReader::SessionReader(base::reader::IObjectReader::Key) :
......@@ -111,7 +111,7 @@ void SessionReader::setPassword(const core::crypto::secure_string& password)
void SessionReader::setEncryptionPolicy(const PasswordKeeper::EncryptionPolicy policy)
{
m_pimpl->m_EncryptionPolicy = policy;
m_pimpl->m_encryptionPolicy = policy;
}
} // namespace sight::io::session
......@@ -47,7 +47,7 @@ public:
inline SessionWriterImpl(SessionWriter* const sessionWriter) :
m_SessionWriter(sessionWriter),
m_password(std::make_unique<PasswordKeeper>()),
m_EncryptionPolicy(PasswordKeeper::EncryptionPolicy::DEFAULT)
m_encryptionPolicy(PasswordKeeper::EncryptionPolicy::DEFAULT)
{
}
......@@ -67,7 +67,7 @@ public:
m_SessionWriter->getFile(),
root_object,
m_password->getPassword(),
m_EncryptionPolicy
m_encryptionPolicy
);
}
......@@ -78,7 +78,7 @@ public:
const std::unique_ptr<PasswordKeeper> m_password;
/// The encryption policy
PasswordKeeper::EncryptionPolicy m_EncryptionPolicy;
PasswordKeeper::EncryptionPolicy m_encryptionPolicy;
};
SessionWriter::SessionWriter(base::writer::IObjectWriter::Key) :
......@@ -114,7 +114,7 @@ void SessionWriter::setPassword(const core::crypto::secure_string& password)
void SessionWriter::setEncryptionPolicy(const PasswordKeeper::EncryptionPolicy policy)
{
m_pimpl->m_EncryptionPolicy = policy;
m_pimpl->m_encryptionPolicy = policy;
}
} //namespace sight::io::session
......@@ -230,18 +230,29 @@ public:
{
// In case of error, unlock the file
m_attributes.m_archive->unlock(m_attributes.m_filePath);
}
SIGHT_THROW_EXCEPTION_IF(
exception::Read(
"Cannot open file '"
+ m_attributes.m_filePath.string()
+ "' in archive '"
+ m_attributes.m_archive->m_archivePath.string()
+ "'."
),
result != MZ_OK
);
SIGHT_THROW_EXCEPTION_IF(
exception::BadPassword(
"The password used to open file '"
+ m_attributes.m_filePath.string()
+ "' in archive '"
+ m_attributes.m_archive->m_archivePath.string()
+ "' is wrong."
),
result == MZ_PASSWORD_ERROR
);
SIGHT_THROW_EXCEPTION(
exception::Read(
"Cannot open file '"
+ m_attributes.m_filePath.string()
+ "' in archive '"
+ m_attributes.m_archive->m_archivePath.string()
+ "'.\n\n Error code: "
+ std::to_string(result)
)
);
}
}
~HandleKeeper()
......
/************************************************************************
*
* Copyright (C) 2009-2021 IRCAD France
* Copyright (C) 2012-2015 IHU Strasbourg
*
* This file is part of Sight.
*
* Sight is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Sight 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Sight. If not, see <https://www.gnu.org/licenses/>.
*
***********************************************************************/
#include "io/zip/exception/Read.hpp"
#include "io/zip/config.hpp"
#include <core/Exception.hpp>
namespace sight::io::zip
{
namespace exception
{
Read::Read(const std::string& err) :
core::Exception(err)
{
}
} // namespace exception
} // namespace sight::io::zip
......@@ -35,7 +35,18 @@ namespace exception
/// Read exception.
struct Read : core::Exception
{
IO_ZIP_API Read(const std::string& err);
inline Read(const std::string& err) :
core::Exception(err)
{
}
};
struct BadPassword : Read
{
inline BadPassword(const std::string& err) :
Read(err)
{
}
};
} // namespace exception
......
/************************************************************************
*
* Copyright (C) 2009-2021 IRCAD France
* Copyright (C) 2012-2015 IHU Strasbourg
*
* This file is part of Sight.
*
* Sight is free software: you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Sight 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with Sight. If not, see <https://www.gnu.org/licenses/>.
*
***********************************************************************/
#include "io/zip/exception/Write.hpp"
#include "io/zip/config.hpp"
#include <core/Exception.hpp>
namespace sight::io::zip
{
namespace exception
{
Write::Write(const std::string& err) :
core::Exception(err)
{
}
} // namespace exception
} // namespace sight::io::zip
......@@ -35,7 +35,10 @@ namespace exception
/// Write exception.
struct Write : core::Exception
{
IO_ZIP_API Write(const std::string& err);
inline Write(const std::string& err) :
core::Exception(err)
{
}
};
} // namespace exception
......
......@@ -61,6 +61,7 @@ public:
YES = 1 << 2,
NO = 1 << 3,
CANCEL = 1 << 4,
RETRY = 1 << 5,
YES_NO = YES | NO
} Buttons;
......@@ -81,7 +82,7 @@ public:
/// Set the icon (CRITICAL, WARNING, INFO or QUESTION)
UI_BASE_API virtual void setIcon(Icons icon) = 0;
/// Add a button (OK, YES_NO, YES, NO, CANCEL)
/// Add a button (OK, YES_NO, YES, NO, CANCEL, RETRY)
UI_BASE_API virtual void addButton(Buttons button) = 0;
/// Set the default button
......
......@@ -61,7 +61,8 @@ MessageDialogQmlButtonType messageDialogQmlButton =
{ui::base::dialog::IMessageDialog::OK, StandardButton::ButtonList::Ok},
{ui::base::dialog::IMessageDialog::CANCEL, StandardButton::ButtonList::Cancel},
{ui::base::dialog::IMessageDialog::YES, StandardButton::ButtonList::Yes},
{ui::base::dialog::IMessageDialog::NO, StandardButton::ButtonList::No}
{ui::base::dialog::IMessageDialog::NO, StandardButton::ButtonList::No},
{ui::base::dialog::IMessageDialog::RETRY, StandardButton::ButtonList::Retry}
};
//------------------------------------------------------------------------------
......
......@@ -48,11 +48,12 @@ MessageDialogQtIconsType messageDialogQtIcons = {{ui::base::dialog::IMessageDial
typedef const std::map<ui::base::dialog::IMessageDialog::Buttons,
QMessageBox::StandardButtons> MessageDialogQtButtonType;
MessageDialogQtButtonType messageDialogQtButton = {{ui::base::dialog::IMessageDialog::OK, QMessageBox::Ok},
MessageDialogQtButtonType messageDialogQtButton = {
{ui::base::dialog::IMessageDialog::OK, QMessageBox::Ok},
{ui::base::dialog::IMessageDialog::CANCEL, QMessageBox::Cancel},
{ui::base::dialog::IMessageDialog::YES, QMessageBox::Yes},
{ui::base::dialog::IMessageDialog::NO, QMessageBox::No
}
{ui::base::dialog::IMessageDialog::NO, QMessageBox::No},
{ui::base::dialog::IMessageDialog::RETRY, QMessageBox::Retry}
};
//------------------------------------------------------------------------------
......
......@@ -31,6 +31,7 @@
#include <io/session/PasswordKeeper.hpp>
#include <io/session/SessionReader.hpp>
#include <io/zip/exception/Read.hpp>
#include <ui/base/Cursor.hpp>
#include <ui/base/dialog/InputDialog.hpp>
......@@ -74,13 +75,16 @@ public:
std::string m_extensionDescription {"Sight session"};
/// Password policy to use
PasswordKeeper::PasswordPolicy m_PasswordPolicy {PasswordKeeper::PasswordPolicy::DEFAULT};
PasswordKeeper::PasswordPolicy m_passwordPolicy {PasswordKeeper::PasswordPolicy::DEFAULT};
/// Encryption policy to use
PasswordKeeper::EncryptionPolicy m_EncryptionPolicy {PasswordKeeper::EncryptionPolicy::DEFAULT};
PasswordKeeper::EncryptionPolicy m_encryptionPolicy {PasswordKeeper::EncryptionPolicy::DEFAULT};
/// Signal emitted when job created.
JobCreatedSignal::sptr m_jobCreatedSignal;
/// Used in case of bad password
int m_passwordRetry {0};
};
SReader::SReader() noexcept :
......@@ -124,23 +128,23 @@ void SReader::configuring()
if(password.is_initialized())
{
// Password policy
m_pimpl->m_PasswordPolicy = PasswordKeeper::stringToPasswordPolicy(
m_pimpl->m_passwordPolicy = PasswordKeeper::stringToPasswordPolicy(
password->get<std::string>("policy")
);
SIGHT_THROW_IF(
"Cannot read password policy.",
m_pimpl->m_PasswordPolicy == PasswordKeeper::PasswordPolicy::INVALID
m_pimpl->m_passwordPolicy == PasswordKeeper::PasswordPolicy::INVALID
);
// Encryption policy
m_pimpl->m_EncryptionPolicy = PasswordKeeper::stringToEncryptionPolicy(
m_pimpl->m_encryptionPolicy = PasswordKeeper::stringToEncryptionPolicy(
password->get<std::string>("encryption")
);
SIGHT_THROW_IF(
"Cannot read encryption policy.",
m_pimpl->m_EncryptionPolicy == PasswordKeeper::EncryptionPolicy::INVALID
m_pimpl->m_encryptionPolicy == PasswordKeeper::EncryptionPolicy::INVALID
);
}
}
......@@ -171,7 +175,7 @@ void SReader::updating()
const secure_string& password =
[&]
{
if(m_pimpl->m_PasswordPolicy == PasswordKeeper::PasswordPolicy::NEVER)
if(m_pimpl->m_passwordPolicy == PasswordKeeper::PasswordPolicy::NEVER)
{
// No password management
return secure_string();
......@@ -180,8 +184,9 @@ void SReader::updating()
{
const secure_string& globalPassword = PasswordKeeper::getGlobalPassword();
if((m_pimpl->m_PasswordPolicy == PasswordKeeper::PasswordPolicy::ALWAYS)
|| (m_pimpl->m_PasswordPolicy == PasswordKeeper::PasswordPolicy::ONCE
if(m_pimpl->m_passwordRetry > 0
|| (m_pimpl->m_passwordPolicy == PasswordKeeper::PasswordPolicy::ALWAYS)
|| (m_pimpl->m_passwordPolicy == PasswordKeeper::PasswordPolicy::ONCE
&& globalPassword.empty()))
{
sight::ui::base::dialog::InputDialog inputDialog;
......@@ -194,7 +199,7 @@ void SReader::updating()
)
);
if(m_pimpl->m_PasswordPolicy == PasswordKeeper::PasswordPolicy::ONCE)
if(m_pimpl->m_passwordPolicy == PasswordKeeper::PasswordPolicy::ONCE)
{
PasswordKeeper::setGlobalPassword(newPassword);
}
......@@ -216,7 +221,7 @@ void SReader::updating()
auto reader = sight::io::session::SessionReader::New();
reader->setFile(filepath);
reader->setPassword(password);
reader->setEncryptionPolicy(m_pimpl->m_EncryptionPolicy);
reader->setEncryptionPolicy(m_pimpl->m_encryptionPolicy);
// Set cursor to busy state. It will be reset to default even if exception occurs
const sight::ui::base::BusyCursor busyCursor;
......@@ -253,6 +258,28 @@ void SReader::updating()
jobs->run().get();
m_readFailed = false;
}
catch(sight::io::zip::exception::BadPassword& badPassword)
{
// Ask if the user want to retry.
sight::ui::base::dialog::MessageDialog messageBox;
messageBox.setTitle("Wrong password");
messageBox.setMessage(
"The file is password protected and the provided password is wrong.\n\nRetry with a different password ?"
);
messageBox.setIcon(ui::base::dialog::IMessageDialog::QUESTION);
messageBox.addButton(ui::base::dialog::IMessageDialog::RETRY);
messageBox.addButton(ui::base::dialog::IMessageDialog::CANCEL);
if(messageBox.show() == sight::ui::base::dialog::IMessageDialog::RETRY)
{
m_pimpl->m_passwordRetry++;
updating();
}
else
{
m_pimpl->m_passwordRetry = 0;
}
}
catch(std::exception& _e)
{
// Handle the error.
......
......@@ -74,10 +74,10 @@ public:
std::string m_extensionDescription {"Sight session"};
/// Password policy to use
PasswordKeeper::PasswordPolicy m_PasswordPolicy {PasswordKeeper::PasswordPolicy::DEFAULT};
PasswordKeeper::PasswordPolicy m_passwordPolicy {PasswordKeeper::PasswordPolicy::DEFAULT};
/// Encryption policy to use
PasswordKeeper::EncryptionPolicy m_EncryptionPolicy {PasswordKeeper::EncryptionPolicy::DEFAULT};
PasswordKeeper::EncryptionPolicy m_encryptionPolicy {PasswordKeeper::EncryptionPolicy::DEFAULT};
/// Signal emitted when job created.
JobCreatedSignal::sptr m_jobCreatedSignal;
......@@ -124,20 +124,20 @@ void SWriter::configuring()
if(password.is_initialized())
{
// Password policy
m_pimpl->m_PasswordPolicy = PasswordKeeper::stringToPasswordPolicy(password->get<std::string>("policy"));
m_pimpl->m_passwordPolicy = PasswordKeeper::stringToPasswordPolicy(password->get<std::string>("policy"));
SIGHT_THROW_IF(
"Cannot read password policy.",
m_pimpl->m_PasswordPolicy == PasswordKeeper::PasswordPolicy::INVALID
m_pimpl->m_passwordPolicy == PasswordKeeper::PasswordPolicy::INVALID
);
// Encryption policy
m_pimpl->m_EncryptionPolicy = PasswordKeeper::stringToEncryptionPolicy(
m_pimpl->m_encryptionPolicy = PasswordKeeper::stringToEncryptionPolicy(
password->get<std::string>("encryption")
);
SIGHT_THROW_IF(
"Cannot read encryption policy.",
m_pimpl->m_EncryptionPolicy == PasswordKeeper::EncryptionPolicy::INVALID
m_pimpl->m_encryptionPolicy == PasswordKeeper::EncryptionPolicy::INVALID
);
}
}
......@@ -177,7 +177,7 @@ void SWriter::updating()
const secure_string& password =
[&]
{
if(m_pimpl->m_PasswordPolicy == PasswordKeeper::PasswordPolicy::NEVER)
if(m_pimpl->m_passwordPolicy == PasswordKeeper::PasswordPolicy::NEVER)
{
// No password management
return secure_string();
......@@ -186,8 +186,8 @@ void SWriter::updating()
{
const secure_string& globalPassword = PasswordKeeper::getGlobalPassword();
if((m_pimpl->m_PasswordPolicy == PasswordKeeper::PasswordPolicy::ALWAYS)
|| (m_pimpl->m_PasswordPolicy == PasswordKeeper::PasswordPolicy::ONCE
if((m_pimpl->m_passwordPolicy == PasswordKeeper::PasswordPolicy::ALWAYS)
|| (m_pimpl->m_passwordPolicy == PasswordKeeper::PasswordPolicy::ONCE
&& globalPassword.empty()))
{
sight::ui::base::dialog::InputDialog inputDialog;
......@@ -200,7 +200,7 @@ void SWriter::updating()
)
);
if(m_pimpl->m_PasswordPolicy == PasswordKeeper::PasswordPolicy::ONCE)
if(m_pimpl->m_passwordPolicy == PasswordKeeper::PasswordPolicy::ONCE)
{
PasswordKeeper::setGlobalPassword(newPassword);
}
......@@ -226,7 +226,7 @@ void SWriter::updating()
writer->setObject(data.get_shared());
writer->setFile(temporaryFile.getTemporaryFilePath());
writer->setPassword(password);
writer->setEncryptionPolicy(m_pimpl->m_EncryptionPolicy);
writer->setEncryptionPolicy(m_pimpl->m_encryptionPolicy);
}
// Set cursor to busy state. It will be reset to default even if exception occurs
......@@ -247,7 +247,7 @@ void SWriter::updating()
runningJob.doneWork(80);
// Robust rename
core::tools::System::robustRename(temporaryFile.getTemporaryFilePath(), filepath);
core::tools::System::robustRename(temporaryFile.getTemporaryFilePath(), filepath, true);
runningJob.done();
},
......
Supports Markdown
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