From 405c9eeef6b66acb80d1fef81e01634d96a4fca5 Mon Sep 17 00:00:00 2001 From: Lior Date: Fri, 17 Jan 2020 14:35:37 +0300 Subject: [PATCH 1/2] configs are written into storage --- src/main/scala/encry/Starter.scala | 28 ++++--- .../encry/api/http/SettingsStorage.scala | 76 +++++++++++++++++++ 2 files changed, 95 insertions(+), 9 deletions(-) create mode 100644 src/main/scala/encry/api/http/SettingsStorage.scala diff --git a/src/main/scala/encry/Starter.scala b/src/main/scala/encry/Starter.scala index a7b8249851..87b92fdb21 100644 --- a/src/main/scala/encry/Starter.scala +++ b/src/main/scala/encry/Starter.scala @@ -1,6 +1,8 @@ package encry +import java.io.File import java.net.InetSocketAddress +import java.nio.file.Files import akka.actor.{ Actor, ActorRef } import akka.http.scaladsl.Http import cats.Functor @@ -12,7 +14,7 @@ import cats.syntax.either._ import cats.syntax.option._ import cats.syntax.validated._ import encry.Starter.InitNodeResult -import encry.api.http.DataHolderForApi +import encry.api.http.{ DataHolderForApi, SettingsStorage } import encry.api.http.DataHolderForApi.PassForStorage import encry.cli.ConsoleListener import encry.cli.ConsoleListener.{ prompt, StartListening } @@ -65,7 +67,9 @@ class Starter(settings: EncryAppSettings, self ! res } - def startNonEmptyNode: Either[Throwable, InitNodeResult] = + def startNonEmptyNode: Either[Throwable, InitNodeResult] = { + val storage = SettingsStorage.init(settings) + val newSettings: EncryAppSettings = storage.getSettings.getOrElse(settings) for { walletPassword <- { println("Please, enter wallet password:") @@ -75,16 +79,17 @@ class Starter(settings: EncryAppSettings, InitNodeResult( "", walletPassword, - settings.node.offlineGeneration, + newSettings.node.offlineGeneration, fastSync = false, - settings.snapshotSettings.enableSnapshotCreation, - settings.network.knownPeers, - settings.network.connectOnlyWithKnownPeers.getOrElse(false), + newSettings.snapshotSettings.enableSnapshotCreation, + newSettings.network.knownPeers, + newSettings.network.connectOnlyWithKnownPeers.getOrElse(false), "", - settings.network.nodeName.getOrElse(""), - settings.network.declaredAddress, - settings.network.bindAddress + newSettings.network.nodeName.getOrElse(""), + newSettings.network.declaredAddress, + newSettings.network.bindAddress ) + } def startEmptyNode: Either[Throwable, InitNodeResult] = for { @@ -400,6 +405,11 @@ class Starter(settings: EncryAppSettings, network = networkSettings, snapshotSettings = snapshotSettings ) + if (!Files.exists(new File(s"${settings.directory}/state").toPath)) { + val storage: SettingsStorage = SettingsStorage.init(newSettings) + storage.putSettings(newSettings) + storage.close() + } val influxRef: Option[ActorRef] = newSettings.influxDB.map { influxSettings => context.system .actorOf(StatsSender.props(influxSettings, newSettings.network, newSettings.constants), "statsSender") diff --git a/src/main/scala/encry/api/http/SettingsStorage.scala b/src/main/scala/encry/api/http/SettingsStorage.scala new file mode 100644 index 0000000000..f8326d04b1 --- /dev/null +++ b/src/main/scala/encry/api/http/SettingsStorage.scala @@ -0,0 +1,76 @@ +package encry.api.http + +import java.io.{ ByteArrayInputStream, ByteArrayOutputStream, File, ObjectInputStream, ObjectOutputStream } +import cats.syntax.either._ +import com.typesafe.scalalogging.StrictLogging +import encry.settings.EncryAppSettings +import org.encryfoundation.common.utils.Algos +import org.iq80.leveldb.{ DB, Options } +import scorex.crypto.hash.Digest32 +import encry.storage.levelDb.versionalLevelDB.LevelDbFactory + +trait SettingsStorage extends StrictLogging with AutoCloseable { + + val storage: DB + + def getSettings: Option[EncryAppSettings] = SettingsStorage.deserialise(storage.get(SettingsStorage.SettingsKey)) + + def putSettings(settings: EncryAppSettings): Either[Throwable, Unit] = { + println(s"settings = ${settings.network.nodeName}") + val batch = storage.createWriteBatch() + val serialisedSettings: Array[Byte] = SettingsStorage.serialise(settings) + try { + batch.put(SettingsStorage.SettingsKey, serialisedSettings) + storage.write(batch).asRight[Throwable] + } catch { + case err: Throwable => err.asLeft[Unit] + } finally { + batch.close() + } + } + + override def close(): Unit = storage.close() + +} + +object SettingsStorage extends StrictLogging { + + val SettingsKey: Digest32 = Algos.hash(s"Settings_Key") + + def serialise(value: EncryAppSettings): Array[Byte] = { + val stream: ByteArrayOutputStream = new ByteArrayOutputStream() + val oos = new ObjectOutputStream(stream) + try { + oos.writeObject(value) + stream.toByteArray + } catch { + case err: Throwable => throw new Exception(s"Error during serialisation cause of $err") + } finally { + oos.close() + } + } + + def deserialise(bytes: Array[Byte]): Option[EncryAppSettings] = { + val ois = new ObjectInputStream(new ByteArrayInputStream(bytes)) + try { + val value = ois.readObject + val deserialised: Option[EncryAppSettings] = value match { + case set: EncryAppSettings => + logger.info(s"Deserialisation ended successfully") + Some(set) + } + deserialised + } catch { + case err: Throwable => throw new Exception(s"Error during serialisation cause of $err") + } finally { + ois.close() + } + } + + def getDirStorage(settings: EncryAppSettings): File = new File(s"${settings.directory}/userSettings") + + def init(settings: EncryAppSettings): SettingsStorage = new SettingsStorage { + override val storage: DB = LevelDbFactory.factory.open(getDirStorage(settings), new Options) + } + +} From 2bd70eebd75432fb22349621075403c9e51873c3 Mon Sep 17 00:00:00 2001 From: Lior Date: Fri, 24 Jan 2020 17:11:24 +0300 Subject: [PATCH 2/2] added wallet password verification --- src/main/scala/encry/Starter.scala | 27 ++++++++--- .../scala/encry/api/http/AccStorage.scala | 6 ++- .../encry/api/http/SettingsStorage.scala | 45 ++++++++++--------- 3 files changed, 50 insertions(+), 28 deletions(-) diff --git a/src/main/scala/encry/Starter.scala b/src/main/scala/encry/Starter.scala index 87b92fdb21..61792c9f15 100644 --- a/src/main/scala/encry/Starter.scala +++ b/src/main/scala/encry/Starter.scala @@ -14,8 +14,8 @@ import cats.syntax.either._ import cats.syntax.option._ import cats.syntax.validated._ import encry.Starter.InitNodeResult -import encry.api.http.{ DataHolderForApi, SettingsStorage } import encry.api.http.DataHolderForApi.PassForStorage +import encry.api.http.{ AccStorage, DataHolderForApi, SettingsStorage } import encry.cli.ConsoleListener import encry.cli.ConsoleListener.{ prompt, StartListening } import encry.local.miner.Miner @@ -70,6 +70,7 @@ class Starter(settings: EncryAppSettings, def startNonEmptyNode: Either[Throwable, InitNodeResult] = { val storage = SettingsStorage.init(settings) val newSettings: EncryAppSettings = storage.getSettings.getOrElse(settings) + storage.close() for { walletPassword <- { println("Please, enter wallet password:") @@ -146,8 +147,21 @@ class Starter(settings: EncryAppSettings, .fold(handleError, handleResult) } - def validatePassword(password: String): Validated[NonEmptyChain[String], String] = - if (password.nonEmpty) password.validNec else "Password is empty".invalidNec + def validatePassword(password: String): Validated[NonEmptyChain[String], String] = { + val passExists = Files.exists(new File(s"${settings.directory}/userKeys").toPath) + if (password.nonEmpty && !passExists) password.validNec + else if (password.nonEmpty && passExists) { + val storage = AccStorage.init(settings) + if (storage.verifyPassword(password)) { + storage.close() + password.validNec + } else { + storage.close() + "Incorrect password, please try again.".invalidNec + } + } + else "You can't use empty password, please think of another one.".invalidNec + } def validateNodeName(nodeName: String): Validated[NonEmptyChain[String], String] = if (nodeName.nonEmpty) nodeName.validNec else "Node name is empty".invalidNec @@ -385,9 +399,11 @@ class Starter(settings: EncryAppSettings, bindAddr) => import scala.concurrent.duration._ Functor[Option].compose[Future].map(initHttpApiServer)(_.terminate(3.seconds)) + val storage = AccStorage.init(settings) + storage.setPassword(password) + storage.close() if (mnemonic.nonEmpty) AccountManager.init(mnemonic, password, settings) - val walletSettings: Option[WalletSettings] = settings.wallet.map(_.copy(password = password)) - val nodeSettings: NodeSettings = settings.node.copy(offlineGeneration = offlineGeneration) + val nodeSettings: NodeSettings = settings.node.copy(offlineGeneration = offlineGeneration) val networkSettings: NetworkSettings = settings.network.copy(knownPeers = peers, connectOnlyWithKnownPeers = connectWithOnlyKnownPeers.some, @@ -400,7 +416,6 @@ class Starter(settings: EncryAppSettings, enableSnapshotCreation = snapshotCreation ) val newSettings = settings.copy( - wallet = walletSettings, node = nodeSettings, network = networkSettings, snapshotSettings = snapshotSettings diff --git a/src/main/scala/encry/api/http/AccStorage.scala b/src/main/scala/encry/api/http/AccStorage.scala index 92c138194c..eda6a852e4 100644 --- a/src/main/scala/encry/api/http/AccStorage.scala +++ b/src/main/scala/encry/api/http/AccStorage.scala @@ -51,7 +51,11 @@ object AccStorage extends StrictLogging { val PasswordHashKey: StorageKey = StorageKey @@ Algos.hash("Password_Key") val SaltKey: StorageKey = StorageKey @@ Algos.hash("Salt_Key") - def getDirStorage(settings: EncryAppSettings): File = new File(s"${settings.directory}/userKeys") + def getDirStorage(settings: EncryAppSettings): File = { + val dir = new File(s"${settings.directory}/userKeys") + dir.mkdirs() + dir + } def init(settings: EncryAppSettings): AccStorage = new AccStorage { override val storage: DB = LevelDbFactory.factory.open(getDirStorage(settings), new Options) diff --git a/src/main/scala/encry/api/http/SettingsStorage.scala b/src/main/scala/encry/api/http/SettingsStorage.scala index f8326d04b1..b310927233 100644 --- a/src/main/scala/encry/api/http/SettingsStorage.scala +++ b/src/main/scala/encry/api/http/SettingsStorage.scala @@ -1,11 +1,10 @@ package encry.api.http -import java.io.{ ByteArrayInputStream, ByteArrayOutputStream, File, ObjectInputStream, ObjectOutputStream } -import cats.syntax.either._ +import java.io.{ByteArrayInputStream, ByteArrayOutputStream, File, ObjectInputStream, ObjectOutputStream} import com.typesafe.scalalogging.StrictLogging import encry.settings.EncryAppSettings import org.encryfoundation.common.utils.Algos -import org.iq80.leveldb.{ DB, Options } +import org.iq80.leveldb.{DB, Options} import scorex.crypto.hash.Digest32 import encry.storage.levelDb.versionalLevelDB.LevelDbFactory @@ -13,31 +12,24 @@ trait SettingsStorage extends StrictLogging with AutoCloseable { val storage: DB - def getSettings: Option[EncryAppSettings] = SettingsStorage.deserialise(storage.get(SettingsStorage.SettingsKey)) + val SettingsKey: Digest32 = Algos.hash(s"Settings_Key") + + def getSettings: Option[EncryAppSettings] = deserialise(storage.get(SettingsKey)) - def putSettings(settings: EncryAppSettings): Either[Throwable, Unit] = { - println(s"settings = ${settings.network.nodeName}") + def putSettings(settings: EncryAppSettings): Unit = { val batch = storage.createWriteBatch() - val serialisedSettings: Array[Byte] = SettingsStorage.serialise(settings) try { - batch.put(SettingsStorage.SettingsKey, serialisedSettings) - storage.write(batch).asRight[Throwable] + val serialisedSettings: Array[Byte] = serialise(settings) + batch.put(SettingsKey, serialisedSettings) + storage.write(batch) } catch { - case err: Throwable => err.asLeft[Unit] + case err: Throwable => throw new Exception(s"Error during saving settings cause of $err") } finally { batch.close() } } - override def close(): Unit = storage.close() - -} - -object SettingsStorage extends StrictLogging { - - val SettingsKey: Digest32 = Algos.hash(s"Settings_Key") - - def serialise(value: EncryAppSettings): Array[Byte] = { + private final def serialise(value: EncryAppSettings): Array[Byte] = { val stream: ByteArrayOutputStream = new ByteArrayOutputStream() val oos = new ObjectOutputStream(stream) try { @@ -50,7 +42,7 @@ object SettingsStorage extends StrictLogging { } } - def deserialise(bytes: Array[Byte]): Option[EncryAppSettings] = { + private final def deserialise(bytes: Array[Byte]): Option[EncryAppSettings] = { val ois = new ObjectInputStream(new ByteArrayInputStream(bytes)) try { val value = ois.readObject @@ -67,7 +59,18 @@ object SettingsStorage extends StrictLogging { } } - def getDirStorage(settings: EncryAppSettings): File = new File(s"${settings.directory}/userSettings") + override def close(): Unit = storage.close() + +} + +object SettingsStorage extends StrictLogging { + + def getDirStorage(settings: EncryAppSettings): File = { + val dir = new File(s"${settings.directory}/userSettings") + dir.mkdirs() + dir + } + def init(settings: EncryAppSettings): SettingsStorage = new SettingsStorage { override val storage: DB = LevelDbFactory.factory.open(getDirStorage(settings), new Options)