Skip to content

Commit 3f258ce

Browse files
committed
feat: read from windows registry
1 parent 77a27fe commit 3f258ce

File tree

2 files changed

+66
-5
lines changed

2 files changed

+66
-5
lines changed

packages/electron-chrome-extensions/src/browser/api/lib/native-messaging-host.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { promises as fs } from 'node:fs'
33
import * as path from 'node:path'
44
import { app } from 'electron'
55
import { ExtensionSender } from '../../router'
6+
import { readRegistryKey } from './winreg'
67

78
const d = require('debug')('electron-chrome-extensions:nativeMessaging')
89

@@ -17,21 +18,41 @@ interface NativeConfig {
1718
async function readNativeMessagingHostConfig(
1819
application: string,
1920
): Promise<NativeConfig | undefined> {
20-
let searchPaths = [path.join(app.getPath('userData'), 'NativeMessagingHosts')]
21+
let searchPaths: string[]
2122
switch (process.platform) {
2223
case 'darwin':
23-
searchPaths.push('/Library/Google/Chrome/NativeMessagingHosts')
24+
searchPaths = [
25+
path.join(app.getPath('userData'), 'NativeMessagingHosts', `${application}.json`),
26+
path.join('/Library/Google/Chrome/NativeMessagingHosts', `${application}.json`),
27+
]
2428
break
29+
case 'linux':
30+
searchPaths = [
31+
path.join(app.getPath('userData'), 'NativeMessagingHosts', `${application}.json`),
32+
path.join('/etc/opt/chrome/native-messaging-hosts/', `${application}.json`),
33+
]
34+
break
35+
case 'win32': {
36+
searchPaths = (
37+
await Promise.allSettled([
38+
readRegistryKey('HKLM', '\\Software\\Google\\Chrome\\NativeMessagingHosts', application),
39+
readRegistryKey('HKCU', '\\Software\\Google\\Chrome\\NativeMessagingHosts', application),
40+
])
41+
)
42+
.map((result) => (result.status === 'fulfilled' ? result.value : undefined))
43+
.filter(Boolean) as string[]
44+
break
45+
}
2546
default:
2647
throw new Error('Unsupported platform')
2748
}
2849

29-
for (const basePath of searchPaths) {
30-
const filePath = path.join(basePath, `${application}.json`)
50+
for (const filePath of searchPaths) {
3151
try {
3252
const data = await fs.readFile(filePath)
3353
return JSON.parse(data.toString())
34-
} catch {
54+
} catch (error) {
55+
d('readNativeMessagingHostConfig: unable to read %s', filePath, error)
3556
continue
3657
}
3758
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { spawn } from 'child_process'
2+
3+
export function readRegistryKey(hive: string, path: string, key?: string) {
4+
if (process.platform !== 'win32') {
5+
return Promise.reject('Unsupported platform')
6+
}
7+
8+
return new Promise<string | null>((resolve, reject) => {
9+
const child = spawn('reg', ['query', `${hive}\\${path}`, ...(key ? ['/v', key] : [])])
10+
11+
let output = ''
12+
let error = ''
13+
14+
child.stdout.on('data', (data) => {
15+
output += data.toString()
16+
})
17+
18+
child.stderr.on('data', (data) => {
19+
error += data.toString()
20+
})
21+
22+
child.on('close', (code) => {
23+
if (code !== 0 || error) {
24+
return reject(new Error(`Failed to read registry: ${error}`))
25+
}
26+
27+
const lines = output.trim().split('\n')
28+
const resultLine = lines.find((line) =>
29+
key ? line.includes(key) : line.includes('(Default)'),
30+
)
31+
32+
if (resultLine) {
33+
const parts = resultLine.trim().split(/\s{2,}/)
34+
resolve(parts.pop() || null)
35+
} else {
36+
resolve(null)
37+
}
38+
})
39+
})
40+
}

0 commit comments

Comments
 (0)