[DeviceHome] Support one time pincode 14/274114/8
authorDongHyun Song <dh81.song@samsung.com>
Thu, 21 Apr 2022 11:13:37 +0000 (20:13 +0900)
committerDongHyun Song <dh81.song@samsung.com>
Mon, 9 May 2022 05:25:41 +0000 (14:25 +0900)
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 <dh81.song@samsung.com>
device_home/pincode/js/pincode.js [changed mode: 0755->0644]
device_home/service/service.js

old mode 100755 (executable)
new mode 100644 (file)
index e284054..8e40d83
@@ -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();
+    }
 };
index d73de5a..1428a02 100644 (file)
@@ -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)