wordpressflutterwordpress-json-api

How to solve flutter wordpress json api error?


I am trying to parse json from my wordpress site http://crunchbox.epizy.com/wp-json/wp/v2/ on a flutter app which fetch title and featured image from all existing post here is the code:

final String apiUrl = "http://crunchbox.epizy.com/wp-json/wp/v2/";
  List posts;

  Future<String> getPosts() async {
    var res = await http.get(apiUrl,
        headers: {"Accept": "application/json"});

    setState(() {
      var resBody = jsonDecode(res.body);
      print(resBody);
      posts = resBody;
    });
    return "Success!";

After running this code i am getting this error:

E/flutter ( 2931): [ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] Unhandled exception:
E/flutter ( 2931): FormatException: Unexpected character (at character 1)
E/flutter ( 2931): <html><body><script type="text/javascript" src="/aes.js" ></script><script>...
E/flutter ( 2931): ^
E/flutter ( 2931): 
E/flutter ( 2931): #0      _ChunkedJsonParser.fail (dart:convert/runtime/libconvert_patch.dart:1362:5)
E/flutter ( 2931): #1      _ChunkedJsonParser.parseNumber (dart:convert/runtime/libconvert_patch.dart:1258:9)
E/flutter ( 2931): #2      _ChunkedJsonParser.parse (dart:convert/runtime/libconvert_patch.dart:926:22)
E/flutter ( 2931): #3      _parseJson (dart:convert/runtime/libconvert_patch.dart:29:10)
E/flutter ( 2931): #4      JsonDecoder.convert (dart:convert/json.dart:542:36)
E/flutter ( 2931): #5      JsonCodec.decode (dart:convert/json.dart:169:41)
E/flutter ( 2931): #6      jsonDecode (dart:convert/json.dart:101:10)
E/flutter ( 2931): #7      _WordpressHomeState.getPosts.<anonymous closure> (file:///C:/Users/Arbaaz_AJ/IdeaProjects/wordpress_flutter/lib/main.dart:31:21)
E/flutter ( 2931): #8      State.setState (package:flutter/src/widgets/framework.dart:1125:30)
E/flutter ( 2931): #9      _WordpressHomeState.getPosts (file:///C:/Users/Arbaaz_AJ/IdeaProjects/wordpress_flutter/lib/main.dart:30:5)
E/flutter ( 2931): <asynchronous suspension>
E/flutter ( 2931): #10     _WordpressHomeState.initState (file:///C:/Users/Arbaaz_AJ/IdeaProjects/wordpress_flutter/lib/main.dart:41:10)
E/flutter ( 2931): #11     StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3751:58)
E/flutter ( 2931): #12     ComponentElement.mount (package:flutter/src/widgets/framework.dart:3617:5)
E/flutter ( 2931): #13     Element.inflateWidget (package:flutter/src/widgets/framework.dart:2907:14)
E/flutter ( 2931): #14     Element.updateChild (package:flutter/src/widgets/framework.dart:2710:12)
E/flutter ( 2931): #15     SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:4654:14)
E/flutter ( 2931): #16     Element.inflateWidget (package:flutter/src/widgets/framework.dart:2907:14)
E/flutter ( 2931): #17     Element.updateChild (package:flutter/src/widgets/framework.dart:2710:12)
E/flutter ( 2931): #18     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
E/flutter ( 2931): #19     Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
E/flutter ( 2931): #20     ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3622:5)
E/flutter ( 2931): #21     ComponentElement.mount (package:flutter/src/widgets/framework.dart:3617:5)
E/flutter ( 2931): #22     Element.inflateWidget (package:flutter/src/widgets/framework.dart:2907:14)
E/flutter ( 2931): #23     Element.updateChild (package:flutter/src/widgets/framework.dart:2710:12)
E/flutter ( 2931): #24     SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:4654:14)
E/flutter ( 2931): #25     Element.inflateWidget (package:flutter/src/widgets/framework.dart:2907:14)
E/flutter ( 2931): #26     Element.updateChild (package:flutter/src/widgets/framework.dart:2710:12)
E/flutter ( 2931): #27     SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:4654:14)
E/flutter ( 2931): #28     Element.inflateWidget (package:flutter/src/widgets/framework.dart:2907:14)
E/flutter ( 2931): #29     Element.updateChild (package:flutter/src/widgets/framework.dart:2710:12)
E/flutter ( 2931): #30     SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:4654:14)
E/flutter ( 2931): #31     Element.inflateWidget (package:flutter/src/widgets/framework.dart:2907:14)
E/flutter ( 2931): #32     Element.updateChild (package:flutter/src/widgets/framework.dart:2710:12)
E/flutter ( 2931): #33     SingleChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:4654:14)
E/flutter ( 2931): #34     Element.inflateWidget (package:flutter/src/widgets/framework.dart:2907:14)
E/flutter ( 2931): #35     Element.updateChild (package:flutter/src/widgets/framework.dart:2710:12)
E/flutter ( 2931): #36     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
E/flutter ( 2931): #37     Element.rebuild (package:flutter/src/widgets/framework.dart:3495:5)
E/flutter ( 2931): #38     ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3622:5)
E/flutter ( 2931): #39     StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3769:11)
E/flutter ( 2931): #40     ComponentElement.mount (package:flutter/src/widgets/framework.dart:3617:5)
E/flutter ( 2931): #41     Element.inflateWidget (package:flutter/src/widgets/framework.dart:2907:14)
E/flutter ( 2931): #42     Element.updateChild (package:flutter/src/widgets/framework.dart:2710:12)
E/flutter ( 2931): #43     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3653:16)
E/flutter ( 2931): #44     Element.rebuild (package:flutter/src/widg

What i am trying to achieve is fetch the title and excerpt in a listview here is the code for that:

FadeInImage.memoryNetwork(
                        placeholder: kTransparentImage,
                        image: posts[index]["featured_media"] == 0
                            ? 'images/placeholder.png'
                            : posts[index]["_embedded"]["wp:featuredmedia"][0]
                                ["source_url"],
                      ),
                      Padding(
                        padding: EdgeInsets.all(10.0),
                        child: ListTile(
                          title: Padding(
                            padding: EdgeInsets.symmetric(vertical: 10.0),
                            child: Text(posts[index]["title"]["rendered"]),
                          ),
                          subtitle: Text(posts[index]["excerpt"]["rendered"]
                              .replaceAll(new RegExp(r'<[^>]*>'), '')),
                        ),

Please help me, thank you.


Solution

  • Your API is returning an html response as part of its bot protection. The response is actually some code that needs to run on your client before the server will allow it to access the API.

    This is the html it's returning (not formatted on purpose):

    <html><body><script type="text/javascript" src="/aes.js" ></script><script>function toNumbers(d){var e=[];d.replace(/(..)/g,function(d){e.push(parseInt(d,16))});return e}function toHex(){for(var d=[],d=1==arguments.length&&arguments[0].constructor==Array?arguments[0]:arguments,e="",f=0;f<d.length;f++)e+=(16>d[f]?"0":"")+d[f].toString(16);return e.toLowerCase()}var a=toNumbers("..................."),b=toNumbers(".................."),c=toNumbers("...........");document.cookie="__test="+toHex(slowAES.decrypt(c,2,a,b))+"; expires=Thu, 31-Dec-37 23:55:55 GMT; path=/"; location.href="http://crunchbox.epizy.com/wp-json/wp/v2/posts?i=1";</script><noscript>This site requires Javascript to work, please enable Javascript in your browser or use a browser with Javascript support</noscript></body></html>
    

    The important part is the javascript in the middle:

    function toNumbers(d) {
        var e = [];
        d.replace(/(..)/g, function(d) {
            e.push(parseInt(d, 16))
        });
        return e
    }
    
    function toHex() {
        for (var d = [], d = 1 == arguments.length && arguments[0].constructor == Array ? arguments[0] : arguments, e = "", f = 0; f < d.length; f++) e += (16 > d[f] ? "0" : "") + d[f].toString(16);
        return e.toLowerCase()
    }
    var a = toNumbers("..............."),
        b = toNumbers("..............."),
        c = toNumbers("...............");
    document.cookie = "__test=" + toHex(slowAES.decrypt(c, 2, a, b)) + "; expires=Thu, 31-Dec-37 23:55:55 GMT; path=/";
    location.href = "http://crunchbox.epizy.com/wp-json/wp/v2/posts?i=1"; < /script>
    

    Note that I've replaced the three binary sequences in toNumber("abcd1234") with....`.

    If you have access to the NGINX server (I assume) that is serving the wordpress site, you could disable this. Or you could use wordpress's authentication and add an additional authentication method with a plugin - see the bottom of the wordpress documentation for api authentication.

    A third option is that you could 'run' the js code and set the cookie into your request using a header. Obviously flutter can't run the js natively. But you could theoretically do it with webviews on android & ios, or you could parse the code to find the 'a', 'b', and 'c' and perform the AES-128 cbc decryption using some sort of library (this may work but no promises).