Skip to content

Commit 4858b70

Browse files
author
Steven Edouard
committed
Merge pull request CatalystCode#6 from ritazh/feat_uac
feat uac: elevate priviledge
2 parents 85dc0bc + 43d8768 commit 4858b70

File tree

7 files changed

+156
-4
lines changed

7 files changed

+156
-4
lines changed

Gruntfile.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ var files = ['lib/**/*.js', 'app.js', 'test/**/*.js'];
55
grunt.initConfig({
66
mochacli: {
77
options: {
8+
timeout: 4000,
89
reporter: 'spec',
910
bail: true
1011
},

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# windows-registry-node
22

3-
Read and Write to the Windows registry in-process from Node.js. Easily set application file associations and other goodies & such.
3+
Read and Write to the Windows registry in-process from Node.js. Easily set application file associations and other goodies & such. You can also enable your application to run processes as an Administrator.
44

55
## Install
66

@@ -69,6 +69,13 @@ To write a value, you'll again need a [Key](lib/key.js) object and just need to
6969
```js
7070
registry.setValueForKeyObject(key, 'test_value_name', windef.REG_VALUE_TYPE.REG_SZ, 'test_value');
7171
```
72+
## Launching a Process as An Admin
73+
74+
To launch a process as an Administrator, you can call the `uac.elevate` api, which will launch a process as an Administrator causing the UAC (User Account Control) elevation prompt to appear if required. This is similar to the Windows Explorer command "Run as administrator". Pass in `FILEPATH` to the process you want to elevate. Pass in any`PARAMETERS` to run with the process. Since this is an asychronous call, pass in a callback to handle user's selection.
75+
76+
```js
77+
uac.elevate('C:\\Program Files\\nodejs\\node.exe', 'index.js', function (err, result){console.log('callback');});
78+
```
7279

7380
## More Docs?
7481

index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,6 @@ module.exports = {
44
types: require('./lib/types'),
55
windef: require('./lib/windef'),
66
Key: require('./lib/key'),
7-
fileAssociation: require('./lib/file_association')
7+
fileAssociation: require('./lib/file_association'),
8+
uac: require('./lib/uac')
89
};

lib/types.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,17 @@ var ref = require('ref');
33
var types = {
44
REGSAM: ref.types.uint64,
55
DWORD: ref.types.uint32,
6+
ULONG: ref.types.uint32,
7+
HWND: ref.refType(ref.types.void),
68
BYTE: ref.types.uint8,
79
HKEY: ref.refType(ref.types.void),
810
PVOID: ref.refType(ref.types.void),
9-
LPCTSTR: ref.refType(ref.types.CString)
11+
HANDLE: ref.refType(ref.types.void),
12+
HINSTANCE: ref.refType(ref.types.void),
13+
LPCTSTR: ref.refType(ref.types.CString),
14+
STRING: ref.types.CString,
15+
INT: ref.types.int32,
16+
LPVOID: ref.refType(ref.types.void)
1017
};
1118

1219
types.PHKEY = ref.refType(types.HKEY);

lib/uac.js

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
'use strict';
2+
var ffi = require('ffi'),
3+
ref = require('ref'),
4+
struct = require('ref-struct'),
5+
uniontype = require('ref-union'),
6+
types = require('./types');
7+
8+
// Create the SHELLEXECUTEINFO struct
9+
10+
// yes, this is the name in the official MSDN doc
11+
var DUMMYUNIONNAME = uniontype({
12+
hIcon: types.HANDLE,
13+
hMonitor: types.HANDLE
14+
});
15+
16+
var SHELLEXECUTEINFO = struct({
17+
cbSize: types.DWORD,
18+
fMask: types.ULONG,
19+
hwnd: types.HWND,
20+
lpVerb: types.STRING,
21+
lpFile: types.STRING,
22+
lpParameters: types.STRING,
23+
lpDirectory: types.STRING,
24+
nShow: types.INT,
25+
hInstApp: types.HINSTANCE,
26+
lpIDList: types.LPVOID,
27+
lpClass: types.STRING,
28+
hkeyClass: types.HKEY,
29+
dwHotKey: types.DWORD,
30+
DUMMYUNIONNAME: DUMMYUNIONNAME,
31+
hProcess: types.HANDLE
32+
});
33+
34+
var SHELLEXECUTEINFOPtr = ref.refType(SHELLEXECUTEINFO);
35+
36+
var shell32 = new ffi.Library('Shell32', {
37+
ShellExecuteExA: ['bool', [SHELLEXECUTEINFOPtr]]
38+
});
39+
40+
// pass in default values for members
41+
var lpVerb = 'runas';
42+
var lpFile = null;
43+
var lpParameters = null;
44+
var hInstApp = ref.alloc(types.HINSTANCE);
45+
var SW_SHOWNORMAL = 0x1;
46+
47+
var uac = {
48+
FILEPATH: lpFile,
49+
PARAMETERS: lpParameters,
50+
elevate: function (filepath, parameters, callback) {
51+
this.FILEPATH = filepath;
52+
this.PARAMETERS = parameters;
53+
if(this.FILEPATH === null || this.FILEPATH === '') {
54+
console.log('Missing parameters FILEPATH');
55+
return;
56+
}
57+
var shellexecuteinfoval = new SHELLEXECUTEINFO({
58+
cbSize: SHELLEXECUTEINFO.size,
59+
fMask: 0x00000000,
60+
hwnd: null,
61+
lpVerb: lpVerb,
62+
lpFile: this.FILEPATH,
63+
lpParameters: this.PARAMETERS,
64+
lpDirectory: null,
65+
nShow: SW_SHOWNORMAL,
66+
hInstApp: hInstApp,
67+
lpIDList: null,
68+
lpCLass: null,
69+
hkeyClass: null,
70+
dwHotKey: null,
71+
DUMMYUNIONNAME: {
72+
hIcon: null,
73+
hMonitor: null
74+
},
75+
hProcess: ref.alloc(types.HANDLE)
76+
});
77+
78+
shell32.ShellExecuteExA.async(shellexecuteinfoval.ref(), callback);
79+
}
80+
};
81+
82+
module.exports = uac;

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
"grunt": "^0.4.5",
1212
"grunt-mocha-cli": "^2.0.0",
1313
"load-grunt-tasks": "^3.3.0",
14-
"ref": "^1.2.0"
14+
"ref": "^1.2.0",
15+
"ref-struct": "^1.0.2",
16+
"ref-union": "^1.0.0"
1517
},
1618
"devDependencies": {
1719
"grunt": "^0.4.5",
@@ -34,6 +36,7 @@
3436
"Registry",
3537
"regedit",
3638
"file",
39+
"uac",
3740
"association"
3841
],
3942
"author": "sedouard",

test/uac.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/* global describe, it */
2+
'use strict';
3+
var uac = require('../lib/uac'),
4+
assert = require('assert');
5+
6+
describe('UAC elevate tests', () => {
7+
it('Empty file path, should return', () => {
8+
uac.elevate('', null, function (err, result) {
9+
assert.equal(result, true);
10+
});
11+
assert.equal(uac.FILEPATH, '');
12+
});
13+
14+
it('Missing file path, should return', () => {
15+
uac.elevate(null, null, function (err, result) {
16+
assert.equal(result, true);
17+
});
18+
assert.equal(uac.FILEPATH, null);
19+
assert.equal(uac.PARAMETERS, null);
20+
});
21+
22+
it('Should get results for elevate for a given file', (done) => {
23+
uac.elevate('C:\\Program Files\\nodejs\\node.exe', null, function (err, result) {
24+
try {
25+
assert.ok(true);
26+
console.log('callback');
27+
assert(result !== null);
28+
done();
29+
} catch (x) {
30+
done(x);
31+
}
32+
});
33+
assert.equal(uac.FILEPATH, 'C:\\Program Files\\nodejs\\node.exe');
34+
assert.equal(uac.PARAMETERS, null);
35+
});
36+
37+
it('Should get results for elevate for a given file and parameter', (done) => {
38+
uac.elevate('C:\\Program Files\\nodejs\\node.exe', '--version', function (err, result) {
39+
try {
40+
assert.ok(true);
41+
console.log('callback');
42+
assert(result !== null);
43+
done();
44+
} catch (x) {
45+
done(x);
46+
}
47+
});
48+
assert.equal(uac.FILEPATH, 'C:\\Program Files\\nodejs\\node.exe');
49+
assert.equal(uac.PARAMETERS, '--version');
50+
});
51+
});

0 commit comments

Comments
 (0)