[DeviceHome] Upgrade to v1.0.6 71/262171/4 accepted/tizen/unified/20210804.043635 accepted/tizen/unified/20210804.043636 submit/tizen/20210803.160020 submit/tizen/20210803.230135
authorYoungsoo Choi <kenshin.choi@samsung.com>
Tue, 3 Aug 2021 08:49:22 +0000 (01:49 -0700)
committerYoungsoo Choi <kenshin.choi@samsung.com>
Tue, 3 Aug 2021 09:04:46 +0000 (02:04 -0700)
- Support message port communication between device home and web app
  instead of web socket to prevent smack security vulnerabilities
- Support emulator connection with device home

Change-Id: Ia23f954a8b2c5a6020490a3b8c47ae2120b56bb4
Signed-off-by: Youngsoo Choi <kenshin.choi@samsung.com>
device_home/client/js/myApps.js
device_home/pincode/js/pincode.js
device_home/service/relay-server.js
device_home/service/service.js

index 9ea6114..9e2b7e5 100755 (executable)
@@ -143,4 +143,3 @@ const myappsmodule = {};
 export function openAppWindow(response) {
     myappsmodule.openAppWindow(response);
 };
-
index fd03484..e284054 100755 (executable)
@@ -24,20 +24,20 @@ function init() {
     numbers = Array.prototype.slice.call(numbers);
     numbers.forEach(function(number, index) {
         number.addEventListener('click', function() {
-            number.className += ' grow';
+            number.classList.add('grow');
             if (number.innerHTML === '0') {
                 input += 0;
             } else {
                 input += index + 1;
             }
-            dots[input.length - 1].className += ' active';
+            dots[input.length - 1].classList.add('active');
             if (input.length >= 4) {
                 console.log(`${TAG} input: ${input}`);
                 sendPinCode(input);
 
                 setTimeout(function() {
                     dots.forEach(function(dot, index) {
-                        dot.className = 'dot';
+                        dot.classList.add('dot');
                     });
                     input = '';
                 }, 900);
@@ -46,7 +46,7 @@ function init() {
                 }, 1000);
             }
             setTimeout(function() {
-                number.className = 'number';
+                number.classList.add('number');
             }, 1000);
         });
     });
@@ -63,7 +63,7 @@ async function sendPinCode(data) {
                 dots.forEach(function(dot, index) {
                     dot.classList.add('wrong');
                 });
-                document.body.className += ' 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);
@@ -84,17 +84,17 @@ async function sendPinCode(data) {
 function chkPinCode(returnVal) {
     if (returnVal) {
         dots.forEach(function(dot, index) {
-            dot.className += ' correct';
+            dot.classList.add('correct');
         });
-        document.body.className += ' correct';
+        document.body.classList.add('correct');
         setTimeout(function() {
             loginForm.submit();
         }, 1000);
     } else {
         dots.forEach(function(dot, index) {
-            dot.className += ' wrong';
+            dot.classList.add('wrong');
         });
-        document.body.className += ' wrong';
+        document.body.classList.add('wrong');
     }
 }
 
index e912c4f..0063afc 100755 (executable)
@@ -1,4 +1,4 @@
-"use strict";
+'use strict';
 const io = require('socket.io');
 const JSEncryptLib = require('./jsencrypt');
 const localClientIps = [
@@ -6,14 +6,18 @@ const localClientIps = [
     '127.0.0.1'
 ];
 const TAG = '[DeviceHome][relay-server.js]'
+const TAG_HOST = `${TAG}[Host]`;
+const TAG_CLIENT = `${TAG}[Client]`;
 const TO_ALL = 100;
 
+let receiver = {};
+let sender = {};
 let remoteClients = {};
-let localClients = {};
 let localClientMessageQueues = {};
+let globalClientPublicKeys = {};
 
 var getIp = function(rawIp) {
-    return rawIp.slice(rawIp.lastIndexOf(":") + 1);
+    return rawIp.slice(rawIp.lastIndexOf(':') + 1);
 }
 var decrypt = function(msg, ws) {
     const crypto = new JSEncryptLib();
@@ -31,143 +35,130 @@ var encrypt = function(msg, ws, pkgId, clientPublicKeys) {
     console.log(`${TAG}[encrypt] plain : ${msg}`);
     return serverCrypto.encrypt(msg);
 }
+var OnReceived = function (msg) {
+    console.log(`${TAG_HOST}[OnReceived] msg[0].key : ${msg[0].key}`);
+    console.log(`${TAG_HOST}[OnReceived] msg[0].value : ${msg[0].value}`);
+    const pkgId = msg[0].key;
+    msg = JSON.parse(msg[0].value);
+    if (msg.type === 'AppId') {
+        const appId = msg.data;
+        console.log(`${TAG_HOST}[OnReceived] Initialize msg port sender : ${appId}`);
+        if (!sender[pkgId])
+            sender[pkgId] = {};
+        sender[pkgId].messagePort = tizen.messageport.requestRemoteMessagePort(appId, `${pkgId}.Companion`);
+        if (localClientMessageQueues[pkgId] !== undefined) {
+            while (localClientMessageQueues[pkgId].length) {
+                const msg = localClientMessageQueues[pkgId].shift();
+                console.log(`${TAG_HOST} #################################`);
+                console.log(`${TAG_HOST} send pending msg : ${msg}`);
+                console.log(`${TAG_HOST} #################################`);
+                sender[pkgId].messagePort.sendMessage([{
+                    key: pkgId,
+                    value: msg,
+                }]);
+            }
+        }
+    } else {
+        console.log(`${TAG_HOST}[OnReceived] Send message from msg port to web socket`);
+        if (!remoteClients || !remoteClients[pkgId].length) {
+            console.log(`${TAG_HOST}[OnReceived] There's no available web socket remote clients`);
+            return;
+        }
+        const id = msg.id;
+        if (id === -1) {
+            console.log(`${TAG_HOST}[OnReceived] Handle message only on relay server`);
+            // Do what need to handle in relay server only
+            return;
+        }
+        console.log(`${TAG_HOST}[OnReceived] id : ${id}`);
+        if (id === TO_ALL) {
+            console.log(`${TAG_HOST}[OnReceived] Send message to all web sockets`);
+            console.log(`${TAG_HOST}[OnReceived] remoteClients length : ${remoteClients[pkgId].length}`);
+            for (let client of remoteClients[pkgId]) {
+                const encrypted = encrypt(JSON.stringify(msg), client, pkgId, globalClientPublicKeys);
+                if (encrypted === false || encrypted === null) {
+                    console.log(`${TAG_HOST}[OnReceived] Failed to encrypt message!`);
+                    return;
+                }
+                console.log(`${TAG_HOST}[OnReceived] encrypted : ${encrypted}`);
+                client.emit('d2d_message', encrypted);
+            }
+        } else {
+            console.log(`${TAG_HOST}[OnReceived] Send message to a web socket #${id}`);
+            if (id < remoteClients[pkgId].length) {
+                const encrypted = encrypt(JSON.stringify(msg), remoteClients[pkgId][id], pkgId, globalClientPublicKeys);
+                if (encrypted === false || encrypted === null) {
+                    console.log(`${TAG_HOST}[OnReceived] Failed to encrypt message!`);
+                    return;
+                }
+                console.log(`${TAG_HOST}[OnReceived] encrypted : ${encrypted}`);
+                remoteClients[pkgId][id].emit('d2d_message', encrypted);
+            }
+        }
+    }
+};
 var addConnection = function(wsServer, pkgId, sessionMiddleware, clientPublicKeys) {
+    globalClientPublicKeys = clientPublicKeys;
+    // Host
+    console.log(`${TAG_HOST} Initialize msg port recevier : ${pkgId}.Companion`);
+    if (!receiver[pkgId])
+        receiver[pkgId] = {};
+    receiver[pkgId].messagePort = tizen.messageport.requestLocalMessagePort(`${pkgId}.Companion`);
+    receiver[pkgId].messagePortListener = receiver[pkgId].messagePort.addMessagePortListener(OnReceived.bind(this));
+
+    // Remote Client
+    console.log(`${TAG_CLIENT} Initialize client web socket`);
     const namespace = wsServer.of(`/${pkgId}`);
     namespace.use((socket, next) => {
         sessionMiddleware(socket.request, {}, next);
     });
     namespace.on('connection', ws => {
-        console.log(`${TAG} connection event : ${pkgId}`);
+        console.log(`${TAG_CLIENT} connection event : ${pkgId}`);
         // In case of local client, remoteAddress will be ::1
         // In case of remote client, remoteAddress will be ::ffff:ipaddress
         // e.g.) ::ffff:192.168.0.21
-        console.log(`${TAG} address : ${ws.handshake.address}`);
-        console.log(`${TAG} url : ${ws.handshake.url}`);
-        console.log(`${TAG} session id : ${ws.request.session.id}`);
+        console.log(`${TAG_CLIENT} address : ${ws.handshake.address}`);
+        console.log(`${TAG_CLIENT} url : ${ws.handshake.url}`);
+        console.log(`${TAG_CLIENT} session id : ${ws.request.session.id}`);
 
         if (remoteClients[pkgId] === undefined)
             remoteClients[pkgId] = [];
 
-        if (localClientIps.includes(getIp(ws.handshake.address))) {
-            const TAG_LOCAL = `${TAG}[Local]`;
-            console.log(`${TAG_LOCAL} connected from local`);
-            localClients[pkgId] = ws;
-            console.log(`${TAG_LOCAL} remote length : ${remoteClients[pkgId].length}`);
-
-            if (!remoteClients[pkgId].length) {
-                console.log(`${TAG_LOCAL} connected : no remote-clients`);
-            }
-            if (localClientMessageQueues[pkgId] !== undefined) {
-                while (localClientMessageQueues[pkgId].length) {
-                    const msg = localClientMessageQueues[pkgId].shift();
-                    console.log(`${TAG_LOCAL} #################################`);
-                    console.log(`${TAG_LOCAL} send pending msg : ${msg}`);
-                    console.log(`${TAG_LOCAL} #################################`);
-                    ws.emit('d2d_message', msg);
-                }
-            }
-            ws.on('d2d_message', function(msg) {
-                console.log(`${TAG_LOCAL} #################################`);
-                console.log(`${TAG_LOCAL} on d2d message : ${msg}`);
-                console.log(`${TAG_LOCAL} #################################`);
-
-                let myPkgId = null;
-                for (let key in localClients) {
-                    if (localClients[key] === ws) {
-                        myPkgId = key;
-                        break;
-                    }
-                }
-
-                let id = JSON.parse(msg).id;
-                console.log(`${TAG_LOCAL} id : ${id}`);
-                if (id == -1) {
-                    // Do what need to handle in relay server only
-                    return;
-                }
-                if (!remoteClients[myPkgId].length)
-                    return;
-                if (id == TO_ALL) {
-                    console.log(`${TAG_LOCAL} remoteClients length : ${remoteClients[myPkgId].length}`);
-                    for (let client of remoteClients[myPkgId]) {
-                        const encrypted = encrypt(msg, client, myPkgId, clientPublicKeys);
-                        if (encrypted === false || encrypted === null) {
-                            console.log("Error: Failed to encrypt message");
-                            return;
-                        }
-                        console.log(`${TAG_LOCAL} encrypted : ${encrypted}`);
-                        client.emit('d2d_message', encrypted);
-                    }
-                } else {
-                    console.log(`${TAG_LOCAL} id : ${id}`);
-                    if (id < remoteClients[myPkgId].length) {
-                        msg = encrypt(msg, remoteClients[myPkgId][id], myPkgId, clientPublicKeys);
-                        if (msg === false || msg === null) {
-                            console.log("Error: Failed to encrypt message");
-                            return;
-                        }
-                        console.log(`${TAG_LOCAL} encrypted : ${msg}`);
-                        remoteClients[myPkgId][id].emit('d2d_message', msg);
-                    }
-                }
-            });
-            ws.on('disconnect', function(msg) {
-                console.log(`${TAG_LOCAL}[close] #################################`);
-                console.log(`${TAG_LOCAL}[close] on disconnect event : ${msg}`);
-                console.log(`${TAG_LOCAL}[close] #################################`);
-                let myPkgId = null;
-                for (let key in localClients) {
-                    if (localClients[key] === ws) {
-                        myPkgId = key;
-                        break;
-                    }
-                }
-                localClients[myPkgId] = undefined;
-                console.log(`${TAG_LOCAL}[close] remoteClients[${myPkgId}] : ${remoteClients[myPkgId]}`);
-                for (let remoteClient of remoteClients[myPkgId]) {
-                    console.log(`${TAG}[close local client] sent local_client_disconnect`);
-                    let disconnection = JSON.stringify({
-                        type: "local_client_disconnect",
-                        data: {
-                            totalcount: localClients.length,
-                            id: 0
-                        },
-                        id: -1
-                    });
-                    disconnection = encrypt(disconnection, remoteClient, myPkgId, clientPublicKeys);
-                        if (disconnection === false || disconnection === null) {
-                            console.log("Error: Failed to encrypt message");
-                            return;
-                        }
-                        console.log(`${TAG_LOCAL} encrypted : ${disconnection}`);
-                    remoteClient.emit('d2d_message', disconnection);
-                }
-            });
-        } else {
-            const TAG_REMOTE = `${TAG}[Remote]`;
+        if (!localClientIps.includes(getIp(ws.handshake.address))) {
             const ip = getIp(ws.handshake.address);
-            console.log(`${TAG_REMOTE} connected from ${ip}`);
-            if (remoteClients[pkgId].indexOf(ws) == -1) {
+            console.log(`${TAG_CLIENT} connected from ${ip}`);
+            if (remoteClients[pkgId].indexOf(ws) === -1) {
                 remoteClients[pkgId].push(ws);
                 const index = remoteClients[pkgId].length - 1;
-                console.log(`${TAG_REMOTE} pkgId : ${pkgId}`);
-                console.log(`${TAG_REMOTE} remote length : ${remoteClients[pkgId].length}`);
-                console.log(`${TAG_REMOTE} local length : ${Object.keys(localClients).length}`);
+                console.log(`${TAG_CLIENT} pkgId : ${pkgId}`);
+                console.log(`${TAG_CLIENT} client length : ${remoteClients[pkgId].length}`);
+                console.log(`${TAG_CLIENT} host length : ${Object.keys(sender).length}`);
 
-                let res = JSON.stringify({type: "id", data: index, id: -1});
-                res = encrypt(res, ws, pkgId, clientPublicKeys);
-                console.log(`${TAG_REMOTE} encrypted : ${res}`);
-                if (res === false || res === null) {
-                    console.log("Error: Failed to encrypt message");
+                const res = JSON.stringify({type: 'id', data: index, id: -1});
+                const encrypted = encrypt(res, ws, pkgId, clientPublicKeys);
+                console.log(`${TAG_CLIENT} encrypted : ${encrypted}`);
+                if (encrypted === false || encrypted === null) {
+                    console.log('Error: Failed to encrypt message');
                     return;
                 }
-                ws.emit('d2d_message', res);
+                ws.emit('d2d_message', encrypted);
+                if (sender[pkgId]) {
+                    sender[pkgId].messagePort.sendMessage([{
+                        key: pkgId,
+                        value: res,
+                    }]);
+                }
 
-                console.log(`${TAG_REMOTE}[connection] localClients.length : ${localClients.length}`);
-                if (localClients[pkgId] === undefined || Object.keys(localClients).length === 0) {
-                    console.log(`${TAG_REMOTE} connected : no local-client`);
+                console.log(`${TAG_CLIENT}[connection] sender.length : ${sender.length}`);
+                if (sender[pkgId] === undefined || Object.keys(sender).length === 0) {
+                    console.log(`${TAG_CLIENT} connected : waiting for host`);
                 } else {
-                    localClients[pkgId].emit('d2d_message', JSON.stringify({type: "new_client", data: index, id: -1}));
+                    if (sender[pkgId]) {
+                        sender[pkgId].messagePort.sendMessage([{
+                            key: pkgId,
+                            value: JSON.stringify({type: 'new_client', data: index, id: -1}),
+                        }]);
+                    }
                 }
             }
             ws.on('d2d_message', function(msg) {
@@ -178,32 +169,35 @@ var addConnection = function(wsServer, pkgId, sessionMiddleware, clientPublicKey
                         break;
                     }
                 }
-                console.log(`${TAG_REMOTE} #################################`);
-                console.log(`${TAG_REMOTE} on d2d message : ${msg}`);
+                console.log(`${TAG_CLIENT} #################################`);
+                console.log(`${TAG_CLIENT} on d2d message : ${msg}`);
                 msg = decrypt(msg, ws);
-                console.log(`${TAG_REMOTE} #################################`);
+                console.log(`${TAG_CLIENT} #################################`);
                 if (msg === false || msg === null) {
-                    console.log("Error: Failed to decrypt message");
+                    console.log('Error: Failed to decrypt message');
                     return;
                 }
 
-                if (localClients[myPkgId]) {
-                    console.log(`${TAG_REMOTE} decrypted : ${msg}`);
-                    localClients[myPkgId].emit('d2d_message', msg);
+                if (sender[myPkgId]) {
+                    console.log(`${TAG_CLIENT} decrypted : ${msg}`);
+                    sender[myPkgId].messagePort.sendMessage([{
+                        key: myPkgId,
+                        value: msg,
+                    }]);
                 } else {
-                    console.log(`${TAG_REMOTE} #################################`);
-                    console.log(`${TAG_REMOTE} localClient is not ready`);
-                    console.log(`${TAG_REMOTE} #################################`);
+                    console.log(`${TAG_CLIENT} #################################`);
+                    console.log(`${TAG_CLIENT} localClient is not ready`);
+                    console.log(`${TAG_CLIENT} #################################`);
                     if (localClientMessageQueues[myPkgId] === undefined)
                         localClientMessageQueues[myPkgId] = [];
                     localClientMessageQueues[myPkgId].push(msg);
-                    console.log(`${TAG_REMOTE} localClient is not ready : ${localClientMessageQueues[myPkgId]}`);
+                    console.log(`${TAG_CLIENT} localClient is not ready : ${localClientMessageQueues[myPkgId]}`);
                 }
             });
             ws.on('disconnect', function(msg) {
-                console.log(`${TAG_REMOTE}[close] #################################`);
-                console.log(`${TAG_REMOTE}[close] on disconnect event : ${msg}`);
-                console.log(`${TAG_REMOTE}[close] #################################`);
+                console.log(`${TAG_CLIENT}[close] #################################`);
+                console.log(`${TAG_CLIENT}[close] on disconnect event : ${msg}`);
+                console.log(`${TAG_CLIENT}[close] #################################`);
                 let myPkgId = null;
                 for (let key in remoteClients) {
                     if (remoteClients[key].indexOf(ws) != -1) {
@@ -215,17 +209,20 @@ var addConnection = function(wsServer, pkgId, sessionMiddleware, clientPublicKey
                 let index = remoteClients[myPkgId].indexOf(ws);
                 remoteClients[myPkgId][index] = undefined;
                 remoteClients[myPkgId].splice(index, 1);
-                console.log(`${TAG_REMOTE}[close] localClients[${myPkgId}] : ${localClients[myPkgId]}`);
-                if (localClients[myPkgId] !== undefined) {
-                    console.log(`${TAG_REMOTE}[close] sent remote_client_disconnect`);
-                    localClients[myPkgId].emit('d2d_message', JSON.stringify({
-                        type: "remote_client_disconnect",
-                        data: {
-                            totalcount: remoteClients[myPkgId].length,
-                            id: index
-                        },
-                        id: -1
-                    }));
+                console.log(`${TAG_CLIENT}[close] sender[${myPkgId}] : ${sender[myPkgId]}`);
+                if (sender[myPkgId] !== undefined) {
+                    console.log(`${TAG_CLIENT}[close] sent remote_client_disconnect to host`);
+                    sender[myPkgId].messagePort.sendMessage([{
+                        key: pkgId,
+                        value: JSON.stringify({
+                            type: 'remote_client_disconnect',
+                            data: {
+                                totalcount: remoteClients[myPkgId].length,
+                                id: index
+                            },
+                            id: -1
+                        }),
+                    }]);
                 }
             });
         }
index c7206f6..8e2882d 100755 (executable)
@@ -26,11 +26,14 @@ const TIZEN_WEB_APP_SHARED_RESOURCES = 'shared/res/';
 const WEBCLIP_DIRECTORY = 'webclip';
 const WEBCLIP_MANIFEST = 'manifest.json';
 const is_tv = webapis.cachedProperty !== undefined;
+const emulator_ip = '10.0.2.15';
+const local_ip = '127.0.0.1';
 const non_ip_list = [
   '1',
-  '127.0.0.1',
-  '192.168.250.250'
+  '192.168.250.250',
+  local_ip
 ]
+
 const security = new Security();
 
 var apps = [];
@@ -194,8 +197,18 @@ function getWebClipsList() {
 }
 
 function sendLoginIdAndDeviceName(login_id, device_ip) {
-  const device_name = webapis.mde.getDeviceName();
-  console.log(`${TAG} login_id = ${login_id}, device_name = ${device_name}`);
+  let device_name = 'Tizen';
+  if (device_ip === emulator_ip) {
+    device_ip = `${local_ip}:${g.port}`;
+    device_name = 'Tizen Emulator';
+    // Skip pin-code for emulator
+    DEMO_MODE = true;
+  } else if (typeof webapis.mde !== 'undefined') {
+    device_name = webapis.mde.getDeviceName();
+  }
+  console.log(`${TAG} login_id : ${login_id}`);
+  console.log(`${TAG} device_ip : ${device_ip}`);
+  console.log(`${TAG} device_name : ${device_name}`);
 
   const xhr = new XMLHttpRequest();
   const keyVal = {
@@ -223,7 +236,7 @@ function sendLoginIdAndDeviceName(login_id, device_ip) {
 function updateDNSresolver(device_ip) {
   console.log(`${TAG} Server is listening on ${device_ip}:${g.port}`);
   let login_id = 'stester81@gmail.com';
-  if (is_tv)
+  if (is_tv && typeof webapis.mde !== 'undefined')
     login_id = webapis.mde.getCurrentLoginId();
   sendLoginIdAndDeviceName(login_id, device_ip);
 }
@@ -368,7 +381,7 @@ var HTTPserverStart = function() {
     res.sendFile(file, options, function(err) {
       if (err) {
         console.log(`${TAG} err: ${err}`);
-        res.send("err", err);
+        res.status('err').send(err);
       } else {
         console.log(`${TAG} res.sendFile() done: ${file}`);
       }
@@ -410,7 +423,8 @@ var HTTPserverStart = function() {
         // FIXME: Remove app logic here
         res.render("client/invited.html");
       } else if (req.query.pageUrl !== undefined) {
-        webapis.mde.launchBrowserFromUrl(req.query.pageUrl);
+        if (typeof webapis.mde !== 'undefined')
+          webapis.mde.launchBrowserFromUrl(req.query.pageUrl);
       } else {
         // Device home
         res.render("client/client.html");
@@ -485,7 +499,8 @@ var HTTPserverStart = function() {
   });
 
   app.post('/url', (req, res) => {
-    webapis.mde.launchBrowserFromUrl(req.body.url);
+    if (typeof webapis.mde !== 'undefined')
+      webapis.mde.launchBrowserFromUrl(req.body.url);
   });
 
   httpserver = http.createServer(app);