Luca
02/07/2024, 7:15 AMwindow.crypto
on browser or node crypto
for node on the wasmJs target?
This works on for the js target. But in the wasmJs target I can only get it to work correctly for one at a time.
import org.khronos.webgl.Uint8Array
import org.khronos.webgl.get
import org.khronos.webgl.ArrayBufferView
external interface WebCrypto {
fun <T : ArrayBufferView> getRandomValues(array: T): T
}
// For node
@JsModule("crypto")
external val webcrypto: WebCrypto
// For browser
external object window {
val crypto: WebCrypto
}
actual class SecureRandom {
var crypto: WebCrypto? = null
init {
crypto =
try {
// browser
window.crypto
} catch (_: Throwable) {
null
}
if (crypto == null) {
try {
// node
crypto = webcrypto
} catch (_: Throwable) {
}
}
requireNotNull(crypto) { "Could not get crypto from window or node" }
}
actual fun nextBytes(bytes: ByteArray) {
val uint8bytes = Uint8Array(bytes.size)
crypto!!.getRandomValues(uint8bytes)
for (i in bytes.indices) {
bytes[i] = uint8bytes[i]
}
}
}
To get it to work for node I need to comment out:
crypto =
try {
// browser
window.crypto
} catch (_: Throwable) {
null
}
and respectively to get it to work for browser I need to comment out:
if (crypto == null) {
try {
// node
crypto = webcrypto
} catch (_: Throwable) {
}
}
Luca
02/07/2024, 7:18 AMwindow.crypto
part will throw:
ReferenceError: window is not defined
at jslibs.window_$external_object_getInstance
Luca
02/07/2024, 7:22 AMunsafeCast
doesn’t seem to let you do this unlike the unsafeCast
on the js target
fun Uint8Array.asByteArray(): ByteArray = this.unsafeCast<ByteArray>()
fun ByteArray.asUint8Array(): Uint8Array = this.unsafeCast<Uint8Array>()
Oleg Yukhnevich
02/07/2024, 7:27 AMcrypto
in a safe way for both browser and node you can take a look here: https://github.com/whyoleg/cryptography-kotlin/blob/d524143a0719e6926b0ae190977a73[…]raphy-random/src/wasmJsMain/kotlin/CryptographyRandom.wasmJs.kt
regarding conversion between JS arrays and Kotlin arrays in WASM - now you need to do a copy (like here: https://github.com/whyoleg/cryptography-kotlin/blob/d524143a0719e6926b0ae190977a73[…]raphy-random/src/wasmJsMain/kotlin/CryptographyRandom.wasmJs.kt)Luca
02/07/2024, 7:32 AMCalls to js(code) should be a single expression inside a top-level function body or a property initializer in Kotlin/Wasm
Luca
02/07/2024, 7:34 AMjs("…")
on the wasm targetOleg Yukhnevich
02/07/2024, 7:37 AMjs("...")
has a lot of restrictions (https://kotlinlang.org/docs/wasm-js-interop.html#kotlin-functions-with-javascript-code)
But at least this variant, that I've posted above works with Kotlin 1.9.20
By this variant I mean not only code inside js("...")
but also where it's placed:
// js(...) should be single declaration in a function, should not be an expression, just a statement
fun getCrypto(): Crypto {
js(
code = """
var isNodeJs = typeof process !== 'undefined' && process.versions != null && process.versions.node != null
if (isNodeJs) {
return (eval('require')('node:crypto').webcrypto);
} else {
return (window ? (window.crypto ? window.crypto : window.msCrypto) : self.crypto);
}
"""
)
}
Luca
02/07/2024, 7:41 AMfun getCrypto(): Crypto
out of my class and you’re right it does work!Luca
02/07/2024, 7:42 AMOleg Yukhnevich
02/07/2024, 7:42 AMLuca
02/07/2024, 7:45 AMOleg Yukhnevich
02/07/2024, 7:46 AMLuca
02/07/2024, 8:09 AMOleg Yukhnevich
02/07/2024, 8:19 AMdev
branch)
to try snapshot: https://github.com/whyoleg/cryptography-kotlin?tab=readme-ov-file#using-in-your-projects (under a drop-down)Luca
02/07/2024, 8:22 AM