BetterDiscordApp-v2/client/src/modules/packageinstaller.js

121 lines
4.3 KiB
JavaScript
Raw Normal View History

2018-08-29 05:19:18 +02:00
import EventListener from './eventlistener';
import asar from 'asar';
import fs from 'fs';
import path from 'path';
2018-08-29 05:19:18 +02:00
import { Modals } from 'ui';
import { Utils } from 'common';
2018-08-29 22:02:41 +02:00
import PluginManager from './pluginmanager';
import Globals from './globals';
2018-08-30 06:05:14 +02:00
import Security from './security';
import { ReactComponents } from './reactcomponents';
import Reflection from './reflection';
import DiscordApi from './discordapi';
2018-08-29 05:19:18 +02:00
export default class PackageInstaller {
2018-08-29 05:19:18 +02:00
/**
* Handler for drag and drop package install
* @param {String} filePath Path to local file
* @param {String} channelId Current channel id
*/
static async dragAndDropHandler(filePath, channelId) {
2018-08-29 05:19:18 +02:00
try {
const config = JSON.parse(asar.extractFile(filePath, 'config.json').toString());
2018-08-29 05:19:18 +02:00
const { info, main } = config;
let icon = null;
if (info.icon && info.icon_type) {
const extractIcon = asar.extractFile(filePath, info.icon);
2018-08-29 05:19:18 +02:00
icon = `data:${info.icon_type};base64,${Utils.arrayBufferToBase64(extractIcon)}`;
}
2018-08-30 08:08:52 +02:00
const isPlugin = info.type && info.type === 'plugin' || main.endsWith('.js');
2018-08-29 05:19:18 +02:00
// Show install modal
const modalResult = await Modals.installModal(isPlugin ? 'plugin' : 'theme', config, filePath, icon).promise;
2018-08-29 05:19:18 +02:00
if (modalResult === 0) {
// Upload it instead
}
} catch (err) {
console.log(err);
}
2018-08-29 05:19:18 +02:00
}
2018-08-30 06:05:14 +02:00
/**
* Hash and verify a package
* @param {Byte[]|String} bytesOrPath byte array of binary or path to local file
2018-08-30 08:08:52 +02:00
* @param {String} id Package id
2018-08-30 06:05:14 +02:00
*/
2018-08-30 08:08:52 +02:00
static async verifyPackage(bytesOrPath, id) {
2018-08-30 06:05:14 +02:00
const bytes = typeof bytesOrPath === 'string' ? fs.readFileSync(bytesOrPath) : bytesOrPath;
// Temporary hash to simulate response from server
2018-08-30 08:08:52 +02:00
const tempVerified = ['2e3532ee366816adc37b0f478bfef35e03f96e7aeee9b115f5918ef6a4e94de8', '06a2eb4e37b926354ab80cd83207db67e544c932e9beddce545967a21f8db5aa'];
2018-08-30 06:05:14 +02:00
const hashBytes = Security.hash('sha256', bytes, 'hex');
2018-08-30 08:08:52 +02:00
return tempVerified.includes(hashBytes);
2018-08-30 06:05:14 +02:00
}
// TODO lots of stuff
/**
* Installs or updates defined package
* @param {Byte[]|String} bytesOrPath byte array of binary or path to local file
* @param {String} name Package name
* @param {Boolean} update Does an older version already exist
*/
2018-08-30 08:08:52 +02:00
static async installPackage(bytesOrPath, id, update = false) {
2018-08-30 17:30:49 +02:00
try {
const bytes = typeof bytesOrPath === 'string' ? fs.readFileSync(bytesOrPath) : bytesOrPath;
2018-08-30 06:05:14 +02:00
2018-08-30 17:30:49 +02:00
const outputName = `${id}.bd`;
const outputPath = path.join(Globals.getPath('plugins'), outputName);
fs.writeFileSync(outputPath, bytes);
2018-08-30 17:30:49 +02:00
let newContent = null;
if (!update) {
newContent = await PluginManager.preloadPackedContent(outputName);
} else {
newContent = await PluginManager.reloadContent(PluginManager.getPluginById(id));
}
return newContent;
2018-08-30 17:30:49 +02:00
} catch (err) {
throw err;
}
}
/**
* Patches Discord upload area for .bd files
*/
static async uploadAreaPatch() {
const { selector } = Reflection.resolve('uploadArea');
this.UploadArea = await ReactComponents.getComponent('UploadArea', { selector });
const reflect = Reflection.DOM(selector);
const stateNode = reflect.getComponentStateNode(this.UploadArea);
const callback = function (e) {
if (!e.dataTransfer.files.length || !e.dataTransfer.files[0].name.endsWith('.bd')) return;
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
stateNode.clearDragging();
PackageInstaller.dragAndDropHandler(e.dataTransfer.files[0].path, DiscordApi.currentChannel.id);
};
// Remove their handler, add ours, then read theirs to give ours priority to stop theirs when we get a .bd file.
reflect.element.removeEventListener('drop', stateNode.handleDrop);
reflect.element.addEventListener('drop', callback);
reflect.element.addEventListener('drop', stateNode.handleDrop);
this.unpatchUploadArea = function () {
reflect.element.removeEventListener('drop', callback);
};
}
2018-08-29 05:19:18 +02:00
}