Tie up CSRF tokens in the frontend

This commit is contained in:
Antonin Delpeuch 2019-10-14 16:08:15 +01:00
parent 5dc005749a
commit 9ae6a7a581
11 changed files with 49 additions and 15 deletions

View File

@ -317,7 +317,7 @@ public abstract class Command {
w.close(); w.close();
} }
static protected void respondJSON(HttpServletResponse response, Object o) public static void respondJSON(HttpServletResponse response, Object o)
throws IOException { throws IOException {
respondJSON(response, o, new Properties()); respondJSON(response, o, new Properties());

View File

@ -34,6 +34,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.refine.commands; package com.google.refine.commands;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -67,7 +68,7 @@ public class SetPreferenceCommand extends Command {
ps.put(prefName, PreferenceStore.loadObject(o)); ps.put(prefName, PreferenceStore.loadObject(o));
respond(response, "{ \"code\" : \"ok\" }"); respondJSON(response, Collections.singletonMap("code", "ok"));
} catch (IOException e) { } catch (IOException e) {
respondException(response, e); respondException(response, e);
} }

View File

@ -34,7 +34,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
package com.google.refine.commands.importing; package com.google.refine.commands.importing;
import java.io.IOException; import java.io.IOException;
import java.io.Writer;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
@ -46,7 +45,6 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.refine.commands.Command; import com.google.refine.commands.Command;
import com.google.refine.importing.ImportingJob; import com.google.refine.importing.ImportingJob;
import com.google.refine.importing.ImportingManager; import com.google.refine.importing.ImportingManager;
import com.google.refine.util.ParsingUtilities;
public class GetImportingJobStatusCommand extends Command { public class GetImportingJobStatusCommand extends Command {
protected static class JobStatusResponse { protected static class JobStatusResponse {
@ -77,11 +75,10 @@ public class GetImportingJobStatusCommand extends Command {
long jobID = Long.parseLong(request.getParameter("jobID")); long jobID = Long.parseLong(request.getParameter("jobID"));
ImportingJob job = ImportingManager.getJob(jobID); ImportingJob job = ImportingManager.getJob(jobID);
Writer w = response.getWriter();
if (job == null) { if (job == null) {
ParsingUtilities.defaultWriter.writeValue(w, new JobStatusResponse("error", "No such import job", null)); respondJSON(response, new JobStatusResponse("error", "No such import job", null));
} else { } else {
ParsingUtilities.defaultWriter.writeValue(w, new JobStatusResponse("ok", null, job)); respondJSON(response, new JobStatusResponse("ok", null, job));
} }
} }
} }

View File

@ -63,6 +63,8 @@ public class ImportingControllerCommand extends Command {
ImportingController controller = getController(request); ImportingController controller = getController(request);
if (controller != null) { if (controller != null) {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
controller.doPost(request, response); controller.doPost(request, response);
} else { } else {
HttpUtilities.respond(response, "error", "No such import controller"); HttpUtilities.respond(response, "error", "No such import controller");
@ -75,6 +77,8 @@ public class ImportingControllerCommand extends Command {
ImportingController controller = getController(request); ImportingController controller = getController(request);
if (controller != null) { if (controller != null) {
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "application/json");
controller.doPost(request, response); controller.doPost(request, response);
} else { } else {
HttpUtilities.respond(response, "error", "No such import controller"); HttpUtilities.respond(response, "error", "No such import controller");

View File

@ -50,6 +50,7 @@ import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.refine.RefineServlet; import com.google.refine.RefineServlet;
import com.google.refine.commands.Command;
import com.google.refine.commands.HttpUtilities; import com.google.refine.commands.HttpUtilities;
import com.google.refine.importing.ImportingManager.Format; import com.google.refine.importing.ImportingManager.Format;
import com.google.refine.util.JSONUtilities; import com.google.refine.util.JSONUtilities;
@ -218,7 +219,7 @@ public class DefaultImportingController implements ImportingController {
JSONUtilities.safePut(result, "status", "ok"); JSONUtilities.safePut(result, "status", "ok");
JSONUtilities.safePut(result, "options", options); JSONUtilities.safePut(result, "options", options);
HttpUtilities.respond(response, result.toString()); Command.respondJSON(response, result);
} else { } else {
HttpUtilities.respond(response, "error", "Unrecognized format or format has no parser"); HttpUtilities.respond(response, "error", "Unrecognized format or format has no parser");
} }

View File

@ -251,7 +251,7 @@ Refine.DefaultImportingController.prototype.getPreviewData = function(callback,
var result = {}; var result = {};
$.post( $.post(
"command/core/get-models?" + $.param({ "importingJobID" : this._jobID }), "command/core/get-models?" + $.param({ "importingJobID" : self._jobID }),
null, null,
function(data) { function(data) {
for (var n in data) { for (var n in data) {

View File

@ -332,12 +332,12 @@ Refine.DefaultImportingController.prototype._commitFileSelection = function() {
$.post( $.post(
"command/core/importing-controller?" + $.param({ "command/core/importing-controller?" + $.param({
"controller": "core/default-importing-controller", "controller": "core/default-importing-controller",
"jobID": this._jobID, "jobID": self._jobID,
"subCommand": "update-file-selection", "subCommand": "update-file-selection",
"csrf_token": token "csrf_token": token
}), }),
{ {
"fileSelection" : JSON.stringify(this._job.config.fileSelection) "fileSelection" : JSON.stringify(self._job.config.fileSelection)
}, },
function(data) { function(data) {
dismissBusy(); dismissBusy();
@ -348,7 +348,7 @@ Refine.DefaultImportingController.prototype._commitFileSelection = function() {
self._createProjectUI.showImportJobError((data.message) ? ($.i18n('core-index-import/error')+ ' ' + data.message) : $.i18n('core-index-import/unknown-err')); self._createProjectUI.showImportJobError((data.message) ? ($.i18n('core-index-import/error')+ ' ' + data.message) : $.i18n('core-index-import/unknown-err'));
} else { } else {
// Different files might be selected. We start over again. // Different files might be selected. We start over again.
delete this._parserOptions; delete self._parserOptions;
self._job = data.job; self._job = data.job;
self._showParsingPanel(true); self._showParsingPanel(true);

View File

@ -35,7 +35,7 @@ Refine.ImportProjectUI = function(elmt) {
elmt.html(DOM.loadHTML("core", "scripts/index/import-project-ui.html")); elmt.html(DOM.loadHTML("core", "scripts/index/import-project-ui.html"));
Refine.wrapCSRF(function(token) { Refine.wrapCSRF(function(token) {
elem.attr('action', "command/core/import-project?" + $.param({ csrf_token: token}); elmt.attr('action', "command/core/import-project?" + $.param({ csrf_token: token}));
}); });
this._elmt = elmt; this._elmt = elmt;

View File

@ -33,6 +33,37 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
var preferenceUIs = []; var preferenceUIs = [];
var Refine = {
};
// Requests a CSRF token and calls the supplied callback
// with the token
Refine.wrapCSRF = function(onCSRF) {
$.get(
"command/core/get-csrf-token",
{},
function(response) {
onCSRF(response['token']);
},
"json"
);
};
// Performs a POST request where an additional CSRF token
// is supplied in the POST data. The arguments match those
// of $.post().
Refine.postCSRF = function(url, data, success, dataType, failCallback) {
return Refine.wrapCSRF(function(token) {
var fullData = data || {};
fullData['csrf_token'] = token;
var req = $.post(url, fullData, success, dataType);
if (failCallback !== undefined) {
req.fail(failCallback);
}
});
};
var lang = (navigator.language|| navigator.userLanguage).split("-")[0]; var lang = (navigator.language|| navigator.userLanguage).split("-")[0];
var dictionary = ""; var dictionary = "";
$.ajax({ $.ajax({

View File

@ -190,7 +190,7 @@ ExporterManager.handlers.exportProject = function() {
var name = window.prompt(prompt, theProject.metadata.name); var name = window.prompt(prompt, theProject.metadata.name);
if (name) { if (name) {
var dismiss = DialogSystem.showBusy($.i18n('gdata-exporter/uploading')); var dismiss = DialogSystem.showBusy($.i18n('gdata-exporter/uploading'));
$.post( Refine.postCSRF(
"command/gdata/upload", "command/gdata/upload",
{ {
"project" : theProject.id, "project" : theProject.id,

View File

@ -200,7 +200,7 @@ ProcessPanel.prototype._render = function(newData) {
} else { } else {
if (window.confirm($.i18n('core-project/last-op-er')+':\n' + messages + if (window.confirm($.i18n('core-project/last-op-er')+':\n' + messages +
'\n\n'+$.i18n('core-project/continue-remaining')+'?')) { '\n\n'+$.i18n('core-project/continue-remaining')+'?')) {
$.post( Refine.postCSRF(
"command/core/apply-operations?" + $.param({ project: theProject.id }), "command/core/apply-operations?" + $.param({ project: theProject.id }),
{ operations: '[]' }, { operations: '[]' },
function(o) {}, function(o) {},