Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,15 @@ function injectHeader(header, tokenValue, jqXHR) {
}

function injectData(tokenValue, options, key) {
var data = options.data ? JSON.parse(options.data) : {};
data[key] = tokenValue;
options.data = JSON.stringify(data);
var data;
if (~options.contentType.indexOf('application/json')) {
data = options.data ? JSON.parse(options.data) : {};
data[key] = tokenValue;
options.data = JSON.stringify(data);
} else {
options.data += options.data ? '&' : '';
options.data += key + '=' + tokenValue;
}
}

function injectQuery(tokenValue, options, param) {
Expand Down
66 changes: 66 additions & 0 deletions karma.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/* jshint node:true */
'use strict';

module.exports = function(config) {
config.set({
// base path, that will be used to resolve files and exclude
basePath: '',

frameworks: ['browserify', 'mocha'],

// list of files / patterns to load in the browser
files: [
'test/integration/*.test.js'
],

// list of files to exclude
exclude: [],

preprocessors: {
'test/**/*.js': ['browserify']
},

browserify: {
debug: true
},

// test results reporter to use
// possible values: 'dots', 'progress', 'junit'
reporters: ['dots'],

// web server port
port: 9876,

// cli runner port
runnerPort: 9100,

// enable / disable colors in the output (reporters and logs)
colors: true,

// level of logging
// possible values: config.LOG_{DISABLE,ERROR,WARN,INFO,DEBUG}
logLevel: config.LOG_INFO,

// watch files and execute tests whenever any file changes
autoWatch: false,

// Start these browsers, currently available:
// - Chrome
// - ChromeCanary
// - Firefox
// - Opera
// - Safari (only Mac)
// - PhantomJS
// - IE (only Windows)
browsers: [
'PhantomJS'
],

// If browser does not capture in given timeout [ms], kill it
captureTimeout: 60000,

// Continuous Integration mode
// if true, it capture browsers, run tests and exit
singleRun: true
});
};
10 changes: 9 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@
"coveralls": "npm run coverage && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage",
"coverage": "istanbul cover node_modules/.bin/_mocha -- test/unit/index.test.js",
"lint": "jshint .",
"test": "mocha test/unit/index.test.js",
"test": "npm run test-unit && npm run test-integration",
"test-integration": "karma start",
"test-unit": "mocha test/unit/index.test.js",
"validate": "npm run lint && npm test && npm run coveralls"
},
"repository": {
Expand All @@ -30,8 +32,14 @@
"devDependencies": {
"coveralls": "^2.11.2",
"istanbul": "^0.3.16",
"jquery": "^2.1.4",
"jshint": "^2.8.0",
"karma": "^0.12.37",
"karma-browserify": "^4.2.1",
"karma-mocha": "^0.2.0",
"karma-phantomjs-launcher": "^0.2.0",
"mocha": "^2.2.5",
"phantomjs": "^1.9.17",
"sinon": "^1.15.3"
}
}
140 changes: 140 additions & 0 deletions test/integration/index.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
'use strict';

var $ = require('jquery'),
assert = require('assert'),
sinon = require('sinon'),
createCsrfPrefilter = require('../..');

describe('Requests prefiltered with CSRF token injection', function() {
var xhr, requests, prefilter, prefilters = $.Callbacks();

$.ajaxPrefilter(prefilters.fire);

describe('POST with header prefilter', function() {

beforeEach(function() {
prefilter = createCsrfPrefilter('my-token-value');
prefilters.add(prefilter);
xhr = sinon.useFakeXMLHttpRequest();
requests = [];
xhr.onCreate = function(req) { requests.push(req); };

$.ajax({
type: 'POST',
url: '/some/url',
dataType: 'json',
data: {
foo: 'bar',
baz: 'qux'
}
});
});

afterEach(function() {
xhr.restore();
prefilters.remove(prefilter);
});

it('should inject expected header', function() {
assert.strictEqual(requests[0].requestHeaders['X-CSRF-Token'], 'my-token-value');
});
});

describe('POST with data prefilter and application/json content-type', function() {

beforeEach(function() {
prefilter = createCsrfPrefilter('my-token-value', {
data: '_csrf'
});
prefilters.add(prefilter);
xhr = sinon.useFakeXMLHttpRequest();
requests = [];
xhr.onCreate = function(req) { requests.push(req); };

$.ajax({
type: 'POST',
url: '/some/url',
contentType: 'application/json',
dataType: 'json',
data: JSON.stringify({
foo: 'bar',
baz: 'qux'
})
});
});

afterEach(function() {
xhr.restore();
prefilters.remove(prefilter);
});

it('should inject expected header', function() {
var requestBody = JSON.parse(requests[0].requestBody);
assert.strictEqual(requestBody._csrf, 'my-token-value');
});
});

describe('POST with data prefilter and application/x-www-form-urlencoded content-type', function() {

beforeEach(function() {
prefilter = createCsrfPrefilter('my-token-value', {
data: '_csrf'
});
prefilters.add(prefilter);
xhr = sinon.useFakeXMLHttpRequest();
requests = [];
xhr.onCreate = function(req) { requests.push(req); };

$.ajax({
type: 'POST',
url: '/some/url',
dataType: 'json',
data: {
foo: 'bar',
baz: 'qux'
}
});
});

afterEach(function() {
xhr.restore();
prefilters.remove(prefilter);
});

it('should inject expected header', function() {
assert.strictEqual(requests[0].requestBody, 'foo=bar&baz=qux&_csrf=my-token-value');
});
});

describe('POST with query prefilter', function() {

beforeEach(function() {
prefilter = createCsrfPrefilter('my-token-value', {
query: '_csrf'
});
prefilters.add(prefilter);
xhr = sinon.useFakeXMLHttpRequest();
requests = [];
xhr.onCreate = function(req) { requests.push(req); };

$.ajax({
type: 'POST',
url: '/some/url',
dataType: 'json',
data: {
foo: 'bar',
baz: 'qux'
}
});
});

afterEach(function() {
xhr.restore();
prefilters.remove(prefilter);
});

it('should inject expected header', function() {
assert.strictEqual(requests[0].url, '/some/url?_csrf=my-token-value');
});
});
});
36 changes: 35 additions & 1 deletion test/unit/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,11 @@ describe('jQuery CSRF prefilter factory', function() {
});
});

describe('when prefilter created with data option', function() {
describe('when prefilter created with data option and content type application/json', function() {

beforeEach(function() {
opts.data = '_csrf';
options.contentType = 'application/json';
prefilter = createCsrfPrefilter(tokenValue, opts);
});

Expand Down Expand Up @@ -108,6 +109,38 @@ describe('jQuery CSRF prefilter factory', function() {
});
});

describe('when prefilter created with data option and content type application/x-www-form-urlencoded', function() {

beforeEach(function() {
opts.data = '_csrf';
options.contentType = 'application/x-www-form-urlencoded';
prefilter = createCsrfPrefilter(tokenValue, opts);
});

describe('and ajax request is safe', function() {

it('should not inject specified data into request', function() {
safeMethods.forEach(function(method) {
options.type = method;
prefilter(options, originalOptions, jqXHR);
assert(!options.data);
});
});
});

describe('and ajax request is unsafe', function() {

it('should inject specified data into request', function() {
unsafeMethods.forEach(function(method) {
options.type = method;
prefilter(options, originalOptions, jqXHR);
assert(~options.data.indexOf('_csrf=' + tokenValue), tokenValue);
assert(!jqXHR.setRequestHeader.calledWith('X-CSRF-Token', tokenValue));
});
});
});
});

describe('when prefilter created with query option', function() {

beforeEach(function() {
Expand Down Expand Up @@ -152,6 +185,7 @@ describe('jQuery CSRF prefilter factory', function() {
opts.header = 'X-CSRFToken';
opts.data = '_csrf';
opts.query = '_csrf';
options.contentType = 'application/json';
prefilter = createCsrfPrefilter(tokenValue, opts);
});

Expand Down