keychain feature refactored

This commit is contained in:
Sale Djenic 2021-10-17 12:44:21 +02:00 committed by Iuri Matias
parent 44ba3f43f7
commit 48a39e4569
22 changed files with 167 additions and 128 deletions

View File

@ -116,7 +116,7 @@ proc newAppController*(appService: AppService): AppController =
result.communityService = community_service.newService(result.chatService)
# Core
result.localAccountSettings = newLocalAccountSettings(result.localSettingsService)
result.localAccountSettingsVariant = newQVariant(result.localSettingsService)
result.localAccountSettingsVariant = newQVariant(result.localAccountSettings)
# Modules
result.startupModule = startup_module.newModule[AppController](result,
appService.status.events, appService.status.fleet, result.localSettingsService,

View File

@ -41,7 +41,22 @@ method delete*(self: Controller) =
discard
method init*(self: Controller) =
discard
echo "INIT MAIN CONTROLLER"
if(defined(macosx)):
let account = self.accountsService.getLoggedInAccount()
self.localSettingsService.updateAccountSettingsFilePath(account.name)
self.events.on("keychainServiceSuccess") do(e:Args):
let args = KeyChainServiceArg(e)
echo "Received keychainServiceSuccess ", repr(args)
self.delegate.emitStoringPasswordSuccess()
self.events.on("keychainServiceError") do(e:Args):
let args = KeyChainServiceArg(e)
echo "Received keychainServiceError ", repr(args)
self.localSettingsService.setAccountValue(LS_KEY_STORE_TO_KEYCHAIN,
newQVariant(LS_VALUE_NOTNOW))
self.delegate.emitStoringPasswordError(args.errDescription)
method getCommunities*(self: Controller): seq[community_service.CommunityDto] =
return self.communityService.getCommunities()
@ -54,8 +69,6 @@ method checkForStoringPassword*(self: Controller) =
if(not defined(macosx)):
return
let account = self.accountsService.getLoggedInAccount()
self.localSettingsService.updateAccountSettingsFilePath(account.name)
let value = self.localSettingsService.getAccountValue(
LS_KEY_STORE_TO_KEYCHAIN).stringVal
@ -68,9 +81,4 @@ method checkForStoringPassword*(self: Controller) =
method storePassword*(self: Controller, password: string) =
let account = self.accountsService.getLoggedInAccount()
self.keychainService.storePassword(account.name, password)
method updateUserPreferenceForStoreToKeychain*(self: Controller,
selection: string) =
self.localSettingsService.setAccountValue(LS_KEY_STORE_TO_KEYCHAIN,
newQVariant(selection))
self.keychainService.storePassword(account.name, password)

View File

@ -18,8 +18,4 @@ method checkForStoringPassword*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method storePassword*(self: AccessInterface, password: string) {.base.} =
raise newException(ValueError, "No implementation available")
method updateUserPreferenceForStoreToKeychain*(self: AccessInterface,
selection: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -114,6 +114,10 @@ method offerToStorePassword*[T](self: Module[T]) =
method storePassword*[T](self: Module[T], password: string) =
self.controller.storePassword(password)
method updateUserPreferenceForStoreToKeychain*[T](self: Module[T],
selection: string) =
self.controller.updateUserPreferenceForStoreToKeychain(selection)
method emitStoringPasswordError*[T](self: Module[T], errorDescription: string) =
echo "Notify VIEW about error: ", errorDescription
self.view.emitStoringPasswordError(errorDescription)
method emitStoringPasswordSuccess*[T](self: Module[T]) =
echo "Notify VIEW about success: "
self.view.emitStoringPasswordSuccess()

View File

@ -1,2 +1,9 @@
method offerToStorePassword*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
raise newException(ValueError, "No implementation available")
method emitStoringPasswordError*(self: AccessInterface, errorDescription: string)
{.base.} =
raise newException(ValueError, "No implementation available")
method emitStoringPasswordSuccess*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -2,8 +2,4 @@ method viewDidLoad*(self: AccessInterface) {.base.} =
raise newException(ValueError, "No implementation available")
method storePassword*(self: AccessInterface, password: string) {.base.} =
raise newException(ValueError, "No implementation available")
method updateUserPreferenceForStoreToKeychain*(self: AccessInterface,
selection: string) {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -42,11 +42,15 @@ QtObject:
proc offerToStorePassword*(self: View) =
self.openStoreToKeychainPopup()
proc storePassword(self: View, password: string) {.slot.} =
proc storePassword*(self: View, password: string) {.slot.} =
self.delegate.storePassword(password)
proc storingPasswordError*(self:View, errorDescription: string) {.signal.}
proc updateUserPreferenceForStoreToKeychain(self: View, selection: string)
{.slot.} =
self.delegate.updateUserPreferenceForStoreToKeychain(selection)
proc emitStoringPasswordError*(self: View, errorDescription: string) =
self.storingPasswordError(errorDescription)
proc storingPasswordSuccess*(self:View) {.signal.}
proc emitStoringPasswordSuccess*(self: View) =
self.storingPasswordSuccess()

View File

@ -47,12 +47,12 @@ method init*(self: Controller) =
self.events.on(SignalType.NodeStopped.event) do(e:Args):
echo "-NEW-EVENT-- NodeStopped: ", repr(e)
#self.status.events.emit("nodeStopped", Args())
self.events.emit("nodeStopped", Args())
#self.view.onLoggedOut()
self.events.on(SignalType.NodeReady.event) do(e:Args):
echo "-NEW-EVENT-- NodeReady: ", repr(e)
#self.status.events.emit("nodeReady", Args())
self.events.emit("nodeReady", Args())
method shouldStartWithOnboardingScreen*(self: Controller): bool =
return self.accountsService.openedAccounts().len == 0

View File

@ -41,7 +41,23 @@ method init*(self: Controller) =
self.events.on(SignalType.NodeLogin.event) do(e:Args):
let signal = NodeSignal(e)
if signal.event.error != "":
self.delegate.loginAccountError(signal.event.error)
echo "(LOGIN) ERRORRRRR ", repr(signal.event.error)
self.delegate.emitAccountLoginError(signal.event.error)
self.events.on("keychainServiceSuccess") do(e:Args):
let args = KeyChainServiceArg(e)
echo "(LOGIN) Received keychainServiceSuccess ", repr(args)
self.delegate.emitObtainingPasswordSuccess(args.data)
self.events.on("keychainServiceError") do(e:Args):
let args = KeyChainServiceArg(e)
echo "(LOGIN) Received keychainServiceError ", repr(args)
# We are notifying user only about keychain errors.
if (args.errType == ERROR_TYPE_AUTHENTICATION):
return
self.localSettingsService.removeAccountValue(LS_KEY_STORE_TO_KEYCHAIN)
self.delegate.emitObtainingPasswordError(args.errDescription)
method getOpenedAccounts*(self: Controller): seq[AccountDto] =
return self.accountsService.openedAccounts()
@ -55,9 +71,13 @@ proc getSelectedAccount(self: Controller): AccountDto =
method setSelectedAccountKeyUid*(self: Controller, keyUid: string) =
self.selectedAccountKeyUid = keyUid
# Dealing with Keychain is the MacOS only feature
if(not defined(macosx)):
return
let selectedAccount = self.getSelectedAccount()
self.localSettingsService.updateAccountSettingsFilePath(selectedAccount.name)
self.delegate.emitStoreToKeychainValueChanged()
self.keychainService.tryToObtainPassword(selectedAccount.name)
method login*(self: Controller, password: string) =
@ -65,8 +85,4 @@ method login*(self: Controller, password: string) =
let error = self.accountsService.login(selectedAccount, password)
if(error.len > 0):
self.delegate.loginAccountError(error)
method getStoreToKeychainValue*(self: Controller): string =
return self.localSettingsService.getAccountValue(
LS_KEY_STORE_TO_KEYCHAIN).stringVal
self.delegate.emitAccountLoginError(error)

View File

@ -17,7 +17,4 @@ method setSelectedAccountKeyUid*(self: AccessInterface, keyUid: string) {.base.}
raise newException(ValueError, "No implementation available")
method login*(self: AccessInterface, password: string) {.base.} =
raise newException(ValueError, "No implementation available")
method getStoreToKeychainValue*(self: AccessInterface): string {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -83,11 +83,13 @@ method setSelectedAccount*(self: Module, item: Item) =
method login*(self: Module, password: string) =
self.controller.login(password)
method loginAccountError*(self: Module, error: string) =
self.view.loginAccountError(error)
method emitAccountLoginError*(self: Module, error: string) =
self.view.emitAccountLoginError(error)
method emitStoreToKeychainValueChanged*(self: Module) =
self.view.emitStoreToKeychainValueChanged()
method emitObtainingPasswordError*(self: Module, errorDescription: string) =
echo "Notify VIEW about error: ", errorDescription
self.view.emitObtainingPasswordError(errorDescription)
method getStoreToKeychainValue*(self: Module): string =
return self.controller.getStoreToKeychainValue()
method emitObtainingPasswordSuccess*(self: Module, password: string) =
echo "Notify VIEW about success: ", password
self.view.emitObtainingPasswordSuccess(password)

View File

@ -1,5 +1,10 @@
method loginAccountError*(self: AccessInterface, error: string) {.base.} =
method emitAccountLoginError*(self: AccessInterface, error: string) {.base.} =
raise newException(ValueError, "No implementation available")
method emitStoreToKeychainValueChanged*(self: AccessInterface) {.base.} =
method emitObtainingPasswordError*(self: AccessInterface, errorDescription: string)
{.base.} =
raise newException(ValueError, "No implementation available")
method emitObtainingPasswordSuccess*(self: AccessInterface, password: string)
{.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -7,7 +7,4 @@ method setSelectedAccount*(self: AccessInterface, item: Item) {.base.} =
raise newException(ValueError, "No implementation available")
method login*(self: AccessInterface, password: string) {.base.} =
raise newException(ValueError, "No implementation available")
method getStoreToKeychainValue*(self: AccessInterface): string {.base.} =
raise newException(ValueError, "No implementation available")

View File

@ -65,17 +65,15 @@ QtObject:
proc accountLoginError*(self: View, error: string) {.signal.}
proc loginAccountError*(self: View, error: string) =
proc emitAccountLoginError*(self: View, error: string) =
self.accountLoginError(error)
proc storeToKeychainValueChanged*(self: View) {.signal.}
proc obtainingPasswordError*(self:View, errorDescription: string) {.signal.}
proc emitStoreToKeychainValueChanged*(self: View) =
self.storeToKeychainValueChanged()
proc emitObtainingPasswordError*(self: View, errorDescription: string) =
self.obtainingPasswordError(errorDescription)
proc obtainingPasswordSuccess*(self:View, password: string) {.signal.}
proc getStoreToKeychainValue(self: View): string {.slot.} =
return self.delegate.getStoreToKeychainValue()
QtProperty[string] storeToKeychainValue:
read = getStoreToKeychainValue
notify = storeToKeychainValueChanged
proc emitObtainingPasswordSuccess*(self: View, password: string) =
self.obtainingPasswordSuccess(password)

View File

@ -7,15 +7,15 @@ import eventemitter
logScope:
topics = "keychain-service"
const ERROR_TYPE_AUTHENTICATION = "authentication"
const ERROR_TYPE_KEYCHAIN = "keychain"
const ERROR_TYPE_AUTHENTICATION* = "authentication"
const ERROR_TYPE_KEYCHAIN* = "keychain"
type
KeyChainServiceArg* = ref object of Args
data*: string
errCode: int
errType: string
errDescription: string
errCode*: int
errType*: string
errDescription*: string
QtObject:
type Service* = ref object of QObject
@ -67,17 +67,13 @@ QtObject:
## This slot is called in case an error occured while we're dealing with
## KeychainManager. So far we're just logging the error.
info "KeychainManager stopped: ", msg = errorCode, errorDescription
if (errorType == ERROR_TYPE_AUTHENTICATION):
return
# We are notifying user only about keychain errors.
self.localSettingsService.removeAccountValue(LS_KEY_STORE_TO_KEYCHAIN)
let arg = KeyChainServiceArg(errCode: errorCode, errType: errorType,
errDescription: errorDescription)
self.events.emit("obtainingPasswordError", arg)
self.events.emit("keychainServiceError", arg)
proc onKeychainManagerSuccess*(self: Service, data: string) {.slot.} =
## This slot is called in case a password is successfully retrieved from the
## Keychain. In this case @data contains required password.
echo "USER PASSWORD RECEIVED: ", data
self.events.emit("obtainingPasswordSuccess", KeyChainServiceArg(data: data))
self.events.emit("keychainServiceSuccess", KeyChainServiceArg(data: data))

View File

@ -22,7 +22,7 @@ ModalPopup {
id: accountList
anchors.fill: parent
model: LoginStore.loginModul.accountsModel
model: LoginStore.loginModuleInst.accountsModel
isSelected: function (index, keyUid) {
return LoginStore.currentAccount.keyUid === keyUid
}

View File

@ -159,21 +159,14 @@ ModalPopup {
onClicked: {
if (storingPasswordModal)
{
accountSettings.storeToKeychain = Constants.storeToKeychainValueStore
applicationWindow.prepareForStoring(repeatPasswordField.text)
applicationWindow.prepareForStoring(repeatPasswordField.text, true)
popup.close()
}
else
{
loading = true
const result = onboardingModule.storeSelectedAccountAndLogin(repeatPasswordField.text);
const error = JSON.parse(result).error
if (error) {
importError.text += error
return importError.open()
}
applicationWindow.prepareForStoring(repeatPasswordField.text)
onboardingModule.storeSelectedAccountAndLogin(repeatPasswordField.text);
applicationWindow.prepareForStoring(repeatPasswordField.text, false)
}
}
}

View File

@ -3,22 +3,18 @@ pragma Singleton
import QtQuick 2.13
QtObject {
property var loginModul: loginModule
property var currentAccount: loginModule.selectedAccount
property var loginModuleInst: loginModule
property var currentAccount: loginModuleInst.selectedAccount
function login(password) {
loginModul.login(password)
loginModuleInst.login(password)
}
// function tryToObtainPassword() {
// loginModel.tryToObtainPassword()
// }
function setCurrentAccount(index) {
loginModul.setSelectedAccountByIndex(index)
loginModuleInst.setSelectedAccountByIndex(index)
}
function rowCount() {
return loginModul.accountsModel.rowCount()
return loginModuleInst.accountsModel.rowCount()
}
}

View File

@ -31,16 +31,16 @@ Item {
loading = true
LoginStore.login(password)
applicationWindow.prepareForStoring(password)
applicationWindow.prepareForStoring(password, false)
txtPassword.textField.clear()
}
function resetLogin() {
if(accountSettings.storeToKeychain === Constants.storeToKeychainValueStore)
console.warn("----ResetLogin: ", localAccountSettings.storeToKeychainValue)
if(localAccountSettings.storeToKeychainValue === Constants.storeToKeychainValueStore)
{
connection.enabled = true
txtPassword.visible = false
// LoginStore.tryToObtainPassword()
}
else
{
@ -53,22 +53,23 @@ Item {
resetLogin()
}
// NEED TO HANDLE IT
// Connections{
// id: connection
// target: LoginStore.loginModelInst
Connections{
id: connection
target: LoginStore.loginModuleInst
// onObtainingPasswordError: {
// enabled = false
// obtainingPasswordErrorNotification.confirmationText = errorDescription
// obtainingPasswordErrorNotification.open()
// }
onObtainingPasswordError: {
console.warn("ERR QML: ", errorDescription)
enabled = false
obtainingPasswordErrorNotification.confirmationText = errorDescription
obtainingPasswordErrorNotification.open()
}
// onObtainingPasswordSuccess: {
// enabled = false
// doLogin(password)
// }
// }
onObtainingPasswordSuccess: {
console.warn("SUCC QML: ", password)
enabled = false
doLogin(password)
}
}
ConfirmationDialog {
id: obtainingPasswordErrorNotification
@ -227,7 +228,7 @@ Item {
}
Connections {
target: LoginStore.loginModul
target: LoginStore.loginModuleInst
onAccountLoginError: {
if (error) {
// SQLITE_NOTADB: "file is not a database"

View File

@ -16,6 +16,16 @@ ModalPopup {
destroy()
}
function updateListState() {
if (localAccountSettings.storeToKeychainValue === Constants.storeToKeychainValueStore)
storeBtn.checked = true
else if (localAccountSettings.storeToKeychainValue === Constants.storeToKeychainValueNotNow ||
localAccountSettings.storeToKeychainValue === "")
notNowBtn.checked = true
else if (localAccountSettings.storeToKeychainValue === Constants.storeToKeychainValueNever)
neverBtn.checked = true
}
Column {
anchors.top: parent.top
anchors.bottom: parent.bottom
@ -26,26 +36,36 @@ ModalPopup {
spacing: 0
Connections {
target: localAccountSettings
onStoreToKeychainValueChanged: {
updateListState()
}
}
Connections {
target: mainModule
onStoringPasswordError: {
updateListState()
}
}
ButtonGroup {
id: openLinksWithGroup
}
RadioButtonSelector {
id: storeBtn
title: qsTr("Store")
buttonGroup: openLinksWithGroup
checked: accountSettings.storeToKeychain === Constants.storeToKeychainValueStore
checked: localAccountSettings.storeToKeychainValue === Constants.storeToKeychainValueStore
onCheckedChanged: {
if (checked && accountSettings.storeToKeychain !== Constants.storeToKeychainValueStore) {
if (checked && localAccountSettings.storeToKeychainValue !== Constants.storeToKeychainValueStore) {
var storePassPopup = openPopup(storePasswordModal)
if(storePassPopup)
{
storePassPopup.closed.connect(function(){
if (accountSettings.storeToKeychain === Constants.storeToKeychainValueStore)
popup.close()
else if (accountSettings.storeToKeychain === Constants.storeToKeychainValueNotNow)
notNowBtn.checked = true
else if (accountSettings.storeToKeychain === Constants.storeToKeychainValueNever)
neverBtn.checked = true
updateListState()
})
}
}
@ -56,11 +76,11 @@ ModalPopup {
id: notNowBtn
title: qsTr("Not now")
buttonGroup: openLinksWithGroup
checked: accountSettings.storeToKeychain === Constants.storeToKeychainValueNotNow ||
accountSettings.storeToKeychain === ""
checked: localAccountSettings.storeToKeychainValue === Constants.storeToKeychainValueNotNow ||
localAccountSettings.storeToKeychainValue === ""
onCheckedChanged: {
if (checked) {
accountSettings.storeToKeychain = Constants.storeToKeychainValueNotNow
localAccountSettings.storeToKeychainValue = Constants.storeToKeychainValueNotNow
}
}
}
@ -69,10 +89,10 @@ ModalPopup {
id: neverBtn
title: qsTr("Never")
buttonGroup: openLinksWithGroup
checked: accountSettings.storeToKeychain === Constants.storeToKeychainValueNever
checked: localAccountSettings.storeToKeychainValue === Constants.storeToKeychainValueNever
onCheckedChanged: {
if (checked) {
accountSettings.storeToKeychain = Constants.storeToKeychainValueNever
localAccountSettings.storeToKeychainValue = Constants.storeToKeychainValueNever
}
}
}

View File

@ -88,7 +88,7 @@ Item {
implicitHeight: 52
visible: Qt.platform.os == "osx" // For now, this is available only on MacOS
label: {
let value = accountSettings.storeToKeychain
let value = localAccountSettings.storeToKeychainValue
if(value == Constants.storeToKeychainValueStore)
return qsTr("Store")

View File

@ -325,10 +325,13 @@ StatusWindow {
// }
// }
function prepareForStoring(password) {
function prepareForStoring(password, runStoreToKeychainPopup) {
if(Qt.platform.os == "osx")
{
storeToKeychainConfirmationPopup.password = password
if(runStoreToKeychainPopup)
storeToKeychainConfirmationPopup.open()
}
}
@ -350,18 +353,18 @@ StatusWindow {
}
onConfirmButtonClicked: {
console.warn("STOREEEEEE....pass: ", password)
localAccountSettings.storeToKeychainValue = Constants.storeToKeychainValueStore
mainModule.storePassword(password)
finish()
}
onRejectButtonClicked: {
mainModule.updateUserPreferenceForStoreToKeychain(Constants.storeToKeychainValueNotNow)
localAccountSettings.storeToKeychainValue = Constants.storeToKeychainValueNotNow
finish()
}
onCancelButtonClicked: {
mainModule.updateUserPreferenceForStoreToKeychain(Constants.storeToKeychainValueNever)
localAccountSettings.storeToKeychainValue = Constants.storeToKeychainValueNever
finish()
}
}