Merged 1.0.8_branch into master
This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
# Changelog
|
||||
|
||||
## 1.0.8
|
||||
* \#8: Add tooltips to settings
|
||||
* \#36: Add ability to select Linux distribution type if OS is unsupported
|
||||
* \#37: Version check fails with incorrect message when VC runtime is missing
|
||||
* Added additional WinFsp uninstall strings
|
||||
|
||||
## 1.0.7
|
||||
* \#31: New installation displays 'Mount location is not set' on Windows
|
||||
* \#33: Add 'Microsoft Visual C++ Redistributable' as dependency installation on Windows
|
||||
|
||||
@@ -9,11 +9,10 @@ Repertory allows you to mount Sia and/or SiaPrime blockchain storage solutions v
|
||||
* SiaPrime >=1.4.0
|
||||
|
||||
## Downloads
|
||||
* **Repertory UI v1.0.7 Linux 64-bit** [<Primary\>](https://pixeldrain.com/u/thkU0RHP) [<Alternate\>](https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage)
|
||||
* **Repertory UI v1.0.8 Linux 64-bit** [<Primary\>](https://pixeldrain.com/u/a1H78Dc_) [<Alternate\>](https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage)
|
||||
* NOTE: Linux distributions require `fuse` and `libfuse` to be installed.
|
||||
* **Repertory UI v1.0.7 OS X 64-bit** [<Primary\>](https://pixeldrain.com/u/gBW5TSR0) [<Alternate\>](https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_mac.dmg)
|
||||
* **Repertory UI v1.0.7 Windows 64-bit** [<Primary\>](https://pixeldrain.com/u/AcsttDQ_) [<Alternate\>](https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_win.exe)
|
||||
* NOTE: Windows systems require [Microsoft Visual C++ Redistributable for Visual Studio 2015, 2017 and 2019](https://aka.ms/vs/16/release/vc_redist.x64.exe)
|
||||
* **Repertory UI v1.0.8 OS X 64-bit** [<Primary\>](https://pixeldrain.com/u/6NjT6uEl) [<Alternate\>](https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_mac.dmg)
|
||||
* **Repertory UI v1.0.8 Windows 64-bit** [<Primary\>](https://pixeldrain.com/u/u_pP3IAk) [<Alternate\>](https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_win.exe)
|
||||
|
||||
## Supported Platforms
|
||||
* OS X 64-bit
|
||||
|
||||
17
package.json
17
package.json
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "repertory-ui",
|
||||
"version": "1.0.7",
|
||||
"version": "1.0.8",
|
||||
"private": true,
|
||||
"author": "scott.e.graves@protonmail.com",
|
||||
"description": "GUI for Repertory - Repertory allows you to mount Sia and/or SiaPrime blockchain storage solutions via FUSE on Linux/OS X or via WinFSP on Windows.",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.19",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.9.0",
|
||||
"@fortawesome/fontawesome-svg-core": "^1.2.22",
|
||||
"@fortawesome/free-solid-svg-icons": "^5.10.2",
|
||||
"@fortawesome/react-fontawesome": "^0.1.4",
|
||||
"auto-launch": "^5.0.5",
|
||||
"axios": "^0.18.1",
|
||||
@@ -14,10 +14,10 @@
|
||||
"font-awesome": "^4.7.0",
|
||||
"node-schedule": "^1.3.2",
|
||||
"randomstring": "^1.1.5",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6",
|
||||
"react": "^16.9.0",
|
||||
"react-dom": "^16.9.0",
|
||||
"react-loader-spinner": "^2.3.0",
|
||||
"react-redux": "^7.1.0",
|
||||
"react-redux": "^7.1.1",
|
||||
"react-scripts": "2.1.8",
|
||||
"react-tooltip": "^3.10.0",
|
||||
"redux": "^4.0.4",
|
||||
@@ -28,7 +28,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"cross-env": "^5.2.0",
|
||||
"electron": "^4.2.8",
|
||||
"electron": "^4.2.9",
|
||||
"electron-builder": "^20.44.4",
|
||||
"extract-text-webpack-plugin": "^3.0.2",
|
||||
"typescript": "^3.5.3",
|
||||
@@ -40,7 +40,7 @@
|
||||
"test": "react-scripts test",
|
||||
"eject": "react-scripts eject",
|
||||
"electron-dev": "cross-env ELECTRON_START_URL=http://localhost:3000 electron .",
|
||||
"electron-dev-unix": "cross-env ELECTRON_START_URL=http://localhost:3000 electron $NODE_DEBUG_OPTION .",
|
||||
"electron-dev-unix": "cross-env ELECTRON_START_URL=http://localhost:3000 electron .",
|
||||
"pack": "npm run build && electron-builder --dir --x64",
|
||||
"dist": "npm run build && electron-builder --x64",
|
||||
"dist-all": "npm run build && electron-builder --x64 --win --linux --mac",
|
||||
@@ -69,6 +69,7 @@
|
||||
"build/**/*",
|
||||
"node_modules/**/*",
|
||||
"src/helpers.js",
|
||||
"src/renderer/**/*",
|
||||
"public/detect_linux.sh",
|
||||
"public/install_linux.sh"
|
||||
],
|
||||
|
||||
@@ -1,43 +1,48 @@
|
||||
// Modules to control application life and create native browser window
|
||||
|
||||
const {app, BrowserWindow, Tray, nativeImage, Menu, dialog} = require('electron');
|
||||
const {ipcMain} = require('electron');
|
||||
const {
|
||||
app,
|
||||
BrowserWindow,
|
||||
dialog,
|
||||
ipcMain,
|
||||
Menu,
|
||||
nativeImage,
|
||||
Tray
|
||||
} = require('electron');
|
||||
const AutoLaunch = require('auto-launch');
|
||||
const Constants = require('../src/constants');
|
||||
const fs = require('fs');
|
||||
const helpers = require('../src/helpers');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const url = require('url');
|
||||
require('electron-debug/index')();
|
||||
const os = require('os');
|
||||
const helpers = require('../src/helpers');
|
||||
const fs = require('fs');
|
||||
const unzip = require('unzipper');
|
||||
const AutoLaunch = require('auto-launch');
|
||||
|
||||
require.extensions['.sh'] = function (module, filename) {
|
||||
module.exports = fs.readFileSync(filename, 'utf8');
|
||||
};
|
||||
const detectScript = require('./detect_linux.sh');
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let trayContextMenu;
|
||||
let mainWindow;
|
||||
let mainWindowTray;
|
||||
let mountedData = {};
|
||||
let mountedLocations = [];
|
||||
let expectedUnmount = {};
|
||||
let launchHidden = false;
|
||||
let firstMountCheck = true;
|
||||
let manualMountDetection = {};
|
||||
const AppIPC = require('../src/renderer/ipc/AppIPC');
|
||||
const ConfigIPC = require('../src/renderer/ipc/ConfigIPC');
|
||||
const DaemonIPC = require('../src/renderer/ipc/DaemonIPC');
|
||||
const DependencyIPC = require('../src/renderer/ipc/DependencyIPC');
|
||||
const DownloadIPC = require('../src/renderer/ipc/DownloadIPC');
|
||||
const FilesystemIPC = require('../src/renderer/ipc/FilesystemIPC');
|
||||
const MountsIPC = require('../src/renderer/ipc/MountsIPC');
|
||||
const PlatformIPC = require('../src/renderer/ipc/PlatformIPC');
|
||||
const ReleaseIPC = require('../src/renderer/ipc/ReleaseIPC');
|
||||
const StateIPC = require('../src/renderer/ipc/StateIPC');
|
||||
const SystemIPC = require('../src/renderer/ipc/SystemIPC');
|
||||
const UpgradeIPC = require('../src/renderer/ipc/UpgradeIPC');
|
||||
|
||||
let isShutdown = false;
|
||||
let isQuiting = false;
|
||||
let isInstalling = false;
|
||||
let launchHidden = false;
|
||||
let mainWindow;
|
||||
let mainWindowTray;
|
||||
let trayContextMenu;
|
||||
|
||||
app.on('before-quit', function () {
|
||||
isQuiting = true;
|
||||
});
|
||||
|
||||
function closeApplication() {
|
||||
const closeApplication = () => {
|
||||
if (!isShutdown) {
|
||||
isShutdown = true;
|
||||
if (mainWindowTray) {
|
||||
@@ -45,50 +50,23 @@ function closeApplication() {
|
||||
}
|
||||
app.quit();
|
||||
}
|
||||
}
|
||||
|
||||
function setWindowVisibility(show) {
|
||||
if (show) {
|
||||
mainWindow.show();
|
||||
if (os.platform() === 'darwin') {
|
||||
app.dock.show();
|
||||
}
|
||||
|
||||
if (mainWindow.isMinimized()) {
|
||||
mainWindow.restore();
|
||||
}
|
||||
mainWindow.focus();
|
||||
} else {
|
||||
mainWindow.hide();
|
||||
if (os.platform() === 'darwin') {
|
||||
app.dock.hide();
|
||||
}
|
||||
}
|
||||
|
||||
if (trayContextMenu && mainWindowTray) {
|
||||
trayContextMenu.items[0].checked = show;
|
||||
mainWindowTray.setContextMenu(trayContextMenu)
|
||||
}
|
||||
}
|
||||
|
||||
const unmountAllDrives = () => {
|
||||
// Reset mount states
|
||||
for (const provider of Constants.PROVIDER_LIST) {
|
||||
clearManualMountDetection(provider);
|
||||
expectedUnmount[provider] = true;
|
||||
}
|
||||
|
||||
// Unmount all items
|
||||
for (const i in mountedLocations) {
|
||||
const data = mountedData[mountedLocations[i]];
|
||||
helpers.stopMountProcessSync(data.Version, data.Provider);
|
||||
}
|
||||
|
||||
mountedLocations = [];
|
||||
mountedData = {};
|
||||
};
|
||||
|
||||
function createWindow() {
|
||||
const configurePrimaryApp = () => {
|
||||
app.on('second-instance', () => {
|
||||
if (!isInstalling && mainWindow) {
|
||||
setWindowVisibility(true);
|
||||
}
|
||||
});
|
||||
|
||||
app.on('ready', createWindow);
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
closeApplication();
|
||||
});
|
||||
};
|
||||
|
||||
const createWindow = () => {
|
||||
loadUiSettings();
|
||||
|
||||
let extra = {};
|
||||
@@ -140,7 +118,7 @@ function createWindow() {
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null;
|
||||
|
||||
unmountAllDrives();
|
||||
MountsIPC.unmountAllDrives();
|
||||
});
|
||||
|
||||
const appPath = (os.platform() === 'win32') ? path.resolve(path.join(app.getAppPath(), '..\\..\\repertory-ui.exe')) :
|
||||
@@ -203,39 +181,10 @@ function createWindow() {
|
||||
});
|
||||
|
||||
mainWindow.loadURL(startUrl);
|
||||
}
|
||||
|
||||
let instanceLock = app.requestSingleInstanceLock();
|
||||
const configurePrimaryApp = () => {
|
||||
app.on('second-instance', () => {
|
||||
if (!isInstalling && mainWindow) {
|
||||
setWindowVisibility(true);
|
||||
}
|
||||
});
|
||||
|
||||
app.on('ready', createWindow);
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
closeApplication();
|
||||
});
|
||||
};
|
||||
if (!instanceLock) {
|
||||
setTimeout(() => {
|
||||
if ((instanceLock = app.requestSingleInstanceLock())) {
|
||||
configurePrimaryApp();
|
||||
} else {
|
||||
closeApplication();
|
||||
}
|
||||
}, 3000);
|
||||
} else {
|
||||
configurePrimaryApp();
|
||||
}
|
||||
|
||||
const clearManualMountDetection = (provider) => {
|
||||
if (manualMountDetection[provider]) {
|
||||
clearInterval(manualMountDetection[provider]);
|
||||
delete manualMountDetection[provider];
|
||||
}
|
||||
const getMainWindow = () => {
|
||||
return mainWindow;
|
||||
};
|
||||
|
||||
const loadUiSettings = () => {
|
||||
@@ -244,49 +193,61 @@ const loadUiSettings = () => {
|
||||
if (fs.statSync(settingFile).isFile()) {
|
||||
const settings = JSON.parse(fs.readFileSync(settingFile, 'utf8'));
|
||||
launchHidden = settings.launch_hidden;
|
||||
PlatformIPC.setPlatformOverride(settings.platform_override);
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
};
|
||||
|
||||
const monitorMount = (sender, provider, version, pid, location) => {
|
||||
manualMountDetection[provider] = setInterval(() => {
|
||||
helpers
|
||||
.detectRepertoryMounts(version)
|
||||
.then(result => {
|
||||
if (result[provider].PID !== pid) {
|
||||
if (result[provider].PID === -1) {
|
||||
clearManualMountDetection(provider);
|
||||
sender.send(Constants.IPC_Unmount_Drive_Reply, {
|
||||
data: {
|
||||
Expected: expectedUnmount[provider],
|
||||
Location: location,
|
||||
Provider: provider,
|
||||
Error: Error(provider + ' Unmounted').toString(),
|
||||
Success: false,
|
||||
}
|
||||
});
|
||||
} else {
|
||||
pid = result[provider].PID;
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e);
|
||||
});
|
||||
},6000);
|
||||
};
|
||||
|
||||
const saveUiSettings = () => {
|
||||
const settingFile = path.join(helpers.getDataDirectory(), 'ui.json');
|
||||
try {
|
||||
fs.writeFileSync(settingFile, JSON.stringify({
|
||||
launch_hidden: launchHidden,
|
||||
platform_override: PlatformIPC.getPlatformOverride(),
|
||||
}), 'utf-8');
|
||||
} catch (e) {
|
||||
}
|
||||
};
|
||||
|
||||
const setIsInstalling = installing => {
|
||||
isInstalling = installing;
|
||||
};
|
||||
|
||||
const setTrayImage = driveInUse => {
|
||||
let image;
|
||||
if (driveInUse) {
|
||||
image = nativeImage.createFromPath(path.join(__dirname, os.platform() === 'darwin' ? '../build/logo_both_mac.png' : '../build/logo_both.png'));
|
||||
} else {
|
||||
image = nativeImage.createFromPath(path.join(__dirname, os.platform() === 'darwin' ? '../build/logo_mac.png' : '../build/logo.png'));
|
||||
}
|
||||
mainWindowTray.setImage(image);
|
||||
};
|
||||
|
||||
const setWindowVisibility = show => {
|
||||
if (show) {
|
||||
mainWindow.show();
|
||||
if (os.platform() === 'darwin') {
|
||||
app.dock.show();
|
||||
}
|
||||
|
||||
if (mainWindow.isMinimized()) {
|
||||
mainWindow.restore();
|
||||
}
|
||||
mainWindow.focus();
|
||||
} else {
|
||||
mainWindow.hide();
|
||||
if (os.platform() === 'darwin') {
|
||||
app.dock.hide();
|
||||
}
|
||||
}
|
||||
|
||||
if (trayContextMenu && mainWindowTray) {
|
||||
trayContextMenu.items[0].checked = show;
|
||||
mainWindowTray.setContextMenu(trayContextMenu)
|
||||
}
|
||||
};
|
||||
|
||||
const standardIPCReply = (event, channel, data, error) => {
|
||||
if (mainWindow) {
|
||||
event.sender.send(channel, {
|
||||
@@ -299,677 +260,36 @@ const standardIPCReply = (event, channel, data, error) => {
|
||||
}
|
||||
};
|
||||
|
||||
ipcMain.on(Constants.IPC_Browse_Directory + '_sync', (event, data) => {
|
||||
dialog.showOpenDialog(mainWindow, {
|
||||
defaultPath: data.Location,
|
||||
properties: ['openDirectory'],
|
||||
title: data.Title,
|
||||
}, (filePaths) => {
|
||||
if (filePaths && (filePaths.length > 0)) {
|
||||
event.returnValue = filePaths[0];
|
||||
|
||||
|
||||
|
||||
app.on('before-quit', function () {
|
||||
isQuiting = true;
|
||||
});
|
||||
|
||||
let instanceLock = app.requestSingleInstanceLock();
|
||||
if (!instanceLock) {
|
||||
setTimeout(() => {
|
||||
if ((instanceLock = app.requestSingleInstanceLock())) {
|
||||
configurePrimaryApp();
|
||||
} else {
|
||||
event.returnValue = '';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Check_Daemon_Version, (event, data) => {
|
||||
helpers
|
||||
.checkDaemonVersion(data.Version, data.Provider)
|
||||
.then(code => {
|
||||
standardIPCReply(event, Constants.IPC_Check_Daemon_Version_Reply, {
|
||||
Valid: (code === 0),
|
||||
Code: code,
|
||||
});
|
||||
})
|
||||
.catch(e => {
|
||||
standardIPCReply(event, Constants.IPC_Check_Daemon_Version_Reply, {
|
||||
Valid: false,
|
||||
}, e);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Check_Daemon_Version + '_sync', (event, data) => {
|
||||
helpers
|
||||
.checkDaemonVersion(data.Version, data.Provider)
|
||||
.then(code => {
|
||||
event.returnValue = {
|
||||
data: {
|
||||
Success: true,
|
||||
Valid: (code === 0),
|
||||
Code: code,
|
||||
},
|
||||
};
|
||||
})
|
||||
.catch(e => {
|
||||
event.returnValue = {
|
||||
data: {
|
||||
Error: e.toString(),
|
||||
Success: false,
|
||||
Valid: false
|
||||
},
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Check_Dependency_Installed, (event, data) => {
|
||||
try {
|
||||
const exists = fs.lstatSync(data.File).isFile();
|
||||
standardIPCReply(event, Constants.IPC_Check_Dependency_Installed_Reply, {
|
||||
data: {
|
||||
Exists: exists,
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
standardIPCReply(event, Constants.IPC_Check_Dependency_Installed_Reply, {
|
||||
data : {
|
||||
Exists: false,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Check_Dependency_Installed + '_sync', (event, data) => {
|
||||
try {
|
||||
const ls = fs.lstatSync(data.File);
|
||||
event.returnValue = {
|
||||
data: {
|
||||
Exists: ls.isFile() || ls.isSymbolicLink(),
|
||||
},
|
||||
};
|
||||
} catch (e) {
|
||||
event.returnValue = {
|
||||
data: {
|
||||
Exists: false
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Check_Installed, (event, data) => {
|
||||
const destination = path.join(helpers.getDataDirectory(), data.Version);
|
||||
helpers
|
||||
.getMissingDependencies(data.Dependencies)
|
||||
.then((dependencies) => {
|
||||
let exists = false;
|
||||
try {
|
||||
exists = fs.existsSync(destination) && fs.lstatSync(destination).isDirectory();
|
||||
} catch (e) {
|
||||
}
|
||||
standardIPCReply(event, Constants.IPC_Check_Installed_Reply, {
|
||||
Dependencies: dependencies,
|
||||
Exists: exists,
|
||||
Version: data.Version,
|
||||
});
|
||||
}).catch(error => {
|
||||
standardIPCReply(event, Constants.IPC_Check_Installed_Reply, {
|
||||
Dependencies: [],
|
||||
Version: data.Version,
|
||||
}, error);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Check_Mount_Location + '_sync', (event, data) => {
|
||||
let response = {
|
||||
Success: true,
|
||||
Error: ''
|
||||
};
|
||||
|
||||
try {
|
||||
if (fs.existsSync(data.Location) && fs.statSync(data.Location).isDirectory()) {
|
||||
if (fs.readdirSync(data.Location).length !== 0) {
|
||||
response.Success = false;
|
||||
response.Error = 'Directory not empty: ' + data.Location;
|
||||
}
|
||||
} else {
|
||||
response.Success = false;
|
||||
response.Error = 'Directory not found: ' + data.Location;
|
||||
}
|
||||
} catch (e) {
|
||||
response.Success = false;
|
||||
response.Error = e.toString();
|
||||
}
|
||||
event.returnValue = response;
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Delete_File, (event, data) => {
|
||||
try {
|
||||
if (fs.existsSync(data.FilePath)) {
|
||||
fs.unlinkSync(data.FilePath);
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Delete_File + '_sync', (event, data) => {
|
||||
try {
|
||||
if (fs.existsSync(data.FilePath)) {
|
||||
fs.unlinkSync(data.FilePath);
|
||||
}
|
||||
event.returnValue = {
|
||||
data: true,
|
||||
};
|
||||
} catch (e) {
|
||||
event.returnValue = {
|
||||
data: false,
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Detect_Mounts, (event, data) => {
|
||||
let driveLetters = {};
|
||||
for (const provider of Constants.PROVIDER_LIST) {
|
||||
driveLetters[provider] = [];
|
||||
}
|
||||
|
||||
const grabDriveLetters = (locations) => {
|
||||
for (let i = 'c'.charCodeAt(0); i <= 'z'.charCodeAt(0); i++) {
|
||||
const drive = (String.fromCharCode(i) + ':').toUpperCase();
|
||||
let driveInUse;
|
||||
if (Object.keys(locations).length > 0) {
|
||||
for (const provider of Constants.PROVIDER_LIST) {
|
||||
driveInUse = locations[provider].startsWith(drive);
|
||||
if (driveInUse)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!driveInUse) {
|
||||
try {
|
||||
if (!fs.existsSync(drive)) {
|
||||
for (const provider of Constants.PROVIDER_LIST) {
|
||||
driveLetters[provider].push(drive);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(locations).length > 0) {
|
||||
for (const provider of Constants.PROVIDER_LIST) {
|
||||
if (locations[provider].length > 0) {
|
||||
if (!driveLetters[provider].find((driveLetter) => {
|
||||
return driveLetter === locations[provider];
|
||||
})) {
|
||||
driveLetters[provider].push(locations[provider]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const setImage = (locations) => {
|
||||
let driveInUse;
|
||||
if (Object.keys(locations).length > 0) {
|
||||
for (const provider of Constants.PROVIDER_LIST) {
|
||||
driveInUse = locations[provider].length > 0;
|
||||
if (driveInUse)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let image;
|
||||
if (driveInUse) {
|
||||
image = nativeImage.createFromPath(path.join(__dirname, os.platform() === 'darwin' ? '../build/logo_both_mac.png' : '../build/logo_both.png'));
|
||||
} else {
|
||||
image = nativeImage.createFromPath(path.join(__dirname, os.platform() === 'darwin' ? '../build/logo_mac.png' : '../build/logo.png'));
|
||||
}
|
||||
|
||||
mainWindowTray.setImage(image);
|
||||
};
|
||||
|
||||
helpers
|
||||
.detectRepertoryMounts(data.Version)
|
||||
.then((results) => {
|
||||
let storageData = {};
|
||||
let locations = {};
|
||||
for (const provider of Constants.PROVIDER_LIST) {
|
||||
storageData[provider] = results[provider] ? results[provider] : {
|
||||
Active: false,
|
||||
Location: '',
|
||||
PID: -1,
|
||||
};
|
||||
locations[provider] = storageData[provider].Location;
|
||||
|
||||
if (storageData[provider].PID !== -1) {
|
||||
expectedUnmount[provider] = false;
|
||||
if (firstMountCheck) {
|
||||
monitorMount(event.sender, provider, data.Version, storageData[provider].PID, storageData[provider].Location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (os.platform() === 'win32') {
|
||||
grabDriveLetters(locations);
|
||||
}
|
||||
|
||||
setImage(locations);
|
||||
if (firstMountCheck) {
|
||||
firstMountCheck = false;
|
||||
}
|
||||
standardIPCReply(event, Constants.IPC_Detect_Mounts_Reply, {
|
||||
DriveLetters: driveLetters,
|
||||
Locations: locations,
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
if (os.platform() === 'win32') {
|
||||
grabDriveLetters({});
|
||||
}
|
||||
setImage({});
|
||||
standardIPCReply(event, Constants.IPC_Detect_Mounts_Reply, {
|
||||
DriveLetters: driveLetters,
|
||||
}, error);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Download_File, (event, data) => {
|
||||
const destination = path.join(helpers.getDataDirectory(), data.Filename);
|
||||
helpers.downloadFile(data.URL, destination, (progress) => {
|
||||
standardIPCReply(event, Constants.IPC_Download_File_Progress, {
|
||||
Destination: destination,
|
||||
Progress: progress,
|
||||
URL: data.URL,
|
||||
});
|
||||
}, error => {
|
||||
standardIPCReply(event, Constants.IPC_Download_File_Complete, {
|
||||
Destination: destination,
|
||||
URL: data.URL,
|
||||
}, error);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Extract_Release, (event, data) => {
|
||||
const destination = path.join(helpers.getDataDirectory(), data.Version);
|
||||
helpers.mkDirByPathSync(destination);
|
||||
|
||||
const stream = fs.createReadStream(data.Source);
|
||||
stream
|
||||
.pipe(unzip.Extract({ path: destination }))
|
||||
.on('error', error => {
|
||||
try {
|
||||
helpers.removeDirectoryRecursively(destination);
|
||||
} catch (e) {
|
||||
}
|
||||
stream.close();
|
||||
standardIPCReply(event, Constants.IPC_Extract_Release_Complete, {
|
||||
Source: data.Source,
|
||||
}, error);
|
||||
})
|
||||
.on('finish', () => {
|
||||
stream.close();
|
||||
if (os.platform() !== 'win32') {
|
||||
helpers
|
||||
.executeAndWait("chmod +x \"" + path.join(destination, 'repertory') + "\"")
|
||||
.then(() => {
|
||||
standardIPCReply(event, Constants.IPC_Extract_Release_Complete, {
|
||||
Source: data.Source,
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
standardIPCReply(event, Constants.IPC_Extract_Release_Complete, {
|
||||
Source: data.Source,
|
||||
}, error);
|
||||
})
|
||||
} else {
|
||||
standardIPCReply(event, Constants.IPC_Extract_Release_Complete, {
|
||||
Source: data.Source,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Get_Config, (event, data) => {
|
||||
helpers
|
||||
.getConfig(data.Version, data.Provider)
|
||||
.then((data) => {
|
||||
if (data.Code === 0) {
|
||||
standardIPCReply(event, Constants.IPC_Get_Config_Reply, {
|
||||
Config: data.Data,
|
||||
});
|
||||
} else {
|
||||
standardIPCReply(event, Constants.IPC_Get_Config_Reply, {}, data.Code);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
standardIPCReply(event, Constants.IPC_Get_Config_Reply, {}, error);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Get_Config_Template, (event, data) => {
|
||||
helpers
|
||||
.getConfigTemplate(data.Version, data.Provider)
|
||||
.then((data) => {
|
||||
standardIPCReply(event, Constants.IPC_Get_Config_Template_Reply, {
|
||||
Template: data,
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
standardIPCReply(event, Constants.IPC_Get_Config_Template_Reply, {}, error);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Get_Platform, (event) => {
|
||||
const sendResponse = (appPlatform, platform) => {
|
||||
event.sender.send(Constants.IPC_Get_Platform_Reply, {
|
||||
AppPlatform: appPlatform,
|
||||
Platform: platform,
|
||||
});
|
||||
};
|
||||
|
||||
const platform = os.platform();
|
||||
if (platform === 'linux') {
|
||||
const scriptFile = path.join(os.tmpdir(), 'repertory_detect_linux.sh');
|
||||
fs.writeFileSync(scriptFile, detectScript);
|
||||
|
||||
helpers
|
||||
.executeScript(scriptFile)
|
||||
.then(data => {
|
||||
let appPlatform = data.replace(/(\r\n|\n|\r)/gm,"");
|
||||
if (appPlatform === 'unknown') {
|
||||
helpers
|
||||
.downloadFile(Constants.LINUX_DETECT_SCRIPT_URL, scriptFile, null, err => {
|
||||
if (err) {
|
||||
sendResponse(appPlatform, platform);
|
||||
} else {
|
||||
helpers
|
||||
.executeScript(scriptFile)
|
||||
.then(data => {
|
||||
appPlatform = data.replace(/(\r\n|\n|\r)/gm, "");
|
||||
sendResponse(appPlatform, platform);
|
||||
})
|
||||
.catch(() => {
|
||||
sendResponse(appPlatform, platform);
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
sendResponse(appPlatform, platform);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
sendResponse(platform, platform);
|
||||
});
|
||||
} else {
|
||||
sendResponse(platform, platform);
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Get_State, event => {
|
||||
helpers.mkDirByPathSync(helpers.getDataDirectory());
|
||||
const configFile = path.join(helpers.getDataDirectory(), 'settings.json');
|
||||
if (fs.existsSync(configFile)) {
|
||||
event.sender.send(Constants.IPC_Get_State_Reply, {
|
||||
data: JSON.parse(fs.readFileSync(configFile, 'utf8')),
|
||||
});
|
||||
} else {
|
||||
event.sender.send(Constants.IPC_Get_State_Reply, {
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Install_Dependency, (event, data) => {
|
||||
if (data.Source.toLowerCase().endsWith('.dmg')) {
|
||||
helpers
|
||||
.executeAsync('open', ['-a', 'Finder', '-W', data.Source])
|
||||
.then(() => {
|
||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||
Source: data.Source,
|
||||
URL: data.URL,
|
||||
});
|
||||
})
|
||||
.catch(error=> {
|
||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||
Source: data.Source,
|
||||
URL: data.URL,
|
||||
}, error);
|
||||
});
|
||||
} else {
|
||||
const execInstall = () => {
|
||||
helpers
|
||||
.executeAndWait(data.Source)
|
||||
.then(() => {
|
||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||
Source: data.Source,
|
||||
URL: data.URL,
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||
Source: data.Source,
|
||||
URL: data.URL,
|
||||
}, error);
|
||||
});
|
||||
};
|
||||
if (data.IsWinFSP) {
|
||||
helpers
|
||||
.performWindowsUninstall(["WinFsp 2019.3 B1", "WinFsp 2019.3 B2"])
|
||||
.then(uninstalled => {
|
||||
if (uninstalled) {
|
||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||
RebootRequired: true,
|
||||
Source: data.Source,
|
||||
URL: data.URL,
|
||||
});
|
||||
} else {
|
||||
execInstall();
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||
Source: data.Source,
|
||||
URL: data.URL,
|
||||
}, error);
|
||||
});
|
||||
} else {
|
||||
execInstall();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Install_Upgrade, (event, data) => {
|
||||
let allowSkipVerification = true;
|
||||
|
||||
unmountAllDrives();
|
||||
|
||||
let tempSig;
|
||||
let tempPub;
|
||||
const cleanupFiles = () => {
|
||||
try {
|
||||
if (tempSig) {
|
||||
fs.unlinkSync(tempSig);
|
||||
}
|
||||
if (tempPub) {
|
||||
fs.unlinkSync(tempPub);
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
};
|
||||
|
||||
const errorHandler = err => {
|
||||
cleanupFiles();
|
||||
standardIPCReply(event, Constants.IPC_Install_Upgrade_Reply, {
|
||||
AllowSkipVerification: allowSkipVerification,
|
||||
Source: data.Source,
|
||||
}, err);
|
||||
};
|
||||
|
||||
// TODO Enable verification in 1.0.4
|
||||
const hasSignature = false;//!data.SkipVerification && data.Signature && (data.Signature.length > 0);
|
||||
const hasHash = false;//!data.SkipVerification && data.Sha256 && (data.Sha256.length > 0);
|
||||
if (hasSignature) {
|
||||
try {
|
||||
const files = helpers.createSignatureFiles(data.Signature, Constants.DEV_PUBLIC_KEY);
|
||||
tempPub = files.PublicKeyFile;
|
||||
tempSig = files.SignatureFile;
|
||||
} catch (e) {
|
||||
errorHandler(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let command;
|
||||
let args;
|
||||
const platform = os.platform();
|
||||
if (platform === 'win32') {
|
||||
command = data.Source;
|
||||
} else if (platform === 'darwin') {
|
||||
command = 'open';
|
||||
args = ['-a', 'Finder', data.Source];
|
||||
} else if (platform === 'linux') {
|
||||
try {
|
||||
command = data.Source;
|
||||
fs.chmodSync(command, '750');
|
||||
} catch (e) {
|
||||
errorHandler(e);
|
||||
}
|
||||
} else {
|
||||
errorHandler(Error('Platform not supported: ' + os.platform()));
|
||||
}
|
||||
|
||||
if (command) {
|
||||
const executeInstall = () => {
|
||||
isInstalling = true;
|
||||
helpers
|
||||
.executeAsync(command, args)
|
||||
.then(() => {
|
||||
cleanupFiles();
|
||||
standardIPCReply(event, Constants.IPC_Install_Upgrade_Reply)
|
||||
})
|
||||
.catch(error => {
|
||||
isInstalling = false;
|
||||
errorHandler(error);
|
||||
});
|
||||
};
|
||||
|
||||
if (hasSignature) {
|
||||
helpers
|
||||
.verifySignature(data.Source, tempSig, tempPub)
|
||||
.then(() => {
|
||||
executeInstall();
|
||||
})
|
||||
.catch(() => {
|
||||
errorHandler(Error('Failed to verify installation package signature'));
|
||||
});
|
||||
} else if (hasHash) {
|
||||
helpers
|
||||
.verifyHash(data.Source, data.Sha256)
|
||||
.then(()=> {
|
||||
executeInstall();
|
||||
})
|
||||
.catch(() => {
|
||||
errorHandler(Error('Failed to verify installation package hash'));
|
||||
});
|
||||
} else {
|
||||
if (platform === 'darwin') {
|
||||
setTimeout(executeInstall, 3000);
|
||||
} else {
|
||||
executeInstall();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
errorHandler(Error('Unsupported upgrade: ' + data.Source));
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Mount_Drive, (event, data) => {
|
||||
expectedUnmount[data.Provider] = false;
|
||||
|
||||
if (mountedLocations.indexOf(data.Location) !== -1) {
|
||||
console.log(data.Provider + ' already mounted: ' + data.Location);
|
||||
} else {
|
||||
mountedLocations.push(data.Location);
|
||||
mountedData[data.Location] = {
|
||||
Version: data.Version,
|
||||
Provider: data.Provider,
|
||||
};
|
||||
const errorHandler = (pid, error) => {
|
||||
if (mountedLocations.indexOf(data.Location) !== -1) {
|
||||
mountedLocations.splice(mountedLocations.indexOf(data.Location), 1);
|
||||
delete mountedData[data.Location];
|
||||
}
|
||||
|
||||
standardIPCReply(event, Constants.IPC_Unmount_Drive_Reply, {
|
||||
Expected: expectedUnmount[data.Provider],
|
||||
Location: data.Location,
|
||||
Provider: data.Provider,
|
||||
}, error || Error(data.Provider + ' Unmounted'));
|
||||
};
|
||||
helpers
|
||||
.executeMount(data.Version, data.Provider, data.Location, data.NoConsoleSupported, (error, pid) => {
|
||||
errorHandler(pid, error);
|
||||
})
|
||||
.then(() => {
|
||||
standardIPCReply(event, Constants.IPC_Mount_Drive_Reply, {
|
||||
Provider: data.Provider,
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
errorHandler(-1, error);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Reboot_System, () => {
|
||||
if (os.platform() === 'win32') {
|
||||
helpers.executeAsync('shutdown.exe', ['/r', '/t', '30']);
|
||||
}
|
||||
closeApplication();
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Save_State, (event, data) => {
|
||||
helpers.mkDirByPathSync(helpers.getDataDirectory());
|
||||
const configFile = path.join(helpers.getDataDirectory(), 'settings.json');
|
||||
fs.writeFileSync(configFile, JSON.stringify(data.State), 'utf8');
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Set_Config_Values, (event, data) => {
|
||||
const setConfigValue = (i) => {
|
||||
if (i < data.Items.length) {
|
||||
helpers
|
||||
.setConfigValue(data.Items[i].Name, data.Items[i].Value, data.Provider, data.Version)
|
||||
.then(() => {
|
||||
setConfigValue(++i);
|
||||
})
|
||||
.catch(() => {
|
||||
setConfigValue(++i);
|
||||
});
|
||||
} else {
|
||||
standardIPCReply(event, Constants.IPC_Set_Config_Values_Reply, {});
|
||||
}
|
||||
};
|
||||
setConfigValue(0);
|
||||
});
|
||||
}, 3000);
|
||||
} else {
|
||||
configurePrimaryApp();
|
||||
}
|
||||
|
||||
ipcMain.on(Constants.IPC_Shutdown, () => {
|
||||
closeApplication();
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Show_Window, () => {
|
||||
setWindowVisibility(true);
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Show_Window + '_sync', event => {
|
||||
setWindowVisibility(true);
|
||||
event.returnValue = true;
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Unmount_All_Drives, (event, data) => {
|
||||
unmountAllDrives();
|
||||
standardIPCReply(event, Constants.IPC_Unmount_All_Drives_Reply);
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Unmount_Drive, (event, data) => {
|
||||
clearManualMountDetection(data.Provider);
|
||||
|
||||
expectedUnmount[data.Provider] = true;
|
||||
helpers
|
||||
.stopMountProcess(data.Version, data.Provider)
|
||||
.then(result => {
|
||||
console.log(result);
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e);
|
||||
});
|
||||
});
|
||||
AppIPC.addListeners(ipcMain, closeApplication, setWindowVisibility);
|
||||
ConfigIPC.addListeners(ipcMain, standardIPCReply);
|
||||
DaemonIPC.addListeners(ipcMain, standardIPCReply);
|
||||
DependencyIPC.addListeners(ipcMain, standardIPCReply);
|
||||
DownloadIPC.addListeners(ipcMain, standardIPCReply);
|
||||
FilesystemIPC.addListeners(ipcMain, getMainWindow, dialog);
|
||||
MountsIPC.addListeners(ipcMain, setTrayImage, standardIPCReply);
|
||||
PlatformIPC.addListeners(ipcMain, detectScript, saveUiSettings);
|
||||
ReleaseIPC.addListeners(ipcMain, standardIPCReply);
|
||||
StateIPC.addListeners(ipcMain);
|
||||
SystemIPC.addListeners(ipcMain, closeApplication);
|
||||
UpgradeIPC.addListeners(ipcMain, setIsInstalling, MountsIPC.unmountAllDrives, standardIPCReply);
|
||||
192
releases.json
192
releases.json
@@ -1,220 +1,220 @@
|
||||
{
|
||||
"Locations": {
|
||||
"arch": {
|
||||
"1.0.7": {
|
||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
||||
"1.0.8": {
|
||||
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||
"urls": [
|
||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
||||
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||
]
|
||||
}
|
||||
},
|
||||
"centos7": {
|
||||
"1.0.7": {
|
||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
||||
"1.0.8": {
|
||||
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||
"urls": [
|
||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
||||
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||
]
|
||||
}
|
||||
},
|
||||
"darwin": {
|
||||
"1.0.7": {
|
||||
"sha256": "e4f5cf9765224d4c25472310089e0996f59772573dc59c1baa065810a16c19ba",
|
||||
"sig": "A11yvEkveuPo2yyJaDhw9xt/+/xw7/4T3D2Kd/Px1LwCREio25gCr5BWPSIef5yALCS1nDHIzG8CIaDS+OHc4w87YAqIqVOcQaDi2E2t1El7B1noW8yXs+Ew/Ro3AwqN0lnJrtr8fZWVFKqxUTvxLLOJmh5jiud9vdrFzlaI2MNEvC0dY62T0hS1o4uij5/NIXHrZJuz43sa8WftL1RSD/z0lQELF43MaFYCfcDeyCZn2N/htyyvlOEi0bVbjZg1N2cyWAhKbAZu47t5Z5uyoV+VYcIPJT0IsGK2Vr/Js6ziSr3IqdpWl44ztXRLGp4Es17MMnjne30AbhOt+qIOPIcwyRQ7ENEu6MEgT3nA35y5fd1YK7Nz3IkJMxMe1XwyjLE82MgXg9tywb46zKeEJ9zzWk4No71Z6CPwo7kGEl7kzKLw61GYL+1AY+o2dmiDrO+l+DmTzHqGJ3GqBuCnG+5yKM+6klEKU+zmtuaQsPHamY5YLa302G59ecnH90+XIP9veB8jj0ipID8UoGZqJNZgUvkNN3CFoV3TMqA01M5VH7xqWTGPib+aoxCwFsaYiaKTbZBYjw9PQ/ECGXakfX3YpkR1YniNq+Y6UHpfnQNznqZBC+lrud67R2SmRN5JO6wIKiqaKwUT5B5k1ze3Ltdfb1i8bkhk1yNJZBmnr3MA4n5w7wvS/Fw4Uq1zkeUb+No4lP3nH1TcAwU+shesB44MUaLiTlnWUii1AGivEsTtqNp1YoSKVdX1c5GOia0F3iJBqyO1T++bgRpm433AkwaFLqvOr66CirCRtelhZaZtZPStBXATzSBlXEn1J2NbEA6rS185Twco4Cp92+otMFfACm59Ew94E0I8/NSXWEtGkaF7OadMdjS9WPf/5jHWoMnqA8dpYZZXXnZN3xU1eUaVxlu7bdoQxwjllkVMElLp30nOE7Gg2sHuV9xTZ5L2zaueDhZToiItZqce1mlG7zqN0fPlJ8SY0V5nGkm91L90rVi7/9YLKa3jE63Kkv6rMd/o1MAqaFIu1KOgcEbVzexIh1f3ikphIfgxT0PdEuhYa5OGhXwHI/7oaNT8I9XebFRVXCIRHoaYz+zxqCIDQVqDWnW62aTKBwdmGBAp0b9RsCNekCheR2SHfiJi2qAvMWbQR1c3MZpC9A5xAIJZ+FJpTqpagR5U09RIkMjfewpCrfXQYdIWXDJ7CDm2pYGxVn2IIrxvc5kpbsh7VpvNh8bA/TaHyxEKqRWFbua9JZcGP17jliBx3R2ZLt45BYET63Z7z6C8A/Js4bfEspXDd8KfF+rmu83crc1txaJx4WRpbVx8KTLlU/b9o+B5PaoV+BTt/CV3Jgf6uLLXKLB/EXU=",
|
||||
"1.0.8": {
|
||||
"sha256": "fa978eeb6f5456c1fcea902cafb039eeda6d13f93770150564a0253341cb3d63",
|
||||
"sig": "CfzV0Jl/Saq6Yqtwz21Qm5F7C/geGtmotifZrUcSFpGTaniYbtWtwJSap1tAep1EzL43l4wtxmpDM9EJ3qkquD6JMQjKK89twYotzMoWneZyyEB7obhpi/M3mfih8fYrPCgxaUkVm4DZ4DNbZn2GwjMmdCV698OnUfg2PKhVH4LnjqekqOEsU02B/cvlym2zPLLoEhjJoL8+s2ICIV3WBVDHpcF4ZF3lnI8HgfjjpvhQ+V8LQCk+LQTzIwwBDj6C1sH5V9om7ZUyZZEQk8ALcvo6EJHhhOoQ6extou5NIfBSkDir9IJW8hnTVykgYwoFXSUSAf7tvLn/fx+xpvp27hh+MQqA7KPhVyUD0I2qobm87KV9RBUuW0eqC/ijkcfacyhBnTEikSrHbew3cy69KtBTs4xaicIErQogJXcRfn0bQsVYxk1H3lRyoZnnaFliLwBw/8NQnrvjZqMiqlVXijZj6w0gWZjfrJ/s7UZ0K+yofVAyp3Qzf8JsdlUeCS+lqsv65ANWOBrUeF2Tz2neIWWISnVADmBMeacp/Xuz/bwuGLc4FnMWyhIBjBGwYLBTiaq0nk0oC6wn7a+LZoib8WtU9CAJ4v82k0e8YgiwBDPZPfU03wWWVJoRC2yUu89/6x8AQaClwNh364XWmF7bgbCyjThjC70iz2Feu0ORkj4D0vjClYnP1Kz5HOAvzCRlJTtwVnB9xrEBtV45ONaw6wRwVPkADLg/624FTHzwpi7BTTV2xCAn3kx2JvSH7n9ISySu8ZG6Z2pZ5IBs7+7jWQKmtbC8b6wB0VpYwoCcLjGIduaYtx2YKv0FvjMxOeMmrfu3X33Ab9KL/T4meu5LhqcW01JDP2MlzZ8UYebykd+0KI2mts+hGHNhCT3/d7fEh/ccmaJQ1sNl8VoKos1DlwUL+U8t7PVUNj6e4SXZK+Na9pPLI3pMPKvaoPZimbXRKShF+mYUGlLEcQLcjFTTmOnFSkIP39pa98K7mtTwy50dgcqroTm9rAoBGLcicjdlOi76XcSikYrYrBupx2LtAiWUuXrD0Zm9lQ/Lfwp3smUaC6aFNmnyxPmDJ1XscbQr3m/5oxfNopBNliZCvlGLUc/HGUpy0XcEZymPA77AZog4cHcjgAi9tsdnPHfxMmFTniThDD/SgVjTolzSu4Sm/RY2K2hCJ8qFeSuvbhmgPPWOBbNMOfsv9Nswa4Rd57uEqxxSrpAo1dzxdJPklrDsCxeexVz1/6xW3Qj+I12abMacCCa8oX+PLfpdT6hDqBSlzT3KbVz6ApWNRheM/z8kwpDCDHKGIKPZ5OjRm0SRn/SlogRCUHZ93TSOClIPRr37TDYDpvzeoSjAxnwQ2jTxuIs=",
|
||||
"urls": [
|
||||
"https://pixeldrain.com/api/file/gBW5TSR0",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_mac.dmg"
|
||||
"https://pixeldrain.com/api/file/6NjT6uEl",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_mac.dmg"
|
||||
]
|
||||
}
|
||||
},
|
||||
"debian9": {
|
||||
"1.0.7": {
|
||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
||||
"1.0.8": {
|
||||
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||
"urls": [
|
||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
||||
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||
]
|
||||
}
|
||||
},
|
||||
"debian10": {
|
||||
"1.0.7": {
|
||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
||||
"1.0.8": {
|
||||
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||
"urls": [
|
||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
||||
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||
]
|
||||
}
|
||||
},
|
||||
"fedora28": {
|
||||
"1.0.7": {
|
||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
||||
"1.0.8": {
|
||||
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||
"urls": [
|
||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
||||
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||
]
|
||||
}
|
||||
},
|
||||
"fedora29": {
|
||||
"1.0.7": {
|
||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
||||
"1.0.8": {
|
||||
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||
"urls": [
|
||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
||||
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||
]
|
||||
}
|
||||
},
|
||||
"fedora30": {
|
||||
"1.0.7": {
|
||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
||||
"1.0.8": {
|
||||
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||
"urls": [
|
||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
||||
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||
]
|
||||
}
|
||||
},
|
||||
"opensuse15": {
|
||||
"1.0.7": {
|
||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
||||
"1.0.8": {
|
||||
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||
"urls": [
|
||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
||||
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||
]
|
||||
}
|
||||
},
|
||||
"opensuse15.1": {
|
||||
"1.0.7": {
|
||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
||||
"1.0.8": {
|
||||
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||
"urls": [
|
||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
||||
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||
]
|
||||
}
|
||||
},
|
||||
"solus": {
|
||||
"1.0.7": {
|
||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
||||
"1.0.8": {
|
||||
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||
"urls": [
|
||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
||||
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||
]
|
||||
}
|
||||
},
|
||||
"tumbleweed": {
|
||||
"1.0.7": {
|
||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
||||
"1.0.8": {
|
||||
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||
"urls": [
|
||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
||||
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||
]
|
||||
}
|
||||
},
|
||||
"ubuntu18.04": {
|
||||
"1.0.7": {
|
||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
||||
"1.0.8": {
|
||||
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||
"urls": [
|
||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
||||
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||
]
|
||||
}
|
||||
},
|
||||
"ubuntu18.10": {
|
||||
"1.0.7": {
|
||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
||||
"1.0.8": {
|
||||
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||
"urls": [
|
||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
||||
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||
]
|
||||
}
|
||||
},
|
||||
"ubuntu19.04": {
|
||||
"1.0.7": {
|
||||
"sha256": "dac898185beb12bd6e0eaf0164f2cdcd517223981678ee18e8ec99983921ecbf",
|
||||
"sig": "A/jHXV4OFVc4jjczUlB+CzHZbmaCWIygzshHVS3wjpPYBuQjZRbqn0Lj7yIV7PBoaT3xBAykI0Nd6BAxFHdWwwt10d/Snz8jbW94U7LpQMYjhbmy/7FxlbVOcLJSGs1AeoZUIMsYZpyu74IFD0eHn7x37z5Sg62HBE03uggiwVdwKi5g5qfvgzpBkQnzlSAYRQFOb3wELjLu5GRupJQiKdYsUaSkh8xLeloxhsb3UD8VKB427lfyDG7Da+ZMUFROJN9e+1afkGshlJmLu+/6G+Wiyik7gnjVvNEIQyZOoUMfZNZfhO2oL+5YH1a5Sc7vXcPo1CqHxC9ZT9d5L2QLi/9isAk72FemdiRYhPcMHMJ52Zkp4s5WP/2HxCGunAMLx+qC+Zp4NIihkC99fGJcsJfJ4MX7W9ENdxtBA9al4E+Au2CftrxFWXuARhyCy3X6+b1JlQ1jeMWBqixEqthcsAHvWgVTJUOJKCcEJb4BzpQQt2iEIAqNg2nxIKcSeal86GSvz27Z7Cf7CaNXCxrc0CAJ8XeIm8ZzB17Fg/GnKfEDRzaxweL3yyMIrzpIZnGECc8xHBVa1cLpOpuL3s5DxsLRB4XvcNEQ9ywcyuK0ZiEDRHJMW7lWeKEHgvxhMZNTKFnBp72Fgla9Sb7r+ZGXkwJjSn2chwPkKyFr4HlQgMLU386C2fieL8aqaScbb9VpZnPC9gfXDE/ZaFnLug1ORQYwE45DFXoUSnLNVrFUAMne3ISDaXJ946dMQm/6lrAQm1PglS7WKk+1V+GYmrszx9YeHi+Mqz8Dmlww7PCOPbCYsDFHqeruxxcfisq7SoFoHEOzmlq1FNqT3h0hNatpGIKJ2/FM4tQnEuDIGb6gQZMUZrLrLiVYW4ZmeNBe/GoqOt6c8REbtbt4Hpo9UgueKhZtCZOppZZBXu6i59eJXOIgBtNqX+6Kg8R9iM8vhTNbpec5hC0Q9yyELdkoRZkbUDmKWObKZQSr6h82LlsDSggHFYKRtZ4mOqJNxR7U8T8XEr7xqSaC0jmCl9bbxNND1Ir1x6PREfOuSNABxCYHRvZBAqp3PI+T41OsN/2Gcbz5FKc1ShfRcEZKH6npg/mPeYB6KNtuTtgpTJefAAgEra6t3mrV84sjEPig0IfQhfp8VeZItB09OXV02aOOXHKOBU2VilXWF7+Lapjk51I6+BnWRulBkZg6k70YZP/6icOaR+Z60PS8kTqplELfsk4r41nsGlo7iQPHONd5jOa4vhRdmAws7Fan2o5x6wfCJyn1nljNTysLktSm9y8PzJFUVq/kscXac5Q7Rfl4F8JIqbVvmUT740/tJv1zTB4YLfgYJI5cnwVbFuTzTXeDOR/KPCk=",
|
||||
"1.0.8": {
|
||||
"sha256": "6bbbb94934d12aa125400a4565d645387515ed4eebd4e54e3e2319423966ec66",
|
||||
"sig": "AgRclnw5BALJpZFKkvqkXsu8nt5gzYU62xLrPwa5CEsQVjv55LnFiPjQp8pDHi7rH+r2fh+PludH59muiYvmG1WXc52CYZih0rH3I3+Zv169bq+HoooCOuzCOgDkuGlVT7KCc0lCV5UfaWu4tme7NOiOBecEdBAG6ppyq432PjjNPdupe/MGwT4IAYfHAsoR2lPH9nyNKtzTnbMGX1EXEUPOjnsFxyVKKbfer3QKUst7aF5xh30vSzDvq5OpXseA0sCKroWIndaDHW6dLnywnaUqOEW/IyuMNuksAw9LTMFovbULRrxhF4S9VTMZ1wp8X99JlM4MBtTcN2homtqP3Mr7MEmChQR4XyqwF9lrLcq8nbGK5ni6ZpV7AfMLqTB+K+jH5rdNY2H812TYjAJA14ntGBKTRJSgPn/mzKLbBVQtpAMMZ/G/280QKkDH1E6ULEJPdBxDGRDNvDCE7Goe5L4tG9VKn8ncFLPGJIttP3qJreRyx3lBVnSbp0Ya+IUs1YrXctbbUsiM7dubql2H+rLnhzsX33PgkpPcOyR01P1pymI8LLNBLotCDJjwCNIF+hOB+a34txJFiOWIX7Uw8U4h5HWO6XAZFy8/UNG5Miljv+Y6xFIVv1HQxeivKGNBWHlh/m2nvg9sSf2FEydk78zHoBaeB/XFZNgQmhfolQSnywyugPZMxxAmYqI64pvgrNpo+tLp5XFy0vmCvKJNEdrjkKfYNYks66+aBHsNd76jKocaFNu/nc24X5nqpTpBowJXLG7jAGeo7+yqj6V8mK5yNMhGT5HbcyhB+5DSkeTTHcVD+x2Hdimy0VNNXI6qjAaE3R5SlUnv5a/lt+t5HM248LwAbYSzk//Jjk1rR+AnNuBJ5HSxuVdLKqUIkwZ+k0EjFebATmHx+89ieliOv0VAuoMlFr06tjoIyvn2QojOICaB/gHdeOMM6NYoTEl3K4xPbM/Ve1n2ZdYq/PapM8IEJ33H9l3zVjb5oC5lW1B02qiD+qu4BK39RV2nYrCXZbr9Xs7F4M+YifeYVA7oMSa+qDJvNGBj5XGPnBidEDp+jWWIsRoykdjpt0vJA1PoX659UuW/cr1vB9wkI8IxgXEya8mOxEQ7QrPW5RKlha1oi1GVhdzM7tJPzehSyhe+y9zSyVELmhfcJRjC0sy39WYaaDQuCoVhz1gztR6innjUkKFBuEYRQYOsdraBitRkQC48gMPrKe/XmsvJM1o6Uo06GIq9Xiv/VEQrN7uKd7Xqy+nKkdKzy/BtkxsnXrUjc+tAuM89z33trkGYdRDdbAefYz7nVQ2HZ6SPEhT6LGhW8uBa1RU9bIryFBQHStbvbrGvdwDBZvt8z8qfyKUYzhQ=",
|
||||
"urls": [
|
||||
"https://pixeldrain.com/api/file/thkU0RHP",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_linux_x86_64.AppImage"
|
||||
"https://pixeldrain.com/api/file/a1H78Dc_",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_linux_x86_64.AppImage"
|
||||
]
|
||||
}
|
||||
},
|
||||
"win32": {
|
||||
"1.0.7": {
|
||||
"sha256": "fbf7611bca712413bd6e6900bcbd49bd3a1545b4d4e70afb2ee9bd59f74b8f97",
|
||||
"sig": "B3URP0wqwJcxuisX/qkoLg19Tm1tUu0rQbkBrCtpscaSa5PhUS/p+6ID/eApKMy91SWqCeqw0C071OvTVfTmWRoB/v+9Kkftqs9IISIMDBZgJEAcwf5h0CYqRp/cLyl5XfZLnZoMDR6x7cIVejBaDu1EWtWtACTxfDy3SvtbHkXTfo5ojKk5DScTSNAeDVSL1dY7BBsGuy5WDR0GYpB+519//V4uNCeLSxmHMekEQdyMmjpaO4iKDOkqccwYNSrw3LpL6TQ6YpTX8g2I1tD1ucTKob5Z44LANceL/PMjk7XYRCplufZBIiAnK6mBQFjFFMm4dDTSWqFQKn+pJboTE1E20Gvs/1MFwO1S30mwOIuYebZ4Xfa/D26rFjjxsA8a62Xrxw5YenKczRWs1iNRK+BZUUNw3pbm0KtEwvJZX/XhaVBBuHwT4CDTLIK0tvVsVF6cMNXLdgJEBmItkSw8LdDta81SwHVco0oMxwExqFbwhXqZf7hQBx4NaytBft0QeXNGF0T1B7GTi+D2qr9F5YcIALzYPh5b6RC8yTuTuVgIW+f3LSY8yPTvJaFS3idjTMbzebWAC2aR0BNW1dPyEEoLzsQEfBDbXqSN4m7j+Nt2l5HGfpy370uOaVeKhIFgASJTvhp6FJ0+3FdJfv5E6E0h6EXCXsGCXmh51kcz5kPpmeLXa3OaoF8G5277hICztyUfqskmgz6cu5udRglW57ZwVM8nWRYo9yO5oiLn9ygq4ALOhUfQhbaCpICsDO5nG1R3rAj0t4a2yzQg+CqN9GXzf0+xlbuO0wdg92s2Tgs1O2F5U8yPvgp7fJIil8/GYmmJHj9zqj+kWjFm+ZPdreXns5m+jr58/hepaVyu7KVV/I/o5Q2dse5Xf+jvt7B8u2TC+JWmitzBJkDGRM0Rml+3QIb2F1lKMfPSs34aI7HJHjrfvExAcFiXDVsFXudVZqayjKWreA4gsgZ07GUi1lZ6qX00K7trxWz0BmlZqtXGofrDUQGgsiZ5FoGW5tFSs9t7DqUnpQAZCiVfPki8bphbPMeRsPXBMXsHKTK6TzbU8nukq8urMJWURetWQP5N4/dSI5zrgByBVI7n1TQvdE2bzMQrJP/xTLWGZUCRXfi2J7FmW7fbUtcAStVC2TPWPuzEC9Lvb3ybg0wepgEbMn1kGfb7mohJ5jeLHqhGzY9mx9fO191cduH9zI+yV5wrnYqWd5wN9J4NY66ULxeGxt03rzjMd2hv2tRRVRsT+/4ACUZcIV8JwUZgK51s5DuUWUsl2e5DBPAND/RVpThXJVFyAtBo/vDqoY3lg/pc4RaQZ6gNMoFeHbXwD/yu6TDDTWq5u00ZwNCbR0PaBTwDabs=",
|
||||
"1.0.8": {
|
||||
"sha256": "1dcf2ca95ee9ce1893166e7966e4aaa465735d00476d99414c57d18e7232212f",
|
||||
"sig": "AzXf0WkuGx4lXoGPgxsj2LDCAHwotKnvZHBFZv1f2A77sNtJaDQAgS3b4Hjg0AiWCRL9HzjJNprBv5lEUwc7AeRLXuj+4AI6Z7PeRaVs2NBgEHlIqldPwjime8bE2NBrkKfdDDdiAzhm3AqxgRzwhZ4sxkb3vNDdKIj4WnH79LsVCEcBgtuWalNvt3Q0i5ppBvu6+Iy/gZuGa7z+Jv2WU+Ijm7WjkmmmTdpcvP1UQTBL2UkriYOxVMIfrjHM0b2ch6RGBKUxS2h26h0xmJ7SzFoZ6lHcHDIxi8fsi7DIO/QDpottJPVgZLRuufSTyXLCbehLRI3dd1IWhQns0OTU11MBAUTRczJTaZ8nrjMesKdwbWqDDGMWOHyl39EuGIaGm3Mbi4iQWI3gz4RmX9kIWf0OSaT73okPvfjWA2Onn8IOs57TDw5fIyKKFjMkxqAPy0O+WonjJ5bd4Q/8HUpVx9M9NoClbztMQUhom2hVPkPiD3jQ8I9YcrmD9phZYkMf5As1G6RBsITsbpRA0bu9426y6K+nNJLPAM0TrW33oOziYV2z5HD1/Z+TsUMcusAPTbatjPLyLZ9kWIUqybPga8iPZW9iqszei2ywKl3EgAP/rZx2fn3qko9PvdpsoV6VBp9FxT2mguoRnkIo3lPGYXssBlfVBz0treGyjDoqcOrtciVLJbal54FTPU5o+Acuffi0Ft2F4qW7d3VglhEeA2i4zzPH2l8R0CuStei8ePMhOpebtByTPrclkvlbcOCg5adF+3/zTH9H261+P/IyrPct1ucvVpa6FlpcKfErWttRmxc9QhqiepyPUonLkHgB4Ur/ft6PzlE/+wD6arA7avSKdZqzeSksFSdnX/41fD8gL5CHfsCdbeqPvPd97CliiMCeGjVngQ5qFbC1+5DHuDopvs0yWcmDAO+nFrcQt3K01VjDYT+5plb263Ba3HKHqkT9N2gH8yWK/DdfT4Y8WAABomcgPeRSg6lAtNFv5RtWbSq9Q4dLFuhGM55EtXPG15zYAZqePCcyWYieP0wNuszcSsVNDScU8gqilwtn1oKO0ISZSYZUbdzI3fDc6SbaJNLwYdT/AlELZy0fAKILmJJN8MUXvcC7we6zyPOqwEf1ESLOb84Zw3+gPtH+Ao9dWHKdHOlyNyRzPvTYrcqSn2Uf3iHOLeoazqEEJ5Bh7jbDgVBkB4XEwijb+BvFV3cBcLdSg1Id3zZF02jkpaN4SMbEmqPbUv393CKRNs47p6ffFKKS5oUEpF6GpZq/wtjmKkdMSIzGVurbHPIaZI8JfLrEu/GAxAMGM7G3O5AiKOf0AH0wexhP5Vh6iE3MLNMA7n8SEQL5i/YUIL6b0tDL/wc=",
|
||||
"urls": [
|
||||
"https://pixeldrain.com/api/file/AcsttDQ_",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.7_win.exe"
|
||||
"https://pixeldrain.com/api/file/u_pP3IAk",
|
||||
"https://bitbucket.org/blockstorage/repertory-ui/downloads/repertory-ui_1.0.8_win.exe"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"Versions": {
|
||||
"arch": [
|
||||
"1.0.7"
|
||||
"1.0.8"
|
||||
],
|
||||
"centos7": [
|
||||
"1.0.7"
|
||||
"1.0.8"
|
||||
],
|
||||
"darwin": [
|
||||
"1.0.7"
|
||||
"1.0.8"
|
||||
],
|
||||
"debian9": [
|
||||
"1.0.7"
|
||||
"1.0.8"
|
||||
],
|
||||
"debian10": [
|
||||
"1.0.7"
|
||||
"1.0.8"
|
||||
],
|
||||
"fedora28": [
|
||||
"1.0.7"
|
||||
"1.0.8"
|
||||
],
|
||||
"fedora29": [
|
||||
"1.0.7"
|
||||
"1.0.8"
|
||||
],
|
||||
"fedora30": [
|
||||
"1.0.7"
|
||||
"1.0.8"
|
||||
],
|
||||
"linux": [
|
||||
"unavailable"
|
||||
],
|
||||
"opensuse15": [
|
||||
"1.0.7"
|
||||
"1.0.8"
|
||||
],
|
||||
"opensuse15.1": [
|
||||
"1.0.7"
|
||||
"1.0.8"
|
||||
],
|
||||
"solus": [
|
||||
"1.0.7"
|
||||
"1.0.8"
|
||||
],
|
||||
"tumbleweed": [
|
||||
"1.0.7"
|
||||
"1.0.8"
|
||||
],
|
||||
"ubuntu18.04": [
|
||||
"1.0.7"
|
||||
"1.0.8"
|
||||
],
|
||||
"ubuntu18.10": [
|
||||
"1.0.7"
|
||||
"1.0.8"
|
||||
],
|
||||
"ubuntu19.04": [
|
||||
"1.0.7"
|
||||
"1.0.8"
|
||||
],
|
||||
"unknown": [
|
||||
"unavailable"
|
||||
],
|
||||
"win32": [
|
||||
"1.0.7"
|
||||
"1.0.8"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
31
src/App.js
31
src/App.js
@@ -7,6 +7,7 @@ import DependencyList from './components/DependencyList/DependencyList';
|
||||
import DownloadProgress from './components/DownloadProgress/DownloadProgress';
|
||||
import ErrorDetails from './components/ErrorDetails/ErrorDetails';
|
||||
import Grid from './components/UI/Grid/Grid';
|
||||
import InfoDetails from './components/InfoDetails/InfoDetails';
|
||||
import IPCContainer from './containers/IPCContainer/IPCContainer';
|
||||
import Loading from './components/UI/Loading/Loading';
|
||||
import Modal from './components/UI/Modal/Modal';
|
||||
@@ -14,7 +15,11 @@ import MountItems from './containers/MountItems/MountItems';
|
||||
import {notifyError} from './redux/actions/error_actions';
|
||||
import Reboot from './components/Reboot/Reboot';
|
||||
import ReleaseVersionDisplay from './components/ReleaseVersionDisplay/ReleaseVersionDisplay';
|
||||
import {saveState} from './redux/actions/common_actions';
|
||||
import {
|
||||
displaySelectAppPlatform,
|
||||
saveState
|
||||
} from './redux/actions/common_actions';
|
||||
import SelectAppPlatform from './containers/SelectAppPlatform/SelectAppPlatform';
|
||||
import Text from './components/UI/Text/Text';
|
||||
import UpgradeIcon from './components/UpgradeIcon/UpgradeIcon';
|
||||
import UpgradeUI from './components/UpgradeUI/UpgradeUI';
|
||||
@@ -30,13 +35,17 @@ class App extends IPCContainer {
|
||||
componentDidMount() {
|
||||
const detectUpgrades = () => {
|
||||
if (this.props.AppPlatform === 'unknown') {
|
||||
if (this.props.Platform === 'linux') {
|
||||
this.props.displaySelectAppPlatform(true);
|
||||
} else {
|
||||
this.props.notifyError('Operating system is not supported.', true);
|
||||
}
|
||||
} else {
|
||||
this.props.loadReleases();
|
||||
}
|
||||
};
|
||||
this.scheduledUpdateJob = Scheduler.scheduleJob('23 11 * * *', detectUpgrades);
|
||||
detectUpgrades();
|
||||
this.scheduledUpdateJob = Scheduler.scheduleJob('23 11 * * *', detectUpgrades);
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
@@ -113,15 +122,19 @@ class App extends IPCContainer {
|
||||
!this.props.DismissDependencies &&
|
||||
this.props.AllowMount;
|
||||
|
||||
const infoDisplay = this.createModalConditionally(this.props.DisplayInfo, <InfoDetails/>, true);
|
||||
const rebootDisplay = this.createModalConditionally(this.props.RebootRequired, <Reboot />);
|
||||
const configDisplay = this.createModalConditionally(showConfig, <Configuration version={selectedVersion} />);
|
||||
const dependencyDisplay = this.createModalConditionally(showDependencies, <DependencyList/>);
|
||||
const downloadDisplay = this.createModalConditionally(this.props.DownloadActive, <DownloadProgress/>);
|
||||
const errorDisplay = this.createModalConditionally(this.props.DisplayError, <ErrorDetails/>, true);
|
||||
const upgradeDisplay = this.createModalConditionally(showUpgrade, <UpgradeUI/>);
|
||||
const selectAppPlatformDisplay = this.createModalConditionally(this.props.DisplaySelectAppPlatform, <SelectAppPlatform/>);
|
||||
|
||||
let mainContent = [];
|
||||
if (this.props.AppReady) {
|
||||
if (this.props.DisplaySelectAppPlatform || !this.props.AppReady) {
|
||||
mainContent = <Loading/>
|
||||
} else {
|
||||
let key = 0;
|
||||
mainContent.push((
|
||||
<div key={'rvd_' + key++}
|
||||
@@ -140,18 +153,18 @@ class App extends IPCContainer {
|
||||
</div>
|
||||
));
|
||||
}
|
||||
} else {
|
||||
mainContent = <Loading/>
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={'App'}>
|
||||
{errorDisplay}
|
||||
{selectAppPlatformDisplay}
|
||||
{dependencyDisplay}
|
||||
{upgradeDisplay}
|
||||
{downloadDisplay}
|
||||
{configDisplay}
|
||||
{infoDisplay}
|
||||
{downloadDisplay}
|
||||
{rebootDisplay}
|
||||
{errorDisplay}
|
||||
<div className={'AppContainer'}>
|
||||
<div className={'AppHeader'}>
|
||||
<Box>
|
||||
@@ -193,12 +206,15 @@ const mapStateToProps = state => {
|
||||
DismissDependencies: state.install.DismissDependencies,
|
||||
DisplayConfiguration: state.mounts.DisplayConfiguration,
|
||||
DisplayError: state.error.DisplayError,
|
||||
DisplayInfo: state.error.DisplayInfo,
|
||||
DisplaySelectAppPlatform: state.common.DisplaySelectAppPlatform,
|
||||
DownloadActive: state.download.DownloadActive,
|
||||
InstallActive: state.install.InstallActive,
|
||||
InstalledVersion: state.relver.InstalledVersion,
|
||||
LocationsLookup: state.relver.LocationsLookup,
|
||||
MissingDependencies: state.install.MissingDependencies,
|
||||
MountsBusy: state.mounts.MountsBusy,
|
||||
Platform: state.common.Platform,
|
||||
ProviderState: state.mounts.ProviderState,
|
||||
RebootRequired: state.common.RebootRequired,
|
||||
Release: state.relver.Release,
|
||||
@@ -212,6 +228,7 @@ const mapStateToProps = state => {
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
displaySelectAppPlatform: display => dispatch(displaySelectAppPlatform(display)),
|
||||
loadReleases: ()=> dispatch(loadReleases()),
|
||||
notifyError: (msg, critical, callback) => dispatch(notifyError(msg, critical, callback)),
|
||||
saveState: () => dispatch(saveState()),
|
||||
|
||||
29
src/assets/settings.json
Normal file
29
src/assets/settings.json
Normal file
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"HostConfig": {
|
||||
"AgentString": "'User-Agent' used when communicating with Sia/SiaPrime's API.",
|
||||
"ApiPassword": "Password used when communicating with Sia/SiaPrime's API.\n\nThis is not the same as your wallet's password, so please do not enter it here. Sia/SiaPrime typically auto-generate this value. It is exclusively used for API authentication purposes.",
|
||||
"ApiPort": "API port used to connect to Sia/SiaPrime's daemon.",
|
||||
"HostNameOrIp": "IP address or host name of Sia/SiaPrime daemon.",
|
||||
"TimeoutMs": "Number of milliseconds to wait for Sia/SiaPrime API responses before timing out."
|
||||
},
|
||||
"Settings": {
|
||||
"ApiAuth": "Password used to communicate with Repertory's API. Auto-generated by default.",
|
||||
"ApiPort": "Repertory API port to use for JSON-RPC requests.",
|
||||
"ApiUser": "Username used to communicate with Repertory's API.",
|
||||
"ChunkDownloaderTimeoutSeconds": "Files that are not cached locally will download data in ChunkSize chunks when a read or write operation occurs. This timeout value specifies the amount of time chunks should continue downloading after the last file handle has been closed.",
|
||||
"ChunkSize": "This is the minimum data size (converted to KiB - value of 8 means 8KiB) used for downloads. This value cannot be less than 8 and should also be a multiple of 8.",
|
||||
"EnableChunkDownloaderTimeout": "This setting applies to full allocation downloads. When set to true, downloads will timeout after ChunkDownloaderTimeoutSeconds if the file has no more open handles. If set to false, the entire file will always download.",
|
||||
"EnableDriveEvents": "When set to true, additional logging for FUSE on UNIX or WinFSP on Windows will occur. It's best to leave this value set to 'false' unless troubleshooting an issue as enabling it may have an adverse affect on performance.",
|
||||
"EnableMaxCacheSize": "If set to true, files will begin to be removed from the local cache as soon as MaxCacheSizeBytes and MinimumRedundancy have been met. This does not mean further attempts to write will fail when MaxCacheSizeBytes is reached. Writes will continue as long as there is enough local drive space to accommodate the operation.\n\nIf set to false, files will begin to be removed from the local cache as soon as MinimumRedundancy has been met.\n\nIn both cases, files that do not have any open handles will be chosen by oldest modification date for removal.",
|
||||
"EventLevel": "Internally, events are fired during certain operations. This setting determines which events should be logged to repertory.log. Valid values are Error, Warn, Normal, Debug, and Verbose.",
|
||||
"EvictionDelaySeconds": "Number of seconds to wait after all file handles are closed before allowing file to be evicted from cache.",
|
||||
"EvictionDelayMinutes": "Number of minutes to wait after all file handles are closed before allowing file to be evicted from cache.",
|
||||
"MaxCacheSizeBytes": "This value specifies the maximum amount of local space to consume before files are removed from cache. EnableMaxCacheSize must also be set to true for this value to take affect.",
|
||||
"MinimumRedundancy": "Files are elected for removal once this value has been reached. Be aware that this value cannot be set to less than 1.5x.",
|
||||
"OnlineCheckRetrySeconds": "Number of seconds to wait for Sia/SiaPrime daemon to become available/connectable.",
|
||||
"OrphanedFileRetentionDays": "Repertory attempts to keep modifications between Sia-UI and the mounted location in sync as much as possible. In the event a file is removed from Sia-UI, it will be marked as orphaned in Repertory and moved into an 'orphaned' directory within Repertory's data directory. This setting specifies the number of days this file is retained before final deletion.",
|
||||
"PreferredDownloadType": "Repertory supports 3 download modes for reading files that are not cached locally: full file allocation, ring buffer mode and direct mode.\n\nFull file allocation mode pre-allocates the entire file prior to downloading. This mode is required for writes but also ensures the best performance when reading data.\n\nRing buffer mode utilizes a fixed size file buffer to enable a reasonable amount of seeking. This alleviates the need to fully allocate a file. By default, it is 512MiB. When the buffer is full, it attempts to maintain the ability to seek 50% ahead or behind the current read location without the need to re-download data from Sia/SiaPrime.\n\nDirect mode utilizes no disk space. All data is read directly from Sia/SiaPrime.\n\nPreferred download type modes are:\n\nFallback - If there isn't enough local space to allocate the full file, ring buffer mode is used. If there isn't enough local space to create the ring buffer's file, then direct mode is used.\nRingBuffer - Full file allocation is always bypassed; however, if there isn't enough space to create the ring buffer's file, then direct mode will be chosen.\nDirect - All files will be read directly from Sia/SiaPrime.",
|
||||
"ReadAheadCount": "This value specifies the number of read-ahead chunks to use when downloading a file. This is a per-open file setting and will result in the creation of an equal number of threads.",
|
||||
"RingBufferFileSize": "The size of the ring buffer file in MiB. Default is 512. Valid values are: 64, 128, 256, 512, 1024."
|
||||
}
|
||||
}
|
||||
@@ -34,3 +34,7 @@ input.ConfigurationItemInput {
|
||||
border-color: rgba(10, 10, 20, 0.9);
|
||||
color: var(--text_color);
|
||||
}
|
||||
|
||||
.ConfigurationInfo {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -1,7 +1,18 @@
|
||||
import React from 'react';
|
||||
import './ConfigurationItem.css';
|
||||
import settings from '../../assets/settings';
|
||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
||||
import {faInfoCircle} from '@fortawesome/free-solid-svg-icons';
|
||||
import {connect} from 'react-redux';
|
||||
import {notifyInfo} from '../../redux/actions/error_actions';
|
||||
|
||||
export default props => {
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
notifyInfo: (title, msg) => dispatch(notifyInfo(title, msg))
|
||||
}
|
||||
};
|
||||
|
||||
export default connect(null, mapDispatchToProps)(props => {
|
||||
const handleChanged = (e) => {
|
||||
const target = e.target;
|
||||
if (target.type === 'checkbox') {
|
||||
@@ -10,6 +21,18 @@ export default props => {
|
||||
props.changed(target);
|
||||
};
|
||||
|
||||
let infoDisplay;
|
||||
if (settings[props.grouping] && settings[props.grouping][props.label]) {
|
||||
const displayInfo = () => {
|
||||
const description = settings[props.grouping][props.label];
|
||||
props.notifyInfo(props.label, description);
|
||||
};
|
||||
|
||||
infoDisplay = <a href={void(0)}
|
||||
className={'ConfigurationInfo'}
|
||||
onClick={()=>{displayInfo(); return false;}}><FontAwesomeIcon icon={faInfoCircle}/></a>;
|
||||
}
|
||||
|
||||
let data;
|
||||
switch (props.template.type) {
|
||||
case "bool":
|
||||
@@ -96,11 +119,13 @@ export default props => {
|
||||
width='100%'>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td width='100%'>{props.label}</td>
|
||||
{infoDisplay ?
|
||||
<td width='100%'>{infoDisplay} {props.label}</td> :
|
||||
<td width='100%'>{props.label}</td>}
|
||||
<td>{data}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
});
|
||||
@@ -22,8 +22,7 @@ export default connect(mapStateToProps)(props => {
|
||||
</td>
|
||||
<td>
|
||||
{props.AllowDownload ?
|
||||
<a
|
||||
href={void(0)}
|
||||
<a href={void(0)}
|
||||
className={'DependencyLink'}
|
||||
onClick={()=>{props.onDownload(); return false;}}><u>Install</u></a> :
|
||||
'Installing...'}
|
||||
|
||||
11
src/components/InfoDetails/InfoDetails.css
Normal file
11
src/components/InfoDetails/InfoDetails.css
Normal file
@@ -0,0 +1,11 @@
|
||||
.InfoDetailsHeading {
|
||||
text-align: center;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.InfoDetailsContent {
|
||||
max-height: 60vh;
|
||||
min-width: 80vw;
|
||||
overflow-y: auto;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
30
src/components/InfoDetails/InfoDetails.js
Normal file
30
src/components/InfoDetails/InfoDetails.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import React from 'react';
|
||||
import {dismissInfo} from '../../redux/actions/error_actions';
|
||||
import {connect} from 'react-redux';
|
||||
import Box from '../UI/Box/Box';
|
||||
import Button from '../UI/Button/Button';
|
||||
import './InfoDetails.css';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
InfoMessage: state.error.InfoStack.length > 0 ? state.error.InfoStack[0] : '',
|
||||
};
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
dismissInfo: () => dispatch(dismissInfo()),
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(props => {
|
||||
return (
|
||||
<Box dxDark dxStyle={{padding: '8px'}}>
|
||||
<h1 className={'InfoDetailsHeading'}>{props.InfoMessage.title}</h1>
|
||||
<div className={'InfoDetailsContent'}>
|
||||
<p style={{textAlign: 'left', whiteSpace: 'pre-line'}}>{props.InfoMessage.message}</p>
|
||||
</div>
|
||||
<Button clicked={props.dismissInfo}>Dismiss</Button>
|
||||
</Box>
|
||||
);
|
||||
});
|
||||
@@ -36,6 +36,12 @@ exports.UI_RELEASES_URL = 'https://bitbucket.org/blockstorage/repertory-ui/raw/'
|
||||
|
||||
exports.LINUX_DETECT_SCRIPT_URL = 'https://bitbucket.org/blockstorage/repertory/raw/' + REPERTORY_BRANCH + '/detect_linux.sh';
|
||||
|
||||
exports.LINUX_SELECTABLE_PLATFORMS = [
|
||||
'ubuntu18.04',
|
||||
'ubuntu18.10',
|
||||
'ubuntu19.04'
|
||||
];
|
||||
|
||||
exports.DATA_LOCATIONS = {
|
||||
linux: '~/.local/repertory/ui',
|
||||
darwin: '~/Library/Application Support/repertory/ui',
|
||||
@@ -62,6 +68,7 @@ exports.RELEASE_TYPES = [
|
||||
exports.INSTALL_TYPES = {
|
||||
Dependency: 'dependency',
|
||||
Release: 'release',
|
||||
TestRelease: 'test_release',
|
||||
Upgrade: 'upgrade',
|
||||
};
|
||||
|
||||
@@ -120,8 +127,13 @@ exports.IPC_Show_Window = 'show_window';
|
||||
exports.IPC_Set_Config_Values = 'set_config_values';
|
||||
exports.IPC_Set_Config_Values_Reply = 'set_config_values_reply';
|
||||
|
||||
exports.IPC_Set_Linux_AppPlatform = 'IPC_Set_Linux_AppPlatform';
|
||||
|
||||
exports.IPC_Shutdown = 'shutdown';
|
||||
|
||||
exports.IPC_Test_Release = 'test_release';
|
||||
exports.IPC_Test_Release_Reply = 'test_release_reply';
|
||||
|
||||
exports.IPC_Unmount_All_Drives = 'unmount_all';
|
||||
exports.IPC_Unmount_All_Drives_Reply = 'unmount_all_reply';
|
||||
|
||||
|
||||
@@ -231,6 +231,7 @@ class Configuration extends IPCContainer {
|
||||
((this.state.ShowAdvanced && k.advanced) || !k.advanced) ?
|
||||
<ConfigurationItem advanced={k.advanced}
|
||||
changed={e=>this.handleItemChanged(e, i)}
|
||||
grouping={'Settings'}
|
||||
items={this.state.Template[k.label].items}
|
||||
key={i}
|
||||
label={k.label}
|
||||
@@ -251,6 +252,7 @@ class Configuration extends IPCContainer {
|
||||
((this.state.ShowAdvanced && k.advanced) || !k.advanced) ?
|
||||
<ConfigurationItem advanced={k.advanced}
|
||||
changed={e=>this.handleObjectItemChanged(e, key, i)}
|
||||
grouping={key}
|
||||
items={this.state.Template[key].template[k.label].items}
|
||||
key={i}
|
||||
label={k.label}
|
||||
|
||||
@@ -171,9 +171,13 @@ class MountItems extends IPCContainer {
|
||||
}
|
||||
} else {
|
||||
allowAction = false;
|
||||
if (this.props.Platform === 'win32') {
|
||||
this.props.notifyError('Failed to launch repertory. Please install Microsoft Visual C++ Redistributable for Visual Studio 2015, 2017 and 2019.');
|
||||
} else {
|
||||
this.displayRetryMount(provider, location, 'Version check failed: ' + result.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allowAction) {
|
||||
this.props.setMountsBusy(true);
|
||||
|
||||
18
src/containers/SelectAppPlatform/SelectAppPlatform.css
Normal file
18
src/containers/SelectAppPlatform/SelectAppPlatform.css
Normal file
@@ -0,0 +1,18 @@
|
||||
.SAPHeading {
|
||||
color: var(--text_color_error);
|
||||
text-align: center;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
.SAPContent {
|
||||
max-height: 60vh;
|
||||
width: 255px;
|
||||
overflow-y: auto;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.SAPActions {
|
||||
margin-top: 4px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
89
src/containers/SelectAppPlatform/SelectAppPlatform.js
Normal file
89
src/containers/SelectAppPlatform/SelectAppPlatform.js
Normal file
@@ -0,0 +1,89 @@
|
||||
import React from 'react';
|
||||
import './SelectAppPlatform.css';
|
||||
import axios from 'axios';
|
||||
import {connect} from 'react-redux';
|
||||
import * as Constants from '../../constants';
|
||||
import Box from '../../components/UI/Box/Box';
|
||||
import Button from '../../components/UI/Button/Button';
|
||||
import {
|
||||
downloadItem,
|
||||
setAllowDownload
|
||||
} from '../../redux/actions/download_actions';
|
||||
import DropDown from '../../components/UI/DropDown/DropDown';
|
||||
import IPCContainer from '../IPCContainer/IPCContainer';
|
||||
import {notifyError} from '../../redux/actions/error_actions';
|
||||
import {setInstallTestActive} from '../../redux/actions/install_actions';
|
||||
|
||||
class SelectAppPlatform extends IPCContainer {
|
||||
state = {
|
||||
Selected: 0,
|
||||
};
|
||||
|
||||
grabLatestRelease = appPlatform => {
|
||||
const errorHandler = error => {
|
||||
this.props.notifyError(error);
|
||||
this.props.setInstallTestActive(false);
|
||||
this.props.setAllowDownload(false);
|
||||
};
|
||||
axios
|
||||
.get(Constants.RELEASES_URL)
|
||||
.then(response => {
|
||||
try {
|
||||
const releases = response.data.Versions.Release[appPlatform];
|
||||
const latestVersion = releases[releases.length - 1];
|
||||
const release = response.data.Locations[appPlatform][latestVersion];
|
||||
this.props.downloadItem(latestVersion + '.zip', Constants.INSTALL_TYPES.TestRelease, release.urls, false, latestVersion, appPlatform);
|
||||
} catch (error) {
|
||||
errorHandler(error);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
errorHandler(error);
|
||||
});
|
||||
};
|
||||
|
||||
handleTestClicked = () => {
|
||||
this.props.setInstallTestActive(true);
|
||||
this.props.setAllowDownload(true);
|
||||
this.grabLatestRelease(Constants.LINUX_SELECTABLE_PLATFORMS[this.state.Selected])
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Box dxDark dxStyle={{padding: '8px'}}>
|
||||
<h1 className={'SAPHeading'}>Select Linux Platform</h1>
|
||||
<div className={'SAPContent'}>
|
||||
<p>Repertory was unable to detect your Linux distribution. Please select one of the following and click <b>Test</b> to continue:</p>
|
||||
</div>
|
||||
<div className={'SAPActions'}>
|
||||
<DropDown changed={e => this.setState({
|
||||
...this.state,
|
||||
Selected: e.target.value
|
||||
})}
|
||||
disabled={this.props.InstallTestActive}
|
||||
items={Constants.LINUX_SELECTABLE_PLATFORMS}
|
||||
selected={this.state.Selected}/>
|
||||
<Button clicked={this.handleTestClicked}
|
||||
disabled={this.props.InstallTestActive}>Test</Button>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
InstallTestActive: state.install.InstallTestActive,
|
||||
}
|
||||
};
|
||||
|
||||
const mapDispatchToProps = dispatch => {
|
||||
return {
|
||||
downloadItem: (name, type, urls, isWinFSP, testVersion, appPlatform) => dispatch(downloadItem(name, type, urls, isWinFSP, testVersion, appPlatform)),
|
||||
notifyError: msg => dispatch(notifyError(msg)),
|
||||
setAllowDownload: allow => dispatch(setAllowDownload(allow)),
|
||||
setInstallTestActive: active => dispatch(setInstallTestActive(active)),
|
||||
};
|
||||
};
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SelectAppPlatform);
|
||||
@@ -705,6 +705,23 @@ module.exports.stopMountProcessSync = (version, provider) => {
|
||||
process.unref();
|
||||
};
|
||||
|
||||
module.exports.testRepertoryBinary = version => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const command = path.join(_getDataDirectory(), version, (os.platform() === 'win32') ? 'repertory.exe' : 'repertory');
|
||||
_executeProcess(command, ['-dc'])
|
||||
.then(code => {
|
||||
if (code === 0) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(Error('Invalid exit code: ' + code));
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.verifyHash = (file, hash) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const platform = os.platform();
|
||||
|
||||
@@ -4,8 +4,17 @@ import {getIPCRenderer} from '../../utils';
|
||||
|
||||
const ipcRenderer = getIPCRenderer();
|
||||
|
||||
export const displaySelectAppPlatform = display => {
|
||||
return dispatch => {
|
||||
if (display) {
|
||||
dispatch(showWindow());
|
||||
}
|
||||
|
||||
dispatch(setDisplaySelectAppPlatform(display));
|
||||
};
|
||||
};
|
||||
|
||||
export const notifyRebootRequired = createAction('common/notifyRebootRequired');
|
||||
export const setAllowMount = createAction('common/setAllowMount');
|
||||
|
||||
export const rebootSystem = () => {
|
||||
return dispatch => {
|
||||
@@ -16,7 +25,19 @@ export const rebootSystem = () => {
|
||||
}
|
||||
};
|
||||
|
||||
export const setAllowMount = createAction('common/setAllowMount');
|
||||
export const setApplicationReady = createAction('common/setApplicationReady');
|
||||
|
||||
export const SET_DISPLAY_SELECT_APPPLATFORM = 'common/displaySelectAppPlatform';
|
||||
export const setDisplaySelectAppPlatform = display => {
|
||||
return {
|
||||
type: SET_DISPLAY_SELECT_APPPLATFORM,
|
||||
payload: display,
|
||||
};
|
||||
};
|
||||
|
||||
export const setLinuxAppPlatform = createAction('common/setLinuxAppPlatform');
|
||||
|
||||
export const setRebootRequired = () => {
|
||||
return dispatch => {
|
||||
dispatch(showWindow());
|
||||
|
||||
@@ -3,6 +3,7 @@ import {createAction} from 'redux-starter-kit';
|
||||
import {getIPCRenderer} from '../../utils';
|
||||
import {notifyError} from './error_actions';
|
||||
import {
|
||||
installAndTestRelease,
|
||||
installDependency,
|
||||
installRelease,
|
||||
installUpgrade
|
||||
@@ -25,7 +26,7 @@ export const setDownloadBegin = (name, type, url) => {
|
||||
export const setDownloadEnd = createAction('download/setDownloadEnd');
|
||||
export const setDownloadProgress = createAction('download/setDownloadProgress');
|
||||
|
||||
export const downloadItem = (name, type, urls, isWinFSP) => {
|
||||
export const downloadItem = (name, type, urls, isWinFSP, testVersion, appPlatform) => {
|
||||
return (dispatch, getState) => {
|
||||
if (!Array.isArray(urls)) {
|
||||
urls = [urls];
|
||||
@@ -40,6 +41,9 @@ export const downloadItem = (name, type, urls, isWinFSP) => {
|
||||
case Constants.INSTALL_TYPES.Release:
|
||||
dispatch(installRelease(result.Destination));
|
||||
break;
|
||||
case Constants.INSTALL_TYPES.TestRelease:
|
||||
dispatch(installAndTestRelease(result.Destination, testVersion, appPlatform));
|
||||
break;
|
||||
case Constants.INSTALL_TYPES.Upgrade:
|
||||
//const info = this.props.LocationsLookup[this.props.AppPlatform][this.props.VersionLookup[this.props.AppPlatform][0]];
|
||||
const sha256 = null;//info.sha256;
|
||||
@@ -51,6 +55,9 @@ export const downloadItem = (name, type, urls, isWinFSP) => {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
if (type === Constants.INSTALL_TYPES.TestRelease) {
|
||||
this.props.setAllowDownload(false);
|
||||
}
|
||||
dispatch(notifyError(result.Error));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -13,6 +13,14 @@ export const clearError = () => {
|
||||
};
|
||||
};
|
||||
|
||||
export const CLEAR_INFO = 'error/clearInfo';
|
||||
export const clearInfo = () => {
|
||||
return {
|
||||
type: CLEAR_INFO,
|
||||
payload: null,
|
||||
};
|
||||
};
|
||||
|
||||
export const dismissError = () => {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(clearError());
|
||||
@@ -27,6 +35,12 @@ export const dismissError = () => {
|
||||
};
|
||||
};
|
||||
|
||||
export const dismissInfo = () => {
|
||||
return dispatch => {
|
||||
dispatch(clearInfo());
|
||||
};
|
||||
};
|
||||
|
||||
export const notifyError = (msg, critical, callback) => {
|
||||
return dispatch => {
|
||||
ErrorActions = [callback, ...ErrorActions];
|
||||
@@ -36,6 +50,14 @@ export const notifyError = (msg, critical, callback) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const notifyInfo = (title, msg) => {
|
||||
return dispatch => {
|
||||
title = title ? title.toString() : 'Information';
|
||||
msg = msg ? msg.toString() : '';
|
||||
dispatch(setInfo(title, msg));
|
||||
};
|
||||
};
|
||||
|
||||
export const SET_ERROR_INFO = 'error/setErrorInfo';
|
||||
export const setErrorInfo = (msg, critical) => {
|
||||
return {
|
||||
@@ -46,3 +68,15 @@ export const setErrorInfo = (msg, critical) => {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
export const SET_INFO = 'error/setInfo';
|
||||
export const setInfo = (title, msg) => {
|
||||
return {
|
||||
type: SET_INFO,
|
||||
payload: {
|
||||
title,
|
||||
msg
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -7,13 +7,16 @@ import {
|
||||
import {notifyError} from './error_actions';
|
||||
import {setAllowDownload} from './download_actions';
|
||||
import {
|
||||
loadReleases,
|
||||
setActiveRelease,
|
||||
setInstalledVersion,
|
||||
setReleaseUpgradeAvailable
|
||||
} from './release_version_actions';
|
||||
import {
|
||||
displaySelectAppPlatform,
|
||||
setAllowMount,
|
||||
setApplicationReady,
|
||||
setLinuxAppPlatform,
|
||||
setRebootRequired,
|
||||
showWindow,
|
||||
shutdownApplication
|
||||
@@ -134,6 +137,43 @@ export const installDependency = (source, url, isWinFSP) => {
|
||||
};
|
||||
};
|
||||
|
||||
export const installAndTestRelease = (source, version, appPlatform) => {
|
||||
return (dispatch, getState) => {
|
||||
if (ipcRenderer && getState().install.InstallTestActive) {
|
||||
const extractReleaseComplete = (event, arg) => {
|
||||
ipcRenderer.send(Constants.IPC_Delete_File, {
|
||||
FilePath: source,
|
||||
});
|
||||
|
||||
ipcRenderer.once(Constants.IPC_Test_Release_Reply, (event, arg) => {
|
||||
if (arg.data.Success) {
|
||||
ipcRenderer.sendSync(Constants.IPC_Set_Linux_AppPlatform, {
|
||||
AppPlatform: appPlatform,
|
||||
});
|
||||
dispatch(setLinuxAppPlatform(appPlatform));
|
||||
dispatch(setInstallTestActive(false));
|
||||
dispatch(displaySelectAppPlatform(false));
|
||||
dispatch(setAllowDownload(false));
|
||||
dispatch(loadReleases());
|
||||
} else {
|
||||
dispatch(notifyError(arg.data.Error));
|
||||
dispatch(setInstallTestActive(false));
|
||||
}
|
||||
});
|
||||
ipcRenderer.send(Constants.IPC_Test_Release, {
|
||||
Version: version,
|
||||
})
|
||||
};
|
||||
|
||||
ipcRenderer.once(Constants.IPC_Extract_Release_Complete, extractReleaseComplete);
|
||||
ipcRenderer.send(Constants.IPC_Extract_Release, {
|
||||
Source: source,
|
||||
Version: version,
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
export const installRelease = source => {
|
||||
return (dispatch, getState) => {
|
||||
if (ipcRenderer && !getState().install.InstallActive) {
|
||||
@@ -193,5 +233,6 @@ export const installUpgrade = (source, sha256, signature, skipVerification) => {
|
||||
|
||||
export const setDismissDependencies = createAction('install/setDismissDependencies');
|
||||
export const setInstallActive = createAction('install/setInstallActive');
|
||||
export const setInstallTestActive = createAction('install/setInstallTestActive');
|
||||
export const setInstallComplete = createAction('install/setInstallComplete');
|
||||
export const setMissingDependencies = createAction('install/setMissingDependencies');
|
||||
|
||||
@@ -3,6 +3,8 @@ import {
|
||||
notifyRebootRequired,
|
||||
setAllowMount,
|
||||
setApplicationReady,
|
||||
setLinuxAppPlatform,
|
||||
SET_DISPLAY_SELECT_APPPLATFORM
|
||||
} from '../actions/common_actions';
|
||||
|
||||
export const createCommonReducer = (platform, appPlatform, version) => {
|
||||
@@ -10,10 +12,17 @@ export const createCommonReducer = (platform, appPlatform, version) => {
|
||||
AllowMount: false,
|
||||
AppPlatform: appPlatform,
|
||||
AppReady: false,
|
||||
DisplaySelectAppPlatform: false,
|
||||
Platform: platform,
|
||||
RebootRequired: false,
|
||||
Version: version,
|
||||
}, {
|
||||
[SET_DISPLAY_SELECT_APPPLATFORM]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
DisplaySelectAppPlatform: action.payload,
|
||||
}
|
||||
},
|
||||
[setAllowMount]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
@@ -26,6 +35,12 @@ export const createCommonReducer = (platform, appPlatform, version) => {
|
||||
AppReady: action.payload,
|
||||
};
|
||||
},
|
||||
[setLinuxAppPlatform]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
AppPlatform: action.payload,
|
||||
}
|
||||
},
|
||||
[notifyRebootRequired]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
import {createReducer} from 'redux-starter-kit';
|
||||
import {
|
||||
CLEAR_ERROR,
|
||||
SET_ERROR_INFO
|
||||
CLEAR_INFO,
|
||||
SET_ERROR_INFO,
|
||||
SET_INFO
|
||||
} from '../actions/error_actions';
|
||||
|
||||
export const errorReducer = createReducer({
|
||||
DisplayError: false,
|
||||
DisplayInfo: false,
|
||||
ErrorCritical: false,
|
||||
ErrorStack: [],
|
||||
InfoStack: [],
|
||||
}, {
|
||||
[CLEAR_ERROR]: state => {
|
||||
const errorStack = (state.ErrorStack.length > 0) ? state.ErrorStack.slice(1) : [];
|
||||
@@ -17,6 +21,14 @@ export const errorReducer = createReducer({
|
||||
ErrorStack: errorStack,
|
||||
}
|
||||
},
|
||||
[CLEAR_INFO]: state => {
|
||||
const infoStack = (state.InfoStack.length > 0) ? state.InfoStack.slice(1) : [];
|
||||
return {
|
||||
...state,
|
||||
DisplayInfo: (infoStack.length > 0),
|
||||
InfoStack: infoStack,
|
||||
}
|
||||
},
|
||||
[SET_ERROR_INFO]: (state, action) => {
|
||||
const errorStack = [action.payload.msg, ...state.ErrorStack];
|
||||
return {
|
||||
@@ -25,5 +37,16 @@ export const errorReducer = createReducer({
|
||||
ErrorCritical: state.ErrorCritical || action.payload.critical,
|
||||
ErrorStack: errorStack,
|
||||
}
|
||||
},
|
||||
[SET_INFO]: (state, action) => {
|
||||
const infoStack = [{
|
||||
title: action.payload.title,
|
||||
message: action.payload.msg
|
||||
}, ...state.InfoStack];
|
||||
return {
|
||||
...state,
|
||||
DisplayInfo: true,
|
||||
InfoStack: infoStack,
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
setDismissDependencies,
|
||||
setInstallActive,
|
||||
setInstallComplete,
|
||||
setInstallTestActive,
|
||||
setMissingDependencies
|
||||
} from '../actions/install_actions';
|
||||
|
||||
@@ -10,6 +11,7 @@ export const installReducer = createReducer({
|
||||
DismissDependencies: false,
|
||||
InstallActive: false,
|
||||
InstallResult: null,
|
||||
InstallTestActive: false,
|
||||
InstallType: null,
|
||||
MissingDependencies: [],
|
||||
}, {
|
||||
@@ -35,6 +37,12 @@ export const installReducer = createReducer({
|
||||
InstallType: null,
|
||||
}
|
||||
},
|
||||
[setInstallTestActive]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
InstallTestActive: action.payload,
|
||||
}
|
||||
},
|
||||
[setMissingDependencies]: (state, action) => {
|
||||
return {
|
||||
...state,
|
||||
|
||||
20
src/renderer/ipc/AppIPC.js
Normal file
20
src/renderer/ipc/AppIPC.js
Normal file
@@ -0,0 +1,20 @@
|
||||
const Constants = require('../../constants');
|
||||
|
||||
const addListeners = (ipcMain, closeApplication, setWindowVisibility) => {
|
||||
ipcMain.on(Constants.IPC_Shutdown, () => {
|
||||
closeApplication();
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Show_Window, () => {
|
||||
setWindowVisibility(true);
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Show_Window + '_sync', event => {
|
||||
setWindowVisibility(true);
|
||||
event.returnValue = true;
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addListeners
|
||||
};
|
||||
56
src/renderer/ipc/ConfigIPC.js
Normal file
56
src/renderer/ipc/ConfigIPC.js
Normal file
@@ -0,0 +1,56 @@
|
||||
const Constants = require('../../constants');
|
||||
const helpers = require('../../helpers');
|
||||
|
||||
const addListeners = (ipcMain, standardIPCReply) => {
|
||||
ipcMain.on(Constants.IPC_Get_Config, (event, data) => {
|
||||
helpers
|
||||
.getConfig(data.Version, data.Provider)
|
||||
.then((data) => {
|
||||
if (data.Code === 0) {
|
||||
standardIPCReply(event, Constants.IPC_Get_Config_Reply, {
|
||||
Config: data.Data,
|
||||
});
|
||||
} else {
|
||||
standardIPCReply(event, Constants.IPC_Get_Config_Reply, {}, data.Code);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
standardIPCReply(event, Constants.IPC_Get_Config_Reply, {}, error);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Get_Config_Template, (event, data) => {
|
||||
helpers
|
||||
.getConfigTemplate(data.Version, data.Provider)
|
||||
.then((data) => {
|
||||
standardIPCReply(event, Constants.IPC_Get_Config_Template_Reply, {
|
||||
Template: data,
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
standardIPCReply(event, Constants.IPC_Get_Config_Template_Reply, {}, error);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Set_Config_Values, (event, data) => {
|
||||
const setConfigValue = (i) => {
|
||||
if (i < data.Items.length) {
|
||||
helpers
|
||||
.setConfigValue(data.Items[i].Name, data.Items[i].Value, data.Provider, data.Version)
|
||||
.then(() => {
|
||||
setConfigValue(++i);
|
||||
})
|
||||
.catch(() => {
|
||||
setConfigValue(++i);
|
||||
});
|
||||
} else {
|
||||
standardIPCReply(event, Constants.IPC_Set_Config_Values_Reply, {});
|
||||
}
|
||||
};
|
||||
setConfigValue(0);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addListeners
|
||||
};
|
||||
47
src/renderer/ipc/DaemonIPC.js
Normal file
47
src/renderer/ipc/DaemonIPC.js
Normal file
@@ -0,0 +1,47 @@
|
||||
const Constants = require('../../constants');
|
||||
const helpers = require('../../helpers');
|
||||
|
||||
const addListeners = (ipcMain, standardIPCReply) => {
|
||||
ipcMain.on(Constants.IPC_Check_Daemon_Version, (event, data) => {
|
||||
helpers
|
||||
.checkDaemonVersion(data.Version, data.Provider)
|
||||
.then(code => {
|
||||
standardIPCReply(event, Constants.IPC_Check_Daemon_Version_Reply, {
|
||||
Valid: (code === 0),
|
||||
Code: code,
|
||||
});
|
||||
})
|
||||
.catch(e => {
|
||||
standardIPCReply(event, Constants.IPC_Check_Daemon_Version_Reply, {
|
||||
Valid: false,
|
||||
}, e);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Check_Daemon_Version + '_sync', (event, data) => {
|
||||
helpers
|
||||
.checkDaemonVersion(data.Version, data.Provider)
|
||||
.then(code => {
|
||||
event.returnValue = {
|
||||
data: {
|
||||
Success: true,
|
||||
Valid: (code === 0),
|
||||
Code: code,
|
||||
},
|
||||
};
|
||||
})
|
||||
.catch(e => {
|
||||
event.returnValue = {
|
||||
data: {
|
||||
Error: e.toString(),
|
||||
Success: false,
|
||||
Valid: false
|
||||
},
|
||||
};
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addListeners
|
||||
};
|
||||
102
src/renderer/ipc/DependencyIPC.js
Normal file
102
src/renderer/ipc/DependencyIPC.js
Normal file
@@ -0,0 +1,102 @@
|
||||
const Constants = require('../../constants');
|
||||
const fs = require('fs');
|
||||
const helpers = require('../../helpers');
|
||||
|
||||
const addListeners = (ipcMain, standardIPCReply) => {
|
||||
ipcMain.on(Constants.IPC_Check_Dependency_Installed, (event, data) => {
|
||||
try {
|
||||
const exists = fs.lstatSync(data.File).isFile();
|
||||
standardIPCReply(event, Constants.IPC_Check_Dependency_Installed_Reply, {
|
||||
data: {
|
||||
Exists: exists,
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
standardIPCReply(event, Constants.IPC_Check_Dependency_Installed_Reply, {
|
||||
data : {
|
||||
Exists: false,
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Check_Dependency_Installed + '_sync', (event, data) => {
|
||||
try {
|
||||
const ls = fs.lstatSync(data.File);
|
||||
event.returnValue = {
|
||||
data: {
|
||||
Exists: ls.isFile() || ls.isSymbolicLink(),
|
||||
},
|
||||
};
|
||||
} catch (e) {
|
||||
event.returnValue = {
|
||||
data: {
|
||||
Exists: false
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Install_Dependency, (event, data) => {
|
||||
if (data.Source.toLowerCase().endsWith('.dmg')) {
|
||||
helpers
|
||||
.executeAsync('open', ['-a', 'Finder', '-W', data.Source])
|
||||
.then(() => {
|
||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||
Source: data.Source,
|
||||
URL: data.URL,
|
||||
});
|
||||
})
|
||||
.catch(error=> {
|
||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||
Source: data.Source,
|
||||
URL: data.URL,
|
||||
}, error);
|
||||
});
|
||||
} else {
|
||||
const execInstall = () => {
|
||||
helpers
|
||||
.executeAndWait(data.Source)
|
||||
.then(() => {
|
||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||
Source: data.Source,
|
||||
URL: data.URL,
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||
Source: data.Source,
|
||||
URL: data.URL,
|
||||
}, error);
|
||||
});
|
||||
};
|
||||
if (data.IsWinFSP) {
|
||||
helpers
|
||||
.performWindowsUninstall(["WinFsp 2019.1", "WinFsp 2019.2", "WinFsp 2019.3 B1", "WinFsp 2019.3 B2"])
|
||||
.then(uninstalled => {
|
||||
if (uninstalled) {
|
||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||
RebootRequired: true,
|
||||
Source: data.Source,
|
||||
URL: data.URL,
|
||||
});
|
||||
} else {
|
||||
execInstall();
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
standardIPCReply(event, Constants.IPC_Install_Dependency_Reply, {
|
||||
Source: data.Source,
|
||||
URL: data.URL,
|
||||
}, error);
|
||||
});
|
||||
} else {
|
||||
execInstall();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addListeners
|
||||
};
|
||||
25
src/renderer/ipc/DownloadIPC.js
Normal file
25
src/renderer/ipc/DownloadIPC.js
Normal file
@@ -0,0 +1,25 @@
|
||||
const Constants = require('../../constants');
|
||||
const helpers = require('../../helpers');
|
||||
const path = require('path');
|
||||
|
||||
const addListeners = (ipcMain, standardIPCReply) => {
|
||||
ipcMain.on(Constants.IPC_Download_File, (event, data) => {
|
||||
const destination = path.join(helpers.getDataDirectory(), data.Filename);
|
||||
helpers.downloadFile(data.URL, destination, (progress) => {
|
||||
standardIPCReply(event, Constants.IPC_Download_File_Progress, {
|
||||
Destination: destination,
|
||||
Progress: progress,
|
||||
URL: data.URL,
|
||||
});
|
||||
}, error => {
|
||||
standardIPCReply(event, Constants.IPC_Download_File_Complete, {
|
||||
Destination: destination,
|
||||
URL: data.URL,
|
||||
}, error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addListeners
|
||||
};
|
||||
31
src/renderer/ipc/FilesystemIPC.js
Normal file
31
src/renderer/ipc/FilesystemIPC.js
Normal file
@@ -0,0 +1,31 @@
|
||||
const Constants = require('../../constants');
|
||||
const fs = require('fs');
|
||||
|
||||
const addListeners = (ipcMain, getMainWindow, dialog) => {
|
||||
ipcMain.on(Constants.IPC_Browse_Directory + '_sync', (event, data) => {
|
||||
dialog.showOpenDialog(getMainWindow(), {
|
||||
defaultPath: data.Location,
|
||||
properties: ['openDirectory'],
|
||||
title: data.Title,
|
||||
}, (filePaths) => {
|
||||
if (filePaths && (filePaths.length > 0)) {
|
||||
event.returnValue = filePaths[0];
|
||||
} else {
|
||||
event.returnValue = '';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Delete_File, (event, data) => {
|
||||
try {
|
||||
if (fs.existsSync(data.FilePath)) {
|
||||
fs.unlinkSync(data.FilePath);
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addListeners
|
||||
};
|
||||
249
src/renderer/ipc/MountsIPC.js
Normal file
249
src/renderer/ipc/MountsIPC.js
Normal file
@@ -0,0 +1,249 @@
|
||||
const Constants = require('../../constants');
|
||||
const fs = require('fs');
|
||||
const helpers = require('../../helpers');
|
||||
const os = require('os');
|
||||
|
||||
let expectedUnmount = {};
|
||||
let firstMountCheck = true;
|
||||
let manualMountDetection = {};
|
||||
let mountedData = {};
|
||||
let mountedLocations = [];
|
||||
|
||||
const clearManualMountDetection = provider => {
|
||||
if (manualMountDetection[provider]) {
|
||||
clearInterval(manualMountDetection[provider]);
|
||||
delete manualMountDetection[provider];
|
||||
}
|
||||
};
|
||||
|
||||
const monitorMount = (sender, provider, version, pid, location) => {
|
||||
manualMountDetection[provider] = setInterval(() => {
|
||||
helpers
|
||||
.detectRepertoryMounts(version)
|
||||
.then(result => {
|
||||
if (result[provider].PID !== pid) {
|
||||
if (result[provider].PID === -1) {
|
||||
clearManualMountDetection(provider);
|
||||
sender.send(Constants.IPC_Unmount_Drive_Reply, {
|
||||
data: {
|
||||
Expected: expectedUnmount[provider],
|
||||
Location: location,
|
||||
Provider: provider,
|
||||
Error: Error(provider + ' Unmounted').toString(),
|
||||
Success: false,
|
||||
}
|
||||
});
|
||||
} else {
|
||||
pid = result[provider].PID;
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e);
|
||||
});
|
||||
},6000);
|
||||
};
|
||||
|
||||
const unmountAllDrives = () => {
|
||||
// Reset mount states
|
||||
for (const provider of Constants.PROVIDER_LIST) {
|
||||
clearManualMountDetection(provider);
|
||||
expectedUnmount[provider] = true;
|
||||
}
|
||||
|
||||
// Unmount all items
|
||||
for (const i in mountedLocations) {
|
||||
const data = mountedData[mountedLocations[i]];
|
||||
helpers.stopMountProcessSync(data.Version, data.Provider);
|
||||
}
|
||||
|
||||
mountedLocations = [];
|
||||
mountedData = {};
|
||||
};
|
||||
|
||||
const addListeners = (ipcMain, setTrayImage, standardIPCReply) => {
|
||||
ipcMain.on(Constants.IPC_Check_Mount_Location + '_sync', (event, data) => {
|
||||
let response = {
|
||||
Success: true,
|
||||
Error: ''
|
||||
};
|
||||
|
||||
try {
|
||||
if (fs.existsSync(data.Location) && fs.statSync(data.Location).isDirectory()) {
|
||||
if (fs.readdirSync(data.Location).length !== 0) {
|
||||
response.Success = false;
|
||||
response.Error = 'Directory not empty: ' + data.Location;
|
||||
}
|
||||
} else {
|
||||
response.Success = false;
|
||||
response.Error = 'Directory not found: ' + data.Location;
|
||||
}
|
||||
} catch (e) {
|
||||
response.Success = false;
|
||||
response.Error = e.toString();
|
||||
}
|
||||
event.returnValue = response;
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Detect_Mounts, (event, data) => {
|
||||
let driveLetters = {};
|
||||
for (const provider of Constants.PROVIDER_LIST) {
|
||||
driveLetters[provider] = [];
|
||||
}
|
||||
|
||||
const grabDriveLetters = (locations) => {
|
||||
for (let i = 'c'.charCodeAt(0); i <= 'z'.charCodeAt(0); i++) {
|
||||
const drive = (String.fromCharCode(i) + ':').toUpperCase();
|
||||
let driveInUse;
|
||||
if (Object.keys(locations).length > 0) {
|
||||
for (const provider of Constants.PROVIDER_LIST) {
|
||||
driveInUse = locations[provider].startsWith(drive);
|
||||
if (driveInUse)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!driveInUse) {
|
||||
try {
|
||||
if (!fs.existsSync(drive)) {
|
||||
for (const provider of Constants.PROVIDER_LIST) {
|
||||
driveLetters[provider].push(drive);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(locations).length > 0) {
|
||||
for (const provider of Constants.PROVIDER_LIST) {
|
||||
if (locations[provider].length > 0) {
|
||||
if (!driveLetters[provider].find((driveLetter) => {
|
||||
return driveLetter === locations[provider];
|
||||
})) {
|
||||
driveLetters[provider].push(locations[provider]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const setImage = (locations) => {
|
||||
let driveInUse;
|
||||
if (Object.keys(locations).length > 0) {
|
||||
for (const provider of Constants.PROVIDER_LIST) {
|
||||
driveInUse = locations[provider].length > 0;
|
||||
if (driveInUse)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
setTrayImage(driveInUse)
|
||||
};
|
||||
|
||||
helpers
|
||||
.detectRepertoryMounts(data.Version)
|
||||
.then((results) => {
|
||||
let storageData = {};
|
||||
let locations = {};
|
||||
for (const provider of Constants.PROVIDER_LIST) {
|
||||
storageData[provider] = results[provider] ? results[provider] : {
|
||||
Active: false,
|
||||
Location: '',
|
||||
PID: -1,
|
||||
};
|
||||
locations[provider] = storageData[provider].Location;
|
||||
|
||||
if (storageData[provider].PID !== -1) {
|
||||
expectedUnmount[provider] = false;
|
||||
if (firstMountCheck) {
|
||||
monitorMount(event.sender, provider, data.Version, storageData[provider].PID, storageData[provider].Location);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (os.platform() === 'win32') {
|
||||
grabDriveLetters(locations);
|
||||
}
|
||||
|
||||
setImage(locations);
|
||||
if (firstMountCheck) {
|
||||
firstMountCheck = false;
|
||||
}
|
||||
standardIPCReply(event, Constants.IPC_Detect_Mounts_Reply, {
|
||||
DriveLetters: driveLetters,
|
||||
Locations: locations,
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
if (os.platform() === 'win32') {
|
||||
grabDriveLetters({});
|
||||
}
|
||||
setImage({});
|
||||
standardIPCReply(event, Constants.IPC_Detect_Mounts_Reply, {
|
||||
DriveLetters: driveLetters,
|
||||
}, error);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Mount_Drive, (event, data) => {
|
||||
expectedUnmount[data.Provider] = false;
|
||||
|
||||
if (mountedLocations.indexOf(data.Location) !== -1) {
|
||||
console.log(data.Provider + ' already mounted: ' + data.Location);
|
||||
} else {
|
||||
mountedLocations.push(data.Location);
|
||||
mountedData[data.Location] = {
|
||||
Version: data.Version,
|
||||
Provider: data.Provider,
|
||||
};
|
||||
const errorHandler = (pid, error) => {
|
||||
if (mountedLocations.indexOf(data.Location) !== -1) {
|
||||
mountedLocations.splice(mountedLocations.indexOf(data.Location), 1);
|
||||
delete mountedData[data.Location];
|
||||
}
|
||||
|
||||
standardIPCReply(event, Constants.IPC_Unmount_Drive_Reply, {
|
||||
Expected: expectedUnmount[data.Provider],
|
||||
Location: data.Location,
|
||||
Provider: data.Provider,
|
||||
}, error || Error(data.Provider + ' Unmounted'));
|
||||
};
|
||||
helpers
|
||||
.executeMount(data.Version, data.Provider, data.Location, data.NoConsoleSupported, (error, pid) => {
|
||||
errorHandler(pid, error);
|
||||
})
|
||||
.then(() => {
|
||||
standardIPCReply(event, Constants.IPC_Mount_Drive_Reply, {
|
||||
Provider: data.Provider,
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
errorHandler(-1, error);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Unmount_All_Drives, (event, data) => {
|
||||
unmountAllDrives();
|
||||
standardIPCReply(event, Constants.IPC_Unmount_All_Drives_Reply);
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Unmount_Drive, (event, data) => {
|
||||
clearManualMountDetection(data.Provider);
|
||||
|
||||
expectedUnmount[data.Provider] = true;
|
||||
helpers
|
||||
.stopMountProcess(data.Version, data.Provider)
|
||||
.then(result => {
|
||||
console.log(result);
|
||||
})
|
||||
.catch(e => {
|
||||
console.log(e);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addListeners,
|
||||
unmountAllDrives
|
||||
};
|
||||
79
src/renderer/ipc/PlatformIPC.js
Normal file
79
src/renderer/ipc/PlatformIPC.js
Normal file
@@ -0,0 +1,79 @@
|
||||
const Constants = require('../../constants');
|
||||
const fs = require('fs');
|
||||
const helpers = require('../../helpers');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
|
||||
let _platformOverride;
|
||||
|
||||
const getPlatformOverride = () => {
|
||||
return _platformOverride;
|
||||
};
|
||||
|
||||
const setPlatformOverride = platformOverride => {
|
||||
_platformOverride = platformOverride;
|
||||
};
|
||||
|
||||
const addListeners = (ipcMain, detectScript, saveUiSettings) => {
|
||||
ipcMain.on(Constants.IPC_Get_Platform, (event) => {
|
||||
const sendResponse = (appPlatform, platform) => {
|
||||
event.sender.send(Constants.IPC_Get_Platform_Reply, {
|
||||
AppPlatform: appPlatform,
|
||||
Platform: platform,
|
||||
});
|
||||
};
|
||||
|
||||
const platform = os.platform();
|
||||
if (platform === 'linux') {
|
||||
if (_platformOverride && (_platformOverride.length > 0)) {
|
||||
sendResponse(_platformOverride, 'linux');
|
||||
} else {
|
||||
const scriptFile = path.join(os.tmpdir(), 'repertory_detect_linux.sh');
|
||||
fs.writeFileSync(scriptFile, detectScript);
|
||||
|
||||
helpers
|
||||
.executeScript(scriptFile)
|
||||
.then(data => {
|
||||
let appPlatform = data.replace(/(\r\n|\n|\r)/gm, "");
|
||||
if (appPlatform === 'unknown') {
|
||||
helpers
|
||||
.downloadFile(Constants.LINUX_DETECT_SCRIPT_URL, scriptFile, null, err => {
|
||||
if (err) {
|
||||
sendResponse(appPlatform, platform);
|
||||
} else {
|
||||
helpers
|
||||
.executeScript(scriptFile)
|
||||
.then(data => {
|
||||
appPlatform = data.replace(/(\r\n|\n|\r)/gm, "");
|
||||
sendResponse(appPlatform, platform);
|
||||
})
|
||||
.catch(() => {
|
||||
sendResponse(appPlatform, platform);
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
sendResponse(appPlatform, platform);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
sendResponse(platform, platform);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
sendResponse(platform, platform);
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Set_Linux_AppPlatform, (event, data) => {
|
||||
setPlatformOverride(data.AppPlatform);
|
||||
saveUiSettings();
|
||||
event.returnValue = true;
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
getPlatformOverride,
|
||||
setPlatformOverride,
|
||||
addListeners
|
||||
};
|
||||
87
src/renderer/ipc/ReleaseIPC.js
Normal file
87
src/renderer/ipc/ReleaseIPC.js
Normal file
@@ -0,0 +1,87 @@
|
||||
const Constants = require('../../constants');
|
||||
const fs = require('fs');
|
||||
const helpers = require('../../helpers');
|
||||
const os = require('os');
|
||||
const path = require('path');
|
||||
const unzip = require('unzipper');
|
||||
|
||||
const addListeners = (ipcMain, standardIPCReply) => {
|
||||
ipcMain.on(Constants.IPC_Check_Installed, (event, data) => {
|
||||
const destination = path.join(helpers.getDataDirectory(), data.Version);
|
||||
helpers
|
||||
.getMissingDependencies(data.Dependencies)
|
||||
.then((dependencies) => {
|
||||
let exists = false;
|
||||
try {
|
||||
exists = fs.existsSync(destination) && fs.lstatSync(destination).isDirectory();
|
||||
} catch (e) {
|
||||
}
|
||||
standardIPCReply(event, Constants.IPC_Check_Installed_Reply, {
|
||||
Dependencies: dependencies,
|
||||
Exists: exists,
|
||||
Version: data.Version,
|
||||
});
|
||||
}).catch(error => {
|
||||
standardIPCReply(event, Constants.IPC_Check_Installed_Reply, {
|
||||
Dependencies: [],
|
||||
Version: data.Version,
|
||||
}, error);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Extract_Release, (event, data) => {
|
||||
const destination = path.join(helpers.getDataDirectory(), data.Version);
|
||||
helpers.removeDirectoryRecursively(destination);
|
||||
helpers.mkDirByPathSync(destination);
|
||||
|
||||
const stream = fs.createReadStream(data.Source);
|
||||
stream
|
||||
.pipe(unzip.Extract({ path: destination }))
|
||||
.on('error', error => {
|
||||
try {
|
||||
helpers.removeDirectoryRecursively(destination);
|
||||
} catch (e) {
|
||||
}
|
||||
stream.close();
|
||||
standardIPCReply(event, Constants.IPC_Extract_Release_Complete, {
|
||||
Source: data.Source,
|
||||
}, error);
|
||||
})
|
||||
.on('finish', () => {
|
||||
stream.close();
|
||||
if (os.platform() !== 'win32') {
|
||||
helpers
|
||||
.executeAndWait("chmod +x \"" + path.join(destination, 'repertory') + "\"")
|
||||
.then(() => {
|
||||
standardIPCReply(event, Constants.IPC_Extract_Release_Complete, {
|
||||
Source: data.Source,
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
standardIPCReply(event, Constants.IPC_Extract_Release_Complete, {
|
||||
Source: data.Source,
|
||||
}, error);
|
||||
})
|
||||
} else {
|
||||
standardIPCReply(event, Constants.IPC_Extract_Release_Complete, {
|
||||
Source: data.Source,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Test_Release, (event, data) => {
|
||||
helpers
|
||||
.testRepertoryBinary(data.Version)
|
||||
.then(() => {
|
||||
standardIPCReply(event, Constants.IPC_Test_Release_Reply, {});
|
||||
})
|
||||
.catch(error => {
|
||||
standardIPCReply(event, Constants.IPC_Test_Release_Reply, {}, error);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addListeners
|
||||
};
|
||||
30
src/renderer/ipc/StateIPC.js
Normal file
30
src/renderer/ipc/StateIPC.js
Normal file
@@ -0,0 +1,30 @@
|
||||
const Constants = require('../../constants');
|
||||
const fs = require('fs');
|
||||
const helpers = require('../../helpers');
|
||||
const path = require('path');
|
||||
|
||||
const addListeners = ipcMain => {
|
||||
ipcMain.on(Constants.IPC_Get_State, event => {
|
||||
helpers.mkDirByPathSync(helpers.getDataDirectory());
|
||||
const configFile = path.join(helpers.getDataDirectory(), 'settings.json');
|
||||
if (fs.existsSync(configFile)) {
|
||||
event.sender.send(Constants.IPC_Get_State_Reply, {
|
||||
data: JSON.parse(fs.readFileSync(configFile, 'utf8')),
|
||||
});
|
||||
} else {
|
||||
event.sender.send(Constants.IPC_Get_State_Reply, {
|
||||
data: null,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.on(Constants.IPC_Save_State, (event, data) => {
|
||||
helpers.mkDirByPathSync(helpers.getDataDirectory());
|
||||
const configFile = path.join(helpers.getDataDirectory(), 'settings.json');
|
||||
fs.writeFileSync(configFile, JSON.stringify(data.State), 'utf8');
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addListeners
|
||||
};
|
||||
16
src/renderer/ipc/SystemIPC.js
Normal file
16
src/renderer/ipc/SystemIPC.js
Normal file
@@ -0,0 +1,16 @@
|
||||
const Constants = require('../../constants');
|
||||
const os = require('os');
|
||||
const helpers = require('../../helpers');
|
||||
|
||||
const addListeners = (ipcMain, closeApplication) => {
|
||||
ipcMain.on(Constants.IPC_Reboot_System, () => {
|
||||
if (os.platform() === 'win32') {
|
||||
helpers.executeAsync('shutdown.exe', ['/r', '/t', '30']);
|
||||
}
|
||||
closeApplication();
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addListeners
|
||||
};
|
||||
116
src/renderer/ipc/UpgradeIPC.js
Normal file
116
src/renderer/ipc/UpgradeIPC.js
Normal file
@@ -0,0 +1,116 @@
|
||||
const Constants = require('../../constants');
|
||||
const fs = require('fs');
|
||||
const helpers = require('../../helpers');
|
||||
const os = require('os');
|
||||
|
||||
const addListeners = (ipcMain, setIsInstalling, unmountAllDrives, standardIPCReply) => {
|
||||
ipcMain.on(Constants.IPC_Install_Upgrade, (event, data) => {
|
||||
let allowSkipVerification = true;
|
||||
|
||||
unmountAllDrives();
|
||||
|
||||
let tempSig;
|
||||
let tempPub;
|
||||
const cleanupFiles = () => {
|
||||
try {
|
||||
if (tempSig) {
|
||||
fs.unlinkSync(tempSig);
|
||||
}
|
||||
if (tempPub) {
|
||||
fs.unlinkSync(tempPub);
|
||||
}
|
||||
} catch (e) {
|
||||
}
|
||||
};
|
||||
|
||||
const errorHandler = err => {
|
||||
cleanupFiles();
|
||||
setIsInstalling(false);
|
||||
standardIPCReply(event, Constants.IPC_Install_Upgrade_Reply, {
|
||||
AllowSkipVerification: allowSkipVerification,
|
||||
Source: data.Source,
|
||||
}, err);
|
||||
};
|
||||
|
||||
// TODO Enable verification in 1.0.4
|
||||
const hasSignature = false;//!data.SkipVerification && data.Signature && (data.Signature.length > 0);
|
||||
const hasHash = false;//!data.SkipVerification && data.Sha256 && (data.Sha256.length > 0);
|
||||
if (hasSignature) {
|
||||
try {
|
||||
const files = helpers.createSignatureFiles(data.Signature, Constants.DEV_PUBLIC_KEY);
|
||||
tempPub = files.PublicKeyFile;
|
||||
tempSig = files.SignatureFile;
|
||||
} catch (e) {
|
||||
errorHandler(e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let command;
|
||||
let args;
|
||||
const platform = os.platform();
|
||||
if (platform === 'win32') {
|
||||
command = data.Source;
|
||||
} else if (platform === 'darwin') {
|
||||
command = 'open';
|
||||
args = ['-a', 'Finder', data.Source];
|
||||
} else if (platform === 'linux') {
|
||||
try {
|
||||
command = data.Source;
|
||||
fs.chmodSync(command, '750');
|
||||
} catch (e) {
|
||||
errorHandler(e);
|
||||
}
|
||||
} else {
|
||||
errorHandler(Error('Platform not supported: ' + os.platform()));
|
||||
}
|
||||
|
||||
if (command) {
|
||||
const executeInstall = () => {
|
||||
setIsInstalling(true);
|
||||
helpers
|
||||
.executeAsync(command, args)
|
||||
.then(() => {
|
||||
cleanupFiles();
|
||||
standardIPCReply(event, Constants.IPC_Install_Upgrade_Reply)
|
||||
})
|
||||
.catch(error => {
|
||||
setIsInstalling(false);
|
||||
errorHandler(error);
|
||||
});
|
||||
};
|
||||
|
||||
if (hasSignature) {
|
||||
helpers
|
||||
.verifySignature(data.Source, tempSig, tempPub)
|
||||
.then(() => {
|
||||
executeInstall();
|
||||
})
|
||||
.catch(() => {
|
||||
errorHandler(Error('Failed to verify installation package signature'));
|
||||
});
|
||||
} else if (hasHash) {
|
||||
helpers
|
||||
.verifyHash(data.Source, data.Sha256)
|
||||
.then(()=> {
|
||||
executeInstall();
|
||||
})
|
||||
.catch(() => {
|
||||
errorHandler(Error('Failed to verify installation package hash'));
|
||||
});
|
||||
} else {
|
||||
if (platform === 'darwin') {
|
||||
setTimeout(executeInstall, 3000);
|
||||
} else {
|
||||
executeInstall();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
errorHandler(Error('Unsupported upgrade: ' + data.Source));
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
addListeners
|
||||
};
|
||||
Reference in New Issue
Block a user