/**
* @module account-model
*/
const utils = require( '../lib/utils' );
const config = require( './config-model' ).server;
const customGetAccount = config[ 'account lib' ] ? require( config[ 'account lib' ] ).getAccount : undefined;
// var debug = require( 'debug' )( 'account-model' );
/**
* @typedef AccountObj
* @property { string } linkedServer
* @property { string } [openRosaServer]
* @property { string } key
* @property {number} quota
*/
/**
* Obtains account.
*
* @static
* @param {module:survey-model~SurveyObject} survey - survey object
* @return {Promise<Error|AccountObj>} promise that resolves in {@link module:account-model~AccountObj|Account object}
*/
function get( survey ) {
let error;
const server = _getServer( survey );
if ( !server ) {
error = new Error( 'Bad Request. Server URL missing.' );
error.status = 400;
return Promise.reject( error );
} else if ( !utils.isValidUrl( server ) ) {
error = new Error( 'Bad Request. Server URL is not a valid URL.' );
error.status = 400;
return Promise.reject( error );
} else if ( /https?:\/\/testserver.com\/bob/.test( server ) ) {
return Promise.resolve( {
linkedServer: server,
key: 'abc',
quota: 100
} );
} else if ( /https?:\/\/testserver.com\/noquota/.test( server ) ) {
error = new Error( 'Forbidden. No quota left.' );
error.status = 403;
return Promise.reject( error );
} else if ( /https?:\/\/testserver.com\/noapi/.test( server ) ) {
error = new Error( 'Forbidden. No API access granted.' );
error.status = 405;
return Promise.reject( error );
} else if ( /https?:\/\/testserver.com\/noquotanoapi/.test( server ) ) {
error = new Error( 'Forbidden. No API access granted.' );
error.status = 405;
return Promise.reject( error );
} else if ( /https?:\/\/testserver.com\/notpaid/.test( server ) ) {
error = new Error( 'Forbidden. The account is not active.' );
error.status = 403;
return Promise.reject( error );
}
return _getAccount( server );
}
/**
* Check if account for passed survey is active, and not exceeding quota.
* This passes back the original survey object and therefore differs from the get function!
*
* @static
* @param {module:survey-model~SurveyObject} survey - survey object
* @return {Promise<module:survey-model~SurveyObject>} updated SurveyObject
*/
function check( survey ) {
return get( survey )
.then( account => {
survey.account = account;
return survey;
} );
}
/**
* Checks if the provided serverUrl is part of the allowed 'linked' OpenRosa Server.
*
* @param { AccountObj } account - an account object
* @param { string } serverUrl - server URL
* @return { boolean } Whether server URL is allowed
*/
function _isAllowed( account, serverUrl ) {
return account.linkedServer === '' || new RegExp( `https?://${_stripProtocol( account.linkedServer )}` ).test( serverUrl );
}
/**
* Strips http(s):// from the provided url
*
* @param { string } url - URL
* @return {string|null} stripped url
*/
function _stripProtocol( url ) {
if ( !url ) {
return null;
}
// strip http(s)://
if ( /https?:\/\//.test( url ) ) {
url = url.substring( url.indexOf( '://' ) + 3 );
}
return url;
}
/**
* Obtains account from either configuration (hardcoded) or via custom function
*
* @param { string } serverUrl - The serverUrl to be used to look up the account.
* @return { AccountObj } {@link module:account-model~AccountObj|Account object}
*/
function _getAccount( serverUrl ) {
const hardcodedAccount = _getHardcodedAccount();
if ( _isAllowed( hardcodedAccount, serverUrl ) ) {
return Promise.resolve( hardcodedAccount );
}
if ( customGetAccount ) {
return customGetAccount( serverUrl, config[ 'account api url' ] );
}
const error = new Error( 'Forbidden. This server is not linked with Enketo.' );
error.status = 403;
return Promise.reject( error );
}
/**
* Obtains the hardcoded account from the config
*
* @return { null|AccountObj } `null` or {@link module:account-model~AccountObj|Account object}
*/
function _getHardcodedAccount() {
const app = require( '../../config/express' );
const linkedServer = app.get( 'linked form and data server' );
// check if configuration is acceptable
if ( !linkedServer || typeof linkedServer[ 'server url' ] === 'undefined' || typeof linkedServer[ 'api key' ] === 'undefined' ) {
return null;
}
// do not add default branding
return {
linkedServer: linkedServer[ 'server url' ],
key: linkedServer[ 'api key' ],
quota: linkedServer[ 'quota' ] || Infinity
};
}
/**
* Extracts the server from a survey object or server string.
*
* @param { string|module:survey-model~SurveyObject } survey - Server string or survey object.
* @return { string|null } server
*/
function _getServer( survey ) {
if ( !survey || ( typeof survey === 'object' && !survey.openRosaServer ) ) {
return null;
}
return ( typeof survey === 'string' ) ? survey : survey.openRosaServer;
}
module.exports = {
get,
check
};