From 4bf18c902a9a32f2954e5aa8fa63f26100ff8595 Mon Sep 17 00:00:00 2001 From: exoego Date: Tue, 24 Sep 2019 15:33:13 +0900 Subject: [PATCH 1/2] Use symlink if possible for productivity in IDE --- build.sbt | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index 8937d0843..7a66cc591 100644 --- a/build.sbt +++ b/build.sbt @@ -48,7 +48,11 @@ lazy val nodejs_v10 = (project in file("./app/nodejs-v10")) .settings(MySettings.commonMacroParadiseSetting) .settings(MySettings.publishingSettings) .settings( - unmanagedSourceDirectories in Compile += (baseDirectory in current).value / "src" / "main" / "scala", + unmanagedSourceDirectories in Compile ++= { + val symlinkDir = baseDirectory.value / "src" / "main" + val hasSymlink = symlinkDir.exists && symlinkDir.isDirectory + Seq((baseDirectory in current).value / "src" / "main" / "scala").filter(_ => !hasSymlink) + }, scalacOptions ++= Seq( "-Xmacro-settings:nodeJs10.16.0" ), @@ -66,7 +70,11 @@ lazy val nodejs_v8 = (project in file("./app/nodejs-v8")) .settings(MySettings.commonMacroParadiseSetting) .settings(MySettings.publishingSettings) .settings( - unmanagedSourceDirectories in Compile += (baseDirectory in current).value / "src" / "main" / "scala", + unmanagedSourceDirectories in Compile ++= { + val symlinkDir = baseDirectory.value / "src" / "main" + val hasSymlink = symlinkDir.exists && symlinkDir.isDirectory + Seq((baseDirectory in current).value / "src" / "main" / "scala").filter(_ => !hasSymlink) + }, scalacOptions ++= Seq( "-Xmacro-settings:nodeJs8.16.0" ), From 2c40b0d69b965f989591d35da2752b1b34dd9dc5 Mon Sep 17 00:00:00 2001 From: exoego Date: Tue, 24 Sep 2019 15:19:41 +0900 Subject: [PATCH 2/2] Overhaul crypto module --- README.md | 2 +- .../io/scalajs/nodejs/buffer/Buffer.scala | 2 +- .../scalajs/nodejs/crypto/Certificate.scala | 29 ++ .../io/scalajs/nodejs/crypto/Cipher.scala | 36 +- .../io/scalajs/nodejs/crypto/Crypto.scala | 333 ++++++++++++++++-- .../io/scalajs/nodejs/crypto/Decipher.scala | 31 +- .../scalajs/nodejs/crypto/DiffieHellman.scala | 36 ++ .../nodejs/crypto/DiffieHellmanGroup.scala | 37 ++ .../scala/io/scalajs/nodejs/crypto/ECDH.scala | 47 +++ .../scala/io/scalajs/nodejs/crypto/Hash.scala | 25 +- .../scala/io/scalajs/nodejs/crypto/Hmac.scala | 10 +- .../io/scalajs/nodejs/crypto/KeyObject.scala | 22 ++ .../scala/io/scalajs/nodejs/crypto/Sign.scala | 26 +- .../io/scalajs/nodejs/crypto/Verify.scala | 41 +-- .../io/scalajs/nodejs/crypto/package.scala | 19 + .../io/scalajs/nodejs/stream/Transform.scala | 12 +- .../io/scalajs/nodejs/stream/Writable.scala | 22 +- .../scala/nodejs/crypto/CertificateTest.scala | 29 ++ .../test/scala/nodejs/crypto/CryptoTest.scala | 40 +++ .../scala/nodejs/crypto/CertificateTest.scala | 35 ++ .../test/scala/nodejs/crypto/CryptoTest.scala | 5 + 21 files changed, 700 insertions(+), 139 deletions(-) create mode 100644 app/current/src/main/scala/io/scalajs/nodejs/crypto/Certificate.scala create mode 100644 app/current/src/main/scala/io/scalajs/nodejs/crypto/DiffieHellman.scala create mode 100644 app/current/src/main/scala/io/scalajs/nodejs/crypto/DiffieHellmanGroup.scala create mode 100644 app/current/src/main/scala/io/scalajs/nodejs/crypto/ECDH.scala create mode 100644 app/current/src/main/scala/io/scalajs/nodejs/crypto/KeyObject.scala create mode 100644 app/current/src/main/scala/io/scalajs/nodejs/crypto/package.scala create mode 100644 app/nodejs-v10/src/test/scala/nodejs/crypto/CertificateTest.scala create mode 100644 app/nodejs-v10/src/test/scala/nodejs/crypto/CryptoTest.scala create mode 100644 app/nodejs-v8/src/test/scala/nodejs/crypto/CertificateTest.scala diff --git a/README.md b/README.md index 61102cc71..e055c233a 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ The following core Node.js modules (v8.7.0+) have been implemented: | [child_process](https://nodejs.org/api/child_process.html) | :heavy_check_mark: | | [cluster](https://nodejs.org/api/cluster.html) | :heavy_check_mark: | | [console](https://nodejs.org/api/console.html) | :heavy_check_mark: | -| [crypto](https://nodejs.org/api/crypto.html) | | +| [crypto](https://nodejs.org/api/crypto.html) | :heavy_check_mark: | | [dgram](https://nodejs.org/api/dgram.html) | | | [dns](https://nodejs.org/api/dns.html) | | | [events](https://nodejs.org/api/events.html) | | diff --git a/app/current/src/main/scala/io/scalajs/nodejs/buffer/Buffer.scala b/app/current/src/main/scala/io/scalajs/nodejs/buffer/Buffer.scala index 0230f9593..cf35c97f6 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/buffer/Buffer.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/buffer/Buffer.scala @@ -529,7 +529,7 @@ class Buffer protected () extends Uint8Array( /* dummy to trick constructor */ - * @return a string according to the specified character encoding in encoding. * @example {{{ buf.toString([encoding[, start[, end]]]) }}} */ - def toString(encoding: String = js.native, start: Int = js.native, end: Int = js.native): String = js.native + def toString(encoding: String, start: Int = js.native, end: Int = js.native): String = js.native /** * Re-encodes the given Buffer instance from one character encoding to another. Returns a new Buffer instance. diff --git a/app/current/src/main/scala/io/scalajs/nodejs/crypto/Certificate.scala b/app/current/src/main/scala/io/scalajs/nodejs/crypto/Certificate.scala new file mode 100644 index 000000000..a4fb08e0b --- /dev/null +++ b/app/current/src/main/scala/io/scalajs/nodejs/crypto/Certificate.scala @@ -0,0 +1,29 @@ +package io.scalajs.nodejs.crypto + +import com.thoughtworks.enableIf +import io.scalajs.nodejs.buffer.Buffer + +import scala.scalajs.js +import scala.scalajs.js.annotation.JSImport +import scala.scalajs.js.| + +@js.native +@JSImport("crypto", "Certificate") +class Certificate extends js.Object { + def exportChallenge(spkac: String | BufferLike): Buffer = js.native + def exportPublicKey(spkac: String | BufferLike, encoding: String = js.native): Buffer = js.native + def verifySpkac(spkac: BufferLike): Boolean = js.native +} + +@js.native +@JSImport("crypto", "Certificate") +object Certificate extends js.Object { + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def exportChallenge(spkac: String | BufferLike): Buffer = js.native + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def exportPublicKey(spkac: String | BufferLike, encoding: String = js.native): Buffer = js.native + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def verifySpkac(spkac: BufferLike): Boolean = js.native +} diff --git a/app/current/src/main/scala/io/scalajs/nodejs/crypto/Cipher.scala b/app/current/src/main/scala/io/scalajs/nodejs/crypto/Cipher.scala index 12bbb894e..3139da855 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/crypto/Cipher.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/crypto/Cipher.scala @@ -1,7 +1,7 @@ package io.scalajs.nodejs.crypto import io.scalajs.nodejs.buffer.Buffer -import io.scalajs.nodejs.stream.IDuplex +import io.scalajs.nodejs.stream.{Transform, TransformOptions} import scala.scalajs.js @@ -16,7 +16,7 @@ import scala.scalajs.js * are not to be created directly using the new keyword. */ @js.native -trait Cipher extends IDuplex { +sealed trait Cipher extends Transform { /** * Returns any remaining enciphered contents. If output_encoding parameter is one of 'binary', 'base64' or 'hex', @@ -26,7 +26,7 @@ trait Cipher extends IDuplex { * Attempts to call cipher.final() more than once will result in an error being thrown. * @example cipher.final([output_encoding]) */ - def `final`(output_encoding: String): String = js.native + def `final`(outputEncoding: String): String = js.native /** * Returns any remaining enciphered contents. If output_encoding parameter is one of 'binary', 'base64' or 'hex', @@ -43,7 +43,7 @@ trait Cipher extends IDuplex { * the value used for the additional authenticated data (AAD) input parameter. * @example cipher.setAAD(buffer) */ - def setAAD(buffer: Buffer): Unit = js.native + def setAAD(buffer: Buffer, options: SetAADOptions = js.native): Cipher = js.native /** * When using an authenticated encryption mode (only GCM is currently supported), the cipher.getAuthTag() method @@ -52,7 +52,7 @@ trait Cipher extends IDuplex { * The cipher.getAuthTag() method should only be called after encryption has been completed using the cipher.final() method. * @example cipher.getAuthTag() */ - def getAuthTag(): js.Any = js.native + def getAuthTag(): Buffer = js.native /** * When using block encryption algorithms, the Cipher class will automatically add padding to the input data to the @@ -65,7 +65,7 @@ trait Cipher extends IDuplex { * The cipher.setAutoPadding() method must be called before cipher.final(). * @example cipher.setAutoPadding(auto_padding=true) */ - def setAutoPadding(auto_padding: Boolean = js.native): Unit = js.native + def setAutoPadding(auto_padding: Boolean = js.native): Cipher = js.native /** * Updates the cipher with data. If the input_encoding argument is given, it's value must be one of 'utf8', 'ascii', @@ -80,21 +80,13 @@ trait Cipher extends IDuplex { * cipher.update() after cipher.final() will result in an error being thrown. * @example cipher.update(data[, input_encoding][, output_encoding]) */ - def update(data: String, input_encoding: String, output_encoding: String = js.native): String = js.native - - /** - * Updates the cipher with data. If the input_encoding argument is given, it's value must be one of 'utf8', 'ascii', - * or 'binary' and the data argument is a string using the specified encoding. If the input_encoding argument is not - * given, data must be a Buffer. If data is a Buffer then input_encoding is ignored. - * - * The output_encoding specifies the output format of the enciphered data, and can be 'binary', 'base64' or 'hex'. - * If the output_encoding is specified, a string using the specified encoding is returned. If no output_encoding is - * provided, a Buffer is returned. - * - * The cipher.update() method can be called multiple times with new data until cipher.final() is called. Calling - * cipher.update() after cipher.final() will result in an error being thrown. - * @example cipher.update(data[, input_encoding][, output_encoding]) - */ - def update(data: Buffer): Buffer = js.native + def update(data: String, inputEncoding: String, outputEncoding: String): String = js.native + def update(data: String, inputEncoding: String): Buffer = js.native + def update(data: BufferLike): Buffer = js.native } + +class SetAADOptions(override val transform: js.UndefOr[js.Function] = js.undefined, + override val flush: js.UndefOr[js.Function] = js.undefined, + val plaintextLength: js.UndefOr[Int] = js.undefined) + extends TransformOptions(transform, flush) {} diff --git a/app/current/src/main/scala/io/scalajs/nodejs/crypto/Crypto.scala b/app/current/src/main/scala/io/scalajs/nodejs/crypto/Crypto.scala index 141ef3c63..5702faa23 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/crypto/Crypto.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/crypto/Crypto.scala @@ -1,8 +1,11 @@ package io.scalajs.nodejs.crypto +import com.thoughtworks.enableIf import io.scalajs.nodejs.buffer.Buffer +import io.scalajs.nodejs.stream.{TransformOptions, WritableOptions} import scala.scalajs.js + import scala.scalajs.js.annotation.JSImport import scala.scalajs.js.| @@ -25,36 +28,16 @@ trait Crypto extends js.Object { * The crypto.DEFAULT_ENCODING mechanism is provided for backwards compatibility with legacy programs that * expect 'binary' to be the default encoding. */ + @deprecated("New applications should expect the default to be 'buffer'.", "Node.js v10.0") val DEFAULT_ENCODING: String = js.native /** * Property for checking and controlling whether a FIPS compliant crypto provider is currently in use. * Setting to true requires a FIPS build of Node.js. */ + @deprecated("Please use crypto.setFips() and crypto.getFips() instead.", "Node.js v10.0") var fips: Boolean = js.native - ///////////////////////////////////////////////////////////////////////////////// - // Classes - ///////////////////////////////////////////////////////////////////////////////// - - def Certificate: js.Function0[js.Dynamic] = js.native - - def Cipher: js.Function0[Cipher] = js.native - - def Decipher: js.Function0[Decipher] = js.native - - def DiffieHellman: js.Function0[js.Dynamic] = js.native - - def ECDH: js.Function0[js.Dynamic] = js.native - - def Hash: js.Function0[Hash] = js.native - - def Hmac: js.Function0[Hmac] = js.native - - def Sign: js.Function0[Sign] = js.native - - def Verify: js.Function0[Verify] = js.native - ///////////////////////////////////////////////////////////////////////////////// // Methods ///////////////////////////////////////////////////////////////////////////////// @@ -67,8 +50,20 @@ trait Crypto extends js.Object { * either a 'binary' encoded string or a Buffer. * @example crypto.createCipher(algorithm, password) */ + @deprecated("Use crypto.createCipheriv() instead.", "Node.js v10.0") def createCipher(algorithm: String, password: Buffer | String): Cipher = js.native + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def createCipheriv(algorithm: String, + key: String | BufferLike, + iv: String | BufferLike, + options: TransformOptions = js.native): Cipher = js.native + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12) + def createCipheriv(algorithm: String, key: KeyObject, iv: String | BufferLike, options: TransformOptions): Cipher = + js.native + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12) + def createCipheriv(algorithm: String, key: KeyObject, iv: String | BufferLike): Cipher = js.native + /** * Creates and returns a Decipher object that uses the given algorithm and password (key). * The implementation of crypto.createDecipher() derives keys using the OpenSSL function EVP_BytesToKey with the @@ -80,7 +75,33 @@ trait Crypto extends js.Object { * derive a key and IV on their own using crypto.pbkdf2() and to use crypto.createDecipheriv() to create the Decipher object. * @example crypto.createDecipher(algorithm, password) */ + @deprecated("Use crypto.createDecipheriv() instead.", "Node.js v10.0") def createDecipher(algorithm: String, password: Buffer | String): Decipher = js.native + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def createDecipheriv(algorithm: String, + key: String | BufferLike, + iv: String | BufferLike, + options: TransformOptions = js.native): Decipher = js.native + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12) + def createDecipheriv(algorithm: String, + key: KeyObject, + iv: String | BufferLike, + options: TransformOptions): Decipher = js.native + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12) + def createDecipheriv(algorithm: String, key: KeyObject, iv: String | BufferLike): Decipher = js.native + + def createDiffieHellman(prime: String, primeEncoding: String, generator: Int | BufferLike): DiffieHellman = js.native + def createDiffieHellman(prime: String, + primeEncoding: String, + generator: String, + generatorEncoding: String): DiffieHellman = js.native + def createDiffieHellman(prime: BufferLike, generator: String, generatorEncoding: String): DiffieHellman = js.native + def createDiffieHellman(prime: BufferLike, generator: Int | BufferLike): DiffieHellman = js.native + def createDiffieHellman(primeLength: Int, generator: Int | String | BufferLike): DiffieHellman = js.native + + def createDiffieHellmanGroup(name: String): DiffieHellman = js.native + + def createECDH(curveName: String): ECDH = js.native /** * Creates and returns a Hash object that can be used to generate hash digests using the given algorithm. @@ -90,7 +111,8 @@ trait Crypto extends js.Object { * will display the available digest algorithms. * @param algorithm the given algorithm (e.g. 'sha256', 'sha512') */ - def createHash(algorithm: String): Hash = js.native + def createHash(algorithm: String, options: TransformOptions): Hash = js.native + def createHash(algorithm: String, options: CreateHashOptions = js.native): Hash = js.native /** * Creates and returns an Hmac object that uses the given algorithm and key. @@ -101,21 +123,44 @@ trait Crypto extends js.Object { * @param algorithm the given algorithm (e.g. 'sha256', 'sha512') * @param key The key is the HMAC key used to generate the cryptographic HMAC hash. */ - def createHmac(algorithm: String, key: String): Hmac = js.native + def createHmac(algorithm: String, key: String | BufferLike, options: TransformOptions = js.native): Hmac = js.native + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12) + def createHmac(algorithm: String, key: KeyObject, options: TransformOptions): Hmac = js.native + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12) + def createHmac(algorithm: String, key: KeyObject): Hmac = js.native + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12) + def createPrivateKey(key: String | Buffer | CreatePrivateKeyOptions): KeyObject = js.native + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12) + def createPublicKey(key: String | Buffer | KeyObject | CreatePublicKeyOptions): KeyObject = js.native + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12) + def createSecretKey(key: Buffer): KeyObject = js.native /** * Creates and returns a Sign object that uses the given algorithm. On recent OpenSSL releases, openssl * list-public-key-algorithms will display the available signing algorithms. One example is 'RSA-SHA256'. * @param algorithm the given algorithm (e.g. 'RSA-SHA256') */ - def createSign(algorithm: String): Sign = js.native + def createSign(algorithm: String, options: WritableOptions = js.native): Sign = js.native /** * Creates and returns a Verify object that uses the given algorithm. On recent OpenSSL releases, openssl * list-public-key-algorithms will display the available signing algorithms. One example is 'RSA-SHA256'. * @param algorithm the given algorithm (e.g. 'RSA-SHA256') */ - def createVerify(algorithm: String): Verify = js.native + def createVerify(algorithm: String, options: WritableOptions = js.native): Verify = js.native + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def generateKeyPair( + `type`: String, + options: GenerateKeyPairOptions, + callback: Callback2[String | Buffer | KeyObject, String | Buffer | KeyObject] + ): Unit = js.native + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def generateKeyPairSync(`type`: String, options: GenerateKeyPairOptions): KeyPair = js.native /** * Returns an array with the names of the supported cipher algorithms. @@ -123,6 +168,22 @@ trait Crypto extends js.Object { */ def getCiphers(): js.Array[String] = js.native + def getCurves(): js.Array[String] = js.native + + def getDiffieHellman(groupName: String): DiffieHellmanGroup = js.native + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def getFips(): Boolean = js.native + + def getHashes(): js.Array[String] = js.native + + def pbkdf2(password: String | BufferLike, + salt: String | BufferLike, + iterations: Int, + keylen: Int, + digest: String, + callback: Callback1[Buffer]): Buffer = js.native + /** * Provides a synchronous Password-Based Key Derivation Function 2 (PBKDF2) implementation. A selected HMAC digest * algorithm specified by digest is applied to derive a key of the requested byte length (keylen) from the password, @@ -138,8 +199,100 @@ trait Crypto extends js.Object { * * (Doc source: https://nodejs.org/api/crypto.html#crypto_crypto_pbkdf2sync_password_salt_iterations_keylen_digest) */ - def pbkdf2Sync(password: String, salt: String, iterations: Int, keylen: Int, digest: String): Buffer = js.native + def pbkdf2Sync(password: String | BufferLike, + salt: String | BufferLike, + iterations: Int, + keylen: Int, + digest: String): Buffer = js.native + + def privateDecrypt(privateKey: String | Buffer, buffer: BufferLike): Buffer = js.native + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12) + def privateDecrypt(privateKey: KeyObject, buffer: BufferLike): Buffer = js.native + + def privateEncrypt(privateKey: String | Buffer, buffer: BufferLike): Buffer = js.native + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12) + def privateEncrypt(privateKey: KeyObject, buffer: BufferLike): Buffer = js.native + + def publicDecrypt(key: String | Buffer, buffer: BufferLike): Buffer = js.native + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12) + def publicDecrypt(key: KeyObject, buffer: BufferLike): Buffer = js.native + def publicEncrypt(key: String | Buffer, buffer: BufferLike): Buffer = js.native + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12) + def publicEncrypt(key: KeyObject, buffer: BufferLike): Buffer = js.native + + def randomBytes(size: Int): Buffer = js.native + def randomBytes(size: Int, callback: Callback1[Buffer]): Unit = js.native + + def randomFillSync(buffer: Buffer, offset: Int, size: Int): Buffer = js.native + def randomFillSync(buffer: Buffer, offset: Int): Buffer = js.native + def randomFillSync(buffer: Buffer): Buffer = js.native + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def randomFillSync(buffer: scala.scalajs.js.typedarray.DataView, + offset: Int, + size: Int): scala.scalajs.js.typedarray.DataView = js.native + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def randomFillSync(buffer: scala.scalajs.js.typedarray.DataView, offset: Int): scala.scalajs.js.typedarray.DataView = + js.native + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def randomFillSync(buffer: scala.scalajs.js.typedarray.DataView): scala.scalajs.js.typedarray.DataView = js.native + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def randomFillSync[T <: scala.scalajs.js.typedarray.TypedArray[_, T]](buffer: T, + offset: Int = js.native, + size: Int = js.native): T = js.native + + def randomFill(buffer: Buffer, offset: Int, size: Int, callback: Callback1[Buffer]): Buffer = js.native + def randomFill(buffer: Buffer, offset: Int, callback: Callback1[Buffer]): Buffer = js.native + def randomFill(buffer: Buffer, callback: Callback1[Buffer]): Buffer = js.native + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def randomFill(buffer: scala.scalajs.js.typedarray.DataView, + offset: Int, + size: Int, + callback: Callback1[scala.scalajs.js.typedarray.DataView]): scala.scalajs.js.typedarray.DataView = + js.native + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def randomFill(buffer: scala.scalajs.js.typedarray.DataView, + offset: Int, + callback: Callback1[scala.scalajs.js.typedarray.DataView]): scala.scalajs.js.typedarray.DataView = + js.native + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def randomFill(buffer: scala.scalajs.js.typedarray.DataView, + callback: Callback1[scala.scalajs.js.typedarray.DataView]): scala.scalajs.js.typedarray.DataView = + js.native + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def randomFill[T <: scala.scalajs.js.typedarray.TypedArray[_, T]](buffer: T, + offset: Int = js.native, + size: Int = js.native, + callback: Callback1[T]): T = js.native + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def scrypt(password: String | BufferLike, + salt: String | BufferLike, + keylen: Int, + options: ScryptOptions = js.native, + callback: Callback1[Buffer]): Unit = js.native + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def scryptSync(password: String | BufferLike, + salt: String | BufferLike, + keylen: Int, + options: ScryptOptions = js.native): Buffer = js.native + + def setEngine(engine: String, fips: Int = js.native): Unit = js.native + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) + def setFips(enable: Boolean): Unit = js.native + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12) + def sign(algorithm: String = js.native, data: BufferLike, key: String | Buffer | KeyObject): Buffer = js.native + + def timingSafeEqual(a: BufferLike, b: BufferLike): Boolean = js.native + + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12) + def verify(algorithm: String = js.native, data: BufferLike, key: String | Buffer | KeyObject): Boolean = js.native } /** @@ -147,4 +300,128 @@ trait Crypto extends js.Object { */ @js.native @JSImport("crypto", JSImport.Namespace) -object Crypto extends Crypto +object Crypto extends Crypto { + type Certificate = io.scalajs.nodejs.crypto.Certificate + type Cipher = io.scalajs.nodejs.crypto.Cipher + type Decipher = io.scalajs.nodejs.crypto.Decipher + type DiffieHellman = io.scalajs.nodejs.crypto.DiffieHellman + type ECDH = io.scalajs.nodejs.crypto.ECDH + type Hash = io.scalajs.nodejs.crypto.Hash + type Hmac = io.scalajs.nodejs.crypto.Hmac + type Sign = io.scalajs.nodejs.crypto.Sign + type Verify = io.scalajs.nodejs.crypto.Verify + + val constants: Constants.type = js.native +} + +@js.native +@JSImport("crypto", "constants") +object Constants extends js.Object { + val SSL_OP_ALL: Int = js.native + val SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION: Int = js.native + val SSL_OP_CIPHER_SERVER_PREFERENCE: Int = js.native + val SSL_OP_CISCO_ANYCONNECT: Int = js.native + val SSL_OP_COOKIE_EXCHANGE: Int = js.native + val SSL_OP_CRYPTOPRO_TLSEXT_BUG: Int = js.native + val SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS: Int = js.native + val SSL_OP_EPHEMERAL_RSA: Int = js.native + val SSL_OP_LEGACY_SERVER_CONNECT: Int = js.native + val SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER: Int = js.native + val SSL_OP_MICROSOFT_SESS_ID_BUG: Int = js.native + val SSL_OP_MSIE_SSLV2_RSA_PADDING: Int = js.native + val SSL_OP_NETSCAPE_CA_DN_BUG: Int = js.native + val SSL_OP_NETSCAPE_CHALLENGE_BUG: Int = js.native + val SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG: Int = js.native + val SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG: Int = js.native + val SSL_OP_NO_COMPRESSION: Int = js.native + val SSL_OP_NO_QUERY_MTU: Int = js.native + val SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION: Int = js.native + val SSL_OP_NO_SSLv2: Int = js.native + val SSL_OP_NO_SSLv3: Int = js.native + val SSL_OP_NO_TICKET: Int = js.native + val SSL_OP_NO_TLSv1: Int = js.native + val SSL_OP_NO_TLSv1_1: Int = js.native + val SSL_OP_NO_TLSv1_2: Int = js.native + val SSL_OP_PKCS1_CHECK_1: Int = js.native + val SSL_OP_PKCS1_CHECK_2: Int = js.native + val SSL_OP_SINGLE_DH_USE: Int = js.native + val SSL_OP_SINGLE_ECDH_USE: Int = js.native + val SSL_OP_SSLEAY_080_CLIENT_DH_BUG: Int = js.native + val SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG: Int = js.native + val SSL_OP_TLS_BLOCK_PADDING_BUG: Int = js.native + val SSL_OP_TLS_D5_BUG: Int = js.native + val SSL_OP_TLS_ROLLBACK_BUG: Int = js.native + + val ENGINE_METHOD_RSA: Int = js.native + val ENGINE_METHOD_DSA: Int = js.native + val ENGINE_METHOD_DH: Int = js.native + val ENGINE_METHOD_RAND: Int = js.native + val ENGINE_METHOD_EC: Int = js.native + val ENGINE_METHOD_CIPHERS: Int = js.native + val ENGINE_METHOD_DIGESTS: Int = js.native + val ENGINE_METHOD_PKEY_METHS: Int = js.native + val ENGINE_METHOD_PKEY_ASN1_METHS: Int = js.native + val ENGINE_METHOD_ALL: Int = js.native + val ENGINE_METHOD_NONE: Int = js.native + + val DH_CHECK_P_NOT_SAFE_PRIME: Int = js.native + val DH_CHECK_P_NOT_PRIME: Int = js.native + val DH_UNABLE_TO_CHECK_GENERATOR: Int = js.native + val DH_NOT_SUITABLE_GENERATOR: Int = js.native + val ALPN_ENABLED: Int = js.native + val RSA_PKCS1_PADDING: Int = js.native + val RSA_SSLV23_PADDING: Int = js.native + val RSA_NO_PADDING: Int = js.native + val RSA_PKCS1_OAEP_PADDING: Int = js.native + val RSA_X931_PADDING: Int = js.native + val RSA_PKCS1_PSS_PADDING: Int = js.native + val RSA_PSS_SALTLEN_DIGEST: Int = js.native + val RSA_PSS_SALTLEN_MAX_SIGN: Int = js.native + val RSA_PSS_SALTLEN_AUTO: Int = js.native + + val POINT_CONVERSION_COMPRESSED: Int = js.native + val POINT_CONVERSION_UNCOMPRESSED: Int = js.native + val POINT_CONVERSION_HYBRID: Int = js.native + + val defaultCoreCipherList: String = js.native + val defaultCipherList: String = js.native + +} + +class CreatePrivateKeyOptions( + val key: String | Buffer, + val format: js.UndefOr[String] = js.undefined, + val `type`: js.UndefOr[String] = js.undefined, + val passphrase: js.UndefOr[String | Buffer] = js.undefined +) extends js.Object + +class CreatePublicKeyOptions( + val key: String | Buffer, + val format: js.UndefOr[String] = js.undefined, + val `type`: js.UndefOr[String] = js.undefined +) extends js.Object + +class GenerateKeyPairOptions( + val modulusLength: Int, + val publicExponent: js.UndefOr[Int] = js.undefined, + val divisorLength: js.UndefOr[Int] = js.undefined, + val namedCurve: js.UndefOr[String] = js.undefined, + val publicKeyEncoding: js.UndefOr[KeyObjectExportOptions] = js.undefined, + val privateKeyEncoding: js.UndefOr[KeyObjectExportOptions] = js.undefined +) extends js.Object + +class ScryptOptions( + val cost: js.UndefOr[Int] = js.undefined, + val blockSize: js.UndefOr[Int] = js.undefined, + val parallelization: js.UndefOr[Int] = js.undefined, + val N: js.UndefOr[Int] = js.undefined, + val r: js.UndefOr[Int] = js.undefined, + val p: js.UndefOr[Int] = js.undefined, + val maxmem: js.UndefOr[Int] = js.undefined +) extends js.Object + +@js.native +trait KeyPair extends js.Object { + val publicKey: String | Buffer | KeyObject + val privateKey: String | Buffer | KeyObject +} diff --git a/app/current/src/main/scala/io/scalajs/nodejs/crypto/Decipher.scala b/app/current/src/main/scala/io/scalajs/nodejs/crypto/Decipher.scala index 95eecc2b8..335963fc6 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/crypto/Decipher.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/crypto/Decipher.scala @@ -1,7 +1,7 @@ package io.scalajs.nodejs.crypto import io.scalajs.nodejs.buffer.Buffer -import io.scalajs.nodejs.stream.IDuplex +import io.scalajs.nodejs.stream.Transform import scala.scalajs.js @@ -16,7 +16,7 @@ import scala.scalajs.js * Decipher objects are not to be created directly using the new keyword. */ @js.native -trait Decipher extends IDuplex { +sealed trait Decipher extends Transform { /** * Returns any remaining deciphered contents. If output_encoding parameter is one of 'binary', 'base64' or 'hex', @@ -26,7 +26,7 @@ trait Decipher extends IDuplex { * Attempts to call decipher.final() more than once will result in an error being thrown. * @example decipher.final([output_encoding]) */ - def `final`(output_encoding: String): String = js.native + def `final`(outputEncoding: String): String = js.native /** * Returns any remaining deciphered contents. If output_encoding parameter is one of 'binary', 'base64' or 'hex', @@ -43,7 +43,7 @@ trait Decipher extends IDuplex { * the value used for the additional authenticated data (AAD) input parameter. * @example decipher.setAAD(buffer) */ - def setAAD(buffer: Buffer): Unit = js.native + def setAAD(buffer: BufferLike, options: SetAADOptions): Decipher = js.native /** * When using an authenticated encryption mode (only GCM is currently supported), the decipher.setAuthTag() method @@ -51,7 +51,7 @@ trait Decipher extends IDuplex { * with, decipher.final() with throw, indicating that the cipher text should be discarded due to failed authentication. * @example decipher.setAuthTag(buffer) */ - def setAuthTag(buffer: Buffer): Unit = js.native + def setAuthTag(buffer: BufferLike): Decipher = js.native /** * When data has been encrypted without standard block padding, calling decipher.setAutoPadding(false) will disable @@ -61,7 +61,7 @@ trait Decipher extends IDuplex { * The decipher.setAutoPadding() method must be called before decipher.update(). * @example decipher.setAutoPadding(auto_padding=true) */ - def setAutoPadding(auto_padding: Boolean = true): Unit = js.native + def setAutoPadding(auto_padding: Boolean = true): Decipher = js.native /** * Updates the decipher with data. If the input_encoding argument is given, it's value must be one of 'binary', @@ -76,21 +76,8 @@ trait Decipher extends IDuplex { * Calling decipher.update() after decipher.final() will result in an error being thrown. * @example decipher.update(data[, input_encoding][, output_encoding]) */ - def update(data: String, input_encoding: String, output_encoding: String = null): String = js.native - - /** - * Updates the decipher with data. If the input_encoding argument is given, it's value must be one of 'binary', - * 'base64', or 'hex' and the data argument is a string using the specified encoding. If the input_encoding - * argument is not given, data must be a Buffer. If data is a Buffer then input_encoding is ignored. - * - * The output_encoding specifies the output format of the enciphered data, and can be 'binary', 'ascii' or 'utf8'. - * If the output_encoding is specified, a string using the specified encoding is returned. If no output_encoding - * is provided, a Buffer is returned. - * - * The decipher.update() method can be called multiple times with new data until decipher.final() is called. - * Calling decipher.update() after decipher.final() will result in an error being thrown. - * @example decipher.update(data[, input_encoding][, output_encoding]) - */ - def update(data: Buffer): Buffer = js.native + def update(data: String, inputEncoding: String, outputEncoding: String): String = js.native + def update(data: String, inputEncoding: String): Buffer = js.native + def update(data: BufferLike): Buffer = js.native } diff --git a/app/current/src/main/scala/io/scalajs/nodejs/crypto/DiffieHellman.scala b/app/current/src/main/scala/io/scalajs/nodejs/crypto/DiffieHellman.scala new file mode 100644 index 000000000..063962a05 --- /dev/null +++ b/app/current/src/main/scala/io/scalajs/nodejs/crypto/DiffieHellman.scala @@ -0,0 +1,36 @@ +package io.scalajs.nodejs.crypto + +import io.scalajs.nodejs.buffer.Buffer + +import scala.scalajs.js + +@js.native +trait DiffieHellman extends js.Object { + def computeSecret(otherPublicKey: String, inputEncoding: String, outputEncoding: String): String = js.native + def computeSecret(otherPublicKey: String, inputEncoding: String): Buffer = js.native + def computeSecret(otherPublicKey: BufferLike, inputEncoding: Null, outputEncoding: String): String = js.native + def computeSecret(otherPublicKey: BufferLike): Buffer = js.native + + def generateKeys(): Buffer = js.native + def generateKeys(encoding: String): String = js.native + + def getGenerator(): Buffer = js.native + def getGenerator(encoding: String): String = js.native + + def getPrime(): Buffer = js.native + def getPrime(encoding: String): String = js.native + + def getPrivateKey(): Buffer = js.native + def getPrivateKey(encoding: String): String = js.native + + def getPublicKey(): Buffer = js.native + def getPublicKey(encoding: String): String = js.native + + def setPrivateKey(privateKey: String, encoding: String): DiffieHellman = js.native + def setPrivateKey(privateKey: BufferLike): DiffieHellman = js.native + + def setPublicKey(privateKey: String, encoding: String): DiffieHellman = js.native + def setPublicKey(privateKey: BufferLike): DiffieHellman = js.native + + val verifyError: Int = js.native +} diff --git a/app/current/src/main/scala/io/scalajs/nodejs/crypto/DiffieHellmanGroup.scala b/app/current/src/main/scala/io/scalajs/nodejs/crypto/DiffieHellmanGroup.scala new file mode 100644 index 000000000..da3ee1f75 --- /dev/null +++ b/app/current/src/main/scala/io/scalajs/nodejs/crypto/DiffieHellmanGroup.scala @@ -0,0 +1,37 @@ +package io.scalajs.nodejs.crypto + +import io.scalajs.nodejs.buffer.Buffer + +import scala.scalajs.js + +// NOT inherit DiffieHellman +@js.native +trait DiffieHellmanGroup extends js.Object { + def computeSecret(otherPublicKey: String, inputEncoding: String, outputEncoding: String): String = js.native + def computeSecret(otherPublicKey: String, inputEncoding: String): Buffer = js.native + def computeSecret(otherPublicKey: BufferLike, inputEncoding: Null, outputEncoding: String): String = js.native + def computeSecret(otherPublicKey: BufferLike): Buffer = js.native + + def generateKeys(): Buffer = js.native + def generateKeys(encoding: String): String = js.native + + def getGenerator(): Buffer = js.native + def getGenerator(encoding: String): String = js.native + + def getPrime(): Buffer = js.native + def getPrime(encoding: String): String = js.native + + def getPrivateKey(): Buffer = js.native + def getPrivateKey(encoding: String): String = js.native + + def getPublicKey(): Buffer = js.native + def getPublicKey(encoding: String): String = js.native + + def setPrivateKey(privateKey: String, encoding: String): DiffieHellmanGroup = js.native + def setPrivateKey(privateKey: BufferLike): DiffieHellmanGroup = js.native + + def setPublicKey(privateKey: String, encoding: String): DiffieHellmanGroup = js.native + def setPublicKey(privateKey: BufferLike): DiffieHellmanGroup = js.native + + val verifyError: Int = js.native +} diff --git a/app/current/src/main/scala/io/scalajs/nodejs/crypto/ECDH.scala b/app/current/src/main/scala/io/scalajs/nodejs/crypto/ECDH.scala new file mode 100644 index 000000000..c9d9da8b5 --- /dev/null +++ b/app/current/src/main/scala/io/scalajs/nodejs/crypto/ECDH.scala @@ -0,0 +1,47 @@ +package io.scalajs.nodejs.crypto + +import com.thoughtworks.enableMembersIf +import io.scalajs.nodejs.buffer.Buffer + +import scala.scalajs.js +import scala.scalajs.js.annotation.JSImport + +// NOT inherit DiffieHellman +@js.native +trait ECDH extends js.Object { + def computeSecret(otherPublicKey: String, inputEncoding: String, outputEncoding: String): String = js.native + def computeSecret(otherPublicKey: String, inputEncoding: String): Buffer = js.native + def computeSecret(otherPublicKey: BufferLike, inputEncoding: Null, outputEncoding: String): String = js.native + def computeSecret(otherPublicKey: BufferLike): Buffer = js.native + + def generateKeys(): Buffer = js.native + def generateKeys(encoding: Null, format: String): Buffer = js.native + def generateKeys(encoding: String, format: String): String = js.native + + def getPrivateKey(): Buffer = js.native + def getPrivateKey(encoding: String): String = js.native + + def getPublicKey(): Buffer = js.native + def getPublicKey(encoding: Null, format: String): Buffer = js.native + def getPublicKey(encoding: String): String = js.native + def getPublicKey(encoding: String, format: String): String = js.native + + def setPrivateKey(privateKey: String, encoding: String): ECDH = js.native + def setPrivateKey(privateKey: BufferLike): ECDH = js.native +} + +@js.native +@enableMembersIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs10) +@JSImport("crypto", "ECDH") +object ECDH extends js.Object { + def convertKey(key: String, curve: String, inputEncoding: String, outputEncoding: String, format: String): String = + js.native + def convertKey(key: BufferLike, curve: String, inputEncoding: Null, outputEncoding: String, format: String): String = + js.native + def convertKey(key: String, curve: String, inputEncoding: String, outputEncoding: String): String = js.native + def convertKey(key: BufferLike, curve: String, inputEncoding: Null, outputEncoding: String): String = js.native + def convertKey(key: String, curve: String, inputEncoding: String): Buffer = js.native + def convertKey(key: BufferLike, curve: String, inputEncoding: Null): Buffer = js.native + def convertKey(key: BufferLike, curve: String): Buffer = js.native + def convertKey(key: BufferLike): Buffer = js.native +} diff --git a/app/current/src/main/scala/io/scalajs/nodejs/crypto/Hash.scala b/app/current/src/main/scala/io/scalajs/nodejs/crypto/Hash.scala index 127315141..be2a28139 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/crypto/Hash.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/crypto/Hash.scala @@ -1,7 +1,7 @@ package io.scalajs.nodejs.crypto import io.scalajs.nodejs.buffer.Buffer -import io.scalajs.nodejs.stream.IDuplex +import io.scalajs.nodejs.stream.{Transform, TransformOptions} import scala.scalajs.js @@ -15,7 +15,7 @@ import scala.scalajs.js * the new keyword. */ @js.native -trait Hash extends IDuplex { +sealed trait Hash extends Transform { /** * Calculates the digest of all of the data passed to be hashed (using the hash.update() method). The encoding can @@ -45,18 +45,15 @@ trait Hash extends IDuplex { * * This can be called many times with new data as it is streamed. * @param data the given [[String data]] - * @param input_encoding the given encoding (e.g. 'utf8', 'ascii' or 'binary') + * @param inputEncoding the given encoding (e.g. 'utf8', 'ascii' or 'binary') */ - def update(data: String, input_encoding: String = null): Unit = js.native - - /** - * Updates the hash content with the given data, the encoding of which is given in input_encoding and can be 'utf8', - * 'ascii' or 'binary'. If encoding is not provided, and the data is a string, an encoding of 'utf8' is enforced. - * If data is a Buffer then input_encoding is ignored. - * - * This can be called many times with new data as it is streamed. - * @param data the given [[Buffer data]] - */ - def update(data: Buffer): Unit = js.native + def update(data: String, inputEncoding: String): Hash = js.native + def update(data: String): Hash = js.native + def update(data: BufferLike): Hash = js.native } + +class CreateHashOptions(override val transform: js.UndefOr[js.Function] = js.undefined, + override val flush: js.UndefOr[js.Function] = js.undefined, + val outputLength: js.UndefOr[Int] = js.undefined) + extends TransformOptions(transform, flush) diff --git a/app/current/src/main/scala/io/scalajs/nodejs/crypto/Hmac.scala b/app/current/src/main/scala/io/scalajs/nodejs/crypto/Hmac.scala index 08c265cfe..18ef9f2ee 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/crypto/Hmac.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/crypto/Hmac.scala @@ -1,7 +1,7 @@ package io.scalajs.nodejs.crypto import io.scalajs.nodejs.buffer.Buffer -import io.scalajs.nodejs.stream.IDuplex +import io.scalajs.nodejs.stream.Transform import scala.scalajs.js @@ -16,7 +16,7 @@ import scala.scalajs.js * the new keyword. */ @js.native -trait Hmac extends IDuplex { +sealed trait Hmac extends Transform { /** * Calculates the HMAC digest of all of the data passed using hmac.update(). The encoding can be 'hex', 'binary' @@ -56,9 +56,9 @@ trait Hmac extends IDuplex { * * This can be called many times with new data as it is streamed. * @param data the given [[String data]] - * @param input_encoding the given encoding (e.g. 'utf8', 'ascii' or 'binary' + * @param inputEncoding the given encoding (e.g. 'utf8', 'ascii' or 'binary' */ - def update(data: String, input_encoding: String): Unit = js.native + def update(data: String, inputEncoding: String): Hmac = js.native /** * Updates the Hmac content with the given data, the encoding of which is given in input_encoding and can be 'utf8', @@ -68,6 +68,6 @@ trait Hmac extends IDuplex { * This can be called many times with new data as it is streamed. * @param data the given [[Buffer data]] */ - def update(data: Buffer): Unit = js.native + def update(data: BufferLike): Hmac = js.native } diff --git a/app/current/src/main/scala/io/scalajs/nodejs/crypto/KeyObject.scala b/app/current/src/main/scala/io/scalajs/nodejs/crypto/KeyObject.scala new file mode 100644 index 000000000..d6006a463 --- /dev/null +++ b/app/current/src/main/scala/io/scalajs/nodejs/crypto/KeyObject.scala @@ -0,0 +1,22 @@ +package io.scalajs.nodejs.crypto + +import io.scalajs.nodejs.buffer.Buffer + +import scala.scalajs.js +import scala.scalajs.js.| + +@js.native +sealed trait KeyObject extends js.Object { + def export(options: KeyObjectExportOptions): Buffer | String = js.native + def export(): Buffer = js.native + + val symmetricKeySize: js.UndefOr[Int] = js.native + val `type`: String = js.native +} + +class KeyObjectExportOptions( + val `type`: js.UndefOr[String] = js.undefined, + val format: js.UndefOr[String] = js.undefined, + val cipher: js.UndefOr[String] = js.undefined, + val passphrase: js.UndefOr[String | Buffer] = js.undefined +) extends js.Object diff --git a/app/current/src/main/scala/io/scalajs/nodejs/crypto/Sign.scala b/app/current/src/main/scala/io/scalajs/nodejs/crypto/Sign.scala index b87dcf90e..5b02759c8 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/crypto/Sign.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/crypto/Sign.scala @@ -1,9 +1,11 @@ package io.scalajs.nodejs.crypto +import com.thoughtworks.enableIf import io.scalajs.nodejs.buffer.Buffer -import io.scalajs.nodejs.stream.IDuplex +import io.scalajs.nodejs.stream.WritableClass import scala.scalajs.js +import scala.scalajs.js.| /** * The Sign Class is a utility for generating signatures. It can be used in one of two ways: @@ -16,16 +18,14 @@ import scala.scalajs.js * the new keyword. */ @js.native -trait Sign extends IDuplex { - - def sign(private_key: String): String = js.native - - def sign(private_key: String, output_format: String): String = js.native - - def update(data: String, input_encoding: String): Unit = js.native - - def update(data: String): Unit = js.native - - def update(data: Buffer): Unit = js.native - +sealed trait Sign extends WritableClass { + def sign(privateKey: String | Buffer): Buffer = js.native + def sign(privateKey: String | Buffer, outputEncoding: String): String = js.native + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12) + def sign(privateKey: KeyObject): Buffer = js.native + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12) + def sign(privateKey: KeyObject, outputEncoding: String): String = js.native + + def update(data: String, inputEncoding: String = js.native): Unit = js.native + def update(data: BufferLike): Unit = js.native } diff --git a/app/current/src/main/scala/io/scalajs/nodejs/crypto/Verify.scala b/app/current/src/main/scala/io/scalajs/nodejs/crypto/Verify.scala index 6a66e7a99..867099283 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/crypto/Verify.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/crypto/Verify.scala @@ -1,9 +1,11 @@ package io.scalajs.nodejs.crypto +import com.thoughtworks.enableIf import io.scalajs.nodejs.buffer.Buffer -import io.scalajs.nodejs.stream.IDuplex +import io.scalajs.nodejs.stream.WritableClass import scala.scalajs.js +import scala.scalajs.js.| /** * The Verify class is a utility for verifying signatures. It can be used in one of two ways: @@ -15,50 +17,37 @@ import scala.scalajs.js * the new keyword. */ @js.native -trait Verify extends IDuplex { +trait Verify extends WritableClass { /** * Updates the Verify content with the given data. * This can be called many times with new data as it is streamed. * @param data with the given data - * @param input_encoding the encoding of which is given in input_encoding and can be + * @param inputEncoding the encoding of which is given in input_encoding and can be * 'utf8', 'ascii' or 'binary'. If encoding is not provided, and the data is a string, an * encoding of 'utf8' is enforced. If data is a Buffer then input_encoding is ignored. */ - def update(data: String, input_encoding: String): Unit = js.native - - /** - * Updates the Verify content with the given data. - * This can be called many times with new data as it is streamed. - * @param data with the given data - */ - def update(data: Buffer): Unit = js.native + def update(data: String, inputEncoding: String = js.native): Unit = js.native + def update(data: BufferLike): Unit = js.native /** * Verifies the provided data using the given object and signature. * * The verifier object can not be used again after verify.verify() has been called. Multiple calls to verify.verify() * will result in an error being thrown. - * @param `object` The object argument is a string containing a PEM encoded object, which can be one an + * @param obj The object argument is a string containing a PEM encoded object, which can be one an * RSA public key, a DSA public key, or an X.509 certificate. * @param signature The signature argument is the previously calculated signature for the data, in the * signature_format which can be 'binary', 'hex' or 'base64'. - * @param signature_format If a signature_format is specified, the signature is expected to be a string; otherwise + * @param signatureEncoding If a signatureEncoding is specified, the signature is expected to be a string; otherwise * signature is expected to be a Buffer. * @return true or false depending on the validity of the signature for the data and public key. */ - def verify(`object`: String, signature: String, signature_format: String): Boolean = js.native - - /** - * Verifies the provided data using the given object and signature. - * - * The verifier object can not be used again after verify.verify() has been called. Multiple calls to verify.verify() - * will result in an error being thrown. - * @param `object` The object argument is a string containing a PEM encoded object, which can be one an - * RSA public key, a DSA public key, or an X.509 certificate. - * @param signature The signature argument is the previously calculated signature for the data. - * @return true or false depending on the validity of the signature for the data and public key. - */ - def verify(`object`: String, signature: Buffer): Boolean = js.native + def verify(obj: String | Buffer, signature: String, signatureEncoding: String): Boolean = js.native + def verify(obj: String | Buffer, signature: BufferLike): Boolean = js.native + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12) + def verify(obj: KeyObject, signature: String, signatureEncoding: String): Boolean = js.native + @enableIf(io.scalajs.nodejs.CompilerSwitches.gteNodeJs12) + def verify(obj: KeyObject, signature: BufferLike): Boolean = js.native } diff --git a/app/current/src/main/scala/io/scalajs/nodejs/crypto/package.scala b/app/current/src/main/scala/io/scalajs/nodejs/crypto/package.scala new file mode 100644 index 000000000..5163d3000 --- /dev/null +++ b/app/current/src/main/scala/io/scalajs/nodejs/crypto/package.scala @@ -0,0 +1,19 @@ +package io.scalajs.nodejs + +import io.scalajs.nodejs.{Error => NodeError} + +import scala.scalajs.js +import scala.scalajs.js.typedarray.{DataView, TypedArray} +import scala.scalajs.js.| + +package object crypto { + + type BufferLike = TypedArray[_, _] | DataView + type Callback1[T] = js.Function2[NodeError, T, Any] + type Callback2[T1, T2] = js.Function3[NodeError, T1, T2, Any] + + implicit final class CryptoModuleEnrichment(private val crypto: Crypto.type) extends AnyVal { + @inline def Certificate = io.scalajs.nodejs.crypto.Certificate + } + +} diff --git a/app/current/src/main/scala/io/scalajs/nodejs/stream/Transform.scala b/app/current/src/main/scala/io/scalajs/nodejs/stream/Transform.scala index ee17882bc..f6effaf0b 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/stream/Transform.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/stream/Transform.scala @@ -9,10 +9,10 @@ import scala.scalajs.js.annotation.JSImport */ @js.native @JSImport("stream", "Transform") -class Transform extends IDuplex +class Transform(options: TransformOptions = js.native) extends IDuplex { + def destroy(error: io.scalajs.nodejs.Error = js.native): Unit = js.native +} -/** - * Transform Interface - */ -@js.native -trait ITransform extends IDuplex +class TransformOptions(val transform: js.UndefOr[js.Function] = js.undefined, + val flush: js.UndefOr[js.Function] = js.undefined) + extends js.Object diff --git a/app/current/src/main/scala/io/scalajs/nodejs/stream/Writable.scala b/app/current/src/main/scala/io/scalajs/nodejs/stream/Writable.scala index b11239059..d6f9c6313 100644 --- a/app/current/src/main/scala/io/scalajs/nodejs/stream/Writable.scala +++ b/app/current/src/main/scala/io/scalajs/nodejs/stream/Writable.scala @@ -7,9 +7,17 @@ import io.scalajs.util.PromiseHelper._ import scala.concurrent.Future import scala.scalajs.js - +import scala.scalajs.js.annotation.JSImport import scala.scalajs.js.| +/** + * The Writable stream interface is an abstraction for a destination that you are writing data to. + */ +@js.native +@JSImport("stream", "Writable") +class WritableClass(options: WritableOptions = js.native) extends Writable + +// TODO: Merge WritableClass and trait? /** * The Writable stream interface is an abstraction for a destination that you are writing data to. */ @@ -231,3 +239,15 @@ object Writable { * @param encoding the data's optional encoding */ class Chunk(val chunk: Buffer | String, val encoding: js.UndefOr[String] = js.undefined) extends js.Object + +class WritableOptions(val highWaterMark: js.UndefOr[Int] = js.undefined, + val decodeStrings: js.UndefOr[Boolean] = js.undefined, + val defaultEncoding: js.UndefOr[String] = js.undefined, + val objectMode: js.UndefOr[Boolean] = js.undefined, + val emitClose: js.UndefOr[Boolean] = js.undefined, + val write: js.UndefOr[js.Function] = js.undefined, + val writev: js.UndefOr[js.Function] = js.undefined, + val destroy: js.UndefOr[js.Function] = js.undefined, + val `final`: js.UndefOr[js.Function] = js.undefined, + val autoDestroy: js.UndefOr[Boolean] = js.undefined) + extends js.Object diff --git a/app/nodejs-v10/src/test/scala/nodejs/crypto/CertificateTest.scala b/app/nodejs-v10/src/test/scala/nodejs/crypto/CertificateTest.scala new file mode 100644 index 000000000..e4c63af67 --- /dev/null +++ b/app/nodejs-v10/src/test/scala/nodejs/crypto/CertificateTest.scala @@ -0,0 +1,29 @@ +package io.scalajs.nodejs.crypto + +import io.scalajs.nodejs.buffer.Buffer +import org.scalatest.{ FunSpec, MustMatchers } + +class CertificateTest extends FunSpec with MustMatchers { + val spkacExample = "MIIBXjCByDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3L0IfUijj7+A8CPC8EmhcdNoe5fUAog7OrBdhn7EkxFButUp40P7+LiYiygYG1TmoI/a5EgsLU3s9twEz3hmgY9mYIqb/rb+SF8qlD/K6KVyUORC7Wlz1Df4L8O3DuRGzx6/+3jIW6cPBpfgH1sVuYS1vDBsP/gMMIxwTsKJ4P0CAwEAARYkYzBkZjFlYjctMTU0NC00MWVkLWFmN2EtZDRkYjBkNDc5ZjZmMA0GCSqGSIb3DQEBBAUAA4GBALEiapUjaIPs5uEdvCP0gFK2qofo+4GpeK1A43mu28lirYPAvCWsmYvKIZIT9TxvzmQIxAfxobf70aSNlSm6MJJKmvurAK+Bpn6ZUKQZ6A1m927LvctVSYJuUi+WVmr0fGE/OfdQ+BqSm/eQ3jnm3fBPVx1uwLPgjC5g4EvGMh8M" + + describe("Certificate object") { + it("exportChallenge") { + assert(Certificate.exportChallenge(spkacExample).toString("utf8") === "c0df1eb7-1544-41ed-af7a-d4db0d479f6f") + } + + it("exportPublicKey") { + assert(Certificate.exportPublicKey(spkacExample).toString("utf8") === + """-----BEGIN PUBLIC KEY----- + |MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcvQh9SKOPv4DwI8LwSaFx02h7 + |l9QCiDs6sF2GfsSTEUG61SnjQ/v4uJiLKBgbVOagj9rkSCwtTez23ATPeGaBj2Zg + |ipv+tv5IXyqUP8ropXJQ5ELtaXPUN/gvw7cO5EbPHr/7eMhbpw8Gl+AfWxW5hLW8 + |MGw/+AwwjHBOwong/QIDAQAB + |-----END PUBLIC KEY----- + |""".stripMargin) + } + + it("verifySpkac") { + assert(Crypto.Certificate.verifySpkac(Buffer.from("foo")) === false) + } + } +} diff --git a/app/nodejs-v10/src/test/scala/nodejs/crypto/CryptoTest.scala b/app/nodejs-v10/src/test/scala/nodejs/crypto/CryptoTest.scala new file mode 100644 index 000000000..f249711c9 --- /dev/null +++ b/app/nodejs-v10/src/test/scala/nodejs/crypto/CryptoTest.scala @@ -0,0 +1,40 @@ +package io.scalajs.nodejs.crypto + +import io.scalajs.nodejs.buffer.Buffer +import org.scalatest.{ FunSpec, MustMatchers } + +import scala.scalajs.js +import scala.scalajs.js.typedarray.{ DataView, _ } + +class CryptoTest extends FunSpec with MustMatchers { + val spkacExample = "MIIBXjCByDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3L0IfUijj7+A8CPC8EmhcdNoe5fUAog7OrBdhn7EkxFButUp40P7+LiYiygYG1TmoI/a5EgsLU3s9twEz3hmgY9mYIqb/rb+SF8qlD/K6KVyUORC7Wlz1Df4L8O3DuRGzx6/+3jIW6cPBpfgH1sVuYS1vDBsP/gMMIxwTsKJ4P0CAwEAARYkYzBkZjFlYjctMTU0NC00MWVkLWFmN2EtZDRkYjBkNDc5ZjZmMA0GCSqGSIb3DQEBBAUAA4GBALEiapUjaIPs5uEdvCP0gFK2qofo+4GpeK1A43mu28lirYPAvCWsmYvKIZIT9TxvzmQIxAfxobf70aSNlSm6MJJKmvurAK+Bpn6ZUKQZ6A1m927LvctVSYJuUi+WVmr0fGE/OfdQ+BqSm/eQ3jnm3fBPVx1uwLPgjC5g4EvGMh8M" + + describe("Crypto object") { + describe("randomFillSync") { + it("should accept Buffer and return value in type as received") { + val buffer = Buffer.alloc(5) + val result1 = Crypto.randomFillSync(buffer) + assert(result1.length === 5) + assert(result1.isInstanceOf[Buffer]) + } + + it("should accept DataView and return value in type as received") { + val view = new DataView(new ArrayBuffer(4)) + val result1 = Crypto.randomFillSync(view) + assert(result1.isInstanceOf[DataView]) + } + + it("should accept any TypedArray and return value in type as received") { + val array1 = Uint8Array.from(js.Array[Short](1,2,3)) + val result1 = Crypto.randomFillSync(array1) + assert(result1.length === 3) + assert(result1.isInstanceOf[Uint8Array]) + + val array2 = Uint16Array.from(js.Array[Int](1,2,3,4)) + val result2 = Crypto.randomFillSync(array2) + assert(result2.length === 4) + assert(result2.isInstanceOf[Uint16Array]) + } + } + } +} diff --git a/app/nodejs-v8/src/test/scala/nodejs/crypto/CertificateTest.scala b/app/nodejs-v8/src/test/scala/nodejs/crypto/CertificateTest.scala new file mode 100644 index 000000000..d339c2aef --- /dev/null +++ b/app/nodejs-v8/src/test/scala/nodejs/crypto/CertificateTest.scala @@ -0,0 +1,35 @@ +package io.scalajs.nodejs.crypto + +import io.scalajs.nodejs.buffer.Buffer +import org.scalatest.{FunSpec, MustMatchers} + +class CertificateTest extends FunSpec with MustMatchers { + val spkacExample = + "MIIBXjCByDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3L0IfUijj7+A8CPC8EmhcdNoe5fUAog7OrBdhn7EkxFButUp40P7+LiYiygYG1TmoI/a5EgsLU3s9twEz3hmgY9mYIqb/rb+SF8qlD/K6KVyUORC7Wlz1Df4L8O3DuRGzx6/+3jIW6cPBpfgH1sVuYS1vDBsP/gMMIxwTsKJ4P0CAwEAARYkYzBkZjFlYjctMTU0NC00MWVkLWFmN2EtZDRkYjBkNDc5ZjZmMA0GCSqGSIb3DQEBBAUAA4GBALEiapUjaIPs5uEdvCP0gFK2qofo+4GpeK1A43mu28lirYPAvCWsmYvKIZIT9TxvzmQIxAfxobf70aSNlSm6MJJKmvurAK+Bpn6ZUKQZ6A1m927LvctVSYJuUi+WVmr0fGE/OfdQ+BqSm/eQ3jnm3fBPVx1uwLPgjC5g4EvGMh8M" + + describe("Certificate class (Legacy)") { + val instance = new Certificate() + + it("exportChallenge") { + assert(instance.exportChallenge(spkacExample).toString("utf8") === "c0df1eb7-1544-41ed-af7a-d4db0d479f6f") + } + + it("exportPublicKey") { + assert( + instance.exportPublicKey(spkacExample).toString("utf8") === + """-----BEGIN PUBLIC KEY----- + |MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDcvQh9SKOPv4DwI8LwSaFx02h7 + |l9QCiDs6sF2GfsSTEUG61SnjQ/v4uJiLKBgbVOagj9rkSCwtTez23ATPeGaBj2Zg + |ipv+tv5IXyqUP8ropXJQ5ELtaXPUN/gvw7cO5EbPHr/7eMhbpw8Gl+AfWxW5hLW8 + |MGw/+AwwjHBOwong/QIDAQAB + |-----END PUBLIC KEY----- + |""".stripMargin + ) + } + + it("verifySpkac") { + assert(instance.verifySpkac(Buffer.from("foo")) === false) + } + } + +} diff --git a/app/nodejs-v8/src/test/scala/nodejs/crypto/CryptoTest.scala b/app/nodejs-v8/src/test/scala/nodejs/crypto/CryptoTest.scala index a45d79520..a8d492b03 100644 --- a/app/nodejs-v8/src/test/scala/nodejs/crypto/CryptoTest.scala +++ b/app/nodejs-v8/src/test/scala/nodejs/crypto/CryptoTest.scala @@ -53,4 +53,9 @@ class CryptoTest extends FunSpec with MustMatchers { } + describe("Crypto module") { + it("has constants") { + assert(Crypto.constants.ENGINE_METHOD_DSA === 2) + } + } }