diff --git a/Modules/Aead/js/src/main/scala/com/github/ckuessner/aead/AeadHelper.scala b/Modules/Aead/js/src/main/scala/com/github/ckuessner/aead/AeadHelper.scala index e602ce93c..e78252280 100644 --- a/Modules/Aead/js/src/main/scala/com/github/ckuessner/aead/AeadHelper.scala +++ b/Modules/Aead/js/src/main/scala/com/github/ckuessner/aead/AeadHelper.scala @@ -1,8 +1,5 @@ package com.github.ckuessner.aead -import typings.libsodiumWrappers.mod as sodium -import typings.libsodiumWrappers.mod.StringOutputFormat - import scala.concurrent.Future import scala.scalajs.js.typedarray.Uint8Array import scala.scalajs.js.undefined @@ -23,9 +20,9 @@ object AeadHelper { sodium.ready.toFuture } - def toBase64(bytes: Uint8Array): String = sodium.toBase64(bytes, sodium.base64Variants.ORIGINAL) + def toBase64(bytes: Uint8Array): String = sodium.to_base64(bytes, base64Variants.ORIGINAL) - def fromBase64(bytes: String): Uint8Array = sodium.fromBase64(bytes, sodium.base64Variants.ORIGINAL) + def fromBase64(bytes: String): Uint8Array = sodium.from_base64(bytes, base64Variants.ORIGINAL) /** Generates a new AeadKey. * @@ -42,7 +39,7 @@ object AeadHelper { * The new key */ def generateRawKey: Uint8Array = { - sodium.cryptoAeadXchacha20poly1305IetfKeygen() + sodium.crypto_aead_xchacha20poly1305_ietf_keygen() } /** Instantiates an AeadKey instance for the provided raw key material @@ -65,7 +62,7 @@ object AeadHelper { */ def aeadKeyFromBase64(rawKey: String): LibsodiumJsAeadKey = { LibsodiumJsAeadKey( - sodium.fromBase64(rawKey, sodium.base64Variants.ORIGINAL) + sodium.from_base64(rawKey, base64Variants.ORIGINAL) ) } @@ -75,7 +72,7 @@ object AeadHelper { * A random nonce */ private inline def generateRandomNonce(): Uint8Array = { - sodium.randombytesBuf(sodium.cryptoAeadXchacha20poly1305IetfNPUBBYTES) + sodium.randombytes_buf(sodium.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES) } /** Encrypts and authenticates a message along the authenticated non-confidential associated data. @@ -93,7 +90,7 @@ object AeadHelper { */ def encrypt(message: String, associatedData: String, key: Uint8Array): Try[Uint8Array] = Try { val nonce: Uint8Array = generateRandomNonce() - val cipherText = sodium.cryptoAeadXchacha20poly1305IetfEncrypt(message, associatedData, null, nonce, key, undefined) + val cipherText = sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(message, associatedData, null, nonce, key, undefined) concatenateArrays(nonce, cipherText) } @@ -112,7 +109,7 @@ object AeadHelper { */ def encrypt(message: Uint8Array, associatedData: Uint8Array, key: Uint8Array): Try[Uint8Array] = Try { val nonce: Uint8Array = generateRandomNonce() - val cipherText = sodium.cryptoAeadXchacha20poly1305IetfEncrypt(message, associatedData, null, nonce, key, undefined) + val cipherText = sodium.crypto_aead_xchacha20poly1305_ietf_encrypt(message, associatedData, null, nonce, key, undefined) concatenateArrays(nonce, cipherText) } @@ -131,7 +128,7 @@ object AeadHelper { def decrypt(encryptedMessage: Uint8Array, associatedData: Uint8Array, key: Uint8Array): Try[Uint8Array] = { val (usedNonce, cipherText) = extractNonceAndCiphertext(encryptedMessage) Try { - sodium.cryptoAeadXchacha20poly1305IetfDecrypt(null, cipherText, associatedData, usedNonce, key, undefined) + sodium.crypto_aead_xchacha20poly1305_ietf_decrypt(null, cipherText, associatedData, usedNonce, key, undefined) } } @@ -148,9 +145,9 @@ object AeadHelper { * The plaintext of the encrypted message if the encryption was successful, or a Failure */ def decrypt(encryptedMessage: Uint8Array, associatedData: String, key: Uint8Array): Try[String] = { - val (usedNonce, cipherText) = extractNonceAndCiphertext(encryptedMessage) + val (usedNonce: Uint8Array, cipherText: Uint8Array) = extractNonceAndCiphertext(encryptedMessage) Try { - sodium.cryptoAeadXchacha20poly1305IetfDecrypt( + sodium.crypto_aead_xchacha20poly1305_ietf_decrypt( null, cipherText, associatedData, @@ -169,7 +166,7 @@ object AeadHelper { } private inline def extractNonceAndCiphertext(combinedCipherText: Uint8Array): (Uint8Array, Uint8Array) = { - val nonceLength: Int = sodium.cryptoAeadXchacha20poly1305IetfNPUBBYTES.toInt + val nonceLength: Int = sodium.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES.toInt val usedNonce: Uint8Array = combinedCipherText.subarray(0, nonceLength) val cipherText: Uint8Array = combinedCipherText.subarray(nonceLength, combinedCipherText.length) (usedNonce, cipherText) diff --git a/Modules/Aead/js/src/main/scala/com/github/ckuessner/aead/LibsodiumJsAeadKey.scala b/Modules/Aead/js/src/main/scala/com/github/ckuessner/aead/LibsodiumJsAeadKey.scala index 303bd515d..9c22a2c15 100644 --- a/Modules/Aead/js/src/main/scala/com/github/ckuessner/aead/LibsodiumJsAeadKey.scala +++ b/Modules/Aead/js/src/main/scala/com/github/ckuessner/aead/LibsodiumJsAeadKey.scala @@ -1,11 +1,9 @@ package com.github.ckuessner.aead -import typings.libsodiumWrappers.mod as sodium - import scala.scalajs.js.typedarray.Uint8Array case class LibsodiumJsAeadKey(rawKeyBytes: Uint8Array) extends AeadKey { override def aeadPrimitive: Aead = LibsodiumJsAead(rawKeyBytes) - override def rawKeyBase64: String = sodium.toBase64(rawKeyBytes, sodium.base64Variants.ORIGINAL) + override def rawKeyBase64: String = sodium.to_base64(rawKeyBytes, base64Variants.ORIGINAL) } diff --git a/Modules/Aead/js/src/main/scala/com/github/ckuessner/aead/libsodiumFacade.scala b/Modules/Aead/js/src/main/scala/com/github/ckuessner/aead/libsodiumFacade.scala new file mode 100644 index 000000000..e0ad0f317 --- /dev/null +++ b/Modules/Aead/js/src/main/scala/com/github/ckuessner/aead/libsodiumFacade.scala @@ -0,0 +1,202 @@ +package com.github.ckuessner.aead + +import scala.scalajs.js +import scala.scalajs.js.annotation.{JSBracketAccess, JSGlobal, JSGlobalScope, JSImport, JSName} +import scala.scalajs.js.typedarray.Uint8Array + +object libsodiumWrappersStrings { + + @js.native + sealed trait base64 + extends js.Object + with StringOutputFormat + def base64: base64 = "base64".asInstanceOf[base64] + + @js.native + sealed trait curve25519 + extends js.Object + with KeyType + def curve25519: curve25519 = "curve25519".asInstanceOf[curve25519] + + @js.native + sealed trait ed25519 + extends js.Object + with KeyType + def ed25519: ed25519 = "ed25519".asInstanceOf[ed25519] + + @js.native + sealed trait hex + extends js.Object + with StringOutputFormat + def hex: hex = "hex".asInstanceOf[hex] + + @js.native + sealed trait text + extends js.Object + with StringOutputFormat + def text: text = "text".asInstanceOf[text] + + @js.native + sealed trait uint8array extends js.Object + def uint8array: uint8array = "uint8array".asInstanceOf[uint8array] + + @js.native + sealed trait x25519 + extends js.Object + with KeyType + def x25519: x25519 = "x25519".asInstanceOf[x25519] +} + +trait KeyType extends js.Object +object KeyType { + + def curve25519: libsodiumWrappersStrings.curve25519 = + "curve25519".asInstanceOf[libsodiumWrappersStrings.curve25519] + + def ed25519: libsodiumWrappersStrings.ed25519 = + "ed25519".asInstanceOf[libsodiumWrappersStrings.ed25519] + + def x25519: libsodiumWrappersStrings.x25519 = + "x25519".asInstanceOf[libsodiumWrappersStrings.x25519] +} + +trait StringOutputFormat extends js.Object +object StringOutputFormat { + + def base64: libsodiumWrappersStrings.base64 = + "base64".asInstanceOf[libsodiumWrappersStrings.base64] + + def hex: libsodiumWrappersStrings.hex = + "hex".asInstanceOf[libsodiumWrappersStrings.hex] + + def text: libsodiumWrappersStrings.text = + "text".asInstanceOf[libsodiumWrappersStrings.text] +} + +@js.native +sealed trait base64Variants extends js.Object + +@JSImport("libsodium-wrappers", "base64_variants") +@js.native +object base64Variants extends js.Object { + + @JSBracketAccess + def apply(value: Double): js.UndefOr[base64Variants & Double] = js.native + + @js.native + sealed trait ORIGINAL + extends js.Object + with base64Variants + /* 0 */ + val ORIGINAL: base64Variants.ORIGINAL & Double = js.native + + @js.native + sealed trait ORIGINAL_NO_PADDING + extends js.Object + with base64Variants + /* 1 */ + val ORIGINAL_NO_PADDING: base64Variants.ORIGINAL_NO_PADDING & Double = js.native + + @js.native + sealed trait URLSAFE + extends js.Object + with base64Variants + /* 2 */ + val URLSAFE: base64Variants.URLSAFE & Double = js.native + + @js.native + sealed trait URLSAFE_NO_PADDING + extends js.Object + with base64Variants + /* 3 */ + val URLSAFE_NO_PADDING: base64Variants.URLSAFE_NO_PADDING & Double = js.native +} + +@JSImport("libsodium-wrappers", JSImport.Namespace) +@js.native +object sodium extends js.Object { + + def SODIUM_LIBRARY_VERSION_MAJOR: _root_.scala.Double = js.native + + def SODIUM_LIBRARY_VERSION_MINOR: _root_.scala.Double = js.native + + def SODIUM_VERSION_STRING: _root_.scala.Predef.String = js.native + + def add( + a: _root_.scala.scalajs.js.typedarray.Uint8Array, + b: _root_.scala.scalajs.js.typedarray.Uint8Array + ): _root_.scala.Unit = js.native + + def crypto_aead_xchacha20poly1305_ietf_ABYTES: _root_.scala.Double = js.native + + def crypto_aead_xchacha20poly1305_ietf_decrypt( + secret_nonce: Uint8Array | Null, + ciphertext: Uint8Array, + additional_data: String | Null, + public_nonce: Uint8Array, + key: Uint8Array, + outputFormat: js.UndefOr[StringOutputFormat | Null] + ): String = js.native + + def crypto_aead_xchacha20poly1305_ietf_decrypt( + secret_nonce: Uint8Array | Null, + ciphertext: Uint8Array, + additional_data: Uint8Array | Null, + public_nonce: Uint8Array, + key: Uint8Array, + outputFormat: js.UndefOr[StringOutputFormat | Null] + ): Uint8Array = js.native + + def crypto_aead_xchacha20poly1305_ietf_encrypt( + message: _root_.scala.|[_root_.scala.Predef.String, _root_.scala.scalajs.js.typedarray.Uint8Array], + additional_data: _root_.scala.|[ + _root_.scala.|[_root_.scala.Predef.String, _root_.scala.scalajs.js.typedarray.Uint8Array], + _root_.scala.Null + ], + secret_nonce: _root_.scala.|[ + _root_.scala.|[_root_.scala.Predef.String, _root_.scala.scalajs.js.typedarray.Uint8Array], + _root_.scala.Null + ], + public_nonce: _root_.scala.scalajs.js.typedarray.Uint8Array, + key: _root_.scala.scalajs.js.typedarray.Uint8Array, + outputFormat: _root_.scala.scalajs.js.UndefOr[_root_.scala.|[ + libsodiumWrappersStrings.uint8array, + _root_.scala.Null + ]] + ): _root_.scala.scalajs.js.typedarray.Uint8Array = js.native + + def fromBase64(input: _root_.scala.Predef.String): _root_.scala.scalajs.js.typedarray.Uint8Array = js.native + + def from_base64( + input: _root_.scala.Predef.String, + variant: base64Variants + ): _root_.scala.scalajs.js.typedarray.Uint8Array = js.native + + def randombytes_buf(length: _root_.scala.Double): _root_.scala.scalajs.js.typedarray.Uint8Array = js.native + + def randombytes_buf( + length: _root_.scala.Double, + outputFormat: StringOutputFormat + ): _root_.scala.Predef.String = js.native + + def randombytes_buf( + length: _root_.scala.Double, + outputFormat: libsodiumWrappersStrings.uint8array + ): _root_.scala.scalajs.js.typedarray.Uint8Array = js.native + + def ready: _root_.scala.scalajs.js.Promise[_root_.scala.Unit] = js.native + + def to_base64( + input: _root_.scala.scalajs.js.typedarray.Uint8Array, + variant: base64Variants + ): _root_.scala.Predef.String = js.native + + def toString(bytes: _root_.scala.scalajs.js.typedarray.Uint8Array): _root_.scala.Predef.String = js.native + + def crypto_aead_xchacha20poly1305_ietf_keygen(): _root_.scala.scalajs.js.typedarray.Uint8Array = js.native + + def crypto_aead_xchacha20poly1305_ietf_NPUBBYTES: _root_.scala.Double = js.native + + def crypto_aead_xchacha20poly1305_ietf_KEYBYTES: Double = js.native + +} diff --git a/Modules/Aead/js/src/test/scala/com/github/ckuessner/aead/AeadHelperTest.scala b/Modules/Aead/js/src/test/scala/com/github/ckuessner/aead/AeadHelperTest.scala index a7c04d684..7b94bbf44 100644 --- a/Modules/Aead/js/src/test/scala/com/github/ckuessner/aead/AeadHelperTest.scala +++ b/Modules/Aead/js/src/test/scala/com/github/ckuessner/aead/AeadHelperTest.scala @@ -3,7 +3,6 @@ package com.github.ckuessner.aead import com.github.ckuessner.aead.AeadHelper import org.scalatest.BeforeAndAfter import org.scalatest.flatspec.AsyncFlatSpec -import typings.libsodiumWrappers.mod as sodium import scala.concurrent.ExecutionContext import scala.scalajs.js.typedarray.Uint8Array @@ -27,8 +26,8 @@ class AeadHelperTest extends AsyncFlatSpec with BeforeAndAfter { otherKey = AeadHelper.generateRawKey expectedCiphertextLength = testMessage.getBytes.length - + sodium.cryptoAeadXchacha20poly1305IetfABYTES.intValue() - + sodium.cryptoAeadXchacha20poly1305IetfNPUBBYTES.intValue() + + sodium.crypto_aead_xchacha20poly1305_ietf_ABYTES.intValue() + + sodium.crypto_aead_xchacha20poly1305_ietf_NPUBBYTES.intValue() } } @@ -42,7 +41,7 @@ class AeadHelperTest extends AsyncFlatSpec with BeforeAndAfter { AeadHelper .ready() .map(_ => { - assert(key.length == sodium.cryptoAeadXchacha20poly1305IetfKEYBYTES) + assert(key.length == sodium.crypto_aead_xchacha20poly1305_ietf_KEYBYTES) }) } diff --git a/build.sbt b/build.sbt index 3962ff7d3..ac608d945 100644 --- a/build.sbt +++ b/build.sbt @@ -101,11 +101,10 @@ lazy val aead = crossProject(JSPlatform, JVMPlatform).in(file("Modules/Aead")) .jvmSettings( RescalaDependencies.tink ) - .jsConfigure(_.enablePlugins(ScalablyTypedConverterPlugin)) + .jsConfigure(_.enablePlugins(ScalaJSBundlerPlugin)) .jsSettings( Compile / npmDependencies ++= Seq( "libsodium-wrappers" -> "0.7.13", - "@types/libsodium-wrappers" -> "0.7.13" ) ) diff --git a/project/plugins.sbt b/project/plugins.sbt index 3d8babcff..55675367c 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -20,5 +20,6 @@ addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.11.0") addSbtPlugin("com.github.sbt" % "sbt-pgp" % "2.2.1") // tooling -addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.7") -addSbtPlugin("org.scalablytyped.converter" % "sbt-converter" % "1.0.0-beta44") +addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.7") +addSbtPlugin("ch.epfl.scala" % "sbt-scalajs-bundler" % "0.21.1") +//addSbtPlugin("org.scalablytyped.converter" % "sbt-converter" % "1.0.0-beta44")