mStream/electron/index3.html
Paul Sori 9b5bc64e46 typo
2019-03-29 14:24:16 -04:00

1157 lines
56 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<link rel="shortcut icon" type="image/png" href="images/favicon.png"/>
<title>mStream Express Server</title>
<script src="js/materialize.min.js"></script>
<link href="css/materialize.min.css" rel="stylesheet">
<link href="css/index3.css" rel="stylesheet">
<link href="css/boot.css" rel="stylesheet">
<script src="js/vue.js"></script>
<script src="js/izi-toast.min.js"></script>
<link href="css/izi-toast.min.css" rel="stylesheet">
<link href="fonts/jura.css" rel="stylesheet">
</head>
<body>
<div class="modal">
<div id="switcherModal">
<component :key="componentKey" v-bind:is="currentViewModal">
</component>
</div>
</div>
<div class="main">
<div class="main-left-col">
<!-- Buttons -->
<div class="left-nav-menu-header">
Server
</div>
<ul class="left-nav-menu">
<li id="nav-directories" class="left-nav-button waves-effect waves-purple nav-selected">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" height="28"><path fill="#FFA000" d="M38 12H22l-4-4H8c-2.2 0-4 1.8-4 4v24c0 2.2 1.8 4 4 4h31c1.7 0 3-1.3 3-3V16c0-2.2-1.8-4-4-4z"/><path fill="#FFCA28" d="M42.2 18H15.3c-1.9 0-3.6 1.4-3.9 3.3L8 40h31.7c1.9 0 3.6-1.4 3.9-3.3l2.5-14c.5-2.4-1.4-4.7-3.9-4.7z"/></svg>
<span>Directories</span>
</li>
<li id="nav-users" class="left-nav-button waves-effect waves-purple">
<svg xmlns="http://www.w3.org/2000/svg" height="28" viewBox="200 200 800 800"><path fill="#FFF" d="M671.027 410.286c31.749 19.852 54.013 53.574 58.044 92.642 12.928 6.092 27.325 9.578 42.596 9.578 55.593 0 100.645-45.073 100.645-100.73 0-55.591-45.052-100.706-100.645-100.706-55.152.087-99.807 44.283-100.64 99.216m-65.998 206.146c55.611 0 100.749-45.093 100.749-100.705 0-55.568-45.138-100.665-100.749-100.665-55.569 0-100.662 45.097-100.662 100.665 0 55.612 45.092 100.705 100.662 100.705m42.706 6.883H562.3c-71.084 0-128.886 57.823-128.886 128.886v104.541l.218 1.623 7.232 2.255c67.816 21.213 126.781 28.225 175.295 28.225 94.746 0 149.683-26.955 153.076-28.728l6.707-3.375h.723V752.201c0-71.063-57.827-128.886-128.93-128.886M814.33 519.32h-84.754c-.965 33.965-15.406 64.487-38.305 86.465 63.217 18.8 109.431 77.392 109.431 146.613v32.211c83.705-3.089 131.951-26.823 135.152-28.442l6.707-3.42h.744V648.273c0-71.106-57.826-128.953-128.975-128.953m-385.958-6.814c19.655 0 37.997-5.742 53.556-15.537 4.907-32.188 22.172-60.344 46.827-79.498.108-1.882.283-3.726.283-5.611 0-55.631-45.094-100.704-100.666-100.704-55.633 0-100.751 45.073-100.751 100.704.001 55.573 45.118 100.646 100.751 100.646m90.433 93.279c-22.766-21.846-37.249-52.261-38.279-85.942-3.159-.216-6.248-.523-9.468-.523h-85.455c-71.083 0-128.929 57.847-128.929 128.953v104.474l.26 1.644 7.188 2.301c54.474 17.026 103.075 24.829 145.234 27.238v-31.532c-.001-69.221 46.233-127.77 109.449-146.613"/></svg>
<span>Users</span>
</li>
<li id="nav-security" class="left-nav-button waves-effect waves-purple">
<svg xmlns="http://www.w3.org/2000/svg" height="28" viewBox="0 0 460 460"><path d="M360.228,386.747L230,460L99.772,386.747c-27.804-15.639-45.01-45.06-45.01-76.96 V21.905L230,0l175.238,21.905v287.882C405.238,341.687,388.032,371.107,360.228,386.747z" fill="#86c867"/><path d="M335.565,357.061L230,416.442l-105.565-59.38 c-22.538-12.678-36.486-36.526-36.486-62.385V54.762L230,37.006l142.051,17.756v239.915 C372.051,320.535,358.103,344.384,335.565,357.061z" fill="#5e9b3e"/><path d="M230,460l130.228-73.253c27.803-15.64,45.01-45.06,45.01-76.96V21.905 L230,0v37.005l142.051,17.756v239.915c0,25.859-13.948,49.707-36.486,62.385L230,416.442V460z" opacity=".7" fill="#86c867"/><path d="M230,98.571c-30.244,0-54.762,24.518-54.762,54.762 c0,22.454,13.519,41.74,32.857,50.192V222.2h9.701c4.308,0,7.8,3.492,7.8,7.8s-3.492,7.8-7.8,7.8h-9.701v17.257h9.701 c4.308,0,7.8,3.492,7.8,7.8c0,4.308-3.492,7.8-7.8,7.8h-9.701v17.257h9.701c4.308,0,7.8,3.492,7.8,7.8c0,4.308-3.492,7.8-7.8,7.8 h-9.701v25.057L230,339.524l21.905-10.952V203.525c19.338-8.452,32.857-27.739,32.857-50.192 C284.762,123.089,260.244,98.571,230,98.571z M230,157.167c-8.166,0-14.786-6.62-14.786-14.786c0-8.166,6.62-14.786,14.786-14.786 s14.786,6.62,14.786,14.786C244.786,150.547,238.166,157.167,230,157.167z" fill="#ecf0f1"/></svg>
<span>Security</span>
</li>
<li id="nav-network" class="left-nav-button waves-effect waves-purple">
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="#FFF"><path fill="none" d="M0 0h24v24H0z"/><path d="M20.2 5.9l.8-.8C19.6 3.7 17.8 3 16 3s-3.6.7-5 2.1l.8.8C13 4.8 14.5 4.2 16 4.2s3 .6 4.2 1.7zm-.9.8c-.9-.9-2.1-1.4-3.3-1.4s-2.4.5-3.3 1.4l.8.8c.7-.7 1.6-1 2.5-1 .9 0 1.8.3 2.5 1l.8-.8zM19 13h-2V9h-2v4H5c-1.1 0-2 .9-2 2v4c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-4c0-1.1-.9-2-2-2zM8 18H6v-2h2v2zm3.5 0h-2v-2h2v2zm3.5 0h-2v-2h2v2z"/></svg>
<span>Network</span>
</li>
<!-- <li id="nav-settings" class="left-nav-button waves-effect waves-purple">
<svg height="28" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"><path d="M490.51 294.933V216.32l-57.766-11.093c-3.883-13.594-9.354-26.549-16.092-38.657l32.701-48.337-55.602-55.587-48.244 32.663c-12.309-6.885-25.492-12.177-39.338-16.109l-11.043-57.14h-78.614l-11.049 57.194c-13.895 3.956-27.123 9.4-39.463 16.338l-48.069-32.61-55.589 55.562 32.726 48.312c-6.765 12.204-12.277 25.253-16.142 38.959L21.49 216.841v78.613l57.659 11.078c3.917 13.661 9.426 26.676 16.228 38.834l-32.932 48.67 55.601 55.59 48.83-33.061c12.103 6.719 25.048 11.981 38.629 15.852l11.099 57.524h78.614l11.096-57.531c13.684-3.894 26.717-9.275 38.896-16.063l48.832 33.101 55.588-55.574-33.072-48.836c6.805-12.221 12.383-25.298 16.279-39.032l57.673-11.073m-234.535 83.084c-67.441 0-122.115-54.673-122.115-122.114s54.674-122.115 122.115-122.115S378.09 188.461 378.09 255.903s-54.674 122.114-122.115 122.114" fill="#FFF"/><path d="M254.297 378v.006c.439.006.877.01 1.316.01-.291-.002-.324-.011-1.316-.016m1.379-244.211c-.461 0-.92.004-1.379.011v.005c1.016-.004 1.062-.014 1.379-.016m.299-.001l-.086.001c67.402.047 122.113 54.702 122.113 122.114 0 67.405-54.744 122.055-122.135 122.114h.107c67.441 0 122.115-54.673 122.115-122.114s-54.673-122.115-122.114-122.115m137.8-71.143l-.014.009 55.592 55.579-32.701 48.337c6.738 12.108 12.209 25.063 16.092 38.657l57.766 11.093v78.613-78.613l-57.766-11.093a182.588 182.588 0 0 0-16.006-38.657l32.66-48.337-55.623-55.588m-98.648-40.587h-40.83 40.83l11.043 57.14c13.846 3.933 27.029 9.225 39.338 16.109l.006-.003c-12.307-6.884-25.494-12.174-39.338-16.106l-11.049-57.14" fill="#FFF"/><path d="M295.127 22.058h-40.83V133.8c.459-.007.918-.011 1.379-.011l.125-.001.088.001.086-.001c67.441 0 122.115 54.673 122.115 122.115s-54.674 122.114-122.115 122.114h-.216l-.145-.001c-.439 0-.877-.004-1.316-.01v111.936h40.92l11.096-57.531c13.684-3.894 26.717-9.275 38.896-16.063l48.832 33.101 55.588-55.574-33.072-48.836c6.805-12.221 12.383-25.298 16.279-39.032l57.674-11.073v-78.613l-57.766-11.093c-3.883-13.594-9.354-26.549-16.092-38.657l32.701-48.337-55.592-55.579-48.244 32.654-.004-.003-.006.003c-12.309-6.885-25.492-12.177-39.338-16.109l-11.043-57.142" fill="#FFF"/><path d="M256.072 111.928c-79.505 0-143.957 64.451-143.957 143.956 0 79.503 64.452 143.955 143.957 143.955 79.504 0 143.955-64.452 143.955-143.955 0-79.505-64.451-143.956-143.955-143.956zm0 217.641c-40.696 0-73.687-32.99-73.687-73.686 0-40.697 32.991-73.687 73.687-73.687 40.695 0 73.686 32.989 73.686 73.687 0 40.696-32.99 73.686-73.686 73.686z" fill="#FFF"/></svg>
<span>Settings</span>
</li> -->
</ul>
<div class="left-nav-menu-header">
Other
</div>
<ul class="left-nav-menu">
<li id="nav-auto-dns" class="left-nav-button waves-effect waves-light">
<svg xmlns="http://www.w3.org/2000/svg" height="28" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path fill="#8c9eff" d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96z"/></svg>
<span>Auto DNS</span>
</li>
<li id="nav-about" class="left-nav-button waves-effect waves-light">
<svg xmlns="http://www.w3.org/2000/svg" height="28" viewBox="0 -1 24 24" fill="#fff"><path d="M4 2c-1.093 0-2 .907-2 2v18.406l1.719-1.687L6.438 18H20c1.093 0 2-.907 2-2V4c0-1.093-.907-2-2-2H4zm0 2h16v12H5.594l-.313.281L4 17.563V4zm7 2v2h2V6h-2zm0 3v5h2V9h-2z"/></svg>
<span>About</span>
</li>
</ul>
<!-- Boot Server Button -->
<div class="boot-server-button-wrapper">
<div class="boot-server-flex-wrapper">
<label class="autoboot-label">
<input id="boot-server-checkbox" type="checkbox" checked="checked" />
<span>Boot on startup</span>
</label>
<a id="boot-server-button" class="waves-effect waves-light btn blue accent-3">Boot Server</a>
</div>
</div>
</div>
<div id="switcherMain" class="main-right-col">
<component v-bind:is="currentViewMain">
</component>
</div>
</div>
<script>
const remote = require('electron').remote;
const {ipcRenderer} = require('electron');
const app = remote.app;
const dialog = remote.require('electron').dialog;
const internalIp = require('internal-ip');
const publicIpMod = require('public-ip');
const path = require('path');
const fs = require('fs');
const Login = require('../modules/login');
const shell = require('electron').shell
var loadJson = {};
var configFile = path.join(app.getPath('userData'), 'save/server-config.json');
var editThisUser;
var bootFlag = false;
var publicIp;
(async () => {
publicIp = await publicIpMod.v4();
})();
// Open a tags in OS browser
document.addEventListener('click', function (event) {
if (event.target.tagName === 'A' && event.target.href.startsWith('http')) {
event.preventDefault();
shell.openExternal(event.target.href);
}
})
try {
if (fs.statSync(configFile).isFile()) {
loadJson = JSON.parse(fs.readFileSync(configFile, 'utf8'));
}
} catch(error) {
console.log('Failed To Load JSON');
}
if (!loadJson.users || typeof loadJson.users !== 'object') {
loadJson.users = {};
}
if (!loadJson.folders || typeof loadJson.users !== 'object') {
loadJson.folders = {};
}
if (!loadJson.ssl || typeof loadJson.ssl !== 'object') {
loadJson.ssl = {};
}
if (!loadJson.port) {
loadJson.port = 3000;
}
function hashPassword(password) {
return new Promise((resolve, reject) => {
Login.hashPassword(password, (salt, hashedPassword, err) => {
if (err) {
// return callback(false, err);
return reject('Failed to hash password');
}
resolve({salt, hashPassword: Buffer.from(hashedPassword).toString('hex')});
});
});
}
window.onload = function () {
// Initialize Modal
var modalInstance = M.Modal.init(document.querySelectorAll('.modal'), { endingTop: '20%' });
Vue.component('folder-accordion', {
data: function() {
return {
instances: null,
directories: loadJson.folders,
resetFlag: false,
closeOverride: () => {
if (this.resetFlag) {
this.$parent.componentKey = !this.$parent.componentKey;
}
}
};
},
template: '\
<ul class="z-depth-1 collapsible-folders">\
<li v-for="(value, key, index) in directories">\
<div v-on:click="toggleOptions(index, $event)" class="collapsible-header">\
<div class="accordion-header-left">\
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="32" height="100%"><path fill="#FFA000" d="M38 12H22l-4-4H8c-2.2 0-4 1.8-4 4v24c0 2.2 1.8 4 4 4h31c1.7 0 3-1.3 3-3V16c0-2.2-1.8-4-4-4z"/><path fill="#FFCA28" d="M42.2 18H15.3c-1.9 0-3.6 1.4-3.9 3.3L8 40h31.7c1.9 0 3.6-1.4 3.9-3.3l2.5-14c.5-2.4-1.4-4.7-3.9-4.7z"/></svg>\
</div>\
<div class="accordion-header-right">\
<div><b>{{key}}</b></div>\
<div>{{value.root}}</div>\
</div>\
</div>\
<div class="collapsible-body clearfix">\
<div class="folder-button-group">\
<a v-on:click="changeDirectory(value, key, index)" class="waves-effect waves-light btn">Change Directory</a>\
<a v-on:click="deleteFolder(value, key, index)" class="waves-effect waves-light btn red">\
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="100%" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path fill="#FFF" d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zm2.46-7.12l1.41-1.41L12 12.59l2.12-2.12 1.41 1.41L13.41 14l2.12 2.12-1.41 1.41L12 15.41l-2.12 2.12-1.41-1.41L10.59 14l-2.13-2.12zM15.5 4l-1-1h-5l-1 1H5v2h14V4z"/><path fill="none" d="M0 0h24v24H0z"/></svg>\
</a>\
</div>\
</div>\
</li>\
</ul>',
mounted: function () {
this.instances = M.Collapsible.init(document.querySelectorAll('.collapsible-folders'), { onCloseEnd: this.closeOverride });
},
beforeDestroy: function() {
this.instances[0].destroy();
},
methods: {
changeDirectory: function(value, key, index) {
dialog.showOpenDialog({properties: [ 'openDirectory']}, (selectedDirectory) => {
if(selectedDirectory == null ){
return;
}
loadJson.folders[key] = { root: selectedDirectory[0] };
fs.writeFileSync(configFile, JSON.stringify(loadJson), 'utf8');
this.resetFlag = true;
this.instances[0].close(index);
});
},
deleteFolder: function(value, key, index) {
iziToast.question({
timeout: 20000,
close: false,
overlayClose: true,
overlay: true,
displayMode: 'once',
id: 'question',
zindex: 99999,
title: "Delete <b>'" + value.root + "'</b>?",
position: 'center',
buttons: [
['<button><b>Delete</b></button>', (instance, toast) => {
delete loadJson.folders[key];
if(loadJson.users) {
Object.keys(loadJson.users).forEach(user => {
loadJson.users[user].vpaths = loadJson.users[user].vpaths.filter(e => {
return ![key].includes(e);
});
});
}
fs.writeFileSync(configFile, JSON.stringify(loadJson), 'utf8');
this.resetFlag = true;
this.instances[0].close(index);
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
}, true],
['<button>Go Back</button>', (instance, toast) => {
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
}],
]
});
},
toggleOptions: function(index, el) {
if(el.target.classList.contains('btn')){
return;
}
if(el.currentTarget.parentElement.classList.contains('active')){
this.instances[0].close(index);
return;
}
this.instances[0].open(index);
}
}
});
const foldersView = Vue.component('folders-view', {
data() {
return {
componentKey: false, // Flip this value to force re-render the folder accordion thing
dirName: '' // for the input field
};
},
template: '\
<div>\
<div class="row">\
<div class="col s12">\
<div class="card">\
<div class="section-header">Add Folder</div>\
<form id="choose-directory-form" class="choose-directory-form" @submit.prevent="addFolderDialog">\
<div class="input-field directory-name-field">\
<input @blur="maybeResetForm()" pattern="[a-zA-Z0-9-]+" v-model="dirName" id="add-directory-name" required type="text" class="validate">\
<label for="add-directory-name">Display Name</label>\
<span class="helper-text" >No special characters</span>\
</div>\
<button class="btn green waves-effect waves-light select-folder-button" type="submit">\
Select Folder\
</button>\
</form>\
</div>\
</div>\
</div>\
<div class="row">\
<div class="col s12">\
<div class="section-header">Your Folders:</div>\
<template>\
<folder-accordion :key="componentKey" />\
</template>\
</div>\
</div>\
</div>',
methods: {
maybeResetForm: function() {
if (this.dirName === '') {
document.getElementById("choose-directory-form").reset();
}
},
addFolderDialog: function (event) {
dialog.showOpenDialog({properties: [ 'openDirectory']}, (selectedDirectory) => {
if(selectedDirectory == null ){
return;
}
if (loadJson.folders[this.dirName]) {
iziToast.warning({
title: 'Display Name Already Exists',
    message: 'Display names must be unique',
position: 'topCenter',
timeout: 3500
});
return;
}
loadJson.folders[this.dirName] = { root: selectedDirectory[0] };
fs.writeFileSync(configFile, JSON.stringify(loadJson), 'utf8');
this.componentKey = !this.componentKey;
this.dirName = '';
document.getElementById("choose-directory-form").reset();
});
},
}
});
const aboutView = Vue.component('about-view', {
template: '\
<div>\
<img class="mstream-logo" src="images/mstream-logo.svg">\
<div class="row">\
<div class="col s12">\
<div class="card">\
<div class="about-content-section">\
<div class="about-content-header">Developed By</div>\
<div class="about-content-body">Paul Sori</div>\
<div class="about-content-body">paul@mstream.io</div>\
</div>\
</div>\
</div>\
</div>\
</div>',
});
Vue.component('user-accordion', {
data: function() {
return {
instances: null,
users: loadJson.users,
resetFlag: false,
closeOverride: () => {
if (this.resetFlag) {
this.$parent.componentKey = !this.$parent.componentKey;
}
}
};
},
template: '\
<ul class="z-depth-1 collapsible-folders">\
<li v-for="(value, key, index) in users">\
<div v-on:click="toggleOptions(index, $event)" class="collapsible-header">\
<div class="accordion-header-left">\
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="100%" viewBox="0 0 24 24"><path d="M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"/><path d="M0 0h24v24H0z" fill="none"/></svg>\
</div>\
<div class="accordion-header-right">\
<div><b>{{key}}</b></div>\
<div class="user-folders-line">\
<?xml version="1.0" encoding="utf-8"?><svg width="24" height="22" xmlns="http://www.w3.org/2000/svg" viewBox="6 6 40 40" style="enable-background:new 0 0 48 48"><path d="M16.516 20.688C16.266 21.25 12 31.906 12 31.906V17c0-.55.45-1 1-1h1.334l.35-1.052C14.857 14.427 15.45 14 16 14h5c.55 0 1.143.427 1.316.948l.35 1.052H32c.55 0 1 .45 1 1v3H17.5c-.275 0-.734.125-.984.688zM41 21H19c-.55 0-1.167.418-1.371.929l-5.258 13.143c-.204.51.079.928.629.928h22c.55 0 1.167-.418 1.371-.929l5.258-13.143c.204-.51-.079-.928-.629-.928z"/></svg>\
{{folderList(value.vpaths)}}\
</div>\
</div>\
</div>\
<div class="collapsible-body clearfix">\
<div class="folder-button-group">\
<a v-on:click="openUserPasswordModal(value, key, index)" class="waves-effect waves-light btn">Reset Password</a>\
<a v-on:click="openChangeFoldersModal(value, key, index)" class="waves-effect waves-light btn">Edit</a>\
<a v-on:click="deleteUser(value, key, index)" class="waves-effect waves-light btn red">\
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="100%" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path fill="#FFF" d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zm2.46-7.12l1.41-1.41L12 12.59l2.12-2.12 1.41 1.41L13.41 14l2.12 2.12-1.41 1.41L12 15.41l-2.12 2.12-1.41-1.41L10.59 14l-2.13-2.12zM15.5 4l-1-1h-5l-1 1H5v2h14V4z"/><path fill="none" d="M0 0h24v24H0z"/></svg>\
</a>\
</div>\
</div>\
</li>\
</ul>',
mounted: function () {
this.instances = M.Collapsible.init(document.querySelectorAll('.collapsible-folders'), { onCloseEnd: this.closeOverride });
},
beforeDestroy: function() {
this.instances[0].destroy();
},
methods: {
folderList: function(arr) {
var returnThis = '';
arr.forEach((element) => {
returnThis += element + ', '
});
returnThis = returnThis.slice(0, -2);
return returnThis;
},
openUserPasswordModal: function(value, key, index) {
editThisUser = key;
if (vModal.$children[0]) {
vModal.componentKey = !vModal.componentKey;
}
vModal.currentViewModal = 'user-password-view';
modalInstance[0].open();
},
openChangeFoldersModal: function(value, key, index) {
editThisUser = key;
if (vModal.$children[0]) {
vModal.componentKey = !vModal.componentKey;
}
vModal.currentViewModal = 'user-folders-view';
modalInstance[0].open();
},
deleteUser: function(value, key, index) {
iziToast.question({
timeout: 20000,
close: false,
overlayClose: true,
overlay: true,
displayMode: 'once',
id: 'question',
zindex: 99999,
title: "Delete <b>'" + key + "'</b>?",
position: 'center',
buttons: [
['<button><b>Delete</b></button>', (instance, toast) => {
delete loadJson.users[key];
fs.writeFileSync(configFile, JSON.stringify(loadJson), 'utf8');
this.resetFlag = true;
this.instances[0].close(index);
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
}, true],
['<button>Go Back</button>', (instance, toast) => {
instance.hide({ transitionOut: 'fadeOut' }, toast, 'button');
}],
]
});
},
toggleOptions: function(index, el) {
if(el.target.classList.contains('btn')){
return;
}
if(el.currentTarget.parentElement.classList.contains('active')){
this.instances[0].close(index);
return;
}
this.instances[0].open(index);
}
}
});
const usersView = Vue.component('users-view', {
data() {
return {
directories: loadJson.folders,
componentKey: false, // Flip this value to force re-render the folder accordion thing
newUsername: '', // for the input field
selectInstance: null,
newPassword: ''
};
},
template: '\
<div>\
<div class="row">\
<div class="col s12">\
<div class="card">\
<div class="section-header">New User</div>\
<form id="add-user-form" class="" @submit.prevent="addUser">\
<div class="row row-mod">\
<div class="input-field directory-name-field col s12 m6">\
<input @blur="maybeResetForm()" pattern="[a-zA-Z0-9-]+" v-model="newUsername" id="new-username" required type="text" class="validate">\
<label for="new-username">Username</label>\
</div>\
<div class="input-field directory-name-field col s12 m6">\
<input @blur="maybeResetForm()" v-model="newPassword" id="new-password" required type="password" class="validate">\
<label for="new-password">Password</label>\
</div>\
</div>\
<div class="row row-mod">\
<div class="input-field col s12">\
<select :disabled="Object.keys(directories).length === 0" id="new-user-dirs" multiple>\
<option disabled selected value="" v-if="Object.keys(directories).length === 0">You must add a directory before adding a user</option>\
<option v-for="(key, value) in directories" :value="value">{{ value }}</option>\
</select>\
<label for="new-user-dirs">Select User\'s Directories</label>\
</div>\
</div>\
<div class="row row-mod">\
<div class="col s12 m6">\
</div>\
<div class="col s12 m6">\
<button id="submit-add-user-form" class="btn green waves-effect waves-light col s6" type="submit">\
Add user\
</button>\
</div>\
</div>\
</form>\
</div>\
</div>\
</div>\
<div class="row">\
<div class="col s12">\
<div class="section-header">Users:</div>\
<template>\
<user-accordion :key="componentKey" />\
</template>\
</div>\
</div>\
</div>',
mounted: function () {
this.selectInstance = M.FormSelect.init(document.querySelectorAll("#new-user-dirs"));
},
beforeDestroy: function() {
this.selectInstance[0].destroy();
},
methods: {
maybeResetForm: function() {
if (this.newUsername === '' && this.newPassword === '' && this.selectInstance[0].getSelectedValues().length === 0) {
document.getElementById("add-user-form").reset();
}
},
addUser: function (event) {
if (this.selectInstance[0].getSelectedValues().length === 0) {
iziToast.warning({
title: 'Cannot add user without a directory',
position: 'topCenter',
timeout: 3500
});
return;
}
if (loadJson.users[this.newUsername]) {
iziToast.warning({
title: 'User Already Exists',
position: 'topCenter',
timeout: 3500
});
return;
}
hashPassword(this.newPassword).then(hashObj => {
loadJson.users[this.newUsername] = {
vpaths: this.selectInstance[0].getSelectedValues(),
password: hashObj.hashPassword,
salt: hashObj.salt
};
fs.writeFileSync(configFile, JSON.stringify(loadJson), 'utf8');
this.newPassword = '';
this.newUsername = '';
this.selectInstance[0].input.value = '';
this.selectInstance[0].el.value = "";
this.componentKey = !this.componentKey;
document.getElementById("add-user-form").reset();
});
},
}
});
const networkView = Vue.component('network-view', {
data() {
return {
lJson: loadJson,
};
},
template: '\
<div>\
<div class="row">\
<div class="col s12">\
<div class="card">\
<div class="row row-mod">\
<div class="section-header">Network Details</div>\
<div class="col s12">\
<div>Local IP: {{networkIp}}</div>\
<div>Public IP: {{pIp}}</div>\
</div>\
</div>\
</div>\
</div>\
</div>\
<div class="row">\
<div class="col s4">\
<div class="card">\
<div class="row row-mod">\
<div class="col s12 port-form-container">\
<div class="input-field">\
<input v-model="lJson.port" @blur="updateConfig()" id="server-port" type="number" class="validate" min="1" max="65535" step="1" required />\
<label for="server-port">Port #</label>\
</div>\
</div>\
</div>\
</div>\
</div>\
<div class="row">\
<div class="col s8">\
<div class="card">\
<div class="section-header">Going Online</div>\
<div class="row row-mod">\
<div class="col s12">\
Getting your server online can take some work depending on your local network. <a href="https://mstream.io/">You can read our how-to guide here.</a>\
<br><br>\
mStream Auto DNS will get your computer online effortlessly. We are now offering a free 2 weeks of our DNS services \
</div>\
<div class="col s12">\
<button v-on:click="goToAutoDns()" class="btn blue waves-effect waves-light auto-dns-link-button">\
Check Out Auto DNS\
</button>\
</div>\
</div>\
</div>\
</div>\
</div>\
</div>\
</div>',
computed: {
networkIp: function () {
// `this` points to the vm instance
return internalIp.v4.sync();
},
pIp: function() {
return publicIp;
}
},
methods: {
updateConfig: function() {
fs.writeFileSync(configFile, JSON.stringify(loadJson), 'utf8');
},
goToAutoDns: function() {
if(bootFlag === true) {
return;
}
vm.currentViewMain = 'auto-dns-view';
resetNav(document.getElementById("nav-auto-dns"));
}
}
});
const securityView = Vue.component('security-view', {
data: function() {
return {
currentViewSsl: (!loadJson.ssl.cert && !loadJson.ssl.key) ? 'security-view-signup' : 'security-view-diy'
};
},
template: '\
<div>\
<div class="row">\
<div class="col s12">\
<div class="card">\
<div class="section-header">SSL Encryption</div>\
<div class="row row-mod">\
<div class="col s12">\
This feature is not enabled by default. You must provide your own SSL certificates to enable encryption. SSL certificates can be registered for free with <a href="https://certbot.eff.org/">Certbot</a>\
<br><br>\
mStream Auto DNS takes care of registering certificates and configuring server encryption. <a href="https://mstream.io">Read more about it here</a>\
</div>\
</div>\
</div>\
</div>\
</div>\
<div class="row">\
<div class="col s12 security-container">\
<transition name="component-fade" mode="out-in">\
<component v-bind:is="currentViewSsl">\
</component>\
</transition>\
</div>\
</div>\
</div>',
});
const securityViewDiyKeys = Vue.component('security-view-diy', {
data: function() {
return {
ssl: loadJson.ssl
};
},
template: '\
<div class="card security-diy">\
<svg v-on:click="clearSSL($event)" class="remove-ssl" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="#e53935" d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z"/><path d="M0 0h24v24H0z" fill="none"/></svg>\
<div class="section-header">SSL Credentials</div>\
<div class="row row-mod">\
<div class="col s12">\
<div class="input-field">\
<input v-model="ssl.key" v-on:click="selectKeyFile($event)" id="server-ssl-key" type="text">\
<label for="server-ssl-key">Key File</label>\
</div>\
</div>\
<div class="col s12">\
<div class="input-field">\
<input v-model="ssl.cert" v-on:click="selectCertFile($event)" id="server-ssl-cert" type="text">\
<label for="server-ssl-cert">Certificate</label>\
</div>\
</div>\
</div>\
</div>',
mounted: function() {
M.updateTextFields();
},
methods: {
clearSSL: function() {
loadJson.ssl.key = '';
loadJson.ssl.cert = '';
fs.writeFileSync(configFile, JSON.stringify(loadJson), 'utf8');
M.updateTextFields();
this.$parent._data.currentViewSsl = 'security-view-signup';
},
selectKeyFile: function(el) {
dialog.showOpenDialog({properties: [ 'openFile']}, (selectedFile) => {
if(selectedFile == null ){
return;
}
el.target.value = selectedFile;
loadJson.ssl.key = selectedFile;
el.target.blur();
fs.writeFileSync(configFile, JSON.stringify(loadJson), 'utf8');
});
},
selectCertFile: function(el) {
dialog.showOpenDialog({properties: [ 'openFile']}, (selectedFile) => {
if(selectedFile == null ){
return;
}
el.target.value = selectedFile;
loadJson.ssl.cert = selectedFile;
el.target.blur();
fs.writeFileSync(configFile, JSON.stringify(loadJson), 'utf8');
});
},
}
});
const securityViewLoggedIn = Vue.component('security-view-logged-in', {
template: '\
<div class="ssl-overlay card">\
<div id="logged-in-panel" class="logged-in-panel">\
<img class="logged-in-checkmark" src="images/checkmark.svg">\
<div>\
<p class="bigger-text">Logged In</p>\
<p>Domain: <span id="your-domain">LOADING...</span> </br>\
IP Address: <span id="ip-status">LOADING...</span> </br>\
Certs: <span id="cert-status">LOADING...</span> </br>\
</p>\
</div>\
</div>\
</div>'
});
const securityViewSignup = Vue.component('security-view-signup', {
data: function() {
return {
ssl: loadJson.ssl
};
},
template: '\
<div class="ssl-choice card no-pad-bot">\
<div v-on:click="goToAutoDns()" class="signup-button waves-effect waves-default">\
<p class="center bigger-text"><b>Auto DNS</b></p>\
<svg height="88" width="100%" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg"><path d="M46.698 33.004H31.99c-3.306 0-5.986 2.68-5.986 5.986v8.295c0 3.637 2.948 6.585 6.585 6.585H46.1c3.637 0 6.585-2.948 6.585-6.585V38.99C52.684 35.684 50.004 33.004 46.698 33.004zM49.547 47.588c0 1.93-1.564 3.494-3.494 3.494H32.635c-1.93 0-3.494-1.564-3.494-3.494v-8.302c0-1.93 1.564-3.494 3.494-3.494h13.419c1.93 0 3.494 1.564 3.494 3.494V47.588zM31.99 31.935h2.01V28.42c0-2.947 2.398-5.345 5.345-5.345 2.947 0 5.345 2.398 5.345 5.345v3.515h2.01c.574 0 1.133.071 1.668.201V28.42c0-4.975-4.047-9.022-9.022-9.022s-9.022 4.047-9.022 9.022v3.716C30.857 32.006 31.415 31.935 31.99 31.935z" fill="#3E4753"/><path d="M45.095,37.451H33.593c-1.287,0-2.331,1.043-2.331,2.331v7.311c0,1.287,1.043,2.331,2.331,2.331h11.503 c1.287,0,2.331-1.043,2.331-2.331v-7.311C47.426,38.494,46.382,37.451,45.095,37.451z M40.705,43.86v2.064 c0,0.748-0.612,1.361-1.361,1.361c-0.748,0-1.361-0.612-1.361-1.361V43.86c-0.599-0.426-0.991-1.126-0.991-1.918 c0-1.299,1.053-2.353,2.353-2.353c1.299,0,2.353,1.054,2.353,2.353C41.697,42.734,41.305,43.434,40.705,43.86z" fill="#2E7EB8"/><g><path d="M60.7,29.153c-1.119-1.406-2.581-2.503-4.224-3.19c-0.306-4.111-2.037-7.917-4.952-10.832 c-3.225-3.225-7.542-5.002-12.154-5.002c-5.136,0-9.986,2.323-13.291,6.292c-1.267-0.358-2.555-0.539-3.848-0.539 c-6.201,0-11.544,3.92-13.466,9.701C6.783,26.166,5,27.308,3.638,28.889C1.937,30.865,1,33.402,1,36.035 c0,5.957,4.846,10.803,10.803,10.803h2.839h8.154V42.25h-8.154h-2.839c-3.427,0-6.215-2.788-6.215-6.215 c0-3.173,2.246-5.796,5.341-6.238l1.571-0.224l0.344-1.549c0.988-4.446,4.848-7.552,9.386-7.552c1.27,0,2.546,0.263,3.792,0.782 l1.731,0.721l1.051-1.554c2.416-3.571,6.365-5.703,10.564-5.703c7.047,0,12.567,5.52,12.567,12.567v2.193l1.789,0.404 c2.842,0.642,4.768,3.145,4.684,6.086l-0.001,0.066c0,2.041-0.993,3.85-2.517,4.984v5.154c4.128-1.511,7.091-5.462,7.105-10.105 C63.061,33.55,62.246,31.095,60.7,29.153z" fill="#2E7EB8"/></g></svg>\
<p class="signup-price">Sign Up / Login</p>\
</div>\
<div v-on:click="goToDiy()" class="diy-button clearfix waves-effect waves-default">\
<svg class="ssl-svg3 center" height="60" width="100%" viewBox="0 0 33 33" xmlns="http://www.w3.org/2000/svg"><path d="M13.641 8.239c2.021-1.023 3.667-2.107 4.591-2.76 1.732 1.223 5.988 3.967 10.535 4.972-.121 1.343-.432 3.75-1.211 6.384l2.445 1.14c1.351-4.386 1.468-8.24 1.476-8.577l.026-1.163-1.152-.17C24.813 7.249 19.1 2.848 19.043 2.805l-.81-.631-.81.63C17.387 2.833 15 4.67 11.825 6.192 12.553 6.762 13.167 7.456 13.641 8.239zM18.232 28.08c-4.332-1.375-6.896-4.98-8.415-8.664-.851.328-1.754.504-2.677.514 1.758 4.531 4.947 9.158 10.734 10.795l.357.102.359-.102c3.113-.881 5.475-2.629 7.267-4.76l-2.523-1.178C21.988 26.24 20.316 27.418 18.232 28.08z" fill="#2B79C2"/><path d="M26.357 16.275c.527-1.839.818-3.558.979-4.827-3.756-1.059-7.178-3.089-9.104-4.373-.992.662-2.383 1.521-4.011 2.344.172.443.307.904.396 1.382L26.357 16.275zM18.232 26.688c1.516-.551 2.782-1.422 3.845-2.486l-11.01-5.135C12.42 22.287 14.627 25.379 18.232 26.688z" fill="#2B79C2"/><path d="M30.555,19.479l-16.966-7.912c-0.23-2.219-1.58-4.266-3.749-5.276C7.375,5.141,4.561,5.655,2.662,7.37 L7.616,9.68l0.639,3.115l-2.797,1.512l-4.953-2.311c-0.094,2.557,1.322,5.042,3.787,6.193c2.168,1.01,4.604,0.729,6.451-0.52 l16.966,7.91c1.686,0.787,3.688,0.057,4.475-1.627C32.969,22.268,32.24,20.264,30.555,19.479z M28.001,23.615 c-0.731-0.34-1.048-1.211-0.707-1.943s1.212-1.049,1.943-0.707s1.049,1.211,0.708,1.943C29.604,23.641,28.733,23.957,28.001,23.615 z" fill="#454C51"/></svg>\
<div><p class="center bigger-text"><b>DIY</b></p></div>\
</div>\
</div>',
methods: {
goToDiy: function() {
this.$parent._data.currentViewSsl = 'security-view-diy';
},
goToAutoDns: function() {
if(bootFlag === true) {
return;
}
vm.currentViewMain = 'auto-dns-view';
resetNav(document.getElementById("nav-auto-dns"));
}
}
});
const settingsView = Vue.component('settings-view', {
template: '\
<div>\
Settings\
</div>',
});
const userPasswordView = Vue.component('user-password-view', {
data() {
return {
users: loadJson.users,
currentUser: editThisUser,
resetPassword: '',
componentKey: false,
};
},
template: '\
<form @submit.prevent="updatePassword" id="reset-password-form">\
<div class="modal-content">\
<h4>Password Reset </h4>\
<p>User: <b>{{currentUser}}</b></p>\
<div class="input-field directory-name-field">\
<input @blur="maybeResetForm()" v-model="resetPassword" id="reset-password" required type="password" class="validate">\
<label for="reset-password">New Password</label>\
</div>\
</div>\
<div class="modal-footer">\
<a href="#!" class="modal-close waves-effect waves-green btn-flat">Go Back</a>\
<button id="submit-reset-password-form" class="btn green waves-effect waves-light" type="submit">\
Update Password\
</button>\
</div>\
</form>',
methods: {
maybeResetForm: function() {
if (this.resetPassword === '') {
document.getElementById("reset-password-form").reset();
}
},
updatePassword: function() {
hashPassword(this.resetPassword).then(hashObj => {
loadJson.users[this.currentUser].password = hashObj.hashPassword;
loadJson.users[this.currentUser].salt = hashObj.salt;
fs.writeFileSync(configFile, JSON.stringify(loadJson), 'utf8');
this.resetPassword = '';
document.getElementById("reset-password-form").reset();
modalInstance[0].close();
iziToast.success({
title: 'Password Updated',
position: 'topCenter',
timeout: 2500
});
});
}
}
});
const userFoldersView = Vue.component('user-folders-view', {
data() {
return {
directories: loadJson.folders,
users: loadJson.users,
currentUser: editThisUser,
selectInstance: null,
};
},
template: '\
<form @submit.prevent="updateFolders" id="update-folders-form">\
<div class="modal-content">\
<h4>User Folders</h4>\
<p>User: <b>{{currentUser}}</b></p>\
<select :disabled="Object.keys(directories).length === 0" id="edit-user-dirs" multiple>\
<option disabled selected value="" v-if="Object.keys(directories).length === 0">You must add a directory before adding a user</option>\
<option :selected="users[currentUser].vpaths.includes(value)" v-for="(key, value) in directories" :value="value">{{ value }}</option>\
</select>\
</div>\
<div class="modal-footer">\
<a href="#!" class="modal-close waves-effect waves-green btn-flat">Go Back</a>\
<button id="submit-reset-password-form" class="btn green waves-effect waves-light" type="submit">\
Update\
</button>\
</div>\
</form>',
mounted: function () {
this.selectInstance = M.FormSelect.init(document.querySelectorAll("#edit-user-dirs"));
},
beforeDestroy: function() {
this.selectInstance[0].destroy();
},
methods: {
maybeResetForm: function() {
},
updateFolders: function() {
loadJson.users[this.currentUser].vpaths = this.selectInstance[0].getSelectedValues();
fs.writeFileSync(configFile, JSON.stringify(loadJson), 'utf8');
modalInstance[0].close();
iziToast.success({
title: 'User Updated',
position: 'topCenter',
timeout: 2500
});
}
}
});
const bootView = Vue.component('boot-view', {
template: "\
<div>\
<div id='bars'>\
<div class='bar'></div>\
<div class='bar'></div>\
<div class='bar'></div>\
<div class='bar'></div>\
<div class='bar'></div>\
<div class='bar'></div>\
<div class='bar'></div>\
<div class='bar'></div>\
<div class='bar'></div>\
<div class='bar'></div>\
</div>\
<div id='boot-server-text' class='boot-server-text'>\
Booting Server\
</div>\
<div id='post-boot-content'></div>\
</div>",
});
const autoDnsView = Vue.component('auto-dns-view', {
data() {
return {
username: '',
password: '',
};
},
template: '\
<div>\
<div class="row auto-dns-selection">\
<div class="col m6 s12 auto-dns-selection-item">\
<div v-on:click="goToSignUp()" class="card auto-dns-card auto-dns-sign-up-item">\
<div class="section-header">Sign Up</div>\
<svg viewBox="0 0 128 128" height="120" width="100%" xmlns="http://www.w3.org/2000/svg"><path d="M94.894,68.493c-1.379-4.803-5.663-8.043-10.661-8.063h-0.631c0.146-3.979-0.709-7.176-2.677-10.032 c-2.403-3.498-5.605-5.677-9.788-6.663c-1.014-0.237-2.09-0.357-3.197-0.357c-4.143,0-9.78,1.83-13.333,6.942 c-1.344-0.545-2.772-0.822-4.249-0.822c-5.846,0-10.765,4.5-11.299,10.287c-0.633,0.333-1.228,0.719-1.773,1.149 c-1.67,1.311-2.967,3.049-3.752,5.025c-1.284,3.234-1.095,6.848,0.518,9.914c1.72,3.263,4.408,5.412,7.774,6.215l0.023-0.096 c0.691,0.135,2.776,0.148,9.075,0.188l5.487,0.037l0.012,0.071l0.348,0.003c3.083,0.029,9.591,0.055,15.166,0.076l4.354,0.018 l-0.024,0.042l6.333,0.045c0.85,0,1.507-0.01,2.126-0.029c3.362-0.11,6.442-1.754,8.451-4.513 C95.189,75.181,95.816,71.743,94.894,68.493z M43.606,62.33c-0.108-0.479-0.162-0.98-0.162-1.494c0-3.807,3.102-6.904,6.915-6.904 c1.844,0,3.579,0.724,4.884,2.039l0.184,0.186l0.247-0.087c0.697-0.244,1.267-0.758,1.565-1.407 c0.272-0.583,0.566-1.105,0.901-1.598c2.562-3.852,6.742-5.224,9.8-5.224c0.748,0,1.483,0.08,2.181,0.239 c3.054,0.717,5.386,2.302,7.132,4.846c1.572,2.293,2.148,5.027,1.813,8.601l-0.039,0.401c-0.078,0.745,0.174,1.503,0.693,2.082 c0.514,0.561,1.241,0.884,1.998,0.884h2.496c3.005,0.01,5.571,1.949,6.385,4.831c0.55,1.897,0.177,3.933-1.022,5.587 c-1.191,1.632-3.01,2.611-4.991,2.682c-0.573,0.019-1.188-0.026-1.983,0.019H45.094c-3.293-0.01-5.615-1.387-7.097-4.216 c-1.002-1.913-1.118-4.172-0.32-6.194c0.504-1.246,1.32-2.342,2.346-3.154l0.12-0.089c0.522-0.389,1.062-0.703,1.594-0.927 c0.036-0.013,0.109-0.031,0.261-0.073c0.359-0.102,0.902-0.256,1.423-0.587l0.247-0.156L43.606,62.33z" fill="#2E79BE"/><path d="M116.277,93.951c0.098-0.469,0.137-0.958,0.137-1.447v-59.98c0-5.357-4.047-9.677-9.032-9.677h-1.916 h-4.086H20.638c-4.985,0-9.032,4.321-9.032,9.677v59.98c0,0.489,0.039,0.977,0.098,1.447H2.535v1.505 c0,5.376,4.027,9.697,9.012,9.697h104.906c4.966,0,9.013-4.321,9.013-9.697v-1.505H116.277z M71.194,100.246 c0,1.036-0.684,1.877-1.564,1.877H58.37c-0.88,0-1.564-0.821-1.564-1.877v-1.212c0-1.056,0.684-1.896,1.564-1.896H69.63 c0.88,0,1.564,0.86,1.564,1.896V100.246z M107.577,93.951H20.423V32.368h79.093h3.882h4.179V93.951z" fill="#2D3E4F"/></svg>\
</div>\
</div>\
<div class="col m6 s12 auto-dns-selection-item">\
<div class="card auto-dns-card">\
<div class="section-header">Login</div>\
<form id="login-form" class="" @submit.prevent="login">\
<div class="row row-mod">\
<div class="input-field directory-name-field col s12">\
<input @blur="maybeResetForm()" v-model="username" id="login-username" required type="text" class="validate">\
<label for="login-username">Username</label>\
</div>\
<div class="input-field directory-name-field col s12">\
<input @blur="maybeResetForm()" v-model="password" id="login-password" required type="password" class="validate">\
<label for="login-password">Password</label>\
</div>\
<div class="col s12">\
<button class="btn green waves-effect waves-light login-button" type="submit">\
Login\
</button>\
</div>\
</div>\
</form>\
</div>\
</div>\
</div>\
<div class="row">\
<div class="col s12">\
<div class="card">\
<div class="row row-mod">\
<div class="section-header">mStream Auto DNS</div>\
<div class="col s12">\
<ul class="browser-default">\
<li>Get your own personal domain @ https://your-name.mstream.io</li>\
<li>Automatically configures SSL Encryption for your server</li>\
<li>State of the art \'Hole Punching\' software guarantees your server stays online as long as you have a working internet connection</li>\
<li>Auto DNS software can be re-used for any self-hosted service. You can use it host your own blog, store, or chat service right our of your own home!</li>\
</ul>\
mStream Auto DNS comes with everything you need to get your new server online in seconds. Think of it as your private cloud.\
</div>\
</div>\
</div>\
</div>\
</div>\
</div>',
methods: {
maybeResetForm: function() {
if (this.username === '' && this.password === '') {
document.getElementById("login-form").reset();
}
},
goToSignUp: function() {
shell.openExternal('https://mstream.io');
},
login: function() {
iziToast.warning({
title: 'Incorrect Username or Password',
position: 'topCenter',
timeout: 3500
});
}
}
});
var vModal = new Vue({
el: '#switcherModal',
components: {
'user-password-view': userPasswordView,
'user-folders-view': userFoldersView,
},
data: {
componentKey: false,
currentViewModal: false
}
});
var vm = new Vue({
el: '#switcherMain',
components: {
'folders-view': foldersView,
'about-view': aboutView,
'users-view': usersView,
'network-view': networkView,
'security-view': securityView,
'settings-view': settingsView,
'boot-view': bootView,
'auto-dns-view': autoDnsView
},
data: {
currentViewMain: false
}
});
vm.currentViewMain = 'folders-view';
document.getElementById("nav-directories").onclick = function(){
if(bootFlag === true) {
return;
}
vm.currentViewMain = 'folders-view';
resetNav(this);
}
document.getElementById("nav-about").onclick = function(){
if(bootFlag === true) {
return;
}
vm.currentViewMain = 'about-view';
resetNav(this);
}
document.getElementById("nav-users").onclick = function(){
if(bootFlag === true) {
return;
}
vm.currentViewMain = 'users-view';
resetNav(this);
}
document.getElementById("nav-network").onclick = function(){
if(bootFlag === true) {
return;
}
vm.currentViewMain = 'network-view';
resetNav(this);
}
document.getElementById("nav-security").onclick = function(){
if(bootFlag === true) {
return;
}
vm.currentViewMain = 'security-view';
resetNav(this);
}
document.getElementById("nav-auto-dns").onclick = function(){
if(bootFlag === true) {
return;
}
vm.currentViewMain = 'auto-dns-view';
resetNav(this);
}
function resetNav(that) {
document.querySelectorAll('.left-nav-button').forEach((el) => {
el.classList.remove("nav-selected");
});
if (that) {
that.classList.add('nav-selected');
}
}
document.getElementById("boot-server-button").onclick = function(){
if(!loadJson.folders) {
iziToast.warning({
title: 'You must set tat least one folder',
position: 'topCenter',
timeout: 3500
});
resetNav(document.getElementById("nav-directories"));
vm.currentViewMain = 'folders-view';
return;
}
if(!loadJson.port) {
iziToast.warning({
title: 'You must set the port before booting the server',
position: 'topCenter',
timeout: 3500
});
resetNav(document.getElementById("nav-network"));
vm.currentViewMain = 'network-view';
return;
}
if(bootFlag === true) {
return;
}
vm.currentViewMain = 'boot-view';
document.getElementById("boot-server-button").innerHTML = 'Booting...'
bootFlag = true;
resetNav();
if (document.getElementById("boot-server-checkbox").checked === true) {
loadJson.autoboot = true;
}
setTimeout(() => {
ipcRenderer.send('start-server', loadJson);
setTimeout(() => {
document.getElementById("boot-server-button").innerHTML = 'Success';
document.getElementById("boot-server-text").innerHTML = 'Server Booted!';
// document.getElementById("post-boot-content").innerHTML = '<div>This window will automatically close in <span id="countdown">30</span> seconds to save on memory</div>';
const localhostAdd = loadJson.ssl && loadJson.ssl.cert && loadJson.ssl.key ? 'https' : 'http' + '://localhost:' + loadJson.port;
document.getElementById("post-boot-content").innerHTML = '<div class="row">\
<div class="col s12">\
<div class="card">\
<div class="about-content-section">\
<div>This window will automatically close in <span id="countdown">30</span> seconds to save on memory</div>\
<br>\
<div>Test mStream locally at: <a href="'+localhostAdd+'">'+localhostAdd+'</a></div>\
</div>\
</div>\
</div>\
</div>';
var countdown = 30;
setInterval(() => {
countdown--;
if(countdown === 0){
var window = remote.getCurrentWindow();
window.close();
}else{
document.getElementById("countdown").innerHTML = countdown;
}
}, 1000);
}, 2500);
}, 2500);
}
}
</script>
</body>
</html>