diff --git a/addons/point_of_sale/static/lib/sha1.js b/addons/point_of_sale/static/lib/sha1.js new file mode 100644 index 00000000000..0fc324cfd33 --- /dev/null +++ b/addons/point_of_sale/static/lib/sha1.js @@ -0,0 +1,159 @@ +/* from http://www.movable-type.co.uk/scripts/sha1.html */ +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +/* SHA-1 implementation in JavaScript (c) Chris Veness 2002-2014 / MIT Licence */ +/* */ +/* - see http://csrc.nist.gov/groups/ST/toolkit/secure_hashing.html */ +/* http://csrc.nist.gov/groups/ST/toolkit/examples.html */ +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + +/* jshint node:true *//* global define, escape, unescape */ +'use strict'; + + +/** + * SHA-1 hash function reference implementation. + * + * @namespace + */ +var Sha1 = {}; + + +/** + * Generates SHA-1 hash of string. + * + * @param {string} msg - (Unicode) string to be hashed. + * @returns {string} Hash of msg as hex character string. + */ +Sha1.hash = function(msg) { + // convert string to UTF-8, as SHA only deals with byte-streams + msg = msg.utf8Encode(); + + // constants [§4.2.1] + var K = [ 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 ]; + + // PREPROCESSING + + msg += String.fromCharCode(0x80); // add trailing '1' bit (+ 0's padding) to string [§5.1.1] + + // convert string msg into 512-bit/16-integer blocks arrays of ints [§5.2.1] + var l = msg.length/4 + 2; // length (in 32-bit integers) of msg + ‘1’ + appended length + var N = Math.ceil(l/16); // number of 16-integer-blocks required to hold 'l' ints + var M = new Array(N); + + for (var i=0; i>> 32, but since JS converts + // bitwise-op args to 32 bits, we need to simulate this by arithmetic operators + M[N-1][14] = ((msg.length-1)*8) / Math.pow(2, 32); M[N-1][14] = Math.floor(M[N-1][14]); + M[N-1][15] = ((msg.length-1)*8) & 0xffffffff; + + // set initial hash value [§5.3.1] + var H0 = 0x67452301; + var H1 = 0xefcdab89; + var H2 = 0x98badcfe; + var H3 = 0x10325476; + var H4 = 0xc3d2e1f0; + + // HASH COMPUTATION [§6.1.2] + + var W = new Array(80); var a, b, c, d, e; + for (var i=0; i>>(32-n)); +}; + + +/** + * Hexadecimal representation of a number. + * @private + */ +Sha1.toHexStr = function(n) { + // note can't use toString(16) as it is implementation-dependant, + // and in IE returns signed numbers when used on full words + var s="", v; + for (var i=7; i>=0; i--) { v = (n>>>(i*4)) & 0xf; s += v.toString(16); } + return s; +}; + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ + + +/** Extend String object with method to encode multi-byte string to utf8 + * - monsur.hossa.in/2012/07/20/utf-8-in-javascript.html */ +if (typeof String.prototype.utf8Encode == 'undefined') { + String.prototype.utf8Encode = function() { + return unescape( encodeURIComponent( this ) ); + }; +} + +/** Extend String object with method to decode utf8 string to multi-byte */ +if (typeof String.prototype.utf8Decode == 'undefined') { + String.prototype.utf8Decode = function() { + try { + return decodeURIComponent( escape( this ) ); + } catch (e) { + return this; // invalid UTF-8? return as-is + } + }; +} + + +/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ +if (typeof module != 'undefined' && module.exports) module.exports = Sha1; // CommonJs export +if (typeof define == 'function' && define.amd) define([], function() { return Sha1; }); // AMD diff --git a/addons/point_of_sale/views/point_of_sale.xml b/addons/point_of_sale/views/point_of_sale.xml index b476328700a..1d8cc009793 100644 --- a/addons/point_of_sale/views/point_of_sale.xml +++ b/addons/point_of_sale/views/point_of_sale.xml @@ -10,6 +10,7 @@ + diff --git a/addons/pos_hr/models/__init__.py b/addons/pos_hr/models/__init__.py index 5e5c6fc9b07..784da4cda9e 100644 --- a/addons/pos_hr/models/__init__.py +++ b/addons/pos_hr/models/__init__.py @@ -2,3 +2,4 @@ from . import pos_config from . import pos_order +from . import hr_employee diff --git a/addons/pos_hr/models/hr_employee.py b/addons/pos_hr/models/hr_employee.py new file mode 100644 index 00000000000..fc5a3f9b154 --- /dev/null +++ b/addons/pos_hr/models/hr_employee.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +import hashlib + +from odoo import api, models + +class HrEmployee(models.Model): + + _inherit = 'hr.employee' + + def get_barcodes_and_pin_hashed(self): + if not self.env.user.has_group('point_of_sale.group_pos_user'): + return [] + # Apply visibility filters (record rules) + visible_emp_ids = self.search([('id', 'in', self.ids)]) + employees_data = self.sudo().search_read([('id', 'in', visible_emp_ids.ids)], ['barcode', 'pin']) + + for e in employees_data: + e['barcode'] = hashlib.sha1(e['barcode'].encode('utf8')).hexdigest() if e['barcode'] else False + e['pin'] = hashlib.sha1(e['pin'].encode('utf8')).hexdigest() if e['pin'] else False + return employees_data diff --git a/addons/pos_hr/static/src/js/gui.js b/addons/pos_hr/static/src/js/gui.js index b0faa322924..45c20b7551e 100644 --- a/addons/pos_hr/static/src/js/gui.js +++ b/addons/pos_hr/static/src/js/gui.js @@ -56,7 +56,7 @@ gui.Gui.include({ self.show_popup('password',{ 'title': _t('Password ?'), confirm: function (pw) { - if (pw !== password) { + if (Sha1.hash(pw) !== password) { self.show_popup('error', _t('Incorrect Password')); reject(); } else { diff --git a/addons/pos_hr/static/src/js/models.js b/addons/pos_hr/static/src/js/models.js index 54a6b1d31d1..4d9e0e20e23 100644 --- a/addons/pos_hr/static/src/js/models.js +++ b/addons/pos_hr/static/src/js/models.js @@ -2,6 +2,7 @@ odoo.define('pos_hr.employees', function (require) { "use strict"; var models = require('point_of_sale.models'); +var rpc = require('web.rpc'); models.load_models([{ model: 'res.users', @@ -27,7 +28,7 @@ models.load_models([{ }, },{ model: 'hr.employee', - fields: ['name', 'id', 'barcode', 'pin', 'user_id'], + fields: ['name', 'id', 'user_id'], domain: function(self){ return [['company_id', '=', self.config.company_id[0]]]; }, loaded: function(self, employees) { if (self.config.module_pos_hr) { @@ -53,4 +54,29 @@ models.load_models([{ } } }]); + +var posmodel_super = models.PosModel.prototype; +models.PosModel = models.PosModel.extend({ + load_server_data: function () { + var self = this; + return posmodel_super.load_server_data.apply(this, arguments).then(function () { + var employee_ids = _.map(self.employees, function(employee){return employee.id;}); + var records = rpc.query({ + model: 'hr.employee', + method: 'get_barcodes_and_pin_hashed', + args: [employee_ids], + }); + return records.then(function (employee_data) { + self.employees.forEach(function (employee) { + var data = _.findWhere(employee_data, {'id': employee.id}); + if (data !== undefined){ + employee.barcode = data.barcode; + employee.pin = data.pin; + } + }); + }); + }); + }, +}); + }); diff --git a/addons/pos_hr/static/src/js/screens.js b/addons/pos_hr/static/src/js/screens.js index 9b7fe1c4a9a..bef83516f0f 100644 --- a/addons/pos_hr/static/src/js/screens.js +++ b/addons/pos_hr/static/src/js/screens.js @@ -17,7 +17,7 @@ ScreenWidget.include({ var self = this; var employees = this.pos.employees; for(var i = 0, len = employees.length; i < len; i++){ - if(employees[i].barcode === code.code){ + if(employees[i].barcode === Sha1.hash(code.code)){ if (employees[i].id !== this.pos.get_cashier().id && employees[i].pin) { return this.gui.ask_password(employees[i].pin).then(function(){ self.pos.set_cashier(employees[i]);