Module dependency cleanup.

This commit is contained in:
Ylian Saint-Hilaire 2019-03-25 11:32:16 -07:00
parent d63639fc62
commit ac6c39dabe
11 changed files with 16630 additions and 48 deletions

View File

@ -1606,23 +1606,16 @@ function InstallModules(modules, func) {
// Check if a module is present and install it if missing // Check if a module is present and install it if missing
var InstallModuleChildProcess = null; var InstallModuleChildProcess = null;
function InstallModule(modulename, func, tag1, tag2) { function InstallModule(modulename, func, tag1, tag2) {
try { console.log('Installing ' + modulename + '...');
var module = require(modulename); var child_process = require('child_process');
} catch (e) {
console.log('Installing ' + modulename + '...');
var child_process = require('child_process');
// Looks like we need to keep a global reference to the child process object for this to work correctly.
InstallModuleChildProcess = child_process.exec('npm install ' + modulename + ' --no-optional --save', { maxBuffer: 512000, timeout: 10000 }, function (error, stdout, stderr) {
InstallModuleChildProcess = null;
if (error != null) { console.log('ERROR: Unable to install missing package \'' + modulename + '\', make sure npm is installed: ' + error); process.exit(); return; }
func(tag1, tag2);
return;
});
// Looks like we need to keep a global reference to the child process object for this to work correctly.
InstallModuleChildProcess = child_process.exec('npm install ' + modulename + ' --no-optional --save', { maxBuffer: 512000, timeout: 10000 }, function (error, stdout, stderr) {
InstallModuleChildProcess = null;
if (error != null) { console.log('ERROR: Unable to install missing package \'' + modulename + '\', make sure npm is installed: ' + error); process.exit(); return; }
func(tag1, tag2);
return; return;
} });
func(tag1, tag2);
} }
// Detect CTRL-C on Linux and stop nicely // Detect CTRL-C on Linux and stop nicely
@ -1640,10 +1633,12 @@ function mainStart(args) {
var config = getConfig(false); var config = getConfig(false);
if (config == null) { process.exit(); } if (config == null) { process.exit(); }
// Check is Windows SSPI will be used // Check is Windows SSPI and YubiKey OTP will be used
var sspi = false; var sspi = false;
var allsspi = true; var allsspi = true;
if (require('os').platform() == 'win32') { for (var i in config.domains) { if (config.domains[i].auth == 'sspi') { sspi = true; } else { allsspi = false; } } } var yubikey = false;
if (require('os').platform() == 'win32') { for (var i in config.domains) { if (config.domains[i].auth == 'sspi') { sspi = true; } else { allsspi = false; } } } else { allsspi = false; }
for (var i in config.domains) { if (config.domains[i].yubikey != null) { yubikey = true; } }
// Build the list of required modules // Build the list of required modules
var modules = ['ws', 'nedb', 'https', 'yauzl', 'xmldom', 'express', 'archiver', 'multiparty', 'node-forge', 'express-ws', 'compression', 'body-parser', 'connect-redis', 'express-handlebars']; var modules = ['ws', 'nedb', 'https', 'yauzl', 'xmldom', 'express', 'archiver', 'multiparty', 'node-forge', 'express-ws', 'compression', 'body-parser', 'connect-redis', 'express-handlebars'];
@ -1651,6 +1646,7 @@ function mainStart(args) {
if (config.letsencrypt != null) { modules.push('greenlock'); modules.push('le-store-certbot'); modules.push('le-challenge-fs'); modules.push('le-acme-core'); } // Add Greenlock Modules if (config.letsencrypt != null) { modules.push('greenlock'); modules.push('le-store-certbot'); modules.push('le-challenge-fs'); modules.push('le-acme-core'); } // Add Greenlock Modules
if (config.settings.mongodb != null) { modules.push('mongojs'); } // Add MongoDB if (config.settings.mongodb != null) { modules.push('mongojs'); } // Add MongoDB
if (config.smtp != null) { modules.push('nodemailer'); } // Add SMTP support if (config.smtp != null) { modules.push('nodemailer'); } // Add SMTP support
if (yubikey == true) { modules.push('yubikeyotp'); } // Add YubiKey OTP support
// Get the current node version // Get the current node version
var nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]); var nodeVersion = Number(process.version.match(/^v(\d+\.\d+)/)[1]);
@ -1658,9 +1654,9 @@ function mainStart(args) {
// If running NodeJS < 8, install "util.promisify" // If running NodeJS < 8, install "util.promisify"
if (nodeVersion < 8) { modules.push('util.promisify'); } if (nodeVersion < 8) { modules.push('util.promisify'); }
// if running NodeJS 8 or higher, we can install WebAuthn/FIDO2 support // if not all SSPI, WebAuthn/FIDO2 or U2F support depending on the NodeJS version. FIDO2 does not work below NodeJS 8.x
if ((nodeVersion >= 8) && (allsspi == false)) { modules.push('@davedoesdev/fido2-lib'); } if (allsspi == false) { modules.push('otplib'); if (nodeVersion >= 8) { modules.push('@davedoesdev/fido2-lib'); } else { modules.push('authdog'); } }
// Install any missing modules and launch the server // Install any missing modules and launch the server
InstallModules(modules, function () { meshserver = CreateMeshCentralServer(config, args); meshserver.Start(); }); InstallModules(modules, function () { meshserver = CreateMeshCentralServer(config, args); meshserver.Start(); });
}); });
@ -1670,4 +1666,4 @@ if (require.main === module) {
mainStart(require('minimist')(process.argv.slice(2))); // Called directly, launch normally. mainStart(require('minimist')(process.argv.slice(2))); // Called directly, launch normally.
} else { } else {
module.exports.mainStart = mainStart; // Required as a module, useful for winservice.js module.exports.mainStart = mainStart; // Required as a module, useful for winservice.js
} }

View File

@ -1773,7 +1773,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
const twoStepLoginSupported = ((domain.auth != 'sspi') && (parent.parent.certificates.CommonName.indexOf('.') != -1) && (args.lanonly !== true) && (args.nousers !== true)); const twoStepLoginSupported = ((domain.auth != 'sspi') && (parent.parent.certificates.CommonName.indexOf('.') != -1) && (args.lanonly !== true) && (args.nousers !== true));
if (twoStepLoginSupported) { if (twoStepLoginSupported) {
// Request a one time password to be setup // Request a one time password to be setup
const otplib = require('otplib'); var otplib = null;
try { otplib = require('otplib'); } catch (ex) { }
if (otplib == null) { break; }
const secret = otplib.authenticator.generateSecret(); // TODO: Check the random source of this value. const secret = otplib.authenticator.generateSecret(); // TODO: Check the random source of this value.
ws.send(JSON.stringify({ action: 'otpauth-request', secret: secret, url: otplib.authenticator.keyuri(user.name, parent.certificates.CommonName, secret) })); ws.send(JSON.stringify({ action: 'otpauth-request', secret: secret, url: otplib.authenticator.keyuri(user.name, parent.certificates.CommonName, secret) }));
} }
@ -1785,7 +1787,9 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
const twoStepLoginSupported = ((domain.auth != 'sspi') && (parent.parent.certificates.CommonName.indexOf('.') != -1) && (args.lanonly !== true) && (args.nousers !== true)); const twoStepLoginSupported = ((domain.auth != 'sspi') && (parent.parent.certificates.CommonName.indexOf('.') != -1) && (args.lanonly !== true) && (args.nousers !== true));
if (twoStepLoginSupported) { if (twoStepLoginSupported) {
// Perform the one time password setup // Perform the one time password setup
const otplib = require('otplib'); var otplib = null;
try { otplib = require('otplib'); } catch (ex) { }
if (otplib == null) { break; }
otplib.authenticator.options = { window: 2 }; // Set +/- 1 minute window otplib.authenticator.options = { window: 2 }; // Set +/- 1 minute window
if (otplib.authenticator.check(command.token, command.secret) === true) { if (otplib.authenticator.check(command.token, command.secret) === true) {
// Token is valid, activate 2-step login on this account. // Token is valid, activate 2-step login on this account.
@ -1853,8 +1857,6 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
} }
case 'otp-hkey-get': case 'otp-hkey-get':
{ {
// Check is 2-step login is supported // Check is 2-step login is supported
const twoStepLoginSupported = ((domain.auth != 'sspi') && (parent.parent.certificates.CommonName.indexOf('.') != -1) && (args.lanonly !== true) && (args.nousers !== true)); const twoStepLoginSupported = ((domain.auth != 'sspi') && (parent.parent.certificates.CommonName.indexOf('.') != -1) && (args.lanonly !== true) && (args.nousers !== true));
if (twoStepLoginSupported == false) break; if (twoStepLoginSupported == false) break;
@ -1887,10 +1889,12 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
case 'otp-hkey-yubikey-add': case 'otp-hkey-yubikey-add':
{ {
// Yubico API id and signature key can be requested from https://upgrade.yubico.com/getapikey/ // Yubico API id and signature key can be requested from https://upgrade.yubico.com/getapikey/
var yubikeyotp = null;
try { yubikeyotp = require('yubikeyotp'); } catch (ex) { }
// Check is 2-step login is supported // Check is 2-step login is supported
const twoStepLoginSupported = ((domain.auth != 'sspi') && (parent.parent.certificates.CommonName.indexOf('.') != -1) && (args.lanonly !== true) && (args.nousers !== true)); const twoStepLoginSupported = ((domain.auth != 'sspi') && (parent.parent.certificates.CommonName.indexOf('.') != -1) && (args.lanonly !== true) && (args.nousers !== true));
if ((twoStepLoginSupported == false) || (typeof command.otp != 'string')) { if ((yubikeyotp == null) || (twoStepLoginSupported == false) || (typeof command.otp != 'string')) {
ws.send(JSON.stringify({ action: 'otp-hkey-yubikey-add', result: false, name: command.name })); ws.send(JSON.stringify({ action: 'otp-hkey-yubikey-add', result: false, name: command.name }));
break; break;
} }
@ -1904,7 +1908,6 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
// TODO: Check if command.otp is modhex encoded, reject if not. // TODO: Check if command.otp is modhex encoded, reject if not.
// Query the YubiKey server to validate the OTP // Query the YubiKey server to validate the OTP
var yubikeyotp = require('yubikeyotp');
var request = { otp: command.otp, id: domain.yubikey.id, key: domain.yubikey.secret, timestamp: true } var request = { otp: command.otp, id: domain.yubikey.id, key: domain.yubikey.secret, timestamp: true }
if (domain.yubikey.proxy) { request.requestParams = { proxy: domain.yubikey.proxy }; } if (domain.yubikey.proxy) { request.requestParams = { proxy: domain.yubikey.proxy }; }
yubikeyotp.verifyOTP(request, function (err, results) { yubikeyotp.verifyOTP(request, function (err, results) {
@ -1934,16 +1937,19 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
} }
case 'otp-hkey-setup-request': case 'otp-hkey-setup-request':
{ {
var authdoglib = null;
try { authdoglib = require('authdog'); } catch (ex) { }
// Check is 2-step login is supported // Check is 2-step login is supported
const twoStepLoginSupported = ((domain.auth != 'sspi') && (parent.parent.certificates.CommonName.indexOf('.') != -1) && (args.lanonly !== true) && (args.nousers !== true)); const twoStepLoginSupported = ((domain.auth != 'sspi') && (parent.parent.certificates.CommonName.indexOf('.') != -1) && (args.lanonly !== true) && (args.nousers !== true));
if (twoStepLoginSupported == false) break; if ((authdoglib == null) || (twoStepLoginSupported == false)) break;
// Build list of known keys // Build list of known keys
var knownKeys = []; var knownKeys = [];
if (user.otphkeys != null) { for (var i = 0; i < user.otphkeys.length; i++) { if (user.otphkeys[i].type == 1) { knownKeys.push(user.otphkeys[i]); } } } if (user.otphkeys != null) { for (var i = 0; i < user.otphkeys.length; i++) { if (user.otphkeys[i].type == 1) { knownKeys.push(user.otphkeys[i]); } } }
// Build a key registration request and send it over // Build a key registration request and send it over
require('authdog').startRegistration('https://' + parent.parent.certificates.CommonName, knownKeys, { requestId: 556, timeoutSeconds: 100 }).then(function (registrationRequest) { authdoglib.startRegistration('https://' + parent.parent.certificates.CommonName, knownKeys, { requestId: 556, timeoutSeconds: 100 }).then(function (registrationRequest) {
// Save registration request to session for later use // Save registration request to session for later use
obj.hardwareKeyRegistrationRequest = registrationRequest; obj.hardwareKeyRegistrationRequest = registrationRequest;
@ -1957,12 +1963,15 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
} }
case 'otp-hkey-setup-response': case 'otp-hkey-setup-response':
{ {
var authdoglib = null;
try { authdoglib = require('authdog'); } catch (ex) { }
// Check is 2-step login is supported // Check is 2-step login is supported
const twoStepLoginSupported = ((domain.auth != 'sspi') && (parent.parent.certificates.CommonName.indexOf('.') != -1) && (args.lanonly !== true) && (args.nousers !== true)); const twoStepLoginSupported = ((domain.auth != 'sspi') && (parent.parent.certificates.CommonName.indexOf('.') != -1) && (args.lanonly !== true) && (args.nousers !== true));
if ((twoStepLoginSupported == false) || (command.response == null) || (command.name == null) || (obj.hardwareKeyRegistrationRequest == null)) break; if ((authdoglib == null) || (twoStepLoginSupported == false) || (command.response == null) || (command.name == null) || (obj.hardwareKeyRegistrationRequest == null)) break;
// Check the key registration request // Check the key registration request
require('authdog').finishRegistration(obj.hardwareKeyRegistrationRequest, command.response).then(function (registrationStatus) { authdoglib.finishRegistration(obj.hardwareKeyRegistrationRequest, command.response).then(function (registrationStatus) {
var keyIndex = parent.crypto.randomBytes(4).readUInt32BE(0); var keyIndex = parent.crypto.randomBytes(4).readUInt32BE(0);
ws.send(JSON.stringify({ action: 'otp-hkey-setup-response', result: true, name: command.name, index: keyIndex })); ws.send(JSON.stringify({ action: 'otp-hkey-setup-response', result: true, name: command.name, index: keyIndex }));
if (user.otphkeys == null) { user.otphkeys = []; } if (user.otphkeys == null) { user.otphkeys = []; }

57
package - Copy.json Normal file
View File

@ -0,0 +1,57 @@
{
"name": "meshcentral",
"version": "0.3.0-x",
"keywords": [
"Remote Management",
"Intel AMT",
"Active Management",
"Remote Desktop"
],
"homepage": "http://meshcommander.com",
"description": "Web based remote computer management and file server",
"author": "Ylian Saint-Hilaire <ysainthilaire@hotmail.com>",
"main": "meshcentral.js",
"bin": {
"meshcentral": "./bin/meshcentral"
},
"license": "Apache-2.0",
"files": [
"*.js",
"sample-config.json",
"license.txt",
"readme.txt",
"agents",
"public",
"views",
"bin"
],
"dependencies": {
"archiver": "^3.0.0",
"authdog": "^0.1.1",
"body-parser": "^1.18.2",
"compression": "^1.7.3",
"connect-redis": "^3.4.0",
"cookie-session": "^2.0.0-beta.3",
"express": "^4.16.4",
"express-handlebars": "^3.0.0",
"express-ws": "^4.0.0",
"ipcheck": "^0.1.0",
"meshcentral": "*",
"minimist": "^1.2.0",
"mongojs": "^2.6.0",
"multiparty": "^4.2.1",
"nedb": "^1.8.0",
"node-forge": "^0.7.6",
"otplib": "^10.0.1",
"ws": "^6.1.2",
"xmldom": "^0.1.27",
"yauzl": "^2.10.0",
"yubikeyotp": "^0.2.0"
},
"devDependencies": {},
"repository": {
"type": "git",
"url": "https://github.com/Ylianst/MeshCentral.git"
},
"readme": "readme.txt"
}

View File

@ -1,6 +1,6 @@
{ {
"name": "meshcentral", "name": "meshcentral",
"version": "0.3.0-u", "version": "0.3.0-y",
"keywords": [ "keywords": [
"Remote Management", "Remote Management",
"Intel AMT", "Intel AMT",
@ -27,7 +27,6 @@
], ],
"dependencies": { "dependencies": {
"archiver": "^3.0.0", "archiver": "^3.0.0",
"authdog": "^0.1.1",
"body-parser": "^1.18.2", "body-parser": "^1.18.2",
"compression": "^1.7.3", "compression": "^1.7.3",
"connect-redis": "^3.4.0", "connect-redis": "^3.4.0",
@ -41,11 +40,9 @@
"multiparty": "^4.2.1", "multiparty": "^4.2.1",
"nedb": "^1.8.0", "nedb": "^1.8.0",
"node-forge": "^0.7.6", "node-forge": "^0.7.6",
"otplib": "^10.0.1",
"ws": "^6.1.2", "ws": "^6.1.2",
"xmldom": "^0.1.27", "xmldom": "^0.1.27",
"yauzl": "^2.10.0", "yauzl": "^2.10.0"
"yubikeyotp": "^0.2.0"
}, },
"devDependencies": {}, "devDependencies": {},
"repository": { "repository": {

1
reinstall-modules.bat Normal file
View File

@ -0,0 +1 @@
npm install archiver authdog body-parser compression connect-redis cookie-session express express-handlebars express-ws ipcheck minimist mongojs multiparty nedb node-forge otplib ws xmldom yauzl yubikeyotp

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -287,7 +287,34 @@
if ('{{loginmode}}' == '4') { if ('{{loginmode}}' == '4') {
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null } try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
if ((hardwareKeyChallenge != null) && u2fSupported()) { if ((hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn')) {
hardwareKeyChallenge.challenge = Uint8Array.from(atob(hardwareKeyChallenge.challenge), c => c.charCodeAt(0)).buffer;
const publicKeyCredentialRequestOptions = { challenge: hardwareKeyChallenge.challenge, allowCredentials: [], timeout: hardwareKeyChallenge.timeout }
for (var i = 0; i < hardwareKeyChallenge.keyIds.length; i++) {
publicKeyCredentialRequestOptions.allowCredentials.push(
{ id: Uint8Array.from(atob(hardwareKeyChallenge.keyIds[i]), c => c.charCodeAt(0)), type: 'public-key', transports: ['usb', 'ble', 'nfc'], }
);
}
// New WebAuthn hardware keys
navigator.credentials.get({ publicKey: publicKeyCredentialRequestOptions }).then(
function (rawAssertion) {
var assertion = {
id: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.rawId))),
clientDataJSON: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.clientDataJSON))),
userHandle: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.userHandle))),
signature: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.signature))),
authenticatorData: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.authenticatorData))),
};
Q('hwtokenInput').value = JSON.stringify(assertion);
QE('tokenOkButton', true);
Q('tokenOkButton').click();
},
function (error) { console.log('credentials-get error', error); }
);
} else if ((hardwareKeyChallenge != null) && u2fSupported()) {
// Old U2F hardware keys
window.u2f.sign(hardwareKeyChallenge.appId, hardwareKeyChallenge.challenge, hardwareKeyChallenge.registeredKeys, function (authResponse) { window.u2f.sign(hardwareKeyChallenge.appId, hardwareKeyChallenge.challenge, hardwareKeyChallenge.registeredKeys, function (authResponse) {
if ((currentpanel == 4) && authResponse.signatureData) { if ((currentpanel == 4) && authResponse.signatureData) {
Q('hwtokenInput').value = JSON.stringify(authResponse); Q('hwtokenInput').value = JSON.stringify(authResponse);
@ -300,7 +327,34 @@
if ('{{loginmode}}' == '5') { if ('{{loginmode}}' == '5') {
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null } try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
if ((hardwareKeyChallenge != null) && u2fSupported()) { if ((hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn')) {
hardwareKeyChallenge.challenge = Uint8Array.from(atob(hardwareKeyChallenge.challenge), c => c.charCodeAt(0)).buffer;
const publicKeyCredentialRequestOptions = { challenge: hardwareKeyChallenge.challenge, allowCredentials: [], timeout: hardwareKeyChallenge.timeout }
for (var i = 0; i < hardwareKeyChallenge.keyIds.length; i++) {
publicKeyCredentialRequestOptions.allowCredentials.push(
{ id: Uint8Array.from(atob(hardwareKeyChallenge.keyIds[i]), c => c.charCodeAt(0)), type: 'public-key', transports: ['usb', 'ble', 'nfc'], }
);
}
// New WebAuthn hardware keys
navigator.credentials.get({ publicKey: publicKeyCredentialRequestOptions }).then(
function (rawAssertion) {
var assertion = {
id: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.rawId))),
clientDataJSON: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.clientDataJSON))),
userHandle: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.userHandle))),
signature: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.signature))),
authenticatorData: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.authenticatorData))),
};
Q('resetHwtokenInput').value = JSON.stringify(assertion);
QE('resetTokenOkButton', true);
Q('resetTokenOkButton').click();
},
function (error) { console.log('credentials-get error', error); }
);
} else if ((hardwareKeyChallenge != null) && u2fSupported()) {
// Old U2F hardware keys
window.u2f.sign(hardwareKeyChallenge.appId, hardwareKeyChallenge.challenge, hardwareKeyChallenge.registeredKeys, function (authResponse) { window.u2f.sign(hardwareKeyChallenge.appId, hardwareKeyChallenge.challenge, hardwareKeyChallenge.registeredKeys, function (authResponse) {
if ((currentpanel == 5) && authResponse.signatureData) { if ((currentpanel == 5) && authResponse.signatureData) {
Q('resetHwtokenInput').value = JSON.stringify(authResponse); Q('resetHwtokenInput').value = JSON.stringify(authResponse);

View File

@ -386,11 +386,11 @@
navigator.credentials.get({ publicKey: publicKeyCredentialRequestOptions }).then( navigator.credentials.get({ publicKey: publicKeyCredentialRequestOptions }).then(
function (rawAssertion) { function (rawAssertion) {
var assertion = { var assertion = {
id: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.rawId))), //base64encode(rawAssertion.rawId), id: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.rawId))),
clientDataJSON: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.clientDataJSON))), //arrayBufferToString(rawAssertion.response.clientDataJSON), clientDataJSON: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.clientDataJSON))),
userHandle: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.userHandle))), //base64encode(rawAssertion.response.userHandle), userHandle: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.userHandle))),
signature: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.signature))), //base64encode(rawAssertion.response.signature), signature: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.signature))),
authenticatorData: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.authenticatorData))), //base64encode(rawAssertion.response.authenticatorData) authenticatorData: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.authenticatorData))),
}; };
Q('hwtokenInput').value = JSON.stringify(assertion); Q('hwtokenInput').value = JSON.stringify(assertion);
QE('tokenOkButton', true); QE('tokenOkButton', true);
@ -412,7 +412,34 @@
if ('{{loginmode}}' == '5') { if ('{{loginmode}}' == '5') {
try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null } try { if (hardwareKeyChallenge.length > 0) { hardwareKeyChallenge = JSON.parse(hardwareKeyChallenge); } else { hardwareKeyChallenge = null; } } catch (ex) { hardwareKeyChallenge = null }
if ((hardwareKeyChallenge != null) && u2fSupported()) { if ((hardwareKeyChallenge != null) && (hardwareKeyChallenge.type == 'webAuthn')) {
hardwareKeyChallenge.challenge = Uint8Array.from(atob(hardwareKeyChallenge.challenge), c => c.charCodeAt(0)).buffer;
const publicKeyCredentialRequestOptions = { challenge: hardwareKeyChallenge.challenge, allowCredentials: [], timeout: hardwareKeyChallenge.timeout }
for (var i = 0; i < hardwareKeyChallenge.keyIds.length; i++) {
publicKeyCredentialRequestOptions.allowCredentials.push(
{ id: Uint8Array.from(atob(hardwareKeyChallenge.keyIds[i]), c => c.charCodeAt(0)), type: 'public-key', transports: ['usb', 'ble', 'nfc'], }
);
}
// New WebAuthn hardware keys
navigator.credentials.get({ publicKey: publicKeyCredentialRequestOptions }).then(
function (rawAssertion) {
var assertion = {
id: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.rawId))),
clientDataJSON: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.clientDataJSON))),
userHandle: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.userHandle))),
signature: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.signature))),
authenticatorData: btoa(String.fromCharCode.apply(null, new Uint8Array(rawAssertion.response.authenticatorData))),
};
Q('resetHwtokenInput').value = JSON.stringify(assertion);
QE('resetTokenOkButton', true);
Q('resetTokenOkButton').click();
},
function (error) { console.log('credentials-get error', error); }
);
} else if ((hardwareKeyChallenge != null) && u2fSupported()) {
// Old U2F hardware keys
window.u2f.sign(hardwareKeyChallenge.appId, hardwareKeyChallenge.challenge, hardwareKeyChallenge.registeredKeys, function (authResponse) { window.u2f.sign(hardwareKeyChallenge.appId, hardwareKeyChallenge.challenge, hardwareKeyChallenge.registeredKeys, function (authResponse) {
if ((currentpanel == 5) && authResponse.signatureData) { if ((currentpanel == 5) && authResponse.signatureData) {
Q('resetHwtokenInput').value = JSON.stringify(authResponse); Q('resetHwtokenInput').value = JSON.stringify(authResponse);

View File

@ -62,7 +62,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates) {
const constants = (obj.crypto.constants ? obj.crypto.constants : require('constants')); // require('constants') is deprecated in Node 11.10, use require('crypto').constants instead. const constants = (obj.crypto.constants ? obj.crypto.constants : require('constants')); // require('constants') is deprecated in Node 11.10, use require('crypto').constants instead.
// Setup WebAuthn / FIDO2 // Setup WebAuthn / FIDO2
try { const { Fido2Lib } = require("@davedoesdev/fido2-lib"); obj.f2l = new Fido2Lib({ attestation: "none" }); } catch (ex) { console.log(ex); } try { const { Fido2Lib } = require("@davedoesdev/fido2-lib"); obj.f2l = new Fido2Lib({ attestation: "none" }); } catch (ex) { }
// Variables // Variables
obj.parent = parent; obj.parent = parent;