gpii-windows
Version:
Components of the GPII personalization infrastructure for use on Microsoft's "Windows" ™
562 lines (480 loc) • 20.7 kB
JavaScript
/*
* Windows Registry Settings Handler
*
* Licensed under the New BSD license. You may not use this file except in
* compliance with this License.
*
* You may obtain a copy of the License at
* https://github.com/GPII/universal/blob/master/LICENSE.txt
*/
"use strict";
var fluid = require("gpii-universal"),
os = require("os");
var jqUnit = fluid.require("node-jqunit");
var gpii = fluid.registerNamespace("gpii");
require("../src/RegistrySettingsHandler.js");
fluid.registerNamespace("gpii.tests.windows.registrySettingsHandler");
jqUnit.module("RegistrySettingsHandler Module");
gpii.tests.windows.registrySettingsHandler.apiTest = {
init: {
"settings": {
"FollowMouse": 1,
"Invert": 0,
"Magnification": 225
},
"options": {
"hKey": "HKEY_CURRENT_USER",
"path": "Software\\GPIIMagnifier",
"dataTypes": {
"FollowMouse": "REG_DWORD",
"Invert": "REG_DWORD",
"Magnification": "REG_DWORD"
}
}
},
set: {
payload: {
"com.windows.magnifier": [{
"settings": {
"FollowMouse": 0,
"Invert": 1,
"Magnification": 235
},
"options": {
"hKey": "HKEY_CURRENT_USER",
"path": "Software\\GPIIMagnifier",
"dataTypes": {
"FollowMouse": "REG_DWORD",
"Invert": "REG_DWORD",
"Magnification": "REG_DWORD"
}
}
}]
},
uwpPayload: {
"com.windows.magnifier": [{
"settings": {
"FollowMouse": 0,
"Invert": 1,
"Magnification": 235
},
"options": {
"hKey": "HKEY_CURRENT_USER",
"path": "Software\\GPIIMagnifier",
"dataTypes": {
"FollowMouse": "REG_DWORD",
"Invert": "REG_DWORD",
"Magnification": "REG_DWORD"
},
"uwp": true
}
}]
},
expectedResult: {
"com.windows.magnifier": [{
"settings": {
"FollowMouse": {
"oldValue": 1,
"statusCode": 200,
"newValue": 0
},
"Invert": {
"oldValue": 0,
"statusCode": 200,
"newValue": 1
},
"Magnification": {
"oldValue": 225,
"statusCode": 200,
"newValue": 235
}
}
}]
}
},
get: {
payload: {
"com.windows.magnifier": [{
"settings": {
"FollowMouse": {
"dataType": "REG_DWORD"
},
"Invert": {
"dataType": "REG_DWORD"
},
"Magnification": {
"dataType": "REG_DWORD"
}
},
"options": {
"hKey": "HKEY_CURRENT_USER",
"path": "Software\\GPIIMagnifier",
"dataTypes": {
"FollowMouse": "REG_DWORD",
"Invert": "REG_DWORD",
"Magnification": "REG_DWORD"
}
}
}]
},
expectedResult: {
"com.windows.magnifier": [{
"settings": {
"FollowMouse": 1,
"Invert": 0,
"Magnification": 225
}
}]
}
}
};
gpii.tests.windows.registrySettingsHandler.handlerOneTest = {
initPayload: {
"settings": {
"FollowMouse": 1,
"Invert": 0,
"Magnification": 255
},
"options": {
"hKey": "HKEY_CURRENT_USER",
"path": "Software\\GPIIMagnifier",
"dataTypes": {
"FollowMouse": "REG_DWORD",
"Invert": "REG_DWORD",
"Magnification": "REG_DWORD"
}
}
},
setPayload: {
"settings": {
"FollowMouse": 0,
"Invert": 1
},
"options": {
"hKey": "HKEY_CURRENT_USER",
"path": "Software\\GPIIMagnifier",
"dataTypes": {
"FollowMouse": "REG_DWORD",
"Invert": "REG_DWORD",
"Magnification": "REG_DWORD"
}
}
},
expectedReturn: {
"FollowMouse": {
"oldValue": 1,
"statusCode": 200,
"newValue": 0
},
"Invert": {
"oldValue": 0,
"statusCode": 200,
"newValue": 1
}
}
};
gpii.tests.windows.registrySettingsHandler.enumerationTest = {
initPayload: {
"settings": {
"FollowMouse": 1,
"Invert": 0,
"Magnification": 255,
"Description": "GPII Magnifier",
"ZeroLength": ""
},
"options": {
"hKey": "HKEY_CURRENT_USER",
"path": "Software\\GPIIMagnifier",
"dataTypes": {
"FollowMouse": "REG_DWORD",
"Invert": "REG_DWORD",
"Magnification": "REG_DWORD",
"Description": "REG_SZ",
"ZeroLength": "REG_SZ"
}
},
"count": 5
},
expectedReturn: {
"FollowMouse": {
"data": 1,
"bytes": 4,
"name": "FollowMouse",
"type": "REG_DWORD"
},
"Invert": {
"data": 0,
"bytes": 4,
"name": "Invert",
"type": "REG_DWORD"
},
"Magnification": {
"data": 255,
"bytes": 4,
"name": "Magnification",
"type": "REG_DWORD"
},
"Description": {
"data": "GPII Magnifier",
"bytes": 30,
"name": "Description",
"type": "REG_SZ"
},
"ZeroLength": {
"data": "",
"bytes": 2,
"name": "ZeroLength",
"type": "REG_SZ"
}
}
};
gpii.tests.windows.registrySettingsHandler.deleteKeyTest = {
initPayload: {
"settings": {
"FollowMouse": 1,
"Invert": 0,
"Magnification": 255,
"Description": "GPII Magnifier"
},
"options": {
"hKey": "HKEY_CURRENT_USER",
"path": "Software\\GPIIMagnifier",
"dataTypes": {
"FollowMouse": "REG_DWORD",
"Invert": "REG_DWORD",
"Magnification": "REG_DWORD",
"Description": "REG_SZ"
}
},
"count": 4
},
expectedReturn: {
"statusCode": 404
}
};
jqUnit.test("Testing registrySettingsHandler.setImpl incl undefined value.value", function () {
jqUnit.expect(1);
// set to initial values:
gpii.windows.registrySettingsHandler.setImpl(gpii.tests.windows.registrySettingsHandler.handlerOneTest.initPayload);
// now that we 'know' current values, set new ones:
var actualReturn = gpii.windows.registrySettingsHandler.setImpl(gpii.tests.windows.registrySettingsHandler.handlerOneTest.setPayload);
// check results
jqUnit.assertDeepEq("Checking return payload", gpii.tests.windows.registrySettingsHandler.handlerOneTest.expectedReturn, gpii.resolveSync(actualReturn));
// cleanup
gpii.windows.deleteRegistryKey("HKEY_CURRENT_USER", "Software\\GPIIMagnifier");
});
jqUnit.test("Reading and writing single registry keys", function () {
jqUnit.expect(7);
var dwordValue = 100;
gpii.windows.writeRegistryKey("HKEY_CURRENT_USER", "Software\\GPIIMagnifier", "Magnification", dwordValue, "REG_DWORD");
var value = gpii.windows.readRegistryKey("HKEY_CURRENT_USER", "Software\\GPIIMagnifier", "Magnification", "REG_DWORD");
jqUnit.assertEquals("Assert REG_DWORD", dwordValue, value.value);
var unicodeString = "I am Agent Гюнтер";
gpii.windows.writeRegistryKey("HKEY_CURRENT_USER", "Software\\GPIIMagnifier", "MagnificationAnnotation", unicodeString, "REG_SZ");
var value2 = gpii.windows.readRegistryKey("HKEY_CURRENT_USER", "Software\\GPIIMagnifier", "MagnificationAnnotation", "REG_SZ");
jqUnit.assertEquals("Assert REG_SZ", unicodeString, value2.value);
gpii.windows.writeRegistryKey("HKEY_CURRENT_USER", "Software\\GPIIMagnifier", "MagnificationBinary", "0a, b0, cAfebAbe", "REG_BINARY");
var value3 = gpii.windows.readRegistryKey("HKEY_CURRENT_USER", "Software\\GPIIMagnifier", "MagnificationBinary", "REG_BINARY");
jqUnit.assertEquals("Assert REG_BINARY", "0a b0 ca fe ba be", value3.value);
var stringArray = [ "item 1", "item 2", "item 3" ];
gpii.windows.writeRegistryKey("HKEY_CURRENT_USER", "Software\\GPIIMagnifier", "MagnificationArray", stringArray, "REG_MULTI_SZ");
var value4 = gpii.windows.readRegistryKey("HKEY_CURRENT_USER", "Software\\GPIIMagnifier", "MagnificationArray", "REG_MULTI_SZ");
jqUnit.assertDeepEq("Assert REG_MULTI_SZ", stringArray, value4.value);
var stringNotArray = "item ABC";
gpii.windows.writeRegistryKey("HKEY_CURRENT_USER", "Software\\GPIIMagnifier", "MagnificationArray", stringNotArray, "REG_MULTI_SZ");
var value5 = gpii.windows.readRegistryKey("HKEY_CURRENT_USER", "Software\\GPIIMagnifier", "MagnificationArray", "REG_MULTI_SZ");
jqUnit.assertDeepEq("Assert REG_MULTI_SZ", [ stringNotArray ], value5.value);
gpii.windows.writeRegistryKey("HKEY_CURRENT_USER", "Software\\GPIIMagnifier", "Magnification", undefined, "REG_DWORD");
var value6 = gpii.windows.readRegistryKey("HKEY_CURRENT_USER", "Software\\GPIIMagnifier", "Magnification", "REG_DWORD");
jqUnit.assertDeepEq("Assert value not found after deleted", {statusCode: 404}, value6);
// Test zero-length values return an empty string (GPII-2751).
// The failure of this test also depends on the 2 bytes after the buffer being zero, so run it a few times to reduce
// the element of luck.
var tries = 500;
jqUnit.expect(tries);
for (var retry = 0; retry < tries; retry++) {
var emptyString = "";
gpii.windows.writeRegistryKey("HKEY_CURRENT_USER", "Software\\GPIIMagnifier", "ZeroTest", emptyString, "REG_SZ");
var result = gpii.windows.readRegistryKey("HKEY_CURRENT_USER", "Software\\GPIIMagnifier", "ZeroTest", "REG_SZ");
jqUnit.assertEquals("Assert empty REG_SZ", 0, result.value.length);
if (result.value.length !== 0) {
// One fail is enough.
break;
}
}
// clean up after ourselves
gpii.windows.deleteRegistryKey("HKEY_CURRENT_USER", "Software\\GPIIMagnifier");
// test for GPII-1108 - deletion of subkey of nonexistent parent should be permitted
gpii.windows.writeRegistryKey("HKEY_CURRENT_USER", "Software\\GPIIMagnifier", "Magnification", undefined, "REG_DWORD");
jqUnit.assert("Deletion of subkey of nonexistent parent should be valid noop");
});
jqUnit.test("Testing registrySettingsHandler API (get and set functions)", function () {
jqUnit.expect(2);
// set to initial values:
gpii.windows.registrySettingsHandler.setImpl(gpii.tests.windows.registrySettingsHandler.apiTest.init);
// First we test the get functionality
var result = gpii.windows.registrySettingsHandler.get(gpii.tests.windows.registrySettingsHandler.apiTest.get.payload);
// check results
jqUnit.assertDeepEq("Checking return payload of get", gpii.tests.windows.registrySettingsHandler.apiTest.get.expectedResult, gpii.resolveSync(result));
// Test set functionality
var result2 = gpii.windows.registrySettingsHandler.set(gpii.tests.windows.registrySettingsHandler.apiTest.set.payload);
// check results
jqUnit.assertDeepEq("Checking return payload of set", gpii.tests.windows.registrySettingsHandler.apiTest.set.expectedResult, gpii.resolveSync(result2));
// cleanup
gpii.windows.deleteRegistryKey("HKEY_CURRENT_USER", "Software\\GPIIMagnifier");
});
jqUnit.test("Enumerating registry key values", function () {
var testData = gpii.tests.windows.registrySettingsHandler.enumerationTest;
var baseKey = testData.initPayload.options.hKey;
var path = testData.initPayload.options.path;
// Apply the data
gpii.windows.registrySettingsHandler.setImpl(testData.initPayload);
// Enumerate the key
var result = gpii.windows.enumRegistryValues(baseKey, path);
// Check the result
jqUnit.assertDeepEq("Checking the return of enumRegistryValues", testData.expectedReturn, result);
// Clean up
gpii.windows.deleteRegistryKey("HKEY_CURRENT_USER", "Software\\GPIIMagnifier");
});
jqUnit.test("Enumerating registry key sub-keys", function () {
var baseKey = "HKEY_CURRENT_USER";
var path = "Software\\GPIIMagnifier";
var subkeys = [];
for (var n = 0; n < 10; n++) {
var subkeyName = "subkey" + n;
subkeys.push(subkeyName);
gpii.windows.writeRegistryKey(baseKey, path + "\\" + subkeyName, "dummyvalue", "abc", "REG_SZ");
}
// Enumerate the key
var result = gpii.windows.enumRegistryKeys(baseKey, path);
// Check the result
jqUnit.assertDeepEq("Checking the return of enumRegistryKeys", subkeys.sort(), result.sort());
// Clean up
fluid.each(subkeys, function (keyName) {
gpii.windows.deleteRegistryKey("HKEY_CURRENT_USER", "Software\\GPIIMagnifier\\" + keyName);
});
gpii.windows.deleteRegistryKey("HKEY_CURRENT_USER", "Software\\GPIIMagnifier");
});
jqUnit.test("Key deletion", function () {
var testData = gpii.tests.windows.registrySettingsHandler.deleteKeyTest;
var baseKey = testData.initPayload.options.hKey;
var path = testData.initPayload.options.path;
// Apply the data
gpii.windows.registrySettingsHandler.setImpl(testData.initPayload);
// Delete it
gpii.windows.deleteRegistryKey("HKEY_CURRENT_USER", "Software\\GPIIMagnifier");
// Enumerate the key
var result = gpii.windows.enumRegistryValues(baseKey, path);
// Check the result
jqUnit.assertDeepEq("Checking the return of enumRegistryValues", testData.expectedReturn, result);
});
jqUnit.test("Non-existing key deletion", function () {
jqUnit.expect(1);
try {
// Delete it
gpii.windows.deleteRegistryKey("HKEY_CURRENT_USER", "Software\\key-does-not-exist");
} catch (e) {
jqUnit.fail("Should not fail.");
throw e;
}
jqUnit.assert("Should succeed.");
});
jqUnit.test("Testing 32/64 bit views", function () {
// HKEY_LOCAL_MACHINE\Software has different values for 32/64-bit processes, however this one is write-able.
// https://msdn.microsoft.com/library/aa384253
var baseKey = "HKEY_CURRENT_USER";
var path = "Software\\Classes\\CLSID\\GPII-Test";
var path32 = "32:" + path;
var path64 = "64:" + path;
var testValue = "test";
var bits = (os.arch() === "x64") ? "64" : "32";
// 32-bit read/write
gpii.windows.writeRegistryKey(baseKey, path32, "test32", testValue, "REG_SZ");
var result1 = gpii.windows.readRegistryKey(baseKey, path32, "test32", "REG_SZ");
jqUnit.assertEquals("32-bit registry view should work", testValue, result1.value);
// 64-bit read/write
gpii.windows.writeRegistryKey(baseKey, path64, "test64", testValue, "REG_SZ");
var result2 = gpii.windows.readRegistryKey(baseKey, path64, "test64", "REG_SZ");
jqUnit.assertEquals("64-bit registry view should work", testValue, result2.value);
if (gpii.windows.isWow64() || bits === "64") {
// These tests aren't valid on a 32-bit OS because there is only 1 registry view; 32-bit and 64-bit views
// point to the same thing, so both values will exist.
// Try 32-bit value from 64-bit
var result3 = gpii.windows.readRegistryKey(baseKey, path64, "test32", "REG_SZ");
jqUnit.assertUndefined("32-bit value should not exist in 64-bit registry view", result3.value);
// Try 32-bit value from 64-bit
var result4 = gpii.windows.readRegistryKey(baseKey, path32, "test64", "REG_SZ");
jqUnit.assertUndefined("64-bit value should not exist in 32-bit registry view", result4.value);
// Get native value from native view
var result5 = gpii.windows.readRegistryKey(baseKey, path, "test" + bits, "REG_SZ");
jqUnit.assertEquals("native-bit value should be in native-bit registry view", testValue, result5.value);
// Try other value from native view
var otherBits = (bits === "64") ? "32" : "64";
var result6 = gpii.windows.readRegistryKey(baseKey, path, "test" + otherBits, "REG_SZ");
jqUnit.assertUndefined("non-native-bit value should not be in in native-bit registry view", result6.value);
}
// Clean up
gpii.windows.deleteRegistryKey(baseKey, path32);
gpii.windows.deleteRegistryKey(baseKey, path64);
});
var windows = fluid.registerNamespace("gpii.windows");
var ffi = require("ffi-napi"),
ref = require("ref");
var advapi32 = new ffi.Library("advapi32", {
GetExplicitEntriesFromAclW: [
"uint32", ["void*", "uint32*", "void*"]
],
LookupAccountSidW: [
"bool", [ "pointer", "pointer", "char*", "uint32*", "char*", "uint32*", "uint32*"]
]
});
jqUnit.test("Testing UWP key permissions", function () {
jqUnit.expect(2);
// set to initial values:
gpii.windows.registrySettingsHandler.setImpl(gpii.tests.windows.registrySettingsHandler.apiTest.init);
// Test set functionality
var result2 = gpii.windows.registrySettingsHandler.set(gpii.tests.windows.registrySettingsHandler.apiTest.set.uwpPayload);
// check results
jqUnit.assertDeepEq("Checking return payload of set", gpii.tests.windows.registrySettingsHandler.apiTest.set.expectedResult, gpii.resolveSync(result2));
var keyHolder = Buffer.alloc(4);
// Check key permissions
try {
var information = windows.securityInformation.DACL_SECURITY_INFORMATION;
var baseKey = "HKEY_CURRENT_USER";
var path = "Software\\GPIIMagnifier";
windows.openRegistryKey(baseKey, path, keyHolder, windows.securityAccess);
var secBuffer = windows.regGetKeySecurity(keyHolder, information);
var isPresent = Buffer.alloc(4);
var isDefaulted = Buffer.alloc(4);
var oldACL = windows.getSecurityDescriptorDacl(secBuffer, isPresent, isDefaulted);
var entriesBuff = Buffer.alloc(4);
var eaRef = ref.alloc("int");
advapi32.GetExplicitEntriesFromAclW(oldACL.deref(), entriesBuff, eaRef);
var entries = entriesBuff.readUInt32LE();
var foundCorrectPermission = false;
var allACLs = eaRef.readPointer(0, windows.ExplicitAccess.size * entries);
for (var i = 0; i < entries; i++) {
var curACL = ref.get(allACLs, i * windows.ExplicitAccess.size, windows.ExplicitAccess);
var nameBuff = Buffer.alloc(200);
var bufferSize = Buffer.alloc(4);
bufferSize.writeUInt32LE(100);
var domainName = Buffer.alloc(200);
var domainNameSize = Buffer.alloc(4);
domainNameSize.writeUInt32LE(100);
var nameUse = Buffer.alloc(4);
var systemName = Buffer.alloc(10);
advapi32.LookupAccountSidW(systemName, curACL.Trustee.ptstrName, nameBuff,
bufferSize, domainName, domainNameSize, nameUse);
var name = windows.fromWideChar(nameBuff);
if (name === "ALL APPLICATION PACKAGES") {
foundCorrectPermission = true;
break;
}
}
jqUnit.assertDeepEq("Correct permissions where found into modified key", true, foundCorrectPermission);
windows.kernel32.LocalFree(eaRef.deref());
} finally {
windows.closeRegistryKey(keyHolder);
gpii.windows.deleteRegistryKey("HKEY_CURRENT_USER", "Software\\GPIIMagnifier");
}
});