Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experimental NodeJS Support #69

Merged
merged 4 commits into from
Nov 2, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
!src/**/build/
src/jsTest/generated
src/jsMain/generated
webpack.config.d/
20 changes: 17 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,21 @@ Sample data objects are provided in `SampleData`, with special thanks to Christi
## Usage (JS)

The build result of this library for JS is a module in UMD format, located under `build/distributions/hcert-kotlin.js`. This script runs in a web browser environment and can be used in the following way (see [demo.html](demo.html)).
In addition, we also (experimentally) support node as target environment (also based on a bundled UMD) by passing the `node` flag to gradle (see the [sample node project](node-demo)).

Build the module either for development or production:
Build the module either for development or production for a **browser** target:
```
./gradlew jsBrowserDevelopmentWebpack
./gradlew jsBrowserProductionWebpack
```

Build the module either for development or production (**NodeJS** target):
```
./gradlew -Pnode jsBrowserDevelopmentWebpack
./gradlew -Pnode jsBrowserProductionWebpack
```


To verify a single QR code content:

```JavaScript
Expand Down Expand Up @@ -613,7 +621,7 @@ See these links for details:
## Changelog

Version NEXT:
- Fix constructors and overloads fro Java callers
- Fix constructors and overloads for Java callers
- Update dependencies:
- Common:
- Kotlin: 1.5.31
Expand All @@ -632,7 +640,13 @@ Version NEXT:
- node-inspect-extracted: 1.0.8
- ajv (JSON schema validator): 8.6.3
- ajv-formats: 2.1.1
- JS: Switch to upstream cose-js 0.7.0 (deprecates forked version)
- JS:
- Switch to upstream cose-js 0.7.0 (deprecates forked version)
- Fix deprecated calls to `Buffer` constructor (possibly not all calls yet)
- Switch intermediate (=node) output from CommonJS to UMD
- Experimental NodeJS support
- Enable outputting a bundled js module (UMD) targeting NodeJS if desired
- the Gradle [npm-publish](https://github.com/mpetuska/npm-publish) plugin does not work as desired

Version 1.3.2:
- Export `SignedDataDownloader` to JS
Expand Down
49 changes: 32 additions & 17 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -104,13 +104,18 @@ kotlin {
}
}
webpackTask {
val currentTemplate = if (project.hasProperty("node")) "node" else "browser"
val templateSrc = "${projectDir.absolutePath}/webpack-templates/patch-$currentTemplate.js"

//we want to overwrite, else we could end up in a messy state if we switch profiles
File(templateSrc).copyTo(File("${projectDir.absolutePath}/webpack.config.d/patch.js"), overwrite = true)
output.library = "hcert"
output.libraryTarget = "umd"
}
}
binaries.executable()
useCommonJs()
}

sourceSets {
val commonShared by creating {
sourceSets { kotlin.srcDir(customSrcDirs.commonShared) }
Expand Down Expand Up @@ -153,31 +158,41 @@ kotlin {
dependsOn(jvmDataGenMain)
}

val jsMain by getting {
val jsNode by creating {
sourceSets { kotlin.srcDir(customSrcDirs.jsMainGenerated) }
dependencies {
implementation(npm("pako", Versions.js.pako))
implementation(npm("pkijs", Versions.js.pkijs))
implementation(npm("cose-js", Versions.js.cose, generateExternals = false))
implementation(npm("cbor", Versions.js.cbor))
implementation(npm("fast-sha256", Versions.js.sha256, generateExternals = true))
implementation(npm("bignumber.js", Versions.js.bignumber))
implementation(npm("elliptic", Versions.js.elliptic))
implementation(npm("node-rsa", Versions.js.rsa))
implementation(npm("ajv", Versions.js.ajv))
implementation(npm("ajv-formats", Versions.js.`ajv-formats`))
implementation(npm("@nuintun/qrcode", Versions.js.qrcode))
}
}

val jsBrowser by creating {
dependencies {
implementation(npm("crypto-browserify", Versions.js.`crypto-browserify`))
implementation(npm("stream-browserify", Versions.js.`stream-browserify`))
implementation(npm("util", Versions.js.util))
implementation(npm("buffer", Versions.js.buffer))
implementation(npm("process", Versions.js.process))
implementation(npm("cbor", Versions.js.cbor))
implementation(npm("node-inspect-extracted", Versions.js.`node-inspect-extracted`))
implementation(npm("bignumber.js", Versions.js.bignumber))
implementation(npm("fast-sha256", Versions.js.sha256, generateExternals = true))
implementation(npm("url", Versions.js.url))
implementation(npm("elliptic", Versions.js.elliptic))
implementation(npm("node-rsa", Versions.js.rsa))
implementation(npm("constants-browserify", Versions.js.`constants-browserify`))
implementation(npm("assert", Versions.js.assert))
implementation(npm("ajv", Versions.js.ajv))
implementation(npm("ajv-formats", Versions.js.`ajv-formats`))
implementation(npm("@nuintun/qrcode", Versions.js.qrcode))
}
}
val jsMain by getting {
dependsOn(jsNode)
if (!project.hasProperty("node")) dependsOn(jsBrowser)
}

val jsTest by getting {
sourceSets { kotlin.srcDir(customSrcDirs.jsTestGenerated) }
}
Expand Down Expand Up @@ -221,12 +236,12 @@ tasks {
val baseFile = File(basePath)
baseFile.walkBottomUp().filter { !it.isDirectory }.filterNot { it.extension == "png" }
.filterNot { it.extension == "jpg" }.forEach {
val encodeBase64 =
de.undercouch.gradle.tasks.download.org.apache.commons.codec.binary.Base64.encodeBase64(it.readBytes())
val key = it.absolutePath.substring(baseFile.absolutePath.length + 1)
val safeKey = key.replace("\$", "\\\$").replace("\\", "/")
w.write("m[\"$safeKey\"] = \"${String(encodeBase64)}\"\n")
}
val encodeBase64 =
de.undercouch.gradle.tasks.download.org.apache.commons.codec.binary.Base64.encodeBase64(it.readBytes())
val key = it.absolutePath.substring(baseFile.absolutePath.length + 1)
val safeKey = key.replace("\$", "\\\$").replace("\\", "/")
w.write("m[\"$safeKey\"] = \"${String(encodeBase64)}\"\n")
}
w.write("}\noverride fun get(key:String) = m[key]\n")
w.write("override fun allResourceNames() = m.keys.sorted()\n}")
}
Expand Down Expand Up @@ -275,4 +290,4 @@ publishing {
}
}
}
}
}
22 changes: 22 additions & 0 deletions node-demo/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
const hcert = require("../build/distributions/hcert-node")

const qr = "HC1:NCFTW2H:7*I06R3W/J:O6:P4QB3+7RKFVJWV66UBCE//UXDT:*ML-4D.NBXR+SRHMNIY6EB8I595+6UY9-+0DPIO6C5%0SBHN-OWKCJ6BLC2M.M/NPKZ4F3WNHEIE6IO26LB8:F4:JVUGVY8*EKCLQ..QCSTS+F$:0PON:.MND4Z0I9:GU.LBJQ7/2IJPR:PAJFO80NN0TRO1IB:44:N2336-:KC6M*2N*41C42CA5KCD555O/A46F6ST1JJ9D0:.MMLH2/G9A7ZX4DCL*010LGDFI$MUD82QXSVH6R.CLIL:T4Q3129HXB8WZI8RASDE1LL9:9NQDC/O3X3G+A:2U5VP:IE+EMG40R53CG9J3JE1KB KJA5*$4GW54%LJBIWKE*HBX+4MNEIAD$3NR E228Z9SS4E R3HUMH3J%-B6DRO3T7GJBU6O URY858P0TR8MDJ$6VL8+7B5$G CIKIPS2CPVDK%K6+N0GUG+TG+RB5JGOU55HXDR.TL-N75Y0NHQTZ3XNQMTF/ZHYBQ$8IR9MIQHOSV%9K5-7%ZQ/.15I0*-J8AVD0N0/0USH.3"

const pemCert =
"-----BEGIN CERTIFICATE-----\n" +
"MIIBvTCCAWOgAwIBAgIKAXk8i88OleLsuTAKBggqhkjOPQQDAjA2MRYwFAYDVQQD\n" +
"DA1BVCBER0MgQ1NDQSAxMQswCQYDVQQGEwJBVDEPMA0GA1UECgwGQk1TR1BLMB4X\n" +
"DTIxMDUwNTEyNDEwNloXDTIzMDUwNTEyNDEwNlowPTERMA8GA1UEAwwIQVQgRFND\n" +
"IDExCzAJBgNVBAYTAkFUMQ8wDQYDVQQKDAZCTVNHUEsxCjAIBgNVBAUTATEwWTAT\n" +
"BgcqhkjOPQIBBggqhkjOPQMBBwNCAASt1Vz1rRuW1HqObUE9MDe7RzIk1gq4XW5G\n" +
"TyHuHTj5cFEn2Rge37+hINfCZZcozpwQKdyaporPUP1TE7UWl0F3o1IwUDAOBgNV\n" +
"HQ8BAf8EBAMCB4AwHQYDVR0OBBYEFO49y1ISb6cvXshLcp8UUp9VoGLQMB8GA1Ud\n" +
"IwQYMBaAFP7JKEOflGEvef2iMdtopsetwGGeMAoGCCqGSM49BAMCA0gAMEUCIQDG\n" +
"2opotWG8tJXN84ZZqT6wUBz9KF8D+z9NukYvnUEQ3QIgdBLFSTSiDt0UJaDF6St2\n" +
"bkUQuVHW6fQbONd731/M4nc=\n" +
"-----END CERTIFICATE-----"

const verifier = new hcert.VerifierDirect([pemCert]);


console.debug(verifier.verify(qr))
12 changes: 12 additions & 0 deletions node-demo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"name": "nodetest",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ fun ByteArray.toUint8ClampedArray(): Uint8ClampedArray {
return Uint8ClampedArray(toTypedArray())
}

fun ByteArray.toBuffer(): Buffer = Buffer(toUint8Array())
fun ByteArray.toBuffer(): Buffer = Buffer.from(toUint8Array())

fun Uint8Array.toByteArray(): ByteArray {
return ByteArray(this.length) { this[it] }
Expand Down
2 changes: 1 addition & 1 deletion src/jsMain/kotlin/external/crypto/index.module_bn.js.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ external interface `T$2` {
var b: BN
var gcd: BN
}

@JsNonModule
@JsModule("bn.js")
open external class BN {
constructor(number: Number, base: Number = definedExternally, endian: String = definedExternally)
Expand Down
2 changes: 1 addition & 1 deletion src/jsMain/kotlin/external/crypto/index.module_node-rsa.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"RETURN_TYPE_MISMATCH_ON_OVERRIDE",
"CONFLICTING_OVERLOADS"
)

@JsNonModule
@JsModule("node-rsa")
open external class NodeRSA {
constructor(key: KeyBits = definedExternally)
Expand Down
File renamed without changes.
7 changes: 7 additions & 0 deletions webpack-templates/patch-node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
config.target="node"
config.output.filename="hcert-node.js"
config.performance = {
maxEntrypointSize: 512000 * 5,
maxAssetSize: 512000 * 5
}
config.resolve.fallback = {"node-inspect-extracted":false}