//WebSocket var WebSocket_value = '1.0.0'; //(預設)依照瀏覽器動態給版本 var beta_WebSocket_value = '1.0.0'; //(預設)依照瀏覽器動態給正式測試版本 var local_WebSocket_value = '0.0.0'; //(預設)local 版本 var msg_WS_title = '關務署關務資訊組 提示訊息 \r\n'; //(預設)msg var msg_WS_version = '請安裝WebSocket元件'; //(預設)msg var window_WebSocket_value = '1.2.3'; //window 目前穩定發佈版本(供比對使用者的版本) var window_WebSocket_value_beta = '1.2.3'; //window 正式測試版本 var Mac_WebSocket_value = '1.2.4mac'; //MAC 目前穩定發佈版本(供比對使用者的版本) var Mac_WebSocket_value_beta = '1.2.4mac'; //MAC 正式測試版本 var download_WebSocket_value; //下載時提供的版本(checkOS()依作業系統設定, 測試通過的最新發佈版本) //有使用WebSocket.js 都要檢查WebSocket版本 $(function() { //判斷IE瀏覽器 IE10以上版本才執行 if(checkBrowser(false)){ //有憑證資料欄位才檢查 if($('#signature').size() > 0){ //確認作業系統 checkOS(); //確認版本 checkWebSocketVersion(false); } } }); //只有用判斷IE瀏覽器 只有判斷 IE6 IE7 IE8 IE9 function isIE(ver) { var b = document.createElement('b') b.innerHTML = '' return b.getElementsByTagName('i').length === 1 } //只有用判斷IE瀏覽器 function checkBrowser(alertMsg) { //IE6 if(isIE(6)) { if(alertMsg) alert("您的IE瀏覽器版本為 IE6 憑證套件WebSocket 不支援 !"); return false; } //IE7 if(isIE(7)) { if(alertMsg) alert("您的IE瀏覽器版本為 IE7 憑證套件WebSocket 不支援 !"); return false; } //IE8 if(isIE(8)) { if(alertMsg) alert("您的IE瀏覽器版本為 IE8 憑證套件WebSocket 不支援 !"); return false; } //IE9 if(isIE(9)) { if(alertMsg) alert("您的IE瀏覽器版本為 IE9 憑證套件WebSocket 不支援 !"); return false; } return true; } //檢查 OS 系統 (clientOs.js) 並給 os WebSocket 版號 function checkOS() { var os = $.client.os; console.log("client os = " + os); if(os=='Windows'){ WebSocket_value = window_WebSocket_value; beta_WebSocket_value= window_WebSocket_value_beta download_WebSocket_value = "1.3.3.4"; }else if(os=='Mac'){ WebSocket_value = Mac_WebSocket_value; beta_WebSocket_value= Mac_WebSocket_value_beta download_WebSocket_value = "1.2.4mac"; }else{ WebSocket_value = 'NVL'; beta_WebSocket_value= 'NVL'; } } //檢查WebSocket版本 正式版 與 beta 都可以 function checkVersion() { var local_WS_int = 0; var WS_int = 0; var beta_WS_int = 0; //基於指定WebSocket版本之歷史共業,參考俊宏(TV6286)建議修改檢查WebSocket版本方法,避免較高版本也被誤判為版本過低問題 try{ //因為若有重大更新才會表現在版本號前三碼,所以只取版本號前三碼並轉為整數做比較 local_WS_int = local_WebSocket_value.replace(/\./g, "").substr( 0, 3 ); WS_int = WebSocket_value.replace('mac','').replace(/\./g, "").substr( 0, 3 ); beta_WS_int = beta_WebSocket_value.replace('mac','').replace(/\./g, "").substr( 0, 3 ); }catch(e) { console.log("##### WebSocket checkVersion fail #####"); return true; } console.group("### checkVersion ###"); console.log("local_WebSocket_value = " + local_WebSocket_value ); console.log("WebSocket_value = " + WebSocket_value ); console.log("beta_WebSocket_value = " + beta_WebSocket_value ); //console.log("local_WS_int = " + local_WS_int ); //console.log("WS_int = " + WS_int ); //console.log("beta_WS_int = " + beta_WS_int ); console.groupEnd(); //若低於指定版本會回傳true讓提示訊息跳出 if( ( local_WS_int < WS_int ) && ( local_WS_int < beta_WS_int ) ){ return true; } /* if ( local_WebSocket_value != WebSocket_value.replace('mac','') && local_WebSocket_value != beta_WebSocket_value.replace('mac','') ) { return true; } */ return false; } function checkWebSocketVersion(download) { console.group("##### checkWebSocketVersion #####"); var downloadMsg = "<安裝WebSocket "+download_WebSocket_value+" 版本元件>\r\n"+ "為提供跨瀏覽器憑證支援服務,\r\n"+ "使用新版憑證登入者,請務必安裝憑證WebSocket元件,\r\n"+ "若尚未安裝,請點選確定按鈕下載檔案,解壓縮檔案後執行安裝檔,\r\n"+ "安裝完畢請重新整理網頁!"; try{ console.log("new WebSocket Start"); var ws = new WebSocket('wss://localhost:9991/ws/version'); console.log("new WebSocket Complete"); }catch(e){ console.log("#### SecurityError >>> new WebSocket Fail at websocket.js ####"); return; } ws.onopen = function() { console.log("ws.onopen"); ws.send(JSON.stringify({})); }; ws.onmessage = function(evt) { console.log("ws.onmessage"); var obj = JSON.parse(evt.data); local_WebSocket_value = obj.data.version; if (obj.success == false) { //提示訊息設定 msg_WS_version = msg_WS_title+ "無法偵測到WebSocket元件服務,請確認是否已安裝WebSocket元件及啟動服務!\r\n" +downloadMsg; //下載元件 if(typeof (download) != 'boolean' || download == true) alertDownloadWebSocket(); } else if (checkVersion()) { //提示訊息設定 msg_WS_version = msg_WS_title+ "您目前的版本為 "+local_WebSocket_value+",請升級至最新版本!\r\n" +downloadMsg; //更新元件 if(typeof (download) != 'boolean' || download == true) alertDownloadWebSocket(); } console.log("ws.close start"); ws.close(); console.log("ws.close complete"); console.groupEnd(); }; ws.onerror = function(error) { console.log("ws.onerror"); //提示訊息設定 msg_WS_version = msg_WS_title+ "無法偵測到WebSocket元件服務,請確認是否已安裝WebSocket元件及啟動服務!\r\n" +downloadMsg; //異常下載元件 if(typeof (download) != 'boolean' || download == true) alertDownloadWebSocket(); console.groupEnd(); }; } /*2019/01/21 俊宏(TV6286)提供之讀取讀卡機資訊相關方法Star function RunTest(url,param) function WebRestTest(url,params) function postProcess(evt , obj) function prepareParam(url,params) function readCert() 引用 slot參數來選擇要使用的卡片裝置 */ function prepareParam(url,params) { if(! params) params={}; var e = document.getElementById("slot"); var str = e.options[e.selectedIndex].value; params["slot"]=str; params["type"]="2"; } function postProcess(evt , obj) { //console.log('=== postProcess ==='); //document.getElementById('result').innerHTML = evt.data; if(obj.success == false){ //console.log('error1'); // document.getElementById('signResult').innerHTML = obj.error + " : " + obj.messages; var optionSlot = document.getElementById('slot'); var j; for( j = optionSlot.options.length - 1; j >= 0; j-- ){ optionSlot.remove(j); } var new_option = new Option( "無讀卡機資訊", 0 ); optionSlot.options.add( new_option ); }else if( obj.data.deviceList ) { if(obj.success == false){ //console.log('error2'); //document.getElementById('signResult').innerHTML = JSON.stringify(obj.data.deviceList); } var optionSlot = document.getElementById('slot'); //console.log('#### postProcess ####'); //console.log( obj.data.deviceList ); //console.log('======================='); var j; for(j=optionSlot.options.length-1;j>=0;j--) { optionSlot.remove(j); } //存讀卡機資訊,並依照是否有插卡來排序 var optionAry =[]; for(var i=0 ;i < obj.data.deviceList.length ;i++) { if(obj.data.deviceList[i].readerName) { var tmpValue=obj.data.deviceList[i].readerName; var tmpMoicaId = obj.data.deviceList[i].moicaId; //var new_option = new Option(tmpValue,i); if( tmpMoicaId == "" ){ optionAry.push({ "opts" : tmpValue, "id" : i }); }else{ optionAry.unshift({ "opts" : tmpValue + ", 卡號: " + tmpMoicaId, "id" : i }); } //console.log('readerName: ' + tmpValue); //console.log('moicaId: ' + tmpMoicaId); } else { optionAry.length = 0; var tmpValue=obj.data.deviceList[i].filename; var new_option = new Option(tmpValue,tmpValue); //console.log('tmpValue: ' + tmpValue); optionSlot.options.add(new_option); } //optionSlot.options.add( new_option ); } //console.log("### === = optionAry === ###"); //console.log( optionAry ); //console.log("### === === ==== === === ###"); //有讀卡機時才產生選項 if( optionAry && optionAry.length ){ for( var a = 0; a < optionAry.length; a++ ){ var new_option = new Option( optionAry[a].opts, optionAry[a].id ); optionSlot.options.add( new_option ); } } }else if(obj.data) { //console.log('error3'); //document.getElementById('signResult').innerHTML = JSON.stringify(obj.data); } } function WebRestTest(url,params) { //console.log("=== WebRestTest ===") $('#useSlotNum').val("Y"); if(! params) params={}; prepareParam(url,params); cor = new XMLHttpRequest(); cor.onreadystatechange = function () { if (cor.readyState == 4 && this.status == 200) { //console.log('this.status: ' + this.status); var obj = JSON.parse(this.responseText); //console.log('obj' + obj); var evt={}; evt["data"]=this.responseText; //console.log('this.responseText' + this.responseText); //console.log('this.obj' + obj.data.deviceList); postProcess(obj, obj); } }; protocolPrefix = (window.location.protocol === 'https:') ? 'https:' : 'https:'; protocolPrefix = protocolPrefix + '//' + "localhost:9991" + "/ws/"; //console.log('protocolPrefix: ' + protocolPrefix); //console.log('params: ' + JSON.stringify(params)); cor.open("POST",protocolPrefix+url, true); cor.send(JSON.stringify(params)); } //2019/04/01 新增判斷瀏覽器為IE或Chrome function isIEBrowser() { var userAgent = navigator.userAgent; //取得瀏覽器的的userAgent字符串 var isIE = window.ActiveXObject || "ActiveXObject" in window; if( isIE ){ var reIE = new RegExp("MSIE (\\d+\\.\\d+);"); reIE.test( userAgent ); var fIEVersion = parseFloat(RegExp["$1"]); if( userAgent.indexOf( 'MSIE 6.0' ) != -1 ){ return "IE6"; }else if( fIEVersion == 7 ){ return "IE7"; }else if( fIEVersion == 8 ){ return "IE8"; }else if( fIEVersion == 9 ){ return "IE9"; }else if( fIEVersion == 10 ){ return "IE10"; }else if( userAgent.toLowerCase().match(/rv:([\d.]+)\) like gecko/) ){ return "IE11"; }else{ return "0" }//IE版本過低 }//isIE end return "NOT IE"; } //判斷當前瀏覽器為IE或Chrome var browser = isIEBrowser(); //2019/04/01 俊宏(TV6286)新增之讀取讀卡機資訊相關方法Star function WebSocketTest(url,params) { //console.log("=== WebSocketTest ===") $('#useSlotNum').val("Y"); //console.log("### 1 ###"); if(! params) params={}; prepareParam(url,params); //console.log("### 2 ###"); if ("WebSocket" in window) { protocolPrefix = (window.location.protocol === 'https:') ? 'wss:' : 'ws:'; protocolPrefix = protocolPrefix + '//' + "localhost:9991" + "/ws/"; //console.log("### 3 ###"); var ws = new WebSocket(protocolPrefix+url); ws.onopen = function() { //console.log("### 4 ###"); ws.send(JSON.stringify(params)); }; ws.onmessage = function(evt) { //console.log("### 5 ###"); var obj = JSON.parse(evt.data); postProcess(evt, obj); ws.close(); }; ws.onclose = function() { //console.log("### 6 ###"); //document.getElementById('status').value = 'websocket closed'; $('#status').val('websocket closed'); }; ws.onerror = function (error) { if( ( browser === "IE10" ) || ( browser === "IE11" ) ) { console.log("IE Browser, Error code=" +ws.readyState+","+error); }else{ console.log("Error code=" +ws.readyState+","+error); } }; $.unblockUI(); } else { $.unblockUI(); alert("This browser does not support WebSockets."); } } function RunTest2(url,param) { $.blockUI({ message : '載入中,請稍候...' }); WebSocketTest(url,param); }//2019/04/01 俊宏(TV6286)新增方法End function RunTest(url,param) { WebRestTest(url,param); } /*TV6286提供之讀取讀卡機資訊相關方法End*/ // 讀取卡片資訊 function readCert() { console.group("##### readCert #####"); var errorChk = 0; $.blockUI({ message : '讀取中,請稍候...' }); //判斷瀏覽器 只有IE流覽器判斷 if(!checkBrowser(true)){ $.unblockUI(); return false; } //判斷WebSocket是否安裝 if (checkVersion()) { if (confirm(msg_WS_version)) downloadWebSocket(); $.unblockUI(); return false; } // 使用者輸入的密碼 var password = $('#pinCode').val(); if (password == null || password == '') { alert("請輸入Pin碼"); $.unblockUI(); return false; } //console.log("### useSlotNum =" + $('#useSlotNum').val() + "###"); //預設讀卡機裝置為value=0的第一個 var slotNum = '0'; if( $('#useSlotNum').val() == 'Y' ) { slotNum = $('#slot').val(); }else{ slotNum = '0'; } //console.log("### slotNum =" + slotNum + ", slot =" + $('#slot').val() + "###"); //var params = getCertParams('0', '2', 'default', password, ''); var errMsg; var params = getCertParams( slotNum, '2', 'default', password, ''); var ws = new WebSocket('wss://localhost:9991/ws/cert'); ws.onopen = function() { ws.send(JSON.stringify(params)); }; ws.onmessage = function(evt) { var obj = JSON.parse(evt.data); if (obj.success == false) { errMsg = obj.error + ' : ' + obj.messages; alert(errMsg); errorChk = 1; $.unblockUI(); } else if (obj.data.certInfo) { var serialNoHex = getSerialNoHex(obj.data.certInfo.serialNumberHex); $('#serialNo').val(serialNoHex); var startTime = formatDate(obj.data.certInfo.notBeforeDate); var endTime = formatDate(obj.data.certInfo.notAfterDate); $('#startTime').val(startTime); $('#endTime').val(endTime); } else { errMsg = "憑證讀卡失敗!請重新嘗試!"; alert(errMsg); errorChk = 1; $.unblockUI(); } ws.close(); console.groupEnd(); if (errorChk == 1) { return; } else { readSign(); } }; /* * ws.onclose = function(event) { var reason = ""; if (event.code == 1001) reason = "An endpoint is \"going away\", such as a server going down or a browser having navigated away from a page."; else if (event.code == 1002) reason = "An endpoint is terminating the connection due to a protocol * error"; else if (event.code == 1003) reason = "An endpoint is terminating the connection because it has received a type of data it cannot accept (e.g., an endpoint that understands only text data MAY send this if it receives a binary message)."; else if (event.code == 1006) reason = "The * connection was closed abnormally, e.g., without sending or receiving a Close control frame"; else if (event.code == 1007) reason = "An endpoint is terminating the connection because it has received data within a message that was not consistent with the type of the message (e.g., non-UTF-8 * [http://tools.ietf.org/html/rfc3629] data within a text message)."; else if (event.code == 1008) reason = "An endpoint is terminating the connection because it has received a message that \"violates its policy\". This reason is given either if there is no other sutible reason, or if there is * a need to hide specific details about the policy."; else if (event.code == 1009) reason = "An endpoint is terminating the connection because it has received a message that is too big for it to process."; else if (event.code == 1011) reason = "A server is terminating the connection because it * encountered an unexpected condition that prevented it from fulfilling the request."; else if (event.code == 1015) reason = "The connection was closed due to a failure to perform a TLS handshake (e.g., the server certificate can't be verified)."; if (reason != "") { alert(reason + event.code); * $.unblockUI(); } }; */ ws.onerror = function(error) { if (navigator.userAgent.match("MSIE") || (!navigator.userAgent.match("CHROME") && navigator.appName == 'Netscape')) { $.unblockUI(); } else { alert("WebSocket Connection ERROR." + error); $.unblockUI(); } console.groupEnd(); }; } // 讀取簽章資訊 function readSign() { console.group("##### readSign #####"); var errorChk = 0; var errMsg; var password = $('#pinCode').val(); //console.log("### readSign() useSlotNum =" + $('#useSlotNum').val() + "###"); //預設讀卡機裝置為value=0的第一個 var slotNum = '0'; if( $('#useSlotNum').val() == 'Y' ) { slotNum = $('#slot').val(); }else{ slotNum = '0'; } //console.log("### readSign() slotNum =" + slotNum + ", slot =" + $('#slot').val() + "###"); var params = getCertParams( slotNum, '2', 'sha1', password, 'RegistryMainCert'); var ws = new WebSocket('wss://localhost:9991/ws/P7_Sign'); ws.onopen = function() { console.log("ws.onopen"); ws.send(JSON.stringify(params)); }; ws.onmessage = function(evt) { console.log("ws.onmessage"); var obj = JSON.parse(evt.data); if (obj.success == false) { errMsg = obj.error + ' : ' + obj.messages; alert(errMsg); errorChk = 1; $.unblockUI(); } else if (obj.data.signature) { $('#signature').val(obj.data.signature); //確認憑證類型 工商憑證 or 自然人憑證 var websocketCertType = ""; //統編 var ban = ""; //身份證 var citizenID = ""; //1.2.3 if(obj.data.ban !== ''){ //工商憑證 websocketCertType = "MOEACA"; ban = obj.data.ban; } //1.2.3 else if(obj.data.citizenID !== ''){ //自然人 websocketCertType = "MOICA"; citizenID = obj.data.citizenID; } //1.1.2 // else if(typeof(obj.data.signer) !== 'undefined'){ // } // else{ // //政府憑證 // websocketCertType = "GCA"; // } /* 當使用政府機關GCA 或 組織團體憑證XCA 時 * 因無法從websocket元件辨識類別,改由畫面申請類別判斷 */ if( obj.data.ban == '' && obj.data.citizenID == '' ){ websocketCertType = 'undefined'; } $('#websocketCertType').val(websocketCertType); $('#certType').val(websocketCertType); //統編 $('#ban').val(ban); //身份證 $('#citizenID').val(citizenID); //alert("憑證載入完成。"); //處理完之後要做的事 doAfterP7_Sign(); $.unblockUI(); } else { errMsg = "取得憑證簽章失敗!請重新嘗試!"; alert(errMsg); errorChk = 1; $.unblockUI(); } console.log("ws.close start"); ws.close(); console.log("ws.close complete"); console.groupEnd(); }; ws.onerror = function(error) { console.log("ws.onerror"); if (navigator.userAgent.match("MSIE") || (!navigator.userAgent.match("CHROME") && navigator.appName == 'Netscape')) { console.log("IE error ignore"); $.unblockUI(); } else { alert("WebSocket Connection ERROR." + error); $.unblockUI(); } }; } //P7_Sign SUCCESS 要做的事 function doAfterP7_Sign(){}; //下載元件提示 function alertDownloadWebSocket(){ if (confirm(msg_WS_version)){ downloadWebSocket(); return true; } return false; } //下載元件 function downloadWebSocket() { if(WebSocket_value == 'NVL'){ alert("無此作業系統 WebSocket元件(憑證元件) 請洽資訊人員 !!"); return; } var server = "portal.sw.nat.gov.tw"; var ctx = "/PPL/home/DownLoad?fileName="; var link = "https://" + server + ctx + encodeURI("WebSocket_"+download_WebSocket_value+".zip"); window.open(link, '_new'); } // 設定憑證基本資料 function getCertParams(slot, type, algo, password, data) { var params = {}; params["slot"] = slot; params["type"] = type; params["algo"] = algo; params["pin"] = password; params["data"] = data; // 無資料 params["refId"] = ""; params["sign"] = ""; params["remoteDn"] = ""; params["sigId"] = ""; params["authCert"] = ""; params["confCert"] = ""; params["newPin"] = ""; return params; } // 處理serialNo function getSerialNoHex(serialNoHex) { var result = ""; if (serialNoHex != null) { var first = serialNoHex.substring(0, 1); if ("8" == first || "9" == first || "A" == first || "B" == first || "C" == first || "D" == first || "E" == first || "F" == first) { result = "00" + serialNoHex; } else { result = serialNoHex; } } return result; } // 處理日期格式 function formatDate(date) { var result = ""; if (date != null) { var d = date.split(' ')[0].replace(/[-]/g, ''); var t = date.split(' ')[1].replace(/[:]/g, ''); result = d + t; } return result; }