Skip to content

Instantly share code, notes, and snippets.

@bfu4
Last active September 10, 2021 20:27
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bfu4/3013cfb42666c4ebb4a47255e3cbc3a9 to your computer and use it in GitHub Desktop.
Save bfu4/3013cfb42666c4ebb4a47255e3cbc3a9 to your computer and use it in GitHub Desktop.
dyknow r/e [BRIEF]

due to html failing to want to format, i've migrated this writeup to a gist. also, since by having your extension on the chrome web store you're basically open-source, the files referred to are ATTACHED to this gist. ha!

did you know?

a small writeup on the reverse-engineering of dyknow (school-wide chrome extension

introduction

i felt like doing a little analysis on dyknow, to see what goes on in it. this writeup is what i discovered while exploring the source-code of the extension. enjoy, i guess!

right into it

to get into a dyknow session with a teacher/'district', you use your EMAIL.

this is mentioned specifically for those who told me it was strictly wifi based. lol. an exception to this, is that you could call it "wifi-based" (not at all, but in ideology), as it's not supposed to track you when at home. an exception to that however, is that it still respects IP-based restrictions. see:

  /** ... Also need to be sure that it                                       
   * still respects the time-based limitations enforced at the district       
   * level, and finally if they are still running ip-based restrictions        
   * even at home, we need to respect that (which at home would mean that     
   * nobody's activity history would be tracked)                              
   */    

permissions

first up, we're going right into dyknow's permissions when looking at js/tests/filesystem/filesystem.tests.js we can make the assumption that dyknow probably has access to your device's filesystem. we learn that in the first 12 lines:

  // here we can make the assumption it's doing something with fs         
  define(['amd/filesystem'], function (filesystemLog) {                   
      describe('filesystem', function () {                                 
      var file = false;                                                  
      beforeEach(function (done) {                                       
            file = {                                                      
             name: filesystemLog.getActualLogFilename()                 
           };                                                            
      });                                                                             
      // luckily, i don't have to dissect it. it tells us what it's doing!    
      it('determines if a file is from today', function () {             
        expect(filesystemLog.isFromToday(file)).toBe(true);            
      });                                                                
                                                                        
  });                                                                  

as google has a fileSystem API anyways, this ability makes sense. although, it just seems annoying that whoever is using this software's admin can see if a file in the filesystem was last changed today.

next, it enacts a filesystem API feature, fake filesystems. it also uses direct write access to the filesystem, typically for logging, however, there is a method that is just writeToFile(), which could be interesting, at minimum.

despite what you might think, it's website blocking isnt actually scary (lol). it's got an options file of whitelisted websites and extensions (and of course, the hardcoded ones), and basically reads current url state off of that. blockingManager.js is the blocking manager.

dyknow also stores system information. once again, nothing scary (respect for the dev, i thought this was going to be borderline spyware if im going to be completely honest). DeviceInfo, hostname, and other things seem to return nothing. it will however get an architecture, OS description, physical memory, user memory, and platform info. it also gets the chrome version.

on an even less worrying note for students, activity monitor is in BETA with beta schools (supposedly). as for activity collector, i've priorly noticed delay in screen capture from dyknow, but the source code kinda proves it. along with some (and hilarious) comments that literally explain it's a little buggy/not working at the moment. the activityCollector(.js) has a few key features:

       - start a timed session
       - a timed session
       - ability to capture website state*
       - ability to stream that capture*
       - get the user
       - ' target time ', last time, if user is online,
          if an upload fails, and user activies (sigh)
       - window time in minutes
       - and whatever the (unpromising) addOnlineOrOfflineActivities()
           function may do.
  • denotes delay

another noteworthy .js is browserEvents.js. adds a bunch of listeners to events in the chrome browser. also application listeners, where it notices if chrome-extension applications and when they are installed/uninstalled/closed/focused. luckily, this isn't much of a worry when you have android/linux apps. but anything that is chrome browser related, is seen ;). the browser listener listens for whether a tab was opened/closed/removed (and logs what was removed!).

the keepAlive promise. something i found interesting, is that there is an ability to keep a specific window alive. alive, is assumed as in a functional, not closed state, and focused state. it also logs whether the keepAlive window is focused or not, mainly as debug.

another thing that confuses me, is that some of the source supports the idea that it's browser based, whereas some naming and comments make me think that it's not just browser based. anyways, this seems to give the vibe that it can change your activity, and get the name of your activity, browser based or not. i understand that chrome has some browser-device capabilities, but i never came to an understanding that the browser could interact with an android filesystem outside of itself. maybe that is the case. still interesting. another bonus, is that it seems to be able to lock activities.

over all, it seems to be more trustable than i originally felt, although i don't like to be monitored, so of course im "eh" on this stuff. respect to the developer for the fantastic comments (thank you!). i learned some new features, so i thought that was cool. lastly, i feel like this writeToFile() seems pretty safe, but i feel it could be misused in some way, however that's how i feel when i look at chrome-os related things anyways.. overall, not bad - i respect it for not being info greedy. i'm still not 100% sold on the "can't monitor from home thing", but as i didn't read every bit of the source code, i'm sure ill find something that proves it later, and thats fine.

define([
'amd/clients/core', 'amd/logger/logger', 'amd/sandbox',
'underscore', 'amd/cabra/helper/pal', 'amd/lib/pako',
'amd/clients/delaySwitchboardTracker'
], function(
CoreApiClient, Logger, Sandbox,
_, Pal, pako,
delaySwitchboardTracker
) {
/* now that e-learning has moved from the syncronous classroom
* to an async schedule, it is harder for teachers to keep track
* of issues students are having without students having the insight
* into their own challenges. Effectively, "walking around the room"
* is no longer available as a teacher strategy when there's no room.
* This feature, needs to be opt-in explicitly at the district level
* till we have been able to verify that we have nailed down fully
* reliable reporting/error recovery/etc. Also need to be sure that it
* still respects the time-based limitations enforced at the district
* level, and finally if they are still running ip-based restrictions
* even at home, we need to respect that (which at home would mean that
* nobody's activity history would be tracked)
*/
var activityCollector = {
_run: false,
_userDfd: null,
_user: null,
_resetForTest: function () {
activityCollector._run = false;
activityCollector._userDfd = null;
activityCollector._user = null;
activityCollector.pal = new Pal();
activityCollector.api = new CoreApiClient();
activityCollector._targetTime = null;
activityCollector._collectionWindowTime = null;
activityCollector._lastTime = null;
activityCollector._isOnline = true;
activityCollector._lastActivity = null;
activityCollector._uploadFails = 0;
activityCollector.activities = [];
activityCollector._windowTimeInMinutes = 60;
},
_targetTime: null,
_collectionWindowTime:null,
_lastTime: null,
_isOnline: true,
_lastActivity: null,
_uploadFails: 0,
activities:[],
pal: new Pal(),
api: new CoreApiClient(),
start: function(){
//in order to properly start, we need to be allowed to start
//(we assume that we only call start when we have )
activityCollector._run = true;
//we have a race condition we have to deal with here
if (!activityCollector._userDfd){
var userResolve;
activityCollector._userDfd = new Promise(function (resolve, reject){
userResolve = resolve;//capture resolve for use later
});
activityCollector._userDfd.resolve = userResolve;//for convenience
}
activityCollector._userDfd.then(function (user){
//begin our process doing stuff
activityCollector._user = user;
activityCollector.subscribe();
activityCollector.pal.start();
activityCollector.runTimer();
});
},
setToken: function (token){
activityCollector.api.accessToken = token;
},
setUser: function (user){
//have to have an identified/associated user before
//we can
if (!activityCollector._userDfd){
activityCollector._userDfd = Promise.resolve(user);
} else if (activityCollector._userDfd.resolve) {
//important to remember that all subsequent resolve
//calls are noop's, including this one if we've not
//reset ourselves properly
activityCollector._userDfd.resolve(user);
}
},
subscribe: function (){
activityCollector.pal.on("activity", activityCollector.onActivity);
},
unsubscribe: function(){
activityCollector.pal.off("activity", activityCollector.onActivity);
},
_formatNow: function (now){
//now expected to be a number, like _.now()
var str = new Date(now).toISOString();
if (str.endsWith("Z")){
str = str.substr(0, str.length -1);
}
return str;
},
_windowTimeInMinutes: 60,
_anchorToHour: function (now){
var date = new Date(now);
date.setMinutes(date.getMinutes() + activityCollector._windowTimeInMinutes, 0, 0);
if (activityCollector._windowTimeInMinutes === 60)
{
date.setMinutes(0, 0, 0); // Resets also seconds and milliseconds
} else {
date.setMinutes(
Math.floor(date.getMinutes() /activityCollector._windowTimeInMinutes) * activityCollector._windowTimeInMinutes,
0,0);
}
return +date;//convert back to number
},
_getWindowStartFromEnd: function (windowEndTime){
return windowEndTime - 60000 * activityCollector._windowTimeInMinutes;
},
_getCurrentWindowStart: function (){
return activityCollector._getWindowStartFromEnd(
activityCollector._collectionWindowTime
);
},
_getNumberOfWindowsBetweenTimes: function (then, now){
//prereq: now > then+30000
var nextWindow = activityCollector._anchorToHour(now);
var firstWindowEnd = activityCollector._anchorToHour(then);
//window0.Start, then, window0.end, window1.start, window1.end,windowN.start, now, nextwindow
return Math.floor((nextWindow - firstWindowEnd) / (60000*activityCollector._windowTimeInMinutes));
},
addOnlineOrOfflineActivities: function (fromActivity){
var now = _.now();
if (now > activityCollector._lastTime + 60000*1.5){
var then = activityCollector._lastTime + 60000;
activityCollector.activities.push({
time: activityCollector._formatNow(then),
payload_uuid: "c4bec4c2-725b-40f9-b484-e45061e8463c",
payload:{
status: "offline"
}
});
activityCollector.activities.push({
time: activityCollector._formatNow(now),
payload_uuid: "c4bec4c2-725b-40f9-b484-e45061e8463c",
payload:{
status: "ok"
}
});
if(!fromActivity && activityCollector._lastActivity){
activityCollector.activities.push({
time: activityCollector._formatNow(now),
payload_uuid: "39c4f580-5f5b-417f-8b55-b432802aa1d9",
payload: activityCollector._lastActivity,
stale: "stale"//stale communicates that we dont want there to be an additional viewCount
});
}
// obviously we're running now
activityCollector._isOnline = true;
}
activityCollector._lastTime = now;//if we dont do this we can doublecount
},
onActivity: function (activity){
activityCollector.addOnlineOrOfflineActivities(true);
activityCollector.activities.push({
time: activityCollector._formatNow(_.now()),
payload_uuid: "39c4f580-5f5b-417f-8b55-b432802aa1d9",
payload: activity
});
activityCollector._lastActivity = activity;
},
runTimer: function () {
var now = _.now();
if (!activityCollector._targetTime){
activityCollector._collectionWindowTime = activityCollector._anchorToHour(now);
activityCollector._targetTime = activityCollector._collectionWindowTime + 60000;
activityCollector._lastTime = now;
}
activityCollector.addOnlineOrOfflineActivities();
if (now >= activityCollector._targetTime && !delaySwitchboardTracker.delaySwitchboard){
var oldWindowTime = activityCollector._collectionWindowTime;
var oldTargetTime = activityCollector._targetTime;
//at this point, we are ready to upload, but to do that
//we need to...
//1. determine if there are multiple segments we need to be uploading
// (todo, determine if this should be categorized as catching up)
//2. calculate the new window time
//3. slice off the window
//4. update the current activities to ensure consistency
//5. update the window slice to be internally consistent
//stash the old values for later
var collectionWindowStr = activityCollector._formatNow(activityCollector._collectionWindowTime);
var collectionWindowEndTime = activityCollector._collectionWindowTime;
var then;
if (activityCollector.activities.length && activityCollector.activities[0].time){
then = +new Date(activityCollector.activities[0].time +"Z");//ensures utc, convert to num
}
//special case alert!
if (!then || then > collectionWindowEndTime){
//cant relay on then bc nothing has happened in a while. so we need
//instead to send then to be the start of our collectionwindow above
then = activityCollector._getWindowStartFromEnd(collectionWindowEndTime);
}
var numWindows = activityCollector._getNumberOfWindowsBetweenTimes(then, now);
if (numWindows > 1){
//reset to the end of the first windows
collectionWindowEndTime = activityCollector._anchorToHour(then);
collectionWindowStr = activityCollector._formatNow(collectionWindowEndTime);
//bump window times up in a controlled fashion
activityCollector._collectionWindowTime = activityCollector._anchorToHour(collectionWindowEndTime);
activityCollector._targetTime = activityCollector._anchorToHour(collectionWindowEndTime) + 60000;
} else {
//we are all caught up, so reset the target times
activityCollector._targetTime = null;
activityCollector._collectionWindowTime = null;
}
var collectionWindowStartTime = activityCollector._getWindowStartFromEnd(collectionWindowEndTime);
var collectionWindowStartTimeStr = activityCollector._formatNow(collectionWindowStartTime);
var currentActivities = activityCollector.activities;
var activitiesToSave = currentActivities.filter(function(a){
return a.time < collectionWindowStr;
});
var activitiesToKeep = currentActivities.filter(function(a){
return a.time >= collectionWindowStr;
});
//if we're starting off online, we need to bring the last stale
//activity over as well
var startingOffOnline = !activitiesToKeep.length ||
(activitiesToKeep[0].payload_uuid === "39c4f580-5f5b-417f-8b55-b432802aa1d9" &&
!(activitiesToKeep[0].time === collectionWindowStr &&
activitiesToKeep[0].stale === "stale")
//a prior attempt may have already added this
);
if (startingOffOnline && activitiesToSave.length){
//WARNING: DO NOT CHANGE THIS OBJECT AS IT IS A REFERENCE TO THE
//OBJECT WE NEED TO UPLOAD IN THE PRIOR CHUNK!!!
var lastActivityFromPriorChunk = activitiesToSave[activitiesToSave.length -1];
activitiesToKeep = [{
time: collectionWindowStr,//window boundary is non-inclusive, so this defines the timeframe
payload_uuid: "39c4f580-5f5b-417f-8b55-b432802aa1d9",
payload: lastActivityFromPriorChunk.payload,
stale: "stale"
}].concat(activitiesToKeep);
}
activityCollector.activities = activitiesToKeep;
//the window slice has to begin at the start of the timeframe.
//if it doesnt with an activity, that tells us that it started offline
//which is no big, lets just make that explicit here.
if (!activitiesToSave.length || activitiesToSave[0].time !==collectionWindowStartTimeStr){
activitiesToSave = [{
time: collectionWindowStartTimeStr,//window boundary is non-inclusive, so this defines the timeframe
payload_uuid: "c4bec4c2-725b-40f9-b484-e45061e8463c",
payload:{
status: "offline"
}
}].concat(activitiesToSave);
}
//we're gonna have to ask for a different url if we are uploading a
//chunk in the past so we have to calculate our window before all this goes
//down.
activityCollector._getConfig(collectionWindowStartTimeStr+"Z").then(function (config){
if (config.reason && !config.upload_url){
if (config.start_time && config.end_time){
//special case where the
var blackoutStart = config.end_time.substr(0, config.end_time.length-1);
var blackoutEnd = config.start_time.substr(0, config.start_time.length -1);
var activitiesToDump = activityCollector.activities.filter(function(a){
return a.time >= blackoutStart && a.time < blackoutEnd;
});
var activitiesToKeep = activityCollector.activities.filter(function(a){
return a.time < blackoutStart || a.time >= blackoutEnd;
});
activityCollector.activities = activitiesToKeep;
}
activityCollector._targetTime = null;
activitiesToSave = [];
return $.Deferred().resolve();//exit early without sending
}
if (config.reason && config.start_time){
//a start_time implies that we are out of the blackout hours
//at the start of our timeframe but at start_time, we start
//collecting. this means we now need to dump all the data before this
var strippedTime = config.start_time.substr(0, config.start_time.length -1);
var activitiesToDump = activitiesToSave.filter(function (a){
return a.time < strippedTime;
});
activitiesToSave = activitiesToSave.filter(function(a){
return a.time >= strippedTime;
});
if (activitiesToDump.length){
var staleActivity = activitiesToDump[activitiesToDump.length-1];
staleActivity.time = strippedTime;//we're dumping this so we can mutate it
if (staleActivity.payload_uuid ==="39c4f580-5f5b-417f-8b55-b432802aa1d9"){
staleActivity.stale = "stale";
}
activitiesToSave = [
staleActivity
].concat(activitiesToSave);
}
collectionWindowStartTimeStr = strippedTime;
} else if (config.reason && config.end_time){
//an end_time implies that we begin the timeframe within the
//blackout hours, but we end the timeframe blacked out. this
//means we need to dump all the data after
var strippedTime = config.end_time.substr(0, config.end_time.length -1);
activitiesToSave = activitiesToSave.filter(function (a){
return a.time < strippedTime;
});
collectionWindowStr = strippedTime;
}
if (config.reason && config.ip_address){
activitiesToSave = [{
time: collectionWindowStartTimeStr,
payload_uuid: "c4bec4c2-725b-40f9-b484-e45061e8463c",
payload:{
status: "ip-restricted: " + config.ip_address
}
}];
}
var data = pako.gzip(JSON.stringify({
cabra_name:"dyknow.me/participant_activity_monitor",
created: collectionWindowStartTimeStr,
completed: collectionWindowStr,
objects: activitiesToSave
}), {level:9});
return activityCollector.api.uploadToUrl(config.upload_url, data).then(function(ret){
activityCollector._uploadFails = 0;
return ret;
}, function (err){
//for the time being we will consider all failures the same
activityCollector._uploadFails ++;
if (activityCollector._uploadFails >= 2){
//sigh: lets give up on this window
Logger.error(err);
Logger.error("activityCollector - failure number " +
activityCollector._uploadFails +
" giving up on window " +
collectionWindowStartTimeStr
);
//note: we're not resetting the fails here
//because we want to limit exposure to more
//systemic deterministic errors at a school
return $.Deferred().resolve();
}
});
}).then(function (succcess){
//lets ensure we dont tight loop saving up
_.delay(function (){
activityCollector.runTimer();
}, 60000);
}, function (err){
activityCollector._collectionWindowTime = oldWindowTime;
activityCollector._targetTime = oldTargetTime;
activityCollector.activities = activitiesToSave.concat(activityCollector.activities);
//hmm we need to try and restore these activities
//and then also we need to run again, but for now
//lets just dump the data and try again
_.delay(function (){
activityCollector.runTimer();
}, 60000);
});
} else {
if (delaySwitchboardTracker.delaySwitchboard){
//what does this being active tell us about the current window?
//nothing about the current window. what does it tell us about
//past windows? well, nothing there either bc honestly
}
_.delay(function (){
activityCollector.runTimer();
}, 60000);
}
},
_getConfig: function (date_time, deviceOffset){
if(!deviceOffset){ deviceOffset = 0;}
return activityCollector.api.getActivityConfig(date_time, deviceOffset).then(function (config){
if (config.reason && !config.head_url){
//bail early, server doesnt want us to save
return $.Deferred().resolve(config);
}
return activityCollector.api.checkHeadOfUrl(config.head_url).then(function (){
//already exists! oh no!
var newDevice = deviceOffset + 1;
return activityCollector._getConfig(date_time, newDevice);
}, function (err){
if (err && err.status === 404){
return $.Deferred().resolve(config);//I think that resolves?
}
});
});
}
};
return activityCollector;
});
define([
'amd/cabra/helper/appBlock', 'amd/cabra/helper/urlFilter', 'amd/logger/logger',
'underscore'
], function(
AppBlock, UrlFilter, Logger,
_
) {
var instance = null;
/**
* Blocking manager constructor.
* The blocking manager is designed to be accessed through the singleton
* getter. It provides methods to use shared AppBlock and UrlFilter
* instances.
*/
function BlockingManager() {
Logger.info('BlockingManager: construct');
this.appBlock = new AppBlock();
this.urlFilter = new UrlFilter();
this.coreApplicationWhiteList = [
{
name: 'Dyknow Cloud',
identifier: chrome.runtime.id
},
{
name: 'Aristotle',
identifier: "jpnfjgjikmagakmnbiicfdkofbjinnpi" //content filter extension
},
{
name: 'Relay',
identifier: "adkcpkpghahmbopkjchobieckeoaoeem" //content filter extension (Lightspeed)
},
{
name: 'Securely-1',
identifier: "ppdeajpebepbknlalnhnlebhioceijka" //content filter extension
},
{
name: 'Securely-2',
identifier: "iheobagjkfklnlikgihanlhcddjoihkg" //content filter extension
}
];
this.customerApplicationWhiteList = [];
this.coreUrlWhiteList = ["studentontask.com"];
this.customerUrlWhiteList = [];
}
/**
* Blocking manager singleton getter.
* @return {BlockingManager} The blocking manager singleton.
*/
BlockingManager.instance = function() {
if (!instance) { instance = new BlockingManager(); }
return instance;
};
/**
* Restore from a captured state.
* @param {State} state A QSR state to restore.
*/
BlockingManager.prototype.restoreState = function(state) {
var blockingState = state.getNamed('blocking');
Logger.info('BlockingManager: restoring state', blockingState);
this.applyState(blockingState);
};
/**
* Set the state for the blocking manager.
* @param {mixed} state The state to apply. Falsy values clear the state.
*/
BlockingManager.prototype.applyState = function(state) {
if (state && !_.isEmpty(state)) {
this.applyApplicationRulesFromState(state);
this.applyUrlFilteringFromState(state);
} else {
Logger.info('BlockingManager: Clearing plans');
this.applyApplicationRule([], []);
this.applyUrlFiltering([], []);
}
};
/**
* Return an app list based on OS type.
* @param {array} apps The applications to filter.
* @param {string} type The OS type.
* @param {boolean} [exclude=false] If the app should be excluded (`true`)
* instead of included (`false`).
* @return {array} The filtered apps.
*/
BlockingManager.prototype.applicationsForOsType = function(apps, type, exclude) {
var negate = exclude === true;
return apps.filter(function(app) {
var includeApp = app.os.type === type;
return negate ? !includeApp : includeApp;
});
};
/**
* Get all applications from all bundles.
* @param {array} bundles The application bundles.
* @return {array} The bundle apps.
*/
BlockingManager.prototype.bundledApplications = function(bundles) {
return Array.prototype.concat.apply([], bundles.map(function(bundle) {
return bundle.applications || [];
}));
};
/**
* Get all applications from the bundles.
* @param {array} bundles The application bundles.
* @return {array} The bundle apps.
*/
BlockingManager.prototype.applicationsFromBundles = function(bundles) {
var bundlesExcludingWeb = this.applicationsForOsType(
this.bundledApplications(bundles), 'web', true);
var bundlesExcludingWebAndFragment = this.applicationsForOsType(
bundlesExcludingWeb, 'web-fragment', true);
return bundlesExcludingWebAndFragment.map(function(app) {
return {name: app.name, identifier: app.identifier};
});
};
/**
* Get all websites from the bundles.
* @param {array} bundles The application bundles.
* @return {array} The bundle websites.
*/
BlockingManager.prototype.websitesFromBundles = function(bundles) {
var apps = this.bundledApplications(bundles);
var web = this.applicationsForOsType(apps, 'web');
var fragment = this.applicationsForOsType(apps, 'web-fragment');
var chrome = this.applicationsForOsType(apps, 'chrome');
var allWeb = web.concat(fragment);
return allWeb.concat(chrome).map(function(app) {
return {identifier: app.identifier, ostype: app.os.type};
});
};
/**
* Apply application rules from a state.
* @param {object} state The state to apply.
*/
BlockingManager.prototype.applyApplicationRulesFromState = function(state) {
var whitelist = [];
var blacklist = [];
if (state.payload && Object.keys(state.payload).length) {
var rule = state.payload;
if (rule.type === 'whitelist') {
Logger.info('BlockingManager: Received Whitelist AppRule');
whitelist = this.applicationsFromBundles(rule.bundles);
} else if (rule.type === 'blacklist') {
Logger.info('BlockingManager: Received Blacklist AppRule');
blacklist = this.applicationsFromBundles(rule.bundles);
} else {
Logger.error('BlockingManager: Unsupported Rule Type, to be safe we will apply a clear all rule', rule.type);
}
} else {
Logger.debug('BlockingManager: Payload was ommited or did not include any keys, we will assume the desired behavior is to clear blocking');
}
this.applyApplicationRule(whitelist, blacklist);
};
/**
* Apply URL filtering from a state.
* @param {object} state The state to apply.
*/
BlockingManager.prototype.applyUrlFilteringFromState = function(state) {
var whitelist = [];
var blacklist = [];
if (state.payload && Object.keys(state.payload).length > 0) {
var rule = state.payload;
if (rule.type === 'whitelist') {
Logger.info('BlockingManager: Received Whitelist WebsiteRule');
whitelist = this.websitesFromBundles(rule.bundles);
} else if (rule.type === 'blacklist') {
Logger.info('BlockingManager: Received Blacklist WebsiteRule');
blacklist = this.websitesFromBundles(rule.bundles);
} else {
Logger.error('BlockingManager: Unsupported Rule Type, to be safe we will apply a clear all rule', rule.type);
}
} else {
Logger.debug('BlockingManager: Payload was ommited or did not include any keys, we will assume the desired behavior is to clear blocking');
}
this.applyUrlFiltering(whitelist, blacklist);
};
/**
* Apply application blocking rules.
* @param {array} whitelist Applications to whitelist.
* @param {array} blacklist Applications to blacklist.
*/
BlockingManager.prototype.applyApplicationRule = function(whitelist, blacklist) {
this.appBlock.applicationRule(
this.coreApplicationWhiteList,
this.customerApplicationWhiteList,
whitelist,
blacklist
);
};
/**
* Apply URL filtering rules.
* @param {array} whitelist Websites to whitelist.
* @param {array} blacklist Websites to blacklist.
*/
BlockingManager.prototype.applyUrlFiltering = function(whitelist, blacklist) {
this.urlFilter.filter(
this.coreUrlWhiteList,
this.customerUrlWhiteList,
whitelist,
blacklist
);
};
return BlockingManager;
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment