Java: Get JavaScript Array Elements from page - javascript

I am at a point where I can pull a single javascript declaration such as:
var cars = ["Saab", "Volvo", "BMW"];
parsed from a page.
I would like to be able to get all the elements of the array ("Saab", "Volvo", "BMW") from this declaration.
Should I be using some javascript engine for this, or what else would be the best way to get javascript variable values from my Java code.
I would hate to reinvent the wheel if something is already out there that is able to do this, so I am just looking for advice on something I can use to do this function.

I assume you found a way to transport that javascript object/array into your Java domain as a String or Stream. What you want now is a JSON parser.
One way is to use json.org or other libraries. Further information about json parsing can be found in this thread:
How to parse JSON in Java
The [org.json][1] library is easy to use. Example code below:
import org.json.*;
JSONObject obj = new JSONObject(" .... ");
String pageName = obj.getJSONObject("pageInfo").getString("pageName");
JSONArray arr = obj.getJSONArray("posts");
for (int i = 0; i < arr.length(); i++)
{
String post_id = arr.getJSONObject(i).getString("post_id");
......
} You may find extra examples from: [Parse JSON in Java][2]
Downloadable jar: http://mvnrepository.com/artifact/org.json/json
[1]: http://www.json.org/java/index.html
[2]: http://theoryapp.com/parse-json-in-java/
You might also want to look into jsonb (https://jcp.org/en/jsr/detail?id=353) that was introduced with Java 7. You can bind an object model and transform JSON objects into java objects and vice versa.

you can iterate through all the values in 'window'
for ( var key in window )
{
if ( typeof window]key] == 'object' && window]key].length > 0 )
{
//this is the array you are looking for
}
}
You can get access to javascript object from java by using httpunit

Method 1: JSON parser, as Alex's answer.
Method 2: Javascript parser for Java
Method 3: Regular Expression (A weird way I figured out!)
First pattern is var\s+([a-zA-Z0-9]+)\s+=\s+\[(.*)\]\s*;*
var + one or more space(s) + variable name($1) + one or more space(s) + equals sign + one or more space(s) + array content($2) + ......
Second pattern is "(.*?)", get the string between two quotation marks.
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class JSParser {
public String arrayName;
private String tempValues;
public ArrayList<String> values = new ArrayList<String>();
public boolean parseJSArray(String arrayStr){
String p1 = "var\\s+([a-zA-Z0-9]+)\\s+=\\s+\\[(.*)\\]\\s*;*";
Pattern pattern1 = Pattern.compile(p1);
Matcher matcher = pattern1.matcher(arrayStr);
if(matcher.find()){
arrayName = matcher.group(1);
tempValues = matcher.group(2);
Pattern getVal = Pattern.compile("\"(.*?)\"");
Matcher valMatcher = getVal.matcher(tempValues);
while (valMatcher.find()) { // find next match
String value = valMatcher.group(1);
values.add(value);
}
return true;
}else{
return false;
}
}
}

With JDK 8 the code bellow works :
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
String js = "var carsfromjs = [\"Saab\", \"Volvo\", \"BMW\"]";
engine.eval(js);
String[] cars = (String[])engine.eval("Java.to(carsfromjs, \"java.lang.String[]\")");
for(int i=0; i<cars.length; i++){
System.out.println(cars[i]);
}
You can find many ways to access Javascript code throught "nashorn" :
http://winterbe.com/posts/2014/04/05/java8-nashorn-tutorial/
http://www.oracle.com/technetwork/articles/java/jf14-nashorn-2126515.html
http://docs.oracle.com/javase/8/docs/technotes/guides/scripting/nashorn/

Related

Constructing a string array with Frida

I'm trying to call a function with Frida that takes a string array as one of its arguments.
public void coolFunction(long value, String[] strArr);
Within Java it gets called like this:
long importantValue = 4L;
String[] importantArr = new String[]{"TEST"};
coolFunction(importantValue, importantArr);
The overload looks like this: .overload('long', '[Ljava.lang.String;')
I could probably create a string array from scratch, but I don't know how to express it in Javascript. What's the Frida equivalent of new String[]{"TEST"}?
Because of that I tried to turn an ArrayList<String> into a String[], which also wasn't successful.
As far as I can tell there are two simple ways to turn ArrayList<String> into String[]:
Attempt #1:
List<String> list = new ArrayList<String>();
list.add("TEST");
String[] stringArray = list.toArray(new String[0]);
If I try to express it with Javascript it looks like this:
var AL_class = Java.use("java.util.ArrayList");
var arrList = AL_class.$new();
arrList.add("TEST");
var stringArray = arrList.toArray(Java.use("[Ljava.lang.String;").$new(0));
This fails with the following error message:
Error: no supported overloads
Attempt #2:
List<String> list = new ArrayList<String>();
list.add("TEST");
Object[] objectArray = list.toArray();
String[] stringArray = (String[]) objectArray;
Javascript:
var AL_class = Java.use("java.util.ArrayList");
var arrList = AL_class.$new();
arrList.add("TEST");
var arrayButAsObject = arrList.toArray();
var stringArray = Java.cast(arrayButAsObject, "[Ljava.lang.String;");
This fails because it assumes that I want to use Javascript's toArray() function.
The solution to this problem is probably very simple but I've been stuck here for quite a while now and can't seem to figure it out. Any help would be appreciated.
Instead of trying to construct a java.util.List and then convert it to an array I would use the Frida function Java.array and directly construct a Java String array:
var javaStringArray = Java.array('java.lang.String', [ "Test" ]);

GraalVM how to return an array from a method to the guest language?

I'm playing around with GraalVM (Truffle) in OpenJDK 17, and would like to know what the correct way is to return values to the guest language from method calls? Right now I'm struggling with passing a String[] array back.
Exmaple:
Java (host)
class Services
{
Value message;
#HostAccess.Export
public String[] getArrayString()
{
return new String[]{"s1", "s2", "s3"};
}
#HostAccess.Export
public void setMessage( Value v )
{
message = v;
message.pin();
}
}
...
String jsScript = " ... " // see below
try ( Context context = Context.newBuilder().allowHostAccess(HostAccess.SCOPED).build() )
{
Services s = new Services();
context.getBindings("js").putMember("services", s);
context.eval("js", jsScript);
}
JavaScript (guest)
var a = services.getArrayString();
b = '';
for ( var c in a ) b += c;
services.setMessage('' + a + ' // ' + b)
The final message value is "[object Object] // " (b is blank), however I expected something like "[object Object] // s1s2s3".
I've also tried the return types Object[] and ArrayList<String>. I'm not sure why I can't access the elements of the array, either I'm not passing the array back correctly, or I'm not accessing it correctly within the JavaScript script. The examples I've found in the GraalVM docs are always about passing values directly from the host to the guest, but I'd like to do it via a method call - how is that done?
I've finally found a way to pass an array from the host to the guest - using ProxyArray.
https://www.graalvm.org/22.1/reference-manual/embed-languages/#computed-arrays-using-polyglot-proxies
Reading through the Graalvm documentation and experimenting with the very primative examples they provide, I came up with the following changes to my Services class:
ArrayList<String> array = new ArrayList<String>();
#HostAccess.Export
public void prepareList()
{
array.add("s1");
array.add("s2");
array.add("s3");
}
#HostAccess.Export
public ProxyArray getArray()
{
return new ProxyArray() {
#Override
public Object get( long index )
{
return array.get((int)index);
}
#Override
public void set( long index, Value value )
{
// TODO Auto-generated method stub
}
#Override
public long getSize()
{
return array.size();
}
};
}
And finally the guest call looks like this:
services.prepareList();
var a = services.getArray();
b = '';
for ( i = 0; i < a.length; i++ ) b += a[i];
services.setMessage('' + a + ' // ' + b)
And the value of the message is then as expected "[object Object] // s1s2s3"
Hope someone finds this useful ... and if you have a better way of returning objects (Array, Hashtable, whatever) post your answers here - thanks.
First I would give a straight forward answer to your question. To pass an array from Java scope to the guest language scope, you can just send the Java array/list as input to the execute method. For example:
Context context = Context.newBuilder().allowAllAccess(true).build();
int intArray[] = {1,2,3};
Value ret = context.eval("js", "(function getArray(a) {console.log(a[2]);})").execute(intArray);
The above should print 3 in the JS scope.
Now I decide to add the following paragraphs because after reading your code as well as those in some proposed answers, I think it could be of help.
Say you have a Java code snippet like the one below which returns an array from the JS context.
Value val = context.eval("js", "(function getArray() {return [1,2,3];})").execute();
It is not possible to directly access the whole array object from val in the Java language scope because the memory layout of Java arrays is different from the memory layout of JS arrays. However you can obtain elements at different indices of the JS array from within the Java scope as follows:
int index2 = val.getArrayElement(2).asInt();
System.out.println(index2);
The above should print the value 3.
In order to obtain the full array in the Java scope, you must do an explicit array copy. The classic way to do this is to leverage the technique described here: https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Value.html#as-org.graalvm.polyglot.TypeLiteral-
Using that technique one can define an INTEGER_LIST TypeLiteral as such:
public static final TypeLiteral<List<Integer>> INTEGER_LIST =
new TypeLiteral<List<Integer>>() {};
And then return the polyglot Value as an INTEGER_LIST as follows:
List<Integer> intList = context.eval("js", "(function getArray() {return [1,2,3];})").execute().as(INTEGER_LIST);
System.out.println("JS array in Java scope: " + intList);
The above print should produce: [1,2,3]. This strategy also does an explicit array copy in the back ground but it is neat, more or less.
You could apply exactly the same strategy for your String array, by defining a TypeLiteral like:
public static final TypeLiteral<List<String>> STRING_LIST =
new TypeLiteral<List<STRING>>() {};
And obtaining the String list/array in Java scope via ...execute().as(STRING_LIST);. This should give you your String array in the Java scope.

How to pass list of object from JavaScript to Windows Runtime Component C#?

I have created a WinRT component in C# which accepts a IEnumarable as a parameter
C#
public sealed class MyClass
{
public IEnumarable<DtoClass> MyFunction(IEnumarable<DtoClass> properties) {
return properties;
}
}
Java script
var Test=[];
for (var i = 0; i < res1.length; i++)
{
Test.push({ category_id: res1[i].category_id });
}
var Conncetion = WindowsRTSqlite.MyClass();
var result = Conncetion.MyFunction(Test);
I'm returning the same input parameters which I'm sending to MyFunction method but it's not return any result. I am not sure why this is not working. Any Ideas?
Thanks in advance.
How to pass list of object from JavaScript to Windows Runtime Component C#?
Actually the correct way is to serialize the collection to a json string and pass this string to the Windows Runtime Component. And deserialize the json string in the runtime component side for data dealing. After that return back the serialized json string to JavaScript uwp app. For how to serialize in JavaScript please reference this class, for how to serialize in C# you can reference this namespcase. So your code on the JavaScript side may as follows:
var Test = [];
for (var i = 1; i < 6; i++) {
Test.push({ category_id: i });
}
var Conncetion = RuntimeComponent1.MyClass();
var Testserialation = JSON.stringify(Test);
var resultnew = Conncetion.newFunction(Testserialation);
var Testreturn = JSON.parse(resultnew);
And in windows runtime component:
public sealed class MyClass
{
public string NewFunction(string jsonstring)
{
JsonArray entity= JsonArray.Parse(jsonstring);
return entity.ToString();
}
}
I am not sure why this is not working.
According to your code snippet, you created an object array and trying to pass it to the runtime component as IEnumarable<DtoClass>. You passed an array, in my opinion you should be able receive it as an array. And I don't think object can be parsed to DtoClass automatically. If you use a string or int array that can be recognized. For example , an int array:
var newTest = [1, 2, 3, 4];
var result2 = Conncetion.changeArray(newTest);
Code in component:
public int[] ChangeArray([ReadOnlyArray()] int[] input)
{
int[] output =(int[])input.Clone();
// Manipulate the copy.
// ...
return output;
}
More details about passing arrays to a Windows Runtime Component please reference this article.

How to fully dump / print variable to console in the Dart language?

Hey there I am searching for a function which is printing a dynamic variable as completely as possible to the console in Dart language.
In PHP for instance I would use var_dump() in order to get all information about a variable.
In JavaScript I would do one of the following:
1) Convert Object to JSON and print console.log(JSON.stringify(obj))
2) Or a custom function like this:
function dump(arr,level) {
var dumped_text = "";
if(!level) level = 0;
//The padding given at the beginning of the line.
var level_padding = "";
for(var j=0;j<level+1;j++) level_padding += " ";
if(typeof(arr) == 'object') { //Array/Hashes/Objects
for(var item in arr) {
var value = arr[item];
if(typeof(value) == 'object') { //If it is an array,
dumped_text += level_padding + "'" + item + "' ...\n";
dumped_text += dump(value,level+1);
} else {
dumped_text += level_padding + "'" + item + "' => \"" + value + "\"\n";
}
}
} else { //Stings/Chars/Numbers etc.
dumped_text = "===>"+arr+"<===("+typeof(arr)+")";
}
return dumped_text;
}
However in Dart if I do print(variable) I get something like Instance of 'FooBarObject'. I cannot just convert an object to JSON like in JavaScript as this is not possible for all objects.
So my question in detail:
Is where a function or custom function in dart which can print a variable with unknown type (object, array, etc.) including all (public) properties as well as nested objects and variables to my console? Or which function is closest to this desire?
dart:developer library includes inspect function that allows debuggers to open an inspector on the object.
To use it add:
import 'dart:developer';
And then you can see your inspected variable/object in console with:
inspect(myVar);
There is no built in function that generates such an output.
print(variable) prints variable.toString() and Instance of 'FooBarObject' is the default implementation. You can override it in custom classes and print something different.
You can use reflection (https://www.dartlang.org/articles/libraries/reflection-with-mirrors) to build a function yourself that investigates all kinds of properties of an instance and prints it the way you want.
There is almost no limitation of what you can do and for debugging purposes it's definitely a fine option.
For production web application it should be avoided because it limits tree-shaking seriously and will cause the build output size to increase notable.
Flutter (mobile) doesn't support reflection at all.
You can also use one of the JSON serialization packages, that make it easy to add serialization to custom classes and then print the serialized value.
For example
https://pub.dartlang.org/packages/dson
I think there are others, but I don't know about (dis)advantages, because I usually roll my own using https://pub.dartlang.org/packages/source_gen
If it's a map then you can convert to JSON. First import convert package from flutter.
import 'dart:convert';
then convert to JSON and print
print(json.encode(yourMapVariable));
Update
Above answer is for map. For class / object add to toString() method.
Eg: say we have a user class
class User {
String name;
String address;
toString() {
return "name: " + name + ", address: " + address;
}
}
You can auto generate this toString() method using your IDE.
Simple little trick does the job
void printObject(Object object) {
// Encode your object and then decode your object to Map variable
Map jsonMapped = json.decode(json.encode(object));
// Using JsonEncoder for spacing
JsonEncoder encoder = new JsonEncoder.withIndent(' ');
// encode it to string
String prettyPrint = encoder.convert(jsonMapped);
// print or debugPrint your object
debugPrint(prettyPrint);
}
// To use simply pass your object to it
printObject(yourObject);
Instance of 'FooBarObject' This happens when you try to directly do print(object);
Even if you use convert package from flutter, it would throw Uncaught Error: Converting object to an encodable object failed:
To resolve this issue, first, make sure your model class or data class contains fromJson and toJson methods.
If you do so, your model class would look like this.
class User {
String name;
String gender;
int age;
User({this.name, this.gender, this.age});
User.fromJson(Map<String, dynamic> json) {
name = json['name'];
gender = json['gender'];
age = json['age'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['name'] = this.name;
data['gender'] = this.gender;
data['age'] = this.age;
return data;
}
}
And to print this as json import convert package
import 'dart:convert';
And call json.encode
//after initializing the user object
print('value is--> ' + json.encode(user);
Which will print the data as
value is--> {"name": "Vignesh","gender": "Male","age": 25}
use await keyword with an object in async function
void _registerUser() async { print(await form.result); }
If you want to know more about an instance of any class in an android studio click on a class name before variable then press ctrl+b it will take you to the class file where this object belongs from there you can see user attributes and methods of this class.
Try this one..
void printWrapped(String text) {
final pattern = new RegExp('.{1,800}'); // 800 is the size of each chunk
pattern.allMatches(text).forEach((match) => print(match.group(0)));
}

javascript multiline dict declaration

I'm having an issue. I want to have a static dict
var myDict={"aaa":true,"aab":false,"aac":false,"aad":true, [...] };
There are a lot of entries, and I want to have an easy access to all of them in case I need to change their value. Because of this, I don't like the single-line declaration.
As an alternative, I did manage to do the following, since multi-line text is allowed in Javascript:
var dict = {};
var loadDict = function() {
text = "aaa,true\n\
aab,false\n\
aac,false\n\
aad,true\n\[...]";
var words = text.split( "\n" );
for ( var i = 0; i < words.length; i++ ) {
var pair = words[i].split(",");
dict[ pair[0].trim() ] = pair[1].trim();
}
}
Is there a better/more elegant way of having a multi-line declaration of a dict?
note: Creating multiline strings in JavaScript is a solution only for strings. it doesn't work with a dict.
edit: I was adding a '\' at the end of each line. That was the issue. thanks.
var myDict = {
"aaa": true,
"aab": false,
"aac": false,
"aad": true,
[...]
};
I hope this is what you meant, because it's basic Javascript syntax.
Also, if for some reasons you want to "store" simple objects (made of strings, numbers, booleans, arrays or objects of the above entities) into strings, you can consider JSON:
var myDictJSON = '{\
"aaa": true,\
"aab": false,\
"aac": false,\
"aad": true,\
[...]
}';
var myDict = JSON.parse(myDictJSON);
Support for JSON is native for all the major browsers, including IE since version 8. For the others, there's this common library json2.js that does the trick.
You can also convert your simple objects into string using JSON.stringify.
that's easy-
var myDict={
"aaa":true,
"aab":false,
"aac":false,
"aad":true
};
please remember, don't place the curly bracket in the next line.
i like responses. Please respond
This (a complex data structure containing both "string" and "booleans"):
var myDict={"aaa":true,"aab":false,"aac":false,"aad":true, [...] };
Can be expressed like this:
var myDict={
"aaa":true,
"aab":false,
"aac":false,
"aad":true,
[...]
};
Similarly, this:
var myBigHairyString = "Supercalifragilsticexpialidocious";
Can be expressed like this:
var myBigHairyString =
"Super" +
"califragilstic" +
"expialidocious";

Categories