Compare commits
	
		
			18 Commits
		
	
	
		
			1.0.4
			...
			e782254749
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| e782254749 | |||
| 211ddc21ef | |||
| 7ae74eb72d | |||
| 38b8c4a342 | |||
| 6b70259829 | |||
| 586dc4698f | |||
|  | ed4c3593a4 | ||
|  | 10d3de84d6 | ||
|  | 91dc523420 | ||
|  | 06e9ca7249 | ||
|  | c42d89bea9 | ||
| 4de1511546 | |||
| 99b248577e | |||
| 8aed85fba5 | |||
| dab4cba11d | |||
| f5b93f5d39 | |||
| 5dacc36836 | |||
| 453f84f0e3 | 
| @@ -69,12 +69,12 @@ RUN apk --no-cache add php${PHP_VERSION} \ | ||||
|     rm -rf /var/cache/apk/* | ||||
|  | ||||
| COPY nginx.conf /etc/nginx/nginx.conf | ||||
|  | ||||
| RUN mkdir -p /usr/share/nginx/html | ||||
| COPY *.html    /usr/share/nginx/html | ||||
| COPY *.php   /usr/share/nginx/html | ||||
| COPY *.css /usr/share/nginx/html | ||||
| COPY *.js /usr/share/nginx/html | ||||
| COPY img /usr/share/nginx/html/img | ||||
| RUN chown -R nginx:nginx /usr/share/nginx/html | ||||
|  | ||||
| RUN mkdir -p /usr/share/nginx/html/shared | ||||
|   | ||||
							
								
								
									
										84
									
								
								common.js
									
									
									
									
									
								
							
							
						
						| @@ -18,13 +18,13 @@ function check_deployments() { | ||||
| 		console.log(data[k]); | ||||
| 		service_name = data[k].name; | ||||
| 		orig_service_name = data[k].orig_name; | ||||
| 		content = data[k].content; | ||||
| 		version = data[k].version; | ||||
| 		installed = data[k].installed; | ||||
| 		if (installed=='true') { | ||||
| 			html_data += '<div><a href="#" onclick="reinstall(\''+service_name+'\',\''+service_name+'\')">'+orig_service_name+'</a> - '+content+' - INSTALLED</div>'; | ||||
| 			html_data += '<div><a href="#" onclick="reinstall(\''+service_name+'\',\''+service_name+'\')">'+orig_service_name+'</a> - '+version+' - INSTALLED</div>'; | ||||
| 		} | ||||
| 		else { | ||||
| 			html_data += '<div><a href="#" onclick="load_template(\''+service_name+'\',\''+service_name+'\')">'+orig_service_name+'</a> - '+content+'</div>'; | ||||
| 			html_data += '<div><a href="#" onclick="load_template(\''+service_name+'\',\''+service_name+'\')">'+orig_service_name+'</a> - '+version+'</div>'; | ||||
| 		} | ||||
| 		html_data += '<div id="'+service_name+'" class="deployment"></div>'; | ||||
| 	} | ||||
| @@ -111,10 +111,14 @@ function check_vpn() { | ||||
|         if (data=="2") { | ||||
|           $('#vpn_off').hide(); | ||||
|           $('#vpn_on').show(); | ||||
|           $('#pro_off').hide(); | ||||
|           $('#pro_on').show(); | ||||
|         } | ||||
|         else { | ||||
|           $('#vpn_on').hide(); | ||||
|           $('#vpn_off').show(); | ||||
|           $('#pro_on').hide(); | ||||
|           $('#pro_off').show(); | ||||
|         } | ||||
|         setTimeout(check_vpn, 10000); | ||||
|   }); | ||||
| @@ -266,6 +270,25 @@ function confirm_uninstall(additional) { | ||||
|   }); | ||||
| } | ||||
|  | ||||
| function update_deployment(additional) { | ||||
|   //jQuery("#"+additional).html('Loading...'); | ||||
|   pars = ''; | ||||
|   jQuery('input.additional_'+additional).each(function(index) { | ||||
| 	console.log('Field ' + $(this).attr('name') + ': ' + $(this).val()); | ||||
| 	//pars += '&'+$(this).attr('id') + '=' + $(this).val(); | ||||
| 	pars += '&'+$(this).attr('name') + '=' + $(this).val(); | ||||
|   }); | ||||
|   //console.log(pars); | ||||
|   var url  = 'scan.php?op=edit&additional='+additional+pars; | ||||
|   jQuery.get(url, function(data) { | ||||
|         console.log('edit '+additional+': '+data); | ||||
|           if (data!="") { | ||||
|                 jQuery("#"+additional).html(data); | ||||
|                 setTimeout(check_deployment, 1000, additional); | ||||
|           } | ||||
|   }); | ||||
| } | ||||
|  | ||||
| function request_letsencrypt(domain) { | ||||
|   var url  = 'scan.php?op=request_letsencrypt&domain='+domain; | ||||
|   jQuery.get(url, function(data) { | ||||
| @@ -358,6 +381,61 @@ function get_services() { | ||||
|   }); | ||||
| } | ||||
|  | ||||
| function get_proxy_html() { | ||||
|         proxy_html = ` | ||||
| 	<fieldset> | ||||
| 	<legend>Enable proxy</legend> | ||||
|         <div class="input-group"> | ||||
| 	<form class="form-install" action="#" method="post" id="save_vpn"> | ||||
| 		<div class="row"> | ||||
| 		    <div class="mb-3"> | ||||
| 				<label for="vpn_domain">Please add domain url to download the VPN hash from (default: https://portal.safebox.network):</label> | ||||
| 				<input type="text" class="form-control" name="VPN_DOMAIN" id="vpn_domain" value="https://portal.safebox.network"> | ||||
| 				<div class="invalid-feedback"> | ||||
| 				Please enter a valid domain. | ||||
| 				</div> | ||||
| 		    </div> | ||||
| 		</div> | ||||
| 		<div class="row"> | ||||
| 		    <div class="mb-3"> | ||||
| 				<label for="vpn_pass">Please type in the generated VPN passkey (8 digits):</label> | ||||
| 				<input type="text" class="form-control" name="VPN_PASS" id="vpn_pass" value="" maxlength="8" size="10"> | ||||
| 		    </div> | ||||
| 		</div> | ||||
| 		<div class="row"> | ||||
| 		    <div class="mb-3"> | ||||
| 				<label for="letsencrypt_mail">Please add the letsencrypt mail address:</label> | ||||
| 				<input type="email" class="form-control" name="LETSENCRYPT_MAIL" id="letsencrypt_mail" value=""> | ||||
| 				<div class="invalid-feedback"> | ||||
| 				Please enter a valid email. | ||||
| 				</div> | ||||
| 		    </div> | ||||
| 		</div> | ||||
| 		<div class="row"> | ||||
| 		    <div class="mb-3"> | ||||
| 				<label for="letsencrypt_servername">Please add letsencrypt server name (default is letsencrypt but you can add zerossl too):</label> | ||||
| 				<input type="text" class="form-control" name="LETSENCRYPT_SERVERNAME" id="letsencrypt_servername" value="letsencrypt"> | ||||
| 		    </div> | ||||
| 		</div> | ||||
| 		<div class="row buttons"> | ||||
| 		    <div class="mb-3"> | ||||
| 			<button class="btn btn-lg btn-primary btn-block" type="button" id="vpn_save_btn"> Save </button> | ||||
| 		    </div> | ||||
| 		</div> | ||||
| 	</form> | ||||
| 	</div> | ||||
| 	</fieldset> | ||||
| 	<script> | ||||
| 	jQuery('#vpn_save_btn').click(function() { | ||||
| 		console.log('vpn save'); | ||||
| 		jQuery('#vpn').html('Loading...'); | ||||
| 		save_vpn(); | ||||
| 	}); | ||||
| 	</script> | ||||
|         `; | ||||
| 	jQuery("#vpn").html(proxy_html); | ||||
| } | ||||
|  | ||||
| function check_containers() { | ||||
|   var url  = 'scan.php?op=check_containers'; | ||||
|   jQuery.get(url, function(data) { | ||||
|   | ||||
| @@ -141,23 +141,24 @@ function show_service($name, $containers) { | ||||
| } | ||||
|  | ||||
| function show_service_update($name, $update, $uptodate, $error) { | ||||
| 	$str = '<table id="update_'.$name.'">'; | ||||
| 	$str .= "<tr><th>{$name}</th></tr>"; | ||||
|  | ||||
| 	$str = ""; | ||||
| 	$update = trim($update); | ||||
| 	if (!empty($update)) { | ||||
| 		$arr = explode(" ",$update); | ||||
| 		foreach ($arr as $container) { | ||||
| 			$str .= "<tr><td> </td><td>".$container."</td><td><div id=\"status_".$name."\">UPDATE AVAILABLE</div></td><td><a href=\"javascript:void(0)\" onclick=\"upgrade('{$name}')\">UPDATE</a></td></tr>"; | ||||
| 			$str .= "<tr><td> </td><td>".$container."</td><td><div id=\"status_".$name."\">UPDATE AVAILABLE</div></td><td> </td></tr>"; | ||||
| 		} | ||||
| 		$update_str = "<a href=\"javascript:void(0)\" onclick=\"upgrade('{$name}')\">UPDATE</a>"; | ||||
| 	} | ||||
|  | ||||
| 	$uptodate = trim($uptodate); | ||||
| 	if (!empty($uptodate)) { | ||||
| 		$arr = explode(" ",$uptodate); | ||||
| 		foreach ($arr as $container) { | ||||
| 			$str .= "<tr><td> </td><td>".$container."</td><td><div id=\"status_".$name."\">Already up to date</div></td><td><a href=\"javacript:void(0)\" onclick=\"upgrade('{$name}')\">FORCE UPDATE</a></td></tr>"; | ||||
| 			$str .= "<tr><td> </td><td>".$container."</td><td><div id=\"status_".$name."\">Already up to date</div></td><td> </td></tr>"; | ||||
| 		} | ||||
| 		$update_str = "<a href=\"javacript:void(0)\" onclick=\"upgrade('{$name}')\">FORCE UPDATE</a>"; | ||||
| 	} | ||||
|  | ||||
|         $error = trim($error); | ||||
| @@ -165,13 +166,15 @@ function show_service_update($name, $update, $uptodate, $error) { | ||||
|                 $arr = explode(" ",$error); | ||||
|                 foreach ($arr as $container) { | ||||
|                         //$str .= "<tr><td> </td><td>".$container."</td><td>N/A</td><td></td></tr>"; | ||||
|                         $str .= "<tr><td> </td><td>".$container."</td><td><div id=\"status_".$name."\">N/A</div></td><td><a href=\"javascript:void(0)\" onclick=\"upgrade('{$name}')\">TRY UPDATE</a></td></tr>"; | ||||
|                         $str .= "<tr><td> </td><td>".$container."</td><td><div id=\"status_".$name."\">N/A</div></td><td> </td></tr>"; | ||||
|                 } | ||||
| 		$update_str = "<a href=\"javascript:void(0)\" onclick=\"upgrade('{$name}')\">TRY UPDATE</a>"; | ||||
|         } | ||||
|  | ||||
| 	$str .= '</table>'; | ||||
|  | ||||
| 	echo '<table id="update_'.$name.'">'; | ||||
| 	echo "<tr><th>{$name}</th><th> </th><th> </th><th>{$update_str}</th></tr>"; | ||||
| 	echo $str; | ||||
| 	echo '</table>'; | ||||
| } | ||||
|  | ||||
| // not in use | ||||
|   | ||||
							
								
								
									
										
											BIN
										
									
								
								img/app.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 760 B | 
							
								
								
									
										
											BIN
										
									
								
								img/app2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 608 B | 
							
								
								
									
										
											BIN
										
									
								
								img/bell.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 652 B | 
							
								
								
									
										
											BIN
										
									
								
								img/disk.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 709 B | 
							
								
								
									
										
											BIN
										
									
								
								img/disk2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 517 B | 
							
								
								
									
										
											BIN
										
									
								
								img/globe.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 747 B | 
							
								
								
									
										
											BIN
										
									
								
								img/logo.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.8 KiB | 
							
								
								
									
										
											BIN
										
									
								
								img/monitor.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 708 B | 
							
								
								
									
										
											BIN
										
									
								
								img/monitor2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 492 B | 
							
								
								
									
										
											BIN
										
									
								
								img/off.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 684 B | 
							
								
								
									
										
											BIN
										
									
								
								img/on.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 701 B | 
							
								
								
									
										
											BIN
										
									
								
								img/settings.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 660 B | 
							
								
								
									
										
											BIN
										
									
								
								img/settings2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 487 B | 
							
								
								
									
										
											BIN
										
									
								
								img/upgrade.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.6 KiB | 
							
								
								
									
										
											BIN
										
									
								
								img/x2.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 291 B | 
							
								
								
									
										
											BIN
										
									
								
								img/yellow_corner.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| After Width: | Height: | Size: 2.0 KiB | 
| @@ -1,5 +1,5 @@ | ||||
| .hidden {display:none} | ||||
| fieldset {border: 1px solid  #049dff; padding-left: 40px; padding-right: 20px} | ||||
| fieldset {border: 1px solid  #049dff; padding-left: 40px; padding-right: 20px; border-radius: 10px; width: 100%} | ||||
| legend {width: auto;text-align: left !important; padding: 10px; color: #049dff;} | ||||
| fieldset.sub_block {border: 1px solid black; margin:-20px 0px 20px -15px} | ||||
| fieldset.sub_block legend {color: black} | ||||
| @@ -132,3 +132,55 @@ body#scan{ | ||||
|     transform: rotate(135deg); | ||||
|   } | ||||
| } | ||||
|  | ||||
|     .info-container { | ||||
|       position: relative; | ||||
|       display: inline-block; | ||||
|       font-family: Arial, sans-serif; | ||||
|     } | ||||
|  | ||||
|     .info-icon { | ||||
|       background-color: #007BFF; | ||||
|       color: white; | ||||
|       border-radius: 50%; | ||||
|       padding: 4px 8px; | ||||
|       cursor: pointer; | ||||
|       font-weight: bold; | ||||
|       font-size: 14px; | ||||
|       text-align: center; | ||||
|       line-height: 1; | ||||
|       display: inline-block; | ||||
|     } | ||||
|  | ||||
|     .tooltip { | ||||
|       visibility: hidden; | ||||
|       background-color: #333; | ||||
|       color: #fff; | ||||
|       text-align: left; | ||||
|       border-radius: 4px; | ||||
|       padding: 8px; | ||||
|       position: absolute; | ||||
|       z-index: 1; | ||||
|       bottom: 125%; /* above the icon */ | ||||
|       left: 50%; | ||||
|       transform: translateX(-50%); | ||||
|       opacity: 0; | ||||
|       transition: opacity 0.3s; | ||||
|       white-space: nowrap; | ||||
|     } | ||||
|  | ||||
|     .tooltip::after { | ||||
|       content: ""; | ||||
|       position: absolute; | ||||
|       top: 100%; /* bottom of tooltip */ | ||||
|       left: 50%; | ||||
|       margin-left: -5px; | ||||
|       border-width: 5px; | ||||
|       border-style: solid; | ||||
|       border-color: #333 transparent transparent transparent; | ||||
|     } | ||||
|  | ||||
|     .info-container:hover .tooltip { | ||||
|       visibility: visible; | ||||
|       opacity: 1; | ||||
|     } | ||||
|   | ||||
| @@ -8,7 +8,7 @@ | ||||
| <!-- Bootstrap CSS --> | ||||
| <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.2.1/dist/css/bootstrap.min.css" integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS" crossorigin="anonymous"> | ||||
| <!-- Custom styles for this template --> | ||||
| <link href="installer.css?t=5" rel="stylesheet"> | ||||
| <link href="installer.css?t=7" rel="stylesheet"> | ||||
| </head> | ||||
| <body id="manage" class="text-center"> | ||||
| <div class="container-fluid"> | ||||
| @@ -152,6 +152,6 @@ | ||||
| <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> | ||||
| <script src="https://cdn.jsdelivr.net/npm/popper.js@1.14.6/dist/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" crossorigin="anonymous"></script> | ||||
| <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.2.1/dist/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script> | ||||
| <script src="common.js?t=3"></script> | ||||
| <script src="common.js?t=5"></script> | ||||
| </body> | ||||
| </html> | ||||
|   | ||||
							
								
								
									
										204
									
								
								manage2.html
									
									
									
									
									
								
							
							
						
						| @@ -39,6 +39,9 @@ | ||||
| 	label {text-align: left !important;} | ||||
| 	a, a:hover, a:visited {color: orange} | ||||
|  | ||||
| 	fieldset {border: 1px solid  #ffffff; padding-left: 20px; padding-right: 20px; border-radius: 10px;} | ||||
| 	legend {width: auto;text-align: left !important; padding: 10px; color: #ffffff;} | ||||
|  | ||||
|         .profile { | ||||
|             display: flex; | ||||
|             flex-direction: column; | ||||
| @@ -101,6 +104,11 @@ | ||||
|         .toggle.active::after { | ||||
|             transform: translateX(20px); | ||||
|         } | ||||
|         div#themeToggle { | ||||
| 		position: fixed; | ||||
| 		top: 10px; | ||||
| 		right: 10px; | ||||
|         } | ||||
|         .buttons { | ||||
|             display: flex; | ||||
|             justify-content: center; | ||||
| @@ -109,7 +117,8 @@ | ||||
|             cursor: pointer; | ||||
|         } | ||||
|         .buttons button { | ||||
|             padding: 10px 20px; | ||||
|             min-width: 150px; | ||||
|             padding: 10px 10px; | ||||
|             background: none; | ||||
|             border: 1px solid var(--button-border); | ||||
|             border-radius: 10px; | ||||
| @@ -120,17 +129,46 @@ | ||||
| 		color: orange; | ||||
|             	border: 1px solid orange; | ||||
|         } | ||||
|         .left-buttons { | ||||
|             display: flex; | ||||
|             justify-content: center; | ||||
|             gap: 10px; | ||||
|             margin: 20px 0; | ||||
|             cursor: pointer; | ||||
|         } | ||||
|         .left-buttons button { | ||||
|             min-width: 120px; | ||||
|             padding: 5px 5px; | ||||
|             background: none; | ||||
|             border: 1px solid var(--button-border); | ||||
|             border-radius: 10px; | ||||
|             cursor: pointer; | ||||
|             color: var(--text-color); | ||||
|         } | ||||
|         .container-frame { | ||||
| 		border: 1px solid; | ||||
|             	border-radius: 10px; | ||||
| 		padding: 0px; | ||||
| 		margin: 5px; | ||||
| 		height: 98vh; | ||||
|         } | ||||
|         .container { | ||||
| 		clear:both; | ||||
| 		float:none; | ||||
| 		padding-bottom: 10px; | ||||
| 		margin: 5px; | ||||
| 		height: 88vh; | ||||
|         } | ||||
|         .leftside { | ||||
| 		float:left; | ||||
| 		width:20%; | ||||
| 		width:10%; | ||||
|         } | ||||
|         .rightside { | ||||
| 		float:right; | ||||
| 		width:80%; | ||||
| 		width:90%; | ||||
| 		display: flex; | ||||
| 		flex-direction: column; | ||||
| 		height: 88vh; | ||||
|         } | ||||
|         .my-apps { | ||||
|             flex: 1; | ||||
| @@ -141,12 +179,17 @@ | ||||
|             justify-content: flex-start; | ||||
|             align-items: flex-start; | ||||
|             gap: 40px; | ||||
|             min-width: 92%; | ||||
|             max-width: 92%; | ||||
|             min-width: 96%; | ||||
|             max-width: 96%; | ||||
|             margin: 0 auto; | ||||
|             border-radius: 10px; | ||||
|             box-sizing: border-box; | ||||
|         } | ||||
|         .my-apps-container { | ||||
|             width:100%; | ||||
|             display: flex; | ||||
|             flex-wrap: wrap; | ||||
|         } | ||||
|         .app { | ||||
|             display: flex; | ||||
|             flex-direction: column; | ||||
| @@ -160,13 +203,21 @@ | ||||
|             object-fit: contain; | ||||
|             margin-bottom: 10px; | ||||
|         } | ||||
|         .innerDiv { | ||||
|             width:100%; | ||||
|         } | ||||
|         footer { | ||||
| 	    position: fixed; | ||||
| 	    bottom: 0; | ||||
| 	    left: 0; | ||||
| 	    width: 97%; | ||||
|             display: flex; | ||||
|             justify-content: space-between; | ||||
|             align-items: center; | ||||
|             padding: 20px; | ||||
|             font-size: 14px; | ||||
|         } | ||||
| 	    z-index: 1000; | ||||
| 	} | ||||
|         .footer-links { | ||||
|             display: flex; | ||||
|             gap: 15px; | ||||
| @@ -265,6 +316,7 @@ | ||||
|         } | ||||
|  | ||||
|         .input-group input { | ||||
| 		min-width:260px; | ||||
|             margin-top: 5px; | ||||
|             margin-bottom: 5px; | ||||
|             padding: 5px; | ||||
| @@ -368,6 +420,68 @@ | ||||
|             background-image: url("data:image/svg+xml;charset=US-ASCII,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='10' viewBox='0 0 14 10'%3E%3Cpolyline points='1 1 7 7 13 1' style='fill:none;stroke:white;stroke-width:2' /%3E%3C/svg%3E"); | ||||
|         } | ||||
|  | ||||
|  | ||||
|         #popup .input-group { | ||||
|             display: block; | ||||
|         } | ||||
|  | ||||
|         #popup .row { | ||||
|             display: flex; | ||||
|         } | ||||
|  | ||||
| 	.info-container { | ||||
| 		position: relative; | ||||
| 		display: inline-block; | ||||
| 		font-family: Arial, sans-serif; | ||||
| 		margin: 5px 0px 0px 5px; | ||||
| 	} | ||||
|  | ||||
|     .info-icon { | ||||
|       background-color: #007BFF; | ||||
|       color: white; | ||||
|       border-radius: 50%; | ||||
|       padding: 4px 8px; | ||||
|       cursor: pointer; | ||||
|       font-weight: bold; | ||||
|       font-size: 14px; | ||||
|       text-align: center; | ||||
|       line-height: 1; | ||||
|       display: inline-block; | ||||
|     } | ||||
|  | ||||
|     .tooltip { | ||||
|       visibility: hidden; | ||||
|       background-color: #333; | ||||
|       color: #fff; | ||||
|       text-align: left; | ||||
|       border-radius: 4px; | ||||
|       padding: 8px; | ||||
|       position: absolute; | ||||
|       z-index: 1; | ||||
|       bottom: 125%; /* above the icon */ | ||||
|       left: 50%; | ||||
|       transform: translateX(-50%); | ||||
|       opacity: 0; | ||||
|       transition: opacity 0.3s; | ||||
|       white-space: nowrap; | ||||
|     } | ||||
|  | ||||
|     .tooltip::after { | ||||
|       content: ""; | ||||
|       position: absolute; | ||||
|       top: 100%; /* bottom of tooltip */ | ||||
|       left: 50%; | ||||
|       margin-left: -5px; | ||||
|       border-width: 5px; | ||||
|       border-style: solid; | ||||
|       border-color: #333 transparent transparent transparent; | ||||
|     } | ||||
|  | ||||
|     .info-container:hover .tooltip { | ||||
|       visibility: visible; | ||||
|       opacity: 1; | ||||
|     } | ||||
|  | ||||
|         @media (max-width: 768px) { | ||||
|             header { | ||||
|                 flex-direction: column; | ||||
| @@ -422,6 +536,7 @@ | ||||
| </head> | ||||
| <body> | ||||
|  | ||||
| <div class="container-frame"> | ||||
| <div class="container"> | ||||
| <div class="leftside"> | ||||
|     <div class="logo"> | ||||
| @@ -434,17 +549,19 @@ | ||||
| 	<!--<img src="image.png" alt="Profilkép">--> | ||||
|         <div id="vpnBtn">Pro</div> | ||||
|     </div> | ||||
| 	<div class="buttons"> | ||||
|     <div style="text-align:center"> | ||||
| 	Proxy status | ||||
| 	<span id="vpn_on" class="hidden green"><b>ON</b></span> | ||||
| 	<span id="vpn_off" class="hidden red"><b>OFF</b></span> | ||||
|     </div> | ||||
| 	<div class="left-buttons"> | ||||
| 	 	<button id="servicesBtn">Services</button> | ||||
| 	</div> | ||||
|     	<div class="settings">Settings</div> | ||||
| 	<div class="buttons"> | ||||
| 		<button id="updatesBtn">Updates</button> | ||||
| 	</div> | ||||
| 	<div class="buttons"> | ||||
| 	<div class="left-buttons"> | ||||
| 		<button id="repositoriesBtn">Repositories</button> | ||||
| 	</div> | ||||
| 	<div class="buttons"> | ||||
| 	<div class="left-buttons"> | ||||
| 		<button id="systemservicesBtn">System services</button> | ||||
| 	</div> | ||||
| 	<br> | ||||
| @@ -461,13 +578,14 @@ | ||||
| 	<div class="buttons"> | ||||
| 	    <button id="myAppsBtn">My Apps</button> | ||||
| 	    <button id="installAppsBtn">Install Apps</button> | ||||
| 	    <button id="updatesBtn">Updates</button> | ||||
| 	    <button id="backupBtn">Backup</button> | ||||
| 	    <button id="diskBtn">Disk Management</button> | ||||
| 	    <button id="monitorBtn">Monitor</button> | ||||
| 	    <div class="toggle" id="themeToggle"></div> | ||||
| 	</div> | ||||
|  | ||||
| 	<div class="my-apps" id="myAppsContainer"></div> | ||||
| 	<div class="my-apps"><div id="myAppsContainer" class="my-apps-container"></div></div> | ||||
| </div> | ||||
| </div> | ||||
|  | ||||
| @@ -488,7 +606,8 @@ | ||||
|  | ||||
|     <div class="footer-center"> | ||||
|         <p>Want to access your services remotely?</p> | ||||
|         <p><strong><a href="#">Go Pro!</a></strong></p> | ||||
|         <p class="hidden" id="pro_off"><strong><a href="#">Get Pro!</a></strong></p> | ||||
|         <p class="hidden" id="pro_on"><strong><a href="#">Pro settings</a></strong></p> | ||||
|     </div> | ||||
|  | ||||
|     <div class="footer-social"> | ||||
| @@ -497,6 +616,8 @@ | ||||
|     </div> | ||||
| </footer> | ||||
|  | ||||
| </div> | ||||
|  | ||||
| <script> | ||||
|     const toggle = document.getElementById('themeToggle'); | ||||
|     toggle.addEventListener('click', () => { | ||||
| @@ -543,10 +664,10 @@ | ||||
| 		    const appDiv = document.createElement('div'); | ||||
| 		    appDiv.className = 'app'; | ||||
| 		    appDiv.innerHTML = ` | ||||
| 			<img src="${app.image}" alt="${app.name}" title="${app.orig_name}">${app.orig_name} | ||||
| 			<img src="${app.image}" alt="${app.name}" title="${app.orig_name} ${app.version}">${app.orig_name} | ||||
| 		    `; | ||||
| 		    appDiv.addEventListener('click', () => { | ||||
| 			popupText.textContent = `You clicked on ${app.name}!`; | ||||
| 			    popupText.textContent = `You clicked on ${app.name} ${app.version}!`; | ||||
| 			if (app.installed=='true') reinstall(app.name, 'popupText'); | ||||
| 			else load_template(app.name,'popupText'); | ||||
| 			popup.classList.remove('hidden'); | ||||
| @@ -599,53 +720,16 @@ | ||||
|  | ||||
|     function renderVPN() { | ||||
|         myAppsContainer.innerHTML = ` | ||||
| 	<fieldset> | ||||
| 	<legend>Enable proxy</legend> | ||||
| 	<form class="form-install" action="#" method="post" id="save_vpn"> | ||||
| 		<div class="row"> | ||||
| 		    <div class="mb-3"> | ||||
| 				<label for="vpn_domain">Please add domain url to download the VPN hash from (default: https://portal.safebox.network):</label> | ||||
| 				<input type="text" class="form-control" name="VPN_DOMAIN" id="vpn_domain" value="https://portal.safebox.network"> | ||||
| 				<div class="invalid-feedback"> | ||||
| 				Please enter a valid domain. | ||||
| 				</div> | ||||
| 		    </div> | ||||
| 		</div> | ||||
| 		<div class="row"> | ||||
| 		    <div class="mb-3"> | ||||
| 				<label for="vpn_pass">Please type in the generated VPN passkey (8 digits):</label> | ||||
| 				<input type="text" class="form-control" name="VPN_PASS" id="vpn_pass" value="" maxlength="8" size="10"> | ||||
| 		    </div> | ||||
| 		</div> | ||||
| 		<div class="row"> | ||||
| 		    <div class="mb-3"> | ||||
| 				<label for="letsencrypt_mail">Please add the letsencrypt mail address:</label> | ||||
| 				<input type="email" class="form-control" name="LETSENCRYPT_MAIL" id="letsencrypt_mail" value=""> | ||||
| 				<div class="invalid-feedback"> | ||||
| 				Please enter a valid email. | ||||
| 				</div> | ||||
| 		    </div> | ||||
| 		</div> | ||||
| 		<div class="row"> | ||||
| 		    <div class="mb-3"> | ||||
| 				<label for="letsencrypt_servername">Please add letsencrypt server name (default is letsencrypt but you can add zerossl too):</label> | ||||
| 				<input type="text" class="form-control" name="LETSENCRYPT_SERVERNAME" id="letsencrypt_servername" value="letsencrypt"> | ||||
| 		    </div> | ||||
| 		</div> | ||||
| 		<div class="row"> | ||||
| 		    <div class="mb-3"> | ||||
| 			<button class="btn btn-lg btn-primary btn-block" type="submit" id="vpn_save_btn"> Save </button>   | ||||
| 			<button class="btn btn-lg btn-primary btn-block" type="button" id="vpn_cancel_btn"> Cancel </button> | ||||
| 		    </div> | ||||
| 		</div> | ||||
| 	</form> | ||||
| 	</fieldset> | ||||
|             <div id="vpn" class="innerDiv"> | ||||
| 	    Loading... | ||||
|             </div> | ||||
|         `; | ||||
| 	get_proxy_html(); | ||||
|     } | ||||
|  | ||||
|     function renderServices() { | ||||
|         myAppsContainer.innerHTML = ` | ||||
|             <div id="services"> | ||||
|             <div id="services" class="innerDiv"> | ||||
| 	    Loading... | ||||
|             </div> | ||||
|         `; | ||||
| @@ -654,7 +738,7 @@ | ||||
|  | ||||
|     function renderUpdates() { | ||||
|         myAppsContainer.innerHTML = ` | ||||
|             <div id="updates"> | ||||
|             <div id="updates" class="innerDiv"> | ||||
| 	    Looking for updates... Please wait... | ||||
|             </div> | ||||
|         `; | ||||
| @@ -743,6 +827,6 @@ | ||||
| <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> | ||||
| <script src="https://cdn.jsdelivr.net/npm/popper.js@1.14.6/dist/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" crossorigin="anonymous"></script> | ||||
| <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.2.1/dist/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script> | ||||
| <script src="common.js?t=4"></script> | ||||
| <script src="common.js?t=9"></script> | ||||
| </body> | ||||
| </html> | ||||
|   | ||||
							
								
								
									
										853
									
								
								manage2B.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										875
									
								
								manage3.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						| @@ -0,0 +1,875 @@ | ||||
| <!DOCTYPE html> | ||||
| <html lang="hu"> | ||||
| <head> | ||||
|   <meta charset="UTF-8" /> | ||||
|   <meta name="viewport" content="width=device-width, initial-scale=1" /> | ||||
|   <title>Safebox</title> | ||||
|   <link href="https://fonts.googleapis.com/css2?family=Switzer:ital,wght@0,300;0,400;0,500;0,600;1,400&display=swap" rel="stylesheet" /> | ||||
|   <style> | ||||
|     :root { | ||||
|       --highlight-color: #F9DB54; | ||||
|     } | ||||
|  | ||||
|     body { | ||||
|       margin: 0; | ||||
|       font-family: 'Switzer', sans-serif; | ||||
|       font-weight: 500; | ||||
|       font-size: 16px; | ||||
|       background-color: #000; | ||||
|       color: white; | ||||
|       display: flex; | ||||
|       height: 100vh; | ||||
|     } | ||||
|  | ||||
|     h4 { | ||||
| 	font-size: 16px; | ||||
|     } | ||||
|  | ||||
| 	table {border: 1px solid var(--highlight-color); width:100%;} | ||||
| 	table th {padding-left: 20px; text-align: left; color: var(--highlight-color); width: 25%;} | ||||
| 	table td {padding-left: 20px; text-align:left; width: 25%;} | ||||
|  | ||||
|     .sidebar { | ||||
|       width: 250px; | ||||
|       background-color: #101214; | ||||
|       display: flex; | ||||
|       flex-direction: column; | ||||
|       justify-content: space-between; | ||||
|       padding: 20px 0; | ||||
|       margin: 20px; | ||||
|       border-radius: 20px; | ||||
|       transition: width 0.3s; | ||||
|     } | ||||
|  | ||||
|     .logo { | ||||
|       text-align: center; | ||||
|       margin-bottom: 40px; | ||||
|       font-size: 24px; | ||||
|       font-weight: bold; | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       justify-content: center; | ||||
|       gap: 10px; | ||||
|     } | ||||
|  | ||||
|     .logo img { | ||||
|       height: 30px; | ||||
|     } | ||||
|  | ||||
|     .menu { | ||||
|       display: flex; | ||||
|       flex-direction: column; | ||||
|       gap: 10px; | ||||
|       padding: 0 10px; | ||||
|     } | ||||
|  | ||||
|     .menu-item { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       gap: 10px; | ||||
|       padding: 10px 20px; | ||||
|       cursor: pointer; | ||||
|       color: white; | ||||
|       transition: color 0.3s; | ||||
|     } | ||||
|  | ||||
|     .menu-item:hover { | ||||
|       color: var(--highlight-color); | ||||
|     } | ||||
|  | ||||
|     .menu-item i { | ||||
|       font-size: 18px; | ||||
|     } | ||||
|  | ||||
|     .menu-item span { | ||||
|       display: inline; | ||||
|     } | ||||
|  | ||||
|     .menu-item img { | ||||
|       width: 24px; | ||||
|     } | ||||
|  | ||||
|     .menu-item.active { | ||||
|       background-color: var(--highlight-color); | ||||
|       color: black; | ||||
|       border-radius: 10px; | ||||
|       font-weight: bold; | ||||
|       margin: 4px; | ||||
|     } | ||||
|  | ||||
|     .menu-item.active:hover { | ||||
|       color: black; | ||||
|     } | ||||
|  | ||||
|     .details { | ||||
|       color: white; | ||||
|       text-decoration: none; | ||||
|     } | ||||
|  | ||||
|     .yellow-row { | ||||
| 	max-width:250px; | ||||
| 	display: flex; | ||||
| 	align-items: flex-start; | ||||
| 	box-sizing: border-box; | ||||
|         margin: 0px; | ||||
| 	width: 100%; | ||||
| 	padding: 0 20px; | ||||
|     } | ||||
|  | ||||
|     .yellow-box { | ||||
|       background-color: var(--highlight-color); | ||||
|       color: black; | ||||
|       text-align: left; | ||||
|       margin: 0px; | ||||
|       padding: 10px 18px; | ||||
|       border-radius: 20px 20px 0px 20px; | ||||
|       font-weight: bold; | ||||
|       font-size: 12px; | ||||
|     } | ||||
|  | ||||
|     .yellow-corner { | ||||
| 	padding:0px; | ||||
| 	border: 0px; | ||||
| 	display: flex; | ||||
| 	margin: 0px; | ||||
| 	margin-top: auto; | ||||
| 	align-items: flex-end; | ||||
|     } | ||||
|  | ||||
|     .main { | ||||
|       flex: 1; | ||||
|       padding: 30px; | ||||
|       display: flex; | ||||
|       flex-direction: column; | ||||
|       overflow-y: auto; | ||||
|     } | ||||
|  | ||||
| 	#appsContainer { | ||||
| 	  display: flex; | ||||
| 	  flex-wrap: wrap; | ||||
| 	  gap: 16px; | ||||
| 	  padding: 0px; | ||||
| 	} | ||||
|  | ||||
| 	.app { | ||||
| 	  border: 1px solid #41464f; | ||||
| 	  border-radius: 15px; | ||||
| 	  text-align: left; | ||||
| 	  padding: 20px; | ||||
| 	  width: 130px; | ||||
| 	  min-height: 200px; | ||||
| 	  text-align: left; | ||||
| 	  display: flex; | ||||
| 	  flex-direction: column; | ||||
| 	  align-items: left; | ||||
| 	} | ||||
|  | ||||
| 	.app-img { | ||||
| 	  padding: 0px; | ||||
| 	} | ||||
|  | ||||
| 	.app img { | ||||
| 	  border-radius: 15px; | ||||
| 	  background-color: #101214; | ||||
| 	  width: 110px; | ||||
| 	  height: 110px; | ||||
| 	  object-fit: contain; | ||||
| 	  margin-bottom: 20px; | ||||
| 	  padding: 10px; | ||||
| 	} | ||||
|  | ||||
| 	.app-label { | ||||
| 	  font-size: 10px; | ||||
| 	  color: #cccccc; | ||||
| 	  margin-bottom: 10px; | ||||
| 	  align-items: left; | ||||
| 	  text-align: left; | ||||
| 	} | ||||
|  | ||||
| 	.app-name { | ||||
| 	  font-size: 16px; | ||||
| 	  font-weight: bold; | ||||
| 	  margin-bottom: 30px; | ||||
| 	} | ||||
|  | ||||
| 	.more-btn { | ||||
| 	  background-color: var(--highlight-color); | ||||
| 	  border: none; | ||||
| 	  border-radius: 15px; | ||||
| 	  padding: 20px; | ||||
| 	  font-size: 16px; | ||||
| 	  font-weight: 400; | ||||
| 	  cursor: pointer; | ||||
| 	  width: 100%; | ||||
| 	} | ||||
|  | ||||
| 	.app-details { | ||||
| 		padding: 0px 50px; | ||||
| 	} | ||||
|  | ||||
| 	.app-fields { | ||||
| 	  border: 1px solid #41464f; | ||||
| 	  border-radius: 15px; | ||||
| 	  text-align: left; | ||||
| 	  padding: 20px; | ||||
| 	  margin: 30px 0px 10px 0px; | ||||
| 	  display: flex; | ||||
| 	  flex-direction: column; | ||||
| 	  align-items: left; | ||||
| 	} | ||||
|  | ||||
| 	.app-fields .row { | ||||
|             display: block; | ||||
| 	      justify-content: space-between; | ||||
| 	      align-items: center; | ||||
| 	      padding: 5px 20px; | ||||
| 	      border-radius: 10px; | ||||
| 	      gap: 10px; | ||||
| 	} | ||||
|  | ||||
| 	#letsencrypt { | ||||
| 		padding-top: 20px; | ||||
| 	} | ||||
|  | ||||
| .header-block { | ||||
|   display: flex; | ||||
|   justify-content: space-between; | ||||
|   align-items: flex-start; | ||||
|   padding: 20px 0px; | ||||
| } | ||||
|  | ||||
| .logo-and-text { | ||||
|   display: flex; | ||||
|   align-items: flex-start; | ||||
|   gap: 16px; | ||||
| } | ||||
|  | ||||
| .applogo img { | ||||
|   border-radius: 15px; | ||||
|   background-color: #101214; | ||||
|   width: 70px; | ||||
|   height: 70px; | ||||
|   object-fit: contain; | ||||
|   padding: 40px; | ||||
| } | ||||
|  | ||||
| .text-content { | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
| } | ||||
|  | ||||
| .title { | ||||
|   font-size: 20px; | ||||
|   font-weight: bold; | ||||
|   margin: 0; | ||||
| } | ||||
|  | ||||
| .subtitle { | ||||
|   font-size: 14px; | ||||
|   margin: 4px 0; | ||||
|   color: #999; | ||||
| } | ||||
|  | ||||
| .description { | ||||
|   font-size: 12px; | ||||
|   margin: 20px 0 0; | ||||
|   color: #999; | ||||
| } | ||||
|  | ||||
| .notification-btn { | ||||
|       background-color: var(--highlight-color); | ||||
|       color: black; | ||||
|       border: none; | ||||
|       padding: 10px 20px; | ||||
|       border-radius: 10px; | ||||
|       cursor: pointer; | ||||
|       font-weight: bold; | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       gap: 10px; | ||||
| } | ||||
|  | ||||
|     .main-header { | ||||
|       display: flex; | ||||
|       justify-content: space-between; | ||||
|       align-items: center; | ||||
|       margin-bottom: 30px; | ||||
|     } | ||||
|  | ||||
|     .main-header h1 { | ||||
|       margin: 0; | ||||
|       font-size: 28px; | ||||
|     } | ||||
|  | ||||
|     .main-header button { | ||||
|       background-color: var(--highlight-color); | ||||
|       color: black; | ||||
|       border: none; | ||||
|       padding: 10px 20px; | ||||
|       border-radius: 10px; | ||||
|       cursor: pointer; | ||||
|       font-weight: bold; | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       gap: 10px; | ||||
|     } | ||||
|  | ||||
|     .input-row, .input-group { | ||||
|       display: flex; | ||||
|       justify-content: space-between; | ||||
|       align-items: center; | ||||
|       border: 1px solid #41464f; | ||||
|       padding: 15px 20px; | ||||
|       margin-bottom: 15px; | ||||
|       border-radius: 10px; | ||||
|       gap: 10px; | ||||
|     } | ||||
|  | ||||
|     .input-container { | ||||
|       display: flex; | ||||
|       align-items: center; | ||||
|       gap: 5px; | ||||
|       flex: 1; | ||||
|       justify-content: flex-end; | ||||
|       position: relative; | ||||
|     } | ||||
|  | ||||
|     .input-row input, | ||||
|     .input-row select, | ||||
|     .row input,  | ||||
|     .row select { | ||||
|       background: transparent; | ||||
|       border: 1px solid #41464f; | ||||
|       padding: 8px 30px 8px 8px; | ||||
|       border-radius: 10px; | ||||
|       color: white; | ||||
|       transition: color 0.2s; | ||||
|       max-width: 40%; | ||||
|       box-sizing: border-box; | ||||
|     } | ||||
|  | ||||
|     .row input,  | ||||
|     .row select { | ||||
|       padding: 12px 30px 12px 12px; | ||||
|       font-size: 16px; | ||||
|     } | ||||
|  | ||||
|     .input-row input:focus, | ||||
|     .input-row select:focus, | ||||
|     .row input, | ||||
|     .row select { | ||||
|       outline: none; | ||||
|       background-color: black; | ||||
|       color: var(--highlight-color); | ||||
|     } | ||||
|  | ||||
|     .input-row select, | ||||
|     .row select { | ||||
|       appearance: none; | ||||
|       -webkit-appearance: none; | ||||
|       -moz-appearance: none; | ||||
|       background-image: url('data:image/svg+xml;utf8,<svg fill="white" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M7 10l5-5 5 5zM7 14l5 5 5-5z"/></svg>'); | ||||
|       background-repeat: no-repeat; | ||||
|       background-position: right 8px center; | ||||
|       background-size: 16px; | ||||
|       padding-right: 32px; | ||||
|     } | ||||
|  | ||||
| 	.info-container { | ||||
| 		position: relative; | ||||
| 		left: -18px; | ||||
| 		top: -22px; | ||||
| 		display: inline-block; | ||||
| 		font-family: Arial, sans-serif; | ||||
| 		margin: 0px; | ||||
| 		width: 0px; | ||||
| 	} | ||||
|  | ||||
|     .info-icon { | ||||
|       background-color: var(--highlight-color); | ||||
|       color: black; | ||||
|       border-radius: 50%; | ||||
|       padding: 1px 4px; | ||||
|       cursor: pointer; | ||||
|       font-weight: bold; | ||||
|       font-size: 10px; | ||||
|       text-align: center; | ||||
|       line-height: 1; | ||||
|       display: inline-block; | ||||
|     } | ||||
|  | ||||
|     .tooltip { | ||||
|       visibility: hidden; | ||||
|       background-color: #333; | ||||
|       border-radius: 5px; | ||||
|       padding: 4px 8px; | ||||
|       position: absolute; | ||||
|       z-index: 1; | ||||
|       bottom: 100%; /* above the icon */ | ||||
|       left: 50%; | ||||
|       transform: translateX(-78%); | ||||
|       opacity: 0; | ||||
|       transition: opacity 0.3s; | ||||
|       /*white-space: nowrap;*/ | ||||
|       text-align: right; | ||||
|       width: 300px; | ||||
|     } | ||||
|  | ||||
|     .tooltip::after { | ||||
|       content: ""; | ||||
|       position: absolute; | ||||
|       top: 100%; /* bottom of tooltip */ | ||||
|       left: 80%; | ||||
|       margin-left: -5px; | ||||
|       border-width: 5px; | ||||
|       border-style: solid; | ||||
|       border-color: #333 transparent transparent transparent; | ||||
|     } | ||||
|  | ||||
|     .info-container:hover .tooltip { | ||||
|       visibility: visible; | ||||
|       opacity: 1; | ||||
|     } | ||||
|  | ||||
|     .clear-btn { | ||||
|       position: absolute; | ||||
|       right: 8px; | ||||
|       background: transparent; | ||||
|       border: none; | ||||
|       color: white; | ||||
|       cursor: pointer; | ||||
|       font-size: 16px; | ||||
|       padding: 0; | ||||
|       width: 20px; | ||||
|       height: 20px; | ||||
|       line-height: 20px; | ||||
|       text-align: center; | ||||
|       user-select: none; | ||||
|     } | ||||
|  | ||||
|     .save-button { | ||||
|       background-color: var(--highlight-color); | ||||
|       color: black; | ||||
|       border: none; | ||||
|       padding: 15px 30px; | ||||
|       font-size: 16px; | ||||
|       border-radius: 10px; | ||||
|       font-weight: bold; | ||||
|       cursor: pointer; | ||||
|       margin-top: 30px; | ||||
|       align-self: flex-start; | ||||
|     } | ||||
|  | ||||
|     .save-button:hover { | ||||
|       background-color: #f5c300; | ||||
|     } | ||||
|  | ||||
|     .buttons .btn { | ||||
|       background-color: black; | ||||
|       border: 1px solid #999; | ||||
|       color: #999; | ||||
|       padding: 10px 15px; | ||||
|       font-size: 14px; | ||||
|       border-radius: 5px; | ||||
|       font-weight: bold; | ||||
|       cursor: pointer; | ||||
|       margin-top: 10px; | ||||
|       align-self: flex-start; | ||||
|     } | ||||
|  | ||||
|     .buttons .btn:hover { | ||||
|       border: 1px solid #f5c300; | ||||
|       color: #f5c300; | ||||
|     } | ||||
|  | ||||
|         .hidden { | ||||
|             display: none; | ||||
|         } | ||||
|  | ||||
|         .popup { | ||||
| 	    width: 100%; | ||||
|         } | ||||
|  | ||||
|         .popup-content { | ||||
|             width: 100%; | ||||
|             text-align: left; | ||||
|         } | ||||
|  | ||||
|         #popup .row { | ||||
|             display: flex; | ||||
|         } | ||||
|  | ||||
|     @media (max-width: 768px) { | ||||
|       .sidebar { | ||||
|         width: 80px; | ||||
|         padding: 20px 5px; | ||||
|       } | ||||
|  | ||||
|       .logo { | ||||
|         font-size: 0; | ||||
|       } | ||||
|  | ||||
|       .logo span { | ||||
|         display: none; | ||||
|       } | ||||
|  | ||||
|       .menu-item { | ||||
|         justify-content: center; | ||||
|         gap: 0; | ||||
|       } | ||||
|  | ||||
|       .menu-item span { | ||||
|         display: none; | ||||
|       } | ||||
|  | ||||
|       .yellow-box { | ||||
|         font-size: 0; | ||||
|         padding: 10px; | ||||
|       } | ||||
|  | ||||
|       .input-row { | ||||
|         flex-direction: column; | ||||
|         align-items: flex-start; | ||||
|       } | ||||
|  | ||||
|       .input-container { | ||||
|         width: 100%; | ||||
|         justify-content: flex-start; | ||||
|       } | ||||
|  | ||||
|       .input-row input, | ||||
|       .input-row select { | ||||
|         max-width: 100%; | ||||
|       } | ||||
|     } | ||||
|   </style> | ||||
|   <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"/> | ||||
| </head> | ||||
| <body> | ||||
|   <div class="sidebar"> | ||||
|     <div> | ||||
|       <div class="logo"> | ||||
|         <img src="/img/logo.png" alt="Safebox"/> | ||||
|         <span>Safebox</span> | ||||
|       </div> | ||||
|       <div class="menu"> | ||||
| <!-- | ||||
| 	<div class="menu-item"><i class="fas fa-th"></i><span>Applications</span></div> | ||||
|         <div class="menu-item"><i class="fas fa-hdd"></i><span>Disk Management</span></div> | ||||
|         <div class="menu-item"><i class="fas fa-chart-line"></i><span>Monitor</span></div> | ||||
|         <div class="menu-item active"><i class="fas fa-cog"></i><span>Settings</span></div> | ||||
| --> | ||||
| 	<div class="menu-item" id="installAppsBtn"><img src="/img/app.png" data-src="/img/app.png" data-hover="/img/app2.png" alt="Applications" /><span>Applications</span></div> | ||||
|         <div class="menu-item" id="backupBtn"><img src="/img/disk.png" data-src="/img/disk.png" data-hover="/img/disk2.png" alt="Backup" /><span>Backup</span></div> | ||||
|         <div class="menu-item" id="diskBtn"><img src="/img/disk.png" data-src="/img/disk.png" data-hover="/img/disk2.png" alt="Disk Management" /><span>Disk Management</span></div> | ||||
|         <div class="menu-item" id="monitorBtn"><img src="/img/monitor.png" data-src="/img/monitor.png" data-hover="/img/monitor2.png" alt="Monitor" /><span>Monitor</span></div> | ||||
| 	<div class="menu-item" id="settingsBtn"><img src="/img/settings.png" data-src="/img/settings.png" data-hover="/img/settings2.png" alt="Settings" /><span>Settings</span></div> | ||||
|       </div> | ||||
|     </div> | ||||
|     <div class="yellow-row"> | ||||
| 	    <div class="yellow-box"> | ||||
| 	      <h4>Safebox Pro</h4> | ||||
| 	      <p>Enjoy benefits and unlock more feature such as remote access, geo-redundant backups etc. <br><br> | ||||
| 	      <a href="" class="details">Read details</a><br><br> | ||||
| 		<img src="/img/upgrade.png" alt="Upgrade now" width="100%"/>	 | ||||
| 	      </p> | ||||
| 	    </div> | ||||
| 	    <div class="yellow-corner"> | ||||
| 		<img src="img/yellow_corner.png" alt=""/> | ||||
| 	    </div> | ||||
|     </div> | ||||
|   </div> | ||||
|   <div class="main" > | ||||
|     <div id="myAppsContainer"> | ||||
| 	    <div class="main-header"> | ||||
| 	      <h1>Settings</h1> | ||||
| 	      <button id="updatesBtn"><i class="fas fa-bell"></i> Notification</button> | ||||
| 	    </div> | ||||
| 	    <div class="input-row"> | ||||
| 	      <label>Docker registry name</label> | ||||
| 	      <div class="input-container"> | ||||
| 		<input type="text" placeholder="Enter name" /> | ||||
| 		<button class="clear-btn" onclick="this.previousElementSibling.value = ''">×</button> | ||||
| 	      </div> | ||||
| 	    </div> | ||||
| 	    <div class="input-row"> | ||||
| 	      <label>Enable logging</label> | ||||
| 	      <div class="input-container"> | ||||
| 		<select> | ||||
| 		  <option>Yes</option> | ||||
| 		  <option>No</option> | ||||
| 		</select> | ||||
| 	      </div> | ||||
| 	    </div> | ||||
| 	    <div class="input-row"> | ||||
| 	      <label>Backup folder</label> | ||||
| 	      <div class="input-container"> | ||||
| 		<input type="text" placeholder="Path to backup" /> | ||||
| 		<button class="clear-btn" onclick="this.previousElementSibling.value = ''">×</button> | ||||
| 	      </div> | ||||
| 	    </div> | ||||
| 	    <div class="input-row"> | ||||
| 	      <label>Send alerts</label> | ||||
| 	      <div class="input-container"> | ||||
| 		<select> | ||||
| 		  <option>Yes</option> | ||||
| 		  <option>No</option> | ||||
| 		</select> | ||||
| 	      </div> | ||||
| 	    </div> | ||||
| 	    <button class="save-button">Save Settings</button> | ||||
|     </div> | ||||
|     <div id="popup" class="popup hidden"> | ||||
| 	<div class="popup-content"> | ||||
| 		<div id="popupText" class="deployment"></div> | ||||
| 	</div> | ||||
|     </div> | ||||
|   </div> | ||||
|  | ||||
| <script> | ||||
|     // apps array beállítása common.js-ben | ||||
|     const apps = []; // GLOBAL VARIABLE | ||||
|  | ||||
|     document.addEventListener('DOMContentLoaded', function() { | ||||
|  | ||||
| 	  document.querySelectorAll('.menu-item.active').forEach(item => { | ||||
| 	    const img = item.querySelector('img'); | ||||
| 	      img.src = img.dataset.hover; | ||||
| 	/* | ||||
| 	    item.addEventListener('mouseenter', () => { | ||||
| 	      img.src = img.dataset.hover; | ||||
| 	    }); | ||||
| 	    item.addEventListener('mouseleave', () => { | ||||
| 	      img.src = img.dataset.src; | ||||
| 	    }); | ||||
| 	*/ | ||||
| 	  }); | ||||
|  | ||||
|     const myAppsBtn = document.getElementById('myAppsBtn'); | ||||
|     const installAppsBtn = document.getElementById('installAppsBtn'); | ||||
|     const backupBtn = document.getElementById('backupBtn'); | ||||
|     const diskBtn = document.getElementById('diskBtn'); | ||||
|     const monitorBtn = document.getElementById('monitorBtn'); | ||||
|     const settingsBtn = document.getElementById('settingsBtn'); | ||||
|  | ||||
|     const vpnBtn = document.getElementById('vpnBtn'); | ||||
|  | ||||
|     const myAppsContainer = document.getElementById('myAppsContainer'); | ||||
|     const popup = document.getElementById('popup'); | ||||
|     const popupText = document.getElementById('popupText'); | ||||
|     const closeBtn = document.querySelector('.close'); | ||||
|  | ||||
|     //Appok betöltése | ||||
|     function renderApps(all) { | ||||
| 	myAppsContainer.innerHTML = '<div class="main-header"><h1>Applications</h1><button id="updatesBtn"><i class="fas fa-bell"></i> Notification</button></div><div id="appsContainer"></div>'; | ||||
|     	const appsContainer = document.getElementById('appsContainer'); | ||||
|     	const updatesBtn = document.getElementById('updatesBtn'); | ||||
| 	updatesBtn.addEventListener('click', () => renderUpdates()); | ||||
|  | ||||
|         apps.forEach(app => { | ||||
| 	    //if ((all==false && app.installed=='true') || (all==true && app.installed!='true')) { | ||||
| 		    const appDiv = document.createElement('div'); | ||||
| 		    appDiv.className = 'app'; | ||||
| 		    appDiv.innerHTML = ` | ||||
| 			<div class="app-img"><img src="${app.image}" alt="${app.name}" title="${app.orig_name} ${app.version}"></div> | ||||
| 			<div class="app-label">${app.name} ${app.version}</div> | ||||
| 			<div class="app-name">${app.orig_name}</div> | ||||
| 			<button class="more-btn">More</button> | ||||
| 		    `; | ||||
| 		    appDiv.addEventListener('click', () => { | ||||
| 			popupText.textContent = `You clicked on ${app.name} ${app.version}!`; | ||||
| 			if (app.installed=='true') reinstall(app.name, 'popupText'); | ||||
| 			else load_template(app.name,'popupText'); | ||||
| 			popup.classList.remove('hidden'); | ||||
| 			myAppsContainer.classList.add('hidden'); | ||||
| 		    }); | ||||
| 		    appsContainer.appendChild(appDiv); | ||||
|             //} | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     //TODO: Ilyen függvényeket kell csinálni és a listenerekhez adni az egyes részeket | ||||
|     function renderText(title) { | ||||
|         //TODO: itt kell a buttont editálni és így kell hozzáadni hozzá mindent | ||||
|         myAppsContainer.innerHTML = ` | ||||
|             <h1 style="text-align: center;">${title}</h1> | ||||
|  | ||||
|             <div class="input-group"> | ||||
|                 <input type="text" placeholder="Írj be valamit..." id="textInput"> | ||||
|                 <button id="submitButton">Küldés</button> | ||||
|  | ||||
|                 <select id="myComboBox" class="custom-select"> | ||||
|                     <option value="">Válassz egy lehetőséget...</option> | ||||
|                     <option value="1">Első opció</option> | ||||
|                     <option value="2">Második opció</option> | ||||
|                     <option value="3">Harmadik opció</option> | ||||
|                 </select> | ||||
|  | ||||
|                 <label class="checkbox-container"> | ||||
|                     <input type="checkbox" id="myCheckbox"> | ||||
|                     <span class="checkmark"></span> | ||||
|                     Elfogadom a feltételeket | ||||
|                 </label> | ||||
|             </div> | ||||
|         `; | ||||
|  | ||||
|         const submitButton = document.getElementById('submitButton'); | ||||
|         const textInput = document.getElementById('textInput'); | ||||
|  | ||||
|         if (submitButton && textInput) { | ||||
|             submitButton.addEventListener('click', () => { | ||||
|                 const value = textInput.value.trim(); | ||||
|                 if (value) { | ||||
|                     alert(`Beírt szöveg: ${value}`); | ||||
|                     textInput.value = ''; | ||||
|                 } else { | ||||
|                     alert('Kérlek írj be valamit!'); | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     function renderVPN() { | ||||
|         myAppsContainer.innerHTML = ` | ||||
| 	    <div class="main-header"> | ||||
| 	      <h1>VPN</h1> | ||||
| 	    </div> | ||||
|             <div id="vpn" class="innerDiv"> | ||||
| 	    Loading... | ||||
|             </div> | ||||
|         `; | ||||
| 	get_proxy_html(); | ||||
|     } | ||||
|  | ||||
|     function renderServices() { | ||||
|         myAppsContainer.innerHTML = ` | ||||
| 	    <div class="main-header"> | ||||
| 	      <h1>Services</h1> | ||||
| 	    </div> | ||||
|             <div id="services" class="innerDiv"> | ||||
| 	    Loading... | ||||
|             </div> | ||||
|         `; | ||||
| 	get_services(); | ||||
|     } | ||||
|  | ||||
|     function renderUpdates() { | ||||
|         myAppsContainer.innerHTML = ` | ||||
| 	    <div class="main-header"> | ||||
| 	      <h1>Updates</h1> | ||||
| 	    </div> | ||||
|             <div id="updates" class="innerDiv"> | ||||
| 	    Looking for updates... Please wait... | ||||
|             </div> | ||||
|         `; | ||||
| 	get_updates(); | ||||
|     } | ||||
|  | ||||
|     function renderSystemServices() { | ||||
|         myAppsContainer.innerHTML = ` | ||||
| 	    <div class="main-header"> | ||||
| 	      <h1>System services</h1> | ||||
| 	    </div> | ||||
|             <div id="system" class="innerDiv"> | ||||
| 	    Loading... | ||||
|             </div> | ||||
|         `; | ||||
| 	get_system(); | ||||
|     } | ||||
|  | ||||
|     function renderSettings() { | ||||
| 	myAppsContainer.innerHTML = ` | ||||
|     <div class="main-header"> | ||||
|       <h1>Settings</h1> | ||||
|       <button id="updatesBtn"><i class="fas fa-bell"></i> Notification</button> | ||||
|     </div> | ||||
|     <div class="input-row"> | ||||
| 	<button id="servicesBtn" class="save-button">Services</button> | ||||
| 	<button id="repositoriesBtn" class="save-button">Repositories</button> | ||||
| 	<button id="systemservicesBtn" class="save-button">System services</button> | ||||
|     </div> | ||||
|         `; | ||||
| 	const servicesBtn = document.getElementById('servicesBtn'); | ||||
| 	const repositoriesBtn = document.getElementById('repositoriesBtn'); | ||||
| 	const systemservicesBtn = document.getElementById('systemservicesBtn'); | ||||
|     	const updatesBtn = document.getElementById('updatesBtn'); | ||||
| 	servicesBtn.addEventListener('click', () => renderServices()); | ||||
| 	repositoriesBtn.addEventListener('click', () => renderRepositories()); | ||||
| 	systemservicesBtn.addEventListener('click', () => renderSystemServices()); | ||||
| 	updatesBtn.addEventListener('click', () => renderUpdates()); | ||||
|     } | ||||
|  | ||||
|     function renderRepositories() { | ||||
|         myAppsContainer.innerHTML = ` | ||||
| 	    <div class="main-header"> | ||||
| 	      <h1>Repositories</h1> | ||||
| 	    </div> | ||||
| 		<div id="repositories" style="text-align:left">Loading...</div> | ||||
| 		<br> | ||||
| 		<form class="form-install" action="#" method="post" id="add_repo"> | ||||
| 		<div class="input-row"> | ||||
| 			<label for="registry">Please add a new GIT repository URL: </label> | ||||
|       			<div class="input-container"> | ||||
| 				<input type="registry" name="repository" id="repository" size="100" value="" required> | ||||
|         			<button class="clear-btn" onclick="this.previousElementSibling.value = ''">×</button> | ||||
|       			</div> | ||||
| 			<!--<div class="invalid-feedback"> | ||||
| 			Please enter a valid repository url. | ||||
| 			</div>--> | ||||
| 		</div> | ||||
| 		<div class="row"> | ||||
| 			<button class="save-button" type="submit" id="repo_add_btn"> Add </button> | ||||
| 		</div> | ||||
| 		</form> | ||||
|         `; | ||||
| 	jQuery('#add_repo').submit(function() { | ||||
| 		jQuery('#repositories').html('Loading...'); | ||||
| 		add_repository(); | ||||
| 		return false; | ||||
| 	}); | ||||
|  | ||||
| 	get_repositories(); | ||||
|     } | ||||
|  | ||||
| 	function activate(btn) { | ||||
| 		//myAppsBtn.classList.remove('active'); | ||||
| 		installAppsBtn.classList.remove('active'); | ||||
| 		backupBtn.classList.remove('active'); | ||||
| 		diskBtn.classList.remove('active'); | ||||
| 		monitorBtn.classList.remove('active'); | ||||
| 		settingsBtn.classList.remove('active'); | ||||
| 		btn.classList.add('active'); | ||||
| 	} | ||||
|  | ||||
|     //myAppsBtn.addEventListener('click', () => {renderApps(false); activate(myAppsBtn);}); | ||||
| 	installAppsBtn.addEventListener('click', () => {renderApps(true); activate(installAppsBtn);}); | ||||
| 	backupBtn.addEventListener('click', () => {renderText('Backup'); activate(backupBtn);}); | ||||
| 	diskBtn.addEventListener('click', () => {renderText('Disk Management'); activate(diskBtn)}); | ||||
| 	monitorBtn.addEventListener('click', () => {renderText('Monitor'); activate(monitorBtn)}); | ||||
|     	settingsBtn.addEventListener('click', () => {renderSettings(); activate(settingsBtn)}); | ||||
|  | ||||
| //    vpnBtn.addEventListener('click', () => renderVPN()); | ||||
| /* | ||||
|     closeBtn.addEventListener('click', () => { | ||||
|         popup.classList.add('hidden'); | ||||
|     }); | ||||
|  | ||||
|     popup.addEventListener('click', (event) => { | ||||
|         if (event.target === popup) { | ||||
|             popup.classList.add('hidden'); | ||||
|         } | ||||
|     }); | ||||
| */ | ||||
| //    renderApps(false); | ||||
| }); | ||||
| </script> | ||||
|  | ||||
| <!-- Optional JavaScript --> | ||||
| <!-- jQuery first, then Popper.js, then Bootstrap JS --> | ||||
| <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> | ||||
| <script src="https://cdn.jsdelivr.net/npm/popper.js@1.14.6/dist/umd/popper.min.js" integrity="sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut" crossorigin="anonymous"></script> | ||||
| <script src="https://cdn.jsdelivr.net/npm/bootstrap@4.2.1/dist/js/bootstrap.min.js" integrity="sha384-B0UglyR+jN6CkvvICOB2joaf5I4l3gm9GU6Hc1og6Ls7i6U/mkkaduKaBhlAXv9k" crossorigin="anonymous"></script> | ||||
| <script src="common.js?t=10"></script> | ||||
| </body> | ||||
| </html> | ||||
|  | ||||
							
								
								
									
										82
									
								
								scan.php
									
									
									
									
									
								
							
							
						
						| @@ -144,12 +144,14 @@ switch ($_GET["op"]) { | ||||
| 						else { | ||||
| 							foreach ($data["DEPLOYMENTS"] as $service_name => $content) { | ||||
|                                                                 $orig_service_name = $service_name; | ||||
|                                                                 $service_name = strtolower($service_name); | ||||
|                                                                 //echo base64_decode($content); | ||||
| 								$service_name = strtolower($service_name); | ||||
| 								$version = $content["version"]; | ||||
| 								$icon = $content["icon"]; | ||||
| 								if (empty($icon) || $icon == "null") $icon = "image.png"; // default icon image | ||||
| 								if (array_key_exists($service_name,$data["INSTALLED_SERVICES"])) $installed = "true"; | ||||
| 								else $installed = "false"; | ||||
| 								if (!empty($deployments)) $deployments .= ", "; | ||||
| 								$deployments .= '{"name": "'.$service_name.'", "orig_name": "'.$orig_service_name.'", "image": "image.png", "content": "'.$content.'", "installed": "'.$installed.'"}'; | ||||
| 								$deployments .= '{"name": "'.$service_name.'", "orig_name": "'.$orig_service_name.'", "image": "'.$icon.'", "version": "'.$version.'", "installed": "'.$installed.'"}'; | ||||
| 							} | ||||
| 							if (!empty($deployments)) $deployments = "[{$deployments}]"; | ||||
| 						} | ||||
| @@ -178,13 +180,29 @@ switch ($_GET["op"]) { | ||||
| 				if ($key=="deployment") { | ||||
| 					if ($data["STATUS"]=="0") { // ask | ||||
| 						$template = json_decode(base64_decode($data["TEMPLATE"])); | ||||
| 						echo "<fieldset><form action=\"#\" method=\"post\" id=\"deploy_{$template->name}_form\"><br>"; | ||||
| 						echo '<div id="letsencrypt">'; | ||||
|  | ||||
| 						echo ' | ||||
| 						<div class="app-details"> | ||||
| 							<div class="header-block"> | ||||
| 							  <div class="logo-and-text"> | ||||
| 							    <div class="applogo"> | ||||
| 								<img src="'.$template->icon.'"> | ||||
| 							    </div> | ||||
| 							    <div class="text-content"> | ||||
| 							      <h1 class="title">'.$template->name.'</h1> | ||||
| 							      <h2 class="subtitle">'.$template->title.'</h2> | ||||
| 							      <p class="description">'.$template->description.'</p> | ||||
| 							    </div> | ||||
| 							  </div> | ||||
| 							  <button id="updatesBtn" class="notification-btn"><i class="fas fa-bell"></i> Notification</button> | ||||
| 							</div> | ||||
| 						'; | ||||
| 						if ($reinstall) { | ||||
| 							echo '<div id="letsencrypt">'; | ||||
| 							//var_dump($template); | ||||
|                                                         $letsencrypt = check_letsencrypt(); | ||||
| 							if (empty($letsencrypt)) echo "LETSENCRYPT file doesn't exists..."; | ||||
| 							elseif ($letsencrypt=="ERROR") echo "LETSENCRYPT file: read JSON error..."; | ||||
| 							if (empty($letsencrypt)) echo "LETSENCRYPT file doesn't exists...<br><br>"; | ||||
| 							elseif ($letsencrypt=="ERROR") echo "LETSENCRYPT file: read JSON error...<br><br>"; | ||||
| 							else { | ||||
| 								$domain = ""; | ||||
| 								foreach ($template->fields as $field) { | ||||
| @@ -192,23 +210,41 @@ switch ($_GET["op"]) { | ||||
| 								} | ||||
| 								if (!empty($domain)) show_letsencrypt($letsencrypt, $domain); | ||||
| 							} | ||||
| 							echo '</div>'; | ||||
| 						} | ||||
| 						echo '</div>'; | ||||
| 						echo "<form action=\"#\" method=\"post\" id=\"deploy_{$template->name}_form\">"; | ||||
| 						echo "<div class=\"app-fields\">"; | ||||
| 						foreach ($template->fields as $field) { | ||||
| 							if (!empty($field->title)) echo "<div class=\"row\"><h3>".$field->title."</h3></div>"; | ||||
| 							if (isset($field->generated)) { | ||||
| 								echo "<input type=\"hidden\" value=\"generated:{$field->generated}\" name=\"{$field->key}\" id=\"{$template->name}_{$field->key}\" class=\"additional_{$template->name}\">"; | ||||
| 								echo "<input type=\"hidden\" value=\"generated:{$field->generated}:{$field->value}\" name=\"{$field->key}\" id=\"{$template->name}_{$field->key}\" class=\"additional_{$template->name}\">"; | ||||
| 							} | ||||
| 							else { | ||||
| 							echo "<div class=\"row\"><div class=\"mb-3\"><label>".$field->description."</label> | ||||
| 								<input ".($field->required=="true" ? "required" : "")." type=\"".(!empty($field->type) ? $field->type : "text")."\" value=\"{$field->value}\" name=\"{$field->key}\" id=\"{$template->name}_{$field->key}\" class=\"additional_{$template->name}\"> | ||||
| 							</div></div>"; | ||||
| 								echo "<div class=\"row\">"; | ||||
| 								echo "<label>".$field->description."</label> | ||||
| 								<div class=\"input-container\"><input ".($field->required=="true" ? "required" : "")." type=\"".(!empty($field->type) ? $field->type : "text")."\" value=\"{$field->value}\" name=\"{$field->key}\" id=\"{$template->name}_{$field->key}\" class=\"additional_{$template->name}\"></div> | ||||
| 								<div class=\"info-container\"> | ||||
| 								"; | ||||
| 								if (!empty($field->info)) echo " | ||||
| 									  <span class=\"info-icon\">i</span> | ||||
| 									  <div class=\"tooltip\">{$field->info}</div> | ||||
| 								"; | ||||
| 								echo "</div>"; | ||||
| 								echo "</div>"; | ||||
| 								if (!empty($field->details)) echo "<div class=\"row\"><i>".$field->details."</i></div>"; | ||||
| 							} | ||||
| 						} | ||||
| 						echo "</div>"; | ||||
|  | ||||
|  | ||||
|                                                 echo " | ||||
|                                                 <div class=\"row buttons\"> | ||||
|                                                 <div class=\"mb-3\"> | ||||
|                                                 echo "<div class=\"row buttons\">"; | ||||
| 						if ($reinstall) { | ||||
| 							echo " | ||||
| 							<div class=\"mb-3\"> | ||||
| 							<button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\" id=\"update_{$template->name}_btn\" onclick=\"update_deployment('{$template->name}')\">Update</button> | ||||
| 							</div>"; | ||||
| 						} | ||||
| 						echo " | ||||
|                                                 <div class=\"mb-3\" style=\"margin-left:30px;\"> | ||||
|                                                 <button class=\"btn btn-lg btn-primary btn-block\" type=\"submit\" id=\"deploy_{$template->name}_btn\">".($reinstall ? "Reinstall" : "Install")."</button> | ||||
|                                                 </div>"; | ||||
| 						if ($reinstall) { | ||||
| @@ -217,12 +253,13 @@ switch ($_GET["op"]) { | ||||
| 							<button class=\"btn btn-lg btn-primary btn-block\" type=\"button\" id=\"uninstall_{$template->name}_btn\" onclick=\"uninstall('{$template->name}')\">Uninstall</button> | ||||
| 							</div>"; | ||||
| 						} | ||||
| 						echo "<div class=\"mb-3\" style=\"margin-left:30px;\"> | ||||
| 						echo "<div class=\"mb-3\" style=\"margin-left:230px;float:\"> | ||||
| 						<button class=\"btn btn-lg btn-primary btn-block\" type=\"button\" id=\"cancel_{$template->name}_btn\">Cancel</button> | ||||
| 						</div>"; | ||||
| 						</div>"; // buttons | ||||
|                                                 echo " | ||||
|                                                 </div> | ||||
|                                                 </form></fieldset> | ||||
| 						</form> | ||||
| 						</div> | ||||
| <script> | ||||
| 	jQuery('#deploy_{$template->name}_form').submit(function() { | ||||
| 		".($reinstall ? "redeploy" : "deploy")."('{$template->name}'); | ||||
| @@ -230,6 +267,7 @@ switch ($_GET["op"]) { | ||||
| 	}); | ||||
|         jQuery('#cancel_{$template->name}_btn').click(function() { | ||||
|                 $('div#{$template->name}').html(''); | ||||
|     		document.getElementById('myAppsContainer').classList.remove('hidden'); // manage3 | ||||
|     		document.getElementById('popup').classList.add('hidden'); // manage2 | ||||
|         }); | ||||
| </script> | ||||
| @@ -280,6 +318,7 @@ switch ($_GET["op"]) { | ||||
| 			show_letsencrypt($letsencrypt, $domain); | ||||
| 		} | ||||
| 	break; | ||||
| 	case "edit": // update deployment after edit | ||||
| 	case "redeploy": | ||||
| 	case "deploy": | ||||
| 		if ($key=check_deploy($_GET["additional"])) {  | ||||
| @@ -294,6 +333,11 @@ switch ($_GET["op"]) { | ||||
| 			foreach ($fields as $field_key => $field_value) { | ||||
| 				$field_arr = explode(":",$field_value); | ||||
| 				if ($field_arr[0]=="generated") { | ||||
| 					if ($_GET["op"]=="edit") { | ||||
| 						$fields[$field_key] = $field_arr[2]; // replace with previously stored value | ||||
| 						continue; // do NOT regenerate values | ||||
| 					} | ||||
|  | ||||
| 					if (intval($field_arr[3])==0) $len = 10; // default length | ||||
| 					else $len = $field_arr[3]; | ||||
|  | ||||
|   | ||||