arangodb-java-driver icon indicating copy to clipboard operation
arangodb-java-driver copied to clipboard

Arbitrary JS code execution

Open wajda opened this issue 5 years ago • 5 comments

In out client system we need to implement a mechanism for automatic incremental database migration. For that we need to execute a number of (potentially complex) migration scripts on the ArangoDB server. Something like one would do in Arangosh, but it needs to be done from a Java application.

My first attempt was to utilize the db.transaction() method. Unfortunately due to Arango's inability to create/delete collections and indices from inside a transaction it's not suitable for our needs.

Now I'm looking at the POST /_admin/execute hoping that it does exactly what I need. But I cannot find a way to invoke this API via the Arango Java driver.

Is there any way to call POST /_admin/execute from a Java driver?

Thanks!

wajda avatar Aug 04 '20 14:08 wajda

You can build arbitrary requests and execute them using ArangoDB#execute(Request): https://github.com/arangodb/arangodb-java-driver/blob/d00ddb1afe787199e604424020475953defd46b3/src/main/java/com/arangodb/ArangoDB.java#L798-L805

rashtao avatar Aug 04 '20 16:08 rashtao

Thanks Michele. I tried that but couldn't create a request body object. I might be doing something wrong, could you please correct me? The aforementioned POST accepts a javascript block as a string. The Request.body filed however has a type VPackSlice which (if I get it right) is sort of a binary representation of JSON. How would I serialize e.g "console.log('test');" string to a VPackSlice?

wajda avatar Aug 04 '20 16:08 wajda

In general, you can serialize the body in this way:

        ArangoSerialization serializer = arangoDB.util();
        // or using user custom serializer 
        // ArangoSerialization serializer = arangoDB.util(ArangoSerializationFactory.Serializer.CUSTOM);
        Request request = new Request("_system", RequestType.POST, "/_admin/execute");
        String code = "console.log('test');";
        VPackSlice body = serializer.serialize(code);
        request.setBody(body);

        Response response = arangoDB.execute(request);
        // ...

If the driver is configured with Protocol.HTTP_JSON then the VPackSlice will be automatically converted to JSON.

Nevertheless I have just realized that POST /_admin/execute decodes the body as text/plain, while the VPack serializer encodes it as a JSON string (a quoted string). So the entire payload is interpreted as a javascript string rather than code to be evaluated.

Therefore at the moment I don't see any way to call POST /_admin/execute from the Java driver and more in general to perform any request with content type other than application/json.

rashtao avatar Aug 05 '20 11:08 rashtao

Thanks for the prompt response. That's what I ended up with as well. It would be great to have that ability in the driver. Meantime I'll use a separate HTTP connection for that request.

wajda avatar Aug 05 '20 12:08 wajda

Server bug tracked here: https://arangodb.atlassian.net/jira/software/c/projects/BTS/issues/BTS-209

rashtao avatar Feb 15 '21 07:02 rashtao

Fixed on the server side: https://github.com/arangodb/arangodb/pull/17426 It should be released in ArangoDB 3.11.

rashtao avatar Nov 02 '22 09:11 rashtao

Closing as fixed, tested in https://github.com/arangodb/arangodb-java-driver/commit/ca34bd9aa35a3ea8b8a1075c349168489537b427

rashtao avatar Dec 18 '23 19:12 rashtao