From c4445e85b93809ba34f8ee799d271b58fcbda514 Mon Sep 17 00:00:00 2001
From: Javi Rueda <foss@franjaru.com>
Date: Tue, 23 Feb 2021 13:21:28 +0100
Subject: [PATCH] Use commentron instead of Comment SDK calls

---
 .../lbry/browser/tasks/CommentCreateTask.java | 65 ++++++------
 .../lbry/browser/tasks/CommentListTask.java   |  7 +-
 .../java/io/lbry/browser/utils/Comments.java  | 99 +++++++++++++++++++
 3 files changed, 131 insertions(+), 40 deletions(-)
 create mode 100644 app/src/main/java/io/lbry/browser/utils/Comments.java

diff --git a/app/src/main/java/io/lbry/browser/tasks/CommentCreateTask.java b/app/src/main/java/io/lbry/browser/tasks/CommentCreateTask.java
index 54f810e6..5cdce1d9 100644
--- a/app/src/main/java/io/lbry/browser/tasks/CommentCreateTask.java
+++ b/app/src/main/java/io/lbry/browser/tasks/CommentCreateTask.java
@@ -7,29 +7,18 @@ import org.json.JSONException;
 import org.json.JSONObject;
 
 import java.io.IOException;
-import java.math.BigDecimal;
-import java.text.DecimalFormat;
-import java.text.DecimalFormatSymbols;
-import java.util.HashMap;
-import java.util.Locale;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
+import java.util.Objects;
 
 import io.lbry.browser.exceptions.ApiCallException;
 import io.lbry.browser.model.Comment;
+import io.lbry.browser.utils.Comments;
 import io.lbry.browser.utils.Helper;
-import io.lbry.browser.utils.Lbry;
-import io.lbry.browser.utils.Lbryio;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
 import okhttp3.Response;
 
 public class CommentCreateTask extends AsyncTask<Void, Void, Comment> {
-    private static final String STATUS_ENDPOINT = "https://comments.lbry.com";
-
-    private Comment comment;
-    private View progressView;
-    private CommentCreateWithTipHandler handler;
+    private final Comment comment;
+    private final View progressView;
+    private final CommentCreateWithTipHandler handler;
     private Exception error;
 
     public CommentCreateTask(Comment comment, View progressView, CommentCreateWithTipHandler handler) {
@@ -46,29 +35,31 @@ public class CommentCreateTask extends AsyncTask<Void, Void, Comment> {
         Comment createdComment = null;
         try {
             // check comments status endpoint
-            Request request = new Request.Builder().url(STATUS_ENDPOINT).build();
-            OkHttpClient client = new OkHttpClient.Builder().
-                    writeTimeout(30, TimeUnit.SECONDS).
-                    readTimeout(30, TimeUnit.SECONDS).
-                    build();
-            Response response = client.newCall(request).execute();
-            JSONObject status = new JSONObject(response.body().string());
-            String statusText = Helper.getJSONString("text", null, status);
-            boolean isRunning = Helper.getJSONBoolean("is_running", false, status);
-            if (!"ok".equalsIgnoreCase(statusText) || !isRunning) {
-                throw new ApiCallException("The comment server is not available at this time. Please try again later.");
+            Comments.checkCommentsEndpointStatus();
+
+            JSONObject comment_body = new JSONObject();
+            comment_body.put("comment", comment.getText());
+            comment_body.put("claim_id", comment.getClaimId());
+            if (!Helper.isNullOrEmpty(comment.getParentId())) {
+                comment_body.put("parent_id", comment.getParentId());
+            }
+            comment_body.put("channel_id", comment.getChannelId());
+            comment_body.put("channel_name", comment.getChannelName());
+
+            JSONObject jsonChannelSign = Comments.channelSign(comment_body, comment.getChannelId(), comment.getChannelName());
+
+            if (jsonChannelSign.has("signature") && jsonChannelSign.has("signing_ts")) {
+                comment_body.put("signature", jsonChannelSign.getString("signature"));
+                comment_body.put("signing_ts", jsonChannelSign.getString("signing_ts"));
             }
 
-            Map<String, Object> options = new HashMap<>();
-            options.put("comment", comment.getText());
-            options.put("claim_id", comment.getClaimId());
-            options.put("channel_id", comment.getChannelId());
-            options.put("channel_name", comment.getChannelName());
-            if (!Helper.isNullOrEmpty(comment.getParentId())) {
-                options.put("parent_id", comment.getParentId());
-            }
-            JSONObject jsonObject = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_COMMENT_CREATE, options);
-            createdComment = Comment.fromJSONObject(jsonObject);
+            Response resp = Comments.performRequest(comment_body, "comment.Create");
+            String responseString = Objects.requireNonNull(resp.body()).string();
+            resp.close();
+            JSONObject jsonResponse = new JSONObject(responseString);
+
+            if (jsonResponse.has("result"))
+                createdComment = Comment.fromJSONObject(jsonResponse.getJSONObject("result"));
         } catch (ApiCallException | ClassCastException | IOException | JSONException ex) {
             error = ex;
         }
diff --git a/app/src/main/java/io/lbry/browser/tasks/CommentListTask.java b/app/src/main/java/io/lbry/browser/tasks/CommentListTask.java
index 2833e003..36cf3131 100644
--- a/app/src/main/java/io/lbry/browser/tasks/CommentListTask.java
+++ b/app/src/main/java/io/lbry/browser/tasks/CommentListTask.java
@@ -14,6 +14,7 @@ import java.util.List;
 import java.util.Map;
 
 import io.lbry.browser.model.Comment;
+import io.lbry.browser.utils.Comments;
 import io.lbry.browser.utils.Helper;
 import io.lbry.browser.utils.Lbry;
 
@@ -21,8 +22,8 @@ public class CommentListTask extends AsyncTask<Void, Void, List<Comment>> {
     private final int page;
     private final int pageSize;
     private final String claim;
-    private ProgressBar progressBar;
-    private CommentListHandler handler;
+    private final ProgressBar progressBar;
+    private final CommentListHandler handler;
     private Exception error;
 
     public CommentListTask(int page, int pageSize, String claim, ProgressBar progressBar, CommentListHandler handler) {
@@ -52,7 +53,7 @@ public class CommentListTask extends AsyncTask<Void, Void, List<Comment>> {
             options.put("skip_validation", true);
             options.put("visible", true);
 
-            JSONObject result = (JSONObject) Lbry.genericApiCall(Lbry.METHOD_COMMENT_LIST, options);
+            JSONObject result = (JSONObject) Lbry.parseResponse(Comments.performRequest(Lbry.buildJsonParams(options), "comment.List"));
             JSONArray items = result.getJSONArray("items");
 
             List<Comment> children = new ArrayList<>();
diff --git a/app/src/main/java/io/lbry/browser/utils/Comments.java b/app/src/main/java/io/lbry/browser/utils/Comments.java
new file mode 100644
index 00000000..5100cef5
--- /dev/null
+++ b/app/src/main/java/io/lbry/browser/utils/Comments.java
@@ -0,0 +1,99 @@
+package io.lbry.browser.utils;
+
+import android.os.Build;
+
+import org.apache.commons.codec.binary.Hex;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+
+import io.lbry.browser.exceptions.ApiCallException;
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okhttp3.Response;
+
+public class Comments {
+    private static final String STATUS_ENDPOINT = "https://comments.lbry.com";
+    public static final String COMMENT_SERVER_ENDPOINT = "https://comments.lbry.com/api/v2";
+
+    public static JSONObject channelSign(JSONObject commentBody, String channelId, String channelName) throws ApiCallException, JSONException {
+        byte[] commentBodyBytes = commentBody.getString("comment").getBytes(StandardCharsets.UTF_8);
+        String encodedCommentBody;
+
+        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.O_MR1)
+            encodedCommentBody = Hex.encodeHexString(commentBodyBytes, false);
+        else
+            encodedCommentBody = new String(Hex.encodeHex(commentBodyBytes));
+
+        Map<String, Object> signingParams = new HashMap<>(3);
+        signingParams.put("hexdata", encodedCommentBody);
+        signingParams.put("channel_id", channelId);
+        signingParams.put("channel_name", channelName);
+
+        return (JSONObject) Lbry.genericApiCall("channel_sign", signingParams);
+    }
+
+    /**
+     * Performs request to default Comment Server
+     * @param params JSON containing parameters to send to the server
+     * @param method One of the available methods for comments
+     * @return Response from the server
+     * @throws IOException throwable from OkHttpClient execute()
+     */
+    public static Response performRequest(JSONObject params, String method) throws IOException {
+        return performRequest(COMMENT_SERVER_ENDPOINT, params, method);
+    }
+
+    /**
+     * Performs the request to Comment Server
+     * @param commentServer Url where to direct the request
+     * @param params JSON containing parameters to send to the server
+     * @param method One of the available methods for comments
+     * @return Response from the server
+     * @throws IOException throwable from OkHttpClient execute()
+     */
+    public static Response performRequest(String commentServer, JSONObject params, String method) throws IOException {
+        final MediaType JSON = MediaType.get("application/json; charset=utf-8");
+
+        Map<String, Object> requestParams = new HashMap<>(4);
+        requestParams.put("jsonrpc", "2.0");
+        requestParams.put("id",1);
+        requestParams.put("method", method);
+        requestParams.put("params", params);
+
+        RequestBody requestBody = RequestBody.create(Lbry.buildJsonParams(requestParams).toString(), JSON);
+
+        Request commentCreateRequest = new Request.Builder()
+                                                  .url(commentServer.concat("?m=").concat(method))
+                                                  .post(requestBody)
+                                                  .build();
+
+        OkHttpClient client = new OkHttpClient.Builder().writeTimeout(30, TimeUnit.SECONDS)
+                                                        .readTimeout(30, TimeUnit.SECONDS)
+                                                        .build();
+
+        return client.newCall(commentCreateRequest).execute();
+    }
+
+    public static void checkCommentsEndpointStatus() throws IOException, JSONException, ApiCallException {
+        Request request = new Request.Builder().url(STATUS_ENDPOINT).build();
+        OkHttpClient client = new OkHttpClient.Builder().writeTimeout(30, TimeUnit.SECONDS)
+                                                        .readTimeout(30, TimeUnit.SECONDS)
+                                                        .build();
+        Response response = client.newCall(request).execute();
+        JSONObject status = new JSONObject(Objects.requireNonNull(response.body()).string());
+        String statusText = Helper.getJSONString("text", null, status);
+        boolean isRunning = Helper.getJSONBoolean("is_running", false, status);
+        if (!"ok".equalsIgnoreCase(statusText) || !isRunning) {
+            throw new ApiCallException("The comment server is not available at this time. Please try again later.");
+        }
+    }
+}