Skip to content

Commit

Permalink
[ES-21] QRCode buffer configuration added (mosip#274)
Browse files Browse the repository at this point in the history
* QRCode buffer configuration added

* config key name updated

* README updated

* sbi-integrator version updated

* application properties updated
  • Loading branch information
anshulv1401 authored and ase-101 committed Jan 23, 2024
1 parent 779451e commit 91d785b
Show file tree
Hide file tree
Showing 9 changed files with 122 additions and 43 deletions.
7 changes: 5 additions & 2 deletions esignet-service/src/main/resources/application-dev.properties
Original file line number Diff line number Diff line change
Expand Up @@ -229,14 +229,17 @@ mosip.keymanager.dao.enabled=false
crypto.PrependThumbprint.enable=true

## -------------------------------------------- IDP-UI config ----------------------------------------------------------
# NOTE:
# 1. linked-transaction-expire-in-secs value should be a sum of mosip.esignet.authentication-expire-in-secs and linked cache expire in seconds under mosip.esignet.cache.expire-in-seconds property
# 2. A new Qrcode will be autogenerated before the expiry of current qr-code, and the time difference in seconds for the same is defined in wallet.qr-code-buffer-in-secs property

mosip.esignet.ui.config.key-values={'sbi.env': 'Developer', 'sbi.timeout.DISC': 30, \
'sbi.timeout.DINFO': 30, 'sbi.timeout.CAPTURE': 30, 'sbi.capture.count.face': 1, 'sbi.capture.count.finger': 2, \
'sbi.capture.count.iris': 1, 'sbi.capture.score.face': 70, 'sbi.capture.score.finger':70, 'sbi.capture.score.iris':70, 'wallet.logo-url': 'inji_logo.png', \
'send.otp.channels':'email,phone', 'consent.screen.timeout-in-secs':${mosip.esignet.authentication-expire-in-secs}, \
'consent.screen.timeout-buffer-in-secs': 5, 'sbi.port.range': 4501-4600, 'sbi.bio.subtypes.iris': 'UNKNOWN', 'sbi.bio.subtypes.finger': 'UNKNOWN', \
'resend.otp.delay.secs': 120, 'captcha.enable': 'OTP', 'captcha.sitekey': '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI', \
'mosip.esignet.link-auth-code-expire-in-secs': 120, 'mosip.esignet.link-status-deferred-response-timeout-secs': 25, \
'resend.otp.delay.secs': 120, 'captcha.enable': '', 'captcha.sitekey': '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI', \
'linked-transaction-expire-in-secs': 120, 'wallet.qr-code-buffer-in-secs': 10, \
'mosip.esignet.qr-code.deep-link-uri': 'inji://landing-page-name?linkCode=LINK_CODE&linkExpireDateTime=LINK_EXPIRE_DT', \
'mosip.esignet.qr-code.download-uri': '#', 'mosip.esignet.qr-code.enable': 'true', 'auth.txnid.length': 10, \
'otp.length': 6, 'password.regex': ''}
Original file line number Diff line number Diff line change
Expand Up @@ -224,14 +224,17 @@ mosip.keymanager.dao.enabled=false
crypto.PrependThumbprint.enable=true

## -------------------------------------------- IDP-UI config ----------------------------------------------------------
# NOTE:
# 1. linked-transaction-expire-in-secs value should be a sum of mosip.esignet.authentication-expire-in-secs and linked cache expire in seconds under mosip.esignet.cache.expire-in-seconds property
# 2. A new Qrcode will be autogenerated before the expiry of current qr-code, and the time difference in seconds for the same is defined in wallet.qr-code-buffer-in-secs property

mosip.esignet.ui.config.key-values={'sbi.env': 'Developer', 'sbi.timeout.DISC': 30, \
'sbi.timeout.DINFO': 30, 'sbi.timeout.CAPTURE': 30, 'sbi.capture.count.face': 1, 'sbi.capture.count.finger': 2, \
'sbi.capture.count.iris': 1, 'sbi.capture.score.face': 70, 'sbi.capture.score.finger':70, 'sbi.capture.score.iris':70, 'wallet.logo-url': 'inji_logo.png', \
'send.otp.channels':'email,phone', 'consent.screen.timeout-in-secs':${mosip.esignet.authentication-expire-in-secs}, \
'consent.screen.timeout-buffer-in-secs': 5, 'sbi.port.range': 4501-4600, 'sbi.bio.subtypes.iris': 'UNKNOWN', 'sbi.bio.subtypes.finger': 'UNKNOWN', \
'resend.otp.delay.secs': 120, 'captcha.enable': 'OTP', 'captcha.sitekey': '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI', \
'mosip.esignet.link-auth-code-expire-in-secs': 120, 'mosip.esignet.link-status-deferred-response-timeout-secs': 25, \
'resend.otp.delay.secs': 120, 'captcha.enable': '', 'captcha.sitekey': '6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI', \
'linked-transaction-expire-in-secs': 120, 'wallet.qr-code-buffer-in-secs': 10, \
'mosip.esignet.qr-code.deep-link-uri': 'inji://landing-page-name?linkCode=LINK_CODE&linkExpireDateTime=LINK_EXPIRE_DT', \
'mosip.esignet.qr-code.download-uri': '#', 'mosip.esignet.qr-code.enable': 'true', 'auth.txnid.length': 10, \
'otp.length': 6, 'password.regex': ''}
4 changes: 2 additions & 2 deletions oidc-ui/.env
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ REACT_APP_SBI_IRIS_CAPTURE_SCORE=70
REACT_APP_SBI_IRIS_BIO_SUBTYPES="UNKNOWN"
REACT_APP_SBI_FINGER_BIO_SUBTYPES="UNKNOWN"

REACT_APP_LINK_AUTH_CODE_TIMEOUT_IN_SEC=120
REACT_APP_LINK_CODE_DEFERRED_TIMEOUT_IN_SEC=25
REACT_APP_LINKED_TRANSACTION_EXPIRE_IN_SEC=120
REACT_APP_QR_CODE_BUFFER_IN_SEC=10
REACT_APP_QRCODE_DEEP_LINK_URI="inji://landing-page-name?linkCode=LINK_CODE&linkExpireDateTime=LINK_EXPIRE_DT"
REACT_APP_QRCODE_APP_DOWNLOAD_URI="#"
REACT_APP_QRCODE_ENABLE="true"
Expand Down
14 changes: 10 additions & 4 deletions oidc-ui/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,13 @@ The application runs on PORT=3000 by default.
```

- Build and run on the local system:
Update ".env.development" file, add REACT_APP_ESIGNET_API_URL=<'Complete URL of Esignet Services'>
```
$ npm start
```
- Update ".env.development" file, add REACT_APP_ESIGNET_API_URL=<'Complete URL of Esignet Services'>
- Start oidc-ui
```
$ npm start
```
- Run the browser with web-security disabled. For Google chrome the command is
```
chrome.exe --user-data-dir="C://Chrome dev session" --disable-web-security
```
- Open URL http://localhost:3000
2 changes: 1 addition & 1 deletion oidc-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"i18next-browser-languagedetector": "^7.0.0",
"i18next-http-backend": "^2.0.1",
"jose": "^4.9.3",
"secure-biometric-interface-integrator": "^0.1.0",
"secure-biometric-interface-integrator": "^0.9.0",
"qrcode": "^1.5.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
Expand Down
6 changes: 5 additions & 1 deletion oidc-ui/public/locales/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@
"invalid_value": "قيمة غير صالحة",
"duplicate_individual_id": "المعرف الفردي موجود بالفعل.",
"password_error_msg": "رمز مرور خاطئ",
"invalid_qrcode_config": "تكوين QRCode غير صالح. يرجى إبلاغ مدير الموقع.",
"0": "النجاح",
"100": "الجهاز غير مسجل",
"101": "غير قادر على الكشف عن كائن القياسات الحيوية",
Expand Down Expand Up @@ -344,6 +345,9 @@
"IDA-RST-005": "المهلة غير صالحة",
"IDA-RST-006": "4XX - حدث خطأ في العميل",
"IDA-RST-007": "5XX - حدث خطأ في الخادم",
"IDA-RST-008": "انتهت مدة الاتصال"
"IDA-RST-008": "انتهت مدة الاتصال",
"IDA-KBT-001": "لم يتم العثور على الشهادة المنضمة",
"IDA-KBT-002": "الرمز المميز الموقع الصادر في (iat) ليس في النطاق الزمني المسموح به.",
"IDA-KBT-003": "خطأ في التحقق من الرمز المميز المرتبط بالمفتاح."
}
}
6 changes: 5 additions & 1 deletion oidc-ui/public/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@
"invalid_value": "Invalid value",
"duplicate_individual_id": "Individual ID already exists.",
"password_error_msg": "Invalid Password",
"invalid_qrcode_config": "Invalid QRCode configuration. Please report to the site admin.",
"0": "Success",
"100": "Device Not Registered",
"101": "Unable to Detect a Biometrics",
Expand Down Expand Up @@ -344,6 +345,9 @@
"IDA-RST-005": "Timeout is invalid",
"IDA-RST-006": "4XX - Client Error occurred",
"IDA-RST-007": "5XX - Server Error occurred",
"IDA-RST-008": "Connection timed out"
"IDA-RST-008": "Connection timed out",
"IDA-KBT-001": "Bound certificate not found",
"IDA-KBT-002": "Signed token issued at (iat) is not in allowed time range.",
"IDA-KBT-003": "Error verifying key binded token."
}
}
115 changes: 87 additions & 28 deletions oidc-ui/src/components/LoginQRCode.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,32 @@ export default function LoginQRCode({
const [qr, setQr] = useState("");
const [status, setStatus] = useState({ state: states.LOADED, msg: "" });
const [error, setError] = useState(null);
const [qrCodeTimeOut, setQrCodeTimeout] = useState();

const linkAuthCodeExpireInSec =
const linkedTransactionExpireInSec =
openIDConnectService.getEsignetConfiguration(
configurationKeys.linkAuthCodeExpireInSec
) ?? process.env.REACT_APP_LINK_AUTH_CODE_TIMEOUT_IN_SEC;
configurationKeys.linkedTransactionExpireInSecs
) ?? process.env.REACT_APP_LINKED_TRANSACTION_EXPIRE_IN_SEC;

/*
linkCodeDeferredTimeoutInSec is link_status Grace period. link-status request will not be triggered
if the linkCode is going to expire within grace period.
The QRCode will be valid even after expiring on the UI for the period of qrCodeBufferInSecs.
*/
const linkCodeDeferredTimeoutInSec =
const qrCodeBufferInSecs =
openIDConnectService.getEsignetConfiguration(
configurationKeys.linkCodeDeferredTimeoutInSec
) ?? process.env.REACT_APP_LINK_CODE_DEFERRED_TIMEOUT_IN_SEC;
configurationKeys.qrCodeBufferInSecs
) ?? process.env.REACT_APP_QR_CODE_BUFFER_IN_SEC;

let parseTimeout = parseInt(linkCodeDeferredTimeoutInSec);
const qrCodeBuffer =
parseInt(qrCodeBufferInSecs) !== "NaN"
? parseInt(qrCodeBufferInSecs)
: process.env.REACT_APP_QR_CODE_BUFFER_IN_SEC;

const linkStatusGracePeriod = parseTimeout !== "NaN" ? parseTimeout : 25;
const walletLogoURL =
openIDConnectService.getEsignetConfiguration(
configurationKeys.walletLogoURL
) ?? process.env.REACT_APP_WALLET_LOGO_URL;

const GenerateQRCode = (response) => {
const GenerateQRCode = (response, logoUrl) => {
let text =
openIDConnectService.getEsignetConfiguration(
configurationKeys.qrCodeDeepLinkURI
Expand All @@ -56,7 +62,9 @@ export default function LoginQRCode({
response.expireDateTime
);

QRCode.toDataURL(
const canvas = document.createElement("canvas");
QRCode.toCanvas(
canvas,
text,
{
width: 500,
Expand All @@ -65,20 +73,54 @@ export default function LoginQRCode({
dark: "#000000",
},
},
(err, text) => {
(err) => {
if (err) {
setError({
errorCode: "link_code_refresh_failed",
});
return;
}
setQr(text);
if (logoUrl) {
const logo = new Image();
logo.src = logoUrl;
logo.onload = () => {
const ctx = canvas.getContext("2d");
const size = canvas.width / 6;
const x = (canvas.width - size) / 2;
const y = (canvas.height - size) / 2;
// Create a new canvas to filter the logo image
const filterCanvas = document.createElement("canvas");
filterCanvas.width = logo.width;
filterCanvas.height = logo.height;
const filterCtx = filterCanvas.getContext("2d");
filterCtx.drawImage(logo, 0, 0);
ctx.fillStyle = "#000000";
ctx.fillRect(x - 6, y - 6, size + 12, size + 12);
// Draw the filtered image onto the QR code canvas
ctx.fillStyle = "#ffffff";
ctx.fillRect(200, 200, 100, 100);
ctx.drawImage(filterCanvas, x, y, size, size);
setQr(canvas.toDataURL());
};
logo.onerror = () => {
// If there's an error fetching the logo, generate QR code without the logo
setQr(canvas.toDataURL());
};
} else {
// If logoUrl is not configured, generate QR code without the logo
setQr(canvas.toDataURL());
}
}
);
};

useEffect(() => {
fetchQRCode();

return () => {
//clearing timeout before component unmount
clearTimeout(qrCodeTimeOut);
};
}, []);

const fetchQRCode = async () => {
Expand All @@ -99,13 +141,42 @@ export default function LoginQRCode({
defaultMsg: errors[0].errorMessage,
});
} else {
GenerateQRCode(response);
let qrCodeExpiryDateTime = new Date(response.expireDateTime);
let timeLeft = (qrCodeExpiryDateTime - new Date()) / 1000; // timeleft in sec

if (qrCodeBuffer > (timeLeft + 1) / 2) {
/*
qrCodeBuffer should not be greater then the half of link-code-expire-in-secs.
It reduces the chances of more then 2 active link-status polling request at a time.
*/
setError({
errorCode: "invalid_qrcode_config",
defaultMsg:
"Invalid QRCode configuration. Please report to the site admin.",
});
return;
}

/*
considering buffer time before next qrcode render, which will allow previous
qrcode's link-status polling request to be active for the buffer period.
*/
let timeLeftWithBuffer = timeLeft - qrCodeBuffer;

GenerateQRCode(response, walletLogoURL);
setStatus({ state: states.LOADED, msg: "" });
triggerLinkStatus(
response.transactionId,
response.linkCode,
response.expireDateTime
);

clearTimeout(qrCodeTimeOut);
let _timer = setTimeout(() => {
if (linkAuthTriggered) return;
fetchQRCode();
}, timeLeftWithBuffer * 1000);
setQrCodeTimeout(_timer);
}
} catch (error) {
setError({
Expand All @@ -124,7 +195,6 @@ export default function LoginQRCode({
try {
let expiryDateTime = new Date(linkCodeExpiryDateTime);
let timeLeft = (expiryDateTime - new Date()) / 1000; // timeleft in sec
let qrExpired = false;
let linkStatusResponse;
while (timeLeft > 0) {
try {
Expand All @@ -150,17 +220,6 @@ export default function LoginQRCode({
}

timeLeft = (expiryDateTime - new Date()) / 1000;
if (
!qrExpired &&
timeLeft < linkStatusGracePeriod &&
(!linkStatusResponse || !linkStatusResponse?.response)
) {
qrExpired = true;
// setError({
// errorCode: "qr_code_expired",
// });
fetchQRCode();
}
}

if (linkAuthTriggered) return;
Expand Down Expand Up @@ -203,7 +262,7 @@ export default function LoginQRCode({
try {
let codeExpiryDateTime = new Date();
codeExpiryDateTime.setSeconds(
codeExpiryDateTime.getSeconds() + Number(linkAuthCodeExpireInSec)
codeExpiryDateTime.getSeconds() + Number(linkedTransactionExpireInSec)
);
let timeLeft = (codeExpiryDateTime - new Date()) / 1000;
let linkAuthResponse;
Expand Down
4 changes: 2 additions & 2 deletions oidc-ui/src/constants/clientConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ const configurationKeys = {
captchaEnableComponents: "captcha.enable", //comma separated list of components where captcha needs to be shown
captchaSiteKey: "captcha.sitekey", //site key for ReCAPTCHA

linkAuthCodeExpireInSec: "mosip.esignet.link-auth-code-expire-in-secs",
linkCodeDeferredTimeoutInSec: "mosip.esignet.link-status-deferred-response-timeout-secs",
linkedTransactionExpireInSecs: "linked-transaction-expire-in-secs",
qrCodeBufferInSecs: "wallet.qr-code-buffer-in-secs",
qrCodeDeepLinkURI: "mosip.esignet.qr-code.deep-link-uri",
appDownloadURI: "mosip.esignet.qr-code.download-uri",
signInWithQRCodeEnable: "mosip.esignet.qr-code.enable",
Expand Down

0 comments on commit 91d785b

Please sign in to comment.