/* This file is part of web3.js. web3.js is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. web3.js is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with web3.js. If not, see . */ /** * @file iban.js * @author Marek Kotewicz * @date 2015 */ var BigNumber = require('bignumber.js'); var padLeft = function (string, bytes) { var result = string; while (result.length < bytes * 2) { result = '00' + result; } return result; }; /** * Prepare an IBAN for mod 97 computation by moving the first 4 chars to the end and transforming the letters to * numbers (A = 10, B = 11, ..., Z = 35), as specified in ISO13616. * * @method iso13616Prepare * @param {String} iban the IBAN * @returns {String} the prepared IBAN */ var iso13616Prepare = function (iban) { var A = 'A'.charCodeAt(0); var Z = 'Z'.charCodeAt(0); iban = iban.toUpperCase(); iban = iban.substr(4) + iban.substr(0,4); return iban.split('').map(function(n){ var code = n.charCodeAt(0); if (code >= A && code <= Z){ // A = 10, B = 11, ... Z = 35 return code - A + 10; } else { return n; } }).join(''); }; /** * Calculates the MOD 97 10 of the passed IBAN as specified in ISO7064. * * @method mod9710 * @param {String} iban * @returns {Number} */ var mod9710 = function (iban) { var remainder = iban, block; while (remainder.length > 2){ block = remainder.slice(0, 9); remainder = parseInt(block, 10) % 97 + remainder.slice(block.length); } return parseInt(remainder, 10) % 97; }; /** * This prototype should be used to create iban object from iban correct string * * @param {String} iban */ var Iban = function (iban) { this._iban = iban; }; /** * This method should be used to create iban object from ethereum address * * @method fromAddress * @param {String} address * @return {Iban} the IBAN object */ Iban.fromAddress = function (address) { var asBn = new BigNumber(address, 16); var base36 = asBn.toString(36); var padded = padLeft(base36, 15); return Iban.fromBban(padded.toUpperCase()); }; /** * Convert the passed BBAN to an IBAN for this country specification. * Please note that "generation of the IBAN shall be the exclusive responsibility of the bank/branch servicing the account". * This method implements the preferred algorithm described in http://en.wikipedia.org/wiki/International_Bank_Account_Number#Generating_IBAN_check_digits * * @method fromBban * @param {String} bban the BBAN to convert to IBAN * @returns {Iban} the IBAN object */ Iban.fromBban = function (bban) { var countryCode = 'XE'; var remainder = mod9710(iso13616Prepare(countryCode + '00' + bban)); var checkDigit = ('0' + (98 - remainder)).slice(-2); return new Iban(countryCode + checkDigit + bban); }; /** * Should be used to create IBAN object for given institution and identifier * * @method createIndirect * @param {Object} options, required options are "institution" and "identifier" * @return {Iban} the IBAN object */ Iban.createIndirect = function (options) { return Iban.fromBban('ETH' + options.institution + options.identifier); }; /** * Thos method should be used to check if given string is valid iban object * * @method isValid * @param {String} iban string * @return {Boolean} true if it is valid IBAN */ Iban.isValid = function (iban) { var i = new Iban(iban); return i.isValid(); }; /** * Should be called to check if iban is correct * * @method isValid * @returns {Boolean} true if it is, otherwise false */ Iban.prototype.isValid = function () { return /^XE[0-9]{2}(ETH[0-9A-Z]{13}|[0-9A-Z]{30,31})$/.test(this._iban) && mod9710(iso13616Prepare(this._iban)) === 1; }; /** * Should be called to check if iban number is direct * * @method isDirect * @returns {Boolean} true if it is, otherwise false */ Iban.prototype.isDirect = function () { return this._iban.length === 34 || this._iban.length === 35; }; /** * Should be called to check if iban number if indirect * * @method isIndirect * @returns {Boolean} true if it is, otherwise false */ Iban.prototype.isIndirect = function () { return this._iban.length === 20; }; /** * Should be called to get iban checksum * Uses the mod-97-10 checksumming protocol (ISO/IEC 7064:2003) * * @method checksum * @returns {String} checksum */ Iban.prototype.checksum = function () { return this._iban.substr(2, 2); }; /** * Should be called to get institution identifier * eg. XREG * * @method institution * @returns {String} institution identifier */ Iban.prototype.institution = function () { return this.isIndirect() ? this._iban.substr(7, 4) : ''; }; /** * Should be called to get client identifier within institution * eg. GAVOFYORK * * @method client * @returns {String} client identifier */ Iban.prototype.client = function () { return this.isIndirect() ? this._iban.substr(11) : ''; }; /** * Should be called to get client direct address * * @method address * @returns {String} client direct address */ Iban.prototype.address = function () { if (this.isDirect()) { var base36 = this._iban.substr(4); var asBn = new BigNumber(base36, 36); return padLeft(asBn.toString(16), 20); } return ''; }; Iban.prototype.toString = function () { return this._iban; }; module.exports = Iban;