Skip to content
Permalink
master
Go to file
 
 
Cannot retrieve contributors at this time
332 lines (332 sloc) 11.5 KB
//Define console log function if not exists
console = console || {log: function(){}};
//Add format method to String so we can do printf
String.prototype.format = function() {
var args = arguments;
return this.replace(/{(\d+)}/g, function(match, number) {
return typeof args[number] != 'undefined'
? args[number]
: match
;
});
};
//Time and date format functions
//Example new Date().formatDate("{0}.{1}.{2}"); -> "24.07.2012"
Date.prototype.formatDate = function(format){
var format = format || "{0}.{1}.{2}";
var d = this.getDate();
var m = this.getMonth()+1;
var y = this.getFullYear();
return format.format((d<10?"0"+d:d),(m<10?"0"+m:m),y);
}
//Example new Date().formatTime("{0}:{1}:{2}") -> "12:48:55"
Date.prototype.formatTime = function(format){
var format = format || "{0}:{1}:{2}";
var h = this.getHours();
var min = this.getMinutes();
var s = this.getSeconds();
return format.format((h<10?"0"+h:h),(min<10?"0"+min:min),(s<10?"0"+s:s));
}
//Read all params from URL
getUrlParams = function(){
var urlParams = {};
var match,
pl = /\+/g, // Regex for replacing addition symbol with a space
search = /([^&=]+)=?([^&]*)/g,
decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); },
query = window.location.search.substring(1);
while (match = search.exec(query))
urlParams[decode(match[1])] = decode(match[2]);
return urlParams;
}
// Read one param from url
getUrlParam = function(name){
var urlParams = getUrlParams();
return urlParams[name];
}
//Classes
//Packet
//Represents all the parameters that are exchanged by bank and merchant
function Packet(packetId, parameters){
//TODO: make packetId and parameters "private"
this.packetId = packetId;
this.parameters = parameters || [];
}
//Sets specified parameter value
Packet.prototype.setParam = function(paramName, paramValue){
for(i=0;i<this.parameters.length;i++){
var param = this.parameters[i];
if(param.name == paramName){
if(paramValue.length <= param.length){
param.value = $.trim(paramValue);
return;
}
throw new RangeError("Parameter "+param.name+" value too long!["+paramValue.length+","+param.length+"]");
}
}
throw new ParameterError("Parameter "+paramName+" doesn't exist!");
}
//Gets specified parameter value
Packet.prototype.getParam = function(paramName){
for(i=0;i<this.parameters.length;i++){
if(this.parameters[i].name == paramName){
return this.parameters[i].value;
}
}
throw new ParameterError("Parameter "+paramName+" doesn't exist!");
}
//Generates MAC string according to 008 algorithm specified in IPizza spec
//TODO: Nordea has its own algorithm so 008 doesn't belong in a common superclass
Packet.prototype.toMac = function(){
function pad(length){
var str = '' + length;
while (str.length < 3)
str = '0' + str;
return str;
}
var macString = "";
for(i=0;i<this.parameters.length;i++){
var param = this.parameters[i];
if(param.order != 0){
macString += pad(param.value.length)+param.value;
}
}
return macString;
}
//"Abstract" methods
//Returns packet private key
Packet.prototype.privateKey = function(){
throw new NotImplementedError("Packet.privateKey");
}
//Returns packet certificate
Packet.prototype.certificate = function(){
throw new NotImplementedError("Packet.certificate");
}
//Sign parameters and return URL
Packet.prototype.sign = function(){
var rsa = new RSAKey();
rsa.readPrivateKeyFromPEMString(this.privateKey());
var signature = rsa.signString(this.toMac(), "sha1");
var b64 = hex2b64(signature);
this.setParam("VK_MAC", b64);
}
//Verifiy request parameters
Packet.prototype.verify = function(){
var x509 = new X509();
x509.readCertPEM(this.certificate());
var mac = decodeURIComponent(this.getParam("VK_MAC"));
var signature = b64tohex(mac);
return x509.subjectPublicKeyRSA.verifyString(this.toMac(), signature);
}
//Generate table for displaying all parameters
Packet.prototype.html = function(){
var result = "<table class='table table-bordered table-striped'><thead><tr><th>Parameeter</th><th>Väärtus</th></tr></thead><tbody>";
for(i=0;i<this.parameters.length;i++){
var param = this.parameters[i];
if(param.name != "VK_MAC"){
result += "<tr><td>"+param.name+"</td><td>"+param.value+"</td></tr>";
}
}
result += "</tbody></table>";
return result;
}
//Generate query string with all packet parameters
Packet.prototype.queryString = function(){
this.sign();
var query = "?";
for(i=0;i<this.parameters.length;i++){
var param = this.parameters[i];
query += param.name+"="+encodeURIComponent(param.value)+"&";
}
return query;
}
//Initialize packet from request
Packet.init = function(){
var urlParams = getUrlParams();
var packet;
if(urlParams["VK_SERVICE"] != undefined){
eval("packet = new Packet"+urlParams["VK_SERVICE"]+"();");
}
else{
return null;
}
for(param in urlParams){
if(param.indexOf("VK_") == 0)
packet.setParam(param, urlParams[param]);
}
return packet;
}
//RequestPacket
//Represents a packet that is sent from a merchant to the bank
RequestPacket.prototype = new Packet();
RequestPacket.prototype.constructor = RequestPacket;
function RequestPacket(packetId,parameters){
Packet.call(packetId,parameters);
this.packetId = packetId;
this.parameters = parameters || [];
}
//Request private key is used when signing request packet
//Only useful internally for testing
RequestPacket.prototype.privateKey = function(){
return MERCHANT_PRIVATE_KEY;
}
//Request certificate is used to verify request
RequestPacket.prototype.certificate = function(){
return MERCHANT_CERT;
}
//"Abstract" functions
//Returns a corresponding response packet for this request packet
RequestPacket.prototype.response = function(){
throw new NotImplementedError("RequestPacket.response");
}
//Response packet
//Represents a packet that is sent from the bank to a merchant
ResponsePacket.prototype = new Packet();
ResponsePacket.prototype.constructor = ResponsePacket;
function ResponsePacket(packetId, parameters){
Packet.call(packetId,parameters);
this.packetId = packetId;
this.parameters = parameters || [];
}
//Response private key is used when signing response packet
ResponsePacket.prototype.privateKey = function(){
return BANK_PRIVATE_KEY;
}
//Response certificate is used to verify response
//Only useful internally for testing
ResponsePacket.prototype.certificate = function(){
return BANK_CERT;
}
//PacketParameter
function PacketParameter(name, length, order, value){
this.name = name;
this.length = length;
this.order = order || 0;
this.value = value || "";
}
//Errors
//ParameterError
//Thrown when there is something wrong with the parameter
ParameterError.prototype = new Error();
ParameterError.prototype.constructor = ParameterError;
function ParameterError(message){
Error.call(message);
this.message = message;
}
//NotImplementedError
//Thrown when a method is not implemented
NotImplementedError.prototype = new Error();
NotImplementedError.prototype.constructor = NotImplementedError;
function NotImplementedError(method){
var message = "Method "+method+" not implemented!";
Error.call(message);
this.message = message;
}
//AuthHistory
//Used to keep history of used authentications
function AuthHistory(history){
this.history = history || [];
}
//Checks if history is empty
AuthHistory.prototype.isEmpty = function() {
return this.history.length == 0;
}
AuthHistory.prototype.contains = function(id) {
var found = false;
$.each(this.history, function(i,item){
if(item.id == id){
found = true;
return (false);
}
});
return found;
}
AuthHistory.prototype.add = function(id, firstName, lastName) {
if(!this.contains(id)){
this.history.push({id: id, firstName: firstName, lastName: lastName});
localStorage.setItem("history", JSON.stringify(this.history));
}
}
AuthHistory.prototype.get = function(id){
var found = null;
$.each(this.history, function(i,item){
if(item.id == id){
found = item;
return (false);
}
});
return found;
}
//Generates a select box of used authentications
AuthHistory.prototype.asSelect = function() {
if(this.isEmpty()){
return "";
}
var select = "<select>";
$.each(this.history, function(i,item){
select += "<option value='"+item.id+"'>"+item.firstName+" "+item.lastName+"</option>"
});
select += "</select>";
return select;
}
//Initializes auth history object
AuthHistory.init = function(){
(localStorage != undefined)
var history = $.parseJSON(localStorage.getItem("history")) || [];
return new AuthHistory(history);
}
//Certs and keys
var MERCHANT_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\
MIICWwIBAAKBgQDRhGF7X4A0ZVlEg594WmODVVUIiiPQs04aLmvfg8SborHss5gQ\
Xu0aIdUT6nb5rTh5hD2yfpF2WIW6M8z0WxRhwicgXwi80H1aLPf6lEPPLvN29EhQ\
NjBpkFkAJUbS8uuhJEeKw0cE49g80eBBF4BCqSL6PFQbP9/rByxdxEoAIQIDAQAB\
AoGAA9/q3Zk6ib2GFRpKDLO/O2KMnAfR+b4XJ6zMGeoZ7Lbpi3MW0Nawk9ckVaX0\
ZVGqxbSIX5Cvp/yjHHpww+QbUFrw/gCjLiiYjM9E8C3uAF5AKJ0r4GBPl4u8K4bp\
bXeSxSB60/wPQFiQAJVcA5xhZVzqNuF3EjuKdHsw+dk+dPECQQDubX/lVGFgD/xY\
uchz56Yc7VHX+58BUkNSewSzwJRbcueqknXRWwj97SXqpnYfKqZq78dnEF10SWsr\
/NMKi+7XAkEA4PVqDv/OZAbWr4syXZNv/Mpl4r5suzYMMUD9U8B2JIRnrhmGZPzL\
x23N9J4hEJ+Xh8tSKVc80jOkrvGlSv+BxwJAaTOtjA3YTV+gU7Hdza53sCnSw/8F\
YLrgc6NOJtYhX9xqdevbyn1lkU0zPr8mPYg/F84m6MXixm2iuSz8HZoyzwJARi2p\
aYZ5/5B2lwroqnKdZBJMGKFpUDn7Mb5hiSgocxnvMkv6NjT66Xsi3iYakJII9q8C\
Ma1qZvT/cigmdbAh7wJAQNXyoizuGEltiSaBXx4H29EdXNYWDJ9SS5f070BRbAIl\
dqRh3rcNvpY6BKJqFapda1DjdcncZECMizT/GMrc1w==\
-----END RSA PRIVATE KEY-----";
var MERCHANT_CERT="-----BEGIN CERTIFICATE-----\
MIIBvTCCASYCCQD55fNzc0WF7TANBgkqhkiG9w0BAQUFADAjMQswCQYDVQQGEwJK\
UDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwHhcNMTAwNTI4MDIwODUxWhcNMjAwNTI1\
MDIwODUxWjAjMQswCQYDVQQGEwJKUDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwgZ8w\
DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANGEYXtfgDRlWUSDn3haY4NVVQiKI9Cz\
Thoua9+DxJuiseyzmBBe7Roh1RPqdvmtOHmEPbJ+kXZYhbozzPRbFGHCJyBfCLzQ\
fVos9/qUQ88u83b0SFA2MGmQWQAlRtLy66EkR4rDRwTj2DzR4EEXgEKpIvo8VBs/\
3+sHLF3ESgAhAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAEZ6mXFFq3AzfaqWHmCy1\
ARjlauYAa8ZmUFnLm0emg9dkVBJ63aEqARhtok6bDQDzSJxiLpCEF6G4b/Nv/M/M\
LyhP+OoOTmETMegAVQMq71choVJyOFE5BtQa6M/lCHEOya5QUfoRF2HF9EjRF44K\
3OK+u3ivTSj3zwjtpudY5Xo=\
-----END CERTIFICATE-----";
var BANK_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\
MIICWwIBAAKBgQDRhGF7X4A0ZVlEg594WmODVVUIiiPQs04aLmvfg8SborHss5gQ\
Xu0aIdUT6nb5rTh5hD2yfpF2WIW6M8z0WxRhwicgXwi80H1aLPf6lEPPLvN29EhQ\
NjBpkFkAJUbS8uuhJEeKw0cE49g80eBBF4BCqSL6PFQbP9/rByxdxEoAIQIDAQAB\
AoGAA9/q3Zk6ib2GFRpKDLO/O2KMnAfR+b4XJ6zMGeoZ7Lbpi3MW0Nawk9ckVaX0\
ZVGqxbSIX5Cvp/yjHHpww+QbUFrw/gCjLiiYjM9E8C3uAF5AKJ0r4GBPl4u8K4bp\
bXeSxSB60/wPQFiQAJVcA5xhZVzqNuF3EjuKdHsw+dk+dPECQQDubX/lVGFgD/xY\
uchz56Yc7VHX+58BUkNSewSzwJRbcueqknXRWwj97SXqpnYfKqZq78dnEF10SWsr\
/NMKi+7XAkEA4PVqDv/OZAbWr4syXZNv/Mpl4r5suzYMMUD9U8B2JIRnrhmGZPzL\
x23N9J4hEJ+Xh8tSKVc80jOkrvGlSv+BxwJAaTOtjA3YTV+gU7Hdza53sCnSw/8F\
YLrgc6NOJtYhX9xqdevbyn1lkU0zPr8mPYg/F84m6MXixm2iuSz8HZoyzwJARi2p\
aYZ5/5B2lwroqnKdZBJMGKFpUDn7Mb5hiSgocxnvMkv6NjT66Xsi3iYakJII9q8C\
Ma1qZvT/cigmdbAh7wJAQNXyoizuGEltiSaBXx4H29EdXNYWDJ9SS5f070BRbAIl\
dqRh3rcNvpY6BKJqFapda1DjdcncZECMizT/GMrc1w==\
-----END RSA PRIVATE KEY-----";
var BANK_CERT="-----BEGIN CERTIFICATE-----\
MIIBvTCCASYCCQD55fNzc0WF7TANBgkqhkiG9w0BAQUFADAjMQswCQYDVQQGEwJK\
UDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwHhcNMTAwNTI4MDIwODUxWhcNMjAwNTI1\
MDIwODUxWjAjMQswCQYDVQQGEwJKUDEUMBIGA1UEChMLMDAtVEVTVC1SU0EwgZ8w\
DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANGEYXtfgDRlWUSDn3haY4NVVQiKI9Cz\
Thoua9+DxJuiseyzmBBe7Roh1RPqdvmtOHmEPbJ+kXZYhbozzPRbFGHCJyBfCLzQ\
fVos9/qUQ88u83b0SFA2MGmQWQAlRtLy66EkR4rDRwTj2DzR4EEXgEKpIvo8VBs/\
3+sHLF3ESgAhAgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAEZ6mXFFq3AzfaqWHmCy1\
ARjlauYAa8ZmUFnLm0emg9dkVBJ63aEqARhtok6bDQDzSJxiLpCEF6G4b/Nv/M/M\
LyhP+OoOTmETMegAVQMq71choVJyOFE5BtQa6M/lCHEOya5QUfoRF2HF9EjRF44K\
3OK+u3ivTSj3zwjtpudY5Xo=\
-----END CERTIFICATE-----";