fix(@desktop/profile): Split account and profile settings

Avoid to reveal which alias own which settings. The only settings
pre-login available is the storeToKeychain

Ideally we should also encrypt the profile settings
This commit is contained in:
Anthony Laibe 2021-09-22 10:10:54 +02:00 committed by Iuri Matias
parent a44822d7f6
commit 22e8c8a7ff
10 changed files with 90 additions and 27 deletions

View File

@ -63,6 +63,8 @@ QtObject:
identityImage: currNodeAcct.identityImage identityImage: currNodeAcct.identityImage
)) ))
self.status.events.emit("accountChanged", AccountArgs(account: currNodeAcct))
QtProperty[QVariant] currentAccount: QtProperty[QVariant] currentAccount:
read = getCurrentAccount read = getCurrentAccount
write = setCurrentAccount write = setCurrentAccount
@ -172,7 +174,7 @@ QtObject:
self.keychainManager.storeDataAsync(username, password) self.keychainManager.storeDataAsync(username, password)
proc tryToObtainPassword*(self: LoginView) {.slot.} = proc tryToObtainPassword*(self: LoginView) {.slot.} =
let value = self.appService.localSettingsService.getValue( let value = self.appService.localSettingsService.getAccountValue(
LS_KEY_STORE_TO_KEYCHAIN).stringVal LS_KEY_STORE_TO_KEYCHAIN).stringVal
if (value == LS_VALUE_STORE): if (value == LS_VALUE_STORE):
self.keychainManager.readDataAsync(self.currentAccount.username) self.keychainManager.readDataAsync(self.currentAccount.username)
@ -189,7 +191,7 @@ QtObject:
return return
# We are notifying user only about keychain errors. # We are notifying user only about keychain errors.
self.appService.localSettingsService.removeValue(LS_KEY_STORE_TO_KEYCHAIN) self.appService.localSettingsService.removeAccountValue(LS_KEY_STORE_TO_KEYCHAIN)
self.obtainingPasswordError(errorDescription) self.obtainingPasswordError(errorDescription)
proc onKeychainManagerSuccess*(self: LoginView, data: string) {.slot.} = proc onKeychainManagerSuccess*(self: LoginView, data: string) {.slot.} =

View File

@ -4,6 +4,8 @@ import status/[status, wallet]
import status/types/[rpc_response] import status/types/[rpc_response]
import status/types/account as status_account_type import status/types/account as status_account_type
import views/account_info import views/account_info
import ../../app_service/[main]
type type
AccountRoles {.pure.} = enum AccountRoles {.pure.} = enum
@ -101,6 +103,8 @@ QtObject:
proc storeDerivedAndLogin(self: OnboardingView, password: string): string {.slot.} = proc storeDerivedAndLogin(self: OnboardingView, password: string): string {.slot.} =
let genAcc = self.currentAccount.account let genAcc = self.currentAccount.account
let acc = Account(name: genAcc.name, keyUid: genAcc.keyUid, identicon: genAcc.identicon, identityImage: genAcc.identityImage)
self.status.events.emit("accountChanged", status_account_type.AccountArgs(account: acc))
try: try:
result = self.status.accounts.storeDerivedAndLogin(self.status.fleet.config, genAcc, password).toJson result = self.status.accounts.storeDerivedAndLogin(self.status.fleet.config, genAcc, password).toJson

View File

@ -209,6 +209,19 @@ QtObject:
read = getSettingsFile read = getSettingsFile
notify = settingsFileChanged notify = settingsFileChanged
proc accountSettingsFileChanged*(self: ProfileView) {.signal.}
proc setAccountSettingsFile*(self: ProfileView, alias: string) =
self.appService.localSettingsService.updateAccountSettingsFilePath(alias)
self.accountSettingsFileChanged()
proc getAccountSettingsFile*(self: ProfileView): string {.slot.} =
self.appService.localSettingsService.getAccountSettingsFilePath
QtProperty[string] accountSettingsFile:
read = getAccountSettingsFile
notify = accountSettingsFileChanged
proc setSendUserStatus*(self: ProfileView, sendUserStatus: bool) {.slot.} = proc setSendUserStatus*(self: ProfileView, sendUserStatus: bool) {.slot.} =
if (sendUserStatus == self.profile.sendUserStatus): if (sendUserStatus == self.profile.sendUserStatus):
return return

View File

@ -1,12 +1,13 @@
import NimQml, os, chronicles import NimQml, os, chronicles
import ../../../constants import ../../../constants
# Local Settings keys: # Local Account Settings keys:
const LS_KEY_STORE_TO_KEYCHAIN* = "storeToKeychain" const LS_KEY_STORE_TO_KEYCHAIN* = "storeToKeychain"
# Local Settings values: # Local Account Settings values:
const LS_VALUE_STORE* = "store" const LS_VALUE_STORE* = "store"
const UNKNOWN_ACCOUNT = "unknownAccount" const UNKNOWN_ACCOUNT = "unknownAccount"
const UNKNOWN_PROFILE = "unknownProfile"
logScope: logScope:
topics = "local-settings" topics = "local-settings"
@ -15,12 +16,16 @@ QtObject:
type LocalSettingsService* = ref object of QObject type LocalSettingsService* = ref object of QObject
settingsFilePath: string settingsFilePath: string
settings: QSettings settings: QSettings
accountSettingsFilePath: string
accountSettings: QSettings
globalSettingsFilePath: string globalSettingsFilePath: string
globalSettings: QSettings globalSettings: QSettings
proc setup(self: LocalSettingsService) = proc setup(self: LocalSettingsService) =
self.settingsFilePath = os.joinPath(DATADIR, "qt", UNKNOWN_ACCOUNT) self.settingsFilePath = os.joinPath(DATADIR, "qt", UNKNOWN_PROFILE)
self.settings = newQSettings(self.settingsFilePath, QSettingsFormat.IniFormat) self.settings = newQSettings(self.settingsFilePath, QSettingsFormat.IniFormat)
self.accountSettingsFilePath = os.joinPath(DATADIR, "qt", UNKNOWN_ACCOUNT)
self.accountSettings = newQSettings(self.accountSettingsFilePath, QSettingsFormat.IniFormat)
self.globalSettingsFilePath = os.joinPath(DATADIR, "qt", "global") self.globalSettingsFilePath = os.joinPath(DATADIR, "qt", "global")
self.globalSettings = newQSettings(self.globalSettingsFilePath, QSettingsFormat.IniFormat) self.globalSettings = newQSettings(self.globalSettingsFilePath, QSettingsFormat.IniFormat)
self.QObject.setup self.QObject.setup
@ -37,11 +42,14 @@ QtObject:
proc getGlobalSettingsFilePath*(self: LocalSettingsService): string = proc getGlobalSettingsFilePath*(self: LocalSettingsService): string =
return self.globalSettingsFilePath return self.globalSettingsFilePath
proc getAccountSettingsFilePath*(self: LocalSettingsService): string =
return self.accountSettingsFilePath
proc getSettingsFilePath*(self: LocalSettingsService): string = proc getSettingsFilePath*(self: LocalSettingsService): string =
return self.settingsFilePath return self.settingsFilePath
proc updateSettingsFilePath*(self: LocalSettingsService, pubKey: string) = proc updateSettingsFilePath*(self: LocalSettingsService, pubKey: string) =
let unknownSettingsPath = os.joinPath(DATADIR, "qt", UNKNOWN_ACCOUNT) let unknownSettingsPath = os.joinPath(DATADIR, "qt", UNKNOWN_PROFILE)
if (not unknownSettingsPath.tryRemoveFile): if (not unknownSettingsPath.tryRemoveFile):
# Only fails if the file exists and an there was an error removing it # Only fails if the file exists and an there was an error removing it
# More info: https://nim-lang.org/docs/os.html#tryRemoveFile%2Cstring # More info: https://nim-lang.org/docs/os.html#tryRemoveFile%2Cstring
@ -51,6 +59,27 @@ QtObject:
self.settingsFilePath = os.joinPath(DATADIR, "qt", pubKey) self.settingsFilePath = os.joinPath(DATADIR, "qt", pubKey)
self.settings = newQSettings(self.settingsFilePath, QSettingsFormat.IniFormat) self.settings = newQSettings(self.settingsFilePath, QSettingsFormat.IniFormat)
proc updateAccountSettingsFilePath*(self: LocalSettingsService, alias: string) =
let unknownAccountSettingsPath = os.joinPath(DATADIR, "qt", UNKNOWN_ACCOUNT)
if (not unknownAccountSettingsPath.tryRemoveFile):
# Only fails if the file exists and an there was an error removing it
# More info: https://nim-lang.org/docs/os.html#tryRemoveFile%2Cstring
warn "Failed to remove unused settings file", file=unknownAccountSettingsPath
self.accountSettings.delete
self.accountSettingsFilePath = os.joinPath(DATADIR, "qt", alias)
self.accountSettings = newQSettings(self.accountSettingsFilePath, QSettingsFormat.IniFormat)
proc setAccountValue*(self: LocalSettingsService, key: string, value: QVariant) =
self.accountSettings.setValue(key, value)
proc getAccountValue*(self: LocalSettingsService, key: string,
defaultValue: QVariant = newQVariant()): QVariant =
self.accountSettings.value(key, defaultValue)
proc removeAccountValue*(self: LocalSettingsService, key: string) =
self.accountSettings.remove(key)
proc setValue*(self: LocalSettingsService, key: string, value: QVariant) = proc setValue*(self: LocalSettingsService, key: string, value: QVariant) =
self.settings.setValue(key, value) self.settings.setValue(key, value)

View File

@ -7,6 +7,7 @@ import app/node/core as node
import app/utilsView/core as utilsView import app/utilsView/core as utilsView
import app/browser/core as browserView import app/browser/core as browserView
import app/profile/core as profile import app/profile/core as profile
import app/profile/view
import app/onboarding/core as onboarding import app/onboarding/core as onboarding
import app/login/core as login import app/login/core as login
import app/provider/core as provider import app/provider/core as provider
@ -192,6 +193,13 @@ proc mainProc() =
var onboarding = onboarding.newController(status) var onboarding = onboarding.newController(status)
defer: onboarding.delete() defer: onboarding.delete()
proc onAccountChanged(account: Account) =
profile.view.setAccountSettingsFile(account.name)
status.events.on("accountChanged") do(a: Args):
var args = AccountArgs(a)
onAccountChanged(args.account)
status.events.once("login") do(a: Args): status.events.once("login") do(a: Args):
var args = AccountArgs(a) var args = AccountArgs(a)
appService.onLoggedIn() appService.onLoggedIn()
@ -206,7 +214,8 @@ proc mainProc() =
status.events.once("loginCompleted") do(a: Args): status.events.once("loginCompleted") do(a: Args):
var args = AccountArgs(a) var args = AccountArgs(a)
onAccountChanged(args.account)
status.startMessenger() status.startMessenger()
profile.init(args.account) profile.init(args.account)
wallet.init() wallet.init()

View File

@ -51,7 +51,7 @@ Item {
text: qsTr("Store pass to Keychain") text: qsTr("Store pass to Keychain")
visible: Qt.platform.os == "osx" // For now, this is available only on MacOS visible: Qt.platform.os == "osx" // For now, this is available only on MacOS
currentValue: { currentValue: {
let value = appSettings.storeToKeychain let value = accountSettings.storeToKeychain
if(value == Constants.storeToKeychainValueStore) if(value == Constants.storeToKeychainValueStore)
return qsTr("Store") return qsTr("Store")

View File

@ -31,18 +31,18 @@ ModalPopup {
StatusRadioButtonRow { StatusRadioButtonRow {
text: qsTr("Store") text: qsTr("Store")
buttonGroup: openLinksWithGroup buttonGroup: openLinksWithGroup
checked: appSettings.storeToKeychain === Constants.storeToKeychainValueStore checked: accountSettings.storeToKeychain === Constants.storeToKeychainValueStore
onRadioCheckedChanged: { onRadioCheckedChanged: {
if (checked && appSettings.storeToKeychain !== Constants.storeToKeychainValueStore) { if (checked && accountSettings.storeToKeychain !== Constants.storeToKeychainValueStore) {
var storePassPopup = openPopup(storePasswordModal) var storePassPopup = openPopup(storePasswordModal)
if(storePassPopup) if(storePassPopup)
{ {
storePassPopup.closed.connect(function(){ storePassPopup.closed.connect(function(){
if (appSettings.storeToKeychain === Constants.storeToKeychainValueStore) if (accountSettings.storeToKeychain === Constants.storeToKeychainValueStore)
popup.close() popup.close()
else if (appSettings.storeToKeychain === Constants.storeToKeychainValueNotNow) else if (accountSettings.storeToKeychain === Constants.storeToKeychainValueNotNow)
notNowBtn.checked = true notNowBtn.checked = true
else if (appSettings.storeToKeychain === Constants.storeToKeychainValueNever) else if (accountSettings.storeToKeychain === Constants.storeToKeychainValueNever)
neverBtn.checked = true neverBtn.checked = true
}) })
} }
@ -54,11 +54,11 @@ ModalPopup {
id: notNowBtn id: notNowBtn
text: qsTr("Not now") text: qsTr("Not now")
buttonGroup: openLinksWithGroup buttonGroup: openLinksWithGroup
checked: appSettings.storeToKeychain === Constants.storeToKeychainValueNotNow || checked: accountSettings.storeToKeychain === Constants.storeToKeychainValueNotNow ||
appSettings.storeToKeychain === "" accountSettings.storeToKeychain === ""
onRadioCheckedChanged: { onRadioCheckedChanged: {
if (checked) { if (checked) {
appSettings.storeToKeychain = Constants.storeToKeychainValueNotNow accountSettings.storeToKeychain = Constants.storeToKeychainValueNotNow
} }
} }
} }
@ -67,10 +67,10 @@ ModalPopup {
id: neverBtn id: neverBtn
text: qsTr("Never") text: qsTr("Never")
buttonGroup: openLinksWithGroup buttonGroup: openLinksWithGroup
checked: appSettings.storeToKeychain === Constants.storeToKeychainValueNever checked: accountSettings.storeToKeychain === Constants.storeToKeychainValueNever
onRadioCheckedChanged: { onRadioCheckedChanged: {
if (checked) { if (checked) {
appSettings.storeToKeychain = Constants.storeToKeychainValueNever accountSettings.storeToKeychain = Constants.storeToKeychainValueNever
} }
} }
} }

View File

@ -38,10 +38,16 @@ StatusWindow {
} }
} }
Settings {
id: accountSettings
fileName: profileModel.accountSettingsFile
property string storeToKeychain: ""
}
Settings { Settings {
id: appSettings id: appSettings
fileName: profileModel.settingsFile fileName: profileModel.settingsFile
property string storeToKeychain: ""
property var chatSplitView property var chatSplitView
property var walletSplitView property var walletSplitView
@ -277,11 +283,11 @@ StatusWindow {
{ {
if(clearStoredValue) if(clearStoredValue)
{ {
appSettings.storeToKeychain = "" accountSettings.storeToKeychain = ""
} }
if(appSettings.storeToKeychain === "" || if(accountSettings.storeToKeychain === "" ||
appSettings.storeToKeychain === Constants.storeToKeychainValueNotNow) accountSettings.storeToKeychain === Constants.storeToKeychainValueNotNow)
{ {
storeToKeychainConfirmationPopup.password = password storeToKeychainConfirmationPopup.password = password
storeToKeychainConfirmationPopup.username = username storeToKeychainConfirmationPopup.username = username
@ -310,18 +316,18 @@ StatusWindow {
} }
onConfirmButtonClicked: { onConfirmButtonClicked: {
appSettings.storeToKeychain = Constants.storeToKeychainValueStore accountSettings.storeToKeychain = Constants.storeToKeychainValueStore
loginModel.storePassword(username, password) loginModel.storePassword(username, password)
finish() finish()
} }
onRejectButtonClicked: { onRejectButtonClicked: {
appSettings.storeToKeychain = Constants.storeToKeychainValueNotNow accountSettings.storeToKeychain = Constants.storeToKeychainValueNotNow
finish() finish()
} }
onCancelButtonClicked: { onCancelButtonClicked: {
appSettings.storeToKeychain = Constants.storeToKeychainValueNever accountSettings.storeToKeychain = Constants.storeToKeychainValueNever
finish() finish()
} }
} }

View File

@ -158,7 +158,7 @@ ModalPopup {
onClicked: { onClicked: {
if (storingPasswordModal) if (storingPasswordModal)
{ {
appSettings.storeToKeychain = Constants.storeToKeychainValueStore accountSettings.storeToKeychain = Constants.storeToKeychainValueStore
loginModel.storePassword(profileModel.profile.username, repeatPasswordField.text) loginModel.storePassword(profileModel.profile.username, repeatPasswordField.text)
popup.close() popup.close()
} }

View File

@ -34,7 +34,7 @@ Item {
} }
function resetLogin() { function resetLogin() {
if(appSettings.storeToKeychain === Constants.storeToKeychainValueStore) if(accountSettings.storeToKeychain === Constants.storeToKeychainValueStore)
{ {
connection.enabled = true connection.enabled = true
txtPassword.visible = false txtPassword.visible = false