Files
webtorrent-desktop/src/main/handlers.js
Feross Aboukhadijeh 9ed3533225 standard
2019-07-05 14:26:38 -07:00

369 lines
9.0 KiB
JavaScript

module.exports = {
install,
uninstall
}
const config = require('../config')
const path = require('path')
function install () {
switch (process.platform) {
case 'darwin': installDarwin()
break
case 'win32': installWin32()
break
case 'linux': installLinux()
break
}
}
function uninstall () {
switch (process.platform) {
case 'darwin': uninstallDarwin()
break
case 'win32': uninstallWin32()
break
case 'linux': uninstallLinux()
break
}
}
function installDarwin () {
const electron = require('electron')
const app = electron.app
// On Mac, only protocols that are listed in `Info.plist` can be set as the
// default handler at runtime.
app.setAsDefaultProtocolClient('magnet')
app.setAsDefaultProtocolClient('stream-magnet')
// File handlers are defined in `Info.plist`.
}
function uninstallDarwin () {}
const EXEC_COMMAND = [process.execPath, '--']
if (!config.IS_PRODUCTION) {
EXEC_COMMAND.push(config.ROOT_PATH)
}
function installWin32 () {
const Registry = require('winreg')
const log = require('./log')
const iconPath = path.join(
process.resourcesPath, 'app.asar.unpacked', 'static', 'WebTorrentFile.ico'
)
registerProtocolHandlerWin32(
'magnet',
'URL:BitTorrent Magnet URL',
iconPath,
EXEC_COMMAND
)
registerProtocolHandlerWin32(
'stream-magnet',
'URL:BitTorrent Stream-Magnet URL',
iconPath,
EXEC_COMMAND
)
registerFileHandlerWin32(
'.torrent',
'io.webtorrent.torrent',
'BitTorrent Document',
iconPath,
EXEC_COMMAND
)
/**
* To add a protocol handler, the following keys must be added to the Windows registry:
*
* HKEY_CLASSES_ROOT
* $PROTOCOL
* (Default) = "$NAME"
* URL Protocol = ""
* DefaultIcon
* (Default) = "$ICON"
* shell
* open
* command
* (Default) = "$COMMAND" "%1"
*
* Source: https://msdn.microsoft.com/en-us/library/aa767914.aspx
*
* However, the "HKEY_CLASSES_ROOT" key can only be written by the Administrator user.
* So, we instead write to "HKEY_CURRENT_USER\Software\Classes", which is inherited by
* "HKEY_CLASSES_ROOT" anyway, and can be written by unprivileged users.
*/
function registerProtocolHandlerWin32 (protocol, name, icon, command) {
const protocolKey = new Registry({
hive: Registry.HKCU, // HKEY_CURRENT_USER
key: '\\Software\\Classes\\' + protocol
})
setProtocol()
function setProtocol (err) {
if (err) return log.error(err.message)
protocolKey.set('', Registry.REG_SZ, name, setURLProtocol)
}
function setURLProtocol (err) {
if (err) return log.error(err.message)
protocolKey.set('URL Protocol', Registry.REG_SZ, '', setIcon)
}
function setIcon (err) {
if (err) return log.error(err.message)
const iconKey = new Registry({
hive: Registry.HKCU,
key: `\\Software\\Classes\\${protocol}\\DefaultIcon`
})
iconKey.set('', Registry.REG_SZ, icon, setCommand)
}
function setCommand (err) {
if (err) return log.error(err.message)
const commandKey = new Registry({
hive: Registry.HKCU,
key: `\\Software\\Classes\\${protocol}\\shell\\open\\command`
})
commandKey.set('', Registry.REG_SZ, `${commandToArgs(command)} "%1"`, done)
}
function done (err) {
if (err) return log.error(err.message)
}
}
/**
* To add a file handler, the following keys must be added to the Windows registry:
*
* HKEY_CLASSES_ROOT
* $EXTENSION
* (Default) = "$EXTENSION_ID"
* $EXTENSION_ID
* (Default) = "$NAME"
* DefaultIcon
* (Default) = "$ICON"
* shell
* open
* command
* (Default) = "$COMMAND" "%1"
*/
function registerFileHandlerWin32 (ext, id, name, icon, command) {
setExt()
function setExt () {
const extKey = new Registry({
hive: Registry.HKCU, // HKEY_CURRENT_USER
key: `\\Software\\Classes\\${ext}`
})
extKey.set('', Registry.REG_SZ, id, setId)
}
function setId (err) {
if (err) return log.error(err.message)
const idKey = new Registry({
hive: Registry.HKCU,
key: `\\Software\\Classes\\${id}`
})
idKey.set('', Registry.REG_SZ, name, setIcon)
}
function setIcon (err) {
if (err) return log.error(err.message)
const iconKey = new Registry({
hive: Registry.HKCU,
key: `\\Software\\Classes\\${id}\\DefaultIcon`
})
iconKey.set('', Registry.REG_SZ, icon, setCommand)
}
function setCommand (err) {
if (err) return log.error(err.message)
const commandKey = new Registry({
hive: Registry.HKCU,
key: `\\Software\\Classes\\${id}\\shell\\open\\command`
})
commandKey.set('', Registry.REG_SZ, `${commandToArgs(command)} "%1"`, done)
}
function done (err) {
if (err) return log.error(err.message)
}
}
}
function uninstallWin32 () {
const Registry = require('winreg')
unregisterProtocolHandlerWin32('magnet', EXEC_COMMAND)
unregisterProtocolHandlerWin32('stream-magnet', EXEC_COMMAND)
unregisterFileHandlerWin32('.torrent', 'io.webtorrent.torrent', EXEC_COMMAND)
function unregisterProtocolHandlerWin32 (protocol, command) {
getCommand()
function getCommand () {
const commandKey = new Registry({
hive: Registry.HKCU, // HKEY_CURRENT_USER
key: `\\Software\\Classes\\${protocol}\\shell\\open\\command`
})
commandKey.get('', (err, item) => {
if (!err && item.value.indexOf(commandToArgs(command)) >= 0) {
destroyProtocol()
}
})
}
function destroyProtocol () {
const protocolKey = new Registry({
hive: Registry.HKCU,
key: `\\Software\\Classes\\${protocol}`
})
protocolKey.destroy(() => {})
}
}
function unregisterFileHandlerWin32 (ext, id, command) {
eraseId()
function eraseId () {
const idKey = new Registry({
hive: Registry.HKCU, // HKEY_CURRENT_USER
key: `\\Software\\Classes\\${id}`
})
idKey.destroy(getExt)
}
function getExt () {
const extKey = new Registry({
hive: Registry.HKCU,
key: `\\Software\\Classes\\${ext}`
})
extKey.get('', (err, item) => {
if (!err && item.value === id) {
destroyExt()
}
})
}
function destroyExt () {
const extKey = new Registry({
hive: Registry.HKCU, // HKEY_CURRENT_USER
key: `\\Software\\Classes\\${ext}`
})
extKey.destroy(() => {})
}
}
}
function commandToArgs (command) {
return command.map((arg) => `"${arg}"`).join(' ')
}
function installLinux () {
const fs = require('fs')
const os = require('os')
const path = require('path')
const config = require('../config')
const log = require('./log')
// Do not install in user dir if running on system
if (/^\/opt/.test(process.execPath)) return
installDesktopFile()
installIconFile()
function installDesktopFile () {
const templatePath = path.join(
config.STATIC_PATH, 'linux', 'webtorrent-desktop.desktop'
)
fs.readFile(templatePath, 'utf8', writeDesktopFile)
}
function writeDesktopFile (err, desktopFile) {
if (err) return log.error(err.message)
const appPath = config.IS_PRODUCTION
? path.dirname(process.execPath)
: config.ROOT_PATH
desktopFile = desktopFile
.replace(/\$APP_NAME/g, config.APP_NAME)
.replace(/\$APP_PATH/g, appPath)
.replace(/\$EXEC_PATH/g, EXEC_COMMAND.join(' '))
.replace(/\$TRY_EXEC_PATH/g, process.execPath)
const desktopFilePath = path.join(
os.homedir(),
'.local',
'share',
'applications',
'webtorrent-desktop.desktop'
)
fs.mkdirp(path.dirname(desktopFilePath))
fs.writeFile(desktopFilePath, desktopFile, err => {
if (err) return log.error(err.message)
})
}
function installIconFile () {
const iconStaticPath = path.join(config.STATIC_PATH, 'WebTorrent.png')
fs.readFile(iconStaticPath, writeIconFile)
}
function writeIconFile (err, iconFile) {
if (err) return log.error(err.message)
const mkdirp = require('mkdirp')
const iconFilePath = path.join(
os.homedir(),
'.local',
'share',
'icons',
'webtorrent-desktop.png'
)
mkdirp(path.dirname(iconFilePath), err => {
if (err) return log.error(err.message)
fs.writeFile(iconFilePath, iconFile, err => {
if (err) log.error(err.message)
})
})
}
}
function uninstallLinux () {
const os = require('os')
const path = require('path')
const rimraf = require('rimraf')
const desktopFilePath = path.join(
os.homedir(),
'.local',
'share',
'applications',
'webtorrent-desktop.desktop'
)
rimraf(desktopFilePath)
const iconFilePath = path.join(
os.homedir(),
'.local',
'share',
'icons',
'webtorrent-desktop.png'
)
rimraf(iconFilePath)
}