import PubSub from 'pubsub-js'; import XHRRetry from '../common/xhrRetry'; import Preferences from './preferences'; import { Logger } from '../common/logger'; import { CatchAllOrg, AppRuntimeId } from '../common/defs'; export interface Policy { enabled: boolean; full_screen_thumbnail: boolean; student_privacy: boolean; provisioning_code: string; socket_server?: string; api_server: string; reprovision_code: string; allowNonChromebook?: boolean; } export class ConfigPolicy { private logger = Logger.getInstance(); public static defaultPolicy: Policy = { enabled: true, full_screen_thumbnail: false, student_privacy: false, provisioning_code: CatchAllOrg, api_server: 'https://api-lsa.lenovosoftware.com', reprovision_code: '1000' }; constructor(private preferences: Preferences) {} async loadPolicy(): Promise { let policy: Policy | null = await this.loadPolicyFromGoogleAdmin(); if (!policy) { policy = await this.loadSelfHostedPolicy(); } if (policy) { policy = this.setMissingFields(policy); } else { this.logger.logMessage('ConfigPolicy.loadPolicy(): Using default policy'); policy = ConfigPolicy.defaultPolicy; } this.sendPolicyUpdate(policy); return policy; } private async loadPolicyFromGoogleAdmin(): Promise { return new Promise((resolve, reject) => { chrome.storage.managed.get((policy: Policy) => { if (chrome.runtime.lastError) { this.logger.logMessage( "ConfigPolicy.loadPolicyFromGoogleAdmin(): Error retrieving policy: '" + chrome.runtime.lastError + "'" ); resolve(null); return; } if (Object.keys(policy).length === 0) { this.logger.logMessage( 'ConfigPolicy.loadPolicyFromGoogleAdmin(): Policy not found via management API' ); resolve(null); return; } else { this.logger.logMessage( 'ConfigPolicy.loadPolicyFromGoogleAdmin(): Loaded Policy' + JSON.stringify(policy) ); } resolve(policy); }); }); } private async loadSelfHostedPolicy(): Promise { let finalPolicy; const policyUrl = await this.getPolicyUrl(); if (policyUrl.length > 0) { let p = new PolicyFromServer(policyUrl, AppRuntimeId); let policy = null; try { policy = await p.retrievePolicy(); } catch (err) { //will happen if policy can't be found } if (policy) { this.logger.logMessage( 'ConfigPolicy.loadSelfHostedPolicy: Retrieved self-hosted policy:' + JSON.stringify(policy) ); finalPolicy = policy; this.preferences.saveSetting('lastKnownGoodPolicy', policy); } else { this.logger.logMessage( 'ConfigPolicy.loadSelfHostedPolicy: Unable to find a self-hosted policy. Will check for lastKnownPolicy' ); const lastKnownPolicy = this.getLastKnownPolicy(); if (lastKnownPolicy) { this.logger.logMessage('ConfigPolicy.loadSelfHostedPolicy: Using lastKnownPolicy from prefs'); finalPolicy = lastKnownPolicy; } else { this.logger.logMessage( 'ConfigPolicy.loadSelfHostedPolicy: Retrieving policy from preferences unsuccessful. Using defaults.' ); finalPolicy = lastKnownPolicy; } } return finalPolicy; } else { return null; } } private hasValidProvision(): boolean { const provisioningData = this.preferences.getSetting(Preferences.ProvisioningData_Key); const provisioningParams = this.preferences.getSetting(Preferences.ProvisioningParams_Key); return !!( provisioningData && provisioningParams && provisioningData.hasOwnProperty('id') && provisioningParams.hasOwnProperty('machineCode') && provisioningParams.machineCode !== CatchAllOrg ); } private getLastKnownPolicy(): Policy | null { if (this.hasValidProvision()) { const lastKnown = this.preferences.getSetting('lastKnownPolicy'); if ( lastKnown && lastKnown.hasOwnProperty('api_server') && typeof lastKnown.api_server !== 'undefined' && lastKnown.api_server && lastKnown.api_server.length > 0 ) { return lastKnown; } } return null; } private getPolicyUrl(): string { let manifestObj = chrome.runtime.getManifest(); if (manifestObj && manifestObj.hasOwnProperty('policy_url')) { this.logger.logMessage( 'ConfigPolicy.getPolicyUrl(): Getting policy_url from manifest:' + manifestObj.policy_url ); return manifestObj.policy_url; } this.logger.logMessage('ConfigPolicy.getPolicyUrl():No policy_url is defined in manifest'); return ''; } private setMissingFields(policy: Policy = {} as Policy): Policy { let fields = Object.keys(ConfigPolicy.defaultPolicy); for (let field of fields) { //@ts-ignore if (!policy.hasOwnProperty(field)) { //@ts-ignore policy[field] = ConfigPolicy.defaultPolicy[field]; } } return policy; } private sendPolicyUpdate(policy: Policy): void { this.logger.logMessage('ConfigPolicy.sendPolicyUpdate(): Sending final policy: ' + JSON.stringify(policy)); if (policy.enabled) { chrome.runtime.sendMessage({ message: 'PolicyUpdate', policy: policy }); } PubSub.publish('onPolicyUpdate', policy); } } export class PolicyFromServer { private url: string; private runtimeId: string; private maxAttempts: number; private retryPeriod: number; constructor(policyUrl: string, runtimeId: string) { this.url = policyUrl; if (!this.url.endsWith('/')) { this.url += '/'; } this.runtimeId = runtimeId; this.maxAttempts = 5; this.retryPeriod = 10000; } async retrievePolicy(): Promise { let myUrl = new URL(this.url + this.runtimeId); let retriever = new XHRRetry( myUrl, { key: 'Content-type', value: 'application/json' }, { maxAttempts: this.maxAttempts, retryPeriod: this.retryPeriod, responseChecker: this.checkResponse } ); const policyResponseText: any = await retriever.retrieve(); return this.sanitizePolicy(JSON.parse(policyResponseText)); } checkResponse(xhrResponse: any): boolean { if (xhrResponse) { return true; } return false; } sanitizePolicy(parsedObj: any): any { let retObj: any = {}; for (var key in parsedObj) { if (parsedObj.hasOwnProperty(key)) { if (typeof parsedObj[key] === 'object' && parsedObj[key].hasOwnProperty('Value')) { retObj[key] = parsedObj[key]['Value']; } else { retObj[key] = parsedObj[key]; } } } return retObj; } }