diff options
-rw-r--r-- | Readme.md | 8 | ||||
-rw-r--r-- | spec/DjangoSpecRunner.html | 75 | ||||
-rw-r--r-- | spec/django/login.js | 69 | ||||
-rw-r--r-- | spec/django/signup.js | 50 | ||||
-rw-r--r-- | spec/helper.js (renamed from spec/specHelper.js) | 0 | ||||
-rw-r--r-- | spec/login_spec.js (renamed from spec/restful/login.js) | 6 | ||||
-rw-r--r-- | spec/runner.html (renamed from spec/RestfulSpecRunner.html) | 11 | ||||
-rw-r--r-- | spec/session_spec.js (renamed from spec/restful/session.js) | 0 | ||||
-rw-r--r-- | spec/signup_spec.js (renamed from spec/restful/signup.js) | 2 | ||||
-rw-r--r-- | src/jqueryRest.js | 52 | ||||
-rw-r--r-- | src/plainXHR.js | 120 |
11 files changed, 17 insertions, 376 deletions
@@ -1,8 +1,7 @@ -imported to github from: https://code.google.com/p/srp-js/ +originally imported to github from: https://code.google.com/p/srp-js/ License: [New BSD License](http://www.opensource.org/licenses/bsd-license.php) - Many websites today require some form of authentication to access the site's full functionality. Unfortunately, many of these websites do not use secure authentication protocols. In some cases, websites will store user passwords in their database. If the database ever becomes compromised, an attacker could authenticate as any user he wanted. @@ -15,6 +14,7 @@ The Secure Remote Password protocol addresses this problem. First presented by T This project aims to provide a strong javascript implementation of SRP that will provide some peace of mind when using websites that do not use HTTPS. Due to the nature of HTTP, it is not invulnerable to man-in-the-middle attacks, but it should provide strong security against passive eavesdroppers, which are increasingly common in the age of wireless internet. -To accompany the Javascript implementation of the client, the [original repository](https://code.google.com/p/srp-js/) had a django server. +[ruby-srp](https://github.com/leapcode/ruby-srp) contains client and server implementations in ruby that work with the current version of srp-js. It also ships an example using srp-js as the client. + +The [original repository](https://code.google.com/p/srp-js/) had code working with a django server. This was removed after the commit tagged 0.1.0 -[ruby-srp](https://github.com/leapcode/ruby-srp) contains client and server implementations in ruby that work with srp-js. It also ships an example using srp-js as the client. diff --git a/spec/DjangoSpecRunner.html b/spec/DjangoSpecRunner.html deleted file mode 100644 index 5920745..0000000 --- a/spec/DjangoSpecRunner.html +++ /dev/null @@ -1,75 +0,0 @@ -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" - "http://www.w3.org/TR/html4/loose.dtd"> -<html> -<head> - <title>Jasmine Spec Runner</title> - - <link rel="shortcut icon" type="image/png" href="lib/jasmine-1.1.0.rc1/jasmine_favicon.png"> - - <link rel="stylesheet" type="text/css" href="lib/jasmine/jasmine.css"> - <script type="text/javascript" src="lib/jasmine/jasmine.js"></script> - <script type="text/javascript" src="lib/jasmine/jasmine-html.js"></script> - - <script type="text/javascript" src="lib/sinon/sinon-1.3.4.js"></script> - <script type="text/javascript" src="lib/jasmine-sinon.js"></script> - - <!-- the files we are testing... --> - <script type="text/javascript" src="../lib/SHA256.js"></script> - <script type="text/javascript" src="../lib/prng4.js"></script> - <script type="text/javascript" src="../lib/rng.js"></script> - <script type="text/javascript" src="../lib/jsbn.js"></script> - <script type="text/javascript" src="../lib/jsbn2.js"></script> - <script type="text/javascript" src="../src/srp.js"></script> - <script type="text/javascript" src="../src/plainXHR.js"></script> - <script type="text/javascript" src="../src/srp_session.js"></script> - - <!-- include spec files here... --> - <script type="text/javascript" src="specHelper.js"></script> - <script type="text/javascript" src="django/signup.js"></script> - <script type="text/javascript" src="django/login.js"></script> - - <script type="text/javascript"> - - (function() { - var jasmineEnv = jasmine.getEnv(); - jasmineEnv.updateInterval = 1000; - - var htmlReporter = new jasmine.HtmlReporter(); - - jasmineEnv.addReporter(htmlReporter); - - jasmineEnv.specFilter = function(spec) { - return htmlReporter.specFilter(spec); - }; - - var currentWindowOnload = window.onload; - window.onload = function() { - if (currentWindowOnload) { - currentWindowOnload(); - } - - execJasmine(); - }; - - function execJasmine() { - jasmineEnv.execute(); - } - })(); - - </script> - -</head> - -<body> - <form action="." onsubmit="return register()"> - <table> - <tr><td>Username:</td><td><input type="text" id="srp_username" value="user" /></td></tr> - <tr><td>Password:</td><td><input type="password" id="srp_password" value="opensesami"/></td></tr> - <input type="hidden" id="srp_url" value=""/> - <input type="hidden" id="srp_forward" value="#logged_in"/> - <input type="hidden" id="srp_server" value="django"/> - </table> - <input type="submit"/> - </form> -</body> -</html> diff --git a/spec/django/login.js b/spec/django/login.js deleted file mode 100644 index d13f695..0000000 --- a/spec/django/login.js +++ /dev/null @@ -1,69 +0,0 @@ -describe("Login", function() { - - it("has an identify function", function() { - var srp = new SRP(); - expect(typeof srp.identify).toBe('function'); - }); - - describe("(INTEGRATION)", function (){ - // a valid auth attempt for the user / password given in the spec runner: - var a = 'af141ae6'; - var B = '887005895b1f5528b4e4dfdce914f73e763b96d3c901d2f41d8b8cd26255a75'; - var salt = '5d3055e0acd3ddcfc15'; - var M = 'be6d7db2186d5f6a2c55788479b6eaf75229a7ca0d9e7dc1f886f1970a0e8065' - var M2 = '2547cf26318519090f506ab73a68995a2626b1c948e6f603ef9e1b0b78bf0f7b'; - var A, callback; - - - beforeEach(function() { - var srp = new SRP(); - var session = new srp.Session(); - this.srp = new SRP(null, session) - A = session.calculateAndSetA(a); - - specHelper.setupFakeXHR.apply(this); - - this.srp.success = sinon.spy(); - }); - - afterEach(function() { - this.xhr.restore(); - }); - - it("works with XML responses", function(){ - this.srp.identify(); - - this.expectRequest('handshake/', 'I=user&A='+A); - this.respondXML("<r s='"+salt+"' B='"+B+"' />"); - this.expectRequest('authenticate/', 'M='+M); - this.respondXML("<M>"+M2+"</M>"); - - expect(this.srp.success).toHaveBeenCalled(); - }); - - it("works with JSON responses", function(){ - this.srp.identify(); - - this.expectRequest('handshake/', 'I=user&A='+A); - this.respondJSON({s: salt, B: B}); - this.expectRequest('authenticate/', 'M='+M); - this.respondJSON({M: M2}); - - expect(this.srp.success).toHaveBeenCalled(); - }); - - it("rejects B = 0", function(){ - this.srp.error = sinon.spy(); - this.srp.identify(); - - this.expectRequest('handshake/', 'I=user&A='+A); - this.respondJSON({s: salt, B: 0}); - // aborting if B=0 - expect(this.requests).toEqual([]); - expect(this.srp.error).toHaveBeenCalled(); - }); - }); - - -}); - diff --git a/spec/django/signup.js b/spec/django/signup.js deleted file mode 100644 index 383dd14..0000000 --- a/spec/django/signup.js +++ /dev/null @@ -1,50 +0,0 @@ -describe("Signup", function() { - - beforeEach(function() { - this.srp = new SRP(); - specHelper.setupFakeXHR.apply(this); - }); - - afterEach(function() { - this.xhr.restore(); - }); - - it("has a register function", function() { - expect(typeof this.srp.register).toBe('function'); - }); - - it("receives the salt from /register/salt", function(){ - var callback = sinon.spy(); - this.srp.remote.sendVerifier = callback; - this.srp.register(); - this.expectRequest('register/salt/', "I=user") - this.respondXML("<salt>5d3055e0acd3ddcfc15</salt>"); - expect(callback).toHaveBeenCalledWith(this.srp.session, this.srp.registered_user); - }); - - it("identifies after successful registration (INTEGRATION)", function(){ - var callback = sinon.spy(); - this.srp.identify = callback; - this.srp.register(); - this.expectRequest('register/salt/', "I=user") - this.respondXML("<salt>5d3055e0acd3ddcfc15</salt>"); - this.expectRequest('register/user/', "v=adcd57b4a4a05c2e205b0b7b30014d9ff635d8d8db2f502f08e9b9c132800c44"); - this.respondXML("<ok />"); - expect(callback).toHaveBeenCalled(); - }); - - it("identifies after successful registration with JSON (INTEGRATION)", function(){ - var callback = sinon.spy(); - this.srp.identify = callback; - this.srp.register(); - this.expectRequest('register/salt/', "I=user") - this.respondJSON({salt: "5d3055e0acd3ddcfc15"}); - this.expectRequest('register/user/', "v=adcd57b4a4a05c2e205b0b7b30014d9ff635d8d8db2f502f08e9b9c132800c44"); - this.respondJSON({ok: true}); - expect(callback).toHaveBeenCalled(); - }); - - -}); - - diff --git a/spec/specHelper.js b/spec/helper.js index 11327af..11327af 100644 --- a/spec/specHelper.js +++ b/spec/helper.js diff --git a/spec/restful/login.js b/spec/login_spec.js index 9c43c00..4df62a8 100644 --- a/spec/restful/login.js +++ b/spec/login_spec.js @@ -52,9 +52,9 @@ describe("Login", function() { var success = sinon.spy(); this.srp.identify(success); - this.expectRequest('sessions', 'login=' +login+ '&A=' +A, 'POST'); + this.expectRequest('sessions.json', 'login=' +login+ '&A=' +A, 'POST'); this.respondJSON({salt: salt, B: B}); - this.expectRequest('sessions/'+login, 'client_auth='+M, 'PUT'); + this.expectRequest('sessions/'+login+'.json', 'client_auth='+M, 'PUT'); this.respondJSON({M2: M2}); expect(success).toHaveBeenCalled(); @@ -65,7 +65,7 @@ describe("Login", function() { var error = sinon.spy(); this.srp.identify(success, error); - this.expectRequest('sessions', 'login=' +login+ '&A=' +A, 'POST'); + this.expectRequest('sessions.json', 'login=' +login+ '&A=' +A, 'POST'); this.respondJSON({salt: salt, B: 0}); // aborting if B=0 expect(this.requests).toEqual([]); diff --git a/spec/RestfulSpecRunner.html b/spec/runner.html index a9d708b..5f4727c 100644 --- a/spec/RestfulSpecRunner.html +++ b/spec/runner.html @@ -2,6 +2,7 @@ "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> + <meta http-equiv = "Content-Type" content = "text/html; charset=utf-8"> <title>Jasmine Spec Runner</title> <link rel="shortcut icon" type="image/png" href="lib/jasmine-1.1.0.rc1/jasmine_favicon.png"> @@ -12,7 +13,7 @@ <script type="text/javascript" src="lib/sinon/sinon-1.3.4.js"></script> <script type="text/javascript" src="lib/jasmine-sinon.js"></script> - <script type="text/javascript" src="lib/jquery-1.8.2.js"></script> + <script type="text/javascript" src="http://code.jquery.com/jquery-1.8.2.js"></script> <!-- the files we are testing... --> <script type="text/javascript" src="../lib/SHA256.js"></script> @@ -25,10 +26,10 @@ <script type="text/javascript" src="../src/srp_session.js"></script> <!-- include spec files here... --> - <script type="text/javascript" src="specHelper.js"></script> - <script type="text/javascript" src="restful/signup.js"></script> - <script type="text/javascript" src="restful/login.js"></script> - <script type="text/javascript" src="restful/session.js"></script> + <script type="text/javascript" src="helper.js"></script> + <script type="text/javascript" src="signup_spec.js"></script> + <script type="text/javascript" src="login_spec.js"></script> + <script type="text/javascript" src="session_spec.js"></script> <script type="text/javascript"> diff --git a/spec/restful/session.js b/spec/session_spec.js index b7f16f0..b7f16f0 100644 --- a/spec/restful/session.js +++ b/spec/session_spec.js diff --git a/spec/restful/signup.js b/spec/signup_spec.js index 7b66dd7..e4d70df 100644 --- a/spec/restful/signup.js +++ b/spec/signup_spec.js @@ -22,7 +22,7 @@ describe("Signup", function() { this.srp.identify = callback; this.srp.session.getSalt = function() {return "4c78c3f8"}; this.srp.register(); - this.expectRequest('users', "user[login]=testuser&user[password_salt]=4c78c3f8&user[password_verifier]=474c26aa42d11f20544a00f7bf9711c4b5cf7aab95ed448df82b95521b96668e7480b16efce81c861870302560ddf6604c67df54f1d04b99d5bb9d0f02c6051ada5dc9d594f0d4314e12f876cfca3dcd99fc9c98c2e6a5e04298b11061fb8549a22cde0564e91514080df79bca1c38c682214d65d590f66b3719f954b078b83c", 'POST') + this.expectRequest('users.json', "user[login]=testuser&user[password_salt]=4c78c3f8&user[password_verifier]=474c26aa42d11f20544a00f7bf9711c4b5cf7aab95ed448df82b95521b96668e7480b16efce81c861870302560ddf6604c67df54f1d04b99d5bb9d0f02c6051ada5dc9d594f0d4314e12f876cfca3dcd99fc9c98c2e6a5e04298b11061fb8549a22cde0564e91514080df79bca1c38c682214d65d590f66b3719f954b078b83c", 'POST') this.respondJSON({password_salt: "4c78c3f8", login: "testuser", ok: "true"}); expect(callback).toHaveBeenCalled(); }); diff --git a/src/jqueryRest.js b/src/jqueryRest.js index f50080b..54a0908 100644 --- a/src/jqueryRest.js +++ b/src/jqueryRest.js @@ -1,51 +1,5 @@ jqueryRest = function() { - function parseResponse() { - if (responseIsXML()) { - return parseXML(xhr.responseXML); - } else if (responseIsJSON()) { - return JSON.parse(xhr.responseText); - } - } - - function responseIsXML() { - return (xhr.responseType == 'document') || - (xhr.getResponseHeader("Content-Type").indexOf('application/xml') >= 0); - } - - function responseIsJSON() { - return (xhr.responseType == 'json') || - (xhr.getResponseHeader("Content-Type").indexOf('application/json') >= 0); - } - - function parseXML(xml) { - if (xml.getElementsByTagName("r").length > 0) { - return parseAttributesOfElement(xml.getElementsByTagName("r")[0]); - } else { - return parseNodes(xml.childNodes); - } - } - - function parseAttributesOfElement(elem) { - var response = {}; - for (var i = 0; i < elem.attributes.length; i++) { - var attrib = elem.attributes[i]; - if (attrib.specified) { - response[attrib.name] = attrib.value; - } - } - return response; - } - - function parseNodes(nodes) { - var response = {}; - for (var i = 0; i < nodes.length; i++) { - var node = nodes[i]; - response[node.tagName] = node.textContent || true; - } - return response; - } - // we do not fetch the salt from the server function register(session, callback) { @@ -54,7 +8,7 @@ jqueryRest = function() { function sendVerifier(session, callback) { var salt = session.getSalt(); - $.post("users", { user: + $.post("users.json", { user: { login: session.getI(), password_salt: salt, password_verifier: session.getV(salt).toString(16)} @@ -62,13 +16,13 @@ jqueryRest = function() { } function handshake(session, callback) { - $.post("sessions", { login: session.getI(), + $.post("sessions.json", { login: session.getI(), A: session.getAstr()}, callback); } function authenticate(session, success) { $.ajax({ - url: "sessions/" + session.getI(), + url: "sessions/" + session.getI() + ".json", type: 'PUT', data: {client_auth: session.getM()}, success: success diff --git a/src/plainXHR.js b/src/plainXHR.js deleted file mode 100644 index c03c90a..0000000 --- a/src/plainXHR.js +++ /dev/null @@ -1,120 +0,0 @@ -// -// SRP JS - Plain XHR module -// -// This is deprecated - unless you are using srp-js with the original drupal -// server side I recommend you use a different API such as restful.js -// -// This code has been largely refactored, tests are still passing but I did -// not test it with the server itself. - -SRP.prototype.Remote = function() { - - // Perform ajax requests at the specified path, with the specified parameters - // Calling back the specified function. - function ajaxRequest(url, params, callback) - { - if( window.XMLHttpRequest) { - xhr = new XMLHttpRequest(); - } - else if (window.ActiveXObject){ - try{ - xhr = new ActiveXObject("Microsoft.XMLHTTP"); - }catch (e){} - } - else - { - session.error_message("Ajax not supported."); - return; - } - if(xhr){ - xhr.onreadystatechange = function() { - if(xhr.readyState == 4 && xhr.status == 200) { - callback(parseResponse()); - } - }; - xhr.open("POST", url, true); - xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); - xhr.setRequestHeader("Content-length", params.length); - xhr.send(params); - } - else - { - session.error_message("Ajax failed."); - } - } - - function parseResponse() { - if (responseIsXML()) { - return parseXML(xhr.responseXML); - } else if (responseIsJSON()) { - return JSON.parse(xhr.responseText); - } - } - - function responseIsXML() { - return (xhr.responseType == 'document') || - (xhr.getResponseHeader("Content-Type").indexOf('application/xml') >= 0); - } - - function responseIsJSON() { - return (xhr.responseType == 'json') || - (xhr.getResponseHeader("Content-Type").indexOf('application/json') >= 0); - } - - function parseXML(xml) { - if (xml.getElementsByTagName("r").length > 0) { - return parseAttributesOfElement(xml.getElementsByTagName("r")[0]); - } else { - return parseNodes(xml.childNodes); - } - } - - function parseAttributesOfElement(elem) { - var response = {}; - for (var i = 0; i < elem.attributes.length; i++) { - var attrib = elem.attributes[i]; - if (attrib.specified) { - response[attrib.name] = attrib.value; - } - } - return response; - } - - function parseNodes(nodes) { - var response = {}; - for (var i = 0; i < nodes.length; i++) { - var node = nodes[i]; - response[node.tagName] = node.textContent || true; - } - return response; - } - - // Drupal version fetches the salt from the server. No idea why but this - // should still do it. - this.register = function(session, callback) - { - function receive_salt(response) { - if(response.salt) - { - var s = response.salt; - var v = session.getV(s); - that.sendVerifier(session, callback); - } - } - - var that = this; - ajaxRequest("register/salt/", "I="+session.getI(), receive_salt); - }; - - this.sendVerifier = function(session, callback) { - ajaxRequest("register/user/", "v="+session.getV().toString(16), callback); - }; - - this.handshake = function(session, callback) { - ajaxRequest("handshake/", "I="+session.getI()+"&A="+session.getAstr(), callback); - }; - - this.authenticate = function(session, callback) { - ajaxRequest("authenticate/", "M="+session.getM(), callback); - }; -}; |