[MM-14740] Integrate GPO functionality (#961)

* integrate gpo functionality

* support multiple windows registry ‘hives’

* correct some copy paste errors

* registry config progress

* tweaks
This commit is contained in:
Dean Whillier
2019-04-18 13:19:04 -04:00
committed by GitHub
parent 9c0ac76f69
commit 25b920f412
7 changed files with 140 additions and 35 deletions

View File

@@ -80,6 +80,7 @@
"src/common/config/buildConfig.js", "src/common/config/buildConfig.js",
"src/common/config/pastDefaultPreferences.js", "src/common/config/pastDefaultPreferences.js",
"src/common/config/upgradePreferences.js", "src/common/config/upgradePreferences.js",
"src/common/config/RegistryConfig.js",
"src/common/osVersion.js", "src/common/osVersion.js",
"src/common/config/defaultPreferences.js", "src/common/config/defaultPreferences.js",
"src/common/JsonFileManager.js", "src/common/JsonFileManager.js",

View File

@@ -19,7 +19,7 @@ import AutoSaveIndicator from './AutoSaveIndicator.jsx';
const CONFIG_TYPE_SERVERS = 'servers'; const CONFIG_TYPE_SERVERS = 'servers';
const CONFIG_TYPE_APP_OPTIONS = 'appOptions'; const CONFIG_TYPE_APP_OPTIONS = 'appOptions';
const config = new Config(remote.app.getPath('userData') + '/config.json'); const config = new Config(remote.app.getPath('userData') + '/config.json', remote.getCurrentWindow().registryConfigData);
function backToIndex(index) { function backToIndex(index) {
const target = typeof index === 'undefined' ? 0 : index; const target = typeof index === 'undefined' ? 0 : index;
@@ -340,7 +340,7 @@ export default class SettingsPage extends React.Component {
addServer={this.addServer} addServer={this.addServer}
allowTeamEdit={this.state.enableTeamModification} allowTeamEdit={this.state.enableTeamModification}
onTeamClick={(index) => { onTeamClick={(index) => {
backToIndex(index + this.state.buildTeams.length + this.state.GPOTeams.length); backToIndex(index + this.state.buildTeams.length + this.state.registryTeams.length);
}} }}
/> />
</Col> </Col>
@@ -618,7 +618,7 @@ export default class SettingsPage extends React.Component {
bsStyle='link' bsStyle='link'
style={settingsPage.close} style={settingsPage.close}
onClick={this.handleCancel} onClick={this.handleCancel}
disabled={this.state.localTeams.length === 0} disabled={this.state.teams.length === 0}
> >
<span>{'×'}</span> <span>{'×'}</span>
</Button> </Button>

View File

@@ -21,7 +21,7 @@ import Config from '../common/config';
import MainPage from './components/MainPage.jsx'; import MainPage from './components/MainPage.jsx';
import {createDataURL as createBadgeDataURL} from './js/badge'; import {createDataURL as createBadgeDataURL} from './js/badge';
const config = new Config(remote.app.getPath('userData') + '/config.json'); const config = new Config(remote.app.getPath('userData') + '/config.json', remote.getCurrentWindow().registryConfigData);
const teams = config.teams; const teams = config.teams;

View File

@@ -0,0 +1,106 @@
// Copyright (c) 2015-2016 Yuya Ochiai
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {EventEmitter} from 'events';
import WindowsRegistry from 'winreg';
const REGISTRY_HIVE_LIST = [WindowsRegistry.HKLM, WindowsRegistry.HKCU];
const BASE_REGISTRY_KEY_PATH = '\\Software\\Policies\\Mattermost';
export default class RegistryConfig extends EventEmitter {
constructor() {
super();
this.initialized = false;
this.data = {
teams: [],
};
}
async init() {
if (process.platform === 'win32') {
// extract DefaultServerList from the registry
try {
const servers = await this.getServersListFromRegistry();
if (servers.length) {
this.data.teams.push(...servers);
}
} catch (error) {
console.log('[RegistryConfig] Nothing retrieved for \'DefaultServerList\'', error);
}
// extract EnableServerManagement from the registry
try {
const enableServerManagement = await this.getEnableServerManagementFromRegistry();
if (enableServerManagement !== null) {
this.data.enableServerManagement = enableServerManagement;
}
} catch (error) {
console.log('[RegistryConfig] Nothing retrieved for \'EnableServerManagement\'', error);
}
// extract EnableAutoUpdater from the registry
try {
const enableAutoUpdater = await this.getEnableAutoUpdatorFromRegistry();
if (enableAutoUpdater !== null) {
this.data.enableAutoUpdater = enableAutoUpdater;
}
} catch (error) {
console.log('[RegistryConfig] Nothing retrieved for \'EnableAutoUpdater\'', error);
}
this.initialized = true;
this.emit('update', this.data);
}
}
async getServersListFromRegistry() {
const defaultTeams = await this.getRegistryEntry(`${BASE_REGISTRY_KEY_PATH}\\DefaultServerList`);
return defaultTeams.flat(2).reduce((teams, team) => {
if (team) {
teams.push({
name: team.name,
url: team.value,
});
}
return teams;
}, []);
}
async getEnableServerManagementFromRegistry() {
const entries = (await this.getRegistryEntry(BASE_REGISTRY_KEY_PATH, 'EnableServerManagement'));
const entry = entries.pop();
return entry ? entry === '0x1' : null;
}
async getEnableAutoUpdatorFromRegistry() {
const entries = (await this.getRegistryEntry(BASE_REGISTRY_KEY_PATH, 'EnableAutoUpdater'));
const entry = entries.pop();
return entry ? entry === '0x1' : null;
}
async getRegistryEntry(key, name) {
const results = [];
for (const hive of REGISTRY_HIVE_LIST) {
results.push(this.getRegistryEntryValues(new WindowsRegistry({hive, key}), name));
}
const entryValues = await Promise.all(results);
return entryValues.filter((value) => value);
}
getRegistryEntryValues(regKey, name) {
return new Promise((resolve) => {
regKey.values((error, items) => {
if (error || !items || !items.length) {
resolve();
return;
}
if (name) { // looking for a single entry value
const registryItem = items.find((item) => item.name === name);
resolve(registryItem && registryItem.value ? registryItem.value : null);
} else { // looking for an entry list
resolve(items);
}
});
});
}
}

View File

@@ -15,9 +15,10 @@ import buildConfig from './buildConfig';
* Handles loading and merging all sources of configuration as well as saving user provided config * Handles loading and merging all sources of configuration as well as saving user provided config
*/ */
export default class Config extends EventEmitter { export default class Config extends EventEmitter {
constructor(configFilePath) { constructor(configFilePath, registryConfigData = {teams: []}) {
super(); super();
this.configFilePath = configFilePath; this.configFilePath = configFilePath;
this.registryConfigData = registryConfigData;
this.reload(); this.reload();
} }
@@ -35,8 +36,6 @@ export default class Config extends EventEmitter {
this.localConfigData = this.loadLocalConfigFile(); this.localConfigData = this.loadLocalConfigFile();
this.localConfigData = this.checkForConfigUpdates(this.localConfigData); this.localConfigData = this.checkForConfigUpdates(this.localConfigData);
this.GPOConfigData = this.loadGPOConfigData();
this.regenerateCombinedConfigData(); this.regenerateCombinedConfigData();
this.emit('update', this.combinedData); this.emit('update', this.combinedData);
@@ -77,6 +76,11 @@ export default class Config extends EventEmitter {
} }
} }
setRegistryConfigData(registryConfigData = {teams: []}) {
this.registryConfigData = Object.assign({}, registryConfigData);
this.reload();
}
/** /**
* Used to replace the existing config data with new config data * Used to replace the existing config data with new config data
* *
@@ -126,8 +130,8 @@ export default class Config extends EventEmitter {
get buildData() { get buildData() {
return this.buildConfigData; return this.buildConfigData;
} }
get GPOData() { get registryData() {
return this.GPOConfigData; return this.registryConfigData;
} }
// convenience getters // convenience getters
@@ -142,7 +146,7 @@ export default class Config extends EventEmitter {
return this.localConfigData.teams; return this.localConfigData.teams;
} }
get predefinedTeams() { get predefinedTeams() {
return [...this.buildConfigData.defaultTeams, ...this.GPOConfigData.teams]; return [...this.buildConfigData.defaultTeams, ...this.registryConfigData.teams];
} }
get enableHardwareAcceleration() { get enableHardwareAcceleration() {
return this.combinedData.enableHardwareAcceleration; return this.combinedData.enableHardwareAcceleration;
@@ -216,23 +220,6 @@ export default class Config extends EventEmitter {
return configData; return configData;
} }
/**
* Loads and returns config data defined in GPO for Windows
*/
loadGPOConfigData() {
const configData = {
teams: [],
enableServerManagement: true,
enableAutoUpdater: true,
};
if (process.platform === 'win32') {
//
// TODO: GPO data needs to be retrieved here and merged into the local `configData` variable for return
//
}
return configData;
}
/** /**
* Determines if locally stored data needs to be updated and upgrades as needed * Determines if locally stored data needs to be updated and upgrades as needed
* *
@@ -257,7 +244,7 @@ export default class Config extends EventEmitter {
*/ */
regenerateCombinedConfigData() { regenerateCombinedConfigData() {
// combine all config data in the correct order // combine all config data in the correct order
this.combinedData = Object.assign({}, this.defaultConfigData, this.localConfigData, this.buildConfigData, this.GPOConfigData); this.combinedData = Object.assign({}, this.defaultConfigData, this.localConfigData, this.buildConfigData, this.registryConfigData);
// remove unecessary data pulled from default and build config // remove unecessary data pulled from default and build config
delete this.combinedData.defaultTeam; delete this.combinedData.defaultTeam;
@@ -271,9 +258,9 @@ export default class Config extends EventEmitter {
combinedTeams.push(...this.buildConfigData.defaultTeams); combinedTeams.push(...this.buildConfigData.defaultTeams);
} }
// - add GPO defined teams, if any // - add registry defined teams, if any
if (this.GPOConfigData.teams && this.GPOConfigData.teams.length) { if (this.registryConfigData.teams && this.registryConfigData.teams.length) {
combinedTeams.push(...this.GPOConfigData.teams); combinedTeams.push(...this.registryConfigData.teams);
} }
// - add locally defined teams only if server management is enabled // - add locally defined teams only if server management is enabled
@@ -284,7 +271,7 @@ export default class Config extends EventEmitter {
this.combinedData.teams = combinedTeams; this.combinedData.teams = combinedTeams;
this.combinedData.localTeams = this.localConfigData.teams; this.combinedData.localTeams = this.localConfigData.teams;
this.combinedData.buildTeams = this.buildConfigData.defaultTeams; this.combinedData.buildTeams = this.buildConfigData.defaultTeams;
this.combinedData.GPOTeams = this.GPOConfigData.teams; this.combinedData.registryTeams = this.registryConfigData.teams;
} }
/** /**

View File

@@ -37,6 +37,7 @@ global.willAppQuit = false;
app.setAppUserModelId('com.squirrel.mattermost.Mattermost'); // Use explicit AppUserModelID app.setAppUserModelId('com.squirrel.mattermost.Mattermost'); // Use explicit AppUserModelID
import RegistryConfig from './common/config/RegistryConfig';
import Config from './common/config'; import Config from './common/config';
import CertificateStore from './main/certificateStore'; import CertificateStore from './main/certificateStore';
const certificateStore = CertificateStore.load(path.resolve(app.getPath('userData'), 'certificate.json')); const certificateStore = CertificateStore.load(path.resolve(app.getPath('userData'), 'certificate.json'));
@@ -63,7 +64,9 @@ let deeplinkingUrl = null;
let scheme = null; let scheme = null;
let appState = null; let appState = null;
let permissionManager = null; let permissionManager = null;
let config = null;
const registryConfig = new RegistryConfig();
const config = new Config(app.getPath('userData') + '/config.json');
const argv = parseArgv(process.argv.slice(1)); const argv = parseArgv(process.argv.slice(1));
const hideOnStartup = shouldBeHiddenOnStartup(argv); const hideOnStartup = shouldBeHiddenOnStartup(argv);
@@ -74,13 +77,20 @@ if (argv['data-dir']) {
global.isDev = isDev && !argv.disableDevMode; global.isDev = isDev && !argv.disableDevMode;
config = new Config(app.getPath('userData') + '/config.json');
// can only call this before the app is ready // can only call this before the app is ready
if (config.enableHardwareAcceleration === false) { if (config.enableHardwareAcceleration === false) {
app.disableHardwareAcceleration(); app.disableHardwareAcceleration();
} }
registryConfig.on('update', (registryConfigData) => {
config.setRegistryConfigData(registryConfigData);
if (app.isReady() && mainWindow) {
mainWindow.registryConfigData = registryConfigData;
}
});
registryConfig.init();
config.on('update', (configData) => { config.on('update', (configData) => {
if (process.platform === 'win32' || process.platform === 'linux') { if (process.platform === 'win32' || process.platform === 'linux') {
const appLauncher = new AutoLauncher(); const appLauncher = new AutoLauncher();

View File

@@ -24,6 +24,7 @@
"semver": "^5.5.0", "semver": "^5.5.0",
"simple-spellchecker": "^0.9.8", "simple-spellchecker": "^0.9.8",
"underscore": "^1.9.1", "underscore": "^1.9.1",
"winreg": "^1.2.4",
"yargs": "^3.32.0" "yargs": "^3.32.0"
} }
} }