I think this topic might be the right choice. Does someone know how to handle async code here?
/* globals module */
/**
/* globals module */
/**
* Copyright (c) 2020-2021 Julian Knight (Totally Information)
* https://it.knightnet.org.uk
*
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
/**
* Template security functions for uibuilder.
* Only used if the node.useSecurity flag is set.
* Please replace with your own code.
*
* You MUST export the following functions:
* - userValidate - based on an id, lookup the user data to see if the user is valid.
* MUST return a boolean or object of type userValidation.
* Called from the server's logon process. (uiblib.js::logon)
*
*
* Each function MUST at least return true/false. See each function for more details.
*
* NOTES & WARNINGS:
* 1) IF there is an error in this JavaScript, it is very likely that Node-RED will terminate.
* 2) You can use different security.js files for different instances of uibuilder.
* Simply, place a securiy.js file in the instances root folder (e.g ~/.node-red/uibuilder/<url>/security.js)
* Note, however, that this means that the security.js file can be edited using the admin Editor.
* You have to restart Node-RED to pick up the new file.
*/
'use strict'
/** Define the _auth object
* @typedef {Object} _auth The standard auth object used by uibuilder security. See docs for details.
* Note that any other data may be passed from your front-end code in the uibAuth object.
* @property {String} id Required. A unique user identifier.
* @property {String} [password] Required for input to login only.
* @property {String} [jwt] Required if logged in. Needed for ongoing session validation and management.
* @property {String} [sessionExpiry] Required if logged in. ISO8601 formatted date/time string. Needed for ongoing session validation and management.
* @property {boolean} [userValidated] Required after user validation. Whether the input ID (and optional additional data from the _auth object) validated correctly or not.
* @property {Object=} [info] Optional metadata about the user.
*/
const sql = require('mssql')
const bcrypt = require('bcrypt')
var queryResult = async id => {
var result
try {
var config = {
...
}
// make sure that any items are correctly URL encoded in the connection string
await sql.connect(config)
//TODO: Sanitizing ID
result = await sql.query`select * from dbo.users where UserName = ${id}`
} catch (err) {
}
return result
}
module.exports = {
/** Validate user against your own user data.
* The minimum input data is _auth.id which must represent a unique ID.
* Called from the logon function (uiblib.js::logon) which is triggered by a uibuilder control msg from the client of type 'logon'.
* May also be called to revalidate users at any time.
* @param {_auth} _auth Required.
* @return {_auth} Object of type _auth
*/
userValidate: function(_auth) {
//console.log(`[uibuilder:.common/security.js] userValidate Security from '${__filename}' used. Replace this template with your own code. _auth:`, _auth
var password = _auth.password
var id = _auth.id
_auth.userValidated = false
var result
queryResult(id).then(result => {
if(result.recordset.length > 0){
bcrypt.compare(password, result.recordset[0].Hash,(err, response)=> { //function(err,result){
if(response){
_auth.userValidated = true
_auth.info = {"UserName": result.recordset[0].UserName, "FirstName": result.recordset[0].FirstName, "LastName": result.recordset[0].LastName, "Scope": result.recordset[0].Scope}
resolve(true)
}
else {
_auth.userValidated = false
resolve(true)
}
})
}
})
return _auth
} // ---- End of userValidate ---- //
}
I'm kind of working on authenticating with mssql, but have some problems validating the user. QueryResult is async, so I'm chaining promises. How can I wait for my async code to finish? Making the userValidate async and wraping everything in a promise and awaiting it, does not do the trick, since userValidate is called synchrounous throughout the uibuilder auth system. So how do I wait for _auth to be set? Any Ideas? A quickfix might be a loop checking some variable to be set repeatedly, but that is some nasty bad code to me.