1
0
Fork 0

Resolve server-side validation internal flag race condition

master
Mike Gerwitz 2018-05-02 14:01:54 -04:00
commit 7a1af0253a
2 changed files with 44 additions and 15 deletions

View File

@ -1,7 +1,7 @@
/* /*
* Contains program Server class * Contains program Server class
* *
* Copyright (C) 2017 R-T Specialty, LLC. * Copyright (C) 2017, 2018 R-T Specialty, LLC.
* *
* This file is part of the Liza Data Collection Framework. * This file is part of the Liza Data Collection Framework.
* *
@ -815,7 +815,11 @@ module.exports = Class( 'Server' )
// permitted), thereby evading client-side forward-validations // permitted), thereby evading client-side forward-validations
if ( step_id > cur_id ) if ( step_id > cur_id )
{ {
if ( this._forwardValidate( quote, program, cur_id ) === false ) const validated = this._forwardValidate(
quote, program, cur_id, session
);
if ( !validated )
{ {
this.sendError( request, this.sendError( request,
"The previous step contains errors; please correct them " + "The previous step contains errors; please correct them " +
@ -903,13 +907,14 @@ module.exports = Class( 'Server' )
* otherwise permitted), preventing the `forward' event from triggering on * otherwise permitted), preventing the `forward' event from triggering on
* the client (as it is a relative event). * the client (as it is a relative event).
* *
* @param {Quote} quote quote to forward-validate * @param {Quote} quote quote to forward-validate
* @param {Program} program program to validate against * @param {Program} program program to validate against
* @param {number} step_id id of current step (before navigation) * @param {number} step_id id of current step (before navigation)
* @param {UserSession} session user session
* *
* @return {boolean} validation success/failure * @return {boolean} validation success/failure
*/ */
'private _forwardValidate': function( quote, program, step_id ) 'private _forwardValidate': function( quote, program, step_id, session )
{ {
var success = false, var success = false,
_self = this; _self = this;
@ -921,6 +926,10 @@ module.exports = Class( 'Server' )
{ {
try try
{ {
// WARNING: must set immediately before running assertions,
// ensuring that stack doesn't clear
program.isInternal = session.isInternal();
// forward event returns an object containing failures // forward event returns an object containing failures
success = ( program.forward( step_id, bucket, {} ) === null ); success = ( program.forward( step_id, bucket, {} ) === null );
} }
@ -1182,7 +1191,7 @@ module.exports = Class( 'Server' )
quote.setLastPremiumDate( 0 ); quote.setLastPremiumDate( 0 );
} }
server.quoteFill( quote, step_id, server.quoteFill( quote, step_id, request.getSession(),
// success // success
function() function()
{ {
@ -1238,7 +1247,7 @@ module.exports = Class( 'Server' )
quote.getId(), quote.getId(),
program.id, program.id,
step_id, step_id,
util.inspect( failures ) util.inspect( server._formatValidationFailures( failures ) )
); );
server.sendError( request, server.sendError( request,
@ -1258,6 +1267,25 @@ module.exports = Class( 'Server' )
}, },
/**
* Format validation failures for encoded display
*
* That is, output data in a format that is useful for JSON-encoded display.
*
* @param {Object} failures failure array per key
*
* @return {Object} formatted object
*/
'private _formatValidationFailures'( failures )
{
return Object.keys( failures ).reduce( ( results, id ) =>
{
results[ id ] = failures[ id ].map( failure => failure.toString() );
return results;
}, {} );
},
'private _postSubmit': function( request, quote, step_id, program, internal ) 'private _postSubmit': function( request, quote, step_id, program, internal )
{ {
var server = this, var server = this,
@ -1376,7 +1404,7 @@ module.exports = Class( 'Server' )
}, },
quoteFill: function( data, step_id, success, failure ) quoteFill: function( data, step_id, session, success, failure )
{ {
if ( data instanceof Function ) if ( data instanceof Function )
{ {
@ -1398,7 +1426,7 @@ module.exports = Class( 'Server' )
var len = this.quoteFillHooks.length; var len = this.quoteFillHooks.length;
for ( var i = 0; i < len; i++ ) for ( var i = 0; i < len; i++ )
{ {
this.quoteFillHooks[i].call( event, data, step_id ); this.quoteFillHooks[i].call( event, data, step_id, session );
// if we aborted, there's no need to continue // if we aborted, there's no need to continue
if ( abort ) if ( abort )
@ -1480,7 +1508,7 @@ module.exports = Class( 'Server' )
const program = program_module(); const program = program_module();
// hook ourselves // hook ourselves
server.quoteFill( function( quote, step_id ) server.quoteFill( function( quote, step_id, session )
{ {
var _self = this; var _self = this;
@ -1533,6 +1561,10 @@ module.exports = Class( 'Server' )
FieldClassMatcher( program.whens ) FieldClassMatcher( program.whens )
.match( classdata, function( cmatch ) .match( classdata, function( cmatch )
{ {
// WARNING: must set immediately before running
// assertions, ensuring that stack doesn't clear
program.isInternal = session.isInternal();
var failures = program.submit( step_id, var failures = program.submit( step_id,
bucket_tmp, bucket_tmp,
cmatch cmatch

View File

@ -1,7 +1,7 @@
/** /**
* Route controller * Route controller
* *
* Copyright (C) 2017 R-T Specialty, LLC. * Copyright (C) 2017, 2018 R-T Specialty, LLC.
* *
* This file is part of the Liza Data Collection Framework. * This file is part of the Liza Data Collection Framework.
* *
@ -379,9 +379,6 @@ function doRoute( program, request, data, resolve, reject )
request.getSession().setAgentId( '900000' ); request.getSession().setAgentId( '900000' );
} }
// if we're internal, let the program know for the sake of assertions
program.isInternal = request.getSession().isInternal();
// we'll be serving all our responses as plain text // we'll be serving all our responses as plain text
request.setContentType( 'text/plain' ); request.setContentType( 'text/plain' );