-
Notifications
You must be signed in to change notification settings - Fork 11
Development using JavaScript
When you use the graalvm-native-image
runtime, you have the option to enable JavaScript language support.
When enabled, you can create a context in which you can load and execute a JavaScript source module.
This module can either run to completion and terminate, or it can define a set of functions and variables that
can subsequently be called and accessed from your Java enclave code.
The sample "hello world" enclave took us through a tutorial on how to write an
enclave that takes a string, reverses it, and returns it via the host to the client. In this section, we
will take the code from the sample and modify it to reverse the string using JavaScript to replace the
existing Java reverse()
function.
Make sure you've already run through the tutorial and have a working sample application as a starting point.
Enabling JavaScript support in an enclave requires pulling in a number of dependencies that result in a
larger enclave size. Therefore, JavaScript is not enabled by default. To enable support, add the
following line to your enclave build.gradle
.
Javascript
```groovy hl_lines="4"
conclave {
productID = 1
revocationLevel = 0
supportLanguages = "js"
}
```
More details on enclave configuration are available on this page.
We need to use the GraalVM SDK to build a context in which to run the JavaScript code. The dependency to
the SDK is automatically added when you specify supportLanguages = "js"
for Javascript.
So you just need to add the following import statements to ReverseEnclave.java
:
import com.r3.conclave.enclave.Enclave;
import com.r3.conclave.mail.EnclaveMail;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;
The next step is to define and parse our JavaScript code. Once we have done this we can set up the bindings to Java which allow us to access the functions and variables that are defined within the JavaScript code. Add a constructor that prepares the JavaScript context:
Javascript
```java hl_lines="4-15"
// We store the previous result to showcase that the enclave internals can be examined in a mock test.
byte[] previousResult;
private final Value bindings;
private static final String jsCode = "function reverse(input) {"
+ " var split = input.split('');"
+ " var reverse = split.reverse();"
+ " return reverse.join('');"
+ "}";
public ReverseEnclave() {
Context context = Context.create("js");
bindings = context.getBindings("js");
context.eval("js", jsCode);
}
@Override
protected byte[] receiveFromUntrustedHost(byte[] bytes) {
```
The context that runs the code must be closed before the enclave is destroyed. Otherwise, the application will hang once the method destroyEnclave is invoked. The best place to close the context is at the bottom of the receiveMail
method as shown below:
```java hl_lines="13-16"
@Override
protected void receiveMail(long id, EnclaveMail mail, String routingHint) {
// This is used when the host delivers a message from the client.
// First, decode the Mail body as a String.
final String stringToReverse = new String(mail.getBodyAsBytes());
// Reverse it and re-encode to UTF-8 to send back.
final byte[] reversedEncodedString = reverse(stringToReverse).getBytes();
// Get the post office object for responding back to this mail and use it to encrypt our response.
final byte[] responseBytes = postOffice(mail).encryptMail(reversedEncodedString);
postMail(responseBytes, routingHint);
// Please ensure that close is called before or while the enclave is being destroyed. Failing to do so
// will hang the application when the method destroyEnclave is called
context.close();
}
```
Remove the Java code that reverses the string and replace it with the following function. Note
that static
has been removed from the function declaration because it now accesses the bindings
member variable.
return result;
}
private String reverse(String input) {
Value result = bindings.getMember("reverse").execute(input);
return result.asString();
}
@Override
protected void receiveMail(long id, EnclaveMail mail, String routingHint) {
Finally, run the sample code as described in the tutorial.
Build times can be quite long when running in simulation mode. For productivity reasons, it is advisable to run the sample in mock mode. Before running the sample in mock mode, it is necessary to:
1. Download [graalvm-ce-java17](https://github.com/graalvm/graalvm-ce-builds/releases).
2. Set the environment variable ```JAVA_HOME``` to point to the GraalVM that was previously downloaded. For instance,
```export JAVA_HOME=/usr/lib/jvm/graalvm-ce-java17-22.0.0.2)```.
3. Update the environment variable PATH by running ```export PATH=JAVA_HOME/bin:$PATH```.
Conclave support for JavaScript is provided by the polyglot capabilities in GraalVM. Refer to the GraalVM documentation on embedding languages for detailed instructions on how to use this capability.
Note
-
The functionality described on this page involves JIT compilation within the secure enclave. Due to the unavailability of the CPUID instruction in SGX enclaves, some optimizations which depend on the presence of certain instruction set extensions may not take place, and performance may be degraded.
-
The processor of the host system must support the SSE and SSE2 instruction set extensions. If these extensions are not present, the enclave may abort unexpectedly.