<!DOCTYPE html>
<html lang=“en”>
<head>
<meta charset=“UTF-8”>
<meta http-equiv=“X-UA-Compatible” content=“IE=edge”>
<meta name=“viewport” content=“width=device-width, initial-scale=1.0”>
<title>AUTHENTICATION PAGE</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 0;
background-color: #f4f4f4;
}
.container {
max-width: 1200px;
height: 700px;
margin: 20px auto;
background-color: #fff;
padding: 20px;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.5);
background-image: url(‘https://6714807-sb1.app.netsuite.com/core/media/media.nl?id=15563&c=6714807_SB1&h=CHLhht2H8a_iVK5shyUR6IVgn76sMH7D_bDL8NrP0lt7NZiX’);
background-size: cover;
background-position: center;
}
h1 {
text-align: left;
color: #555050;
}
.subheading {
text-align: left;
margin-bottom: 20px;
color: #666;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 5px;
color: #333;
}
input[type=“text”] {
width: 100%;
padding: 10px;
border: 1px solid #ccc;
border-radius: 3px;
box-sizing: border-box;
}
.login-image {
display: block;
margin: 0 auto;
max-width: 70%;
height: auto;
}
.btn {
padding: 10px 20px;
border: none;
border-radius: 3px;
cursor: pointer;
}
.btn.authenticate {
background-color: #007bff;
color: #fff;
display: none;
}
.btn.validate {
background-color: #28a745;
color: #fff;
display: block;
}
.btn.register {
background-color: #dc3545;
color: #fff;
display: none;
}
.btn:hover {
opacity: 0.8;
}
@media only screen and (max-width: 600px) {
.container {
width: 90%;
}
.login-image {
max-width: 70%;
height: auto;
}
}
@media only screen and (max-aspect-ratio: 3/8) {
.container {
max-width: 600px;
height: auto;
}
}
@media only screen and (min-width: 1360px) {
.container {
max-width: 1200px;
height: auto;
}
}
@media only screen and (min-width: 600px) and (max-width: 1300px) {
input[type=“text”] {
max-width: 400px;
width: 100%;
height: auto;
}
}
input[type=“text”] {
width: calc(100% – 20px);
}
</style>
</head>
<body>
<div class=“container”>
<img src=“https://6714807-sb1.app.netsuite.com/core/media/media.nl?id=15564&c=6714807_SB1&h=iHgST3ePR9YPD6w54icR5WrFXO_OMO6tn-GzRUyLl1sOyYQh&_xt=.bin/”
alt=“Login Image” class=“login-image”>
<h1>User Registration Page</h1>
<p class=“subheading”>Authentication is required to access job processes.</p>
<form id=“loginForm”>
<div class=“form-group”>
<label for=“username”>Username</label>
<input type=“text” id=“username” name=“username” required>
</div>
<div class=“form-group”>
<button type=“button” id=“validate” class=“btn validate”
onclick=“callSuitelet(‘validate’)”>Validate</button>
<button type=“button” id=“authenticate” class=“btn authenticate”
onclick=“authenticateUser()”>Authenticate</button>
<button type=“button” id=“register” class=“btn register” onclick=“registerUser()”>Register</button>
</div>
</form>
</div>
</body>
<script>
/**
* Sets focus on the username input field when the window is loaded.
* @returns {void}
*/
window.onload = function () {
document.getElementById(‘username’).focus();
};
/**
* Converts an ArrayBuffer to a base64 string.
* @param {ArrayBuffer} buf – The ArrayBuffer to convert.
* @returns {string} The base64 string representation of the ArrayBuffer.
*/
function ab2str(buf) {
try {
return btoa(String.fromCharCode.apply(null, new Uint8Array(buf)));
} catch (error) {
console.log(“error@ab2str”, error);
}
}
/**
* Converts a base64 string to an ArrayBuffer.
* @param {string} str – The base64 string to convert.
* @returns {Uint8Array} The Uint8Array representing the ArrayBuffer.
*/
function str2ab(str) {
try {
return new Uint8Array(atob(str).split(”).map(char => char.charCodeAt(0)));
} catch (error) {
console.log(“error@str2ab”, error);
}
}
/**
* @description the fuctcion to construct the url
* @param user – username
* @param rawValue – raw value for constructing the key
*/
function generateSuiteletURL(user, rawValue) {
try {
return `https://6714807-sb1.extforms.netsuite.com/app/site/hosting/scriptlet.nl?script=2038&deploy=1&compid=6714807_SB1&h=2ae41c67dd15388e45db&username=${user}&rawVal=${rawValue}`;
} catch (error) {
console.log(“error@generateSuiteletURL”, error);
}
}
/**
* @description the fuctcion to check whether the user name is valid
* @param requestTypParam – parameter based on which the function is executed in suitelet
*/
function callSuitelet(requestTypParam) {
let username = document.getElementById(‘username’).value;
console.log(“username”, username)
let SUITELET_URL = generateSuiteletURL(username)
// Perform a fetch operation to call the Suitelet script
fetch(SUITELET_URL, {
method: ‘POST’,
headers: {
‘Content-Type’: ‘application/x-www-form-urlencoded;charset=UTF-8’,
},
body: JSON.stringify({
requestType: requestTypParam == “validate” ? “validatePassKey” : “IsUserExist”,
data: username
})
})
.then(response => response.json())
.then(data => {
try {
console.log(“data”, data);
if (data.data != null) {
document.getElementById(‘validate’).style.display = ‘none’;
if (data.userkey) {
document.getElementById(‘register’).style.display = ‘inline-block’;
document.getElementById(‘authenticate’).style.display = ‘inline-block’;
} else {
document.getElementById(‘register’).style.display = ‘inline-block’;
}
}
else {
alert(“The User is not available in the NetSuite account. Please contact your administrator”)
}
} catch (err) {
console.log(“err”, err)
}
})
}
/**
* @description the fuctcion to register the user when register button is clicked
*/
function registerUser() {
try {
let user = document.getElementById(‘username’).value;
if (user != ”) {
const publicKeyCredentialCreationOptions = {
challenge: new Uint8Array([
// must be a cryptographically random number sent from a server
0x8c, 0x0a, 0x26, 0xff, 0x22, 0x91, 0xc1, 0xe9, 0xb9, 0x4e, 0x2e, 0x17, 0x1a,
0x98, 0x6a, 0x73, 0x71, 0x9d, 0x43, 0x48, 0xd5, 0xa7, 0x6a, 0x15, 0x7e, 0x38,
0x94, 0x52, 0x77, 0x97, 0x0f, 0xef,
]),
rp: {
name: “NetSuite”,
},
user: {
id: new Uint8Array(16),
name: user,
displayName: user,
},
userVerification: “preferred”,
transports: [“ble”, “internal”, “usb”, “hybrid”, “nfc”],
pubKeyCredParams: [{ alg: –7, type: “public-key” }, { type: “public-key”, alg: –257 }],
authenticatorSelection: {
authenticatorAttachment: “cross-platform”,
},
timeout: 60000,
attestation: “direct”
};
const creds = getNewCreds(publicKeyCredentialCreationOptions);
}
else if (user == ”) {
alert(“Please enter the User name”);
document.getElementById(‘username’).focus();
}
} catch (error) {
console.log(“error@register”, error);
}
}
/**
* Creates new credentials using Web Authentication API and sends them to a Suitelet for processing.
* @param {Object} publicKeyCredentialCreationOptions – Options for creating a new public key credential.
* @returns {void}
*/
function getNewCreds(publicKeyCredentialCreationOptions) {
try {
let user = document.getElementById(‘username’).value;
let SUITELET_URL, rawValue;
navigator.credentials.create({
publicKey: publicKeyCredentialCreationOptions
}).then((cred) => {
rawValue = btoa(String.fromCharCode.apply(null, new Uint8Array(cred.rawId)));
const SUITELET_URL = generateSuiteletURL(user, rawValue);
fetch(SUITELET_URL, {
method: ‘POST’,
headers: {
‘Content-Type’: ‘application/x-www-form-urlencoded;charset=UTF-8’,
},
body: JSON.stringify({
requestType: “updatePassKey”,
data: {
username: user,
passkey: rawValue
}
})
})
.then(response => response.json())
.then(data => {
console.log(“data”, data)
// Check if the response is successful
if (data.status == “passKeyUpdated”) {
document.getElementById(‘register’).style.display = ‘inline-block’;
document.getElementById(‘authenticate’).style.display = ‘inline-block’;
}
else {
alert(“Error occurred during registration, please contact your administrator”)
}
})
})
} catch (error) {
console.log(“error@getNewCreds”, error);
}
}
/**
* @description the fuctcion to authenticate the user when authenticate button is clicked
*/
function authenticateUser() {
try {
let user = document.getElementById(‘username’).value;
if (user != ”) {
user = user.trim();
// const SUITELET_URL = generateSuiteletURL(user);
let SUITELET_URL = ‘https://6714807-sb1.extforms.netsuite.com/app/site/hosting/scriptlet.nl?script=2038&deploy=1&compid=6714807_SB1&h=2ae41c67dd15388e45db’;
fetch(SUITELET_URL, {
method: ‘POST’,
headers: {
‘Content-Type’: ‘application/x-www-form-urlencoded;charset=UTF-8’,
},
body: JSON.stringify({
requestType: “authenticatePassKey”,
data: {
username: user
}
})
})
.then(response => response.json())
.then(data => {
console.log(“data”, data);
if (data.userkey) {
let userName = data.data;
userName = userName.trim();
let value = data.userkey;
console.log(“value”, value);
//value = str2ab(value);
let bufferValue = str2ab(value);
console.log(“bufferValue”, bufferValue);
const publicKeyValues = {
allowCredentials: [{
id: bufferValue,
type: ‘public-key’,
}],
userVerification: “preferred”,
transports: [“ble”, “internal”, “usb”, “hybrid”, “nfc”],
timeout: 60000,
challenge: new Uint8Array([
// must be a cryptographically random number sent from a server
0x8c, 0x0a, 0x26, 0xff, 0x22, 0x91, 0xc1, 0xe9, 0xb9, 0x4e, 0x2e, 0x17, 0x1a,
0x98, 0x6a, 0x73, 0x71, 0x9d, 0x43, 0x48, 0xd5, 0xa7, 0x6a, 0x15, 0x7e, 0x38,
0x94, 0x52, 0x77, 0x97, 0x0f, 0xef,
]),
};
console.log(“publicKeyValues”, publicKeyValues);
const assertion = credentialsGet(publicKeyValues, data.userId);
} else if (data.finalData == null) {
alert(“Biometric authentication failed. Please try again.”);
}
})
} else {
alert(“Please enter the User name”);
}
return false;
} catch (error) {
console.log(“error @authenticateUser”, error);
}
}
/**
* Function to retrieve credentials using Web Authentication API and redirecting to a specified script URL.
* @param {Object} publicKeyValues – Options for retrieving public key credentials.
* @param {string} userName – The username for the current user.
* @returns {void}
*/
function credentialsGet(publicKeyValues, userName) {
try {
console.log(“inside credential”)
let SCRIPT_URL = “https://6714807-sb1.extforms.netsuite.com/app/site/hosting/scriptlet.nl?script=2035&deploy=1&compid=6714807_SB1&h=db3336fdf2c68a14f488&userName=”
if (SCRIPT_URL.includes(“compid”) && SCRIPT_URL.includes(“h”)) {
SCRIPT_URL = SCRIPT_URL + userName;
console.log(“SCRIPT_URL”,SCRIPT_URL)
}
navigator.credentials.get({
publicKey: publicKeyValues
}).then((assertions) => {
window.open(SCRIPT_URL, “_self”)
})
} catch (error) {
console.log(“error @credentialsGet”, error)
alert(“Error in biometric authentication. Please try again.”);
}
}
</script>
</html>
