I'm developing desktop software with JavaFX and Java Spark which is basically a barebones framework for developing web apps, but I'm trying to use it strictly to put/get sensitive methods and variables on a server so that users can't access them. REST seems to be the correct approach but I'm struggling to understand 2 interrelated REST concepts. The Spark docs are light but I've integrated the few good tutorials into a working demo below but I've hit a wall. I'll briefly explain:
With the help of Postman I've been able to put a few records onto the server by using a path of http://localhost:4567/secrets and Body of:
{
      "title" : "demofield1",
    "content" : "12345"
}
Each record contains a title as an identifier (demofield1) and content as the sensitive data that should remain hidden from users at all times (12345). It's pretty trivial to put these strings onto a server and then get them by using title as a parameter, shown below. The demo code simply has a Model class for creating and returning a record (secret), a JSON conversion method, and a get and put Spark method. Secrets are stored locally in a HashMap for now, I'm assuming a real app would simply swap in a server DB.
The get method works as expected, returning the correct JSON record and storing the content as a String with this line:     String secretString = model.getCertainSecret(title).getContent();
With that said...
Questions (partial answers fully appreciated too):
- secretStringabove now holds a confidential value (12345) which is obtained using a supposedly secure REST method. But couldn't a user simply reverse-engineer my source code and write- System.out.println(secretString)and have that 12345 revealed? I don't understand how a simple string is protected after retrieving it from the server, despite not being explicitly shown. The code seems correct yet the value is easily obtainable. What am I missing?
- How do you - putentire java methods on a server? A lot of code I need to protect isn't just strings but methods containing- Tasks,- Platform.runLater()->, and needs to interact with other desktop software. For example, one of my methods uses JACOB to identify when a certain area of a third-party software is clicked. I can't even fathom what a get/put would look like in that context.
My assumption was that a server-side DB would store all content from my put requests, but I don't understand how it stores and returns a method? Should I be reading about servlets or SaaS or something? I'm focused on desktop users.
Code:
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import lombok.Data;
import org.apache.log4j.BasicConfigurator;
import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import static spark.Spark.get;
import static spark.Spark.put;
public class ServerDemo
{
    private static final int HTTP_BAD_REQUEST = 400;
    @Data
    static class NewSecretPayload {
        private String title;
        private String content;
        public boolean isValid() {
            return title != null && !title.isEmpty();
        }
    }
    public static class Model {
        private int nextId = 1;
        private Map<String, Secret> secrets = new HashMap<>();
        @Data
        class Secret {
            private int id;
            private String title;
            private String content;
        }
        public int createSecret(String title, String content){
            int id = nextId++;
            Secret secret = new Secret();
            secret.setId(id);
            secret.setTitle(title);
            secret.setContent(content);
            secrets.put(title, secret);
            return id;
        }
        public Secret getCertainSecret(String titleToUse){
            if(null != secrets.get(titleToUse)){
                return secrets.get(titleToUse);
            }else{
                return null;
            }
        }
    }
    public static String dataToJson(Object data) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            mapper.enable(SerializationFeature.INDENT_OUTPUT);
            StringWriter sw = new StringWriter();
            mapper.writeValue(sw, data);
            return sw.toString();
        } catch (IOException e) {
            throw new RuntimeException("IOException from a StringWriter?");
        }
    }
    public static void main(String[] args) {
        Model model = new Model();
        BasicConfigurator.configure();
        put("/secrets", (request, response) -> {
            try {
                ObjectMapper mapper = new ObjectMapper();
                NewSecretPayload creation = mapper.readValue(request.body(), NewSecretPayload.class);
                if (!creation.isValid()) {
                    response.status(HTTP_BAD_REQUEST);
                    return "";
                }
                int id = model.createSecret(creation.getTitle(), creation.getContent());
                response.status(200);
                response.type("application/json");
                return id;
            } catch (JsonParseException jpe) {
                response.status(HTTP_BAD_REQUEST);
                return "";
            }
        });
        get("/secrets/:title", (req, res) -> {
            String title = req.params(":title");
            if (model.getCertainSecret(title) != null) {
                res.status(200);
                res.type("application/json");
                String secretString = model.getCertainSecret(title).getContent();
                return dataToJson(model.getCertainSecret(title));
            }
            res.status(400);
            return new ResponseError("No user with title "+title+" was found", title);
        });
    }
}
 
    