From: DongHyun Song Date: Thu, 21 Apr 2022 11:13:37 +0000 (+0900) Subject: [DeviceHome] Support one time pincode X-Git-Tag: submit/tizen/20220513.160022~1^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F14%2F274114%2F8;p=platform%2Fframework%2Fweb%2Fwrtjs.git [DeviceHome] Support one time pincode If the 'url' contains a query string '?p=', then it try to verify OTP to DeviceHome server. - this OTP is only alive within 60s. Change-Id: Ic8c22747015f070e1ff5472b94727dc5a2b549b6 Signed-off-by: DongHyun Song --- diff --git a/device_home/pincode/js/pincode.js b/device_home/pincode/js/pincode.js old mode 100755 new mode 100644 index e284054a..8e40d83f --- a/device_home/pincode/js/pincode.js +++ b/device_home/pincode/js/pincode.js @@ -6,17 +6,31 @@ var publicKey; var input = ''; var dots = document.querySelectorAll('.dot'), numbers = document.querySelectorAll('.number'); -function displayPincode() { +function request(method, url, body, callback) { var xhr = new XMLHttpRequest(); xhr.onload = function() { if (xhr.status === 200 || xhr.status === 201) { - publicKey = xhr.responseText; + callback(xhr.responseText); } else { console.error(xhr.responseText); } }; - xhr.open('GET', serverURL + ':' + serverPort + '/pincode/publicKey'); - xhr.send(); + xhr.open(method, url); + if (body) { + xhr.setRequestHeader("Content-Type", "application/json"); + xhr.send(JSON.stringify(body)); + } else { + xhr.send(); + } +} + +function displayPincode() { + request('GET', `${serverURL}:${serverPort}/pincode/publicKey`, + null, + (result) => { + publicKey = result; + } + ); } function init() { @@ -52,33 +66,42 @@ function init() { }); } -async function sendPinCode(data) { +function handleResult(result) { + if (result === 'retry') { + dots.forEach(function (dot, index) { + dot.classList.add('wrong'); + }); + document.body.classList.add('wrong'); + setTimeout(function () { + alert('Failed to input 5 times. A new Pincode has been generated, so check the TV notification.'); + }, 1000); + } else { + chkPinCode(result === 'true' ? true : false); + } +} + +function sendPinCode(data) { var encrypt = new JSEncrypt(); encrypt.setPublicKey(publicKey); - var xhr = new XMLHttpRequest(); - xhr.onload = function() { - if (xhr.status === 200 || xhr.status === 201) { - console.log(`result : ${xhr.responseText}`); - if (xhr.responseText === 'retry') { - dots.forEach(function(dot, index) { - dot.classList.add('wrong'); - }); - document.body.classList.add('wrong'); - setTimeout(function() { - alert('Failed to input 5 times. A new Pincode has been generated, so check the TV notification.'); - }, 1000); - } else { - chkPinCode(xhr.responseText === 'true' ? true : false); - } - } else { - console.error(xhr.responseText); - } - }; - xhr.open('POST', serverURL + ':' + serverPort + '/pincode/pinCodeToServer'); - xhr.setRequestHeader("Content-Type", "application/json"); var data = encrypt.encrypt(data); console.log(`${TAG} data: ${data}`); - xhr.send(JSON.stringify({ pincode: data.toString("utf8") })); + data = { pincode: data.toString("utf8") }; + + request('POST', `${serverURL}:${serverPort}/pincode/pinCodeToServer`, + data, + (result) => { + handleResult(result); + } + ); +} + +function verifyPincode(pincode) { + request('POST', `${serverURL}:${serverPort}/pincode/verifyPincode`, + { pincode }, // need to encrypt by server public key (nice-to-have) + (result) => { + handleResult(result); + } + ); } function chkPinCode(returnVal) { @@ -103,6 +126,13 @@ function pinCode() { } window.onload = function() { - displayPincode(); - init(); + let queryString = location.search; + if (queryString) { + let pincode = queryString.substr(3); // strip '?p=' + console.log(`${TAG} pincode : ${pincode}`); + verifyPincode(pincode); + } else { + displayPincode(); + init(); + } }; diff --git a/device_home/service/service.js b/device_home/service/service.js index d73de5a3..1428a021 100644 --- a/device_home/service/service.js +++ b/device_home/service/service.js @@ -1,14 +1,12 @@ 'use strict'; const express = require('express'); -const fs = require('fs'); const http = require('http'); const path = require('path'); const relayServer = require('./relay-server.js'); const session = require('express-session'); const cookieParser = require('cookie-parser'); const EventEmitter = require('events'); -const XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest; const crypto = require('crypto'); const { Security } = require('./security.js'); const JSEncryptLib = require('./jsencrypt'); @@ -52,6 +50,7 @@ var g = { var tryCount = 0; var sip; var clientPublicKeys = {}; +var oneTimePincode = ''; // The pincode is disabled just for demo. var DEMO_MODE = false; @@ -246,7 +245,7 @@ function registerWrtMessagePort() { try { evtEmit.emit(data[0]['key'], 'message', data[0]['value']); } catch (e) { - console.log('wrt.message.port has exception' + e); + console.log(`${TAG} wrt.message.port has exception ${e}`); } }); } @@ -309,10 +308,26 @@ function comparePincode(req, res, encrypted) { } } +let clearOtpTimer = null; +function generateOneTimePinCode() { + const byteData = crypto.randomBytes(256); + if (!oneTimePincode) { + oneTimePincode = parseInt(byteData.toString('hex').substr(0, 8), 16).toString().substr(0, 4); + } + if (clearOtpTimer) { + clearTimeout(clearOtpTimer); + } + clearOtpTimer = setTimeout(() => { + oneTimePincode = ''; + }, 60 * 1000); + + console.log(`${TAG} oneTimePincode : ${oneTimePincode}`); + return oneTimePincode; +} + async function displayPincode(req) { // Generate pincode - const byteData = crypto.randomBytes(256); - req.session.pincode = parseInt(byteData.toString('hex').substr(0, 8), 16).toString().substr(0, 4); + req.session.pincode = generateOneTimePinCode(); // Generate RSA keys await security.awaitKeyPair(req); // Show pincode popup @@ -324,6 +339,7 @@ function getIp(rawIp) { } var HTTPserverStart = function() { + console.log(`${TAG} HTTPserverStart`); evtEmit = new EventEmitter(); const app = express(); app.engine('html', require('ejs').renderFile); @@ -534,6 +550,17 @@ var HTTPserverStart = function() { comparePincode(req, res, resultData); }); + app.post('/pincode/verifyPincode', express.json(), (req, res) => { + // Verify onetime pincode + const resultData = req.body['pincode']; + console.log(`${TAG} verifyPincode resultData : ${resultData}`); + let base64otp = Buffer.from(oneTimePincode, 'utf8').toString('base64'); + let isSame = (base64otp == resultData); + if (isSame) + req.session.ip = getIp(req.socket.remoteAddress); + res.send(isSame); + }); + app.post('/pincode/publicKeyToServer', express.json(), (req, res) => { const pkgId = req.body['pkgId'] if (clientPublicKeys[pkgId] === undefined)