Initial import

This commit is contained in:
Nextcloud Team 2021-11-30 11:20:42 +01:00 committed by Lukas Reschke
commit 2295a33590
884 changed files with 93939 additions and 0 deletions

View file

@ -0,0 +1 @@
I_AM_HERE

79
php/public/forms.js Normal file
View file

@ -0,0 +1,79 @@
"use strict";
(function (){
var lastError;
function showError(message) {
const body = document.getElementsByTagName('body')[0]
const toast = document.createElement("div")
toast.className = "toast error"
toast.prepend(message)
if (lastError) {
lastError.remove()
}
lastError = toast
body.prepend(toast)
setTimeout(toast.remove.bind(toast), 3000)
}
function handleEvent(e) {
const xhr = e.target;
if (xhr.status === 201) {
window.location.replace(xhr.getResponseHeader('Location'));
}
if (xhr.status === 422) {
showError(xhr.response);
}
if (xhr.status === 500) {
showError("Server error. Please see the logs for details.");
}
}
function disable(element) {
document.getElementById('overlay').classList.add('loading');
element.classList.add('loading');
element.disabled = true;
}
function enable(element) {
document.getElementById('overlay').classList.remove('loading');
element.classList.remove('loading');
element.disabled = false;
}
function initForm(form) {
function submit(event)
{
if (lastError) {
lastError.remove()
}
var xhr = new XMLHttpRequest();
xhr.addEventListener('load', handleEvent);
xhr.addEventListener('error', () => showError("Failed to talk to server."));
xhr.addEventListener('load', () => enable(event.submitter));
xhr.addEventListener('error', () => enable(event.submitter));
xhr.open(form.method, form.getAttribute("action"));
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
disable(event.submitter);
xhr.send(new URLSearchParams(new FormData(form)));
event.preventDefault();
}
form.onsubmit = submit;
console.info(form);
}
function initForms() {
const forms = document.querySelectorAll('form.xhr')
console.info("Making " + forms.length + " form(s) use XHR.");
for (const form of forms) {
initForm(form);
}
}
if (document.readyState === 'loading') {
// Loading hasn't finished yet
document.addEventListener('DOMContentLoaded', initForms);
} else { // `DOMContentLoaded` has already fired
initForms();
}
})()

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

BIN
php/public/img/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

1
php/public/img/logo.svg Normal file
View file

@ -0,0 +1 @@
<svg width="256" height="128" version="1.1" viewBox="0 0 256 128" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke-width="22"><circle cx="40" cy="64" r="26" stroke="#ffffff" fill="none"/><circle cx="216" cy="64" r="26" stroke="#ffffff" fill="none"/><circle cx="128" cy="64" r="46" stroke="#ffffff" fill="none"/></g></svg>

After

Width:  |  Height:  |  Size: 330 B

140
php/public/index.php Normal file
View file

@ -0,0 +1,140 @@
<?php
declare(strict_types=1);
// increase memory limit to 2GB
ini_set('memory_limit', '2048M');
// set max execution time to 2h just in case of a very slow internet connection
ini_set('max_execution_time', '7200');
use DI\Container;
use Slim\Csrf\Guard;
use Slim\Factory\AppFactory;
use Slim\Views\Twig;
use Slim\Views\TwigMiddleware;
require __DIR__ . '/../vendor/autoload.php';
$container = \AIO\DependencyInjection::GetContainer();
$dataConst = $container->get(\AIO\Data\DataConst::class);
ini_set('session.save_path', $dataConst->GetSessionDirectory());
// Auto logout on browser close
ini_set('session.cookie_lifetime', '0');
// Make sure to delete all stale sessions after at least one day
ini_set('session.gc_maxlifetime', '86400');
ini_set('session.gc_probability', '1');
ini_set('session.gc_divisor', '1');
// Create app
AppFactory::setContainer($container);
$app = AppFactory::create();
$responseFactory = $app->getResponseFactory();
// Register Middleware On Container
$container->set(Guard::class, function () use ($responseFactory) {
$guard = new Guard($responseFactory);
$guard->setPersistentTokenMode(true);
return $guard;
});
// Register Middleware To Be Executed On All Routes
session_start();
$app->add(Guard::class);
// Create Twig
$twig = Twig::create(__DIR__ . '/../templates/', ['cache' => false]);
$app->add(TwigMiddleware::create($app, $twig));
$twig->addExtension(new \AIO\Twig\CsrfExtension($container->get(Guard::class)));
// Auth Middleware
$app->add(new \AIO\Middleware\AuthMiddleware($container->get(\AIO\Auth\AuthManager::class)));
// API
$app->post('/api/docker/watchtower', AIO\Controller\DockerController::class . ':StartWatchtowerContainer');
$app->post('/api/docker/start', AIO\Controller\DockerController::class . ':StartContainer');
$app->post('/api/docker/backup', AIO\Controller\DockerController::class . ':StartBackupContainerBackup');
$app->post('/api/docker/backup-check', AIO\Controller\DockerController::class . ':StartBackupContainerCheck');
$app->post('/api/docker/restore', AIO\Controller\DockerController::class . ':StartBackupContainerRestore');
$app->post('/api/docker/stop', AIO\Controller\DockerController::class . ':StopContainer');
$app->get('/api/docker/logs', AIO\Controller\DockerController::class . ':GetLogs');
$app->post('/api/auth/login', AIO\Controller\LoginController::class . ':TryLogin');
$app->get('/api/auth/getlogin', AIO\Controller\LoginController::class . ':GetTryLogin');
$app->post('/api/auth/logout', AIO\Controller\LoginController::class . ':Logout');
$app->post('/api/configuration', \AIO\Controller\ConfigurationController::class . ':SetConfig');
// Views
$app->get('/containers', function ($request, $response, $args) use ($container) {
$view = Twig::fromRequest($request);
/** @var \AIO\Data\ConfigurationManager $configurationManager */
$configurationManager = $container->get(\AIO\Data\ConfigurationManager::class);
$dockerActionManger = $container->get(\AIO\Docker\DockerActionManager::class);
$dockerActionManger->ConnectMasterContainerToNetwork();
$dockerController = $container->get(\AIO\Controller\DockerController::class);
$dockerController->StartDomaincheckContainer();
$view->addExtension(new \AIO\Twig\ClassExtension());
return $view->render($response, 'containers.twig', [
'domain' => $configurationManager->GetDomain(),
'borg_backup_host_location' => $configurationManager->GetBorgBackupHostLocation(),
'borg_backup_mode' => $configurationManager->GetBorgBackupMode(),
'nextcloud_password' => $configurationManager->GetSecret('NEXTCLOUD_PASSWORD'),
'containers' => (new \AIO\ContainerDefinitionFetcher($container->get(\AIO\Data\ConfigurationManager::class), $container))->FetchDefinition(),
'borgbackup_password' => $configurationManager->GetSecret('BORGBACKUP_PASSWORD'),
'is_mastercontainer_update_available' => $dockerActionManger->IsMastercontainerUpdateAvailable(),
'has_backup_run_once' => $configurationManager->hasBackupRunOnce(),
'backup_exit_code' => $dockerActionManger->GetBackupcontainerExitCode(),
'was_start_button_clicked' => $configurationManager->wasStartButtonClicked(),
'has_update_available' => $dockerActionManger->isAnyUpdateAvailable(),
'last_backup_time' => $configurationManager->GetLastBackupTime(),
]);
})->setName('profile');
$app->get('/login', function ($request, $response, $args) {
$view = Twig::fromRequest($request);
return $view->render($response, 'login.twig');
});
$app->get('/setup', function ($request, $response, $args) use ($container) {
$view = Twig::fromRequest($request);
/** @var \AIO\Data\Setup $setup */
$setup = $container->get(\AIO\Data\Setup::class);
if(!$setup->CanBeInstalled()) {
return $view->render(
$response,
'already-installed.twig'
);
}
return $view->render(
$response,
'setup.twig',
[
'password' => $setup->Setup(),
]
);
});
// Auth Redirector
$app->get('/', function (\Psr\Http\Message\RequestInterface $request, \Psr\Http\Message\ResponseInterface $response, $args) use ($container) {
$authManager = $container->get(\AIO\Auth\AuthManager::class);
/** @var \AIO\Data\Setup $setup */
$setup = $container->get(\AIO\Data\Setup::class);
if($setup->CanBeInstalled()) {
return $response
->withHeader('Location', '/setup')
->withStatus(302);
}
if($authManager->IsAuthenticated()) {
return $response
->withHeader('Location', '/containers')
->withStatus(302);
} else {
return $response
->withHeader('Location', '/login')
->withStatus(302);
}
});
$app->run();

206
php/public/style.css Normal file
View file

@ -0,0 +1,206 @@
html, body {
padding: 0;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen-Sans, Cantarell, Ubuntu, Helvetica Neue, Arial, Noto Color Emoji, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;;
}
a {
text-decoration: none;
}
.button {
padding: 6px 16px;
width: auto;
min-height: 34px;
cursor: pointer;
background-color:#0082c9;
font-weight: bold;
border-radius: 100px;
margin: 3px 3px 3px 0;
font-size: 13px;
color: white;
border: 1px solid black;
outline: none;
}
ul {
list-style: none;
padding: 0;
}
li {
padding-bottom: 5px;
}
span.error {
background-color: #e9322d;
}
div.toast.error {
border-left-color: #e9322d;
}
.status {
display: inline-block;
height: 16px;
width: 16px;
vertical-align: text-bottom
}
.status {
border-radius: 50%
}
span.success {
background-color: #46ba61;
}
span.running {
background-color: rgb(255, 208, 0);
}
div.toast.success {
border-left-color: #46ba61;
}
div.toast {
border-left: 3px solid;
right: 10px;
min-width: 200px;
box-shadow: 0 0 6px 0 rgba(77, 77, 77, 0.3);
padding: 12px;
margin-top: 45px;
position: fixed;
z-index: 1;
border-radius: 3px;
background: none;
background-color: white;
}
.login {
padding: 50px;
background-color: white;
width: 500px;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
border-radius: 16px;
}
.login > .monospace {
font-family: monospace;
font-size: 17px;
}
input {
padding: 10px;
margin-bottom: 15px;
}
.login > form > input {
width: 100%;
}
.login > img {
margin-left: auto;
margin-right: auto;
display: block;
}
.login > .button {
margin-left: auto;
margin-right: auto;
display: block;
text-align: center;
line-height: 33px;
margin-top: 20px;
}
.login-wrapper {
height: 100%;
width: 100%;
background-color: #0082c9;
background-image: linear-gradient(
40deg
, #0082c9 0%, #30b6ff 100%);
background-size: contain;
background-image: url('/img/background.png'), linear-gradient(
40deg
, #0082c9 0%, #30b6ff 100%);
position: relative;
}
.content {
padding: 20px;
max-width: 100%;
word-break: break-word;
max-width: 450px;
margin: 0 auto;
}
.logo {
background-image: url('/img/logo.svg');
height: 50px;
background-repeat: no-repeat;
display: inline-flex;
background-size: contain;
background-position: center center;
width: 62px;
position: absolute;
left: 12px;
top: 1px;
bottom: 1px;
}
header {
background-color: #0082c9;
background-image: linear-gradient(40deg, #0082c9 0%, #30b6ff 100%);
height: 50px;
justify-content: space-between;
display: flex;
}
.loading {
color: grey;
}
#overlay {
position: fixed; /* Sit on top of the page content */
display: none; /* Hidden by default */
width: 100%; /* Full width (cover the whole page) */
height: 100%; /* Full height (cover the whole page) */
top: 0;
left: 0;
background-color: rgba(0,0,0,0.5); /* Black background with opacity */
z-index: 2;
}
#overlay.loading {
display: block;
}
.loader {
border: 16px solid #f3f3f3;
border-radius: 50%;
border-top: 16px solid #3498db;
width: 120px;
height: 120px;
-webkit-animation: spin 2s linear infinite; /* Safari */
animation: spin 2s linear infinite;
position: absolute;
top: calc(50% - 60px);
left: calc(50% - 60px);
}
/* Safari */
@-webkit-keyframes spin {
0% { -webkit-transform: rotate(0deg); }
100% { -webkit-transform: rotate(360deg); }
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}