Untitled
unknown
javascript
3 years ago
107 kB
5
Indexable
var ekycSDK = (function () { var __wrapper; var __options; var __sessionPlan; var __uploadType; var __allowFullResults; var __pc; var __dc; // Liveness functions var __webcam; var __guideBox; var __guideTitle; var __guideIcons = []; var __lvns_step = 1; var __successIcon; var __warningIcon; const LIVENESS_MESSAGES = { 'TurnLeft': 'Quay trái', 'TurnRight': 'Quay phải', 'TurnUp': 'Ngửa đầu', 'TurnDown': 'Cúi đầu', 'HoldSteady2Second': 'Nhìn thẳng trong 2 giây', 'EyeBlink': 'Nháy mắt', 'ShakeHead': 'Lắc đầu sang trái hoặc phải', 'NodeHead': 'Gật đầu', 'Success': 'success', 'Connecting': 'Đang kết nối...', 'Initializing': 'Đang khởi tạo...', 'Processing': 'Đang xác thực...', 'ConnectionFailed': 'Kết nối thất bại' }; var __createPeerConnection = function () { __pc = new RTCPeerConnection({ sdpSemantics: 'unified-plan', iceTransportPolicy: 'relay', iceServers: [ { urls: ['turn:27.71.226.88:64001?transport=tcp'], credential: 'kalapa123456', username: 'kalapa' } ] }); __pc.addEventListener('icegatheringstatechange', function() { console.log(__pc.iceGatheringState) }, false); __pc.addEventListener('iceconnectionstatechange', function () { if (['disconnected', 'failed'].includes(__pc.iceGatheringState)) { __stop(); console.log(LIVENESS_MESSAGES['ConnectionFailed']); } }, false); }; var __createDataChannel = function () { __dc = __pc.createDataChannel('chat', {ordered: true}); }; var __handleMessageEvent = function () { __dc.onmessage = function (e) { var data = e.data.split("&&")[1].replaceAll("'", '"'); data = JSON.parse(data); console.log(data); var message = ''; if (data.status === 3) { __stop(); message = 'Không đạt, vui lòng thử lại.'; __showError(message, liveness, true); } else if (data.status === 2) { __stop(); __warningIcon.css('display', 'block'); message = 'Quá thời gian quy định. Vui lòng thử lại.'; __showError(message, liveness, true); } else if (data.status === 1) { __stop(true); message = 'Đạt.'; if (data.error.code !== 0 && data.error.code !== 21) { message = 'Không đạt, vui lòng thử lại.'; __showError(message, liveness, true); } else { __guideTitle.text('Vui lòng chờ trong giây lát...'); // save selfie localStorage.setItem('selfie_dataurl', 'data:image/jpeg;base64,' + data.base64_image); __confirmResults(); } } else { message = LIVENESS_MESSAGES[data.message]; // render message; if (message === 'success') { __successIcon.css('display', 'block'); __guideIcons[__lvns_step - 1].css({opacity: 1.0}); __lvns_step = __lvns_step + 1; setTimeout(function () { __successIcon.css('display', 'none'); }, 2000) } else { if (message != LIVENESS_MESSAGES.Processing) { console.log("Liveness step " + __lvns_step) if (__lvns_step >= 4) { if (__lvns_step == 4) { __guideIcons.forEach(x => x.hide()); } else { __guideIcons[__lvns_step - 2].hide(); } let added_icon = __options.style.photos.HoldSteady2Second; switch (message) { case LIVENESS_MESSAGES.TurnLeft: added_icon = __options.style.photos.TurnLeft; break; case LIVENESS_MESSAGES.TurnRight: added_icon = __options.style.photos.TurnRight; break; case LIVENESS_MESSAGES.TurnUp: added_icon = __options.style.photos.TurnUp; break; case LIVENESS_MESSAGES.TurnDown: added_icon = __options.style.photos.TurnDown; break; } __guideIcons.push(jQuery('<img/>', { src: added_icon, css: { opacity: "0.5", width: Math.min(45, 45 * jQuery(__wrapper).height() / 870, 45 * jQuery(__wrapper).width() / 375), margin: "15px" }, }).insertBefore(__guideTitle)); } } __guideTitle.text(message); } } } }; var __addTracks = function () { var isFirefox = typeof InstallTrigger !== 'undefined'; let videoParams; if (!isFirefox) { videoParams = { width: 640, height: 640, frameRate: { max: 10 } } } else { videoParams = { width: 640, height: 640 } } navigator.mediaDevices.getUserMedia({ video: videoParams }).then(function (stream) { __webcam.get(0).srcObject = stream; __webcam.get(0).play(); stream.getTracks().forEach(function (track) { __pc.addTrack(track, stream); }); __negotiate(); }).catch(function (err) { console.log(err); }); }; var __negotiate = function () { __pc.createOffer().then(function (offer) { __pc.setLocalDescription(offer); return offer; }).then(function (offer) { return new Promise(function (resolve) { function ____checkState() { if (__pc.iceGatheringState === 'complete') { __pc.removeEventListener('icegatheringstatechange', ____checkState); resolve(); } } if (__pc.iceGatheringState === 'complete') { resolve(); } else { __pc.addEventListener('icegatheringstatechange', ____checkState) } }) }).then(function () { var offer = __pc.localDescription; return fetch(__options.host + '/api/kyc/liveness/offer/v2', { body: JSON.stringify({ sdp: __sdpFilterCodec('video', 'VP8/90000', offer.sdp), type: offer.type, video_transform: 'none', version: "2", is_save_result: true, // use_additional_check: true, session_id: localStorage.getItem('session_token') }), headers: { 'Content-Type': 'application/json', "Authorization": localStorage.getItem('session_token') }, method: 'POST' }) }).then(function (response) { return response.json(); }).then(function (answer) { console.log(LIVENESS_MESSAGES['Initializing']); return __pc.setRemoteDescription(answer); }).catch(function (err) { console.log(err); }); }; var __sdpFilterCodec = function (kind, codec, realSdp) { var allowed = []; var rtxRegex = new RegExp('a=fmtp:(\\d+) apt=(\\d+)\r$'); var codecRegex = new RegExp('a=rtpmap:([0-9]+) ' + __escapeRegExp(codec)) var videoRegex = new RegExp('(m=' + kind + ' .*?)( ([0-9]+))*\\s*$') var lines = realSdp.split('\n'); var isKind = false; for (let i = 0; i < lines.length; i++) { if (lines[i].startsWith('m=' + kind + ' ')) { isKind = true; } else if (lines[i].startsWith('m=')) { isKind = false; } if (isKind) { var match = lines[i].match(codecRegex); if (match) { allowed.push(parseInt(match[1])); } match = lines[i].match(rtxRegex); if (match && allowed.includes(parseInt(match[2]))) { allowed.push(parseInt(match[1])); } } } var skipRegex = 'a=(fmtp|rtcp-fb|rtpmap):([0-9]+)'; var sdp = ''; isKind = false; for (let i = 0; i < lines.length; i++) { if (lines[i].startsWith('m=' + kind + ' ')) { isKind = true; } else if (lines[i].startsWith('m=')) { isKind = false; } if (isKind) { var skipMatch = lines[i].match(skipRegex); if (skipMatch && !allowed.includes(parseInt(skipMatch[2]))) { continue; } else if (lines[i].match(videoRegex)) { sdp += lines[i].replace(videoRegex, '$1 ' + allowed.join(' ')) + '\n'; } else { sdp += lines[i] + '\n'; } } else { sdp += lines[i] + '\n'; } } return sdp; }; var __escapeRegExp = function (string) { return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); }; var __stop = function (stopWebcam=false) { if (__dc) { __dc.close(); } if (__pc.getTransceivers) { __pc.getTransceivers().forEach(function(transceiver) { if (transceiver.stop) { transceiver.stop(); } }); } if (stopWebcam) { __pc.getSenders().forEach(function(sender) { try { sender.track.stop(); } catch { console.log("Track closed already"); } }); __webcam.get(0).srcObject.getTracks().forEach(function(track) { track.stop(); }); console.log("stopped webcam") } setTimeout(function () { __pc.close(); }, 500); }; // END: Liveness functions var __getErrorMessage = function (errorCode) { if (__options.error_messages[errorCode]) { return __options.error_messages[errorCode] + '. Vui lòng thử lại.'; } else { return 'Lỗi hệ thống. Vui lòng thử lại.'; } }; var __convertToSlug = function (str) { str = str.toUpperCase(); str = str .normalize('NFD') .replace(/[\u0300-\u036f]/g, ''); str = str.replace(/[đĐ]/g, 'd'); str = str.replace(/([^0-9A-Z-\s])/g, ''); str = str.replace(/(\s+)/g, '-'); str = str.replace(/-+/g, '-'); str = str.replace(/^-+|-+$/g, ''); return str; }; var __getDataUrl = function (imageFile) { var reader = new FileReader(); // reader.onloadend = function (e) { // cb(e.target.result, e.target.error); // }; reader.readAsDataURL(imageFile); reader.onload = function () { localStorage.setItem('selfie_dataurl', reader.result); }; reader.onerror = function (error) { console.log('Error: ', error); }; }; var __getBlob = function (dataURI) { // convert base64 to raw binary data held in a string // doesn't handle URLEncoded DataURIs - see SO answer #6850276 for code that does this var byteString = atob(dataURI.split(',')[1]); // separate out the mime component var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; // write the bytes of the string to an ArrayBuffer var ab = new ArrayBuffer(byteString.length); var ia = new Uint8Array(ab); for (var i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } //New Code return new Blob([ab], {type: mimeString}); }; var __showError = function (errorMessage, confirmCallback, callBackArgument) { if (Swal) { Swal.fire({ icon: 'error', html: `<small style="font-size: .775em; color: ${__options.style.textColor}">${errorMessage}</small>`, customClass: { icon: 'swal2-icon-small', }, target: __options.wrap_id, background: "rgb(22, 31, 45, 0.9)", confirmButtonColor: "rgb(2, 253, 174, 0.75)", width: "90%", }).then((result) => { if (result.isConfirmed) { if (confirmCallback) confirmCallback(callBackArgument); } }); jQuery(".swal2-container").css({ position: "absolute" }); } else { alert(errorMessage) } }; var __showWarning = function (errorMessage, confirmCallback, callBackArgument) { if (Swal) { Swal.fire({ icon: 'warning', html: `<small style="font-size: .775em; color: ${__options.style.textColor}">${errorMessage}</small>`, customClass: { icon: 'swal2-icon-small', }, target: __options.wrap_id, background: "rgb(22, 31, 45, 0.9)", confirmButtonColor: "rgb(2, 253, 174, 0.75)", width: "90%", }).then((result) => { if (result.isConfirmed) { if (confirmCallback) confirmCallback(callBackArgument); } }); jQuery(".swal2-container").css({ position: "absolute" }); } else { alert(errorMessage) } }; var __clearLayout = function () { jQuery(__options.wrap_id).html( null ); __wrapper = jQuery("<div/>", { css: { height: "100%", minHeight: 500, position: 'relative', backgroundColor: __options.style.backgroundColor, textAlign: "center" } }).appendTo(__options.wrap_id); footer = jQuery("<img/>", { src: __options.style.photos.footer, css: { position: "absolute", bottom: 0, width: "100%", opacity: 0.45, left: 0 } }).appendTo(__wrapper); }; var __clearLocalStorage = function () { localStorage.clear(); }; var renderResult = function () { jQuery(__options.wrap_id).html(null); __wrapper = jQuery("<div/>", { css: { height: "100%", minHeight: 500 } }).appendTo(__options.wrap_id); overflow_wrap = jQuery("<div/>", { css: { position: "absolute", top: 0, width: "100%", } } ).appendTo(__wrapper) footer = jQuery("<img/>", { src: __options.style.photos.footer, css: { position: "absolute", bottom: 0, width: "100%", left: 0 } }).appendTo(overflow_wrap); var selfieData, antifraudData, verifyData, idData, qrCodeData, mrzData, dlData; try { selfieData = JSON.parse(localStorage.getItem('selfie')).data; } catch { selfieData = null; } try { antifraudData = JSON.parse(localStorage.getItem('antifraud')).results; } catch { antifraudData = null; } try { dlData = JSON.parse(localStorage.getItem('decision_details')); } catch { dlData = null; } try { verifyData = JSON.parse(localStorage.getItem('verify')); } catch { verifyData = null; } try { idData = JSON.parse(localStorage.getItem('ocr_data')); } catch { idData = null; } try { qrCodeData = JSON.parse(localStorage.getItem('qr_decode')); } catch { qrCodeData = null; } try { mrzData = JSON.parse(localStorage.getItem('mrz_decode')); } catch { mrzData = null; } // var dl_checks = { // "LG_01": "Độ dài ID phù hợp với loại thẻ", // "LG_02": "Ngày sinh và giới tính khớp với ID", // "LG_03": "Địa chỉ khớp với ID", // "LG_04": "Ngày cấp, ngày sinh, ngày hết hạn không bất thường", // "LG_06": "Ảnh mặt trước và mặt sau cùng một loại", // "LG_07": "Ảnh mặt trước và mặt sau có cùng điều kiện ánh sáng" // }; // var dl_results = []; // if (dlData) { // dlData.map(x => { // if (Object.keys(dl_checks).includes(x.code)) { // dl_results.push({ // description: x.description_vi ? x.description_vi : x.description ? x.description : dl_checks[x.code], // pass: x.is_pass // }); // } // }); // } // else { // Object.keys(dl_checks).map(x => { // dl_results.push({ // description: dl_checks[x], // pass: null // }); // }) // } // console.log(dl_results); console.log(dlData); jQuery("<div/>", { html: `<img style="width: 200px; height: 200px; object-fit: cover; border-radius: 100%; border: 3px solid #02FDAE; box-shadow: 2px 0px 5px #02FDAE, -2px 0px 5px #02FDAE; " src=${localStorage.getItem('selfie_dataurl')} /> <br/> <img style="height: 60px;" src="${__options.style.photos.loading}" id="frontImage" /> <br/> <img style="height: 60px;" src="${__options.style.photos.loading}" id="backImage" /> <div style="color: ${__options.style.textColor};font-size: 0.9rem; font-weight: 700; padding: 2%">` + ( localStorage.getItem("decision") != "REJECTED" ? `<span style="line-height: 15px">Đăng ký thành công. </span> <p style="line-height: 15px">Hồ sơ của bạn đang được xét duyệt.</p>` : `<span style="line-height: 15px">Đăng ký không thành công. </span> <p style="line-height: 15px">Đã có vấn đề xảy ra với hồ sơ của bạn.</p> <p style="line-height: 15px">Vui lòng kiểm tra lại thông tin.</p>` ) + `</div> `, css: { width: "100%", marginTop: "10%" } }).appendTo(overflow_wrap); axios.get(__options.host + "/api/data/image?type=FRONT", { headers: { 'Authorization': localStorage.getItem('session_token') }, responseType: 'blob' }).then(function (response) { var reader = new window.FileReader(); reader.readAsDataURL(response.data); reader.onload = function() { var imageDataUrl = reader.result; $("#frontImage").attr("src", imageDataUrl); $("#frontImage").attr("style", "border: 1px solid #02FDAE; box-shadow: 2px 0px 5px #02FDAE, -2px 0px 5px #02FDAE; width: 80%; max-width: 300px; margin: 20px;"); } }) axios.get(__options.host + "/api/data/image?type=BACK", { headers: { 'Authorization': localStorage.getItem('session_token') }, responseType: 'blob' }).then(function (response) { var reader = new window.FileReader(); reader.readAsDataURL(response.data); reader.onload = function() { var imageDataUrl = reader.result; $("#backImage").attr("src", imageDataUrl); $("#backImage").attr("style", "border: 1px solid #02FDAE; box-shadow: 2px 0px 5px #02FDAE, -2px 0px 5px #02FDAE; width: 80%; max-width: 300px; margin: 20px;"); } }) results_wrap = jQuery("<div/>", { css: { "position": "relative", "width": "100%", "marginTop": "5%", "marginBottom": "20%" } }).appendTo(overflow_wrap); results = jQuery("<div/>", { css: { "position": "relative", "width": "100%", "maxWidth": 500, "padding": 0, "margin": "0 auto" } }).appendTo(results_wrap); var isFirefox = typeof InstallTrigger !== 'undefined'; if (!isFirefox) { jQuery('<div/>', { css: { height: '100%', position: "absolute", top: "0", width: "65%", left: "50%", transform: "translateX(-50%)", background: "rgba(2, 253, 174, 0.15)", border: "none" // border: "1px solid #02FDAE", // borderBottom: "none", // borderTop: "none" } }).appendTo(results); jQuery('<div/>', { css: { height: '100%', position: "absolute", top: "0", width: "60%", left: "50%", transform: "translateX(-50%)", border: "1px solid rgb(2, 253, 174, 0.39)", borderBottom: "none", borderTop: "none" } }).appendTo(results); jQuery('<div/>', { css: { height: '100%', position: "absolute", top: "0", width: "70%", left: "50%", transform: "translateX(-50%)", border: "1px solid rgb(2, 253, 174, 0.39)", borderBottom: "none", borderTop: "none" } }).appendTo(results); } jQuery('<div/>', { id: 'personal_information', html: __sessionPlan != "PLAN_PASSPORT_BASIC" ? ( `<p style="font-size: 12px; text-align: center; margin-bottom: 5%; color: ${__options.style.headlineButtonStyle.backgroundColor}; font-weight: 600">Thông tin OCR</p> <div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">ID</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.id_number}</div> </div><hr>` + `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">Họ và tên</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.name}</div> </div><hr>` + `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày sinh</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.birthday}</div> </div><hr>` + `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">Giới tính</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.gender}</div> </div><hr>` + `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">Quê quán</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.home}</div> </div><hr>` + `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">Địa chỉ</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.resident}</div> </div><hr>` + (idData && idData.doi ? `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày cấp</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.doi}</div> </div><hr>` : '') + (idData && idData.doe ? `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày hết hạn</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.doe}</div> </div><hr>` : '') + (idData && idData.features ? `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">Đặc điểm nhận dạng</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.features}</div> </div><hr>` : '') + (idData && idData.poi ? `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">Nơi cấp</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.poi}</div> </div><hr>` : '') + (idData && idData.religion ? `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">Tôn giáo</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.religion}</div> </div><hr>` : '') + (idData && idData.ethnicity ? `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">Dân tộc</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.ethnicity}</div> </div><hr>` : '') + (qrCodeData != null && qrCodeData.data != null && typeof(qrCodeData.data.decoded_text) == "string" ? `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">QR Code</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right; word-wrap: break-word">${qrCodeData.data.decoded_text.replaceAll("|", "; ")}</div> </div><hr>` : '') + (mrzData != null && mrzData.data != null && typeof(mrzData.data.raw_mrz) == "string" ? `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">MRZ Code</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right; word-wrap: break-word">${mrzData.data.raw_mrz.replaceAll("<", "‹").replaceAll("\n", "")}</div> </div><hr>` : '') ) : ( `<p style="font-size: 12px; text-align: center; margin-bottom: 5%; color: ${__options.style.headlineButtonStyle.backgroundColor}; font-weight: 600">Thông tin OCR</p>` + `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">ID</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.id_number}</div> </div><hr>` + `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">Passport ID</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.pp_number}</div> </div><hr>` + `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">Họ và tên</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.name}</div> </div><hr>` + `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày sinh</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.dob}</div> </div><hr>` + `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">Giới tính</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.gender}</div> </div><hr>` + `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">Quốc tịch</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.nationality}</div> </div><hr>` + `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">Nơi sinh</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.pob}</div> </div><hr>` + (idData && idData.doi ? `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày cấp</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.doi}</div> </div><hr>` : '') + (idData && idData.doe ? `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày hết hạn</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.doe}</div> </div><hr>` : '') + (idData && idData.poi ? `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">Nơi cấp</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.poi}</div> </div><hr>` : '') + (idData && idData.type ? `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">Loại</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.type}</div> </div><hr>` : '') + (idData && idData.code ? `<div style="display: flex"> <div style="padding: 5px 0; width: 50%; display: inline-block">Mã số</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${idData.code}</div> </div><hr>` : '') ), css: { textAlign: 'left', background: "rgba(255, 255, 255, 0.2)", border: "1px solid #02FDAE", boxSizing: "border-box", boxShadow: "0px 1px 24px -1px rgba(0, 0, 0, 0.18)", backdropFilter: "blur(24px)", borderRadius: "19px", padding: "5%", width: "80%", margin: "0 auto", color: __options.style.textColor, fontSize: "0.8rem" } }).appendTo(results); if (__allowFullResults) { jQuery('<div/>', { html: ` <p style="font-size: 12px; text-align: center; margin-bottom: 5%; color: ${__options.style.headlineButtonStyle.backgroundColor}; font-weight: 600">So khớp khuôn mặt</p> <div> <div style="padding: 5px 0; width: 50%; display: inline-block">Độ tương đồng</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${(selfieData.matching_score).toFixed(2)}%</div> </div><hr>` + `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Kết quả</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right"><img style="height: 15px; width: 15px" src='${selfieData.is_matched ? __options.style.photos.pass : __options.style.photos.notPass}'/></div> </div><hr>` , css: { textAlign: 'left', background: "rgba(255, 255, 255, 0.2)", border: "1px solid #02FDAE", boxSizing: "border-box", boxShadow: "0px 1px 24px -1px rgba(0, 0, 0, 0.18)", backdropFilter: "blur(24px)", borderRadius: "19px", padding: "5%", width: "80%", margin: "0 auto", color: __options.style.textColor, fontSize: "0.8rem", marginTop: "10%" } }).appendTo(results); if ((__sessionPlan == "PLAN_BASIC") || (__sessionPlan == "PLAN_PLUS")) { jQuery('<div/>', { html: ` <p style="font-size: 12px; text-align: center; margin-bottom: 5%; color: ${__options.style.headlineButtonStyle.backgroundColor}; font-weight: 600">So khớp thông tin</p> <div> <div style="padding: 5px 0; width: 50%; display: inline-block">Họ tên - ID</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right"><img style="height: 15px; width: 15px" src='${(verifyData.verified === undefined || verifyData.verified == null) ? __options.style.photos.unknown : verifyData.verified ? __options.style.photos.pass : __options.style.photos.notPass}'/></div> </div><hr>` + `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Khuôn mặt - ID</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${(antifraudData == null || antifraudData.verify_face_id == undefined || Object.keys(antifraudData.verify_face_id).length == 0) ? `<img style="height: 15px; width: 15px" src='${__options.style.photos.unknown}'/>` : `<img style="height: 15px; width: 15px" src="${antifraudData.verify_face_id.matched ? __options.style.photos.pass : __options.style.photos.notPass}"/>`}</div> </div><hr>`, css: { textAlign: 'left', background: "rgba(255, 255, 255, 0.2)", border: "1px solid #02FDAE", boxSizing: "border-box", boxShadow: "0px 1px 24px -1px rgba(0, 0, 0, 0.18)", backdropFilter: "blur(24px)", borderRadius: "19px", padding: "5%", width: "80%", margin: "0 auto", color: __options.style.textColor, fontSize: "0.7rem", marginTop: "10%" } }).appendTo(results); } if (__sessionPlan == "PLAN_FULL") { dlContent = ''; dlData.map(x => { if (x.is_pass != 1) { dlContent = dlContent + ` <div> <div style="padding: 5px 0; width: 50%; display: inline-block">${x.description_vi}</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right">${x.is_pass == -1 ? `<img style="height: 15px; width: 15px" src='${__options.style.photos.unknown}'/>` : `<img style="height: 15px; width: 15px" src='${x.is_pass == 1 ? __options.style.photos.pass : __options.style.photos.notPass}'/>`}</div> </div><hr> ` } }) if (dlContent == '') { dlContent = ` <div> <div style="padding: 5px 0; width: 50%; display: inline-block">Không có</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right"></div> </div>` } jQuery('<div/>', { html: ` <p style="font-size: 12px; text-align: center; margin-bottom: 5%; color: ${__options.style.headlineButtonStyle.backgroundColor}; font-weight: 600">Dấu hiệu bất thường, gian lận</p>` + dlContent , css: { textAlign: 'left', background: "rgba(255, 255, 255, 0.2)", border: "1px solid #02FDAE", boxSizing: "border-box", boxShadow: "0px 1px 24px -1px rgba(0, 0, 0, 0.18)", backdropFilter: "blur(24px)", borderRadius: "19px", padding: "5%", width: "80%", margin: "0 auto", color: __options.style.textColor, fontSize: "0.8rem", marginTop: "10%" } }).appendTo(results); } faceSearchContent = ''; try { faceSearchData = JSON.parse(localStorage.getItem("faceSearchData")); faceSearchData.nearests.map(x => { faceSearchContent = faceSearchContent + ` <div> <div style="padding: 5px 0; width: 70%; display: inline-block"><img style="width: 100%; border:` + `${x[3] ? '2px solid rgb(2, 253, 174)' : '2px solid red' }` + `" src="data:image/jpg;base64,${x[0]}"></div><div style="padding: 5px 0; width: 30%; display: inline-block; text-align: right"><img style="width: 80%; border:` + `${x[3] ? '2px solid rgb(2, 253, 174)' : '2px solid red' }` + `" src="data:image/jpg;base64,${x[1]}"></div> </div> ` }) } catch { faceSearchContent = ` <div> <div style="padding: 5px 0; display: inline-block">${localStorage.getItem("faceSearchData")}</div><div style="padding: 5px 0; width: 50%; display: inline-block; text-align: right"></div> </div> ` } jQuery('<div/>', { html: ` <p style="font-size: 12px; text-align: center; margin-bottom: 5%; color: ${__options.style.headlineButtonStyle.backgroundColor}; font-weight: 600">ID(s) có gương mặt tương tự</p>` + faceSearchContent , css: { textAlign: 'left', background: "rgba(255, 255, 255, 0.2)", border: "1px solid #02FDAE", boxSizing: "border-box", boxShadow: "0px 1px 24px -1px rgba(0, 0, 0, 0.18)", backdropFilter: "blur(24px)", borderRadius: "19px", padding: "5%", width: "80%", margin: "0 auto", color: __options.style.textColor, fontSize: "0.8rem", marginTop: "10%" } }).appendTo(results); } jQuery('<div/>', { html: ` <p style="font-size: 0.8rem; line-height: 40px; font-weight: 600; color: #696969;">Thử lại</p> `, css: { height: '40px', cursor: "pointer", width: "100px", backgroundColor: "#02FDAE", borderRadius: "21.35px", margin: "30px auto" }, on: { click: function () { initSession(); } } }).appendTo(results_wrap); }; var liveness = function (isRestart=false) { if (isRestart) { __createPeerConnection(); __createDataChannel(); __handleMessageEvent(); stream = __webcam.get(0).srcObject; stream.getTracks().forEach(function (track) { __pc.addTrack(track, stream); }); __negotiate(); __lvns_step = 1; if (__guideIcons.length > 3) { console.log(__guideIcons.length); let tmp = __guideIcons.length; for (let idx = 3; idx < tmp; idx ++) { __guideIcons[idx].remove(); } for (let idx = 3; idx < tmp; idx ++) { __guideIcons.pop(); } console.log(__guideIcons.length); } __guideIcons.forEach(child => { child.css({ display: "inline-block", opacity: 0.5 }) }); __warningIcon.hide(); __guideTitle.text(LIVENESS_MESSAGES.Initializing); } else { __clearLayout(); __guideIcons = []; __lvns_step = 1; var webcamWrap; var header = jQuery( ` <div style="width: 80%; position: absolute; top: 5%; left: 50%; -webkit-transform: translateX(-50%); transform: translateX(-50%); height: 20px"> <p style="font-size: 0.8rem; font-weight: bold; line-height: 20px;">Xác thực sự sống</p> </div> `, ).appendTo(__wrapper); // var backBtn = jQuery("<span/>", { // html: `<img style="height: 12px; margin-top: 4px" src=${__options.style.photos.back} />`, // css: { // float: "left", // cursor: "pointer", // height: "20px", // marginTop: "-20px", // width: "20px", // backgroundColor: __options.style.headlineButtonStyle.backgroundColor, // borderRadius: "100%" // }, // on: { // click: () => backToUploadID("back") // } // }).appendTo(header); webcamWrap = jQuery('<div/>', { css: { position: 'absolute', top: "15%", width: '100%', height: "50%", display: "flex", alignItems: "center", justifyContent: "center" } }).appendTo(__wrapper); __webcam = jQuery('<video/>', { autoplay: true, playsinline: true, css: { position: "absolute", maxHeight: '100%', height: Math.min(300, jQuery(__wrapper).height() * 0.4, jQuery(__wrapper).width() * 0.7), width: Math.min(300, jQuery(__wrapper).height() * 0.4, jQuery(__wrapper).width() * 0.7), objectFit: 'cover', borderRadius: '100%', transform: "scale(-1, 1)" } }).appendTo(webcamWrap); cameraFrame = jQuery('<img/>', { src: "./static/_pngtree_round_yellow_light_effect_6670101_1.png", css: { position: "absolute", maxHeight: '100%', width: "270px", objectFit: 'cover', borderRadius: '100%', animationName: "spin", animationDuration: "5000ms", animationIterationCount: "infinite", animationTimingFunction: "linear" } }).appendTo(webcamWrap); __guideBox = jQuery('<div/>', { css: Object.assign({ position: "absolute", textAlign: "center", bottom: "10%", left: "50%", width: "80%", maxWidth: "300px", transform: "translateX(-50%)" }, __options.style.guideBoxStyle), }).appendTo(__wrapper); __guideIcons.push(jQuery('<img/>', { src: __options.style.photos.HoldSteady2Second, css: { opacity: "0.5", width: Math.min(45, 45 * jQuery(__wrapper).height() / 870, 45 * jQuery(__wrapper).width() / 375), margin: "15px" }, }).appendTo(__guideBox)); __guideIcons.push(jQuery('<img/>', { src: __options.style.photos.TurnDown, css: { opacity: "0.5", width: Math.min(45, 45 * jQuery(__wrapper).height() / 870, 45 * jQuery(__wrapper).width() / 375), margin: "15px" }, }).appendTo(__guideBox)); __guideIcons.push(jQuery('<img/>', { src: __options.style.photos.TurnLeft, css: { opacity: "0.5", width: Math.min(45, 45 * jQuery(__wrapper).height() / 870, 45 * jQuery(__wrapper).width() / 375), margin: "15px" }, }).appendTo(__guideBox)); __guideTitle = jQuery('<p/>', { text: LIVENESS_MESSAGES.Initializing, css: { fontSize: "0.9rem", fontWeight: 500, marginBottom: "5%" }, }).appendTo(__guideBox); __successIcon = jQuery('<img/>', { src: __options.style.photos.LivenessSuccessIcon, css: { position: "absolute", display: 'none', borderRadius: '100%', background: 'white', width: '80px' } }).appendTo(webcamWrap); __warningIcon = jQuery('<img/>', { src: __options.style.photos.LivenessWarningIcon, css: { display: 'none', position: "absolute", borderRadius: '100%', background: 'white', width: '80px' } }).appendTo(webcamWrap); __createPeerConnection(); __createDataChannel(); __handleMessageEvent(); __addTracks(); } }; var scanQrCode = () => { __clearLayout(); var qrScanner; var canvas; var webcam; var webcamWrap; var header = jQuery( ` <div style="width: 80%; position: absolute; top: 5%; left: 50%; -webkit-transform: translateX(-50%); transform: translateX(-50%); height: 20px"> <p style="font-size: 0.8rem; font-weight: bold; line-height: 20px;">Quét QR Code</p> </div> `, ).appendTo(__wrapper); // var backBtn = jQuery("<span/>", { // html: `<img style="height: 12px; margin-top: 4px" src=${__options.style.photos.back} />`, // css: { // float: "left", // cursor: "pointer", // height: "20px", // marginTop: "-20px", // width: "20px", // backgroundColor: __options.style.headlineButtonStyle.backgroundColor, // borderRadius: "100%" // }, // on: { // click: () => backToUploadID("front") // } // }).appendTo(header) webcamHeight = parseInt(jQuery(__wrapper).height() * 0.35); console.log(webcamHeight); webcamWrap = jQuery('<div/>', { css: { position: 'absolute', top: "10%", width: "100%", height: webcamHeight, backgroundColor: "black", display: "flex", alignItems: "center", justifyContent: "center", left: "50%", transform: "translateX(-50%)" } }).appendTo(__wrapper); webcam = jQuery('<video/>', { autoplay: true, playsinline: true, css: { width: "100%", height: webcamHeight, // transform: "scale(-1, 1)" } }).appendTo(webcamWrap); canvas = jQuery('<canvas/>', { css: { left: "50%", transform: "translateX(-50%)", height: webcamHeight, position: 'absolute', top: "10%", display: 'none' } }).appendTo(__wrapper); QrScanner.WORKER_PATH = './static/qr-scanner-worker.min.js'; qrScanner = new QrScanner(webcam[0], result => { // Swal.fire({ // icon: 'success', // title: 'QR COde', // text: result, // }); qrScanner.destroy(); qrScanner = null; webcam.get(0).srcObject.getTracks().forEach(function(track) { track.stop(); }); localStorage.setItem('qr_decode', result); uploadId("back"); }, error => console.log(error || 'No QR code found.')); navigator.mediaDevices.getUserMedia({ video: { width: { ideal: __options.using_mobile ? 720 : 1280 }, height: { ideal: __options.using_mobile ? 1280: 720 }, facingMode: 'environment' }, audio: false }).then(function (stream) { webcam.get(0).srcObject = stream; webcam.get(0).play(); qrScanner.start(); setTimeout(() => { if (localStorage.getItem("qr_decode") === null) { qrScanner.destroy(); qrScanner = null; webcam.get(0).srcObject.getTracks().forEach(function(track) { track.stop(); }); uploadId("back"); } }, __options.qrCodeTimeOut * 1000); let stream_settings = stream.getVideoTracks()[0].getSettings(); // actual width & height of the camera video let stream_width = stream_settings.width; let stream_height = stream_settings.height; if (webcamHeight * stream_width / stream_height > jQuery(__wrapper).width()) { // webcam falls to width=100% webcam_actual_height = jQuery(__wrapper).width() * stream_height / stream_width; webcamWrap.css({ height: webcam_actual_height }); webcam.css({ height: webcam_actual_height }); canvas.css({ height: webcam_actual_height }); } else { webcam_actual_height = webcamHeight; } console.log(stream_width, stream_height); jQuery('<img/>', { src: __options.style.photos.cameraFrameLarge, css: { height: webcam_actual_height * 0.6, width: webcam_actual_height * 0.6, position: "absolute", background: "rgba(2, 253, 174, 0.4)", borderRadius: "16px" } }).appendTo(webcamWrap); }).catch(function (err) { console.log(err); }) } var uploadId = function (side) { __clearLayout(); var inputFile; var canvas; var webcam; var webcamWrap; var guide; var header = jQuery( side == "qr" ? ` <div style="width: 80%; position: absolute; top: 5%; left: 50%; -webkit-transform: translateX(-50%); transform: translateX(-50%); height: 20px"> <p style="font-size: 0.8rem; font-weight: bold; line-height: 20px;">${__uploadType === 'UPLOAD' ? 'Tải' : 'Chụp'} ảnh vùng QR Code</p> </div> ` : side == "selfie" ? ` <div style="width: 80%; position: absolute; top: 5%; left: 50%; -webkit-transform: translateX(-50%); transform: translateX(-50%); height: 20px"> <p style="font-size: 0.8rem; font-weight: bold; line-height: 20px;">${__uploadType === 'UPLOAD' ? 'Tải' : 'Chụp'} ảnh chân dung</p> </div> ` : ` <div style="width: 80%; position: absolute; top: 5%; left: 50%; -webkit-transform: translateX(-50%); transform: translateX(-50%); height: 20px"> <p style="font-size: 0.8rem; font-weight: bold; line-height: 20px;">${__uploadType === 'UPLOAD' ? 'Tải' : 'Chụp'} ảnh ${__sessionPlan != "PLAN_PASSPORT_BASIC" ? "CMND/CCCD" : "Passport"} mặt ${side == 'front' ? 'trước' : 'sau' }</p> </div> `, ).appendTo(__wrapper); // var backBtn = jQuery("<span/>", { // html: `<img style="height: 12px; margin-top: 4px" src=${__options.style.photos.back} />`, // css: { // float: "left", // cursor: "pointer", // height: "20px", // marginTop: "-20px", // width: "20px", // backgroundColor: __options.style.headlineButtonStyle.backgroundColor, // borderRadius: "100%" // }, // on: { // click: () => side == "back" ? backToUploadID("front") : backToUploadID("back") // } // }) // if (side == "back" || side == "selfie") { // backBtn.appendTo(header) // } var previewImage = jQuery('<img/>', { src: (__sessionPlan == "PLAN_PASSPORT_BASIC" && side == "front") ? __options.style.photos.guidePassport : side == "front" ? __options.style.photos.guideFront : side == "back" ? __options.style.photos.guideBack : side == "selfie" ? __options.style.photos.guideSelfie : __options.style.photos.guideFront, css: { display: __uploadType === 'UPLOAD' ? 'block' : 'none', maxHeight: jQuery(__wrapper).innerHeight() * 0.4 , width: '80%', maxWidth: "300px", position: 'absolute', top: '10%', left: "50%", transform: "translateX(-50%)" }}).appendTo(__wrapper); if (__uploadType === 'UPLOAD') { inputBtn = jQuery('<label/>', { html: `<p style="font-weight: 600">Chọn ảnh</p>`, css: Object.assign({ position: "absolute", width: "96px", height: "44px", top: '60%', left: "50%", transform: "translateX(-50%)", borderRadius: "21.35px" }, __options.style.snapshotButtonStyle) }).appendTo(__wrapper) inputFile = jQuery('<input/>', { type: 'file', accept: 'image/*', // capture: 'camera', css: { display: 'none' }, on: { change: function (e) { console.log(inputFile.get(0).files[0]); if (inputFile.get(0).files[0]) { previewImage.prop('src', URL.createObjectURL(e.target.files[0])); inputBtn.css({ left: "50%", transform: "translateX(-150%)" }) nextButton.css({ "display": "flex", "pointerEvents": "auto" }); } else { previewImage.prop('src', (__sessionPlan == "PLAN_PASSPORT_BASIC" && side == "front") ? __options.style.photos.guidePassport : side == "front" ? __options.style.photos.guideFront : side == "back" ? __options.style.photos.guideBack : side == "selfie" ? __options.style.photos.guideSelfie : __options.style.photos.guideFront); } } } }).appendTo(inputBtn); } var takeSnapshotForWebrtc; if (__uploadType === "WEBRTC") { webcamHeight = parseInt(jQuery(__wrapper).height() * 0.35); console.log(webcamHeight); webcamWrap = jQuery('<div/>', { css: { position: 'absolute', top: "10%", width: "100%", height: webcamHeight, backgroundColor: "black", display: "flex", alignItems: "center", justifyContent: "center", left: "50%", transform: "translateX(-50%)" } }).appendTo(__wrapper); webcam = jQuery('<video/>', { autoplay: true, playsinline: true, css: { width: "100%", height: webcamHeight, // transform: "scale(-1, 1)" } }).appendTo(webcamWrap); canvas = jQuery('<canvas/>', { css: { left: "50%", transform: "translateX(-50%)", height: webcamHeight, position: 'absolute', top: "10%", display: 'none' } }).appendTo(__wrapper); if (jQuery(__wrapper).height() * 0.23 > 180) { guide = jQuery('<div/>', { html: ` <p style="font-size: 0.8rem; position: absolute; top: 10px">Chú ý: tránh chụp ảnh mờ, thiếu góc, chói sáng</p> <img src="${(__sessionPlan == "PLAN_PASSPORT_BASIC" && side == "front") ? __options.style.photos.guidePassport : side == "front" ? __options.style.photos.guideFront : side == "back" ? __options.style.photos.guideBack : side == "selfie" ? __options.style.photos.guideSelfie : __options.style.photos.guideFront}" style="height: 70%;" /> `, css: Object.assign({ position: "absolute", top: "55%", width: "80%", maxWidth: "300px", height: "23%", transform: "translateX(-50%)", left: "50%", position: "absolute", display: "flex", justifyContent: "center", alignItems: "center" }, __options.style.guideBoxStyle) }).appendTo(__wrapper); } else { guide = jQuery('<div/>', { html: ` <p style="font-size: 0.8rem; margin: 10px">Chú ý: tránh chụp ảnh mờ, thiếu góc, chói sáng</p> <img src="${(__sessionPlan == "PLAN_PASSPORT_BASIC" && side == "front") ? __options.style.photos.guidePassport : side == "front" ? __options.style.photos.guideFront : side == "back" ? __options.style.photos.guideBack : side == "selfie" ? __options.style.photos.guideSelfie : __options.style.photos.guideFront}" style="height: 70%; margin: 10px" /> `, css: Object.assign({ position: "absolute", top: "55%", width: "80%", maxWidth: "300px", height: "23%", transform: "translateX(-50%)", left: "50%", position: "absolute", display: "flex", justifyContent: "center", alignItems: "center" }, __options.style.guideBoxStyle) }).appendTo(__wrapper); } takeSnapshotForWebrtc = jQuery('<div/>', { html: `<img style="width: ${Math.min(65, 65 * jQuery(__wrapper).height() / 870, 65 * jQuery(__wrapper).width() / 375) * 40 / 65}px" src="${__options.style.photos.snapshotButtonIcon}"/>`, css: Object.assign({ width: Math.min(65, 65 * jQuery(__wrapper).height() / 870, 65 * jQuery(__wrapper).width() / 375), height: Math.min(65, 65 * jQuery(__wrapper).height() / 870, 65 * jQuery(__wrapper).width() / 375), position: "absolute", bottom: "8%", transform: "translateX(-50%)", left: "50%", borderRadius: "100%", }, __options.style.snapshotButtonStyle ), on: { click: function () { canvas.get(0).width = webcam.get(0).videoWidth; canvas.get(0).height = webcam.get(0).videoHeight; canvas.get(0).getContext('2d').drawImage(webcam.get(0), 0, 0, canvas.get(0).width, canvas.get(0).height); webcamWrap.css({ display: 'none' }); canvas.css({ display: 'block' }); takeSnapshotForWebrtc.css({ display: 'none' }); loadingBox.hide(); guide.css({ display: "none" }) nextButton.css({ "display": "flex", "pointerEvents": "auto" }); tryAgainButton.css({ "display": "flex", "pointerEvents": "auto" }); } } }).appendTo(__wrapper); navigator.mediaDevices.getUserMedia({ video: { // width: 640, // height: 480, width: { ideal: __options.using_mobile ? 1080 : 1920 }, height: { ideal: __options.using_mobile ? 1920: 1080 }, // width: __options.using_mobile ? 480 : 640, // height: __options.using_mobile ? 640 : 480, facingMode: 'environment' }, audio: false }).then(function (stream) { takeSnapshotForWebrtc.css({ display: 'flex' }); webcam.get(0).srcObject = stream; webcam.get(0).play(); let stream_settings = stream.getVideoTracks()[0].getSettings(); // actual width & height of the camera video let stream_width = stream_settings.width; let stream_height = stream_settings.height; if (webcamHeight * stream_width / stream_height > jQuery(__wrapper).width()) { // webcam falls to width=100% webcam_actual_height = jQuery(__wrapper).width() * stream_height / stream_width; webcamWrap.css({ height: webcam_actual_height }); webcam.css({ height: webcam_actual_height }); canvas.css({ height: webcam_actual_height }); } else { webcam_actual_height = webcamHeight; } console.log(stream_width, stream_height); jQuery('<img/>', { src: __options.style.photos.cameraFrameLarge, css: { height: webcam_actual_height * 0.9, width: webcam_actual_height * 0.9 * 280 / 180, position: "absolute", background: "rgba(2, 253, 174, 0.4)", borderRadius: "16px" } }).appendTo(webcamWrap); jQuery('<img/>', { src: __options.style.photos.cameraFrameSmall, css: { height: webcam_actual_height * 0.2, position: "absolute" } }).appendTo(webcamWrap); }).catch(function (err) { console.log(err); }) } var nextButton = jQuery('<div/>', { html: '<p style="font-weight: 600">Xác nhận</p>', type: "button", css: Object.assign({ position: "absolute", width: "96px", height: "44px", right: "50%", transform: "translateX(150%)", top: "60%" }, __options.style.nextButtonStyle), on: { click: function () { var self = this; jQuery(self)[0].style.pointerEvents = 'none'; tryAgainButton[0].style.pointerEvents = 'none'; if (__uploadType == "UPLOAD") { inputFile.prop("disabled", true); } loadingBox.show(); var formData = new FormData(); // var newFormData = new FormData(); if (__uploadType === 'UPLOAD') { formData.append(side != "qr" ? 'image' : "image_file", inputFile.get(0).files[0]); // if (side == "front") newFormData.append("image_file", inputFile.get(0).files[0]); } else { canvas.get(0).toBlob(function (blob) { formData.append(side != "qr" ? 'image' : "image_file", blob, 'id_' + side + '.jpg'); // if (side == "front") newFormData.append("image_file", blob, 'id_' + side + '.jpg'); }, 'image/jpeg', 0.95); } if (side == "selfie") { formData.append("call_decision", true) } setTimeout(function () { if (side != "qr") { if (side == "front") { console.log("basepath", __options.basepath); axios.post(__options.basepath + '/face-search-demo', formData, { headers: { "Authorization": __options.token } } ).then(function (response) { console.log("face search", response); localStorage.setItem("faceSearchData", JSON.stringify(response.data.image_data)); }).catch(function (error) { console.log(error); if (error.response && error.response.status === 429) { localStorage.setItem("faceSearchData", 'API đang gọi quá tần suất cho phép, vui lòng thử lại sau ít phút.'); } else if (error.response && error.response.status === 401) { localStorage.setItem("faceSearchData", 'Vui lòng điền token để xem thông tin này'); } else { localStorage.setItem("faceSearchData", 'API đang gặp lỗi, vui lòng thử lại sau ít phút.'); } }) } axios.post(__options.host + (side == "selfie" ? '/api/kyc/check-selfie' : __sessionPlan == "PLAN_PASSPORT_BASIC" ? '/api/kyc/check-' + side : '/api/kyc/scan-' + side), formData, { headers: { 'Authorization': localStorage.getItem('session_token') } }).then(function (response) { console.log(response.data); if (response.data.error.code === 0) { if (__uploadType == "WEBRTC") { webcam.get(0).srcObject.getTracks().forEach(function(track) { track.stop(); }); } if (side == "selfie") { localStorage.setItem(side, JSON.stringify(response.data)); } else { localStorage.setItem(`id_${side}`, JSON.stringify(response.data)); } if (side == "front") { if (__sessionPlan != "PLAN_PASSPORT_BASIC") { uploadId("back"); } else { if (__uploadType == "UPLOAD") { uploadId("selfie"); } else { liveness(); } } } else if (side == "back") { if (__uploadType == "UPLOAD") { uploadId("selfie"); } else { liveness(); } } else { __getDataUrl(inputFile.get(0).files[0]); __confirmResults(); } } else if (side == "selfie" && response.data.error.code == 21) { __getDataUrl(inputFile.get(0).files[0]); __confirmResults(); } else { throw new Error(response.data.error.code); } }).catch(function (error) { console.log(error); loadingBox.hide(); if (__uploadType === 'UPLOAD' && !inputFile.get(0).files[0]) { __showError('Ảnh CCCD / CMND mặt ' + side == "front" ? "trước" : "sau" + ' là bắt buộc.'); } else if (error.response && error.response.status === 401) { __showError('Phiên làm việc đã bị huỷ. Vui lòng tạo phiên làm việc mới.', initSession); } else { console.log(__getErrorMessage(error.message)); // tryAgainButton.click(); if (__uploadType == "WEBRTC") { __showError(__getErrorMessage(error.message), () => tryAgainButton.click()); } else { __showError(__getErrorMessage(error.message), () => inputBtn.click()); } } }).finally(function () { // jQuery(self).prop('disabled', false); if (__uploadType == "UPLOAD") { inputFile.prop("disabled", false); } if (side != "selfie") { loadingBox.hide(); } }); } else if (side == "qr") { axios.post(__options.host + "/qr-code", formData).then(function (response) { console.log(response.data); if (response.data.error.code === 0) { if (__uploadType == "WEBRTC") { webcam.get(0).srcObject.getTracks().forEach(function(track) { track.stop(); }); } localStorage.setItem('qr_decode', response.data.data.decoded_text); uploadId("back"); } else { if (__uploadType == "WEBRTC") { __showError(response.data.error.message, () => tryAgainButton.click()); } else { __showError(response.data.error.message, () => inputBtn.click()); } } }).catch(function (error) { console.log(error); if (__uploadType === 'UPLOAD' && !inputFile.get(0).files[0]) { __showError('Ảnh QR Code là bắt buộc.'); } else if (error.response && error.response.status === 401) { __showError('Phiên làm việc đã bị huỷ. Vui lòng tạo phiên làm việc mới.', initSession); } }).finally(function () { jQuery(self).prop('disabled', false); loadingBox.hide(); }); } }, 300); } } }).appendTo(__wrapper).hide(); var tryAgainButton = jQuery('<div/>', { html: `<p style="font-weight: 600">${__uploadType === 'UPLOAD' ? 'Tải' : 'Chụp'} lại</p>`, css: Object.assign({ position: "absolute", width: "96px", height: "44px", left: "50%", transform: "translateX(-150%)", top: "60%" }, __options.style.tryAgainButtonStyle), on: { click: function () { if (__uploadType == "WEBRTC") canvas.hide() nextButton.hide() var self = this; jQuery(self).hide(); webcamWrap.css({ display: "flex" }) guide.css({ display: "flex" }) takeSnapshotForWebrtc.css({ display: "flex" }) } } }).appendTo(__wrapper).hide(); var loadingBox = jQuery('<div/>', { html: `<img style="height: 60px;" src="${__options.style.photos.loading}" />`, css: Object.assign({ position: "absolute", width: "100%", bottom: "15%", textAlign: "center", display: "none" }, {}) }).appendTo(__wrapper).hide(); }; var __confirmResults = function() { axios.get(__options.host + "/api/kyc/get-result", { headers: { 'Authorization': localStorage.getItem('session_token') } }).then(function (response) { console.log(response.data); localStorage.setItem("qr_decode", JSON.stringify(response.data.data.qr_code)); localStorage.setItem("mrz_decode", JSON.stringify(response.data.data.mrz_data)); jQuery(__options.wrap_id).html(null); __wrapper = jQuery("<div/>", { css: { height: "100%", minHeight: 500 } }).appendTo(__options.wrap_id); overflow_wrap = jQuery("<div/>", { css: { position: "absolute", top: 0, width: "100%", minHeight: "100%" } } ).appendTo(__wrapper) footer = jQuery("<img/>", { src: __options.style.photos.footer, css: { position: "absolute", bottom: 0, width: "100%", left: 0 } }).appendTo(overflow_wrap); var header = jQuery( ` <div style="width: 80%; position: absolute; top: 5%; left: 50%; -webkit-transform: translateX(-50%); transform: translateX(-50%); height: 20px"> <p style="font-size: 0.8rem; font-weight: bold; line-height: 20px;">Xác nhận thông tin</p> </div> ` ).appendTo(overflow_wrap); // var backBtn = jQuery("<span/>", { // html: `<img style="height: 12px; margin-top: 4px" src=${__options.style.photos.back} />`, // css: { // float: "left", // cursor: "pointer", // height: "20px", // marginTop: "-20px", // width: "20px", // backgroundColor: __options.style.headlineButtonStyle.backgroundColor, // borderRadius: "100%" // }, // on: { // click: () => backToUploadID("selfie") // } // }).appendTo(header) results_wrap = jQuery("<div/>", { css: { "position": "relative", "width": "100%", "marginTop": "5%", "marginBottom": "20%" } }).appendTo(overflow_wrap); results = jQuery("<div/>", { css: { "position": "relative", "maxWidth": 500, "padding": 0, "margin": "25% auto" } }).appendTo(results_wrap); var isFirefox = typeof InstallTrigger !== 'undefined'; if (!isFirefox) { jQuery('<div/>', { css: { height: '100%', position: "absolute", top: "0", width: "65%", left: "50%", transform: "translateX(-50%)", background: "rgba(2, 253, 174, 0.15)", border: "none" // border: "1px solid #02FDAE", // borderBottom: "none", // borderTop: "none" } }).appendTo(results); jQuery('<div/>', { css: { height: '100%', position: "absolute", top: "0", width: "60%", left: "50%", transform: "translateX(-50%)", border: "1px solid rgb(2, 253, 174, 0.39)", borderBottom: "none", borderTop: "none" } }).appendTo(results); jQuery('<div/>', { css: { height: '100%', position: "absolute", top: "0", width: "70%", left: "50%", transform: "translateX(-50%)", border: "1px solid rgb(2, 253, 174, 0.39)", borderBottom: "none", borderTop: "none" } }).appendTo(results); } var idData = response.data.data.fields; jQuery('<div/>', { id: 'personal_information', html: __sessionPlan != "PLAN_PASSPORT_BASIC" ? ( `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">ID</div> <input class="cf-input" type="text" id="cf-id_number" value="${idData.id_number}"/> </div>` + `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Họ và tên</div> <input class="cf-input" type="text" id="cf-name" value="${idData.name}"/> </div>` + `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày sinh</div> <input class="cf-input" type="text" id="cf-dob" value="${idData.birthday}"/> </div>` + `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Giới tính</div> <input class="cf-input" type="text" id="cf-gender" value="${idData.gender}"/> </div>` + `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Quê quán</div> <input class="cf-input" type="text" id="cf-home" value="${idData.home}"/> </div>` + `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Địa chỉ</div> <input class="cf-input" type="text" id="cf-resident" value="${idData.resident}"/> </div>` + (idData.doi ? `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày cấp</div> <input class="cf-input" type="text" id="cf-doi" value="${idData.doi}"/> </div>` : '') + (idData.doe ? `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày hết hạn</div> <input class="cf-input" type="text" id="cf-doe" value="${idData.doe}"/> </div>` : '') + (idData.features ? `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Đặc điểm nhận dạng</div> <input class="cf-input" type="text" id="cf-features" value="${idData.features}"/> </div>` : '') + (idData.poi ? `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Nơi cấp</div> <input class="cf-input" type="text" id="cf-poi" value="${idData.poi}"/> </div>` : '') + (idData.religion ? `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Tôn giáo</div> <input class="cf-input" type="text" id="cf-religion" value="${idData.religion}"/> </div>` : '') + (idData.ethnicity ? `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Dân tộc</div> <input class="cf-input" type="text" id="cf-ethnicity" value="${idData.ethnicity}"/> </div>` : '') ) : ( `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">ID</div> <input class="cf-input" type="text" id="cf-id_number" value="${idData.id_number}"/> </div>` + `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Passport ID</div> <input class="cf-input" type="text" id="cf-pp_number" value="${idData.pp_number}"/> </div>` + `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Họ và tên</div> <input class="cf-input" type="text" id="cf-name" value="${idData.name}"/> </div>` + `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày sinh</div> <input class="cf-input" type="text" id="cf-dob" value="${idData.dob}"/> </div>` + `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Giới tính</div> <input class="cf-input" type="text" id="cf-gender" value="${idData.gender}"/> </div>` + `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Quốc tịch</div> <input class="cf-input" type="text" id="cf-nationality" value="${idData.nationality}"/> </div>` + `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Nơi sinh</div> <input class="cf-input" type="text" id="cf-pob" value="${idData.pob}"/> </div>` + (idData.doi ? `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày cấp</div> <input class="cf-input" type="text" id="cf-doi" value="${idData.doi}"/> </div>` : '') + (idData.doe ? `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Ngày hết hạn</div> <input class="cf-input" type="text" id="cf-doe" value="${idData.doe}"/> </div>` : '') + (idData.poi ? `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Nơi cấp</div> <input class="cf-input" type="text" id="cf-poi" value="${idData.poi}"/> </div>` : '') + (idData.type ? `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Loại</div> <input class="cf-input" type="text" id="cf-type" value="${idData.type}"/> </div>` : '') + (idData.code ? `<div> <div style="padding: 5px 0; width: 50%; display: inline-block">Mã số</div> <input class="cf-input" type="text" id="cf-code" value="${idData.code}"/> </div>` : '') ) , css: { textAlign: 'left', background: "rgba(255, 255, 255, 0.2)", border: "1px solid #02FDAE", boxSizing: "border-box", boxShadow: "0px 1px 24px -1px rgba(0, 0, 0, 0.18)", backdropFilter: "blur(24px)", borderRadius: "19px", padding: "5%", width: "80%", margin: "0 auto", color: __options.style.textColor, fontSize: "0.8rem" } }).appendTo(results); var loadingBox = jQuery('<div/>', { html: `<img style="height: 60px;" src="${__options.style.photos.loading}" />`, css: Object.assign({ position: "absolute", width: "100%", bottom: "-15%", textAlign: "center", display: "none" }, {}) }).appendTo(results).hide(); var nextButton = jQuery('<div/>', { html: '<p style="font-weight: 600">Xác nhận</p>', type: "button", css: Object.assign({ position: "absolute", width: "96px", height: "44px", left: "50%", transform: "translateX(-50%)", bottom: "-15%" }, __options.style.nextButtonStyle), on: { click: function() { var self = this; jQuery(self).hide(); loadingBox.show(); if (__sessionPlan != "PLAN_PASSPORT_BASIC") { idData.id_number = jQuery("#cf-id_number").val(); idData.name = jQuery("#cf-name").val(); idData.birthday = jQuery("#cf-dob").val(); idData.gender = jQuery("#cf-gender").val(); idData.home = jQuery("#cf-home").val(); idData.resident = jQuery("#cf-resident").val(); idData.doi = jQuery("#cf-doi").val(); idData.doe = jQuery("#cf-doe").val(); idData.features = jQuery("#cf-features").val(); idData.poi = jQuery("#cf-poi").val(); idData.religion = jQuery("#cf-religion").val(); idData.ethnicity = jQuery("#cf-ethnicity").val(); } else { idData.id_number = jQuery("#cf-id_number").val(); idData.pp_number = jQuery("#cf-pp_number").val(); idData.name = jQuery("#cf-name").val(); idData.dob = jQuery("#cf-dob").val(); idData.gender = jQuery("#cf-gender").val(); idData.nationality = jQuery("#cf-nationality").val(); idData.doi = jQuery("#cf-doi").val(); idData.doe = jQuery("#cf-doe").val(); idData.pob = jQuery("#cf-pob").val(); idData.poi = jQuery("#cf-poi").val(); idData.code = jQuery("#cf-code").val(); idData.type = jQuery("#cf-type").val(); } axios.post(__options.host + "/api/kyc/confirm?get_full_result=true", JSON.stringify( idData ), { headers: { 'Authorization': localStorage.getItem('session_token'), "Content-Type": "application/json" } }).then(function (response) { console.log(response.data); localStorage.setItem("antifraud", JSON.stringify(response.data.antifraud_data)); localStorage.setItem("selfie", JSON.stringify(response.data.selfie_data)); localStorage.setItem("decision", response.data.decision); localStorage.setItem("decision_details", JSON.stringify(response.data.decision_detail)); localStorage.setItem("verify", JSON.stringify(response.data.verify_data)); localStorage.setItem("ocr_data", JSON.stringify(response.data.recorrect_data)); renderResult(); }).catch(function (error) { console.log(error); if (error.response && error.response.status === 400) { console.log(error.response.data); if (error.response.data.data) __showError(error.response.data.data); else __showError("Lỗi hệ thống. Vui lòng thử lại.", __confirmResults); } else if (error.response && error.response.status === 504) { __showWarning('Vẫn đang trong quá trình xử lý, vui lòng thử lại sau vài giây.', initSession); } else { __showError("Lỗi hệ thống. Vui lòng thử lại.", __confirmResults); } }) .finally(function () { jQuery(self).show(); loadingBox.hide(); }); } } }).appendTo(results); }).catch(function (error) { console.log(error); if (error.response && error.response.status === 401) { __showError('Phiên làm việc đã bị huỷ. Vui lòng tạo phiên làm việc mới.', initSession); } else if (error.response && error.response.status === 504) { __showWarning('Vẫn đang trong quá trình xử lý, vui lòng thử lại sau vài giây.', __confirmResults); } else { __showError("Lỗi hệ thống. Vui lòng thử lại.", __confirmResults); } }) } var initSession = function () { __clearLocalStorage(); __clearLayout(); var loadingBox = jQuery('<div/>', { html: `<img style="height: 60px;" src="${__options.style.photos.loading}" />`, css: Object.assign({ position: "absolute", width: "100%", top: "50%", transform: "translateY(-50%)", textAlign: "center", }, {}) }).appendTo(__options.wrap_id); jQuery(__options.wrap_id).css({ color: __options.style.textColor, overflowY: "scroll", }) var css = `${__options.wrap_id}::-webkit-scrollbar{ display: none}`; var style = document.createElement('style'); if (style.styleSheet) { style.styleSheet.cssText = css; } else { style.appendChild(document.createTextNode(css)); } document.getElementsByTagName('head')[0].appendChild(style); setTimeout(() => { getSessionData = new Promise(resolve => { resolve(__options.app_authorization()); }); getSessionData.then((response) => { localStorage.setItem("session_token", response.session_id); __sessionPlan = response.session_plan; __uploadType = response.upload_type; __allowFullResults = response.allow_sdk_full_results; uploadId("front"); // liveness(); }).catch((error) => { if (error.response && error.response.status != 200) { __showError("Hệ thống đang nhiều người dùng, vui lòng thử lại sau ít phút.", () => window.location.reload()); } else { console.log(error); __showError("Có lỗi xảy ra :(", () => window.location.reload()); } }); }, 1000); }; var backToUploadID = function (side) { try { __stop(true); } catch (err) { console.error(err) } setTimeout(() => uploadId(side), 1000); } var init = function (options) { if (!window.jQuery) { console.error('jQuery plugin did not load. Please import jQuery plugin to use ekyc sdk.'); } else { console.log('jQuery plugin loaded.'); __options = Object.assign({}, {}, options); jQuery("body").append(`<script src="https://cdn.jsdelivr.net/npm/qr-scanner@1.3.0/qr-scanner.umd.min.js" integrity="sha256-9MELwMQTIue1iGGeA6c2/4X62FGsTxBEScdDoPNnNaQ=" crossorigin="anonymous"></script>`); if (__options.app_authorization) { // add other plugins jQuery('body').append('<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.26.0/axios.min.js"></script>'); if (__options.handle_result === 'socket') { jQuery('body').append('<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.2.0/socket.io.js"></script>'); } if (__options.sweetalert2_install) { jQuery('body').append('<script src="//cdn.jsdelivr.net/npm/sweetalert2@11"></script>'); } // render initSession(); } else { console.log('initSessionFunction is missing.'); } } }; return { init: init }; })();
Editor is loading...