diff --git a/core/acs.js b/core/acs.js index a86db329..1ae4fa93 100644 --- a/core/acs.js +++ b/core/acs.js @@ -10,15 +10,15 @@ const assert = require('assert'); const _ = require('lodash'); class ACS { - constructor(client) { - this.client = client; + constructor(subject) { + this.subject = subject; } check(acs, scope, defaultAcs) { acs = acs ? acs[scope] : defaultAcs; acs = acs || defaultAcs; try { - return checkAcs(acs, { client : this.client } ); + return checkAcs(acs, { subject : this.subject } ); } catch(e) { Log.warn( { exception : e, acs : acs }, 'Exception caught checking ACS'); return false; @@ -57,7 +57,7 @@ class ACS { return true; // no ACS check req. } try { - return checkAcs(acs, { client : this.client } ); + return checkAcs(acs, { subject : this.subject } ); } catch(e) { Log.warn( { exception : e, acs : acs }, 'Exception caught checking ACS'); return false; @@ -75,7 +75,7 @@ class ACS { const matchCond = condArray.find( cond => { if(_.has(cond, 'acs')) { try { - return checkAcs(cond.acs, { client : this.client } ); + return checkAcs(cond.acs, { subject : this.subject } ); } catch(e) { Log.warn( { exception : e, acs : cond }, 'Exception caught checking ACS'); return false; diff --git a/core/acs_parser.js b/core/acs_parser.js index 6e32cb06..d6983b17 100644 --- a/core/acs_parser.js +++ b/core/acs_parser.js @@ -844,32 +844,36 @@ function peg$parse(input, options) { } - const client = options.client; - const user = options.client.user; - const UserProps = require('./user_property.js'); + const Log = require('./logger.js').log; + const _ = require('lodash'); const moment = require('moment'); + const client = _.get(options, 'subject.client'); + const user = _.get(options, 'subject.user'); + function checkAccess(acsCode, value) { try { return { LC : function isLocalConnection() { - return client.isLocal(); + return client && client.isLocal(); }, AG : function ageGreaterOrEqualThan() { - return !isNaN(value) && user.getAge() >= value; + return !isNaN(value) && user && user.getAge() >= value; }, AS : function accountStatus() { + if(!user) { + return false; + } if(!Array.isArray(value)) { value = [ value ]; } - const userAccountStatus = user.getPropertyAsNumber(UserProps.AccountStatus); return value.map(n => parseInt(n, 10)).includes(userAccountStatus); }, EC : function isEncoding() { - const encoding = client.term.outputEncoding.toLowerCase(); + const encoding = _.get(client, 'term.outputEncoding', '').toLowerCase(); switch(value) { case 0 : return 'cp437' === encoding; case 1 : return 'utf-8' === encoding; @@ -877,27 +881,41 @@ function peg$parse(input, options) { } }, GM : function isOneOfGroups() { + if(!user) { + return false; + } if(!Array.isArray(value)) { return false; } - return value.some(groupName => user.isGroupMember(groupName)); }, NN : function isNode() { + if(!client) { + return false; + } if(!Array.isArray(value)) { value = [ value ]; } return value.map(n => parseInt(n, 10)).includes(client.node); }, NP : function numberOfPosts() { + if(!user) { + return false; + } const postCount = user.getPropertyAsNumber(UserProps.PostCount) || 0; return !isNaN(value) && postCount >= value; }, NC : function numberOfCalls() { + if(!user) { + return false; + } const loginCount = user.getPropertyAsNumber(UserProps.LoginCount); return !isNaN(value) && loginCount >= value; }, AA : function accountAge() { + if(!user) { + return false; + } const accountCreated = moment(user.getProperty(UserProps.AccountCreated)); const now = moment(); const daysOld = accountCreated.diff(moment(), 'days'); @@ -907,78 +925,98 @@ function peg$parse(input, options) { daysOld >= value; }, BU : function bytesUploaded() { + if(!user) { + return false; + } const bytesUp = user.getPropertyAsNumber(UserProps.FileUlTotalBytes) || 0; return !isNaN(value) && bytesUp >= value; }, UP : function uploads() { + if(!user) { + return false; + } const uls = user.getPropertyAsNumber(UserProps.FileUlTotalCount) || 0; return !isNaN(value) && uls >= value; }, BD : function bytesDownloaded() { + if(!user) { + return false; + } const bytesDown = user.getPropertyAsNumber(UserProps.FileDlTotalBytes) || 0; return !isNaN(value) && bytesDown >= value; }, DL : function downloads() { + if(!user) { + return false; + } const dls = user.getPropertyAsNumber(UserProps.FileDlTotalCount) || 0; return !isNaN(value) && dls >= value; }, NR : function uploadDownloadRatioGreaterThan() { + if(!user) { + return false; + } const ulCount = user.getPropertyAsNumber(UserProps.FileUlTotalCount) || 0; const dlCount = user.getPropertyAsNumber(UserProps.FileDlTotalCount) || 0; const ratio = ~~((ulCount / dlCount) * 100); return !isNaN(value) && ratio >= value; }, KR : function uploadDownloadByteRatioGreaterThan() { + if(!user) { + return false; + } const ulBytes = user.getPropertyAsNumber(UserProps.FileUlTotalBytes) || 0; const dlBytes = user.getPropertyAsNumber(UserProps.FileDlTotalBytes) || 0; const ratio = ~~((ulBytes / dlBytes) * 100); return !isNaN(value) && ratio >= value; }, - PC : function postCallRatio() { + PC : function postCallRatio() { + if(!user) { + return false; + } const postCount = user.getPropertyAsNumber(UserProps.PostCount) || 0; const loginCount = user.getPropertyAsNumber(UserProps.LoginCount) || 0; const ratio = ~~((postCount / loginCount) * 100); return !isNaN(value) && ratio >= value; }, SC : function isSecureConnection() { - return client.session.isSecure; + return _.get(client, 'session.isSecure', false); }, ML : function minutesLeft() { // :TODO: implement me! return false; }, TH : function termHeight() { - return !isNaN(value) && client.term.termHeight >= value; + return !isNaN(value) && _.get(client, 'term.termHeight', 0) >= value; }, TM : function isOneOfThemes() { if(!Array.isArray(value)) { return false; } - - return value.includes(client.currentTheme.name); + return value.includes(_.get(client, 'currentTheme.name')); }, TT : function isOneOfTermTypes() { if(!Array.isArray(value)) { return false; } - - return value.includes(client.term.termType); + return value.includes(_.get(client, 'term.termType')); }, TW : function termWidth() { - return !isNaN(value) && client.term.termWidth >= value; + return !isNaN(value) && _.get(client, 'term.termWidth', 0) >= value; }, ID : function isUserId(value) { + if(!user) { + return false; + } if(!Array.isArray(value)) { value = [ value ]; } - return value.map(n => parseInt(n, 10)).includes(user.userId); }, WD : function isOneOfDayOfWeek() { if(!Array.isArray(value)) { value = [ value ]; } - return value.map(n => parseInt(n, 10)).includes(new Date().getDay()); }, MM : function isMinutesPastMidnight() { @@ -989,7 +1027,9 @@ function peg$parse(input, options) { } }[acsCode](value); } catch (e) { - client.log.warn( { acsCode : acsCode, value : value }, 'Invalid ACS string!'); + const logger = _.get(client, 'log', Log); + logger.warn( { acsCode : acsCode, value : value }, 'Invalid ACS string!'); + return false; } } diff --git a/core/client.js b/core/client.js index 60a04af7..300285a3 100644 --- a/core/client.js +++ b/core/client.js @@ -85,7 +85,7 @@ function Client(/*input, output*/) { this.currentTheme = { info : { name : 'N/A', description : 'None' } }; this.lastKeyPressMs = Date.now(); this.menuStack = new MenuStack(this); - this.acs = new ACS(this); + this.acs = new ACS( { client : this, user : this.user } ); this.mciCache = {}; this.interruptQueue = new UserInterruptQueue(this); diff --git a/misc/acs_parser.pegjs b/misc/acs_parser.pegjs index ed6089ba..bd6a8d96 100644 --- a/misc/acs_parser.pegjs +++ b/misc/acs_parser.pegjs @@ -1,31 +1,35 @@ { - const client = options.client; - const user = options.client.user; - const UserProps = require('./user_property.js'); + const Log = require('./logger.js').log; + const _ = require('lodash'); const moment = require('moment'); + const client = _.get(options, 'subject.client'); + const user = _.get(options, 'subject.user'); + function checkAccess(acsCode, value) { try { return { LC : function isLocalConnection() { - return client.isLocal(); + return client && client.isLocal(); }, AG : function ageGreaterOrEqualThan() { - return !isNaN(value) && user.getAge() >= value; + return !isNaN(value) && user && user.getAge() >= value; }, AS : function accountStatus() { + if(!user) { + return false; + } if(!Array.isArray(value)) { value = [ value ]; } - const userAccountStatus = user.getPropertyAsNumber(UserProps.AccountStatus); return value.map(n => parseInt(n, 10)).includes(userAccountStatus); }, EC : function isEncoding() { - const encoding = client.term.outputEncoding.toLowerCase(); + const encoding = _.get(client, 'term.outputEncoding', '').toLowerCase(); switch(value) { case 0 : return 'cp437' === encoding; case 1 : return 'utf-8' === encoding; @@ -33,27 +37,41 @@ } }, GM : function isOneOfGroups() { + if(!user) { + return false; + } if(!Array.isArray(value)) { return false; } - return value.some(groupName => user.isGroupMember(groupName)); }, NN : function isNode() { + if(!client) { + return false; + } if(!Array.isArray(value)) { value = [ value ]; } return value.map(n => parseInt(n, 10)).includes(client.node); }, NP : function numberOfPosts() { + if(!user) { + return false; + } const postCount = user.getPropertyAsNumber(UserProps.PostCount) || 0; return !isNaN(value) && postCount >= value; }, NC : function numberOfCalls() { + if(!user) { + return false; + } const loginCount = user.getPropertyAsNumber(UserProps.LoginCount); return !isNaN(value) && loginCount >= value; }, AA : function accountAge() { + if(!user) { + return false; + } const accountCreated = moment(user.getProperty(UserProps.AccountCreated)); const now = moment(); const daysOld = accountCreated.diff(moment(), 'days'); @@ -63,78 +81,98 @@ daysOld >= value; }, BU : function bytesUploaded() { + if(!user) { + return false; + } const bytesUp = user.getPropertyAsNumber(UserProps.FileUlTotalBytes) || 0; return !isNaN(value) && bytesUp >= value; }, UP : function uploads() { + if(!user) { + return false; + } const uls = user.getPropertyAsNumber(UserProps.FileUlTotalCount) || 0; return !isNaN(value) && uls >= value; }, BD : function bytesDownloaded() { + if(!user) { + return false; + } const bytesDown = user.getPropertyAsNumber(UserProps.FileDlTotalBytes) || 0; return !isNaN(value) && bytesDown >= value; }, DL : function downloads() { + if(!user) { + return false; + } const dls = user.getPropertyAsNumber(UserProps.FileDlTotalCount) || 0; return !isNaN(value) && dls >= value; }, NR : function uploadDownloadRatioGreaterThan() { + if(!user) { + return false; + } const ulCount = user.getPropertyAsNumber(UserProps.FileUlTotalCount) || 0; const dlCount = user.getPropertyAsNumber(UserProps.FileDlTotalCount) || 0; const ratio = ~~((ulCount / dlCount) * 100); return !isNaN(value) && ratio >= value; }, KR : function uploadDownloadByteRatioGreaterThan() { + if(!user) { + return false; + } const ulBytes = user.getPropertyAsNumber(UserProps.FileUlTotalBytes) || 0; const dlBytes = user.getPropertyAsNumber(UserProps.FileDlTotalBytes) || 0; const ratio = ~~((ulBytes / dlBytes) * 100); return !isNaN(value) && ratio >= value; }, - PC : function postCallRatio() { + PC : function postCallRatio() { + if(!user) { + return false; + } const postCount = user.getPropertyAsNumber(UserProps.PostCount) || 0; const loginCount = user.getPropertyAsNumber(UserProps.LoginCount) || 0; const ratio = ~~((postCount / loginCount) * 100); return !isNaN(value) && ratio >= value; }, SC : function isSecureConnection() { - return client.session.isSecure; + return _.get(client, 'session.isSecure', false); }, ML : function minutesLeft() { // :TODO: implement me! return false; }, TH : function termHeight() { - return !isNaN(value) && client.term.termHeight >= value; + return !isNaN(value) && _.get(client, 'term.termHeight', 0) >= value; }, TM : function isOneOfThemes() { if(!Array.isArray(value)) { return false; } - - return value.includes(client.currentTheme.name); + return value.includes(_.get(client, 'currentTheme.name')); }, TT : function isOneOfTermTypes() { if(!Array.isArray(value)) { return false; } - - return value.includes(client.term.termType); + return value.includes(_.get(client, 'term.termType')); }, TW : function termWidth() { - return !isNaN(value) && client.term.termWidth >= value; + return !isNaN(value) && _.get(client, 'term.termWidth', 0) >= value; }, ID : function isUserId(value) { + if(!user) { + return false; + } if(!Array.isArray(value)) { value = [ value ]; } - return value.map(n => parseInt(n, 10)).includes(user.userId); }, WD : function isOneOfDayOfWeek() { if(!Array.isArray(value)) { value = [ value ]; } - return value.map(n => parseInt(n, 10)).includes(new Date().getDay()); }, MM : function isMinutesPastMidnight() { @@ -145,7 +183,9 @@ } }[acsCode](value); } catch (e) { - client.log.warn( { acsCode : acsCode, value : value }, 'Invalid ACS string!'); + const logger = _.get(client, 'log', Log); + logger.warn( { acsCode : acsCode, value : value }, 'Invalid ACS string!'); + return false; } }