Untitled
unknown
javascript
3 years ago
107 kB
6
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...