mirror of
https://github.com/fluencelabs/crypto
synced 2025-04-24 14:22:18 +00:00
Cli demo (#66)
* CLI reorganization WIP * clean up reference.conf, add application.conf to gitignore * linearizing ClientComposer; some free operations * keyPath config path corrected * compilation error fixed * AuthorizedClient removed * test compilation error fixed * fix keystore tests * Merge branch 'master' into cli-demo # Conflicts: # client/src/main/scala/fluence/client/ClientApp.scala # client/src/main/scala/fluence/client/ConfigParsers.scala # client/src/main/scala/fluence/client/FluenceClient.scala # client/src/main/scala/fluence/client/KademliaConfigParser.scala # client/src/main/scala/fluence/client/cli/CliOps.scala # client/src/main/scala/fluence/client/config/KademliaConfigParser.scala * cats effect 0.9 * replicationN in ClientApp * add logs to FileKeyStorage * add logs to node dataset storage * fix typos * add logs to server contract allocator * ClientApp recursive calls * launches and joins with docker * with volumes * update port parameters * update port parameters * fix test * update port parameters * add check before put * change assertion * no fluence_grpc_port * run client in docker * some TODOs for Cli * fix assertion * add some logs * add implicit
This commit is contained in:
parent
4a966657a6
commit
26b41e7b4d
@ -18,7 +18,7 @@
|
||||
package fluence.crypto
|
||||
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.{ Files, Paths }
|
||||
|
||||
import cats.MonadError
|
||||
import cats.syntax.flatMap._
|
||||
@ -29,21 +29,37 @@ import io.circe.syntax._
|
||||
|
||||
import scala.language.higherKinds
|
||||
|
||||
class FileKeyStorage[F[_]](file: File)(implicit F: MonadError[F, Throwable]) {
|
||||
/**
|
||||
* TODO use cats IO
|
||||
* File based storage for crypto keys.
|
||||
*
|
||||
* @param file Path to keys in file system
|
||||
*/
|
||||
class FileKeyStorage[F[_]](file: File)(implicit F: MonadError[F, Throwable]) extends slogging.LazyLogging {
|
||||
import KeyStore._
|
||||
|
||||
def readKeyPair: F[KeyPair] = {
|
||||
val keyBytes = Files.readAllBytes(file.toPath)
|
||||
val keyBytes = Files.readAllBytes(file.toPath) // TODO: it throws!
|
||||
for {
|
||||
storageOp ← F.fromEither(decode[Option[KeyStore]](new String(keyBytes)))
|
||||
storage ← storageOp match {
|
||||
case None ⇒ F.raiseError[KeyStore](new RuntimeException("Cannot parse file with keys."))
|
||||
case Some(ks) ⇒ F.pure(ks)
|
||||
case None ⇒
|
||||
logger.warn(s"Reading keys from file=$file was failed")
|
||||
F.raiseError[KeyStore](new RuntimeException("Cannot parse file with keys."))
|
||||
case Some(ks) ⇒
|
||||
logger.info(s"Reading keys from file=$file was success")
|
||||
F.pure(ks)
|
||||
}
|
||||
} yield storage.keyPair
|
||||
}
|
||||
|
||||
def storeSecretKey(key: KeyPair): F[Unit] =
|
||||
F.catchNonFatal {
|
||||
logger.info("Storing secret key to file: " + file)
|
||||
if (!file.getParentFile.exists()) {
|
||||
logger.info(s"Parent directory does not exist: ${file.getParentFile}, trying to create")
|
||||
Files.createDirectories(file.getParentFile.toPath)
|
||||
}
|
||||
if (!file.exists()) file.createNewFile() else throw new RuntimeException(file.getAbsolutePath + " already exists")
|
||||
val str = KeyStore(key).asJson.toString()
|
||||
|
||||
@ -57,6 +73,24 @@ class FileKeyStorage[F[_]](file: File)(implicit F: MonadError[F, Throwable]) {
|
||||
for {
|
||||
newKeys ← f
|
||||
_ ← storeSecretKey(newKeys)
|
||||
} yield newKeys
|
||||
} yield {
|
||||
logger.info(s"New keys were generated and saved to file=$file")
|
||||
newKeys
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object FileKeyStorage {
|
||||
/**
|
||||
* Generates or loads keypair
|
||||
*
|
||||
* @param keyPath Path to store keys in
|
||||
* @param algo Sign algo
|
||||
* @return Keypair, either loaded or freshly generated
|
||||
*/
|
||||
def getKeyPair[F[_]](keyPath: String, algo: SignAlgo)(implicit F: MonadError[F, Throwable]): F[KeyPair] = {
|
||||
val keyFile = new File(keyPath)
|
||||
val keyStorage = new FileKeyStorage[F](keyFile)
|
||||
keyStorage.getOrCreateKeyPair(algo.generateKeyPair[F]().value.flatMap(F.fromEither))
|
||||
}
|
||||
}
|
||||
|
@ -198,5 +198,4 @@ object AesCrypt extends slogging.LazyLogging {
|
||||
|
||||
def apply[F[_] : Applicative, T](password: ByteVector, withIV: Boolean, config: AesConfig)(implicit ME: MonadError[F, Throwable], codec: Codec[F, T, Array[Byte]]): AesCrypt[F, T] =
|
||||
new AesCrypt(password.toHex.toCharArray, withIV, config)
|
||||
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
package fluence.crypto
|
||||
|
||||
import fluence.crypto.algorithm.{AesConfig, AesCrypt, CryptoErr}
|
||||
import fluence.crypto.algorithm.{ AesConfig, AesCrypt, CryptoErr }
|
||||
import cats.instances.try_._
|
||||
import org.scalactic.source.Position
|
||||
import org.scalatest.{Assertion, Matchers, WordSpec}
|
||||
import org.scalatest.{ Assertion, Matchers, WordSpec }
|
||||
import scodec.bits.ByteVector
|
||||
|
||||
import scala.util.{Random, Try}
|
||||
import scala.util.{ Random, Try }
|
||||
|
||||
class AesSpec extends WordSpec with Matchers with slogging.LazyLogging {
|
||||
|
||||
@ -57,7 +57,7 @@ class AesSpec extends WordSpec with Matchers with slogging.LazyLogging {
|
||||
def checkCryptoError(tr: Try[String])(implicit pos: Position): Assertion = {
|
||||
tr.map(_ ⇒ false).recover {
|
||||
case e: CryptoErr ⇒ true
|
||||
case e ⇒
|
||||
case e ⇒
|
||||
logger.error("Unexpected error", e)
|
||||
false
|
||||
}.get shouldBe true
|
||||
|
@ -17,6 +17,10 @@
|
||||
|
||||
package fluence.crypto
|
||||
|
||||
import cats.Monad
|
||||
import cats.syntax.functor._
|
||||
import cats.syntax.flatMap._
|
||||
import cats.data.EitherT
|
||||
import fluence.crypto.keypair.KeyPair
|
||||
import io.circe.{ Decoder, Encoder, HCursor, Json }
|
||||
import scodec.bits.{ Bases, ByteVector }
|
||||
@ -63,16 +67,18 @@ object KeyStore {
|
||||
} yield KeyStore(KeyPair.fromByteVectors(public, secret))
|
||||
}
|
||||
|
||||
def fromBase64(base64: String): KeyStore = {
|
||||
val jsonStr = ByteVector.fromBase64(base64, alphabet) match {
|
||||
case Some(bv) ⇒ new String(bv.toArray)
|
||||
case None ⇒
|
||||
throw new IllegalArgumentException("'" + base64 + "' is not a valid base64.")
|
||||
}
|
||||
decode[Option[KeyStore]](jsonStr) match {
|
||||
case Right(Some(ks)) ⇒ ks
|
||||
case Right(None) ⇒ throw new IllegalArgumentException("'" + base64 + "' is not a valid key store.")
|
||||
case Left(err) ⇒ throw new IllegalArgumentException("'" + base64 + "' is not a valid key store.", err)
|
||||
}
|
||||
}
|
||||
def fromBase64[F[_] : Monad](base64: String): EitherT[F, IllegalArgumentException, KeyStore] =
|
||||
for {
|
||||
jsonStr ← ByteVector.fromBase64(base64, alphabet) match {
|
||||
case Some(bv) ⇒ EitherT.pure[F, IllegalArgumentException](new String(bv.toArray))
|
||||
case None ⇒ EitherT.leftT(
|
||||
new IllegalArgumentException("'" + base64 + "' is not a valid base64.")
|
||||
)
|
||||
}
|
||||
keyStore ← decode[Option[KeyStore]](jsonStr) match {
|
||||
case Right(Some(ks)) ⇒ EitherT.pure[F, IllegalArgumentException](ks)
|
||||
case Right(None) ⇒ EitherT.leftT[F, KeyStore](new IllegalArgumentException("'" + base64 + "' is not a valid key store."))
|
||||
case Left(err) ⇒ EitherT.leftT[F, KeyStore](new IllegalArgumentException("'" + base64 + "' is not a valid key store.", err))
|
||||
}
|
||||
} yield keyStore
|
||||
}
|
||||
|
@ -54,21 +54,21 @@ class KeyStoreSpec extends WordSpec with Matchers {
|
||||
"throw an exception" when {
|
||||
"invalid base64 format" in {
|
||||
val invalidBase64 = "!@#$%"
|
||||
the[IllegalArgumentException] thrownBy {
|
||||
KeyStore.fromBase64(invalidBase64)
|
||||
} should have message "'" + invalidBase64 + "' is not a valid base64."
|
||||
|
||||
val e = KeyStore.fromBase64(invalidBase64).value.left.get
|
||||
e should have message "'" + invalidBase64 + "' is not a valid base64."
|
||||
}
|
||||
"invalid decoded json" in {
|
||||
val invalidJson = ByteVector("""{"keystore":{"public":"cHViS2V5"}}""".getBytes).toBase64(alphabet)
|
||||
the[IllegalArgumentException] thrownBy {
|
||||
KeyStore.fromBase64(invalidJson)
|
||||
}
|
||||
|
||||
KeyStore.fromBase64(invalidJson).value.isLeft shouldBe true
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
"fetch KeyStore from valid base64" in {
|
||||
val invalidJson = ByteVector(jsonString.getBytes).toBase64(alphabet)
|
||||
val result = KeyStore.fromBase64(invalidJson)
|
||||
val result = KeyStore.fromBase64(invalidJson).value.right.get
|
||||
result shouldBe keyStore
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user